1
votes

My overall program goal is to create a better 3D printer calibration GUI using Lua and I luckily have the GUI part already working. I am trying to read and write to a COM port on my Windows 10 computer to the printer's Arduino. However, I am stumped by the serial communication. Currently, I have two FTDI cables wired together and can communicate between them using RealTerm (a terminal program) for testing, so I do know the wiring is correct. I am using ZeroBrane Studio for development but am not yet comfortable installing libraries.

So far, I have tried the following solutions:

  1. Attempt: Embed a powershell script to open the serial port

Result: No data comes out the port, but no errors are generated

  1. Attempt: Use srdgame/librs232 library

Result: require "rs232" fails in the code as it can't find the file. I installed the contents of SRC into the same directory as my Lua code, however it is probable that is not the right way to do it.

  1. Attempt: Use native io function in Lua

Result: I was able to send data using this method which is great news. However, I do not see a way to adjust the baud rate of the port. Going into device manager and mucking with the settings had no effect. It defaults to 115200bps.

Code:

file = io.open("COM5","wb")
io.output(file)
io.write("Hello world!")

Other options: I have installed luarocks, but cannot get it to install any libraries in Command Prompt. "Error: Could not find expected file ffi.lib, or ffi.dll, or libffi.dll for FFI -- you may have to install FFI in your system and/or set the FFI_DIR variable"

If any solutions require libraries, I would love some guidance on what files go where.

Thank you in advance!

PS: Here are some further references I investigated.

  1. posix appears to only be for linux

  2. lua-user.org Serial Communication wiki. I did not understand the instructions and their recommended library is out of data..

1
io.open("COM5:","wb") would be more correct on WindowsEgor Skriptunoff
To set com port parameters: os.execute[[mode COM5: baud=9600 parity=N data=8 stop=1]]Egor Skriptunoff
Thanks for the recommendation! I have been going through Microsoft's documentation on System.IO.Ports and cannot yet find a way to read any of the values that powershell prints. If Lua calls a powershell script, and the powershell script does any printing, that show's up in Lua's console.Ryan Friedman
To read stdout of a program, use file=io.popen("program args", "rb"); s=file:read"*a"; file:close()Egor Skriptunoff
Great! Powershell has been working well so far. The only issue I have is that opening the port removes any data sent before it, and I can't open the port in one scrip (when the user starts the program) and then read in another (continuously). I have attached my powershell script as an answer. To avoid this, I tried using io.read, but it always reads the Lua console. fileIn = io.open("COM2:","rb"); io.input(fileIn); print(io.read("*line"));Ryan Friedman

1 Answers

0
votes

The first workable solution I have is to use a powershell script. It takes in parameters from Lua including the COM port, Baud Rate, and a string to write.

First off, here the the Lua Script.

writeThenReadCOMinLua.lua

local comPort = "COM2"
local baud = "9600"
local dataToWrite = "Hello. Is Anyone There?"
--run the powershell script with supplied params. Spaces are important.
local file = io.popen("powershell.exe -file ./liblocal/psLibs/writeAndReadCOM.ps1 
"..comPort.. " " .. baud .. " " .. dataToWrite)

--Wait for a reply (indefinitely)
local rslt = file:read("*a")
print("Response: " .. rslt)

And, the powershell script to write then wait for reply.

writeAndReadCOM.ps1

$nargs = $args.Count #args is the list of input arguments
$comPortName=$args[0] #This is the com port. It has zero spaces
$baud = $args[1] #this is the numberical baud rate
#the remainder of the arguments are processed below


#Combine argument 2,3,...,n with a space because of command prompt shortfalls to pass arguments with spaces
$dataToWrite = ""
For ($i=2; $i -le $nargs ; $i++) {
    $dataToWrite = "$($dataToWrite) $($args[$i])"
}

#$port= new-Object System.IO.Ports.SerialPort COM2,9600,None,8,one
$port= new-Object System.IO.Ports.SerialPort $comPortName,$baud,None,8,one

#open port if it's not yet open
IF ($port.IsOpen) {
    #already open
} ELSE {
    #open port
    $port.Open()
}

#write the data
$port.WriteLine($dataToWrite)

#wait for a response (must end in newline). This removes the need to have a hard coded delay
$line = $port.ReadLine()
Write-Host $line #send read data out

#if the response was multiple lines, then read the rest of the buffer. If the port was just opened.
while ($port.BytesToRead -ne 0) {
    $dataReturned = 1
    $line = $port.ReadLine()
    Write-Host $line #send read data out for the remainder of the buffer
}

$port.Close()

#IF ($dataReturned -eq 0) {'PS_NO_BYTES_TO_READ'}

There are a few things going on here. First, the serial data sent by lua may have spaces. Unfortunately, these all get separated into multiple args by the terminal, so powershell then goes and regroups them into a single string. Second, the port must be opened to read or write data. If any serial data is sent before it is opened, that data is lost.

Issue Remaining: I can't leave the port open then go do stuff in Lua and periodically check the port for new data. This is unfortunate because the hardware I am using sometimes sends data without a request, or takes a long time to reply with all the data (in the case of an iterative level calibration). Additionally, each time I open the port, the hardware restarts. At this point, I have no good solution.

Here was my attempt at a fix: Create three separate powershell scripts #1) open the port #2) read the port and return nil within 500mS if no data exists otherwise reply with all the data and #3)close it. Unfortunately, #2 throws an error about the port being closed even after #1 is run. I'd love to hear some thoughts, and will gladly update this answer with any solutions.

Many thanks to Egor for all the help so far.