Reading from two serial ports at the same - c#

I have a C# program that reads from two serial ports at the same time. The serial port device is a Prolific USD to 4 serial ports adapter and I plug the two hardware on separate ports of the adapter. The problem is when I read from each port one at a time, everything works fine but when I try to read from both ports at the same time, one of the port is not responding. To troubleshoot the problem, I started two instances of the application and was able to read from the two ports at a time (one from each instance of the application). Does anyone know how to read from two separate serial ports in one application at the same time? Thank you.
Adding some codes:
Port 1:
// button to start or stop reading from port 1. Because the hardware requires me to write to it before reading the response, the writing is done in the timer
private void buttonPort1_Click(object sender, EventArgs e)
{
if (buttonPort1.Text == "Start Recording")
{
if (!port1.IsOpen)
{
port1.Open();
}
timerPort1.Start();
buttonPort1.Text = "Stop Recording";
}
else
{
timerPort1.Stop();
buttonPort1.Text = "Start Recording";
}
}
// Write "D" to the hardware each time to receive back the response
private void timerPort1_Tick(object sender, EventArgs e)
{
port1.Write("D");
}
void port1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
try
{
string result = port1.ReadLine();
oneParamDelegate dg = PHandCondResult; // send back the result to the main thread
this.Invoke(dg, result);
}
catch
{
}
}
Port 2
The code for the second port is similar to the above really, the difference being different port, datareceived event and timer.
I'll try the multiple thread options suggested by Grant Thomas: I didn't try this before because I thought serial ports are already working on separate threads: the datareceived event doesn't block the main thread and you can't access controls created on the main thread but I'll still give it a go using background worker and revert back later. Thank you all for the quick response.

You're going to need to do some reading, specifically on Threading.
If you have, say, some code that looks like this:
ReadDataFromSomePort();
ReadDataFromSomeOtherPort();
Then the first will execute synchronously (blocking) and then the latter. This happens on the same thread, the main application thread. When you want to do asynchronous things, including just doing one thing while keeping a UI interactive/responsive, then you need to delegate work to other threads.
So, you end up with something like this:
var thread1 = new Thread(ReadDataFromSomePort);
var thread2 = new Thread(ReadDataFromSomeOtherPort);
thread1.Start();
thread2.Start();
There's more to it than this, rest assured, so I recommend some research on the concept before proceeding.
MSDN has a tutorial/programming reference for threading that should get you started.

Creating two different objects of SerialPort and different DataReceived events for both should work.

Related

C# use date from serial port in mainprogram

I need to read data from COM port. The data comes from Arduino, it needs to be parsed by the C# program and do certain things on the host PC. I can read the data, but only with endless "while true" loop. which is blocking the form and other tasks to be executed. So currently it looks like that:
while (true) {
oneLine = myPort.ReadLine();
this.Invoke(new EventHandler(display_data_Event));
// TBD: add analysis of data from port
// TBD: execute according to data from Arduino
}
the handler:
private void display_data_Event(object sender, EventArgs e)
{
string curr_time = DateTime.Now.ToString("h:mm:ss tt");
port_in_TextBox.AppendText(curr_time + " " + oneLine + "\n");
}
So I can display the data to a textbox, but not use it with my main program.
How can I use the "one line" string only when the event occurs, instead of the "while true"?
I tried calling functions from the handler - I guess it failed because it is another thread. So perhaps the problem is how to share the string from one thread to another.
I am lost, here is the core program:
https://learn.microsoft.com/en-us/dotnet/api/system.io.ports.serialport.datareceived?view=netframework-4.8
Now, the question is do you need one input or many. If the former, add AutoResetEvent so the main program will be blocked, and reading the data will signal it to unblock. Or if there are many lines add your "main" action in the event just after you read each line.

Two ways to implement an application invoving serial communication

I am in the process of writing an application, that involves serial communication with a device among other things. (in C#). I have seen some sample code, in concrete two examples.
In the first example, the code is based on a Background control which has a while loop that checks if there is data read from the serial port (another control) and when it does do some processing
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{ serialPort1.Open();
while (backgroundWorker1.CancellationPending == false)
{
if (serialPort1.BytesToRead >= 240)
{
serialPort1.Read(RDATA, 0, 240);
//Some other process
}
}
serialPort1.Close();
}
The second example is quite different. This involves delegates and events. In this case the serial port (created in code) has an event "DataReceived". To this we add an event handler
ComPort.DataReceived +=
new System.IO.Ports.SerialDataReceivedEventHandler(port_DataReceived_1);
and then the port_DataReceived_1 function is defined, in which the input data is read
private void port_DataReceived_1(object sender, SerialDataReceivedEventArgs e)
{
InputData = ComPort.ReadExisting();
if (InputData != String.Empty)
{
this.BeginInvoke(new SetTextCallback(SetText), new object[] { InputData });
}
}
private void SetText(string text)
{
this.rtbIncoming.Text += text;
}
Anyway, I can see two different styles of coding serial communication here. On one hand we have a constant polling (through while) that would block the rest of the program if it weren't on another thread. It is done in a different thread though.
On the other hand we have interruptions in which the processing is done only when an event happens and not the rest of the time. It is all done on the main thread though.
My question is which of these ways would be preferable. I am imaging that the first method, even if it is on a different thread takes a lot of resources of the computer, maybe even taking the load of the CPU to 100% or something.
I am more inclined to do the second one but then again it is all in one thread.
Any recommendations, advice on this?
(My application will involve not only serial communication but maybe processing on the data received, perhaps even machine learning)
You should definitely go with the second option, which is likely handled by an I/O Completion Port thread. If you're writing a WinForms application then you'll need to make sure to check the InvokeRequired flag and perform any UI manipulation on the main thread by passing a delegate to the Invoke method.

Application wide serial port utilisation

I am developing a WPF application in C# and am communicating with a serial device. Currently in the main window of my application I am displaying some information that I obtain by periodically reading lines from the serial device.
Sometimes I need to constantly receive and save data from the serial device to a file. I stop other methods that are utilizing the serial port (like the one that is periodically reading lines to display on the main window) so that the recording process is not interfered with. It can be cumbersome to manage access to the serial port across the application and so "System.UnauthorizedAccessException" is not uncommon.
In each method or window within the application that utilizes the serial device I define a new serial port, open it, read lines and then close and dispose it. I have read though that it is good practice to open the serial port when the application launches and close it when the application closes and I can see why this would be helpful with where I am getting to with this application. I have some questions though:
Where should I define the serial port object?
If I am calling the serial port object from more than one window or method am I creating more than one instance of the serial port object? Can you have more than one instance of a serial port object for just one physical serial port?
If I had SerialPort.ReadLine() being called from two different methods (on two different threads), would one line go to one method and then the next line to the other method and repeat like that? How could I make all serial data go to both?
You should create a separate class to manage the SerialPort connection. It should have its own thread that reads from the serial port. It can then distribute the information it reads to the other places in your application. One good way to do this is using Rx. Make a singleton from this class and inject it into anywhere else in the application that needs it.
Using Rx you can subscribe to messages from the serial port as many times as you need to.
Create a class to manage the serial port:
public class SerialPortManager
{
private SerialPort;
private string comPort;
Subject<string> messageBus = new Subject<string>();
public IObservable<string> MessageBus => messageBus;
private CancellationTokenSource cts = new CancellationTokenSource();
public SerialPortManager(string comPort)
{
this.comport = comport;
}
public void Start()
{
ThreadStart ts = new ThreadStart(SerialDeviceThread);
Thread t = new Thread(ts);
t.IsBackground = true;
t.Name = this.Name;
t.Start();
}
private void SerialDeviceThread()
{
this.serialPort = new SerialPort(this.comPort, ...);
while (true)
{
string line = this.serialPort.ReadLine();
this.messageBus.OnNext(line);
}
}
}
Create a singelton of this class somewhere:
public static Lazy<SerialPortManager> SerialPortManager =
new Lazy<SerialPortManager>(x => {
var sm = new SerialPortManager("COM2");
sm.Start();
return sm;
});
and elsewhere
SerialPortManager.Value.MessageBus.Subscribe( ...)
[This is still greatly simplified, I would have logic around the serial port to catch failures and recreate the port when it disconnects. I'd also use a dependency injection container (e.g. Autofac) rather than a static value.]
It sounds like what you need is an object managing access to your serial port. This object would set up the port object once and start a new thread that would read lines continuously from the serial port, and fire an event when it has read the line. Then your other application objects would attach delegates to that event when they want to be notified of data coming in from the serial port. In that way, data from the serial port would always be broadcast to those who were interested. Depending on your UI, you will have to use the Invoke() method on Dispatcher (for WPF) or on a Windows form object (for Windows forms) to make sure the event is fired from the UI thread so it can invoke UI methods correctly.

c#: serial data write from read thread

I am sending and receiving data from a device using
c# (serial communication). For receiving my setup is like this.
I am receiving on a separate thread i.e. I have something like this
comPort.DataReceived += new SerialDataReceivedEventHandler(comPort_DataReceived);
private void comPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
.....
}
To write I push a button which write data to the device.
Now I was thinking to write data automatically when ever I receive some data from device instead of me pushing
the button when ever I receive data. So my q is that can I put
comPort.WriteLine(textBox1.Text + "\r\n"); in the body of
private void comPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
function. Becase when I put write here it stops working. Otherwise write works with separate button push as I mentioned above.
Can somebody tell me whats the correct way. Is there any issue of threads or someting
Thanks !
Any operation with UI controls (including reading and writing properties like Text) should be done in application's main thread. If you are in another thread, you should use the Invoke method to do the operation:
var text = (string)textBox1.Invoke(new Func<string>(() =>
{
return textBox1.Text;
}));
comPort.WriteLine(text + "\r\n");
Read this answer for more information.

Serial Port Async Read (non blocking) + Threads

Well, I've been strugling for the last 4 days with this SerialPort control in C# with no satisfactory results. Let me explain:
I have a device (Arduino UNO Board) that comunicates with a c# prog which simulates a scale (simple request/response pattern), the device sends a command sequence consisting of 3 bytes (asking for a weigh): CHR(27)+P+CHR(13) so the simulator responds with a simulated weight (I have sorted out how the device catches and parses this weight so this is not longer of the problem).
Using the DataReceive event seems I'm loosing data using Serialport.Read() so I wasted this approach so far.
The simulator HAVE TO BE ALWAYS listening for the said seq. of bytes and HAVE TO HAVE a GUI. I understand that for this I must use a Thread in order to prevent the GUI is locked (perhaps a backgroundworker?) and a sort of buffer which is shared between (now) this 2 threads and prevent the threads read/write at the same time to the buffer (do I need a state machine?) (I ask for help on this since I don't know if this is a good approach or my assumptions are wrong or if theres is a more easy way to solve this) so I'm asking for advice and (with lot of luck) code fragments or if you've faced to develop a similar app how you solved it.
I can provide the code I've done so far if necesary to clarify further more. Hope you can shed a light on this.
Thanks in advance.
UPDATE 1
This is the code i have so far:
ConcurrentQueue<byte> queue = new ConcurrentQueue<byte>();
....
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
bool listening = true;
while(listening)
{
if(serialPort.BytesToRead > 0)
{
byte b = (byte)serialPort.ReadByte();
queue.Enqueue(b);
}
}
}
So since a command have to end with character 13 (CR in ASCII):
public string GetCommand()
{
string ret = "";
byte[] ba = new byte[1];
byte b = (byte)' ';
while(b!=13)
{
if(queue.TryDequeue(out b))
{
ba[0] = b;
ret += ASCIIEncoding.ASCII.GetString([ba]);
}
}
return ret;
}
In order to test this GetCommand() method I call it from the main ui thread within a buton_click event but it hangs the app, do i need to create another thread to call GetCommand() ?
This is ok for small amount of data. But if the data is bigger like if you are passing some http information, then the queue size may not be sufficient. So I think you should use a non-blocking type of architecture.
See this answer for how to implement the sending side.
For the reading side use a dedicated thread, in that thread read a message from the port, queue it up in a suitable concurrent data structure (e.g. a ConcurrentQueue) and immediately loop back to wait for the next input from the serial port.
Consume the input from the queue on a separate thread.
There may be more efficient ways but this one is easy to implement and foolproof.

Categories