diff --git a/Kconfig b/Kconfig
index bfd47962..2d282149 100644
--- a/Kconfig
+++ b/Kconfig
@@ -1,5 +1,17 @@
menu "ESP-NimBLE-CPP configuration"
+config NIMBLE_USING_ARDUINO_IOT
+ bool "Renames the enums READ and WRITE that conflit with the Arduino IoT lib"
+ default "n"
+ help
+ Enabling this option will change the enum NIMBLE_PROPERTY:READ to NIMBLE_PROPERTY:BLE_READ and NIMBLE_PROPERTY:WRITE to NIMBLE_PROPERTY:BLE_WRITE
+
+config NIMBLE_USE_MAGIC_ENUM
+ bool "Enable if magic enum lib is set to get detailed text for Class of device property"
+ default "n"
+ help
+ Enable if magic enum lib is set to get detailed text for Class of device property
+
choice NIMBLE_CPP_LOG_LEVEL
prompt "NimBLE CPP log verbosity"
default NIMBLE_CPP_LOG_LEVEL_NONE
diff --git a/README.md b/README.md
index ea6b8976..c9036449 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,7 @@
[
](https://github.com/h2zero/esp-nimble-cpp/releases/latest/)
+
> [!IMPORTANT]
> Version 2 is now released!
> Check out the [1.x to 2.x Migration Guide](docs/1.x_to2.x_migration_guide.md) and [Release Notes](https://github.com/h2zero/esp-nimble-cpp/releases/latest/)
@@ -27,16 +28,6 @@ NimBLE is a completely open source Bluetooth Low Energy stack produced by [Apach
It is more suited to resource constrained devices than bluedroid and has now been ported to the ESP32 by Espressif.
-# Installation
-
-### ESP-IDF v4.0+
-Download as .zip and extract or clone into the components folder in your esp-idf project.
-
-Run menuconfig, go to `Component config->Bluetooth` enable Bluetooth and in `Bluetooth host` NimBLE.
-Configure settings in `NimBLE Options`.
-`#include "NimBLEDevice.h"` in main.cpp.
-Call `NimBLEDevice::init("");` in `app_main`.
-
# Using
This library is intended to be compatible with the original ESP32 BLE functions and types with minor changes.
diff --git a/src/NimBLEAdvertisementData.cpp b/src/NimBLEAdvertisementData.cpp
index 5f598978..04ca2b5c 100644
--- a/src/NimBLEAdvertisementData.cpp
+++ b/src/NimBLEAdvertisementData.cpp
@@ -14,9 +14,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
#include "NimBLEAdvertisementData.h"
-#if (CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_BROADCASTER) && !MYNEWT_VAL(BLE_EXT_ADV)) || defined(_DOXYGEN_)
+#if (CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_BROADCASTER && !CONFIG_BT_NIMBLE_EXT_ADV) || defined(_DOXYGEN_)
# include "NimBLEDevice.h"
# include "NimBLEUtils.h"
@@ -31,6 +30,22 @@
static const char* LOG_TAG = "NimBLEAdvertisementData";
+/**
+ * @brief Set the advertisement flags.
+ * @param [in] flag The flags to be set in the advertisement.
+ * * BLE_HS_ADV_F_DISC_LTD
+ * * BLE_HS_ADV_F_DISC_GEN
+ * * BLE_HS_ADV_F_BREDR_UNSUP - must always use with NimBLE
+ * A flag value of 0 will remove the flags from the advertisement.
+ */
+bool NimBLEAdvertisementData::setCODData(const NimClassOfDeviceType::bluetooth_cod_t cod) {
+ int dataLoc = getDataLocation(BLE_HS_ADV_TYPE_CLASS_OF_DEVICE);
+ if (dataLoc != -1) {
+ removeData(BLE_HS_ADV_TYPE_CLASS_OF_DEVICE);
+ }
+ return addData((const uint8_t*)((NimClassOfDeviceType::makeATT_Payload_CodeClassOfDevice(cod)).data()),5);
+} // SetCOD
+
/**
* @brief Add data to the payload to be advertised.
* @param [in] data The data to be added to the payload.
@@ -38,8 +53,9 @@ static const char* LOG_TAG = "NimBLEAdvertisementData";
*/
bool NimBLEAdvertisementData::addData(const uint8_t* data, size_t length) {
if (m_payload.size() + length > BLE_HS_ADV_MAX_SZ) {
- NIMBLE_LOGE(LOG_TAG, "Data length exceeded");
- return false;
+
+ NIMBLE_LOGE(LOG_TAG, "Data length exceeded %i mx lenth id %i",m_payload.size() + length, BLE_HS_ADV_MAX_SZ);
+ NIMBLE_LOGE(LOG_TAG, "Current data %s", NimBLEUtils::dataToHexString(m_payload.data(),m_payload.size()).c_str());
}
m_payload.insert(m_payload.end(), data, data + length);
diff --git a/src/NimBLEAdvertising.h b/src/NimBLEAdvertising.h
index 316002ff..3d99e37e 100644
--- a/src/NimBLEAdvertising.h
+++ b/src/NimBLEAdvertising.h
@@ -64,12 +64,12 @@ class NimBLEAdvertising {
void setMaxInterval(uint16_t maxInterval);
void setMinInterval(uint16_t minInterval);
- bool setAdvertisementData(const NimBLEAdvertisementData& advertisementData);
- bool setScanResponseData(const NimBLEAdvertisementData& advertisementData);
+ bool setAdvertisementData(const NimBLEAdvertisementData& advertisementData);
+ bool setScanResponseData(const NimBLEAdvertisementData& advertisementData);
const NimBLEAdvertisementData& getAdvertisementData();
const NimBLEAdvertisementData& getScanData();
- void clearData();
- bool refreshAdvertisingData();
+ void clearData();
+ bool refreshAdvertisingData();
bool addServiceUUID(const NimBLEUUID& serviceUUID);
bool addServiceUUID(const char* serviceUUID);
diff --git a/src/NimBLECharacteristic.h b/src/NimBLECharacteristic.h
index e3c70b63..a8489ea6 100644
--- a/src/NimBLECharacteristic.h
+++ b/src/NimBLECharacteristic.h
@@ -33,6 +33,12 @@ class NimBLE2904;
# include
# include
+// updated as READ and WRITE conflict with ArduinoIOT libs
+# if defined(CONFIG_NIMBLE_USING_ARDUINO_IOT)
+# define WRITE BLE_WRITE
+# define READ BLE_READ
+# endif
+
/**
* @brief The model of a BLE Characteristic.
*
@@ -324,5 +330,12 @@ class NimBLECharacteristicCallbacks {
virtual void onSubscribe(NimBLECharacteristic* pCharacteristic, NimBLEConnInfo& connInfo, uint16_t subValue);
};
+
+// updated as READ and WRITE conflict with ArduinoIOT libs
+# if defined(CONFIG_NIMBLE_USING_ARDUINO_IOT)
+# undef WRITE
+# undef READ
+# endif
+
#endif // CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
#endif // NIMBLE_CPP_CHARACTERISTIC_H_
diff --git a/src/NimBLEDescriptor.cpp b/src/NimBLEDescriptor.cpp
index 8f1bb41e..0d765f7c 100644
--- a/src/NimBLEDescriptor.cpp
+++ b/src/NimBLEDescriptor.cpp
@@ -23,6 +23,12 @@
# include
+// updated as READ and WRITE conflict with ArduinoIOT libs
+# if defined(CONFIG_NIMBLE_USING_ARDUINO_IOT)
+# define WRITE BLE_WRITE
+# define READ BLE_READ
+# endif
+
static const char* LOG_TAG = "NimBLEDescriptor";
static NimBLEDescriptorCallbacks defaultCallbacks;
@@ -147,4 +153,11 @@ void NimBLEDescriptorCallbacks::onWrite(NimBLEDescriptor* pDescriptor, NimBLECon
NIMBLE_LOGD("NimBLEDescriptorCallbacks", "onWrite: default");
} // onWrite
+
+// updated as READ and WRITE conflict with ArduinoIOT libs
+# if defined(CONFIG_NIMBLE_USING_ARDUINO_IOT)
+# undef WRITE
+# undef READ
+# endif
+
#endif // CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
diff --git a/src/NimBLEExtAdvertising.cpp b/src/NimBLEExtAdvertising.cpp
index 237e75b0..3dae3946 100644
--- a/src/NimBLEExtAdvertising.cpp
+++ b/src/NimBLEExtAdvertising.cpp
@@ -616,11 +616,6 @@ bool NimBLEExtAdvertisement::setFlags(uint8_t flag) {
* @return True if successful.
*/
bool NimBLEExtAdvertisement::setManufacturerData(const uint8_t* data, size_t length) {
- if (length > 0xFF - 1) {
- NIMBLE_LOGE(LOG_TAG, "Manufacturer data too long!");
- return false;
- }
-
uint8_t header[2];
header[0] = length + 1;
header[1] = BLE_HS_ADV_TYPE_MFG_DATA;
@@ -657,11 +652,6 @@ bool NimBLEExtAdvertisement::setManufacturerData(const std::vector& dat
* @return True if successful.
*/
bool NimBLEExtAdvertisement::setURI(const std::string& uri) {
- if (uri.length() > 0xFF - 1) {
- NIMBLE_LOGE(LOG_TAG, "URI too long!");
- return false;
- }
-
uint8_t header[2];
header[0] = uri.length() + 1;
header[1] = BLE_HS_ADV_TYPE_URI;
@@ -680,11 +670,6 @@ bool NimBLEExtAdvertisement::setURI(const std::string& uri) {
* @return True if successful.
*/
bool NimBLEExtAdvertisement::setName(const std::string& name, bool isComplete) {
- if (name.length() > 0xFF - 1) {
- NIMBLE_LOGE(LOG_TAG, "Name too long!");
- return false;
- }
-
uint8_t header[2];
header[0] = name.length() + 1;
header[1] = isComplete ? BLE_HS_ADV_TYPE_COMP_NAME : BLE_HS_ADV_TYPE_INCOMP_NAME;
@@ -932,12 +917,8 @@ bool NimBLEExtAdvertisement::setServices(bool complete, uint8_t size, const std:
*/
bool NimBLEExtAdvertisement::setServiceData(const NimBLEUUID& uuid, const uint8_t* data, size_t length) {
uint8_t uuidBytes = uuid.bitSize() / 8;
- if (length + uuidBytes + 2 > 0xFF) {
- NIMBLE_LOGE(LOG_TAG, "Service data too long!");
- return false;
- }
+ uint8_t sDataLen = 2 + uuidBytes + length;
- uint8_t sDataLen = 2 + uuidBytes + length;
if (m_payload.size() + sDataLen > MYNEWT_VAL(BLE_EXT_ADV_MAX_SIZE)) {
return false;
}
@@ -1109,4 +1090,20 @@ std::string NimBLEExtAdvertisement::toString() const {
return str;
} // toString
+/**
+ * @brief Set the advertisement flags.
+ * @param [in] flag The flags to be set in the advertisement.
+ * * BLE_HS_ADV_F_DISC_LTD
+ * * BLE_HS_ADV_F_DISC_GEN
+ * * BLE_HS_ADV_F_BREDR_UNSUP - must always use with NimBLE
+ * A flag value of 0 will remove the flags from the advertisement.
+ */
+bool NimBLEExtAdvertisement::setCODData(const NimClassOfDeviceType::bluetooth_cod_t cod) {
+ int dataLoc = getDataLocation(BLE_HS_ADV_TYPE_CLASS_OF_DEVICE);
+ if (dataLoc != -1) {
+ removeData(BLE_HS_ADV_TYPE_CLASS_OF_DEVICE);
+ }
+ return addData((const uint8_t*)((NimClassOfDeviceType::makeATT_Payload_CodeClassOfDevice(cod)).data()),5);
+} // SetCOD
+
#endif // CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_BROADCASTER) && MYNEWT_VAL(BLE_EXT_ADV)
diff --git a/src/NimBLEExtAdvertising.h b/src/NimBLEExtAdvertising.h
index a9cc7347..214bff72 100644
--- a/src/NimBLEExtAdvertising.h
+++ b/src/NimBLEExtAdvertising.h
@@ -19,6 +19,7 @@
#define NIMBLE_CPP_EXTADVERTISING_H_
#include "syscfg/syscfg.h"
+#include "NimClassOfDeviceType.h"
#if CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_BROADCASTER) && MYNEWT_VAL(BLE_EXT_ADV)
# ifdef USING_NIMBLE_ARDUINO_HEADERS
@@ -46,6 +47,8 @@ class NimBLEUUID;
class NimBLEExtAdvertisement {
public:
NimBLEExtAdvertisement(uint8_t priPhy = BLE_HCI_LE_PHY_1M, uint8_t secPhy = BLE_HCI_LE_PHY_1M);
+
+ bool setCODData(const NimClassOfDeviceType::bluetooth_cod_t cod);
bool setAppearance(uint16_t appearance);
bool addServiceUUID(const NimBLEUUID& serviceUUID);
bool addServiceUUID(const char* serviceUUID);
diff --git a/src/NimBLEHIDDevice.cpp b/src/NimBLEHIDDevice.cpp
index af0d38ed..8980ab1a 100644
--- a/src/NimBLEHIDDevice.cpp
+++ b/src/NimBLEHIDDevice.cpp
@@ -22,6 +22,12 @@
# include "NimBLEService.h"
# include "NimBLE2904.h"
+// updated as READ and WRITE conflict with ArduinoIOT libs
+# if defined(CONFIG_NIMBLE_USING_ARDUINO_IOT)
+# define WRITE BLE_WRITE
+# define READ BLE_READ
+# endif
+
static constexpr uint16_t deviceInfoSvcUuid = 0x180a;
static constexpr uint16_t hidSvcUuid = 0x1812;
static constexpr uint16_t batterySvcUuid = 0x180f;
@@ -338,4 +344,11 @@ NimBLEService* NimBLEHIDDevice::getBatteryService() {
return m_batterySvc;
} // getBatteryService
+
+// updated as READ and WRITE conflict with ArduinoIOT libs
+# if defined(CONFIG_NIMBLE_USING_ARDUINO_IOT)
+# undef WRITE
+# undef READ
+# endif
+
#endif // CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
diff --git a/src/NimBLELocalValueAttribute.h b/src/NimBLELocalValueAttribute.h
index 5fd37e55..16daa6bd 100644
--- a/src/NimBLELocalValueAttribute.h
+++ b/src/NimBLELocalValueAttribute.h
@@ -33,11 +33,17 @@
/**************************/
typedef enum {
- READ = BLE_GATT_CHR_F_READ,
- READ_ENC = BLE_GATT_CHR_F_READ_ENC,
- READ_AUTHEN = BLE_GATT_CHR_F_READ_AUTHEN,
- READ_AUTHOR = BLE_GATT_CHR_F_READ_AUTHOR,
- WRITE = BLE_GATT_CHR_F_WRITE,
+# if defined(CONFIG_NIMBLE_USING_ARDUINO_IOT)
+ BLE_READ = BLE_GATT_CHR_F_READ,
+ BLE_WRITE = BLE_GATT_CHR_F_WRITE,
+# else
+ READ = BLE_GATT_CHR_F_READ,
+ WRITE = BLE_GATT_CHR_F_WRITE,
+# endif
+ READ_ENC = BLE_GATT_CHR_F_READ_ENC,
+ READ_AUTHEN = BLE_GATT_CHR_F_READ_AUTHEN,
+ READ_AUTHOR = BLE_GATT_CHR_F_READ_AUTHOR,
+
WRITE_NR = BLE_GATT_CHR_F_WRITE_NO_RSP,
WRITE_ENC = BLE_GATT_CHR_F_WRITE_ENC,
WRITE_AUTHEN = BLE_GATT_CHR_F_WRITE_AUTHEN,
@@ -101,7 +107,7 @@ class NimBLELocalValueAttribute : public NimBLELocalAttribute, public NimBLEValu
NimBLELocalValueAttribute(const NimBLEUUID& uuid,
uint16_t handle,
uint16_t maxLen,
- uint16_t initLen = MYNEWT_VAL(NIMBLE_CPP_ATT_VALUE_INIT_LENGTH))
+ uint16_t initLen = CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH)
: NimBLELocalAttribute(uuid, handle), NimBLEValueAttribute(maxLen, initLen) {}
/**
* @brief Destroy the NimBLELocalValueAttribute object.
diff --git a/src/NimBLEServer.cpp b/src/NimBLEServer.cpp
index 42579791..1a123f3f 100644
--- a/src/NimBLEServer.cpp
+++ b/src/NimBLEServer.cpp
@@ -98,7 +98,10 @@ NimBLEService* NimBLEServer::createService(const char* uuid) {
NimBLEService* NimBLEServer::createService(const NimBLEUUID& uuid) {
NimBLEService* pService = new NimBLEService(uuid);
m_svcVec.push_back(pService);
- setServiceChanged();
+ serviceChanged();
+
+ // added for debugging by synapse2
+ NIMBLE_LOGI(LOG_TAG, "Added serice to GATT table service %s", pService->toString().c_str());
return pService;
} // createService
@@ -300,7 +303,7 @@ bool NimBLEServer::start() {
return false;
}
-# if MYNEWT_VAL(NIMBLE_CPP_LOG_LEVEL) >= 4
+# if CONFIG_NIMBLE_CPP_LOG_LEVEL >= 4
ble_gatts_show_local();
// Check that all services were registered and log if any are missing.
@@ -852,6 +855,17 @@ void NimBLEServer::removeService(NimBLEService* service, bool deleteSvc) {
# endif
} // removeService
+/**
+ * @brief debug to get a string of teeh services database
+ *
+ */
+std::string NimBLEServer::toString(){
+
+ std::string rStr ="Nimble Server service count " + m_svcVec.size(); + "\n";
+
+ return rStr;
+}
+
/**
* @brief Adds a service which was either already created but removed from availability,\n
* or created and later added to services list.
@@ -1191,4 +1205,6 @@ void NimBLEServerCallbacks::onPhyUpdate(NimBLEConnInfo& connInfo, uint8_t txPhy,
NIMBLE_LOGD("NimBLEServerCallbacks", "onPhyUpdate: default, txPhy: %d, rxPhy: %d", txPhy, rxPhy);
} // onPhyUpdate
+
+
#endif // CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
diff --git a/src/NimBLEServer.h b/src/NimBLEServer.h
index b2b79e1e..039d17dc 100644
--- a/src/NimBLEServer.h
+++ b/src/NimBLEServer.h
@@ -34,6 +34,7 @@
# include
# include
+#include
# define NIMBLE_ATT_REMOVE_HIDE 1
# define NIMBLE_ATT_REMOVE_DELETE 2
@@ -86,6 +87,8 @@ class NimBLEServer {
bool getPhy(uint16_t connHandle, uint8_t* txPhy, uint8_t* rxPhy);
void sendServiceChangedIndication() const;
+ std::string toString();
+
# if MYNEWT_VAL(BLE_ROLE_CENTRAL)
NimBLEClient* getClient(uint16_t connHandle);
NimBLEClient* getClient(const NimBLEConnInfo& connInfo);
diff --git a/src/NimBLEService.h b/src/NimBLEService.h
index dcbe1f94..ee8afc13 100644
--- a/src/NimBLEService.h
+++ b/src/NimBLEService.h
@@ -21,12 +21,21 @@
#include "syscfg/syscfg.h"
#if CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
+
class NimBLEService;
# include "NimBLEAttribute.h"
# include "NimBLEServer.h"
# include "NimBLECharacteristic.h"
+
+/// updated as READ and WRITE conflict with ArduinoIOT libs
+#if defined(CONFIG_NIMBLE_USING_ARDUINO_IOT)
+#define WRITE BLE_WRITE
+#define READ BLE_READ
+#endif
+
+
/**
* @brief The model of a BLE service.
*
@@ -79,5 +88,11 @@ class NimBLEService : public NimBLELocalAttribute {
ble_gatt_svc_def m_pSvcDef[2]{};
}; // NimBLEService
+// updated as READ and WRITE conflict with ArduinoIOT libs
+# if defined(CONFIG_NIMBLE_USING_ARDUINO_IOT)
+# undef WRITE
+# undef READ
+# endif
+
#endif // CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
#endif // NIMBLE_CPP_SERVICE_H_
diff --git a/src/NimClassOfDeviceType.cpp b/src/NimClassOfDeviceType.cpp
new file mode 100644
index 00000000..ab039212
--- /dev/null
+++ b/src/NimClassOfDeviceType.cpp
@@ -0,0 +1,200 @@
+
+#include "NimBLELog.h"
+#include "NimBLEUtils.h"
+
+
+#if defined(CONFIG_NIMBLE_USE_MAGIC_ENUM)
+# include "magicEnum/magic_enum.hpp"
+# include "magicEnum/magic_enum_iostream.hpp"
+
+template
+auto to_integer(magic_enum::Enum value) -> int
+{
+ // magic_enum::Enum - C++17 Concept for enum type.
+ return static_cast>(value);
+}
+
+#endif
+#include "NimClassOfDeviceType.h"
+
+#define BLE_HS_ADV_TYPE_CLASS_OF_DEV 0x0d
+
+static const char* LOG_TAG = "NimClassOfDeviceType";
+
+namespace NimClassOfDeviceType {
+
+// fucntion to add the serivce H aand L comps together
+static NimClassOfDeviceType::service_class_t getH_LService(bluetooth_cod_t cod) {
+ uint16_t service_highBit = (cod.bit_field.service_classH << 3);
+ uint16_t service = service_highBit | ((uint16_t)cod.bit_field.service_classL);
+ NIMBLE_LOGI(LOG_TAG,
+ " Merging Service H (0x%02x) and L (0x%02x) into (0x%02x) ",
+ service_highBit,
+ cod.bit_field.service_classL,
+ service);
+
+ return (NimClassOfDeviceType::service_class_t)service;
+}
+
+// Function to construct a CoD from its components
+bluetooth_cod_t encodeClassOfDevice(service_class_t services, major_device_class_t major, uint8_t minor) {
+ bluetooth_cod_t cod = {0x000000}; // Initialize all bits to zero
+ cod.bit_field.format_type = 0; // Standard format
+ cod.bit_field.major_device = major & 0x1f; // only use the 5 lower bits
+ cod.bit_field.minor_device = (minor & 0x7f) ; // only use the higher 6 bits and move for the 2 bits unused
+
+ NIMBLE_LOGI(LOG_TAG, "MINOR in 0x%02x and masked 0x%02x out 0x%02x", minor, (minor & 0x7f),cod.bit_field.minor_device);
+
+ if (services > 0x007) {
+ // any bigger we get a core dump so we need to manually break the service setting.
+ uint8_t L_3Bit = services & 0x0007; // only use the 3 lower bits
+ cod.bit_field.service_classL = L_3Bit;
+ uint8_t H_8Bit =
+ (uint8_t)((services >> 3) &
+ 0x00FF); // get the remaining 8 bits and shift left by 3 for deleting the 3 bits to discard
+ cod.bytes3.byte2 = H_8Bit; // stuff the reming 8 bits in the byte 2
+ NIMBLE_LOGI(LOG_TAG, "Breaking services 0x%02x into 3 bits 0x%02x and 8 bits 0x%02x", services, L_3Bit, H_8Bit);
+ } else {
+ // increasing bits from 11 to 16 as the esp32 core dumps at higher bits ( this filed (two bytes)is now across three bytes !)
+ cod.bit_field.service_classL = services & 0x007; // only use the 3 lower bits
+ }
+
+ NIMBLE_LOGI(LOG_TAG,
+ "Making servies %s RAW HEX cod value only three bytes are used %s",
+ decodeClassOfDevice(cod).c_str(),
+ NimBLEUtils::dataToHexString((((const unsigned char*)&cod)), 3).c_str());
+
+ NIMBLE_LOGD(LOG_TAG,
+ " Making COB Byte0:0x%02x Byte1:0x%02x Byte2:0x%02x",
+ (cod.bytes3.byte0),
+ (cod.bytes3.byte1),
+ (cod.bytes3.byte2));
+ return cod;
+}
+
+std::string decodeMajorMinor(major_device_class_t major, uint8_t minor) {
+ std::string ret = "Magic Enum not enabled";
+#if defined(CONFIG_NIMBLE_USE_MAGIC_ENUM)
+ std::string cmd = "";
+ ret = " Major Device:";
+ cmd = ((magic_enum::enum_flags_name(major)));
+ if (major == 0) {
+ cmd = "COD_MAJOR_MISCELLANEOUS";
+ }
+ ret = ret + cmd;
+ ret = ret + " Minor Device:";
+ switch (major) {
+ case major_device_class_t::COD_MAJOR_AUDIO_VIDEO:
+ cmd = ((magic_enum::enum_flags_name((av_minor_class_t)minor)));
+ if (minor == 0) {
+ cmd = "COD_MINOR_AV_UNCATEGORIZED";
+ }
+ break;
+ case major_device_class_t::COD_MAJOR_COMPUTER:
+ cmd = ((magic_enum::enum_flags_name((computer_minor_class_t)minor)));
+ if (minor == 0) {
+ cmd = "COD_MINOR_COMPUTER_UNCATEGORIZED";
+ }
+ break;
+ case major_device_class_t::COD_MAJOR_HEALTH:
+ cmd = ((magic_enum::enum_flags_name((health_minor_class_t)minor)));
+
+ if (minor == 0) {
+ cmd = "COD_MINOR_HEALTH_UNDEFINED";
+ }
+ break;
+ case major_device_class_t::COD_MAJOR_IMAGING:
+ cmd = ((magic_enum::enum_flags_name((imaging_minor_class_t)minor)));
+ if (minor == 0) {
+ cmd = "COD_IMAGING_UNCATEGORIZED";
+ }
+ break;
+
+ case major_device_class_t::COD_MAJOR_NETWORK:
+ cmd = ((magic_enum::enum_flags_name((lan_minor_class_t)minor)));
+ if (minor == 0) {
+ cmd = "COD_MINOR_LAN_UTIL_FULLY_AVAILABLE";
+ }
+ break;
+
+ case major_device_class_t::COD_MAJOR_PERIPHERAL:
+ cmd = ((magic_enum::enum_flags_name((peripheral_pointing_device_t)minor)));
+ if (minor == 0) {
+ cmd = "COD_MINOR_PERIPHERA_UNCATEGORIZED";
+ }
+ break;
+ case major_device_class_t::COD_MAJOR_PHONE:
+ cmd = ((magic_enum::enum_flags_name((phone_minor_class_t)minor)));
+ if (minor == 0) {
+ cmd = "COD_MINOR_PHONE_UNCATEGORIZED";
+ }
+ break;
+ case major_device_class_t::COD_MAJOR_TOY:
+ cmd = ((magic_enum::enum_flags_name((toy_minor_class_t)minor)));
+ if (minor == 0) {
+ cmd = "COD_MINOR_TOY_UNCATEGORIZED";
+ }
+ break;
+
+ case major_device_class_t::COD_MAJOR_WEARABLE:
+ cmd = ((magic_enum::enum_flags_name((wearable_minor_class_t)minor)));
+ if (minor == 0) {
+ cmd = "COD_MINOR_WEARABLE_UNCATEGORIZED";
+ }
+ break;
+
+ default:
+ cmd = "Undefined";
+ break;
+ }
+ ret = ret + cmd + " ";
+#endif
+ return ret;
+}
+
+std::string decodeClassOfDevice(service_class_t services, major_device_class_t major, uint8_t minor) {
+ std::string ret = "MAGIC Enum not enabled";
+
+#if defined(CONFIG_NIMBLE_USE_MAGIC_ENUM)
+ ret = "Service Class:";
+ std::string cmd = "";
+ cmd = magic_enum::enum_flags_name(services);
+ if (services == 0) {
+ cmd = "COD_SERVICE_NA";
+ }
+ ret = ret + cmd;
+ cmd = decodeMajorMinor(major, minor);
+ ret = ret + cmd;
+#endif
+
+ return ret;
+}
+
+std::string decodeClassOfDevice(bluetooth_cod_t cod) {
+ // NIMBLE_LOGD(LOG_TAG,
+ // "In DeCODE COS - RAW HEX cod value only 3 bytes are used %s",
+ // NimBLEUtils::dataToHexString((((const unsigned char*)&cod)), 3).c_str());
+ return decodeClassOfDevice(getH_LService(cod), (major_device_class_t)cod.bit_field.major_device, cod.bit_field.minor_device);
+}
+
+std::vector makeATT_Payload_CodeClassOfDevice(bluetooth_cod_t cod) {
+ uint8_t out[5];
+
+ // we are folling little edinan format here
+ out[0] = 4; // length
+ out[1] = BLE_HS_ADV_TYPE_CLASS_OF_DEV; // class of device
+ out[2] = (cod.bytes3.byte0);
+ out[3] = (cod.bytes3.byte1);
+ out[4] = (cod.bytes3.byte2);
+ std::vector v(out, out + 5);
+
+ NIMBLE_LOGD(LOG_TAG, " COB Byte0:%02x Byte1:%02x Byte2:%02x", (cod.bytes3.byte0), (cod.bytes3.byte1), (cod.bytes3.byte2));
+ NIMBLE_LOGD(LOG_TAG,
+ " Convetred COB %s to bytes in hex for ADV playload %s",
+ decodeClassOfDevice(cod).c_str(),
+ NimBLEUtils::dataToHexString(v.data(), v.size()).c_str());
+
+ return v;
+}
+
+} // namespace NimClassOfDeviceType
\ No newline at end of file
diff --git a/src/NimClassOfDeviceType.h b/src/NimClassOfDeviceType.h
new file mode 100644
index 00000000..9a29c632
--- /dev/null
+++ b/src/NimClassOfDeviceType.h
@@ -0,0 +1,261 @@
+#pragma once
+
+#include
+#include
+#include
+#include
+#include
+
+#if defined(CONFIG_NIMBLE_USE_MAGIC_ENUM)
+# include "magicEnum/magic_enum.hpp"
+# include "magicEnum/magic_enum_iostream.hpp"
+#endif
+
+#define BLE_HS_ADV_TYPE_CLASS_OF_DEVICE 0x0d
+
+namespace NimClassOfDeviceType {
+
+// Use __attribute__((packed)) to prevent the compiler from adding padding,
+// which ensures the struct is exactly 24 bits (3 bytes) long.
+// but we need to allocate 34 bits as we have service class broken aacross two bytes and we need to use int 16 for it
+// note esp 32 is liitle edian. ie byte0 is least significant and byte 2 is most
+typedef union {
+ struct {
+ uint8_t format_type : 2; // Bits 0-1 (least significant)
+ uint8_t minor_device : 6; // Bits 2-8
+ uint8_t major_device : 5; // Bits 8-12
+ uint8_t service_classL : 3; // Bits 13-15 (out of 13 - 23) we have to break the serivce class as it core dumps other wise
+ uint8_t service_classH : 8; // Bits 16-23 (out of 13 - 23) we have to break the serivce class as it core dumps other wise
+ } __attribute__((packed)) bit_field;
+ struct {
+ uint8_t byte0;
+ uint8_t byte1;
+ uint8_t byte2;
+ } __attribute__((packed)) bytes3;
+
+} __attribute__((packed)) bluetooth_cod_t;
+
+// Enum for Service Class (using a bitmask)
+typedef enum : uint16_t {
+ COD_SERVICE_NA = 0x0000,
+ COD_SERVICE_LIMITED_DISCOVERABLE = 0x0001,
+ COD_SERVICE_LE_AUDIO = 0x0002,
+ COD_SERVICE_RESERVED = 0x0004,
+ COD_SERVICE_POSITIONING = 0x0008,
+ COD_SERVICE_NETWORKING = 0x0010,
+ COD_SERVICE_RENDERING = 0x0020,
+ COD_SERVICE_CAPTURING = 0x0040,
+ COD_SERVICE_OBJECT_TRANSFER = 0x0080,
+ COD_SERVICE_AUDIO = 0x0100,
+ COD_SERVICE_TELEPHONY = 0x0200,
+ COD_SERVICE_INFORMATION = 0x0400
+} service_class_t;
+
+// Enum for Major Device Class
+typedef enum : uint8_t {
+ COD_MAJOR_MISCELLANEOUS = 0x00,
+ COD_MAJOR_COMPUTER = 0x01,
+ COD_MAJOR_PHONE = 0x02,
+ COD_MAJOR_NETWORK = 0x03,
+ COD_MAJOR_AUDIO_VIDEO = 0x04,
+ COD_MAJOR_PERIPHERAL = 0x05,
+ COD_MAJOR_IMAGING = 0x06,
+ COD_MAJOR_WEARABLE = 0x07,
+ COD_MAJOR_TOY = 0x8,
+ COD_MAJOR_HEALTH = 0x09,
+ COD_MAJOR_UNCATEGORY = 0x1F
+} major_device_class_t;
+
+// Enum for Minor Device Class when Major Class is 'Computer'
+typedef enum : uint8_t {
+ COD_MINOR_COMPUTER_UNCATEGORIZED = 0x00, // Uncategorized computer
+ COD_MINOR_COMPUTER_DESKTOP = 0x01, // Desktop computer
+ COD_MINOR_COMPUTER_SERVER = 0x02, // Server-class computer
+ COD_MINOR_COMPUTER_LAPTOP = 0x03, // Laptop computer
+ COD_MINOR_COMPUTER_HANDHELD_CLAM = 0x04, // Handheld PC/PDA (clam shell)
+ COD_MINOR_COMPUTER_PALM_SIZE = 0x05, // Palm-sized PC/PDA
+ COD_MINOR_COMPUTER_WEARABLE = 0x06, // Wearable computer
+ COD_MINOR_COMPUTER_TABLET = 0x07 // Tablet computer
+} computer_minor_class_t;
+
+// Enum for Minor Device Class when Major Class is 'Phone'
+typedef enum : uint8_t {
+ COD_MINOR_PHONE_UNCATEGORIZED = 0x00, // Uncategorized phone device
+ COD_MINOR_PHONE_CELLULAR = 0x01, // A cellular phone
+ COD_MINOR_PHONE_CORDLESS = 0x02, // A cordless phone
+ COD_MINOR_PHONE_SMARTPHONE = 0x03, // A smartphone
+ COD_MINOR_PHONE_WIRED_MODEM = 0x04, // A wired modem or voice gateway
+ COD_MINOR_PHONE_COMMON_ISDN_ACCESS = 0x05, // A device that provides ISDN access
+} phone_minor_class_t;
+
+// Enum for Minor Device Class when Major Class is 'LAN/Network Access Point'
+typedef enum : uint8_t {
+ COD_MINOR_LAN_UTIL_FULLY_AVAILABLE = 0x00, // 0% utilized
+ COD_MINOR_LAN_UTIL_1_TO_17_PERC = 0x08, // 1-17% utilized
+ COD_MINOR_LAN_UTIL_17_TO_33_PERC = 0x10, // 17-33% utilized
+ COD_MINOR_LAN_UTIL_33_TO_50_PERC = 0x18, // 33-50% utilized
+ COD_MINOR_LAN_UTIL_50_TO_67_PERC = 0x20, // 50-67% utilized
+ COD_MINOR_LAN_UTIL_67_TO_83_PERC = 0x21, // 67-83% utilized
+ COD_MINOR_LAN_UTIL_83_TO_99_PERC = 0x28, // 83-99% utilized
+ COD_MINOR_LAN_UTIL_NO_SERVICE = 0x38, // No service available (100% utilized)
+} lan_minor_class_t;
+
+// Enum for Minor Device Class when Major Class is 'Audio/Video'
+typedef enum : uint8_t {
+ COD_MINOR_AV_UNCATEGORIZED = 0x00, // Uncategorized, code not assigned
+ COD_MINOR_AV_HEADSET = 0x01, // Wearable Headset Device
+ COD_MINOR_AV_HANDS_FREE = 0x02, // Hands-free device
+ COD_MINOR_AV_MICROPHONE = 0x04, // Microphone
+ COD_MINOR_AV_LOUDSPEAKER = 0x05, // Loudspeaker
+ COD_MINOR_AV_HEADPHONES = 0x06, // Headphones
+ COD_MINOR_AV_PORTABLE_AUDIO = 0x07, // Portable Audio device
+ COD_MINOR_AV_CAR_AUDIO = 0x08, // Car audio
+ COD_MINOR_AV_SET_TOP_BOX = 0x09, // Set-top box
+ COD_MINOR_AV_HIFI_AUDIO = 0x0A, // HiFi Audio device
+ COD_MINOR_AV_VCR = 0x0B, // VCR
+ COD_MINOR_AV_VIDEO_CAMERA = 0x0C, // Video Camera
+ COD_MINOR_AV_CAMCORDER = 0x0D, // Camcorder
+ COD_MINOR_AV_VIDEO_MONITOR = 0x0E, // Video Monitor
+ COD_MINOR_AV_VIDEO_DISPLAY_LOUD = 0x0F, // Video Display and Loudspeaker
+ COD_MINOR_AV_VIDEO_CONFERENCING = 0x10, // Video Conferencing device
+ COD_MINOR_AV_RESERVED = 0x11, // RESERVED
+ COD_MINOR_AV_GAMING_TOY = 0x12, // Gaming/Toy device
+} av_minor_class_t;
+
+// Enum for the lower bits of the Peripheral minor device class (bits 5-2)
+// This portion specifies the type of pointing device or remote control.
+typedef enum : uint8_t {
+ COD_MINOR_PERIPHERA_UNCATEGORIZED = 0x00,
+ COD_MINOR_PERIPHERAL_MOUSE_UNCATEGORIZED = 0x00 | 0x0, // Uncategorized
+ COD_MINOR_PERIPHERAL_MOUSE_JOYSTICK = 0x01 | 0x20, // Joystick
+ COD_MINOR_PERIPHERAL_MOUSE_GAMEPAD = 0x02 | 0x20, // Gamepad
+ COD_MINOR_PERIPHERAL_MOUSE_REMOTE_CONTROL = 0x03 | 0x20, // Remote Control
+ COD_MINOR_PERIPHERAL_MOUSE_SENSING_DEVICE = 0x04 | 0x20, // Sensing Device
+ COD_MINOR_PERIPHERAL_MOUSE_DIGITIZER_TABLET = 0x05 | 0x20, // Digitizer Tablet
+ COD_MINOR_PERIPHERAL_MOUSE_CARD_READER = 0x06 | 0x20, // Card Reader
+ COD_MINOR_PERIPHERAL_MOUSE_DIGITAL_PEN = 0x07 | 0x20, // Digital pen
+ COD_MINOR_PERIPHERAL_MOUSE_HANDHELD_SCANNER = 0x08 | 0x20, // HandHeld Scnner
+ COD_MINOR_PERIPHERAL_MOUSE_HANDHELD_G_INPUT = 0x09 | 0x20, // HandheldGestural InputDevice(e.g., ”wand” form factor)
+
+ COD_MINOR_PERIPHERAL_KBD_UNCATEGORIZED = 0x00 | 0x10, // Uncategorized
+ COD_MINOR_PERIPHERAL_KBD_JOYSTICK = 0x01 | 0x10, // Joystick
+ COD_MINOR_PERIPHERAL_KBD_GAMEPAD = 0x02 | 0x10, // Gamepad
+ COD_MINOR_PERIPHERAL_KBD_REMOTE_CONTROL = 0x03 | 0x10, // Remote Control
+ COD_MINOR_PERIPHERAL_KBD_SENSING_DEVICE = 0x04 | 0x10, // Sensing Device
+ COD_MINOR_PERIPHERAL_KBD_DIGITIZER_TABLET = 0x05 | 0x10, // Digitizer Tablet
+ COD_MINOR_PERIPHERAL_KBD_CARD_READER = 0x06 | 0x10, // Card Reader
+ COD_MINOR_PERIPHERAL_KBD_DIGITAL_PEN = 0x07 | 0x10, // Digital pen
+ COD_MINOR_PERIPHERAL_KBD_HANDHELD_SCANNER = 0x08 | 0x10, // HandHeld Scnner
+ COD_MINOR_PERIPHERAL_KBD_HANDHELD_G_INPUT = 0x09 | 0x10, // HandheldGestural InputDevice(e.g., ”wand” form factor)
+ COD_MINOR_PERIPHERAL_KBD_MSE_UNCATEGORIZED = 0x00 | 0x30, // Uncategorized
+ COD_MINOR_PERIPHERAL_KBD_MSE_JOYSTICK = 0x01 | 0x30, // Joystick
+ COD_MINOR_PERIPHERAL_KBD_MSE_GAMEPAD = 0x02 | 0x30, // Gamepad
+ COD_MINOR_PERIPHERAL_KBD_MSE_REMOTE_CONTROL = 0x03 | 0x30, // Remote Control
+ COD_MINOR_PERIPHERAL_KBD_MSE_SENSING_DEVICE = 0x04 | 0x30, // Sensing Device
+ COD_MINOR_PERIPHERAL_KBD_MSE_DIGITIZER_TABLET = 0x05 | 0x30, // Digitizer Tablet
+ COD_MINOR_PERIPHERAL_KBD_MSE_CARD_READER = 0x06 | 0x30, // Card Reader
+ COD_MINOR_PERIPHERAL_KBD_MSE_DIGITAL_PEN = 0x07 | 0x30, // Digital pen
+ COD_MINOR_PERIPHERAL_KBD_MSE_HANDHELD_SCANNER = 0x08 | 0x30, // HandHeld Scnner
+ COD_MINOR_PERIPHERAL_KBD_MSE_HANDHELD_G_INPUT = 0x09 | 0x30 // HandheldGestural InputDevice(e.g., ”wand” form factor)
+} peripheral_pointing_device_t;
+
+// Bitmask for the Imaging minor device class (bits 7-4)
+// These bits can be combined using bitwise OR.
+typedef enum : uint8_t {
+ COD_MINOR_IMAGING_DISPLAY_MASK = 0x04, // Bit 4: Display capable
+ COD_MINOR_IMAGING_CAMERA_MASK = 0x08, // Bit 5: Camera capable
+ COD_MINOR_IMAGING_SCANNER_MASK = 0x10, // Bit 6: Scanner capable
+ COD_MINOR_IMAGING_PRINTER_MASK = 0x20 // Bit 7: Printer capable
+} imaging_minor_class_t;
+
+// Enum for Minor Device Class when Major Class is 'Wearable'
+typedef enum : uint8_t {
+ COD_MINOR_WEARABLE_UNCATEGORIZED = 0x00, // Uncategorized
+ COD_MINOR_WEARABLE_WRIST_WATCH = 0x01, // A wristwatch
+ COD_MINOR_WEARABLE_PAGER = 0x02, // A pager
+ COD_MINOR_WEARABLE_JACKET = 0x03, // A jacket
+ COD_MINOR_WEARABLE_HELMET = 0x04, // A helmet
+ COD_MINOR_WEARABLE_GLASSES = 0x05, // Glasses, such as those with a display
+ COD_MINOR_WEARABLE_PIN = 0x06 // PIN
+} wearable_minor_class_t;
+
+// Enum for Minor Device Class when Major Class is 'Toy'
+typedef enum : uint8_t {
+ COD_MINOR_TOY_UNCATEGORIZED = 0x00, // Uncategorized toy
+ COD_MINOR_TOY_ROBOT = 0x01, // Robot toy
+ COD_MINOR_TOY_VEHICLE = 0x02, // Vehicle toy
+ COD_MINOR_TOY_DOLL = 0x03, // Doll toy
+ COD_MINOR_TOY_CONTROLLER = 0x04, // Controller toy
+ COD_MINOR_TOY_GAME = 0x05 // Game toy
+} toy_minor_class_t;
+
+// Enum for Minor Device Class when Major Class is 'Health'
+typedef enum : uint8_t {
+ COD_MINOR_HEALTH_UNDEFINED = 0x00, // Undefined Health Device
+ COD_MINOR_HEALTH_BLOOD_PRESSURE = 0x01, // Blood Pressure Monitor
+ COD_MINOR_HEALTH_THERMOMETER = 0x02, // Thermometer
+ COD_MINOR_HEALTH_WEIGHING_SCALE = 0x03, // Weighing Scale
+ COD_MINOR_HEALTH_GLUCOSE_METER = 0x04, // Glucose Meter
+ COD_MINOR_HEALTH_PULSE_OXIMETER = 0x05, // Pulse Oximeter
+ COD_MINOR_HEALTH_HEART_RATE_MONITOR = 0x06, // Heart/Pulse Rate Monitor
+ COD_MINOR_HEALTH_HEALTH_DATA_DISPLAY = 0x07, // Health Data Display
+ COD_MINOR_HEALTH_STEP_COUNTER = 0x08, // Step Counter
+ COD_MINOR_HEALTH_BODY_COMPOSITION = 0x09, // Body Composition Analyzer
+ COD_MINOR_HEALTH_PEAK_FLOW_MONITOR = 0x0A, // Peak Flow Monitor
+ COD_MINOR_HEALTH_MEDICATION_MONITOR = 0x0B, // Medication Monitor
+ COD_MINOR_HEALTH_KNEE_PROTH = 0x0C, // KneeProsthesis
+ COD_MINOR_HEALTH_ANKLE_PROTH = 0x0D, // AnkleProsthesis
+ COD_MINOR_HEALTH_GENERIC_HEATH_MGR = 0x0E, // GenericHealthManager
+ COD_MINOR_HEALTH_PERSONAL_MOBLTY = 0x0F // PersonalMobilityDevice
+} health_minor_class_t;
+
+static service_class_t getH_LService(bluetooth_cod_t cod);
+// Function to construct a CoD from its components
+bluetooth_cod_t encodeClassOfDevice(service_class_t services, major_device_class_t major, uint8_t minor);
+
+std::string decodeClassOfDevice(bluetooth_cod_t cod);
+std::string decodeClassOfDevice(service_class_t services, major_device_class_t major, uint8_t minor);
+std::string decodeMajorMinor(major_device_class_t major, uint8_t minor);
+
+std::vector makeATT_Payload_CodeClassOfDevice(bluetooth_cod_t cod);
+
+} // namespace NimClassOfDeviceType
+
+#if defined(CONFIG_NIMBLE_USE_MAGIC_ENUM)
+namespace magic_enum::customize {
+
+// enable flag use by the magic enum for debug print
+constexpr auto magic_enum_is_flags(NimClassOfDeviceType::service_class_t) -> std::true_type;
+
+// enable flag use by the magic enum for debug print
+constexpr auto magic_enum_is_flags(NimClassOfDeviceType::major_device_class_t) -> std::true_type;
+
+// enable flag use by the magic enum for debug print
+constexpr auto magic_enum_is_flags(NimClassOfDeviceType::phone_minor_class_t) -> std::true_type;
+
+// enable flag use by the magic enum for debug print
+constexpr auto magic_enum_is_flags(NimClassOfDeviceType::lan_minor_class_t) -> std::true_type;
+
+// enable flag use by the magic enum for debug print
+constexpr auto magic_enum_is_flags(NimClassOfDeviceType::av_minor_class_t) -> std::true_type;
+
+// enable flag use by the magic enum for debug print
+constexpr auto magic_enum_is_flags(NimClassOfDeviceType::peripheral_pointing_device_t) -> std::true_type;
+
+// enable flag use by the magic enum for debug print
+constexpr auto magic_enum_is_flags(NimClassOfDeviceType::imaging_minor_class_t) -> std::true_type;
+
+// enable flag use by the magic enum for debug print
+constexpr auto magic_enum_is_flags(NimClassOfDeviceType::wearable_minor_class_t) -> std::true_type;
+
+// enable flag use by the magic enum for debug print
+constexpr auto magic_enum_is_flags(NimClassOfDeviceType::toy_minor_class_t) -> std::true_type;
+
+// enable flag use by the magic enum for debug print
+constexpr auto magic_enum_is_flags(NimClassOfDeviceType::health_minor_class_t) -> std::true_type;
+
+// enable flag use by the magic enum for debug print
+constexpr auto magic_enum_is_flags(NimClassOfDeviceType::computer_minor_class_t) -> std::true_type;
+
+} // namespace magic_enum::customize
+#endif
\ No newline at end of file