2
votes

I would like to send and receive bytes over serial. My receiver should get the bytes asynchronously. I've written the small example below that appears to work, but it leaves me with an unsettled feeling.

  1. Should I really be using WriteLine, ReadLine? As it's written now, is it possible that the code in the event handler m_port_DataReceived is going to be called for each and every byte? That was my understanding of the event "DataReceived"; perhaps I'm wrong. Does ReadLine block until it sees an end of line character?

  2. Should I somehow use the "if (e.EventType == SerialData.Eof)" construct in the event handler? You can see I have it commented out. I tried it and could not get it to work. When would one expect a SerialData.Eof? My idea was that I could wait before all bytes were present before calling "ReadExisting". However, the "if" statement never evaluated to true. Force the code to go to ReadExisting did correctly read all the bytes however.

  3. In general, what's the best way to set up my code to receive bytes coming over the serial port? The sender will be sending small chunks of bytes every 125 msecs, but will not be sending special characters. The packets of bytes are spaced out in time, so I don't think there's a problem of mixing packets together. More the problem is, "once you see one byte, go read everything, as long as you wait a very short time, you'll get everything". Given this scenario, is there a preferred way?

Thanks in advance, Dave

public class SerialPortController
{
    SerialPort m_port;

    public SerialPortController(bool server)
    {


        if (server)
        {
            m_port = new SerialPort("COM4"); 
            m_port.BaudRate = 115200;
            m_port.Open();
            byte[] sillyBytes = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7 };
            ASCIIEncoding encoding = new ASCIIEncoding();
            string output_string = encoding.GetString(sillyBytes);
            m_port.WriteLine(output_string);
            //m_port.Write(sillyBytes, 0, 8);                  
        }
        else
        {
            m_port = new SerialPort("COM5"); 
        m_port.DataReceived += new SerialDataReceivedEventHandler(m_port_DataReceived);
            m_port.BaudRate = 115200;
            m_port.Open();
        }
        int character = Console.Read();
    }

    void m_port_DataReceived(object sender, SerialDataReceivedEventArgs e)
    {
        //if (e.EventType == SerialData.Eof)
        {
           // string answer = m_port.ReadExisting();
            string answer = m_port.ReadLine();
            ASCIIEncoding encoding = new ASCIIEncoding();
            byte[] byte_answer = encoding.GetBytes(answer);

        }
    }
}
1
Assuming that the property ReceivedBytesThreshold = 1, (which is the default, and it does not appear that you have changed it), then the DataReceivedEvent will fire when there are is at least 1 byte to receive. There may be more. This is not the same as the event firing for every byte received. It means that when it does fire, there will be at least 1 byte.Andy
The approach I have always used without problem, is to read the data as a byte array when the DataRcvd handler fires. I shove that buffer of byte array into a queue. When I need the data I piece it back together and use it / convert it ... Depending on the application I do one of the following: 1 - DataRcvd handler raises an event on the UI thread; 2 - use a timer; 3 - DataRcvd handler invokes a method on the UI thread.dbasnett

1 Answers

1
votes

There´s and example at MSDN which shows simple use of this.

And it used ReadExisting instead of ReadLine.

Also from the docs:

The DataReceived event is not guaranteed to be raised for every byte received. Use the BytesToRead property to determine how much data is left to be read in the buffer.

private static void DataReceviedHandler(
                    object sender,
                    SerialDataReceivedEventArgs e)
{
    SerialPort sp = (SerialPort)sender;
    string indata = sp.ReadExisting();
    Console.WriteLine("Data Received:");
    Console.Write(indata);
}