8
votes

I'm new to lua and I'm trying to receive data from the port, ttyACM0, I can write to the port by:

wserial = io.open("/dev/ttyACM0","w")
wserial:write("hellloooo")
wserial:flush()

I thought since I can write to it in the same way as I would write to a file that I could read it in the same way as I would read a file. But when I try to read it (using the code below) I just end up in an infinite loop.

rserial=io.open("/dev/ttyACM0","r")
while chaine==nil do
  chaine=rserial:read()
  rserial:flush()
end
print(chaine)

So my question is what am I doing wrong, how do I read from the port, ttyACM0?

2
Using io.read() will read until it receives a newline character. Maybe you're not sending any to it? Take a look at this lua.org/pil/21.1.html (about halfway down, there's stuff about io.read). I'd try :read("*all") or, if you know how long the message will be, :read(10) (for 10 characters). You can always do :read(1) to get one byte, then decide if you want more or not.Advert
Thank you for replying, I tried that it didn't work. do you have any other suggestions?lana
Hmm, how about checking that you're getting anything at all? cat /dev/ttyACM0Advert
Okay, so I tried everything I could think of but you're right when I do cat /dev/ttyACM0 I don't get anything but I tried to read and write to the file by python and I could successfully read the file. So I was wondering if I could integrate python with lua?lana

2 Answers

4
votes

There are two kinds of line buffering going on here: one in the C library, which you can avoid using :read(1) like @Advert mentioned in the comments, and another one in the terminal driver itself. You can disable input line buffering in the terminal driver using the stty command line utility (stty -F /dev/ttyACM0 -icanon) or e.g. using luaposix (untested code):

local p = require( "posix" )
local rserial = assert( io.open( "/dev/ttyACM0", "r" ) )
local fd = assert( p.fileno( rserial ) )

local function table_copy( t )
  local copy = {}
  for k,v in pairs( t ) do
    if type( v ) == "table" then
      copy[ k ] = table_copy( v )
    else
      copy[ k ] = v
    end
  end
  return copy
end

-- get current settings
local saved_tcattr = assert( p.tcgetattr( fd ) )
local raw_tcattr = table_copy( saved_tcattr )
-- clear ICANON bits from local flags using Lua 5.2 bit32 module
raw_tcattr.lflag = bit32.band( raw_tcattr.lflag, bit32.bnot( p.ICANON ) )

-- apply modified settings
assert( p.tcsetattr( fd, p.TCSANOW, raw_tcattr ) )
local c = rserial:read( 1 )
print( c )
-- restore default settings afterwards
p.tcsetattr( fd, p.TCSANOW, saved_tcattr )
rserial:close()

There is also a specialized C module for handling serial ports in Lua, and the latest unreleased version of LuaSocket has code for handling serial ports (but it's disabled in default builds).

-1
votes

I will not answer what you did wrong, but based one 1 answer here I did this for Windows environment:

-- You can generate PowerShell script at run-time
local script = [[
    $port= new-Object System.IO.Ports.SerialPort COM78,115200,None,8,one
    $port.open()
    $port.WriteLine('serialRequest')
    $port.ReadLine() > 'c:\\temp\\serialResponse.txt'
    $port.Close()
]]
-- Now create powershell process and feed your script to its stdin
local pipe = io.popen("powershell -command -", "w")
pipe:write(script)
pipe:close()

Not very nice as response must be taken from file, but it works.