async Task DoFallbackReconnect(GattConnectionConfig config, CancellationToken ct) { if (this.Status == ConnectionStatus.Connected) { Log.Debug("Reconnect", "Reconnection successful"); } else { this.context.Close(); // kill current gatt if (ct.IsCancellationRequested) { Log.Debug("Reconnect", "Reconnection loop cancelled"); } else { Log.Debug("Reconnect", "Reconnection failed - handing off to android autoReconnect"); try { await this.context.Connect(config.Priority, true); } catch (Exception ex) { Log.Error("Reconnect", "Reconnection failed to hand off - " + ex); } } } }
async Task DoReconnect(GattConnectionConfig config, CancellationToken ct) { Log.Debug("Reconnect", "Starting reconnection loop"); this.connSubject.OnNext(ConnectionStatus.Connecting); var attempts = 1; while (!ct.IsCancellationRequested && this.Status != ConnectionStatus.Connected && attempts <= CrossBleAdapter.AndroidMaxAutoReconnectAttempts) { Log.Write("Reconnect", "Reconnection Attempt " + attempts); // breathe before attempting (again) await Task.Delay( CrossBleAdapter.AndroidPauseBetweenAutoReconnectAttempts, ct ); try { await this.context.Reconnect(config.Priority); } catch (Exception ex) { Log.Warn("Reconnect", "Error reconnecting " + ex); } attempts++; } if (this.Status != ConnectionStatus.Connected) { await this.DoFallbackReconnect(config, ct); } }
// TODO: do I need to watch for connection errors here? IDisposable CreateAutoReconnectSubscription(GattConnectionConfig config) => this .WhenStatusChanged() .Skip(1) // skip the initial "Disconnected" .Where(x => x == ConnectionStatus.Disconnected) .Select(_ => Observable.FromAsync(ct1 => this.DoReconnect(config, ct1))) .Merge() .Subscribe();
protected virtual void SetupAutoReconnect(GattConnectionConfig config) { if (this.ReconnectSubscription != null) { return; } if (!config.IsPersistent) { return; } this.cancelReconnect = false; this.ReconnectSubscription = this.WhenStatusChanged() .Skip(1) // skip the initial registration .Where(x => x == ConnectionStatus.Disconnected) .Subscribe(async x => { while (!this.cancelReconnect && this.Status != ConnectionStatus.Connected) { try { await Task.Delay(300); if (!this.cancelReconnect) { await this.Connect(config); } } catch (Exception ex) { Log.Out("Failed to reconnect to device - " + ex); } } }); }
public IObservable <object> Connect(GattConnectionConfig config) { // TODO: configurable "connection" type - RSSI check, timed read on first characteristic, device watcher // TODO: monitor devicewatcher - if removed d/c, if added AND paired - connected this.connSubject.OnNext(ConnectionStatus.Connected); this.status = ConnectionStatus.Connected; return(Observable.Return(new object())); }
public override IObservable <object> Connect(GattConnectionConfig config) => Observable.Create <object>(ob => { var sub = this.WhenStatusChanged() .Where(x => x == ConnectionStatus.Connected) .Subscribe(_ => ob.Respond(null)); this.context.Connect(); return(sub); });
public override IObservable <object> Connect(GattConnectionConfig config) { config = config ?? GattConnectionConfig.DefaultConfiguration; this.SetupAutoReconnect(config); return(Observable.Create <object>(ob => { var cancelSrc = new CancellationTokenSource(); var connected = this .WhenStatusChanged() .Take(1) .Where(x => x == ConnectionStatus.Connected) .Subscribe(_ => ob.Respond(null)); if (this.Status != ConnectionStatus.Connecting) { try { ob.OnNext(ConnectionStatus.Connecting); switch (AndroidConfig.ConnectionThread) { case ConnectionThread.MainThread: Application.SynchronizationContext.Post(_ => this.Context.Connect(config), null); break; case ConnectionThread.ScanThread: Task.Factory.StartNew( () => this.Context.Connect(config), cancelSrc.Token, TaskCreationOptions.None, this.scheduler ); break; case ConnectionThread.Default: default: this.Context.Connect(config); break; } } catch (Exception ex) { ob.OnNext(ConnectionStatus.Disconnected); ob.OnError(ex); } } return () => { connected?.Dispose(); cancelSrc.Dispose(); }; })); }
public override IObservable <object> Connect(GattConnectionConfig config) => Observable.FromAsync(async token => { //if (this.native == null) //this.native = await BluetoothLEDevice.FromIdAsync(this.deviceId); //this.native = await BluetoothLEDevice.FromBluetoothAddressAsync(0L); this.status = ConnectionStatus.Connected; this.connSubject.OnNext(ConnectionStatus.Connected); return(new object()); });
protected void DoConnect(IObserver <object> ob, GattConnectionConfig config) { try { this.connSubject.OnNext(ConnectionStatus.Connecting); if (!this.context.Connect(config)) { throw new ArgumentException("Unable to connect"); } ob.Respond(null); } catch (Exception ex) { this.connSubject.OnNext(ConnectionStatus.Disconnected); ob.OnError(ex); } }
public override IObservable <object> Connect(GattConnectionConfig config) { config = config ?? GattConnectionConfig.DefaultConfiguration; this.SetupAutoReconnect(config); return(Observable.Create <object>(ob => { IDisposable sub1 = null; IDisposable sub2 = null; if (this.Status == ConnectionStatus.Connected) { ob.Respond(null); } else { sub1 = this.context .PeripheralConnected .Where(x => x.Equals(this.peripheral)) .Subscribe(x => ob.Respond(null)); sub2 = this.context .FailedConnection .Where(x => x.Peripheral.Equals(this.peripheral)) .Subscribe(x => ob.OnError(new Exception(x.Error.ToString()))); this.context.Manager.ConnectPeripheral(this.peripheral, new PeripheralConnectionOptions { NotifyOnDisconnection = config.NotifyOnDisconnect, #if __IOS__ || __TVOS__ NotifyOnConnection = config.NotifyOnConnect, NotifyOnNotification = config.NotifyOnNotification #endif }); } return () => { sub1?.Dispose(); sub2?.Dispose(); }; })); }
public override IObservable <object> Connect(GattConnectionConfig config) => Observable.Create <object>(ob => { config = config ?? GattConnectionConfig.DefaultConfiguration; IDisposable sub1 = null; IDisposable sub2 = null; if (this.Status == ConnectionStatus.Connected) { ob.Respond(null); } else { sub1 = this.context .PeripheralConnected .Where(x => x.Equals(this.peripheral)) .Subscribe(x => { if (config.IsPersistent) { this.autoReconnect = this.SetupAutoReconnect(); } ob.Respond(null); }); sub2 = this.context .FailedConnection .Where(x => x.Peripheral.Equals(this.peripheral)) .Subscribe(x => ob.OnError(new Exception(x.Error.ToString()))); this.DoConnection(); } return(() => { sub1?.Dispose(); sub2?.Dispose(); }); });
public override IObservable <object> Connect(GattConnectionConfig config) => Observable.Create <object>(async ob => { var connected = false; config = config ?? GattConnectionConfig.DefaultConfiguration; var sub1 = this.WhenStatusChanged() .Where(x => x == ConnectionStatus.Connected) .Subscribe(_ => { connected = true; if (config.IsPersistent) { this.autoReconnectSub = this.CreateAutoReconnectSubscription(config); } ob.Respond(null); }); var sub2 = this.connFailSubject.Subscribe(x => { this.connSubject.OnNext(ConnectionStatus.Disconnected); this.context.Gatt?.Close(); ob.OnError(new Exception("Connection failed - " + x)); }); this.connSubject.OnNext(ConnectionStatus.Connecting); await this.context.Connect(config.Priority, config.AndroidAutoConnect); return(() => { if (!connected) { this.context.Gatt?.Close(); this.connSubject.OnNext(ConnectionStatus.Disconnected); } sub1.Dispose(); sub2.Dispose(); }); });
public abstract IObservable <object> Connect(GattConnectionConfig config);
public override IObservable <object> Connect(GattConnectionConfig config) { throw new NotImplementedException(); }
public override IObservable <object> Connect(GattConnectionConfig config) => Observable.Create <object>(ob => { this.native.GattConnect(config.AutoConnect); return(() => { }); });