C++ Pixels Library For Windows
Enable communications with Pixels dice using Bluetooth Low Energy.
Loading...
Searching...
No Matches
Characteristic.h
Go to the documentation of this file.
1
6#pragma once
7
8#include <type_traits> // underlying_type
9
11{
12 class Peripheral;
13
16 {
17 None = 0,
18
20 Broadcast = 0x001,
21
23 Read = 0x002,
24
27
29 Write = 0x008,
30
32 Notify = 0x010,
33
35 Indicate = 0x020,
36
38 SignedWrite = 0x040,
39
42
45
48 };
49
62 {
63 using GattCharacteristic = winrt::Windows::Devices::Bluetooth::GenericAttributeProfile::GattCharacteristic;
64 using GattValueChangedEventArgs = winrt::Windows::Devices::Bluetooth::GenericAttributeProfile::GattValueChangedEventArgs;
65
66 // Characteristic
67 GattCharacteristic _characteristic{ nullptr };
68
69 // The user callback for value changes
70 std::function<void(const std::vector<std::uint8_t>&)> _onValueChanged{};
71
72 // Value change
73 winrt::event_token _valueChangedToken{};
74 std::recursive_mutex _subscribeMtx{};
75
76 public:
79
84 {
85 if (_characteristic)
86 {
87 _characteristic.ValueChanged(_valueChangedToken);
88 _characteristic = nullptr;
89 }
90 }
91
95
101 std::uint16_t handle() const
102 {
103 return _characteristic.AttributeHandle();
104 }
105
111 winrt::guid uuid() const
112 {
113 return _characteristic.Uuid();
114 }
115
122 std::underlying_type<CharacteristicProperties>::type properties() const
123 {
124 return static_cast<std::underlying_type<CharacteristicProperties>::type>(
125 _characteristic.CharacteristicProperties());
126 }
127
133 bool canWrite() const
134 {
136 }
137
143 bool canRead() const
144 {
146 }
147
153 bool canNotify() const
154 {
156 }
157
161
169 std::future<std::vector<std::uint8_t>> readValueAsync()
170 {
171 // TODO return error code
172
173 // Read from characteristic
174 auto result = co_await _characteristic.ReadValueAsync();
175 co_return Internal::dataBufferToBytesVector(result.Value());
176 }
177
187 std::future<BleRequestStatus> writeAsync(const std::vector<std::uint8_t>& data, bool withoutResponse = false)
188 {
189 // TODO use std::span, test with empty buffer
190 using namespace winrt::Windows::Devices::Bluetooth::GenericAttributeProfile;
191
192 // Write to characteristic
193 auto options = withoutResponse ? GattWriteOption::WriteWithoutResponse : GattWriteOption::WriteWithResponse;
194 auto result = co_await _characteristic.WriteValueAsync(Internal::bytesVectorToDataBuffer(data), options);
195
196 co_return result == GattCommunicationStatus::Success ? BleRequestStatus::Success : BleRequestStatus::Error;
197 }
198
208 std::future<BleRequestStatus> subscribeAsync(const std::function<void(const std::vector<std::uint8_t>&)>& onValueChanged)
209 {
210 using namespace winrt::Windows::Devices::Bluetooth::GenericAttributeProfile;
211
212 // Check parameters
213 if (!onValueChanged) co_return BleRequestStatus::InvalidParameters;
215
216 {
217 std::lock_guard lock{ _subscribeMtx };
218
219 // Store the callback and subscribe
220 _onValueChanged = onValueChanged;
221 if (!_valueChangedToken)
222 {
223 _valueChangedToken = _characteristic.ValueChanged({ this, &Characteristic::onValueChanged });
224 }
225 }
226
227 // Update characteristic configuration
228 auto result = co_await _characteristic.WriteClientCharacteristicConfigurationDescriptorAsync(
229 GattClientCharacteristicConfigurationDescriptorValue::Notify);
230
231 co_return result == GattCommunicationStatus::Success ? BleRequestStatus::Success : BleRequestStatus::Error;
232 }
233
239 std::future<BleRequestStatus> unsubscribeAsync()
240 {
241 using namespace winrt::Windows::Devices::Bluetooth::GenericAttributeProfile;
242
243 {
244 // Check if subscribed
245 std::lock_guard lock{ _subscribeMtx };
246 if (!_onValueChanged)
247 {
249 }
250
251 // Forget the callback
252 _onValueChanged = nullptr;
253 }
254
255 // Unsubscribe
256 _characteristic.ValueChanged(_valueChangedToken);
257 _valueChangedToken = winrt::event_token{};
258
259 // Update characteristic configuration
260 auto result = co_await _characteristic.WriteClientCharacteristicConfigurationDescriptorAsync(
261 GattClientCharacteristicConfigurationDescriptorValue::None);
262
263 co_return result == GattCommunicationStatus::Success ? BleRequestStatus::Success : BleRequestStatus::Error;
264 }
265
266 private:
267 friend std::future<BleRequestStatus> Peripheral::connectAsync(std::vector<winrt::guid>, bool);
268
269 // Initialize a new instance with a GattCharacteristic object
270 explicit Characteristic(GattCharacteristic characteristic)
271 : _characteristic{ characteristic }
272 {
273 }
274
275 // Called when subscribed to the characteristic and its value changes
276 void onValueChanged(GattCharacteristic _, GattValueChangedEventArgs args)
277 {
278 // Safely get the callback
279 std::function<void(const std::vector<std::uint8_t>&)> callback{};
280 {
281 std::lock_guard lock{ _subscribeMtx };
282 callback = _onValueChanged;
283 }
284
285 if (callback)
286 {
287 callback(Internal::dataBufferToBytesVector(args.CharacteristicValue()));
288 }
289 }
290 };
291}
Represents a service's characteristic of a Bluetooth Low Energy (BLE) peripheral.
Definition: Characteristic.h:62
std::future< std::vector< std::uint8_t > > readValueAsync()
Reads the value from the characteristic.
Definition: Characteristic.h:169
winrt::guid uuid() const
Gets the UUID of the characteristic.
Definition: Characteristic.h:111
bool canRead() const
Indicates whether the characteristic can be read.
Definition: Characteristic.h:143
std::uint16_t handle() const
Gets the 16 bits handle of the BLE characteristic.
Definition: Characteristic.h:101
std::future< BleRequestStatus > unsubscribeAsync()
Unsubscribes from value changes of the characteristic.
Definition: Characteristic.h:239
std::future< BleRequestStatus > subscribeAsync(const std::function< void(const std::vector< std::uint8_t > &)> &onValueChanged)
Subscribes for value changes of the characteristic.
Definition: Characteristic.h:208
~Characteristic()
Destroys the Characteristic instance.
Definition: Characteristic.h:83
std::underlying_type< CharacteristicProperties >::type properties() const
Gets the standard BLE properties of the characteristic.
Definition: Characteristic.h:122
bool canWrite() const
Indicates whether the characteristic can be written.
Definition: Characteristic.h:133
bool canNotify() const
Indicates whether the characteristic can notify its value changes.
Definition: Characteristic.h:153
std::future< BleRequestStatus > writeAsync(const std::vector< std::uint8_t > &data, bool withoutResponse=false)
Writes the given data to the value of the characteristic.
Definition: Characteristic.h:187
std::future< BleRequestStatus > connectAsync(std::vector< winrt::guid > requiredServices=std::vector< winrt::guid >{}, bool maintainConnection=false)
Connects to the BLE peripheral.
A collection of C++ classes that provides a simplified access to Bluetooth Low Energy peripherals.
Definition: BleTypes.h:38
@ InvalidParameters
The request did not run because some of its parameters are invalid.
@ Success
The request completed successfully.
@ Error
The request completed with a non-specific error.
@ NotSupported
The request failed because of the operation is not supported by the peripheral.
CharacteristicProperties
Standard BLE values for characteristic properties, those are flags that can be combined.
Definition: Characteristic.h:16
@ SignedWrite
Characteristic supports write with signature.
Definition: Characteristic.h:38
@ Write
Characteristic can be written.
Definition: Characteristic.h:29
@ WriteWithoutResponse
Characteristic can be written without response.
Definition: Characteristic.h:26
@ Indicate
Characteristic supports indication.
Definition: Characteristic.h:35
@ NotifyEncryptionRequired
Characteristic notification uses encryption.
Definition: Characteristic.h:44
@ ExtendedProperties
Characteristic has extended properties.
Definition: Characteristic.h:41
@ Notify
Characteristic supports notification.
Definition: Characteristic.h:32
@ IndicateEncryptionRequired
Characteristic indication uses encryption.
Definition: Characteristic.h:47
@ Broadcast
Characteristic is broadcastable.
Definition: Characteristic.h:20
@ Read
Characteristic is readable.
Definition: Characteristic.h:23
@ Peripheral
Disconnection was initiated by peripheral.