| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /* GATE PROJECT LICENSE: | ||
| 2 | +----------------------------------------------------------------------------+ | ||
| 3 | | Copyright(c) 2018-2026, Stefan Meislinger | | ||
| 4 | | All rights reserved. | | ||
| 5 | | | | ||
| 6 | | Redistribution and use in source and binary forms, with or without | | ||
| 7 | | modification, are permitted provided that the following conditions are met:| | ||
| 8 | | | | ||
| 9 | | 1. Redistributions of source code must retain the above copyright notice, | | ||
| 10 | | this list of conditions and the following disclaimer. | | ||
| 11 | | 2. Redistributions in binary form must reproduce the above copyright | | ||
| 12 | | notice, this list of conditions and the following disclaimer in the | | ||
| 13 | | documentation and/or other materials provided with the distribution. | | ||
| 14 | | | | ||
| 15 | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"| | ||
| 16 | | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | ||
| 17 | | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | ||
| 18 | | ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | | ||
| 19 | | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | ||
| 20 | | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | ||
| 21 | | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | ||
| 22 | | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | ||
| 23 | | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | ||
| 24 | | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | | ||
| 25 | | THE POSSIBILITY OF SUCH DAMAGE. | | ||
| 26 | +----------------------------------------------------------------------------+ | ||
| 27 | */ | ||
| 28 | |||
| 29 | #include "gate/system/devices.hpp" | ||
| 30 | #include "gate/exceptions.hpp" | ||
| 31 | |||
| 32 | namespace gate | ||
| 33 | { | ||
| 34 | namespace sys | ||
| 35 | { | ||
| 36 | |||
| 37 | ✗ | Bluetooth::Device::Device() noexcept | |
| 38 | { | ||
| 39 | ✗ | } | |
| 40 | |||
| 41 | ✗ | Bluetooth::Device::Device(gate_device_bth_t const& bth) noexcept | |
| 42 | { | ||
| 43 | ✗ | Mem::copy(this->impl, bth); | |
| 44 | ✗ | } | |
| 45 | |||
| 46 | ✗ | gate_device_bth_t* Bluetooth::Device::c_impl() noexcept | |
| 47 | { | ||
| 48 | ✗ | return &this->impl; | |
| 49 | } | ||
| 50 | |||
| 51 | ✗ | gate_device_bth_t const* Bluetooth::Device::c_impl() const noexcept | |
| 52 | { | ||
| 53 | ✗ | return &this->impl; | |
| 54 | } | ||
| 55 | |||
| 56 | ✗ | String Bluetooth::Device::getUid() const | |
| 57 | { | ||
| 58 | ✗ | return this->impl.uid; | |
| 59 | } | ||
| 60 | ✗ | String Bluetooth::Device::getName() const | |
| 61 | { | ||
| 62 | ✗ | return this->impl.name; | |
| 63 | } | ||
| 64 | ✗ | String Bluetooth::Device::getAddress() const | |
| 65 | { | ||
| 66 | ✗ | return this->impl.address; | |
| 67 | } | ||
| 68 | ✗ | uint32_t Bluetooth::Device::getDeviceClass() const noexcept | |
| 69 | { | ||
| 70 | ✗ | return this->impl.device_class; | |
| 71 | } | ||
| 72 | ✗ | bool_t Bluetooth::Device::isConnected() const noexcept | |
| 73 | { | ||
| 74 | ✗ | return this->impl.connected; | |
| 75 | } | ||
| 76 | ✗ | bool_t Bluetooth::Device::isAuthenticated() const noexcept | |
| 77 | { | ||
| 78 | ✗ | return this->impl.authenticated; | |
| 79 | } | ||
| 80 | ✗ | Time Bluetooth::Device::getLastSeenTime() const | |
| 81 | { | ||
| 82 | ✗ | return Time(this->impl.last_seen, 0); | |
| 83 | } | ||
| 84 | ✗ | Time Bluetooth::Device::getLastUsedTime() const | |
| 85 | { | ||
| 86 | ✗ | return Time(this->impl.last_used, 0); | |
| 87 | } | ||
| 88 | |||
| 89 | ✗ | Bluetooth::Bluetooth() | |
| 90 | { | ||
| 91 | ✗ | } | |
| 92 | |||
| 93 | struct GATE_API_LOCAL BluetoothDispatcherParam | ||
| 94 | { | ||
| 95 | Bluetooth::DeviceEnumCallback const* ptrCb; | ||
| 96 | }; | ||
| 97 | |||
| 98 | ✗ | static gate_bool_t GATE_CALL Bluetooth_enumDevices_dispatcher(gate_device_bth_t const* bth_dev, void* param) | |
| 99 | { | ||
| 100 | ✗ | BluetoothDispatcherParam* ptrParam = static_cast<BluetoothDispatcherParam*>(param); | |
| 101 | ✗ | if (ptrParam && ptrParam->ptrCb) | |
| 102 | { | ||
| 103 | ✗ | Bluetooth::Device dev(*bth_dev); | |
| 104 | ✗ | ptrParam->ptrCb->invoke(&dev); | |
| 105 | } | ||
| 106 | ✗ | return true; | |
| 107 | } | ||
| 108 | |||
| 109 | ✗ | void Bluetooth::enumDevices(DeviceEnumCallback const& cb) | |
| 110 | { | ||
| 111 | BluetoothDispatcherParam param; | ||
| 112 | ✗ | param.ptrCb = &cb; | |
| 113 | ✗ | result_t result = gate_device_bth_enum(&Bluetooth_enumDevices_dispatcher, ¶m); | |
| 114 | ✗ | GATEXX_CHECK_EXCEPTION(result); | |
| 115 | ✗ | } | |
| 116 | |||
| 117 | ✗ | static gate_bool_t GATE_CALL Bluetooth_enumDevices_array_dispatcher(gate_device_bth_t const* bth_dev, void* param) | |
| 118 | { | ||
| 119 | ✗ | ArrayList<Bluetooth::Device>* ptrList = static_cast<ArrayList<Bluetooth::Device>*>(param); | |
| 120 | ✗ | if (ptrList) | |
| 121 | { | ||
| 122 | ✗ | ptrList->add(Bluetooth::Device(*bth_dev)); | |
| 123 | } | ||
| 124 | ✗ | return true; | |
| 125 | } | ||
| 126 | |||
| 127 | ✗ | Array<Bluetooth::Device> Bluetooth::enumDevices() | |
| 128 | { | ||
| 129 | ✗ | ArrayList<Bluetooth::Device> list; | |
| 130 | ✗ | result_t result = gate_device_bth_enum(&Bluetooth_enumDevices_array_dispatcher, &list); | |
| 131 | ✗ | GATEXX_CHECK_EXCEPTION(result); | |
| 132 | ✗ | return list.toArray(); | |
| 133 | } | ||
| 134 | |||
| 135 | |||
| 136 | |||
| 137 | |||
| 138 | ✗ | BluetoothLE::Device::Device() noexcept | |
| 139 | { | ||
| 140 | ✗ | Mem::clear(this->impl); | |
| 141 | ✗ | } | |
| 142 | |||
| 143 | ✗ | BluetoothLE::Device::Device(gate_device_bthle_t const& bthle) noexcept | |
| 144 | ✗ | : impl(bthle) | |
| 145 | { | ||
| 146 | ✗ | } | |
| 147 | |||
| 148 | ✗ | gate_device_bthle_t* BluetoothLE::Device::c_impl() noexcept | |
| 149 | { | ||
| 150 | ✗ | return &this->impl; | |
| 151 | } | ||
| 152 | |||
| 153 | ✗ | gate_device_bthle_t const* BluetoothLE::Device::c_impl() const noexcept | |
| 154 | { | ||
| 155 | ✗ | return &this->impl; | |
| 156 | } | ||
| 157 | |||
| 158 | ✗ | String BluetoothLE::Device::getUid() const | |
| 159 | { | ||
| 160 | ✗ | return String(this->impl.uid); | |
| 161 | } | ||
| 162 | |||
| 163 | ✗ | String BluetoothLE::Device::getName() const | |
| 164 | { | ||
| 165 | ✗ | return String(this->impl.name); | |
| 166 | } | ||
| 167 | |||
| 168 | ✗ | String BluetoothLE::Device::getAddress() const | |
| 169 | { | ||
| 170 | ✗ | return String(this->impl.address); | |
| 171 | } | ||
| 172 | |||
| 173 | ✗ | Array<BluetoothLE::Service> BluetoothLE::Device::getServices() const | |
| 174 | { | ||
| 175 | ✗ | Array<BluetoothLE::Service> arr(this->impl.services, this->impl.service_count); | |
| 176 | ✗ | return arr; | |
| 177 | } | ||
| 178 | |||
| 179 | |||
| 180 | ✗ | BluetoothLE::BluetoothLE() | |
| 181 | { | ||
| 182 | ✗ | } | |
| 183 | |||
| 184 | ✗ | BluetoothLE::~BluetoothLE() | |
| 185 | { | ||
| 186 | ✗ | } | |
| 187 | |||
| 188 | ✗ | static gate_bool_t GATE_CALL bthle_enum_cb(gate_device_bthle_t const* device, void* param) | |
| 189 | { | ||
| 190 | ✗ | BluetoothLE::DeviceEnumCallback const* cb = static_cast<BluetoothLE::DeviceEnumCallback const*>(param); | |
| 191 | ✗ | if (cb) | |
| 192 | { | ||
| 193 | ✗ | BluetoothLE::Device leDevice(*device); | |
| 194 | ✗ | ExceptionInfo xcptStatus; | |
| 195 | ✗ | GATEXX_TRY_CATCHINFO(xcptStatus, { | |
| 196 | cb->invoke(&leDevice); | ||
| 197 | }); | ||
| 198 | ✗ | return xcptStatus.succeeded(); | |
| 199 | } | ||
| 200 | else | ||
| 201 | { | ||
| 202 | ✗ | return true; | |
| 203 | } | ||
| 204 | } | ||
| 205 | |||
| 206 | ✗ | static gate_bool_t GATE_CALL bthle_enum_devices_cb(gate_device_bthle_t const* device, void* param) | |
| 207 | { | ||
| 208 | ✗ | ArrayList<BluetoothLE::Device>* devices = static_cast<ArrayList<BluetoothLE::Device>*>(param); | |
| 209 | ✗ | if (devices && device) | |
| 210 | { | ||
| 211 | ✗ | devices->tryAdd(BluetoothLE::Device(*device)); | |
| 212 | } | ||
| 213 | ✗ | return true; | |
| 214 | } | ||
| 215 | |||
| 216 | ✗ | void BluetoothLE::enumDevices(DeviceEnumCallback const& cb) | |
| 217 | { | ||
| 218 | ✗ | result_t result = gate_device_bthle_enum(&bthle_enum_cb, (void*)&cb); | |
| 219 | ✗ | GATEXX_CHECK_EXCEPTION(result); | |
| 220 | ✗ | } | |
| 221 | |||
| 222 | ✗ | Array<BluetoothLE::Device> BluetoothLE::enumDevices() | |
| 223 | { | ||
| 224 | ✗ | ArrayList<Device> devices; | |
| 225 | ✗ | result_t result = gate_device_bthle_enum(&bthle_enum_devices_cb, static_cast<void*>(&devices)); | |
| 226 | ✗ | GATEXX_CHECK_EXCEPTION(result); | |
| 227 | ✗ | return devices.toArray(); | |
| 228 | } | ||
| 229 | |||
| 230 | ✗ | BluetoothLE::Device BluetoothLE::getDeviceByUid(String const& uid) | |
| 231 | { | ||
| 232 | gate_device_bthle_t device; | ||
| 233 | ✗ | result_t result = gate_device_bthle_get(uid.c_impl(), &device); | |
| 234 | ✗ | GATEXX_CHECK_EXCEPTION(result); | |
| 235 | ✗ | return Device(device); | |
| 236 | } | ||
| 237 | |||
| 238 | ✗ | BluetoothLE::Device BluetoothLE::getDeviceByAddress(String const& address) | |
| 239 | { | ||
| 240 | gate_device_bthle_t device; | ||
| 241 | ✗ | result_t result = gate_device_bthle_get_by_address(address.c_impl(), &device); | |
| 242 | ✗ | GATEXX_CHECK_EXCEPTION(result); | |
| 243 | ✗ | return Device(device); | |
| 244 | } | ||
| 245 | |||
| 246 | struct GATE_API_LOCAL bthle_chara_cb_param | ||
| 247 | { | ||
| 248 | BluetoothLE::Device const* device; | ||
| 249 | BluetoothLE::Service const* service; | ||
| 250 | BluetoothLE::CharacteristicsEnumCallback const* cb; | ||
| 251 | }; | ||
| 252 | |||
| 253 | ✗ | static gate_bool_t GATE_CALL bthle_chara_cb(gate_device_bthle_characteristic_t const* chara, void* user_param) | |
| 254 | { | ||
| 255 | ✗ | bthle_chara_cb_param* param = static_cast<bthle_chara_cb_param*>(user_param); | |
| 256 | ✗ | if (param) | |
| 257 | { | ||
| 258 | ✗ | GATEXX_TRY_IGNORE({ | |
| 259 | param->cb->invoke(param->device, param->service, chara); | ||
| 260 | }); | ||
| 261 | } | ||
| 262 | ✗ | return true; | |
| 263 | } | ||
| 264 | |||
| 265 | ✗ | static BluetoothLE::Service const* resolveBthLEService(BluetoothLE::Device const& device, Guid const& serviceGuid) | |
| 266 | { | ||
| 267 | ✗ | gate_device_bthle_service_t const* const services = &device.c_impl()->services[0]; | |
| 268 | ✗ | gate_size_t const service_count = device.c_impl()->service_count; | |
| 269 | |||
| 270 | ✗ | for (size_t ndx = 0; ndx != service_count; ++ndx) | |
| 271 | { | ||
| 272 | ✗ | if (serviceGuid == services[ndx].service_guid) | |
| 273 | { | ||
| 274 | ✗ | return &services[ndx]; | |
| 275 | } | ||
| 276 | } | ||
| 277 | ✗ | return NULL; | |
| 278 | } | ||
| 279 | |||
| 280 | ✗ | void BluetoothLE::enumCharacteristics(Device const& device, Guid const& serviceGuid, CharacteristicsEnumCallback const& cb) | |
| 281 | { | ||
| 282 | ✗ | Service const* const ptrSvc = resolveBthLEService(device, serviceGuid); | |
| 283 | ✗ | if (ptrSvc == NULL) | |
| 284 | { | ||
| 285 | ✗ | GATEXX_RAISE_EXCEPTION(results::InvalidArg, "Invalid service GUID", 0); | |
| 286 | } | ||
| 287 | bthle_chara_cb_param param; | ||
| 288 | ✗ | param.device = &device; | |
| 289 | ✗ | param.service = ptrSvc; | |
| 290 | ✗ | param.cb = &cb; | |
| 291 | ✗ | result_t result = gate_device_bthle_service_enum(device.c_impl(), ptrSvc, &bthle_chara_cb, ¶m); | |
| 292 | ✗ | GATEXX_CHECK_EXCEPTION(result); | |
| 293 | ✗ | } | |
| 294 | |||
| 295 | ✗ | static gate_bool_t GATE_CALL bthle_chara_guid_cb(gate_device_bthle_characteristic_t const* chara, void* user_param) | |
| 296 | { | ||
| 297 | ✗ | ArrayList<Guid>* guids = static_cast<ArrayList<Guid>*>(user_param); | |
| 298 | ✗ | if (guids) | |
| 299 | { | ||
| 300 | ✗ | guids->tryAdd(Guid(chara->characteristic_guid)); | |
| 301 | } | ||
| 302 | ✗ | return true; | |
| 303 | } | ||
| 304 | |||
| 305 | ✗ | Array<Guid> BluetoothLE::enumCharacteristicsGuids(Device const& device, Guid const& serviceGuid) | |
| 306 | { | ||
| 307 | ✗ | ArrayList<Guid> guids; | |
| 308 | ✗ | Service const* const ptrSvc = resolveBthLEService(device, serviceGuid); | |
| 309 | ✗ | if (ptrSvc == NULL) | |
| 310 | { | ||
| 311 | ✗ | GATEXX_RAISE_EXCEPTION(results::InvalidArg, "Invalid service GUID", 0); | |
| 312 | } | ||
| 313 | ✗ | result_t result = gate_device_bthle_service_enum(device.c_impl(), ptrSvc, &bthle_chara_guid_cb, &guids); | |
| 314 | ✗ | GATEXX_CHECK_EXCEPTION(result); | |
| 315 | ✗ | return guids.toArray(); | |
| 316 | } | ||
| 317 | |||
| 318 | |||
| 319 | ✗ | Blob BluetoothLE::getCharacteristicValue(Device const& device, Guid const& serviceGuid, Guid const& charaGuid) | |
| 320 | { | ||
| 321 | char buffer[4096]; | ||
| 322 | ✗ | gate_size_t bufferLen = sizeof(buffer); | |
| 323 | ✗ | result_t result = gate_device_bthle_characteristic_get(device.c_impl(), &serviceGuid, &charaGuid, buffer, &bufferLen); | |
| 324 | ✗ | GATEXX_CHECK_EXCEPTION(result); | |
| 325 | |||
| 326 | ✗ | if (bufferLen > sizeof(buffer)) | |
| 327 | { | ||
| 328 | ✗ | GATEXX_RAISE_ERROR(results::OutOfBounds); | |
| 329 | } | ||
| 330 | ✗ | return Blob(&buffer[0], bufferLen); | |
| 331 | } | ||
| 332 | |||
| 333 | ✗ | void BluetoothLE::setCharacteristicValue(Device const& device, Guid const& serviceGuid, Guid const& charaGuid, Blob const& value) | |
| 334 | { | ||
| 335 | ✗ | result_t result = gate_device_bthle_characteristic_set(device.c_impl(), &serviceGuid, &charaGuid, | |
| 336 | ✗ | static_cast<char const*>(value.data()), value.length()); | |
| 337 | ✗ | GATEXX_CHECK_EXCEPTION(result); | |
| 338 | ✗ | } | |
| 339 | |||
| 340 | |||
| 341 | } // end of namespace sys | ||
| 342 | } // end of namespace gate | ||
| 343 |