News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Question: Serial Port Programming methods

Started by dicky96, August 28, 2006, 02:38:57 PM

Previous topic - Next topic

dicky96

Hi guys
Decided to put this one in the workshop rather than the Campus (maybe I'm learning, maybe I'm just getting ahead of myself.....)

My current win32 project (I'm a hobbyist programmer, not a professional) involves communicating with an external device on the serial port. The device sends binary data, I need to get that data, process it and respond back via the serial port.  My question is what is the best method to implement this? 

I have some info about data, and that may help work out the best method:

1. I have the rs232 parameters (baud rate, bits, parity etc) these are fixed

2. The data is binary and variable length (but generally 200 byte ish) 

3. The data follows a specific format, for instance the second byte of each data packet always specifies the length of the data packet

4. The data comes in "packets" several times a minute

5. It may occur that I get a new data packet before I finished dealing with the previous one

I've done some reading around, it would appear the best strategy (to me anyway,but then I'm a novice) would be something like this:  Initialise the com port settings and open the port in my main thread (when the user clicks the "connect" button) and use "worker" threads to send and recieve serial information.  When the User clicks "disconnect" close the worker threads and com port.

However there are plenty things I'm not sure about.   

Like how to know when the data was all received, should the "recieve" thread use that length byte to see if all the packet arrived?
How best to handle errors in received data - should the receive thread handle all that, or should it pass any received data, regardless of it's integrity, to the main thread which then deals with it?
How best to notify the main thread that a data packet is ready to process?
What to do if another data packet arrives before I finished with the previous one?
What if one data packet immediately follows another, with no time gap?

So if anyone would like to discuss the best strategy then please feel free to help me out here :)  At least then I can go and bark up the right tree.

At the moment I'm playing around with the code from Light-I on this thread  http://www.masm32.com/board/index.php?topic=4408.0

dicky

Tedd

My thoughts.. (the issues are pretty much the same as network communication.)

Using multiple threads is a very good idea, but I presume you would only need one extra thread to send/receive the data (worker), while your 'normal' thread runs the application. (RS232 can only send or receive one at a time - half-duplex?)
I would make a distinction between the worker and main threads - such that only the worker handles the serial communcation, and the main thread communications with the worker to send/receive messages.
So, it would be the worker who initialises the com port, puts data on, takes data off, and closes it.
As you have no other indication of how long a message will be, then you'll have to go with the length parameter - this should be 'automagically' handled by the worker.
Errors would also be hnadled by the worker (poor worker!) since this is about the data sent/received. Though it would probably be nice to signal to the main thread that bad data was sent/received/failed/whatever.
You have two choices for notification. You could either wait for the main thread to ask for the next packet (if there is one then you give it the next one in the queue, otherwise return null); or you can post the main thread a message to say there's data waiting, and it can get it when it's ready. (The first would be simpler, but would require the main thread to keep polling.)
If the worker buffers packets (as it should if it's going to keep them in a queue) then it will simply receive each one as it comes and save it in the queue. If many come one after the other (no 'gap'), this shouldn't be a problem since you will know the length of each one (from the length parameter) so separating the two is easy. As for data arriving while the worker is busy.. I don't expect this will actually happen given the relatively slow speed of the serial port and fast speed of cpu, but isn't this what RTS# (ready-to-send) is for?
No snowflake in an avalanche feels responsible.

dicky96

Thanks Tedd
I was wondering if my Question was too vague to get a useful answer.

I read somewhere it was best to have two threads, one for receive and one for send as it is easier to write/debug your code that way.  But may7be that would make it harder to synchronise everything?     I think the best bet is I get some code written and see what happens, I'll just try and receive some data from the serial device first and see if it is coming through OK.

dicky

Mark Jones

Hi Dicky, take a look at this thread already here about this:

http://www.masm32.com/board/index.php?topic=428.0

There used to be more, but hmmm I can't find them.
"To deny our impulses... foolish; to revel in them, chaos." MCJ 2003.08

dicky96

Thanks mark

Also I decided to make one of these  http://www.beyondlogic.org/protocolanalyser/protocolanalyser.htm .... the soldering iron is just cooling down  :8)

Should help debugging me thinks

dicky

dicky96

OK guys
Having some fun with all this lot now :)

What I want to know about is how to properly use COMMTIMEOUTS structure

I have packets of data arriving sporadically, sometimes it can be 15 to 20 seconds between packets, though the gap could ber less than a second in some cases.  Each packet is several hundred bytes.  Com settings are for 115200 Baud rate.  I think I make that 8.68mS per byte if data is sent continually.

I have some ideas (and some confusions)

I have a worker thread that I want to wait for a data packet to arrive, then when a packet has arrived it sends a user defined WM_DATAREADY Message to my main thread.

For the COMMTIMEOUTS structure:

QUESTION 1.   cmtout.ReadIntervalTimeout   - Can I calculate a proper wait time from the baud rate used ?
QUESTION 2.   cmtout.ReadTotalTimeoutMultiplier - As I do not know how many bytes to receive shoud I set this to 0?  The second byte of data packet is a len parameter but at the point data is arriving, I already set the timeouts
QUESTION 3.   cmtout.ReadTotalTimeoutConstant - Do I need to set this for a time exceeding the expected gap between data packets (20 seconds) ?

The Write Timeouts seem easier to set, as at least I know how many bytes I am sending

QUESTION 4. As I understand it, the ReadIntervalTimeout applies from when the first byte in a packet is received. In that case can I use ReadIntervalTimeout to successfully detect the end of the received data packet?

QUESTION 5. If I do that will the recieve buffer hold all the received bytes from that packet when Readfile returns?

At the moment, when the user clicks the CLOSE PORT button, I set a global variable that the worker thread checks after each Readfile operation returns. Then the worker thread posts a custom WM_DONE message and terminates.  My main thread picks WM_DONE Message up, then tidies up and closes the file handle. 

However if I set a long ReadTotalTimeoutConstant (as there could be 20 secs between data packets) then this means thatwhen the user clicks CLOSE PORT it could take a while for the Worker thread to finish the current Readfile operation. 

QUESTION 6. Is there another way I can gracefully terminate the current (blocking) Readfile when the user wants to close the port?

in which case I could also set cmtout.ReadTotalTimeoutConstant to 0 and then (hopefully) the Readfile operaion will always block until a data packet arrives, regardless of the gap between packets.

QUESTION 7. Oh and one other thing (before i get to programming some funtions to send data) can I send a Writefile while a Readfile operation is blocking?  Common sense would suggest I can, seeing as there is no data on the serial cable at that time.

Sorry about so many questions - but I've not done any Serial Port programming before in Windows, and I'm quite new to win32asm in general.

dicky




dicky96

OKdid some coding and tested a few things out and managed to answer most of these for myself.

Seems that

Q1 - a timeout o 10mS seems to work well
Q2 - 0 worked well for this parameter
Q3 - looks like I need to set this long enough so that next data packet arrives before Readfile times out
Q4 - yes
Q5 - yes

So that leaves me with Q6 - how can I terminate an api call that is blocking, without waiting ages for it to time out???


Q7 - didn't get so far as writing data to the com port just yet....

Howard

Hi Dicky
There are 2 basic issues with RX timeouts. 1st is the Rx'd inter-byte timeout and the 2nd is the timeout for no RX bytes at all.

Yes, the 1st does depend to some extent on the baud rate, but you need to be aware that in any RX of a packet, the flow of chtrs is   not necessarily very close together - I've monitored it on a 'scope - I'd be inclined to go up a bit from 10 mS - maybe 25 - 50 mS. For example, some packets may flow fine from the other end, but have a delay while the Checksum is calculated, etc., or while the Sending machine deals with some occasional priority interrupt - depends what the machine is. Use this same timeout to sense the end of the packet.

If you are making use of the 2nd type of timeout, you will indeed get the RX blocking situation you mention. This is not good practice. Generally instead you should set up a scheme to monitor the port's RX status, whence you can easily force an exit. But read the section covering this in the "Serial Communications in Win32" in the MSDN Library, which covers some 'gotcha's.

For Q7, because RS-232 has separate RX & TX wires in the cable, and channels in the USART, RX & TX do not have to be synchronized at all - called Full-Duplex comms.

Hope this helps some.
Howard