C# Serial communcation with arduino - c#

I'm trying to send a string from my arduino(leonardo) to a C# program.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO.Ports;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
SerialPort mySerialPort = new SerialPort("COM7");
mySerialPort.BaudRate = 9600;
mySerialPort.Parity = Parity.None;
mySerialPort.StopBits = StopBits.One;
mySerialPort.DataBits = 8;
mySerialPort.Handshake = Handshake.None;
mySerialPort.DataReceived += new SerialDataReceivedEventHandler(sp_DataReceived);
mySerialPort.Open();
Console.WriteLine("Press any key to continue...");
Console.WriteLine();
Console.ReadKey();
mySerialPort.Close();
}
static void sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
string indata = sp.ReadExisting();
Console.WriteLine("Data Received:");
Console.Write(indata);
}
}
}
This is my code wich I copied from the msdn example to try and understand what it does.
My arduino code below just sends hello world over te com port with a delay of 1000.
void setup ()
{
Serial.begin(9600);
}
void loop(){
Serial.println("Hello World");
delay(1000);
}
My arduino is using the COM7 like I defined in the C# program. When I run bot programs, The C# program never comes within the datareceived event handler. So no data is received. I really want tis to work :)
Kind regards

I Switched the code to a windows form application, it still was not working. Then i found a topic about serial communication with C# about arduino leonardo
here
I had to do this:
serial.DtrEnable = true;
serial.RtsEnable = true;
I consider my problem as solved.

Console applications do not have a message loop so naturally they don't respond to events. You have one thread and it will be stuck blocking at Console.ReadKey(). Either use synchronous reads from the serial port or, if you wish to stick to an event-based model, move this code to a windows-based applications.
For a synchronous example, see this MSDN example :
while (_continue)
{
try
{
string message = _serialPort.ReadLine();
Console.WriteLine(message);
}
catch (TimeoutException) { }
}
The above is only an excerpt - the full example demonstrates setting up the timeout values, etc.

Related

How to hide some return data from RS232 Serial Port

I am using C# Console app to interact with firmware on sas Expander card.
It was connected by RS232 Serial Port.
Here is the 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)
{
mySerialPort.Write("\r");
}
mySerialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
while (true)
{
string userResponse = Console.ReadLine();
if (userResponse == "sys")
{
mySerialPort.Write("sys\r");
}
else if (userResponse == "counters")
{
mySerialPort.Write("counters\r");
}
else if (userResponse == "phyinfo")
{
mySerialPort.Write("phyinfo\r");
}
else if (userResponse == "? -a")
{
mySerialPort.Write("? -a\r");
}
else
{
mySerialPort.Write("\r");
}
}
}
private static void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
string indata = sp.ReadExisting();
Console.Write(indata);
}
}
}
What the app execute command counters result:
Using PuTTy by sending command counters result:
You can see counters will show up on the app page
and counters won't show up in PuTTY's page.
What should I do to let my code result just like PuTTY does?
How to hide some return data from Serial Port?
My C# Console app is using .Net Framwork 4.7.2.
.....................................................
Update:
After I add mySerialPort.ReadChar(); in code,
the code looks like:
string userResponse = Console.ReadLine();
if (userResponse == "sys")
{
mySerialPort.Write("sys\r");
mySerialPort.ReadChar();
mySerialPort.ReadChar();
mySerialPort.ReadChar();
}
and the result is:
I am not satisfied with this result
because there are at least twenty command in firmware.
I don't want keep adding mySerialPort.ReadChar() in every condition.
Is there another way to fullfill my goal?
.......................................................
Update Part2:
After adding string echocancel = sp.ReadLine(); in DataReceivedHandler,
the code looks like:
private static void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
string echocancel = sp.ReadLine();
string indata = sp.ReadExisting();
Console.Write(indata);
}
and the result looks like:
After product identity :'s word should have default
and between product Identity and <<Alarm status>>
should have space, it should show up.
At least, sys , this three character won't show up again.
Did someone has some solution about it?
Seems like a situation of double echo of keyboard input.
By default the typical terminal emulation program (e.g. minicom) disables local echo for keyboard input; apparent putty does the same.
So when the attached device does echo the typed input, you only see one copy of the input displayed.
(Because of this default mode, you will not see what you type when the attached device also has its echo inhibited.)
With your program, characters typed as input on keyboard are echoed locally to your display, and when transmitted that line is echoed by the attached device and then displayed (by your program) as part of the response.
You can verify this hypothesis by changing your code to accept a foo command instead of counters:
...
else if (userResponse == "foo")
{
mySerialPort.Write("counters\r");
}
...
The expected display should then be something like
bp1 >foo
counters
...
Possible solutions are:
a. disable echo from the device (preferred), or
b. disable local echo, or
c. echo cancellation.
Echo cancellation can be simplified in your program because each command transmitted seems to be a line terminated by a carriage return. So instead of absorbing individual characters as you did for an individual command, you only need a single read of a line to absorb the echoed line:
while (true)
{
string userResponse = Console.ReadLine();
if (userResponse == "sys")
...
else
{
mySerialPort.Write("\r");
}
/*
* might need a delay here allow serial output to drain/complete
* and give device time to respond
*/
string echocancel = mySerialPort.Readline();
}
However such echo cancellation would also require proper setting of the line-terminator character, i.e. mySerialPort.NewLine = "\r";
See
https://learn.microsoft.com/en-us/dotnet/api/system.io.ports.serialport.newline?redirectedfrom=MSDN&view=dotnet-plat-ext-5.0#System_IO_Ports_SerialPort_NewLine
Note that disabling echo from the device is the standard mode for (serial) communication with a device by software (i.e. machine to machine). This simply reduces the amount of data transferred. Echo is only enabled for the convenience of humans.
What is the local echo in my code? Console.ReadLine()?
For Linux, minicom disables local echo by configuring termios flags for stdin (aka the keyboard).
Seems like you're using Windows, so I don't know the equivalent operation.
Yes, the local echo should be occurring during the Console.ReadLine().
Addendum in response to Update Part2
My suggestion for echo cancellation guarantees that only one line of input would be discarded per command sent.
Your modification differs from my suggestion in order to keep all serial port reads within a single procedure/handler.
However that could introduce a synchronization issue, because now you have to ensure that DataReceivedHandler() is performed only once per iteration of the while loop that receives userResponse.
But there seems to be absolutely nothing in that while loop that could enforce any synchronization with DataReceivedHandler().
Prior to this echo cancellation modification, your program really didn't have to rely on any synchronization. Since DataReceivedHandler() simply displayed whatever it received, this data transfer seems flawless, and you weren't concerned about how indata aligned with the text of the response.
To test this synchronization hypothesis, report the line(s) that is/are being discarded for echo cancellation, e.g.
private static void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
string echocancel = sp.ReadLine();
Console.WriteLine($"DEBUG: {echocancel}");
string indata = sp.ReadExisting();
Console.Write(indata);
}
In practice echo cancellation is probably the method of last choice in comparison to simply avoiding the generation of the echo. Some schemes validate the received data prior to discarding (e.g. using a FIFO of expected echo data) to ensure the cancellation is accurate.

sniff serial port - .net

I have this Arduino code just for testing purpose:
int num=0;
void setup() {
Serial.begin(9600);
}
void loop() {
Serial.println(num);
num+=1;
delay(800);
}
Now it prints an integer and increments its value by one. When I open up Serial Monitor it prints as expected every 800ms.
My Arduino is connected on PORT-6
Now if I try to access the port, it says it is in use, I'm trying to access that from a .NET application. How can I do so?
c# code, collected from the internet, modified a little:
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 = "COM6";//Set your board COM
_serialPort.BaudRate = 9600;
_serialPort.Open();
while (true)
{
string a = _serialPort.ReadExisting();
Console.WriteLine(a);
}
}
}
}
How can I sniff data from that serial port ? [Educational Purpose]
You can't open a serial port twice.
If what you want is to get to see what is going through the bus (sniffing), you can use virtual ports and port forwarding, see here for a complete example.
Nothing will stop you from replacing any of the tools discussed in the link with your own code (.NET or other), in case they don't suit your needs or if you have enough determination to reinvent the wheel.

Port does not close

I am using a serial port event handler very similar to the code below. Nothing fancy and it works fine... most of the time. I have been able to induce an error by unplugging the serial port connection, waiting for a bit, then plugging it back in. After I close the application, I have discovered that it is not closing the port so I can't reopen the port. It does not throw an exception when it locks up, it just stops reading. I have to reboot the machine to force it to release the port.
I have some ideas but if anyone can offer some suggestions without shaming me, I would greatly appreciate it. One caveat to this that may be causing a problem is that I am using a third party app to share serial ports. My app must shadow a mission critical app that CANNOT be closed.
using System;
using System.IO.Ports;
class PortDataReceived
{
public static void Main()
{
SerialPort mySerialPort = new SerialPort("COM1");
mySerialPort.BaudRate = 9600;
mySerialPort.Parity = Parity.None;
mySerialPort.StopBits = StopBits.One;
mySerialPort.DataBits = 8;
mySerialPort.Handshake = Handshake.None;
mySerialPort.RtsEnable = true;
mySerialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
mySerialPort.Open();
Console.WriteLine("Press any key to continue...");
Console.WriteLine();
Console.ReadKey();
mySerialPort.Close();
}
private static void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
string indata = sp.ReadExisting();
Console.WriteLine("Data Received:");
Console.Write(indata);
}
}
There are no exceptions thrown or error messages.

C# Application will not Receive Serial Data Stream

I am developing a C# Windows Forms Application to communicate via a Bluetooth Connection with a Raspberry Pi Model 3. This connection is mimicked through a virtual serial port on the client machine. I am able to start a bluetooth connection within the C# program but I cannot receive any data from the program. When I use the program Putty, I can see that the data is transmitting on COM Port the way that I would like it to.
I also discovered a weird sort of glitch with the C# program. If i have the COM Port open on Putty and then start the C# program, an error will occur with the port.open() command since the port is reserved. So then if I close Putty and continue the C# application the data will stream perfectly to the program. Has anyone encountered this issue before? I've been at a bit of a loss for a few days now. The Code in my program is shown below:
using System;
using System.IO.Ports;
using System.IO;
using System.Threading.Tasks;
using System.Windows.Forms;
using InTheHand.Net;
using InTheHand.Net.Sockets;
using InTheHand.Net.Bluetooth;
using System.Threading;
namespace GUIfromPI
{
static class Program
{
//PC BT USB adapter
private static BluetoothEndPoint EP = new BluetoothEndPoint(BluetoothAddress.Parse("##:##:##:##:##:##"), BluetoothService.BluetoothBase); //addressing the usb adapter used on the PC (endpoint)
private static BluetoothClient BC = new BluetoothClient(EP);
//Pi BT Adapter
private static BluetoothDeviceInfo BTDevice = new BluetoothDeviceInfo(BluetoothAddress.Parse("##:##:##:##:##:##")); //addressing the BT adapter on the Rasperry Pi
// private static NetworkStream stream = null;
public static SerialPort mySerialPort = new SerialPort(); //Bluetooth module mimics serial protocol by streaming data through the COM5 port in the host80 computer
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
public static void Main(string[] args)
{
Console.WriteLine("Executing Program...");
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
if (BluetoothSecurity.PairRequest(BTDevice.DeviceAddress, "1234"))//MY_PAIRING_CODE))
{
Console.WriteLine("PairRequest: OK");
if (BTDevice.Authenticated)
{
Console.WriteLine("Authenticated: OK");
BC.SetPin("1234");//pairing code
//BC.BeginConnect(BTDevice.DeviceAddress, BluetoothService.SerialPort, new AsyncCallback(Connect), BTDevice);
}
else
{
Console.WriteLine("Authenticated:No");
}
}
else
{
Console.WriteLine("PairRequest: No");
}
//mySerialPort = new SerialPort("COM5");
SerialThreadFunction();
}
public static void SerialThreadFunction()
{
mySerialPort.PortName = "COM10";
mySerialPort.BaudRate = 9600;
mySerialPort.Parity = Parity.None;
mySerialPort.StopBits = StopBits.One;
mySerialPort.DataBits = 8;
mySerialPort.Handshake = Handshake.None;
mySerialPort.DtrEnable = true;
mySerialPort.RtsEnable = true;
mySerialPort.ReadTimeout = 100000;
mySerialPort.Open();
//mySerialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
string mydata = "hello";
while (true)
{
Console.WriteLine(mySerialPort.ReadLine());
mydata = mySerialPort.ReadLine();
}
mySerialPort.Close();
}
private static void DataReceivedHandler(
object sender,
SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
string indata = sp.ReadExisting();
Console.WriteLine("Data Received: ");
Console.Write(indata);
}
}
}
UPDATE: I just discovered that declaring my Bluetooth Endpoint, client, and device are interfering with reading off of my serial port. Since the bluetooth connection was already initialized previously, I was able to see the data on the port. Now for why it does this?
Okay, it seems you are not doing anything wrong. Inherently .NET cannot handle multiple ownership of the same port. When you declare your SerialPort instance and connect to say... COM11... You have given ownership of COM11 solely to your SerialPort instance. In order to have access to COM11 you will now need to provide a reference to that specific SerialPort object which has ownership of COM11.
In your case you are opening PuTTY and then running your program. Once PuTTY obtains access to the port, your program will not be able to do so. This is completely standard in the .NET framework. Now, there are other ways that you can get multiple accesses to a COM port, but I think that's outside the scope of this question. Here's a software that will allow you to run an application and sniff traffic over the port at the same time... Free Serial Port Monitor. You can get this for free, and there is a better version for purchase that does all kinds of magic.
Here is a little algorithm for ensuring your port is opened properly, you may want to take this... modify it a little bit... and use it as the Connect method on your BluetoothClient class.
SerialPort port = null;
string error = string.Empty;
bool success = false;
int tries = 5;
foreach(var name in System.IO.Ports.SerialPort.GetPortNames())
{
// try each port until you find an open one
port.Name = name;
// there is always a chance that the port is open
// if trying some operations back-to-back
// give it a few extra tries if necessary
for (int i = tries; i > 0; --i)
{
try
{
// avoid the exception by testing if open first
if (!port.IsOpen)
{
port.Open();
success = true;
return;
}
}
catch (UnauthorizedAccessException e)
{
// sometimes the exception happens anyway, especially
// if you have multiple threads/processes banging on the
// ports
error += e.Message;
}
}
}
In addition to all of this, you may want to watch that your Bluetooth classes are not claiming ownership of the port when you need to read it. That may be what's interfering with reading the port. You really should create one single class and call it say BluetoothClient or something, and have that single class be responsible for all the interactions with the SerialPort reference. This way you ensure that whether you want to send/receive on the port you will always have ownership.

Serial port c# how to interpret data received

When i read the serial port using c# in a console application, this is the output i get.
Does anyone know how i should read this data so it's readable by a human.
The data that should be received is like : 6025 1045 1806 116 0000000 and GPS coördinates.
I know its a bit vague, but i am new to serial port programming and would like to know how to move on.This is the code i have so far:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO.Ports;
using System.Diagnostics;
using System.Threading;
using System.IO;
namespace ClarityListener
{
class Program
{
static void Main(string[] args)
{
ClarityWarning("Starting communication...");
SerialPort Dave = new SerialPort("COM1");
Dave.BaudRate = 9600;
Dave.Parity = Parity.Odd;
Dave.DataBits = 8;
Dave.StopBits = StopBits.One;
Dave.Handshake = Handshake.None;
Dave.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
try
{
Dave.Open();
ClarityMssg("Connected!\n");
}
catch
{
ClarityError("Problem!\n");
}
ClarityWarning("Press any key to shutdown program");
Console.WriteLine();
Console.ReadKey();
Dave.Close();
}
private static void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
string indata = sp.ReadExisting();
ClarityWarning("Data received : ");
ClarityWarning(indata.ToString() + "\n");
}
private static void ClarityMssg(string message)
{
Console.ForegroundColor = ConsoleColor.Blue;
Console.WriteLine(message);
Console.ForegroundColor = ConsoleColor.White;
}
private static void ClarityError(string message)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(message);
Console.ForegroundColor = ConsoleColor.White;
}
private static void ClarityWarning(string message)
{
Console.ForegroundColor = ConsoleColor.DarkYellow;
Console.WriteLine(message);
Console.ForegroundColor = ConsoleColor.White;
}
}
}
Data received over a channel is a stream of bytes, being it over tcp/ip or serial or read from a file. Programming against a serial port is not that different/difficult as there is no hitech black magic involved.
Just dumping the received bytes to the console assuming that it is ascii is not the way to go. Although it can give you a head-start in determining what's send.
First check the parameters set on the receiving serial-port. Most devices are using 9600 baud, no parity, 8, 1 stopbit. If there is a mismatch data gets mangled. Check the specs from the manual of the device.
Do you know in what format the data is send? Are numbers converted to ascii literals before sending or are they send as int32 in 4 bytes?
What is the flow control of the source?
Are there control/command bytes in or between the messages?
In short: know the protocol used by the sender. Check the documentation and as a last resort call the vendor / distributor.
First things that come to mind :
make sure the parity, stop bits and baud rate of your serial port reader are configured to match the requirements of the device sending the data.
Also make sure your serial device is indeed sending ASCII encoded text.
(this is the standard for NMEA, a protocol mostly used for devices like this, but there is no guarantee your device adheres the the standard 100%)

Categories