UART

The thing I needed most for my project was UART support including setting operation mode (like 115200-8n1), which lua doesnt have out of box.

Here is a short script relying on a basic tool called stty to set serial port operation mode:

function sutil.set_line_params(dev, speed)
   speed = tostring(speed)
   os.execute("stty -F "..dev.." -echo cbreak ispeed "..speed.." ospeed "..speed.." min 0 time 3")
end

Example usage:

print("Setting ttyS0 params")
sutil.set_line_params("/dev/ttyS0", 115200)

local ttyout = io.open("/dev/ttyS0", "wb")
local ttyin = io.open("/dev/ttyS0", "rb")

ttyout:write("s")
ttyin:read(1)

Sometimes just a read function is not enough. Thats when you need readall. Timeout handling is a nice addition too.

function sutil.readall_timeout(ttyfile, n, time)
   local data = ""
   local ret = true
   local ctr = 0
   local start = os.time()
   local timeout = false
   while (ctr<n) do
      local current = os.time()
      if (current-start>time) then
         print("Timeout [current: "..tostring(current).." start: "..tostring(start).." diff: "..tostring(current-start).."]")
         timeout = true
         break
      end
      local char = ttyfile:read(n-ctr)
      if char ~= nil then
         ctr=ctr+char:len()
         data = data..char
      end
   end
   return data, timeout
end

Int32 / int64 operations and byte reversal (htonl)

Lua has string.char and string.byte for number to character and character to number conversions, which can be used for 32 and 64 bit integers conversions too. These functions convert number to byte sequence of a known size, which can be written to file or transmitted over network or written to some register.

-- convert a 64-bit unsigned integer into a 8 bytes (network order)
function sutil.int64_to_bytes(n)
  -- adjust for 2's complement
   --n = (n < 0) and (4294967296 + n) or n
   return string.char((math.modf(n/0x100000000000000))%256)..string.char((math.modf(n/0x1000000000000))%256)..string.char((math.modf(n/0x10000000000))%256)..string.char((math.modf(n/4294967296))%256)..string.char((math.modf(n/16777216))%256)..string.char((math.modf(n/65536))%256)..string.char((math.modf(n/256))%256)..string.char(n%256)
end

-- convert bytes (network order) to a 64-bit unsigned integer
function sutil.bytes_to_int64(s)
   local n = string.byte(s, 1)*0x100000000000000 + string.byte(s, 2)*0x1000000000000 + string.byte(s, 3)*0x10000000000 + string.byte(s, 4)*0x100000000 + string.byte(s, 5)*0x1000000 + string.byte(s, 6)*0x10000 + string.byte(s, 7)*0x100 + string.byte(s, 8)
   return n
end

-- convert a 64-bit two's complement integer into a 8 bytes (network order)
function sutil.int32_to_bytes(n)
  -- adjust for 2's complement
   --n = (n < 0) and (4294967296 + n) or n
   return string.char((math.modf(n/16777216))%256)..string.char((math.modf(n/65536))%256)..string.char((math.modf(n/256))%256)..string.char(n%256)
end

-- convert bytes (network order) to a 64-bit two's complement integer
function sutil.bytes_to_int32(s)
   local n = string.byte(s, 1)*0x1000000 + string.byte(s, 2)*0x10000 + string.byte(s, 3)*0x100 + string.byte(s, 4)
   return n
end

function sutil.htonl(int_str)
   return string.sub(int_str, 4, 4)..string.sub(int_str, 3, 3)..string.sub(int_str, 2, 2)..string.sub(int_str, 1, 1)
end

Example usage:

sutil.set_line_params("/dev/ttyS0", 115200)
local ttyout = io.open("/dev/ttyS0", "wb")
time_pkt = sutil.htonl(sutil.int32_to_bytes(sleep_time))
ttyout:write("p"..time_pkt)
ttyout:close()

These functions are organized in serial util file: sutil.lua

I use it this way:

local sutil = require("sutil")

...

sutil.set_line_params("/dev/ttyS0", 115200)

...