Skip to content

Commit 1ff1c68

Browse files
committed
feat: Aggregate Format (0x2905) descriptor, reapplied onto 2.5.0
Ports the 0x2905 Characteristic Aggregate Format feature (from feat/aggregate-format-2905 @ dc01636, 2.3.6-based) onto NimBLE-Arduino 2.5.0. Only the feature is carried: NimBLE2905 descriptor class, NimBLECharacteristic::create2905(), the 0x2905 branch in createDescriptor(), the NIMBLE_MAX_AGGREGATE_FORMAT_DESCRIPTORS knob, and the post-start initValue() pass in NimBLEServer::start(). The fork's descriptor-handle-assignment fix (Phase-1 + the ble_gatts_find_dsc dsc_arg change) is intentionally dropped: 2.5.0 already contains upstream #1107 ("Properly set attribute handles"), which owns duplicate-safe handle assignment via the GATT register callback. So the host-C is left untouched.
1 parent a9eab2f commit 1ff1c68

6 files changed

Lines changed: 171 additions & 0 deletions

File tree

src/NimBLE2905.cpp

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/*
2+
* Copyright 2020-2025 Ryan Powell <ryan@nable-embedded.io> and
3+
* esp-nimble-cpp, NimBLE-Arduino contributors.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
#include "NimBLE2905.h"
19+
#include "NimBLELog.h"
20+
21+
#include "NimBLECharacteristic.h"
22+
#if CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
23+
24+
// Define default if not already defined
25+
#ifndef NIMBLE_MAX_AGGREGATE_FORMAT_DESCRIPTORS
26+
#define NIMBLE_MAX_AGGREGATE_FORMAT_DESCRIPTORS 5 // Default value
27+
#else
28+
// Ensure the value is within a valid range
29+
#if NIMBLE_MAX_AGGREGATE_FORMAT_DESCRIPTORS < 1 || NIMBLE_MAX_AGGREGATE_FORMAT_DESCRIPTORS > 255
30+
#error "NIMBLE_MAX_AGGREGATE_FORMAT_DESCRIPTORS must be between 1 and 128"
31+
#endif
32+
#endif
33+
34+
static const char* LOG_TAG = "NimBLE2905";
35+
36+
NimBLE2905::NimBLE2905(NimBLECharacteristic* pChr)
37+
: NimBLEDescriptor(NimBLEUUID(static_cast<uint16_t>(0x2905)), BLE_GATT_CHR_F_READ, NIMBLE_MAX_AGGREGATE_FORMAT_DESCRIPTORS * sizeof(uint16_t), pChr) {
38+
} // NimBLE2905
39+
40+
void NimBLE2905::initValue() {
41+
const size_t count = m_vAggregatedDescriptors.size();
42+
uint16_t aggregatedHandles[count];
43+
44+
for (size_t i = 0; i < count; ++i) {
45+
auto* desc = m_vAggregatedDescriptors[i];
46+
uint16_t handle = desc->getHandle();
47+
48+
if (handle == 0) {
49+
NIMBLE_LOGE(LOG_TAG, "Failed to initialize value: presentation format descriptor handle is not initialized");
50+
return;
51+
}
52+
53+
aggregatedHandles[i] = desc->getHandle();
54+
} // initValue
55+
56+
setValue(reinterpret_cast<const uint8_t*>(aggregatedHandles), sizeof(aggregatedHandles));
57+
58+
// Presentation formats no longer needed, let's free some memory
59+
m_vAggregatedDescriptors.clear();
60+
m_vAggregatedDescriptors.shrink_to_fit();
61+
} // initValue
62+
63+
64+
/**
65+
* @brief Add presentation format descriptor.
66+
* @param [in] presentationFormat The 2904 descriptor to aggregate.
67+
*/
68+
void NimBLE2905::add2904Descriptor(const NimBLE2904* presentationFormat) {
69+
if (presentationFormat == nullptr) {
70+
NIMBLE_LOGE(LOG_TAG, "Failed to add presentation format descriptor: nullptr");
71+
return;
72+
}
73+
74+
if (m_vAggregatedDescriptors.size() < NIMBLE_MAX_AGGREGATE_FORMAT_DESCRIPTORS) {
75+
m_vAggregatedDescriptors.push_back(presentationFormat);
76+
} else {
77+
NIMBLE_LOGE(LOG_TAG, "Failed to add presentation format descriptor: maximum capacity reached");
78+
}
79+
} // add2904Descriptor
80+
81+
82+
#endif // CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_PERIPHERAL)

src/NimBLE2905.h

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* Copyright 2020-2025 Ryan Powell <ryan@nable-embedded.io> and
3+
* esp-nimble-cpp, NimBLE-Arduino contributors.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
#ifndef NIMBLE_CPP_2905_H_
19+
#define NIMBLE_CPP_2905_H_
20+
21+
#include "syscfg/syscfg.h"
22+
#if CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
23+
24+
# include "NimBLEDescriptor.h"
25+
26+
/**
27+
* @brief Characteristic Aggregate Format descriptor (UUID: 0x2905).
28+
*
29+
* @details Contains an ordered list of handles referencing 0x2904 Presentation Format
30+
* descriptors that define the parent characteristic’s value.
31+
*/
32+
class NimBLE2905 : public NimBLEDescriptor {
33+
public:
34+
NimBLE2905(NimBLECharacteristic* pChr = nullptr);
35+
36+
void add2904Descriptor(const NimBLE2904* presentationFormat);
37+
private:
38+
39+
/**
40+
* @brief Descriptor for the Characteristic Aggregate Format (UUID: 0x2905).
41+
*
42+
* @details Contains an ordered list of handles referencing the 0x2904
43+
* Presentation Format descriptors that define the parent characteristic's value.
44+
*
45+
* @see NimBLEServer::start()
46+
*/
47+
void initValue();
48+
49+
friend class NimBLECharacteristic;
50+
friend class NimBLEServer;
51+
52+
std::vector<const NimBLE2904*> m_vAggregatedDescriptors;
53+
}; // NimBLE2904
54+
55+
#endif // CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
56+
#endif // NIMBLE_CPP_2904_H_

src/NimBLECharacteristic.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
# endif
2727

2828
# include "NimBLE2904.h"
29+
# include "NimBLE2905.h"
2930
# include "NimBLEDevice.h"
3031
# include "NimBLELog.h"
3132

@@ -86,6 +87,9 @@ NimBLEDescriptor* NimBLECharacteristic::createDescriptor(const NimBLEUUID& uuid,
8687
if (uuid == NimBLEUUID(static_cast<uint16_t>(0x2904))) {
8788
NIMBLE_LOGW(LOG_TAG, "0x2904 descriptor should be created with create2904()");
8889
pDescriptor = create2904();
90+
} else if (uuid == NimBLEUUID(static_cast<uint16_t>(0x2905))) {
91+
NIMBLE_LOGW(LOG_TAG, "0x2905 descriptor should be created with create2905()");
92+
pDescriptor = create2905();
8993
} else {
9094
pDescriptor = new NimBLEDescriptor(uuid, properties, maxLen, this);
9195
}
@@ -104,6 +108,16 @@ NimBLE2904* NimBLECharacteristic::create2904() {
104108
return pDescriptor;
105109
} // create2904
106110

111+
/**
112+
* @brief Create a Characteristic Aggregate Format Descriptor for this characteristic.
113+
* @return A pointer to a NimBLE2905 descriptor.
114+
*/
115+
NimBLE2905* NimBLECharacteristic::create2905() {
116+
NimBLE2905* pDescriptor = new NimBLE2905(this);
117+
addDescriptor(pDescriptor);
118+
return pDescriptor;
119+
} // create2905
120+
107121
/**
108122
* @brief Add a descriptor to the characteristic.
109123
* @param [in] pDescriptor A pointer to the descriptor to add.

src/NimBLECharacteristic.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ class NimBLEService;
2626
class NimBLECharacteristic;
2727
class NimBLEDescriptor;
2828
class NimBLE2904;
29+
class NimBLE2905;
2930

3031
# include "NimBLELocalValueAttribute.h"
3132

@@ -69,6 +70,7 @@ class NimBLECharacteristic : public NimBLELocalValueAttribute {
6970
uint32_t properties = NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE,
7071
uint16_t maxLen = BLE_ATT_ATTR_MAX_LEN);
7172
NimBLE2904* create2904();
73+
NimBLE2905* create2905();
7274
NimBLEDescriptor* getDescriptorByUUID(const char* uuid, uint16_t index = 0) const;
7375
NimBLEDescriptor* getDescriptorByUUID(const NimBLEUUID& uuid, uint16_t index = 0) const;
7476
NimBLEDescriptor* getDescriptorByHandle(uint16_t handle) const;

src/NimBLEServer.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "NimBLEServer.h"
1919
#if CONFIG_BT_NIMBLE_ENABLED && MYNEWT_VAL(BLE_ROLE_PERIPHERAL)
2020

21+
# include "NimBLE2905.h"
2122
# include "NimBLEDevice.h"
2223
# include "NimBLELog.h"
2324

@@ -317,6 +318,19 @@ bool NimBLEServer::start() {
317318
}
318319
# endif
319320

321+
// Populate any Aggregate Format (0x2905) descriptors now that every attribute handle has been
322+
// assigned during ble_gatts_start() (via the GATT register callback). A 0x2905 value is the
323+
// ordered list of its aggregated 0x2904 presentation-format descriptor handles.
324+
for (const auto& svc : m_svcVec) {
325+
for (const auto& chr : svc->getCharacteristics()) {
326+
for (auto& desc : chr->m_vDescriptors) {
327+
if (desc->getUUID() == NimBLEUUID(static_cast<uint16_t>(0x2905))) {
328+
static_cast<NimBLE2905*>(desc)->initValue();
329+
}
330+
}
331+
}
332+
}
333+
320334
// If the services have changed indicate it now
321335
if (m_svcChanged) {
322336
m_svcChanged = false;

src/nimconfig.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
* Arduino User Options *
66
**********************************************/
77

8+
/** @brief Uncomment to change the maximum number of aggregated presentation format descriptors; 5 by default. */
9+
// #define NIMBLE_MAX_AGGREGATE_FORMAT_DESCRIPTORS 5
10+
811
/** @brief Un-comment to change the number of simultaneous connections (esp controller max is 9) */
912
// #define MYNEWT_VAL_BLE_MAX_CONNECTIONS 3
1013

0 commit comments

Comments
 (0)