EN RU CN
Windows IoT BackgroundTask Async/Await



  • I am having a play with a Raspberry Pi 3 running Windows IoT. I have wired up a DS18B20 sensor and I am able to communicate to it fine via a UWP app.

    Here is the ds18b20 datesheet:http://www.componentschip.com/pdf/6a-DS18B20-T-R.pdf


    I now wanted to make this app into a BackgroundTask app. I am using this code for the OneWire coms

    class WireSearchResult
    {
    public byte[] id = new byte[8];
    public int lastForkPoint = 0;
    }
    public class OneWire
    {
    private SerialDevice serialPort = null;
    DataWriter dataWriteObject = null;
    DataReader dataReaderObject = null;

    public async Task GetFirstSerialPort()
    {
    try
    {
    string aqs = SerialDevice.GetDeviceSelector("UART0");
    var dis = await DeviceInformation.FindAllAsync(aqs);
    if (dis.Count > 0)
    {
    var deviceInfo = dis.First();
    return deviceInfo.Id;
    }
    }
    catch (Exception ex)
    {
    Debug.WriteLine("Unable to get serial device: " + ex.Message);
    }

    return null;
    }

    public void shutdown()
    {
    if (serialPort != null)
    {
    serialPort.Dispose();
    serialPort = null;
    }
    }

    async Task onewireReset(string deviceId)
    {
    try
    {
    if (serialPort != null)
    serialPort.Dispose();

    serialPort = await SerialDevice.FromIdAsync(deviceId);

    // Configure serial settings
    serialPort.WriteTimeout = TimeSpan.FromMilliseconds(1000);
    serialPort.ReadTimeout = TimeSpan.FromMilliseconds(1000);
    serialPort.BaudRate = 9600;
    serialPort.Parity = SerialParity.None;
    serialPort.StopBits = SerialStopBitCount.One;
    serialPort.DataBits = 8;
    serialPort.Handshake = SerialHandshake.None;

    dataWriteObject = new DataWriter(serialPort.OutputStream);
    dataWriteObject.WriteByte(0xF0);
    await dataWriteObject.StoreAsync();

    dataReaderObject = new DataReader(serialPort.InputStream);
    await dataReaderObject.LoadAsync(1);
    byte resp = dataReaderObject.ReadByte();
    if (resp == 0xFF)
    {
    System.Diagnostics.Debug.WriteLine("Nothing connected to UART");
    return false;
    }
    else if (resp == 0xF0)
    {
    System.Diagnostics.Debug.WriteLine("No 1-wire devices are present");
    return false;
    }
    else
    {
    //System.Diagnostics.Debug.WriteLine("Response: " + resp);
    serialPort.Dispose();
    serialPort = await SerialDevice.FromIdAsync(deviceId);

    // Configure serial settings
    serialPort.WriteTimeout = TimeSpan.FromMilliseconds(1000);
    serialPort.ReadTimeout = TimeSpan.FromMilliseconds(1000);
    serialPort.BaudRate = 115200;
    serialPort.Parity = SerialParity.None;
    serialPort.StopBits = SerialStopBitCount.One;
    serialPort.DataBits = 8;
    serialPort.Handshake = SerialHandshake.None;
    dataWriteObject = new DataWriter(serialPort.OutputStream);
    dataReaderObject = new DataReader(serialPort.InputStream);
    return true;
    }
    }
    catch (Exception ex)
    {
    System.Diagnostics.Debug.WriteLine("Exception: " + ex.Message);
    return false;
    }
    }

    public async Task onewireWriteByte(byte b)
    {
    for (byte i = 0; i < 8; i++, b = (byte)(b >> 1))
    {
    // Run through the bits in the byte, extracting the
    // LSB (bit 0) and sending it to the bus
    await onewireBit((byte)(b & 0x01));
    }
    }

    async Task onewireBit(byte b)
    {
    var bit = b > 0 ? 0xFF : 0x00;
    dataWriteObject.WriteByte((byte)bit);
    await dataWriteObject.StoreAsync();
    await dataReaderObject.LoadAsync(1);
    var data = dataReaderObject.ReadByte();
    return (byte)(data & 0xFF);
    }

    async Task onewireReadByte()
    {
    byte b = 0;
    for (byte i = 0; i < 8; i++)
    {
    // Build up byte bit by bit, LSB first
    b = (byte)((b >> 1) + 0x80 * await onewireBit(1));
    }
    // System.Diagnostics.Debug.WriteLine("onewireReadByte result: " + b);
    return b;
    }

    public async Task getTemperature(string deviceId)
    {
    double tempCelsius = -200;

    if (await onewireReset(deviceId))
    {
    await onewireWriteByte(0xCC); //1-Wire SKIP ROM command (ignore device id)
    await onewireWriteByte(0x44); //DS18B20 convert T command
    // (initiate single temperature conversion)
    // thermal data is stored in 2-byte temperature
    // register in scratchpad memory

    // Wait for at least 750ms for data to be collated
    await Task.Delay(750);

    // Get the data
    await onewireReset(deviceId);
    await onewireWriteByte(0xCC); //1-Wire Skip ROM command (ignore device id)
    await onewireWriteByte(0xBE); //DS18B20 read scratchpad command
    // DS18B20 will transmit 9 bytes to master (us)
    // starting with the LSB

    byte tempLSB = await onewireReadByte(); //read lsb
    byte tempMSB = await onewireReadByte(); //read msb

    // Reset bus to stop sensor sending unwanted data
    await onewireReset(deviceId);

    // Log the Celsius temperature
    tempCelsius = ((tempMSB * 256) + tempLSB) / 16.0;
    var temp2 = ((tempMSB << 8) + tempLSB) * 0.0625; //just another way of calculating it<br />
    System.Diagnostics.Debug.WriteLine("Temperature: " + tempCelsius + " degrees C " + temp2);
    }
    return tempCelsius;
    }
    }

    And finally the StartupTask

    public sealed class StartupTask : IBackgroundTask
    {
    private BackgroundTaskDeferral deferral;

    private OneWire onewire;
    private string deviceId = string.Empty;
    private bool inprog = false;
    private Timer timer;

    public void Run(IBackgroundTaskInstance taskInstance)
    {
    deferral = taskInstance.GetDeferral();

    onewire = new OneWire();
    deviceId = await onewire.GetFirstSerialPort();

    if(deviceId != null)
    await onewire.getTemperature(deviceId));

    BackgroundTaskDeferral.Complete();
    }

    }

    The problem I have is that when I run this code it hangs on one of the lines that disposes of the SerialDevice in OneWire class.

    I have read in a few places that its related to the BackgroundTask and using Async/Await