Simple COMs Handler Linux
BlitzMax Forums/BlitzMax Programming/Simple COMs Handler Linux
| ||
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. |
| ||
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? |
| ||
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. |
| ||
Cheers, thought it might be due to this. Any idea how to do this? PeekByte? |
| ||
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 |
| ||
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. |
| ||
..or using threads to implement async behaviour :) |
| ||
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 |
| ||
Hmmm. that would be damn useful if so. Stupid question No.1 Can socket streams be directed to /dev/ttyS0? |
| ||
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. |
| ||
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. |
| ||
Sigh. |
| ||
Not able to get socket streams working? Maybe you could just use Eof() or Size() to tell if you can read/write the byte? |
| ||
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. |
| ||
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, |
| ||
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. |
| ||
Most appreciated, interesting reading.. |
| ||
@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. |