/// <summary> /// Run actual filmware upgrade procedure (Secure DFU) /// </summary> /// <param name="device">Device which is switched to Secure DFU mode</param> /// <param name="FirmwarePath"></param> /// <param name="InitFilePath"></param> /// <returns></returns> private async Task RunSecureDFU(IDevice device, Stream FirmwarePacket, Stream InitPacket) { IGattCharacteristic controlPoint = null; IGattCharacteristic packetPoint = null; //await RefreshGattAsync(device); device.Connect(); await device.ConnectWait().Timeout(DeviceConnectionTimeout); // Request MTU only once await device.RequestMtu(256).Timeout(OperationTimeout); controlPoint = await device.GetKnownCharacteristics(DfuService, SecureDFUControlPointCharacteristic).Timeout(OperationTimeout); packetPoint = await device.GetKnownCharacteristics(DfuService, SecureDFUPacketCharacteristic).Timeout(OperationTimeout); await controlPoint.EnableNotifications(true); try { await SendInitPacket(device, InitPacket, controlPoint, packetPoint); await SendFirmware(device, FirmwarePacket, controlPoint, packetPoint); } catch (Exception) { await Cleanup(controlPoint, device); throw; } finally { await Cleanup(controlPoint, device); } }
/// <summary> /// /// </summary> /// <param name="characteristic"></param> /// <param name="useIndicationIfAvailable"></param> /// <returns></returns> public static IObservable <CharacteristicResult> RegisterAndNotify(this IGattCharacteristic characteristic, bool useIndicationIfAvailable = false) => characteristic .EnableNotifications(useIndicationIfAvailable) .Where(x => x) .Select(x => characteristic.WhenNotificationReceived()) .Switch() .Finally(() => characteristic.DisableNotifications().Subscribe());
public async Task <CharacteristicGattResult> GetNotifyResult(IGattCharacteristic characteristic) { await characteristic.EnableNotifications(); var TXN = await characteristic.RegisterAndNotify(); return(await characteristic.WhenNotificationReceived()); }
/// <summary> /// Enables notifications and hooks it for discovered characteristic. When subscription is disposed, it will also clean up. /// </summary> /// <param name="characteristic"></param> /// <param name="useIndicationIfAvailable"></param> /// <returns></returns> public static IObservable <CharacteristicGattResult> RegisterAndNotify(this IGattCharacteristic characteristic, bool useIndicationIfAvailable = false) => characteristic .EnableNotifications(useIndicationIfAvailable) .Select(x => x.Characteristic.WhenNotificationReceived()) .Switch() .Finally(() => characteristic .DisableNotifications() .Where(x => x.Characteristic.Service.Device.Status == ConnectionStatus.Connected) .Subscribe( _ => {}, ex => Log.Warn( BleLogCategory.Characteristic, "Could not cleanly disable notifications in RegisterAndNotify - " + ex ) ) );
public static IObservable <CharacteristicResult> WhenReadOrNotify(this IGattCharacteristic character, TimeSpan readInterval) { if (character.CanNotify()) { return(character .EnableNotifications() .Where(x => x) .Select(x => character.WhenNotificationReceived()) .Switch()); } if (character.CanRead()) { return(character.ReadInterval(readInterval)); } throw new ArgumentException($"Characteristic {character.Uuid} does not have read or notify permissions"); }
/// <summary> /// Enables notifications and hooks it for discovered characteristic. When subscription is disposed, it will also clean up. /// </summary> /// <param name="characteristic"></param> /// <param name="useIndicationIfAvailable"></param> /// <param name="autoCleanup"></param> /// <returns></returns> public static IObservable <CharacteristicGattResult> RegisterAndNotify(this IGattCharacteristic characteristic, bool useIndicationIfAvailable = false, bool autoCleanup = true) { var ob = characteristic .EnableNotifications(useIndicationIfAvailable) .Select(x => x.Characteristic.WhenNotificationReceived()) .Switch(); if (autoCleanup) { ob = ob.Finally(() => characteristic .DisableNotifications() .Where(x => x.Characteristic.Service.Peripheral.Status == ConnectionState.Connected) .Subscribe( _ => { }, ex => Log.Write(ex) ) ); } return(ob); }
private async Task CharacteristicsDiscovered(IGattCharacteristic result) { await result.Read(); await result.EnableNotifications(); result.WhenNotificationReceived().Subscribe(); //Zmiany w interfejsie this.RunOnUiThread(() => { FindViewById <AppCompatImageButton>(Resource.Id.buttonClear).Click += buttonClearClicked; FindViewById <AppCompatImageButton>(Resource.Id.buttonClear).Visibility = ViewStates.Visible; FindViewById <AppCompatImageButton>(Resource.Id.buttonColor).Click += buttonColorClicked; FindViewById <AppCompatImageButton>(Resource.Id.buttonColor).Visibility = ViewStates.Visible; FindViewById <AppCompatImageButton>(Resource.Id.buttonText).Click += buttonAddText; FindViewById <AppCompatImageButton>(Resource.Id.buttonText).Visibility = ViewStates.Visible; FindViewById <Android.Widget.LinearLayout>(Resource.Id.linearLayout1).AddView(drawView); FindViewById <TextInputEditText>(Resource.Id.textInputEditText1).Visibility = ViewStates.Visible; FindViewById <FloatingActionButton>(Resource.Id.fab).Click += FabOnClick; FindViewById <FloatingActionButton>(Resource.Id.fab).Visibility = ViewStates.Visible; }); gattCharacteristic = result; drawExist = true; Snackbar.Make(FindViewById <Android.Widget.LinearLayout>(Resource.Id.linearLayout), "Połączono", Snackbar.LengthShort) .SetAction("Action", (View.IOnClickListener)null).Show(); this.RGB = drawView.GetColor(); sendColorToArduino(); }
public async Task <bool> ToggleNotify(IGattCharacteristic Characteristic) { if (Characteristic.IsNotifying) { this.watcher?.Dispose(); this.IsNotifying = false; } else { this.IsNotifying = true; //var utf8 = await UserDialogs.Instance.ConfirmAsync( // "Display Value as UTF8 or HEX?", // okText: "UTF8", // cancelText: "HEX" //var utf8 = false; ////); //this.watcher = Characteristic // .RegisterAndNotify() // .Subscribe(x => this.SetReadValue(x, utf8)); await Characteristic.EnableNotifications(); } return(IsNotifying); }
/// <summary> /// Enables (and disables) notifications and hooks to listener /// </summary> /// <param name="characteristic"></param> /// <param name="useIndicationsIfAvailable"></param> /// <returns></returns> public static IObservable <GattCharacteristicResult> Notify(this IGattCharacteristic characteristic, bool useIndicationsIfAvailable = false) => characteristic .EnableNotifications(true, useIndicationsIfAvailable) .Select(_ => characteristic.WhenNotificationReceived()) .Switch() .Finally(() => characteristic.EnableNotifications(false).Subscribe());
/// <summary> /// Switch device in Secure DFU state /// ! IMPORTANT, assumes that each device has different name ! /// </summary> /// <param name="device"></param> /// <returns>Device which is in buttonles state</returns> private async Task <IDevice> ButtonlessDFUWithoutBondsToSecureDFU(IDevice device) { Debug.WriteLineIf(LogLevelDebug, String.Format("Start of Buttonless switching")); //await RefreshGattAsync(device); IGattCharacteristic buttonlessCharacteristic = null; TaskCompletionSource <CharacteristicGattResult> notif = null; device.Connect(); device = await device.ConnectWait().Timeout(DeviceConnectionTimeout); buttonlessCharacteristic = await device.GetKnownCharacteristics(DfuService, DfuButtonlessCharacteristicWithoutBonds).Timeout(OperationTimeout); await buttonlessCharacteristic.EnableNotifications(true).Timeout(OperationTimeout); // Change device Name // Advertisment name should not be longer than 20 symbols var newFullName = device.Name + "DFU"; var newName = new string(newFullName.Take(20).ToArray()); byte[] name = Encoding.ASCII.GetBytes(newName); int newNameLen = name.Length; byte[] newNameCommand = new byte[newNameLen + 1 + 1]; newNameCommand[0] = CChangeAdvertisedName; newNameCommand[1] = (byte)(uint)newNameLen; name.CopyTo(newNameCommand, 2); var nameChangeNotif = GetTimedNotification(buttonlessCharacteristic); await buttonlessCharacteristic.Write(newNameCommand).Timeout(OperationTimeout); var nameChangeResult = await nameChangeNotif.Task; Debug.WriteLineIf(LogLevelDebug, String.Format("Device name change response {0}", nameChangeResult.Data != null ? BitConverter.ToString(nameChangeResult.Data) : "Empty")); // Jump from the main application to Secure DFU bootloader (Secure DFU mode) notif = GetTimedNotification(buttonlessCharacteristic); await buttonlessCharacteristic.Write(CEnterDFU).Timeout(OperationTimeout); var result = await notif.Task; Debug.WriteLineIf(LogLevelDebug, String.Format("Restart response {0}", result.Data != null ? BitConverter.ToString(result.Data) : "Empty")); await buttonlessCharacteristic.DisableNotifications(); /* * The response received from the DFU device contains: * +---------+--------+----------------------------------------------------+ * | byte no | value | description | * +---------+--------+----------------------------------------------------+ * | 0 | 0x20 | Response code | * | 1 | 0x01 | The Op Code of a request that this response is for | * | 2 | STATUS | Status code | * +---------+--------+----------------------------------------------------+ */ int status = result.Data[2]; if (status != ButtonlessSwitchSuccessCode) { throw new Exception("Init status not correct " + status); } bool alreadyRestarted = false; IDisposable dispose = null; dispose = device.WhenStatusChanged().Subscribe(res => { if (res == ConnectionStatus.Disconnected || res == ConnectionStatus.Disconnecting) { alreadyRestarted = true; } Debug.WriteLine("###################### STAT {0}", res); }); dispose?.Dispose(); if (!alreadyRestarted) { await device.WhenDisconnected().Take(1).Timeout(DeviceRestartTimeout); device.CancelConnection(); } IDevice newDevice = await ScanDFUDevice(device, newName); Debug.WriteLineIf(LogLevelDebug, String.Format("End of Buttonless switching")); return(newDevice); }
/// <summary> /// Ensures connection status. Connects device if necessary. /// </summary> public override void EnsureConnection() { // Stop scan if device gets connected EEDeviceManagerFactory.DeviceManager.StopScan(); if (_bleDevice != null && !_bleDevice.IsConnected()) { bool success = Task.Run(async() => { _bleDevice.Connect(new ConnectionConfig { AutoConnect = true, AndroidConnectionPriority = ConnectionPriority.High }); // Change MTU size to at least 256 bytes otherwise protocol might not work int mtu = await _bleDevice.RequestMtu(256); if (mtu < 256) { Diagnostic.Msg(1, "EnsureConnection", "Unable to set MTU size to 256. Communication might not work correctly."); } else { Diagnostic.Msg(1, "EnsureConnection", "Set MTU size to " + mtu); } int loopCnt = 0; while (loopCnt < 100 && !_bleDevice.IsConnected()) { loopCnt++; await Task.Delay(100); } if (!_bleDevice.IsConnected()) { // Could not connect to device return(false); } await _bleDevice.DiscoverServices(); // Check rx Characteristic for notification or indication IGattCharacteristic rxCharacteristic = await _bleDevice.GetCharacteristicsForService(ServiceUuid) .FirstOrDefaultAsync(x => x.Uuid == RxCharacteristicUuid); if (!rxCharacteristic.CanNotifyOrIndicate()) { return(false); } // Enable notification/indication on device await rxCharacteristic.EnableNotifications(true); rxCharacteristic.WhenNotificationReceived().Subscribe(result => { _stopWatch.Stop(); lock (_lockDebugInfo) { if (_responseTimeMs.Count >= 1000) { _responseTimeMs.RemoveAt(0); } _responseTimeMs.Add(_stopWatch.ElapsedMilliseconds); } foreach (byte b in result.Data) { _queueRx.Enqueue(b); } }); return(_bleDevice.IsConnected()); }).Result; Connected = success; if (!success) { // Could not connect to device Diagnostic.Msg(1, "EnsureConnection", "Could not connect to device"); return; } else { // Need to send DIAS to keep connection open var ee31 = new Protocol.EE31Protocol(this); IEECommandResult result = ee31.ExecuteCommand(EE31Command.Discovery, new DiscoveryCmdParams(DiscoveryCmdParams.BuildNewDiscoveryId(), 0, 20, 500, 0xAF)); if (result.Code != EECmdResultCode.Success) { Diagnostic.Msg(1, "EnsureConnection", "Failed to send DIAS command (" + result.Code.ToString() + ")"); } } } _cmdTx = 0x0; while (!_queueRx.IsEmpty) { _queueRx.TryDequeue(out byte dummy); } }
private void ConnectToServer() { server.Connect(); Server_Name.Text = "Currently connected to " + server.Name; server.WhenAnyCharacteristicDiscovered().Subscribe(characteristic => { //Debug.WriteLine("Char" + characteristic.Uuid); }); //set up identity management server.GetKnownCharacteristics(StaticGuids.buzzerServiceGuid, StaticGuids.identityCharGuid).Subscribe(identityChar => { Debug.WriteLine("Found Identity char"); this.identityChar = identityChar; //writing nickname allows server to create association b/w uuid and nickname identityChar.Write(Encoding.UTF8.GetBytes(nickname)).Subscribe(write => { Debug.WriteLine("Successful identity write"); }, error => { Debug.WriteLine(error.GetBaseException()); }); identityChar.Read().Subscribe(read => { addOne(LoadLabel); clientGuid = Guid.Parse(Encoding.UTF8.GetString(read.Data)); Debug.WriteLine("Found own GUID: " + clientGuid.ToString()); }, error => { Debug.WriteLine(error.ToString()); }); }); //set up lock status server.GetKnownCharacteristics(StaticGuids.buzzerServiceGuid, StaticGuids.lockStatusGuid).Subscribe(lockStatusChar => { Debug.WriteLine("Found Lock char"); lockStatusChar.EnableNotifications(); lockStatusChar.WhenNotificationReceived().Subscribe(result => { Debug.WriteLine("Notification recieved" + Encoding.UTF8.GetString(result.Data)); string reply = Encoding.UTF8.GetString(result.Data); char tempLockState = reply[0]; Debug.WriteLine(reply.Substring(1, 36)); Guid buzzDevice = Guid.Parse(reply.Substring(1, 36)); //TODO fix risk that client guid is not yet found if (buzzDevice == clientGuid) { tempLockState = 'U'; } lockStatus = tempLockState; addOne(LoadLabel); }); }); //set up buzz char server.GetKnownCharacteristics(StaticGuids.buzzerServiceGuid, StaticGuids.buzzCharGuid).Subscribe(buzzerChar => { Debug.WriteLine("Found buzzer char"); this.buzzerChar = buzzerChar; addOne(LoadLabel); }); //set up team info server.GetKnownCharacteristics(StaticGuids.buzzerServiceGuid, StaticGuids.teamCharGuid).Subscribe(teamChar => { Debug.WriteLine("Team char found"); teamChar.EnableNotifications(); teamChar.WhenNotificationReceived().Subscribe(result => { Debug.WriteLine("Team info recieved"); string teamInfoString = Encoding.UTF8.GetString(result.Data); string[] teamInfo = teamInfoString.Split(teamSplitter, 2, StringSplitOptions.None); foreach (string teamString in teamInfo) { string[] names = teamString.Split(nameSplitter, 50, StringSplitOptions.None); if (!teams.ContainsKey(names[0])) { teams[names[0]] = new List <Guid>(); } List <Guid> teamMembers = teams[names[0]]; for (int i = 1; i < names.Length; i++) { teamMembers.Add(Guid.Parse(names[i])); } } addOne(LoadLabel); }); }); }
public override IObservable <CharacteristicGattResult> EnableNotifications(bool enableIndicationsIfAvailable) { return(chs.EnableNotifications()); }