Problem with DataReceived handler in serialport
-
Im using a SerialPort in order to connect a client and a server through modem. I write some AT commands in the servers' modem buffer, and the client makes the handshaking correctly. The AT commands are written when the DataReceived Handler is triggered. The problem is that when handshaking finishes and communication is established, I cant use the handler to detect new data , I have to do a loop, reading the serialport input buffer constantly. Is there a way to trigger the event handler and read data instead of using a loop? Any help would be apreciated and excuse my english if I made a mistake :) Ivan
-
Im using a SerialPort in order to connect a client and a server through modem. I write some AT commands in the servers' modem buffer, and the client makes the handshaking correctly. The AT commands are written when the DataReceived Handler is triggered. The problem is that when handshaking finishes and communication is established, I cant use the handler to detect new data , I have to do a loop, reading the serialport input buffer constantly. Is there a way to trigger the event handler and read data instead of using a loop? Any help would be apreciated and excuse my english if I made a mistake :) Ivan
I often use serial ports and other similar way of communicating to instruments and devices, and personally I prefer to write a thread for reading incoming data. You can have the thread loop and check on incoming data and if any, read it all up (or up to a maximum of "n" bytes), and insert a Thread.Sleep(1) in the loop or similar to avoid using up all the CPU time. You can use events to break the thread on closing the serial port and cleaning up, or even a simple boolean. You must of course use some locking to ensure thread-safe access to the serial port object. I've been using this technique for quite a few years, and it works quite nice IMO. Hope this can help, if you need it I can give you some code snippets, just let me know. :)
2+2=5 for very large amounts of 2 (always loved that one hehe!)
-
I often use serial ports and other similar way of communicating to instruments and devices, and personally I prefer to write a thread for reading incoming data. You can have the thread loop and check on incoming data and if any, read it all up (or up to a maximum of "n" bytes), and insert a Thread.Sleep(1) in the loop or similar to avoid using up all the CPU time. You can use events to break the thread on closing the serial port and cleaning up, or even a simple boolean. You must of course use some locking to ensure thread-safe access to the serial port object. I've been using this technique for quite a few years, and it works quite nice IMO. Hope this can help, if you need it I can give you some code snippets, just let me know. :)
2+2=5 for very large amounts of 2 (always loved that one hehe!)
Thanks for your suggestion Moreno! Yeah, I think thats the best way to do this task, but... Im using GUI to report and show the status of each serialport (Im using 60 instances of it, I have 60 COM ports). For example, report if CD is on, CTS, if its reading, writing and so on... so I would have to make 60 threads for each serialport, plus main thread which manages all the GUI stuff, so I think I would have to use some sort of thread cross communication, and I'm not good at that topic ;P. However, I'm googling that. BTW if someone have any good resource about threads communication (sharing data between them), it would be very useful. Thanks! Ivan
-
Thanks for your suggestion Moreno! Yeah, I think thats the best way to do this task, but... Im using GUI to report and show the status of each serialport (Im using 60 instances of it, I have 60 COM ports). For example, report if CD is on, CTS, if its reading, writing and so on... so I would have to make 60 threads for each serialport, plus main thread which manages all the GUI stuff, so I think I would have to use some sort of thread cross communication, and I'm not good at that topic ;P. However, I'm googling that. BTW if someone have any good resource about threads communication (sharing data between them), it would be very useful. Thanks! Ivan
I understand your doubts: threading can be a pain if you're not used to it, but it pays off. My best suggestions is you create a wrapper class which includes all the serial port functionality, for example:
using System.IO.Ports;
internal class MySerialPortClass
{
...
// *** Incapsulated serial port object ***
private SerialPort MySerialPort = null;
...
// *** Routines to handle the serial port ***
internal void Open()
...
internal void Close()
....
internal void Send(string Message)
}The class will also contain your thread and start/stop it automatically, for example upon creation/distruction or upon opening/closing the serial port. To handle thread-safety you can simply use locking on the serial port object every time you access it, since that's the only shared resource. For example:
internal class MySerialPortClass
{
private object MySerialPortLock = new object();
...
internal void Open()
{
...
lock (MySerialPortLock)
{
MySerialPort.Open()
}
...
}
...
}And the same technique must be used on any other property in your class that will be accessed by the read thread. For example, if you store the communication results in some variable and then access it from other threads, then you must use locking on it. Finally, you can set up events for anything you want notification about. End of communications by either reading the answer from the device or timing out is the basic event you will need, but you can also add others depending on your needs. For example:
internal class MySerialPortClass
{
internal delegate void CommEndDelegate(string Result);
internal delegare void CommErrorDelegate(string ErrorMessage);internal event CommEndDelegate OnCommEnd; internal event CommErrorDelegate OnCommError;
...
private void DoOnCommEnd(string Result)
{
if (OnCommEnd != null) OnCommEnd(Result);
}
...
private void DoOnCommError(string ErrorMessage)
{
if (OnCommError != null) OnCommError(ErrorMessage);
}
...
internal void MyReadThreadRoutine()
{
...
// *** Received a correct answer from the device, signal end of communications ***
DoOnCommEnd(Result);
...
// *** Timeout waiting for response from device, signal error ***
DoOnCommError("Timeout");
...
}
...
}This will make it
-
I understand your doubts: threading can be a pain if you're not used to it, but it pays off. My best suggestions is you create a wrapper class which includes all the serial port functionality, for example:
using System.IO.Ports;
internal class MySerialPortClass
{
...
// *** Incapsulated serial port object ***
private SerialPort MySerialPort = null;
...
// *** Routines to handle the serial port ***
internal void Open()
...
internal void Close()
....
internal void Send(string Message)
}The class will also contain your thread and start/stop it automatically, for example upon creation/distruction or upon opening/closing the serial port. To handle thread-safety you can simply use locking on the serial port object every time you access it, since that's the only shared resource. For example:
internal class MySerialPortClass
{
private object MySerialPortLock = new object();
...
internal void Open()
{
...
lock (MySerialPortLock)
{
MySerialPort.Open()
}
...
}
...
}And the same technique must be used on any other property in your class that will be accessed by the read thread. For example, if you store the communication results in some variable and then access it from other threads, then you must use locking on it. Finally, you can set up events for anything you want notification about. End of communications by either reading the answer from the device or timing out is the basic event you will need, but you can also add others depending on your needs. For example:
internal class MySerialPortClass
{
internal delegate void CommEndDelegate(string Result);
internal delegare void CommErrorDelegate(string ErrorMessage);internal event CommEndDelegate OnCommEnd; internal event CommErrorDelegate OnCommError;
...
private void DoOnCommEnd(string Result)
{
if (OnCommEnd != null) OnCommEnd(Result);
}
...
private void DoOnCommError(string ErrorMessage)
{
if (OnCommError != null) OnCommError(ErrorMessage);
}
...
internal void MyReadThreadRoutine()
{
...
// *** Received a correct answer from the device, signal end of communications ***
DoOnCommEnd(Result);
...
// *** Timeout waiting for response from device, signal error ***
DoOnCommError("Timeout");
...
}
...
}This will make it
:omg: This is really useful. Thanks a lot Moreno!, I'll try this... :-D