Esempio n. 1
0
 /// <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());
Esempio n. 2
0
 /// <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
                  )
              )
          );
        /// <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);
        }
Esempio n. 4
0
        /// <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);
        }
Esempio n. 5
0
        /// <summary>
        /// Close connections, try to reenter standart mode, unsubscribe notifications
        /// </summary>
        /// <returns></returns>
        private async Task Cleanup(IGattCharacteristic controlPoint, IDevice device)
        {
            await controlPoint.DisableNotifications();

            device.CancelConnection();
        }