Skip to content

Commit

Permalink
Refactor NimBLEAddress - use NimBLE core representation.
Browse files Browse the repository at this point in the history
This simplifies the NimBLEAddress code by directly using the NimBLE core ble_addr_t type to hold the address
and allows using NimBLE core functions and macros to replace code in some methods.

* Adds getBase method to access the base NimBLE address struct.
* Adds isNrpa method to test if an address is random non-resolvable.
* Adds isStatic method to test if an address is random static.
* equals method and == operator will now also test if the address types are the same.
* Code cleanup
  • Loading branch information
h2zero committed Jul 5, 2024
1 parent 44977cd commit 37addff
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 141 deletions.
164 changes: 81 additions & 83 deletions src/NimBLEAddress.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,192 +14,190 @@
#include "nimconfig.h"
#if defined(CONFIG_BT_ENABLED)

#include <algorithm>

#include "NimBLEAddress.h"
#include "NimBLEUtils.h"
#include "NimBLELog.h"
# include "NimBLEAddress.h"
# include "NimBLEUtils.h"
# include "NimBLELog.h"
# include <algorithm>

static const char* LOG_TAG = "NimBLEAddress";

/*************************************************
* NOTE: NimBLE address bytes are in INVERSE ORDER!
* We will accomodate that fact in these methods.
*************************************************/
* We will accommodate that fact in these methods.
*************************************************/

/**
* @brief Create an address from the native NimBLE representation.
* @param [in] address The native NimBLE address.
*/
NimBLEAddress::NimBLEAddress(ble_addr_t address) {
memcpy(m_address, address.val, 6);
m_addrType = address.type;
} // NimBLEAddress


/**
* @brief Create a blank address, i.e. 00:00:00:00:00:00, type 0.
*/
NimBLEAddress::NimBLEAddress() {
NimBLEAddress("");
m_address = address;
} // NimBLEAddress


/**
* @brief Create an address from a hex string
*
* A hex string is of the format:
* ```
* 00:00:00:00:00:00
* ```
* which is 17 characters in length.
*
* @param [in] stringAddress The hex string representation of the address.
* @brief Create an address from a hex string.
* @param [in] addr The hex string representation of the address.
* @param [in] type The type of the address.
*/
NimBLEAddress::NimBLEAddress(const std::string &stringAddress, uint8_t type) {
m_addrType = type;
NimBLEAddress::NimBLEAddress(const std::string& addr, uint8_t type) {
m_address.type = type;

if (stringAddress.length() == 0) {
memset(m_address, 0, 6);
return;
if (addr.length() != BLE_DEV_ADDR_LEN && addr.length() != 17) {
goto Error;
}

if (stringAddress.length() == 6) {
std::reverse_copy(stringAddress.data(), stringAddress.data() + 6, m_address);
if (addr.length() == BLE_DEV_ADDR_LEN) {
std::reverse_copy(addr.data(), addr.data() + BLE_DEV_ADDR_LEN, m_address.val);
return;
}

if (stringAddress.length() != 17) {
memset(m_address, 0, sizeof m_address); // "00:00:00:00:00:00" represents an invalid address
NIMBLE_LOGD(LOG_TAG, "Invalid address '%s'", stringAddress.c_str());
return;
if (sscanf(addr.c_str(),
"%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
&m_address.val[5],
&m_address.val[4],
&m_address.val[3],
&m_address.val[2],
&m_address.val[1],
&m_address.val[0]) != BLE_DEV_ADDR_LEN) {
memset(&m_address, 0, sizeof m_address);
goto Error;
}

int data[6];
if(sscanf(stringAddress.c_str(), "%x:%x:%x:%x:%x:%x", &data[5], &data[4], &data[3], &data[2], &data[1], &data[0]) != 6) {
memset(m_address, 0, sizeof m_address); // "00:00:00:00:00:00" represents an invalid address
NIMBLE_LOGD(LOG_TAG, "Invalid address '%s'", stringAddress.c_str());
}
for(size_t index = 0; index < sizeof m_address; index++) {
m_address[index] = data[index];
}
} // NimBLEAddress
return;

Error:
NIMBLE_LOGE(LOG_TAG, "Invalid address '%s'", addr.c_str());
} // NimBLEAddress

/**
* @brief Constructor for compatibility with bluedroid esp library using native ESP representation.
* @param [in] address A uint8_t[6] or esp_bd_addr_t containing the address.
* @param [in] type The type of the address.
*/
NimBLEAddress::NimBLEAddress(uint8_t address[6], uint8_t type) {
std::reverse_copy(address, address + sizeof m_address, m_address);
m_addrType = type;
NimBLEAddress::NimBLEAddress(const uint8_t address[BLE_DEV_ADDR_LEN], uint8_t type) {
std::reverse_copy(address, address + BLE_DEV_ADDR_LEN, m_address.val);
m_address.type = type;
} // NimBLEAddress


/**
* @brief Constructor for address using a hex value.\n
* Use the same byte order, so use 0xa4c1385def16 for "a4:c1:38:5d:ef:16"
* @param [in] address uint64_t containing the address.
* @param [in] type The type of the address.
*/
NimBLEAddress::NimBLEAddress(const uint64_t &address, uint8_t type) {
memcpy(m_address, &address, sizeof m_address);
m_addrType = type;
NimBLEAddress::NimBLEAddress(const uint64_t& address, uint8_t type) {
memcpy(m_address.val, &address, sizeof m_address);
m_address.type = type;
} // NimBLEAddress


/**
* @brief Determine if this address equals another.
* @param [in] otherAddress The other address to compare against.
* @return True if the addresses are equal.
*/
bool NimBLEAddress::equals(const NimBLEAddress &otherAddress) const {
bool NimBLEAddress::equals(const NimBLEAddress& otherAddress) const {
return *this == otherAddress;
} // equals


/**
* @brief Get the native representation of the address.
* @return a pointer to the uint8_t[6] array of the address.
*/
const uint8_t *NimBLEAddress::getNative() const {
return m_address;
const uint8_t* NimBLEAddress::getNative() const {
return m_address.val;
} // getNative

/**
* @brief Get the NimBLE core base representation of the address.
* @return a reference to the ble_addr_t struct of the address.
*/
const ble_addr_t& NimBLEAddress::getBase() const {
return m_address;
}

/**
* @brief Get the address type.
* @return The address type.
*/
uint8_t NimBLEAddress::getType() const {
return m_addrType;
return m_address.type;
} // getType


/**
* @brief Determine if this address is a Resolvable Private Address.
* @return True if the address is a RPA.
*/
bool NimBLEAddress::isRpa() const {
return (m_addrType && ((m_address[5] & 0xc0) == 0x40));
return BLE_ADDR_IS_RPA(&m_address);
} // isRpa

/**
* @brief Determine if this address is a Non-Resolvable Private Address.
* @return True if the address is a NRPA.
*/
bool NimBLEAddress::isNrpa() const {
return BLE_ADDR_IS_NRPA(&m_address);
} // isNrpa

/**
* @brief Determine if this address is a Static Address.
* @return True if the address is a Static Address.
*/
bool NimBLEAddress::isStatic() const {
return BLE_ADDR_IS_STATIC(&m_address);
} // isStatic

/**
* @brief Convert a BLE address to a string.
*
* A string representation of an address is in the format:
*
* ```
* xx:xx:xx:xx:xx:xx
* ```
*
* @return The string representation of the address.
* @deprecated Use std::string() operator instead.
*/
std::string NimBLEAddress::toString() const {
return std::string(*this);
} // toString


/**
* @brief Convenience operator to check if this address is equal to another.
*/
bool NimBLEAddress::operator ==(const NimBLEAddress & rhs) const {
return memcmp(rhs.m_address, m_address, sizeof m_address) == 0;
} // operator ==
bool NimBLEAddress::operator==(const NimBLEAddress& rhs) const {
if (m_address.type != rhs.m_address.type) {
return false;
}

return memcmp(rhs.m_address.val, m_address.val, sizeof m_address.val) == 0;
} // operator ==

/**
* @brief Convenience operator to check if this address is not equal to another.
*/
bool NimBLEAddress::operator !=(const NimBLEAddress & rhs) const {
bool NimBLEAddress::operator!=(const NimBLEAddress& rhs) const {
return !this->operator==(rhs);
} // operator !=


/**
* @brief Convienience operator to convert this address to string representation.
* @details This allows passing NimBLEAddress to functions
* that accept std::string and/or or it's methods as a parameter.
* @brief Convenience operator to convert this address to string representation.
* @details This allows passing NimBLEAddress to functions that accept std::string and/or it's methods as a parameter.
*/
NimBLEAddress::operator std::string() const {
char buffer[18];
snprintf(buffer, sizeof(buffer), "%02x:%02x:%02x:%02x:%02x:%02x",
m_address[5], m_address[4], m_address[3],
m_address[2], m_address[1], m_address[0]);
snprintf(buffer,
sizeof(buffer),
"%02x:%02x:%02x:%02x:%02x:%02x",
m_address.val[5],
m_address.val[4],
m_address.val[3],
m_address.val[2],
m_address.val[1],
m_address.val[0]);
return std::string(buffer);
} // operator std::string


/**
* @brief Convenience operator to convert the native address representation to uint_64.
*/
NimBLEAddress::operator uint64_t() const {
uint64_t address = 0;
memcpy(&address, m_address, sizeof m_address);
memcpy(&address, m_address.val, sizeof m_address.val);
return address;
} // operator uint64_t

Expand Down
63 changes: 34 additions & 29 deletions src/NimBLEAddress.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,46 +17,51 @@
#include "nimconfig.h"
#if defined(CONFIG_BT_ENABLED)

#if defined(CONFIG_NIMBLE_CPP_IDF)
#include "nimble/ble.h"
#else
#include "nimble/nimble/include/nimble/ble.h"
#endif
# if defined(CONFIG_NIMBLE_CPP_IDF)
# include "nimble/ble.h"
# else
# include "nimble/nimble/include/nimble/ble.h"
# endif

/**** FIX COMPILATION ****/
#undef min
#undef max
# undef min
# undef max
/**************************/

#include <string>
#include <algorithm>
# include <string>
# include <algorithm>

/**
* @brief A %BLE device address.
*
* Every %BLE device has a unique address which can be used to identify it and form connections.
*/
class NimBLEAddress {
public:
NimBLEAddress();
NimBLEAddress(ble_addr_t address);
NimBLEAddress(uint8_t address[6], uint8_t type = BLE_ADDR_PUBLIC);
NimBLEAddress(const std::string &stringAddress, uint8_t type = BLE_ADDR_PUBLIC);
NimBLEAddress(const uint64_t &address, uint8_t type = BLE_ADDR_PUBLIC);
bool isRpa() const;
bool equals(const NimBLEAddress &otherAddress) const;
const uint8_t* getNative() const;
std::string toString() const;
uint8_t getType() const;

bool operator ==(const NimBLEAddress & rhs) const;
bool operator !=(const NimBLEAddress & rhs) const;
operator std::string() const;
operator uint64_t() const;

private:
uint8_t m_address[6];
uint8_t m_addrType;
public:
/**
* @brief Create a blank address, i.e. 00:00:00:00:00:00, type 0.
*/
NimBLEAddress() {}
NimBLEAddress(const ble_addr_t address);
NimBLEAddress(const uint8_t address[BLE_DEV_ADDR_LEN], uint8_t type = BLE_ADDR_PUBLIC);
NimBLEAddress(const std::string& stringAddress, uint8_t type = BLE_ADDR_PUBLIC);
NimBLEAddress(const uint64_t& address, uint8_t type = BLE_ADDR_PUBLIC);

bool isRpa() const;
bool isNrpa() const;
bool isStatic() const;
bool equals(const NimBLEAddress& otherAddress) const;
const uint8_t* getNative() const;
const ble_addr_t& getBase() const;
std::string toString() const;
uint8_t getType() const;
bool operator==(const NimBLEAddress& rhs) const;
bool operator!=(const NimBLEAddress& rhs) const;
operator std::string() const;
operator uint64_t() const;

private:
ble_addr_t m_address{};
};

#endif /* CONFIG_BT_ENABLED */
Expand Down
10 changes: 4 additions & 6 deletions src/NimBLEClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -199,10 +199,8 @@ bool NimBLEClient::connect(const NimBLEAddress &address, bool deleteAttributes)
return false;
}

ble_addr_t peerAddr_t;
memcpy(&peerAddr_t.val, address.getNative(),6);
peerAddr_t.type = address.getType();
if(ble_gap_conn_find_by_addr(&peerAddr_t, NULL) == 0) {
ble_addr_t peerAddr = address.getBase();
if(ble_gap_conn_find_by_addr(&peerAddr, NULL) == 0) {
NIMBLE_LOGE(LOG_TAG, "A connection to %s already exists",
address.toString().c_str());
return false;
Expand All @@ -227,7 +225,7 @@ bool NimBLEClient::connect(const NimBLEAddress &address, bool deleteAttributes)
do {
#if CONFIG_BT_NIMBLE_EXT_ADV
rc = ble_gap_ext_connect(NimBLEDevice::m_own_addr_type,
&peerAddr_t,
&peerAddr,
m_connectTimeout,
m_phyMask,
&m_pConnParams,
Expand All @@ -237,7 +235,7 @@ bool NimBLEClient::connect(const NimBLEAddress &address, bool deleteAttributes)
this);

#else
rc = ble_gap_connect(NimBLEDevice::m_own_addr_type, &peerAddr_t,
rc = ble_gap_connect(NimBLEDevice::m_own_addr_type, &peerAddr,
m_connectTimeout, &m_pConnParams,
NimBLEClient::handleGapEvent, this);
#endif
Expand Down
Loading

0 comments on commit 37addff

Please sign in to comment.