问题
I haven't ever written any code in tcl and pretty novice on serial communication, so sorry in advance if my question doesn't make sense.
I'm trying to solve this problem where I want to listen to a serial port and print the updates line by line in SciLab like a normal serial terminal (e.g. Arduino's serial monitor). The Serial Communication Toolbox for Scilab has a readserial
macro (source on GitHub):
function buf=readserial(h,n)
if ~exists("n","local") then
N=serialstatus(h); n=N(1)
end
TCL_EvalStr("binary scan [read "+h+" "+string(n)+"] cu* ttybuf")
buf=ascii(evstr(TCL_GetVar("ttybuf")));
endfunction
where the TCL_EvalStr
interprets a string in tcl. So my questin is how I can change the line:
binary scan [read "+h+" "+string(n)+"] cu* ttybuf
so it only returns the latest non-empty line on the serial port? I would also appreciate if you could eli5 what this line does?
P.S.1. So far from here I tried:
TCL_EvalStr("binary scan [lindex [split [read -nonewline "+h+" "+string(n)+"] "\n"] end] cu* ttybuf")
but I get the error message:
Error: syntax error, unexpected string, expecting "," or )
In SciLab.
P.S.2. Defining a new function:
function buf=readlnserial(h)
TCL_EvalStr("binary scan [lindex [split [read -nonewline "+h+"] \"\n\"] end] cu* ttybuf")
buf=ascii(evstr(TCL_GetVar("ttybuf")));
endfunction
leads to error message:
Undefined operation for the given operands.
check or define function %c_l_s for overloading.
In SciLab terminal.
P.S.3. Commands:
TCL_EvalStr('[split [read -nonewline '+h+'] "\n"]')
or
TCL_EvalStr("[split [read -nonewline "+h+"] '\n']")
both lead to error:
Error: Heterogeneous string detected, starting with ' and ending with ".
In SciLab.
P.S.4. I think if I use the SciLab command TCL_EvalFile
instead of TCL_EvalStr
I can solve the issue above. I just need to figure out how to pass h
to the tcl script and read back ttybuf
.
P.S.5. I was able to solve the crazy conflict between SciLab string and "\n"
by using curly brackets instead of double quotation:
TCL_EvalStr("binary scan [lindex [split [read -nonewline "+h+"] {\n}] end] cu* ttybuf")
however it is still not giving what I'm lookking for.
P.S.6. For those who end up here due to the heterogeneous strings with quotation or double quotation, the correct syntax is 'this '"string'" is inside quotation'
. Basically single quotation before other single quotation or double quotations turn them into literal characters.
回答1:
First, let's finish taking apart the line:
binary scan [read "+h+" "+string(n)+"] cu* ttybuf
That's really this:
binary scan [read CHANNEL NUM_BYTES] cu* ttybuf
where CHANNEL
is really the name of the Tcl channel that you're reading from (which probably ought to be in binary mode but that's out of scope of the code you're showing), and NUM_BYTES
is the number of bytes to be read. This is then processed to a list of numbers (written to the Tcl variable ttybuf
) which are the unsigned bytes that were read.
Now, you're wanting to use line-oriented reading. Well, Tcl's read
command doesn't do that (that's either fixed-buffer or whole-file oriented); you need gets
for line-oriented reading. (You never want whole-file oriented processing when reading from a serial line; it never reaches EOF. You can do trickery with non-blocking reads… but that's quite complex.)
The gets
command will return the next line read from a channel, with end-of-line marker removed. We can still use it with binary channels (it's a little weird, but not impossible) so that means we can then do:
binary scan [gets CHANNEL] cu* ttybuf
Converting that back through all that wrapper you've got:
function buf=readserialline(h)
TCL_EvalStr("binary scan [gets "+h+"] cu* ttybuf")
buf=ascii(evstr(TCL_GetVar("ttybuf")));
endfunction
I renamed it, and I removed all the manipulation of n
; lines are lines, and are not of fixed length. (I wonder whether we can retrieve the string directly without converting through a list of bytes; that would be quite a bit more efficient. But that's secondary to getting this working at all.)
来源:https://stackoverflow.com/questions/54935990/read-the-latest-line-of-a-serial-port