Direct-BT  2.3.1
Direct-BT - Direct Bluetooth Programming.
BTManager.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 <cstdio>
31 
32 #include <algorithm>
33 
34 // #define PERF_PRINT_ON 1
35 // PERF3_PRINT_ON for close
36 // #define PERF3_PRINT_ON 1
37 #include <jau/debug.hpp>
38 
39 #include <jau/basic_algos.hpp>
40 
41 #include "BTIoctl.hpp"
42 
43 #include "HCIIoctl.hpp"
44 #include "HCIComm.hpp"
45 #include "BTTypes1.hpp"
46 #include "SMPHandler.hpp"
47 
48 #include "BTAdapter.hpp"
49 #include "BTManager.hpp"
50 
51 extern "C" {
52  #include <inttypes.h>
53  #include <unistd.h>
54  #include <poll.h>
55  #include <signal.h>
56 }
57 
58 using namespace direct_bt;
59 
60 BTMode MgmtEnv::getEnvBTMode() {
61  // Environment variable is 'direct_bt.mgmt.btmode' or 'org.tinyb.btmode'
62  // Default is BTMode::LE, if non of the above environment variable is set.
63  std::string val = jau::environment::getProperty("direct_bt.mgmt.btmode");
64  if( val.empty() ) {
65  val = jau::environment::getProperty("org.tinyb.btmode");
66  }
67  const BTMode res = direct_bt::to_BTMode(val);
68  return BTMode::NONE != res ? res : BTMode::DUAL; // fallback to default DUAL
69 }
70 
71 MgmtEnv::MgmtEnv() noexcept
72 : DEBUG_GLOBAL( jau::environment::get("direct_bt").debug ),
73  exploding( jau::environment::getExplodingProperties("direct_bt.mgmt") ),
74  MGMT_READER_THREAD_POLL_TIMEOUT( jau::environment::getInt32Property("direct_bt.mgmt.reader.timeout", 10000, 1500 /* min */, INT32_MAX /* max */) ),
75  MGMT_COMMAND_REPLY_TIMEOUT( jau::environment::getInt32Property("direct_bt.mgmt.cmd.timeout", 3000, 1500 /* min */, INT32_MAX /* max */) ),
76  MGMT_EVT_RING_CAPACITY( jau::environment::getInt32Property("direct_bt.mgmt.ringsize", 64, 64 /* min */, 1024 /* max */) ),
77  DEBUG_EVENT( jau::environment::getBooleanProperty("direct_bt.debug.mgmt.event", false) ),
78  DEFAULT_BTMODE( getEnvBTMode() ),
79  MGMT_READ_PACKET_MAX_RETRY( MGMT_EVT_RING_CAPACITY )
80 {
81 }
82 
83 const pid_t BTManager::pidSelf = getpid();
84 std::mutex BTManager::mtx_singleton;
85 
86 void BTManager::mgmtReaderThreadImpl() noexcept {
87  {
88  const std::lock_guard<std::mutex> lock(mtx_mgmtReaderLifecycle); // RAII-style acquire and relinquish via destructor
89  mgmtReaderShallStop = false;
90  mgmtReaderRunning = true;
91  DBG_PRINT("DBTManager::reader: Started");
92  cv_mgmtReaderInit.notify_all();
93  }
94  thread_local jau::call_on_release thread_cleanup([&]() {
95  DBG_PRINT("DBTManager::mgmtReaderThreadCleanup: mgmtReaderRunning %d -> 0", mgmtReaderRunning.load());
96  mgmtReaderRunning = false;
97  });
98 
99  while( !mgmtReaderShallStop ) {
100  jau::snsize_t len;
101  if( !comm.isOpen() ) {
102  // not open
103  ERR_PRINT("DBTManager::reader: Not connected");
104  mgmtReaderShallStop = true;
105  break;
106  }
107 
108  len = comm.read(rbuffer.get_wptr(), rbuffer.getSize(), env.MGMT_READER_THREAD_POLL_TIMEOUT);
109  if( 0 < len ) {
110  const jau::nsize_t len2 = static_cast<jau::nsize_t>(len);
111  const jau::nsize_t paramSize = len2 >= MGMT_HEADER_SIZE ? rbuffer.get_uint16_nc(4) : 0;
112  if( len2 < MGMT_HEADER_SIZE + paramSize ) {
113  WARN_PRINT("DBTManager::reader: length mismatch %zu < MGMT_HEADER_SIZE(%u) + %u", len2, MGMT_HEADER_SIZE, paramSize);
114  continue; // discard data
115  }
116  std::unique_ptr<MgmtEvent> event = MgmtEvent::getSpecialized(rbuffer.get_ptr(), len2);
117  const MgmtEvent::Opcode opc = event->getOpcode();
119  COND_PRINT(env.DEBUG_EVENT, "DBTManager-IO RECV (CMD) %s", event->toString().c_str());
120  if( mgmtEventRing.isFull() ) {
121  const jau::nsize_t dropCount = mgmtEventRing.capacity()/4;
122  mgmtEventRing.drop(dropCount);
123  WARN_PRINT("DBTManager-IO RECV Drop (%u oldest elements of %u capacity, ring full)", dropCount, mgmtEventRing.capacity());
124  }
125  mgmtEventRing.putBlocking( std::move( event ) );
126  } else if( MgmtEvent::Opcode::INDEX_ADDED == opc ) {
127  COND_PRINT(env.DEBUG_EVENT, "DBTManager-IO RECV (ADD) %s", event->toString().c_str());
128  std::thread adapterAddedThread(&BTManager::processAdapterAdded, this, std::move( event) ); // @suppress("Invalid arguments")
129  adapterAddedThread.detach();
130  } else if( MgmtEvent::Opcode::INDEX_REMOVED == opc ) {
131  COND_PRINT(env.DEBUG_EVENT, "DBTManager-IO RECV (REM) %s", event->toString().c_str());
132  std::thread adapterRemovedThread(&BTManager::processAdapterRemoved, this, std::move( event ) ); // @suppress("Invalid arguments")
133  adapterRemovedThread.detach();
134  } else {
135  // issue a callback
136  COND_PRINT(env.DEBUG_EVENT, "DBTManager-IO RECV (CB) %s", event->toString().c_str());
137  sendMgmtEvent( *event );
138  }
139  } else if( ETIMEDOUT != errno && !mgmtReaderShallStop ) { // expected exits
140  ERR_PRINT("DBTManager::reader: HCIComm read error");
141  }
142  }
143  {
144  const std::lock_guard<std::mutex> lock(mtx_mgmtReaderLifecycle); // RAII-style acquire and relinquish via destructor
145  WORDY_PRINT("DBTManager::reader: Ended. Ring has %u entries flushed", mgmtEventRing.getSize());
146  mgmtEventRing.clear();
147  mgmtReaderRunning = false;
148  cv_mgmtReaderInit.notify_all();
149  }
150 
151 
152 }
153 
154 void BTManager::sendMgmtEvent(const MgmtEvent& event) noexcept {
155  const uint16_t dev_id = event.getDevID();
156  MgmtAdapterEventCallbackList & mgmtEventCallbackList = mgmtAdapterEventCallbackLists[static_cast<uint16_t>(event.getOpcode())];
157  int invokeCount = 0;
158 
159  jau::for_each_fidelity(mgmtEventCallbackList, [&](MgmtAdapterEventCallback &cb) {
160  if( 0 > cb.getDevID() || dev_id == cb.getDevID() ) {
161  try {
162  cb.getCallback().invoke(event);
163  } catch (std::exception &e) {
164  ERR_PRINT("DBTManager::sendMgmtEvent-CBs %d/%zd: MgmtAdapterEventCallback %s : Caught exception %s",
165  invokeCount+1, mgmtEventCallbackList.size(),
166  cb.toString().c_str(), e.what());
167  }
168  invokeCount++;
169  }
170  });
171 
172  COND_PRINT(env.DEBUG_EVENT, "DBTManager::sendMgmtEvent: Event %s -> %d/%zd callbacks", event.toString().c_str(), invokeCount, mgmtEventCallbackList.size());
173  (void)invokeCount;
174 }
175 
176 static void mgmthandler_sigaction(int sig, siginfo_t *info, void *ucontext) noexcept {
177  bool pidMatch = info->si_pid == BTManager::pidSelf;
178  WORDY_PRINT("DBTManager.sigaction: sig %d, info[code %d, errno %d, signo %d, pid %d, uid %d, fd %d], pid-self %d (match %d)",
179  sig, info->si_code, info->si_errno, info->si_signo,
180  info->si_pid, info->si_uid, info->si_fd,
181  BTManager::pidSelf, pidMatch);
182  (void)ucontext;
183 
184  if( !pidMatch || SIGALRM != sig ) {
185  return;
186  }
187 #if 0
188  // We do not de-install the handler on single use,
189  // as we act for multiple SIGALRM events within direct-bt
190  {
191  struct sigaction sa_setup;
192  bzero(&sa_setup, sizeof(sa_setup));
193  sa_setup.sa_handler = SIG_DFL;
194  sigemptyset(&(sa_setup.sa_mask));
195  sa_setup.sa_flags = 0;
196  if( 0 != sigaction( SIGALRM, &sa_setup, NULL ) ) {
197  ERR_PRINT("DBTManager.sigaction: Resetting sighandler");
198  }
199  }
200 #endif
201 }
202 
203 bool BTManager::send(MgmtCommand &req) noexcept {
204  const std::lock_guard<std::recursive_mutex> lock(mtx_sendReply); // RAII-style acquire and relinquish via destructor
205  COND_PRINT(env.DEBUG_EVENT, "DBTManager-IO SENT %s", req.toString().c_str());
206  TROOctets & pdu = req.getPDU();
207  if ( comm.write( pdu.get_ptr(), pdu.getSize() ) < 0 ) {
208  ERR_PRINT("DBTManager::sendWithReply: HCIComm write error, req %s", req.toString().c_str());
209  return false;
210  }
211  return true;
212 }
213 
214 std::unique_ptr<MgmtEvent> BTManager::sendWithReply(MgmtCommand &req) noexcept {
215  const std::lock_guard<std::recursive_mutex> lock(mtx_sendReply); // RAII-style acquire and relinquish via destructor
216  if( !send(req) ) {
217  return nullptr;
218  }
219 
220  // Ringbuffer read is thread safe
221  int32_t retryCount = 0;
222  while( retryCount < env.MGMT_READ_PACKET_MAX_RETRY ) {
223  std::unique_ptr<MgmtEvent> res = mgmtEventRing.getBlocking(env.MGMT_COMMAND_REPLY_TIMEOUT);
224  // std::unique_ptr<MgmtEvent> res = receiveNext();
225  if( nullptr == res ) {
226  errno = ETIMEDOUT;
227  ERR_PRINT("DBTManager::sendWithReply.X: nullptr result (timeout -> abort): req %s", req.toString().c_str());
228  return nullptr;
229  } else if( !res->validate(req) ) {
230  // This could occur due to an earlier timeout w/ a nullptr == res (see above),
231  // i.e. the pending reply processed here and naturally not-matching.
232  COND_PRINT(env.DEBUG_EVENT, "DBTManager-IO RECV sendWithReply: res mismatch (drop evt, retryCount %d): res %s; req %s",
233  retryCount, res->toString().c_str(), req.toString().c_str());
234  retryCount++;
235  } else {
236  COND_PRINT(env.DEBUG_EVENT, "DBTManager-IO RECV sendWithReply: res %s; req %s", res->toString().c_str(), req.toString().c_str());
237  return res;
238  }
239  }
240  return nullptr;
241 }
242 
243 std::unique_ptr<AdapterInfo> BTManager::initAdapter(const uint16_t dev_id, const BTMode btMode) noexcept {
244  /**
245  * We weight on PairingMode::PASSKEY_ENTRY. FIXME: Have it configurable!
246  *
247  * BT Core Spec v5.2: Vol 3, Part H (SM): 2.3.5.1 Selecting key generation method Table 2.8
248  *
249  * See SMPTypes.cpp: getPairingMode(const bool le_sc_pairing, const SMPIOCapability ioCap_init, const SMPIOCapability ioCap_resp) noexcept
250  */
251 #if USE_LINUX_BT_SECURITY
252  const uint8_t debug_keys = 0;
253  const uint8_t ssp_on_param = 0x01; // SET_SSP 0x00 disabled, 0x01 enable Secure Simple Pairing. SSP only available for BREDR >= 2.1 not single-mode LE.
254  const uint8_t sc_on_param = 0x01; // SET_SECURE_CONN 0x00 disabled, 0x01 enables SC mixed, 0x02 enables SC only mode
255 #endif
256 
257  std::unique_ptr<AdapterInfo> adapterInfo(nullptr); // nullptr
258  AdapterSetting current_settings;
259  MgmtCommand req0(MgmtCommand::Opcode::READ_INFO, dev_id);
260  {
261  std::unique_ptr<MgmtEvent> res = sendWithReply(req0);
262  if( nullptr == res ) {
263  goto fail;
264  }
265  if( MgmtEvent::Opcode::CMD_COMPLETE != res->getOpcode() || res->getTotalSize() < MgmtEvtAdapterInfo::getRequiredTotalSize()) {
266  ERR_PRINT("Insufficient data for adapter info: req %d, res %s", MgmtEvtAdapterInfo::getRequiredTotalSize(), res->toString().c_str());
267  goto fail;
268  }
269  const MgmtEvtAdapterInfo * res1 = static_cast<MgmtEvtAdapterInfo*>(res.get());
270  adapterInfo = res1->toAdapterInfo();
271  if( dev_id != adapterInfo->dev_id ) {
272  ABORT("AdapterInfo dev_id=%d != dev_id=%d: %s", adapterInfo->dev_id, dev_id, adapterInfo->toString().c_str());
273  }
274  }
275  DBG_PRINT("initAdapter[%d, BTMode %s]: Start: %s", dev_id, to_string(btMode).c_str(), adapterInfo->toString().c_str());
276  current_settings = adapterInfo->getCurrentSettingMask();
277 
278  setMode(dev_id, MgmtCommand::Opcode::SET_POWERED, 0, current_settings);
279 
280  switch ( btMode ) {
281  case BTMode::DUAL:
282  setMode(dev_id, MgmtCommand::Opcode::SET_BREDR, 1, current_settings);
283  setDiscoverable(dev_id, 0, 0, current_settings);
284  setMode(dev_id, MgmtCommand::Opcode::SET_LE, 1, current_settings);
285 #if USE_LINUX_BT_SECURITY
286  setMode(dev_id, MgmtCommand::Opcode::SET_SECURE_CONN, sc_on_param, current_settings);
287  setMode(dev_id, MgmtCommand::Opcode::SET_SSP, ssp_on_param, current_settings);
288 #endif
289  break;
290  case BTMode::BREDR:
291  setMode(dev_id, MgmtCommand::Opcode::SET_BREDR, 1, current_settings);
292  setDiscoverable(dev_id, 0, 0, current_settings);
293  setMode(dev_id, MgmtCommand::Opcode::SET_LE, 0, current_settings);
294 #if USE_LINUX_BT_SECURITY
295  setMode(dev_id, MgmtCommand::Opcode::SET_SECURE_CONN, 0, current_settings);
296  setMode(dev_id, MgmtCommand::Opcode::SET_SSP, ssp_on_param, current_settings);
297 #endif
298  break;
299  case BTMode::NONE:
300  [[fallthrough]]; // map NONE -> LE
301  case BTMode::LE:
302  setMode(dev_id, MgmtCommand::Opcode::SET_BREDR, 0, current_settings);
303  setMode(dev_id, MgmtCommand::Opcode::SET_LE, 1, current_settings);
304 #if USE_LINUX_BT_SECURITY
305  setMode(dev_id, MgmtCommand::Opcode::SET_SECURE_CONN, sc_on_param, current_settings);
306  setMode(dev_id, MgmtCommand::Opcode::SET_SSP, 0, current_settings); // SSP not available in LE single mode
307 #endif
308  break;
309  }
310 
311 #if USE_LINUX_BT_SECURITY
312  setMode(dev_id, MgmtCommand::Opcode::SET_DEBUG_KEYS, debug_keys, current_settings);
313  setMode(dev_id, MgmtCommand::Opcode::SET_IO_CAPABILITY, direct_bt::number(BTManager::defaultIOCapability), current_settings);
314  setMode(dev_id, MgmtCommand::Opcode::SET_BONDABLE, 1, current_settings); // required for pairing
315 #else
316  setMode(dev_id, MgmtCommand::Opcode::SET_SECURE_CONN, 0, current_settings);
317  setMode(dev_id, MgmtCommand::Opcode::SET_SSP, 0, current_settings);
318  setMode(dev_id, MgmtCommand::Opcode::SET_DEBUG_KEYS, 0, current_settings);
319  setMode(dev_id, MgmtCommand::Opcode::SET_BONDABLE, 0, current_settings);
320 #endif
321 
322  setMode(dev_id, MgmtCommand::Opcode::SET_CONNECTABLE, 0, current_settings);
323  setMode(dev_id, MgmtCommand::Opcode::SET_FAST_CONNECTABLE, 0, current_settings);
324 
325  removeDeviceFromWhitelist(dev_id, BDAddressAndType::ANY_BREDR_DEVICE); // flush whitelist!
326 
327  setMode(dev_id, MgmtCommand::Opcode::SET_POWERED, 1, current_settings);
328 
329  /**
330  * Update AdapterSettings post settings
331  */
332  if( AdapterSetting::NONE != current_settings ) {
333  adapterInfo->setCurrentSettingMask(current_settings);
334  } else {
335  adapterInfo = nullptr; // flush
336  std::unique_ptr<MgmtEvent> res = sendWithReply(req0);
337  if( nullptr == res ) {
338  goto fail;
339  }
340  if( MgmtEvent::Opcode::CMD_COMPLETE != res->getOpcode() || res->getTotalSize() < MgmtEvtAdapterInfo::getRequiredTotalSize()) {
341  ERR_PRINT("Insufficient data for adapter info: req %d, res %s", MgmtEvtAdapterInfo::getRequiredTotalSize(), res->toString().c_str());
342  goto fail;
343  }
344  const MgmtEvtAdapterInfo * res1 = static_cast<MgmtEvtAdapterInfo*>(res.get());
345  adapterInfo = res1->toAdapterInfo();
346  if( dev_id != adapterInfo->dev_id ) {
347  ABORT("AdapterInfo dev_id=%d != dev_id=%d: %s", adapterInfo->dev_id, dev_id, adapterInfo->toString().c_str());
348  }
349  }
350  DBG_PRINT("initAdapter[%d, BTMode %s]: End: %s", dev_id, to_string(btMode).c_str(), adapterInfo->toString().c_str());
351 
352 fail:
353  return adapterInfo;
354 }
355 
356 void BTManager::shutdownAdapter(BTAdapter& adapter) noexcept {
357  DBG_PRINT("DBTManager::shutdownAdapter: %s", adapter.toString().c_str());
358  const uint16_t dev_id = adapter.dev_id;
359  adapter.close(); // also issues removeMgmtEventCallback(dev_id);
360 
361  AdapterSetting current_settings;
362  setMode(dev_id, MgmtCommand::Opcode::SET_POWERED, 0, current_settings);
363 
364  setMode(dev_id, MgmtCommand::Opcode::SET_BONDABLE, 0, current_settings);
365  setMode(dev_id, MgmtCommand::Opcode::SET_CONNECTABLE, 0, current_settings);
366  setMode(dev_id, MgmtCommand::Opcode::SET_FAST_CONNECTABLE, 0, current_settings);
367 
368  setMode(dev_id, MgmtCommand::Opcode::SET_DEBUG_KEYS, 0, current_settings);
369  setMode(dev_id, MgmtCommand::Opcode::SET_IO_CAPABILITY, direct_bt::number(SMPIOCapability::DISPLAY_ONLY), current_settings);
370  setMode(dev_id, MgmtCommand::Opcode::SET_SSP, 0, current_settings);
371  setMode(dev_id, MgmtCommand::Opcode::SET_SECURE_CONN, 0, current_settings);
372  DBG_PRINT("DBTManager::shutdownAdapter: done: %s", adapter.toString().c_str());
373 }
374 
375 BTManager::BTManager(const BTMode _defaultBTMode) noexcept
376 : env(MgmtEnv::get()),
377  defaultBTMode(BTMode::NONE != _defaultBTMode ? _defaultBTMode : env.DEFAULT_BTMODE),
378  rbuffer(ClientMaxMTU), comm(HCI_DEV_NONE, HCI_CHANNEL_CONTROL),
379  mgmtEventRing(nullptr, env.MGMT_EVT_RING_CAPACITY), mgmtReaderShallStop(false),
380  mgmtReaderThreadId(0), mgmtReaderRunning(false),
381  allowClose( comm.isOpen() )
382 {
383  WORDY_PRINT("DBTManager.ctor: BTMode %s, pid %d", to_string(defaultBTMode).c_str(), BTManager::pidSelf);
384  if( !allowClose ) {
385  ERR_PRINT("DBTManager::open: Could not open mgmt control channel");
386  return;
387  }
388 
389  {
390  struct sigaction sa_setup;
391  bzero(&sa_setup, sizeof(sa_setup));
392  sa_setup.sa_sigaction = mgmthandler_sigaction;
393  sigemptyset(&(sa_setup.sa_mask));
394  sa_setup.sa_flags = SA_SIGINFO;
395  if( 0 != sigaction( SIGALRM, &sa_setup, NULL ) ) {
396  ERR_PRINT("DBTManager::ctor: Setting sighandler");
397  }
398  }
399  {
400  std::unique_lock<std::mutex> lock(mtx_mgmtReaderLifecycle); // RAII-style acquire and relinquish via destructor
401 
402  std::thread mgmtReaderThread(&BTManager::mgmtReaderThreadImpl, this); // @suppress("Invalid arguments")
403  mgmtReaderThreadId = mgmtReaderThread.native_handle();
404  // Avoid 'terminate called without an active exception'
405  // as hciReaderThreadImpl may end due to I/O errors.
406  mgmtReaderThread.detach();
407 
408  while( false == mgmtReaderRunning ) {
409  cv_mgmtReaderInit.wait(lock);
410  }
411  }
412 
413  PERF_TS_T0();
414 
415  // Mandatory
416  {
417  MgmtCommand req0(MgmtCommand::Opcode::READ_VERSION, MgmtConstU16::MGMT_INDEX_NONE);
418  std::unique_ptr<MgmtEvent> res = sendWithReply(req0);
419  if( nullptr == res ) {
420  goto fail;
421  }
422  if( MgmtEvent::Opcode::CMD_COMPLETE != res->getOpcode() || res->getDataSize() < 3) {
423  ERR_PRINT("Wrong version response: %s", res->toString().c_str());
424  goto fail;
425  }
426  const uint8_t *data = res->getData();
427  const uint8_t version = data[0];
428  const uint16_t revision = jau::get_uint16(data, 1, true /* littleEndian */);
429  WORDY_PRINT("Bluetooth version %d.%d", version, revision);
430  if( version < 1 ) {
431  ERR_PRINT("Bluetooth version >= 1.0 required");
432  goto fail;
433  }
434  }
435  // Optional
436  {
437  MgmtCommand req0(MgmtCommand::Opcode::READ_COMMANDS, MgmtConstU16::MGMT_INDEX_NONE);
438  std::unique_ptr<MgmtEvent> res = sendWithReply(req0);
439  if( nullptr == res ) {
440  goto next1;
441  }
442  if( MgmtEvent::Opcode::CMD_COMPLETE == res->getOpcode() && res->getDataSize() >= 4) {
443  const uint8_t *data = res->getData();
444  const uint16_t num_commands = jau::get_uint16(data, 0, true /* littleEndian */);
445  const uint16_t num_events = jau::get_uint16(data, 2, true /* littleEndian */);
446  WORDY_PRINT("Bluetooth %d commands, %d events", num_commands, num_events);
447 #ifdef VERBOSE_ON
448  const int expDataSize = 4 + num_commands * 2 + num_events * 2;
449  if( res->getDataSize() >= expDataSize ) {
450  for(int i=0; i< num_commands; i++) {
451  const MgmtCommand::Opcode op = static_cast<MgmtCommand::Opcode>( get_uint16(data, 4+i*2, true /* littleEndian */) );
452  DBG_PRINT("kernel op %d: %s", i, toString(op).c_str());
453  }
454  }
455 #endif
456  }
457  }
458 
459 next1:
460  // Mandatory
461  {
462  MgmtCommand req0(MgmtCommand::Opcode::READ_INDEX_LIST, MgmtConstU16::MGMT_INDEX_NONE);
463  std::unique_ptr<MgmtEvent> res = sendWithReply(req0);
464  if( nullptr == res ) {
465  goto fail;
466  }
467  if( MgmtEvent::Opcode::CMD_COMPLETE != res->getOpcode() || res->getDataSize() < 2) {
468  ERR_PRINT("Insufficient data for adapter index: res %s", res->toString().c_str());
469  goto fail;
470  }
471  const uint8_t *data = res->getData();
472  const uint16_t num_adapter = jau::get_uint16(data, 0, true /* littleEndian */);
473  WORDY_PRINT("Bluetooth %d adapter", num_adapter);
474 
475  const jau::nsize_t expDataSize = 2 + num_adapter * 2;
476  if( res->getDataSize() < expDataSize ) {
477  ERR_PRINT("Insufficient data for %d adapter indices: res %s", num_adapter, res->toString().c_str());
478  goto fail;
479  }
480  for(int i=0; i < num_adapter; i++) {
481  const uint16_t dev_id = jau::get_uint16(data, 2+i*2, true /* littleEndian */);
482  std::unique_ptr<AdapterInfo> adapterInfo = initAdapter(dev_id, defaultBTMode);
483  if( nullptr != adapterInfo ) {
484  std::shared_ptr<BTAdapter> adapter = BTAdapter::make_shared(*this, *adapterInfo);
485  adapters.push_back( adapter );
486  adapterIOCapability.push_back(BTManager::defaultIOCapability);
487  DBG_PRINT("DBTManager::adapters %d/%d: dev_id %d: %s", i, num_adapter, dev_id, adapter->toString().c_str());
488  } else {
489  DBG_PRINT("DBTManager::adapters %d/%d: dev_id %d: FAILED", i, num_adapter, dev_id);
490  }
491  }
492  }
493 
494  addMgmtEventCallback(-1, MgmtEvent::Opcode::NEW_SETTINGS, jau::bindMemberFunc(this, &BTManager::mgmtEvNewSettingsCB));
495 
496  if( jau::environment::get().debug ) {
497  addMgmtEventCallback(-1, MgmtEvent::Opcode::CONTROLLER_ERROR, jau::bindMemberFunc(this, &BTManager::mgmtEventAnyCB));
498  addMgmtEventCallback(-1, MgmtEvent::Opcode::CLASS_OF_DEV_CHANGED, jau::bindMemberFunc(this, &BTManager::mgmtEventAnyCB));
499  addMgmtEventCallback(-1, MgmtEvent::Opcode::NEW_LINK_KEY, jau::bindMemberFunc(this, &BTManager::mgmtEventAnyCB));
500  addMgmtEventCallback(-1, MgmtEvent::Opcode::NEW_LONG_TERM_KEY, jau::bindMemberFunc(this, &BTManager::mgmtEventAnyCB));
501  addMgmtEventCallback(-1, MgmtEvent::Opcode::DEVICE_CONNECTED, jau::bindMemberFunc(this, &BTManager::mgmtEventAnyCB));
502  addMgmtEventCallback(-1, MgmtEvent::Opcode::DEVICE_DISCONNECTED, jau::bindMemberFunc(this, &BTManager::mgmtEventAnyCB));
503  addMgmtEventCallback(-1, MgmtEvent::Opcode::CONNECT_FAILED, jau::bindMemberFunc(this, &BTManager::mgmtEventAnyCB));
504  addMgmtEventCallback(-1, MgmtEvent::Opcode::PIN_CODE_REQUEST, jau::bindMemberFunc(this, &BTManager::mgmtEventAnyCB));
505  addMgmtEventCallback(-1, MgmtEvent::Opcode::USER_CONFIRM_REQUEST, jau::bindMemberFunc(this, &BTManager::mgmtEventAnyCB));
506  addMgmtEventCallback(-1, MgmtEvent::Opcode::USER_PASSKEY_REQUEST, jau::bindMemberFunc(this, &BTManager::mgmtEventAnyCB));
507  addMgmtEventCallback(-1, MgmtEvent::Opcode::AUTH_FAILED, jau::bindMemberFunc(this, &BTManager::mgmtEventAnyCB));
508  addMgmtEventCallback(-1, MgmtEvent::Opcode::DEVICE_FOUND, jau::bindMemberFunc(this, &BTManager::mgmtEventAnyCB));
509  addMgmtEventCallback(-1, MgmtEvent::Opcode::DISCOVERING, jau::bindMemberFunc(this, &BTManager::mgmtEventAnyCB));
510  addMgmtEventCallback(-1, MgmtEvent::Opcode::DEVICE_BLOCKED, jau::bindMemberFunc(this, &BTManager::mgmtEventAnyCB));
511  addMgmtEventCallback(-1, MgmtEvent::Opcode::DEVICE_UNBLOCKED, jau::bindMemberFunc(this, &BTManager::mgmtEventAnyCB));
512  addMgmtEventCallback(-1, MgmtEvent::Opcode::DEVICE_UNPAIRED, jau::bindMemberFunc(this, &BTManager::mgmtEventAnyCB));
513  addMgmtEventCallback(-1, MgmtEvent::Opcode::PASSKEY_NOTIFY, jau::bindMemberFunc(this, &BTManager::mgmtEventAnyCB));
514  addMgmtEventCallback(-1, MgmtEvent::Opcode::NEW_IRK, jau::bindMemberFunc(this, &BTManager::mgmtEventAnyCB));
515  addMgmtEventCallback(-1, MgmtEvent::Opcode::NEW_CSRK, jau::bindMemberFunc(this, &BTManager::mgmtEventAnyCB));
516  addMgmtEventCallback(-1, MgmtEvent::Opcode::DEVICE_WHITELIST_ADDED, jau::bindMemberFunc(this, &BTManager::mgmtEventAnyCB));
517  addMgmtEventCallback(-1, MgmtEvent::Opcode::DEVICE_WHITELIST_REMOVED, jau::bindMemberFunc(this, &BTManager::mgmtEventAnyCB));
518  addMgmtEventCallback(-1, MgmtEvent::Opcode::NEW_CONN_PARAM, jau::bindMemberFunc(this, &BTManager::mgmtEventAnyCB));
519 
520  addMgmtEventCallback(-1, MgmtEvent::Opcode::LOCAL_OOB_DATA_UPDATED, jau::bindMemberFunc(this, &BTManager::mgmtEventAnyCB));
521 
522  addMgmtEventCallback(-1, MgmtEvent::Opcode::PAIR_DEVICE_COMPLETE, jau::bindMemberFunc(this, &BTManager::mgmtEventAnyCB));
523  addMgmtEventCallback(-1, MgmtEvent::Opcode::HCI_ENC_CHANGED, jau::bindMemberFunc(this, &BTManager::mgmtEventAnyCB));
524  addMgmtEventCallback(-1, MgmtEvent::Opcode::HCI_ENC_KEY_REFRESH_COMPLETE, jau::bindMemberFunc(this, &BTManager::mgmtEventAnyCB));
525  addMgmtEventCallback(-1, MgmtEvent::Opcode::HCI_LE_REMOTE_USR_FEATURES, jau::bindMemberFunc(this, &BTManager::mgmtEventAnyCB));
526  }
527  PERF_TS_TD("DBTManager::ctor.ok");
528  DBG_PRINT("DBTManager::ctor: OK");
529  return;
530 
531 fail:
532  close();
533  PERF_TS_TD("DBTManager::ctor.fail");
534  DBG_PRINT("DBTManager::ctor: FAIL");
535  return;
536 }
537 
538 void BTManager::close() noexcept {
539  // Avoid disconnect re-entry -> potential deadlock
540  bool expConn = true; // C++11, exp as value since C++20
541  if( !allowClose.compare_exchange_strong(expConn, false) ) {
542  // not open
543  DBG_PRINT("DBTManager::close: Not open");
544  whitelist.clear();
546  adapters.clear();
547  adapterIOCapability.clear();
548  comm.close();
549  return;
550  }
551  PERF3_TS_T0();
552 
553  const std::lock_guard<std::recursive_mutex> lock(mtx_sendReply); // RAII-style acquire and relinquish via destructor
554  DBG_PRINT("DBTManager::close: Start");
557 
558  {
559  int i=0;
560  jau::for_each_fidelity(adapters, [&](std::shared_ptr<BTAdapter> & a) {
561  DBG_PRINT("DBTManager::close::shutdownAdapter: %d/%d processing: %s", i, adapters.size(), a->toString().c_str());
562  shutdownAdapter(*a);
563  ++i;
564  });
565  }
566 
567  adapters.clear();
568  adapterIOCapability.clear();
569 
570  // Interrupt DBTManager's HCIComm::read(..), avoiding prolonged hang
571  // and pull all underlying hci read operations!
572  comm.close();
573 
574  PERF3_TS_TD("DBTManager::close.1");
575  {
576  std::unique_lock<std::mutex> lockReader(mtx_mgmtReaderLifecycle); // RAII-style acquire and relinquish via destructor
577  const pthread_t tid_self = pthread_self();
578  const pthread_t tid_reader = mgmtReaderThreadId;
579  mgmtReaderThreadId = 0;
580  const bool is_reader = tid_reader == tid_self;
581  DBG_PRINT("DBTManager::close: mgmtReader[running %d, shallStop %d, isReader %d, tid %p)",
582  mgmtReaderRunning.load(), mgmtReaderShallStop.load(), is_reader, (void*)tid_reader);
583  if( mgmtReaderRunning ) {
584  mgmtReaderShallStop = true;
585  if( !is_reader && 0 != tid_reader ) {
586  int kerr;
587  if( 0 != ( kerr = pthread_kill(tid_reader, SIGALRM) ) ) {
588  ERR_PRINT("DBTManager::close: pthread_kill %p FAILED: %d", (void*)tid_reader, kerr);
589  }
590  }
591  // Ensure the reader thread has ended, no runaway-thread using *this instance after destruction
592  while( true == mgmtReaderRunning ) {
593  cv_mgmtReaderInit.wait(lockReader);
594  }
595  }
596  }
597  PERF3_TS_TD("DBTManager::close.2");
598 
599  {
600  struct sigaction sa_setup;
601  bzero(&sa_setup, sizeof(sa_setup));
602  sa_setup.sa_handler = SIG_DFL;
603  sigemptyset(&(sa_setup.sa_mask));
604  sa_setup.sa_flags = 0;
605  if( 0 != sigaction( SIGALRM, &sa_setup, NULL ) ) {
606  ERR_PRINT("DBTManager.sigaction: Resetting sighandler");
607  }
608  }
609 
610  PERF3_TS_TD("DBTManager::close.X");
611  DBG_PRINT("DBTManager::close: End");
612 }
613 
614 std::shared_ptr<BTAdapter> BTManager::getDefaultAdapter() const noexcept {
615  typename adapters_t::const_iterator it = adapters.cbegin();
616  for (; !it.is_end(); ++it) {
617  if( (*it)->isPowered() ) {
618  return *it;
619  }
620  }
621  return nullptr;
622 }
623 
624 std::shared_ptr<BTAdapter> BTManager::getAdapter(const uint16_t dev_id) const noexcept {
625  typename adapters_t::const_iterator it = adapters.cbegin();
626  for (; !it.is_end(); ++it) {
627  if ( (*it)->dev_id == dev_id ) {
628  return *it;
629  }
630  }
631  return nullptr;
632 }
633 
634 std::shared_ptr<BTAdapter> BTManager::addAdapter(const AdapterInfo& ai ) noexcept {
635  typename adapters_t::iterator it = adapters.begin(); // lock mutex and copy_store
636  for (; !it.is_end(); ++it) {
637  if ( (*it)->dev_id == ai.dev_id ) {
638  break;
639  }
640  }
641  if( it.is_end() ) {
642  // new entry
643  std::shared_ptr<BTAdapter> adapter = BTAdapter::make_shared(*this, ai);
644  it.push_back( adapter );
645  adapterIOCapability.push_back(BTManager::defaultIOCapability);
646  DBG_PRINT("DBTManager::addAdapter: Adding new: %s", adapter->toString().c_str())
647  it.write_back();
648  return adapter;
649  } else {
650  // already existing
651  std::shared_ptr<BTAdapter> adapter = *it;
652  WARN_PRINT("DBTManager::addAdapter: Already existing %s, overwriting %s", ai.toString().c_str(), adapter->toString().c_str())
653  adapter->adapterInfo = ai;
654  return adapter;
655  }
656 }
657 
658 std::shared_ptr<BTAdapter> BTManager::removeAdapter(const uint16_t dev_id) noexcept {
659  typename adapters_t::iterator it = adapters.begin(); // lock mutex and copy_store
660  for(; !it.is_end(); ++it ) {
661  std::shared_ptr<BTAdapter> & ai = *it;
662  if( ai->dev_id == dev_id ) {
663  adapterIOCapability.erase( adapterIOCapability.cbegin() + it.dist_begin() );
664  std::shared_ptr<BTAdapter> res = ai; // copy
665  DBG_PRINT("DBTManager::removeAdapter: Remove: %s", res->toString().c_str())
666  it.erase();
667  it.write_back();
668  return res;
669  }
670  }
671  DBG_PRINT("DBTManager::removeAdapter: Not found: dev_id %d", dev_id)
672  return nullptr;
673 }
674 
675 bool BTManager::removeAdapter(BTAdapter* adapter) noexcept {
676  typename adapters_t::iterator it = adapters.begin(); // lock mutex and copy_store
677  for(; !it.is_end(); ++it ) {
678  std::shared_ptr<BTAdapter> & ai = *it;
679  if( ai.get() == adapter ) {
680  adapterIOCapability.erase( adapterIOCapability.cbegin() + it.dist_begin() );
681  DBG_PRINT("DBTManager::removeAdapter: Remove: %p -> %s", adapter, ai->toString().c_str())
682  it.erase();
683  it.write_back();
684  return true;
685  }
686  }
687  DBG_PRINT("DBTManager::removeAdapter: Not found: %p", adapter)
688  return false;
689 }
690 
691 bool BTManager::setIOCapability(const uint16_t dev_id, const SMPIOCapability io_cap, SMPIOCapability& pre_io_cap) noexcept {
692  if( SMPIOCapability::UNSET != io_cap ) {
693 #if USE_LINUX_BT_SECURITY
694  typename adapters_t::const_iterator it = adapters.cbegin();
695  for (; !it.is_end(); ++it) {
696  if( (*it)->dev_id == dev_id ) {
697  const typename adapters_t::difference_type index = it.dist_begin();
698  const SMPIOCapability o = adapterIOCapability.at(index);
699  AdapterSetting current_settings { AdapterSetting::NONE }; // throw away return value, unchanged on SET_IO_CAPABILITY
700  if( setMode(dev_id, MgmtCommand::Opcode::SET_IO_CAPABILITY, direct_bt::number(io_cap), current_settings) ) {
701  adapterIOCapability.at(index) = io_cap;
702  pre_io_cap = o;
703  return true;
704  } else {
705  return false;
706  }
707  }
708  }
709 #endif
710  }
711  return false;
712 }
713 
714 SMPIOCapability BTManager::getIOCapability(const uint16_t dev_id) const noexcept {
715  typename adapters_t::const_iterator it = adapters.cbegin();
716  for (; !it.is_end(); ++it) {
717  if( (*it)->dev_id == dev_id ) {
718  return adapterIOCapability.at( it.dist_begin() );
719  }
720  }
721  return SMPIOCapability::UNSET;
722 }
723 
724 bool BTManager::setMode(const uint16_t dev_id, const MgmtCommand::Opcode opc, const uint8_t mode, AdapterSetting& current_settings) noexcept {
725  MgmtUint8Cmd req(opc, dev_id, mode);
726  std::unique_ptr<MgmtEvent> reply = sendWithReply(req);
727  MgmtStatus res;
728  if( nullptr != reply ) {
729  if( reply->getOpcode() == MgmtEvent::Opcode::CMD_COMPLETE ) {
730  const MgmtEvtCmdComplete &reply1 = *static_cast<const MgmtEvtCmdComplete *>(reply.get());
731  res = reply1.getStatus();
732  if( MgmtStatus::SUCCESS == res ) {
733  reply1.getCurrentSettings(current_settings);
734  }
735  } else if( reply->getOpcode() == MgmtEvent::Opcode::CMD_STATUS ) {
736  const MgmtEvtCmdStatus &reply1 = *static_cast<const MgmtEvtCmdStatus *>(reply.get());
737  res = reply1.getStatus();
738  } else {
740  }
741  } else {
742  res = MgmtStatus::TIMEOUT;
743  }
744  DBG_PRINT("DBTManager::setMode[%d, %s]: %s, result %s %s", dev_id,
745  MgmtCommand::getOpcodeString(opc).c_str(), jau::to_hexstring(mode).c_str(),
746  to_string(res).c_str(), to_string(current_settings).c_str());
747  return MgmtStatus::SUCCESS == res;
748 }
749 
750 MgmtStatus BTManager::setDiscoverable(const uint16_t dev_id, const uint8_t state, const uint16_t timeout_sec, AdapterSetting& current_settings) noexcept {
751  MgmtSetDiscoverableCmd req(dev_id, state, timeout_sec);
752  std::unique_ptr<MgmtEvent> reply = sendWithReply(req);
753  MgmtStatus res;
754  if( nullptr != reply ) {
755  if( reply->getOpcode() == MgmtEvent::Opcode::CMD_COMPLETE ) {
756  const MgmtEvtCmdComplete &reply1 = *static_cast<const MgmtEvtCmdComplete *>(reply.get());
757  res = reply1.getStatus();
758  if( MgmtStatus::SUCCESS == res ) {
759  reply1.getCurrentSettings(current_settings);
760  }
761  } else if( reply->getOpcode() == MgmtEvent::Opcode::CMD_STATUS ) {
762  const MgmtEvtCmdStatus &reply1 = *static_cast<const MgmtEvtCmdStatus *>(reply.get());
763  res = reply1.getStatus();
764  } else {
766  }
767  } else {
768  res = MgmtStatus::TIMEOUT;
769  }
770  DBG_PRINT("DBTManager::setDiscoverable[%d]: %s, result %s %s", dev_id,
771  req.toString().c_str(), to_string(res).c_str(), to_string(current_settings).c_str());
772  return res;
773 }
774 
775 ScanType BTManager::startDiscovery(const uint16_t dev_id, const BTMode btMode) noexcept {
776  return startDiscovery(dev_id, to_ScanType(btMode));
777 }
778 
779 ScanType BTManager::startDiscovery(const uint16_t dev_id, const ScanType scanType) noexcept {
781  std::unique_ptr<MgmtEvent> res = sendWithReply(req);
782  ScanType type = ScanType::NONE;
783  if( nullptr != res && res->getOpcode() == MgmtEvent::Opcode::CMD_COMPLETE ) {
784  const MgmtEvtCmdComplete &res1 = *static_cast<const MgmtEvtCmdComplete *>(res.get());
785  if( MgmtStatus::SUCCESS == res1.getStatus() && 1 <= res1.getDataSize() ) {
786  const uint8_t *p = res1.getData();
787  if( nullptr == p ) { // G++ 10: -Werror=null-dereference
788  ERR_PRINT("DBTManager::startDiscovery: Impossible MgmtEvtCmdComplete data nullptr: %s - %s", res1.toString().c_str(), req.toString().c_str());
789  return type;
790  }
791  type = static_cast<ScanType>( p[0] );
792  }
793  }
794  return type;
795 }
796 bool BTManager::stopDiscovery(const uint16_t dev_id, const ScanType type) noexcept {
798  std::unique_ptr<MgmtEvent> res = sendWithReply(req);
799  if( nullptr != res && res->getOpcode() == MgmtEvent::Opcode::CMD_COMPLETE ) {
800  const MgmtEvtCmdComplete &res1 = *static_cast<const MgmtEvtCmdComplete *>(res.get());
801  return MgmtStatus::SUCCESS == res1.getStatus();
802  }
803  return false;
804 }
805 
806 bool BTManager::uploadConnParam(const uint16_t dev_id, const BDAddressAndType & addressAndType,
807  const uint16_t conn_min_interval, const uint16_t conn_max_interval,
808  const uint16_t conn_latency, const uint16_t supervision_timeout) noexcept {
809  MgmtConnParam connParam{ addressAndType.address, addressAndType.type, conn_min_interval, conn_max_interval, conn_latency, supervision_timeout };
810  MgmtLoadConnParamCmd req(dev_id, connParam);
811  std::unique_ptr<MgmtEvent> res = sendWithReply(req);
812  if( nullptr != res && res->getOpcode() == MgmtEvent::Opcode::CMD_COMPLETE ) {
813  const MgmtEvtCmdComplete &res1 = *static_cast<const MgmtEvtCmdComplete *>(res.get());
814  return MgmtStatus::SUCCESS == res1.getStatus();
815  }
816  return false;
817 }
818 
819 MgmtStatus BTManager::uploadLinkKey(const uint16_t dev_id, const bool debug_keys, const MgmtLinkKeyInfo &key) noexcept {
820 #if USE_LINUX_BT_SECURITY
821  MgmtLoadLinkKeyCmd req(dev_id, debug_keys, key);
822  std::unique_ptr<MgmtEvent> res = sendWithReply(req);
823  if( nullptr != res && res->getOpcode() == MgmtEvent::Opcode::CMD_COMPLETE ) {
824  const MgmtEvtCmdComplete &res1 = *static_cast<const MgmtEvtCmdComplete *>(res.get());
825  return res1.getStatus();
826  }
827  return MgmtStatus::TIMEOUT;
828 #else
830 #endif
831 
832 }
833 
834 HCIStatusCode BTManager::uploadLongTermKey(const uint16_t dev_id, const MgmtLongTermKeyInfo &key) noexcept {
835 #if USE_LINUX_BT_SECURITY
836  MgmtLoadLongTermKeyCmd req(dev_id, key);
837  HCIStatusCode res;
838  std::unique_ptr<MgmtEvent> reply = sendWithReply(req);
839  if( nullptr != reply ) {
840  if( reply->getOpcode() == MgmtEvent::Opcode::CMD_COMPLETE ) {
841  res = to_HCIStatusCode( static_cast<const MgmtEvtCmdComplete *>(reply.get())->getStatus() );
842  } else if( reply->getOpcode() == MgmtEvent::Opcode::CMD_STATUS ) {
843  res = to_HCIStatusCode( static_cast<const MgmtEvtCmdStatus *>(reply.get())->getStatus() );
844  } else {
846  }
847  } else {
849  }
850  DBG_PRINT("DBTManager::uploadLongTermKeyInfo[%d]: %s, result %s", dev_id,
851  req.toString().c_str(), to_string(res).c_str());
852  return res;
853 #else
855 #endif
856 }
857 
858 HCIStatusCode BTManager::uploadLongTermKeyInfo(const uint16_t dev_id, const BDAddressAndType & addressAndType,
859  const SMPLongTermKeyInfo& ltk) noexcept {
860 #if USE_LINUX_BT_SECURITY
861  const MgmtLTKType key_type = to_MgmtLTKType(ltk.properties);
862  const MgmtLongTermKeyInfo mgmt_ltk_info { addressAndType.address, addressAndType.type, key_type,
863  ltk.isResponder(), ltk.enc_size, ltk.ediv, ltk.rand, ltk.ltk };
864  MgmtLoadLongTermKeyCmd req(dev_id, mgmt_ltk_info);
865  HCIStatusCode res;
866  std::unique_ptr<MgmtEvent> reply = sendWithReply(req);
867  if( nullptr != reply ) {
868  if( reply->getOpcode() == MgmtEvent::Opcode::CMD_COMPLETE ) {
869  res = to_HCIStatusCode( static_cast<const MgmtEvtCmdComplete *>(reply.get())->getStatus() );
870  } else if( reply->getOpcode() == MgmtEvent::Opcode::CMD_STATUS ) {
871  res = to_HCIStatusCode( static_cast<const MgmtEvtCmdStatus *>(reply.get())->getStatus() );
872  } else {
874  }
875  } else {
877  }
878  DBG_PRINT("DBTManager::uploadLongTermKeyInfo[%d]: %s -> %s, result %s", dev_id,
879  ltk.toString().c_str(), req.toString().c_str(), to_string(res).c_str());
880  return res;
881 #else
883 #endif
884 }
885 
886 MgmtStatus BTManager::userPasskeyReply(const uint16_t dev_id, const BDAddressAndType & addressAndType, const uint32_t passkey) noexcept {
887 #if USE_LINUX_BT_SECURITY
888  MgmtUserPasskeyReplyCmd cmd(dev_id, addressAndType, passkey);
889  std::unique_ptr<MgmtEvent> res = sendWithReply(cmd);
890  if( nullptr != res && res->getOpcode() == MgmtEvent::Opcode::CMD_COMPLETE ) {
891  const MgmtEvtCmdComplete &res1 = *static_cast<const MgmtEvtCmdComplete *>(res.get());
892  // FIXME: Analyze address + addressType result?
893  return res1.getStatus();
894  }
895  return MgmtStatus::TIMEOUT;
896 #else
898 #endif
899 }
900 
901 MgmtStatus BTManager::userPasskeyNegativeReply(const uint16_t dev_id, const BDAddressAndType & addressAndType) noexcept {
902 #if USE_LINUX_BT_SECURITY
903  MgmtUserPasskeyNegativeReplyCmd cmd(dev_id, addressAndType);
904  std::unique_ptr<MgmtEvent> res = sendWithReply(cmd);
905  if( nullptr != res && res->getOpcode() == MgmtEvent::Opcode::CMD_COMPLETE ) {
906  const MgmtEvtCmdComplete &res1 = *static_cast<const MgmtEvtCmdComplete *>(res.get());
907  // FIXME: Analyze address + addressType result?
908  return res1.getStatus();
909  }
910  return MgmtStatus::TIMEOUT;
911 #else
913 #endif
914 }
915 
916 MgmtStatus BTManager::userConfirmReply(const uint16_t dev_id, const BDAddressAndType & addressAndType, const bool positive) noexcept {
917 #if USE_LINUX_BT_SECURITY
918  std::unique_ptr<MgmtEvent> res;
919  if( positive ) {
920  MgmtUserConfirmReplyCmd cmd(dev_id, addressAndType);
921  res = sendWithReply(cmd);
922  } else {
923  MgmtUserConfirmNegativeReplyCmd cmd(dev_id, addressAndType);
924  res = sendWithReply(cmd);
925  }
926  if( nullptr != res && res->getOpcode() == MgmtEvent::Opcode::CMD_COMPLETE ) {
927  const MgmtEvtCmdComplete &res1 = *static_cast<const MgmtEvtCmdComplete *>(res.get());
928  // FIXME: Analyze address + addressType result?
929  return res1.getStatus();
930  }
931  return MgmtStatus::TIMEOUT;
932 #else
934 #endif
935 }
936 
937 bool BTManager::pairDevice(const uint16_t dev_id, const BDAddressAndType & addressAndType, const SMPIOCapability iocap) noexcept {
938 #if USE_LINUX_BT_SECURITY
939  MgmtPairDeviceCmd cmd(dev_id, addressAndType, iocap);
940  return send(cmd);
941 #else
942  return false;
943 #endif
944 }
945 
946 MgmtStatus BTManager::unpairDevice(const uint16_t dev_id, const BDAddressAndType & addressAndType, const bool disconnect) noexcept {
947 #if USE_LINUX_BT_SECURITY
948  MgmtUnpairDeviceCmd cmd(dev_id, addressAndType, disconnect);
949  std::unique_ptr<MgmtEvent> res = sendWithReply(cmd);
950 
951  if( nullptr != res && res->getOpcode() == MgmtEvent::Opcode::CMD_COMPLETE ) {
952  const MgmtEvtCmdComplete &res1 = *static_cast<const MgmtEvtCmdComplete *>(res.get());
953  // FIXME: Analyze address + addressType result?
954  return res1.getStatus();
955  }
956  return MgmtStatus::TIMEOUT;
957 #else
959 #endif
960 }
961 
962 bool BTManager::isDeviceWhitelisted(const uint16_t dev_id, const BDAddressAndType & addressAndType) noexcept {
963  auto it = whitelist.cbegin();
964  for( auto end = whitelist.cend(); it != end; ++it) {
965  std::shared_ptr<WhitelistElem> wle = *it;
966  if( wle->dev_id == dev_id && wle->address_and_type == addressAndType ) {
967  return true;
968  }
969  }
970  return false;
971 }
972 
973 bool BTManager::addDeviceToWhitelist(const uint16_t dev_id, const BDAddressAndType & addressAndType, const HCIWhitelistConnectType ctype) noexcept {
974  MgmtAddDeviceToWhitelistCmd req(dev_id, addressAndType, ctype);
975 
976  // Check if already exist in our local whitelist first, reject if so ..
977  if( isDeviceWhitelisted(dev_id, addressAndType) ) {
978  ERR_PRINT("DBTManager::addDeviceToWhitelist: Already in local whitelist, remove first: %s", req.toString().c_str());
979  return false;
980  }
981  std::unique_ptr<MgmtEvent> res = sendWithReply(req);
982  if( nullptr != res && res->getOpcode() == MgmtEvent::Opcode::CMD_COMPLETE ) {
983  const MgmtEvtCmdComplete &res1 = *static_cast<const MgmtEvtCmdComplete *>(res.get());
984  if( MgmtStatus::SUCCESS == res1.getStatus() ) {
985  whitelist.push_back( std::make_shared<WhitelistElem>(dev_id, addressAndType, ctype) );
986  return true;
987  }
988  }
989  return false;
990 }
991 
993 #if 0
994  jau::darray<std::shared_ptr<WhitelistElem>> whitelist_copy = whitelist;
995  int count = 0;
996  DBG_PRINT("DBTManager::removeAllDevicesFromWhitelist.A: Start %zd elements", whitelist_copy.size());
997 
998  for(auto it = whitelist_copy.cbegin(); it != whitelist_copy.cend(); ++it) {
999  std::shared_ptr<WhitelistElem> wle = *it;
1000  removeDeviceFromWhitelist(wle->dev_id, wle->address, wle->address_type);
1001  ++count;
1002  }
1003 #else
1004  int count = 0;
1005  DBG_PRINT("DBTManager::removeAllDevicesFromWhitelist.B: Start %d elements", count);
1006  whitelist.clear();
1007  jau::for_each_const(adapters, [&](const std::shared_ptr<BTAdapter> & a) {
1009  ++count;
1010  }
1011  });
1012 #endif
1013 
1014  DBG_PRINT("DBTManager::removeAllDevicesFromWhitelist: End: Removed %d elements, remaining %zd elements",
1015  count, whitelist.size());
1016  return count;
1017 }
1018 
1019 bool BTManager::removeDeviceFromWhitelist(const uint16_t dev_id, const BDAddressAndType & addressAndType) noexcept {
1020  // Remove from our local whitelist first
1021  {
1022  auto it = whitelist.cbegin();
1023  for( auto end = whitelist.cend(); it != end; ) {
1024  std::shared_ptr<WhitelistElem> wle = *it;
1025  if( wle->dev_id == dev_id && wle->address_and_type == addressAndType ) {
1026  it = whitelist.erase(it);
1027  } else {
1028  ++it;
1029  }
1030  }
1031  }
1032 
1033  // Actual removal
1034  MgmtRemoveDeviceFromWhitelistCmd req(dev_id, addressAndType);
1035  std::unique_ptr<MgmtEvent> res = sendWithReply(req);
1036  if( nullptr != res && res->getOpcode() == MgmtEvent::Opcode::CMD_COMPLETE ) {
1037  const MgmtEvtCmdComplete &res1 = *static_cast<const MgmtEvtCmdComplete *>(res.get());
1038  if( MgmtStatus::SUCCESS == res1.getStatus() ) {
1039  return true;
1040  }
1041  }
1042  return false;
1043 }
1044 
1045 bool BTManager::disconnect(const bool ioErrorCause,
1046  const uint16_t dev_id, const BDAddressAndType & addressAndType,
1047  const HCIStatusCode reason) noexcept {
1048  bool bres = false;
1049 
1050  // Always issue DISCONNECT command, even in case of an ioError (lost-connection),
1051  // see Issue #124 fast re-connect on CSR adapter.
1052  // This will always notify the adapter of a disconnected device.
1053  {
1054  MgmtDisconnectCmd req(dev_id, addressAndType);
1055  std::unique_ptr<MgmtEvent> res = sendWithReply(req);
1056  if( nullptr != res && res->getOpcode() == MgmtEvent::Opcode::CMD_COMPLETE ) {
1057  const MgmtEvtCmdComplete &res1 = *static_cast<const MgmtEvtCmdComplete *>(res.get());
1058  if( MgmtStatus::SUCCESS == res1.getStatus() ) {
1059  bres = true;
1060  }
1061  }
1062  }
1063  if( !ioErrorCause ) {
1064  // In case of an ioError (lost-connection), don't wait for the lagging
1065  // DISCONN_COMPLETE event but send it directly.
1066  const MgmtEvtDeviceDisconnected e(dev_id, addressAndType, reason, 0xffff);
1067  sendMgmtEvent(e);
1068  }
1069  return bres;
1070 }
1071 
1072 std::shared_ptr<ConnectionInfo> BTManager::getConnectionInfo(const uint16_t dev_id, const BDAddressAndType& addressAndType) noexcept {
1073  MgmtGetConnectionInfoCmd req(dev_id, addressAndType);
1074  std::unique_ptr<MgmtEvent> res = sendWithReply(req);
1075  if( nullptr != res && res->getOpcode() == MgmtEvent::Opcode::CMD_COMPLETE ) {
1076  const MgmtEvtCmdComplete &res1 = *static_cast<const MgmtEvtCmdComplete *>(res.get());
1077  if( MgmtStatus::SUCCESS == res1.getStatus() ) {
1078  std::shared_ptr<ConnectionInfo> result = res1.toConnectionInfo();
1079  return result;
1080  }
1081  }
1082  return nullptr;
1083 }
1084 
1085 std::shared_ptr<NameAndShortName> BTManager::setLocalName(const uint16_t dev_id, const std::string & name, const std::string & short_name) noexcept {
1086  MgmtSetLocalNameCmd req (static_cast<uint16_t>(dev_id), name, short_name);
1087  std::unique_ptr<MgmtEvent> res = sendWithReply(req);
1088  if( nullptr != res && res->getOpcode() == MgmtEvent::Opcode::CMD_COMPLETE ) {
1089  const MgmtEvtCmdComplete &res1 = *static_cast<const MgmtEvtCmdComplete *>(res.get());
1090  if( MgmtStatus::SUCCESS == res1.getStatus() ) {
1091  std::shared_ptr<NameAndShortName> result = res1.toNameAndShortName();
1092 
1093  // explicit LocalNameChanged event
1094  MgmtEvtLocalNameChanged e(static_cast<uint16_t>(dev_id), result->getName(), result->getShortName());
1095  sendMgmtEvent(e);
1096  return result;
1097  }
1098  }
1099  return nullptr;
1100 }
1101 
1102 /***
1103  *
1104  * MgmtEventCallback section
1105  *
1106  */
1107 
1109  [](const MgmtAdapterEventCallback &a, const MgmtAdapterEventCallback &b) -> bool { return a == b; };
1110 
1112  [](const MgmtAdapterEventCallback &a, const MgmtAdapterEventCallback &b) -> bool { return a.getCallback() == b.getCallback(); };
1113 
1115  [](const MgmtAdapterEventCallback &a, const MgmtAdapterEventCallback &b) -> bool { return a.getDevID() == b.getDevID(); };
1116 
1117 bool BTManager::addMgmtEventCallback(const int dev_id, const MgmtEvent::Opcode opc, const MgmtEventCallback &cb) noexcept {
1118  if( !isValidMgmtEventCallbackListsIndex(opc) ) {
1119  ERR_PRINT("Opcode %s >= %d", MgmtEvent::getOpcodeString(opc).c_str(), mgmtAdapterEventCallbackLists.size());
1120  return false;
1121  }
1122  MgmtAdapterEventCallbackList &l = mgmtAdapterEventCallbackLists[static_cast<uint16_t>(opc)];
1123  /* const bool added = */ l.push_back_unique(MgmtAdapterEventCallback(dev_id, opc, cb), _mgmtAdapterEventCallbackEqComp_ID_CB);
1124  return true;
1125 }
1127  if( !isValidMgmtEventCallbackListsIndex(opc) ) {
1128  ERR_PRINT("Opcode %s >= %d", MgmtEvent::getOpcodeString(opc).c_str(), mgmtAdapterEventCallbackLists.size());
1129  return 0;
1130  }
1131  MgmtAdapterEventCallbackList &l = mgmtAdapterEventCallbackLists[static_cast<uint16_t>(opc)];
1133  true /* all_matching */, _mgmtAdapterEventCallbackEqComp_CB);
1134 }
1135 int BTManager::removeMgmtEventCallback(const int dev_id) noexcept {
1136  if( 0 > dev_id ) {
1137  // skip dev_id -1 case, use clearAllMgmtEventCallbacks() here
1138  return 0;
1139  }
1140  int count = 0;
1141  for(size_t i=0; i<mgmtAdapterEventCallbackLists.size(); i++) {
1142  MgmtAdapterEventCallbackList &l = mgmtAdapterEventCallbackLists[i];
1144  true /* all_matching */, _mgmtAdapterEventCallbackEqComp_ID);
1145  }
1146  return count;
1147 }
1149  if( !isValidMgmtEventCallbackListsIndex(opc) ) {
1150  ERR_PRINT("Opcode %s >= %d", MgmtEvent::getOpcodeString(opc).c_str(), mgmtAdapterEventCallbackLists.size());
1151  return;
1152  }
1153  mgmtAdapterEventCallbackLists[static_cast<uint16_t>(opc)].clear();
1154 }
1156  for(size_t i=0; i<mgmtAdapterEventCallbackLists.size(); i++) {
1157  mgmtAdapterEventCallbackLists[i].clear();
1158  }
1159  mgmtChangedAdapterSetCallbackList.clear();
1160 }
1161 
1162 void BTManager::processAdapterAdded(std::unique_ptr<MgmtEvent> e) noexcept {
1163  const uint16_t dev_id = e->getDevID();
1164 
1165  std::unique_ptr<AdapterInfo> adapterInfo = initAdapter(dev_id, defaultBTMode);
1166 
1167  if( nullptr != adapterInfo ) {
1168  std::shared_ptr<BTAdapter> adapter = addAdapter( *adapterInfo );
1169  DBG_PRINT("DBTManager::Adapter[%d] Added: Start %s, added %d", dev_id, adapter->toString().c_str());
1170  sendMgmtEvent(*e);
1171  DBG_PRINT("DBTManager::Adapter[%d] Added: User_ %s", dev_id, adapter->toString().c_str());
1172  jau::for_each_fidelity(mgmtChangedAdapterSetCallbackList, [&](ChangedAdapterSetCallback &cb) {
1173  cb.invoke(true /* added */, adapter);
1174  });
1175  DBG_PRINT("DBTManager::Adapter[%d] Added: End__ %s", dev_id, adapter->toString().c_str());
1176  } else {
1177  DBG_PRINT("DBTManager::Adapter[%d] Added: InitAI failed", dev_id);
1178  }
1179 }
1180 void BTManager::processAdapterRemoved(std::unique_ptr<MgmtEvent> e) noexcept {
1181  const uint16_t dev_id = e->getDevID();
1182  std::shared_ptr<BTAdapter> ai = removeAdapter(dev_id);
1183  if( nullptr != ai ) {
1184  DBG_PRINT("DBTManager::Adapter[%d] Removed: Start: %s", dev_id, ai->toString().c_str());
1185  sendMgmtEvent(*e);
1186  DBG_PRINT("DBTManager::Adapter[%d] Removed: User_: %s", dev_id, ai->toString().c_str());
1187  jau::for_each_fidelity(mgmtChangedAdapterSetCallbackList, [&](ChangedAdapterSetCallback &cb) {
1188  cb.invoke(false /* added */, ai);
1189  });
1190  ai->close(); // issuing dtor on DBTAdapter
1191  DBG_PRINT("DBTManager::Adapter[%d] Removed: End__: %s", dev_id, ai->toString().c_str());
1192  } else {
1193  DBG_PRINT("DBTManager::Adapter[%d] Removed: RemoveAI failed", dev_id);
1194  }
1195 }
1196 bool BTManager::mgmtEvNewSettingsCB(const MgmtEvent& e) noexcept {
1197  const MgmtEvtNewSettings &event = *static_cast<const MgmtEvtNewSettings *>(&e);
1198  std::shared_ptr<BTAdapter> adapter = getAdapter(event.getDevID());
1199  if( nullptr != adapter ) {
1200  const AdapterSetting old_settings = adapter->adapterInfo.getCurrentSettingMask();
1201  const AdapterSetting new_settings = adapter->adapterInfo.setCurrentSettingMask(event.getSettings());
1202  DBG_PRINT("DBTManager:mgmt:NewSettings: Adapter[%d] %s -> %s - %s",
1203  event.getDevID(),
1204  to_string(old_settings).c_str(),
1205  to_string(new_settings).c_str(),
1206  e.toString().c_str());
1207  } else {
1208  DBG_PRINT("DBTManager:mgmt:NewSettings: Adapter[%d] %s -> adapter not present - %s",
1209  event.getDevID(),
1210  to_string(event.getSettings()).c_str(),
1211  e.toString().c_str());
1212  }
1213  return true;
1214 }
1215 
1216 bool BTManager::mgmtEventAnyCB(const MgmtEvent& e) noexcept {
1217  DBG_PRINT("DBTManager:mgmt:Any: %s", e.toString().c_str());
1218  (void)e;
1219  return true;
1220 }
1221 
1222 /**
1223  * ChangedAdapterSetCallback handling
1224  */
1225 
1227  [](const ChangedAdapterSetCallback& a, const ChangedAdapterSetCallback& b) -> bool { return a == b; };
1228 
1229 
1231  ChangedAdapterSetCallback* l_p = const_cast<ChangedAdapterSetCallback*>(&l);
1232  mgmtChangedAdapterSetCallbackList.push_back(l);
1233 
1234  jau::for_each_fidelity(adapters, [&](std::shared_ptr<BTAdapter>& ai) {
1235  l_p->invoke(true /* added */, ai);
1236  });
1237 }
1239  return mgmtChangedAdapterSetCallbackList.erase_matching(l, true /* all_matching */, _changedAdapterSetCallbackEqComp);
1240 }
1241 
1245  jau::bindPlainFunc<bool, bool, std::shared_ptr<BTAdapter>&>(f)
1246  ) );
1247 }
1249  ChangedAdapterSetCallback l( jau::bindPlainFunc<bool, bool, std::shared_ptr<BTAdapter>&>(f) );
1250  return mgmtChangedAdapterSetCallbackList.erase_matching(l, true /* all_matching */, _changedAdapterSetCallbackEqComp);
1251 }
direct_bt::SMPIOCapability::UNSET
@ UNSET
Denoting unset value, i.e.
_mgmtAdapterEventCallbackEqComp_CB
static MgmtAdapterEventCallbackList::equal_comparator _mgmtAdapterEventCallbackEqComp_CB
Definition: BTManager.cpp:1111
jau::environment::get
static environment & get(const std::string root_prefix_domain="jau") noexcept
Static singleton initialization of this project's environment with the given global root prefix_domai...
Definition: environment.hpp:234
direct_bt::AdapterSetting
AdapterSetting
Adapter Setting Bits.
Definition: BTTypes1.hpp:136
jau::ordered_atomic::compare_exchange_strong
CXX_ALWAYS_INLINE bool compare_exchange_strong(_Tp &__e, _Tp __i) noexcept
Definition: ordered_atomic.hpp:163
direct_bt::MgmtAddDeviceToWhitelistCmd
mgmt_addr_info { EUI48, uint8_t type }, uint8_t action
Definition: MgmtTypes.hpp:962
mgmthandler_sigaction
static void mgmthandler_sigaction(int sig, siginfo_t *info, void *ucontext) noexcept
Definition: BTManager.cpp:176
direct_bt::MGMT_HEADER_SIZE
@ MGMT_HEADER_SIZE
Definition: MgmtTypes.hpp:74
direct_bt::MgmtEvent::getTotalSize
jau::nsize_t getTotalSize() const noexcept
Definition: MgmtTypes.hpp:1210
direct_bt::MgmtCommand::Opcode::START_DISCOVERY
@ START_DISCOVERY
direct_bt::TROOctets::getSize
constexpr jau::nsize_t getSize() const noexcept
Returns the used memory size for read and write operations, may be zero.
Definition: OctetTypes.hpp:118
jau::for_each_fidelity
constexpr UnaryFunction for_each_fidelity(InputIt first, InputIt last, UnaryFunction f)
Like jau::for_each(), see above.
Definition: basic_algos.hpp:215
direct_bt::MgmtEvtNewSettings
uint32_t settings
Definition: MgmtTypes.hpp:1371
direct_bt::to_MgmtLTKType
MgmtLTKType to_MgmtLTKType(const SMPLongTermKeyInfo::Property ltk_prop_mask) noexcept
Definition: MgmtTypes.cpp:132
direct_bt::MgmtEvent::Opcode::INVALID
@ INVALID
jau::cow_ro_iterator
Implementation of a Copy-On-Write (CoW) read-onlu iterator over immutable value_type storage.
Definition: cow_iterator.hpp:44
direct_bt::TOctets::get_wptr
uint8_t * get_wptr() noexcept
Definition: OctetTypes.hpp:383
direct_bt::BTManager::startDiscovery
ScanType startDiscovery(const uint16_t dev_id, const BTMode btMode) noexcept
Start discovery on given adapter dev_id with a ScanType matching the given BTMode.
Definition: BTManager.cpp:775
jau::cow_darray::cbegin
constexpr const_iterator cbegin() const noexcept
Returns an jau::cow_ro_iterator to the first element of this CoW storage.
Definition: cow_darray.hpp:636
jau::cow_darray::erase_matching
constexpr_atomic int erase_matching(const value_type &x, const bool all_matching, equal_comparator comparator)
Erase either the first matching element or all matching elements.
Definition: cow_darray.hpp:986
direct_bt::MgmtCommand
Definition: MgmtTypes.hpp:371
direct_bt::MgmtEventCallback
jau::FunctionDef< bool, const MgmtEvent & > MgmtEventCallback
Definition: MgmtTypes.hpp:2232
direct_bt::MgmtUnpairDeviceCmd
mgmt_addr_info { EUI48, uint8_t type }, bool disconnect (1 octet)
Definition: MgmtTypes.hpp:873
jau::call_on_release
Call on release allows the user to pass a function to be called at destruction of this instance.
Definition: basic_algos.hpp:58
direct_bt::MgmtEvent::toString
std::string toString() const noexcept override
Definition: MgmtTypes.hpp:1222
direct_bt::MgmtEvent::getOpcodeString
static std::string getOpcodeString(const Opcode opc) noexcept
Definition: MgmtTypes.cpp:314
direct_bt::HCIStatusCode::TIMEOUT
@ TIMEOUT
direct_bt::BTManager::setDiscoverable
MgmtStatus setDiscoverable(const uint16_t dev_id, const uint8_t state, const uint16_t timeout, AdapterSetting &current_settings) noexcept
Definition: BTManager.cpp:750
direct_bt::MgmtAdapterEventCallback::getDevID
int getDevID() const noexcept
Unique adapter index filter or -1 to listen for all adapter.
Definition: MgmtTypes.hpp:2254
basic_algos.hpp
Not
Definition: test_type_traits_queries01.cpp:51
BTManager.hpp
direct_bt::BTManager::disconnect
bool disconnect(const bool ioErrorCause, const uint16_t dev_id, const BDAddressAndType &addressAndType, const HCIStatusCode reason=HCIStatusCode::REMOTE_USER_TERMINATED_CONNECTION) noexcept
Definition: BTManager.cpp:1045
direct_bt::MgmtAdapterEventCallback
Definition: MgmtTypes.hpp:2235
direct_bt::MgmtEvent::validate
virtual bool validate(const MgmtCommand &req) const noexcept
Definition: MgmtTypes.hpp:1218
direct_bt
Definition: ATTPDUTypes.hpp:171
direct_bt::MgmtEvent::getSpecialized
static std::unique_ptr< MgmtEvent > getSpecialized(const uint8_t *buffer, jau::nsize_t const buffer_size) noexcept
Return a newly created specialized instance pointer to base class.
Definition: MgmtTypes.cpp:322
direct_bt::MgmtPairDeviceCmd
mgmt_addr_info { EUI48, uint8_t type }, SMPIOCapability io_cap (1 octet)
Definition: MgmtTypes.hpp:835
direct_bt::to_BTMode
BTMode to_BTMode(const std::string &value) noexcept
Maps the specified name to a constant of BTMode.
Definition: BTTypes0.cpp:360
direct_bt::MgmtEvent::getData
virtual const uint8_t * getData() const noexcept
Definition: MgmtTypes.hpp:1216
direct_bt::BTMode::NONE
@ NONE
Zero mode, neither DUAL, BREDR nor LE.
_mgmtAdapterEventCallbackEqComp_ID
static MgmtAdapterEventCallbackList::equal_comparator _mgmtAdapterEventCallbackEqComp_ID
Definition: BTManager.cpp:1114
direct_bt::MgmtEvent::Opcode
Opcode
Definition: MgmtTypes.hpp:1085
PERF3_TS_TD
#define PERF3_TS_TD(m)
Definition: debug.hpp:117
direct_bt::HCIWhitelistConnectType
HCIWhitelistConnectType
HCI Whitelist connection type.
Definition: BTTypes0.hpp:415
jau::darray::cbegin
constexpr const_iterator cbegin() const noexcept
Definition: darray.hpp:610
direct_bt::MgmtCommand::getOpcodeString
static std::string getOpcodeString(const Opcode op) noexcept
Definition: MgmtTypes.cpp:251
BTTypes1.hpp
direct_bt::BTManager::removeMgmtEventCallback
int removeMgmtEventCallback(const MgmtEvent::Opcode opc, const MgmtEventCallback &cb) noexcept
Returns count of removed given MgmtEventCallback from the named MgmtEvent::Opcode list.
Definition: BTManager.cpp:1126
direct_bt::TROOctets::get_ptr
constexpr uint8_t const * get_ptr() const noexcept
Definition: OctetTypes.hpp:228
direct_bt::MgmtEvtCmdComplete::getDataSize
jau::nsize_t getDataSize() const noexcept override
Definition: MgmtTypes.hpp:1290
direct_bt::MgmtEvent::Opcode::INDEX_ADDED
@ INDEX_ADDED
jau
Definition: basic_algos.hpp:34
direct_bt::MgmtEvtLocalNameChanged
uint8_t name[MGMT_MAX_NAME_LENGTH]; uint8_t short_name[MGMT_MAX_SHORT_NAME_LENGTH];
Definition: MgmtTypes.hpp:1397
PERF3_TS_T0
#define PERF3_TS_T0()
Definition: debug.hpp:116
direct_bt::BTAdapter::close
void close() noexcept
Closes this instance, usually being called by destructor or when this adapter is being removed as rec...
Definition: BTAdapter.cpp:252
direct_bt::MgmtUserConfirmNegativeReplyCmd
mgmt_addr_info { EUI48, uint8_t type },
Definition: MgmtTypes.hpp:909
direct_bt::MgmtUserPasskeyNegativeReplyCmd
mgmt_addr_info { EUI48, uint8_t type },
Definition: MgmtTypes.hpp:946
direct_bt::ScanType
ScanType
Meta ScanType as derived from BTMode, with defined value mask consisting of BDAddressType bits.
Definition: BTTypes0.hpp:294
jau::cow_darray::size
constexpr_atomic size_type size() const noexcept
Like std::vector::size().
Definition: cow_darray.hpp:716
direct_bt::MgmtEvtCmdComplete::toNameAndShortName
std::shared_ptr< NameAndShortName > toNameAndShortName() const noexcept
Convert this instance into ConnectionInfo if getCmdOpcode() == SET_LOCAL_NAME, getStatus() == SUCCESS...
Definition: MgmtTypes.cpp:459
direct_bt::NameAndShortName::getShortName
std::string getShortName() const noexcept
Definition: BTTypes1.hpp:123
direct_bt::HCIComm::isOpen
bool isOpen() const noexcept
Definition: HCIComm.hpp:81
direct_bt::BTAdapter::dev_id
const uint16_t dev_id
Adapter's internal temporary device id.
Definition: BTAdapter.hpp:273
jau::to_string
PRAGMA_DISABLE_WARNING_POP constexpr_cxx20 std::string to_string(const endian &v) noexcept
Return std::string representation of the given jau::endian.
Definition: byte_util.hpp:198
direct_bt::MgmtLTKType
MgmtLTKType
Long Term Key Types compatible with Mgmt's MgmtLongTermKeyInfo.
Definition: MgmtTypes.hpp:138
direct_bt::BTManager::pairDevice
bool pairDevice(const uint16_t dev_id, const BDAddressAndType &addressAndType, const SMPIOCapability iocap) noexcept
Definition: BTManager.cpp:937
direct_bt::MgmtCommand::Opcode
Opcode
Definition: MgmtTypes.hpp:373
direct_bt::TROOctets::get_uint16_nc
constexpr uint16_t get_uint16_nc(const jau::nsize_t i) const noexcept
Definition: OctetTypes.hpp:140
jau::FunctionDef< bool, const MgmtEvent & >
direct_bt::MgmtEvtCmdStatus
Definition: MgmtTypes.hpp:1318
direct_bt::MgmtEvent
uint16_t opcode, uint16_t dev-id, uint16_t param_size
Definition: MgmtTypes.hpp:1083
direct_bt::BTManager::removeAllDevicesFromWhitelist
int removeAllDevicesFromWhitelist() noexcept
Remove all previously added devices from the autoconnect whitelist.
Definition: BTManager.cpp:992
direct_bt::HCIStatusCode
HCIStatusCode
BT Core Spec v5.2: Vol 1, Part F Controller Error Codes: 1.3 List of Error Codes.
Definition: HCITypes.hpp:124
direct_bt::MgmtEvtCmdComplete::toConnectionInfo
std::shared_ptr< ConnectionInfo > toConnectionInfo() const noexcept
Convert this instance into ConnectionInfo if getCmdOpcode() == GET_CONN_INFO, getStatus() == SUCCESS ...
Definition: MgmtTypes.cpp:435
direct_bt::MgmtLoadConnParamCmd
uint16_t param_count 2 MgmtConnParam param[] 15 = 1x
Definition: MgmtTypes.hpp:1027
ABORT
#define ABORT(...)
Use for unconditional ::abort() call with given messages, prefix '[elapsed_time] ABORT @ FILE:LINE: '...
Definition: debug.hpp:124
direct_bt::MgmtGetConnectionInfoCmd
mgmt_addr_info { EUI48, uint8_t type },
Definition: MgmtTypes.hpp:782
jau::darray
Implementation of a dynamic linear array storage, aka vector.
Definition: darray.hpp:102
direct_bt::MgmtLoadLinkKeyCmd
uint8_t debug_keys, uint16_t key_count, MgmtLinkKey keys[key_count]
Definition: MgmtTypes.hpp:580
direct_bt::MgmtStatus::NOT_SUPPORTED
@ NOT_SUPPORTED
SMPHandler.hpp
direct_bt::MgmtStatus
MgmtStatus
Definition: MgmtTypes.hpp:77
direct_bt::BTManager::isDeviceWhitelisted
bool isDeviceWhitelisted(const uint16_t dev_id, const BDAddressAndType &addressAndType) noexcept
Returns true, if the adapter's device is already whitelisted.
Definition: BTManager.cpp:962
jau::cow_ro_iterator::dist_begin
constexpr difference_type dist_begin() const noexcept
Returns the distance to_begin() using zero as first index.
Definition: cow_iterator.hpp:799
direct_bt::BDAddressAndType::ANY_BREDR_DEVICE
static const BDAddressAndType ANY_BREDR_DEVICE
Using EUI48::ANY_DEVICE and BDAddressType::BDADDR_BREDR to match any BREDR device.
Definition: BTAddress.hpp:420
direct_bt::MgmtLinkKeyInfo
Used for MgmtLoadLinkKeyCmd and MgmtEvtNewLinkKey.
Definition: MgmtTypes.hpp:193
BTAdapter.hpp
direct_bt::MgmtEnv::DEBUG_EVENT
const bool DEBUG_EVENT
Debug all Mgmt event communication.
Definition: BTManager.hpp:105
direct_bt::MgmtEvent::Opcode::CMD_COMPLETE
@ CMD_COMPLETE
direct_bt::AdapterInfo::getCurrentSettingMask
AdapterSetting getCurrentSettingMask() const noexcept
Definition: BTTypes1.hpp:272
direct_bt::MgmtUserPasskeyReplyCmd
mgmt_addr_info { EUI48, uint8_t type }, uint32_t passkey
Definition: MgmtTypes.hpp:921
direct_bt::BTAdapter::toString
std::string toString() const noexcept override
Definition: BTAdapter.hpp:784
direct_bt::MgmtEvent::getDataSize
virtual jau::nsize_t getDataSize() const noexcept
Definition: MgmtTypes.hpp:1215
direct_bt::BTManager::addDeviceToWhitelist
bool addDeviceToWhitelist(const uint16_t dev_id, const BDAddressAndType &addressAndType, const HCIWhitelistConnectType ctype) noexcept
Add the given device to the adapter's autoconnect whitelist.
Definition: BTManager.cpp:973
direct_bt::MgmtEvent::Opcode::INDEX_REMOVED
@ INDEX_REMOVED
direct_bt::MgmtEvtCmdComplete::getCurrentSettings
bool getCurrentSettings(AdapterSetting &current_settings) const noexcept
Returns AdapterSetting if getCmdOpcode() expects a single 4-octet AdapterSetting and hence getDataSiz...
Definition: MgmtTypes.cpp:393
direct_bt::MgmtDisconnectCmd
mgmt_addr_info { EUI48, uint8_t type },
Definition: MgmtTypes.hpp:717
WARN_PRINT
#define WARN_PRINT(...)
Use for unconditional warning messages, prefix '[elapsed_time] Warning @ FILE:LINE: '.
Definition: debug.hpp:146
direct_bt::BTManager::removeDeviceFromWhitelist
bool removeDeviceFromWhitelist(const uint16_t dev_id, const BDAddressAndType &addressAndType) noexcept
Remove the given device from the adapter's autoconnect whitelist.
Definition: BTManager.cpp:1019
direct_bt::MgmtCommand::Opcode::STOP_DISCOVERY
@ STOP_DISCOVERY
direct_bt::BTManager::removeChangedAdapterSetCallback
int removeChangedAdapterSetCallback(const ChangedAdapterSetCallback &l)
Remove the given ChangedAdapterSetCallback from this manager.
Definition: BTManager.cpp:1238
jau::ordered_atomic::load
CXX_ALWAYS_INLINE _Tp load() const noexcept
Definition: ordered_atomic.hpp:139
direct_bt::number
constexpr uint8_t number(const BDAddressType rhs) noexcept
Definition: BTAddress.hpp:67
jau::bindMemberFunc
jau::FunctionDef< R, A... > bindMemberFunc(C *base, R(C::*mfunc)(A...)) noexcept
Definition: function_def.hpp:361
direct_bt::BTSecurityRegistry::get
Entry * get(const EUI48 &addr, const std::string &name, AddressNameEntryMatchFunc m) noexcept
Returns a matching BTSecurityRegistry::Entry with the given.
Definition: BTSecurityRegistry.cpp:36
jau::darray::size
constexpr size_type size() const noexcept
Like std::vector::size().
Definition: darray.hpp:668
direct_bt::MgmtEvtCmdComplete::getStatus
static MgmtStatus getStatus(const uint8_t *data)
Definition: MgmtTypes.hpp:1274
direct_bt::BTManager
A thread safe singleton handler of the Linux Kernel's BlueZ manager control channel.
Definition: BTManager.hpp:201
jau::bindPlainFunc
jau::FunctionDef< R, A... > bindPlainFunc(R(*func)(A...)) noexcept
Definition: function_def.hpp:367
direct_bt::BTManager::clearAllCallbacks
void clearAllCallbacks() noexcept
Removes all MgmtEventCallbacks from all MgmtEvent::Opcode lists.
Definition: BTManager.cpp:1155
jau::cow_darray
Implementation of a Copy-On-Write (CoW) using jau::darray as the underlying storage,...
Definition: cow_darray.hpp:130
jau::for_each_const
constexpr UnaryFunction for_each_const(T &data, UnaryFunction f, std::enable_if_t< is_cow_type< T >::value, bool >=true) noexcept
Definition: basic_algos.hpp:323
direct_bt::MGMT_INDEX_NONE
@ MGMT_INDEX_NONE
Definition: MgmtTypes.hpp:66
direct_bt::MgmtStatus::UNKNOWN_COMMAND
@ UNKNOWN_COMMAND
direct_bt::MgmtEvtAdapterInfo::toAdapterInfo
std::unique_ptr< AdapterInfo > toAdapterInfo() const noexcept
Definition: MgmtTypes.cpp:486
debug.hpp
direct_bt::MgmtStatus::SUCCESS
@ SUCCESS
direct_bt::MgmtRemoveDeviceFromWhitelistCmd
mgmt_addr_info { EUI48, uint8_t type },
Definition: MgmtTypes.hpp:987
jau::cow_darray< std::shared_ptr< BTAdapter > >::difference_type
std::make_signed< size_type >::type difference_type
Definition: cow_darray.hpp:147
direct_bt::TROOctets
Transient read only octet data, i.e.
Definition: OctetTypes.hpp:59
direct_bt::MgmtAdapterEventCallback::getCallback
MgmtEventCallback & getCallback() noexcept
MgmtEventCallback reference.
Definition: MgmtTypes.hpp:2257
direct_bt::MgmtStatus::TIMEOUT
@ TIMEOUT
direct_bt::MgmtEvtDeviceDisconnected
mgmt_addr_info { EUI48, uint8_t type }, uint8_t reason
Definition: MgmtTypes.hpp:1539
direct_bt::BTManager::getIOCapability
SMPIOCapability getIOCapability(const uint16_t dev_id) const noexcept
Definition: BTManager.cpp:714
direct_bt::to_string
std::string to_string(const BDAddressType type) noexcept
Definition: BTTypes0.cpp:129
direct_bt::BTManager::addChangedAdapterSetCallback
void addChangedAdapterSetCallback(const ChangedAdapterSetCallback &l)
ChangedAdapterSetCallback handling.
Definition: BTManager.cpp:1230
direct_bt::BTAdapter
BTAdapter represents one Bluetooth Controller.
Definition: BTAdapter.hpp:250
direct_bt::BTManager::sendMgmtEvent
void sendMgmtEvent(const MgmtEvent &event) noexcept
Manually send a MgmtEvent to all of its listeners.
Definition: BTManager.cpp:154
direct_bt::BTMode::DUAL
@ DUAL
Dual Bluetooth mode, i.e.
direct_bt::BTManager::clearMgmtEventCallbacks
void clearMgmtEventCallbacks(const MgmtEvent::Opcode opc) noexcept
Removes all MgmtEventCallbacks from the to the named MgmtEvent::Opcode list.
Definition: BTManager.cpp:1148
direct_bt::AdapterSetting::NONE
@ NONE
direct_bt::ChangedAdapterSetFunc
bool(* ChangedAdapterSetFunc)(bool added, std::shared_ptr< BTAdapter > &adapter)
Callback function to receive change events regarding the system's adapter set, e.g.
Definition: BTManager.hpp:163
jau::to_hexstring
std::string to_hexstring(value_type const &v) noexcept
Produce a lower-case hexadecimal string representation of the given pointer.
Definition: string_util.hpp:104
direct_bt::BTManager::getConnectionInfo
std::shared_ptr< ConnectionInfo > getConnectionInfo(const uint16_t dev_id, const BDAddressAndType &addressAndType) noexcept
Definition: BTManager.cpp:1072
direct_bt::MgmtUserConfirmReplyCmd
mgmt_addr_info { EUI48, uint8_t type },
Definition: MgmtTypes.hpp:898
direct_bt::BTManager::uploadLongTermKey
HCIStatusCode uploadLongTermKey(const uint16_t dev_id, const MgmtLongTermKeyInfo &key) noexcept
Definition: BTManager.cpp:834
jau::snsize_t
int_fast32_t snsize_t
Natural 'ssize_t' alternative using int_fast32_t as its natural sized type.
Definition: int_types.hpp:56
jau::nsize_t
uint_fast32_t nsize_t
Natural 'size_t' alternative using uint_fast32_t as its natural sized type.
Definition: int_types.hpp:44
direct_bt::MgmtConnParam::address
EUI48 address
Definition: MgmtTypes.hpp:1010
direct_bt::HCIStatusCode::UNKNOWN_HCI_COMMAND
@ UNKNOWN_HCI_COMMAND
jau::cow_darray::equal_comparator
bool(* equal_comparator)(const value_type &a, const value_type &b)
Generic value_type equal comparator to be user defined for e.g.
Definition: cow_darray.hpp:921
direct_bt::BTManager::pidSelf
static const pid_t pidSelf
Definition: BTManager.hpp:208
direct_bt::BTManager::setMode
bool setMode(const uint16_t dev_id, const MgmtCommand::Opcode opc, const uint8_t mode, AdapterSetting &current_settings) noexcept
Definition: BTManager.cpp:724
jau::get_uint16
constexpr uint16_t get_uint16(uint8_t const *buffer, nsize_t const byte_offset) noexcept
Definition: byte_util.hpp:586
direct_bt::SMPIOCapability
SMPIOCapability
Vol 3, Part H, 2.3.2 IO capabilities.
Definition: SMPTypes.hpp:185
jau::cow_darray::clear
constexpr_atomic void clear() noexcept
Like std::vector::clear(), but ending with zero capacity.
Definition: cow_darray.hpp:751
direct_bt::BTManager::stopDiscovery
bool stopDiscovery(const uint16_t dev_id, const ScanType type) noexcept
Stop discovery on given adapter dev_id.
Definition: BTManager.cpp:796
ERR_PRINT
#define ERR_PRINT(...)
Use for unconditional error messages, prefix '[elapsed_time] Error @ FILE:LINE: '.
Definition: debug.hpp:132
direct_bt::HCIComm::close
void close() noexcept
Closing the HCI channel, locking mutex_write().
Definition: HCIComm.cpp:111
direct_bt::BTManager::uploadLinkKey
MgmtStatus uploadLinkKey(const uint16_t dev_id, const bool debug_keys, const MgmtLinkKeyInfo &key) noexcept
Security commands.
Definition: BTManager.cpp:819
direct_bt::MgmtEvent::getOpcode
static MgmtEvent::Opcode getOpcode(const uint8_t *buffer)
Definition: MgmtTypes.hpp:1167
direct_bt::BTManager::uploadLongTermKeyInfo
HCIStatusCode uploadLongTermKeyInfo(const uint16_t dev_id, const BDAddressAndType &addressAndType, const SMPLongTermKeyInfo &ltk) noexcept
Definition: BTManager.cpp:858
jau::FunctionDef::invoke
R invoke(A... args)
Definition: function_def.hpp:354
direct_bt::MgmtSetDiscoverableCmd
uint8_t discoverable uint16_t timeout
Definition: MgmtTypes.hpp:533
initAdapter
static bool initAdapter(std::shared_ptr< BTAdapter > &adapter)
Definition: dbt_scanner10.cpp:643
direct_bt::MgmtLongTermKeyInfo::address
EUI48 address
Definition: MgmtTypes.hpp:267
direct_bt::MgmtLoadLongTermKeyCmd
uint16_t key_count MgmtLongTermKey keys[key_count]
Definition: MgmtTypes.hpp:639
direct_bt::BTManager::uploadConnParam
bool uploadConnParam(const uint16_t dev_id, const BDAddressAndType &addressAndType, const uint16_t conn_interval_min=12, const uint16_t conn_interval_max=12, const uint16_t conn_latency=0, const uint16_t supervision_timeout=getHCIConnSupervisorTimeout(0, 15)) noexcept
Uploads given connection parameter for given device to the kernel.
Definition: BTManager.cpp:806
direct_bt::BTManager::getDefaultAdapter
std::shared_ptr< BTAdapter > getDefaultAdapter() const noexcept
Returns the default AdapterInfo.
Definition: BTManager.cpp:614
direct_bt::MgmtCommand::toString
std::string toString() const noexcept override
Definition: MgmtTypes.hpp:513
_mgmtAdapterEventCallbackEqComp_ID_CB
static MgmtAdapterEventCallbackList::equal_comparator _mgmtAdapterEventCallbackEqComp_ID_CB
Definition: BTManager.cpp:1108
startDiscovery
static bool startDiscovery(BTAdapter *a, std::string msg)
Definition: dbt_scanner10.cpp:637
jau::cow_darray::push_back
constexpr_atomic void push_back(const value_type &x)
Like std::vector::push_back(), copy.
Definition: cow_darray.hpp:810
jau::cow_ro_iterator::is_end
constexpr bool is_end() const noexcept
Returns true, if this iterator points to cend().
Definition: cow_iterator.hpp:788
direct_bt::BTManager::unpairDevice
MgmtStatus unpairDevice(const uint16_t dev_id, const BDAddressAndType &addressAndType, const bool disconnect) noexcept
Definition: BTManager.cpp:946
HCIComm.hpp
direct_bt::MgmtEnv::MGMT_READER_THREAD_POLL_TIMEOUT
const int32_t MGMT_READER_THREAD_POLL_TIMEOUT
Poll timeout for mgmt reader thread, defaults to 10s.
Definition: BTManager.hpp:81
direct_bt::MgmtEvtCmdStatus::getStatus
MgmtStatus getStatus() const noexcept
Definition: MgmtTypes.hpp:1334
direct_bt::to_HCIStatusCode
HCIStatusCode to_HCIStatusCode(const MgmtStatus mstatus) noexcept
Definition: MgmtTypes.cpp:543
direct_bt::BTManager::addMgmtEventCallback
bool addMgmtEventCallback(const int dev_id, const MgmtEvent::Opcode opc, const MgmtEventCallback &cb) noexcept
MgmtEventCallback handling
Definition: BTManager.cpp:1117
direct_bt::MgmtCommand::Opcode::SET_IO_CAPABILITY
@ SET_IO_CAPABILITY
direct_bt::MgmtEvtCmdComplete::getData
const uint8_t * getData() const noexcept override
Definition: MgmtTypes.hpp:1291
jau::environment::getProperty
static std::string getProperty(const std::string &name) noexcept
Returns the value of the environment's variable 'name'.
Definition: environment.cpp:46
direct_bt::MgmtAdapterEventCallback::toString
std::string toString() const
Definition: MgmtTypes.hpp:2268
WORDY_PRINT
#define WORDY_PRINT(...)
Use for environment-variable environment::VERBOSE conditional verbose messages, prefix '[elapsed_time...
Definition: debug.hpp:91
direct_bt::AdapterInfo
Definition: BTTypes1.hpp:188
direct_bt::MgmtEvtAdapterInfo
Definition: MgmtTypes.hpp:2199
direct_bt::MgmtConnParam
Used in MgmtLoadConnParamCmd and MgmtEvtNewConnectionParam.
Definition: MgmtTypes.hpp:1010
direct_bt::MgmtUint8Cmd
Definition: MgmtTypes.hpp:519
direct_bt::NameAndShortName::getName
std::string getName() const noexcept
Definition: BTTypes1.hpp:122
direct_bt::MgmtEvent::Opcode::CMD_STATUS
@ CMD_STATUS
direct_bt::BTManager::setLocalName
std::shared_ptr< NameAndShortName > setLocalName(const uint16_t dev_id, const std::string &name, const std::string &short_name) noexcept
Definition: BTManager.cpp:1085
direct_bt::to_ScanType
ScanType to_ScanType(BTMode btMode)
Definition: BTTypes0.cpp:504
PERF_TS_TD
#define PERF_TS_TD(m)
Definition: debug.hpp:103
direct_bt::BDAddressAndType
Unique Bluetooth EUI48 address and BDAddressType tuple.
Definition: BTAddress.hpp:417
COND_PRINT
#define COND_PRINT(C,...)
Use for conditional plain messages, prefix '[elapsed_time] '.
Definition: debug.hpp:165
direct_bt::BTManager::getAdapter
std::shared_ptr< BTAdapter > getAdapter(const uint16_t dev_id) const noexcept
Returns the DBTAdapter with the given dev_id, or nullptr if not found.
Definition: BTManager.cpp:624
direct_bt::BTManager::userConfirmReply
MgmtStatus userConfirmReply(const uint16_t dev_id, const BDAddressAndType &addressAndType, const bool positive) noexcept
Definition: BTManager.cpp:916
direct_bt::BTManager::userPasskeyReply
MgmtStatus userPasskeyReply(const uint16_t dev_id, const BDAddressAndType &addressAndType, const uint32_t passkey) noexcept
Definition: BTManager.cpp:886
jau::cow_ro_iterator::cbegin
constexpr cow_ro_iterator cbegin() const noexcept
Returns a new const_iterator pointing to the first element, aka begin.
Definition: cow_iterator.hpp:736
direct_bt::ChangedAdapterSetCallback
jau::FunctionDef< bool, bool, std::shared_ptr< BTAdapter > & > ChangedAdapterSetCallback
Callback jau::FunctionDef to receive change events regarding the system's adapter set,...
Definition: BTManager.hpp:189
direct_bt::BTSecurityRegistry::clear
void clear() noexcept
Clears internal list.
Definition: BTSecurityRegistry.cpp:90
direct_bt::MgmtLongTermKeyInfo
Used for MgmtLoadLongTermKeyCmd and MgmtEvtNewLongTermKey.
Definition: MgmtTypes.hpp:267
direct_bt::BTMode
BTMode
Bluetooth adapter operating mode.
Definition: BTTypes0.hpp:56
jau::darray::cend
constexpr const_iterator cend() const noexcept
Definition: darray.hpp:616
_changedAdapterSetCallbackEqComp
static ChangedAdapterSetCallbackList::equal_comparator _changedAdapterSetCallbackEqComp
ChangedAdapterSetCallback handling.
Definition: BTManager.cpp:1226
direct_bt::HCIStatusCode::NOT_SUPPORTED
@ NOT_SUPPORTED
direct_bt::MgmtEvtCmdComplete
Definition: MgmtTypes.hpp:1256
jau::darray::clear
constexpr void clear() noexcept
Like std::vector::clear(), but ending with zero capacity.
Definition: darray.hpp:796
DBG_PRINT
#define DBG_PRINT(...)
Use for environment-variable environment::DEBUG conditional debug messages, prefix '[elapsed_time] De...
Definition: debug.hpp:78
direct_bt::ScanType::NONE
@ NONE
jau::cow_darray::push_back_unique
constexpr_atomic bool push_back_unique(const value_type &x, equal_comparator comparator)
Like std::vector::push_back(), but only if the newly added element does not yet exist.
Definition: cow_darray.hpp:948
direct_bt::BTManager::userPasskeyNegativeReply
MgmtStatus userPasskeyNegativeReply(const uint16_t dev_id, const BDAddressAndType &addressAndType) noexcept
Definition: BTManager.cpp:901
PERF_TS_T0
#define PERF_TS_T0()
Definition: debug.hpp:102
direct_bt::HCIComm::read
jau::snsize_t read(uint8_t *buffer, const jau::nsize_t capacity, const int32_t timeoutMS) noexcept
Generic read w/ own timeoutMS, w/o locking suitable for a unique ringbuffer sink.
Definition: HCIComm.cpp:141
direct_bt::MgmtSetLocalNameCmd
uint8_t name[MGMT_MAX_NAME_LENGTH]; uint8_t short_name[MGMT_MAX_SHORT_NAME_LENGTH];
Definition: MgmtTypes.hpp:556
direct_bt::SMPLongTermKeyInfo
SMP Long Term Key Info, used for platform agnostic persistence.
Definition: SMPTypes.hpp:522