Я работаю с температурным датчиком и могу выполнить простую команду «подать звуковой сигнал» на устройство. Это включает в себя прослушивание рекламы и отправку пароля перед отправкой команды, чтобы подать звуковой сигнал с 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;
}