---------------------------- SECS I / SECS II ---------------------------------- SECS_IO = require('secs_i') struct = require('struct') local SF_LIST = 0x00 local SF_NITEMS = 0x1F local SF_BINARY = 0x20 local SF_BOOLEAN = 0x24 local SF_ASCII = 0x40 local SF_JIS_8 = 0x44 local SF_INT8 = 0x60 local SF_INT1 = 0x64 local SF_INT2 = 0x68 local SF_INT4 = 0x70 local SF_FLOAT8 = 0x80 local SF_FLOAT4 = 0x90 local SF_UINT8 = 0xA0 local SF_UINT1 = 0xA4 local SF_UINT2 = 0xA8 local SF_UINT4 = 0xB0 local MDLN = "DS-80B" local SOFTREV = "MI370E" local secsId = 0x1234 local host = false local connected = false local transaction_id = 1 local eq_online = 3 -- 1: online remote, 2: online local, 3: offline local eq_status = 2 -- 1: not ready, 2: ready, 3: busy, 4: process cmpl, 5: pause, 6: complete local onSendEventMsg = nil local onPrimaryMsg = nil local onSecondaryMsg = nil local onProcessMsg = nil local msgQueue = {} -------------------------------------------------------------------------------------------- local function hexDumpString(buf) for i=1,math.ceil(#buf/16) * 16 do if (i-1) % 16 == 0 then io.stderr:write(string.format('%06X ', i-1)) end io.stderr:write( i > #buf and ' ' or string.format('%02X ', buf:byte(i)) ) if i % 8 == 0 then io.stderr:write(' ') end if i % 16 == 0 then io.stderr:write( buf:sub(i-16+1, i):gsub('[^%g]','.'), '\n' ) end end io.stderr:write("\n"); end local function dumpData(items) if items.list then io.stderr:write(string.format("list: %d\n",#items)) end for i=1, #items do if not items.list then if i == 1 then io.stderr:write(string.format("type: "..items[1].."\n")); io.stderr:write(string.format("value: "..items[2].."\n")); end else dumpData(items[i]) end end end local function dumpMsg(msg) io.stderr:write("dumpMsg\n-------\n") io.stderr:write(string.format("id: %02X\n", msg.header.secsId)) io.stderr:write(string.format("reverse:%s\n", msg.header.secsReverse)) io.stderr:write(string.format("stream: %02X\n", msg.header.secsStream)) io.stderr:write(string.format("func: %02X\n", msg.header.secsFunction)) io.stderr:write(string.format("blkn: %02X\n", msg.header.secsBlock)) io.stderr:write(string.format("sys1: %04X\n", msg.header.secsSys1)) io.stderr:write(string.format("sys2: %04X\n", msg.header.secsSys2)) if #msg > 0 then dumpData(msg[1]) end io.stderr:write("\n") end local function appendData(values,types,items) for i=1, #items do if items.list then appendData(values,types,items[i]) else if i == 1 then table.insert(types,items[i]) else table.insert(values,items[i]) end end end end local function msgData(msg) local values = {} local types = {} if #msg > 0 then appendData(values,types,msg[1]) end return values,types; end local function dataSignature(items) local sig = "" if items.list then sig = string.format("L%d",#items) end for i=1, #items do if items.list then sig = sig..dataSignature(items[i]) else if i == 1 then sig = sig..string.format(items[i]); end end end return sig end local function msgSignature(msg) local sig = "" if #msg > 0 then sig = dataSignature(msg[1]) end return sig end --[[ local function parseData(items,buf,idx,cnt) local len ; local code; -- io.stderr:write(string.format("IN: %d\n",idx)) while (idx < #buf - 2) and (cnt>0) do len = bit32.band(buf:byte(idx),0x03); code = bit32.band(buf:byte(idx),0xFC); -- io.stderr:write(string.format("CODE: %02X LEN: %02X\n",code,len)) len = buf:byte(idx+1); -- io.stderr:write(string.format("DATA LEN: %02X\n",len)) cnt = cnt - 1; if code == SF_LIST then local list = {} list.list = true idx = parseData(list,buf,idx+2,len) table.insert(items,list) elseif code == SF_ASCII then table.insert(items,{"A",buf:sub(idx+2,idx+1+len)}) idx = idx + len + 2; elseif code == SF_INT1 then table.insert(items,{"I1",struct.unpack(">b",buf:sub(idx+2))}) idx = idx + len + 1; elseif code == SF_INT2 then table.insert(items,{"I2",struct.unpack(">h",buf:sub(idx+2))}) idx = idx + len + 2; elseif code == SF_INT4 then table.insert(items,{"I4",struct.unpack(">i",buf:sub(idx+2))}) idx = idx + len + 4; elseif code == SF_INT8 then table.insert(items,{"I8",struct.unpack(">l",buf:sub(idx+2))}) idx = idx + len + 8; elseif code == SF_UINT1 then table.insert(items,{"U1",struct.unpack(">B",buf:sub(idx+2))}) idx = idx + len + 1; elseif code == SF_UINT2 then table.insert(items,{"U2",struct.unpack(">H",buf:sub(idx+2))}) idx = idx + len + 2; elseif code == SF_INT4 then table.insert(items,{"U4",struct.unpack(">I",buf:sub(idx+2))}) idx = idx + len + 4; elseif code == SF_UINT8 then table.insert(items,{"U8",struct.unpack(">L",buf:sub(idx+2))}) idx = idx + len + 8; elseif code == SF_BOOLEAN then table.insert(items,{"BOOL",struct.unpack(">B",buf:sub(idx+2))}) idx = idx + len + 1; elseif code == SF_BINARY then table.insert(items,{"B",struct.unpack(">B",buf:sub(idx+2))}) idx = idx + len + 1; -- elseif TODO more formats end end -- io.stderr:write(string.format("OUT: %d\n",idx)) return idx; end --]] local function parseData(items,buf,idx,cnt) local len ; local code; io.stderr:write(string.format("IN: %d\n",idx)) while (idx < #buf - 2) and (cnt>0) do io.stderr:write(string.format("IDX: %d\n",idx)) num = bit32.band(buf:byte(idx),0x03); code = bit32.band(buf:byte(idx),0xFC); io.stderr:write(string.format("CODE: %02X LEN: %02X\n",code,num)) len = buf:byte(idx+1); io.stderr:write(string.format("DATA LEN: %02X %03d\n",len,len)) cnt = cnt - 1; if code == SF_LIST then local list = {} list.list = true idx = parseData(list,buf,idx+2,len) table.insert(items,list) elseif code == SF_ASCII then table.insert(items,{"A",buf:sub(idx+2,idx+1+len)}) idx = idx + len + num + 1; elseif code == SF_INT1 then table.insert(items,{"I1",struct.unpack(">b",buf:sub(idx+2))}) idx = idx + len + num + 1; elseif code == SF_INT2 then table.insert(items,{"I2",struct.unpack(">h",buf:sub(idx+2))}) idx = idx + len + num + 1; elseif code == SF_INT4 then table.insert(items,{"I4",struct.unpack(">i",buf:sub(idx+2))}) idx = idx + len + num + 1; elseif code == SF_INT8 then table.insert(items,{"I8",struct.unpack(">l",buf:sub(idx+2))}) idx = idx + len + num + 1; elseif code == SF_UINT1 then table.insert(items,{"U1",struct.unpack(">B",buf:sub(idx+2))}) idx = idx + len + num + 1; elseif code == SF_UINT2 then table.insert(items,{"U2",struct.unpack(">H",buf:sub(idx+2))}) idx = idx + len + num + 1; elseif code == SF_INT4 then table.insert(items,{"U4",struct.unpack(">I",buf:sub(idx+2))}) idx = idx + len + num + 1; elseif code == SF_UINT8 then table.insert(items,{"U8",struct.unpack(">L",buf:sub(idx+2))}) idx = idx + len + num + 1; elseif code == SF_BOOLEAN then table.insert(items,{"BOOL",struct.unpack(">B",buf:sub(idx+2))}) idx = idx + len + num + 1; elseif code == SF_BINARY then table.insert(items,{"B",struct.unpack(">B",buf:sub(idx+2))}) idx = idx + len + num + 1; -- elseif TODO more formats end end io.stderr:write(string.format("OUT: %d\n",idx)) return idx; end local function unpackHeader(b) local h = {} h.secsId, h.secsStream, h.secsFunction, h.secsBlock, h.secsSys1, h.secsSys2 = struct.unpack('>HBBHHH',b) h.secsReverse = h.secsId > 0x8000; h.secsId = bit32.band(h.secsId,0x7FFF); h.secsWait = h.secsStream > 0x80; h.secsStream = bit32.band(h.secsStream,0x7F); h.secsEnd = h.secsBlock > 0x8000; h.secsBlock = bit32.band(h.secsBlock,0x7FFF); return h; end local function parseMsg(buf) local msg = {}; local len = 0; local code = 0; msg.header = unpackHeader(buf); msg.list = false; parseData(msg,buf,11,#buf); return msg; end local function packHeader(h) return struct.pack('>HBBHHH', ( h.secsReverse and bit32.bor(h.secsId, 0x8000) or h.secsId ), ( h.secsWait and bit32.bor(h.secsStream, 0x80) or h.secsStream ), h.secsFunction, ( h.secsEnd and bit32.bor(h.secsBlock, 0x8000) or h.secsBlock), h.secsSys1, h.secsSys2 ) end local function packString(s) return struct.pack('BB',SF_ASCII+1,#s)..s end local function packBinary(b) return struct.pack('BBB',SF_BINARY+1,1,b) end local function packList(l) return struct.pack('BB',SF_LIST+1,#l)..table.concat(l) end local function secondaryHeader(h,s,f) h.secsId = secsId; -- h.secsReverse = not host -- false: host --> equipment h.secsStream = s; h.secsFunction = f; -- secondary Message SsFf h.secsWait = false; -- no reply h.secsBlock = 1; h.secsEnd = true; -- last block return packHeader(h); end local function primaryHeader(s,f) -- SECS_IO.startTransaction() local h = {} h.secsId = secsId; -- h.secsReverse = not host -- false: host --> equipment h.secsStream = s; h.secsFunction = f; -- primary Message SsFf h.secsWait = true; -- reply h.secsBlock = 1; h.secsEnd = true; -- last block h.secsSys1 = 0 h.secsSys2 = transaction_id; transaction_id = transaction_id + 1 return packHeader(h); end function string.pop(s) return string.sub(s,1,1),string.sub(s,2) end function table.pop(t) local i = t[1] table.remove(t,1) return i,t end local function packData(sig,items) local buf = "" -- print("packData sig: ",sig) while #sig > 0 do -- print("packData len1: ",#sig) typ, sig = string.pop(sig) -- print("packData len2: ",#sig,typ,sig) if typ == "L" then len , sig = string.pop(sig) -- print("packData len3: ",#sig,len,sig) buf = buf..struct.pack('BB',SF_LIST+1,len)..packData(sig,items) -- hexDumpString(buf) return buf elseif typ == "A" then item, items = table.pop(items) buf = buf..packString(item) elseif typ == "B" then item, items = table.pop(items) buf = buf..packBinary(item) end end -- hexDumpString(buf) return buf end local function primaryMsg(s,f,sig,items) return primaryHeader(s,f)..packData(sig,items) end local function secondaryMsg(h,s,f,sig,items) return secondaryHeader(h,s,f)..packData(sig,items) end ------------------------------------------------------- local function SxF0(h) io.stderr:write("\nSECS II: SxF0\n----\n") return secondaryHeader(h,h.secsStream,0) end local function S1F1() io.stderr:write("\nSECS II: S1F1\n----\n") return primaryHeader(1,1) end local function S1F2(h) io.stderr:write("\nSECS II: S1F2\n----\n") if host then return secondaryMsg(h,1,2,"L0",{}) else return secondaryMsg(h,1,2,"L2AA",{MDLN,SOFTREV}) end end local function S1F13() io.stderr:write("\nSECS II: S1F13\n----\n") if host then return primaryMsg(1,13,"L2BL0",{0}) else return primaryMsg(1,13,"L2BL2AA",{0,MDLN,SOFTREV}) end end local function S1F14(h) io.stderr:write("\nSECS II: S1F14\n----\n") if host then return secondaryMsg(h,1,14,"L2BL0",{0}) else return secondaryMsg(h,1,14,"L2BL2AA",{0,MDLN,SOFTREV}) end end local function S2F41(c) io.stderr:write("\nSECS II: S2F41("..c..")\n----\n") if host then return onCreateMsg(2,41,c) else return "" -- host only command end end local function S2F42(h) io.stderr:write("\nSECS II: S2F42\n----\n") return secondaryMsg(h,2,42,"L2BL0",{4}) end local function S5F2(h) io.stderr:write("\nSECS II: S5F2\n----\n") if host then return secondaryMsg(h,5,2,"B",{0}) end end local function S6F12(h) io.stderr:write("\nSECS II: S6F12\n----\n") if host then return secondaryMsg(h,6,12,"B",{0}) else return secondaryHeader(h,h.secsStream,0) end end local function S6F11(e) io.stderr:write("\nSECS II: S6F11("..e..")\n----\n") if not host then return onCreateMsg(6,11,e) else return "" -- equipment only command end end ------------------------------------------------------- local function isSF(msg,s,f) return msg.header.secsStream == s and msg.header.secsFunction == f end local function isSxF0(msg) return msg.header.secsFunction == 0 end local function isS5Fx(msg) dumpMsg(msg) return msg.header.secsStream == 5 end local function isS9Fx(msg) dumpMsg(msg) return msg.header.secsStream == 9 end SECS_IO.onProcessRequest ( function(buf) local request = parseMsg(buf) io.stderr:write("SECS II: ID: ",request.header.secsId,"\n") local s = request.header.secsStream local f = request.header.secsFunction io.stderr:write("SECS II: onProcessMsg ".."S"..s.."F"..f.."\n"); -------------------------------------------------------------------- if not request.header.wait then SECS_IO.stopTransaction() end local sig = msgSignature(request) if isSF(request,1,1) then onPrimaryMsg(1,1,"are you there received") SECS_IO.sendMsg(S1F2(request.header)) elseif isSF(request,1,2) then onSecondaryMsg(1,2,"are you there received akn") elseif isSF(request,1,13) then connected = true; onPrimaryMsg(1,13,"establish communication request received") --io.stderr:write(string.format("CONNECTED %d\n",request[1][1][2])); SECS_IO.sendMsg(S1F14(request.header)) elseif isSF(request,1,14) then connected = true; onSecondaryMsg(1,14,"establish communication request received akn") --io.stderr:write(string.format("CONNECTED %d\n",request[1][1][2])); elseif isSF(request,2,41) then --print("SECS II: Message ",#request) onProcessMsg(request) onPrimaryMsg(2,41,"host command received") SECS_IO.sendMsg(S2F42(request.header)) elseif isSF(request,2,42) then onProcessMsg(request) onSecondaryMsg(2,42,"host command received akn") elseif isSF(request,6,11) then onProcessMsg(request) onPrimaryMsg(6,11,"event report received") SECS_IO.sendMsg(S6F12(request.header)) elseif isSF(request,6,12) then onSecondaryMsg(6,12,"event report received akn") elseif isS5Fx(request) then onProcessMsg(request) --hexDumpString(buf) --io.stderr:write("SIG: "..sig.."\n") onPrimaryMsg(5,request.header.secsFunction,"alarm received") SECS_IO.sendMsg(S5F2(request.header)) elseif isS9Fx(request) then -- no secondary message onProcessMsg(request) onPrimaryMsg(9,request.header.secsFunction,"error received") else if not isSxF0(request) then onPrimaryMsg(0,0,"abort transaction send") SECS_IO.sendMsg(SxF0(request.header)) end end end ) local function dequeMsg() local m = msgQueue[1] table.remove(msgQueue,1) return m end local function queueMsg(msg) io.stderr:write("\n====\nSECS II: queueMsg\n====\n"); table.insert(msgQueue,msg) end local function poll() if not SECS_IO.isPending() and #msgQueue > 0 then -- if not pending and #msgQueue > 0 then io.stderr:write("\n====\nSECS II: dequeueMsg\n====\n"); SECS_IO.startTransaction() SECS_IO.sendMsg(dequeMsg()) end SECS_IO.poll() end; local function setHost(mode) host = mode end local function setId(id) secsId = id end local function begin(device, baud) SECS_IO.begin(device,baud) io.stderr:write("begin\n") SECS_IO.stopTransaction() end return { begin = begin; sendMsg = sendMsg; dumpMsg = dumpMsg; msgSignature = msgSignature; msgData = msgData; --------- DEBUG only ---------------- -- dataSignature = dataSignature; -- parseMsg = parseMsg; -- dumpData = dumpData; -- parseData = parseData; -- packString = packString; -- packBinary = packBinary; -- packList = packList; -- packData = packData; -------------------------------------- primaryMsg = primaryMsg; secondaryMsg = secondaryMsg; setId = setId; setHost = setHost; isHost = function() return host end; isConnected = function() return connected end; isReading = function() return SECS_IO.isReading() end; isWriting = function() return SECS_IO.isWriting() end; isPending = function() return SECS_IO.isPending() end; poll = poll; sendS1F13 = function() queueMsg(S1F13()) end; sendS1F1 = function() queueMsg(S1F1()) end; sendS2F41 = function(c) queueMsg(S2F41(c)) end; sendS6F11 = function(e) queueMsg(S6F11(e)) end; onCreateMsg = function(cb) onCreateMsg = cb end; onPrimaryMsg = function(cb) onPrimaryMsg = cb end; onSecondaryMsg = function(cb) onSecondaryMsg = cb end; onProcessMsg = function(cb) onProcessMsg = cb end; }