Simple COMs Handler Linux

BlitzMax Forums/BlitzMax Programming/Simple COMs Handler Linux

Yeshu777(Posted 2010) [#1]
I'm attempting to create a simple comms handler using the following:


Global hComm:TStream
Global bytes_rcvd

Function InitSerialComms()

      hComm = OpenStream("/dev/ttyS0", True, True)

End Function

Function SendCommand( buf$ )

      WriteString(hComm, buf$)
      FlushStream(hComm)

End Function

Function RxCommand( )

      Local buf$;

      bytes_rcvd = StreamSize(hComm)

      If(bytes_rcvd > 3) Then

         buf$ = ReadString(hComm);

         LogCmd(buf$) ' Print buf$ in main loop

      End If

End Function


Setup

PC 1 - XP running Docklight (simple terminal program )

PC 2 - Ubuntu running BlitzMax with the above code.


Ok, the SendCommand works fine - the string appears correctly on PC 1 terminal program as expected.

Nothing appears to be being recieved when I send a command from PC 1 - PC 2.

For Debug, I've ran 'cutecom' on PC 2 and it recieves everything PC 1 sends, so hardware wise it appears to be working.

I'm displaying bytes_rcvd, in mainline, and StreamSize(hComm) increments when I write to the stream (SendCommand), but there's no increment when I send a simple "test" string from PC 1 using the terminal program.

The /dev/ttyS0 appears to be configured correctly (9600,8,N,1) for a simple 3 wire cable

Following dump from stty on /dev/ttyS0

speed 9600 baud; rows 0; columns 0; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>;
eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V; flush = ^O; min = 1; time = 0;
-parenb -parodd cs8 hupcl -cstopb cread clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr -icrnl -ixon 
-ixoff -iuclc -ixany -imaxbel -iutf8
-opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
-isig -icanon iexten -echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke


Am I missing something simple with regards to how the TStream system works?

Regards.


Yeshu777(Posted 2010) [#2]
Ok, progress.

Created a seperate Stream for RX and TX (mainly for debug so I could see what each one was doing).

I can now read the bytes recieved on the RX Stream.


Function RxCommand()

     If(RXCom) Then
         
          byte_rcvd = ReadByte(RXCom)
          WriteByte(TXCom, byte_rcvd);
          FlushStream(TXCom);

     End If

End Function



I'm now writing the RX byte to the TX Stream (eg. echo) and it's working spot on.

However the program seems to hang unless a byte is recieved - but can't be far off.

Anyone know why ReadByte would hang until it recieved one?


markcw(Posted 2010) [#3]
The Read and Write methods will 'block' if it can't read "at least one byte due to IO buffering."

The 'block' is due to TStreamReadException or TStreamWriteException which are "thrown when a stream operation failed" to read or write the specified number of bytes.

So maybe to avoid this you need to wait or 'listen' for the port to open before reading/writing.


Yeshu777(Posted 2010) [#4]
Cheers, thought it might be due to this.

Any idea how to do this?

PeekByte?


markcw(Posted 2010) [#5]
No I don't know, maybe timeouts? I can't really help as I've never worked with com ports but after a search around I found these.

This is by Nigel Brown, brown.comm
serial port

And this is by Brucey
wxCTB : cross-platform serial (OSX project)

Also some older stuff which might be useful.
Code archives/User Input/COM-Port II
Device/Port already open?
rs232


Yeshu777(Posted 2010) [#6]
Thanks for the advice.

Doesn't seem to throw an exception, just seems to hang until a byte is recieved via the comm port.

As I'm continuosly checking the comm port in main loop, everything hangs..

Send a string of say 4 chars and it'll run around the loop 4 times, print out what it's recieved.

Now I just need to figure out how to make sure there's something to be read before calling read byte.

Or rewrite the the module as it uses a while loop, which I'm guessing is where it's hanging.


Kurator(Posted 2010) [#7]
..or using threads to implement async behaviour :)


Brucey(Posted 2010) [#8]
isn't there some method which calls select() under-the-hood? Like an Avail() or Available() call?
i.e. a non-blocking check for data on the file handle.


Perhaps... :-p


Yeshu777(Posted 2010) [#9]
Hmmm. that would be damn useful if so.

Stupid question No.1

Can socket streams be directed to /dev/ttyS0?


markcw(Posted 2010) [#10]
ReadAvail? There's one in TSocket and another in TPipeStream (FreeProcess).

Can socket streams be directed to /dev/ttyS0?

Not sure but it doesn't look like it.


Yeshu777(Posted 2010) [#11]
Looking at the forums ReadAvail() has been asked for many times before.

Looking through the bmk stream module I think the problem lies with the use of 'fread' from the C stdio.

Which IIRC is itself blocking function, and probably not best used in this context/instance.

Oddly, my original project was in Blitz+ and ran perfectly under XP Embedded, converted it to Bmax Linux, every other aspect works fine but came to a grinding halt on this issue.

Probably more due to my inexperience with Linux than anything else.

However, thanks for everyone's input on the subject.


Yeshu777(Posted 2010) [#12]
Sigh.


markcw(Posted 2010) [#13]
Not able to get socket streams working?

Maybe you could just use Eof() or Size() to tell if you can read/write the byte?


Brucey(Posted 2010) [#14]
http://linux.die.net/man/2/select

This is (more or less) typical what you would use to do a ReadAvail(). I'm pretty sure that's what FreeProcess uses.

The thing is, it's all quite low-level stuff... but very do-able.


Yeshu777(Posted 2010) [#15]
Eof and Size just return -1 as the stream is not seekable, apparently.

In the end I used the following 'hack' method under Ubuntu:

Add:

cat /dev/ttyS0 > /var/tmp/ttyS0.log &

to rc.local

Which creates a text log file of everything recieved from COM 0.


Then simply parse the log file with BMax to see whats been recieved.

Not perfect, but a work around.

Thankfully the commands from the host are only sent every 5 seconds or so.

PS. Have also setup /var/tmp as a RAM disk to aviod to many writes to the USB stick. (this OS is running from USB)

Best Regards,


markcw(Posted 2010) [#16]
Aha! Here's a proper explanation for your previous question:

Anyone know why ReadByte would hang until it recieved one?

http://www.ibiblio.org/pub/Linux/docs/HOWTO/other-formats/html_single/Serial-HOWTO.html#ss3.1

So if I understand this correctly, all you need to do is writebyte first, then readbyte and store that for the next writebyte.


Yeshu777(Posted 2010) [#17]
Most appreciated, interesting reading..


Yeshu777(Posted 2010) [#18]
@markcw.. no joy.

However, my "cat /dev/ttyS0" to RAM disk does work.

I had to add the following line to rc.local after the log file is initiated in order for BMax to be able to access it.

chmod a+rw /var/tmp/ttyS0.log

You can then simply parse the file for the last string recieved.

Obviously requires more testing, but it's a temporary working solution.

If anyone is interested I'll post the serial port code, including setup instructions.

It's simple and requires no additional modules.