public async Task <byte> GAPConnectDirectAsync(string bluetoothAddress, BGGAPAdvertiserAddressType addressType, ushort connectIntervalMinMs, ushort connectIntervalMaxMs, ushort supervisionTimeoutMs, ushort latency) { const int TIMEOUT_MS = 6000; if (connectIntervalMinMs <= 7) { throw new ArgumentOutOfRangeException( nameof(connectIntervalMaxMs), "Connection Interval Min must be greater than 7ms" ); } var supervisionTimeoutMinMs = (1 + latency) * connectIntervalMaxMs * 2; if (supervisionTimeoutMs <= supervisionTimeoutMinMs) { throw new ArgumentException( "According to the specification, the Supervision Timeout in milliseconds " + "shall be larger than (1 + latency) * connectIntervalMaxMs * 2" ); } if (connectIntervalMaxMs < connectIntervalMinMs) { throw new ArgumentOutOfRangeException( nameof(connectIntervalMaxMs), "Connection Interval Max must be greater than or equal to Connection Interval Min" ); } var btaddr = DataConverter.HexStringToByteArray(bluetoothAddress); var type = (byte)addressType; var connIntMin = (UInt16)(connectIntervalMinMs / 1.25); var connIntMax = (UInt16)(connectIntervalMaxMs / 1.25); var timeout = (UInt16)(supervisionTimeoutMs / 10); var cmd = _bglib.BLECommandGAPConnectDirect(btaddr, type, connIntMin, connIntMax, timeout, latency); await _bglib.SendCommandAsync(cmd).ConfigureAwait(false); using (var cts = new CancellationTokenSource(TIMEOUT_MS)) { bool didTimeout = false; try { await _cmdRespWaitHandle.WaitAsync(cts.Token).ConfigureAwait(false); } catch (OperationCanceledException) { didTimeout = true; } if (didTimeout) { throw new TimeoutException(); } } if (_lastResult != 0) { var error = Enum.ToObject(typeof(BGErrorCode), _lastResult); string errMsg = $"GAPConnectDirect returned: error={error} code=0x{_lastResult:X4}"; throw new Exception(errMsg); } byte connectionHandle = ((ConnectDirectEventArgs)_lastResponseArgs).connection_handle; return(connectionHandle); }
public void Connect(CancellationToken connectToken, CancellationToken appToken, int connectTimeoutInMilliseconds, BgBleDevice deviceToConnect) { try { var lockTaken = false; Monitor.TryEnter(ThreadLock, 150, ref lockTaken); if (lockTaken) { if (_busy) { return; } _busy = true; Monitor.Exit(ThreadLock); } _device = deviceToConnect; _currentAction = new CancellationTokenSource(); var connectToDevicesTokenSource = CancellationTokenSource.CreateLinkedTokenSource(connectToken, _currentAction.Token); _bglib.SendCommand(_serialPort, _bglib.BLECommandGAPConnectDirect(deviceToConnect.Identifier, deviceToConnect.Advertisement.AddressType, 0x20, 0x30, 0x100, 0)); WaitHandle.WaitAny(new[] { connectToDevicesTokenSource.Token.WaitHandle }, connectTimeoutInMilliseconds); // cleanup takes 125ms _bglib.SendCommand(_serialPort, _bglib.BLECommandGAPEndProcedure()); WaitHandle.WaitAny(new[] { appToken.WaitHandle }, 130); _logger.LogInformation( $"ControlPlus Repository: Connected to device {deviceToConnect.Address} with {_device.Services.Count} services"); } catch (Exception exception) { _logger.LogWarning(exception, $"ControlPlus Repository: Unable to connect to device {deviceToConnect.Address}"); } _deviceService = null; _device = null; _busy = false; }