Pixels Plugin for Unity
Enable communications with Pixels dice using Bluetooth Low Energy.
Loading...
Searching...
No Matches
Peripheral.h
Go to the documentation of this file.
1
6#pragma once
7
8#include <mutex>
9
11{
12 class Service;
13
32 class Peripheral : public std::enable_shared_from_this<Peripheral>
33 {
34 using BluetoothLEDevice = winrt::Windows::Devices::Bluetooth::BluetoothLEDevice;
35 using GattSession = winrt::Windows::Devices::Bluetooth::GenericAttributeProfile::GattSession;
36
37 // The Bluetooth address
38 const bluetooth_address_t _address{};
39
40 // The user callback for connection events
41 const std::function<void(ConnectionEvent, ConnectionEventReason)> _onConnectionEvent{};
42
43 // Device and session
44 BluetoothLEDevice _device{ nullptr };
45 GattSession _session{ nullptr };
46 winrt::event_token _connectionStatusChangedToken{};
47
48 // Services
49 std::unordered_map<winrt::guid, std::shared_ptr<Service>> _services{};
50
51 // The ready state
52 volatile bool _isReady{};
53
54 // Connection
55 mutable std::recursive_mutex _connectOpMtx{}; // Connection mutex
56 volatile size_t _connectCounter{}; // Incremented every time connect or disconnect is called
57 volatile bool _connecting{}; // Whether we are trying to connect
58
59 // Queue of connection events to notify to user
60 std::vector<std::tuple<ConnectionEvent, ConnectionEventReason>> _connectionEventsQueue{};
61
62 public:
65
73 Peripheral(bluetooth_address_t bluetoothAddress, const std::function<void(ConnectionEvent, ConnectionEventReason)>& onConnectionEvent)
74 : _address{ bluetoothAddress }, _onConnectionEvent{ onConnectionEvent }
75 {
76 assert(bluetoothAddress); //TODO check arguments
77 assert(onConnectionEvent);
78 _connectionEventsQueue.reserve(16);
79 }
80
85 {
86 disconnect();
87 }
88
92
104 std::future<BleRequestStatus> connectAsync(
105 std::vector<winrt::guid> requiredServices = std::vector<winrt::guid>{},
106 bool maintainConnection = false);
107
114 {
115 internalDisconnect(ConnectionEventReason::Success);
116 notifyQueuedConnectionEvents(); //TODO not getting those events!
117 }
118
123
130 {
131 return _address;
132 }
133
141 bool isConnected() const
142 {
143 using namespace winrt::Windows::Devices::Bluetooth;
144
145 auto dev = safeGetDevice();
146 return dev ? (dev.ConnectionStatus() == BluetoothConnectionStatus::Connected) : false;
147 }
148
157 bool isReady() const
158 {
159 return _isReady;
160 }
161
166
172 const wchar_t* deviceId() const
173 {
174 auto dev = safeGetDevice();
175 return dev ? dev.DeviceId().data() : nullptr;
176 }
177
183 const wchar_t* name() const
184 {
185 auto dev = safeGetDevice();
186 return dev ? dev.Name().data() : nullptr;
187 }
188
194 uint16_t mtu() const
195 {
196 //TODO is the lock needed?
197 std::lock_guard lock{ _connectOpMtx };
198 return _session ? _session.MaxPduSize() : 0;
199 }
200
205
212 std::shared_ptr<Service> getDiscoveredService(const winrt::guid& uuid) const
213 {
214 std::lock_guard lock{ _connectOpMtx };
215 auto it = _services.find(uuid);
216 return it != _services.end() ? it->second : nullptr;
217 }
218
224 void copyDiscoveredServices(std::vector<std::shared_ptr<Service>>& outServices) const
225 {
226 std::lock_guard lock{ _connectOpMtx };
227 outServices.reserve(outServices.size() + _services.size());
228 for (auto& [_, s] : _services)
229 {
230 outServices.emplace_back(s);
231 }
232 }
233
235
236 private:
237 // Get the device object in a thread safe manner
238 BluetoothLEDevice safeGetDevice() const
239 {
240 //TODO is the lock needed?
241 std::lock_guard lock{ _connectOpMtx };
242 return _device;
243 }
244
245 // Take the lock and release device and session, be sure to call notifyQueuedConnectionEvents() afterwards
246 void internalDisconnect(ConnectionEventReason reason, bool fromDevice = false);
247
248 // Notify user code with pending connection event
249 void notifyQueuedConnectionEvents()
250 {
251 //TODO optimize for case with 1 or 2 elements in queue
252 decltype(_connectionEventsQueue) queue{};
253 {
254 std::lock_guard lock{ _connectOpMtx };
255 queue = _connectionEventsQueue;
256 _connectionEventsQueue.clear();
257 }
258 if (_onConnectionEvent)
259 {
260 for (auto& [ev, reason] : queue)
261 {
262 _onConnectionEvent(ev, reason);
263 }
264 }
265 }
266
267 // Called by the device when the connection status changes
268 void onDeviceConnectionStatusChanged(BluetoothLEDevice device, winrt::Windows::Foundation::IInspectable _)
269 {
270 using namespace winrt::Windows::Devices::Bluetooth;
271
272 if (device.ConnectionStatus() == BluetoothConnectionStatus::Disconnected)
273 {
274 bool linkLoss = (_session != nullptr) && _session.MaintainConnection();
275 internalDisconnect(linkLoss ? ConnectionEventReason::LinkLoss : ConnectionEventReason::Timeout, true);
276 notifyQueuedConnectionEvents();
277 }
278 else
279 {
280 // Connected event is raised in connectAsync() after it has successfully retrieved the services
281 }
282 }
283 };
284}
Represents a Bluetooth Low Energy (BLE) peripheral.
Definition Peripheral.h:33
bluetooth_address_t address() const
Gets the Bluetooth address of the peripheral.
Definition Peripheral.h:129
const wchar_t * name() const
Gets the name of the peripheral.
Definition Peripheral.h:183
Peripheral(bluetooth_address_t bluetoothAddress, const std::function< void(ConnectionEvent, ConnectionEventReason)> &onConnectionEvent)
Initializes a new instance of Peripheral with the given Bluetooth address and a callback for notifyin...
Definition Peripheral.h:73
std::shared_ptr< Service > getDiscoveredService(const winrt::guid &uuid) const
Gets the Service instance with the given UUID.
Definition Peripheral.h:212
void copyDiscoveredServices(std::vector< std::shared_ptr< Service > > &outServices) const
Copy the discovered services to the given std::vector.
Definition Peripheral.h:224
bool isConnected() const
Indicates whether the peripheral is connected.
Definition Peripheral.h:141
std::future< BleRequestStatus > connectAsync(std::vector< winrt::guid > requiredServices=std::vector< winrt::guid >{}, bool maintainConnection=false)
Connects to the BLE peripheral.
Definition Peripheral.cpp:47
const wchar_t * deviceId() const
Gets the device id assigned by the system for the peripheral.
Definition Peripheral.h:172
uint16_t mtu() const
Gets the Maximum Transmission Unit (MTU).
Definition Peripheral.h:194
void disconnect()
Immediately disconnects the peripheral.
Definition Peripheral.h:113
bool isReady() const
Indicates whether the peripheral is ready.
Definition Peripheral.h:157
~Peripheral()
Disconnects and destroys the Peripheral instance.
Definition Peripheral.h:84
A collection of C++ classes that provides a simplified access to Bluetooth Low Energy peripherals.
Definition bletypes.h:36
std::uint64_t bluetooth_address_t
Type for a Bluetooth address.
Definition bletypes.h:54
@ Timeout
The request did not succeed after the timeout period.
ConnectionEvent
Peripheral connection events.
Definition bletypes.h:101
ConnectionEventReason
Peripheral connection event reasons.
Definition bletypes.h:123