Search code examples
serial-portraspberry-pi3uartwindows-10-iot-core

Reading Task on SerialDevice on Windows Iot Core


I'm attempting to write a Task which will run until cancelled which will read any data which has been received by the UART and proceed to dispatch the received data through a defined event. I want the read loop to read for 200 ms before returning with any data it may have read in that timeslice (including possibly zero data) or when a full buffer has been read, whichever occurs first; the vast majority of the time the timeout will occur first. I have successfully sent data out the UART but I have failed to receive any data even though it has been confirmed the device received the data on the wire.

SerialDevice device;

// Instantiate the SerialDevice.

device.ReadTimeout = new TimeSpan( 0, 0, 0, 0, 200 );
ReadDataCancellationTokenSource = new CancellationTokenSource();

const uint BufferSize_bytes = 50;

ReadDataTask = Task.Factory.StartNew( async () =>
{
    using( DataReader reader = new DataReader( device.InputStream ) )
    {
       reader.InputStreamOptions = InputStreamOptions.Partial;

       while( !ReadDataCancellationTokenSource.IsCancellationRequested )
       {
          uint dataRead = await reader.LoadAsync( BufferSize_bytes ).AsTask();

          if( dataRead > 0 )
          {
             IBuffer buffer = reader.ReadBuffer( dataRead );
             if( buffer.Length > 0 )
                PropogateReceivedData( ReadBuffer( buffer ) );
          }
       }
    }
}, ReadDataCancellationTokenSource.Token );

The PropogateReceivedData( ReadBuffer( buffer ) ) call reads all the data in the buffer and then the data is dispatched; this is known to be working correctly. The ReadDataCancellationTokenSource member is stored to shutdown the Task when needed.

Given the challenges I have experienced trying to get this approach, I am wondering if it should work or if not, what I need to do to get it to work.


Solution

  • I have successfully sent data out the UART but I have failed to receive any data even though it has been confirmed the device received the data on the wire.

    I am not sure how you "confirmed the device received the data on the wire". As you set InputStreamOptions.Partial so even if there is only one byte on the wire this line await reader.LoadAsync( BufferSize_bytes ).AsTask(); will return you will get this one byte in the buffer.

    Also I've no idea how do you handle the received data in PropogateReceivedData( ReadBuffer( buffer ) ), here I use the follow lines converting the data to string and display in UI you can refer to:

                                    var dataReader = DataReader.FromBuffer(buffer);
                                    rcvdText.Text = dataReader.ReadString(buffer.Length);
    

    My suggestion is you can use reader.ReadString(dataRead); if you want get string data and use reader.ReadBytes(readData); if you want get bytes stream. More supported APIs you can refer to DataReader.

    Given the challenges I have experienced trying to get this approach, I am wondering if it should work or if not, what I need to do to get it to work.

    Yes, your logic should work, except for me the read timeout never occurs. Can you confirm the read timeout works for you as you set device.ReadTimeout = new TimeSpan( 0, 0, 0, 0, 200 );? Is there any timeout information?

    The following is the whole code lines I get from your question to test, it works for me.

                    device.ReadTimeout = new TimeSpan(0, 0, 0, 0, 200);
                    var ReadDataCancellationTokenSource = new CancellationTokenSource();
    
                    const uint BufferSize_bytes = 50;
    
                    using (DataReader reader = new DataReader(device.InputStream))
                    {
                        reader.InputStreamOptions = InputStreamOptions.Partial;
    
                        while (!ReadDataCancellationTokenSource.IsCancellationRequested)
                        {
                            uint dataRead = await reader.LoadAsync(BufferSize_bytes).AsTask();
    
                            if (dataRead > 0)
                            {
                                IBuffer buffer = reader.ReadBuffer(dataRead);
                                if (buffer.Length > 0)
                                {
                                    //    rcvdText.Text = reader.ReadString(dataRead);
    
                                    //    var readData = new Byte[dataRead];
                                    //    reader.ReadBytes(readData);
    
                                    var dataReader = DataReader.FromBuffer(buffer);
                                    rcvdText.Text = dataReader.ReadString(buffer.Length);
                                    status.Text = "bytes read successfully!";
                                }
                            }
                        }
                    }
    

    Official serial sample you can refer to.