I am from Embedded domain and need to make a GUI for my device. I have written firmware for the device in C and making GUI application using Visual C# Windows Form Application. Device is sending data to serial port at 100ms and I am trying to receive the data in winforms.
Data:
10Q20Q30Q40Q50Q60Q70Q80Q90Q100Q110Q120Q130Q140Q150Q
I have written following C# code to receive it.
public Form1()
{
InitializeComponent();
//Using data receive event handler to receive data
serialPort1.DataReceived += new SerialDataReceivedEventHandler(comPort_DataReceived);
}
Then in comPort_DataReceived I am calling Read()
void comPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
Read();
}
delegate void Callbackmessage();
void Read()
{
if (this.InvokeRequired)
{
Callbackmessage abc = new Callbackmessage(Read);
this.Invoke(abc);
}
else
{
String data = serialPort1.ReadLine();
}
So finally I am reading the data and saving it into String data. The application is working fine but it is hanging like buttons are responding after 1sec. If I comment this line String data = serialPort1.ReadLine(); , then the application works smoothly. Why the application is hanging. I don't know any other way of receving data from serial port. Please help. Thanks.
You can use a background worker.
https://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker(v=vs.110).aspx
and do the read in the bacground worker RunAsync
e.Result = serial.ReadLine()
and in the backgroundWorker1_RunWorkerCompleted eventHandler you can grab the information and report it back to the client
General suggestion is to use async IO and port.BaseStream.BeginRead. There is a number of Async wrappers around Serial port. For example you can look at this one. Here also a sample of async usage.
Related
I want to receive data via serial port. I want to show this data in a textbox on a UI written in C# -- WPF
I understand that the UI and the comms. run on 2 different threads, but I am unable to get much further.
How can I do this?
They don't necessarily need to run on different threads. Generally with a serial port class, it will have a callback mechanism when data is received, which you can hook in your WPF models. Have you read the official MS documentation?
From this article (3rd item on Google for "wpf serial port communication example")
Receiving Data
Now that we have a serial port, it important to set up a function call for every time the serial port has data to be read out. This is far more efficient that producing a thread, polling for data and waiting for a time out exception. To do this, we simply introduce the following code:
serial.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(Recieve);
This will call the Recieve function every time data is received. Within this function, we read the data out to a String called recieved_data and then we Invoke a function to write this data to our form. To enable Invoke, we have to include:
using System.Windows.Threading;
private void Recieve(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
// Collecting the characters received to our 'buffer' (string).
recieved_data = serial.ReadExisting();
Dispatcher.Invoke(DispatcherPriority.Send,
new UpdateUiTextDelegate(WriteData), recieved_data);
}
I've developed a simple windows form application in c# which is used to send and receive data using serial ports. but when I click my READ button while there is no device connected, the whole application stops working an I have to close it with force! so I need a method to recognize whether a device is connected or not before I click on READ button. please help me get through it.
private void button2_Click(object sender, EventArgs e)
{
try
{
textBox2.Text = serialPort1.ReadLine();
}
catch (TimeoutException)
{
textBox2.Text = "Timeout Exception";
}
}
In this case I found my way out of it! I just Changed ReadLine to ReadExisting in try block and application didn't stop working even with no device connected! But still no way to find whether a device is connected!
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.
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.
I working on an application handling serial port communication. It's a WPF, multithreaded application. Everything went fine until I sent only small packages through the COM port with communication.
No I reached a phase, where I have to listen for data sent to my application on COM port. For this big chunk of data I go into trouble. I have only one DataReceived event fired, which reads part of the data I need. But after that there is no DataReceived event fired anymore for the rest of the data.
If I monitor the COM port I saw that the bytes are there, the monitoring software states, that there are 2067 bytes in the in queue, but the event do not fire.
I searched Google for similar problems, but I was unable to find relevant answers for this. Have you got any idea where to start searching the roots of the problem.
Thanks in advance.
Here is the code of the DataReceived handler:
private void comPort_DataReceived( object sender, SerialDataReceivedEventArgs e )
{
do
{
new Thread(() =>
{
OnReceivingData(new ComPortCommunicationEventArgs(DataTransferDirections.Receiving, DataTransferActions.Start));
}).Start();
byte[] packetData = null;
try
{
IsReceiving = true;
int bytesToReadCount = comPort.BytesToRead;
if ( bytesToReadCount == 0 )
{
return;
}
packetData = new byte[bytesToReadCount];
comPort.Read(packetData, 0, bytesToReadCount);
}
finally
{
IsReceiving = false;
new Thread(() =>
{
OnReceivingData(new ComPortCommunicationEventArgs(DataTransferDirections.Receiving, DataTransferActions.End));
}).Start();
}
OnPacketReceived(new PacketReceivedEventArgs(comPort.PortName, packetData.ToList()));
} while ( comPort.BytesToRead > 0 );
}
What I found out meanwhile, that if I comment out the OnPacketReceived call - which just fires event for the UI with the received data - than the data processing works fine. So it's not a COM port communication error I think...
Update:
I found the solution for my problem. It was not related to serial port handling.
In one of my data processing threads I run into a loop, which was supposed to be finished on succesfull processing, but with not enough data it was just run continously. Doing that it was blocked the DataReceived event handler - which is still not fully clear for my why, since the two process should be on diffrerent threads I supposed. But it seems that I'm wrong with this.
Anyway I corrected the processing method, and no I receive the data from the serisl port.
Sorry to take your time, and thanks for your help anyway your ideas helped my localize this problem.
Br,
Csaba
I worked with COM ports 5 years ago, and I know how tricky it can get sometimes. All sorts of tricky problems happened with the Siemens device I used to work with :)
First off, I couldn't follow your code thoroughly, so I can't know for sure if your DataReceived routine is sane. I suggest you try to replace all that code inside comPort_DataReceived to something very simple, only for test purposes.
private static void comPort_DataReceived(
object sender,
SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
string indata = sp.ReadExisting();
Console.WriteLine("Data Received:");
Console.Write(indata);
}
If it still doesn't work, then the problem is not in your code. If you don't know what else to try, I would mess with parameters such as SerialPort.DtrEnable and SerialPort.RtsEnable and see if something happens, because these also caused some not-in-the-manual bugs for me in the past.
Piece of code extracted from MSDN.