SerialPort communication questions - c#

I know SerialPort communication in .NET is designed to send the DataReceived event to the receiver when data is available and reach the threshhold.
Can we not use that DataReceived event and start a thread in the receiver side to freqenutly call one of those ReadXXX methods to get data?
What will happen if receiver is much slower than the sender? The SerialPort buffer will overflow (data lost)?

There's little point in doing this, just start the reader thread yourself after you open the port and don't bother with DataReceived. Doing it your way is difficult, tough to cleanly unsubscribe from the DataReceived event after you started the thread, especially at the very moment data is being received. You can't afford to have them both.

That works, in fact it's one of the ways I used in my question Constantly reading from a serial port with a background thread.
For your scenario you could listen to the DataReceived event, then start a thread that calls ReadExisting on the port to get all currently available bytes. You can also check how many bytes are waiting in the receive buffer by looking at the SerialPort.BytesToRead property.
As for your receive buffer overflowing, a) it's big enough (you can check with the SerialPort.ReadBufferSize property) and b) this isn't 1982, so CPUs are fast enough to process data from the port so that it doesn't have time to fill up (certainly much faster than the serial data rate).

The function of the thread that read serial port can be as this:
private void ThreadRx()
{
while (true)
{
try
{
if (this._serialPort.IsOpen == true)
{
int count = this._serialPort.BytesToRead;
if (count > 0)
{
byte[] Buffer = new Byte[count];
this._serialPort.Read(Buffer, 0, count);
//To do: Call your reception event (sending the buffer)
}
else
{
Thread.Sleep(50);
}
}
else
{
Thread.Sleep(200);
}
}
catch (ThreadAbortException ex)
{
//this exception is invoked calling the Abort method of the thread to finish the thread
break;//exit from while
}
catch (Exception ex)
{
//To do:call your error event
}
}
}
Do not worry about the input buffer, because the thread can be read much faster than the baud rate of serial port communication, you can even use this same code to read a tcp/ip socket.

Related

thread sleep blocking serial port data event handler

I am reading data through serial port which is working correctly. Following is my code in short
public Form1()
{
InitializeComponent();
//Background worker
m_oWorker = new BackgroundWorker();
m_oWorker.DoWork += new DoWorkEventHandler(m_oWorker_DoWork);
m_oWorker.ProgressChanged += new ProgressChangedEventHandler(m_oWorker_ProgressChanged);
m_oWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(m_oWorker_RunWorkerCompleted);
m_oWorker.WorkerReportsProgress = true;
m_oWorker.WorkerSupportsCancellation = true;
connectComPort.DataReceived += new SerialDataReceivedEventHandler(receiveData);
enableDisable();
}
void m_oWorker_DoWork(object sender, DoWorkEventArgs e)
{
backProcess();
m_oWorker.ReportProgress(100);
}
private void backProcess()
{
//do some work
Thread.Sleep(10000);
if(check if 2000 bytes received)
{
//do some work
}
}
backProcess() is running on background worker and I have a global queue in which I insert bytes received from serial port and I check this queue in if loop.
My problem is that when 2000 bytes are send from other end to pc I receive less than 1000 bytes till after thread.sleep statement but if I set a breakpoint at thread.sleep step I receive complete 2000 bytes. So does thread.sleep(background thread) blocks data receive event handler also? How can I avoid this problem?
Some things don't get quite clear from your question, but I think your design is flawed.
You don't need a background worker at all and you don't need to sleep some thread.
The best way to handle serial input is to use the already asynchronous DataReceived event of the SerialPort class, which is called whenever there's data to be read (you're already doing this, as far as I can tell from your latest edit).
You can then read the existing data, append it to a StringBuilder (or fill a list of up to 2000 bytes) and launch whatever you want to do from there.
Pseudo-Code example would be:
DataReceived event
1. Read data (using `SerialPort.ReadExisting`)
2. Append Data to buffer, increase total number of bytes read
3. If number of bytes >= 2000: Spawn new thread to handle the data
BackgroundWorker is NOT the right tool for this, by the way! If handling the 2000 bytes is fast enough, you don't even need to spawn a new thread at all.

C# multiple COM port synchronization

I am porting an existing app from Borland C++ to .NET. Application handles 4 COM Ports simultaneously, i need to synchronize them, so that whilst one port is receiving data, the other three would block until one reads all the data in the receive buffer.
Requirements are, that new version works exactly in the same way as the previous one, so i need to find a way how to synchronize those 4 ports.
P.S.
I have got 4 instances of SerialPort class.
Below is a handler for receiving data over the COM port.
private void SerialPort_DataReceived( object sender, SerialDataReceivedEventArgs e )
{
SerialPort rThis = (SerialPort)sender;
string existingData = rThis.ReadExisting();
int NumReceived = existingData.Length;
if (NumReceived > 0)
{
char[] ReceivedByte = existingData.ToCharArray();
// if RX bytes cannot be processed
if (!rThis.ProcessReceivedBytes(ReceivedByte, NumReceived))
{
rThis.ReportThreadError(ThreadId.TI_READ, 0x07FFFFF);
}
}
}
Best thing is you have only one thread interacting with the ports, because this way you can't interact with the other ports while the thread is busy. This is exactly what you want, forget about multi-threading here.
Then, you should separate that low-level I/O thread from the GUI thread. So you'll end up with two threads that comunicate with one another over a well-defined API.
The low-level I/O thread requires a way of polling the serial ports without blocking, something like this:
while(polling) // GUI thread may interrupt polling on user request
{
foreach(SerialPort port in serialports)
{
if(port.HasDataToRead) // this is the polling you really need
{
// read data from port and handle it accordingly
}
}
// ... suspend thread now and then to prevent loop from consuming CPU time
}
The HasDataToRead should be implemented in the event handler, meaning:
catch in the event handler the event data is available and signal it with HasDataToRead inside the SerialPort class;
don't read the actual data in the event handler, event handlers often run on the GUI thread, you don't want to lock up the GUI;
at the end of the read method clear the HasDataToRead flag.
The cycle above really is a dispatcher, while the events are only used to orchestrate the flags inside the SerialPort instances.
Pay attention to the HasDataToRead flag, you'll have to lock it to avoid race conditions:
lock(HasDataToRead)
{
// access HasDataToRead
}

SerialPort fires DataReceived event after close

I'm experiencing a weird behavior while trying to stop a SerialPort: the DataReceived event continues to fire after unsubscribing and after calling close! (see StopStreaming in the following code). As a result, in my event handler code I get an InvalidOperationException with the message that "The port is closed".
What am I missing? What is the correct way to close the port and stop the events?
EDIT: I get this error every time I run my code. So this is not a race condition that happens randomly but rather a systematic problem indicating a completely broken code! However, I fail to see how...
private SerialPort comPort = new SerialPort();
public override void StartStreaming()
{
comPort.Open();
comPort.DiscardInBuffer();
comPort.DataReceived += comPort_DataReceived;
}
public override void StopStreaming()
{
comPort.DataReceived -= comPort_DataReceived;
comPort.Close();
isStreaming = false;
}
private void comPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
if (e.EventType == SerialData.Chars)
{
SerialPort port = (SerialPort)sender;
int N = comPort.BytesToRead;
for (; N > 0; N--)
{
byte b = Convert.ToByte(comPort.ReadByte());
//... process b
}
}
}
EDIT: following the suggestions, I changed StopStreaming code to something like this:
public override void StopStreaming()
{
comPort.DataReceived -= comPort_DataReceived;
Thread.Sleep(1000);
comPort.DiscardInBuffer();
Thread.Sleep(1000);
comPort.Close();
isStreaming = false;
}
It seems to work now but I'm not really that happy. I wish there was a more effective way to remove the callback rather than inserting sleep periods in the program.
Your DataReceived event handler is called on a threadpool thread. And yes, they've got the awkward habit of running your code at an unpredictable time, it is not instant. So it is fairly inevitable that, if the device is actively sending data, that it can race with your Close() call and run after you closed it. Unsubscribing doesn't fix it, the threadpool thread already got its target method.
Do realize what you are doing to trigger this problem, you are closing the port while the device is sending data. That's not great, it is guaranteed to cause data loss. But not unlikely to happen when you are debugging your code since you don't actually care about the data.
A counter-measure is to turn off handshaking so the device cannot send anything anymore. Discard the input buffer. Then sleep for a while, a second or two, to ensure that any threadpool threads in-flight have completed running. Then close the port. A very pragmatic one is to simply not close the port, Windows will take care of it when your process terminates.
Looks like multi-threading issue.
SerialPort.DataReceived is raised in a worker thread from thread pool. You're closing port from the thread, that differs from the thread, where SerialPort.DataReceived raised in.
You can handle InvalidOperationException or write some synchronization code to solve this problem.
Update.
The problem is that if your devices sends data intensively, SerialPort queues more and more work items to thread pool. Even if your code will sleep any time before Close, it can be not enough. Unfortunately, SerialPort has an ugly implementation. It hasn't an option, which could tell "please, stop spam me with your data".
Hence, the concrete solution depends on device's protocol and handshaking parameters.
I had the same problem in an application I've been working on. It's exciting to read here about how the threadpool can bring it about.
Before I tracked down it's source though, I found that enclosing the contents of the DataReceived event handler in a try catch statement written in anticipation of the problem was a very effective way to solve it. Now that I know there's not really anything I can do to prevent the issue if I need/want to close a SerialPort while still receiving data, I'm quite happy with this approach.
I had similar issue when the user attempted to Exit application whilst it was still receiving data from the connected device. Application was throwing a System.IO.IOException following call to Me.Close().
Simplest solution I found was to set the SerialPort ReceivedBytesThreshold to a large number in the _FormClosing event handler. This reduces the frequency of DataReceived events and provides time for the Close() call to complete whilst the DataReceived event handler is inactive.

How do I transmit over the serial port asynchronously in .NET?

I am writing a program to simulate a device that transmits data over the serial port. To do this, I created a System.IO.Ports.SerialPort object in my form, and a System.Windows.Forms.Timer to do the transmitting at a given frequency. Everything works fine except that as the frequency approaches the limit of the serial port speed, it starts to lock up the UI and eventually becomes unresponsive when the data is being sent for transmission faster than the port data speed. My code is:
private void OnSendTimerTick(object sender, EventArgs e)
{
StringBuilder outputString = new StringBuilder("$", 51);
//code to build the first output string
SendingPort.WriteLine(outputString.ToString());
outputString = new StringBuilder("$", 44);
//code to build the second output string
SendingPort.WriteLine(outputString.ToString());
if (SendingPort.BytesToWrite > 100)
{
OnStartStopClicked(sender, e);
MessageBox.Show("Warning: Sending buffer is overflowing!");
}
}
I was expecting the WriteLine function to be asynchronous - return immediately while the port transmits in the background. Instead, it seems that the OnSendTimerTick function is properly threaded, but WriteLine seems to be running in the UI thread.
How can I get the serial port to behave in this way? Creating the SerialPort object in the timer seems like a bad idea, because then I'd have to open and close it on each timer tick.
It is only partly asynchronous, it will immediately return but only as long as the bytes you write will fit in the serial port driver's transmit buffer. That's going to come to a screeching stop when you flood the port with too much data, faster than it can transmit. You can make it truly asynchronous by using the SerialPort.BaseStream.BeginWrite() method. That doesn't make it any faster but moves the bottleneck somewhere else, possibly away from the UI.
If you're using System.Windows.Forms.Timer, the timer event handler is being executed on the UI thread. Same is true if you're using System.Timers.Timer when the SynchronizingObject is set to the form. If the serial port buffer fills up, the thread has to wait until it has enough space to hold the new data that you want to send.
I would suggest that you use a System.Threading.Timer to do this. The timer callback is called on a pool thread, meaning that the UI thread won't lock up if the WriteLine has to wait. If you do this, then you have to make sure that there is only one threading executing the timer callback at any time. Otherwise you can get data out of order. The best way to do that would be to make the timer a one-shot and re-initialize it at the end of every callback:
const int TimerFrequency = 50; // or whatever
System.Threading.Timer timer;
void InitTimer()
{
timer = new System.Threading.Timer(TimerCallback, null, TimerFrequency, Timeout.Infinite);
}
void TimerCallback(object state)
{
// do your stuff here
// Now reset the timer
timer.Change(TimerFrequency, Timeout.Infinite);
}
Passing a valid of Timeout.Infinite as the period parameter prevents the timer from being a periodic timer. Instead, it fires just once. The Timer.Change re-initializes the timer after each send.
A possibly better way to handle this is to eliminate the timer altogether by setting the WriteBufferSize to a sufficiently large value. Then your program can just dump all of its data into the buffer and let the SerialPort instance worry about dribbling it out across the wire. This assumes, of course, that you can create a buffer large enough to hold whatever your program is trying to send.
This could be resolved(slowness of the UI) if you created a Queue of strings to be written and had a background thread that wrote to the serial port from the queue. If you take that approach be careful of the size of the queue.
edit: For some reason I can't use Add Comment, so I'll just edit this. The documentation for BeginWrite has this statement "The default implementation of BeginWrite on a stream calls the Write method synchronously, which means that Write might block on some streams." It then goes on to exclude File and Network streams, but not SerialPort. I guess you can try it and see.

How to write a .Net UDP Scalable server

I need to write a very high load UDP server. I'm using .Net. How do I use the Socket class to achieve this?
I am familiar with the winsock API, and completion ports, and what i would do there, is to use several threads to accept sockets using a completion port, and also to receive in the same manner.
My server needs to process a LOT of small UDP packets very quickly, and i want to receive them asynchronously, how do i do this using .net?
I thought of calling BeginReceive several times, but that kinda seems silly...
If anyone has a good .net example for this it would of course help a lot.
What I have found to minimize dropped packets is to read from the socket asynchronously as you mentioned, but to put the bytes read into a thread safe queue, then have another thread read off the queue and process the bytes. If you are using .Net 4.0 you could use ConcurrentQueue:
public class SomeClass {
ConcurrentQueue<IList<Byte>> _Queue;
Byte[] _Buffer;
ManualResetEvent _StopEvent;
AutoResetEvent _QueueEvent;
private void ReceiveCallback(IAsyncResult ar) {
Socket socket = ar.AsyncState as Socket;
Int32 bytesRead = socket.EndReceive(ar);
List<Byte> bufferCopy = new List<byte>(_Buffer);
_Queue.Enqueue(bufferCopy);
_QueueEvent.Set();
if(!_StopEvent.WaitOne(0)) socket.BeginReceive(...);
return;
}
private void ReadReceiveQueue() {
WaitHandle[] handles = new WaitHandle[] { _StopEvent, _QueueEvent };
Boolean loop = true;
while (loop) {
Int32 index = WaitHandle.WaitAny(handles);
switch (index) {
case 0:
loop = false;
break;
case 1:
// Dequeue logic here
break;
default:
break;
}
}
}
}
Note: the _StopEvent is a ManualResetEvent so that both the ReceiveCallback and ReadReceiveQueue methods can use the same event to shut down cleanly.
If you only have a single socket and you can process UDP packets independently of each other, then the best approach would actually be to use a thread pool where each thread invokes a blocking Receive. The OS will take care of waking up one of the waiting threads to receive/process the packet. That way you can avoid any overhead introduced by the async-I/O routines.

Categories

Resources