diff options
author | Sven Gothel <[email protected]> | 2021-09-15 10:50:04 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2021-09-15 10:50:04 +0200 |
commit | 9ce665e96f5b87d83e909330f262378810a8cbb3 (patch) | |
tree | 74484ccdde505c758bd5d0f99da78e49ebe20178 | |
parent | 9b69298eb95b7a0dd7a0d28103fd9b4d03c0a06a (diff) |
Multi Direct-BT application, each using 1 adapter: Have user explicitly initialize adapter with given BTMode, leave others untouched.
Only mutating the desired adapter within one application allows
running multiple Direct-BT applications on one platform,
each using one selected adapter.
BTMode:
- Use byte value, matching native counterpart
BTManager:
- Remove (default) BTMode
BTAdapter:
- Add initialze(const BTMode btMode=BTMode::DUAL),
must be called by user for desired adapter when found
via ChangedAdapterSetFunc/BTManager.ChangedAdapterSetListener.
AdapterInfo:
- Expose mutable ops to public, remove friend decl.
-rw-r--r-- | api/direct_bt/BTAdapter.hpp | 37 | ||||
-rw-r--r-- | api/direct_bt/BTDevice.hpp | 1 | ||||
-rw-r--r-- | api/direct_bt/BTManager.hpp | 45 | ||||
-rw-r--r-- | api/direct_bt/BTTypes1.hpp | 35 | ||||
-rw-r--r-- | api/direct_bt/HCIHandler.hpp | 47 | ||||
-rw-r--r-- | api/direct_bt/MgmtTypes.hpp | 2 | ||||
-rw-r--r-- | examples/direct_bt_scanner10/dbt_scanner10.cpp | 40 | ||||
-rw-r--r-- | examples/java/DBTScanner10.java | 39 | ||||
-rw-r--r-- | java/jau/direct_bt/DBTAdapter.java | 12 | ||||
-rw-r--r-- | java/jau/direct_bt/DBTManager.java | 4 | ||||
-rw-r--r-- | java/jni/direct_bt/DBTAdapter.cxx | 13 | ||||
-rw-r--r-- | java/jni/direct_bt/DBTDevice.cxx | 6 | ||||
-rw-r--r-- | java/jni/direct_bt/DBTManager.cxx | 5 | ||||
-rw-r--r-- | java/org/direct_bt/BTAdapter.java | 47 | ||||
-rw-r--r-- | java/org/direct_bt/BTFactory.java | 19 | ||||
-rw-r--r-- | java/org/direct_bt/BTMode.java | 22 | ||||
-rw-r--r-- | src/direct_bt/BTAdapter.cpp | 89 | ||||
-rw-r--r-- | src/direct_bt/BTDevice.cpp | 6 | ||||
-rw-r--r-- | src/direct_bt/BTManager.cpp | 95 | ||||
-rw-r--r-- | src/direct_bt/HCIHandler.cpp | 151 | ||||
-rw-r--r-- | src/direct_bt/MgmtTypes.cpp | 11 |
21 files changed, 461 insertions, 265 deletions
diff --git a/api/direct_bt/BTAdapter.hpp b/api/direct_bt/BTAdapter.hpp index 7acd9c41..337a9bd1 100644 --- a/api/direct_bt/BTAdapter.hpp +++ b/api/direct_bt/BTAdapter.hpp @@ -254,6 +254,7 @@ namespace direct_bt { const bool debug_event, debug_lock; BTManager& mgmt; AdapterInfo adapterInfo; + jau::sc_atomic_bool adapter_initialized; LE_Features le_features; bool hci_uses_ext_scan; bool hci_uses_ext_conn; @@ -302,7 +303,8 @@ namespace direct_bt { mutable jau::sc_atomic_bool sync_data; bool updateDataFromHCI() noexcept; - bool validateDevInfo() noexcept; + bool updateDataFromAdapterInfo() noexcept; + bool initialSetup() noexcept; static std::shared_ptr<BTDevice> findDevice(device_list_t & devices, const EUI48 & address, const BDAddressType addressType) noexcept; static std::shared_ptr<BTDevice> findDevice(device_list_t & devices, BTDevice const & device) noexcept; @@ -359,6 +361,7 @@ namespace direct_bt { void removeSharedDevice(const BTDevice & device) noexcept; bool mgmtEvNewSettingsMgmt(const MgmtEvent& e) noexcept; + bool updateAdapterSettings(const AdapterSetting new_settings, const bool sendEvent, const uint64_t timestamp) noexcept; bool mgmtEvDeviceDiscoveringMgmt(const MgmtEvent& e) noexcept; bool mgmtEvLocalNameChangedMgmt(const MgmtEvent& e) noexcept; bool mgmtEvDeviceFoundHCI(const MgmtEvent& e) noexcept; @@ -416,8 +419,14 @@ namespace direct_bt { * Closes this instance, usually being called by destructor or when this adapter is being removed * as recognized and handled by BTManager. * <p> + * In case initialize() or setPowered(true) has been called, i.e. this adapter has been powered-on by the user, + * it will be powered-off. + * </p> + * <p> * Renders this adapter's BTAdapter#isValid() state to false. * </p> + * @see initialize() + * @see setPowered() */ void close() noexcept; @@ -548,10 +557,36 @@ namespace direct_bt { /** * Set the power state of the adapter. + * <p> + * Calling the method to power-on this adapter will allow close() to power-off the adapter. + * </p> + * @param value true will power on this adapter, otherwise this adapter will be powered-off. + * @return true for success + * @see close() + * @see initialize() */ bool setPowered(bool value) noexcept; /** + * Initialize the adapter with default values, including power-on. + * <p> + * Method shall be issued on the desired adapter found via ChangedAdapterSetFunc. + * </p> + * <p> + * While initialization, the adapter is first powered-off, setup and then powered-on. + * </p> + * <p> + * Calling the method will allow close() to power-off the adapter. + * </p> + * @param btMode the desired adapter's BTMode, defaults to BTMode::DUAL + * @return HCIStatusCode::SUCCESS or an error state + * @see close() + * @see setPowered() + * @since 2.4.0 + */ + HCIStatusCode initialize(const BTMode btMode=BTMode::DUAL) noexcept; + + /** * Reset the adapter. * <p> * The semantics are specific to the HCI host implementation, diff --git a/api/direct_bt/BTDevice.hpp b/api/direct_bt/BTDevice.hpp index 2df60a5d..7a0c0785 100644 --- a/api/direct_bt/BTDevice.hpp +++ b/api/direct_bt/BTDevice.hpp @@ -63,6 +63,7 @@ namespace direct_bt { L2CAPComm l2cap_att; uint64_t ts_last_discovery; uint64_t ts_last_update; + GAPFlags gap_flags; std::string name; int8_t rssi = 127; // The core spec defines 127 as the "not available" value int8_t tx_power = 127; // The core spec defines 127 as the "not available" value diff --git a/api/direct_bt/BTManager.hpp b/api/direct_bt/BTManager.hpp index 5cfd16e9..22005be0 100644 --- a/api/direct_bt/BTManager.hpp +++ b/api/direct_bt/BTManager.hpp @@ -69,7 +69,6 @@ namespace direct_bt { private: const bool exploding; // just to trigger exploding properties - static BTMode getEnvBTMode(); public: /** @@ -104,17 +103,6 @@ namespace direct_bt { */ const bool DEBUG_EVENT; - /** - * Default {@link BTMode} when initializing new adapter - * <p> - * Environment variable is 'direct_bt.mgmt.btmode' first, then try 'org.tinyb.btmode'. - * </p> - * <p> - * Default is BTMode::DUAL, if non of the above environment variable is set. - * </p> - */ - const BTMode DEFAULT_BTMODE; - private: /** Maximum number of packets to wait for until matching a sequential command. Won't block as timeout will limit. */ const int32_t MGMT_READ_PACKET_MAX_RETRY; @@ -230,7 +218,6 @@ namespace direct_bt { jau::darray<std::shared_ptr<WhitelistElem>> whitelist; const MgmtEnv & env; - const BTMode defaultBTMode; POctets rbuffer; HCIComm comm; @@ -277,16 +264,13 @@ namespace direct_bt { /** * Instantiate singleton. - * @param btMode default {@link BTMode} when initializing new adapter. If BTMode::NONE given, MgmtEnv::DEFAULT_BTMODE is being used. */ - BTManager(const BTMode defaultBTMode) noexcept; + BTManager() noexcept; BTManager(const BTManager&) = delete; void operator=(const BTManager&) = delete; - void setAdapterMode(const uint16_t dev_id, const uint8_t ssp, const uint8_t bredr, const uint8_t le) noexcept; - std::unique_ptr<AdapterInfo> initAdapter(const uint16_t dev_id, const BTMode btMode) noexcept; - void shutdownAdapter(BTAdapter& adapter) noexcept; + std::unique_ptr<AdapterInfo> readAdapterInfo(const uint16_t dev_id) noexcept; void processAdapterAdded(std::unique_ptr<MgmtEvent> e) noexcept; void processAdapterRemoved(std::unique_ptr<MgmtEvent> e) noexcept; @@ -314,10 +298,9 @@ namespace direct_bt { * <p> * First call will open and initialize the bluetooth kernel. * </p> - * @param btMode default {@link BTMode} when initializing new adapter. If BTMode::NONE given (default), MgmtEnv::DEFAULT_BTMODE is being used. * @return singleton instance. */ - static BTManager& get(const BTMode defaultBTMode=BTMode::NONE) { + static BTManager& get() { /** * Thread safe starting with C++11 6.7: * @@ -328,7 +311,7 @@ namespace direct_bt { * * Avoiding non-working double checked locking. */ - static BTManager s(defaultBTMode); + static BTManager s; return s; } ~BTManager() noexcept { close(); } @@ -342,16 +325,13 @@ namespace direct_bt { return std::string(JAVA_DBT_PACKAGE "DBTManager"); } - /** Returns the default {@link BTMode}, adapters are tried to be initialized. */ - BTMode getDefaultBTMode() noexcept { return defaultBTMode; } - /** Returns true if this mgmt instance is open and hence valid, otherwise false */ bool isOpen() const noexcept { return comm.isOpen(); } std::string toString() const noexcept override { - return "MgmtHandler[BTMode "+to_string(defaultBTMode)+", "+std::to_string(adapters.size())+" adapter, "+javaObjectToString()+"]"; + return "MgmtHandler["+std::to_string(adapters.size())+" adapter, "+javaObjectToString()+"]"; } /** retrieve information gathered at startup */ @@ -386,6 +366,21 @@ namespace direct_bt { bool setMode(const uint16_t dev_id, const MgmtCommand::Opcode opc, const uint8_t mode, AdapterSetting& current_settings) noexcept; MgmtStatus setDiscoverable(const uint16_t dev_id, const uint8_t state, const uint16_t timeout, AdapterSetting& current_settings) noexcept; + /** + * Initialize the adapter with default values, including power-on. + * <p> + * Method shall be issued on the desired adapter found via ChangedAdapterSetFunc. + * </p> + * <p> + * While initialization, the adapter is first powered-off, setup and then powered-on. + * </p> + * @param dev_id the adapter's device id + * @param btMode the desired adapter's BTMode, defaults to BTMode::DUAL + * @param adapterInfo reference for the AdapterInfo, updated to reflect the new initialized values. + * @return HCIStatusCode::SUCCESS or an error state + */ + HCIStatusCode initializeAdapter(AdapterInfo& adapterInfo, const uint16_t dev_id, const BTMode btMode=BTMode::DUAL) noexcept; + /** Start discovery on given adapter dev_id with a ScanType matching the given BTMode. Returns set ScanType. */ ScanType startDiscovery(const uint16_t dev_id, const BTMode btMode) noexcept; /** Start discovery on given adapter dev_id with given ScanType. Returns set ScanType. */ diff --git a/api/direct_bt/BTTypes1.hpp b/api/direct_bt/BTTypes1.hpp index b5225f4c..d2336b6f 100644 --- a/api/direct_bt/BTTypes1.hpp +++ b/api/direct_bt/BTTypes1.hpp @@ -186,9 +186,6 @@ namespace direct_bt { class AdapterInfo { - friend class BTManager; // top manager - friend class BTAdapter; // direct manager - public: const uint16_t dev_id; /** @@ -209,20 +206,6 @@ namespace direct_bt { std::string name; std::string short_name; - /** - * Assigns the given 'new_setting & supported_setting' to the current_setting. - * @param new_setting assigned to current_setting after masking with supported_setting. - * @return 'new_setting & supported_setting', i.e. the new current_setting. - */ - AdapterSetting setCurrentSettingMask(const AdapterSetting new_setting) noexcept { - const AdapterSetting _current_setting = new_setting & supported_setting; - current_setting = _current_setting; - return _current_setting; - } - void setDevClass(const uint32_t v) noexcept { dev_class = v; } - void setName(const std::string v) noexcept { name = v; } - void setShortName(const std::string v) noexcept { short_name = v; } - public: AdapterInfo(const uint16_t dev_id_, const BDAddressAndType & addressAndType_, const uint8_t version_, const uint16_t manufacturer_, @@ -264,6 +247,24 @@ namespace direct_bt { { } AdapterInfo& operator=(AdapterInfo &&o) noexcept = delete; + /** + * Assigns the given 'new_setting & supported_setting' to the current_setting. + * @param new_setting assigned to current_setting after masking with supported_setting. + * @return 'new_setting & supported_setting', i.e. the new current_setting. + */ + AdapterSetting setCurrentSettingMask(const AdapterSetting new_setting) noexcept { + const AdapterSetting _current_setting = new_setting & supported_setting; + current_setting = _current_setting; + return _current_setting; + } + void setSettingMasks(const AdapterSetting supported_setting_, const AdapterSetting current_setting_) noexcept { + supported_setting = supported_setting_; + current_setting = current_setting_; + } + void setDevClass(const uint32_t v) noexcept { dev_class = v; } + void setName(const std::string v) noexcept { name = v; } + void setShortName(const std::string v) noexcept { short_name = v; } + constexpr const AdapterSetting& get_supportedSetting() const noexcept { return supported_setting; } bool isSettingMaskSupported(const AdapterSetting setting) const noexcept { diff --git a/api/direct_bt/HCIHandler.hpp b/api/direct_bt/HCIHandler.hpp index 9fb5716b..352add0d 100644 --- a/api/direct_bt/HCIHandler.hpp +++ b/api/direct_bt/HCIHandler.hpp @@ -255,6 +255,7 @@ namespace direct_bt { std::recursive_mutex mtx_sendReply; // for sendWith*Reply, process*Command, ..; Recurses from many.. + LE_Features le_ll_feats; /** * Cached bitfield of Local Supported Commands, 64 octets * <pre> @@ -277,9 +278,6 @@ namespace direct_bt { /** Exclusive [le] connection command (status + pending completed) one at a time */ std::mutex mtx_connect_cmd; - void zeroSupCommands() noexcept; - bool initSupCommands() noexcept; - /** * Returns a newly added HCIConnectionRef tracker connection with given parameters, if not existing yet. * <p> @@ -334,18 +332,20 @@ namespace direct_bt { std::unique_ptr<const SMPPDUMsg> getSMPPDUMsg(const HCIACLData::l2cap_frame & l2cap, const uint8_t * l2cap_data) const noexcept; void hciReaderThreadImpl() noexcept; - bool sendCommand(HCICommand &req) noexcept; + bool sendCommand(HCICommand &req, const bool quiet=false) noexcept; std::unique_ptr<HCIEvent> getNextReply(HCICommand &req, int32_t & retryCount, const int32_t replyTimeoutMS) noexcept; std::unique_ptr<HCIEvent> getNextCmdCompleteReply(HCICommand &req, HCICommandCompleteEvent **res) noexcept; - std::unique_ptr<HCIEvent> processCommandStatus(HCICommand &req, HCIStatusCode *status) noexcept; + std::unique_ptr<HCIEvent> processCommandStatus(HCICommand &req, HCIStatusCode *status, const bool quiet=false) noexcept; template<typename hci_cmd_event_struct> std::unique_ptr<HCIEvent> processCommandComplete(HCICommand &req, - const hci_cmd_event_struct **res, HCIStatusCode *status) noexcept; + const hci_cmd_event_struct **res, HCIStatusCode *status, + const bool quiet=false) noexcept; template<typename hci_cmd_event_struct> std::unique_ptr<HCIEvent> receiveCommandComplete(HCICommand &req, - const hci_cmd_event_struct **res, HCIStatusCode *status) noexcept; + const hci_cmd_event_struct **res, HCIStatusCode *status, + const bool quiet=false) noexcept; template<typename hci_cmd_event_struct> const hci_cmd_event_struct* getReplyStruct(HCIEvent& event, HCIEventType evc, HCIStatusCode *status) noexcept; @@ -356,6 +356,21 @@ namespace direct_bt { public: HCIHandler(const uint16_t dev_id, const BTMode btMode=BTMode::NONE) noexcept; + private: + void zeroSupCommands() noexcept; + bool initSupCommands() noexcept; + + public: + /** + * Reset all internal states, i.e. connection and disconnect lists. + * <p> + * Must be explicitly called with `powered_on=true` when adapter is powered on! + * </p> + * @param powered_on indicates whether the adapter is powered on or not + * @see initSupCommands() + */ + bool resetAllStates(const bool powered_on) noexcept; + HCIHandler(const HCIHandler&) = delete; void operator=(const HCIHandler&) = delete; @@ -376,16 +391,21 @@ namespace direct_bt { } /** Use extended scanning if HCI_LE_Set_Extended_Scan_Parameters and HCI_LE_Set_Extended_Scan_Enable is supported (Bluetooth 5.0). */ - bool use_ext_scan() const noexcept{ + bool use_ext_scan() const noexcept { return 0 != ( sup_commands[37] & ( 1 << 5 ) ) && 0 != ( sup_commands[37] & ( 1 << 6 ) ); } /** Use extended connection if HCI_LE_Extended_Create_Connection is supported (Bluetooth 5.0). */ - bool use_ext_conn() const noexcept{ + bool use_ext_conn() const noexcept { return 0 != ( sup_commands[37] & ( 1 << 7 ) ); } + /** Use extended advertising if LE_Features::LE_Ext_Adv is set (Bluetooth 5.0). */ + bool use_ext_adv() const noexcept { + return isLEFeaturesBitSet(le_ll_feats, LE_Features::LE_Ext_Adv); + } + ScanType getCurrentScanType() const noexcept { return currentScanType.load(); } void setCurrentScanType(const ScanType v) noexcept { currentScanType = v; } @@ -432,7 +452,7 @@ namespace direct_bt { HCIStatusCode getLocalVersion(HCILocalVersion &version) noexcept; /** - * Request and return LE_Features for the controller. + * Return previously fetched LE_Features for the controller via initSupCommands() via resetAllStates() * <pre> * BT Core Spec v5.2: Vol 6, Part B, 4.6 (LE LL) Feature Support * @@ -440,9 +460,12 @@ namespace direct_bt { * </pre> * @param res reference for the resulting LE_Features * @return HCIStatusCode + * @see initSupCommands() + * @see resetAllStates() */ - HCIStatusCode le_read_local_features(LE_Features& res) noexcept; + LE_Features le_get_local_features() noexcept { return le_ll_feats; } + private: /** * Sets LE scanning parameters. * <pre> @@ -473,6 +496,7 @@ namespace direct_bt { 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. * <pre> @@ -621,7 +645,6 @@ namespace direct_bt { * Reset all internal states, i.e. connection and disconnect lists. * @param powered_on indicates whether the adapter is powered on or not */ - void resetAllStates(const bool powered_on) noexcept; /** MgmtEventCallback handling */ diff --git a/api/direct_bt/MgmtTypes.hpp b/api/direct_bt/MgmtTypes.hpp index 21fd5518..4240a75d 100644 --- a/api/direct_bt/MgmtTypes.hpp +++ b/api/direct_bt/MgmtTypes.hpp @@ -2226,7 +2226,7 @@ namespace direct_bt { std::string getShortName() const noexcept { return pdu.get_string_nc(getDataOffset()+20+MgmtConstU16::MGMT_MAX_NAME_LENGTH); } std::unique_ptr<AdapterInfo> toAdapterInfo() const noexcept; - + bool updateAdapterInfo(AdapterInfo& info) const noexcept; }; typedef jau::FunctionDef<bool, const MgmtEvent&> MgmtEventCallback; diff --git a/examples/direct_bt_scanner10/dbt_scanner10.cpp b/examples/direct_bt_scanner10/dbt_scanner10.cpp index 396788c6..7dd74f71 100644 --- a/examples/direct_bt_scanner10/dbt_scanner10.cpp +++ b/examples/direct_bt_scanner10/dbt_scanner10.cpp @@ -105,6 +105,9 @@ const static std::string KEY_PATH = "keys"; static uint64_t timestamp_t0; +static EUI48 useAdapter = EUI48::ALL_DEVICE; +static BTMode btMode = BTMode::DUAL; + static int RESET_ADAPTER_EACH_CONN = 0; static std::atomic<int> deviceReadyCount = 0; @@ -635,12 +638,29 @@ static const uint16_t le_scan_window = 24; // default value static const uint8_t filter_policy = 0; // default value static bool startDiscovery(BTAdapter *a, std::string msg) { + if( useAdapter != EUI48::ALL_DEVICE && useAdapter != a->getAddressAndType().address ) { + fprintf_td(stderr, "****** Start discovery (%s): Adapter not selected: %s\n", msg.c_str(), a->toString().c_str()); + return false; + } HCIStatusCode status = a->startDiscovery( true, le_scan_active, le_scan_interval, le_scan_window, filter_policy ); - fprintf_td(stderr, "****** Start discovery (%s) result: %s\n", msg.c_str(), to_string(status).c_str()); + fprintf_td(stderr, "****** Start discovery (%s) result: %s: %s\n", msg.c_str(), to_string(status).c_str(), a->toString().c_str()); return HCIStatusCode::SUCCESS == status; } static bool initAdapter(std::shared_ptr<BTAdapter>& adapter) { + if( useAdapter != EUI48::ALL_DEVICE && useAdapter != adapter->getAddressAndType().address ) { + fprintf_td(stderr, "initAdapter: Adapter not selected: %s\n", adapter->toString().c_str()); + return false; + } + // Initialize with defaults and power-on + { + HCIStatusCode status = adapter->initialize( btMode ); + if( HCIStatusCode::SUCCESS != status ) { + fprintf_td(stderr, "initAdapter: Adapter initialization failed: %s: %s\n", + to_string(status).c_str(), adapter->toString().c_str()); + return false; + } + } // Even if adapter is not yet powered, listen to it and act when it gets powered-on adapter->addStatusListener(std::shared_ptr<AdapterStatusListener>(new MyAdapterStatusListener())); // Flush discovered devices after registering our status listener. @@ -648,17 +668,17 @@ static bool initAdapter(std::shared_ptr<BTAdapter>& adapter) { adapter->removeDiscoveredDevices(); if( !adapter->isPowered() ) { // should have been covered above - fprintf_td(stderr, "Adapter not powered (2): %s\n", adapter->toString().c_str()); + fprintf_td(stderr, "initAdapter: Adapter not powered (2): %s\n", adapter->toString().c_str()); return false; } if( USE_WHITELIST ) { for (auto it = WHITELIST.begin(); it != WHITELIST.end(); ++it) { bool res = adapter->addDeviceToWhitelist(*it, HCIWhitelistConnectType::HCI_AUTO_CONN_ALWAYS); - fprintf_td(stderr, "Added to WHITELIST: res %d, address %s\n", res, it->toString().c_str()); + fprintf_td(stderr, "initAdapter: Added to WHITELIST: res %d, address %s\n", res, it->toString().c_str()); } } else { - if( !startDiscovery(adapter.get(), "kick-off") ) { + if( !startDiscovery(adapter.get(), "initAdapter") ) { return false; } } @@ -729,7 +749,6 @@ void test() { int main(int argc, char *argv[]) { - BTMode btMode = BTMode::DUAL; bool waitForEnter=false; for(int i=1; i<argc; i++) { @@ -745,11 +764,6 @@ int main(int argc, char *argv[]) setenv("direct_bt.hci", argv[++i], 1 /* overwrite */); } else if( !strcmp("-dbt_mgmt", argv[i]) && argc > (i+1) ) { setenv("direct_bt.mgmt", argv[++i], 1 /* overwrite */); - } else if( !strcmp("-btmode", argv[i]) && argc > (i+1) ) { - btMode = to_BTMode(argv[++i]); - if( BTMode::NONE != btMode ) { - setenv("direct_bt.mgmt.btmode", to_string(btMode).c_str(), 1 /* overwrite */); - } } else if( !strcmp("-wait", argv[i]) ) { waitForEnter = true; } else if( !strcmp("-show_update_events", argv[i]) ) { @@ -758,6 +772,10 @@ int main(int argc, char *argv[]) QUIET = true; } else if( !strcmp("-scanPassive", argv[i]) ) { le_scan_active = false; + } else if( !strcmp("-btmode", argv[i]) && argc > (i+1) ) { + btMode = to_BTMode(argv[++i]); + } else if( !strcmp("-adapter", argv[i]) && argc > (i+1) ) { + useAdapter = EUI48( std::string(argv[++i]) ); } else if( !strcmp("-dev", argv[i]) && argc > (i+1) ) { std::string addrOrNameSub = std::string(argv[++i]); BTDeviceRegistry::addToWaitForDevices( addrOrNameSub ); @@ -811,6 +829,7 @@ int main(int argc, char *argv[]) "[-disconnect] [-enableGATTPing] [-count <number>] [-single] [-show_update_events] [-quiet] " "[-scanPassive]" "[-resetEachCon connectionCount] " + "[-adapter <adapter_address>] " "(-dev <device_[address|name]_sub>)* (-wl <device_address>)* " "(-seclevel <device_[address|name]_sub> <int_sec_level>)* " "(-iocap <device_[address|name]_sub> <int_iocap>)* " @@ -834,6 +853,7 @@ int main(int argc, char *argv[]) fprintf(stderr, "USE_WHITELIST %d\n", USE_WHITELIST); fprintf(stderr, "SHOW_UPDATE_EVENTS %d\n", SHOW_UPDATE_EVENTS); fprintf(stderr, "QUIET %d\n", QUIET); + fprintf(stderr, "adapter %s\n", useAdapter.toString().c_str()); fprintf(stderr, "btmode %s\n", to_string(btMode).c_str()); fprintf(stderr, "scanActive %s\n", to_string(le_scan_active).c_str()); fprintf(stderr, "characteristic-id: %s\n", charIdentifier.c_str()); diff --git a/examples/java/DBTScanner10.java b/examples/java/DBTScanner10.java index 0caabfdc..fa5c63e3 100644 --- a/examples/java/DBTScanner10.java +++ b/examples/java/DBTScanner10.java @@ -80,6 +80,9 @@ public class DBTScanner10 { long timestamp_t0; + EUI48 useAdapter = EUI48.ALL_DEVICE; + BTMode btMode = BTMode.DUAL; + int RESET_ADAPTER_EACH_CONN = 0; AtomicInteger deviceReadyCount = new AtomicInteger(0); @@ -639,12 +642,29 @@ public class DBTScanner10 { static final byte filter_policy = (byte)0; // default value private boolean startDiscovery(final BTAdapter adapter, final String msg) { + if( !useAdapter.equals(EUI48.ALL_DEVICE) && !useAdapter.equals(adapter.getAddressAndType().address) ) { + BTUtils.fprintf_td(System.err, "****** Start discovery (%s): Adapter not selected: %s\n", msg, adapter.toString()); + return false; + } final HCIStatusCode status = adapter.startDiscovery( true, le_scan_active, le_scan_interval, le_scan_window, filter_policy ); BTUtils.println(System.err, "****** Start discovery ("+msg+") result: "+status); return HCIStatusCode.SUCCESS == status; } private boolean initAdapter(final BTAdapter adapter) { + if( !useAdapter.equals(EUI48.ALL_DEVICE) && !useAdapter.equals(adapter.getAddressAndType().address) ) { + BTUtils.fprintf_td(System.err, "initAdapter: Adapter not selected: %s\n", adapter.toString()); + return false; + } + // Initialize with defaults and power-on + { + final HCIStatusCode status = adapter.initialize( btMode ); + if( HCIStatusCode.SUCCESS != status ) { + BTUtils.fprintf_td(System.err, "initAdapter: Adapter initialization failed: %s: %s\n", + status.toString(), adapter.toString()); + return false; + } + } // Even if adapter is not yet powered, listen to it and act when it gets powered-on adapter.addStatusListener(new MyAdapterStatusListener() ); // Flush discovered devices after registering our status listener. @@ -652,7 +672,7 @@ public class DBTScanner10 { adapter.removeDiscoveredDevices(); if( !adapter.isPowered() ) { // should have been covered above - BTUtils.println(System.err, "Adapter not powered (2): "+adapter.toString()); + BTUtils.println(System.err, "initAdapter: Adapter not powered (2): "+adapter.toString()); return false; } @@ -660,10 +680,10 @@ public class DBTScanner10 { for(final Iterator<BDAddressAndType> wliter = whitelist.iterator(); wliter.hasNext(); ) { final BDAddressAndType addr = wliter.next(); final boolean res = adapter.addDeviceToWhitelist(addr, HCIWhitelistConnectType.HCI_AUTO_CONN_ALWAYS); - BTUtils.println(System.err, "Added to whitelist: res "+res+", address "+addr); + BTUtils.println(System.err, "initAdapter: Added to whitelist: res "+res+", address "+addr); } } else { - if( !startDiscovery(adapter, "kick-off") ) { + if( !startDiscovery(adapter, "initAdapter") ) { return false; } } @@ -758,10 +778,6 @@ public class DBTScanner10 { System.setProperty("direct_bt.hci", args[++i]); } else if( arg.equals("-dbt_mgmt") && args.length > (i+1) ) { System.setProperty("direct_bt.mgmt", args[++i]); - } else if( arg.equals("-btmode") && args.length > (i+1) ) { - final BTMode btmode = BTMode.get(args[++i]); - System.setProperty("org.tinyb.btmode", btmode.toString()); - System.err.println("Setting 'org.tinyb.btmode' to "+btmode.toString()); } } final BTManager manager; @@ -796,6 +812,10 @@ public class DBTScanner10 { le_scan_active = false; } else if( arg.equals("-shutdown") && args.length > (i+1) ) { test.shutdownTest = Integer.valueOf(args[++i]).intValue(); + } else if( arg.equals("-btmode") && args.length > (i+1) ) { + test.btMode = BTMode.get(args[++i]); + } else if( arg.equals("-adapter") && args.length > (i+1) ) { + test.useAdapter = new EUI48( args[++i] ); } else if( arg.equals("-dev") && args.length > (i+1) ) { BTDeviceRegistry.addToWaitForDevices( args[++i] ); } else if( arg.equals("-wl") && args.length > (i+1) ) { @@ -845,10 +865,10 @@ public class DBTScanner10 { } } BTUtils.println(System.err, "Run with '[-btmode LE|BREDR|DUAL] "+ - "[-bluetoothManager <BluetoothManager-Implementation-Class-Name>] "+ "[-disconnect] [-enableGATTPing] [-count <number>] [-single] [-show_update_events] [-quiet] "+ "[-scanPassive]"+ "[-resetEachCon connectionCount] "+ + "[-adapter <adapter_address>] "+ "(-dev <device_[address|name]_sub>)* (-wl <device_address>)* "+ "(-seclevel <device_[address|name]_sub> <int_sec_level>)* "+ "(-iocap <device_[address|name]_sub> <int_iocap>)* "+ @@ -873,6 +893,9 @@ public class DBTScanner10 { BTUtils.println(System.err, "USE_WHITELIST "+test.USE_WHITELIST); BTUtils.println(System.err, "SHOW_UPDATE_EVENTS "+test.SHOW_UPDATE_EVENTS); BTUtils.println(System.err, "QUIET "+test.QUIET); + BTUtils.println(System.err, "adapter "+test.useAdapter); + BTUtils.println(System.err, "btmode' to "+test.btMode.toString()); + BTUtils.println(System.err, "characteristic-id: "+test.charIdentifier); BTUtils.println(System.err, "characteristic-value: "+test.charValue); diff --git a/java/jau/direct_bt/DBTAdapter.java b/java/jau/direct_bt/DBTAdapter.java index 994a2539..e12c090c 100644 --- a/java/jau/direct_bt/DBTAdapter.java +++ b/java/jau/direct_bt/DBTAdapter.java @@ -44,6 +44,7 @@ import org.direct_bt.BTGattChar; import org.direct_bt.BTGattDesc; import org.direct_bt.BTGattService; import org.direct_bt.BTManager; +import org.direct_bt.BTMode; import org.direct_bt.BTObject; import org.direct_bt.BTType; import org.direct_bt.BTUtils; @@ -233,6 +234,17 @@ public class DBTAdapter extends DBTObject implements BTAdapter public native boolean setPowered(boolean value); @Override + public final HCIStatusCode initialize() { + return initialize(BTMode.DUAL); + } + + @Override + public final HCIStatusCode initialize(final BTMode btMode) { + return HCIStatusCode.get( initializeImpl(btMode.value) ); + } + private native byte initializeImpl(final byte btModeInt); + + @Override public final HCIStatusCode reset() { return HCIStatusCode.get( resetImpl() ); } diff --git a/java/jau/direct_bt/DBTManager.java b/java/jau/direct_bt/DBTManager.java index 9a943a8d..37972726 100644 --- a/java/jau/direct_bt/DBTManager.java +++ b/java/jau/direct_bt/DBTManager.java @@ -370,11 +370,11 @@ public class DBTManager implements BTManager } } - private native void initImpl(final boolean unifyUUID128Bit, final int btMode) throws BTException; + private native void initImpl(final boolean unifyUUID128Bit) throws BTException; private native void deleteImpl(long nativeInstance); private DBTManager() { - initImpl(unifyUUID128Bit, BTFactory.DEFAULT_BTMODE.value); + initImpl(unifyUUID128Bit); try { adapters.addAll(getAdapterListImpl()); } catch (final BTException be) { diff --git a/java/jni/direct_bt/DBTAdapter.cxx b/java/jni/direct_bt/DBTAdapter.cxx index 5fceee87..028011fe 100644 --- a/java/jni/direct_bt/DBTAdapter.cxx +++ b/java/jni/direct_bt/DBTAdapter.cxx @@ -855,6 +855,19 @@ jboolean Java_jau_direct_1bt_DBTAdapter_setPowered(JNIEnv *env, jobject obj, jbo return JNI_FALSE; } +jbyte Java_jau_direct_1bt_DBTAdapter_initializeImpl(JNIEnv *env, jobject obj, jbyte jbtMode) { + try { + BTAdapter *adapter = jau::getJavaUplinkObject<BTAdapter>(env, obj); + jau::JavaGlobalObj::check(adapter->getJavaObject(), E_FILE_LINE); + const BTMode btMode = static_cast<BTMode>(jbtMode); + HCIStatusCode res = adapter->initialize(btMode); + return (jbyte) number(res); + } catch(...) { + rethrow_and_raise_java_exception(env); + } + return (jbyte) number(HCIStatusCode::INTERNAL_FAILURE); +} + jbyte Java_jau_direct_1bt_DBTAdapter_resetImpl(JNIEnv *env, jobject obj) { try { BTAdapter *adapter = jau::getJavaUplinkObject<BTAdapter>(env, obj); diff --git a/java/jni/direct_bt/DBTDevice.cxx b/java/jni/direct_bt/DBTDevice.cxx index 13d965f4..a76c0e4d 100644 --- a/java/jni/direct_bt/DBTDevice.cxx +++ b/java/jni/direct_bt/DBTDevice.cxx @@ -718,9 +718,9 @@ jobject Java_jau_direct_1bt_DBTDevice_getManufacturerData(JNIEnv *env, jobject o if( nullptr != mdata ) { result = env->NewObject(map_cls, map_ctor, 1); - jbyteArray arr = env->NewByteArray(mdata->data.getSize()); - env->SetByteArrayRegion(arr, 0, mdata->data.getSize(), (const jbyte *)mdata->data.get_ptr()); - jobject key = env->NewObject(short_cls, short_ctor, mdata->company); + jbyteArray arr = env->NewByteArray(mdata->getData().getSize()); + env->SetByteArrayRegion(arr, 0, mdata->getData().getSize(), (const jbyte *)mdata->getData().get_ptr()); + jobject key = env->NewObject(short_cls, short_ctor, mdata->getCompany()); env->CallObjectMethod(result, map_put, key, arr); env->DeleteLocalRef(arr); diff --git a/java/jni/direct_bt/DBTManager.cxx b/java/jni/direct_bt/DBTManager.cxx index b35fe37a..985cb5b8 100644 --- a/java/jni/direct_bt/DBTManager.cxx +++ b/java/jni/direct_bt/DBTManager.cxx @@ -109,12 +109,11 @@ static void _addMgmtCBOnce(JNIEnv *env, BTManager & mgmt, JNIGlobalRef jmgmtRef, } } -void Java_jau_direct_1bt_DBTManager_initImpl(JNIEnv *env, jobject obj, jboolean unifyUUID128Bit, jint jbtMode) +void Java_jau_direct_1bt_DBTManager_initImpl(JNIEnv *env, jobject obj, jboolean unifyUUID128Bit) { directBTJNISettings.setUnifyUUID128Bit(unifyUUID128Bit); try { - BTMode btMode = static_cast<BTMode>(jbtMode); - BTManager *manager = &BTManager::get(btMode); // special: static singleton + BTManager *manager = &BTManager::get(); // special: static singleton setInstance<BTManager>(env, obj, manager); java_exception_check_and_throw(env, E_FILE_LINE); manager->setJavaObject( std::shared_ptr<JavaAnon>( new JavaGlobalObj(obj, nullptr) ) ); diff --git a/java/org/direct_bt/BTAdapter.java b/java/org/direct_bt/BTAdapter.java index 7464a026..8c945349 100644 --- a/java/org/direct_bt/BTAdapter.java +++ b/java/org/direct_bt/BTAdapter.java @@ -309,12 +309,59 @@ public interface BTAdapter extends BTObject /** * Sets the power state the adapter. + * <p> + * Calling the method to power-on this adapter will allow close() to power-off the adapter. + * </p> * @apiNote return value boolean since 2.0.0 + * @see #close() + * @see #initialize(BTMode) * @since 2.0.0 */ public boolean setPowered(boolean value); /** + * Initialize the adapter with default values, including power-on. + * <p> + * Method shall be issued on the desired adapter found via {@link BTManager.ChangedAdapterSetListener}. + * </p> + * <p> + * While initialization, the adapter is first powered-off, setup and then powered-on. + * </p> + * <p> + * Calling the method will allow close() to power-off the adapter. + * </p> + * <p> + * This override uses {@link BTMode#DUAL} + * </p> + * @return {@link HCIStatusCode#SUCCESS} or an error state + * @see #initialize(BTMode) + * @see #close() + * @see #setPowered(boolean) + * @since 2.4.0 + */ + public HCIStatusCode initialize(); + + /** + * Initialize the adapter with default values, including power-on. + * <p> + * Method shall be issued on the desired adapter found via {@link BTManager.ChangedAdapterSetListener}. + * </p> + * <p> + * While initialization, the adapter is first powered-off, setup and then powered-on. + * </p> + * <p> + * Calling the method will allow close() to power-off the adapter. + * </p> + * @param btMode the desired adapter's {@link BTMode}, default shall be {@link BTMode#DUAL} + * @return {@link HCIStatusCode#SUCCESS} or an error state + * @see #initialize() + * @see #close() + * @see #setPowered(boolean) + * @since 2.4.0 + */ + public HCIStatusCode initialize(final BTMode btMode); + + /** * Reset the adapter. * <p> * The semantics are specific to the HCI host implementation, diff --git a/java/org/direct_bt/BTFactory.java b/java/org/direct_bt/BTFactory.java index f66cbd5b..4a29988d 100644 --- a/java/org/direct_bt/BTFactory.java +++ b/java/org/direct_bt/BTFactory.java @@ -147,15 +147,6 @@ public class BTFactory { public static final boolean DEBUG; /** - * Default {@link BTMode} when initializing new adapter - * <p> - * System property {@code org.direct_bt.btmode}, string, default {@code DUAL} {@link BTMode#DUAL}. - * </p> - * @since 2.0.0 - */ - public static final BTMode DEFAULT_BTMODE; - - /** * True if jaulib {@link org.jau.sys.PlatformProps} has been detected. */ public static final boolean JAULIB_AVAILABLE; @@ -177,16 +168,6 @@ public class BTFactory { final String v = System.getProperty("org.direct_bt.verbose", "false"); VERBOSE = Boolean.valueOf(v); } - { - final String v = System.getProperty("org.direct_bt.btmode", "DUAL"); - BTMode btMode = BTMode.DUAL; - try { - btMode = BTMode.get(v); - } catch (final IllegalArgumentException ex) { - System.err.println("Invalid BTMode '"+v+"': "+ex.getMessage()); - } - DEFAULT_BTMODE = btMode; - } implIDs.add(DirectBTImplementationID); boolean isJaulibAvail = false; diff --git a/java/org/direct_bt/BTMode.java b/java/org/direct_bt/BTMode.java index cbdecbab..2395efec 100644 --- a/java/org/direct_bt/BTMode.java +++ b/java/org/direct_bt/BTMode.java @@ -27,21 +27,21 @@ package org.direct_bt; /** * Bluetooth adapter operating mode * <p> - * See {@link #get(int)} for its native integer mapping. + * See {@link #get(byte)} for its native integer mapping. * </p> * @since 2.0.0 */ public enum BTMode { /** Zero mode, neither DUAL, BREDR nor LE. Usually an error. */ - NONE (0), + NONE ((byte)0), /** Dual Bluetooth mode, i.e. BREDR + LE. */ - DUAL (1), + DUAL ((byte)1), /** BREDR only Bluetooth mode */ - BREDR (2), + BREDR ((byte)2), /** LE only Bluetooth mode */ - LE (3); + LE ((byte)3); - public final int value; + public final byte value; /** * Maps the specified name to a constant of BTMode. @@ -63,16 +63,16 @@ public enum BTMode { * @param value the integer value to be mapped to a constant of this enum type. * @return the corresponding constant of this enum type, using {@link #NONE} if not supported. */ - public static BTMode get(final int value) { + public static BTMode get(final byte value) { switch(value) { - case 0x01: return DUAL; - case 0x02: return BREDR; - case 0x03: return LE; + case (byte)0x01: return DUAL; + case (byte)0x02: return BREDR; + case (byte)0x03: return LE; default: return NONE; } } - BTMode(final int v) { + BTMode(final byte v) { value = v; } } diff --git a/src/direct_bt/BTAdapter.cpp b/src/direct_bt/BTAdapter.cpp index fd460a2f..be3fd51c 100644 --- a/src/direct_bt/BTAdapter.cpp +++ b/src/direct_bt/BTAdapter.cpp @@ -127,56 +127,61 @@ bool BTAdapter::updateDataFromHCI() noexcept { HCILocalVersion version; HCIStatusCode status = hci.getLocalVersion(version); if( HCIStatusCode::SUCCESS != status ) { - ERR_PRINT("BTAdapter::validateDevInfo: Adapter[%d]: POWERED, LocalVersion failed %s - %s", + ERR_PRINT("BTAdapter::updateDataFromHCI: Adapter[%d]: POWERED, LocalVersion failed %s - %s", dev_id, to_string(status).c_str(), adapterInfo.toString().c_str()); return false; } - LE_Features le_ll_feats; - if( HCIStatusCode::SUCCESS != hci.le_read_local_features(le_ll_feats) ) { - ERR_PRINT("BTAdapter::validateDevInfo: Adapter[%d]: le_read_local_features failed %s - %s", - dev_id, to_string(status).c_str(), adapterInfo.toString().c_str()); - return false; - } - le_features = le_ll_feats; + le_features = hci.le_get_local_features(); hci_uses_ext_scan = hci.use_ext_scan(); hci_uses_ext_conn = hci.use_ext_conn(); WORDY_PRINT("BTAdapter::updateDataFromHCI: Adapter[%d]: POWERED, %s - %s, hci_ext[scan %d, conn %d], features: %s", dev_id, version.toString().c_str(), adapterInfo.toString().c_str(), hci_uses_ext_scan, hci_uses_ext_conn, - direct_bt::to_string(le_ll_feats).c_str()); + direct_bt::to_string(le_features).c_str()); + return true; +} + +bool BTAdapter::updateDataFromAdapterInfo() noexcept { + BTMode btMode = getBTMode(); + if( BTMode::NONE == btMode ) { + WARN_PRINT("BTAdapter::updateDataFromAdapterInfo: Adapter[%d]: BTMode invalid, BREDR nor LE set: %s", dev_id, adapterInfo.toString().c_str()); + return false; + } + hci.setBTMode(btMode); return true; } -bool BTAdapter::validateDevInfo() noexcept { +bool BTAdapter::initialSetup() noexcept { bool ok = false; currentMetaScanType = ScanType::NONE; keep_le_scan_alive = false; if( !mgmt.isOpen() ) { - ERR_PRINT("BTAdapter::validateDevInfo: Adapter[%d]: Manager not open", dev_id); + ERR_PRINT("BTAdapter::initialSetup: Adapter[%d]: Manager not open", dev_id); goto errout0; } if( !hci.isOpen() ) { - ERR_PRINT("BTAdapter::validateDevInfo: Adapter[%d]: HCIHandler closed", dev_id); + ERR_PRINT("BTAdapter::initialSetup: Adapter[%d]: HCIHandler closed", dev_id); goto errout0; } old_settings = adapterInfo.getCurrentSettingMask(); - btMode = getBTMode(); - if( BTMode::NONE == btMode ) { - ERR_PRINT("BTAdapter::validateDevInfo: Adapter[%d]: BTMode invalid, BREDR nor LE set: %s", dev_id, adapterInfo.toString().c_str()); + if( !updateDataFromAdapterInfo() ) { return false; } - hci.setBTMode(btMode); if( adapterInfo.isCurrentSettingBitSet(AdapterSetting::POWERED) ) { + if( !hci.resetAllStates(true) ) { + return false; + } if( !updateDataFromHCI() ) { return false; } } else { - WORDY_PRINT("BTAdapter::validateDevInfo: Adapter[%d]: Not POWERED: %s", dev_id, adapterInfo.toString().c_str()); + hci.resetAllStates(false); + WORDY_PRINT("BTAdapter::initialSetup: Adapter[%d]: Not POWERED: %s", dev_id, adapterInfo.toString().c_str()); } ok = true; @@ -226,13 +231,14 @@ BTAdapter::BTAdapter(const BTAdapter::ctor_cookie& cc, BTManager& mgmt_, const A debug_lock(jau::environment::getBooleanProperty("direct_bt.debug.adapter.lock", false)), mgmt( mgmt_ ), adapterInfo( adapterInfo_ ), + adapter_initialized( false ), le_features( LE_Features::NONE ), visibleAddressAndType( adapterInfo_.addressAndType ), dev_id( adapterInfo.dev_id ), hci( dev_id ) { (void)cc; - valid = validateDevInfo(); + valid = initialSetup(); } BTAdapter::~BTAdapter() noexcept { @@ -267,6 +273,13 @@ void BTAdapter::close() noexcept { poweredOff(); + if( adapter_initialized ) { + adapter_initialized = false; + if( isPowered() ) { + setPowered(false); + } + } + DBG_PRINT("BTAdapter::close: closeHCI: ..."); hci.close(); DBG_PRINT("BTAdapter::close: closeHCI: XXX"); @@ -360,10 +373,22 @@ bool BTAdapter::setBondable(bool value) noexcept { } bool BTAdapter::setPowered(bool value) noexcept { + if( value ) { + adapter_initialized = true; + } AdapterSetting current_settings { AdapterSetting::NONE } ; return mgmt.setMode(dev_id, MgmtCommand::Opcode::SET_POWERED, value ? 1 : 0, current_settings); } +HCIStatusCode BTAdapter::initialize(const BTMode btMode) noexcept { + adapter_initialized = true; + HCIStatusCode status = mgmt.initializeAdapter(adapterInfo, dev_id, btMode); + if( HCIStatusCode::SUCCESS != status ) { + return status; + } + return updateAdapterSettings(adapterInfo.getCurrentSettingMask(), false, 0) ? HCIStatusCode::SUCCESS : HCIStatusCode::FAILED; +} + bool BTAdapter::lockConnect(const BTDevice & device, const bool wait, const SMPIOCapability io_cap) noexcept { std::unique_lock<std::mutex> lock(mtx_single_conn_device); // RAII-style acquire and relinquish via destructor const uint32_t timeout_ms = 10000; // FIXME: Configurable? @@ -955,7 +980,7 @@ void BTAdapter::removeDevice(BTDevice & device) noexcept { std::string BTAdapter::toString(bool includeDiscoveredDevices) const noexcept { std::string random_address_info = adapterInfo.addressAndType != visibleAddressAndType ? " ("+visibleAddressAndType.toString()+")" : ""; - std::string out("Adapter[BTMode "+to_string(btMode)+", "+adapterInfo.addressAndType.toString()+random_address_info+ + std::string out("Adapter[BTMode "+to_string(getBTMode())+", "+adapterInfo.addressAndType.toString()+random_address_info+ ", '"+getName()+"', id "+std::to_string(dev_id)+ ", curSettings"+to_string(adapterInfo.getCurrentSettingMask())+ ", scanType[native "+to_string(hci.getCurrentScanType())+", meta "+to_string(currentMetaScanType)+"]" @@ -1105,12 +1130,11 @@ bool BTAdapter::mgmtEvNewSettingsMgmt(const MgmtEvent& e) noexcept { COND_PRINT(debug_event, "BTAdapter:mgmt:NewSettings: %s", e.toString().c_str()); const MgmtEvtNewSettings &event = *static_cast<const MgmtEvtNewSettings *>(&e); const AdapterSetting new_settings = adapterInfo.setCurrentSettingMask(event.getSettings()); // probably done by mgmt callback already - { - const BTMode _btMode = getAdapterSettingsBTMode(new_settings); - if( BTMode::NONE != _btMode ) { - btMode = _btMode; - } - } + + return updateAdapterSettings(new_settings, true, event.getTimestamp()); +} + +bool BTAdapter::updateAdapterSettings(const AdapterSetting new_settings, const bool sendEvent, const uint64_t timestamp) noexcept { const AdapterSetting old_settings_ = old_settings; const AdapterSetting changes = getAdapterSettingMaskDiff(new_settings, old_settings_); @@ -1123,17 +1147,22 @@ bool BTAdapter::mgmtEvNewSettingsMgmt(const MgmtEvent& e) noexcept { old_settings = new_settings; - COND_PRINT(debug_event, "BTAdapter::mgmt:NewSettings: %s -> %s, changes %s: %s", + COND_PRINT(debug_event, "BTAdapter::updateAdapterSettings: %s -> %s, changes %s: %s, sendEvent %d", to_string(old_settings_).c_str(), to_string(new_settings).c_str(), - to_string(changes).c_str(), toString().c_str() ); + to_string(changes).c_str(), toString().c_str(), sendEvent ); + + updateDataFromAdapterInfo(); if( justPoweredOn ) { // Adapter has been powered on, ensure all hci states are reset. - hci.resetAllStates(true); - updateDataFromHCI(); + if( hci.resetAllStates(true) ) { + updateDataFromHCI(); + } + } + if( sendEvent ) { + sendAdapterSettingsChanged(old_settings_, new_settings, changes, timestamp); } - sendAdapterSettingsChanged(old_settings_, new_settings, changes, event.getTimestamp()); if( justPoweredOff ) { // Adapter has been powered off, close connections and cleanup off-thread. diff --git a/src/direct_bt/BTDevice.cpp b/src/direct_bt/BTDevice.cpp index 2b19fae7..322ee8da 100644 --- a/src/direct_bt/BTDevice.cpp +++ b/src/direct_bt/BTDevice.cpp @@ -150,7 +150,8 @@ std::string BTDevice::toString(bool includeDiscoveredServices) const noexcept { ", auto "+to_string(pairing_data.ioCap_auto)+", pairing "+to_string(pairing_data.mode)+", state "+to_string(pairing_data.state)+"]], rssi "+std::to_string(getRSSI())+ ", tx-power "+std::to_string(tx_power)+ ", appearance "+jau::to_hexstring(static_cast<uint16_t>(appearance))+" ("+to_string(appearance)+ - "), "+msdstr+", "+javaObjectToString()+"]"); + "), gap "+direct_bt::to_string(gap_flags)+ + ", "+msdstr+", "+javaObjectToString()+"]"); if( includeDiscoveredServices ) { jau::darray<std::shared_ptr<const uuid_t>> _advServices = getAdvertisedServices(); if( _advServices.size() > 0 ) { @@ -186,6 +187,9 @@ EIRDataType BTDevice::update(EInfoReport const & data) noexcept { data.toString().c_str(), this->toString().c_str()); } } + if( data.isSet(EIRDataType::FLAGS) ) { + gap_flags = data.getFlags(); + } if( data.isSet(EIRDataType::NAME) ) { if( 0 == name.length() || data.getName().length() > name.length() ) { name = data.getName(); diff --git a/src/direct_bt/BTManager.cpp b/src/direct_bt/BTManager.cpp index 3f26e379..446fb4d0 100644 --- a/src/direct_bt/BTManager.cpp +++ b/src/direct_bt/BTManager.cpp @@ -57,17 +57,6 @@ extern "C" { using namespace direct_bt; -BTMode MgmtEnv::getEnvBTMode() { - // Environment variable is 'direct_bt.mgmt.btmode' or 'org.tinyb.btmode' - // Default is BTMode::LE, if non of the above environment variable is set. - std::string val = jau::environment::getProperty("direct_bt.mgmt.btmode"); - if( val.empty() ) { - val = jau::environment::getProperty("org.tinyb.btmode"); - } - const BTMode res = direct_bt::to_BTMode(val); - return BTMode::NONE != res ? res : BTMode::DUAL; // fallback to default DUAL -} - MgmtEnv::MgmtEnv() noexcept : DEBUG_GLOBAL( jau::environment::get("direct_bt").debug ), exploding( jau::environment::getExplodingProperties("direct_bt.mgmt") ), @@ -75,7 +64,6 @@ MgmtEnv::MgmtEnv() noexcept MGMT_COMMAND_REPLY_TIMEOUT( jau::environment::getInt32Property("direct_bt.mgmt.cmd.timeout", 3000, 1500 /* min */, INT32_MAX /* max */) ), MGMT_EVT_RING_CAPACITY( jau::environment::getInt32Property("direct_bt.mgmt.ringsize", 64, 64 /* min */, 1024 /* max */) ), DEBUG_EVENT( jau::environment::getBooleanProperty("direct_bt.debug.mgmt.event", false) ), - DEFAULT_BTMODE( getEnvBTMode() ), MGMT_READ_PACKET_MAX_RETRY( MGMT_EVT_RING_CAPACITY ) { } @@ -240,7 +228,31 @@ std::unique_ptr<MgmtEvent> BTManager::sendWithReply(MgmtCommand &req) noexcept { return nullptr; } -std::unique_ptr<AdapterInfo> BTManager::initAdapter(const uint16_t dev_id, const BTMode btMode) noexcept { +std::unique_ptr<AdapterInfo> BTManager::readAdapterInfo(const uint16_t dev_id) noexcept { + std::unique_ptr<AdapterInfo> adapterInfo(nullptr); // nullptr + MgmtCommand req0(MgmtCommand::Opcode::READ_INFO, dev_id); + { + std::unique_ptr<MgmtEvent> res = sendWithReply(req0); + if( nullptr == res ) { + goto fail; + } + if( MgmtEvent::Opcode::CMD_COMPLETE != res->getOpcode() || res->getTotalSize() < MgmtEvtAdapterInfo::getRequiredTotalSize()) { + ERR_PRINT("Insufficient data for adapter info: req %d, res %s", MgmtEvtAdapterInfo::getRequiredTotalSize(), res->toString().c_str()); + goto fail; + } + const MgmtEvtAdapterInfo * res1 = static_cast<MgmtEvtAdapterInfo*>(res.get()); + adapterInfo = res1->toAdapterInfo(); + if( dev_id != adapterInfo->dev_id ) { + ABORT("readAdapterSettings dev_id=%d != dev_id=%d: %s", adapterInfo->dev_id, dev_id, adapterInfo->toString().c_str()); + } + } + DBG_PRINT("readAdapterSettings[%d]: End: %s", dev_id, adapterInfo->toString().c_str()); + +fail: + return adapterInfo; +} + +HCIStatusCode BTManager::initializeAdapter(AdapterInfo& adapterInfo, const uint16_t dev_id, const BTMode btMode) noexcept { /** * We weight on PairingMode::PASSKEY_ENTRY. FIXME: Have it configurable! * @@ -254,7 +266,6 @@ std::unique_ptr<AdapterInfo> BTManager::initAdapter(const uint16_t dev_id, const const uint8_t sc_on_param = 0x01; // SET_SECURE_CONN 0x00 disabled, 0x01 enables SC mixed, 0x02 enables SC only mode #endif - std::unique_ptr<AdapterInfo> adapterInfo(nullptr); // nullptr AdapterSetting current_settings; MgmtCommand req0(MgmtCommand::Opcode::READ_INFO, dev_id); { @@ -267,13 +278,13 @@ std::unique_ptr<AdapterInfo> BTManager::initAdapter(const uint16_t dev_id, const goto fail; } const MgmtEvtAdapterInfo * res1 = static_cast<MgmtEvtAdapterInfo*>(res.get()); - adapterInfo = res1->toAdapterInfo(); - if( dev_id != adapterInfo->dev_id ) { - ABORT("AdapterInfo dev_id=%d != dev_id=%d: %s", adapterInfo->dev_id, dev_id, adapterInfo->toString().c_str()); + res1->updateAdapterInfo(adapterInfo); + if( dev_id != adapterInfo.dev_id ) { + ABORT("initializeAdapter dev_id=%d != dev_id=%d: %s", adapterInfo.dev_id, dev_id, adapterInfo.toString().c_str()); } } - DBG_PRINT("initAdapter[%d, BTMode %s]: Start: %s", dev_id, to_string(btMode).c_str(), adapterInfo->toString().c_str()); - current_settings = adapterInfo->getCurrentSettingMask(); + DBG_PRINT("initializeAdapter[%d, BTMode %s]: Start: %s", dev_id, to_string(btMode).c_str(), adapterInfo.toString().c_str()); + current_settings = adapterInfo.getCurrentSettingMask(); setMode(dev_id, MgmtCommand::Opcode::SET_POWERED, 0, current_settings); @@ -330,9 +341,8 @@ std::unique_ptr<AdapterInfo> BTManager::initAdapter(const uint16_t dev_id, const * Update AdapterSettings post settings */ if( AdapterSetting::NONE != current_settings ) { - adapterInfo->setCurrentSettingMask(current_settings); + adapterInfo.setCurrentSettingMask(current_settings); } else { - adapterInfo = nullptr; // flush std::unique_ptr<MgmtEvent> res = sendWithReply(req0); if( nullptr == res ) { goto fail; @@ -342,45 +352,26 @@ std::unique_ptr<AdapterInfo> BTManager::initAdapter(const uint16_t dev_id, const goto fail; } const MgmtEvtAdapterInfo * res1 = static_cast<MgmtEvtAdapterInfo*>(res.get()); - adapterInfo = res1->toAdapterInfo(); - if( dev_id != adapterInfo->dev_id ) { - ABORT("AdapterInfo dev_id=%d != dev_id=%d: %s", adapterInfo->dev_id, dev_id, adapterInfo->toString().c_str()); + res1->updateAdapterInfo(adapterInfo); + if( dev_id != adapterInfo.dev_id ) { + ABORT("initializeAdapter dev_id=%d != dev_id=%d: %s", adapterInfo.dev_id, dev_id, adapterInfo.toString().c_str()); } } - DBG_PRINT("initAdapter[%d, BTMode %s]: End: %s", dev_id, to_string(btMode).c_str(), adapterInfo->toString().c_str()); + DBG_PRINT("initializeAdapter[%d, BTMode %s]: End: %s", dev_id, to_string(btMode).c_str(), adapterInfo.toString().c_str()); + return HCIStatusCode::SUCCESS; fail: - return adapterInfo; -} - -void BTManager::shutdownAdapter(BTAdapter& adapter) noexcept { - DBG_PRINT("DBTManager::shutdownAdapter: %s", adapter.toString().c_str()); - const uint16_t dev_id = adapter.dev_id; - adapter.close(); // also issues removeMgmtEventCallback(dev_id); - - AdapterSetting current_settings; - setMode(dev_id, MgmtCommand::Opcode::SET_POWERED, 0, current_settings); - - setMode(dev_id, MgmtCommand::Opcode::SET_BONDABLE, 0, current_settings); - setMode(dev_id, MgmtCommand::Opcode::SET_CONNECTABLE, 0, current_settings); - setMode(dev_id, MgmtCommand::Opcode::SET_FAST_CONNECTABLE, 0, current_settings); - - setMode(dev_id, MgmtCommand::Opcode::SET_DEBUG_KEYS, 0, current_settings); - setMode(dev_id, MgmtCommand::Opcode::SET_IO_CAPABILITY, direct_bt::number(SMPIOCapability::DISPLAY_ONLY), current_settings); - setMode(dev_id, MgmtCommand::Opcode::SET_SSP, 0, current_settings); - setMode(dev_id, MgmtCommand::Opcode::SET_SECURE_CONN, 0, current_settings); - DBG_PRINT("DBTManager::shutdownAdapter: done: %s", adapter.toString().c_str()); + return HCIStatusCode::FAILED; } -BTManager::BTManager(const BTMode _defaultBTMode) noexcept +BTManager::BTManager() noexcept : env(MgmtEnv::get()), - defaultBTMode(BTMode::NONE != _defaultBTMode ? _defaultBTMode : env.DEFAULT_BTMODE), rbuffer(ClientMaxMTU), comm(HCI_DEV_NONE, HCI_CHANNEL_CONTROL), mgmtEventRing(nullptr, env.MGMT_EVT_RING_CAPACITY), mgmtReaderShallStop(false), mgmtReaderThreadId(0), mgmtReaderRunning(false), allowClose( comm.isOpen() ) { - WORDY_PRINT("DBTManager.ctor: BTMode %s, pid %d", to_string(defaultBTMode).c_str(), BTManager::pidSelf); + WORDY_PRINT("DBTManager.ctor: pid %d", BTManager::pidSelf); if( !allowClose ) { ERR_PRINT("DBTManager::open: Could not open mgmt control channel"); return; @@ -479,7 +470,7 @@ next1: } for(int i=0; i < num_adapter; i++) { const uint16_t dev_id = jau::get_uint16(data, 2+i*2, true /* littleEndian */); - std::unique_ptr<AdapterInfo> adapterInfo = initAdapter(dev_id, defaultBTMode); + std::unique_ptr<AdapterInfo> adapterInfo = readAdapterInfo(dev_id); if( nullptr != adapterInfo ) { std::shared_ptr<BTAdapter> adapter = BTAdapter::make_shared(*this, *adapterInfo); adapters.push_back( adapter ); @@ -558,8 +549,8 @@ void BTManager::close() noexcept { { int i=0; jau::for_each_fidelity(adapters, [&](std::shared_ptr<BTAdapter> & a) { - DBG_PRINT("DBTManager::close::shutdownAdapter: %d/%d processing: %s", i, adapters.size(), a->toString().c_str()); - shutdownAdapter(*a); + DBG_PRINT("DBTManager::close -> adapter::close(): %d/%d processing: %s", i, adapters.size(), a->toString().c_str()); + a->close(); // also issues removeMgmtEventCallback(dev_id); ++i; }); } @@ -1162,7 +1153,7 @@ void BTManager::clearAllCallbacks() noexcept { void BTManager::processAdapterAdded(std::unique_ptr<MgmtEvent> e) noexcept { const uint16_t dev_id = e->getDevID(); - std::unique_ptr<AdapterInfo> adapterInfo = initAdapter(dev_id, defaultBTMode); + std::unique_ptr<AdapterInfo> adapterInfo = readAdapterInfo(dev_id); if( nullptr != adapterInfo ) { std::shared_ptr<BTAdapter> adapter = addAdapter( *adapterInfo ); diff --git a/src/direct_bt/HCIHandler.cpp b/src/direct_bt/HCIHandler.cpp index 4d0e6932..97ccced1 100644 --- a/src/direct_bt/HCIHandler.cpp +++ b/src/direct_bt/HCIHandler.cpp @@ -165,17 +165,6 @@ HCIHandler::HCIConnectionRef HCIHandler::removeHCIConnection(jau::darray<HCIConn return nullptr; } -void HCIHandler::resetAllStates(const bool powered_on) noexcept { - const std::lock_guard<std::recursive_mutex> lock(mtx_connectionList); // RAII-style acquire and relinquish via destructor - connectionList.clear(); - disconnectCmdList.clear(); - currentScanType = ScanType::NONE; - zeroSupCommands(); - if( powered_on ) { - initSupCommands(); - } -} - MgmtEvent::Opcode HCIHandler::translate(HCIEventType evt, HCIMetaEventType met) noexcept { if( HCIEventType::LE_META == evt ) { switch( met ) { @@ -512,12 +501,14 @@ void HCIHandler::sendMgmtEvent(const MgmtEvent& event) noexcept { (void)invokeCount; } -bool HCIHandler::sendCommand(HCICommand &req) noexcept { +bool HCIHandler::sendCommand(HCICommand &req, const bool quiet) noexcept { COND_PRINT(env.DEBUG_EVENT, "HCIHandler-IO SENT %s", req.toString().c_str()); TROOctets & pdu = req.getPDU(); if ( comm.write( pdu.get_ptr(), pdu.getSize() ) < 0 ) { - ERR_PRINT("HCIHandler::sendCommand: HCIComm write error, req %s - %s", req.toString().c_str(), toString().c_str()); + if( !quiet || jau::environment::get().verbose ) { + ERR_PRINT("HCIHandler::sendCommand: HCIComm write error, req %s - %s", req.toString().c_str(), toString().c_str()); + } return false; } return true; @@ -722,9 +713,7 @@ HCIHandler::HCIHandler(const uint16_t dev_id_, const BTMode btMode_) noexcept #endif filter_put_opcbit(mask); } - - sup_commands_set = false; - initSupCommands(); // OK to fail + zeroSupCommands(); PERF_TS_TD("HCIHandler::ctor.ok"); WORDY_PRINT("HCIHandler.ctor: End OK - %s", toString().c_str()); @@ -740,6 +729,7 @@ fail: void HCIHandler::zeroSupCommands() noexcept { bzero(sup_commands, sizeof(sup_commands)); sup_commands_set = false; + le_ll_feats = LE_Features::NONE; } bool HCIHandler::initSupCommands() noexcept { // We avoid using a lock or an atomic-switch as we rely on sensible calls. @@ -747,10 +737,25 @@ bool HCIHandler::initSupCommands() noexcept { zeroSupCommands(); return false; } + HCIStatusCode status; + + le_ll_feats = LE_Features::NONE; + { + HCICommand req0(HCIOpcode::LE_READ_LOCAL_FEATURES, 0); + const hci_rp_le_read_local_features * ev_lf; + std::unique_ptr<HCIEvent> ev = processCommandComplete(req0, &ev_lf, &status, true /* quiet */); + if( nullptr == ev || nullptr == ev_lf || HCIStatusCode::SUCCESS != status ) { + DBG_PRINT("HCIHandler::le_read_local_features: LE_READ_LOCAL_FEATURES: 0x%x (%s) - %s", + number(status), to_string(status).c_str(), toString().c_str()); + zeroSupCommands(); + return false; + } + le_ll_feats = static_cast<LE_Features>( jau::get_uint64(ev_lf->features, 0, true /* littleEndian */) ); + } + HCICommand req0(HCIOpcode::READ_LOCAL_COMMANDS, 0); const hci_rp_read_local_commands * ev_cmds; - HCIStatusCode status; - std::unique_ptr<HCIEvent> ev = processCommandComplete(req0, &ev_cmds, &status); + std::unique_ptr<HCIEvent> ev = processCommandComplete(req0, &ev_cmds, &status, true /* quiet */); if( nullptr == ev || nullptr == ev_cmds || HCIStatusCode::SUCCESS != status ) { DBG_PRINT("HCIHandler::ctor: READ_LOCAL_COMMANDS: 0x%x (%s) - %s", number(status), to_string(status).c_str(), toString().c_str()); @@ -763,6 +768,20 @@ bool HCIHandler::initSupCommands() noexcept { } } +bool HCIHandler::resetAllStates(const bool powered_on) noexcept { + const std::lock_guard<std::recursive_mutex> lock(mtx_connectionList); // RAII-style acquire and relinquish via destructor + connectionList.clear(); + disconnectCmdList.clear(); + currentScanType = ScanType::NONE; + advertisingEnabled = false; + zeroSupCommands(); + if( powered_on ) { + return initSupCommands(); + } else { + return true; + } +} + void HCIHandler::close() noexcept { // Avoid disconnect re-entry -> potential deadlock bool expConn = true; // C++11, exp as value since C++20 @@ -832,8 +851,7 @@ HCIStatusCode HCIHandler::startAdapter() { return HCIStatusCode::INTERNAL_FAILURE; } } - resetAllStates(true); - return HCIStatusCode::SUCCESS; + return resetAllStates(true) ? HCIStatusCode::SUCCESS : HCIStatusCode::FAILED; #else #warning add implementation #endif @@ -896,7 +914,7 @@ HCIStatusCode HCIHandler::reset() noexcept { return HCIStatusCode::INTERNAL_TIMEOUT; // timeout } if( HCIStatusCode::SUCCESS == status ) { - resetAllStates(true); + status = resetAllStates(true) ? HCIStatusCode::SUCCESS : HCIStatusCode::FAILED; } return status; } @@ -924,25 +942,6 @@ HCIStatusCode HCIHandler::getLocalVersion(HCILocalVersion &version) noexcept { return status; } -HCIStatusCode HCIHandler::le_read_local_features(LE_Features& res) noexcept { - if( !isOpen() ) { - ERR_PRINT("HCIHandler::le_read_local_features: Not connected %s", toString().c_str()); - return HCIStatusCode::INTERNAL_FAILURE; - } - res = LE_Features::NONE; - HCICommand req0(HCIOpcode::LE_READ_LOCAL_FEATURES, 0); - const hci_rp_le_read_local_features * ev_lf; - HCIStatusCode status; - std::unique_ptr<HCIEvent> ev = processCommandComplete(req0, &ev_lf, &status); - if( nullptr == ev || nullptr == ev_lf || HCIStatusCode::SUCCESS != status ) { - ERR_PRINT("HCIHandler::le_read_local_features: LE_READ_LOCAL_FEATURES: 0x%x (%s) - %s", - number(status), to_string(status).c_str(), toString().c_str()); - } else { - res = static_cast<LE_Features>( jau::get_uint64(ev_lf->features, 0, true /* littleEndian */) ); - } - return status; -} - HCIStatusCode HCIHandler::le_set_scan_param(const bool le_scan_active, const HCILEOwnAddressType own_mac_type, const uint16_t le_scan_interval, const uint16_t le_scan_window, @@ -1061,12 +1060,12 @@ HCIStatusCode HCIHandler::le_start_scan(const bool filter_dup, if( HCIStatusCode::SUCCESS != status ) { WARN_PRINT("HCIHandler::le_start_scan: le_set_scan_param failed: %s - %s", to_string(status).c_str(), toString().c_str()); - } else { - status = le_enable_scan(true /* enable */, filter_dup); - if( HCIStatusCode::SUCCESS != status ) { - WARN_PRINT("HCIHandler::le_start_scan: le_enable_scan failed: %s - %s", - to_string(status).c_str(), toString().c_str()); - } + return status; + } + status = le_enable_scan(true /* enable */, filter_dup); + if( HCIStatusCode::SUCCESS != status ) { + WARN_PRINT("HCIHandler::le_start_scan: le_enable_scan failed: %s - %s", + to_string(status).c_str(), toString().c_str()); } return status; } @@ -1401,7 +1400,7 @@ HCIStatusCode HCIHandler::le_read_phy(const uint16_t conn_handle, const BDAddres return status; } -std::unique_ptr<HCIEvent> HCIHandler::processCommandStatus(HCICommand &req, HCIStatusCode *status) noexcept +std::unique_ptr<HCIEvent> HCIHandler::processCommandStatus(HCICommand &req, HCIStatusCode *status, const bool quiet) noexcept { const std::lock_guard<std::recursive_mutex> lock(mtx_sendReply); // RAII-style acquire and relinquish via destructor @@ -1436,10 +1435,12 @@ std::unique_ptr<HCIEvent> HCIHandler::processCommandStatus(HCICommand &req, HCIS } if( nullptr == ev ) { // timeout exit - WARN_PRINT("HCIHandler::processCommandStatus %s -> Status 0x%2.2X (%s), errno %d %s: res nullptr, req %s - %s", - to_string(req.getOpcode()).c_str(), - number(*status), to_string(*status).c_str(), errno, strerror(errno), - req.toString().c_str(), toString().c_str()); + if( !quiet || jau::environment::get().verbose ) { + WARN_PRINT("HCIHandler::processCommandStatus %s -> Status 0x%2.2X (%s), errno %d %s: res nullptr, req %s - %s", + to_string(req.getOpcode()).c_str(), + number(*status), to_string(*status).c_str(), errno, strerror(errno), + req.toString().c_str(), toString().c_str()); + } } exit: @@ -1448,26 +1449,30 @@ exit: template<typename hci_cmd_event_struct> std::unique_ptr<HCIEvent> HCIHandler::processCommandComplete(HCICommand &req, - const hci_cmd_event_struct **res, HCIStatusCode *status) noexcept + const hci_cmd_event_struct **res, HCIStatusCode *status, + const bool quiet) noexcept { const std::lock_guard<std::recursive_mutex> lock(mtx_sendReply); // RAII-style acquire and relinquish via destructor *res = nullptr; *status = HCIStatusCode::INTERNAL_FAILURE; - if( !sendCommand(req) ) { - WARN_PRINT("HCIHandler::processCommandComplete Send failed: Status 0x%2.2X (%s), errno %d %s: res nullptr, req %s - %s", - number(*status), to_string(*status).c_str(), errno, strerror(errno), - req.toString().c_str(), toString().c_str()); + if( !sendCommand(req, quiet) ) { + if( !quiet || jau::environment::get().verbose ) { + WARN_PRINT("HCIHandler::processCommandComplete Send failed: Status 0x%2.2X (%s), errno %d %s: res nullptr, req %s - %s", + number(*status), to_string(*status).c_str(), errno, strerror(errno), + req.toString().c_str(), toString().c_str()); + } return nullptr; // timeout } - return receiveCommandComplete(req, res, status); + return receiveCommandComplete(req, res, status, quiet); } template<typename hci_cmd_event_struct> std::unique_ptr<HCIEvent> HCIHandler::receiveCommandComplete(HCICommand &req, - const hci_cmd_event_struct **res, HCIStatusCode *status) noexcept + const hci_cmd_event_struct **res, HCIStatusCode *status, + const bool quiet) noexcept { *res = nullptr; *status = HCIStatusCode::INTERNAL_FAILURE; @@ -1477,24 +1482,30 @@ std::unique_ptr<HCIEvent> HCIHandler::receiveCommandComplete(HCICommand &req, std::unique_ptr<HCIEvent> ev = getNextCmdCompleteReply(req, &ev_cc); if( nullptr == ev ) { *status = HCIStatusCode::INTERNAL_TIMEOUT; - WARN_PRINT("HCIHandler::processCommandComplete %s -> %s: Status 0x%2.2X (%s), errno %d %s: res nullptr, req %s - %s", - to_string(req.getOpcode()).c_str(), to_string(evc).c_str(), - number(*status), to_string(*status).c_str(), errno, strerror(errno), - req.toString().c_str(), toString().c_str()); + if( !quiet || jau::environment::get().verbose ) { + WARN_PRINT("HCIHandler::processCommandComplete %s -> %s: Status 0x%2.2X (%s), errno %d %s: res nullptr, req %s - %s", + to_string(req.getOpcode()).c_str(), to_string(evc).c_str(), + number(*status), to_string(*status).c_str(), errno, strerror(errno), + req.toString().c_str(), toString().c_str()); + } return nullptr; // timeout } else if( nullptr == ev_cc ) { - WARN_PRINT("HCIHandler::processCommandComplete %s -> %s: Status 0x%2.2X (%s), errno %d %s: res %s, req %s - %s", - to_string(req.getOpcode()).c_str(), to_string(evc).c_str(), - number(*status), to_string(*status).c_str(), errno, strerror(errno), - ev->toString().c_str(), req.toString().c_str(), toString().c_str()); + if( !quiet || jau::environment::get().verbose ) { + WARN_PRINT("HCIHandler::processCommandComplete %s -> %s: Status 0x%2.2X (%s), errno %d %s: res %s, req %s - %s", + to_string(req.getOpcode()).c_str(), to_string(evc).c_str(), + number(*status), to_string(*status).c_str(), errno, strerror(errno), + ev->toString().c_str(), req.toString().c_str(), toString().c_str()); + } return ev; } const uint8_t returnParamSize = ev_cc->getReturnParamSize(); if( returnParamSize < sizeof(hci_cmd_event_struct) ) { - WARN_PRINT("HCIHandler::processCommandComplete %s -> %s: Status 0x%2.2X (%s), errno %d %s: res %s, req %s - %s", - to_string(req.getOpcode()).c_str(), to_string(evc).c_str(), - number(*status), to_string(*status).c_str(), errno, strerror(errno), - ev_cc->toString().c_str(), req.toString().c_str(), toString().c_str()); + if( !quiet || jau::environment::get().verbose ) { + WARN_PRINT("HCIHandler::processCommandComplete %s -> %s: Status 0x%2.2X (%s), errno %d %s: res %s, req %s - %s", + to_string(req.getOpcode()).c_str(), to_string(evc).c_str(), + number(*status), to_string(*status).c_str(), errno, strerror(errno), + ev_cc->toString().c_str(), req.toString().c_str(), toString().c_str()); + } return ev; } *res = (const hci_cmd_event_struct*)(ev_cc->getReturnParam()); diff --git a/src/direct_bt/MgmtTypes.cpp b/src/direct_bt/MgmtTypes.cpp index b9b99dcc..94923b08 100644 --- a/src/direct_bt/MgmtTypes.cpp +++ b/src/direct_bt/MgmtTypes.cpp @@ -493,6 +493,17 @@ std::unique_ptr<AdapterInfo> MgmtEvtAdapterInfo::toAdapterInfo() const noexcept getName(), getShortName()); } +bool MgmtEvtAdapterInfo::updateAdapterInfo(AdapterInfo& info) const noexcept { + if( info.dev_id != getDevID() || info.addressAndType.address != getAddress() ) { + return false; + } + info.setSettingMasks(getSupportedSetting(), getCurrentSetting()); + info.setDevClass(getDevClass()); + info.setName(getName()); + info.setShortName(getShortName()); + return true; +} + std::string MgmtEvtDeviceDisconnected::getDisconnectReasonString(DisconnectReason mgmtReason) noexcept { switch(mgmtReason) { case DisconnectReason::TIMEOUT: return "TIMEOUT"; |