saving and editing serial data c# - c#

For our school project we have to write a code in c# to read and visualize serial data from a weather station.
The code that I have now:
public partial class MainWindow : Window
{
private SerialPort port;
DispatcherTimer timer = new DispatcherTimer();
private string buff;
public MainWindow()
{
InitializeComponent();
}
private void btnPort_Click(object sender, RoutedEventArgs e)
{
timer.Tick += timer_Tick;
timer.Interval = new TimeSpan(0, 0, 0, 0, 500);
timer.Start();
try
{
port = new SerialPort(); // Create a new SerialPort object with default settings.
port.PortName = "COM4";
port.BaudRate = 115200; // Opent de seriele poort, zet data snelheid op 9600 bps.
port.StopBits = StopBits.One; // One Stop bit is used. Stop bits separate each unit of data on an asynchronous serial connection. They are also sent continuously when no data is available for transmission.
port.Parity = Parity.None; // No parity check occurs.
port.DataReceived += Port_DataReceived;
port.Open(); // Opens a new serial port connection.
buff = "";
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void Port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
byte[] buffer = new byte[128];
int len = port.Read(buffer, 0, buffer.Length); // .Read --> Reads a number of characters from the SerialPort input buffer and writes them into an array of characters at a given offset.
if (len > 0)
{
string str = "";
for (int i = 0; i < len; i++)
{
if (buffer[i] != 0)
{
str = str + ((char)buffer[i]).ToString();
}
}
buff += str;
}
// throw new NotImplementedException();
}
private void timer_Tick(object sender, EventArgs e)
{
try
{
if (buff != "")
{
textSerial.Text += buff;
buff = "";
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
This code has the following output:
Humidity: 33 %
Temperature: 25.7 deg C
Visible light: 112 lx
Infrared radiation: 1802.5 mW/m2
UV index: 0.12
CO2: 404 ppm CO2
Pressure: 102126 Pa
I have to store all the numbers in variables because I need to use them in my GUI.
To get all the numbers from the output :
public string[] convertNumbers(string inp)
{
string pattern = "[+-] ?\\b\\d + (\\.\\d +)?\\b";
Regex rgx = new Regex(pattern);
string input = inp;
string[] result = rgx.Split(input, 3);
return result;
}
The regex expression works fine and gives me the exact numbers.
I would like to save them into an array with 7 doubles.
What is the most efficient way to transfer the serial output into variables ?
Can somebody help me out ?

Related

How to have link speed and transfer percentage when sending data to serial-port?

I was developing .Net Console app to communicate with firmware on SAS Expander card.
When I updated the firmware, the Tera Term's page would show :
You can see [4.09KB/S] is the link speed and 71.6% is the transfer percentage.
Here comes a question:
How to have link speed and transfer percentange on my console app?
The link speed and transfer percentage would keep changing the numbers until the data was fully received by card.
I have already added XmodemProtocol library on my console app.
Here is my code:
using XModemProtocol;
using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Windows.Forms;
using System.IO;
using System.Threading;
namespace XModemProtocolExample
{
class Program
{
[STAThread]
static void Main()
{
string[] ports = SerialPort.GetPortNames();
string com = "";
Console.WriteLine("The following serial ports were found:");
foreach (string port in ports)
{
Console.WriteLine(port);
Console.WriteLine("Please choose which port name you want ?");
com = Console.ReadLine();
Console.Clear();
}
SerialPort mySerialPort = new SerialPort(com);
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 = 1500;
mySerialPort.NewLine = "\r";
mySerialPort.Open();
if (mySerialPort.IsOpen)
{
mySerialPort.Write("\r");
}
List<string> Commands = new List<string>();
string command = "";
int counter = 0;
mySerialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
while (true)
{
ConsoleKeyInfo consoleInput = Console.ReadKey();
if (consoleInput.KeyChar == '\r')
{
Commands.Add(command);
counter = Commands.Count - 1;
mySerialPort.Write(command + "\r");
if (command == "fwdl")
{
ClearCurrentConsoleLine();
}
if (command == "y")
{
String FileName = "";
OpenFileDialog openfile1 = new OpenFileDialog();
if (openfile1.ShowDialog() == DialogResult.OK)
{
FileName = openfile1.FileName;
}
if (FileName == "")
{
Console.ReadLine();
}
else
{
var xmodem = new XModemCommunicator();
mySerialPort.Close();
var port = new SerialPort
{
BaudRate = 115200,
DataBits = 8,
Parity = Parity.None,
StopBits = StopBits.One,
Handshake = Handshake.None,
PortName = com,
RtsEnable = true,
DtrEnable = true,
NewLine = "\r",
};
xmodem.Port = port;
xmodem.Data = File.ReadAllBytes(FileName);
xmodem.Completed += (s, e) =>
{
port.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler2);
port.Write("\r");
};
xmodem.Aborted += (s, e) =>
{
Console.WriteLine("Operation Aborted.\nPress enter to exit.");
};
xmodem.StateUpdated += (s, e) =>
{
Console.WriteLine(xmodem.State);
};
port.Open();
// Send Data.
xmodem.Send();
if (xmodem.State != XModemStates.Idle)
{
xmodem.CancelOperation();
Console.ReadLine();
}
Thread.Sleep(10000);
port.Close();
if (!port.IsOpen)
{
mySerialPort.Open();
}
}
}
if (command == "mfgdl")
{
ClearCurrentConsoleLine();
}
ClearCurrentConsoleLine();
command = "";
}
else if (consoleInput.Key == ConsoleKey.UpArrow)
{
if ((counter >= 0) && (counter < Commands.Count))
{
ClearCurrentConsoleLine();
Console.Write(Commands[counter]);
foreach (string obj in Commands)
{
command = obj;
}
if (consoleInput.KeyChar == '\r')
{
Commands.Add(command);
counter = Commands.Count - 1;
mySerialPort.Write(command + "\r");
ClearCurrentConsoleLine();
command = "";
}
}
if (counter > 0)
{
counter--;
}
else
{
counter = Commands.Count - 1;
}
}
else
{
command += consoleInput.KeyChar.ToString();
}
}
}
private static void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
string indata = sp.ReadExisting();
Console.Write(indata);
}
private static void DataReceivedHandler2(object sender, SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
string indata = sp.ReadExisting();
Console.Write(indata);
}
private static void ClearCurrentConsoleLine()
{
int currentLineCursor = Console.CursorTop;
Console.SetCursorPosition(6, Console.CursorTop);
Console.Write(new string(' ', Console.WindowWidth));
Console.SetCursorPosition(6, currentLineCursor);
}
}
}
What my console shows:
I could only know the xmodem's state.
I have no idea about how to build a link speed and transfer percentage.
Could XmodemProtocol do this thing? If so, how to do that?
My Console app is using .Net Framework 4.7.2.
Received xxxxxxxx Bytes is the response from the card.
It could only come out after the data fully sent to the card(100%).
.................................................
Update1:
After adding
xmodem.PacketToSend += (s, e) =>
{
Console.WriteLine(e.PacketToSend.Count);
};
The console shows like:
..............................................
Update2:
After I deleted
xmodem.PacketToSend += (s, e) =>
{
Console.WriteLine(e.PacketToSend.Count);
};
, I replaced it with
xmodem.PacketReceived += (s, e) =>
{
Console.WriteLine(e.PacketReceived.Count);
};
The console's result :
Why PacketReceived event won't fire?
I guess you would like to be able to display something like this:
...
SenderPacketsBeginSent
PendingCompletion
Idle
Link speed: 4.09KB/s
Transfer percentage: 34%
Where the link speed and transfer percentage is updated in place on your console?
You can move your screen cursor using Console.SetCursorPosition(x, y); (https://learn.microsoft.com/en-us/dotnet/api/system.console.setcursorposition?view=net-5.0) to move the output to the two different locations where you want to display your metrics.
The transfer completion calculation you'll need to do yourself. But that's pretty straightforward:
percentage = (total bytes transferred / file size) x 100.
So your program flow will go something like this:
in your while loop when you transfer the data you,
move your screen cursor to where you want to output the 'link speed' then Console.Write your current measured speed.
move your screen cursor to where you want to output the 'transfer percentage' then Console.Write your current calculated percentage.

I want to read from a serial port an int from a potentiometer, but it keeps showing me (4⸮⸮⸮⸮j⸮/⸮.)

So I am sending from an Arduino Uno an int from potentiometer(0 - 1023) and when I am reading it and print it in a label, there are no numbers.And I read somewhere that I need to read the bytes, how I am going to do that?
namespace Receiver
{
public partial class Form1 : Form
{
SerialPort port;
UITimer _timer = new UITimer();
public Form1()
{
InitializeComponent();
if (port == null)
{
port = new SerialPort("COM11", 9600);//Set your board COM
port.Open();
}
}
private void Form1_Load(object sender, EventArgs e)
{
_timer.Interval = 200;
_timer.Tick += _timer_Tick;
_timer.Enabled = true;
_timer.Start();
}
private void _timer_Tick(object sender, EventArgs e)
{
string a = port.ReadExisting();
afisare.Text = a;
}
void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
_timer.Stop();
if (port != null && port.IsOpen)
{
port.Close();
}
}
}
}
First, make sure that you are using the correct Baud rate for your serial communication or otherwise you will receive unreadable data.
Your code is only missing a correct interpretation of the incoming data. On top of that I would recommend removing the timer and using the built-in DataReceived event. That means you can delete all your timer related code and add an event handler to your SerialPort initialization:
if (port == null)
{
port = new SerialPort("COM11", 9600); //Set your board COM
port.DataReceived += DataReceivedEvent;
port.Open();
}
Then you of course have to declare your DataReceivedEvent handler. Since you said that your potentiometer can contain values ranging from 0-1023 and you didn't provide your Arduino code, I'm assuming that that's the only thing being send over the port.
This would mean you are sending 2 bytes every cycle which need to be parsed back to an integer.
This works by performing a left shift of your two received bytes.
private void DataReceivedEvent(object sender, SerialDataReceivedEventArgs e)
{
SerialPort senderPort = (SerialPort)sender;
byte[] buffer = new byte[2];
if (senderPort.Read(buffer, 0, 2) != 0)
{
int data = (int)buffer[0] << 8 | buffer[1];
Console.WriteLine("Received data: {0}", data);
}
}
If you want to use div's Answer on the C# side, you have to send those two bytes as well.
That gives you a bit more precision than in your comment (dividing by 4 and multiply by 4.015 --why??--)
Using the corresponding shift operation:
void loop() {
int a= analogRead(A0);
Serial.write(a>>8);
Serial.write(a & 0xFF);
delay(200);
}
You must be sure that you use the c# DataReceivedEvent trigger, when both bytes are available:
https://learn.microsoft.com/de-de/dotnet/api/system.io.ports.serialport.bytestoread

Setting timeout to check data is received from serial port in c#

I am receiving latitude and longitude value from GPS device connected to my pc. I need to set timeinterval
such that after 500 milliseconds if i don't receive data from port i need to print some text. I don't know
how to do this can someone please help me how to solve this problem. I have also uploaded my code.
class PortDataReceived
{
private static SerialPort mySerialPort;
public static void Main()
{
mySerialPort = new SerialPort("COM5");
mySerialPort.BaudRate = 9600;
mySerialPort.Parity = Parity.None;
mySerialPort.StopBits = StopBits.One;
mySerialPort.DataBits = 8;
mySerialPort.Handshake = Handshake.None;
mySerialPort.RtsEnable = true;
//mySerialPort.ReadTimeout = 500;
mySerialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
mySerialPort.Open();
Console.WriteLine();
Console.ReadKey();
mySerialPort.Close();
}
private static void DataReceivedHandler(
object sender,
SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
string indata = sp.ReadExisting();
////////////////////////////////////
//System.Threading.Thread.Sleep(1000);
//Console.WriteLine("NAN");
/* Timer tmr = new System.Timers.Timer();
tmr.Interval = 500;
tmr.Elapsed += OnTimedEvent;
tmr.AutoReset = true;
// Start the timer
tmr.Enabled = true
private static void OnTimedEvent(Object source, System.Timers.ElapsedEventArgs e)
{
if(indata == null)
* {
* Console.WriteLine("NAN");
* }
}*/
////////////////////////////////////
{
string pattern = #"^\$GNGGA,[^,]+,(\d{2})(\d{2}\.\d+),([NS]),(\d{3})(\d{2}\.\d+),([EW]),.+$";
System.Text.RegularExpressions.MatchCollection matches = System.Text.RegularExpressions.Regex.Matches(indata, pattern);
if (matches.Count > 0)
{
foreach (System.Text.RegularExpressions.Match match in matches)
{
double Lat = Double.Parse(match.Groups[1].Value, System.Globalization.CultureInfo.InvariantCulture);
Lat += Double.Parse(match.Groups[2].Value, System.Globalization.CultureInfo.InvariantCulture) / 60;
Lat *= match.Groups[3].Value == "N" ? 1 : -1;
double Lng = Double.Parse(match.Groups[4].Value, System.Globalization.CultureInfo.InvariantCulture);
Lng += Double.Parse(match.Groups[5].Value, System.Globalization.CultureInfo.InvariantCulture) / 60;
Lng *= match.Groups[6].Value == "E" ? 1 : -1;
string output = "{Lat: " + Lat.ToString(System.Globalization.CultureInfo.InvariantCulture);
output += ", Lng: " + Lng.ToString(System.Globalization.CultureInfo.InvariantCulture) + "}";
Console.WriteLine(output);
}
}
//mySerialPort.DataReceived -= new SerialDataReceivedEventHandler(DataReceivedHandler);
}
}
}
You can use a synchronization object, for example ManualResetEvent to check whether data has been received within 500 milliseconds.
Declare:
class PortDataReceived
{
// Create an event which is not signaled
ManualResetEvent DataReceivedEvent = new ManualResetEvent(false);
...
}
private static void DataReceivedHandler(
object sender,
SerialDataReceivedEventArgs e)
{
// Set the event object to signaled state as soon as data is received
DataReceivedEvent.Set();
...
}
Then in your Main function you can do:
public static void Main()
{
...
mySerialPort.Open();
TimeSpan waitTime = TimeSpan.FromMilliseconds(500);
if(DataReceivedEvent.WaitOne(waitTime) == false)
{
// Failure: Data has not been received within waitTime
// Print text
}
else
{
// Success: Data has been received within waitTime
// Do work
}
...
}
Make another class to handle incoming data
In that class start a timer, stop the timer when the incoming data is a complete gps message.
you can make a public method to start the timer depending what the trigger is for the start so
_gps.Start()
then in your serial just call
_gps.Interpret(indata)
as an asside, make a class for lat long. make a class for translating your gps strings to cooridinates
so interpret will be something like
public void Interpret(string s)
{
var extra = _packet.Consume(s); // extra is if s has more than the data you are expecting
if(_packet.Complete)
{
var location = packet.ToLocation()
}
}

c# Serial DataReceived very slow

I've trying to communicate with an Arduino Due in C#. The communikation works quite well, but my DataReceived handler needs about 1 second to react. This is my problem because I have to send up to 1 billion (1*10E9) commands.
If I activate a DEBUG Setting in the Arduino, it tells me that it's need 64 Milliseconds for a command. I think the C# the App should get it no later than 80 Milliseconds after sending it.
Here is a Part of the Code:
StopWatch s1 = new StopWatch();
private void Open_Port()
{
string port = null;
int baud = 0;
bool ERR = false;
if ((COM_cb.SelectedItem != null) | (BAUD_cb.SelectedItem != null))
{
port = this.COM_cb.GetItemText(this.COM_cb.SelectedItem);
baud = Convert.ToInt32(this.BAUD_cb.GetItemText(this.BAUD_cb.SelectedItem));
ERR = false;
}
else
{
ERR = true;
System.Windows.Forms.MessageBox.Show("Error Msg");
}
if (ERR == false)
{
serialPort1.PortName = port;
serialPort1.BaudRate = baud;
serialPort1.Open();
}
if (serialPort1.IsOpen)//Kalibrieren der Buttons
{
OPEN_btn.Enabled = false;
CLOSE_btn.Enabled = true;
textBox1.ReadOnly = false;
ERR = true;
}
}
private void Print_Click(object sender, EventArgs e) // start
{
Thread t = new Thread(transmit_pic);
t.Start();
}
private void DataReceivedHandler(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
s1.Stop();
//Till this line it take 1 Second after sending
//string t = "";
int byt = serialPort1.BytesToRead;
byte[] buffer = new byte[1];
for (int i = 0; i < byt; i++)
{
serialPort1.Read(buffer, 0, 1);
if(buffer[0] == '0') {
got_answer = true;
}
//t += (char)buffer[0];
}
//RxString= t;
//this.Invoke(new EventHandler(DisplayText));
}
private void sendAktion(int[,] data)
{
string s = int_to_string(data, false);
Console.Write("Send->");
serialPort1.Write(s);
s1.Start();
got_answer = false;
int i = 0;
while (!got_answer) { i++; } //wait for answer
i = 0;
Console.WriteLine("back again ");
}
private void transmit_pic()
{
stop = false;
Bitmap bm = new Bitmap(img);
if (!serialPort1.IsOpen)
{
MessageBox.Show("Open the Serial Port first!");
}
else
{
int size_X = bm.Width;
int size_Y = bm.Height;
for (int h = 0; h < size_Y; h++)
{
for (int w = 0; w < size_X; w++)
{
if(/*somthing happend*/){
//get data...
sendAktion(data)
}
}
}
Console.WriteLine("DONE");
}
}
Does anyone an Idea why c# needs so long to call the datahandler?
Sincere regards,
Fabian Harmsen
UPDATE
- Added comment to DataHandler (24.02.2016 16:30 Europa/Berlin)
The problem lies in the serialPort1_DataReceived received data handler.
I ran a separate thread with a while(true) loop and serial.ReadLine(), all works perfectly.
Hope someone else doesn't need to spend 3 hours fixing this.
using System.Threading;
public void main()
{
setup();
Thread readThread = new Thread(Read);
readThread.Start();
}
public void Read()
{
while(true)
{
try
{
string message = serialPort1.ReadLine();
}
catch (Exception)
{ }
}

Handling large data received on serial port

I am receiving data on serial port 250 packets per second where each packet is of size 23 bytes. I am using following code handling the data received on serial port.
private SerialPort connectComPort = new SerialPort();
List<byte> receivedBytes1 = new List<byte>();
public Form1()
{
InitializeComponent();
connectComPort.DataReceived += new SerialDataReceivedEventHandler(receiveData);
//Background worker for parsing packet
m_oWorker = new BackgroundWorker();
m_oWorker.DoWork += new DoWorkEventHandler(m_oWorker_DoWork);
m_oWorker.ProgressChanged += new ProgressChangedEventHandler(m_oWorker_ProgressChanged);
m_oWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(m_oWorker_RunWorkerCompleted);
m_oWorker.WorkerReportsProgress = true;
m_oWorker.WorkerSupportsCancellation = true;
}
private void buttton_Click(object sender, EventArgs e)
{
m_oWorker.RunWorkerAsync();
}
void m_oWorker_DoWork(object sender, DoWorkEventArgs e)
{
modprocessReceivedBuffer();
m_oWorker.ReportProgress(100);
}
private void receiveData(object sender, SerialDataReceivedEventArgs e)
{
while (connectComPort.BytesToRead > 0)
receivedBytes1.Add((byte)connectComPort.ReadByte());
}
private void modprocessReceivedBuffer()
{
while (1 == 1)
{
if (receivedBytes1.Count() != 0)
{
var tiff = receivedBytes1.GetRange(0, (int)receivedBytes1[4]).ToList<byte>();
receivedBytes1.RemoveRange(0, (int)receivedBytes1[4]);
modifiedProcess(tiff);
}
else
{
Thread.Sleep(100);
}
}
}
Thus I am just queuing the data received on serial port in a list and I am running a process on background thread whose job is to parse packet. My question is their any better method than this to handle such large data. Currently its 250 packets/sec but this rate can be increased to 16000 packets/sec.
This (VB converted to C#) is what I would do. This will eliminate the issue you were going to eventually have with two threads accessing the list. I also changed the code to read all the bytes at once. There are comments in the code that point at areas to be addressed.
System.Threading.AutoResetEvent dataRcvd = new System.Threading.AutoResetEvent(false);
private void receiveData(object sender, SerialDataReceivedEventArgs e)
{
dataRcvd.Set();
}
private void modprocessReceivedBuffer()
{
while (1 == 1) {
dataRcvd.WaitOne();
while (connectComPort.BytesToRead > 0) {
byte[] buf = new byte[connectComPort.BytesToRead];
int bytsRead = connectComPort.Read(buf, 0, buf.Length);
if (buf.Length != bytsRead) {
Array.Resize(ref buf, bytsRead);
}
//what if there is more than one message in receivedBytes1
if (receivedBytes1.Count() != 0) {
//I think a check is needed for enoung bytes in receivedBytes1????????
var tiff = receivedBytes1.GetRange(0, Convert.ToInt32(receivedBytes1(4))).ToList<byte>();
receivedBytes1.RemoveRange(0, Convert.ToInt32(receivedBytes1(4)));
modifiedProcess(tiff);
}
}
}
}

Categories