/*
* Author: Sven Gothel
* Also see {@link DBTEnv::getExplodingProperties(const std::string & prefixDomain)}.
*
* Environment variable is 'direct_bt.hci.reader.timeout'.
*
* Environment variable is 'direct_bt.hci.cmd.status.timeout'.
*
* Environment variable is 'direct_bt.hci.cmd.complete.timeout'.
*
* Used for LE_Create_Connection or Create_Connection
* when waiting for any pending connection commands or the addressed device's disconnect command to been completed
* up to HCI_COMMAND_COMPLETE_REPLY_TIMEOUT.
*
* Environment variable is 'direct_bt.hci.cmd.complete.timeout'.
*
* Environment variable is 'direct_bt.hci.ringsize'.
*
* Environment variable is 'direct_bt.debug.hci.event'.
*
* Environment variable is 'direct_bt.debug.hci.scan_ad_eir'.
*
* Implementation utilizes a lock free ringbuffer receiving data within its separate thread.
*
* Controlling Environment variables, see {@link HCIEnv}.
*
* In case the HCIConnectionRef tracker connection already exists,
* its handle will be updated (see below) and reference returned.
*
* Overwrite existing tracked connection handle with given _valid_ handle only, i.e. non zero!
*
* Must be explicitly called with `powered_on=true` when adapter is powered on!
*
* Currently used in resetAdapter() only.
*
* All allocated resources should be freed and the internal state being reset
* in compliance to
*
* BT Core Spec v5.2: Vol 4, Part E, 6.27 (HCI) Supported Commands
* BT Core Spec v5.2: Vol 4, Part E, 7.4.2 Read Local Supported Commands command
*
*/
uint8_t sup_commands[64];
jau::relaxed_atomic_bool sup_commands_set;
jau::sc_atomic_bool allowClose;
std::atomic
* BT Core Spec v5.2: Vol 4, Part E HCI: 7.3.2 Reset command
*
*
* Currently used in resetAdapter() only. *
* @return HCIStatusCode */ HCIStatusCode stopAdapter(); public: /** * Use post shutdown function, considered to be `noexcept`. * * `HCIStatusCode post_shutdown() noexcept` * * @return HCIStatusCode::SUCCESS to continue the process, otherwise to abort process. */ typedef std::function* BT Core Spec v5.2: Vol 4, Part E HCI: 7.3.2 Reset command ** * @param user_post_shutdown optional custom user function to be executed after successful adapter shutdown. * If function is not null and returns false, the adapter will not be brought up again. * * @return HCIStatusCode */ HCIStatusCode resetAdapter(PostShutdownFunc user_post_shutdown); /** * HCI Reset Command * * Consider using resetAdapter(). * *
* BT Core Spec v5.2: Vol 4, Part E HCI: 7.3.2 Reset command ** @see resetAdapter() */ HCIStatusCode reset() noexcept; HCIStatusCode getLocalVersion(HCILocalVersion &version) noexcept; /** * Return previously fetched LE_Features for the controller via initSupCommands() via resetAllStates() *
* BT Core Spec v5.2: Vol 6, Part B, 4.6 (LE LL) Feature Support * * BT Core Spec v5.2: Vol 4, Part E, 7.8.3 LE Read Local Supported Features command ** @param res reference for the resulting LE_Features * @return HCIStatusCode * @see initSupCommands() * @see resetAllStates() */ LE_Features le_get_local_features() noexcept { return le_ll_feats; } private: /** * Return HCIStatusCode::SUCCESS if isOpen() and the conn_handle is tracked * and matching the give peerAddressAndType * * @param caller caller method base-name for DBG_ or ERR_PRINT. * @param conn_handle * @param peerAddressAndType * @param addUntrackedConn true adds connection if not tracked, * otherwise return HCIStatusCode::INVALID_HCI_COMMAND_PARAMETERS (default) * @return HCIStatusCode */ HCIStatusCode check_open_connection(const std::string& caller, const uint16_t conn_handle, const BDAddressAndType& peerAddressAndType, const bool addUntrackedConn = false); public: /** * Request supported LE_Features from remote device. *
* BT Core Spec v5.2: Vol 6, Part B, 4.6 (LE LL) Feature Support * * BT Core Spec v5.2: Vol 4, Part E, 7.8.21 LE Read Remote Features command ** * Method returns immediate without result. * * Result is being delivered off-thread via HCIMetaEventType::LE_REMOTE_FEAT_COMPLETE, see *
* BT Core Spec v5.2: Vol 4, Part E, 7.7.65.4 LE Read Remote Features Complete event ** @return HCIStatusCode */ HCIStatusCode le_read_remote_features(const uint16_t conn_handle, const BDAddressAndType& peerAddressAndType) noexcept; private: /** * Sets LE scanning parameters. *
* BT Core Spec v5.2: Vol 4 HCI, Part E HCI Functional: 7.8.64 LE Set Extended Scan Parameters command (Bluetooth 5.0) * * if available, otherwise using * * BT Core Spec v5.2: Vol 4 HCI, Part E HCI Functional: 7.8.10 LE Set Scan Parameters command * * * BT Core Spec v5.2: Vol 6 LE, Part B Link Layer: 4.4.3 Scanning State **
* Scan parameters control advertising (AD) Protocol Data Unit (PDU) delivery behavior. *
** Should not be called while LE scanning is active, otherwise HCIStatusCode::COMMAND_DISALLOWED will be returned. *
* * @param le_scan_active true enables delivery of active scanning PDUs, otherwise no scanning PDUs shall be sent (default) * @param own_mac_type HCILEOwnAddressType::PUBLIC (default) or random/private. * @param le_scan_interval in units of 0.625ms, default value 24 for 15ms; Value range [4 .. 0x4000] for [2.5ms .. 10.24s] * @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 * @param filter_policy 0x00 accepts all PDUs (default), 0x01 only of whitelisted, ... */ 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; public: /** * Starts or stops LE scanning. ** BT Core Spec v5.2: Vol 4 HCI, Part E HCI Functional: 7.8.65 LE Set Extended Scan Enable command (Bluetooth 5.0) * * if available, otherwise using * * BT Core Spec v5.2: Vol 4, Part E HCI: 7.8.11 LE Set Scan Enable command ** @param enable true to enable discovery, otherwise false * @param filter_dup true to filter out duplicate AD PDUs (default), otherwise all will be reported. */ HCIStatusCode le_enable_scan(const bool enable, const bool filter_dup=true) noexcept; /** * Start LE scanning, i.e. performs le_set_scan_param() and le_enable_scan() in one atomic operation. *
* BT Core Spec v5.2: Vol 4 HCI, Part E HCI Functional: 7.8.64 LE Set Extended Scan Parameters command (Bluetooth 5.0) * BT Core Spec v5.2: Vol 4 HCI, Part E HCI Functional: 7.8.10 LE Set Scan Parameters command * BT Core Spec v5.2: Vol 4 HCI, Part E HCI Functional: 7.8.65 LE Set Extended Scan Enable command (Bluetooth 5.0) * BT Core Spec v5.2: Vol 4, Part E HCI: 7.8.11 LE Set Scan Enable command **
* Scan parameters control advertising (AD) Protocol Data Unit (PDU) delivery behavior. *
** Should not be called while LE scanning is active, otherwise HCIStatusCode::COMMAND_DISALLOWED will be returned. *
** Method will report errors. *
* * @param filter_dup true to filter out duplicate AD PDUs (default), otherwise all will be reported. * @param le_scan_active true enables delivery of active scanning PDUs like EIR w/ device name (default), otherwise no scanning PDUs shall be sent. * @param own_mac_type HCILEOwnAddressType::PUBLIC (default) or random/private. * @param le_scan_interval in units of 0.625ms, default value 24 for 15ms; Value range [4 .. 0x4000] for [2.5ms .. 10.24s] * @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 * @param filter_policy 0x00 accepts all PDUs (default), 0x01 only of whitelisted, ... * @see le_read_local_features() */ 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; /** * Establish a connection to the given LE peer. ** BT Core Spec v5.2: Vol 4, Part E HCI: 7.8.66 LE Extended Create Connection command (Bluetooth 5.0) * * if available, otherwise using * * BT Core Spec v5.2: Vol 4, Part E HCI: 7.8.12 LE Create Connection command **
* Set window to the same value as the interval, enables continuous scanning. *
*
* The supervising timeout period is the time it takes before a devices gives up on the link if no packets are received.
* Hence this parameter influences the responsiveness on a link loss.
* A too small number may render the link too unstable, it should be at least 6 times of the connection interval.
*
* To detect a link loss one can also send a regular ping to check whether the peripheral is still responding, see BTGattHandler::ping().
*
* Implementation tries to mitigate HCIStatusCode::COMMAND_DISALLOWED failure due to any pending connection commands,
* waiting actively up to HCIEnv::HCI_COMMAND_COMPLETE_REPLY_TIMEOUT, testing every HCIEnv::HCI_COMMAND_POLL_PERIOD if resolved.
*
* In case of no resolution, i.e. another HCI_LE_Create_Connection command is pending,
* HCIStatusCode::COMMAND_DISALLOWED will be returned by the underlying HCI host implementation.
*
* Implementation tries to mitigate HCIStatusCode::CONNECTION_ALREADY_EXISTS failure due to a specific pending disconnect command,
* waiting actively up to HCIEnv::HCI_COMMAND_COMPLETE_REPLY_TIMEOUT, testing every HCIEnv::HCI_COMMAND_POLL_PERIOD if resolved.
*
* In case of no resolution, i.e. the connection persists,
* HCIStatusCode::CONNECTION_ALREADY_EXISTS will be returned by the underlying HCI host implementation.
*
* BT Core Spec v5.2: Vol 4, Part E HCI: 7.1.5 Create Connection command **
* Implementation tries to mitigate HCIStatusCode::COMMAND_DISALLOWED failure due to any pending connection commands,
* waiting actively up to HCIEnv::HCI_COMMAND_COMPLETE_REPLY_TIMEOUT, testing every HCIEnv::HCI_COMMAND_POLL_PERIOD if resolved.
*
* In case of no resolution, i.e. another HCI_Create_Connection command is pending,
* HCIStatusCode::COMMAND_DISALLOWED will be returned by the underlying HCI host implementation.
*
* Implementation tries to mitigate HCIStatusCode::CONNECTION_ALREADY_EXISTS failure due to a specific pending disconnect command,
* waiting actively up to HCIEnv::HCI_COMMAND_COMPLETE_REPLY_TIMEOUT, testing every HCIEnv::HCI_COMMAND_POLL_PERIOD if resolved.
*
* In case of no resolution, i.e. the connection persists,
* HCIStatusCode::CONNECTION_ALREADY_EXISTS will be returned by the underlying HCI host implementation.
*
* BT Core Spec v5.2: Vol 4, Part E HCI: 7.1.6 Disconnect command **/ HCIStatusCode disconnect(const uint16_t conn_handle, const BDAddressAndType& peerAddressAndType, const HCIStatusCode reason=HCIStatusCode::REMOTE_USER_TERMINATED_CONNECTION) noexcept; /** * Request and return LE_PHYs bit for the given connection. *
* BT Core Spec v5.2: Vol 4, Part E, 7.8.47 LE Read PHY command ** * Controller shall send a pending HCIMetaEventType::LE_PHY_UPDATE_COMPLETE event with SUCCESS * after issuing this command in all cases (change or unchanged PHYs). * * @param conn_handle * @param addressAndType * @param resTx reference for the resulting transmitter LE_PHYs bit * @param resRx reference for the resulting receiver LE_PHYs bit * @return HCIStatusCode * @since 2.4.0 */ HCIStatusCode le_read_phy(const uint16_t conn_handle, const BDAddressAndType& peerAddressAndType, LE_PHYs& resTx, LE_PHYs& resRx) noexcept; /** * Sets default preference of used LE_PHYs for all subsequent LE connections. * * BT Core Spec v5.2: Vol 4, Part E, 7.8.48 LE Set Default PHY command * * @param Tx transmitter LE_PHYs bit mask of preference if not set to LE_PHYs::NONE (ignored). * @param Rx receiver LE_PHYs bit mask of preference if not set to LE_PHYs::NONE (ignored). * @return * @since 2.4.0 */ HCIStatusCode le_set_default_phy(const LE_PHYs Tx, const LE_PHYs Rx) noexcept; /** * Sets preference of used LE_PHYs for the given connection. * * - BT Core Spec v5.2: Vol 4, Part E, 7.8.49 LE Set PHY command * - BT Core Spec v5.2: Vol 4, Part E, 7.7.65.12 LE PHY Update Complete event * * @param conn_handle * @param peerAddressAndType * @param Tx transmitter LE_PHYs bit mask of preference if not set to LE_PHYs::NONE (ignored). * @param Rx receiver LE_PHYs bit mask of preference if not set to LE_PHYs::NONE (ignored). * @return * @since 2.4.0 */ HCIStatusCode le_set_phy(const uint16_t conn_handle, const BDAddressAndType& peerAddressAndType, const LE_PHYs Tx, const LE_PHYs Rx) noexcept; private: /** * Sets LE advertising parameters. *
* BT Core Spec v5.2: Vol 4 HCI, Part E HCI Functional: 7.8.53 LE Set Extended Advertising Parameters command (Bluetooth 5.0) * * if available, otherwise using * * BT Core Spec v5.2: Vol 4 HCI, Part E HCI Functional: 7.8.5 LE Set Advertising Parameters command **
* Scan parameters control advertising (AD) Protocol Data Unit (PDU) delivery behavior. *
** Should not be called while LE scanning is active, otherwise HCIStatusCode::COMMAND_DISALLOWED will be returned. *
* * @param peer_bdaddr EUI48 of directed peer, defaults to EUI48::ANY_DEVICE (zero address) * @param own_mac_type HCILEOwnAddressType::PUBLIC (default) or random/private. * @param peer_mac_type HCILEOwnAddressType::PUBLIC (default) or random/private. * @param adv_interval_min in units of 0.625ms, default value 0x0800 for 1.28s; Value range [0x0020 .. 0x4000] for [20ms .. 10.24s] * @param adv_interval_max in units of 0.625ms, default value 0x0800 for 1.28s; Value range [0x0020 .. 0x4000] for [20ms .. 10.24s] * @param adv_type see AD_PDU_Type, default ::AD_PDU_Type::ADV_IND * @param adv_chan_map bit 0: chan 37, bit 1: chan 38, bit 2: chan 39, default is 0x07 (all 3 channels enabled) * @param filter_policy 0x00 accepts all PDUs (default), 0x01 only of whitelisted, ... */ HCIStatusCode le_set_adv_param(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=0x0800, const uint16_t adv_interval_max=0x0800, 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; /** * Sets LE advertising data ** BT Core Spec v5.2: Vol 4 HCI, Part E HCI Functional: 7.8.54 LE Set Extended Advertising Data command (Bluetooth 5.0) * * if available, otherwise using * * BT Core Spec v5.2: Vol 4 HCI, Part E HCI Functional: 7.8.7 LE Set Advertising Data command (Bluetooth 4.0) ** * Advertising_Data_Length: * - Bluetooth 4.0: 0 - 31 octets * - Bluetooth 5.0: 0 - 251 octets, i.e. max-param 255 - 4 bytes cp-args * * * @param eir EInfoReport full ADV EIR * @param mask EIRDataType mask for EInfoReport to select advertisement EIR PDU data, defaults to EIRDataType::FLAGS | EIRDataType::NAME | EIRDataType::MANUF_DATA * @return HCIStatusCode::SUCCESS if successful, otherwise the HCIStatusCode error state */ HCIStatusCode le_set_adv_data(const EInfoReport &eir, const EIRDataType mask = EIRDataType::FLAGS | EIRDataType::NAME | EIRDataType::MANUF_DATA) noexcept; /** * Sets LE scan-response data (active scanning) *
* BT Core Spec v5.2: Vol 4 HCI, Part E HCI Functional: 7.8.55 LE Set Extended Scan Response Data command (Bluetooth 5.0) * * if available, otherwise using * * BT Core Spec v5.2: Vol 4 HCI, Part E HCI Functional: 7.8.8 LE Set Scan Response Data command (Bluetooth 4.0) ** * Advertising_Data_Length: * - Bluetooth 4.0: 0 - 31 octets * - Bluetooth 5.0: 0 - 251 octets, i.e. max-param 255 - 4 bytes cp-args * * @param eir EInfoReport full ADV EIR * @param mask EIRDataType mask for EInfoReport to select scan-response EIR PDU data, defaults to EIRDataType::SERVICE_UUID * @return HCIStatusCode::SUCCESS if successful, otherwise the HCIStatusCode error state */ HCIStatusCode le_set_scanrsp_data(const EInfoReport &eir, const EIRDataType mask = EIRDataType::SERVICE_UUID) noexcept; public: /** * Enables or disabled advertising. * - BT Core Spec v5.2: Vol 4 HCI, Part E HCI Functional: 7.8.56 LE Set Extended Advertising Enable command (Bluetooth 5.0) * * if available, otherwise using * * - BT Core Spec v5.2: Vol 4 HCI, Part E HCI Functional: 7.8.9 LE Set Advertising Enable command * * Advertising is active until either disabled via le_enable_adv(false) or a connection has been made, * see isAdvertising(). * * @param enable * @return HCIStatusCode::SUCCESS if successful, otherwise the HCIStatusCode error state * @since 2.4.0 */ HCIStatusCode le_enable_adv(const bool enable) noexcept; /** * Starts advertising * - BT Core Spec v5.2: Vol 4 HCI, Part E HCI Functional: 7.8.53 LE Set Extended Advertising Parameters command (Bluetooth 5.0) * - BT Core Spec v5.2: Vol 4 HCI, Part E HCI Functional: 7.8.54 LE Set Extended Advertising Data command (Bluetooth 5.0) * - BT Core Spec v5.2: Vol 4 HCI, Part E HCI Functional: 7.8.55 LE Set Extended Scan Response Data command (Bluetooth 5.0) * - BT Core Spec v5.2: Vol 4 HCI, Part E HCI Functional: 7.8.56 LE Set Extended Advertising Enable command (Bluetooth 5.0) * * if available, otherwise using * * - BT Core Spec v5.2: Vol 4 HCI, Part E HCI Functional: 7.8.5 LE Set Advertising Parameters command * - BT Core Spec v5.2: Vol 4 HCI, Part E HCI Functional: 7.8.7 LE Set Advertising Data command * - BT Core Spec v5.2: Vol 4 HCI, Part E HCI Functional: 7.8.8 LE Set Scan Response Data command * - BT Core Spec v5.2: Vol 4 HCI, Part E HCI Functional: 7.8.9 LE Set Advertising Enable command * * Advertising is active until either disabled via le_enable_adv(false) or a connection has been made, * see isAdvertising(). * * TODO: * - Random address for privacy if desired! * - Consider SMP (security) * * @param eir Full ADV EIR EInfoReport * @param adv_mask EIRDataType mask for EInfoReport to select advertisement EIR PDU data, defaults to EIRDataType::FLAGS | EIRDataType::SERVICE_UUID * @param scanrsp_mask EIRDataType mask for EInfoReport to select scan-response (active scanning) EIR PDU data, defaults to EIRDataType::NAME | EIRDataType::CONN_IVAL * @param peer_bdaddr EUI48 of directed peer, defaults to EUI48::ANY_DEVICE (zero address) * @param own_mac_type HCILEOwnAddressType::PUBLIC (default) or random/private. * @param peer_mac_type HCILEOwnAddressType::PUBLIC (default) or random/private. * @param adv_interval_min in units of 0.625ms, default value 160 for 100ms; Value range [0x0020 .. 0x4000] for [20ms .. 10.24s] * @param adv_interval_max in units of 0.625ms, default value 480 for 300ms; Value range [0x0020 .. 0x4000] for [20ms .. 10.24s] * @param adv_type see AD_PDU_Type, default ::AD_PDU_Type::ADV_IND * @param adv_chan_map bit 0: chan 37, bit 1: chan 38, bit 2: chan 39, default is 0x07 (all 3 channels enabled) * @param filter_policy 0x00 accepts all PDUs (default), 0x01 only of whitelisted, ... * @return HCIStatusCode::SUCCESS if successful, otherwise the HCIStatusCode error state * @since 2.4.0 */ 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; /** MgmtEventCallback handling */ /** * Appends the given MgmtEventCallback to the named MgmtEvent::Opcode list, * if it is not present already (opcode + callback). * @param opc opcode index for callback list, the callback shall be added to * @param cb the to be added callback * @return true if newly added or already existing, false if given MgmtEvent::Opcode is out of supported range. */ bool addMgmtEventCallback(const MgmtEvent::Opcode opc, const MgmtEventCallback &cb) noexcept; /** Returns count of removed given MgmtEventCallback from the named MgmtEvent::Opcode list. */ int removeMgmtEventCallback(const MgmtEvent::Opcode opc, const MgmtEventCallback &cb) noexcept; /** Removes all MgmtEventCallbacks from the to the named MgmtEvent::Opcode list. */ void clearMgmtEventCallbacks(const MgmtEvent::Opcode opc) noexcept; void addSMPMsgCallback(const HCISMPMsgCallback & l); int removeSMPMsgCallback(const HCISMPMsgCallback & l); /** Removes all MgmtEventCallbacks from all MgmtEvent::Opcode lists and all SMPSecurityReqCallbacks. */ void clearAllCallbacks() noexcept; /** Manually send a MgmtEvent to all of its listeners. */ void sendMgmtEvent(const MgmtEvent& event) noexcept; }; /**@}*/ } // namespace direct_bt #if 0 // Injecting specialization of std::hash to namespace std of our types above // Would need to make direct_bt::HCIHandler::HCIConnection accessible namespace std { /** \addtogroup DBTSystemAPI * * @{ */ template<> struct hash