locked
How to read synchronously from StreamSocket on RFComm bluetooth connection?

    Question

  • Hi,

    I'm connecting to a RFComm bluetooth device from my Windows(8.1) Store App succesfuly. 

    The device stablishes a communication protocol, I write a command and read for a response. A command is simply a string and the response is also a string.

    The problem, that's why I'm asking to read synchronously, is that when I send an specific command, the response is broken. It was supposed to respond for example a bracket enclosed string: "[100, 2000, 300, 40]" but it responds like this: "[".

    As we can see, the expected string should have all the parameters enclosed in the brackets but it came only the starting bracket. 

    This happens the first time I write the command. I suspect that the device wasn't ready to respond or my logic wasn't ready to read all the data.

    Here is how I connect to the device:

    public async Task Connect() 
            {
                try
                {
                    var devicesInfoCollection = await DeviceInformation.FindAllAsync(
                                     RfcommDeviceService.GetDeviceSelector(RfcommServiceId.SerialPort));
    
                    var myDevice = devicesInfoCollection.FirstOrDefault(d => d.Name.ToUpper().Contains("DEVICE-NAME"));
    
                    var BTService = await RfcommDeviceService.FromIdAsync(myDevice.Id);
                    mySocket = new StreamSocket();
    
                    await mySocket.ConnectAsync(BTService.ConnectionHostName, BTService.ConnectionServiceName);
                    isConnected = true;
                }
                catch (Exception e) 
                {
                    isConnected = false;
                }
            }

    Here is how I write commands to the device:

     public async void WriteData(string data)
            {
                writer = new DataWriter(mySocket.OutputStream);
               
                writer.WriteString(data + "\r");
                await Task.Delay(1000);
                
                await writer.StoreAsync();
    
                writer.DetachBuffer();
                writer.DetachStream();
    
    
            }

    Here's how I read data (probably the problem is here):

     public async Task<string> ReadData()
            {
                reader = new DataReader(mySocket.InputStream);
                reader.InputStreamOptions = InputStreamOptions.Partial;
    
                await Task.Delay(1000);
    
                uint s = await reader.LoadAsync(1000);
                string data = reader.ReadString(s);
    
                System.Diagnostics.Debug.WriteLine(data);
    
                reader.DetachBuffer();
                reader.DetachStream();
                reader.Dispose();
                return data; 
            }

    Notice I put some delays in order to test it because I ran out of solutions of my own. Any help or point to any direction is much appreciated!

    Maybe I could read the data up until I found the last "]", it's possible to read async in a loop?

    Thanks!

    DevDoubts

    Tuesday, April 8, 2014 2:16 PM

All replies

  • Does changing the InputStreamOptions to 'None' or 'ReadAhead' change your repro? It seems like the '[' is initially returned without the other data, and as soon as the '[' is received the call returns and you only end up seeing the '['. Try switching the stream options and see if it helps.

    Windows Store Developer Solutions, follow us on Twitter: @WSDevSol|| Want more solutions? See our blog

    Tuesday, April 8, 2014 11:10 PM
    Moderator
  • Hi, thanks for your answer. No, changing the InputStreamOptions to None or ReadAhead does not help. It´s even worse, when the program reaches the line, uint s = await reader.LoadAsync(1000); on the read method, it does not process the read and only writes this on the ouput: The thread 0x1adc has exited with code 259 (0x103). Is there another way of reading besides LoadAsync? Thanks.
    Wednesday, April 9, 2014 12:46 PM
  • OK, here's my first thoughts:

    1. When writing, you really don't need that 1 second delay.  You also should probably just keep the datawriter around; there's not really much value in making it, using it for a single string, and then deleting it.

    2. For reading, you should be using the Partial option just like you've got.  (Otherwise, it's not supposed to return until you've read in the 1000 bytes)

    3. But you should be doing your reads in a loop.  As you suggest, you need to do a loadAsync()/ReadString() in   a loop.  I normally use the DataReader.UnconsumedBufferLength value as the input to my ReadString() when I read; it seems "neater" than to use the results of the LoadAsync().  And like you suggest, you should read until you get the ']' character that you're expecting.

    All developers should know that when you read in a stream of data, Windows can chop up the stream in whatever way seems useful -- packets can be either split into multiple parts, or consolidated into larger packets (really; it's an acceleration technique that a bunch of network cards have).  And this works all the way up the stack, where the different layers of the network stack can change what's going on.

    I've written code that works with the Bluetooth sockets (to support a joystick), and found that it does indeed work. 


    Network Developer Experience Team (Microsoft)

    Wednesday, April 9, 2014 9:39 PM
  • Thanks for your help.

    Concerning you first comment, about the 1 sec delay, I was testing, in fact troubleshooting trying to find a solution to other problem. When I first built the connection, it was in the same method as was writing and reading. Then, when debugging it would connect and then write and read perfectly but, when executing the program it would not write the command properly. It seemed that the process of connecting wasn't quite finished. That's why I did that.

    Now, the second comment, I did use Partial because any other was not working. When executing the reader.LoadAsync(...) without being Partial, the thread would just exit with no exception or error and without reading anything. It would just write "thread x exited with code xxx" on the output window. And the reason for the 1000 parameter to the LoadAsync, it's totally arbitrary, because trying to get the value of the stream would result in "Trying to read out boundaries value" exception.

    As for the third comment, now I need your help :) How would you do it? I'm trying this:

    public async Task<string> ReadData()
            {
                reader = new DataReader(mySocket.InputStream);
                reader.InputStreamOptions = InputStreamOptions.Partial;
    
                //await reader.LoadAsync(1024);
                string data = "";
                while (reader.UnconsumedBufferLength > 0) 
                {
                    data += reader.ReadString(1000);
                }
                 
                
                //System.Diagnostics.Debug.WriteLine(data);
    
                reader.DetachBuffer();
                reader.DetachStream();
                reader.Dispose();
                reader = null;
                return data; 
            }

    I could not find any where to get a concrete value to supply as parameter to the ReadString method. And still, it is returning only the first character when reading for the first time.

    Anyway, I appreciate your help!

    Thanks


    • Edited by DevDoubts Friday, April 11, 2014 3:58 AM
    Friday, April 11, 2014 3:57 AM
  • try this (psuedocode) instead:

    while (!data.EndsWith("]") {
        var nbytes = await reader.LoadAsync(1000); // get some of that new data into my DataReader
        if(nbytes == 0) break; // socket got closed on me
        data += reader.ReadString(reader.UnconsumedBufferLength)
    }


    Network Developer Experience Team (Microsoft)

    Friday, April 11, 2014 9:34 PM
  • Hi, 

    I think the asynchronous nature of the read is not helping me. I need to control de flow so writing and reading wouldn't get in the way of each other.

    With the loop, the problem of getting the first character is solved. But if I write/read certain amount of times repeatedly, I mean, first I write then I read, it gives an exception: the operation identifier is not valid.

    How to make sure that the async write and async read is done so I could send another write / read and not get any exception in the meantime?

    Thanks for all the help.

    Saturday, April 12, 2014 5:10 PM