0

Im trying to read from a com port, this is my code

   public string HouseState()
    {
        string state = string.Empty;
     if (!Variables.portBusy)
            {
                // Begin communications
                var blockLimit = 13;
                openSerial();
                byte[] buffer = new byte[blockLimit];
                Action kickoffRead = null;

                kickoffRead = delegate
                {
                    serialPort.BaseStream.BeginRead(buffer, 0, buffer.Length, delegate (IAsyncResult ar)
                    {
                        try
                        {
                            int actualLength = serialPort.BaseStream.EndRead(ar);
                            byte[] received = new byte[actualLength];
                            Buffer.BlockCopy(buffer, 0, received, 0, actualLength);
                            state += System.Text.Encoding.UTF8.GetString(received);
                            //MessageBox.Show(state);
                        }
                        catch (IOException exc)
                        {
                            //handleAppSerialError(exc);
                        }
                        if (state.Count() <= 13)
                            kickoffRead();
                    }, null);
                };
                kickoffRead();
            }
        MessageBox.Show(state);
        var index = state.IndexOf("R");
        var command = string.Empty;
        if (index >= 0)
            command = state.Substring(index, 13);


        return command;
    }

What im trying to get is a string that starts with R and has 13 characters. Because sometimes the port sends half the string i do this: if (state.Count() <= 13)

But while inside BaseStream the state string gets what i want, when i try to read the string of state, it appears empty. The MessageBox shows an empty string.

why this is happening?

CDrosos
  • 2,418
  • 4
  • 26
  • 49

1 Answers1

2

The BeginRead method of SerialPort.BaseStream is asynchronous so by the moment you're getting to MessageBox.Show(state); the actual read may have not completed yet and state is still empty. You need to wait until all necessary data is read:

// .....................
var readComplete = new ManualResetEvent(false);
kickoffRead = delegate
{
    serialPort.BaseStream.BeginRead(buffer, 0, buffer.Length, delegate (IAsyncResult ar)
    {
        // ...................
        if (state.Count() <= 13)
            kickoffRead();
        else
            readComplete.Set();
    }, null);
};
kickoffRead();
readComplete.WaitOne();
// ......................

Having said that BeginRead/EndRead based async reading is superseded by ReadAsync one. And based on your original snippet even synchronous read is acceptable in your case. You may find examples for both in the answers to this question: C# Async Serial Port Read

Dmitry Egorov
  • 9,542
  • 3
  • 22
  • 40
  • you rock bro, i didnt know it was async, why it doens require async command? Also i didnt know about this ManualResetEvent, thanks – CDrosos May 31 '17 at 13:24
  • The `async` keyword is supposed to be used with [new async model](https://msdn.microsoft.com/library/hh191443(vs.110).aspx) methods. Being of the old async model implementation, `BeginRead` is not aware of tasks and `async`/`await`. – Dmitry Egorov May 31 '17 at 13:37