How to access serial port data from different methods - c#

I am currently working on a robotics project with Arduino. I want to access the serial port from different methods at different times.
For instance, I want to read the ADC at time t1 and get the motor currents at time t2. So I create readADC() and motorCurrents() methods which should both return int arrays of different sizes. The serial port data received is given below.
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
int n = serialPort1.BytesToRead;
serialPort1.Read(data, 0, data.Length);
}
I have implemented all the relevant coding on the Arduino side. I also have set the serial port. I need to implement the following commands in C#
private int[] ReadADC()
{
string input = "AN\n"; // This is the command for reading the ADC on the Wildthumper board.
serialPort1.Write(input);
// The Wildthumper now sends 11 bytes, the last of which is '*' and the first
// 10 bytes are the data that I want. I need to combine two bytes together
// from data received and make five values and return it.
for (int i = 0; i < 5; i++)
{
adcValues[i] = data[0 + i * 2] <<8+ data[1 + i * 2];
}
return adcValues;
// Where data is the bytes received on serial port;
}
Similarly:
private int[] getMotorCurrents()
{
string input = "MC\n"; // Wildthumper board command
serialPort1.Write(input);
// The Wildthumper now sends 5 bytes with the last one being '*'.
// And the first four bytes are the data that I want.
for (int i = 0; i < 2; i++)
{
MotorCurrents[i] = data[0 + i * 2] <<8 +data[1 + i * 2];
}
return MotorCurrents;
}
First of all, the number of bytes sent to me change. So how can I use a global variable? For data (the variable used to store serial data received as given above)?

You need to create a global variable and save the data to it when data received fires. This isn't hard.
Here is a code example:
public class myclass{
public string arduinoData = "";
private void serialPort1_DataReceived(
object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
this.arduinoData = serialPort1.ReadLine(data, 0, data.Length);
}
//....The rest of your code, such as main methods, etc...
}

Related

Serial Communication - Sending Hex Data via Modbus

I am new to using Modbus Communication, and I found some other related threads here but unfortunately, it was for other languages or using TCP rather than RTU connection for Modbus.
So I have this segment of C# code that I can use to send data:
byte address = Convert.ToByte(txtSlaveID.Text);
ushort start = Convert.ToUInt16(txtWriteRegister.Text);
short[] value = new short[1];
if(Int16.TryParse(txtWriteValue.Text, out short numberValue))
{
value[0] = numberValue; //This part works!
}
else
{
value = new short[3] { 0x52, 0x4E, 0x56 }; //This is where I am trying to send letters/ASCII
}
try
{
mb.SendFc16(address, start, (ushort)value.Length, value);
}
catch (Exception err)
{
WriteLog("Error in write function: " + err.Message);
}
WriteLog(mb.modbusStatus);
So when I want to send down a single value, this code works. It will take the short array and dow the following to build the packet:
//Put write values into message prior to sending:
for (int i = 0; i < registers; i++)
{
message[7 + 2 * i] = (byte)(values[i] >> 8);
message[8 + 2 * i] = (byte)(values[i]);
}
So as you can see I attempted to use the hex values in the array, and send them down to the registers.
How can I modify the first sample of code to be able to send down HEX values, and write out characters into the register space in the first image?
I think you are not able to write the character at the device's register.
You need not to store the hex values into the short array. Simply store the characters into array, before writing them into the register convert them into byte.
Note - Whatever data will be written into the devices register, should be in byte.

Reading data from RadioLink R12DS receiver by S-BUS protocol

My goal is pretty simple: I wanna read information from my RadioLink R12DS receiver by S-BUS protocol using desktop console application, written on C#.
I use AT9S transmitter blinded together with receiver in 12 channel mode. I tested it on Pixhawk flight controller. Everything was fine there, no any problem with retrieving data.
I designed a console application based on investigated articles. Here is a couple most valuable of them:
http://forum.fpv.kz/topic/303-frsky-x8r-sbus-v-cppm-konverter-na-arduino/ https://github.com/bolderflight/SBUS
My application receiving byte stream from a COM Port, one by one, and tries catch message header "0x0F", but it doesn't appear.
The SBUS protocol uses inverted serial logic with a baud rate of 100000, 8 data bits, even parity bit, and 2 stop bits. The SBUS packet is 25 bytes long consisting of:
Byte[0]: SBUS Header, 0x0F
Byte[1-22]: 16 servo channels, 11 bits per servo channel
Byte[23]:
Bit 7: digital channel 17 (0x80)
Bit 6: digital channel 18 (0x40)
Bit 5: frame lost (0x20)
Bit 4: failsafe activated (0x10)
Bit 0 - 3: n/a
Byte[24]: SBUS End Byte, 0x00
A table mapping bytes[1-22] to servo channels is included.
Here is listing of my code:
static void Main(String[] args)
{
var availablePorts = SerialPort.GetPortNames();
using(var port = new SerialPort(availablePorts[0], 100000, Parity.Even, 8, StopBits.Two))
{
port.DataReceived += PortOnDataReceived;
while(true)
{
if(!port.IsOpen)
TryReconnect(port);
Thread.Sleep(1000);
}
}
}
// HANDLERS ///////////////////////////////////////////////////////////////////////////////
private static void PortOnDataReceived(Object sender, SerialDataReceivedEventArgs serialDataReceivedEventArgs)
{
var serialPort = (SerialPort)sender;
if(SbusConverter.TryReadMessage(serialPort, out var messageBuffer))
{
var message = SbusConverter.Convert(messageBuffer);
Console.WriteLine(message.ServoChannels[0]);
}
}
public static Boolean TryReadMessage(SerialPort serialPort, out Byte[] messageBuffer)
{
const Int32 messageLength = 25;
const Int32 endOfStream = -1;
const Byte sBusMessageHeader = 0x0f;
const Byte sBusMessageEndByte = 0x00;
messageBuffer = new Byte[messageLength];
if(serialPort.BytesToRead < messageLength)
return false;
do
{
var value = serialPort.ReadByte();
if(value == endOfStream)
return false;
if(value == sBusMessageHeader)
{
messageBuffer[0] = (Byte)value;
for(var i = 1; i < messageLength; i++)
{
messageBuffer[i] = (Byte)serialPort.ReadByte();
}
if(messageBuffer[0] == sBusMessageHeader &&
messageBuffer[24] == sBusMessageEndByte)
return true;
}
} while(serialPort.BytesToRead > 0);
return false;
}
I have thoughts in my head and I want ask one question here.
It's possible, that RadioLink use different, modified or their own S-BUS implementation, than Futaba and I found no proper documentation yet.
Anybody, who experienced in that field, any suggestions please. It seems, I am stuck.
Thank you!
I made some investigations of received data stream and uncovered that RadioLink devices uses "0x1F" as a frame start byte insted of "0x0F". Another connection and message properties are the same.
var availablePorts = SerialPort.GetPortNames();
using(var port = new SerialPort(availablePorts[0], 100000, Parity.None, 8, StopBits.One)
{
Handshake = Handshake.None
})
{
port.DataReceived += PortOnDataReceived;
while(true)
{
if(!port.IsOpen)
OpenPort(port);
Thread.Sleep(1000);
}
}
Two years too late, but I just noticed you have 1 stop bit set, instead of 2, in the code of your answer. That could probably explain 0x1F instead 0x0F and otherwise shifted data.
I am trying to do the same kind of operation, intercepting Sbus signal from a herelink radio controller, so far I discovered a shift in the data and my start byte is recognised with the value of 0x1E. Moreover the data seems super noisy when looked at the oscilloscope, some 1 might be missing because of the poor quality of the signal and the ramp from 0 to 1.

C# Handle Received data of Multiple TCP clients on TCP Server by displaying them into Datagrid

I have developed a C# based TCP server GUI application which is accepting data from multiple TCP clients.
The data i am receiving from TCP clients is a 32 bit data. In my application multiple TCP client data goes like this:
00012331100025123000124510321562 (from 1 client)
01112563110002512456012451032125 and so on...
Now i want those data of the TCP clients to be parsed into 4 bits first and display it in 8 columns (32/4=8) of (say) datagrid as each 4 bit represents some characteristics of the TCP client. The same thing should work for next TCP client on second row of datagrid.
Can you give me some suggestion or an example how to go about this? Any help would be appreciated. Thank you in advance.
Here is my code for receiving data from multiple TCP clients.
void m_Terminal_MessageRecived(Socket socket, byte[] buffer)
{
string message = ConvertBytesToString(buffer, buffer.Length);
PublishMessage(listMessages, string.Format("Sockets: {0}", message));
// Send Echo
// m_ServerTerminal.DistributeMessage(buffer);
}
private string ConvertBytesToString(byte[] bytes, int iRx)
{
char[] chars = new char[iRx + 1];
System.Text.Decoder d = System.Text.Encoding.UTF8.GetDecoder();
d.GetChars(bytes, 0, iRx, chars, 0);
string szData = new string(chars);
return szData;
}
If you do not have a data grid with columns defined,first add the columns
for (int iIndex = 1; iIndex <= 8; iIndex++)
{
DataColumn col = new DataGridTextColumn();
col.Header = iIndex;
col.Binding = new Binding(iIndex);
YourDatagrid.Columns.Add(col);
}
Then after your get back the message, split the message string into 8 strings of length 4 each,create a DataItem and add it to the datagrid
YourDataGrid.Items.Add(new DataItem
{ 1 = message.SubString(0,4)},
{ 2 = message.SubString(4,4)},
.
.
.
{ 8 = message.SubString(28,4)}
);

C# Serialport not receiving all the bytes in a single transmission

I'm using the following code to receive hex data over the serial port, it seems that some of these transmissions are broken up into 2 lines when they are parts of the same transmission. How do I make sure that each transmission is received properly?
public void Receiver(object sender, SerialDataReceivedEventArgs e)
{
string data;
do
{
data = COMPort.ReadExisting();
} while (COMPort.BytesToRead != 0);
RxARR = data.ToCharArray().ToList();
Dispatcher.Invoke(new MethodInvoker(Display)); // Start "Display" on the UI thread
}
You should never assume that data from a serial port is provided to you in one go (the same is true for network communication by the way). You need to make sure that your code accepts a message only if you have received everything.
Everything is hard to define. This can either be all characters until a defined termination sequence (for example \r\n or EOL byte) or until a fixed number of bytes is read. Generally one can say, as every message can be fragmented, reliable communcation is not possible without a defined end of message signal.
What we do is:
Create a StringBuilder
Read everything into that StringBuilder
Search for termination sequence
Remove everything from the StringBuilder up to and including the termination sequence
Process that chunk of data
Repeat from 3 until termination sequence is not found
Keep the remaining characters in StringBuilder, as this is the start of a new message
Pseudo code:
private StringBuilder serialBuffer = new StringBuilder();
private string terminationSequence = "\r\n"; // Anything that can't be part of a message
public void Receiver(object sender, SerialDataReceivedEventArgs e)
{
string data = COMPort.ReadExisting();
serialBuffer.Append(data);
string bufferString = serialBuffer.ToString();
int index = -1;
do
{
index = bufferString.IndexOf(terminationSequence);
if (index > -1)
{
string message = bufferString.Substring(0, index);
bufferString = bufferString.Remove(0, index + terminationSequence.Length);
HandleMessage(message);
}
}
while (index > -1)
serialBuffer = new StringBuilder(bufferString);
}
By the way: Looping within your DataReceived event is not desired, as this event is called by the SerialPort whenever something new is ready to be read. Reading in a loop may interfere with what SerialPort is doing by default. So: Don't read in a loop within that event! The "loop" is the event being fired in sequence by SerialPort.
I Had almost the same situation.
Like Thorsten said the data sometimes does not come at once..
Maybe because of Hardware or BaundRate..
What really works for me was:
var end = '\r';
int dataLength = _serialPort.BytesToRead;
byte[] data = new byte[dataLength];
int nbrDataRead = _serialPort.Read(data, 0, dataLength);
RxString = Encoding.ASCII.GetString(data);
txtCod.AppendText(RxString);
if (RxString.IndexOf((char)end) > -1)
{
this.Invoke(new EventHandler(Final));
}

C#-Arduino Communication Mismatch?

I'm trying to write a program in C# to communicate with my Arduino UNO from my computer via a serial connection. At the moment I'm just writing a simple application that establishes contact with the Arduino, and then with several controls to control each pin on the arduino; either read a value from it or write a value to it.
I've managed to establish contact with the Arduino and to set pin-values, but it doesn't always want to obey my commands. I set up a few check boxes, and when I check a box, an LED should turn on, and off when I un-check it. The problem is that sometimes the LED's just stay on or off and I have to click the box a few times before it responds again, or reset my circuit...
I was trying to do some fault-finding, but couldn't get to the root of the problem: is it my app or is it the Arduino code?
Here are the relevant pieces of my code:
private void sendValue(int RW, int _Pin, int Val) //send from my app to serial port
{
if (CommPort.IsOpen)
{
CommPort.WriteLine(RW.ToString() + "," + _Pin.ToString() + "," + Val.ToString());
}
}
private void chP9_CheckedChanged(object sender, EventArgs e) //call the sendValue routine
{
if (chP9.Checked)
{
sendValue(1, 9, 255); //('Write', to pin 9, 'On')
}
else
{
sendValue(1, 9, 0); //('Write', to pin 9, 'Off')
}
}
This is my C# code, it compiles a comma-delimited string to send over the serial port to be read by the Arduino.
Here's the Arduino code:
int RW; //0 to read pin, 1 to write to pin
int PN; //Pin number to read or write
int Val; //Value to write to pin
void setup() {
Serial.begin(38400);
}
void loop() {
ReadIncoming();
ProcessIncoming();
}
void ReadIncoming()
{
if(Serial.available() > 0)
{
RW = Serial.parseInt();
PN = Serial.parseInt();
Val = Serial.parseInt();
}
while(Serial.available() > 0) //Clear the buffer if any data remains after reading
{
Serial.read();
}
}
void ProcessIncoming()
{
if(RW == 0)
{
pinMode(PN, INPUT);
}
else
{
pinMode(PN, OUTPUT);
analogWrite(PN, Val);
}
}
parseInt just takes out the first integer value it finds, stores it and throws away the comma, and does it again and again, but it seems a bit counter-intuitive.
I think my problem lies here:
while(Serial.available() > 0) //Clear the buffer if any data remains after reading
{
Serial.read();
}
I think the App is sending data faster than the Arduino code could handle, especially with this loop, but what do I do with excess data?
I don't like to use the parseInt, but it's the only way I could find to read my instructions correctly. How do I send a byte array from C# and read that array into an array in Arduino?
I've pointed out my hypotheses, and explored alternatives but couldn't get any solutions. What suggestions do you guys have for me?
It is not that clear to me why it works at all. You ought to consider a smarter way to encode the command. You need only three bytes:
private void sendValue(int RW, int _Pin, int Val) {
var cmd = new byte[] { (byte)RW, (byte)_Pin, (byte)Val };
ComPort.Write(cmd, 0, cmd.Length);
}
Then you just need to read those 3 bytes on the Arduino end:
void ReadIncoming() {
if (Serial.available() >= 3) {
RW = Serial.read();
PN = Serial.read();
Val = Serial.read();
ProcessIncoming();
}
}

Categories

Resources