Как отключить после прочтения характеристики c? - PullRequest
0 голосов
/ 22 апреля 2020

Я работаю с температурным датчиком и могу выполнить простую команду «подать звуковой сигнал» на устройство. Это включает в себя прослушивание рекламы и отправку пароля перед отправкой команды, чтобы подать звуковой сигнал с WriteValueAsyn c. Я могу сделать один звуковой сигнал, и если я подожду некоторое время, я могу нажать кнопку и дать второй звуковой сигнал. Тем не менее, он пытается подать звуковой сигнал подряд, что вызывает у меня горе. Учитывая, что устройство BLE объявляет каждые 1,285 секунды, а я жду до 20 секунд и все еще испытываю проблемы с последующими командами, я предполагаю, что я все еще подключен, и устройство не вернулось к рекламе. Поэтому мой вопрос:

Как отключить сеанс BLE?

Я знаю, что людям нравится видеть полный код, поэтому я разместил его ниже. Но учитывая количество дополнительной информации (я учусь и что распечатывать промежуточные шаги), я решил выделить ключевые моменты. Я могу слушать рекламу, настроив BluetoothLEAdvertWatcher и зарегистрировавшись для обратных вызовов. В рамках этого обратного вызова я определяю, что это правильное устройство BLE, и устанавливаю событие, которое позволяет моему коду продолжаться. Событие может также прерваться, если не появятся подходящие рекламные объявления, и это происходит во второй раз!
После получения правильной рекламы я смотрю на услуги и одну конкретную характеристику c в этой службе. Найдя, я посылаю несколько команд для аутентификации. Это включает WriteValueWithResultAsyn c и регистрацию обратного вызова для характеристики c. В этом обратном вызове я посылаю команду, чтобы подать звуковой сигнал устройству.
Однако я ничего не делаю, чтобы «отключить» или перезапустить рекламу.

1. Как изящно отключить, чтобы реклама могла перезапустить

2. Почему я должен это делать вообще? Я подумал, что если я не установил сопряжение с устройством, в этом не было необходимости.

Являются ли команды WriteValueWithResultAsyn c, WriteValueAsyn c и ReadValueAsyn c установлением соединения? Это то же самое, что и «сопряжение»?

ПОЛНЫЙ КОД

public async Task ConnectAndBeep(uint serialNumber)
{
    ushort probeRawValue = 0;
    ushort ambientRawValue = 0;
    byte rawVoltage = 0;
    BluetoothLEDevice device = null;

    var advertWatcher = new BluetoothLEAdvertisementWatcher()
    {
        // should we use active or passive?
        ScanningMode = BluetoothLEScanningMode.Active
    };

    // set up filter so we don't get iPad, Tiles etc.
    var manufacturerDataFilter = new BluetoothLEManufacturerData();
    manufacturerDataFilter.CompanyId = 0xC5; // OnSet manufacturing id
    advertWatcher.AdvertisementFilter.Advertisement.ManufacturerData.Add(manufacturerDataFilter);

    ManualResetEvent advertEvent = new ManualResetEvent(false);

    TypedEventHandler<BluetoothLEAdvertisementWatcher, BluetoothLEAdvertisementReceivedEventArgs> myDelegate = async (sender, args) =>
    {


        // Is this needed anymore in view of our filter?
        if (args.Advertisement.ManufacturerData.Count < 1 || args.Advertisement.ManufacturerData[0].CompanyId != 0xC5)
        {
            Console.WriteLine($"Wrong company id. Returning {(args.Advertisement.ManufacturerData.Count > 0 ? args.Advertisement.ManufacturerData[0].CompanyId : -1)}");
            return;
        }
        if (args.Advertisement.DataSections.Count != 3)
        {
            Console.WriteLine($"Wrong number of data sections. Returning {args.Advertisement.DataSections.Count}");
            return;
        }


        // again, perhaps this is unnecessary in view of our AdvertisementFilter?
        device = await BluetoothLEDevice.FromBluetoothAddressAsync(args.BluetoothAddress);
        Console.WriteLine($"args.BluetoothAddress: {args.BluetoothAddress}");
        if (device != null)
        {
            Console.WriteLine($"Device name: {device.Name}");
        }
        if (advertEvent.WaitOne(0))
        {
            Console.WriteLine("Event already tripped");
        }
        if (advertEvent.WaitOne(0) || device == null || !device.Name.ToLower().Contains("cx402".ToLower()))
        {
            return;
        }


        var manufacturerSections = args.Advertisement.ManufacturerData;
        if (manufacturerSections.Count > 0)
        {
            /// print out advertisement stuff
            foreach (var service in args.Advertisement.ServiceUuids)
            {
                Console.WriteLine($"ServiceUuid: {service}");
            }
            foreach (var dataSection in args.Advertisement.DataSections)
            {
                Console.WriteLine($"datasection.DataType: {dataSection.DataType}");
                byte[] output = null;
                CryptographicBuffer.CopyToByteArray(dataSection.Data, out output);
                Console.WriteLine($"data from advert {BitConverter.ToString(output)}");
            }


            var manufacturerData = manufacturerSections[0];
            Console.WriteLine($"manufacturerData.CompanyId: {manufacturerData.CompanyId}");
            var data = new byte[manufacturerData.Data.Length];
            using (var reader = DataReader.FromBuffer(manufacturerData.Data))
            {
                reader.ReadBytes(data);
                uint probeSerialNumber = BitConverter.ToUInt32(data, 1);
                if (probeSerialNumber != serialNumber) // we could have more than one probe!
                    return;
                probeRawValue = BitConverter.ToUInt16(data, 13);
                ambientRawValue = BitConverter.ToUInt16(data, 15);
                rawVoltage = data[17];
                advertEvent.Set();
            }
        }


    };
    advertWatcher.Received += myDelegate;
    advertWatcher.Start();
    bool receivedAdvert = advertEvent.WaitOne(20000);
    advertWatcher.Received -= myDelegate;
    advertWatcher.Stop();
    if (!receivedAdvert)
    {
        Console.WriteLine("Could not get advert");
        return;
    }

    // see if we can pair
    bool isPaired = device.DeviceInformation.Pairing.IsPaired;
    bool canPair = device.DeviceInformation.Pairing.CanPair;
    var protectionLevel = device.DeviceInformation.Pairing.ProtectionLevel;
    var customPairing = device.DeviceInformation.Pairing.Custom;

    // SERVICES!!
    var gatt = await device.GetGattServicesAsync();
    Console.WriteLine($"{device.Name} Services: {gatt.Services.Count}, {gatt.Status}, {gatt.ProtocolError}");
    foreach (var service in gatt.Services)
    {
        Console.WriteLine($"Service Name: name Guid: {service.Uuid}");
        var characs = await service.GetCharacteristicsAsync();
        if (characs != null)
        {
            foreach (var charac in characs.Characteristics)
            {
                Console.WriteLine($"Char Name: {charac.UserDescription} and Guid: {charac.Uuid}");
                if (charac.Uuid == new Guid("65e16f4f-ed4e-4641-ac49-83ccbce6cbcf"))
                {
                    try
                    {
                        Console.WriteLine($"FOUND A MATCH Char Name: {charac.UserDescription} and Guid: {charac.Uuid}");
                        byte[] test = BitConverter.GetBytes(0xFF000000);
                        byte[] chirp = new byte[8] { 1, 1, 2, 1, 0xB, 0, 0, 0 };
                        byte[] backwardChirp = chirp.Reverse().ToArray();

                        byte[] passkey = new byte[16] { 1, 1, 0xD, 5, 0x1c, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
                        byte[] backwardPassKey = passkey.Reverse().ToArray();
                        uint alphaKey = CalculateKey(17, 0, 113);  // try 0 or 1000
                        byte[] alphaKeyArray = new byte[5] { 1, 1, 6, 4, 9 }.Concat(BitConverter.GetBytes(alphaKey)).ToArray();

                        var writer = new Windows.Storage.Streams.DataWriter();
                        GattCharacteristicProperties properties = charac.CharacteristicProperties;
                        if (properties.HasFlag(GattCharacteristicProperties.Read))
                        {
                            Debug.Write("This characteristic supports reading from it.");
                        }
                        if (properties.HasFlag(GattCharacteristicProperties.Write))
                        {
                            Debug.Write("This characteristic supports writing.");
                        }
                        if (properties.HasFlag(GattCharacteristicProperties.Notify))
                        {
                            Debug.Write("This characteristic supports subscribing to notifications.");
                        }


                        var responseInitial = await charac.ReadValueAsync(BluetoothCacheMode.Cached);
                        byte[] newByteArrayInitial;
                        CryptographicBuffer.CopyToByteArray(responseInitial.Value, out newByteArrayInitial);
                        GattCommunicationStatus status = await charac.WriteClientCharacteristicConfigurationDescriptorAsync(GattClientCharacteristicConfigurationDescriptorValue.Notify);
                        Debug.WriteLine($"GattCommunicationStatus {status}");
                        ManualResetEvent characteristicEvent = new ManualResetEvent(false);
                        TypedEventHandler<GattCharacteristic, GattValueChangedEventArgs> myCharacteristicDelegate = async (sender, args) =>
                        {
                            GattReadResult dataFromRead = await sender.ReadValueAsync();
                            CryptographicBuffer.CopyToByteArray(dataFromRead.Value, out byte[] dataRead);
                            Console.WriteLine($"Value of raw B Key received in callback: {BitConverter.ToString(dataRead)}");
                            if (dataRead[3] == 4 && dataRead[4] == 9)
                            {
                                var betaKey = BitConverter.ToUInt32(dataRead, 5);
                                Console.WriteLine($"Value of B Key as uint: {betaKey}");
                                var kKey = CalculateKey(betaKey, 0, 17);
                                Console.WriteLine($"Value of k key is: {kKey}");
                                byte[] encryptedPassword = EncryptPassword(Enumerable.Repeat<byte>(0, 10).ToArray(), kKey);
                                encryptedPassword = (new byte[6] { 1, 1, 0xD, 5, 0x1c, 01 }).Concat(encryptedPassword).ToArray();
                                Console.WriteLine($"Value of encrypted password: {BitConverter.ToString(encryptedPassword)}");
                                var writeResult = await charac.WriteValueAsync(WindowsRuntimeBufferExtensions.AsBuffer(encryptedPassword));
                                writeResult = await charac.WriteValueAsync(WindowsRuntimeBufferExtensions.AsBuffer(chirp));
                                characteristicEvent.Set();
                                device.Dispose();
                            }

                        };
                        charac.ValueChanged += myCharacteristicDelegate;
                        Console.WriteLine($"Value of A Key Sent out: {BitConverter.ToString(alphaKeyArray)}");
                        var alphaKeyResult = await charac.WriteValueWithResultAsync(WindowsRuntimeBufferExtensions.AsBuffer(alphaKeyArray));
                        bool sentChirp = characteristicEvent.WaitOne(2000);
                        if (!sentChirp)
                            Console.WriteLine("Timedout waiting for chirp event");
                        charac.ValueChanged -= myCharacteristicDelegate;

                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine($"Exceptionfor characteristic {charac.Uuid} " + ex.ToString());
                    }
                }
            }
        }
    }

    return;
}
...