I'm trying to write a test application for serial I/O (RS-232) with multiple units in C# and I'm running into an issue with my lack of threading experience so I'm soliciting feedback for a best known method.
I've got a pool of COM ports COM1-16 each of which can read/write at any time and I need to be able to manage them simultaneously. Is this a situation for a thread pool? What is some guidance on structuring this applet?
Edit:
Upon review I was wondering is I really even need to do asynchronous threads here, I could just maintain states for each COM-port and do flow logic (i.e., statemachine) for each COM-port individually.
Much of the difficulty surrounding the serial port is centered around an assumption. The assumption is that the serial port receives data in chunks that are convenient, and what is expected.
Here is an example. I know my GPS receiver sends lines (ends with CRLF). This is an example of one of the NMEA sentences:
$GPGSV,3,1,11,10,75,053,29,29,52,311,32,24,50,298,30,02,39,073,30*77
However, the serial ports DataReceived event handler might(usually does on my PC) fire several times with chunks of that data.
event fire - data
1 $
2 GPGSV,3,1,11,10
3 ,75,053,29,29,52,311,32,24,50,298,30,02,39,073,30*77
Instead of fighting this I created some routines that receive data whenever the event fires, and queue it up. When I need the data I call some other routines that put the data back together in chunk sizes I want. So using my example the first and second time I call read line(my readline) I get back an empty answer.
The third time I get the entire NMEA sentence back.
The bad news is that I don't C#. The code is here SerialPort
Depending on the speed of the ports delegates may not be a good choice. I tested my routines at near 1Mbps using delegates, and not using delegates. At those speeds not using delegates was a better choice.
Here are some tips from those in the know
Kim Hamilton
If you use the backgroundworker you won't be grabbing small
pieces of the data, you'll get the entire string. You need
something like:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
try
{
serialPort1.Open();
if (serialPort1.IsOpen)
{
while (keepReading)
{
backgroundWorker1.ReportProgress(0, serialPort1.ReadLine());
//backgroundWorker1.ReportProgress(0, sentence.Split(','));
// split_gps_data();
}
}
}
}
The .NET way to handle this is to use Events and Delegates. This will end up creating multiple threads, but it will do so in a manner that means you don't explicitly create them. If you create an event handler and add it to the DataReceived event of each port, then when any port receives data, the event handler will be called on a separate thread. Naturally, this means the method must be reentrant, and that access to any shared data structures must be protected against concurrent access.
Your handler routine will do something like the following:
Call ReadExisting to get the data available.
Handle data.
Done.
You need to know at what speed the receiver is spitting out data. Is it once a second, twice a second, 5 times...
I had this same issue reading GPS data. You need to use the backgroundworker in C# to update your variables, screen.
Related
I am currently writing a C# Program and am struggling a bit with a conceptional question.
A domain of the application is the communication with a Microcontroller via UDP. Therefore I am using the UDPClient and wrote a 'communicator' which does some encoding/decoding, checksum checks, etc.
I need to have some kind of Controller which allows me to send commands to the UDP-Server (the device). Some of them are a single pair of Send/Receive, others are long-running.
I thought about the following implemenation:
My idea was that every capability of my Microcontroller/UDP-Server is abstracted in a class, which has an 'Execute'-function which subscribes to the 'Receive' of the underlying Communicator and sends it request.
However, I am a bit stuck here: I could wait in the 'Execute ' function of each task(capability) for an event which I trigger in the OnReceive-Handler (or timeout). But that would not work if I one task needs multiple Send/Receive.
So, is there any good Design-Pattern for that? Or does anyone have a good advise on how to implement it in a proper way?
You can have a Communicator and a CommandExecuter and share a queue between them. Communicator puts every command it receives from UDP and goes back to it's duty to receive new commands. CommandExecuter is always watching the queue. As long as there is a new command in the queue, takes it and executes it.
i would like to implement a rather simple function, that outputs the byte array of a serial port, e.g.
byte[] o = readAllDataFromSerialPort();
Implementing the actual serial port functions is done. I use the serial port to receive some data and process the data through the event DataReceived.
sp = new SerialPort(portname, 9600, System.IO.Ports.Parity.None, 8, System.IO.Ports.StopBits.One);
sp.Handshake = Handshake.None;
sp.DataReceived += new SerialDataReceivedEventHandler(serialDataReceived);
I check the received data for an "message end"-package in order to then close the serial port, so sth. like
if (data = "UA") sp.Close()
So basically what I would like to do is wait for the closure, before giving back the data, so that on the top level view the program doesn't progress, until the data has arrived. However I cannot wrap my head around as to how I implement this "waiting" in an effective and elegant way, as I'm relying on events for my data. Any hints or clues or examples would be much appreciated.
Serial ports are not open or closed. The Open or Close functions open a handle to the serial port driver.
If no handle is open to the driver all input from the port is ignored.
The only way you can determine whether you have received all the data is to design a protocol that provides you with a guaranteed way to detect the end of a transmission.
You can do this with one of:
Either select a unique terminator for the end of your message,
Include a length towards the beginning of your message that indicates the amount of remaining data, or
Wait for long enough (which also depends) to be sure no more data is pending.
A further reason for the Open, Close metaphor is that a serial port is typically an exclusive resource and only a single process can gain access to the handle at a time to prevent incompatible (and possibly dangerous) access to the device at the other end of the port inadvertently. You should keep the port open throughout your program to prevent the connected device from becoming inaccessible because another program opens the device inappropriately.
The lack of hot-plugging facilities (and in fact device identification) makes serial ports much more static and keeping the device open should not be a problem.
You seem to favour the third option. Implement this by resetting a timer that is set each time data is received, and if it expires assume the transmission is complete.
As it sais on the SerialPort.Close() documentation:
The best practice for any application is to wait for some amount of time after calling the Close method before attempting to call the Open method, as the port may not be closed instantly.
There is no way to wait for it to be closed. you can call it a "bug" or a "function as designed"
It is a bad practice to Open and Close a SerialPort over and over again with the same program. You should keep the SerialPort open.
If you really want to close it and will open it later again you can add a small sleep before returning, but sleeps without meanings are bad practice.
I found this nice post https://stackoverflow.com/a/10210279/717559
with a nice quote:
This is the worst possible practice for "best practice" advice since it doesn't at all specify exactly how long you are supposed to wait.
I have a program that is used to talk to hardware over rs232. This software is used to display a stream of data that is pushed over the rs232 from the hardware as fast as it can be. The problem I am running into is that over time the private memory assigned to the program explodes, and will very rapidly crash the program. If I disable the hardware from sending data for about 2 minutes, then the software can clear out the memory, but only if I pause the data stream.
I am using the DataReceived event from the SerialPort, and this appears to be where the problem is at, because it will cause a memory spike even if the DataReceived function does nothing inside it. The only thing I can come up with is that every time this event is raised it creates a new thread to run, and it is happening so fast that the computer doesn't have time to run GC while the data is coming in.
Is there a more efficient way to pull data off a SerialPort object? I only care about a string when I receive a "NewLine"?
Thanks,
John Vickers
DataReceived is executed on a different thread. I had problems with really fast data and this event caused me problems. Because of that, I created one thread and read the data myself:
while (this.serialPort.IsOpen)
{
int b = this.serialPort.ReadByte();
if (b != -1)
{
// data is good here
}
}
But like the others said, without any code sample, there isn't much we can help you with.
This is very unusual but it is technically possible. SerialPort uses threadpool threads to call the DataReceived event handler. As soon as it receives one or more bytes, it grabs a TP thread to notify your app. There's a lock in the event generation code, only one thread can call your event handler at a time.
A potential failure mode here is that one of these calls, likely the first one, enters a loop in your code from which it never exits. If you haven't set up the Handshake property, the device can keep sending and triggering more TP calls, all of them blocking on that lock.
Diagnose this from the Debug + Windows + Threads window. If my guess is accurate then you should see a large number of threads listed here. One of them should be inside your DataReceived event handler, double-click it and look at the call stack to see where it is stuck. The memory you are seeing consumed is eaten by the stacks of these threads, one megabyte each.
Another possibility is that your DataReceived event handling code is very slow, possibly by calling Control.Invoke(). Slow enough to not be able to keep up with the device. You now really do need to use the Handshake property to setup flow control. Or fix whatever makes it so slow. There should also be a very large number of ErrorReceived events btw, be sure to implement it so you can see this stuff going wrong.
There's an upper limit on the number of TP threads that can be running at the same time. It is rather generous, 250 times the number of cores. That can easily consume half a gigabyte of memory on a typical dual-core machine.
Just to revive this issue.
I'm seeing a massive memory leak when using the DataReceived event.
I am using a USB 3G modem which provides a serial modem interface. I wrote a tiny program that just opens the serial port and connects to the DataReceived event. The event handler is just an empty method.
If you yank out the dongle memory starts to leak at about 10MB per second. No exception is thrown.
Spinning up a new thread and using the synchronous Read(...) method solved the problem for me. I now get an exception when I yank out the dongle that I can handle and no memory leaks.
I developed a state-driven serial port programming language in C# and I believe it really solves nearly all of the serial port problems that everybody encounters with.
Would you please try it with the following simple state and check memory leaks ?
state Init
recv();
$len = length($DATA_PACKET);
if("$len > 0") {
log($DATA_PACKET, Debug);
}
end state
Screen shots
Project homepage
Download
If you have any questions, please feel free to ask.
I've written an application which reads from a serial device at a very fast rate. The serial port object however, fails to fire the DataReceieved event after about 20 min of continuous operation. Disconnecting and reconnecting the serial programmatically allows the event to work again but for only another 20 min.
I tried using DiscardInBuffer after every DataReceived event and this has appeared to have solved the problem. But the method consumes a lot of cpu time and is degrading the performance of the application. MSDN mentions that the method "Discards data from the serial driver's receive buffer.", but fails to suggest when it should be used.
When and how should DiscardInBuffer be used, and am I using it in the correct context for my particular problem ?
Edit:
After implementing the ErrorReceived event, the event data returned indicated the event type was an "RXOver".
After more investigations, it appears my problem was more a fundamental issue. Since the data was flooding in at a hot pace, the SerialPort buffer needed to be cleared or processed continuously to prevent the "RXOver" error. I achieved this by reading into another buffer during the DataReceived event and processed it in another separate thread.
From my understanding the DiscardInBuffer should only be used selectively to clear the contents of the ports for initialisation purposes, such as before opening a port. The process of clearing the driver buffer does take some time to complete and therefore should be used wisely in a performance orientated application.
Two ideas come to mind. The first (horrible) idea: call DiscardInBuffer every 15 to 20 minutes instead of after every DataReceived event. The second (somewhat better) idea: call DiscardInBuffer when you receive the ErrorReceived event, which you should be handling.
I'm an embedded programmer trying to do a little bit of coding for a communications app and need a quick start guide on the best / easiest way to do something.
I'm successfully sending serial data packets but need to impliment some form of send/ response protocol to avoid overflow on the target system and to ensure that the packet was received ok.
Right now - I have all the transmit code under a button click and it sends the whole lot without any control.
What's the best way to structure this code , i.e sending some packets - waiting for response .. sending more .. etc etc until it's all done, then carrying on with the main program.
I've not used threads or callbacks or suchlike in this environment before but will learn - I just need a pointer to the most straigtforward ways to do it.
Thanks
Rob
The .NET serialport uses buffers, learn to work with them.
Sending packets that are (far) smaller than the Send-buffer can be done w/o threading.
Receiving can be done by the DataReceived event but beware that that is called from another thread. You might as well start your own thread and use blocking reads from there.
The best approach depends on what your 'packets' and protocol look like.
I think to have a long experience about serial comm, both MCU and PC-based.
I strongly UNSUGGEST the single-thread based solution, although it is very straigthful for light-speed testing, but absolutely out for final releases.
Surely you may choose among several patterns, but they are mostly shaped around a dedicated thread for the comm process and a finite-state-machine to parse the protocol (during receiveing).
The prevoius answers give you an idea to how build a simple program, but it might depends on the protocol specification, target device, scope of the application, etc.
there are of course different ways.
I will describe a thread based and an async operation based way:
If you don't use threads, your app will block as long as the operation is performing. This is not what a user is expecting today. Since you are talking about a series of sending and receiveing commands, I would recommend starting the protocol as a thread and then waiting for it to finish. You might also place an Abort button if neccesary. Set the ReadTimeout values and at every receive be ready to catch the exception! An introducing into creating such a work thread is here
If you want to, use Async Send/Receive functions instead of a thread (e.g. NetworkStream.BeginRead etc.). But this is more difficult because you have to manage state between the calls: I recommend using a Finite State Machine then. In fact you create an enumeration (i.e. ProtocolState) and change the state whenever an operation has completed. You can then simply create a function that performs the next step of the protocol with a simple switch/case statement. Since you are working with a remote entity (in your case the serial target system), you always have to consider the device is not working or stops working during the protocol. Do this by starting a timeout timer (e.g. set to 2000ms) and start it after sending each command (assuming each command will get a reply in your protocol). Stop it if the command was received successfully or on timeout.
You could also implement low-level handshaking on the serial port; set the serial port's Handshake property to rts/cts or xon/xoff.
Otherwise (or in addition), use a background worker thread. For simple threads, I like a Monitor.Wait/Pulse mechanism for managing the thread.
I have some code that does read-only serial communications in a thread; email me and I'll be happy to send it to you.
I wasn't sure from your question if you were designing both the PC and embedded sides of the communication link, if you are you might find this SO question interesting.