Files
pitts-touchscreen/3B/archive/root_10.bak/secs.lua

600 lines
16 KiB
Lua

---------------------------- SECS I / SECS II ----------------------------------
periphery = require('periphery')
Serial = periphery.Serial
Scheduler = require('scheduler')
struct = require('struct')
local ASCII_EOT = "\x04" -- end of transmission
local ASCII_ENQ = "\x05" -- enquiary
local ASCII_ACK = "\x06" -- acknowledge
local ASCII_NAK = "\x15" -- negative acknowledge
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 T1 = 300
local T2 = 1000
local T3 = 3000
local MDLN = "DS-80B"
local SOFTREV = "MI370E"
local serial
local host = false
local connected = false
local pending = false
local transaction_id = 1
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 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,100);
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)
-- io.stderr:write("packList type("..type(l)..")\n")
return struct.pack('BB',SF_LIST+1,#l)..table.concat(l)
end
local function secondaryHeader(h,s,f)
h.secaId = 0; --
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)
pending = true
transactionTimer.restart()
local h = {}
h.secsId = 0; --
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
local function SxF0(h)
io.stderr:write("SxF0\n----\n")
return {
secondaryHeader(h,h.s_stream,0)
}
end
local function S1F1()
io.stderr:write("S1F1\n----\n")
return {
primaryHeader(1,1)
}
end
local function S1F2(h)
io.stderr:write("S1F2\n----\n")
if host then
return {
secondaryHeader(h,1,2),
packList( {} )
}
else
return {
secondaryHeader(h,1,2),
packList( {
packString(MDLN),
packString(SOFTREV)
} )
}
end
end
local function S1F13()
io.stderr:write("S1F13\n----\n")
if host then
return {
primaryHeader(1,13),
packList( {
packBinary(0),
packList( {} )
} )
}
else
return {
primaryHeader(1,13),
packList( {
packBinary(0),
packList( {
packString(MDLN),
packString(SOFTREV)
} )
} )
}
end
end
local function S1F14(h)
io.stderr:write("S1F14\n----\n")
if host then
return {
secondaryHeader(h,1,14),
packList( {
packBinary(0),
packList( {} )
} )
}
else
return {
secondaryHeader(h,1,14),
packList( {
packBinary(0),
packList( {
packString(MDLN),
packString(SOFTREV)
} )
} )
}
end
end
local function S2F41(ppid,mid1,mid2,mid3)
io.stderr:write("S2F41("..ppid..","..mid1..","..mid2..","..mid3..")\n----\n")
if host then
return {
primaryHeader(2,41),
packList( {
packString("START"),
packList( {
packList( {
packString("PPID"),
packString(ppid)
} ),
packList( {
packString("MID1"),
packString(mid1)
} ),
packList( {
packString("MID2"),
packString(mid2)
} ),
packList( {
packString("MID3"),
packString(mid3)
} )
} )
} )
}
else
return {}
end
end
local function S2F42(h)
io.stderr:write("S2F42\n----\n")
return {
secondaryHeader(h,2,42),
packList( {
packBinary(4),
packList({}) -- empty list
} )
}
end
local function S6F12(h)
io.stderr:write("S6F12\n----\n")
if host then
return {
secondaryHeader(h,6,12),
packBinary(0)
}
else
secondaryHeader(h,h.secsStream,0)
end
end
local function isSF(msg,s,f)
return msg.header.secsStream == s and msg.header.secsFunction == f
end
function isSxF0(msg)
return msg.header.secsFunction == 0
end
local function sendMsg(msg)
local buf = table.concat(msg);
-- hexDumpString(buf)
serial:write(ASCII_ENQ)
if serial:poll(T1) then
c = serial:read(1)
if c == ASCII_EOT then
serial:write(string.char(#buf))
local chksum = 0
for i=1, #buf do
serial:write(string.char(buf:byte(i)))
chksum = chksum + buf:byte(i);
-- io.stderr:write(string.format('%02X ',buf:byte(i)));
end
serial:write(string.char(chksum / 256))
serial:write(string.char(chksum % 256))
if serial:poll(T1) then
c = serial:read(1)
if not (c == ASCII_ACK) then
io.stderr:write("SECS I: NAK Received\n")
end
else
io.stderr:write("SECS I: AKN Timeout\n")
end
end
else
io.stderr:write("SECS I: EOT Timeout\n")
end
end
local function receiveMsg()
serial:write(ASCII_EOT)
if serial:poll(T1) then
local cnt = string.byte(serial:read(1))
io.stderr:write("receiveMsg\n----------\ncount: "..cnt.."\n")
local buf = serial:read(cnt+2,10*T1)
-- TODO checksum error handling
-- hexDumpString(buf);
serial:write(ASCII_ACK)
msg = parseMsg(buf)
-- dumpMsg(msg)
return msg
else
io.stderr:write("SECS I: Countbyte Timeout\n")
return {}
end
end
local function poll()
local request = {}
if ( serial:poll(T1) ) then
c = serial:read(1)
-- io.stderr:write(string.format("C: %02X\n",c:byte()));
if c == ASCII_ENQ then
request = receiveMsg()
--------------------------------------------------------------------
if not request.header.wait then
pending = false;
end
msgSignature(request)
if isSF(request,1,1) then
sendMsg(S1F2(request.header))
SECS.onPrimary(1,1,"are you there")
elseif isSF(request,1,2) then
SECS.onSecondary(1,2,"are you there akn")
elseif isSF(request,1,13) then
sendMsg(S1F14(request.header))
connected = true;
SECS.onPrimary(1,13,"establish communication request")
--io.stderr:write(string.format("CONNECTED %d\n",request[1][1][2]));
elseif isSF(request,1,14) then
connected = true;
SECS.onSecondary(1,14,"establish communication request akn")
--io.stderr:write(string.format("CONNECTED %d\n",request[1][1][2]));
elseif isSF(request,2,41) then
SECS.onProcessMsg(msg)
sendMsg(S2F42(request.header))
SECS.onPrimary(2,41,"host command send")
elseif isSF(request,2,42) then
SECS.onSecondary(2,42,"host command send akn")
elseif isSF(request,6,11) then
SECS.onProcessMsg(msg)
sendMsg(S6F12(request.header))
SECS.onPrimary(6,11,"event report send")
elseif isSF(request,6,12) then
--
SECS.onSecondary(6,12,"event report send akn")
else
if not isSxF0(request) then
sendMsg(SxF0(request.header))
SECS.onPrimary(0,0,"abort transaction akn")
end
end
else
---- TODO: Illegal byte, skip input send NAK ----
io.stderr:write("loop poll:"..string.byte(c).."\n")
end
else
if pending and transactionTimer.elapsed() then
---- TODO: Timeout, skip input send NAK ----
io.stderr:write("loop poll: Transaction timeout\n")
pending = false;
end
end
io.stderr:flush();
end
local function setHost(mode)
host = mode
end
local function begin(device, baud)
serial = Serial(device,baud)
transactionTimer = Scheduler.Timer(T3)
end
return {
begin = begin;
sendMsg = sendMsg;
dumpMsg = dumpMsg;
msgSignature= msgSignature;
msgData = msgData;
setHost = setHost;
isHost = function() return host end;
isConnected = function() return connected end;
isPending = function() return pending end;
poll = poll;
sendS1F13 = function() sendMsg(S1F13()) end;
sendS1F1 = function() sendMsg(S1F1()) end;
sendS2F41 = function(a1,a2,a3,a4) sendMsg(S2F41(a1,a2,a3,a4)) end;
}