Xamarin Andriod Bluetooth -> Socket's behaviour

vmorinvmorin ✭✭Member ✭✭

I have an issue regarding Xamarin, Bluetooth via Andriod. When creating a socket when connecting

_socket.IsConnected is always true

I'm storing the MAC address to the latest connected device and is trying to reconnect to that device directly using.

await _socket.ConnectAsync()

That functions dosnt throw any exceptions even if the remote device is off from the start. To handle all this I have tried to implement my own "IsConnected" by actually sending data and see if I get any response, with a timeout.

However, if the connection failed due to the remote devices was turned off, I can never "reuse" the socket. I always get following error when calling again since the first one "passed" even with a device that is off:

_socket.ConnectAsync()

read failed, socket might closed, read ret: -1

Is there a way for me to "reset" the socket in some way? I have included the connection function here below if that makes any sence.

    public async Task<IDevice> Connect(BluetoothUnit device)
    {
        if (_connected)
            return Device(device.Type, this);

        var pinCode = DeviceManagement.PinCode(device.Type);
        var bluetoothDevice = BluetoothAdapter.DefaultAdapter.GetRemoteDevice(device.MAC);
        var setPin = bluetoothDevice.SetPin(Encoding.ASCII.GetBytes(pinCode));

        if (_bluetoothGatt is null)
            _bluetoothGatt = bluetoothDevice.ConnectGatt(Android.App.Application.Context, true, new BluetoothDisconnectCallback());
        _deviceType = device.Type;

        if ((int)Android.OS.Build.VERSION.SdkInt >= 10)
            _socket = bluetoothDevice.CreateInsecureRfcommSocketToServiceRecord(UUID.FromString(STANDARD_SPP));
        else
            _socket = bluetoothDevice.CreateRfcommSocketToServiceRecord(UUID.FromString(STANDARD_SPP));

        try
        {
            _bluetoothGatt.Connect();
            await _socket.ConnectAsync();
            if (!await ConnectionSuccesful(Device(device.Type, this)))
                return default(IDevice);

            BluetoothAdapter.DefaultAdapter.CancelDiscovery();
            _storage.Save(StorageKeys.LatestDevice, device);
            _connected = true;
            return Device(device.Type, this); ;
        }
        catch (Exception e)
        {
            EventLogger.TrackException(e, new Dictionary<string, string> { { $"Andriod.Bluetooth.Connect", "Error while connecting" }, { "Device", JsonConvert.SerializeObject(device) } });
            return default(IDevice);
        }
    }

    private async Task<bool> ConnectionSuccesful(IDevice device)
    {
        try
        {
            return await TaskHelper.RunTask(new Task(() =>
            {
                byte[] inputData = new byte[300];
                var bytes = _socket.InputStream.Read(inputData, 0, inputData.Length);
            }), 250);
        }
        catch (Exception e)
        {
            var msg = e.Message;
            return false;
        }

    }

Best Answer

  • vmorinvmorin ✭✭ ✭✭
    Accepted Answer

    I found the issue, could be good for everyone to know regarding socket failure:
    This causes the error Java.IO.IOException: "read failed, socket might closed or timeout, read ret: -1
    This was casued due to multiple threads calling _socket.ConnectAsync().
    So check that you dont start more then one task :)

Answers

  • GrahamMcKechnieGrahamMcKechnie ✭✭✭ AUMember ✭✭✭

    Your seem to be trying to combine both Bluetooth Classic and Bluetooth LE. You can't do that. What type of device are you trying to connect to - Classic or LE? If it is Bluetooth LE see my post for an example in the following thread https://forums.xamarin.com/discussion/90887/bluetooth-le-texas-instruments-sensortag-tutorial

  • vmorinvmorin ✭✭ Member ✭✭

    I using Bluetooth Classic. Which part is related to Bluetooth LE?
    I manage to get around a lot of issue by using following code and see if devices is connected instead of socket:

    _bluetoothReciever = new BluetoothReciever();
    RegisterReceiver(_bluetoothReciever, new IntentFilter(BluetoothDevice.ActionFound));
    RegisterReceiver(_bluetoothReciever, new IntentFilter(BluetoothDevice.ActionAclDisconnected));
    RegisterReceiver(_bluetoothReciever, new IntentFilter(BluetoothDevice.ActionAclConnected));

        public override async void OnReceive(Context context, Intent intent)
        {
            switch (intent.Action)
            {
                case BluetoothDevice.ActionFound:
                    var device = (BluetoothDevice)intent.GetParcelableExtra(BluetoothDevice.ExtraDevice);
                    if (!Comparer.ContainsOrdinalIgnoreCase(device.Name, Niox))
                        return;
    
                    var bluetoothUnit = device.ToBluetoothUnit();
                    if (!_devices.Any(d => Comparer.StringOrdinalIgnoreCase(d.MAC, bluetoothUnit.MAC)))
                        _devices.Add(bluetoothUnit);
                    _bluetooth.UpdateDeviceList(_devices.ToList());
                    break;
                case BluetoothDevice.ActionAclConnected:
                    _bluetooth.Connected = true;
                    break;
                case BluetoothDevice.ActionAclDisconnected:
                    _bluetooth.Connected = false;
                    await Engine.Disconnect();
                    break;
            }
        }
    
  • vmorinvmorin ✭✭ Member ✭✭

    After reading some I guess bluetoothgatt shouldnt be used by me...
    Thanks!

  • GrahamMcKechnieGrahamMcKechnie ✭✭✭ AUMember ✭✭✭

    Correct

  • vmorinvmorin ✭✭ Member ✭✭

    Still having issue with connecting, disconnecting and then connecting again when socket is casting following exception:
    _socket.ConnectAsync() read failed, socket might closed, read ret: -1

  • vmorinvmorin ✭✭ Member ✭✭
    Accepted Answer

    I found the issue, could be good for everyone to know regarding socket failure:
    This causes the error Java.IO.IOException: "read failed, socket might closed or timeout, read ret: -1
    This was casued due to multiple threads calling _socket.ConnectAsync().
    So check that you dont start more then one task :)

Sign In or Register to comment.