Direct-BT  2.3.1
Direct-BT - Direct Bluetooth Programming.
HCIHandler.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 #include <jau/debug.hpp>
36 
37 #include <jau/environment.hpp>
38 #include <jau/basic_algos.hpp>
39 #include <jau/packed_attribute.hpp>
40 
41 #include "BTIoctl.hpp"
42 
43 #include "HCIIoctl.hpp"
44 #include "HCIComm.hpp"
45 #include "HCIHandler.hpp"
46 #include "BTTypes1.hpp"
47 
48 extern "C" {
49  #include <inttypes.h>
50  #include <unistd.h>
51  #include <poll.h>
52  #include <signal.h>
53  #ifdef __linux__
54  #include <sys/ioctl.h>
55  #endif
56 }
57 
58 using namespace direct_bt;
59 
60 HCIEnv::HCIEnv() noexcept
61 : exploding( jau::environment::getExplodingProperties("direct_bt.hci") ),
62  HCI_READER_THREAD_POLL_TIMEOUT( jau::environment::getInt32Property("direct_bt.hci.reader.timeout", 10000, 1500 /* min */, INT32_MAX /* max */) ),
63  HCI_COMMAND_STATUS_REPLY_TIMEOUT( jau::environment::getInt32Property("direct_bt.hci.cmd.status.timeout", 3000, 1500 /* min */, INT32_MAX /* max */) ),
64  HCI_COMMAND_COMPLETE_REPLY_TIMEOUT( jau::environment::getInt32Property("direct_bt.hci.cmd.complete.timeout", 10000, 1500 /* min */, INT32_MAX /* max */) ),
65  HCI_COMMAND_POLL_PERIOD( jau::environment::getInt32Property("direct_bt.hci.cmd.poll.period", 125, 50 /* min */, INT32_MAX /* max */) ),
66  HCI_EVT_RING_CAPACITY( jau::environment::getInt32Property("direct_bt.hci.ringsize", 64, 64 /* min */, 1024 /* max */) ),
67  DEBUG_EVENT( jau::environment::getBooleanProperty("direct_bt.debug.hci.event", false) ),
68  DEBUG_SCAN_AD_EIR( jau::environment::getBooleanProperty("direct_bt.debug.hci.scan_ad_eir", false) ),
69  HCI_READ_PACKET_MAX_RETRY( HCI_EVT_RING_CAPACITY )
70 {
71 }
72 
73 const pid_t HCIHandler::pidSelf = getpid();
74 
75 __pack( struct hci_rp_status {
76  __u8 status;
77 } );
78 
79 HCIHandler::HCIConnectionRef HCIHandler::addOrUpdateHCIConnection(jau::darray<HCIConnectionRef> &list,
80  const BDAddressAndType& addressAndType, const uint16_t handle) noexcept {
81  const std::lock_guard<std::recursive_mutex> lock(mtx_connectionList); // RAII-style acquire and relinquish via destructor
82  // remove all old entry with given address first
83  auto end = list.end();
84  for (auto it = list.begin(); it != end; ++it) {
85  HCIConnectionRef conn = *it;
86  if ( conn->equals(addressAndType) ) {
87  // reuse same entry
88  WORDY_PRINT("HCIHandler::addTrackerConnection: address%s, handle %s: reuse entry %s - %s",
89  addressAndType.toString().c_str(), jau::to_hexstring(handle).c_str(),
90  conn->toString().c_str(), toString().c_str());
91  // Overwrite tracked connection handle with given _valid_ handle only, i.e. non zero!
92  if( 0 != handle ) {
93  if( 0 != conn->getHandle() && handle != conn->getHandle() ) {
94  WARN_PRINT("HCIHandler::addTrackerConnection: address%s, handle %s: reusing entry %s, overwriting non-zero handle - %s",
95  addressAndType.toString().c_str(), jau::to_hexstring(handle).c_str(),
96  conn->toString().c_str(), toString().c_str());
97  }
98  conn->setHandle( handle );
99  }
100  return conn; // done
101  }
102  }
103  HCIConnectionRef res( new HCIConnection(addressAndType, handle) );
104  list.push_back( res );
105  return res;
106 }
107 
108 HCIHandler::HCIConnectionRef HCIHandler::findHCIConnection(jau::darray<HCIConnectionRef> &list, const BDAddressAndType& addressAndType) noexcept {
109  const std::lock_guard<std::recursive_mutex> lock(mtx_connectionList); // RAII-style acquire and relinquish via destructor
110  const jau::nsize_t size = list.size();
111  for (jau::nsize_t i = 0; i < size; i++) {
112  HCIConnectionRef & e = list[i];
113  if( e->equals(addressAndType) ) {
114  return e;
115  }
116  }
117  return nullptr;
118 }
119 
120 HCIHandler::HCIConnectionRef HCIHandler::findTrackerConnection(const uint16_t handle) noexcept {
121  const std::lock_guard<std::recursive_mutex> lock(mtx_connectionList); // RAII-style acquire and relinquish via destructor
122  const jau::nsize_t size = connectionList.size();
123  for (jau::nsize_t i = 0; i < size; i++) {
124  HCIConnectionRef & e = connectionList[i];
125  if ( handle == e->getHandle() ) {
126  return e;
127  }
128  }
129  return nullptr;
130 }
131 
132 HCIHandler::HCIConnectionRef HCIHandler::removeTrackerConnection(const HCIConnectionRef conn) noexcept {
133  const std::lock_guard<std::recursive_mutex> lock(mtx_connectionList); // RAII-style acquire and relinquish via destructor
134  auto end = connectionList.end();
135  for (auto it = connectionList.begin(); it != end; ++it) {
136  HCIConnectionRef e = *it;
137  if ( *e == *conn ) {
138  connectionList.erase(it);
139  return e; // done
140  }
141  }
142  return nullptr;
143 }
144 int HCIHandler::countPendingTrackerConnections() noexcept {
145  const std::lock_guard<std::recursive_mutex> lock(mtx_connectionList); // RAII-style acquire and relinquish via destructor
146  int count = 0;
147  for (auto it = connectionList.begin(); it != connectionList.end(); it++) {
148  HCIConnectionRef e = *it;
149  if ( e->getHandle() == 0 ) {
150  count++;
151  }
152  }
153  return count;
154 }
155 HCIHandler::HCIConnectionRef HCIHandler::removeHCIConnection(jau::darray<HCIConnectionRef> &list, const uint16_t handle) noexcept {
156  const std::lock_guard<std::recursive_mutex> lock(mtx_connectionList); // RAII-style acquire and relinquish via destructor
157  auto end = list.end();
158  for (auto it = list.begin(); it != end; ++it) {
159  HCIConnectionRef e = *it;
160  if ( e->getHandle() == handle ) {
161  list.erase(it);
162  return e; // done
163  }
164  }
165  return nullptr;
166 }
167 
168 void HCIHandler::resetAllStates(const bool powered_on) noexcept {
169  const std::lock_guard<std::recursive_mutex> lock(mtx_connectionList); // RAII-style acquire and relinquish via destructor
170  connectionList.clear();
171  disconnectCmdList.clear();
172  currentScanType = ScanType::NONE;
173  zeroSupCommands();
174  if( powered_on ) {
175  initSupCommands();
176  }
177 }
178 
179 MgmtEvent::Opcode HCIHandler::translate(HCIEventType evt, HCIMetaEventType met) noexcept {
180  if( HCIEventType::LE_META == evt ) {
181  switch( met ) {
183  [[fallthrough]];
186 
187  default:
189  }
190  }
191  switch( evt ) {
196  default: return MgmtEvent::Opcode::INVALID;
197  }
198 }
199 
200 std::unique_ptr<MgmtEvent> HCIHandler::translate(HCIEvent& ev) noexcept {
201  const HCIEventType evt = ev.getEventType();
202  const HCIMetaEventType mevt = ev.getMetaEventType();
203 
204  if( HCIEventType::LE_META == evt ) {
205  switch( mevt ) {
207  HCIStatusCode status;
208  const hci_ev_le_conn_complete * ev_cc = getMetaReplyStruct<hci_ev_le_conn_complete>(ev, mevt, &status);
209  if( nullptr == ev_cc ) {
210  ERR_PRINT("HCIHandler::translate(reader): LE_CONN_COMPLETE: Null reply-struct: %s - %s",
211  ev.toString().c_str(), toString().c_str());
212  return nullptr;
213  }
214  const HCILEPeerAddressType hciAddrType = static_cast<HCILEPeerAddressType>(ev_cc->bdaddr_type);
215  const BDAddressAndType addressAndType(ev_cc->bdaddr, to_BDAddressType(hciAddrType));
216  const uint16_t handle = jau::le_to_cpu(ev_cc->handle);
217  const HCIConnectionRef conn = addOrUpdateTrackerConnection(addressAndType, handle);
218  if( HCIStatusCode::SUCCESS == status ) {
219  return std::make_unique<MgmtEvtDeviceConnected>(dev_id, addressAndType, handle);
220  } else {
221  removeTrackerConnection(conn);
222  return std::make_unique<MgmtEvtDeviceConnectFailed>(dev_id, addressAndType, status);
223  }
224  }
226  HCIStatusCode status;
227  const hci_ev_le_enh_conn_complete * ev_cc = getMetaReplyStruct<hci_ev_le_enh_conn_complete>(ev, mevt, &status);
228  if( nullptr == ev_cc ) {
229  ERR_PRINT("HCIHandler::translate(reader): LE_EXT_CONN_COMPLETE: Null reply-struct: %s - %s",
230  ev.toString().c_str(), toString().c_str());
231  return nullptr;
232  }
233  const HCILEPeerAddressType hciAddrType = static_cast<HCILEPeerAddressType>(ev_cc->bdaddr_type);
234  const BDAddressAndType addressAndType(ev_cc->bdaddr, to_BDAddressType(hciAddrType));
235  const uint16_t handle = jau::le_to_cpu(ev_cc->handle);
236  const HCIConnectionRef conn = addOrUpdateTrackerConnection(addressAndType, handle);
237  if( HCIStatusCode::SUCCESS == status ) {
238  return std::make_unique<MgmtEvtDeviceConnected>(dev_id, addressAndType, handle);
239  } else {
240  removeTrackerConnection(conn);
241  return std::make_unique<MgmtEvtDeviceConnectFailed>(dev_id, addressAndType, status);
242  }
243  }
245  HCIStatusCode status;
246  const hci_ev_le_remote_feat_complete * ev_cc = getMetaReplyStruct<hci_ev_le_remote_feat_complete>(ev, mevt, &status);
247  if( nullptr == ev_cc ) {
248  ERR_PRINT("HCIHandler::translate(reader): LE_REMOTE_FEAT_COMPLETE: Null reply-struct: %s - %s",
249  ev.toString().c_str(), toString().c_str());
250  return nullptr;
251  }
252  const uint16_t handle = jau::le_to_cpu(ev_cc->handle);
253  const LE_Features features = static_cast<LE_Features>(jau::get_uint64(ev_cc->features, 0, true /* littleEndian */));
254  const HCIConnectionRef conn = findTrackerConnection(handle);
255  if( nullptr == conn ) {
256  WARN_PRINT("HCIHandler::translate(reader): LE_REMOTE_FEAT_COMPLETE: Not tracked conn_handle %s",
257  jau::to_hexstring(handle).c_str());
258  return nullptr;
259  }
260  if( HCIStatusCode::SUCCESS != status ) {
261  WARN_PRINT("HCIHandler::translate(reader): LE_REMOTE_FEAT_COMPLETE: Failed: Status %s, Handle %s: %s",
262  to_string(status).c_str(), jau::to_hexstring(handle).c_str(), conn->toString().c_str());
263  return nullptr;
264  }
265  return std::make_unique<MgmtEvtHCILERemoteUserFeatures>(dev_id, conn->getAddressAndType(), features);
266  }
267  default:
268  return nullptr;
269  }
270  }
271  switch( evt ) {
273  HCIStatusCode status;
274  const hci_ev_conn_complete * ev_cc = getReplyStruct<hci_ev_conn_complete>(ev, evt, &status);
275  if( nullptr == ev_cc ) {
276  ERR_PRINT("HCIHandler::translate(reader): CONN_COMPLETE: Null reply-struct: %s - %s",
277  ev.toString().c_str(), toString().c_str());
278  return nullptr;
279  }
280  const BDAddressAndType addressAndType(ev_cc->bdaddr, BDAddressType::BDADDR_BREDR);
281  HCIConnectionRef conn = addOrUpdateTrackerConnection(addressAndType, ev_cc->handle);
282  if( HCIStatusCode::SUCCESS == status ) {
283  return std::make_unique<MgmtEvtDeviceConnected>(dev_id, conn->getAddressAndType(), conn->getHandle());
284  } else {
285  std::unique_ptr<MgmtEvent> res( new MgmtEvtDeviceConnectFailed(dev_id, conn->getAddressAndType(),status) );
286  removeTrackerConnection(conn);
287  return res;
288  }
289  }
291  HCIStatusCode status;
292  const hci_ev_disconn_complete * ev_cc = getReplyStruct<hci_ev_disconn_complete>(ev, evt, &status);
293  if( nullptr == ev_cc ) {
294  ERR_PRINT("HCIHandler::translate(reader): DISCONN_COMPLETE: Null reply-struct: %s - %s",
295  ev.toString().c_str(), toString().c_str());
296  return nullptr;
297  }
298  removeDisconnectCmd(ev_cc->handle);
299  HCIConnectionRef conn = removeTrackerConnection(ev_cc->handle);
300  if( nullptr == conn ) {
301  WORDY_PRINT("HCIHandler::translate(reader): DISCONN_COMPLETE: Not tracked handle %s: %s - %s",
302  jau::to_hexstring(ev_cc->handle).c_str(), ev.toString().c_str(), toString().c_str());
303  return nullptr;
304  } else {
305  if( HCIStatusCode::SUCCESS != status ) {
306  // FIXME: Ever occuring? Still sending out essential disconnect event!
307  ERR_PRINT("HCIHandler::translate(reader): DISCONN_COMPLETE: !SUCCESS[%s, %s], %s: %s - %s",
308  jau::to_hexstring(static_cast<uint8_t>(status)).c_str(), to_string(status).c_str(),
309  conn->toString().c_str(), ev.toString().c_str(), toString().c_str());
310  }
311  const HCIStatusCode hciRootReason = static_cast<HCIStatusCode>(ev_cc->reason);
312  return std::make_unique<MgmtEvtDeviceDisconnected>(dev_id, conn->getAddressAndType(), hciRootReason, conn->getHandle());
313  }
314  }
316  HCIStatusCode status;
317  const hci_ev_encrypt_change * ev_cc = getReplyStruct<hci_ev_encrypt_change>(ev, evt, &status);
318  if( nullptr == ev_cc ) {
319  ERR_PRINT("HCIHandler::translate(reader): ENCRYPT_CHANGE: Null reply-struct: %s - %s",
320  ev.toString().c_str(), toString().c_str());
321  return nullptr;
322  }
323  const uint16_t handle = jau::le_to_cpu(ev_cc->handle);
324  const HCIConnectionRef conn = findTrackerConnection(handle);
325  if( nullptr == conn ) {
326  WARN_PRINT("HCIHandler::translate(reader): ENCRYPT_CHANGE: Not tracked conn_handle %s",
327  jau::to_hexstring(handle).c_str());
328  return nullptr;
329  }
330  return std::make_unique<MgmtEvtHCIEncryptionChanged>(dev_id, conn->getAddressAndType(), status, ev_cc->encrypt);
331  }
333  HCIStatusCode status;
334  const hci_ev_key_refresh_complete * ev_cc = getReplyStruct<hci_ev_key_refresh_complete>(ev, evt, &status);
335  if( nullptr == ev_cc ) {
336  ERR_PRINT("HCIHandler::translate(reader): ENCRYPT_KEY_REFRESH_COMPLETE: Null reply-struct: %s - %s",
337  ev.toString().c_str(), toString().c_str());
338  return nullptr;
339  }
340  const uint16_t handle = jau::le_to_cpu(ev_cc->handle);
341  const HCIConnectionRef conn = findTrackerConnection(handle);
342  if( nullptr == conn ) {
343  WARN_PRINT("HCIHandler::translate(reader): ENCRYPT_KEY_REFRESH_COMPLETE: Not tracked conn_handle %s",
344  jau::to_hexstring(handle).c_str());
345  return nullptr;
346  }
347  return std::make_unique<MgmtEvtHCIEncryptionKeyRefreshComplete>(dev_id, conn->getAddressAndType(), status);
348  }
349  // TODO: AUTH_COMPLETE
350  // 7.7.6 AUTH_COMPLETE 0x06
351 
352  default:
353  return nullptr;
354  }
355 }
356 
357 std::unique_ptr<const SMPPDUMsg> HCIHandler::getSMPPDUMsg(const HCIACLData::l2cap_frame & l2cap, const uint8_t * l2cap_data) const noexcept {
358  if( nullptr != l2cap_data && 0 < l2cap.len && l2cap.isSMP() ) {
359  return SMPPDUMsg::getSpecialized(l2cap_data, l2cap.len);
360  }
361  return nullptr;
362 }
363 
364 void HCIHandler::hciReaderThreadImpl() noexcept {
365  {
366  const std::lock_guard<std::mutex> lock(mtx_hciReaderLifecycle); // RAII-style acquire and relinquish via destructor
367  hciReaderShallStop = false;
368  hciReaderRunning = true;
369  DBG_PRINT("HCIHandler::reader: Started - %s", toString().c_str());
370  cv_hciReaderInit.notify_all();
371  }
372  thread_local jau::call_on_release thread_cleanup([&]() {
373  DBG_PRINT("HCIHandler::hciReaderThreadCleanup: hciReaderRunning %d -> 0", hciReaderRunning.load());
374  hciReaderRunning = false;
375  });
376 
377  while( !hciReaderShallStop ) {
378  jau::snsize_t len;
379  if( !isOpen() ) {
380  // not open
381  ERR_PRINT("HCIHandler::reader: Not connected %s", toString().c_str());
382  hciReaderShallStop = true;
383  break;
384  }
385 
386  len = comm.read(rbuffer.get_wptr(), rbuffer.getSize(), env.HCI_READER_THREAD_POLL_TIMEOUT);
387  if( 0 < len ) {
388  const jau::nsize_t len2 = static_cast<jau::nsize_t>(len);
389  const HCIPacketType pc = static_cast<HCIPacketType>( rbuffer.get_uint8_nc(0) );
390 
391  if( HCIPacketType::ACLDATA == pc ) {
392  std::unique_ptr<HCIACLData> acldata = HCIACLData::getSpecialized(rbuffer.get_ptr(), len2);
393  if( nullptr == acldata ) {
394  // not valid acl-data ...
395  if( jau::environment::get().verbose ) {
396  WARN_PRINT("HCIHandler-IO RECV Drop (non-acl-data) %s - %s",
397  jau::bytesHexString(rbuffer.get_ptr(), 0, len2, true /* lsbFirst*/).c_str(), toString().c_str());
398  }
399  continue;
400  }
401  const uint8_t* l2cap_data = nullptr; // owned by acldata
402  HCIACLData::l2cap_frame l2cap = acldata->getL2CAPFrame(l2cap_data);
403  std::unique_ptr<const SMPPDUMsg> smpPDU = getSMPPDUMsg(l2cap, l2cap_data);
404  if( nullptr != smpPDU ) {
405  HCIConnectionRef conn = findTrackerConnection(l2cap.handle);
406 
407  if( nullptr != conn ) {
408  COND_PRINT(env.DEBUG_EVENT, "HCIHandler-IO RECV (ACL.SMP) %s for %s",
409  smpPDU->toString().c_str(), conn->toString().c_str());
410  jau::for_each_fidelity(hciSMPMsgCallbackList, [&](HCISMPMsgCallback &cb) {
411  cb.invoke(conn->getAddressAndType(), *smpPDU, l2cap);
412  });
413  } else {
414  WARN_PRINT("HCIHandler-IO RECV Drop (ACL.SMP): Not tracked conn_handle %s: %s, %s",
415  jau::to_hexstring(l2cap.handle).c_str(),
416  l2cap.toString().c_str(), smpPDU->toString().c_str());
417  }
418  } else if( !l2cap.isGATT() ) { // ignore handled GATT packages
419  COND_PRINT(env.DEBUG_EVENT, "HCIHandler-IO RECV Drop (ACL.L2CAP): ???? %s", acldata->toString(l2cap, l2cap_data).c_str());
420  }
421  continue;
422  }
423  if( HCIPacketType::EVENT != pc ) {
424  WARN_PRINT("HCIHandler-IO RECV Drop (not event, nor acl-data) %s - %s",
425  jau::bytesHexString(rbuffer.get_ptr(), 0, len2, true /* lsbFirst*/).c_str(), toString().c_str());
426  continue;
427  }
428 
429  // EVENT
430  std::unique_ptr<HCIEvent> event = HCIEvent::getSpecialized(rbuffer.get_ptr(), len2);
431  if( nullptr == event ) {
432  // not a valid event ...
433  ERR_PRINT("HCIHandler-IO RECV Drop (non-event) %s - %s",
434  jau::bytesHexString(rbuffer.get_ptr(), 0, len2, true /* lsbFirst*/).c_str(), toString().c_str());
435  continue;
436  }
437 
438  const HCIMetaEventType mec = event->getMetaEventType();
439  if( HCIMetaEventType::INVALID != mec && !filter_test_metaev(mec) ) {
440  // DROP
441  COND_PRINT(env.DEBUG_EVENT, "HCIHandler-IO RECV Drop (meta filter) %s", event->toString().c_str());
442  continue; // next packet
443  }
444 
445  if( event->isEvent(HCIEventType::CMD_STATUS) || event->isEvent(HCIEventType::CMD_COMPLETE) )
446  {
447  COND_PRINT(env.DEBUG_EVENT, "HCIHandler-IO RECV (CMD) %s", event->toString().c_str());
448  if( hciEventRing.isFull() ) {
449  const jau::nsize_t dropCount = hciEventRing.capacity()/4;
450  hciEventRing.drop(dropCount);
451  WARN_PRINT("HCIHandler-IO RECV Drop (%u oldest elements of %u capacity, ring full) - %s",
452  dropCount, hciEventRing.capacity(), toString().c_str());
453  }
454  hciEventRing.putBlocking( std::move( event ) );
455  } else if( event->isMetaEvent(HCIMetaEventType::LE_ADVERTISING_REPORT) ) {
456  // issue callbacks for the translated AD events
457  jau::darray<std::unique_ptr<EInfoReport>> eirlist = EInfoReport::read_ad_reports(event->getParam(), event->getParamSize());
458  for(jau::nsize_t eircount = 0; eircount < eirlist.size(); ++eircount) {
459  const MgmtEvtDeviceFound e(dev_id, std::move( eirlist[eircount] ) );
460  COND_PRINT(env.DEBUG_SCAN_AD_EIR, "HCIHandler-IO RECV (AD EIR) [%d] %s",
461  eircount, e.getEIR()->toString().c_str());
462  sendMgmtEvent( e );
463  }
464  } else if( event->isMetaEvent(HCIMetaEventType::LE_EXT_ADV_REPORT) ) {
465  // issue callbacks for the translated EAD events
466  jau::darray<std::unique_ptr<EInfoReport>> eirlist = EInfoReport::read_ext_ad_reports(event->getParam(), event->getParamSize());
467  for(jau::nsize_t eircount = 0; eircount < eirlist.size(); ++eircount) {
468  const MgmtEvtDeviceFound e(dev_id, std::move( eirlist[eircount] ) );
469  COND_PRINT(env.DEBUG_SCAN_AD_EIR, "HCIHandler-IO RECV (EAD EIR (ext)) [%d] %s",
470  eircount, e.getEIR()->toString().c_str());
471  sendMgmtEvent( e );
472  }
473  } else {
474  // issue a callback for the translated event
475  std::unique_ptr<MgmtEvent> mevent = translate(*event);
476  if( nullptr != mevent ) {
477  COND_PRINT(env.DEBUG_EVENT, "HCIHandler-IO RECV (CB) %s", event->toString().c_str());
478  sendMgmtEvent( *mevent );
479  } else {
480  COND_PRINT(env.DEBUG_EVENT, "HCIHandler-IO RECV Drop (no translation) %s", event->toString().c_str());
481  }
482  }
483  } else if( ETIMEDOUT != errno && !hciReaderShallStop ) { // expected exits
484  ERR_PRINT("HCIHandler::reader: HCIComm read error %s", toString().c_str());
485  }
486  }
487  {
488  const std::lock_guard<std::mutex> lock(mtx_hciReaderLifecycle); // RAII-style acquire and relinquish via destructor
489  WORDY_PRINT("HCIHandler::reader: Ended. Ring has %u entries flushed - %s", hciEventRing.getSize(), toString().c_str());
490  hciEventRing.clear();
491  hciReaderRunning = false;
492  cv_hciReaderInit.notify_all();
493  }
494 }
495 
496 void HCIHandler::sendMgmtEvent(const MgmtEvent& event) noexcept {
497  MgmtEventCallbackList & mgmtEventCallbackList = mgmtEventCallbackLists[static_cast<uint16_t>(event.getOpcode())];
498  int invokeCount = 0;
499 
500  jau::for_each_fidelity(mgmtEventCallbackList, [&](MgmtEventCallback &cb) {
501  try {
502  cb.invoke(event);
503  } catch (std::exception &e) {
504  ERR_PRINT("HCIHandler::sendMgmtEvent-CBs %d/%zd: MgmtEventCallback %s : Caught exception %s - %s",
505  invokeCount+1, mgmtEventCallbackList.size(),
506  cb.toString().c_str(), e.what(), toString().c_str());
507  }
508  invokeCount++;
509  });
510 
511  COND_PRINT(env.DEBUG_EVENT, "HCIHandler::sendMgmtEvent: Event %s -> %d/%zd callbacks", event.toString().c_str(), invokeCount, mgmtEventCallbackList.size());
512  (void)invokeCount;
513 }
514 
515 bool HCIHandler::sendCommand(HCICommand &req) noexcept {
516  COND_PRINT(env.DEBUG_EVENT, "HCIHandler-IO SENT %s", req.toString().c_str());
517 
518  TROOctets & pdu = req.getPDU();
519  if ( comm.write( pdu.get_ptr(), pdu.getSize() ) < 0 ) {
520  ERR_PRINT("HCIHandler::sendCommand: HCIComm write error, req %s - %s", req.toString().c_str(), toString().c_str());
521  return false;
522  }
523  return true;
524 }
525 
526 std::unique_ptr<HCIEvent> HCIHandler::getNextReply(HCICommand &req, int32_t & retryCount, const int32_t replyTimeoutMS) noexcept
527 {
528  // Ringbuffer read is thread safe
529  while( retryCount < env.HCI_READ_PACKET_MAX_RETRY ) {
530  std::unique_ptr<HCIEvent> ev = hciEventRing.getBlocking(replyTimeoutMS);
531  if( nullptr == ev ) {
532  errno = ETIMEDOUT;
533  ERR_PRINT("HCIHandler::getNextReply: nullptr result (timeout %d ms -> abort): req %s - %s",
534  replyTimeoutMS, req.toString().c_str(), toString().c_str());
535  return nullptr;
536  } else if( !ev->validate(req) ) {
537  // This could occur due to an earlier timeout w/ a nullptr == res (see above),
538  // i.e. the pending reply processed here and naturally not-matching.
539  retryCount++;
540  COND_PRINT(env.DEBUG_EVENT, "HCIHandler-IO RECV getNextReply: res mismatch (drop, retry %d): res %s; req %s",
541  retryCount, ev->toString().c_str(), req.toString().c_str());
542  } else {
543  COND_PRINT(env.DEBUG_EVENT, "HCIHandler-IO RECV getNextReply: res %s; req %s", ev->toString().c_str(), req.toString().c_str());
544  return ev;
545  }
546  }
547  return nullptr;
548 }
549 
550 std::unique_ptr<HCIEvent> HCIHandler::getNextCmdCompleteReply(HCICommand &req, HCICommandCompleteEvent **res) noexcept {
551  const std::lock_guard<std::recursive_mutex> lock(mtx_sendReply); // RAII-style acquire and relinquish via destructor
552 
553  *res = nullptr;
554 
555  int32_t retryCount = 0;
556  std::unique_ptr<HCIEvent> ev = nullptr;
557 
558  while( retryCount < env.HCI_READ_PACKET_MAX_RETRY ) {
559  ev = getNextReply(req, retryCount, env.HCI_COMMAND_COMPLETE_REPLY_TIMEOUT);
560  if( nullptr == ev ) {
561  break; // timeout, leave loop
562  } else if( ev->isEvent(HCIEventType::CMD_COMPLETE) ) {
563  // gotcha, leave loop
564  *res = static_cast<HCICommandCompleteEvent*>(ev.get());
565  break;
566  } else if( ev->isEvent(HCIEventType::CMD_STATUS) ) {
567  // pending command .. wait for result
568  HCICommandStatusEvent * ev_cs = static_cast<HCICommandStatusEvent*>(ev.get());
569  HCIStatusCode status = ev_cs->getStatus();
570  if( HCIStatusCode::SUCCESS != status ) {
571  WARN_PRINT("HCIHandler::getNextCmdCompleteReply: CMD_STATUS 0x%2.2X (%s), errno %d %s: res %s, req %s - %s",
572  number(status), to_string(status).c_str(), errno, strerror(errno),
573  ev_cs->toString().c_str(), req.toString().c_str(), toString().c_str());
574  break; // error status, leave loop
575  } else {
576  DBG_PRINT("HCIHandler::getNextCmdCompleteReply: CMD_STATUS 0x%2.2X (%s, retryCount %d), errno %d %s: res %s, req %s - %s",
577  number(status), to_string(status).c_str(), retryCount, errno, strerror(errno),
578  ev_cs->toString().c_str(), req.toString().c_str(), toString().c_str());
579  }
580  retryCount++;
581  continue; // next packet
582  } else {
583  retryCount++;
584  DBG_PRINT("HCIHandler::getNextCmdCompleteReply: !(CMD_COMPLETE, CMD_STATUS) (drop, retry %d): res %s; req %s - %s",
585  retryCount, ev->toString().c_str(), req.toString().c_str(), toString().c_str());
586  continue; // next packet
587  }
588  }
589  return ev;
590 }
591 
592 HCIHandler::HCIHandler(const uint16_t dev_id_, const BTMode btMode_) noexcept
593 : env(HCIEnv::get()),
594  dev_id(dev_id_),
595  rbuffer(HCI_MAX_MTU),
596  comm(dev_id_, HCI_CHANNEL_RAW),
597  hciEventRing(nullptr, env.HCI_EVT_RING_CAPACITY), hciReaderShallStop(false),
598  hciReaderThreadId(0), hciReaderRunning(false),
599  allowClose( comm.isOpen() ),
600  btMode(btMode_),
601  currentScanType(ScanType::NONE)
602 {
603  WORDY_PRINT("HCIHandler.ctor: Start pid %d - %s", HCIHandler::pidSelf, toString().c_str());
604  if( !allowClose ) {
605  ERR_PRINT("HCIHandler::ctor: Could not open hci control channel %s", toString().c_str());
606  return;
607  }
608 
609  {
610  std::unique_lock<std::mutex> lock(mtx_hciReaderLifecycle); // RAII-style acquire and relinquish via destructor
611 
612  std::thread hciReaderThread(&HCIHandler::hciReaderThreadImpl, this); // @suppress("Invalid arguments")
613  hciReaderThreadId = hciReaderThread.native_handle();
614  // Avoid 'terminate called without an active exception'
615  // as hciReaderThreadImpl may end due to I/O errors.
616  hciReaderThread.detach();
617 
618  while( false == hciReaderRunning ) {
619  cv_hciReaderInit.wait(lock);
620  }
621  }
622 
623  PERF_TS_T0();
624 
625 #if 0
626  {
627  int opt = 1;
628  if (setsockopt(comm.getSocketDescriptor(), SOL_SOCKET, SO_TIMESTAMP, &opt, sizeof(opt)) < 0) {
629  ERR_PRINT("HCIHandler::ctor: setsockopt SO_TIMESTAMP %s", toString().c_str());
630  goto fail;
631  }
632 
633  if (setsockopt(comm.getSocketDescriptor(), SOL_SOCKET, SO_PASSCRED, &opt, sizeof(opt)) < 0) {
634  ERR_PRINT("HCIHandler::ctor: setsockopt SO_PASSCRED %s", toString().c_str());
635  goto fail;
636  }
637  }
638 #endif
639 
640 #define FILTER_ALL_EVENTS 0
641 
642  // Mandatory socket filter (not adapter filter!)
643  {
644 #if 0
645  // No use for pre-existing hci_ufilter
646  hci_ufilter of;
647  socklen_t olen;
648 
649  olen = sizeof(of);
650  if (getsockopt(comm.getSocketDescriptor(), SOL_HCI, HCI_FILTER, &of, &olen) < 0) {
651  ERR_PRINT("HCIHandler::ctor: getsockopt %s", toString().c_str());
652  goto fail;
653  }
654 #endif
655  HCIComm::filter_clear(&filter_mask);
656  // HCIComm::filter_set_ptype(number(HCIPacketType::COMMAND), &filter_mask); // COMMANDs
657  HCIComm::filter_set_ptype(number(HCIPacketType::EVENT), &filter_mask); // EVENTs
658  HCIComm::filter_set_ptype(number(HCIPacketType::ACLDATA), &filter_mask); // SMP via ACL DATA
659 
660  // Setup generic filter mask for all events, this is also required for
661 #if FILTER_ALL_EVENTS
662  HCIComm::filter_all_events(&filter_mask); // all events
663 #else
672  // HCIComm::filter_set_event(number(HCIEventType::IO_CAPABILITY_REQUEST), &filter_mask);
673  // HCIComm::filter_set_event(number(HCIEventType::IO_CAPABILITY_RESPONSE), &filter_mask);
675  // HCIComm::filter_set_event(number(HCIEventType::DISCONN_PHY_LINK_COMPLETE), &filter_mask);
676  // HCIComm::filter_set_event(number(HCIEventType::DISCONN_LOGICAL_LINK_COMPLETE), &filter_mask);
677 #endif
678  HCIComm::filter_set_opcode(0, &filter_mask); // all opcode
679 
680  if (setsockopt(comm.getSocketDescriptor(), SOL_HCI, HCI_FILTER, &filter_mask, sizeof(filter_mask)) < 0) {
681  ERR_PRINT("HCIHandler::ctor: setsockopt HCI_FILTER %s", toString().c_str());
682  goto fail;
683  }
684  }
685  // Mandatory own LE_META filter
686  {
687  uint32_t mask = 0;
688 #if FILTER_ALL_EVENTS
689  filter_all_metaevs(mask);
690 #else
691  filter_set_metaev(HCIMetaEventType::LE_CONN_COMPLETE, mask);
692  filter_set_metaev(HCIMetaEventType::LE_ADVERTISING_REPORT, mask);
693  filter_set_metaev(HCIMetaEventType::LE_REMOTE_FEAT_COMPLETE, mask);
694  filter_set_metaev(HCIMetaEventType::LE_EXT_CONN_COMPLETE, mask);
695  filter_set_metaev(HCIMetaEventType::LE_EXT_ADV_REPORT, mask);
696  filter_set_metaev(HCIMetaEventType::LE_CHANNEL_SEL_ALGO, mask);
697 #endif
698  filter_put_metaevs(mask);
699  }
700  // Mandatory own HCIOpcodeBit/HCIOpcode filter
701  {
702  uint64_t mask = 0;
703 #if FILTER_ALL_EVENTS
704  filter_all_opcbit(mask);
705 #else
706  filter_set_opcbit(HCIOpcodeBit::CREATE_CONN, mask);
707  filter_set_opcbit(HCIOpcodeBit::DISCONNECT, mask);
708  // filter_set_opcbit(HCIOpcodeBit::IO_CAPABILITY_REQ_REPLY, mask);
709  // filter_set_opcbit(HCIOpcodeBit::IO_CAPABILITY_REQ_NEG_REPLY, mask);
710  filter_set_opcbit(HCIOpcodeBit::RESET, mask);
711  filter_set_opcbit(HCIOpcodeBit::READ_LOCAL_VERSION, mask);
712  filter_set_opcbit(HCIOpcodeBit::READ_LOCAL_COMMANDS, mask);
713  filter_set_opcbit(HCIOpcodeBit::LE_SET_SCAN_PARAM, mask);
714  filter_set_opcbit(HCIOpcodeBit::LE_SET_SCAN_ENABLE, mask);
715  filter_set_opcbit(HCIOpcodeBit::LE_CREATE_CONN, mask);
716  filter_set_opcbit(HCIOpcodeBit::LE_ENABLE_ENC, mask);
717  filter_set_opcbit(HCIOpcodeBit::LE_READ_PHY, mask);
718  // filter_set_opcbit(HCIOpcodeBit::LE_SET_DEFAULT_PHY, mask);
719  filter_set_opcbit(HCIOpcodeBit::LE_SET_EXT_SCAN_PARAMS, mask);
720  filter_set_opcbit(HCIOpcodeBit::LE_SET_EXT_SCAN_ENABLE, mask);
721  filter_set_opcbit(HCIOpcodeBit::LE_EXT_CREATE_CONN, mask);
722 #endif
723  filter_put_opcbit(mask);
724  }
725 
726  sup_commands_set = false;
727  initSupCommands(); // OK to fail
728 
729  PERF_TS_TD("HCIHandler::ctor.ok");
730  WORDY_PRINT("HCIHandler.ctor: End OK - %s", toString().c_str());
731  return;
732 
733 fail:
734  close();
735  PERF_TS_TD("HCIHandler::ctor.fail");
736  WORDY_PRINT("HCIHandler.ctor: End failure - %s", toString().c_str());
737  return;
738 }
739 
740 void HCIHandler::zeroSupCommands() noexcept {
741  bzero(sup_commands, sizeof(sup_commands));
742  sup_commands_set = false;
743 }
744 bool HCIHandler::initSupCommands() noexcept {
745  // We avoid using a lock or an atomic-switch as we rely on sensible calls.
746  if( !isOpen() ) {
747  zeroSupCommands();
748  return false;
749  }
751  const hci_rp_read_local_commands * ev_cmds;
752  HCIStatusCode status;
753  std::unique_ptr<HCIEvent> ev = processCommandComplete(req0, &ev_cmds, &status);
754  if( nullptr == ev || nullptr == ev_cmds || HCIStatusCode::SUCCESS != status ) {
755  DBG_PRINT("HCIHandler::ctor: READ_LOCAL_COMMANDS: 0x%x (%s) - %s",
756  number(status), to_string(status).c_str(), toString().c_str());
757  zeroSupCommands();
758  return false;
759  } else {
760  memcpy(sup_commands, ev_cmds->commands, sizeof(sup_commands));
761  sup_commands_set = true;
762  return true;
763  }
764 }
765 
766 void HCIHandler::close() noexcept {
767  // Avoid disconnect re-entry -> potential deadlock
768  bool expConn = true; // C++11, exp as value since C++20
769  if( !allowClose.compare_exchange_strong(expConn, false) ) {
770  // not open
771  DBG_PRINT("HCIHandler::close: Not connected %s", toString().c_str());
773  resetAllStates(false);
774  comm.close();
775  return;
776  }
777  PERF_TS_T0();
778  const std::lock_guard<std::recursive_mutex> lock(mtx_sendReply); // RAII-style acquire and relinquish via destructor
779  DBG_PRINT("HCIHandler::close: Start %s", toString().c_str());
781  resetAllStates(false);
782 
783  // Interrupt HCIHandler's HCIComm::read(..), avoiding prolonged hang
784  // and pull all underlying hci read operations!
785  comm.close();
786 
787  PERF_TS_TD("HCIHandler::close.1");
788  {
789  std::unique_lock<std::mutex> lockReader(mtx_hciReaderLifecycle); // RAII-style acquire and relinquish via destructor
790  const pthread_t tid_self = pthread_self();
791  const pthread_t tid_reader = hciReaderThreadId;
792  hciReaderThreadId = 0;
793  const bool is_reader = tid_reader == tid_self;
794  DBG_PRINT("HCIHandler::close: hciReader[running %d, shallStop %d, isReader %d, tid %p) - %s",
795  hciReaderRunning.load(), hciReaderShallStop.load(), is_reader, (void*)tid_reader, toString().c_str());
796  if( hciReaderRunning ) {
797  hciReaderShallStop = true;
798  if( !is_reader && 0 != tid_reader ) {
799  int kerr;
800  if( 0 != ( kerr = pthread_kill(tid_reader, SIGALRM) ) ) {
801  ERR_PRINT("HCIHandler::close: pthread_kill %p FAILED: %d - %s", (void*)tid_reader, kerr, toString().c_str());
802  }
803  }
804  // Ensure the reader thread has ended, no runaway-thread using *this instance after destruction
805  while( true == hciReaderRunning ) {
806  cv_hciReaderInit.wait(lockReader);
807  }
808  }
809  }
810  PERF_TS_TD("HCIHandler::close.X");
811  DBG_PRINT("HCIHandler::close: End %s", toString().c_str());
812 }
813 
814 std::string HCIHandler::toString() const noexcept {
815  return "HCIHandler[dev_id "+std::to_string(dev_id)+", BTMode "+to_string(btMode)+", open "+std::to_string(isOpen())+
816  ", scan "+to_string(currentScanType)+
817  ", ext[init "+std::to_string(sup_commands_set)+", scan "+std::to_string(use_ext_scan())+", conn "+std::to_string(use_ext_conn())+
818  "], ring[entries "+std::to_string(hciEventRing.getSize())+"]]";
819 }
820 
822  if( !isOpen() ) {
823  ERR_PRINT("HCIHandler::startAdapter: Not connected %s", toString().c_str());
825  }
826  const std::lock_guard<std::recursive_mutex> lock(mtx_sendReply); // RAII-style acquire and relinquish via destructor
827  #ifdef __linux__
828  int res;
829  if( ( res = ioctl(comm.getSocketDescriptor(), HCIDEVUP, dev_id) ) < 0 ) {
830  if (errno != EALREADY) {
831  ERR_PRINT("HCIHandler::startAdapter(dev_id %d): FAILED: %d - %s", dev_id, res, toString().c_str());
833  }
834  }
835  resetAllStates(true);
836  return HCIStatusCode::SUCCESS;
837  #else
838  #warning add implementation
839  #endif
841 }
842 
844  if( !isOpen() ) {
845  ERR_PRINT("HCIHandler::stopAdapter: Not connected %s", toString().c_str());
847  }
848  const std::lock_guard<std::recursive_mutex> lock(mtx_sendReply); // RAII-style acquire and relinquish via destructor
849  HCIStatusCode status;
850  #ifdef __linux__
851  int res;
852  if( ( res = ioctl(comm.getSocketDescriptor(), HCIDEVDOWN, dev_id) ) < 0) {
853  ERR_PRINT("HCIHandler::stopAdapter(dev_id %d): FAILED: %d - %s", dev_id, res, toString().c_str());
855  } else {
856  status = HCIStatusCode::SUCCESS;
857  }
858  #else
859  #warning add implementation
861  #endif
862  if( HCIStatusCode::SUCCESS == status ) {
863  resetAllStates(false);
864  }
865  return status;
866 }
867 
869  if( !isOpen() ) {
870  ERR_PRINT("HCIHandler::resetAdapter: Not connected %s", toString().c_str());
872  }
873  const std::lock_guard<std::recursive_mutex> lock(mtx_sendReply); // RAII-style acquire and relinquish via destructor
874  #ifdef __linux__
876  return HCIStatusCode::SUCCESS;
877  }
878  #else
879  #warning add implementation
880  #endif
882 }
883 
885  if( !isOpen() ) {
886  ERR_PRINT("HCIHandler::reset: Not connected %s", toString().c_str());
888  }
889  const std::lock_guard<std::recursive_mutex> lock(mtx_sendReply); // RAII-style acquire and relinquish via destructor
890  HCICommand req0(HCIOpcode::RESET, 0);
891 
892  const hci_rp_status * ev_status;
893  HCIStatusCode status;
894  std::unique_ptr<HCIEvent> ev = processCommandComplete(req0, &ev_status, &status);
895  if( nullptr == ev ) {
896  return HCIStatusCode::INTERNAL_TIMEOUT; // timeout
897  }
898  if( HCIStatusCode::SUCCESS == status ) {
899  resetAllStates(true);
900  }
901  return status;
902 }
903 
905  if( !isOpen() ) {
906  ERR_PRINT("HCIHandler::getLocalVersion: Not connected %s", toString().c_str());
908  }
910  const hci_rp_read_local_version * ev_lv;
911  HCIStatusCode status;
912  std::unique_ptr<HCIEvent> ev = processCommandComplete(req0, &ev_lv, &status);
913  if( nullptr == ev || nullptr == ev_lv || HCIStatusCode::SUCCESS != status ) {
914  ERR_PRINT("HCIHandler::getLocalVersion: READ_LOCAL_VERSION: 0x%x (%s) - %s",
915  number(status), to_string(status).c_str(), toString().c_str());
916  bzero(&version, sizeof(version));
917  } else {
918  version.hci_ver = ev_lv->hci_ver;
919  version.hci_rev = jau::le_to_cpu(ev_lv->hci_rev);
920  version.manufacturer = jau::le_to_cpu(ev_lv->manufacturer);
921  version.lmp_ver = ev_lv->lmp_ver;
922  version.lmp_subver = jau::le_to_cpu(ev_lv->lmp_subver);
923  }
924  return status;
925 }
926 
928  if( !isOpen() ) {
929  ERR_PRINT("HCIHandler::le_read_local_features: Not connected %s", toString().c_str());
931  }
932  res = LE_Features::NONE;
934  const hci_rp_le_read_local_features * ev_lf;
935  HCIStatusCode status;
936  std::unique_ptr<HCIEvent> ev = processCommandComplete(req0, &ev_lf, &status);
937  if( nullptr == ev || nullptr == ev_lf || HCIStatusCode::SUCCESS != status ) {
938  ERR_PRINT("HCIHandler::le_read_local_features: LE_READ_LOCAL_FEATURES: 0x%x (%s) - %s",
939  number(status), to_string(status).c_str(), toString().c_str());
940  } else {
941  res = static_cast<LE_Features>( jau::get_uint64(ev_lf->features, 0, true /* littleEndian */) );
942  }
943  return status;
944 }
945 
947  const HCILEOwnAddressType own_mac_type,
948  const uint16_t le_scan_interval, const uint16_t le_scan_window,
949  const uint8_t filter_policy) noexcept {
950  if( !isOpen() ) {
951  ERR_PRINT("HCIHandler::le_set_scan_param: Not connected %s", toString().c_str());
953  }
954  if( hasScanType(currentScanType, ScanType::LE) ) {
955  WARN_PRINT("HCIHandler::le_set_scan_param: Not allowed: LE Scan Enabled: %s - tried scan [interval %.3f ms, window %.3f ms]",
956  toString().c_str(), 0.625f * (float)le_scan_interval, 0.625f * (float)le_scan_window);
958  }
959  DBG_PRINT("HCI Scan Param: scan [active %d, interval %.3f ms, window %.3f ms, filter %d] - %s",
961  0.625f * (float)le_scan_interval, 0.625f * (float)le_scan_window,
962  filter_policy, toString().c_str());
963 
964  HCIStatusCode status;
965  if( use_ext_scan() ) {
966  struct le_set_ext_scan_params {
967  __u8 own_address_type;
969  __u8 scanning_phys;
970  hci_cp_le_scan_phy_params p1;
971  // hci_cp_le_scan_phy_params p2;
972  } __packed;
974  le_set_ext_scan_params * cp = req0.getWStruct();
975  cp->own_address_type = static_cast<uint8_t>(own_mac_type);
976  cp->filter_policy = filter_policy;
977  cp->scanning_phys = direct_bt::number(LE_PHYs::LE_1M); // TODO: Support LM_CODED?
978 
979  cp->p1.type = le_scan_active ? LE_SCAN_ACTIVE : LE_SCAN_PASSIVE;
980  cp->p1.interval = jau::cpu_to_le(le_scan_interval);
981  cp->p1.window = jau::cpu_to_le(le_scan_window);
982  // TODO: Support LE_1M + LE_CODED combo?
983 
984  const hci_rp_status * ev_status;
985  std::unique_ptr<HCIEvent> ev = processCommandComplete(req0, &ev_status, &status);
986  } else {
988  hci_cp_le_set_scan_param * cp = req0.getWStruct();
989  cp->type = le_scan_active ? LE_SCAN_ACTIVE : LE_SCAN_PASSIVE;
990  cp->interval = jau::cpu_to_le(le_scan_interval);
991  cp->window = jau::cpu_to_le(le_scan_window);
992  cp->own_address_type = static_cast<uint8_t>(own_mac_type);
993  cp->filter_policy = filter_policy;
994 
995  const hci_rp_status * ev_status;
996  std::unique_ptr<HCIEvent> ev = processCommandComplete(req0, &ev_status, &status);
997  }
998  return status;
999 }
1000 
1001 HCIStatusCode HCIHandler::le_enable_scan(const bool enable, const bool filter_dup) noexcept {
1002  if( !isOpen() ) {
1003  ERR_PRINT("HCIHandler::le_enable_scan: Not connected %s", toString().c_str());
1005  }
1006  const std::lock_guard<std::recursive_mutex> lock(mtx_sendReply); // RAII-style acquire and relinquish via destructor
1007 
1008  ScanType nextScanType = changeScanType(currentScanType, ScanType::LE, enable);
1009  DBG_PRINT("HCI Enable Scan: enable %s -> %s, filter_dup %d - %s",
1010  to_string(currentScanType).c_str(), to_string(nextScanType).c_str(), filter_dup, toString().c_str());
1011 
1012  HCIStatusCode status;
1013  if( currentScanType != nextScanType ) {
1014  if( use_ext_scan() ) {
1016  hci_cp_le_set_ext_scan_enable * cp = req0.getWStruct();
1017  cp->enable = enable ? LE_SCAN_ENABLE : LE_SCAN_DISABLE;
1018  cp->filter_dup = filter_dup ? LE_SCAN_FILTER_DUP_ENABLE : LE_SCAN_FILTER_DUP_DISABLE;
1019  // cp->duration = 0; // until disabled
1020  // cp->period = 0; // until disabled
1021  const hci_rp_status * ev_status;
1022  std::unique_ptr<HCIEvent> evComplete = processCommandComplete(req0, &ev_status, &status);
1023  } else {
1025  hci_cp_le_set_scan_enable * cp = req0.getWStruct();
1026  cp->enable = enable ? LE_SCAN_ENABLE : LE_SCAN_DISABLE;
1027  cp->filter_dup = filter_dup ? LE_SCAN_FILTER_DUP_ENABLE : LE_SCAN_FILTER_DUP_DISABLE;
1028  const hci_rp_status * ev_status;
1029  std::unique_ptr<HCIEvent> evComplete = processCommandComplete(req0, &ev_status, &status);
1030  }
1031  } else {
1032  status = HCIStatusCode::SUCCESS;
1033  WARN_PRINT("HCI Enable Scan: current %s == next %s, OK, skip command - %s",
1034  to_string(currentScanType).c_str(), to_string(nextScanType).c_str(), toString().c_str());
1035  }
1036 
1037  if( HCIStatusCode::SUCCESS == status ) {
1038  currentScanType = nextScanType;
1039  const MgmtEvtDiscovering e(dev_id, ScanType::LE, enable);
1040  sendMgmtEvent( e );
1041  }
1042  return status;
1043 }
1044 
1046  const bool le_scan_active,
1047  const HCILEOwnAddressType own_mac_type,
1048  const uint16_t le_scan_interval, const uint16_t le_scan_window,
1049  const uint8_t filter_policy) noexcept {
1050  if( !isOpen() ) {
1051  ERR_PRINT("HCIHandler::le_start_scan: Not connected %s", toString().c_str());
1053  }
1054  const std::lock_guard<std::recursive_mutex> lock(mtx_sendReply); // RAII-style acquire and relinquish via destructor
1055 
1056  if( hasScanType(currentScanType, ScanType::LE) ) {
1057  WARN_PRINT("HCIHandler::le_start_scan: Not allowed: LE Scan Enabled: %s", toString().c_str());
1059  }
1060  HCIStatusCode status = le_set_scan_param(le_scan_active, own_mac_type, le_scan_interval, le_scan_window, filter_policy);
1061  if( HCIStatusCode::SUCCESS != status ) {
1062  WARN_PRINT("HCIHandler::le_start_scan: le_set_scan_param failed: %s - %s",
1063  to_string(status).c_str(), toString().c_str());
1064  } else {
1065  status = le_enable_scan(true /* enable */, filter_dup);
1066  if( HCIStatusCode::SUCCESS != status ) {
1067  WARN_PRINT("HCIHandler::le_start_scan: le_enable_scan failed: %s - %s",
1068  to_string(status).c_str(), toString().c_str());
1069  }
1070  }
1071  return status;
1072 }
1073 
1075  const HCILEPeerAddressType peer_mac_type,
1076  const HCILEOwnAddressType own_mac_type,
1077  const uint16_t le_scan_interval, const uint16_t le_scan_window,
1078  const uint16_t conn_interval_min, const uint16_t conn_interval_max,
1079  const uint16_t conn_latency, const uint16_t supervision_timeout) noexcept {
1080  /**
1081  * As we rely on consistent 'pending tracker connections',
1082  * i.e. avoid a race condition on issuing connections via this command,
1083  * we need to synchronize this method.
1084  */
1085  const std::lock_guard<std::mutex> lock(mtx_connect_cmd); // RAII-style acquire and relinquish via destructor
1086 
1087  if( !isOpen() ) {
1088  ERR_PRINT("HCIHandler::le_create_conn: Not connected %s", toString().c_str());
1090  }
1091 
1092  const uint16_t min_ce_length = 0x0000;
1093  const uint16_t max_ce_length = 0x0000;
1094  const uint8_t initiator_filter = 0x00; // whitelist not used but peer_bdaddr*
1095 
1096  DBG_PRINT("HCI Conn Param: scan [interval %.3f ms, window %.3f ms]", 0.625f *
1097  (float)le_scan_interval, 0.625f * (float)le_scan_window);
1098  DBG_PRINT("HCI Conn Param: conn [interval [%.3f ms - %.3f ms], latency %d, sup_timeout %d ms] - %s",
1099  1.25f * (float)conn_interval_min, 1.25f * (float)conn_interval_max,
1100  conn_latency, supervision_timeout*10, toString().c_str());
1101 
1102  int pendingConnections = countPendingTrackerConnections();
1103  if( 0 < pendingConnections ) {
1104  DBG_PRINT("HCIHandler::le_create_conn: %d connections pending - %s", pendingConnections, toString().c_str());
1105  int32_t td = 0;
1106  while( env.HCI_COMMAND_COMPLETE_REPLY_TIMEOUT > td && 0 < pendingConnections ) {
1107  std::this_thread::sleep_for(std::chrono::milliseconds(env.HCI_COMMAND_POLL_PERIOD));
1108  td += env.HCI_COMMAND_POLL_PERIOD;
1109  pendingConnections = countPendingTrackerConnections();
1110  }
1111  if( 0 < pendingConnections ) {
1112  WARN_PRINT("HCIHandler::le_create_conn: %d connections pending after %d ms - %s", pendingConnections, td, toString().c_str());
1113  } else {
1114  DBG_PRINT("HCIHandler::le_create_conn: pending connections resolved after %d ms - %s", td, toString().c_str());
1115  }
1116  }
1117  const BDAddressAndType addressAndType(peer_bdaddr, to_BDAddressType(peer_mac_type));
1118  HCIConnectionRef disconn = findDisconnectCmd(addressAndType);
1119  if( nullptr != disconn ) {
1120  DBG_PRINT("HCIHandler::le_create_conn: disconnect pending %s - %s",
1121  disconn->toString().c_str(), toString().c_str());
1122  int32_t td = 0;
1123  while( env.HCI_COMMAND_COMPLETE_REPLY_TIMEOUT > td && nullptr != disconn ) {
1124  std::this_thread::sleep_for(std::chrono::milliseconds(env.HCI_COMMAND_POLL_PERIOD));
1125  td += env.HCI_COMMAND_POLL_PERIOD;
1126  disconn = findDisconnectCmd(addressAndType);
1127  }
1128  if( nullptr != disconn ) {
1129  WARN_PRINT("HCIHandler::le_create_conn: disconnect persisting after %d ms: %s - %s",
1130  td, disconn->toString().c_str(), toString().c_str());
1131  } else {
1132  DBG_PRINT("HCIHandler::le_create_conn: disconnect resolved after %d ms - %s", td, toString().c_str());
1133  }
1134  }
1135  HCIConnectionRef conn = addOrUpdateTrackerConnection(addressAndType, 0);
1136  HCIStatusCode status;
1137 
1138  if( use_ext_conn() ) {
1139  struct le_ext_create_conn {
1141  __u8 own_address_type;
1142  __u8 peer_addr_type;
1143  bdaddr_t peer_addr;
1144  __u8 phys;
1145  hci_cp_le_ext_conn_param p1;
1146  // hci_cp_le_ext_conn_param p2;
1147  // hci_cp_le_ext_conn_param p3;
1148  } __packed;
1150  le_ext_create_conn * cp = req0.getWStruct();
1151  cp->filter_policy = initiator_filter;
1152  cp->own_address_type = static_cast<uint8_t>(own_mac_type);
1153  cp->peer_addr_type = static_cast<uint8_t>(peer_mac_type);
1154  cp->peer_addr = peer_bdaddr;
1155  cp->phys = direct_bt::number(LE_PHYs::LE_1M); // TODO: Support other PHYs?
1156 
1157  cp->p1.scan_interval = jau::cpu_to_le(le_scan_interval);
1158  cp->p1.scan_window = jau::cpu_to_le(le_scan_window);
1159  cp->p1.conn_interval_min = jau::cpu_to_le(conn_interval_min);
1160  cp->p1.conn_interval_max = jau::cpu_to_le(conn_interval_max);
1161  cp->p1.conn_latency = jau::cpu_to_le(conn_latency);
1162  cp->p1.supervision_timeout = jau::cpu_to_le(supervision_timeout);
1163  cp->p1.min_ce_len = jau::cpu_to_le(min_ce_length);
1164  cp->p1.max_ce_len = jau::cpu_to_le(max_ce_length);
1165  // TODO: Support some PHYs combo settings?
1166 
1167  std::unique_ptr<HCIEvent> ev = processCommandStatus(req0, &status);
1168  // Events on successful connection:
1169  // - HCI_LE_Enhanced_Connection_Complete
1170  // - HCI_LE_Channel_Selection_Algorithm
1171  } else {
1173  hci_cp_le_create_conn * cp = req0.getWStruct();
1174  cp->scan_interval = jau::cpu_to_le(le_scan_interval);
1175  cp->scan_window = jau::cpu_to_le(le_scan_window);
1176  cp->filter_policy = initiator_filter;
1177  cp->peer_addr_type = static_cast<uint8_t>(peer_mac_type);
1178  cp->peer_addr = peer_bdaddr;
1179  cp->own_address_type = static_cast<uint8_t>(own_mac_type);
1180  cp->conn_interval_min = jau::cpu_to_le(conn_interval_min);
1181  cp->conn_interval_max = jau::cpu_to_le(conn_interval_max);
1182  cp->conn_latency = jau::cpu_to_le(conn_latency);
1183  cp->supervision_timeout = jau::cpu_to_le(supervision_timeout);
1184  cp->min_ce_len = jau::cpu_to_le(min_ce_length);
1185  cp->max_ce_len = jau::cpu_to_le(max_ce_length);
1186 
1187  std::unique_ptr<HCIEvent> ev = processCommandStatus(req0, &status);
1188  // Events on successful connection:
1189  // - HCI_LE_Connection_Complete
1190  }
1191  if( HCIStatusCode::SUCCESS != status ) {
1192  removeTrackerConnection(conn);
1193 
1195  const std::string s0 = nullptr != disconn ? disconn->toString() : "null";
1196  WARN_PRINT("HCIHandler::le_create_conn: %s: disconnect pending: %s - %s",
1197  to_string(status).c_str(), s0.c_str(), toString().c_str());
1198  }
1199  }
1200  return status;
1201 }
1202 
1204  const uint16_t pkt_type,
1205  const uint16_t clock_offset, const uint8_t role_switch) noexcept {
1206  /**
1207  * As we rely on consistent 'pending tracker connections',
1208  * i.e. avoid a race condition on issuing connections via this command,
1209  * we need to synchronize this method.
1210  */
1211  const std::lock_guard<std::mutex> lock(mtx_connect_cmd); // RAII-style acquire and relinquish via destructor
1212 
1213  if( !isOpen() ) {
1214  ERR_PRINT("HCIHandler::create_conn: Not connected %s", toString().c_str());
1216  }
1217 
1219  hci_cp_create_conn * cp = req0.getWStruct();
1220  cp->bdaddr = bdaddr;
1221  cp->pkt_type = jau::cpu_to_le((uint16_t)(pkt_type & (uint16_t)ACL_PTYPE_MASK)); /* TODO OK excluding SCO_PTYPE_MASK (HCI_HV1 | HCI_HV2 | HCI_HV3) ? */
1222  cp->pscan_rep_mode = 0x02; /* TODO magic? */
1223  cp->pscan_mode = 0x00; /* TODO magic? */
1224  cp->clock_offset = jau::cpu_to_le(clock_offset);
1225  cp->role_switch = role_switch;
1226 
1227  int pendingConnections = countPendingTrackerConnections();
1228  if( 0 < pendingConnections ) {
1229  DBG_PRINT("HCIHandler::create_conn: %d connections pending - %s", pendingConnections, toString().c_str());
1230  int32_t td = 0;
1231  while( env.HCI_COMMAND_COMPLETE_REPLY_TIMEOUT > td && 0 < pendingConnections ) {
1232  std::this_thread::sleep_for(std::chrono::milliseconds(env.HCI_COMMAND_POLL_PERIOD));
1233  td += env.HCI_COMMAND_POLL_PERIOD;
1234  pendingConnections = countPendingTrackerConnections();
1235  }
1236  if( 0 < pendingConnections ) {
1237  WARN_PRINT("HCIHandler::create_conn: %d connections pending after %d ms - %s", pendingConnections, td, toString().c_str());
1238  } else {
1239  DBG_PRINT("HCIHandler::create_conn: pending connections resolved after %d ms - %s", td, toString().c_str());
1240  }
1241  }
1242  const BDAddressAndType addressAndType(bdaddr, BDAddressType::BDADDR_BREDR);
1243  HCIConnectionRef disconn = findDisconnectCmd(addressAndType);
1244  if( nullptr != disconn ) {
1245  DBG_PRINT("HCIHandler::create_conn: disconnect pending %s - %s",
1246  disconn->toString().c_str(), toString().c_str());
1247  int32_t td = 0;
1248  while( env.HCI_COMMAND_COMPLETE_REPLY_TIMEOUT > td && nullptr != disconn ) {
1249  std::this_thread::sleep_for(std::chrono::milliseconds(env.HCI_COMMAND_POLL_PERIOD));
1250  td += env.HCI_COMMAND_POLL_PERIOD;
1251  disconn = findDisconnectCmd(addressAndType);
1252  }
1253  if( nullptr != disconn ) {
1254  WARN_PRINT("HCIHandler::create_conn: disconnect persisting after %d ms: %s - %s",
1255  td, disconn->toString().c_str(), toString().c_str());
1256  } else {
1257  DBG_PRINT("HCIHandler::create_conn: disconnect resolved after %d ms - %s", td, toString().c_str());
1258  }
1259  }
1260  HCIConnectionRef conn = addOrUpdateTrackerConnection(addressAndType, 0);
1261  HCIStatusCode status;
1262  std::unique_ptr<HCIEvent> ev = processCommandStatus(req0, &status);
1263  if( HCIStatusCode::SUCCESS != status ) {
1264  removeTrackerConnection(conn);
1265 
1267  const std::string s0 = nullptr != disconn ? disconn->toString() : "null";
1268  WARN_PRINT("HCIHandler::create_conn: %s: disconnect pending: %s - %s",
1269  to_string(status).c_str(), s0.c_str(), toString().c_str());
1270  }
1271  }
1272  return status;
1273 }
1274 
1275 HCIStatusCode HCIHandler::disconnect(const uint16_t conn_handle, const BDAddressAndType& peerAddressAndType,
1276  const HCIStatusCode reason) noexcept
1277 {
1278  if( !isOpen() ) {
1279  ERR_PRINT("HCIHandler::create_conn: Not connected %s", toString().c_str());
1281  }
1282  if( 0 == conn_handle ) {
1283  ERR_PRINT("HCIHandler::disconnect: Null conn_handle given address%s (drop) - %s",
1284  peerAddressAndType.toString().c_str(), toString().c_str());
1286  }
1287  {
1288  const std::lock_guard<std::recursive_mutex> lock(mtx_connectionList); // RAII-style acquire and relinquish via destructor
1289  HCIConnectionRef conn = findTrackerConnection(conn_handle);
1290  if( nullptr == conn ) {
1291  // disconnect called w/o being connected through this HCIHandler
1292  conn = addOrUpdateTrackerConnection(peerAddressAndType, conn_handle);
1293  WORDY_PRINT("HCIHandler::disconnect: Not tracked address%s, added %s - %s",
1294  peerAddressAndType.toString().c_str(),
1295  conn->toString().c_str(), toString().c_str());
1296  } else if( !conn->equals(peerAddressAndType) ) {
1297  ERR_PRINT("HCIHandler::disconnect: Mismatch given address%s and tracked %s (drop) - %s",
1298  peerAddressAndType.toString().c_str(),
1299  conn->toString().c_str(), toString().c_str());
1301  }
1302  DBG_PRINT("HCIHandler::disconnect: address%s, handle %s, %s - %s",
1303  peerAddressAndType.toString().c_str(),
1304  jau::to_hexstring(conn_handle).c_str(),
1305  conn->toString().c_str(), toString().c_str());
1306  }
1307 
1308  HCIStatusCode status;
1309 
1310  // Always issue DISCONNECT command, even in case of an ioError (lost-connection),
1311  // see Issue #124 fast re-connect on CSR adapter.
1312  // This will always notify the adapter of a disconnected device.
1313  {
1315  hci_cp_disconnect * cp = req0.getWStruct();
1316  cp->handle = jau::cpu_to_le(conn_handle);
1317  cp->reason = number(reason);
1318 
1319  std::unique_ptr<HCIEvent> ev = processCommandStatus(req0, &status);
1320  }
1321  if( HCIStatusCode::SUCCESS == status ) {
1322  addOrUpdateDisconnectCmd(peerAddressAndType, conn_handle);
1323  }
1324  return status;
1325 }
1326 
1327 HCIStatusCode HCIHandler::le_read_phy(const uint16_t conn_handle, const BDAddressAndType& peerAddressAndType,
1328  LE_PHYs& resRx, LE_PHYs& resTx) noexcept {
1329  resRx = LE_PHYs::NONE;
1330  resTx = LE_PHYs::NONE;
1331 
1332  if( !isOpen() ) {
1333  ERR_PRINT("HCIHandler::le_read_phy: Not connected %s", toString().c_str());
1335  }
1336  if( 0 == conn_handle ) {
1337  ERR_PRINT("HCIHandler::le_read_phy: Null conn_handle given address%s (drop) - %s",
1338  peerAddressAndType.toString().c_str(), toString().c_str());
1340  }
1341  {
1342  const std::lock_guard<std::recursive_mutex> lock(mtx_connectionList); // RAII-style acquire and relinquish via destructor
1343  HCIConnectionRef conn = findTrackerConnection(conn_handle);
1344  if( nullptr == conn ) {
1345  // called w/o being connected through this HCIHandler
1346  ERR_PRINT("HCIHandler::le_read_phy: Not tracked handle %s (address%s) (drop) - %s",
1347  jau::to_hexstring(conn_handle).c_str(),
1348  peerAddressAndType.toString().c_str(), toString().c_str());
1350  } else if( !conn->equals(peerAddressAndType) ) {
1351  ERR_PRINT("HCIHandler::le_read_phy: Mismatch given address%s and tracked %s (drop) - %s",
1352  peerAddressAndType.toString().c_str(),
1353  conn->toString().c_str(), toString().c_str());
1355  }
1356  DBG_PRINT("HCIHandler::le_read_phy: address%s, handle %s, %s - %s",
1357  peerAddressAndType.toString().c_str(),
1358  jau::to_hexstring(conn_handle).c_str(),
1359  conn->toString().c_str(), toString().c_str());
1360  }
1361  struct hci_cp_le_read_phy {
1362  __le16 handle;
1363  } __packed;
1364  struct hci_rp_le_read_phy {
1365  __u8 status;
1366  __le16 handle;
1367  __u8 tx_phys;
1368  __u8 rx_phys;
1369  } __packed;
1370 
1371  HCIStatusCode status;
1372 
1374  hci_cp_le_read_phy * cp = req0.getWStruct();
1375  cp->handle = jau::cpu_to_le(conn_handle);
1376  const hci_rp_le_read_phy * ev_phy;
1377  std::unique_ptr<HCIEvent> ev = processCommandComplete(req0, &ev_phy, &status);
1378 
1379  if( nullptr == ev || nullptr == ev_phy || HCIStatusCode::SUCCESS != status ) {
1380  ERR_PRINT("HCIHandler::le_read_phy: LE_READ_PHY: 0x%x (%s) - %s",
1381  number(status), to_string(status).c_str(), toString().c_str());
1382  } else {
1383  const uint16_t conn_handle_rcvd = jau::le_to_cpu(ev_phy->handle);
1384  if( conn_handle != conn_handle_rcvd ) {
1385  ERR_PRINT("HCIHandler::le_read_phy: Mismatch given address%s conn_handle (req) %s != %s (res) (drop) - %s",
1386  peerAddressAndType.toString().c_str(),
1387  jau::to_hexstring(conn_handle).c_str(), jau::to_hexstring(conn_handle_rcvd).c_str(), toString().c_str());
1389  }
1390  switch( ev_phy->tx_phys ) {
1391  case 0x01: resTx = LE_PHYs::LE_1M; break;
1392  case 0x02: resTx = LE_PHYs::LE_2M; break;
1393  case 0x03: resTx = LE_PHYs::LE_CODED; break;
1394  }
1395  switch( ev_phy->rx_phys ) {
1396  case 0x01: resRx = LE_PHYs::LE_1M; break;
1397  case 0x02: resRx = LE_PHYs::LE_2M; break;
1398  case 0x03: resRx = LE_PHYs::LE_CODED; break;
1399  }
1400  }
1401  return status;
1402 }
1403 
1404 std::unique_ptr<HCIEvent> HCIHandler::processCommandStatus(HCICommand &req, HCIStatusCode *status) noexcept
1405 {
1406  const std::lock_guard<std::recursive_mutex> lock(mtx_sendReply); // RAII-style acquire and relinquish via destructor
1407 
1409 
1410  int32_t retryCount = 0;
1411  std::unique_ptr<HCIEvent> ev = nullptr;
1412 
1413  if( !sendCommand(req) ) {
1414  goto exit;
1415  }
1416 
1417  while( retryCount < env.HCI_READ_PACKET_MAX_RETRY ) {
1418  ev = getNextReply(req, retryCount, env.HCI_COMMAND_STATUS_REPLY_TIMEOUT);
1419  if( nullptr == ev ) {
1421  break; // timeout, leave loop
1422  } else if( ev->isEvent(HCIEventType::CMD_STATUS) ) {
1423  HCICommandStatusEvent * ev_cs = static_cast<HCICommandStatusEvent*>(ev.get());
1424  *status = ev_cs->getStatus();
1425  DBG_PRINT("HCIHandler::processCommandStatus %s -> Status 0x%2.2X (%s), errno %d %s: res %s, req %s - %s",
1426  to_string(req.getOpcode()).c_str(),
1427  number(*status), to_string(*status).c_str(), errno, strerror(errno),
1428  ev_cs->toString().c_str(), req.toString().c_str(), toString().c_str());
1429  break; // gotcha, leave loop - pending completion result handled via callback
1430  } else {
1431  retryCount++;
1432  DBG_PRINT("HCIHandler::processCommandStatus: !CMD_STATUS (drop, retry %d): res %s; req %s - %s",
1433  retryCount, ev->toString().c_str(), req.toString().c_str(), toString().c_str());
1434  continue; // next packet
1435  }
1436  }
1437  if( nullptr == ev ) {
1438  // timeout exit
1439  WARN_PRINT("HCIHandler::processCommandStatus %s -> Status 0x%2.2X (%s), errno %d %s: res nullptr, req %s - %s",
1440  to_string(req.getOpcode()).c_str(),
1441  number(*status), to_string(*status).c_str(), errno, strerror(errno),
1442  req.toString().c_str(), toString().c_str());
1443  }
1444 
1445 exit:
1446  return ev;
1447 }
1448 
1449 template<typename hci_cmd_event_struct>
1450 std::unique_ptr<HCIEvent> HCIHandler::processCommandComplete(HCICommand &req,
1451  const hci_cmd_event_struct **res, HCIStatusCode *status) noexcept
1452 {
1453  const std::lock_guard<std::recursive_mutex> lock(mtx_sendReply); // RAII-style acquire and relinquish via destructor
1454 
1455  *res = nullptr;
1457 
1458  if( !sendCommand(req) ) {
1459  WARN_PRINT("HCIHandler::processCommandComplete Send failed: Status 0x%2.2X (%s), errno %d %s: res nullptr, req %s - %s",
1460  number(*status), to_string(*status).c_str(), errno, strerror(errno),
1461  req.toString().c_str(), toString().c_str());
1462  return nullptr; // timeout
1463  }
1464 
1465  return receiveCommandComplete(req, res, status);
1466 }
1467 
1468 template<typename hci_cmd_event_struct>
1469 std::unique_ptr<HCIEvent> HCIHandler::receiveCommandComplete(HCICommand &req,
1470  const hci_cmd_event_struct **res, HCIStatusCode *status) noexcept
1471 {
1472  *res = nullptr;
1474 
1476  HCICommandCompleteEvent * ev_cc;
1477  std::unique_ptr<HCIEvent> ev = getNextCmdCompleteReply(req, &ev_cc);
1478  if( nullptr == ev ) {
1480  WARN_PRINT("HCIHandler::processCommandComplete %s -> %s: Status 0x%2.2X (%s), errno %d %s: res nullptr, req %s - %s",
1481  to_string(req.getOpcode()).c_str(), to_string(evc).c_str(),
1482  number(*status), to_string(*status).c_str(), errno, strerror(errno),
1483  req.toString().c_str(), toString().c_str());
1484  return nullptr; // timeout
1485  } else if( nullptr == ev_cc ) {
1486  WARN_PRINT("HCIHandler::processCommandComplete %s -> %s: Status 0x%2.2X (%s), errno %d %s: res %s, req %s - %s",
1487  to_string(req.getOpcode()).c_str(), to_string(evc).c_str(),
1488  number(*status), to_string(*status).c_str(), errno, strerror(errno),
1489  ev->toString().c_str(), req.toString().c_str(), toString().c_str());
1490  return ev;
1491  }
1492  const uint8_t returnParamSize = ev_cc->getReturnParamSize();
1493  if( returnParamSize < sizeof(hci_cmd_event_struct) ) {
1494  WARN_PRINT("HCIHandler::processCommandComplete %s -> %s: Status 0x%2.2X (%s), errno %d %s: res %s, req %s - %s",
1495  to_string(req.getOpcode()).c_str(), to_string(evc).c_str(),
1496  number(*status), to_string(*status).c_str(), errno, strerror(errno),
1497  ev_cc->toString().c_str(), req.toString().c_str(), toString().c_str());
1498  return ev;
1499  }
1500  *res = (const hci_cmd_event_struct*)(ev_cc->getReturnParam());
1501  *status = static_cast<HCIStatusCode>((*res)->status);
1502  DBG_PRINT("HCIHandler::processCommandComplete %s -> %s: Status 0x%2.2X (%s): res %s, req %s - %s",
1503  to_string(req.getOpcode()).c_str(), to_string(evc).c_str(),
1504  number(*status), to_string(*status).c_str(),
1505  ev_cc->toString().c_str(), req.toString().c_str(), toString().c_str());
1506  return ev;
1507 }
1508 
1509 template<typename hci_cmd_event_struct>
1510 const hci_cmd_event_struct* HCIHandler::getReplyStruct(HCIEvent& event, HCIEventType evc, HCIStatusCode *status) noexcept
1511 {
1512  const hci_cmd_event_struct* res = nullptr;
1514 
1515  typedef HCIStructCmdCompleteEvtWrap<hci_cmd_event_struct> HCITypeCmdCompleteEvtWrap;
1516  HCITypeCmdCompleteEvtWrap ev_cc( event );
1517  if( ev_cc.isTypeAndSizeValid(evc) ) {
1518  *status = ev_cc.getStatus();
1519  res = ev_cc.getStruct();
1520  } else {
1521  WARN_PRINT("HCIHandler::getReplyStruct: %s: Type or size mismatch: Status 0x%2.2X (%s), errno %d %s: res %s - %s",
1522  to_string(evc).c_str(),
1523  number(*status), to_string(*status).c_str(), errno, strerror(errno),
1524  ev_cc.toString().c_str(), toString().c_str());
1525  }
1526  return res;
1527 }
1528 
1529 template<typename hci_cmd_event_struct>
1530 const hci_cmd_event_struct* HCIHandler::getMetaReplyStruct(HCIEvent& event, HCIMetaEventType mec, HCIStatusCode *status) noexcept
1531 {
1532  const hci_cmd_event_struct* res = nullptr;
1534 
1535  typedef HCIStructCmdCompleteMetaEvtWrap<hci_cmd_event_struct> HCITypeCmdCompleteMetaEvtWrap;
1536  const HCITypeCmdCompleteMetaEvtWrap ev_cc( *static_cast<HCIMetaEvent*>( &event ) );
1537  if( ev_cc.isTypeAndSizeValid(mec) ) {
1538  *status = ev_cc.getStatus();
1539  res = ev_cc.getStruct();
1540  } else {
1541  WARN_PRINT("HCIHandler::getMetaReplyStruct: %s: Type or size mismatch: Status 0x%2.2X (%s), errno %d %s: res %s - %s",
1542  to_string(mec).c_str(),
1543  number(*status), to_string(*status).c_str(), errno, strerror(errno),
1544  ev_cc.toString().c_str(), toString().c_str());
1545  }
1546  return res;
1547 }
1548 
1549 /***
1550  *
1551  * MgmtEventCallback section
1552  *
1553  */
1554 
1556  [](const MgmtEventCallback &a, const MgmtEventCallback &b) -> bool { return a == b; };
1557 
1559  if( !isValidMgmtEventCallbackListsIndex(opc) ) {
1560  ERR_PRINT("Opcode %s >= %d - %s", MgmtEvent::getOpcodeString(opc).c_str(), mgmtEventCallbackLists.size(), toString().c_str());
1561  return false;
1562  }
1563  MgmtEventCallbackList &l = mgmtEventCallbackLists[static_cast<uint16_t>(opc)];
1564  /* const bool added = */ l.push_back_unique(cb, _mgmtEventCallbackEqComparator);
1565  return true;
1566 }
1568  if( !isValidMgmtEventCallbackListsIndex(opc) ) {
1569  ERR_PRINT("Opcode %s >= %d - %s", MgmtEvent::getOpcodeString(opc).c_str(), mgmtEventCallbackLists.size(), toString().c_str());
1570  return 0;
1571  }
1572  MgmtEventCallbackList &l = mgmtEventCallbackLists[static_cast<uint16_t>(opc)];
1573  return l.erase_matching(cb, true /* all_matching */, _mgmtEventCallbackEqComparator);
1574 }
1576  if( !isValidMgmtEventCallbackListsIndex(opc) ) {
1577  ERR_PRINT("Opcode %s >= %d - %s", MgmtEvent::getOpcodeString(opc).c_str(), mgmtEventCallbackLists.size(), toString().c_str());
1578  return;
1579  }
1580  mgmtEventCallbackLists[static_cast<uint16_t>(opc)].clear();
1581 }
1583  for(size_t i=0; i<mgmtEventCallbackLists.size(); i++) {
1584  mgmtEventCallbackLists[i].clear();
1585  }
1586  hciSMPMsgCallbackList.clear();
1587 }
1588 
1589 /**
1590  * SMPMsgCallback handling
1591  */
1592 
1594  [](const HCISMPMsgCallback& a, const HCISMPMsgCallback& b) -> bool { return a == b; };
1595 
1596 
1598  hciSMPMsgCallbackList.push_back(l);
1599 }
1601  return hciSMPMsgCallbackList.erase_matching(l, true /* all_matching */, _changedHCISMPMsgCallbackEqComp);
1602 }
1603 
1604 
direct_bt::HCIMetaEvent
BT Core Spec v5.2: Vol 4, Part E HCI: 7.7.65 LE Meta event.
Definition: HCITypes.hpp:1036
direct_bt::HCIOpcode::LE_READ_LOCAL_FEATURES
@ LE_READ_LOCAL_FEATURES
direct_bt::HCIHandler::resetAdapter
HCIStatusCode resetAdapter()
Reset the adapter.
Definition: HCIHandler.cpp:868
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::HCIOpcode::LE_READ_PHY
@ LE_READ_PHY
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::HCIACLData::getSpecialized
static std::unique_ptr< HCIACLData > getSpecialized(const uint8_t *buffer, jau::nsize_t const buffer_size) noexcept
Return a newly created specialized instance pointer to base class.
Definition: HCITypes.cpp:351
direct_bt::MgmtEvent::Opcode::DEVICE_DISCONNECTED
@ DEVICE_DISCONNECTED
direct_bt::HCIPacketType::EVENT
@ EVENT
direct_bt::TROOctets::get_uint8_nc
constexpr uint8_t get_uint8_nc(const jau::nsize_t i) const noexcept
Definition: OctetTypes.hpp:124
direct_bt::LE_Features::NONE
@ NONE
NONE.
jau::bytesHexString
std::string bytesHexString(const uint8_t *bytes, const nsize_t offset, const nsize_t length, const bool lsbFirst, const bool lowerCase=true) noexcept
Produce a hexadecimal string representation of the given byte values.
Definition: basic_types.cpp:167
direct_bt::HCIOpcode::RESET
@ RESET
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
le_scan_interval
static const uint16_t le_scan_interval
Definition: dbt_scanner10.cpp:633
direct_bt::HCIACLData::l2cap_frame
Representing ACL Datas' L2CAP Frame.
Definition: HCITypes.hpp:672
direct_bt::MgmtEvent::Opcode::INVALID
@ INVALID
direct_bt::TOctets::get_wptr
uint8_t * get_wptr() noexcept
Definition: OctetTypes.hpp:383
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::HCIMetaEventType::LE_REMOTE_FEAT_COMPLETE
@ LE_REMOTE_FEAT_COMPLETE
LE_REMOTE_FEAT_COMPLETE.
direct_bt::HCIComm::filter_set_event
static void filter_set_event(int e, hci_ufilter *f) noexcept
Definition: HCIComm.hpp:132
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::HCIHandler::stopAdapter
HCIStatusCode stopAdapter()
Bring down this adapter into a non-POWERED non-functional state.
Definition: HCIHandler.cpp:843
direct_bt::HCIOpcode::CREATE_CONN
@ CREATE_CONN
direct_bt::HCIHandler::use_ext_conn
bool use_ext_conn() const noexcept
Use extended connection if HCI_LE_Extended_Create_Connection is supported (Bluetooth 5....
Definition: HCIHandler.hpp:385
direct_bt::MgmtEvent::getOpcodeString
static std::string getOpcodeString(const Opcode opc) noexcept
Definition: MgmtTypes.cpp:314
packed_attribute.hpp
direct_bt::HCIHandler::create_conn
HCIStatusCode create_conn(const EUI48 &bdaddr, const uint16_t pkt_type=HCI_DM1|HCI_DM3|HCI_DM5|HCI_DH1|HCI_DH3|HCI_DH5, const uint16_t clock_offset=0x0000, const uint8_t role_switch=0x01) noexcept
Establish a connection to the given BREDR (non LE).
Definition: HCIHandler.cpp:1203
direct_bt::LE_PHYs::LE_1M
@ LE_1M
direct_bt::HCIOpcodeBit::LE_ENABLE_ENC
@ LE_ENABLE_ENC
basic_algos.hpp
direct_bt::HCIOpcode::DISCONNECT
@ DISCONNECT
direct_bt::MgmtEvtDiscovering
Definition: MgmtTypes.hpp:1818
direct_bt::changeScanType
constexpr ScanType changeScanType(const ScanType current, const ScanType changeType, const bool changeEnable) noexcept
Definition: BTTypes0.hpp:321
direct_bt::LE_PHYs::NONE
@ NONE
jau::FunctionDef::toString
std::string toString() const
Definition: function_def.hpp:350
direct_bt::HCIStructCmdCompleteMetaEvtWrap
Generic HCIMetaEvent wrapper for any HCI IOCTL 'command complete' alike meta event struct having a HC...
Definition: HCITypes.hpp:1088
direct_bt::LE_PHYs::LE_CODED
@ LE_CODED
direct_bt
Definition: ATTPDUTypes.hpp:171
__packed
#define __packed
packed: lead out macro, requires packed lead in as well.
Definition: packed_attribute.hpp:43
direct_bt::MgmtEvent::Opcode
Opcode
Definition: MgmtTypes.hpp:1085
direct_bt::HCICommandCompleteEvent::getReturnParam
const uint8_t * getReturnParam() const
Definition: HCITypes.hpp:973
direct_bt::HCIOpcodeBit::LE_SET_SCAN_PARAM
@ LE_SET_SCAN_PARAM
direct_bt::HCIHandler::clearAllCallbacks
void clearAllCallbacks() noexcept
Removes all MgmtEventCallbacks from all MgmtEvent::Opcode lists and all SMPSecurityReqCallbacks.
Definition: HCIHandler.cpp:1582
direct_bt::HCIHandler::toString
std::string toString() const noexcept
Definition: HCIHandler.cpp:814
direct_bt::HCIHandler::clearMgmtEventCallbacks
void clearMgmtEventCallbacks(const MgmtEvent::Opcode opc) noexcept
Removes all MgmtEventCallbacks from the to the named MgmtEvent::Opcode list.
Definition: HCIHandler.cpp:1575
BTTypes1.hpp
direct_bt::HCIHandler::disconnect
HCIStatusCode disconnect(const uint16_t conn_handle, const BDAddressAndType &addressAndType, const HCIStatusCode reason=HCIStatusCode::REMOTE_USER_TERMINATED_CONNECTION) noexcept
Disconnect an established connection.
Definition: HCIHandler.cpp:1275
direct_bt::HCIEvent::getSpecialized
static std::unique_ptr< HCIEvent > getSpecialized(const uint8_t *buffer, jau::nsize_t const buffer_size) noexcept
Return a newly created specialized instance pointer to base class.
Definition: HCITypes.cpp:306
direct_bt::LE_PHYs::LE_2M
@ LE_2M
direct_bt::TROOctets::get_ptr
constexpr uint8_t const * get_ptr() const noexcept
Definition: OctetTypes.hpp:228
jau
Definition: basic_algos.hpp:34
direct_bt::HCIACLData::getL2CAPFrame
l2cap_frame getL2CAPFrame(const uint8_t *&l2cap_data) const noexcept
Definition: HCITypes.cpp:372
direct_bt::HCICommandCompleteEvent
BT Core Spec v5.2: Vol 4, Part E HCI: 7.7.14 Command Complete event.
Definition: HCITypes.hpp:942
direct_bt::HCIHandler::le_start_scan
HCIStatusCode le_start_scan(const bool filter_dup=true, const bool le_scan_active=false, const HCILEOwnAddressType own_mac_type=HCILEOwnAddressType::PUBLIC, const uint16_t le_scan_interval=24, const uint16_t le_scan_window=24, const uint8_t filter_policy=0x00) noexcept
Start LE scanning, i.e.
Definition: HCIHandler.cpp:1045
direct_bt::HCIPacketType::ACLDATA
@ ACLDATA
direct_bt::HCIOpcode::LE_SET_EXT_SCAN_PARAMS
@ LE_SET_EXT_SCAN_PARAMS
direct_bt::ScanType
ScanType
Meta ScanType as derived from BTMode, with defined value mask consisting of BDAddressType bits.
Definition: BTTypes0.hpp:294
direct_bt::HCIMetaEventType::LE_CHANNEL_SEL_ALGO
@ LE_CHANNEL_SEL_ALGO
LE_CHANNEL_SEL_ALGO.
direct_bt::HCIHandler::startAdapter
HCIStatusCode startAdapter()
Bring up this adapter into a POWERED functional state.
Definition: HCIHandler.cpp:821
jau::cow_darray::size
constexpr_atomic size_type size() const noexcept
Like std::vector::size().
Definition: cow_darray.hpp:716
direct_bt::HCIOpcodeBit::RESET
@ RESET
direct_bt::HCIHandler::HCIHandler
HCIHandler(const uint16_t dev_id, const BTMode btMode=BTMode::NONE) noexcept
Definition: HCIHandler.cpp:592
direct_bt::HCIEvent::isEvent
constexpr bool isEvent(HCIEventType t) const noexcept
Definition: HCITypes.hpp:854
direct_bt::to_BDAddressType
constexpr BDAddressType to_BDAddressType(const uint8_t v) noexcept
Definition: BTAddress.hpp:61
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::HCIMetaEventType::LE_CONN_COMPLETE
@ LE_CONN_COMPLETE
LE_CONN_COMPLETE.
__u8
uint8_t __u8
Definition: linux_kernel_types.hpp:40
direct_bt::HCIOpcode::LE_SET_EXT_SCAN_ENABLE
@ LE_SET_EXT_SCAN_ENABLE
jau::FunctionDef
Definition: function_def.hpp:309
direct_bt::MgmtEvent
uint16_t opcode, uint16_t dev-id, uint16_t param_size
Definition: MgmtTypes.hpp:1083
direct_bt::HCIComm::filter_all_events
static void filter_all_events(hci_ufilter *f) noexcept
Definition: HCIComm.hpp:144
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::HCIOpcodeBit::LE_CREATE_CONN
@ LE_CREATE_CONN
jau::darray< HCIConnectionRef >
direct_bt::HCICommand
BT Core Spec v5.2: Vol 4, Part E HCI: 5.4.1 HCI Command packet.
Definition: HCITypes.hpp:546
direct_bt::HCIEventType::ENCRYPT_CHANGE
@ ENCRYPT_CHANGE
direct_bt::HCICommandCompleteEvent::getReturnParamSize
jau::nsize_t getReturnParamSize() const noexcept
Definition: HCITypes.hpp:972
direct_bt::HCIOpcodeBit::LE_READ_PHY
@ LE_READ_PHY
direct_bt::HCIMetaEventType
HCIMetaEventType
BT Core Spec v5.2: Vol 4, Part E HCI: 7.7.65 LE Meta event.
Definition: HCITypes.hpp:314
direct_bt::LE_Features
LE_Features
HCI Supported Commands.
Definition: BTTypes0.hpp:106
direct_bt::HCIOpcode::LE_SET_SCAN_PARAM
@ LE_SET_SCAN_PARAM
direct_bt::MgmtEvent::Opcode::CMD_COMPLETE
@ CMD_COMPLETE
direct_bt::HCIACLData::l2cap_frame::isGATT
constexpr bool isGATT() const noexcept
Definition: HCITypes.hpp:703
le_scan_window
static const uint16_t le_scan_window
Definition: dbt_scanner10.cpp:634
direct_bt::HCIHandler::le_read_phy
HCIStatusCode le_read_phy(const uint16_t conn_handle, const BDAddressAndType &addressAndType, LE_PHYs &resRx, LE_PHYs &resTx) noexcept
Request and return LE_PHYs bit for the given connection.
Definition: HCIHandler.cpp:1327
direct_bt::hasScanType
constexpr bool hasScanType(const ScanType current, const ScanType testType) noexcept
Definition: BTTypes0.hpp:324
direct_bt::HCIHandler::le_set_scan_param
HCIStatusCode le_set_scan_param(const bool le_scan_active=false, const HCILEOwnAddressType own_mac_type=HCILEOwnAddressType::PUBLIC, const uint16_t le_scan_interval=24, const uint16_t le_scan_window=24, const uint8_t filter_policy=0x00) noexcept
Sets LE scanning parameters.
Definition: HCIHandler.cpp:946
_changedHCISMPMsgCallbackEqComp
static HCISMPMsgCallbackList::equal_comparator _changedHCISMPMsgCallbackEqComp
SMPMsgCallback handling.
Definition: HCIHandler.cpp:1593
WARN_PRINT
#define WARN_PRINT(...)
Use for unconditional warning messages, prefix '[elapsed_time] Warning @ FILE:LINE: '.
Definition: debug.hpp:146
direct_bt::EInfoReport::read_ext_ad_reports
static jau::darray< std::unique_ptr< EInfoReport > > read_ext_ad_reports(uint8_t const *data, jau::nsize_t const data_length) noexcept
Reads a complete Advertising Data (AD) Report and returns the number of AD reports in form of a shara...
Definition: BTTypes0.cpp:1183
direct_bt::HCIHandler::reset
HCIStatusCode reset() noexcept
HCI Reset Command.
Definition: HCIHandler.cpp:884
direct_bt::HCIStatusCode::INVALID_HCI_COMMAND_PARAMETERS
@ INVALID_HCI_COMMAND_PARAMETERS
direct_bt::HCIHandler::removeMgmtEventCallback
int removeMgmtEventCallback(const MgmtEvent::Opcode opc, const MgmtEventCallback &cb) noexcept
Returns count of removed given MgmtEventCallback from the named MgmtEvent::Opcode list.
Definition: HCIHandler.cpp:1567
direct_bt::HCIStatusCode::COMMAND_DISALLOWED
@ COMMAND_DISALLOWED
direct_bt::HCIHandler::removeSMPMsgCallback
int removeSMPMsgCallback(const HCISMPMsgCallback &l)
Definition: HCIHandler.cpp:1600
direct_bt::HCIOpcodeBit::LE_SET_SCAN_ENABLE
@ LE_SET_SCAN_ENABLE
direct_bt::HCIHandler::use_ext_scan
bool use_ext_scan() const noexcept
Use extended scanning if HCI_LE_Set_Extended_Scan_Parameters and HCI_LE_Set_Extended_Scan_Enable is s...
Definition: HCIHandler.hpp:379
jau::ordered_atomic::load
CXX_ALWAYS_INLINE _Tp load() const noexcept
Definition: ordered_atomic.hpp:139
direct_bt::HCIEvent
BT Core Spec v5.2: Vol 4, Part E HCI: 5.4.4 HCI Event packet.
Definition: HCITypes.hpp:775
direct_bt::HCIEventType::LE_META
@ LE_META
direct_bt::number
constexpr uint8_t number(const BDAddressType rhs) noexcept
Definition: BTAddress.hpp:67
direct_bt::SMPPDUMsg::toString
virtual std::string toString() const noexcept
Definition: SMPTypes.hpp:795
jau::darray::begin
constexpr iterator begin() noexcept
Definition: darray.hpp:606
direct_bt::HCIEventType
HCIEventType
BT Core Spec v5.2: Vol 4, Part E HCI: 7.7 Events.
Definition: HCITypes.hpp:272
jau::darray::size
constexpr size_type size() const noexcept
Like std::vector::size().
Definition: darray.hpp:668
direct_bt::HCICommandStatusEvent
BT Core Spec v5.2: Vol 4, Part E HCI: 7.7.15 Command Status event.
Definition: HCITypes.hpp:990
direct_bt::HCIACLData::toString
std::string toString() const noexcept
Definition: HCITypes.hpp:755
direct_bt::HCIComm::filter_set_ptype
static void filter_set_ptype(int t, hci_ufilter *f) noexcept
Definition: HCIComm.hpp:116
direct_bt::HCIOpcode::LE_SET_SCAN_ENABLE
@ LE_SET_SCAN_ENABLE
HCIHandler.hpp
jau::cpu_to_le
constexpr uint16_t cpu_to_le(uint16_t const h) noexcept
Definition: byte_util.hpp:334
jau::darray::end
constexpr iterator end() noexcept
Definition: darray.hpp:612
direct_bt::HCIHandler::le_create_conn
HCIStatusCode le_create_conn(const EUI48 &peer_bdaddr, const HCILEPeerAddressType peer_mac_type=HCILEPeerAddressType::PUBLIC, const HCILEOwnAddressType own_mac_type=HCILEOwnAddressType::PUBLIC, const uint16_t le_scan_interval=24, const uint16_t le_scan_window=24, 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
Establish a connection to the given LE peer.
Definition: HCIHandler.cpp:1074
jau::cow_darray
Implementation of a Copy-On-Write (CoW) using jau::darray as the underlying storage,...
Definition: cow_darray.hpp:130
direct_bt::HCIStatusCode::INTERNAL_FAILURE
@ INTERNAL_FAILURE
le_scan_active
static bool le_scan_active
Definition: dbt_scanner10.cpp:632
direct_bt::HCIOpcodeBit::READ_LOCAL_COMMANDS
@ READ_LOCAL_COMMANDS
direct_bt::HCIPacket::toString
std::string toString() const noexcept
Definition: HCITypes.hpp:529
direct_bt::HCIHandler::addMgmtEventCallback
bool addMgmtEventCallback(const MgmtEvent::Opcode opc, const MgmtEventCallback &cb) noexcept
MgmtEventCallback handling
Definition: HCIHandler.cpp:1558
direct_bt::HCIHandler::getLocalVersion
HCIStatusCode getLocalVersion(HCILocalVersion &version) noexcept
Definition: HCIHandler.cpp:904
debug.hpp
direct_bt::HCIHandler::sendMgmtEvent
void sendMgmtEvent(const MgmtEvent &event) noexcept
Manually send a MgmtEvent to all of its listeners.
Definition: HCIHandler.cpp:496
direct_bt::HCIStatusCode::INTERNAL_TIMEOUT
@ INTERNAL_TIMEOUT
direct_bt::HCIEnv::get
static HCIEnv & get() noexcept
Definition: HCIHandler.hpp:142
direct_bt::HCIHandler::isOpen
bool isOpen() const noexcept
Returns true if this mgmt instance is open, connected and hence valid, otherwise false.
Definition: HCIHandler.hpp:374
direct_bt::HCIStructCommand
Generic HCICommand wrapper for any HCI IOCTL structure.
Definition: HCITypes.hpp:624
direct_bt::TROOctets
Transient read only octet data, i.e.
Definition: OctetTypes.hpp:59
jau::get_uint64
constexpr uint64_t get_uint64(uint8_t const *buffer, nsize_t const byte_offset) noexcept
Definition: byte_util.hpp:640
direct_bt::HCIEventType::CMD_COMPLETE
@ CMD_COMPLETE
direct_bt::HCIEnv::DEBUG_EVENT
const bool DEBUG_EVENT
Debug all HCI event communication.
Definition: HCIHandler.hpp:127
direct_bt::HCIMetaEventType::LE_EXT_CONN_COMPLETE
@ LE_EXT_CONN_COMPLETE
LE_ENHANCED_CONN_COMPLETE.
direct_bt::HCIMetaEventType::INVALID
@ INVALID
direct_bt::to_string
std::string to_string(const BDAddressType type) noexcept
Definition: BTTypes0.cpp:129
direct_bt::ScanType::LE
@ LE
direct_bt::HCIMetaEventType::LE_EXT_ADV_REPORT
@ LE_EXT_ADV_REPORT
LE_EXT_ADV_REPORT.
direct_bt::HCIHandler::resetAllStates
void resetAllStates(const bool powered_on) noexcept
Reset all internal states, i.e.
Definition: HCIHandler.cpp:168
direct_bt::HCIHandler::close
void close() noexcept
Definition: HCIHandler.cpp:766
_mgmtEventCallbackEqComparator
static MgmtEventCallbackList::equal_comparator _mgmtEventCallbackEqComparator
Definition: HCIHandler.cpp:1555
direct_bt::MgmtEvent::Opcode::DEVICE_CONNECTED
@ DEVICE_CONNECTED
direct_bt::HCIEvent::validate
virtual bool validate(const HCICommand &cmd) const noexcept
Definition: HCITypes.hpp:865
direct_bt::EUI48
A packed 48 bit EUI-48 identifier, formerly known as MAC-48 or simply network device MAC address (Med...
Definition: BTAddress.hpp:388
jau::le_to_cpu
constexpr uint16_t le_to_cpu(uint16_t const l) noexcept
Definition: byte_util.hpp:325
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::HCIEnv::DEBUG_SCAN_AD_EIR
const bool DEBUG_SCAN_AD_EIR
Debug all scanned HCI 'Advertising Data' (AD) 'Extended Inquiry Response' (EIR) packages.
Definition: HCIHandler.hpp:135
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::HCIComm::filter_clear
static void filter_clear(hci_ufilter *f) noexcept
Definition: HCIComm.hpp:112
direct_bt::HCIEventType::DISCONN_COMPLETE
@ DISCONN_COMPLETE
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::HCIEventType::CONN_COMPLETE
@ CONN_COMPLETE
direct_bt::HCIEventType::ENCRYPT_KEY_REFRESH_COMPLETE
@ ENCRYPT_KEY_REFRESH_COMPLETE
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::HCIComm::getSocketDescriptor
int getSocketDescriptor() const noexcept
Return this HCI socket descriptor.
Definition: HCIComm.hpp:84
direct_bt::HCIEnv::HCI_READER_THREAD_POLL_TIMEOUT
const int32_t HCI_READER_THREAD_POLL_TIMEOUT
Poll timeout for HCI reader thread, defaults to 10s.
Definition: HCIHandler.hpp:81
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::HCIHandler::addSMPMsgCallback
void addSMPMsgCallback(const HCISMPMsgCallback &l)
Definition: HCIHandler.cpp:1597
jau::FunctionDef::invoke
R invoke(A... args)
Definition: function_def.hpp:354
direct_bt::HCIComm::filter_set_opcode
static void filter_set_opcode(uint16_t opcode, hci_ufilter *f) noexcept
Definition: HCIComm.hpp:148
__le16
uint16_t __le16
Definition: linux_kernel_types.hpp:43
direct_bt::HCILocalVersion
Definition: HCITypes.hpp:1108
direct_bt::HCICommandStatusEvent::getStatus
HCIStatusCode getStatus() const noexcept
Definition: HCITypes.hpp:1008
direct_bt::HCIHandler::env
const HCIEnv & env
Definition: HCIHandler.hpp:179
direct_bt::HCIStatusCode::SUCCESS
@ SUCCESS
direct_bt::HCIACLData::l2cap_frame::handle
const uint16_t handle
The connection handle.
Definition: HCITypes.hpp:693
direct_bt::HCIMetaEventType::LE_ADVERTISING_REPORT
@ LE_ADVERTISING_REPORT
LE_ADVERTISING_REPORT.
direct_bt::HCIOpcode::LE_EXT_CREATE_CONN
@ LE_EXT_CREATE_CONN
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
direct_bt::HCIStatusCode::CONNECTION_ALREADY_EXISTS
@ CONNECTION_ALREADY_EXISTS
direct_bt::HCIOpcodeBit::DISCONNECT
@ DISCONNECT
HCIComm.hpp
filter_policy
static const uint8_t filter_policy
Definition: dbt_scanner10.cpp:635
direct_bt::HCIEventType::HARDWARE_ERROR
@ HARDWARE_ERROR
direct_bt::HCIOpcode::READ_LOCAL_COMMANDS
@ READ_LOCAL_COMMANDS
direct_bt::HCIOpcodeBit::CREATE_CONN
@ CREATE_CONN
direct_bt::MgmtEvtDeviceFound
mgmt_addr_info { EUI48, uint8_t type }, int8_t rssi, uint32_t flags, uint16_t eir_len; uint8_t *eir
Definition: MgmtTypes.hpp:1770
direct_bt::HCILEPeerAddressType
HCILEPeerAddressType
HCI LE Address-Type is PUBLIC: 0x00, RANDOM: 0x01.
Definition: BTAddress.hpp:120
WORDY_PRINT
#define WORDY_PRINT(...)
Use for environment-variable environment::VERBOSE conditional verbose messages, prefix '[elapsed_time...
Definition: debug.hpp:91
direct_bt::HCIStructCommand::getWStruct
hcistruct * getWStruct() noexcept
Definition: HCITypes.hpp:643
direct_bt::HCIStructCmdCompleteEvtWrap
Generic HCIEvent wrapper for any HCI IOCTL 'command complete' alike event struct having a HCIStatusCo...
Definition: HCITypes.hpp:874
direct_bt::SMPPDUMsg::getSpecialized
static std::unique_ptr< const SMPPDUMsg > getSpecialized(const uint8_t *buffer, jau::nsize_t const buffer_size) noexcept
Return a newly created specialized instance pointer to base class.
Definition: SMPTypes.cpp:423
direct_bt::HCIHandler::le_enable_scan
HCIStatusCode le_enable_scan(const bool enable, const bool filter_dup=true) noexcept
Starts or stops LE scanning.
Definition: HCIHandler.cpp:1001
direct_bt::MgmtEvent::Opcode::CMD_STATUS
@ CMD_STATUS
direct_bt::HCIOpcode::READ_LOCAL_VERSION
@ READ_LOCAL_VERSION
direct_bt::LE_PHYs
LE_PHYs
LE Transport PHY bit values.
Definition: BTTypes0.hpp:175
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
direct_bt::HCIOpcodeBit::LE_EXT_CREATE_CONN
@ LE_EXT_CREATE_CONN
direct_bt::HCIEventType::CMD_STATUS
@ CMD_STATUS
direct_bt::HCIHandler::pidSelf
static const pid_t pidSelf
Definition: HCIHandler.hpp:177
direct_bt::HCIOpcode::LE_CREATE_CONN
@ LE_CREATE_CONN
LE_CREATE_CONN.
direct_bt::BDAddressType::BDADDR_BREDR
@ BDADDR_BREDR
Bluetooth BREDR address.
COND_PRINT
#define COND_PRINT(C,...)
Use for conditional plain messages, prefix '[elapsed_time] '.
Definition: debug.hpp:165
hci_rp_status
Definition: HCIHandler.cpp:77
direct_bt::BTSecurityRegistry::clear
void clear() noexcept
Clears internal list.
Definition: BTSecurityRegistry.cpp:90
direct_bt::MgmtEvtDeviceConnectFailed
mgmt_addr_info { EUI48, uint8_t type }, uint8_t status
Definition: MgmtTypes.hpp:1621
direct_bt::BTMode
BTMode
Bluetooth adapter operating mode.
Definition: BTTypes0.hpp:56
direct_bt::HCIOpcodeBit::LE_SET_EXT_SCAN_ENABLE
@ LE_SET_EXT_SCAN_ENABLE
direct_bt::HCIOpcodeBit::READ_LOCAL_VERSION
@ READ_LOCAL_VERSION
DBG_PRINT
#define DBG_PRINT(...)
Use for environment-variable environment::DEBUG conditional debug messages, prefix '[elapsed_time] De...
Definition: debug.hpp:78
direct_bt::HCIEventType::AUTH_COMPLETE
@ AUTH_COMPLETE
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::HCIOpcodeBit::LE_SET_EXT_SCAN_PARAMS
@ LE_SET_EXT_SCAN_PARAMS
direct_bt::HCIHandler::le_read_local_features
HCIStatusCode le_read_local_features(LE_Features &res) noexcept
Request and return LE_Features for the controller.
Definition: HCIHandler.cpp:927
direct_bt::HCILEOwnAddressType
HCILEOwnAddressType
Definition: BTAddress.hpp:135
direct_bt::HCIACLData::l2cap_frame::toString
static std::string toString(const PBFlag v) noexcept
Definition: HCITypes.cpp:341
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
environment.hpp
direct_bt::HCIPacketType
HCIPacketType
Definition: HCITypes.hpp:241