184 lines
4.9 KiB
Lua
184 lines
4.9 KiB
Lua
periphery = require('periphery')
|
|
|
|
Serial = periphery.Serial
|
|
|
|
Scheduler = require('scheduler')
|
|
|
|
local T1 = 100 --300
|
|
local T2 = 2000 --1000
|
|
local T3 = 5000 --3000
|
|
|
|
local ASCII_EOT = "\x04" -- end of transmission
|
|
local ASCII_ENQ = "\x05" -- enquiary
|
|
local ASCII_ACK = "\x06" -- acknowledge
|
|
local ASCII_NAK = "\x15" -- negative acknowledge
|
|
|
|
local pending = false
|
|
local reading = false
|
|
local writing = false
|
|
|
|
local serial
|
|
|
|
local onProcessRequest;
|
|
|
|
-----------------------------------------------------------------------
|
|
local function hexDumpString(buf)
|
|
if buf then
|
|
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
|
|
end
|
|
-----------------------------------------------------------------------
|
|
|
|
function begin(device, baud)
|
|
serial = Serial(device,baud)
|
|
transactionTimer = Scheduler.Timer(T3)
|
|
end
|
|
|
|
local function discardInput()
|
|
hexDumpString(buf);
|
|
io.stderr:write("SECS I:\t Discard input: ")
|
|
while serial:poll(100) do
|
|
c = serial:read(1)
|
|
io.stderr:write(string.format('%02X ',c:byte(1)));
|
|
end
|
|
io.stderr:write("\n")
|
|
end
|
|
|
|
local function sendMsg(buf)
|
|
|
|
-- hexDumpString(buf)
|
|
|
|
writing = true
|
|
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 -- 0 normal, 1 force error
|
|
|
|
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(math.floor(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:\t NAK Received\n")
|
|
--discardInput()
|
|
end
|
|
else
|
|
io.stderr:write("SECS I:\t AKN Timeout\n")
|
|
discardInput()
|
|
end
|
|
writing = false
|
|
end
|
|
else
|
|
io.stderr:write("SECS I:\t EOT Timeout\n")
|
|
discardInput()
|
|
writing = false
|
|
end
|
|
|
|
end
|
|
|
|
local function receiveMsg()
|
|
serial:write(ASCII_EOT)
|
|
|
|
reading = true
|
|
if serial:poll(T1) then
|
|
local cnt = string.byte(serial:read(1))
|
|
io.stderr:write("SECS I:\t receiveMsg count: "..cnt.."\n")
|
|
|
|
local buf = serial:read(cnt+2,10*T1)
|
|
|
|
local chksum = 0 -- 0 normal, 1 force error
|
|
for i=1, #buf-2 do
|
|
chksum = chksum + buf:byte(i)
|
|
end
|
|
|
|
local msgChksum = buf:byte(#buf-1)*256 + buf:byte(#buf)
|
|
|
|
if msgChksum == chksum then
|
|
serial:write(ASCII_ACK)
|
|
return buf
|
|
else
|
|
io.stderr:write("SECS I:\t Checksum Error\n")
|
|
hexDumpString(buf)
|
|
serial:write(ASCII_NAK)
|
|
discardInput()
|
|
--io.stderr:write(string.format("SECS I:\t Checksum: %04X %04X\n",chksum,msgChksum))
|
|
io.stderr:write(string.format("SECS I:\t Bytes: %d Checksum: %04X %04X\n",#buf,chksum,msgChksum))
|
|
return ""
|
|
end
|
|
reading = false
|
|
else
|
|
io.stderr:write("SECS I:\t Countbyte Timeout\n")
|
|
discardInput()
|
|
reading = false
|
|
return ""
|
|
end
|
|
end
|
|
|
|
local function poll()
|
|
|
|
if ( serial:poll(T1) ) then
|
|
c = serial:read(1)
|
|
-- io.stderr:write(string.format("C: %02X\n",c:byte()));
|
|
if c == ASCII_ENQ then
|
|
local buf=receiveMsg()
|
|
if #buf >= 11 then
|
|
onProcessRequest(buf)
|
|
else
|
|
io.stderr:write("SECS I:\t Poll error bytes: "..#buf.."\n")
|
|
discardInput(buf)
|
|
serial:write(ASCII_NAK)
|
|
end
|
|
elseif c == ASCII_NAK then
|
|
io.stderr:write("SECS I:\t Poll NAK received\n")
|
|
--discardInput()
|
|
pending = false
|
|
else
|
|
---- TODO: Illegal byte, skip input send NAK ----
|
|
io.stderr:write(string.format("SECS I:\t Poll error byte = %02X\n",string.byte(c)))
|
|
discardInput()
|
|
serial:write(ASCII_NAK)
|
|
pending = false
|
|
end
|
|
else
|
|
if pending and transactionTimer.elapsed() then
|
|
---- TODO: Timeout, skip input send NAK ----
|
|
io.stderr:write("SECS I:\t Poll transaction timeout\n")
|
|
discardInput(buf)
|
|
serial:write(ASCII_NAK)
|
|
pending = false;
|
|
end
|
|
end
|
|
|
|
io.stderr:flush();
|
|
end
|
|
|
|
return {
|
|
begin = begin;
|
|
poll = poll;
|
|
sendMsg = sendMsg;
|
|
receiveMsg = receiveMsg;
|
|
isReading = function() return reading end;
|
|
isWriting = function() return writing end;
|
|
isPending = function() return pending end;
|
|
onProcessRequest = function(cb) onProcessRequest = cb end;
|
|
startTransaction = function() transactionTimer.restart(); pending = true end;
|
|
stopTransaction = function() pending = false end;
|
|
} |