Direct-BT  2.3.1
Direct-BT - Direct Bluetooth Programming.
HCIHandler.hpp
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 #ifndef HCI_HANDLER_HPP_
27 #define HCI_HANDLER_HPP_
28 
29 #include <cstring>
30 #include <string>
31 #include <cstdint>
32 
33 #include <mutex>
34 #include <atomic>
35 #include <thread>
36 
37 #include <jau/darray.hpp>
38 #include <jau/environment.hpp>
39 #include <jau/ringbuffer.hpp>
40 #include <jau/java_uplink.hpp>
41 
42 #include "BTTypes0.hpp"
43 #include "BTIoctl.hpp"
44 #include "OctetTypes.hpp"
45 #include "HCIComm.hpp"
46 #include "HCITypes.hpp"
47 #include "MgmtTypes.hpp"
48 
49 /**
50  * - - - - - - - - - - - - - - -
51  *
52  * Module HCIHandler:
53  *
54  * - BT Core Spec v5.2: Vol 4, Part E Host Controller Interface (HCI)
55  */
56 namespace direct_bt {
57 
58  class HCIHandler; // forward
59 
60  /**
61  * HCI Singleton runtime environment properties
62  * <p>
63  * Also see {@link DBTEnv::getExplodingProperties(const std::string & prefixDomain)}.
64  * </p>
65  */
66  class HCIEnv : public jau::root_environment {
67  friend class HCIHandler;
68 
69  private:
70  HCIEnv() noexcept;
71 
72  const bool exploding; // just to trigger exploding properties
73 
74  public:
75  /**
76  * Poll timeout for HCI reader thread, defaults to 10s.
77  * <p>
78  * Environment variable is 'direct_bt.hci.reader.timeout'.
79  * </p>
80  */
82 
83  /**
84  * Timeout for HCI command status replies, excluding command complete, defaults to 3s.
85  * <p>
86  * Environment variable is 'direct_bt.hci.cmd.status.timeout'.
87  * </p>
88  */
90 
91  /**
92  * Timeout for HCI command complete replies, defaults to 10s.
93  * This timeout is rather longer, as it may include waiting for pending command complete.
94  * <p>
95  * Environment variable is 'direct_bt.hci.cmd.complete.timeout'.
96  * </p>
97  */
99 
100  /**
101  * Poll period for certain HCI commands actively waiting for clearance, defaults to 125ms.
102  * <p>
103  * Used for LE_Create_Connection or Create_Connection
104  * when waiting for any pending connection commands or the addressed device's disconnect command to been completed
105  * up to HCI_COMMAND_COMPLETE_REPLY_TIMEOUT.
106  * </p>
107  * <p>
108  * Environment variable is 'direct_bt.hci.cmd.complete.timeout'.
109  * </p>
110  */
111  const int32_t HCI_COMMAND_POLL_PERIOD;
112 
113  /**
114  * Small ringbuffer capacity for synchronized commands, defaults to 64 messages.
115  * <p>
116  * Environment variable is 'direct_bt.hci.ringsize'.
117  * </p>
118  */
119  const int32_t HCI_EVT_RING_CAPACITY;
120 
121  /**
122  * Debug all HCI event communication
123  * <p>
124  * Environment variable is 'direct_bt.debug.hci.event'.
125  * </p>
126  */
127  const bool DEBUG_EVENT;
128 
129  /**
130  * Debug all scanned HCI 'Advertising Data' (AD) 'Extended Inquiry Response' (EIR) packages.
131  * <p>
132  * Environment variable is 'direct_bt.debug.hci.scan_ad_eir'.
133  * </p>
134  */
135  const bool DEBUG_SCAN_AD_EIR;
136 
137  private:
138  /** Maximum number of packets to wait for until matching a sequential command. Won't block as timeout will limit. */
139  const int32_t HCI_READ_PACKET_MAX_RETRY;
140 
141  public:
142  static HCIEnv& get() noexcept {
143  /**
144  * Thread safe starting with C++11 6.7:
145  *
146  * If control enters the declaration concurrently while the variable is being initialized,
147  * the concurrent execution shall wait for completion of the initialization.
148  *
149  * (Magic Statics)
150  *
151  * Avoiding non-working double checked locking.
152  */
153  static HCIEnv e;
154  return e;
155  }
156  };
157 
158  typedef jau::FunctionDef<bool, const BDAddressAndType& /* addressAndType */,
161 
162  /**
163  * A thread safe singleton handler of the HCI control channel to one controller (BT adapter)
164  * <p>
165  * Implementation utilizes a lock free ringbuffer receiving data within its separate thread.
166  * </p>
167  * <p>
168  * Controlling Environment variables, see {@link HCIEnv}.
169  * </p>
170  */
171  class HCIHandler {
172  public:
175  };
176 
177  static const pid_t pidSelf;
178 
179  const HCIEnv & env;
180 
181  private:
182  class HCIConnection {
183  private:
184  BDAddressAndType addressAndType; // immutable
185  uint16_t handle; // mutable
186 
187  public:
188  HCIConnection(const BDAddressAndType& addressAndType_, const uint16_t handle_)
189  : addressAndType(addressAndType_), handle(handle_) {}
190 
191  HCIConnection(const HCIConnection &o) = default;
192  HCIConnection(HCIConnection &&o) = default;
193  HCIConnection& operator=(const HCIConnection &o) = default;
194  HCIConnection& operator=(HCIConnection &&o) = default;
195 
196  const BDAddressAndType & getAddressAndType() const { return addressAndType; }
197  uint16_t getHandle() const { return handle; }
198 
199  void setHandle(uint16_t newHandle) { handle = newHandle; }
200 
201  bool equals(const BDAddressAndType & other) const
202  { return addressAndType == other; }
203 
204  bool operator==(const HCIConnection& rhs) const {
205  if( this == &rhs ) {
206  return true;
207  }
208  return addressAndType == rhs.addressAndType;
209  }
210 
211  bool operator!=(const HCIConnection& rhs) const
212  { return !(*this == rhs); }
213 
214  std::size_t hash_code() const noexcept {
215  return addressAndType.hash_code();
216  }
217 
218  std::string toString() const {
219  return "HCIConnection[handle "+jau::to_hexstring(handle)+
220  ", address "+addressAndType.toString()+"]";
221  }
222  };
223  typedef std::shared_ptr<HCIConnection> HCIConnectionRef;
224 
225  static MgmtEvent::Opcode translate(HCIEventType evt, HCIMetaEventType met) noexcept;
226 
227  const uint16_t dev_id;
228  POctets rbuffer;
229  HCIComm comm;
230  hci_ufilter filter_mask;
231  std::atomic<uint32_t> metaev_filter_mask;
232  std::atomic<uint64_t> opcbit_filter_mask;
233 
234  inline bool filter_test_metaev(HCIMetaEventType mec) noexcept { return 0 != jau::test_bit_uint32(number(mec)-1, metaev_filter_mask); }
235  inline void filter_put_metaevs(const uint32_t mask) noexcept { metaev_filter_mask=mask; }
236 
237  constexpr static void filter_clear_metaevs(uint32_t &mask) noexcept { mask=0; }
238  constexpr static void filter_all_metaevs(uint32_t &mask) noexcept { mask=0xffffffffU; }
239  inline static void filter_set_metaev(HCIMetaEventType mec, uint32_t &mask) noexcept { jau::set_bit_uint32(number(mec)-1, mask); }
240 
241  inline bool filter_test_opcbit(HCIOpcodeBit opcbit) noexcept { return 0 != jau::test_bit_uint64(number(opcbit), opcbit_filter_mask); }
242  inline void filter_put_opcbit(const uint64_t mask) noexcept { opcbit_filter_mask=mask; }
243 
244  constexpr static void filter_clear_opcbit(uint64_t &mask) noexcept { mask=0; }
245  constexpr static void filter_all_opcbit(uint64_t &mask) noexcept { mask=0xffffffffffffffffUL; }
246  inline static void filter_set_opcbit(HCIOpcodeBit opcbit, uint64_t &mask) noexcept { jau::set_bit_uint64(number(opcbit), mask); }
247 
248  jau::ringbuffer<std::unique_ptr<HCIEvent>, std::nullptr_t, jau::nsize_t> hciEventRing;
249  jau::sc_atomic_bool hciReaderShallStop;
250 
251  std::mutex mtx_hciReaderLifecycle;
252  std::condition_variable cv_hciReaderInit;
253  pthread_t hciReaderThreadId;
254  jau::relaxed_atomic_bool hciReaderRunning;
255 
256  std::recursive_mutex mtx_sendReply; // for sendWith*Reply, process*Command, ..; Recurses from many..
257 
258  /**
259  * Cached bitfield of Local Supported Commands, 64 octets
260  * <pre>
261  * BT Core Spec v5.2: Vol 4, Part E, 6.27 (HCI) Supported Commands
262  * BT Core Spec v5.2: Vol 4, Part E, 7.4.2 Read Local Supported Commands command
263  * </pre>
264  */
265  uint8_t sup_commands[64];
266  jau::relaxed_atomic_bool sup_commands_set;
267 
268  jau::sc_atomic_bool allowClose;
269  std::atomic<BTMode> btMode;
270 
271  std::atomic<ScanType> currentScanType;
272 
273  jau::darray<HCIConnectionRef> connectionList;
274  jau::darray<HCIConnectionRef> disconnectCmdList;
275  std::recursive_mutex mtx_connectionList; // Recurses from disconnect -> findTrackerConnection, addOrUpdateTrackerConnection
276 
277  /** Exclusive [le] connection command (status + pending completed) one at a time */
278  std::mutex mtx_connect_cmd;
279 
280  void zeroSupCommands() noexcept;
281  bool initSupCommands() noexcept;
282 
283  /**
284  * Returns a newly added HCIConnectionRef tracker connection with given parameters, if not existing yet.
285  * <p>
286  * In case the HCIConnectionRef tracker connection already exists,
287  * its handle will be updated (see below) and reference returned.
288  * <p>
289  * Overwrite existing tracked connection handle with given _valid_ handle only, i.e. non zero!
290  * </p>
291  * @param address key to matching connection
292  * @param addrType key to matching connection
293  * @param handle ignored for existing tracker _if_ invalid, i.e. zero.
294  */
295  HCIConnectionRef addOrUpdateHCIConnection(jau::darray<HCIConnectionRef> &list,
296  const BDAddressAndType& addressAndType, const uint16_t handle) noexcept;
297  HCIConnectionRef addOrUpdateTrackerConnection(const BDAddressAndType& addressAndType, const uint16_t handle) noexcept {
298  return addOrUpdateHCIConnection(connectionList, addressAndType, handle);
299  }
300  HCIConnectionRef addOrUpdateDisconnectCmd(const BDAddressAndType& addressAndType, const uint16_t handle) noexcept {
301  return addOrUpdateHCIConnection(disconnectCmdList, addressAndType, handle);
302  }
303 
304  HCIConnectionRef findHCIConnection(jau::darray<HCIConnectionRef> &list, const BDAddressAndType& addressAndType) noexcept;
305  HCIConnectionRef findTrackerConnection(const BDAddressAndType& addressAndType) noexcept {
306  return findHCIConnection(connectionList, addressAndType);
307  }
308  HCIConnectionRef findDisconnectCmd(const BDAddressAndType& addressAndType) noexcept {
309  return findHCIConnection(disconnectCmdList, addressAndType);
310  }
311 
312  HCIConnectionRef findTrackerConnection(const uint16_t handle) noexcept;
313  HCIConnectionRef removeTrackerConnection(const HCIConnectionRef conn) noexcept;
314  int countPendingTrackerConnections() noexcept;
315 
316  HCIConnectionRef removeHCIConnection(jau::darray<HCIConnectionRef> &list, const uint16_t handle) noexcept;
317  HCIConnectionRef removeTrackerConnection(const uint16_t handle) noexcept {
318  return removeHCIConnection(connectionList, handle);
319  }
320  HCIConnectionRef removeDisconnectCmd(const uint16_t handle) noexcept {
321  return removeHCIConnection(disconnectCmdList, handle);
322  }
323 
324  /** One MgmtAdapterEventCallbackList per event type, allowing multiple callbacks to be invoked for each event */
325  std::array<MgmtEventCallbackList, static_cast<uint16_t>(MgmtEvent::Opcode::MGMT_EVENT_TYPE_COUNT)> mgmtEventCallbackLists;
326  inline bool isValidMgmtEventCallbackListsIndex(const MgmtEvent::Opcode opc) const noexcept {
327  return static_cast<uint16_t>(opc) < mgmtEventCallbackLists.size();
328  }
329 
330  HCISMPMsgCallbackList hciSMPMsgCallbackList;
331 
332  std::unique_ptr<MgmtEvent> translate(HCIEvent& ev) noexcept;
333 
334  std::unique_ptr<const SMPPDUMsg> getSMPPDUMsg(const HCIACLData::l2cap_frame & l2cap, const uint8_t * l2cap_data) const noexcept;
335  void hciReaderThreadImpl() noexcept;
336 
337  bool sendCommand(HCICommand &req) noexcept;
338  std::unique_ptr<HCIEvent> getNextReply(HCICommand &req, int32_t & retryCount, const int32_t replyTimeoutMS) noexcept;
339  std::unique_ptr<HCIEvent> getNextCmdCompleteReply(HCICommand &req, HCICommandCompleteEvent **res) noexcept;
340 
341  std::unique_ptr<HCIEvent> processCommandStatus(HCICommand &req, HCIStatusCode *status) noexcept;
342 
343  template<typename hci_cmd_event_struct>
344  std::unique_ptr<HCIEvent> processCommandComplete(HCICommand &req,
345  const hci_cmd_event_struct **res, HCIStatusCode *status) noexcept;
346  template<typename hci_cmd_event_struct>
347  std::unique_ptr<HCIEvent> receiveCommandComplete(HCICommand &req,
348  const hci_cmd_event_struct **res, HCIStatusCode *status) noexcept;
349 
350  template<typename hci_cmd_event_struct>
351  const hci_cmd_event_struct* getReplyStruct(HCIEvent& event, HCIEventType evc, HCIStatusCode *status) noexcept;
352 
353  template<typename hci_cmd_event_struct>
354  const hci_cmd_event_struct* getMetaReplyStruct(HCIEvent& event, HCIMetaEventType mec, HCIStatusCode *status) noexcept;
355 
356  public:
357  HCIHandler(const uint16_t dev_id, const BTMode btMode=BTMode::NONE) noexcept;
358 
359  HCIHandler(const HCIHandler&) = delete;
360  void operator=(const HCIHandler&) = delete;
361 
362  /**
363  * Releases this instance after issuing {@link #close()}.
364  */
365  ~HCIHandler() noexcept { close(); }
366 
367  void close() noexcept;
368 
369  inline BTMode getBTMode() const noexcept { return btMode; }
370 
371  inline void setBTMode(const BTMode mode) noexcept { btMode = mode; }
372 
373  /** Returns true if this mgmt instance is open, connected and hence valid, otherwise false */
374  bool isOpen() const noexcept {
375  return true == allowClose.load() && comm.isOpen();
376  }
377 
378  /** Use extended scanning if HCI_LE_Set_Extended_Scan_Parameters and HCI_LE_Set_Extended_Scan_Enable is supported (Bluetooth 5.0). */
379  bool use_ext_scan() const noexcept{
380  return 0 != ( sup_commands[37] & ( 1 << 5 ) ) &&
381  0 != ( sup_commands[37] & ( 1 << 6 ) );
382  }
383 
384  /** Use extended connection if HCI_LE_Extended_Create_Connection is supported (Bluetooth 5.0). */
385  bool use_ext_conn() const noexcept{
386  return 0 != ( sup_commands[37] & ( 1 << 7 ) );
387  }
388 
389  ScanType getCurrentScanType() const noexcept { return currentScanType.load(); }
390  void setCurrentScanType(const ScanType v) noexcept { currentScanType = v; }
391 
392  std::string toString() const noexcept;
393 
394  /**
395  * Bring up this adapter into a POWERED functional state.
396  */
398 
399  /**
400  * Bring down this adapter into a non-POWERED non-functional state.
401  * <p>
402  * All allocated resources should be freed and the internal state being reset
403  * in compliance to
404  * <pre>
405  * BT Core Spec v5.2: Vol 4, Part E HCI: 7.3.2 Reset command
406  * </pre>
407  * </p>
408  */
410 
411  /**
412  * Reset the adapter.
413  * <p>
414  * The semantics are specific to the HCI host implementation,
415  * however, it shall comply at least with the HCI Reset command
416  * and bring up the device from standby into a POWERED functional state afterwards.
417  * </p>
418  * <pre>
419  * BT Core Spec v5.2: Vol 4, Part E HCI: 7.3.2 Reset command
420  * </pre>
421  */
423 
424  /**
425  * HCI Reset Command
426  * <pre>
427  * BT Core Spec v5.2: Vol 4, Part E HCI: 7.3.2 Reset command
428  * </pre>
429  */
430  HCIStatusCode reset() noexcept;
431 
432  HCIStatusCode getLocalVersion(HCILocalVersion &version) noexcept;
433 
434  /**
435  * Request and return LE_Features for the controller.
436  * <pre>
437  * BT Core Spec v5.2: Vol 6, Part B, 4.6 (LE LL) Feature Support
438  *
439  * BT Core Spec v5.2: Vol 4, Part E, 7.8.3 LE Read Local Supported Features command
440  * </pre>
441  * @param res reference for the resulting LE_Features
442  * @return HCIStatusCode
443  */
445 
446  /**
447  * Sets LE scanning parameters.
448  * <pre>
449  * BT Core Spec v5.2: Vol 4 HCI, Part E HCI Functional: 7.8.64 LE Set Extended Scan Parameters command (Bluetooth 5.0)
450  *
451  * if available, otherwise using
452  *
453  * BT Core Spec v5.2: Vol 4 HCI, Part E HCI Functional: 7.8.10 LE Set Scan Parameters command
454  *
455  *
456  * BT Core Spec v5.2: Vol 6 LE, Part B Link Layer: 4.4.3 Scanning State
457  * </pre>
458  * <p>
459  * Scan parameters control advertising (AD) Protocol Data Unit (PDU) delivery behavior.
460  * </p>
461  * <p>
462  * Should not be called while LE scanning is active, otherwise HCIStatusCode::COMMAND_DISALLOWED will be returned.
463  * </p>
464  *
465  * @param le_scan_active true enables delivery of active scanning PDUs, otherwise no scanning PDUs shall be sent (default)
466  * @param own_mac_type HCILEOwnAddressType::PUBLIC (default) or random/private.
467  * @param le_scan_interval in units of 0.625ms, default value 24 for 15ms; Value range [4 .. 0x4000] for [2.5ms .. 10.24s]
468  * @param le_scan_window in units of 0.625ms, default value 24 for 15ms; Value range [4 .. 0x4000] for [2.5ms .. 10.24s]. Shall be <= le_scan_interval
469  * @param filter_policy 0x00 accepts all PDUs (default), 0x01 only of whitelisted, ...
470  */
472  const HCILEOwnAddressType own_mac_type=HCILEOwnAddressType::PUBLIC,
473  const uint16_t le_scan_interval=24, const uint16_t le_scan_window=24,
474  const uint8_t filter_policy=0x00) noexcept;
475 
476  /**
477  * Starts or stops LE scanning.
478  * <pre>
479  * BT Core Spec v5.2: Vol 4 HCI, Part E HCI Functional: 7.8.65 LE Set Extended Scan Enable command (Bluetooth 5.0)
480  *
481  * if available, otherwise using
482  *
483  * BT Core Spec v5.2: Vol 4, Part E HCI: 7.8.11 LE Set Scan Enable command
484  * </pre>
485  * @param enable true to enable discovery, otherwise false
486  * @param filter_dup true to filter out duplicate AD PDUs (default), otherwise all will be reported.
487  */
488  HCIStatusCode le_enable_scan(const bool enable, const bool filter_dup=true) noexcept;
489 
490  /**
491  * Start LE scanning, i.e. performs le_set_scan_param() and le_enable_scan() in one atomic operation.
492  * <pre>
493  * BT Core Spec v5.2: Vol 4 HCI, Part E HCI Functional: 7.8.64 LE Set Extended Scan Parameters command (Bluetooth 5.0)
494  * BT Core Spec v5.2: Vol 4 HCI, Part E HCI Functional: 7.8.10 LE Set Scan Parameters command
495  * BT Core Spec v5.2: Vol 4 HCI, Part E HCI Functional: 7.8.65 LE Set Extended Scan Enable command (Bluetooth 5.0)
496  * BT Core Spec v5.2: Vol 4, Part E HCI: 7.8.11 LE Set Scan Enable command
497  * </pre>
498  * <p>
499  * Scan parameters control advertising (AD) Protocol Data Unit (PDU) delivery behavior.
500  * </p>
501  * <p>
502  * Should not be called while LE scanning is active, otherwise HCIStatusCode::COMMAND_DISALLOWED will be returned.
503  * </p>
504  * <p>
505  * Method will report errors.
506  * </p>
507  *
508  * @param filter_dup true to filter out duplicate AD PDUs (default), otherwise all will be reported.
509  * @param le_scan_active true enables delivery of active scanning PDUs, otherwise no scanning PDUs shall be sent (default)
510  * @param own_mac_type HCILEOwnAddressType::PUBLIC (default) or random/private.
511  * @param le_scan_interval in units of 0.625ms, default value 24 for 15ms; Value range [4 .. 0x4000] for [2.5ms .. 10.24s]
512  * @param le_scan_window in units of 0.625ms, default value 24 for 15ms; Value range [4 .. 0x4000] for [2.5ms .. 10.24s]. Shall be <= le_scan_interval
513  * @param filter_policy 0x00 accepts all PDUs (default), 0x01 only of whitelisted, ...
514  * @see le_read_local_features()
515  */
516  HCIStatusCode le_start_scan(const bool filter_dup=true,
517  const bool le_scan_active=false,
518  const HCILEOwnAddressType own_mac_type=HCILEOwnAddressType::PUBLIC,
519  const uint16_t le_scan_interval=24, const uint16_t le_scan_window=24,
520  const uint8_t filter_policy=0x00) noexcept;
521 
522  /**
523  * Establish a connection to the given LE peer.
524  * <pre>
525  * BT Core Spec v5.2: Vol 4, Part E HCI: 7.8.66 LE Extended Create Connection command (Bluetooth 5.0)
526  *
527  * if available, otherwise using
528  *
529  * BT Core Spec v5.2: Vol 4, Part E HCI: 7.8.12 LE Create Connection command
530  * </pre>
531  * <p>
532  * Set window to the same value as the interval, enables continuous scanning.
533  * </p>
534  * <p>
535  * The supervising timeout period is the time it takes before a devices gives up on the link if no packets are received.
536  * Hence this parameter influences the responsiveness on a link loss.
537  * A too small number may render the link too unstable, it should be at least 6 times of the connection interval.
538  * <br>
539  * To detect a link loss one can also send a regular ping to check whether the peripheral is still responding, see BTGattHandler::ping().
540  * </p>
541  * <p>
542  * Implementation tries to mitigate HCIStatusCode::COMMAND_DISALLOWED failure due to any pending connection commands,
543  * waiting actively up to HCIEnv::HCI_COMMAND_COMPLETE_REPLY_TIMEOUT, testing every HCIEnv::HCI_COMMAND_POLL_PERIOD if resolved.<br>
544  * <br>
545  * In case of no resolution, i.e. another HCI_LE_Create_Connection command is pending,
546  * HCIStatusCode::COMMAND_DISALLOWED will be returned by the underlying HCI host implementation.
547  * </p>
548  * <p>
549  * Implementation tries to mitigate HCIStatusCode::CONNECTION_ALREADY_EXISTS failure due to a specific pending disconnect command,
550  * waiting actively up to HCIEnv::HCI_COMMAND_COMPLETE_REPLY_TIMEOUT, testing every HCIEnv::HCI_COMMAND_POLL_PERIOD if resolved.<br>
551  * <br>
552  * In case of no resolution, i.e. the connection persists,
553  * HCIStatusCode::CONNECTION_ALREADY_EXISTS will be returned by the underlying HCI host implementation.
554  * </p>
555  * @param peer_bdaddr
556  * @param peer_mac_type
557  * @param own_mac_type
558  * @param le_scan_interval in units of 0.625ms, default value 24 for 15ms; Value range [4 .. 0x4000] for [2.5ms .. 10.24s]
559  * @param le_scan_window in units of 0.625ms, default value 24 for 15ms; Value range [4 .. 0x4000] for [2.5ms .. 10.24s]. Shall be <= le_scan_interval
560  * @param conn_interval_min in units of 1.25ms, default value 12 for 15ms; Value range [6 .. 3200] for [7.5ms .. 4000ms]
561  * @param conn_interval_max in units of 1.25ms, default value 12 for 15ms; Value range [6 .. 3200] for [7.5ms .. 4000ms]
562  * @param conn_latency slave latency in units of connection events, default value 0; Value range [0 .. 0x01F3].
563  * @param supervision_timeout in units of 10ms, default value >= 10 x conn_interval_max, we use HCIConstInt::LE_CONN_MIN_TIMEOUT_MS minimum; Value range [0xA-0x0C80] for [100ms - 32s].
564  * @return
565  */
566  HCIStatusCode le_create_conn(const EUI48 &peer_bdaddr,
567  const HCILEPeerAddressType peer_mac_type=HCILEPeerAddressType::PUBLIC,
568  const HCILEOwnAddressType own_mac_type=HCILEOwnAddressType::PUBLIC,
569  const uint16_t le_scan_interval=24, const uint16_t le_scan_window=24,
570  const uint16_t conn_interval_min=12, const uint16_t conn_interval_max=12,
571  const uint16_t conn_latency=0, const uint16_t supervision_timeout=getHCIConnSupervisorTimeout(0, 15)) noexcept;
572 
573  /**
574  * Establish a connection to the given BREDR (non LE).
575  * <pre>
576  * BT Core Spec v5.2: Vol 4, Part E HCI: 7.1.5 Create Connection command
577  * </pre>
578  * <p>
579  * Implementation tries to mitigate HCIStatusCode::COMMAND_DISALLOWED failure due to any pending connection commands,
580  * waiting actively up to HCIEnv::HCI_COMMAND_COMPLETE_REPLY_TIMEOUT, testing every HCIEnv::HCI_COMMAND_POLL_PERIOD if resolved.<br>
581  * <br>
582  * In case of no resolution, i.e. another HCI_Create_Connection command is pending,
583  * HCIStatusCode::COMMAND_DISALLOWED will be returned by the underlying HCI host implementation.
584  * </p>
585  * <p>
586  * Implementation tries to mitigate HCIStatusCode::CONNECTION_ALREADY_EXISTS failure due to a specific pending disconnect command,
587  * waiting actively up to HCIEnv::HCI_COMMAND_COMPLETE_REPLY_TIMEOUT, testing every HCIEnv::HCI_COMMAND_POLL_PERIOD if resolved.<br>
588  * <br>
589  * In case of no resolution, i.e. the connection persists,
590  * HCIStatusCode::CONNECTION_ALREADY_EXISTS will be returned by the underlying HCI host implementation.
591  * </p>
592  */
593  HCIStatusCode create_conn(const EUI48 &bdaddr,
594  const uint16_t pkt_type=HCI_DM1 | HCI_DM3 | HCI_DM5 | HCI_DH1 | HCI_DH3 | HCI_DH5,
595  const uint16_t clock_offset=0x0000, const uint8_t role_switch=0x01) noexcept;
596 
597  /**
598  * Disconnect an established connection.
599  * <pre>
600  * BT Core Spec v5.2: Vol 4, Part E HCI: 7.1.6 Disconnect command
601  * </pre>
602  */
603  HCIStatusCode disconnect(const uint16_t conn_handle, const BDAddressAndType& addressAndType,
604  const HCIStatusCode reason=HCIStatusCode::REMOTE_USER_TERMINATED_CONNECTION) noexcept;
605 
606  /**
607  * Request and return LE_PHYs bit for the given connection.
608  * <pre>
609  * BT Core Spec v5.2: Vol 4, Part E, 7.8.47 LE Read PHY command (we transfer the sequential value to this bitmask for unification)
610  * </pre>
611  * @param conn_handle
612  * @param addressAndType
613  * @param resRx reference for the resulting receiver LE_PHYs bit
614  * @param resTx reference for the resulting transmitter LE_PHYs bit
615  * @return HCIStatusCode
616  */
617  HCIStatusCode le_read_phy(const uint16_t conn_handle, const BDAddressAndType& addressAndType,
618  LE_PHYs& resRx, LE_PHYs& resTx) noexcept;
619 
620  /**
621  * Reset all internal states, i.e. connection and disconnect lists.
622  * @param powered_on indicates whether the adapter is powered on or not
623  */
624  void resetAllStates(const bool powered_on) noexcept;
625 
626 
627  /** MgmtEventCallback handling */
628 
629  /**
630  * Appends the given MgmtEventCallback to the named MgmtEvent::Opcode list,
631  * if it is not present already (opcode + callback).
632  * @param opc opcode index for callback list, the callback shall be added to
633  * @param cb the to be added callback
634  * @return true if newly added or already existing, false if given MgmtEvent::Opcode is out of supported range.
635  */
636  bool addMgmtEventCallback(const MgmtEvent::Opcode opc, const MgmtEventCallback &cb) noexcept;
637  /** Returns count of removed given MgmtEventCallback from the named MgmtEvent::Opcode list. */
638  int removeMgmtEventCallback(const MgmtEvent::Opcode opc, const MgmtEventCallback &cb) noexcept;
639  /** Removes all MgmtEventCallbacks from the to the named MgmtEvent::Opcode list. */
640  void clearMgmtEventCallbacks(const MgmtEvent::Opcode opc) noexcept;
641 
642  void addSMPMsgCallback(const HCISMPMsgCallback & l);
644 
645  /** Removes all MgmtEventCallbacks from all MgmtEvent::Opcode lists and all SMPSecurityReqCallbacks. */
646  void clearAllCallbacks() noexcept;
647 
648  /** Manually send a MgmtEvent to all of its listeners. */
649  void sendMgmtEvent(const MgmtEvent& event) noexcept;
650  };
651 
652 } // namespace direct_bt
653 
654 #if 0
655 // Injecting specialization of std::hash to namespace std of our types above
656 // Would need to make direct_bt::HCIHandler::HCIConnection accessible
657 namespace std
658 {
659  template<> struct hash<direct_bt::HCIHandler::HCIConnection> {
660  std::size_t operator()(direct_bt::HCIHandler::HCIConnection const& a) const noexcept {
661  return a.hash_code();
662  }
663  };
664 }
665 #endif
666 
667 #endif /* HCI_HANDLER_HPP_ */
668 
direct_bt::HCIHandler::resetAdapter
HCIStatusCode resetAdapter()
Reset the adapter.
Definition: HCIHandler.cpp:868
direct_bt::HCIEnv::HCI_EVT_RING_CAPACITY
const int32_t HCI_EVT_RING_CAPACITY
Small ringbuffer capacity for synchronized commands, defaults to 64 messages.
Definition: HCIHandler.hpp:119
direct_bt::HCIEnv
HCI Singleton runtime environment properties.
Definition: HCIHandler.hpp:66
darray.hpp
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::BDAddressAndType::hash_code
std::size_t hash_code() const noexcept
Implementation uses a lock-free volatile cache.
Definition: BTAddress.hpp:500
jau::root_environment
Base jau environment class, merely to tag all environment settings by inheritance and hence documenta...
Definition: environment.hpp:51
direct_bt::HCIHandler::stopAdapter
HCIStatusCode stopAdapter()
Bring down this adapter into a non-POWERED non-functional state.
Definition: HCIHandler.cpp:843
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::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::HCIHandler::setCurrentScanType
void setCurrentScanType(const ScanType v) noexcept
Definition: HCIHandler.hpp:390
direct_bt
Definition: ATTPDUTypes.hpp:171
direct_bt::operator==
bool operator==(const EUI48Sub &lhs, const EUI48Sub &rhs) noexcept
Definition: BTAddress.hpp:265
direct_bt::MgmtEvent::Opcode
Opcode
Definition: MgmtTypes.hpp:1085
jau::set_bit_uint64
void set_bit_uint64(const uint8_t nr, uint64_t &mask)
Definition: basic_types.hpp:165
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
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::BDAddressAndType::toString
std::string toString() const noexcept
Definition: BTTypes0.cpp:333
jau
Definition: basic_algos.hpp:34
direct_bt::HCIHandler::getCurrentScanType
ScanType getCurrentScanType() const noexcept
Definition: HCIHandler.hpp:389
OctetTypes.hpp
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::ScanType
ScanType
Meta ScanType as derived from BTMode, with defined value mask consisting of BDAddressType bits.
Definition: BTTypes0.hpp:294
direct_bt::HCIHandler::startAdapter
HCIStatusCode startAdapter()
Bring up this adapter into a POWERED functional state.
Definition: HCIHandler.cpp:821
direct_bt::HCIHandler::HCIHandler
HCIHandler(const uint16_t dev_id, const BTMode btMode=BTMode::NONE) noexcept
Definition: HCIHandler.cpp:592
direct_bt::HCIHandler
A thread safe singleton handler of the HCI control channel to one controller (BT adapter)
Definition: HCIHandler.hpp:171
direct_bt::HCISMPMsgCallbackList
jau::cow_darray< HCISMPMsgCallback > HCISMPMsgCallbackList
Definition: HCIHandler.hpp:160
direct_bt::HCIComm::isOpen
bool isOpen() const noexcept
Definition: HCIComm.hpp:81
HCITypes.hpp
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::HCIStatusCode
HCIStatusCode
BT Core Spec v5.2: Vol 1, Part F Controller Error Codes: 1.3 List of Error Codes.
Definition: HCITypes.hpp:124
jau::ordered_atomic< bool, std::memory_order::memory_order_seq_cst >
jau::darray< HCIConnectionRef >
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::HCIOpcodeBit
HCIOpcodeBit
Definition: HCITypes.hpp:410
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::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
direct_bt::HCIHandler::reset
HCIStatusCode reset() noexcept
HCI Reset Command.
Definition: HCIHandler.cpp:884
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::HCIHandler::removeSMPMsgCallback
int removeSMPMsgCallback(const HCISMPMsgCallback &l)
Definition: HCIHandler.cpp:1600
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
jau::set_bit_uint32
void set_bit_uint32(const uint8_t nr, uint32_t &mask)
Definition: basic_types.hpp:147
direct_bt::number
constexpr uint8_t number(const BDAddressType rhs) noexcept
Definition: BTAddress.hpp:67
direct_bt::SMPPDUMsg
Handles the Security Manager Protocol (SMP) using Protocol Data Unit (PDU) encoded messages over L2CA...
Definition: SMPTypes.hpp:644
direct_bt::HCIConstSizeT::PACKET_MAX_SIZE
@ PACKET_MAX_SIZE
Total packet size, guaranteed to be handled by adapter.
direct_bt::HCIEventType
HCIEventType
BT Core Spec v5.2: Vol 4, Part E HCI: 7.7 Events.
Definition: HCITypes.hpp:272
BTTypes0.hpp
direct_bt::HCIHandler::HCI_MAX_MTU
@ HCI_MAX_MTU
Definition: HCIHandler.hpp:174
jau::ringbuffer
Ring buffer implementation, a.k.a circular buffer, exposing lock-free get*(..) and put*(....
Definition: ringbuffer.hpp:115
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< HCISMPMsgCallback >
direct_bt::HCISMPMsgCallback
jau::FunctionDef< bool, const BDAddressAndType &, const SMPPDUMsg &, const HCIACLData::l2cap_frame & > HCISMPMsgCallback
Definition: HCIHandler.hpp:159
le_scan_active
static bool le_scan_active
Definition: dbt_scanner10.cpp:632
direct_bt::HCIComm
Read/Write HCI communication channel.
Definition: HCIComm.hpp:52
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
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::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::getHCIConnSupervisorTimeout
constexpr int32_t getHCIConnSupervisorTimeout(const uint16_t conn_latency, const uint16_t conn_interval_max_ms, const uint16_t min_result_ms=number(HCIConstInt::LE_CONN_MIN_TIMEOUT_MS), const uint16_t multiplier=10) noexcept
Defining the supervising timeout for LE connections to be a multiple of the maximum connection interv...
Definition: HCITypes.hpp:97
direct_bt::HCIEnv::DEBUG_EVENT
const bool DEBUG_EVENT
Debug all HCI event communication.
Definition: HCIHandler.hpp:127
direct_bt::HCIHandler::resetAllStates
void resetAllStates(const bool powered_on) noexcept
Reset all internal states, i.e.
Definition: HCIHandler.cpp:168
direct_bt::MgmtEvent::Opcode::MGMT_EVENT_TYPE_COUNT
@ MGMT_EVENT_TYPE_COUNT
direct_bt::HCIHandler::close
void close() noexcept
Definition: HCIHandler.cpp:766
MgmtTypes.hpp
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::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::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
ringbuffer.hpp
direct_bt::HCIHandler::operator=
void operator=(const HCIHandler &)=delete
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
direct_bt::HCIHandler::addSMPMsgCallback
void addSMPMsgCallback(const HCISMPMsgCallback &l)
Definition: HCIHandler.cpp:1597
jau::test_bit_uint32
uint32_t test_bit_uint32(const uint8_t nr, const uint32_t mask)
Definition: basic_types.hpp:159
direct_bt::HCILocalVersion
Definition: HCITypes.hpp:1108
direct_bt::HCIHandler::env
const HCIEnv & env
Definition: HCIHandler.hpp:179
direct_bt::HCIHandler::getBTMode
BTMode getBTMode() const noexcept
Definition: HCIHandler.hpp:369
direct_bt::HCIHandler::setBTMode
void setBTMode(const BTMode mode) noexcept
Definition: HCIHandler.hpp:371
direct_bt::HCIEnv::HCI_COMMAND_POLL_PERIOD
const int32_t HCI_COMMAND_POLL_PERIOD
Poll period for certain HCI commands actively waiting for clearance, defaults to 125ms.
Definition: HCIHandler.hpp:111
HCIComm.hpp
filter_policy
static const uint8_t filter_policy
Definition: dbt_scanner10.cpp:635
direct_bt::HCIEnv::HCI_COMMAND_STATUS_REPLY_TIMEOUT
const int32_t HCI_COMMAND_STATUS_REPLY_TIMEOUT
Timeout for HCI command status replies, excluding command complete, defaults to 3s.
Definition: HCIHandler.hpp:89
direct_bt::POctets
Persistent octet data, i.e.
Definition: OctetTypes.hpp:451
direct_bt::operator!=
bool operator!=(const EUI48Sub &lhs, const EUI48Sub &rhs) noexcept
Definition: BTAddress.hpp:275
direct_bt::HCILEPeerAddressType
HCILEPeerAddressType
HCI LE Address-Type is PUBLIC: 0x00, RANDOM: 0x01.
Definition: BTAddress.hpp:120
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::LE_PHYs
LE_PHYs
LE Transport PHY bit values.
Definition: BTTypes0.hpp:175
direct_bt::BDAddressAndType
Unique Bluetooth EUI48 address and BDAddressType tuple.
Definition: BTAddress.hpp:417
direct_bt::HCIHandler::pidSelf
static const pid_t pidSelf
Definition: HCIHandler.hpp:177
direct_bt::HCIEnv::HCI_COMMAND_COMPLETE_REPLY_TIMEOUT
const int32_t HCI_COMMAND_COMPLETE_REPLY_TIMEOUT
Timeout for HCI command complete replies, defaults to 10s.
Definition: HCIHandler.hpp:98
direct_bt::HCIHandler::DefaultsSizeT
DefaultsSizeT
Definition: HCIHandler.hpp:173
direct_bt::BTMode
BTMode
Bluetooth adapter operating mode.
Definition: BTTypes0.hpp:56
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
environment.hpp
jau::test_bit_uint64
uint64_t test_bit_uint64(const uint8_t nr, const uint64_t mask)
Definition: basic_types.hpp:177