Serial Port reading char string
-
Oddly is that when I send the 9 character length of a string (i.e. 123A45678), my serial port dataReceived event recieves the message but it reads as: 123A4567 8 Unsure on how to get the whole string as was sent by the other com port? here's my code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Ports;using RS232;
namespace RemoteCFG
{
public class RemoteConfiguration
{
SerialPort serialPort;
RS232Comm rs232Comm = new RS232Comm();
Object lockingObj = new object();public RemoteConfiguration() { } public string strMessage { get; set; } public string cfgNumber { get; set; } public string vloValue { get; set; } public string atcValue { get; set; } public List EnumerateComPorts() { return rs232Comm.GetAvailableComPorts(); } public int OpenPort(string comPort) { serialPort = rs232Comm.OpenPort(comPort); serialPort.DataReceived +=new SerialDataReceivedEventHandler(serialPort\_DataReceived); if (serialPort != null) return 1; else return 0; } public int ClosePort() { try { serialPort.Close(); return 1; } catch (Exception ex) { return 0; } } void serialPort\_DataReceived(object sender, SerialDataReceivedEventArgs e) { SerialPort sp = (SerialPort)sender; string inData = sp.ReadExisting().Trim(); strMessage = inData; switch (inData) { case "PLC": SendMsg("OK"); break; case "CFG": ValidateCFG(); break; case "OFF": serialPort.Close(); break; case "VLO": GetVLO(); break; case "ATC": GetATC(); break; default: System.Diagnostics.Debug.WriteLine(strMessage); break; } } private void GetATC() { if (atcValue != null && atcValue != string.Empty) { int value = 0; if (int.TryParse(atcValue, out value)) { if (value >= 0 || value <= 99) {
-
Oddly is that when I send the 9 character length of a string (i.e. 123A45678), my serial port dataReceived event recieves the message but it reads as: 123A4567 8 Unsure on how to get the whole string as was sent by the other com port? here's my code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Ports;using RS232;
namespace RemoteCFG
{
public class RemoteConfiguration
{
SerialPort serialPort;
RS232Comm rs232Comm = new RS232Comm();
Object lockingObj = new object();public RemoteConfiguration() { } public string strMessage { get; set; } public string cfgNumber { get; set; } public string vloValue { get; set; } public string atcValue { get; set; } public List EnumerateComPorts() { return rs232Comm.GetAvailableComPorts(); } public int OpenPort(string comPort) { serialPort = rs232Comm.OpenPort(comPort); serialPort.DataReceived +=new SerialDataReceivedEventHandler(serialPort\_DataReceived); if (serialPort != null) return 1; else return 0; } public int ClosePort() { try { serialPort.Close(); return 1; } catch (Exception ex) { return 0; } } void serialPort\_DataReceived(object sender, SerialDataReceivedEventArgs e) { SerialPort sp = (SerialPort)sender; string inData = sp.ReadExisting().Trim(); strMessage = inData; switch (inData) { case "PLC": SendMsg("OK"); break; case "CFG": ValidateCFG(); break; case "OFF": serialPort.Close(); break; case "VLO": GetVLO(); break; case "ATC": GetATC(); break; default: System.Diagnostics.Debug.WriteLine(strMessage); break; } } private void GetATC() { if (atcValue != null && atcValue != string.Empty) { int value = 0; if (int.TryParse(atcValue, out value)) { if (value >= 0 || value <= 99) {
You serial port is set at 9600 baud - this is not a fast speed, certainly not in modern terms. 9600 baud means 9,600 bits per second, so with 1 start bit, one stop bit, even parity and 7 bits per character that's a maximum data transfer rate of 960 characters per second. You SerialPort.DataRecieved event does not fire when the final character is received, it fires when the first character is received. And the second, and the third.... So when you read all the data from the serial port buffer, you will get a "random" number of characters, which may - or may not be - the whole message you are looking for. Instead of your existing code, set up a BackgroundWorker thread which processes input data from the serial port, scans it to find whole messages, and then signals up to the main thread that a whole message is ready. If it gets a "partial message" is stores it, and adds the next data on the end before scanning it again.
This message is manufactured from fully recyclable noughts and ones. To recycle this message, please separate into two tidy piles, and take them to your nearest local recycling centre. Please note that in some areas noughts are always replaced with zeros by law, and many facilities cannot recycle zeroes - in this case, please bury them in your back garden and water frequently.
-
Oddly is that when I send the 9 character length of a string (i.e. 123A45678), my serial port dataReceived event recieves the message but it reads as: 123A4567 8 Unsure on how to get the whole string as was sent by the other com port? here's my code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Ports;using RS232;
namespace RemoteCFG
{
public class RemoteConfiguration
{
SerialPort serialPort;
RS232Comm rs232Comm = new RS232Comm();
Object lockingObj = new object();public RemoteConfiguration() { } public string strMessage { get; set; } public string cfgNumber { get; set; } public string vloValue { get; set; } public string atcValue { get; set; } public List EnumerateComPorts() { return rs232Comm.GetAvailableComPorts(); } public int OpenPort(string comPort) { serialPort = rs232Comm.OpenPort(comPort); serialPort.DataReceived +=new SerialDataReceivedEventHandler(serialPort\_DataReceived); if (serialPort != null) return 1; else return 0; } public int ClosePort() { try { serialPort.Close(); return 1; } catch (Exception ex) { return 0; } } void serialPort\_DataReceived(object sender, SerialDataReceivedEventArgs e) { SerialPort sp = (SerialPort)sender; string inData = sp.ReadExisting().Trim(); strMessage = inData; switch (inData) { case "PLC": SendMsg("OK"); break; case "CFG": ValidateCFG(); break; case "OFF": serialPort.Close(); break; case "VLO": GetVLO(); break; case "ATC": GetATC(); break; default: System.Diagnostics.Debug.WriteLine(strMessage); break; } } private void GetATC() { if (atcValue != null && atcValue != string.Empty) { int value = 0; if (int.TryParse(atcValue, out value)) { if (value >= 0 || value <= 99) {
You don't need a background worker and the baud rate has nothing to do with your ability or inability to receive a message. The SerialPort class already operates on its own thread. The truth is the physical serial port on your PC is implemented with a USART and has no buffer of its own. It can hold a single character. When it receives data, it fires an interrupt. The interrupt handler adds the character to a FIFO buffer and notifies the serial port class attached to that port that a character has been received. That message goes into the message queue and your application will receive it via the DataReceived event when the message pump gets around to sending it to your app. When you read the data from the serial port class, you empty the FIFO buffer either in one swoop or a character at a time. Interlocks are already built into the serial port class so you don't contend with any characters that may be received at the port while the data is being read by the application. For all intents and purposes, you read a string of characters as they have been received up to that point in time. What is NOT present is any kind of message framing. And that is where you need to do something. The fact is the DataReceived event could be fired for every character that comes in the serial port. You have to grab those characters, append them to a message string, then determine when the message is complete. It is the same as information coming from the keyboard... the user types a single character at a time. If you are looking for a word, you buffer those characters onto a string until you see a space or a carriage return. Same this with the serial port... just think of it as another keyboard where characters arrive (not full strings!). So you need to decide what your message delimiter is. Normally, for serial communications, the message is ended with a 13... a carriage return. Since it looks like you might be talking to a PLC for data collection, it may also be a fixed-width situation. In that case you need to test the length of the accumulated string each time DataReceived is called. Either way, you need to look for the delimiter or the length in DataRecevied and THEN process your results once the whole string has been received. Make sense? Secondly, you are casting the serial port from the event arguments. You shouldn't do that. You already have a reference to the serial port in your class-scoped serialPort object. Use it inside of the event handler. Usually, inside of this event, you setup a While loop that looks