diff options
author | Sven Gothel <[email protected]> | 2020-05-24 15:35:29 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2020-05-24 15:35:29 +0200 |
commit | eb67f2d4e0100193822df670e17ed659b1debfd4 (patch) | |
tree | f33725ddbc9faa4fd0d86d073ef5826be6279e7f | |
parent | 2d3c107a59abaa0a5e504f9c17aafd0a7824b363 (diff) |
DBTManager: Support LOAD_CONN_PARAM (MgmtLoadConnParamCmd), providing same performance as with explicit HCI le_connect
Turns out the lower performance with whitelist autoconnect was due to the default kernel BlueZ connection parameter.
Adding DBTManager.uploadConnParam(..) using our same default connection params,
which should be called right before DBTManager.addDeviceToWhitelist(..).
DBTAdapter.addDeviceToWhitelist(..) includes upfront the DBTManager.uploadConnParam(..) call
with this commit.
-rw-r--r-- | api/direct_bt/DBTAdapter.hpp | 16 | ||||
-rw-r--r-- | api/direct_bt/DBTManager.hpp | 9 | ||||
-rw-r--r-- | api/direct_bt/MgmtTypes.hpp | 82 | ||||
-rw-r--r-- | src/direct_bt/DBTAdapter.cpp | 13 | ||||
-rw-r--r-- | src/direct_bt/DBTManager.cpp | 21 |
5 files changed, 138 insertions, 3 deletions
diff --git a/api/direct_bt/DBTAdapter.hpp b/api/direct_bt/DBTAdapter.hpp index 88e146e8..7cff8f62 100644 --- a/api/direct_bt/DBTAdapter.hpp +++ b/api/direct_bt/DBTAdapter.hpp @@ -264,8 +264,20 @@ namespace direct_bt { */ bool closeHCI(); - /** Add the given device to the adapter's autoconnect whitelist. */ - bool addDeviceToWhitelist(const EUI48 &address, const BDAddressType address_type, const HCIWhitelistConnectType ctype); + /** + * Add the given device to the adapter's autoconnect whitelist. + * <p> + * The given connection parameter will be uploaded to the kernel for the given device first. + * </p> + * <p> + * Method will reject duplicate devices, in which case it should be removed first. + * </p> + */ + bool addDeviceToWhitelist(const EUI48 &address, const BDAddressType address_type, + const HCIWhitelistConnectType ctype, + const uint16_t min_interval=0x000F, const uint16_t max_interval=0x000F, + const uint16_t latency=0x0000, const uint16_t timeout=0x0C80); + /** Remove the given device from the adapter's autoconnect whitelist. */ bool removeDeviceFromWhitelist(const EUI48 &address, const BDAddressType address_type); diff --git a/api/direct_bt/DBTManager.hpp b/api/direct_bt/DBTManager.hpp index 77503998..a0a8bae3 100644 --- a/api/direct_bt/DBTManager.hpp +++ b/api/direct_bt/DBTManager.hpp @@ -243,6 +243,13 @@ namespace direct_bt { bool stopDiscovery(const int dev_id, const ScanType type); /** + * Uploads given connection parameter for given device to the kernel. + */ + bool uploadConnParam(const int dev_id, const EUI48 &address, const BDAddressType address_type, + const uint16_t min_interval=0x000F, const uint16_t max_interval=0x000F, + const uint16_t latency=0x0000, const uint16_t timeout=0x0C80); + + /** * Returns true, if the adapter's device is already whitelisted. */ bool isDeviceWhitelisted(const int dev_id, const EUI48 &address); @@ -257,8 +264,10 @@ namespace direct_bt { * </p> */ bool addDeviceToWhitelist(const int dev_id, const EUI48 &address, const BDAddressType address_type, const HCIWhitelistConnectType ctype); + /** Remove the given device from the adapter's autoconnect whitelist. */ bool removeDeviceFromWhitelist(const int dev_id, const EUI48 &address, const BDAddressType address_type); + /** Remove all previously added devices from the autoconnect whitelist. Returns number of removed devices. */ int removeAllDevicesFromWhitelist(); diff --git a/api/direct_bt/MgmtTypes.hpp b/api/direct_bt/MgmtTypes.hpp index eec477e4..6e0b4cb1 100644 --- a/api/direct_bt/MgmtTypes.hpp +++ b/api/direct_bt/MgmtTypes.hpp @@ -418,6 +418,88 @@ namespace direct_bt { const std::string getShortName() const { return pdu.get_string(MGMT_HEADER_SIZE + MgmtConstU16::MAX_NAME_LENGTH); } }; + struct MgmtConnParam { + EUI48 address; + uint8_t address_type; + uint16_t min_interval; + uint16_t max_interval; + uint16_t latency; + uint16_t timeout; + } __packed; + + /** + * uint16_t param_count 2 + * MgmtConnParam param[] 15 = 1x + * + * MgmtConnParam { + * mgmt_addr_info { EUI48, uint8_t type }, 7 + * uint16_t min_interval; 2 + * uint16_t max_interval; 2 + * uint16_t latency; 2 + * uint16_t timeout; 2 + * } + * uint8_t name[MGMT_MAX_NAME_LENGTH]; + * uint8_t short_name[MGMT_MAX_SHORT_NAME_LENGTH]; + */ + class MgmtLoadConnParamCmd : public MgmtCommand + { + protected: + std::string valueString() const override { + const int paramCount = getParamCount(); + std::string ps = "count "+std::to_string(paramCount)+": "; + for(int i=0; i<paramCount; i++) { + if( 0 < i ) { + ps.append(", "); + } + ps.append( "[address "+getAddress(i).toString()+", addressType "+getBDAddressTypeString(getAddressType(i))+ + ", interval["+std::to_string(getMinInterval(i))+".."+std::to_string(getMaxInterval(i)) + +"], latency "+std::to_string(getLatency(i))+", timeout "+std::to_string(getTimeout(i))+"]"); + } + return "param[size "+std::to_string(getParamSize())+", data["+ps+"]], tsz "+std::to_string(getTotalSize()); + } + + public: + MgmtLoadConnParamCmd(const uint16_t dev_id, const MgmtConnParam & connParam) + : MgmtCommand(MgmtOpcode::LOAD_CONN_PARAM, dev_id, 2 + 15) + { + int offset = MGMT_HEADER_SIZE; + pdu.put_uint16(offset, 1); offset+= 2; + + pdu.put_eui48(offset, connParam.address); offset+=6; + pdu.put_uint8(offset, connParam.address_type); offset+=1; + pdu.put_uint16(offset, connParam.min_interval); offset+=2; + pdu.put_uint16(offset, connParam.max_interval); offset+=2; + pdu.put_uint16(offset, connParam.latency); offset+=2; + pdu.put_uint16(offset, connParam.timeout); offset+=2; + } + + MgmtLoadConnParamCmd(const uint16_t dev_id, std::vector<std::shared_ptr<MgmtConnParam>> connParams) + : MgmtCommand(MgmtOpcode::LOAD_CONN_PARAM, dev_id, 2 + connParams.size() * 15) + { + int offset = MGMT_HEADER_SIZE; + pdu.put_uint16(offset, connParams.size()); offset+= 2; + + for(auto it = connParams.begin(); it != connParams.end(); ++it) { + std::shared_ptr<MgmtConnParam> connParam = *it; + + pdu.put_eui48(offset, connParam->address); offset+=6; + pdu.put_uint8(offset, connParam->address_type); offset+=1; + pdu.put_uint16(offset, connParam->min_interval); offset+=2; + pdu.put_uint16(offset, connParam->max_interval); offset+=2; + pdu.put_uint16(offset, connParam->latency); offset+=2; + pdu.put_uint16(offset, connParam->timeout); offset+=2; + } + } + uint16_t getParamCount() const { return pdu.get_uint16(MGMT_HEADER_SIZE); } + + const EUI48 getAddress(int idx) const { return EUI48(pdu.get_ptr(MGMT_HEADER_SIZE + 2 + 15*idx)); } // mgmt_addr_info + BDAddressType getAddressType(int idx) const { return static_cast<BDAddressType>(pdu.get_uint8(MGMT_HEADER_SIZE + 2 + 15*idx + 6)); } // mgmt_addr_info + uint16_t getMinInterval(int idx) const { return pdu.get_uint16(MGMT_HEADER_SIZE + 2 + 15*idx + 6 + 1); } + uint16_t getMaxInterval(int idx) const { return pdu.get_uint16(MGMT_HEADER_SIZE + 2 + 15*idx + 6 + 1 + 2); } + uint16_t getLatency(int idx) const { return pdu.get_uint16(MGMT_HEADER_SIZE + 2 + 15*idx + 6 + 1 + 2 + 2); } + uint16_t getTimeout(int idx) const { return pdu.get_uint16(MGMT_HEADER_SIZE + 2 + 15*idx + 6 + 1 + 2 + 2 + 2); } + }; + /** * uint16_t opcode, * uint16_t dev-id, diff --git a/src/direct_bt/DBTAdapter.cpp b/src/direct_bt/DBTAdapter.cpp index 70b10994..a96417a4 100644 --- a/src/direct_bt/DBTAdapter.cpp +++ b/src/direct_bt/DBTAdapter.cpp @@ -218,7 +218,18 @@ bool DBTAdapter::closeHCI() return true; } -bool DBTAdapter::addDeviceToWhitelist(const EUI48 &address, const BDAddressType address_type, const HCIWhitelistConnectType ctype) { +bool DBTAdapter::addDeviceToWhitelist(const EUI48 &address, const BDAddressType address_type, const HCIWhitelistConnectType ctype, + const uint16_t min_interval, const uint16_t max_interval, + const uint16_t latency, const uint16_t timeout) { + if( mgmt.isDeviceWhitelisted(dev_id, address) ) { + ERR_PRINT("DBTAdapter::addDeviceToWhitelist: device already listed: dev_id %d, address %s", dev_id, address.toString().c_str()); + return false; + } + + if( !mgmt.uploadConnParam(dev_id, address, address_type, min_interval, max_interval, latency, timeout) ) { + ERR_PRINT("DBTAdapter::addDeviceToWhitelist: uploadConnParam(dev_id %d, address %s, interval[%u..%u], latency %u, timeout %u): Failed", + dev_id, address.toString().c_str(), min_interval, max_interval, latency, timeout); + } return mgmt.addDeviceToWhitelist(dev_id, address, address_type, ctype); } diff --git a/src/direct_bt/DBTManager.cpp b/src/direct_bt/DBTManager.cpp index 7a840791..f7c20c3e 100644 --- a/src/direct_bt/DBTManager.cpp +++ b/src/direct_bt/DBTManager.cpp @@ -506,6 +506,27 @@ bool DBTManager::stopDiscovery(const int dev_id, const ScanType type) { } } +bool DBTManager::uploadConnParam(const int dev_id, const EUI48 &address, const BDAddressType address_type, + const uint16_t min_interval, const uint16_t max_interval, + const uint16_t latency, const uint16_t timeout) { + MgmtConnParam connParam{ address, address_type, min_interval, max_interval, latency, timeout }; + MgmtLoadConnParamCmd req(dev_id, connParam); + DBG_PRINT("DBTManager::uploadConnParam: %s", req.toString().c_str()); + std::shared_ptr<MgmtEvent> res = sendWithReply(req); + if( nullptr == res ) { + DBG_PRINT("DBTManager::uploadConnParam res: NULL"); + } else { + DBG_PRINT("DBTManager::uploadConnParam res: %s", res->toString().c_str()); + if( res->getOpcode() == MgmtEvent::Opcode::CMD_COMPLETE ) { + const MgmtEvtCmdComplete &res1 = *static_cast<const MgmtEvtCmdComplete *>(res.get()); + if( MgmtStatus::SUCCESS == res1.getStatus() ) { + return true; + } + } + } + return false; +} + bool DBTManager::isDeviceWhitelisted(const int dev_id, const EUI48 &address) { for(auto it = whitelist.begin(); it != whitelist.end(); ) { std::shared_ptr<WhitelistElem> wle = *it; |