2

I'm trying to receive data via bluetooth in Xamarin.Android. If I have data to receive, my method work fine. But if nothing has been sent, nothing is returned from Stream.Read method (_inputStream.Read(buffer, 0, buffer.Length)).

Any idea what am I doing wrong?

private Stream _inputStream;

public string ReceiveData()
{
    byte[] buffer = new byte[30];

    try
    {
        while (true)
        {
            int read = _inputStream.Read(buffer, 0, buffer.Length);

            if (read <= 0)
            {
                return null;
            }

            char[] result = Encoding.ASCII.GetChars(buffer);

            if (!result[0].Equals("\0"))
            {
                return result[0].ToString();
            }
        }
    }
    catch (Exception)
    {
        // Não implementado
    }

    return null;
}

The problem is in the line _inputStream.Read(buffer, 0, buffer.Length). If nothing has been sent via bluetooth, I get stuck in it. Nothing is returned, no exception is raised.

EDIT 1

As @rene suggested, I tried with Task/Async with a CancellationToken with 1500 ms. I get the same behavior.

public async Task<string> ReceiveData()
{
    byte[] buffer = new byte[30];
    CancellationTokenSource token = new CancellationTokenSource();
    token.CancelAfter(TimeSpan.FromMilliseconds(1500));

    try
    {
        while (true)
        {
            int read = await _inputStream.ReadAsync(buffer, 0, buffer.Length, token.Token);

            if (read <= 0)
            {
                return null;
            }

            char[] result = Encoding.ASCII.GetChars(buffer);

            if (!result[0].Equals("\0"))
            {
                return result[0].ToString();
            }
        }
    }
    catch (Exception ex)
    {
        // Não implementado
    }

    return null;
}
gregoryp
  • 920
  • 4
  • 15
  • 35

1 Answers1

2

As told by James Harmon in Cancel ReadAsync, it is not possible to cancel an Stream.ReadAsync since the internal call is unmanaged and uses IOCompletion ports.

He suggest three options to get around this:

  1. Use Socket.Shutdown(). This will return ReadAsync with a socket error of OperationAborted.
  2. Wait for the read to timeout.
  3. Check if data is available before reading from the socket.

I opted for the third option by checking if data is available before reading the socket.

My final code:

public async Task<string> ReceiveData()
{
    byte[] buffer = new byte[30];

    try
    {
        while (true)
        {
            if(_inputStream.IsDataAvailable())
            {
                int read = await _inputStream.ReadAsync(buffer, 0, buffer.Length);

                if (read <= 0)
                {
                    return null;
                }

                char[] result = Encoding.ASCII.GetChars(buffer);

                if (!result[0].Equals("\0"))
                {
                    return result[0].ToString();
                }
            }
        }
    }
    catch (Exception)
    {
        // Não implementado
    }

    return null;
}

Thank you very much H.G. Sandhagen.

gregoryp
  • 920
  • 4
  • 15
  • 35