im very new to C# and is working on a personal project to send a message from Arduino when a button is pressed to my C# code listening on the serial port and writing the message in the console.
This is so far I've gotten:
using System;
using System.IO.Ports;
using System.Threading;
namespace ConsoleApp1
{
class Program
{
static SerialPort _serialPort;
public static void Main()
{
_serialPort = new SerialPort();
_serialPort.PortName = "COM4";//Set your board COM
_serialPort.BaudRate = 9600;
_serialPort.Open();
while (true)
{
string a = _serialPort.ReadExisting();
Console.WriteLine(a);
Thread.Sleep(200);
}
}
}
}
In my console application I would also like to do other things not just wait on incoming data so i guess my option here is to use async?
I tried this: C# Async Serial Port Read
But could not get it to work.
Does anyone have any recommendation on where to start, and sorry for this noobish question i have approx 10 hours of c# experiance :).
Here are some options you can use:
Create a thread with loop calling Read() and call the event when data is received.
Use event DataReceived (but it's not recommended, here's why: long article about SerialPort in C#
Just check the stream if there any data with BytesToRead. If BytesToRead > 0, then call Read.
Use BaseStream property with BeginRead and async callback
Accoring to the article mentioned above the only reliable way is to use Read OR use BaseStream with BeginRead (async option)
Related
I recently got a sas expander card.
The one who gave card to me said:
It has a firmware on the chip and it can show sensor's temperature.
He wants me to develop a C# Console app to execute the firmware.
I didn't know the firmware source code looks like.
But it could be executed by PuTTy and it's connection was via RS232 Serial Port.
PuTTy connection setting:
After I click Open,press Enter and type command sys:
What I try in my C# code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO.Ports;
using System.Threading;
namespace SerialPortExample
{
class SerialPortProgram
{
// Create the serial port with basic settings
[STAThread]
static void Main()
{
SerialPort mySerialPort = new SerialPort("COM5");
mySerialPort.BaudRate = 115200;
mySerialPort.Parity = Parity.None;
mySerialPort.StopBits = StopBits.One;
mySerialPort.DataBits = 8;
mySerialPort.Handshake = Handshake.None;
mySerialPort.RtsEnable = true;
mySerialPort.DtrEnable = true;
mySerialPort.ReadTimeout = 2000;
mySerialPort.WriteTimeout = 1000;
mySerialPort.Open();
if(mySerialPort.IsOpen)
{
string str= "Enter";
mySerialPort.Write(str);
}
mySerialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
Console.ReadLine();
}
private static void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
string indata = sp.ReadExisting();
Console.WriteLine("Data Received:");
Console.Write(indata);
}
}
}
What my code execute:
What is the problem with my code?
How can I execute firmware via RS232 and interact like PuTTy have done?
My Console app is using .Net Framework 4.7.2.
You are sending the string Enter (like typing ⇧E, N, T, E, R). You should probably send the ⏎ Enter key, which is represented on a terminal with the ASCII code 13, i.e. \r in a C# string.
Also you don't yet send any actual command. Try something like counters\r or sys\r.
(You currently receive the Enter back as response because that's what you sent out, and the card echoes any incoming characters so it can be used like a shell without blind typing. There is no other response yet because from the card's perspective you basically started typing the (invalid) command Enter but haven't yet submitted it with the ⏎ Enter key.)
Also I'd suggest adding the event listener for received data before sending any data, otherwise there would be a race condition in which the card could be responding before you even set up your listener and you would lose part of the data.
Additional note: Using the DataRecieved event may not even be desirable in your case.
According to docs:
The DataReceived event is not guaranteed to be raised for every byte received. Use the BytesToRead property to determine how much data is left to be read in the buffer.
This means that your DataReceived event may not even fire at all if there wasn't enough data sent in total yet (it may fire some time later with all the data at once) - but if you quit your program before that, you will never see.
As suggested here (emphasis mine):
Here is my general approach:
Use event-driven (DataReceived) code for streaming data. That is, where data is delivered at regular intervals, without specific associated commands that originate from your application.
Use polling for Command/Response protocols. These might involve a thread the you create to poll, but more frequently would be simple loops that may or may not block other operations until they complete.
So, it would be recommended to use one of the Read methods instead (see docs). There is also ReadTo and ReadLine which you may find useful. You may choose to use ReadTo(" bp1 >") for instance.
I am new to C#, it is my first code :D I was codding in Java in the past and now I have a lot of troubles with sending sockets.
When I try to send a socket, it is only send at the total end of the code:
for example
using System;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.IO;
using System.Text;
namespace HelloWorld
{
class Program
{
public static TcpClient client;
public static NetworkStream networkStream;
public static void Main(string[] args)
{
client = new TcpClient("62.210.130.212", 35025);
networkStream = client.GetStream();
byte[] usernameBytes = Encoding.ASCII.GetBytes("This is just a test bro!");
networkStream.Write(usernameBytes, 0, usernameBytes.Length);
networkStream.Flush();
while (true)
{
// Infinte loop
}
// THE SOCKER WILL ONLY BE SENT HERE, AT THE END OF THE CODE, WHY ?!
}
}
}
Here the socket will only be sent when shutting down the programm (because of the wile loop)
and here
using System;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.IO;
using System.Text;
namespace HelloWorld
{
class Program
{
public static TcpClient client;
public static NetworkStream networkStream;
public static void Main(string[] args)
{
client = new TcpClient("62.210.130.212", 35025);
networkStream = client.GetStream();
byte[] usernameBytes = Encoding.ASCII.GetBytes("This is just a test bro!");
networkStream.Write(usernameBytes, 0, usernameBytes.Length);
networkStream.Flush();
}
}
}
And in this case it will be sent directly because it is the end of the code...
Does anyone know why this happens and how to fix it ? I want my sockets to be sent at any time of the running time, not just at the end :D
Thank you very much ! Thank you for reading this question until there.
Julien.
Does anyone know why this happens and how to fix it? I want my sockets to be sent at any time of the running time, not just at the end.
Why is this happening?
Due to Nagle's algorithm, the transmission will be delayed briefly (in the milliseconds).
Which means your code does not offer enough time before it goes to the loop.
networkStream.Write(usernameBytes, 0, usernameBytes.Length);
networkStream.Flush();
// the time between here is not enough for nagle's algorithm to complete
while (true) { } // blocks the thread from doing any more work
// so, it will end up sending here instead.
How to fix it?
A Quick Solution - Disable Nagle's Algorithm
As documented in this answer you could set TcpClient.NoDelay to true to disable Nagle's algorithm.
You can accomplish that easily by adding it to your code:
client = new TcpClient("62.210.130.212", 35025);
client.NoDelay = true; // add this line of code to disable Nagle's algorithm
Note: This solution will in force an immediate send. However, as your question wasn't clear the on the exact requirement, please note that this is probably not the "best" solution.
A Better Solution - Force execution by disposing your resource(s)
If you dispose/close your TcpClient it will accomplish the same thing. In addition, it will provide the added (and much better practice) of disposing the resource immediately when you're done using it.
public static void Main(string[] args)
{
using (TcpClient client = new TcpClient("62.210.130.212", 35025))
using (NetworkStream networkStream = client.GetStream())
{
byte[] usernameBytes = Encoding.ASCII.GetBytes("This is just a test bro!");
networkStream.Write(usernameBytes, 0, usernameBytes.Length);
}
while (true) { } // loop infinitely
}
Note: This doesn't actually send the packet immediately like the solution above, but instead forces the packet to send because we are closing it. However, the result in your case is the same effect and this is a much better approach that you should practice.
What is Nagle's Algorithm?
The Nagle algorithm is designed to reduce network traffic by causing the socket to buffer small packets and then combine and send them in one packet under certain circumstances.
A TCP packet consists of 40 bytes of header plus the data being sent. When small packets of data are sent with TCP, the overhead resulting from the TCP header can become a significant part of the network traffic.On heavily loaded networks, the congestion resulting from this overhead can result in lost datagrams and retransmissions, as well as excessive propagation time caused by congestion. The Nagle algorithm inhibits the sending of new TCP segmentswhen new outgoing data arrives from the user if any previouslytransmitted data on the connection remains unacknowledged.
The majority of network applications should use the Nagle algorithm.
Setting this property on a User Datagram Protocol (UDP) socket will have no effect.
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.
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.