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; }