Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exception: Read failed, socket might closed or timeout, read ret: -1 #3

Open
Midnayt opened this issue Jun 24, 2021 · 9 comments
Open

Comments

@Midnayt
Copy link

Midnayt commented Jun 24, 2021

Hi, I'am trying to send data to device when user click a button. First time everything is OK. But, when I click the button second time, I receive IOException exception with message "Read failed, socket might closed or timeout, read ret: -1". The problem is in bluetoothSocket.connect(); function. It's android problem after android 4.2.

@rostislav-nikitin
Copy link
Owner

Did you create a new connection instance on each click or reusing the same connection?

@Midnayt
Copy link
Author

Midnayt commented Jun 25, 2021

Did you create a new connection instance on each click or reusing the same connection?

I have a 3 buttons - Create connection, Send data and Close connection. First time, it all works fine. but second time,when previous connection is closed and I try to create new one - receive this error
processed (1)
processed (2)
processed (3)

`public class BLEPageViewModel : ViewModelBase
{
private readonly IBluetoothAdapter _bluetoothAdapter;
public IBluetoothManagedConnection CurrentBluetoothConnection { get; private set; }

    private BluetoothDeviceModel _device;
    public BluetoothDeviceModel Device
    {
        get => _device;
        set => SetProperty(ref _device, value);
    }

    private byte[] Received { get; set; }

    private bool _isReceived;
    public bool IsReceived
    {
        get => _isReceived;
        set => SetProperty(ref _isReceived, value);
    }

    private string _deviceStatus;
    public string DeviceStatus
    {
        get => _deviceStatus;
        set => SetProperty(ref _deviceStatus, value);
    }

    private bool _isConnected;
    public bool IsConnected
    {
        get => _isConnected;
        set => SetProperty(ref _isConnected, value);
    }

    private string _result;
    public string Result
    {
        get => _result;
        set => SetProperty(ref _result, value);
    }

    private ObservableCollection<string> _logs;
    public ObservableCollection<string> Logs
    {
        get => _logs;
        set => SetProperty(ref _logs, value);
    }

    public DelegateCommand TransmiteBytesCommand { get; private set; }
    public DelegateCommand CreateManagedConnectionCommand { get; private set; }
    public DelegateCommand CloseManagedConnectionCommand { get; private set; }

    public BLEPageViewModel(
        INavigationService navigationService,
        ILogAPI logAPI) : base(navigationService, logAPI)
    {
        _bluetoothAdapter = DependencyService.Resolve<IBluetoothAdapter>();

        Logs = new ObservableCollection<string>
        {
            "Start"
        };
        IsPage = false;
        CreateManagedConnectionCommand = new DelegateCommand(async () => await ExecuteCreateManagedConnectionCommand());
        TransmiteBytesCommand = new DelegateCommand(ExecuteTransmiteBytesCommand);
        CloseManagedConnectionCommand = new DelegateCommand(ExecuteCloseManagedConnectionCommand);
    }

    #region constructors

    public override async void OnNavigatedTo(INavigationParameters parameters)
    {
        base.OnNavigatedTo(parameters);
        if (!await CheckLocationPermission())
            return;
        if (_bluetoothAdapter.Enabled)
        {
            foreach (var dev in _bluetoothAdapter.BondedDevices)
            {
                Debug.WriteLine($"{dev.Name}");
            }
            if (_bluetoothAdapter.BondedDevices.Any(x => x.Name.Contains("TaiDoc-Device")))
            {
                Device = _bluetoothAdapter.BondedDevices.First(x => x.Name.Contains("TaiDoc-Device"));
                DeviceStatus = "Device Connected";
                IsConnected = true;
                Logs.Add("Device Connected");
            }
            else
            {
                DeviceStatus = "Device Not Found";
                IsConnected = false;
            }
        }
    }

    #endregion

    #region functions

    private async Task ExecuteCreateManagedConnectionCommand()
    {
        try
        {
            Logs.Add("Start connection");
            var connection = _bluetoothAdapter.CreateManagedConnection(Device);
            connection.Connect();
            Logs.Add(connection.ConnectionState.ToString());
            CurrentBluetoothConnection = connection;
            if (CurrentBluetoothConnection is not null)
            {
                CurrentBluetoothConnection.OnStateChanged += OnStateChanged;
                CurrentBluetoothConnection.OnRecived += CurrentBluetoothConnection_OnRecived;
                CurrentBluetoothConnection.OnError += CurrentBluetoothConnection_OnError;
            }
        }
        catch (BluetoothConnectionException exception)
        {
            await ShowErrorMessage(
                $"Can not connect to the device: {Device.Name}" +
                    $"({Device.Address}).\n" +
                    $"Exception: \"{exception.Message}\"\n" +
                    "Please, try another one."
                );
            return;
        }
        catch (Exception exception)
        {
            await ShowErrorMessage(exception.Message);
            return;
        }
    }

    private void OnStateChanged(object sender, StateChangedEventArgs stateChangedEventArgs)
    {
        Logs.Add(stateChangedEventArgs.ConnectionState.ToString());
    }

    private void CurrentBluetoothConnection_OnRecived(object sender, RecivedEventArgs recivedEventArgs)
    {
        Logs.Add("Start receiving");
        Received = recivedEventArgs.Buffer.ToArray();
        if (Received?.Length > 0)
        {
            Logs.Add($"Received: {Received.Length} bytes");
            IsReceived = true;
            foreach (byte b in Received)
                Logs.Add(b.ToString());
        }
        Logs.Add("End receiving");
    }

    private void CurrentBluetoothConnection_OnError(object sender, System.Threading.ThreadExceptionEventArgs threadExceptionEventArgs)
    {
        Logs.Add(threadExceptionEventArgs.Exception.Message);
    }

    private void ExecuteTransmiteBytesCommand()
    {
        if (CurrentBluetoothConnection?.ConnectionState != ConnectionState.Connected)
            return;
        CurrentBluetoothConnection.Transmit(new byte[] { 0x51, 0x24, 0, 0, 0, 0, 0xA3, 24 });
    }

    private void ExecuteCloseManagedConnectionCommand()
    {
        try
        {
            CurrentBluetoothConnection.Dispose();
        }
        catch (Exception ex) {
            Logs.Add(ex.Message);
        }
    }

    #endregion
    
    private async Task<bool> CheckLocationPermission()
    {
        var status = await Permissions.CheckStatusAsync<Permissions.LocationWhenInUse>();
        if(status != PermissionStatus.Granted)
        {
            await Permissions.RequestAsync<Permissions.LocationWhenInUse>();
        }
        status = await Permissions.CheckStatusAsync<Permissions.LocationWhenInUse>();
        return status == PermissionStatus.Granted;
    }
}`

@rostislav-nikitin
Copy link
Owner

rostislav-nikitin commented Jun 25, 2021

Hello.
JFYI: The managed connections are long-time living ones. For this type of connections you just need to create them once and re-use them. Not to create new ones on each data send.

@Midnayt
Copy link
Author

Midnayt commented Jun 25, 2021

Hello.
JFYI: The managed connections are long-time living ones. For this type of connections you just need to create them once and re-use them. Not to create new ones on each data send.

I see. But, how properly close, remove this connection? because, if I'm testing and relaunch app connection will receive error

@rostislav-nikitin
Copy link
Owner

rostislav-nikitin commented Jun 25, 2021

I looked into my code and found that I put ManagedBluetoothConnection into the App level. And on appear event it closing the connection if it opened.
And then the app shows the "Select device" screen and trying to connect again on any item selected.
And this worked for me without any errors. But I see your code is very similar. Strange...
Below I cut this code, and this is a source file: https://github.com/rostislav-nikitin/Plugin.BluetoothClassic/blob/master/examples/Digit/Digit/SelectBluetoothRemoteDevicePage.xaml.cs.

P.S. I used Samsung Galaxy Note 9 with Android 10 to test.

protected override async void OnAppearing()
{
    RefreshUI();
    await DisconnectIfConnectedAsync();
}
private async Task DisconnectIfConnectedAsync()
{
    if (App.CurrentBluetoothConnection != null)
    {
        try
        {
            App.CurrentBluetoothConnection.Dispose();
        }
        catch (Exception exception)
        {
            await DisplayAlert("Error", exception.Message, "Close");
        }
    }
}

@rostislav-nikitin
Copy link
Owner

rostislav-nikitin commented Jun 25, 2021

Also, did you try this example: https://github.com/rostislav-nikitin/Plugin.BluetoothClassic/tree/master/examples/Digit/Digit
Is it works on your device, or also raise IOException?

@Midnayt
Copy link
Author

Midnayt commented Jun 25, 2021

Need to test.
But have a question again. When I used not managed connection(with using), same error appear when tried send second time. Maybe it is issue with Samsung device.
BWT, how to get response bytes with IBluetoothConnection, ReciveAsync returns only int value

@rostislav-nikitin
Copy link
Owner

For the managed connection I think, after you closed the connection, you need again select the device (new instance) from the bounded devices and then try to create a new connection for a newly selected device.

About response bytes:
This is one of the signatures:
Task<int> ReciveAsync(byte[] buffer, int offset, int count) to receive data from the remote Bluetooth device asynchronously

It accepts a reference to the response buffer as a bytes array, offset and count of bytes to receive and yep, it returns int - the real cont of bytes received.

This is documentation to other methods: https://github.com/rostislav-nikitin/Plugin.BluetoothClassic#ibluetoothconnection-idisposable

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants
@rostislav-nikitin @Midnayt and others