c# Serial comms Read data and add to an array - c#

I have got myself a little lost with this Windows forms application:(
I have a stream of data arriving at a serial port in the format of \W0987654321\L555666444\W3456789900\L9842429009 and so it repeats with different values for \L and \W
I need to split out the \W and \L values and add them to an array which is to expand as needed. and then plot them on a graph in real time.
Where i'm lost is how to read the port to get each complete value once it has arrived and not truncate it. I just can't get my brain around this so any help would be great...
I open the port thus:
port.PortName = "COM9";
port.BaudRate = 38400;
port.DataBits = 8;
port.Parity = Parity.None;
port.StopBits = StopBits.One;
port.DtrEnable = false;
port.Handshake = Handshake.None;
port.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(port_DataReceived_1);
port.Open();
textBox1.Clear();
port.DiscardInBuffer();
port.DtrEnable = true;
Currently i have it all writing to a text box:
private void port_DataReceived_1(object sender, SerialDataReceivedEventArgs e)
{
InputData = port.ReadExisting();
if (InputData != String.Empty)
{
this.BeginInvoke(new SetTextCallback(SetText), new object[] { InputData });
}
}
private void SetText(string text)
{
this.textBox1.AppendText(text);
}
which shows all the data OK

var readQueue = string.Empty;
private void port_DataReceived_1(object sender, SerialDataReceivedEventArgs e)
{
readQueue += port.ReadExisting();
while (readQueue.Substring(1).Contains(#"\"))
{
var slashPos = readQueue.IndexOf(#"\",1);
var completeEntry = readQueue.Substring(0, slashPos);
Console.WriteLine(completeEntry);
readQueue = readQueue.Substring(slashPos);
}
}

Related

C# Serial Port Read - Get COBS coded messages with different lenght

so im new in C# Programming. I have programmed a C# Forms Application in Visual Studio to communicate to/initialze a device over the Serial Port. The communication between the device is COBS coded, so there are no 0x00 bytes except on the end of each message. The messages sent and received have different length.
My problem is at the moment, that the Messages I receive are not complete or start at the middle of a message, so i cannot trigger sent messages on a specific value in the received messages. You can determine end of a message with received 0x00 (0x00 means end of message in COBS coded data)
So what i need is something to handle the complete message and put it in a byte array to analyze i.e. byte[11] for a specific value.
Here is what ive done so far:
private bool b_portopen = false;
private byte[] b_rcv_buffer = new byte[256];
private void button1_Click(object sender, EventArgs e) {
//InitTimer();
if (b_portopen == false)
{
serialPort1.PortName = comboBox1.SelectedItem.ToString();
serialPort1.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
serialPort1.Open();
b_portopen = true;
button1.Text = "Close";
button2.Enabled = true;
Console.WriteLine("Serial Port Opened");
}
else if (b_portopen == true)
{
serialPort1.Close();
b_portopen = false;
button1.Text = "Open";
button2.Enabled = false;
Console.WriteLine("Serial Port Closed");
}
}
private async void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
serialPort1.Read(b_rcv_buffer, 0, 256);
//serialPort1.Read(b_rcv_buffer1, 11, 2);
richTextBox1_receive.Invoke(new Action(() =>
{
richTextBox1_receive.AppendText(BitConverter.ToString(b_rcv_buffer) + "\n");
richTextBox1_receive.ScrollToCaret();
}));
switch (b_rcv_buffer[10])
{
case b_state_startup:
do something
case b_state_be_start_conf:
do something
case b_state_keepalive_conf:
do something
case b_state_unprepare_conf:
do something
case b_state_prepare_conf:
do something
}
}
So, i found a solution with using ConcurrentQueue:
ConcurrentQueue<byte> b_rcv_buffer = new ConcurrentQueue<byte>();
private Timer timer2;
public void InitTimer()
{
timer2 = new System.Windows.Forms.Timer();
timer2.Tick += new EventHandler(timer2_Tick);
timer2.Interval = 1; // in miliseconds
timer2.Start();
}
private async void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
int bytes = serialPort1.BytesToRead;
byte[] buf = new byte[bytes];
serialPort1.Read(buf, 0, serialPort1.BytesToRead);
for(int i = 0; i < buf.Length; i++)
{
b_rcv_buffer.Enqueue(buf[i]); //Enqueue every received Byte in Concurrentqueue
}
}
private async void timer2_Tick(object sender, EventArgs e)
{
if (b_rcv_buffer.Contains<byte>(0x00))
{
byte[] array = b_rcv_buffer.ToArray();
richTextBox1_receive.Invoke(new Action(() =>
{
richTextBox1_receive.AppendText(BitConverter.ToString(array) + "\n");
//richTextBox1_receive.ScrollToCaret();
}));
byte ignored;
while (b_rcv_buffer.TryDequeue(out ignored));
}

Receive data from weighing scale CAS CL5200

Need help with CAS CL5200 scale.
i have already seen all the posts regarding this problem , but none of them are working regarding CAS CL5200 scale- connected with USB cable that creates a virtual com port (COM41)
here are the steps i followed -
To test the communication, I installed CL-Works (scales software for some functions) --> working.
Installed Free Device Monitoring Studio to see all the connection params.
Tested with hyperterminal --> not working
Free Device Monitoring Studio reports that "W" is written to com port but nothing returns.
The code here is what I found on other related post, tested it with byte[] and string, either way the code writes on COM41 "W" but there is nothing to read.
Code:
public partial class Form1 : Form
{
private const int BaudRate = 19200; // BaudRate Constant
private SerialPort _serialPort;
private void button1_Click_1(object sender, EventArgs e)
{
if (_serialPort != null && _serialPort.IsOpen)
_serialPort.Close();
if (_serialPort != null)
_serialPort.Dispose();
_serialPort = new SerialPort("COM41", BaudRate, Parity.None, 8, StopBits.One); // Creates new SerialPort using the name selected in the combobox
_serialPort.Handshake = Handshake.None;
// _serialPort.DataReceived += SerialPortOnDataReceived; // this event happens everytime when new data is received by the ComPort
_serialPort.DataReceived += new SerialDataReceivedEventHandler(_serialPort_DataReceived);
_serialPort.RtsEnable = true;
_serialPort.DtrEnable = true;
_serialPort.Open();
textBox1.Text = "Listening on " + _serialPort.PortName + "...\r\n";
// byte[] towrite = GetBytes("W"); // get the weight from scale wiyh "W" as byte[]
// _serialPort.Write(towrite,0,1);
_serialPort.WriteLine("W");
}
private delegate void Closure();
void _serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
if (InvokeRequired) // makes sure the function is invoked to work properly in the UI-Thread
BeginInvoke(new Closure(() => { _serialPort_DataReceived(sender, e); })); //<-- Function invokes itself
else
while (_serialPort.BytesToRead > 0) //<-- repeats until the In-Buffer is empty
{
//textBox1.Text += string.Format("{0:X2} ", _serialPort.ReadByte());
textBox1.Text += _serialPort.ReadExisting();
//<-- bytewise adds inbuffer to textbox
}
}
private byte[] GetBytes(string str)
{
byte[] bytes = new byte[str.Length * sizeof(char)];
Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
return bytes;
}
}
If you can't see the data in the hyperterminal, you can't see it in the code you wrote. See it there first. then try this
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
Get_Data(serialPort1.ReadLine().ToString());
}
private void Get_Data(string Result_Data)
{
Application.DoEvents();
if (!InvokeRequired)
{
try
{
double dNew = Convert.ToDouble(Result_Data) / 100;
lbl_weight.Text = dNew.ToString("N2");
}
catch (Exception err)
{
MessageBox.Show(err.ToString());
}
}
else { Invoke((MethodInvoker)(() => Get_Data(Result_Data))); }
Application.DoEvents();
}
public void Connection_Start()
{
string comport = "COM1";
serialPort1.DataReceived += new
SerialDataReceivedEventHandler(serialPort1_DataReceived);
serialPort1.PortName = comport;
serialPort1.BaudRate = 9600;
serialPort1.Parity = Parity.None;
serialPort1.DataBits = 8;
serialPort1.StopBits = StopBits.One;
serialPort1.DtrEnable = true;
serialPort1.Open();
}

C# serial connection not working

I am trying to send ASCII caracters to a VideoJet Excel 170i printer, via a RS-232 cable (Serial)
When I am using the test program, i have no problem getting a response from the printer, i can change the status of the printer.
This is the code i've made
public partial class Form1 : Form
{
private SerialPort port = new SerialPort("COM1");
private delegate void SetTextDeleg(string data);
public Form1()
{
InitializeComponent();
}
private void addtoText(string text)
{
this.richTextBox1.Text = this.richTextBox1.Text + "\n" + text;
}
private void Form1_Load(object sender, EventArgs e)
{
try
{
port.BaudRate = 9600;
port.Parity = Parity.None;
port.StopBits = StopBits.One;
port.DataBits = 8;
port.Handshake = Handshake.None;
port.ReadTimeout = 2000;
port.WriteTimeout = 500;
port.DtrEnable = true;
port.RtsEnable = true;
port.Open();
port.DataReceived += DataReceivedHandler;
addtoText("Port is ready");
}
catch (Exception ex)
{
//Console.WriteLine("Error opening my port: {0}", ex.Message);
addtoText("Error opening my port: {0}" + ex.Message);
}
}
public void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
System.Threading.Thread.Sleep(500);
string indata = sp.ReadExisting();
this.BeginInvoke(new SetTextDeleg(DisplayToUI), new object[] { indata });
}
private void DisplayToUI(string displayData)
{
addtoText(displayData);
}
private void button1_Click(object sender, EventArgs e)
{
port.Write(tbxAscii.Text);
}
private void Form1_Leave(object sender, EventArgs e)
{
port.Close();
}
}
I need to sent ASCII caracters to the printer, like
[1B][01][09]
To turn the printer to Print Mode.
The printer is supposed to respond, i get no response, and the printer doesn't change its status.
I have a program made to test the serial connection made by the printer, and i can see that all the settings are OK (Baud rate, Parity... port), and indeed on port COM1.
So i think that my port.write is not sending any info to the printer... or maybe i'm sending corrup info and i'm not reading the response of the printer.
are you sure that you want to send [1B][01][09] or do you want to send that byte sequence 0x1b,0x01,0x09
just to see if this works, send the following in you click handler
private void button1_Click(object sender, EventArgs e)
{
var bytes = new byte[] { 0x1b, 0x01, 0x09 };
port.Write(bytes, 0, bytes.Length);
port.Flush(); // make sure everything is written
}
reading has to be changed, to handle bytes
SerialPort sp = (SerialPort)sender;
System.Threading.Thread.Sleep(500);
var available = sp.BytesToRead; // check how many bytes are ready to be read
if (available < 1)
return;
var buffer = new byte[available];
sp.Read(buffer, 0, available);
var indata = BitConverter.ToString(buffer); // convert bytes to a hex representation
this.BeginInvoke(new SetTextDeleg(DisplayToUI), new object[] { indata });

DataReceived EventHandler works only once

I am new to stackoverflow. I am having a problem with VC# Serial Communication. I need t receive data conyinuously from serial port but my code works only once. That is if I send "This is a Serial Comm Project". The data is received as expected but if I send the data again it doesn't work. Please provide a solution.
private void button1_Click(object sender, EventArgs e)
{
mySerialPort.PortName = cbxCOMPort.Text;
mySerialPort.BaudRate = int.Parse(cbxBaudrate.Text);
mySerialPort.Parity = Parity.None;
mySerialPort.StopBits = StopBits.One;
mySerialPort.DataBits = 8;
mySerialPort.Handshake = Handshake.RequestToSend;
mySerialPort.ReadTimeout = int.Parse(cbxTimeout.Text);
mySerialPort.WriteTimeout = 2000;
mySerialPort.DtrEnable = true;
mySerialPort.RtsEnable = true;
mySerialPort.Encoding = Encoding.ASCII;
mySerialPort.NewLine = "\r\n";
mySerialPort.ReadBufferSize = 512;
mySerialPort.DataReceived += port_DataReceived;
mySerialPort.Open();
button1.Enabled = false;
button2.Enabled = true;
gbxMsgDel.Enabled = true;
}
private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{// Event for receiving data
// Read the buffer to text box.
this.Invoke(new EventHandler(DoUpdate));
}
private void DoUpdate(object s, EventArgs e)
{
receivedMessage += mySerialPort.ReadExisting();
}
receivedMessage is a private string type. It is private to the class.
I had a similar problem before...
From MSDN
"The DataReceived event is not guaranteed to be raised for every byte
received"
One option is to use a timer to check available data instead of the event, something like this:
private void checkPortDataTimer_Tick(object sender, EventArgs e)
{
//You may want to check available bytes instead of this.
string recievedData = comPort.ReadExisting();
if (!string.IsNullOrEmpty(recievedData))
someTextBox.Text += recievedData;
}
Cheers

Serial Port Connection, Readline/ReadExisting Does Not Work

I'm trying to make a serial connection to another machine. I'm using a Virtual Serial Port Emulator to try this. The settings that I use on hyperterminal are like the ones below. I can see the portopen is true, but I can't check whether I can write or read. When I try the ReadLine method it gives TimeoutException and when it's readExisting command it does nothing. DataReceived is never triggered too. Can you help me out with that ?
private void Page1_Load(object sender, EventArgs e)
{
//Port name can be identified by checking the ports
// section in Device Manager after connecting your device
serialPort1.PortName = "COM14"; // that one works for me
//Provide the name of port to which device is connected
//default values of hardware[check with device specification document]
serialPort1.BaudRate = 115200;
serialPort1.Parity = Parity.None;
serialPort1.DataBits = 8;
serialPort1.StopBits = StopBits.One;
serialPort1.Handshake = Handshake.None;
serialPort1.RtsEnable = true;
serialPort1.DtrEnable = true;
serialPort1.ReceivedBytesThreshold = 8;
serialPort1.ReadTimeout = 2000;
serialPort1.DataReceived += new SerialDataReceivedEventHandler(serialPort1_DataReceived); //
// Writes data to the Serial Port output buffer
//opens the port
serialPort1.Open();
}
private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
inputData = serialPort1.ReadExisting();
this.Invoke((MethodInvoker)delegate { DoUpdate(); });
}
public void DoUpdate()
{
textOutput.Text = (textOutput.Text + inputData);
}
private void btnReadExist_Click(object sender, EventArgs e)
{
if ((serialPort1.IsOpen == true))
{
serialPort1.WriteLine("something");
string read= serialPort1.ReadExisting();
//string output = serialPort1.ReadLine();
textOutput.Text += read;
}
}
private void Page1_FormClosed(object sender,System.Windows.Forms.FormClosedEventArgs e)
{
// Close the Serial Port
serialPort1.Close();
}
The problem seems to be that you're reading in two code blocks: first, directly after sending the text in the button's event. Secondly you have an event assigned that reads data when called asynchronously. You should decide which one to use and remove the other.

Categories