C# waiting for the data on serial port - c#

i am trying to get data from fingerprint scanner through c# application, but before the fingerprint can send, a my whole code executes.
I tried using delay function and System.Threading.Thread.Sleep(1000), so it can get data before the next step executes, but it all seems futile.
Could any one please provide any other option?
I am using "SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)" to get data.

This code works perfectly for me:
port = new SerialPort(port, 9600, Parity.None, 8, StopBits.One);
port.Open();
port.DiscardOutBuffer();
port.DiscardInBuffer();
port.DataReceived += OnScan;
void OnScan(object sender, SerialDataReceivedEventArgs args)
{
SerialPort port = sender as SerialPort;
string line = port.ReadExisting();
// etc
}

Unfortunately waiting for a serial port data in C# is tricky, there is nothing like poll().
There is SerialPort.DataReceived which takes functions to be called on incoming data. So you assign there a function to trigger an arbitrary event. Your another function — the one to actually wait — should wait for this event.
Below is a simple example, it is commented, but in short: the TestFunc initializes and opens a serial port (in particular assigns the DataReceived). The Proxy() is a function that will be called every time a data arrived, it triggers an event. And WaitForAData() indeed waits for the event that will be triggered by Proxy() when a data appears. Note the lock(){}s, without them surrounding Monitor's functions it won't work properly.
It's just an example, you would probably want to remake WaitForAData() function to trigger an exception in case of timeout. And to add a boolean variable in case if the Proxy() was triggered before you began waiting, then serial port already have data. But I tested it (cause I need such a function now ☺), and it works.
namespace MyNamespace
{
class MySerial
{
///A condition variable that signals when serial has a data
private System.Object SerialIncoming;
public MySerial()
{
SerialIncoming = new Object();
}
/**
* A proxy function that will be called every time a data arrived
*/
private void Proxy(Object unused1, SerialDataReceivedEventArgs unused2)
{
Console.WriteLine("Data arrived!");
lock (SerialIncoming)
{
Monitor.Pulse(SerialIncoming);
}
}
/**
* Waits for a data for the time interval Timeout
* \param Timeout a timeout in milliseconds to wait for a data
* \returns true in if a data did arrived, and false else
*/
public bool WaitForAData(int Timeout)
{
lock (SerialIncoming)//waits N seconds for a condition variable
{
if (!Monitor.Wait(SerialIncoming, Timeout))
{//if timeout
Console.WriteLine("Time out");
return false;
}
return true;
}
}
/* Just a test function: opens a serial with speed, and waits
* for a data for the «Timeout» milliseconds.
*/
public void TestFunc(string serial, int speed, int Timeout)
{
SerialPort ser = new SerialPort(serial);
ser.BaudRate = speed;
ser.DataReceived += Proxy;
ser.Open();
if (WaitForAData(Timeout))
Console.WriteLine("Okay in TestFunc");
else
Console.WriteLine("Time out in TestFunc");
}
}
}
UPDATE: the problem wasted ½ of my day, so I hope I will save someone's time: the code above won't work in mono (but works in MS implementation) because serial port events are not supported as of writing these words.

If this is a Console application, you can use things like Console.ReadLine() etc. after calling the appropriate function of the COM Port component to start listening asynchronously. If this is a WinForms application. The message loop will of course keep showing your current form. In that case you can call asynchronous listening function in the Form_Load event or behind a button click.
The key point here is that you should call the asynchronous version of the listener function. There is no need to use delays or timers in that case.

Why not make a global marker (bool), that marks if you received anything and make a while(!marker) {} loop and you change the marker in the SerialPort_datareceived subrutine?
The thread.sleep might make you miss the SerialPort data sending?

The serial port is working in a separate thread. Therefore the serialPort_DataReceived event is fired from this thread.
So if your program only starts the serial port and then your main exits, you never receive the event. This is true if you have a console application.
When using a forms application, it keeps the form and the main thread alive until the user closes it.

Related

Correct way to timeout asynchronous namedpipes in C# .net environoment

I have a process that might have multiple instances running at anytime. Each instance should only run for several seconds at most. A process might have to pass data to an earlier started instance, or receive data from a latter started instance using named pipes. Each instance is aware of each other, but doesn't know for sure if it will attempt to pass or receive data. The process has a pipe server and client that each runs on its own thread. Since the process doesn't know before hand if the other process needs to send or receive data, I need the ability to attempt a connection but to time out and close the pipe if it hasn't connected in a few seconds. I'm using the asynch NamedPipeServer.BeginWaitForConnection() method. But I'm not sure if i'm using it correctly.
The process starts with Main() creating a thread with the
receiveServer() method.
receiveServer() starts a NamedPipeServer in a using block and starts the BeginWaitForConnection() method.
the AsychWaitHandle(3000) is used in the if condition so that if it successfully connects the readMessage(namedPipeServer) and a timeout timer is started. If the AsychWaitHandle(3000) expires then control goes to the else block where NamedPipeServer.Close() method is called.
The holdtimer runs as a safeguard while readMessage() method is running in case the pipeserver connects, and waits for data that never comes. When holdtimer expires it calls and event handler that calls the pipe server's close() method.
Being new to some of this, my main questions and concerns with my code are the fact that namedPipeServer.EndWaitForConnection(asynchResult) is only called int the event that the connection succeeds. According to the documentation EndWait must be called exacly once for each BeginWait. Testing the application, if no connection is made in 3 seconds the logic just falls through to the else block and then the pipe is closed, sometimes twice with out throwing any exception.
I'm also concerned about the way that I use the namedpipeserver.close() method in the timeout event when there is a hangup. That can call an exception readMessage() because the while loop tests while (!namedPipeServer.IsMessageComplete) which might be tested on a closed pipe.
I apologize for the lack of brevity, but I thought it would be a clearer question if I included all the relevant parts of the code.
Thanks in advance for the help.
public static void readMessage(NamedPipeServerStream namedPipeServer)
{
//While block continues while the Read() method has not complete,
// but once the Read() begins even if no data is available it blocks
//and the while block continues. Which is the reason for the
//timeout.
{
//Read from pipe to a global string variable
namedPipeServer.Read(messageBuffer, 0, messageBuffer.Length);
}
while (!namedPipeServer.IsMessageComplete);
}
public static void receiveServer()
{
try
{
using (NamedPipeServerStream namedPipeServer = new NamedPipeServerStream("test-pipe", PipeDirection.InOut,
1, PipeTransmissionMode.Message, PipeOptions.Asynchronous))
{
var asynchResult = namedPipeServer.BeginWaitForConnection(null, null);
//Adds a delegate to a timer that explicitly closes the pipe server on timeout
holdtimer.Elapsed += new ElapsedEventHandler((sender, e) => clockExpired(sender, e, namedPipeServer));
holdtimer.AutoReset = true;
//If connection succeeds within 3 seconds
//then control goes to the "if block" where
//the read method is called. And the hold timer
//is started. If the connection doesn't succeed in 3
//seconds then the named pipe server Close() method is called.
if (asynchResult.AsyncWaitHandle.WaitOne(3000))
{
//
namedPipeServer.EndWaitForConnection(asynchResult);
//start timer before calling method
holdtimer.Start();
//Pass namedAPipeServer to readMessage
readMessage(namedPipeServer);
//stop timer after method completes
holdtimer.Stop();
}
else
{
Console.WriteLine("didn't get anything ----------");
}
//Explicately close the PipeServer.
namedPipeServer.Close();
}
}
catch (Exception ex)
{
//This is just for testing.
MessageBox.Show("Exception in receiveMessage :" + ex.Message);
}
}
static void Main(string[] args)
{
//assign clockExpired() delgate to holdtimer
Thread receiverThread = new Thread(receiveServer);
receiverThread.Start();
}

Serial WriteLine in a Thread

I need to write code in C# that sends data from Serial to an Arduino every 2 seconds.
This is what I tried to do:
Thread sender = new Thread(voidSender);
public static void voidSender() {
serialArduino.WriteLine("Test");
Thread.Sleep(2000);
}
In your example you are starting a thread running through the defined method, sending a single message. To send the message multiple times you need to add a loop to this method like
public void voidSender()
{
//Send forever
while(true)
{
serialArduino.WriteLine("Test");
Thread.Sleep(2000);
}
}
However, periodically events are typically done by using a timer. Simply initialize a timer like
System.Timers.Timer sendMessageTimer = new System.Timers.Timer(2000);
sendMessageTimer.Elapsed += OnSend;
sendMessageTimer.AutoReset = true;
sendMessageTimer.Enabled = true;
Inside the elapsed handler you can send the message like
private void OnSend(Object source, ElapsedEventArgs e)
{
serialArduino.WriteLine("Test");
}
Honestly I don't why you would mix open source platform such as Arduino with C# .net if its not running on core, but that's your concern not mine, I personally wouldn't do that.
if you want to send command every two seconds, I would advise you to use windows scheduler that's integrated in every windows system, however you can implement a clock on your own very easy, still why would you need to put such heavy load of 2 seconds timeframe when it will be almost notable by ordinary user. If you don't want to use clock based system you can use this modified example however it may throw stackoverflow exception sometime since its recursion and you must aways stay away from them if you plan to use this on the long run.
//First sorry for reusing your code but I am writing from my smartphone and
//I am kind of lazy here is quick modification that would work but not the most clever way around
Thread sender = new Thread(voidSender);
public static void voidSender()
{
start:
serialArduino.WriteLine("Test");
Thread.Sleep(2000);
goto start;
}

Serial Port Communication on the same Windows machine not working

Excuse me, quick question:
I have this hardware setup:
Same machine: "Com3" -> USB -> To Serial -> To USB -> "Com4"
And I followed MSDN SerialPort Class and MSDN SerialPort.ReadLine() to build this routine:
SerialPort SendSerialPort = new SerialPort("Com3", 9600);
SerialPort ReceiveSerialPort = new SerialPort("Com4", 9600);
SendSerialPort.Open();
ReceiveSerialPort.Open();
SendSerialPort.WriteLine("Test");
var message = ReceiveSerialPort.ReadLine(); // control stops here
SendSerialPort.Close();
ReceiveSerialPort.Close();
Console.WriteLine(message);
However, when I tend to ReadLine(), my control stops and just waits. I did not expect that.
I am expecting to receive the string Test and assign it to my var message. Could you please tell me what am I doing wrong here?
EDIT:
I tested my hardware using the Serial Port Utility Application and it worked just fine.
I've altered from the example you linked:
To actually have both ports running to read and write back and forth you will actually need to implement threading for reading and writing for both.
It can be a good idea to use a timer.
public static void Main()
{
SerialPort SendSerialPort = new SerialPort("Com3", 9600);
SerialPort ReceiveSerialPort = new SerialPort("Com4", 9600);
StringComparer stringComparer = StringComparer.OrdinalIgnoreCase;
Thread readThread = new Thread(Read);
// Set the read/write timeouts
_serialPort.ReadTimeout = 500;
_serialPort.WriteTimeout = 500;
SendSerialPort.Open();
ReceiveSerialPort.Open();
bool _continue = true;
readThread.Start();
Console.Write("Name: ");
name = Console.ReadLine();
Console.WriteLine("Type QUIT to exit");
while (_continue)
{
message = Console.ReadLine();
if (stringComparer.Equals("quit", message))
_continue = false;
else
SendSerialPort.WriteLine(String.Format("<{0}>: {1}", name, message));
}
readThread.Join();
SendSerialPort.Close();
}
public static void Read()
{
while (_continue)
{
try
{
string message = ReceiveSerialPort.ReadLine();
Console.WriteLine(message);
}
catch (TimeoutException) { }
}
}
Usually there will be a beginning and end value within the written data to tell the other port that the message is finished and also for the ports to validate that they are reading data they should be, usually with commands of what to do with that data. (out of scope for this question).
Also lacking and important is the intialisation of your ports.
I prefer to use the default constructor (preference only)
SerialPort Constructor ()
And then set any values like so:
_serialPort.BaudRate = SetPortBaudRate(_serialPort.BaudRate);
_serialPort.Parity = SetPortParity(_serialPort.Parity);
_serialPort.DataBits = SetPortDataBits(_serialPort.DataBits);
_serialPort.StopBits = SetPortStopBits(_serialPort.StopBits);
_serialPort.Handshake = SetPortHandshake(_serialPort.Handshake);
All the constructors will give these values:
This constructor uses default property values when none are specified. For example, the DataBits property defaults to 8, the Parity property defaults to the None enumeration value, the StopBits property defaults to 1, and a default port name of COM1.
Even the handshake has a default value. If you look at the source code.
private const Handshake defaultHandshake = Handshake.None;
The problem with your code is in this line
var message = ReceiveSerialPort.ReadLine();
You block your code to wait for a line, if the line never arrives it will remain here forever or the value set to ReadTimeout
So why does the line never arrive?
The problem can be an error in WriteLine("Test");, you should handle errors, or it can be that your in are blocking your code ReadLine() before the WriteLine("Test") manage to come through, you could insert a Thread.Sleep(100) between, but this is not really improving the code.
Note: Your code will also work as is sometimes, depending on these race conditions.
This synchronized / blocking reading from serial ports seems simple in code just one line; but it creates a lot of negative side effects in your communication protocol's.
A much better solution (considering that you like to Read / Write data from a microcontroller) is to either use a thread as Yvette suggested or use asynchronously reading Stream.BeginRead (Byte[], Int32, Int32, AsyncCallback, Object) which I would prefer.
The asynchronously reading will throw an event when something is incoming on the serial port. The basic idea of this programming strategy is to not do step programming but expecting what ever result and then handle it correctly.
In communications protocol with asynchronously reading the AutoResetEvent is very useful, hence you send something, then you start the AutoResetEvent, if asynchronously the expected result is arriving you will set this event and your code can continue, if it does not arrive the AutoResetEvent will timeout and you can handle this.
It cannot block when there is data available. What you sent either got stuck in the transmit buffer, got lost due to a wiring mistake, triggered an error or was ignored. If it works with another program then a wiring mistake can't be the problem.
Do keep in mind that just setting the Baudrate is not enough, you must also use set the DataBits, Parity and Stopbits properties to match the device settings. A mismatch can trigger an error, the kind you can only see when you write an event handler for the ErrorReceived event. Never skip that event, confounding problems can occur if you never check.
And above all the Handshake property must be set correctly. The proper value depends on how the ports are wired together, it is too common to not connect them. Start by setting it to Handshake.None so a wrong state for the DSR and CTS signals can't block reception and a wrong state for the DTR and RTS signals can't block transmission. Beware that it is common for another program to enable hardware handshaking, a mismatch is guaranteed to cause communications to stall.
If you use synchronous reads instead of the DataReceived event then you should in general deal with the possibility that a device is not responding. Either because it is powered off, not connected at all or malfunctioning. Use the ReadTimeout property for that so your program cannot hang. Aim high, 10000 milliseconds is a reasonable choice.
Beware the randomness of this problem, putzing around with another program can easily get the port configured correctly and now it will suddenly work. And beware that starting a thread accomplishes nothing, it will now be that thread that gets stuck and the Join() call will deadlock.

IO operation aborted error thrown while reading serial port

We are trying to read data written by an external device (weighing scale in this case) connected to serial port using .Net serial port class.
First we initialize the serial port as below:
InitializeSerialPort()
{
if ((serialPort != null) && (serialPort.IsOpen))
{
serialPort.Close();
serialPort.Dispose();
serialPort = null;
}
serialPort = new SerialPort("COM2", 9600, Parity.None, 8,
StopBits.One) { Handshake = Handshake.None };
serialPort.DataReceived += serialPort_DataReceived;
serialPort.NewLine = "\r";
}
We are using background worker thread to poll the device on continuous interval by sending a command(understood by the weighing scale) on the serial port. As soon as we send the command the device connected to serial port reacts with a response output. We call ReadLine API of SerialPort class to get the data present on the serial port written by the device in the DataReceived event as shown in the code snippet below :
private void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
try
{
data = serialPort.ReadLine();
}
catch(System.IO.IOException ex)
{
//since serial port reading threw an error so there is no value to be parsed hence exit the function.
return;
}
//if no error then parse the data received
}
I'm using System.IO.Ports.SerialPort class of .Net framework 4.0. I can see a number of people posting this issue on other forums but with no specific resolution. Some of them terming .Net Serial port class as buggy which has not been fixed by Microsoft till date. One of the forums where this error is mentioned is here
I also tried the solution posted here but of no help. I need some input if any one else has come across this issue or its resolution.
We were able to solve this problem by locking the code inside serialPort_DataReceived method.
Object lockObject = new Object();
private void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
lock(lockObject)
{
try
{
data = serialPort.ReadLine();
}
catch(System.IO.IOException ex)
{
//since serial port reading threw an error so there is no value to be parsed hence exit the function.
return;
}
}
//if no error then parse the data received
}
We had set the polling interval to poll the device connected on serial port as 10 seconds. Possibly the entire code present inside serialPort_DataReceived method was sometimes taking more than 10 seconds. We were not able to exactly establish this fact as it was not happening every time may be.
So we locked the entire piece of code inside serialPort_DataReceived method using lock keyword in C# to ensure that the new execution for new data received from serial port doesn't start unless the older reading hasn't finished. The issue got resolved after implementing this code on trial and error basis. Hope this helps others as well if they come across such an issue.

SerialPort communication in C# splitting frames

I need to write a program, that will listen to communication in ModBus network through RS485.
I am connected to the network with RS485 <> USB dongle.
I can read some data using SerialPort.DataReceived event, but it gives strange results.
Data is often split, when it should come in one piece. (Modbus Master transmits every 100ms).
class Serial
{
private SerialPort port;
Queue<byte[]> buffer;
public Serial()
{
buffer = new Queue<byte[]>();
port = new SerialPort("COM3", 19200, Parity.Even, 8, StopBits.One);
port.DataReceived += port_DataReceived;
}
public void Open()
{
if (port.IsOpen)
{
port.Close();
}
port.Open();
}
void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
byte[] buff = new byte[port.BytesToRead];
port.Read(buff, 0, port.BytesToRead);
buffer.Enqueue(buff);
}
}
I don't have any start sign in transmission.
Delay between frames is min. 3.5 chars, and max delay between chars is 1.5 chars.
This is entirely normal, serial ports are very slow devices. The DataReceived event is fired as soon as one byte was received. You'll need to call Read() and pay attention to the value it returns, the number of bytes it was able to retrieve from the input buffer. Which might be more than one but is only very rarely equal to the number of bytes in a "packet", that could only happen if the machine got very slow for some reason.
Beware that the debugger is one way to make it that slow, a breakpoint or single-stepping the event handler code gives the driver enough time to receive all the bytes in a packet. So that the Read() call returns them all. But that stops working as soon as you stop debugging that code.
You could use the ReceivedBytesThreshold property to delay the event but that can only work when a packet has a fixed size. Simply append the bytes you get into byte[], using the 2nd argument of the Read() call. And don't process the packet until you have them all.

Categories

Resources