private async Task BuildDescriptors(GattCharacteristic ch, BLE_CharacteristicDataModel dataModel) { try { // TODO - change to an awaitable with result this.log.InfoEntry("BuildDescriptors"); dataModel.Descriptors = new List <BLE_DescriptorDataModel>(); GattDescriptorsResult descriptors = await ch.GetDescriptorsAsync(); if (descriptors.Status == GattCommunicationStatus.Success) { if (descriptors.Descriptors.Count > 0) { foreach (GattDescriptor desc in descriptors.Descriptors) { GattReadResult r = await desc.ReadValueAsync(); if (r.Status == GattCommunicationStatus.Success) { // New characteristic data model to add to service IDescParser parser = this.descParserfactory.GetParser(desc.Uuid, desc.AttributeHandle); BLE_DescriptorDataModel descDataModel = new BLE_DescriptorDataModel() { Uuid = desc.Uuid, AttributeHandle = desc.AttributeHandle, ProtectionLevel = (BLE_ProtectionLevel)desc.ProtectionLevel, DisplayName = parser.Parse(r.Value.FromBufferToBytes()), Parser = parser, }; dataModel.Descriptors.Add(descDataModel); this.log.Info("ConnectToDevice", () => string.Format(" Descriptor:{0} Uid:{1} Value:{2}", BLE_DisplayHelpers.GetDescriptorName(desc), desc.Uuid.ToString(), descDataModel.DisplayName)); } ; } } } else { this.log.Error(9999, "BuildDescriptors", () => string.Format("Get Descriptors result:{0}", descriptors.Status.ToString())); } } catch (Exception e) { this.log.Exception(9999, " BuildDescriptors", "", e); } }
private void Ch_BatteryLevelValueChanged(GattCharacteristic sender, GattValueChangedEventArgs args) { // TODO temp to read the changed value in the characteristic //args.CharacteristicValue.Length; byte[] b = args.CharacteristicValue.FromBufferToBytes(); // Will be length 1- value is Hex byte uint8Data = b[0]; // My Arduino maps it 0-100 // TODO - must be hex between 0x00 - 0x64 //int level = Convert.ToInt32(uint8Data.ToString(), 16); int level = Convert.ToInt32(uint8Data.ToString()); this.log.Info("Ch_ValueChanged", () => string.Format(" Characteristic:{0} Value:0x{1} - {2}% Handle:{3}", BLE_DisplayHelpers.GetCharacteristicName(sender), uint8Data, level, sender.AttributeHandle)); }
private async Task BuildCharacteristicDataModel(GattCharacteristic ch, BLE_ServiceDataModel service) { try { this.log.InfoEntry("BuildCharacteristicDataModel"); BLE_CharacteristicDataModel characteristic = new BLE_CharacteristicDataModel(); // Build descriptors first to allow them to be used to build unknown Characteristic values await this.BuildDescriptors(ch, characteristic); characteristic.Uuid = ch.Uuid; characteristic.GattType = BLE_DisplayHelpers.GetCharacteristicEnum(ch); characteristic.UserDescription = ch.UserDescription; characteristic.AttributeHandle = ch.AttributeHandle; characteristic.Service = service; characteristic.CharName = BLE_DisplayHelpers.GetCharacteristicName(ch); // Must put this before the properties for indicate or Notify to work // TODO - notify value is no longer showing properly. But notification itself working bool subscribe = await this.EnableNotifyIndicate(ch); characteristic.PropertiesFlags = ch.CharacteristicProperties.ToUInt().ToEnum <CharacteristicProperties>(); characteristic.ProtectionLevel = (BLE_ProtectionLevel)ch.ProtectionLevel; characteristic.PresentationFormats = this.BuildPresentationFormats(ch); // Do this after all else is defined characteristic.Parser = this.charParserFactory.GetParser(ch.Uuid, ch.AttributeHandle); this.RaiseIfError(characteristic.SetDescriptorParsers()); characteristic.CharValue = await this.ReadValue(ch, characteristic); // Associate the UWP and data model characteristic for 2 way events to set and get this.binderSet.Add(new BLE_CharacteristicBinder(ch, characteristic, subscribe)); service.Characteristics.Add(characteristic); // This also sends and receives dummy data to Arduino //await this.DumpCharacteristic(ch); } catch (Exception e) { this.log.Exception(9999, "Failed during build of characteristic", e); } }
private async Task DumpCharacteristic(GattCharacteristic ch) { try { if (ch.CharacteristicProperties.HasFlag(GattCharacteristicProperties.Read)) { GattReadResult readResult = await ch.ReadValueAsync(); if (readResult.Status == GattCommunicationStatus.Success) { //if (ch.CharacteristicProperties.HasFlag(GattCharacteristicProperties.Read)) { byte[] b = readResult.Value.FromBufferToBytes(); switch (BLE_DisplayHelpers.GetCharacteristicEnum(ch)) { //case GattNativeCharacteristicUuid.String: case GattNativeCharacteristicUuid.DeviceName: case GattNativeCharacteristicUuid.ManufacturerNameString: string strVal = Encoding.ASCII.GetString(b, 0, (int)readResult.Value.Length); this.log.Info("DumpCharacteristic", () => string.Format(" Characteristic:{0} Value:{1} Handle:{2}", BLE_DisplayHelpers.GetCharacteristicName(ch), strVal, ch.AttributeHandle)); break; case GattNativeCharacteristicUuid.BatteryLevel: #region Battery Level // Hardcoded experiment with Arduino // This works until we get another add existing again // Setting it to notify so I can pick up the event var c = await ch.WriteClientCharacteristicConfigurationDescriptorAsync(GattClientCharacteristicConfigurationDescriptorValue.Notify); ch.ValueChanged += Ch_BatteryLevelValueChanged; // Will be length 1- value is Hex byte uint8Data = b[0]; // My Arduino maps it 0-100 // TODO - must be hex between 0x00 - 0x64 //int level = Convert.ToInt32(uint8Data.ToString(), 16); int level = Convert.ToInt32(uint8Data.ToString()); this.log.Info("DumpCharacteristic", () => string.Format(" Characteristic:{0} Value:0x{1} - {2}% Handle:{3}", BLE_DisplayHelpers.GetCharacteristicName(ch), uint8Data, level, ch.AttributeHandle)); #endregion break; case GattNativeCharacteristicUuid.PnPID: #region PPnPID // 7 bytes //0x02,0x5E,0x04,0x17,0x08,0x31,0x01 // field1 - 1 byte uint8 source of Vendor ID // field2 - 2 byte Uint16 - product vendor namespace // field3 - 2 byte Uint16 - manufacturer ID // field4 - 2 byte Uint16 - manufacturer version of product StringBuilder sb = new StringBuilder(); sb .Append("Vendor ID:").Append(b[0]).Append(",") .Append("Vendor Namespace:").Append(BitConverter.ToInt16(b, 1)).Append(",") .Append("Manufacturer ID:").Append(BitConverter.ToInt16(b, 3)).Append(",") .Append("Manufacturer Namespace:").Append(BitConverter.ToInt16(b, 5)); this.log.Info("DumpCharacteristic", () => string.Format(" Characteristic:{0} Value:{1} Handle:{2}", BLE_DisplayHelpers.GetCharacteristicName(ch), sb.ToString(), ch.AttributeHandle)); #endregion break; case GattNativeCharacteristicUuid.Appearance: #region Appearance this.log.Info("DumpCharacteristic", () => string.Format(" Characteristic:{0} Value:{1} Handle:{2}", BLE_DisplayHelpers.GetCharacteristicName(ch), b.ToGattAppearanceEnum().ToString().CamelCaseToSpaces(), ch.AttributeHandle)); #endregion break; case GattNativeCharacteristicUuid.PeripheralPreferredConnectionParameters: #region //Peripheral Preferred Connection Parameters Value:0x14,0x00,0x24,0x00,0x04,0x00,0xC8,0x00 - 8 bytes // 8 bytes in 4 uint16 fields // 1. Minimum Connect interval 6-3200 // 2. Maximum Connect interval 6-3200 // 3. Slave latency 0-1000 // 4. Connection Supervisor Timeout Multiplier 10-3200 StringBuilder sb2 = new StringBuilder(); sb2 .Append("Min Connect Interval:").Append(BitConverter.ToInt16(b, 0)).Append(",") .Append("Max Connect Interval:").Append(BitConverter.ToInt16(b, 2)).Append(",") .Append("Slave Latency:").Append(BitConverter.ToInt16(b, 4)).Append(",") .Append("Connect Supervisor Timout multiplier:").Append(BitConverter.ToInt16(b, 6)); this.log.Info("DumpCharacteristic", () => string.Format(" Characteristic:{0} Value:{1} Handle:{2}", BLE_DisplayHelpers.GetCharacteristicName(ch), sb2.ToString(), ch.AttributeHandle)); #endregion break; default: byte[] data = new byte[readResult.Value.Length]; Array.Copy(b, data, data.Length); // TODO - this is old hardcoded connection to serial Arduino in out. Replace if (BLE_DisplayHelpers.GetCharacteristicName(ch) == "39320") { var xx = await ch.WriteClientCharacteristicConfigurationDescriptorAsync(GattClientCharacteristicConfigurationDescriptorValue.Notify); ch.ValueChanged += Ch_ValueChangedSerialReturn; } this.log.Info("DumpCharacteristic", () => string.Format( " Characteristic: ** NOT ENUMERATED ** {0} Value:{1} Length:{2} Handle:{3}", BLE_DisplayHelpers.GetCharacteristicName(ch), data.ToFormatedByteString(), data.Length, ch.AttributeHandle)); break; } } else { this.log.Info("ConnectToDevice", () => string.Format(" Characteristic:{0} Read FAILED result:{1} Enum:{2}", BLE_DisplayHelpers.GetCharacteristicName(ch), readResult.Status, BLE_DisplayHelpers.GetCharacteristicEnum(ch))); } } else if (ch.CharacteristicProperties.HasFlag(GattCharacteristicProperties.Write)) { if (BLE_DisplayHelpers.GetCharacteristicName(ch) == "39319") { try { // TODO - old hardcoded to write values to an Arduino characteristic //WrapErr.ToErrReport(9999, () => { this.log.Info("LKDJFKLJSDFLK:JSDKLF", "GOT 39319 (output to device)"); // Test message //using (var ms = new DataWriter()) { // // do it this way when we have a multi byte block // ms.WriteBytes(Encoding.ASCII.GetBytes("Blipo message\n\r")); // var result = await ch.WriteValueAsync(ms.DetachBuffer()); //} for (int ii = 0; ii < 5; ii++) { //byte[] bytes = Encoding.ASCII.GetBytes("Blipo message\n\r"); byte[] bytes = Encoding.ASCII.GetBytes("Blipo message being somewhat long and convaluted just to test the return of the entire thing\n\r"); int blockLimit = 20; int count = bytes.Length / blockLimit; int rest = (bytes.Length % blockLimit); int lastIndex = 0; for (int i = 0; i < count; i++) { lastIndex = i * blockLimit; using (var ms = new DataWriter()) { byte[] part = new byte[blockLimit]; Array.Copy(bytes, lastIndex, part, 0, part.Length); this.log.Error(9191, part.ToFormatedByteString()); ms.WriteBytes(part); var result = await ch.WriteValueAsync(ms.DetachBuffer()); } } if (lastIndex > 0) { if (lastIndex > 0) { lastIndex += blockLimit; } using (var ms = new DataWriter()) { byte[] part = new byte[rest]; Array.Copy(bytes, lastIndex, part, 0, part.Length); this.log.Error(9192, part.ToFormatedByteString()); ms.WriteBytes(part); var result = await ch.WriteValueAsync(ms.DetachBuffer()); } } } //for (int i = 0; i < bytes.Length; i++) { // using (var ms = new DataWriter()) { // ms.WriteByte(bytes[i]); // var result = await ch.WriteValueAsync(ms.DetachBuffer()); // } //} //}); } catch (Exception e) { this.log.Exception(9999, "Fail on write to descriptor", e); } } } } catch (Exception e) { this.log.Exception(9999, "Failed during dump info", e); } }
private void DebugDumpPresentationFormats(GattCharacteristic ch, BLE_PresentationFormat f) { this.log.Info("DebugDumpPresentationFormats", () => string.Format("Characteristic : {0}", BLE_DisplayHelpers.GetCharacteristicName(ch))); this.log.Info("DebugDumpPresentationFormats", () => string.Format(" Description: {0}", f.Description)); this.log.Info("DebugDumpPresentationFormats", () => string.Format(" Exponent: {0}", f.Exponent)); this.log.Info("DebugDumpPresentationFormats", () => string.Format(" Format: {0}", f.Format)); this.log.Info("DebugDumpPresentationFormats", () => string.Format(" Namespace: {0}", f.Namespace)); this.log.Info("DebugDumpPresentationFormats", () => string.Format(" Units: {0}", f.Units)); }
/// <summary>Build the GATT service data model</summary> /// <param name="service">The OS GATT service object</param> /// <param name="deviceDataModel">The portable GATT session data model</param> /// <returns>The async task</returns> public async Task BuildServiceDataModel(GattDeviceService service, BLEGetInfoStatus status) { try { this.log.Info("BuildServiceDataModel", () => string.Format("Gatt Service:{0} Uid:{1}", BLE_DisplayHelpers.GetServiceName(service), service.Uuid.ToString())); // New service data model to add to device info BLE_ServiceDataModel serviceDataModel = new BLE_ServiceDataModel() { Characteristics = new List <BLE_CharacteristicDataModel>(), AttributeHandle = service.AttributeHandle, DeviceId = status.DeviceInfo.Id, ServiceTypeEnum = BLE_ParseHelpers.GetServiceTypeEnum(service.Uuid), DisplayName = BLE_DisplayHelpers.GetServiceName(service), Uuid = service.Uuid, SharingMode = (BLE_SharingMode)service.SharingMode, }; if (service.DeviceAccessInformation != null) { serviceDataModel.DeviceAccess = (BLE_DeviceAccessStatus)service.DeviceAccessInformation.CurrentStatus; } this.currentServices.Add(service); this.BuildSessionDataModel(service.Session, serviceDataModel.Session); // TODO //service.ParentServices // Get the characteristics for the service GattCharacteristicsResult characteristics = await service.GetCharacteristicsAsync(); if (characteristics.Status == GattCommunicationStatus.Success) { if (characteristics.Characteristics != null) { if (characteristics.Characteristics.Count > 0) { foreach (GattCharacteristic ch in characteristics.Characteristics) { try { await this.BuildCharacteristicDataModel(ch, serviceDataModel); } catch (Exception e1) { this.log.Exception(9999, "HarvestDeviceInfo", e1); } } } else { this.log.Info("ConnectToDevice", () => string.Format("No characteristics")); } } } else { this.log.Error(9999, "HarvestDeviceInfo", () => string.Format("Failed to get Characteristics result {0}", characteristics.Status.ToString())); } // Add the service data model to the device info data model status.DeviceInfo.Services.Add(serviceDataModel); } catch (Exception e) { this.log.Exception(9999, "BuildServiceDataModel", "", e); } }