read the latest line of a serial port - serial-port

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.

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.)

About
Whatever the string is delimited with " or ', inserting any ' or "
in it is done by doubling it.
So +"] '\n']" must be replaced with +"] ''\n'']", and +'] "\n"]' with +'] ""\n""]'

Related

How to print out a pointer using printf under xv6?

I am using xv6 and I want to print out the pointer's address returned from sbrk
I am trying to use:
printf(sbrk(0),"%p\n");
But when I tried to make, it complained:
error: passing argument 1 of ‘printf’ makes integer from pointer without a cast [-Werror=int-conversion]
printf(sbrk(0), "%p\n");
Is there a way to print out a pointer under xv6?
If you want I can share you with the make file - but I just cloned it from the xv6 repo
What about printf(1, "%p\n", sbrk(0));?
The xv6 printf function (from printf.c) need one extra parameter given first: the fd number in which you want to write.

Ada program to detect an end of line

I was assigned this task as my homework. I have a file which contains lines of text of varying lengths. The program is supposed to write the data onto the screen in precisely the same order in which it is written in the file, yet it fails to do so. To achieve the desired result I tried reading only one character per iteration so as to detect new line characters. What am I doing wrong?
WITH Ada.Text_IO;
WITH Ada.Characters.Latin_1;
USE Ada.Text_IO;
PROCEDURE ASCII_artwork IS
File : File_Type;
c : Character;
BEGIN
Open(File, In_File, "Winnie_The_Pooh.txt");
WHILE NOT End_Of_File(File) LOOP
Get(File, C);
IF (C = Ada.Characters.Latin_1.LF) THEN Put_Line(" "); ELSE
Put(C);
END IF;
END LOOP;
Close(File);
END ASCII_Artwork;
For each file, the Ada runtime maintains a fictitious "cursor". This is not the typical file position cursor (index), but one that indicates the position on a page, line, etc. (see also RM A.10 (7)). This is somewhat of an inheritance from the early versions of Ada.
Get stems from this same era and is expected to update the location of this cursor when some particular control characters are being read (e.g. an end-of-line mark). If Get reads such such a control character, it will only use it to update the cursor (internally) and then continue to read a next character (see also RM A.10.7 (3)). You'll therefore never detect an end-of-line mark when using Get.
This behavior, however, has some uncomfortable consequence: if a file ends with a sequence of control characters, then Get will keep reading those characters and hit the end of the file causing an End_Error exception.
You can, of course, catch this exception and handle it, but such a construct is dubious as having a sequence of control characters at the end of a file is actually not such an abnormal case (and hence dubious if worth an exception). As a programmer, however, you cannot change this behavior: it's defined by the language and the language will not be changed because it has been decided to keep Ada (highly) backwards compatible (which in itself is understandable given its field of application).
Hence, in your case, if you want stick to a character-by-character processing approach, I would suggest to move away from Get and instead use (for example) streams to perform I/O as in the example below.
main.adb
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Text_IO.Text_Streams; use Ada.Text_IO.Text_Streams;
procedure ASCII_artwork IS
File : File_Type;
Input : Stream_Access;
Output : Stream_Access;
C : Character;
begin
Open (File, In_File, "Winnie_The_Pooh.txt");
Input := Stream (File);
Output := Stream (Standard_Output);
while not End_Of_File (File) loop
Character'Read (Input, C);
Character'Write (Output, C);
end loop;
Close(File);
end ASCII_Artwork;
Output is as expected (i.e. the content of this the file at ascii-art.de).
NOTE: Check the source code of the GNAT runtime to actually see how Get works internally (focus on the loop at the end).
As explained by DeeDee, text inputs are buffered linewise in Ada. The idea is to be able to read two integers on the same line. For consistency sake (the designers of Ada are picky on that...), Get(File, C) does the same. It is not practical in your case. Fortunately, Ada 95 has introduced Get_Immediate, to solve precisely that issue.
Otherwise, as suggested by Frédéric, you could use the function Get_Line to absorb Winnie_The_Pooh.txt line by line seamlessly. By the way, the Get_Line method will convert the different end-of-line conventions automatically.
Line terminators in Ada.Text_IO are a concept, not a character or sequence of characters in the file. (Although most commonly used file systems implement them as characters or sequences of characters in the file, there exist file systems that do not.) Line terminators must therefore be manipulated using the operations in the package. For reading, End_Of_Line checks to see if the cursor is at a line terminator, Skip_Line skips the next line terminator, and Get_Line may skip a line terminator. For writing, New_Line and Put_Line write line terminators.
For your problem, the canonical solution is to use the Get_Line function to read lines, and Put_Line to output the lines read.

How to stop console window from closing immediately | GNAT - GPS

I have Ada program that runs and compile perfectly using GNAT - GPS. When I run its exe file and provide user input then instead of saying "Press any key to continue", the exe closes immediately.
I have searched for it online alot but i only found info related to c/c++/visual studio console window using system('pause'); OR Console.Readline().
Is there any way around for this in Ada lanaguage?
Apart from using Get_Line or Get, you can also use Get_Immediate from the Ada.Text_IO package. The difference is that Get_Line and Get will continue to read user input until <Enter> has been hit, while Get_Immediate will block only until a single key has been pressed when standard input is connected to an interactive device (e.g. a keyboard).
Here's an example:
with Ada.Text_IO; use Ada.Text_IO;
procedure Main is
begin
-- Do some interesting stuff here...
declare
User_Response : Character;
begin
Put_Line ("Press any key to continue...");
Get_Immediate (User_Response);
end;
end Main;
NOTES
You should run the program in an interactive terminal (Bash, PowerShell, etc.) to actually see the effect of Get_Immediate. When you run the program from within GPS, then you still have to press enter to actually exit the program.
This might be too much detail, but I think that Get still waits for <Enter> to be pressed because it uses fgetc from the C standard library (libc) under the hood (see here and here). The function fgetc reads from a C stream. C streams are initially line-buffered for interactive devices (source).
The answer from #DeeDee is more portable and only Ada and the preferable way to go, so my answer is just if you are looking for a "windows" way to do it.
I think there is a linker option for it, but I couldn't find it. A more manual way is to bind the system() command from C and give it a "pause" command and place it at the end of your program:
with Ada.Text_IO; use Ada.Text_IO;
with Interfaces.C.Strings;
procedure Main is
function System(Str : Interfaces.c.strings.chars_ptr) return Interfaces.C.int
with Import,
Convention => C,
External_Name => "system";
procedure Pause is
Command : Interfaces.c.Strings.chars_ptr
:= Interfaces.C.Strings.New_String("pause");
Result : Interfaces.C.int
:= System(Command);
begin
Interfaces.C.Strings.Free(Command);
end Pause;
begin
Put_Line("Hello World");
Pause;
end Main;
I know you mentioned seeing about pause already, but just wanted to show an example.
The same way you could use Console.Readline(), you can use Get_Line from the package Ada.Text_IO.
In this case, you will have to put the result into a String that you won't use.

How can I make Modelsim warn me about 'X' signal?

I am working on large design using Modelsim.
I've read about the way modelsim simulation works. I am wondering, is there a way that when modelsim evaluates a signal in the simulation phase and it found it to be a red signal, i.e. 'X', to warn me about it?
Knowing that is impossible to list all the signals of the design and look at them one by one.
Also it's very hard to put assertion command for all signals.
You can use the when command to carry out a desired action when a condition is met. The find command can extract signals from the design hierarchy. Look at the Modelsim command reference documentation to see all of its options. The examine command is used to determine the length of arrays and scalar type signals. This example will not work on record types.
proc whenx {sig action} {
when -label $sig "$sig = [string repeat X [string length [examine $sig]]]" $action
}
foreach s [find signals -r /*] {whenx $s "echo \"$s is an X at \$now\""}
This example does not handle arrays which are only partially X's. While you can use array indices in the when expression to test individual bits, it isn't clear how to determine the bounds of an array programmatically in Modelsim tcl.
You can cancel all when conditions with nowhen *.

Error: "Keyword parameters not allowed in call."

I am very new to IDL so forgive me if this seems dumb. I am trying to simply read a .tif image and let IDL show the image. My commands were:
IDL> a=read_image('frame_1.tif')
IDL> help, a
then I receive
A BYTE = Array[3, 560, 420]
IDL> plotimage ,bytscl(a)
But after I execute the last command, I receive "Keyword parameters not allowed in call."I don't understand what I did wrong. Any ideas?
Thank you in advance.
I'm not sure what is going on, but one thing that seems to generate that error message is that IDL gets confused between arrays (which can use parens to index) and function calls. Try using strictarr before the call:
compile_opt strictarr
This will mean that you must use square brackets to index arrays and parens for function calls.
Note, that you have to put this into every routine (and at the command line) you are having trouble with.

Resources