Search code examples
c#bluetoothwindows-store-appsasync-awaitrfcomm

Workflow of RFComm communication in windows store apps


I've been strugling to make this work without success.

I have a third part device which will be controlled by my Windows Store app through bluetooth. The problem is the async await nature of the communication methods.

The app will first start a connection when a certain page loads. It will use this code to start the connection:

 public async Task Test() 
    {
        var loadedDevices = await DeviceInformation.FindAllAsync(RfcommDeviceService.GetDeviceSelector(RfcommServiceId.SerialPort));

        var foundDevice = loadedDevices.FirstOrDefault(x => x.Name == "DEVICE_NAME");

        if (foundDevice != null) 
        {

            var connection = getConnection(foundDevice);
        }

    }

    public async Task<RfcommDeviceService> getConnection(DeviceInformation device) 
    {
        return await RfcommDeviceService.FromIdAsync(device.Id);
    }

I did separate this from my app because it was just not working.

After getting the connection, I need to get the DataWriter and DataReader from connection stream.

The bluetooth device has a protocol which we write something and then read the response. But the mechanics of it are also async methods. To write a command I was using this method:

 private void SendCommand(string command)
    {
        Task.Run(async () => { await this.writer.FlushAsync(); }).Wait();
        this.writer.WriteString(command);
        Task.Run(async () => { await this.writer.StoreAsync(); }).Wait();
    }

And to read the data I was reading inside a while like this:

 while (!data.EndsWith("\n"))
        {
            uint messageLength = this.reader.UnconsumedBufferLength;
            uint nbytes = 0;

            Task.Run(async () => { nbytes = await this.reader.LoadAsync(1024); }).Wait();

            if (nbytes == 0)
            {
                iterates++;
                continue;
            }

            if (iterates > 3)
            {
                break;
            }

            iterates = 0;
            data += this.reader.ReadString(this.reader.UnconsumedBufferLength);
        }

The problem is that sometimes, I don't know why the connection works, sometimes doesn't. Sometimes it step over the connection or the write or read methods just ignoring the calls and returning null everywhere.

Please, any help towards the best practices of working with async/await with RFComm devices?

I've read a lot of things, questions here and there, but it seems that I lack the foundations (Which I read at MSDN) or explanation.

Any help is much appreciated!

Thanks


Solution

  • When you await an asynchronous operation it is already executed on a background thread, you don't need to add Task.Run. so the code below:

    Task.Run(async () => { nbytes = await this.reader.LoadAsync(1024); }).Wait();
    

    Can be written as:

    nbytes = await this.reader.LoadAsync(1024);
    

    You also don't need to call Wait as that is a blocking operation and will block the current thread until the operation completes. Another example is the method SendCommand

    private void SendCommand(string command)
    {
        await this.writer.FlushAsync();
        this.writer.WriteString(command);
        await this.writer.StoreAsync();
    }
    

    The methods in SendCommand will execute sequentially as the await effectively "pauses" the method until the operation completes. I think you need to learn a bit more about async/await. This article might help.