Ditn
Ditn

Reputation: 3

c# constantly requesting and processing data from serial port

After a long time i need to program again. I need to constantly send a command through serial port from a car ecu(? data).

Then i need to receive that data which i will process to be shown on a display(thinking racing display with car parameters like temperature etc). I need to do this constantly

I wonder before i start whats best way to do this?

1 thread for constantly asking and receiving data main thread for showing data in screen. (store data in buffer and save once a minute or so)

anyone has any tips a guide or so how to start on this. i tested receiving data with terminal and i got data back so config is working.

sent ? data => i got data back.

Upvotes: 0

Views: 1898

Answers (2)

Eike B
Eike B

Reputation: 231

The approach we are using in our SerialPort Handler is, to have an AutoResetEvent to get notified as soon as there is an answer from the port.

SerialPort class of the FrameWork has a few issues with the integrated DataReceived event. It is sometimes fired when there is no complete package available (in case you defined the answer length). So you should check for the answer length you expect.

Our very stripped down implementation:

public class Serialport
{
    private SerialPort _serialPort;
    private List<byte> _buffer;
    private AutoResetEvent _autoResetEvent;
    private const int WriteTimeOut = 5;

    private event EventHandler ReceivedDataChanged;

    public Serialport()
    {
        _serialPort = new SerialPort();

        // set PortName, BaudRate etc

        _serialPort.Open();
        _serialPort.DiscardInBuffer();
        _serialPort.DiscardOutBuffer();
        _serialPort.DataReceived += ReceiveData;
    }

    private void ReceiveData(object sender, SerialDataReceivedEventArgs e)
    {
        var bytes = _serialPort.BytesToRead;

        byte[] buffer = new byte[bytes];
        if (_serialPort.IsOpen)
        {
            _serialPort.BaseStream.Read(buffer, 0, bytes);
            _buffer.AddRange(buffer);
        }

        ReceivedDataChanged?.Invoke(this, new ReceivedBytesEventArgs(_buffer.ToArray()));
        _buffer.Clear();
    }

    private void SendData(byte[] message, int answerLength)
    {
        _serialPort.ReceivedBytesThreshold = answerLength;
        _serialPort.WriteTimeout = WriteTimeOut;
        _serialPort.Write(message, 0, message.Length);
    }

    public string SendDataCommand()
    {
        if (_serialPort.IsOpen)
        {
            ReceivedDataChanged += InterpretAnswer;
            SendData(message, length);
            if (_autoResetEvent.WaitOne(100))
            {
                ReceivedDataChanged -= InterpretAnswer;
                //Data Received and interpreted and send to the caller
                return _requestAnswer;
            }

            ReceivedDataChanged -= InterpretAnswer;
        }

        return "Connection not open";
    }

    private void InterpretAnswer(object sender, EventArgs e)
    {
        // handle all interpretation
        // Set the event
        _autoResetEvent.Set();
    }
}

The serialPort is initialised and opened. After that, we wire up all needed events and call the SendDataCommand() Method. This method is the public visible method which is called from some task. This calls the method SendData. As soon as there is an answer, the event is triggered and the interpretation is started. If the interpretation is done in the specified amount of time (_autoResetEvent.WaitOne(msToWait)) the result is given back to the calling method. This should be done in a separate task, so the ui will not Block while you wait for the answer

As mentioned, this is a very stripped down example. You should do more checking in the received handler of SerialPort, because there are some issues with the event. With this approach you will have a bit more of abstraction to your business logic.

Hope this helps.

Upvotes: 0

Isma
Isma

Reputation: 15209

You could just use the SerialPort class and configure the BaudRate, DataBits etc.. and then just wait for the DataReceived event to fire:

public class SerialPortReader 
{
    public SerialPortReader(string yourPortName)
    {
        var serialPort = new SerialPort() {
            PortName = yourPortName,
            BaudRate = 57600; //This will control the rate at what you receive the data
         }

        serialPort.DataReceived += new SerialDataReceivedEventHandler(OnDataReceived);

        serialPort.Open();
    }
}

public void OnDataReceived(object sender, SerialDataReceivedEventArgs e)
{
    var serialPort = (SerialPort)sender;
    // Process your data reading the stream with Read, ReadLine etc...
}

Upvotes: 1

Related Questions