Direct-BT v3.3.0-1-gc2d430c
Direct-BT - Direct Bluetooth Programming.
dbt_scanner10.cpp
Go to the documentation of this file.
1/*
2 * Author: Sven Gothel <sgothel@jausoft.com>
3 * Copyright (c) 2020 Gothel Software e.K.
4 * Copyright (c) 2020 ZAFENA AB
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be
15 * included in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25
26#include <cstring>
27#include <string>
28#include <memory>
29#include <cstdint>
30#include <fstream>
31#include <iostream>
32
33#include <cinttypes>
34
35#include <pthread.h>
36#include <csignal>
37
38#include <jau/cpp_lang_util.hpp>
40#include <jau/basic_algos.hpp>
41#include <jau/darray.hpp>
42
44
45extern "C" {
46 #include <unistd.h>
47}
48
49#include "dbt_constants.hpp"
50
51using namespace direct_bt;
52using namespace jau;
53using namespace jau::fractions_i64_literals;
54
55/** \file
56 * This _dbt_scanner10_ C++ scanner ::BTRole::Master GATT client example uses an event driven workflow
57 * and multithreading, i.e. one thread processes each found device when notified.
58 *
59 * _dbt_scanner10_ represents the recommended utilization of Direct-BT.
60 *
61 * ### dbt_scanner10 Invocation Examples:
62 * Using `scripts/run-dbt_scanner10.sh` from `dist` directory:
63 *
64 * * Scan and read all devices (using default auto-sec w/ keyboard iocap)
65 * ~~~
66 * ../scripts/run-dbt_scanner10.sh
67 * ~~~
68 *
69 * * Read device C0:26:DA:01:DA:B1 (using default auto-sec w/ keyboard iocap)
70 * ~~~
71 * ../scripts/run-dbt_scanner10.sh -dev C0:26:DA:01:DA:B1
72 * ~~~
73 *
74 * * Read device C0:26:DA:01:DA:B1 (using default auto-sec w/ keyboard iocap) from adapter 01:02:03:04:05:06
75 * ~~~
76 * ../scripts/run-dbt_scanner10.sh -adapter adapter 01:02:03:04:05:06 -dev C0:26:DA:01:DA:B1
77 * ~~~
78 *
79 * * Read device C0:26:DA:01:DA:B1 (enforcing no security)
80 * ~~~
81 * ../scripts/run-dbt_scanner10.sh -dev C0:26:DA:01:DA:B1 -seclevel C0:26:DA:01:DA:B1 1
82 * ~~~
83 *
84 * * Read any device containing C0:26:DA (enforcing no security)
85 * ~~~
86 * ../scripts/run-dbt_scanner10.sh -dev C0:26:DA -seclevel C0:26:DA 1
87 * ~~~
88 *
89 * * Read any device containing name `TAIDOC` (enforcing no security)
90 * ~~~
91 * ../scripts/run-dbt_scanner10.sh -dev 'TAIDOC' -seclevel 'TAIDOC' 1
92 * ~~~
93 *
94 * * Read device C0:26:DA:01:DA:B1, basic debug flags enabled (using default auto-sec w/ keyboard iocap)
95 * ~~~
96 * ../scripts/run-dbt_scanner10.sh -dev C0:26:DA:01:DA:B1 -dbt_debug true
97 * ~~~
98 *
99 * * Read device C0:26:DA:01:DA:B1, all debug flags enabled (using default auto-sec w/ keyboard iocap)
100 * ~~~
101 * ../scripts/run-dbt_scanner10.sh -dev C0:26:DA:01:DA:B1 -dbt_debug adapter.event,gatt.data,hci.event,hci.scan_ad_eir,mgmt.event
102 * ~~~
103 *
104 * ## Special Actions
105 * * To do a BT adapter removal/add via software, assuming the device is '1-4' (Bus 1.Port 4):
106 * ~~~
107 * echo '1-4' > /sys/bus/usb/drivers/usb/unbind
108 * echo '1-4' > /sys/bus/usb/drivers/usb/bind
109 * ~~~
110 */
111
112static uint64_t timestamp_t0;
113
114static EUI48 useAdapter = EUI48::ALL_DEVICE;
115static BTMode btMode = BTMode::DUAL;
116static bool use_privacy = false;
117
118static DiscoveryPolicy discoveryPolicy = DiscoveryPolicy::PAUSE_CONNECTED_UNTIL_READY; // default value
119static bool le_scan_active = true; // default value
120static const uint16_t le_scan_interval = 24; // default value
121static const uint16_t le_scan_window = 24; // default value
122static const uint8_t filter_policy = 0; // default value
123static const bool filter_dup = true; // default value
124
125static std::shared_ptr<BTAdapter> chosenAdapter = nullptr;
126
128static std::atomic<int> deviceReadyCount = 0;
129
130static std::atomic<int> MULTI_MEASUREMENTS = 8;
131
132static bool KEEP_CONNECTED = true;
133static bool GATT_PING_ENABLED = false;
134static bool REMOVE_DEVICE = true;
135
136// Default from dbt_peripheral00.cpp or DBTPeripheral00.java
137static std::unique_ptr<uuid_t> cmd_uuid = jau::uuid_t::create(std::string("d0ca6bf3-3d52-4760-98e5-fc5883e93712"));
138static std::unique_ptr<uuid_t> cmd_rsp_uuid = jau::uuid_t::create(std::string("d0ca6bf3-3d53-4760-98e5-fc5883e93712"));
139static uint8_t cmd_arg = 0x44;
140
141static bool SHOW_UPDATE_EVENTS = false;
142static bool QUIET = false;
143
144static void connectDiscoveredDevice(BTDeviceRef device);
145
146static void processReadyDevice(const BTDeviceRef& device);
147
148static void removeDevice(BTDeviceRef device);
149static void resetAdapter(BTAdapter *a, int mode);
150static bool startDiscovery(BTAdapter *a, const std::string& msg);
151
153
154 void adapterSettingsChanged(BTAdapter &a, const AdapterSetting oldmask, const AdapterSetting newmask,
155 const AdapterSetting changedmask, const uint64_t timestamp) override {
156 const bool initialSetting = AdapterSetting::NONE == oldmask;
157 if( initialSetting ) {
158 fprintf_td(stderr, "****** SETTINGS_INITIAL: %s -> %s, changed %s\n", to_string(oldmask).c_str(),
159 to_string(newmask).c_str(), to_string(changedmask).c_str());
160 } else {
161 fprintf_td(stderr, "****** SETTINGS_CHANGED: %s -> %s, changed %s\n", to_string(oldmask).c_str(),
162 to_string(newmask).c_str(), to_string(changedmask).c_str());
163 }
164 fprintf_td(stderr, "Status BTAdapter:\n");
165 fprintf_td(stderr, "%s\n", a.toString().c_str());
166 (void)timestamp;
167
168 if( !initialSetting &&
169 isAdapterSettingBitSet(changedmask, AdapterSetting::POWERED) &&
170 isAdapterSettingBitSet(newmask, AdapterSetting::POWERED) )
171 {
172 std::thread sd(::startDiscovery, &a, "powered-on"); // @suppress("Invalid arguments")
173 sd.detach();
174 }
175 }
176
177 void discoveringChanged(BTAdapter &a, const ScanType currentMeta, const ScanType changedType, const bool changedEnabled, const DiscoveryPolicy policy, const uint64_t timestamp) override {
178 fprintf_td(stderr, "****** DISCOVERING: meta %s, changed[%s, enabled %d, policy %s]: %s\n",
179 to_string(currentMeta).c_str(), to_string(changedType).c_str(), changedEnabled, to_string(policy).c_str(), a.toString().c_str());
180 (void)timestamp;
181 }
182
183 bool deviceFound(const BTDeviceRef& device, const uint64_t timestamp) override {
184 (void)timestamp;
185
187 ( BTDeviceRegistry::isWaitingForDevice(device->getAddressAndType().address, device->getName()) &&
188 ( 0 < MULTI_MEASUREMENTS || !BTDeviceRegistry::isDeviceProcessed(device->getAddressAndType()) )
189 )
190 )
191 {
192 fprintf_td(stderr, "****** FOUND__-0: Connecting %s\n", device->toString(true).c_str());
193 {
194 const uint64_t td = jau::getCurrentMilliseconds() - timestamp_t0; // adapter-init -> now
195 fprintf_td(stderr, "PERF: adapter-init -> FOUND__-0 %" PRIu64 " ms\n", td);
196 }
197 std::thread dc(::connectDiscoveredDevice, device); // @suppress("Invalid arguments")
198 dc.detach();
199 return true;
200 } else {
201 if( !QUIET ) {
202 fprintf_td(stderr, "****** FOUND__-1: NOP %s\n", device->toString(true).c_str());
203 }
204 return false;
205 }
206 }
207
208 void deviceUpdated(const BTDeviceRef& device, const EIRDataType updateMask, const uint64_t timestamp) override {
209 if( !QUIET && SHOW_UPDATE_EVENTS ) {
210 fprintf_td(stderr, "****** UPDATED: %s of %s\n", to_string(updateMask).c_str(), device->toString(true).c_str());
211 }
212 (void)timestamp;
213 }
214
215 void deviceConnected(const BTDeviceRef& device, const bool discovered, const uint64_t timestamp) override {
216 fprintf_td(stderr, "****** CONNECTED (discovered %d): %s\n", discovered, device->toString(true).c_str());
217 (void)discovered;
218 (void)timestamp;
219 }
220
221 void devicePairingState(const BTDeviceRef& device, const SMPPairingState state, const PairingMode mode, const uint64_t timestamp) override {
222 fprintf_td(stderr, "****** PAIRING STATE: state %s, mode %s, %s\n",
223 to_string(state).c_str(), to_string(mode).c_str(), device->toString().c_str());
224 (void)timestamp;
225 switch( state ) {
226 case SMPPairingState::NONE:
227 // next: deviceReady(..)
228 break;
229 case SMPPairingState::FAILED: {
230 const bool res = SMPKeyBin::remove(CLIENT_KEY_PATH, *device);
231 fprintf_td(stderr, "****** PAIRING_STATE: state %s; Remove key file %s, res %d\n",
232 to_string(state).c_str(), SMPKeyBin::getFilename(CLIENT_KEY_PATH, *device).c_str(), res);
233 // next: deviceReady() or deviceDisconnected(..)
234 } break;
235 case SMPPairingState::REQUESTED_BY_RESPONDER:
236 // next: FEATURE_EXCHANGE_STARTED
237 break;
238 case SMPPairingState::FEATURE_EXCHANGE_STARTED:
239 // next: FEATURE_EXCHANGE_COMPLETED
240 break;
241 case SMPPairingState::FEATURE_EXCHANGE_COMPLETED:
242 // next: PASSKEY_EXPECTED... or KEY_DISTRIBUTION
243 break;
244 case SMPPairingState::PASSKEY_EXPECTED: {
245 const BTSecurityRegistry::Entry* sec = BTSecurityRegistry::getStartOf(device->getAddressAndType().address, device->getName());
246 if( nullptr != sec && sec->getPairingPasskey() != BTSecurityRegistry::Entry::NO_PASSKEY ) {
247 std::thread dc(&BTDevice::setPairingPasskey, device, static_cast<uint32_t>( sec->getPairingPasskey() ));
248 dc.detach();
249 } else {
250 std::thread dc(&BTDevice::setPairingPasskey, device, 0);
251 // 3s disconnect: std::thread dc(&BTDevice::setPairingPasskeyNegative, device);
252 dc.detach();
253 }
254 // next: KEY_DISTRIBUTION or FAILED
255 } break;
256 case SMPPairingState::NUMERIC_COMPARE_EXPECTED: {
257 const BTSecurityRegistry::Entry* sec = BTSecurityRegistry::getStartOf(device->getAddressAndType().address, device->getName());
258 if( nullptr != sec ) {
259 std::thread dc(&BTDevice::setPairingNumericComparison, device, sec->getPairingNumericComparison());
260 dc.detach();
261 } else {
262 std::thread dc(&BTDevice::setPairingNumericComparison, device, false);
263 dc.detach();
264 }
265 // next: KEY_DISTRIBUTION or FAILED
266 } break;
267 case SMPPairingState::OOB_EXPECTED:
268 // FIXME: ABORT
269 break;
270 case SMPPairingState::KEY_DISTRIBUTION:
271 // next: COMPLETED or FAILED
272 break;
273 case SMPPairingState::COMPLETED:
274 // next: deviceReady(..)
275 break;
276 default: // nop
277 break;
278 }
279 }
280
281 void deviceReady(const BTDeviceRef& device, const uint64_t timestamp) override {
282 (void)timestamp;
284 fprintf_td(stderr, "****** READY-0: Processing[%d] %s\n", deviceReadyCount.load(), device->toString(true).c_str());
285 processReadyDevice(device); // AdapterStatusListener::deviceReady() explicitly allows prolonged and complex code execution!
286 }
287
288 void deviceDisconnected(const BTDeviceRef& device, const HCIStatusCode reason, const uint16_t handle, const uint64_t timestamp) override {
289 fprintf_td(stderr, "****** DISCONNECTED: Reason 0x%X (%s), old handle %s: %s\n",
290 static_cast<uint8_t>(reason), to_string(reason).c_str(),
291 to_hexstring(handle).c_str(), device->toString(true).c_str());
292 (void)timestamp;
293
294 if( REMOVE_DEVICE ) {
295 std::thread dc(::removeDevice, device); // @suppress("Invalid arguments")
296 dc.detach();
297 }
299 std::thread dc(::resetAdapter, &device->getAdapter(), 1); // @suppress("Invalid arguments")
300 dc.detach();
301 }
302 }
303
304 std::string toString() const noexcept override {
305 return "MyAdapterStatusListener[this "+to_hexstring(this)+"]";
306 }
307
308};
309
311
313 private:
314 int i, j;
315
316 public:
317
318 MyGATTEventListener(int i_, int j_) : i(i_), j(j_) {}
319
320 void notificationReceived(BTGattCharRef charDecl, const TROOctets& char_value, const uint64_t timestamp) override {
321 const uint64_t tR = jau::getCurrentMilliseconds();
322 fprintf_td(stderr, "**[%2.2d.%2.2d] Characteristic-Notify: UUID %s, td %" PRIu64 " ******\n",
323 i, j, charDecl->value_type->toUUID128String().c_str(), (tR-timestamp));
324 fprintf_td(stderr, "**[%2.2d.%2.2d] Characteristic: %s ******\n", i, j, charDecl->toString().c_str());
325 if( _TEMPERATURE_MEASUREMENT == *charDecl->value_type ) {
326 std::shared_ptr<GattTemperatureMeasurement> temp = GattTemperatureMeasurement::get(char_value);
327 if( nullptr != temp ) {
328 fprintf_td(stderr, "**[%2.2d.%2.2d] Value T: %s ******\n", i, j, temp->toString().c_str());
329 }
330 fprintf_td(stderr, "**[%2.2d.%2.2d] Value R: %s ******\n", i, j, char_value.toString().c_str());
331 } else {
332 fprintf_td(stderr, "**[%2.2d.%2.2d] Value R: %s ******\n", i, j, char_value.toString().c_str());
333 fprintf_td(stderr, "**[%2.2d.%2.2d] Value S: %s ******\n", i, j, jau::dfa_utf8_decode(char_value.get_ptr(), char_value.size()).c_str());
334 }
335 }
336
338 const TROOctets& char_value, const uint64_t timestamp,
339 const bool confirmationSent) override
340 {
341 const uint64_t tR = jau::getCurrentMilliseconds();
342 fprintf_td(stderr, "**[%2.2d.%2.2d] Characteristic-Indication: UUID %s, td %" PRIu64 ", confirmed %d ******\n",
343 i, j, charDecl->value_type->toUUID128String().c_str(), (tR-timestamp), confirmationSent);
344 fprintf_td(stderr, "**[%2.2d.%2.2d] Characteristic: %s ******\n", i, j, charDecl->toString().c_str());
345 if( _TEMPERATURE_MEASUREMENT == *charDecl->value_type ) {
346 std::shared_ptr<GattTemperatureMeasurement> temp = GattTemperatureMeasurement::get(char_value);
347 if( nullptr != temp ) {
348 fprintf_td(stderr, "**[%2.2d.%2.2d] Value T: %s ******\n", i, j, temp->toString().c_str());
349 }
350 fprintf_td(stderr, "**[%2.2d.%2.2d] Value R: %s ******\n", i, j, char_value.toString().c_str());
351 } else {
352 fprintf_td(stderr, "**[%2.2d.%2.2d] Value R: %s ******\n", i, j, char_value.toString().c_str());
353 fprintf_td(stderr, "**[%2.2d.%2.2d] Value S: %s ******\n", i, j, jau::dfa_utf8_decode(char_value.get_ptr(), char_value.size()).c_str());
354 }
355 }
356};
357
358static void connectDiscoveredDevice(BTDeviceRef device) { // NOLINT(performance-unnecessary-value-param): Pass-by-value out-of-thread
359 fprintf_td(stderr, "****** Connecting Device: Start %s\n", device->toString().c_str());
360
361 const BTSecurityRegistry::Entry* sec = BTSecurityRegistry::getStartOf(device->getAddressAndType().address, device->getName());
362 if( nullptr != sec ) {
363 fprintf_td(stderr, "****** Connecting Device: Found SecurityDetail %s for %s\n", sec->toString().c_str(), device->toString().c_str());
364 } else {
365 fprintf_td(stderr, "****** Connecting Device: No SecurityDetail for %s\n", device->toString().c_str());
366 }
367 const BTSecurityLevel req_sec_level = nullptr != sec ? sec->getSecLevel() : BTSecurityLevel::UNSET;
368 HCIStatusCode res = device->uploadKeys(CLIENT_KEY_PATH, req_sec_level, true /* verbose_ */);
369 fprintf_td(stderr, "****** Connecting Device: BTDevice::uploadKeys(...) result %s\n", to_string(res).c_str());
370 if( HCIStatusCode::SUCCESS != res ) {
371 if( nullptr != sec ) {
372 if( sec->isSecurityAutoEnabled() ) {
373 bool r = device->setConnSecurityAuto( sec->getSecurityAutoIOCap() );
374 fprintf_td(stderr, "****** Connecting Device: Using SecurityDetail.SEC AUTO %s, set OK %d\n", sec->toString().c_str(), r);
375 } else if( sec->isSecLevelOrIOCapSet() ) {
376 bool r = device->setConnSecurity( sec->getSecLevel(), sec->getIOCap() );
377 fprintf_td(stderr, "****** Connecting Device: Using SecurityDetail.Level+IOCap %s, set OK %d\n", sec->toString().c_str(), r);
378 } else {
379 bool r = device->setConnSecurityAuto( SMPIOCapability::KEYBOARD_ONLY );
380 fprintf_td(stderr, "****** Connecting Device: Setting SEC AUTO security detail w/ KEYBOARD_ONLY (%s) -> set OK %d\n", sec->toString().c_str(), r);
381 }
382 } else {
383 bool r = device->setConnSecurityAuto( SMPIOCapability::KEYBOARD_ONLY );
384 fprintf_td(stderr, "****** Connecting Device: Setting SEC AUTO security detail w/ KEYBOARD_ONLY -> set OK %d\n", r);
385 }
386 }
387 std::shared_ptr<const EInfoReport> eir = device->getEIR();
388 fprintf_td(stderr, "EIR-1 %s\n", device->getEIRInd()->toString().c_str());
389 fprintf_td(stderr, "EIR-2 %s\n", device->getEIRScanRsp()->toString().c_str());
390 fprintf_td(stderr, "EIR-+ %s\n", eir->toString().c_str());
391
392 uint16_t conn_interval_min = (uint16_t)8; // 10ms
393 uint16_t conn_interval_max = (uint16_t)12; // 15ms
394 const uint16_t conn_latency = (uint16_t)0;
395 if( eir->isSet(EIRDataType::CONN_IVAL) ) {
396 eir->getConnInterval(conn_interval_min, conn_interval_max);
397 }
398 const uint16_t supervision_timeout = (uint16_t) getHCIConnSupervisorTimeout(conn_latency, (int) ( conn_interval_max * 1.25 ) /* ms */);
399 res = device->connectLE(le_scan_interval, le_scan_window, conn_interval_min, conn_interval_max, conn_latency, supervision_timeout);
400 fprintf_td(stderr, "****** Connecting Device: End result %s of %s\n", to_string(res).c_str(), device->toString().c_str());
401}
402
403static void processReadyDevice(const BTDeviceRef& device) {
404 fprintf_td(stderr, "****** Processing Ready Device: Start %s\n", device->toString().c_str());
405
406 const uint64_t t1 = jau::getCurrentMilliseconds();
407
408 SMPKeyBin::createAndWrite(*device, CLIENT_KEY_PATH, true /* verbose */);
409
410 const uint64_t t2 = jau::getCurrentMilliseconds();
411
412 bool success = false;
413
414 if( device->getAdapter().getBTMajorVersion() > 4 ) {
415 LE_PHYs Tx { LE_PHYs::LE_2M }, Rx { LE_PHYs::LE_2M };
416 HCIStatusCode res = device->setConnectedLE_PHY(Tx, Rx);
417 fprintf_td(stderr, "****** Set Connected LE PHY: status %s: Tx %s, Rx %s\n",
418 to_string(res).c_str(), to_string(Tx).c_str(), to_string(Rx).c_str());
419 }
420 {
421 LE_PHYs resTx, resRx;
422 HCIStatusCode res = device->getConnectedLE_PHY(resTx, resRx);
423 fprintf_td(stderr, "****** Got Connected LE PHY: status %s: Tx %s, Rx %s\n",
424 to_string(res).c_str(), to_string(resTx).c_str(), to_string(resRx).c_str());
425 }
426
427 //
428 // GATT Service Processing
429 //
430 fprintf_td(stderr, "****** Processing Ready Device: GATT start: %s\n", device->getAddressAndType().toString().c_str());
431 if( !QUIET ) {
432 device->getAdapter().printDeviceLists();
433 }
434 const uint64_t t3 = jau::getCurrentMilliseconds();
435
436 try {
437 jau::darray<BTGattServiceRef> primServices = device->getGattServices();
438 if( 0 == primServices.size() ) {
439 fprintf_td(stderr, "****** Processing Ready Device: getServices() failed %s\n", device->toString().c_str());
440 goto exit;
441 }
442
443 const uint64_t t5 = jau::getCurrentMilliseconds();
444 {
445 const uint64_t td00 = device->getLastDiscoveryTimestamp() - timestamp_t0; // adapter-init to discovered
446 const uint64_t td01 = t1 - timestamp_t0; // adapter-init to processing-start
447 const uint64_t td05 = t5 - timestamp_t0; // adapter-init -> gatt-complete
448 const uint64_t tdc1 = t1 - device->getLastDiscoveryTimestamp(); // discovered to processing-start
449 const uint64_t tdc5 = t5 - device->getLastDiscoveryTimestamp(); // discovered to gatt-complete
450 const uint64_t td12 = t2 - t1; // SMPKeyBin
451 const uint64_t td23 = t3 - t2; // LE_PHY
452 const uint64_t td13 = t3 - t1; // SMPKeyBin + LE_PHY
453 const uint64_t td35 = t5 - t3; // get-gatt-services
454 fprintf_td(stderr, "\n\n\n");
455 fprintf_td(stderr, "PERF: GATT primary-services completed\n"
456 "PERF: adapter-init to discovered %" PRIu64 " ms,\n"
457 "PERF: adapter-init to processing-start %" PRIu64 " ms,\n"
458 "PERF: adapter-init to gatt-complete %" PRIu64 " ms\n"
459 "PERF: discovered to processing-start %" PRIu64 " ms,\n"
460 "PERF: discovered to gatt-complete %" PRIu64 " ms,\n"
461 "PERF: SMPKeyBin + LE_PHY %" PRIu64 " ms (SMPKeyBin %" PRIu64 " ms, LE_PHY %" PRIu64 " ms),\n"
462 "PERF: get-gatt-services %" PRIu64 " ms,\n\n",
463 td00, td01, td05,
464 tdc1, tdc5,
465 td13, td12, td23, td35);
466 }
467
468 if( nullptr != cmd_uuid ) {
469 BTGattCmd cmd = nullptr != cmd_rsp_uuid ? BTGattCmd(*device, "TestCmd", *cmd_uuid, *cmd_rsp_uuid, 256)
470 : BTGattCmd(*device, "TestCmd", *cmd_uuid);
471 cmd.setVerbose(true);
472 const bool cmd_resolved = cmd.isResolved();
473 fprintf_td(stderr, "Command test: %s, resolved %d\n", cmd.toString().c_str(), cmd_resolved);
474 POctets cmd_data(1, lb_endian::little);
475 cmd_data.put_uint8_nc(0, cmd_arg);
476 const HCIStatusCode cmd_res = cmd.send(true /* prefNoAck */, cmd_data, 3_s);
477 if( HCIStatusCode::SUCCESS == cmd_res ) {
478 if( cmd.hasResponseSet() ) {
479 const jau::TROOctets& resp = cmd.getResponse();
480 if( 1 == resp.size() && resp.get_uint8_nc(0) == cmd_arg ) {
481 fprintf_td(stderr, "Success: %s -> %s (echo response)\n", cmd.toString().c_str(), resp.toString().c_str());
482 } else {
483 fprintf_td(stderr, "Success: %s -> %s (different response)\n", cmd.toString().c_str(), resp.toString().c_str());
484 }
485 } else {
486 fprintf_td(stderr, "Success: %s -> no response\n", cmd.toString().c_str());
487 }
488 } else {
489 fprintf_td(stderr, "Failure: %s -> %s\n", cmd.toString().c_str(), to_string(cmd_res).c_str());
490 }
491 }
492
493 std::shared_ptr<GattGenericAccessSvc> ga = device->getGattGenericAccess();
494 if( nullptr != ga && !QUIET ) {
495 fprintf_td(stderr, " GenericAccess: %s\n\n", ga->toString().c_str());
496 }
497 {
498 std::shared_ptr<BTGattHandler> gatt = device->getGattHandler();
499 if( nullptr != gatt && gatt->isConnected() ) {
500 std::shared_ptr<GattDeviceInformationSvc> di = gatt->getDeviceInformation(primServices);
501 if( nullptr != di && !QUIET ) {
502 fprintf_td(stderr, " DeviceInformation: %s\n\n", di->toString().c_str());
503 }
504 }
505 }
506
507
508 for(size_t i=0; i<primServices.size(); i++) {
509 BTGattService & primService = *primServices.at(i);
510 {
511 fprintf_td(stderr, " [%2.2d] Service UUID %s (%s)\n", i,
512 primService.type->toUUID128String().c_str(),
513 primService.type->getTypeSizeString().c_str());
514 fprintf_td(stderr, " [%2.2d] %s\n", i, primService.toString().c_str());
515 }
516 jau::darray<BTGattCharRef> & serviceCharacteristics = primService.characteristicList;
517 for(size_t j=0; j<serviceCharacteristics.size(); j++) {
518 BTGattCharRef & serviceChar = serviceCharacteristics.at(j);
519 {
520 fprintf_td(stderr, " [%2.2d.%2.2d] Characteristic: UUID %s (%s)\n", i, j,
521 serviceChar->value_type->toUUID128String().c_str(),
522 serviceChar->value_type->getTypeSizeString().c_str());
523 fprintf_td(stderr, " [%2.2d.%2.2d] %s\n", i, j, serviceChar->toString().c_str());
524 }
525 if( serviceChar->hasProperties(BTGattChar::PropertyBitVal::Read) ) {
526 POctets value(BTGattHandler::number(BTGattHandler::Defaults::MAX_ATT_MTU), 0, jau::lb_endian::little);
527 if( serviceChar->readValue(value) ) {
528 std::string sval = dfa_utf8_decode(value.get_ptr(), value.size());
529 {
530 fprintf_td(stderr, " [%2.2d.%2.2d] value: %s ('%s')\n", (int)i, (int)j, value.toString().c_str(), sval.c_str());
531 }
532 }
533 }
534 jau::darray<BTGattDescRef> & charDescList = serviceChar->descriptorList;
535 for(size_t k=0; k<charDescList.size(); k++) {
536 BTGattDesc & charDesc = *charDescList.at(k);
537 {
538 fprintf_td(stderr, " [%2.2d.%2.2d.%2.2d] Descriptor: UUID %s (%s)\n", i, j, k,
539 charDesc.type->toUUID128String().c_str(),
540 charDesc.type->getTypeSizeString().c_str());
541 fprintf_td(stderr, " [%2.2d.%2.2d.%2.2d] %s\n", i, j, k, charDesc.toString().c_str());
542 }
543 }
544 bool cccdEnableResult[2];
545 if( serviceChar->enableNotificationOrIndication( cccdEnableResult ) ) {
546 // ClientCharConfigDescriptor (CCD) is available
547 bool clAdded = serviceChar->addCharListener( std::make_shared<MyGATTEventListener>(i, j) );
548 {
549 fprintf_td(stderr, " [%2.2d.%2.2d] Characteristic-Listener: Notification(%d), Indication(%d): Added %d\n",
550 (int)i, (int)j, cccdEnableResult[0], cccdEnableResult[1], clAdded);
551 fprintf_td(stderr, "\n");
552 }
553 }
554 }
555 fprintf_td(stderr, "\n");
556 }
557 // FIXME sleep 1s for potential callbacks ..
558 jau::sleep_for( 1_s );
559 success = true;
560 } catch ( std::exception & e ) {
561 fprintf_td(stderr, "****** Processing Ready Device: Exception caught for %s: %s\n", device->toString().c_str(), e.what());
562 }
563
564exit:
565 fprintf_td(stderr, "****** Processing Ready Device: End-1: Success %d on %s\n", success, device->toString().c_str());
566
567 if( DiscoveryPolicy::PAUSE_CONNECTED_UNTIL_DISCONNECTED == discoveryPolicy ) {
568 device->getAdapter().removeDevicePausingDiscovery(*device);
569 }
570
571 if( KEEP_CONNECTED && GATT_PING_ENABLED && success ) {
572 while( device->pingGATT() ) {
573 fprintf_td(stderr, "****** Processing Ready Device: pingGATT OK: %s\n", device->getAddressAndType().toString().c_str());
574 jau::sleep_for( 1_s );
575 }
576 fprintf_td(stderr, "****** Processing Ready Device: pingGATT failed, waiting for disconnect: %s\n", device->getAddressAndType().toString().c_str());
577 // Even w/ GATT_PING_ENABLED, we utilize disconnect event to clean up -> remove
578 }
579
580 if( !QUIET ) {
581 device->getAdapter().printDeviceLists();
582 }
583
584 fprintf_td(stderr, "****** Processing Ready Device: End-2: Success %d on %s\n", success, device->toString().c_str());
585
586 if( success ) {
587 BTDeviceRegistry::addToProcessedDevices(device->getAddressAndType(), device->getName());
588 }
589
590 if( !KEEP_CONNECTED ) {
591 device->removeAllCharListener();
592
593 device->remove();
594
596 resetAdapter(&device->getAdapter(), 2);
597 }
598 }
599
600 if( 0 < MULTI_MEASUREMENTS ) {
602 fprintf_td(stderr, "****** Processing Ready Device: MULTI_MEASUREMENTS left %d: %s\n", MULTI_MEASUREMENTS.load(), device->getAddressAndType().toString().c_str());
603 }
604}
605
606static void removeDevice(BTDeviceRef device) { // NOLINT(performance-unnecessary-value-param): Pass-by-value out-of-thread
607 fprintf_td(stderr, "****** Remove Device: removing: %s\n", device->getAddressAndType().toString().c_str());
608
609 device->remove();
610}
611
612static void resetAdapter(BTAdapter *a, int mode) {
613 fprintf_td(stderr, "****** Reset Adapter: reset[%d] start: %s\n", mode, a->toString().c_str());
614 HCIStatusCode res = a->reset();
615 fprintf_td(stderr, "****** Reset Adapter: reset[%d] end: %s, %s\n", mode, to_string(res).c_str(), a->toString().c_str());
616}
617
618static bool startDiscovery(BTAdapter *a, const std::string& msg) {
619 if( useAdapter != EUI48::ALL_DEVICE && useAdapter != a->getAddressAndType().address ) {
620 fprintf_td(stderr, "****** Start discovery (%s): Adapter not selected: %s\n", msg.c_str(), a->toString().c_str());
621 return false;
622 }
624 fprintf_td(stderr, "****** Start discovery (%s) result: %s: %s\n", msg.c_str(), to_string(status).c_str(), a->toString().c_str());
625 return HCIStatusCode::SUCCESS == status;
626}
627
628static bool initAdapter(std::shared_ptr<BTAdapter>& adapter) {
629 if( useAdapter != EUI48::ALL_DEVICE && useAdapter != adapter->getAddressAndType().address ) {
630 fprintf_td(stderr, "initAdapter: Adapter not selected: %s\n", adapter->toString().c_str());
631 return false;
632 }
633 // Initialize with defaults and power-on
634 if( !adapter->isInitialized() ) {
635 HCIStatusCode status = adapter->initialize( btMode, false );
636 if( HCIStatusCode::SUCCESS != status ) {
637 fprintf_td(stderr, "initAdapter: Adapter initialization failed: %s: %s\n",
638 to_string(status).c_str(), adapter->toString().c_str());
639 return false;
640 }
641 adapter->setPrivacy(use_privacy);
642 }
643 if( !adapter->setPowered( true ) ) {
644 fprintf_td(stderr, "initAdapter: Adapter power-on failed:: %s\n", adapter->toString().c_str());
645 return false;
646 }
647 // adapter is powered-on
648 fprintf_td(stderr, "initAdapter: %s\n", adapter->toString().c_str());
649 {
650 const LE_Features le_feats = adapter->getLEFeatures();
651 fprintf_td(stderr, "initAdapter: LE_Features %s\n", to_string(le_feats).c_str());
652 }
653 if( adapter->getBTMajorVersion() > 4 ) {
654 LE_PHYs Tx { LE_PHYs::LE_2M }, Rx { LE_PHYs::LE_2M };
655 HCIStatusCode res = adapter->setDefaultLE_PHY(Tx, Rx);
656 fprintf_td(stderr, "initAdapter: Set Default LE PHY: status %s: Tx %s, Rx %s\n",
657 to_string(res).c_str(), to_string(Tx).c_str(), to_string(Rx).c_str());
658 }
659 std::shared_ptr<AdapterStatusListener> asl(new MyAdapterStatusListener());
660 adapter->addStatusListener( asl );
661
662 if( !startDiscovery(adapter.get(), "initAdapter") ) {
663 adapter->removeStatusListener( asl );
664 return false;
665 }
666 return true;
667}
668
669static void myChangedAdapterSetFunc(const bool added, std::shared_ptr<BTAdapter>& adapter) {
670 if( added ) {
671 if( nullptr == chosenAdapter ) {
672 if( initAdapter( adapter ) ) {
673 chosenAdapter = adapter;
674 fprintf_td(stderr, "****** Adapter ADDED__: InitOK: %s\n", adapter->toString().c_str());
675 } else {
676 fprintf_td(stderr, "****** Adapter ADDED__: Ignored: %s\n", adapter->toString().c_str());
677 }
678 } else {
679 fprintf_td(stderr, "****** Adapter ADDED__: Ignored (other): %s\n", adapter->toString().c_str());
680 }
681 } else {
682 if( nullptr != chosenAdapter && adapter == chosenAdapter ) {
683 chosenAdapter = nullptr;
684 fprintf_td(stderr, "****** Adapter REMOVED: %s\n", adapter->toString().c_str());
685 } else {
686 fprintf_td(stderr, "****** Adapter REMOVED (other): %s\n", adapter->toString().c_str());
687 }
688 }
689}
690
691void test() {
692 bool done = false;
693
695
696 std::shared_ptr<BTManager> mngr = BTManager::get();
697 mngr->addChangedAdapterSetCallback(myChangedAdapterSetFunc);
698
699 while( !done ) {
700 if( 0 == MULTI_MEASUREMENTS ||
702 )
703 {
704 fprintf_td(stderr, "****** EOL Test MULTI_MEASUREMENTS left %d, processed %zu/%zu\n",
706 fprintf_td(stderr, "****** WaitForDevice %s\n", BTDeviceRegistry::getWaitForDevicesString().c_str());
707 fprintf_td(stderr, "****** DevicesProcessed %s\n", BTDeviceRegistry::getProcessedDevicesString().c_str());
708 done = true;
709 } else {
710 jau::sleep_for( 2_s );
711 }
712 }
713 chosenAdapter = nullptr;
714
715 //
716 // just a manually controlled pull down to show status, not required
717 //
718 jau::darray<std::shared_ptr<BTAdapter>> adapterList = mngr->getAdapters();
719
720 jau::for_each_const(adapterList, [](const std::shared_ptr<BTAdapter>& adapter) {
721 fprintf_td(stderr, "****** EOL Adapter's Devices - pre close: %s\n", adapter->toString().c_str());
722 adapter->printDeviceLists();
723 });
724 {
725 BTManager::size_type count = mngr->removeChangedAdapterSetCallback(myChangedAdapterSetFunc);
726 fprintf_td(stderr, "****** EOL Removed ChangedAdapterSetCallback %zu\n", (size_t)count);
727
728 mngr->close();
729 }
730 jau::for_each_const(adapterList, [](const std::shared_ptr<BTAdapter>& adapter) {
731 fprintf_td(stderr, "****** EOL Adapter's Devices - post close: %s\n", adapter->toString().c_str());
732 adapter->printDeviceLists();
733 });
734}
735
736#include <cstdio>
737
738int main(int argc, char *argv[])
739{
740 bool waitForEnter=false;
741
742 fprintf_td(stderr, "Direct-BT Native Version %s (API %s)\n", DIRECT_BT_VERSION, DIRECT_BT_VERSION_API);
743
744 for(int i=1; i<argc; i++) {
745 fprintf(stderr, "arg[%d/%d]: '%s'\n", i, argc, argv[i]);
746
747 if( !strcmp("-dbt_debug", argv[i]) && argc > (i+1) ) {
748 setenv("direct_bt.debug", argv[++i], 1 /* overwrite */);
749 } else if( !strcmp("-dbt_verbose", argv[i]) && argc > (i+1) ) {
750 setenv("direct_bt.verbose", argv[++i], 1 /* overwrite */);
751 } else if( !strcmp("-dbt_gatt", argv[i]) && argc > (i+1) ) {
752 setenv("direct_bt.gatt", argv[++i], 1 /* overwrite */);
753 } else if( !strcmp("-dbt_l2cap", argv[i]) && argc > (i+1) ) {
754 setenv("direct_bt.l2cap", argv[++i], 1 /* overwrite */);
755 } else if( !strcmp("-dbt_hci", argv[i]) && argc > (i+1) ) {
756 setenv("direct_bt.hci", argv[++i], 1 /* overwrite */);
757 } else if( !strcmp("-dbt_mgmt", argv[i]) && argc > (i+1) ) {
758 setenv("direct_bt.mgmt", argv[++i], 1 /* overwrite */);
759 } else if( !strcmp("-wait", argv[i]) ) {
760 waitForEnter = true;
761 } else if( !strcmp("-show_update_events", argv[i]) ) {
762 SHOW_UPDATE_EVENTS = true;
763 } else if( !strcmp("-quiet", argv[i]) ) {
764 QUIET = true;
765 } else if( !strcmp("-discoveryPolicy", argv[i]) ) {
766 discoveryPolicy = to_DiscoveryPolicy(atoi(argv[++i]));
767 } else if( !strcmp("-scanPassive", argv[i]) ) {
768 le_scan_active = false;
769 } else if( !strcmp("-btmode", argv[i]) && argc > (i+1) ) {
770 btMode = to_BTMode(argv[++i]);
771 } else if( !strcmp("-adapter", argv[i]) && argc > (i+1) ) {
772 useAdapter = EUI48( std::string(argv[++i]) );
773 } else if( !strcmp("-privacy", argv[i]) ) {
774 use_privacy = true;
775 } else if( !strcmp("-dev", argv[i]) && argc > (i+1) ) {
776 std::string addrOrNameSub = std::string(argv[++i]);
778 } else if( !strcmp("-passkey", argv[i]) && argc > (i+2) ) {
779 const std::string addrOrNameSub(argv[++i]);
781 sec->passkey = atoi(argv[++i]);
782 fprintf(stderr, "Set passkey in %s\n", sec->toString().c_str());
783 } else if( !strcmp("-seclevel", argv[i]) && argc > (i+2) ) {
784 const std::string addrOrNameSub(argv[++i]);
786 sec->sec_level = to_BTSecurityLevel(atoi(argv[++i]));
787 fprintf(stderr, "Set sec_level in %s\n", sec->toString().c_str());
788 } else if( !strcmp("-iocap", argv[i]) && argc > (i+2) ) {
789 const std::string addrOrNameSub(argv[++i]);
791 sec->io_cap = to_SMPIOCapability(atoi(argv[++i]));
792 fprintf(stderr, "Set io_cap in %s\n", sec->toString().c_str());
793 } else if( !strcmp("-secauto", argv[i]) && argc > (i+2) ) {
794 const std::string addrOrNameSub(argv[++i]);
796 sec->io_cap_auto = to_SMPIOCapability(atoi(argv[++i]));
797 fprintf(stderr, "Set SEC AUTO security io_cap in %s\n", sec->toString().c_str());
798 } else if( !strcmp("-cmd", argv[i]) && argc > (i+1) ) {
799 cmd_uuid = jau::uuid_t::create((std::string)argv[++i]);
800 } else if( !strcmp("-cmdrsp", argv[i]) && argc > (i+1) ) {
801 cmd_rsp_uuid = jau::uuid_t::create((std::string)argv[++i]);
802 } else if( !strcmp("-cmdarg", argv[i]) && argc > (i+1) ) {
803 cmd_arg = (uint8_t)atoi(argv[++i]);
804 } else if( !strcmp("-disconnect", argv[i]) ) {
805 KEEP_CONNECTED = false;
806 } else if( !strcmp("-enableGATTPing", argv[i]) ) {
807 GATT_PING_ENABLED = true;
808 } else if( !strcmp("-keepDevice", argv[i]) ) {
809 REMOVE_DEVICE = false;
810 } else if( !strcmp("-count", argv[i]) && argc > (i+1) ) {
811 MULTI_MEASUREMENTS = atoi(argv[++i]);
812 } else if( !strcmp("-single", argv[i]) ) {
814 } else if( !strcmp("-resetEachCon", argv[i]) && argc > (i+1) ) {
815 RESET_ADAPTER_EACH_CONN = atoi(argv[++i]);
816 }
817 }
818 fprintf_td(stderr, "pid %d\n", getpid());
819
820 fprintf_td(stderr, "Run with '[-btmode LE|BREDR|DUAL] "
821 "[-disconnect] [-enableGATTPing] [-count <number>] [-single] [-show_update_events] [-quiet] "
822 "[-discoveryPolicy <0-4>] "
823 "[-scanPassive] "
824 "[-resetEachCon connectionCount] "
825 "[-adapter <adapter_address>] "
826 "[-privacy] "
827 "(-dev <device_[address|name]_sub>)* "
828 "(-seclevel <device_[address|name]_sub> <int_sec_level>)* "
829 "(-iocap <device_[address|name]_sub> <int_iocap>)* "
830 "(-secauto <device_[address|name]_sub> <int_iocap>)* "
831 "(-passkey <device_[address|name]_sub> <digits>)* "
832 "[-cmd <uuid>] [-cmdrsp <uuid>] [-cmdarg <byte-val>] "
833 "[-dbt_verbose true|false] "
834 "[-dbt_debug true|false|adapter.event,gatt.data,hci.event,hci.scan_ad_eir,mgmt.event] "
835 "[-dbt_mgmt cmd.timeout=3000,ringsize=64,...] "
836 "[-dbt_hci cmd.complete.timeout=10000,cmd.status.timeout=3000,ringsize=64,...] "
837 "[-dbt_gatt cmd.read.timeout=500,cmd.write.timeout=500,cmd.init.timeout=2500,ringsize=128,...] "
838 "[-dbt_l2cap reader.timeout=10000,restart.count=0,...] "
839 "\n");
840
841 fprintf_td(stderr, "MULTI_MEASUREMENTS %d\n", MULTI_MEASUREMENTS.load());
842 fprintf_td(stderr, "KEEP_CONNECTED %d\n", KEEP_CONNECTED);
843 fprintf_td(stderr, "RESET_ADAPTER_EACH_CONN %d\n", RESET_ADAPTER_EACH_CONN);
844 fprintf_td(stderr, "GATT_PING_ENABLED %d\n", GATT_PING_ENABLED);
845 fprintf_td(stderr, "REMOVE_DEVICE %d\n", REMOVE_DEVICE);
846 fprintf_td(stderr, "SHOW_UPDATE_EVENTS %d\n", SHOW_UPDATE_EVENTS);
847 fprintf_td(stderr, "QUIET %d\n", QUIET);
848 fprintf_td(stderr, "adapter %s, privacy %d\n", useAdapter.toString().c_str(), use_privacy);
849 fprintf_td(stderr, "btmode %s\n", to_string(btMode).c_str());
850 fprintf_td(stderr, "discoveryPolicy %s\n", to_string(discoveryPolicy).c_str());
851 fprintf_td(stderr, "scanActive %s\n", to_string(le_scan_active).c_str());
852 fprintf_td(stderr, "Command: cmd %s, arg 0x%X\n rsp %s\n",
853 nullptr != cmd_uuid ? cmd_uuid->toString().c_str() : "n/a", cmd_arg,
854 nullptr != cmd_rsp_uuid ? cmd_rsp_uuid->toString().c_str() : "n/a");
855 fprintf_td(stderr, "security-details: %s\n", BTSecurityRegistry::allToString().c_str());
856 fprintf_td(stderr, "waitForDevice: %s\n", BTDeviceRegistry::getWaitForDevicesString().c_str());
857
858 if( waitForEnter ) {
859 fprintf_td(stderr, "Press ENTER to continue\n");
860 getchar();
861 }
862 fprintf_td(stderr, "****** TEST start\n");
863 test();
864 fprintf_td(stderr, "****** TEST end\n");
865 if( true ) {
866 // Just for testing purpose, i.e. triggering BTManager::close() within the test controlled app,
867 // instead of program shutdown.
868 fprintf_td(stderr, "****** Manager close start\n");
869 std::shared_ptr<BTManager> mngr = BTManager::get(); // already existing
870 mngr->close();
871 fprintf_td(stderr, "****** Manager close end\n");
872 }
873}
void indicationReceived(BTGattCharRef charDecl, const TROOctets &char_value, const uint64_t timestamp, const bool confirmationSent) override
Called from native BLE stack, initiated by a received indication associated with the given BTGattChar...
void notificationReceived(BTGattCharRef charDecl, const TROOctets &char_value, const uint64_t timestamp) override
Called from native BLE stack, initiated by a received notification associated with the given BTGattCh...
MyGATTEventListener(int i_, int j_)
BTAdapter status listener for remote BTDevice discovery events: Added, updated and removed; as well a...
Definition: BTAdapter.hpp:127
BTAdapter represents one local Bluetooth Controller.
Definition: BTAdapter.hpp:324
std::string toString() const noexcept override
Definition: BTAdapter.hpp:1331
HCIStatusCode reset() noexcept
Reset the adapter.
Definition: BTAdapter.cpp:943
HCIStatusCode startDiscovery(const DBGattServerRef &gattServerData_=nullptr, const DiscoveryPolicy policy=DiscoveryPolicy::PAUSE_CONNECTED_UNTIL_READY, const bool le_scan_active=true, const uint16_t le_scan_interval=24, const uint16_t le_scan_window=24, const uint8_t filter_policy=0x00, const bool filter_dup=true) noexcept
Starts discovery.
Definition: BTAdapter.cpp:1150
BDAddressAndType const & getAddressAndType() const noexcept
Returns the adapter's public BDAddressAndType, i.e.
Definition: BTAdapter.hpp:691
BTGattChar event listener for notification and indication events.
Definition: BTGattChar.hpp:450
Class maps a GATT command and optionally its asynchronous response to a synchronous atomic operation.
Definition: BTGattCmd.hpp:67
void setVerbose(const bool v) noexcept
Set verbosity for UUID resolution.
Definition: BTGattCmd.hpp:274
bool hasResponseSet() const noexcept
Return true if a notification or indication response has been set via constructor,...
Definition: BTGattCmd.hpp:268
HCIStatusCode send(const bool prefNoAck, const jau::TROOctets &cmd_data, const jau::fraction_i64 &timeout) noexcept
Send the command to the remote BTDevice.
Definition: BTGattCmd.cpp:176
bool isResolved() noexcept
Query whether all UUIDs of this commands have been resolved.
Definition: BTGattCmd.cpp:167
const jau::TROOctets & getResponse() const noexcept
Returns the read-only response data object for configured commands with response notification or indi...
Definition: BTGattCmd.hpp:283
std::string toString() const noexcept
Definition: BTGattCmd.cpp:262
Representing a Gatt Characteristic Descriptor object from the GATTRole::Client perspective.
Definition: BTGattDesc.hpp:74
std::unique_ptr< const jau::uuid_t > type
Type of descriptor.
Definition: BTGattDesc.hpp:110
std::string toString() const noexcept override
Definition: BTGattDesc.cpp:99
Representing a Gatt Service object from the GATTRole::Client perspective.
std::unique_ptr< const jau::uuid_t > type
Service type UUID.
std::string toString() const noexcept override
jau::darray< BTGattCharRef > characteristicList
List of Characteristic Declarations as shared reference.
jau::nsize_t size_type
Definition: BTManager.hpp:211
Persistent endian aware octet data, i.e.
Definition: octets.hpp:560
std::string toString() const
Definition: octets.hpp:932
constexpr void put_uint8_nc(const nsize_t i, const uint8_t v) noexcept
Definition: octets.hpp:335
Transient read only and endian aware octet data, i.e.
Definition: octets.hpp:67
std::string toString() const noexcept
Definition: octets.hpp:288
constexpr nsize_t size() const noexcept
Returns the used memory size for read and write operations, may be zero.
Definition: octets.hpp:162
constexpr uint8_t get_uint8_nc(const nsize_t i) const noexcept
Definition: octets.hpp:168
constexpr uint8_t const * get_ptr() const noexcept
Definition: octets.hpp:272
Implementation of a dynamic linear array storage, aka vector.
Definition: darray.hpp:148
constexpr size_type size() const noexcept
Like std::vector::size().
Definition: darray.hpp:763
const_reference at(size_type i) const
Like std::vector::at(size_type), immutable reference.
Definition: darray.hpp:814
static std::unique_ptr< uuid_t > create(TypeSize const t, uint8_t const *const buffer, lb_endian_t const le_or_be)
Definition: uuid.cpp:56
static bool REMOVE_DEVICE
static uint8_t cmd_arg
static const uint8_t filter_policy
static std::atomic< int > deviceReadyCount
int main(int argc, char *argv[])
static const uint16_t le_scan_interval
static uint64_t timestamp_t0
static bool use_privacy
static bool SHOW_UPDATE_EVENTS
static const uint16_t le_scan_window
static void connectDiscoveredDevice(BTDeviceRef device)
static void processReadyDevice(const BTDeviceRef &device)
static bool QUIET
static const bool filter_dup
static bool KEEP_CONNECTED
static bool le_scan_active
static std::shared_ptr< BTAdapter > chosenAdapter
static void myChangedAdapterSetFunc(const bool added, std::shared_ptr< BTAdapter > &adapter)
static bool initAdapter(std::shared_ptr< BTAdapter > &adapter)
static bool startDiscovery(BTAdapter *a, const std::string &msg)
static std::atomic< int > MULTI_MEASUREMENTS
static void resetAdapter(BTAdapter *a, int mode)
static DiscoveryPolicy discoveryPolicy
static BTMode btMode
static std::unique_ptr< uuid_t > cmd_uuid
static bool GATT_PING_ENABLED
static int RESET_ADAPTER_EACH_CONN
static EUI48 useAdapter
void test()
static void removeDevice(BTDeviceRef device)
static std::unique_ptr< uuid_t > cmd_rsp_uuid
static const uuid16_t _TEMPERATURE_MEASUREMENT(GattCharacteristicType::TEMPERATURE_MEASUREMENT)
constexpr const char CLIENT_KEY_PATH[]
C++20 we could use constexpr std::string
constexpr UnaryFunction for_each_const(T &data, UnaryFunction f, std::enable_if_t< is_cow_type< T >::value, bool >=true) noexcept
uint32_t dfa_utf8_decode(uint32_t &state, uint32_t &codep, const uint32_t byte_value)
std::string to_string(const alphabet &v) noexcept
Definition: base_codec.hpp:97
SMPPairingState
SMP Pairing Process state definition.
Definition: SMPTypes.hpp:107
constexpr SMPIOCapability to_SMPIOCapability(const uint8_t v) noexcept
Definition: SMPTypes.hpp:223
Entry * getStartOf(const EUI48 &addr, const std::string &name) noexcept
Returns a matching Entry,.
constexpr BTSecurityLevel to_BTSecurityLevel(const uint8_t v) noexcept
Definition: BTTypes0.hpp:300
Entry * getOrCreate(const std::string &addrOrNameSub) noexcept
Determines whether the given addrOrNameSub is a EUI48Sub or just a name and retrieves an entry.
BTMode
Bluetooth adapter operating mode.
Definition: BTTypes0.hpp:112
LE_Features
HCI Supported Commands.
Definition: BTTypes0.hpp:162
DiscoveryPolicy
Discovery policy defines the BTAdapter discovery mode after connecting a remote BTDevice:
Definition: BTAdapter.hpp:82
std::shared_ptr< BTDevice > BTDeviceRef
Definition: BTDevice.hpp:1347
LE_PHYs
LE Transport PHY bit values.
Definition: BTTypes0.hpp:231
Entry * get(const EUI48 &addr, const std::string &name, AddressNameEntryMatchFunc m) noexcept
Returns a matching BTSecurityRegistry::Entry with the given addr and/or name.
ScanType
Meta ScanType as derived from BTMode, with defined value mask consisting of BDAddressType bits.
Definition: BTTypes0.hpp:350
AdapterSetting
Adapter Setting Bits.
Definition: BTTypes1.hpp:144
constexpr bool isAdapterSettingBitSet(const AdapterSetting mask, const AdapterSetting bit) noexcept
Definition: BTTypes1.hpp:185
BTMode to_BTMode(const std::string &value) noexcept
Maps the specified name to a constant of BTMode.
Definition: BTTypes0.cpp:226
std::string allToString() noexcept
BTSecurityLevel
Bluetooth Security Level.
Definition: BTTypes0.hpp:267
PairingMode
Bluetooth secure pairing mode.
Definition: BTTypes0.hpp:317
constexpr DiscoveryPolicy to_DiscoveryPolicy(const uint8_t v) noexcept
Definition: BTAdapter.hpp:103
constexpr uint16_t getHCIConnSupervisorTimeout(const uint16_t conn_latency, const uint16_t conn_interval_max_ms, const uint16_t min_result_ms=number(HCIConstInt::LE_CONN_MIN_TIMEOUT_MS), const uint16_t multiplier=10) noexcept
Defining the supervising timeout for LE connections to be a multiple of the maximum connection interv...
Definition: HCITypes.hpp:102
HCIStatusCode
BT Core Spec v5.2: Vol 1, Part F Controller Error Codes: 1.3 List of Error Codes.
Definition: HCITypes.hpp:138
EIRDataType
Bit mask of 'Extended Inquiry Response' (EIR) data fields, indicating a set of related data.
Definition: BTTypes0.hpp:838
std::shared_ptr< BTGattChar > BTGattCharRef
Definition: BTGattChar.hpp:410
bool remove(const std::string &path, const traverse_options topts=traverse_options::none) noexcept
Remove the given path.
Definition: file_util.cpp:1173
constexpr uint32_t number(const iostate rhs) noexcept
Definition: byte_stream.hpp:72
std::string to_hexstring(value_type const &v) noexcept
Produce a lower-case hexadecimal string representation of the given pointer.
std::string getProcessedDevicesString() noexcept
void addToWaitForDevices(const std::string &addrOrNameSub) noexcept
size_t getProcessedDeviceCount() noexcept
std::string getWaitForDevicesString() noexcept
bool isDeviceProcessed(const BDAddressAndType &a) noexcept
bool areAllDevicesProcessed(DeviceQueryMatchFunc m) noexcept
Returns true if all addToWaitForDevices() awaited devices have been addToProcessedDevices() processed...
bool isWaitingForAnyDevice() noexcept
size_t getWaitForDevicesCount() noexcept
void addToProcessedDevices(const BDAddressAndType &a, const std::string &n) noexcept
bool isWaitingForDevice(const EUI48 &address, const std::string &name, DeviceQueryMatchFunc m) noexcept
Returns true if the given address and/or name matches any of the BTDeviceRegistry::addToWaitForDevice...
__pack(...): Produces MSVC, clang and gcc compatible lead-in and -out macros.
Definition: backtrace.hpp:32
int fprintf_td(const uint64_t elapsed_ms, FILE *stream, const char *format,...) noexcept
Convenient fprintf() invocation, prepending the given elapsed_ms timestamp.
Definition: debug.cpp:270
uint64_t getCurrentMilliseconds() noexcept
Returns current monotonic time in milliseconds.
Definition: basic_types.cpp:64
bool sleep_for(const fraction_timespec &relative_time, const bool monotonic=true, const bool ignore_irq=true) noexcept
sleep_for causes the current thread to block until a specific amount of time has passed.
constexpr bool isSecLevelOrIOCapSet() const noexcept
constexpr const BTSecurityLevel & getSecLevel() const noexcept
constexpr int getPairingPasskey() const noexcept
constexpr bool getPairingNumericComparison() const noexcept
constexpr const SMPIOCapability & getSecurityAutoIOCap() const noexcept
constexpr const SMPIOCapability & getIOCap() const noexcept
constexpr bool isSecurityAutoEnabled() const noexcept
std::string toString() const noexcept
A packed 48 bit EUI-48 identifier, formerly known as MAC-48 or simply network device MAC address (Med...
Definition: eui48.hpp:324
std::string toString() const noexcept
Definition: eui48.cpp:167
@ Read
@ TEMPERATURE_MEASUREMENT