26#ifndef HCI_HANDLER_HPP_
27#define HCI_HANDLER_HPP_
147 const int32_t HCI_READ_PACKET_MAX_RETRY;
190 class HCIConnection {
197 HCIConnection(
const BDAddressAndType& addressAndType_,
const uint16_t handle_)
198 : visibleAddressAndType(addressAndType_), addressAndType(addressAndType_), handle(handle_) {}
200 HCIConnection(
const HCIConnection &o) =
default;
201 HCIConnection(HCIConnection &&o) =
default;
202 HCIConnection&
operator=(
const HCIConnection &o) =
default;
203 HCIConnection&
operator=(HCIConnection &&o) =
default;
205 const BDAddressAndType & getVisibleAddressAndType()
const {
return visibleAddressAndType; }
206 const BDAddressAndType & getAddressAndType()
const {
return addressAndType; }
207 void setResolvAddrAndType(
const BDAddressAndType& val) { addressAndType = val; }
209 uint16_t getHandle()
const {
return handle; }
211 void setHandle(uint16_t newHandle) { handle = newHandle; }
214 {
return addressAndType == other || visibleAddressAndType == other; }
216 bool operator==(
const HCIConnection& rhs)
const {
220 return addressAndType == rhs.addressAndType || visibleAddressAndType == rhs.visibleAddressAndType;
223 bool operator!=(
const HCIConnection& rhs)
const
224 {
return !(*
this == rhs); }
226 std::size_t hash_code()
const noexcept {
231 std::string resaddr_s = visibleAddressAndType != addressAndType ?
", visible "+visibleAddressAndType.
toString() :
"";
233 ", address "+addressAndType.
toString()+resaddr_s+
"]";
244 const uint16_t dev_id;
247 hci_ufilter filter_mask;
248 std::atomic<uint32_t> metaev_filter_mask;
249 std::atomic<uint64_t> opcbit_filter_mask;
252 inline void filter_put_metaevs(
const uint32_t mask)
noexcept { metaev_filter_mask=mask; }
254 constexpr static void filter_clear_metaevs(uint32_t &mask)
noexcept { mask=0; }
255 constexpr static void filter_all_metaevs(uint32_t &mask)
noexcept { mask=0xffffffffU; }
259 inline void filter_put_opcbit(
const uint64_t mask)
noexcept { opcbit_filter_mask=mask; }
261 constexpr static void filter_clear_opcbit(uint64_t &mask)
noexcept { mask=0; }
262 constexpr static void filter_all_opcbit(uint64_t &mask)
noexcept { mask=0xffffffffffffffffUL; }
268 std::recursive_mutex mtx_sendReply;
278 uint8_t sup_commands[64];
282 std::atomic<BTMode> btMode;
284 std::atomic<ScanType> currentScanType;
289 std::recursive_mutex mtx_connectionList;
292 std::mutex mtx_connect_cmd;
295 const BDAddressAndType& visibleAddressAndType,
const BDAddressAndType& addressAndType)
noexcept;
299 setResolvHCIConnectionAddr(connectionList, visibleAddressAndType, addressAndType);
300 setResolvHCIConnectionAddr(disconnectCmdList, visibleAddressAndType, addressAndType);
319 return addOrUpdateHCIConnection(connectionList, addressAndType, handle);
321 HCIConnectionRef addOrUpdateDisconnectCmd(
const BDAddressAndType& addressAndType,
const uint16_t handle)
noexcept {
322 return addOrUpdateHCIConnection(disconnectCmdList, addressAndType, handle);
326 HCIConnectionRef findTrackerConnection(
const BDAddressAndType& addressAndType)
noexcept {
327 return findHCIConnection(connectionList, addressAndType);
329 HCIConnectionRef findDisconnectCmd(
const BDAddressAndType& addressAndType)
noexcept {
330 return findHCIConnection(disconnectCmdList, addressAndType);
335 size_type countPendingTrackerConnections() noexcept;
336 size_type getTrackerConnectionCount() noexcept;
340 return removeHCIConnection(connectionList, handle);
343 return removeHCIConnection(disconnectCmdList, handle);
348 inline bool isValidMgmtEventCallbackListsIndex(
const MgmtEvent::Opcode opc)
const noexcept {
349 return static_cast<uint16_t
>(opc) < mgmtEventCallbackLists.size();
354 std::unique_ptr<MgmtEvent> translate(HCIEvent& ev)
noexcept;
355 std::unique_ptr<MgmtEvent> translate(HCICommand& ev)
noexcept;
357 std::unique_ptr<const SMPPDUMsg> getSMPPDUMsg(
const HCIACLData::l2cap_frame & l2cap,
const uint8_t * l2cap_data)
const noexcept;
361 bool sendCommand(HCICommand &req,
const bool quiet=
false) noexcept;
362 std::unique_ptr<HCIEvent> getNextReply(HCICommand &req, int32_t & retryCount, const
jau::
fraction_i64& replyTimeout) noexcept;
363 std::unique_ptr<HCIEvent> getNextCmdCompleteReply(HCICommand &req, HCICommandCompleteEvent **res) noexcept;
365 std::unique_ptr<HCIEvent> processCommandStatus(HCICommand &req,
HCIStatusCode *status, const
bool quiet=false) noexcept;
367 template<typename hci_cmd_event_struct>
368 std::unique_ptr<HCIEvent> processCommandComplete(HCICommand &req,
370 const
bool quiet=false) noexcept;
371 template<typename hci_cmd_event_struct>
372 std::unique_ptr<HCIEvent> receiveCommandComplete(HCICommand &req,
374 const
bool quiet=false) noexcept;
376 template<typename hci_cmd_event_struct>
379 template<typename hci_cmd_event_struct>
386 void zeroSupCommands() noexcept;
387 bool initSupCommands() noexcept;
398 void close() noexcept;
406 return true == allowClose.
load() && comm.
is_open();
411 return 0 != ( sup_commands[37] & ( 1 << 5 ) ) &&
412 0 != ( sup_commands[37] & ( 1 << 6 ) );
417 return 0 != ( sup_commands[37] & ( 1 << 7 ) );
420 bool use_resolv_add() const noexcept {
return 0 != ( sup_commands[34] & ( 1 << 3 ) ); }
421 bool use_resolv_del() const noexcept {
return 0 != ( sup_commands[34] & ( 1 << 4 ) ); }
423 bool use_resolv_size() const noexcept {
return 0 != ( sup_commands[34] & ( 1 << 6 ) ); }
445 std::string
toString() const noexcept;
547 HCIStatusCode check_open_connection(
const std::string& caller,
549 const bool addUntrackedConn =
false);
696 const uint16_t conn_interval_min=8, const uint16_t conn_interval_max=12,
720 const uint16_t pkt_type=HCI_DM1 | HCI_DM3 | HCI_DM5 | HCI_DH1 | HCI_DH3 | HCI_DH5,
721 const uint16_t clock_offset=0x0000, const uint8_t role_switch=0x01) noexcept;
736 jau::uint128dp_t& peer_irk,
jau::uint128dp_t& local_irk) noexcept;
756 jau::
EUI48& peerResolvableAddress) noexcept;
764 jau::
EUI48& localResolvableAddress) noexcept;
998 template<>
struct hash<
direct_bt::HCIHandler::HCIConnection> {
999 std::size_t operator()(direct_bt::HCIHandler::HCIConnection
const& a)
const noexcept {
1000 return a.hash_code();
Unique Bluetooth EUI48 address and BDAddressType tuple.
std::size_t hash_code() const noexcept
Implementation uses a lock-free volatile cache.
std::string toString() const noexcept
Collection of 'Extended Advertising Data' (EAD), 'Advertising Data' (AD) or 'Extended Inquiry Respons...
Read/Write HCI communication channel.
bool is_open() const noexcept
HCI Singleton runtime environment properties.
static HCIEnv & get() noexcept
const jau::fraction_i64 HCI_COMMAND_STATUS_REPLY_TIMEOUT
Timeout for HCI command status replies, excluding command complete, defaults to 3s.
const jau::fraction_i64 HCI_READER_THREAD_POLL_TIMEOUT
Poll timeout for HCI reader thread, defaults to 10s.
const int32_t HCI_EVT_RING_CAPACITY
Small ringbuffer capacity for synchronized commands, defaults to 64 messages.
const bool DEBUG_EVENT
Debug all HCI event communication.
const jau::fraction_i64 HCI_COMMAND_POLL_PERIOD
Poll period for certain HCI commands actively waiting for clearance, defaults to 125ms.
const jau::fraction_i64 HCI_COMMAND_COMPLETE_REPLY_TIMEOUT
Timeout for HCI command complete replies, defaults to 10s.
const bool DEBUG_SCAN_AD_EIR
Debug all scanned HCI 'Advertising Data' (AD) 'Extended Inquiry Response' (EIR) packages.
A thread safe singleton handler of the HCI control channel to one controller (BT adapter)
bool use_resolv_del() const noexcept
bool use_resolv_readPeerRA() const noexcept
bool use_ext_adv() const noexcept
Use extended advertising if LE_Features::LE_Ext_Adv is set (Bluetooth 5.0).
void setBTMode(const BTMode mode) noexcept
bool use_ext_conn() const noexcept
Use extended connection if HCI_LE_Extended_Create_Connection is supported (Bluetooth 5....
bool use_resolv_clear() const noexcept
bool isOpen() const noexcept
Returns true if this mgmt instance is open, connected and hence valid, otherwise false.
std::shared_ptr< HCIConnection > HCIConnectionRef
bool use_resolv_readLocalRA() const noexcept
HCIStatusCode le_clear_resolv_list() noexcept
BT Core Spec v5.2: Vol 4, Part E HCI: 7.8.40 LE Clear Resolving List command.
HCIStatusCode le_read_remote_features(const uint16_t conn_handle, const BDAddressAndType &peerAddressAndType) noexcept
Request supported LE_Features from remote device.
bool isAdvertising() const noexcept
Advertising is enabled via le_start_adv() or le_enable_adv().
jau::darray< HCIConnectionRef, size_type > HCIConnectionRefList_t
HCIStatusCode le_enable_adv(const bool enable) noexcept
Enables or disabled advertising.
bool use_resolv_size() const noexcept
HCIStatusCode le_enable_scan(const bool enable, const bool filter_dup=true) noexcept
Starts or stops LE scanning.
BTMode getBTMode() const noexcept
bool use_resolv_add() const noexcept
HCIStatusCode resetAdapter(const PostShutdownFunc &user_post_shutdown)
Complete adapter reset.
void clearAllCallbacks() noexcept
Removes all MgmtEventCallbacks from all MgmtEvent::Opcode lists and all SMPSecurityReqCallbacks.
bool addMgmtEventCallback(const MgmtEvent::Opcode opc, const MgmtEventCallback &cb) noexcept
MgmtEventCallback handling
HCIStatusCode le_read_resolv_list_size(uint32_t &size_res) noexcept
BT Core Spec v5.2: Vol 4, Part E HCI: 7.8.41 LE Read Resolving List Size command.
void clearMgmtEventCallbacks(const MgmtEvent::Opcode opc) noexcept
Removes all MgmtEventCallbacks from the to the named MgmtEvent::Opcode list.
LE_Features le_get_local_features() noexcept
Return previously fetched LE_Features for the controller via initSupCommands() via resetAllStates()
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).
HCIStatusCode le_set_phy(const uint16_t conn_handle, const BDAddressAndType &peerAddressAndType, const LE_PHYs Tx, const LE_PHYs Rx) noexcept
Sets preference of used LE_PHYs for the given connection.
HCIStatusCode le_start_adv(const EInfoReport &eir, const EIRDataType adv_mask=EIRDataType::FLAGS|EIRDataType::SERVICE_UUID, const EIRDataType scanrsp_mask=EIRDataType::NAME|EIRDataType::CONN_IVAL, const EUI48 &peer_bdaddr=EUI48::ANY_DEVICE, const HCILEOwnAddressType own_mac_type=HCILEOwnAddressType::PUBLIC, const HCILEOwnAddressType peer_mac_type=HCILEOwnAddressType::PUBLIC, const uint16_t adv_interval_min=160, const uint16_t adv_interval_max=480, const AD_PDU_Type adv_type=AD_PDU_Type::ADV_IND, const uint8_t adv_chan_map=0x07, const uint8_t filter_policy=0x00) noexcept
Starts advertising.
HCIStatusCode le_read_phy(const uint16_t conn_handle, const BDAddressAndType &peerAddressAndType, LE_PHYs &resTx, LE_PHYs &resRx) noexcept
Request and return LE_PHYs bit for the given connection.
HCIStatusCode le_set_default_phy(const LE_PHYs Tx, const LE_PHYs Rx) noexcept
Sets default preference of used LE_PHYs for all subsequent LE connections.
HCIStatusCode le_start_scan(const bool filter_dup=true, const bool le_scan_active=true, 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.
bool resetAllStates(const bool powered_on) noexcept
Reset all internal states, i.e.
ScanType getCurrentScanType() const noexcept
size_type removeMgmtEventCallback(const MgmtEvent::Opcode opc, const MgmtEventCallback &cb) noexcept
Returns count of removed given MgmtEventCallback from the named MgmtEvent::Opcode list.
void sendMgmtEvent(const MgmtEvent &event) noexcept
Manually send a MgmtEvent to all of its listeners.
HCIStatusCode le_add_to_resolv_list(const BDAddressAndType &peerIdentityAddressAndType, jau::uint128dp_t &peer_irk, jau::uint128dp_t &local_irk) noexcept
BT Core Spec v5.2: Vol 4, Part E HCI: 7.8.38 LE Add Device To Resolving List command.
HCIStatusCode getLocalVersion(HCILocalVersion &version) noexcept
HCIStatusCode le_set_addr_resolv_enable(const bool enable) noexcept
BT Core Spec v5.2: Vol 4, Part E HCI: 7.8.44 LE Set Address Resolution Enable command.
HCIStatusCode le_read_peer_resolv_addr(const BDAddressAndType &peerIdentityAddressAndType, jau::EUI48 &peerResolvableAddress) noexcept
BT Core Spec v5.2: Vol 4, Part E HCI: 7.8.42 LE Read Peer Resolvable Address command.
void addSMPMsgCallback(const HCISMPMsgCallback &l)
std::string toString() const noexcept
void setCurrentScanType(const ScanType v) noexcept
HCIStatusCode le_del_from_resolv_list(const BDAddressAndType &peerIdentityAddressAndType) noexcept
BT Core Spec v5.2: Vol 4, Part E HCI: 7.8.39 LE Remove Device From Resolving List command.
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=8, 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.
HCIStatusCode disconnect(const uint16_t conn_handle, const BDAddressAndType &peerAddressAndType, const HCIStatusCode reason=HCIStatusCode::REMOTE_USER_TERMINATED_CONNECTION) noexcept
Disconnect an established connection.
HCIStatusCode le_read_local_resolv_addr(const BDAddressAndType &peerIdentityAddressAndType, jau::EUI48 &localResolvableAddress) noexcept
BT Core Spec v5.2: Vol 4, Part E HCI: 7.8.43 LE Read Local Resolvable Address command.
bool use_resolv_enable() const noexcept
void operator=(const HCIHandler &)=delete
HCIHandler(const uint16_t dev_id, const BTMode btMode=BTMode::NONE) noexcept
size_type removeSMPMsgCallback(const HCISMPMsgCallback &l)
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...
void setResolvHCIConnectionAddr(const BDAddressAndType &visibleAddressAndType, const BDAddressAndType &addressAndType) noexcept
uint16_t opcode, uint16_t dev-id, uint16_t param_size
Handles the Security Manager Protocol (SMP) using Protocol Data Unit (PDU) encoded messages over L2CA...
Persistent endian aware octet data, i.e.
Class template jau::function is a general-purpose static-polymorphic function wrapper.
Ring buffer implementation, a.k.a circular buffer, exposing lock-free get*(..) and put*(....
Base jau environment class, merely to tag all environment settings by inheritance and hence documenta...
Service runner, a reusable dedicated thread performing custom user services.
static const uint8_t filter_policy
static const uint16_t le_scan_interval
static const uint16_t le_scan_window
static const bool filter_dup
static bool le_scan_active
static const uint16_t adv_interval_max
static const uint8_t adv_chan_map
static const uint16_t adv_interval_min
static const AD_PDU_Type adv_type
jau::cow_darray< HCISMPMsgCallback > HCISMPMsgCallbackList
HCIEventType
BT Core Spec v5.2: Vol 4, Part E HCI: 7.7 Events.
HCIMetaEventType
BT Core Spec v5.2: Vol 4, Part E HCI: 7.7.65 LE Meta event.
jau::function< void(const BDAddressAndType &, const SMPPDUMsg &, const HCIACLData::l2cap_frame &)> HCISMPMsgCallback
@ PACKET_MAX_SIZE
Total packet size, guaranteed to be handled by adapter.
bool operator==(const BTAdapter &lhs, const BTAdapter &rhs) noexcept
BTMode
Bluetooth adapter operating mode.
LE_Features
HCI Supported Commands.
LE_PHYs
LE Transport PHY bit values.
HCILEPeerAddressType
HCI LE Address-Type is PUBLIC: 0x00, RANDOM: 0x01.
ScanType
Meta ScanType as derived from BTMode, with defined value mask consisting of BDAddressType bits.
AD_PDU_Type
LE Advertising (AD) Protocol Data Unit (PDU) Types.
bool operator!=(const BTAdapter &lhs, const BTAdapter &rhs) noexcept
constexpr uint16_t getHCIConnSupervisorTimeout(const uint16_t conn_latency, const uint16_t conn_interval_max_ms, const uint16_t min_result_ms=number(HCIConstInt::LE_CONN_MIN_TIMEOUT_MS), const uint16_t multiplier=10) noexcept
Defining the supervising timeout for LE connections to be a multiple of the maximum connection interv...
HCIStatusCode
BT Core Spec v5.2: Vol 1, Part F Controller Error Codes: 1.3 List of Error Codes.
constexpr bool is_set(const LE_Features mask, const LE_Features bit) noexcept
constexpr uint8_t number(const DiscoveryPolicy rhs) noexcept
EIRDataType
Bit mask of 'Extended Inquiry Response' (EIR) data fields, indicating a set of related data.
@ PUBLIC
Public Device Address.
std::enable_if< std::is_floating_point_v< T >, bool >::type constexpr equals(const T &a, const T &b, const T &epsilon=std::numeric_limits< T >::epsilon()) noexcept
Returns true if both values are equal, i.e.
fraction< int64_t > fraction_i64
fraction using int64_t as integral type
uint_fast32_t nsize_t
Natural 'size_t' alternative using uint_fast32_t as its natural sized type.
void set_bit_uint32(const uint8_t nr, uint32_t &mask)
void set_bit_uint64(const uint8_t nr, uint64_t &mask)
uint64_t test_bit_uint64(const uint8_t nr, const uint64_t mask)
uint32_t test_bit_uint32(const uint8_t nr, const uint32_t mask)
std::string to_hexstring(value_type const &v) noexcept
Produce a lower-case hexadecimal string representation of the given pointer.
__pack(...): Produces MSVC, clang and gcc compatible lead-in and -out macros.
Representing ACL Datas' L2CAP Frame.
A packed 48 bit EUI-48 identifier, formerly known as MAC-48 or simply network device MAC address (Med...
CXX_ALWAYS_INLINE _Tp load() const noexcept