Pixels Plugin for Unity
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
26 {
27 using GattCharacteristic = winrt::Windows::Devices::Bluetooth::GenericAttributeProfile::GattCharacteristic;
28 using GattValueChangedEventArgs = winrt::Windows::Devices::Bluetooth::GenericAttributeProfile::GattValueChangedEventArgs;
29
30 // Characteristic
31 GattCharacteristic _characteristic{ nullptr };
32
33 // The user callback for value changes
34 std::function<void(const std::vector<std::uint8_t>&)> _onValueChanged{};
35
36 // Value change
37 winrt::event_token _valueChangedToken{};
38 std::recursive_mutex _subscribeMtx{};
39
40 public:
43
48 {
49 if (_characteristic)
50 {
51 _characteristic.ValueChanged(_valueChangedToken);
52 _characteristic = nullptr;
53 }
54 }
55
59
65 std::uint16_t handle() const
66 {
67 return _characteristic.AttributeHandle();
68 }
69
75 winrt::guid uuid() const
76 {
77 return _characteristic.Uuid();
78 }
79
86 std::underlying_type<CharacteristicProperties>::type properties() const
87 {
88 return static_cast<std::underlying_type<CharacteristicProperties>::type>(
89 _characteristic.CharacteristicProperties());
90 }
91
97 bool canWrite() const
98 {
99 return properties() & CharacteristicProperties::Write;
100 }
101
107 bool canRead() const
108 {
109 return properties() & CharacteristicProperties::Read;
110 }
111
117 bool canNotify() const
118 {
119 return properties() & CharacteristicProperties::Notify;
120 }
121
125
133 std::future<std::vector<std::uint8_t>> readValueAsync()
134 {
135 //TODO return error code
136
137 // Read from characteristic
138 auto result = co_await _characteristic.ReadValueAsync();
139 co_return Internal::dataBufferToBytesVector(result.Value());
140 }
141
151 std::future<BleRequestStatus> writeAsync(const std::vector<std::uint8_t>& data, bool withoutResponse = false)
152 {
153 //TODO use std::span, test with empty buffer
154 using namespace winrt::Windows::Devices::Bluetooth::GenericAttributeProfile;
155
156 // Write to characteristic
157 auto options = withoutResponse ? GattWriteOption::WriteWithoutResponse : GattWriteOption::WriteWithResponse;
158 auto result = co_await _characteristic.WriteValueAsync(Internal::bytesVectorToDataBuffer(data), options);
159
160 co_return result == GattCommunicationStatus::Success ? BleRequestStatus::Success : BleRequestStatus::Error;
161 }
162
172 std::future<BleRequestStatus> subscribeAsync(const std::function<void(const std::vector<std::uint8_t>&)>& onValueChanged)
173 {
174 using namespace winrt::Windows::Devices::Bluetooth::GenericAttributeProfile;
175
176 // Check parameters
177 if (!onValueChanged) co_return BleRequestStatus::InvalidParameters;
178 if (!canNotify()) co_return BleRequestStatus::NotSupported;
179
180 {
181 std::lock_guard lock{ _subscribeMtx };
182
183 // Store the callback and subscribe
184 _onValueChanged = onValueChanged;
185 if (!_valueChangedToken)
186 {
187 _valueChangedToken = _characteristic.ValueChanged({ this, &Characteristic::onValueChanged });
188 }
189 }
190
191 // Update characteristic configuration
192 auto result = co_await _characteristic.WriteClientCharacteristicConfigurationDescriptorAsync(
193 GattClientCharacteristicConfigurationDescriptorValue::Notify);
194
195 co_return result == GattCommunicationStatus::Success ? BleRequestStatus::Success : BleRequestStatus::Error;
196 }
197
203 std::future<BleRequestStatus> unsubscribeAsync()
204 {
205 using namespace winrt::Windows::Devices::Bluetooth::GenericAttributeProfile;
206
207 {
208 // Check if subscribed
209 std::lock_guard lock{ _subscribeMtx };
210 if (!_onValueChanged)
211 {
212 co_return BleRequestStatus::Success;
213 }
214
215 // Forget the callback
216 _onValueChanged = nullptr;
217 }
218
219 // Unsubscribe
220 _characteristic.ValueChanged(_valueChangedToken);
221 _valueChangedToken = winrt::event_token{};
222
223 // Update characteristic configuration
224 auto result = co_await _characteristic.WriteClientCharacteristicConfigurationDescriptorAsync(
225 GattClientCharacteristicConfigurationDescriptorValue::None);
226
227 co_return result == GattCommunicationStatus::Success ? BleRequestStatus::Success : BleRequestStatus::Error;
228 }
229
230 private:
231 friend Peripheral;
232
233 // Initialize a new instance with a GattCharacteristic object
234 Characteristic(GattCharacteristic characteristic)
235 : _characteristic{ characteristic }
236 {
237 }
238
239 // Called when subscribed to the characteristic and its value changes
240 void onValueChanged(GattCharacteristic _, GattValueChangedEventArgs args)
241 {
242 // Safely get the callback
243 std::function<void(const std::vector<std::uint8_t>&)> callback{};
244 {
245 std::lock_guard lock{ _subscribeMtx };
246 callback = _onValueChanged;
247 }
248
249 if (callback)
250 {
251 callback(Internal::dataBufferToBytesVector(args.CharacteristicValue()));
252 }
253 }
254 };
255}
Represents a service's characteristic of a Bluetooth Low Energy (BLE) peripheral.
Definition Characteristic.h:26
std::future< std::vector< std::uint8_t > > readValueAsync()
Reads the value from the characteristic.
Definition Characteristic.h:133
winrt::guid uuid() const
Gets the UUID of the characteristic.
Definition Characteristic.h:75
bool canRead() const
Indicates whether the characteristic can be read.
Definition Characteristic.h:107
std::uint16_t handle() const
Gets the 16 bits handle of the BLE characteristic.
Definition Characteristic.h:65
std::future< BleRequestStatus > unsubscribeAsync()
Unsubscribes from value changes of the characteristic.
Definition Characteristic.h:203
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:172
~Characteristic()
Destroys the Characteristic instance.
Definition Characteristic.h:47
std::underlying_type< CharacteristicProperties >::type properties() const
Gets the standard BLE properties of the characteristic.
Definition Characteristic.h:86
bool canWrite() const
Indicates whether the characteristic can be written.
Definition Characteristic.h:97
bool canNotify() const
Indicates whether the characteristic can notify its value changes.
Definition Characteristic.h:117
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:151
Represents a Bluetooth Low Energy (BLE) peripheral.
Definition Peripheral.h:33
A collection of C++ classes that provides a simplified access to Bluetooth Low Energy peripherals.
Definition bletypes.h:36