Lua - io.read sends me an echo back when I read from serial port - why? - lua

I am writing a code in Lua to read from a serial port, but when I read I receive an echo back with the code :
print("Dragino Uart Test started\n")
while 1 do
serialin=io.open("/dev/ttyS0","r")
print(serialin:read()) --print the data
serialin:close()
end
When I open minicom to send him some data, I enable local echo than I type "text" and I see :
tteexxtt
Then I need to press enter to see my message in my lua script.
I am using a OpenWRT in a Dragino.
It seems that it is like a prompt command that you type every thing that you see and you need to press enter to send you command.
There is any other way to read and write to/from a serial port?
Can somebody help me please? Thank you so much!

The read method with no arguments reads a full line. That's why you need to press enter at the end of the text. Try reading one byte at a time with :read(1) or all of it with :read("*a").

I don know if this is still an issue to someone but maybe this helps a few people. Like lhf said :read(1) is a gread way of doing this. I had a few problems with :read("*a") though. In my opinion the easiest way of doing this is to append the answer piece by piece like:
rserial=io.open("/dev/ttyS0",'r')
lines = ""
repeat
local line=rserial:read(1)
if string.sub(line, 0, 3) == "OED" then --OED is here the stream ending. This can vary
EOD = true
rserial:close()
elseif line then
lines = lines .. line
end
until EOD == true
print (lines)

Related

Lua io.popen freezing after a while of reading a log file

I'm attempting to constantly read and parse a log file (Minecraft log file) by using io.popen in tandem with Ubuntu's tail command so that I can send some messages upon certain events.
Now, I have mostly everything working here, except one small issue. After a while of reading, the entire program just freezes.
Here is the relevant code:
-- Open the tail command, return a file handle for it.
local pop = io.popen(config.listen_command)
-- Simply read a single line, I've pulled this into its own
-- function so that if this ever needs changing I can do so
-- easily.
local function get_line()
logger:log(4, "READ LINE")
return pop:read("*l")
end
-- For each line in the log file, check if it matches any
-- of a list of patterns, return the matches and the
-- pattern information if so.
local function match_line()
local line = get_line()
logger:log(4, "Line: %s", line)
-- This all works, and I've tested that it's not freezing
-- here. I've just included it for completion of the call
-- -stack.
for event_type, data in pairs(config.message_patterns) do
for event_name, pattern in pairs(data) do
local matches = {line:match(pattern)}
if matches[1] then
return event_type, event_name, matches
end
end
end
end
-- The main loop, simply read a line and send a message
-- if there was a match.
logger:log(4, "Main loop begin.")
while true do
local event_type, event_name, matches = match_line()
-- ...
-- The rest of the code here is not relevant.
config.listen_command = "tail -F --lines=1 latest.log"
The issue is in the get_line function. After a while of reading the log file, it completely freezes on the pop:read("*l"). It prints the READ LINE message, but never prints the Line: <whatever data here> line.
This is a really strange issue that I've been getting really confused about. I've tried swapping to different distributions of Lua (Luvit, LuaJIT, Lua) and a very large amount of debugging, changing small things, rerunning, ... But I cannot think of anything that'd be causing this.
Perhaps there's something small I've missed.
So my question here is this: Why is pop:read("*l") freezing, even though more data is being outputted to the logfile? Is there a way to fix this? Perhaps to detect if the next read will freeze indefinitely, so I can try closing the popen'ed file and re-open it (or to preferably stop it happening altogether?)

Issue in pexpect when text wraps within session

I am working on a pexpect script that is running populating an output file name and then a prompt for the file's parameters.
The program that the script runs asks for Device: then Parameters: always on the same line.... so if the file path-name that is entered for Device is long, sometimes the Parameters prompt wraps to the next line.
My code looks like..
child.expect_exact('Device:')
child.sendline('/umcfiles/ftp_dir/ftp_peoplesoft/discount/AES_DISCOUNT_15010.TXT')
child.expect_exact('Parameters:')
This times out.. and here is what is in child.before
' /umcfiles/ftp_dir/ftp_peoplesoft/discount/AES_DISCOUNT_15010.TXT Param\r\neters: "RWSN" => '
so the expect fails... (a child.expect('Parameters:') also fails)
How can I ignore the \r\n if it is there, because depending on the length of the path/filename I am using it may not be there at all, or be in a different position.
Thanks!
Actually... I found a way to calculate how much is left on the given line, and dynamically set my expect to how much of the Parameter prompt should be visible... seems to be working
#look for end of line and fix how much of 'Parameters:' we look for in pexpect
dlen = 80-len('Device: /umcfiles/ftp_dir/ftp_peoplesoft/discount/AES_DISCOUNT_15010.TXT')
pstr='Parameters:'
if dlen > len(pstr):
dlen=len(pstr)
else:
dlen=dlen-3 #remove the /r/n
child.expect(pstr[0:dlen])

Lua script pc to sleep

So i got a new keyboard wit hG-keys. (hotkeys) And i'm not familiar with lua...
So could anybody give me a very simple command that sets my pc to sleep? please?
if gkey == 7 and mkey == 1 then
if event == "G_PRESSED" then
end
end
gkeys
so gkey is the key that is pressed, and mkey is the set it uses. i can have up to 54 differint scripts/macro's.
I want to know what i have to put after the last 'then' so my pc goes to sleep.
thx ahead
edit 1:
got this:
if gkey == 1 and mkey == 3 then
if event == "G_PRESSED" then
execute("rundll32.exe powrprof.dll,SetSuspendState 0,1,0");
end
end
error is: [string "LuaVM"]:40: attempt to call global 'execute'(a nil value)
and with os.execute i get this error:
[string "LuaVM"]:40: attempt to index global 'os'(a nil value)
final answer: not possible with gseries keyboard. use a shortcut
Given the reference to G-keys and the G_PRESSED in your code snippet, I am assuming you have one of the Logitech G-Series keyboards. These keyboards can be programmed so that certain keys run Lua scripts using a custom Lua 5.1 interpreter. The documentation is included with Logitech's Gaming Software program.
According to the documentation, only some of the standard library functions are supported: the string, math and table are available. However, the io, os and debug libraries are not available.
So I doubt you'll be able to make your PC go to sleep.
EDIT in response to OP edit: the Lua library you have access to has the os library removed, so you're probably not going to be able to make your computer sleep directly.
There might be an indirect way to do this by writing something that listens for debugging messages, which you can generate with OutputDebugMessage. There's a Team Speak plugin that does this. But it's probably beyond your programming ability right now and far beyond the scope of a Stackoverflow post to explain.
You can use os.execute to run an executable from Lua.
If you google "Windows sleep command line" you'll get another Stackoverflow post which shows two ways of doing it. One requires that you turn hibernation off, the other requires that you download an additional utility (PsShutdown).
Assuming you've downloaded PsShutdown and put it somewhere in your PATH, then you can use the following to sleep the computer:
os.execute('psshutdown -d -t 0')

Simple program that reads and writes to a pipe

Although I am quite familiar with Tcl this is a beginner question. I would like to read and write from a pipe. I would like a solution in pure Tcl and not use a library like Expect. I copied an example from the tcl wiki but could not get it running.
My code is:
cd /tmp
catch {
console show
update
}
proc go {} {
puts "executing go"
set pipe [open "|cat" RDWR]
fconfigure $pipe -buffering line -blocking 0
fileevent $pipe readable [list piperead $pipe]
if {![eof $pipe]} {
puts $pipe "hello cat program!"
flush $pipe
set got [gets $pipe]
puts "result: $got"
}
}
go
The output is executing go\n result:, however I would expect that reading a value from the pipe would return the line that I have sent to the cat program.
What is my error?
--
EDIT:
I followed potrzebie's answer and got a small example working. That's enough to get me going. A quick workaround to test my setup was the following code (not a real solution but a quick fix for the moment).
cd /home/stephan/tmp
catch {
console show
update
}
puts "starting pipe"
set pipe [open "|cat" RDWR]
fconfigure $pipe -buffering line -blocking 0
after 10
puts $pipe "hello cat!"
flush $pipe
set got [gets $pipe]
puts "got from pipe: $got"
Writing to the pipe and flushing won't make the OS multitasking immediately leave your program and switch to the cat program. Try putting after 1000 between the puts and the gets command, and you'll see that you'll probably get the string back. cat has then been given some time slices and has had the chance to read it's input and write it's output.
You can't control when cat reads your input and writes it back, so you'll have to either use fileevent and enter the event loop to wait (or periodically call update), or periodically try reading from the stream. Or you can keep it in blocking mode, in which case gets will do the waiting for you. It will block until there's a line to read, but meanwhile no other events will be responded to. A GUI for example, will stop responding.
The example seem to be for Tk and meant to be run by wish, which enters the event loop automatically at the end of the script. Add the piperead procedure and either run the script with wish or add a vwait command to the end of the script and run it with tclsh.
PS: For line-buffered I/O to work for a pipe, both programs involved have to use it (or no buffering). Many programs (grep, sed, etc) use full buffering when they're not connected to a terminal. One way to prevent them to, is with the unbuffer program, which is part of Expect (you don't have to write an Expect script, it's a stand-alone program that just happens to be included with the Expect package).
set pipe [open "|[list unbuffer grep .]" {RDWR}]
I guess you're executing the code from http://wiki.tcl.tk/3846, the page entitled "Pipe vs Expect". You seem to have omitted the definition of the piperead proc, indeed, when I copy-and-pasted the code from your question, I got an error invalid command name "piperead". If you copy-and-paste the definition from the wiki, you should find that the code works. It certainly did for me.

Getting return status AND program output

I need to use Lua to run a binary program that may write something in its stdout and also returns a status code (also known as "exit status").
I searched the web and couldn't find something that does what I need. However I found out that in Lua:
os.execute() returns the status code
io.popen() returns a file handler that can be used to read process output
However I need both. Writing a wrapper function that runs both functions behind the scene is not an option because of process overhead and possibly changes in result on consecutive runs. I need to write a function like this:
function run(binpath)
...
return output,exitcode
end
Does anyone has an idea how this problem can be solved?
PS. the target system rung Linux.
With Lua 5.2 I can do the following and it works
-- This will open the file
local file = io.popen('dmesg')
-- This will read all of the output, as always
local output = file:read('*all')
-- This will get a table with some return stuff
-- rc[1] will be true, false or nil
-- rc[3] will be the signal
local rc = {file:close()}
I hope this helps!
I can't use Lua 5.2, I use this helper function.
function execute_command(command)
local tmpfile = '/tmp/lua_execute_tmp_file'
local exit = os.execute(command .. ' > ' .. tmpfile .. ' 2> ' .. tmpfile .. '.err')
local stdout_file = io.open(tmpfile)
local stdout = stdout_file:read("*all")
local stderr_file = io.open(tmpfile .. '.err')
local stderr = stderr_file:read("*all")
stdout_file:close()
stderr_file:close()
return exit, stdout, stderr
end
This is how I do it.
local process = io.popen('command; echo $?') -- echo return code of last run command
local lastline
for line in process:lines() do
lastline = line
end
print(lastline) -- the return code is the last line of output
If the last line has fixed length you can read it directly using file:seek("end", -offset), offset should be the length of the last line in bytes.
This functionality is provided in C by pclose.
Upon successful return, pclose() shall return the termination status
of the command language interpreter.
The interpreter returns the termination status of its child.
But Lua doesn't do this right (io.close always returns true). I haven't dug into these threads but some people are complaining about this brain damage.
http://lua-users.org/lists/lua-l/2004-05/msg00005.html
http://lua-users.org/lists/lua-l/2011-02/msg00387.html
If you're running this code on Win32 or in a POSIX environment, you could try this Lua extension: http://code.google.com/p/lua-ex-api/
Alternatively, you could write a small shell script (assuming bash or similar is available) that:
executes the correct executable, capturing the exit code into a shell variable,
prints a newline and terminal character/string onto standard out
prints the shell variables value (the exit code) onto standard out
Then, capture all the output of io.popen and parse backward.
Full disclosure: I'm not a Lua developer.
yes , your are right that os.execute() has returns and it's very simple if you understand how to run your command with and with out lua
you also may want to know how many variables it returns , and it might take a while , but i think you can try
local a, b, c, d, e=os.execute(-what ever your command is-)
for my example a is an first returned argument , b is the second returned argument , and etc.. i think i answered your question right, based off of what you are asking.

Resources