Multiple serial ports running independently
elmoq
Posts: 4
Hello, I have just started working with the propeller, would appreciate some assistance.
The project I'm working on is to input data strings from four independent RS232 ports, process them, and output a combined string (made from parts of the four input strings), to a fifth serial port.
My intention was to allocate a serial port to each of four separate cogs for the inputs, and have a fifth "master" cog to do the combining and outputting to the fifth port. Seems straightforward enough, but I can't get it to work.
I have used the objects FullDuplexSerial, and Extended_FDSerial. These work fine on separate cogs.
But my problem is this: When the "master" cog starts each of the serial objects (eg RxStr) on the separate cogs, it always stops and waits until the string has been read. I can't quite figure out how to make the separate cogs just read in a string from the serial ports, and raise a flag to the master cog that a buffer of data is ready. When the master cog starts a serial object on the separate cogs to start reading in a string (eg using RxStr from Extended_FDSerial), it always has to wait until the string has been read in, before the method returns. Everything I've tried to make the separate cogs run independently have failed.
Could someone suggest a way for the master cog to start a serial object on a separate cogs, return to its main program, then periodically check whether a string buffer is ready. The separate input cogs should read in a string (say 100bytes), and raise a flag so that the master cog can get the data (eg through passing a buffer pointer)
Thanks
Gary
The project I'm working on is to input data strings from four independent RS232 ports, process them, and output a combined string (made from parts of the four input strings), to a fifth serial port.
My intention was to allocate a serial port to each of four separate cogs for the inputs, and have a fifth "master" cog to do the combining and outputting to the fifth port. Seems straightforward enough, but I can't get it to work.
I have used the objects FullDuplexSerial, and Extended_FDSerial. These work fine on separate cogs.
But my problem is this: When the "master" cog starts each of the serial objects (eg RxStr) on the separate cogs, it always stops and waits until the string has been read. I can't quite figure out how to make the separate cogs just read in a string from the serial ports, and raise a flag to the master cog that a buffer of data is ready. When the master cog starts a serial object on the separate cogs to start reading in a string (eg using RxStr from Extended_FDSerial), it always has to wait until the string has been read in, before the method returns. Everything I've tried to make the separate cogs run independently have failed.
Could someone suggest a way for the master cog to start a serial object on a separate cogs, return to its main program, then periodically check whether a string buffer is ready. The separate input cogs should read in a string (say 100bytes), and raise a flag so that the master cog can get the data (eg through passing a buffer pointer)
Thanks
Gary
Comments
One technique I've used in several projects is to have the PASM driver watch for an end of message character. When the end of message character is received a counter is incremented. Post #9 of this thread has one version of this type of serial driver with flags. The serial driver had been modified to reuse the memory previously occupied by the PASM code so it didn't use much additional RAM for the large rx buffers.
Tracy Allen has greatly improved the multi-port serial driver. If possible, I'd suggest using his driver as a starting point.
I have another project that merges serial lines. The driver adds a prefix to the outgoing signal to indicate which serial line the data was received. Maybe you'll find something useful in the code used for that project.
Thanks for the replies so far. Am looking in detail at the replies.
In the meantime, and in response to kwinn - sorry, should have included some code to show what I've tried, and what I want:
Here's an example of what I've tried (showing two input ports, and one output port):
===========
OBJ
ser1: "External_PDSerial" ' serial input 1
ser2: "External_PDSerial" ' serial input 2
ser3: "External_PDSerial" ' master processor, and output port
VAR
Byte Bytearray1[100],Bytearray2[100]
PUB Serial
ser1.Start(17, 16, 3, 4800)
ser2.Start(19, 18, 3, 4800)
ser3.Start(21, 20, 3, 4800)
repeat
ser1.RXstrTime(1000,@Bytearray1)
ser2.RXstrTime(1000,@Bytearray2)
'process Bytearrays
=============
This works, but the repeat loop gets blocked in each RXstrTime call until that call finishes. Data arriving on the other port in the meantime is lost.
What I would really like is something like this:
===========
..... OBJ, VAR and PUB same as above
repeat
if ser1.dataready1
ser1.RXgetStr(@Bytearray1)
'process Bytearray1
if ser2.dataready2
ser1.RXgetStr(@Bytearray1)
'process Bytearray2
=============
Here, the "serX.datareadyX" is some flag which returns null if there's no data ready.
The important point is that, whatever is happening in this loop, the cogs are still independently reading the port and filling the array.
Thanks
Gary
You have to look at the code behind the
ser1.RXstrTime(1000,@Bytearray1)
to see why it is blocking. Also, since there is no flow control back to the input devices, you may have to specify larger receive buffers for the serial ports, and/or provide double buffering. By double buffering, I mean that there would be two input buffers for each channel
A routine to receive lines from multiple serial ports simultaneously would use the RxCheck method in a loop, something like this as a 1st approximation:
That would require that the time to process each line input is short in relation to the time it takes to fill the serial receive buffers. A variation of this could run in its own cog, in which case it would not call ProcessLineInput directly, but would set a flag so that another cog could do that in parallel and reset the flag when finished.
Come to think back on your original post, it may be that you have to wait until all 4 input strings are available, and only then do you combine them for output--That would simplify things. Do these external devices stream out data asynchronously, or is the whole process command-driven from the Prop? If asynchronous, that complicates things, because you have to wait for the start as well as for the stop.
I want this to be happening on 4 separate cogs monitoring 4 separate serial lines.
I have looked at FullSerial4Input, and the examples, but they don't seem to do what I require.
In the examples for FullSerial4Input(eg demo2_FDS4port), the collection and checking of the strings is *still* done in the main loop (on the first cog).
For example, in demo2_FDS4port, this is in the main cog:
..
fds :FullSerial4Input
...
=================== ===================
I want this to be done in the remote cog(s), and then flag to the main cog when the buffer is ready.
What I would really like is something like this:
=========== =============
Here, the "serX.datareadyX" is some flag which returns null if there's no data ready.
The important point is that, whatever is happening in this loop, the cogs are still independently reading the port and filling the array.
In the examples (eg demo2_FDS4port), the collection and checking of the strings is *still* done in the main loop (on the first cog).
There seem to be a lot of examples of multiple serial ports, but when I look into them I can't see how to do what I want as described above. Any suggestions and help gratefully accepted.
Thanks
Gary
the methode RXCHECK of the FullDuplexSerial checks if something is received but is non blocking (does not wait for a byte).
So a code could look like that (just a draft and not tested): I intentionally made it not optimized, so that it is easier to understand. You can also use object arrays and post clear operators and such things...
Andy
Special thanks to Andy, who took the trouble to write a section of code. This was perfect - Great!
Just what I wanted to handle the four serial ports on a separate cog, and process the resulting strings on the "main" cog. Am using this for my application.
Also helped me learn about the Propeller. Takes a bit of a "mind shift" to get used to the multiple cogs.Still getting used to it. But worth the effort.
The more I look at the Propeller the more I find what a unique device it is.
Gary
PS - Not sure how to change the tag UNSOLVED to SOLVED...?