public override unsafe void WriteDescriptor(BleDescriptor descriptor, byte[] value, int offset, int count, BleRequestFlags requestFlags) { Throw.If.Null(descriptor, "descriptor").Null(value, "value").OutOfRange(value, offset, count); var flags = GetGattFlags(requestFlags); HandleAcquireIfOpenOrFail(); try { lock (_writeSync) { int error; var wd = (WinBleDescriptor)descriptor; var dvp = new NativeMethods.BTH_LE_GATT_DESCRIPTOR_VALUE_PARAMS(); byte[] data = null; int dataOffset = 0, dataCount = 0; switch (wd.NativeData.DescriptorType) { case NativeMethods.BTH_LE_GATT_DESCRIPTOR_TYPE.CharacteristicExtendedProperties: dvp.ExtendedProperties.IsReliableWriteEnabled = (byte)(value.Length >= 1 && 0 != (value[offset] & 1) ? 1 : 0); dvp.ExtendedProperties.IsAuxiliariesWritable = (byte)(value.Length >= 1 && 0 != (value[offset] & 2) ? 1 : 0); data = new byte[0]; break; case NativeMethods.BTH_LE_GATT_DESCRIPTOR_TYPE.ClientCharacteristicConfiguration: dvp.Cccd.IsSubscribeToNotification = (byte)(value.Length >= 1 && 0 != (value[offset] & 1) ? 1 : 0); dvp.Cccd.IsSubscribeToIndication = (byte)(value.Length >= 1 && 0 != (value[offset] & 2) ? 1 : 0); data = new byte[0]; break; case NativeMethods.BTH_LE_GATT_DESCRIPTOR_TYPE.ServerCharacteristicConfiguration: dvp.Sccd.IsBroadcast = (byte)(value.Length >= 1 && 0 != (value[offset] & 1) ? 1 : 0); data = new byte[0]; break; case NativeMethods.BTH_LE_GATT_DESCRIPTOR_TYPE.CharacteristicFormat: throw new NotImplementedException(); default: data = value; dataOffset = offset; dataCount = count; break; } var db = stackalloc byte[NativeMethods.BTH_LE_GATT_DESCRIPTOR_VALUE.Size + dataCount]; var dv = (NativeMethods.BTH_LE_GATT_DESCRIPTOR_VALUE *)db; dv->DescriptorType = wd.NativeData.DescriptorType; dv->DescriptorUuid = wd.NativeData.DescriptorUuid; dv->Params = dvp; dv->Value.DataSize = (uint)dataCount; if (data != null) { Marshal.Copy(data, dataOffset, (IntPtr)(void *)&dv->Value.Data[0], dataCount); } error = NativeMethods.BluetoothGATTSetDescriptorValue(_handle, ref wd.NativeData, dv, flags); if (error != 0) { var message = string.Format("Failed to write {0} bytes to descriptor {1}.", count, descriptor); throw DeviceException.CreateIOException(Device, message, error); } } } finally { HandleRelease(); } }
public override unsafe byte[] ReadDescriptor(BleDescriptor descriptor, BleRequestFlags requestFlags) { Throw.If.Null(descriptor, "descriptor"); var flags = GetGattFlags(requestFlags); HandleAcquireIfOpenOrFail(); try { lock (_readSync) { int error; var wd = (WinBleDescriptor)descriptor; ushort valueSize; error = NativeMethods.BluetoothGATTGetDescriptorValue(_handle, ref wd.NativeData, 0, null, out valueSize, flags | ((requestFlags & BleRequestFlags.Cacheable) == 0 ? NativeMethods.BLUETOOTH_GATT_FLAGS.FORCE_READ_FROM_DEVICE : 0)); if (error != NativeMethods.ERROR_MORE_DATA || valueSize < NativeMethods.BTH_LE_GATT_DESCRIPTOR_VALUE.Size) { var message = string.Format("Failed to read descriptor {0}.", descriptor); throw DeviceException.CreateIOException(Device, message, error); } var cb = stackalloc byte[valueSize]; var cv = (NativeMethods.BTH_LE_GATT_DESCRIPTOR_VALUE *)cb; ushort valueSize2; error = NativeMethods.BluetoothGATTGetDescriptorValue(_handle, ref wd.NativeData, valueSize, cv, out valueSize2, flags); if (error != 0 || valueSize != valueSize2 || cv->Value.DataSize > valueSize - NativeMethods.BTH_LE_GATT_DESCRIPTOR_VALUE.Size) { var message = string.Format("Failed to read descriptor {0}.", descriptor); throw DeviceException.CreateIOException(Device, message, error); } byte[] data; switch (cv->DescriptorType) { case NativeMethods.BTH_LE_GATT_DESCRIPTOR_TYPE.CharacteristicExtendedProperties: data = new byte[2]; if (0 != cv->Params.ExtendedProperties.IsReliableWriteEnabled) { data[0] |= 1; } if (0 != cv->Params.ExtendedProperties.IsAuxiliariesWritable) { data[0] |= 2; } break; case NativeMethods.BTH_LE_GATT_DESCRIPTOR_TYPE.ClientCharacteristicConfiguration: data = new byte[2]; if (0 != cv->Params.Cccd.IsSubscribeToNotification) { data[0] |= 1; } if (0 != cv->Params.Cccd.IsSubscribeToIndication) { data[0] |= 2; } break; case NativeMethods.BTH_LE_GATT_DESCRIPTOR_TYPE.ServerCharacteristicConfiguration: data = new byte[2]; if (0 != cv->Params.Sccd.IsBroadcast) { data[0] |= 1; } break; case NativeMethods.BTH_LE_GATT_DESCRIPTOR_TYPE.CharacteristicFormat: throw new NotImplementedException(); default: //Console.WriteLine(string.Format("{0} {1} {2}", valueSize, cv->DescriptorType, cv->Value.DataSize)); data = new byte[cv->Value.DataSize]; Marshal.Copy((IntPtr)(void *)&cv->Value.Data[0], data, 0, data.Length); break; } return(data); } } finally { HandleRelease(); } }