MeshX 0.4
This repository provides an implementation for Bluetooth Low Energy (BLE) Mesh network nodes. The project allows you to create BLE mesh nodes that can communicate with each other, enabling the development of smart home solutions or other IoT-based applications.
Loading...
Searching...
No Matches
meshXComposition Class Reference

Singleton manager for the dynamic BLE Mesh composition. More...

#include <meshx_composition.hpp>

Public Member Functions

void add_element (std::unique_ptr< meshXElementIF > element)
 Add an element to the composition.
std::vector< std::unique_ptr< meshXElementIF > > & get_elements ()
 Get the list of elements.
bool has_model (uint16_t model_id) const
 Check if any element in the composition contains a specific model.
bool has_elements () const
 Check if there are any elements.
void clear_elements ()
 Clear all elements and reset state.
void set_device_struct (dev_struct_t *pdev)
 Set the device structure pointer.
meshx_err_t bake (uint16_t cid, uint16_t pid, uint16_t vid)
 "Bake" the dynamic composition into a contiguous C-array
bool is_composition_baked () const
 Check if the composition is baked.
MESHX_ELEMENT * get_baked_elements ()
 Get the baked elements array.
MESHX_COMPOSITION * get_baked_composition ()
 Get the baked composition structure.

Static Public Member Functions

static meshXCompositionget_instance ()
 Get the singleton instance.

Private Member Functions

 meshXComposition ()
 ~meshXComposition ()=default
 meshXComposition (const meshXComposition &)=delete
meshXCompositionoperator= (const meshXComposition &)=delete

Private Attributes

dev_struct_tpdev
bool is_baked
std::vector< std::unique_ptr< meshXElementIF > > elements
std::vector< uint8_t > baked_elements
std::vector< std::vector< uint8_t > > baked_sig_model_arrays
std::vector< std::vector< uint8_t > > baked_ven_model_arrays
MESHX_COMPOSITION baked_comp
MESHX_COMPOSITION * baked_comp_ptr

Detailed Description

Singleton manager for the dynamic BLE Mesh composition.

This class manages the collection of elements and flattens them into the contiguous C-arrays required by the platform's BLE Mesh stack.

Constructor & Destructor Documentation

◆ meshXComposition() [1/2]

meshXComposition::meshXComposition ( )
inlineprivate
98: pdev(nullptr), is_baked(false), baked_comp_ptr(nullptr) {}
MESHX_COMPOSITION * baked_comp_ptr
Definition meshx_composition.hpp:121
dev_struct_t * pdev
Definition meshx_composition.hpp:105
bool is_baked
Definition meshx_composition.hpp:106

◆ ~meshXComposition()

meshXComposition::~meshXComposition ( )
privatedefault

◆ meshXComposition() [2/2]

meshXComposition::meshXComposition ( const meshXComposition & )
privatedelete

Member Function Documentation

◆ add_element()

void meshXComposition::add_element ( std::unique_ptr< meshXElementIF > element)
inline

Add an element to the composition.

Parameters
elementUnique pointer to the element to add
26 {
27 elements.push_back(std::move(element));
28 }
std::vector< std::unique_ptr< meshXElementIF > > elements
Definition meshx_composition.hpp:109

◆ bake()

meshx_err_t meshXComposition::bake ( uint16_t cid,
uint16_t pid,
uint16_t vid )

"Bake" the dynamic composition into a contiguous C-array

This flattens the C++ object tree into the format required by the BLE stack.

Parameters
cidCompany ID.
pidProduct ID.
vidVersion ID.
Returns
MESHX_SUCCESS on success, error code otherwise
34 {
35 if (is_baked) return MESHX_SUCCESS;
36 if (!pdev) {
37 MESHX_LOGE(MODULE_ID_COMMON, "Composition bake failed: Device struct not set");
39 }
40
41 MESHX_LOGI(MODULE_ID_BLE_MESH_ELEMENT, "C|P|V|E: 0x%04x|0x%04x|0x%04x|%zu",
42 cid, pid, vid, elements.size());
43 MESHX_LOGD(MODULE_ID_BLE_MESH_ELEMENT, "MESHX_MODEL size: %d, pub offset: %d", (int)sizeof(MESHX_MODEL), (int)offsetof(MESHX_MODEL, pub));
44 MESHX_LOGD(MODULE_ID_BLE_MESH_ELEMENT, "MESHX_MODEL_PUB size: %d", (int)sizeof(MESHX_MODEL_PUB));
45
46 /* Compile-time check for structural alignment */
47 static_assert(sizeof(MESHX_MODEL) >= 40, "MESHX_MODEL size is too small!");
48
49 size_t total_elements = elements.size();
50
51 /* Allocate and initialize platform structures */
52 baked_elements.assign(total_elements * sizeof(MESHX_ELEMENT), 0);
53 baked_sig_model_arrays.resize(total_elements);
54 baked_ven_model_arrays.resize(total_elements);
55
56 MESHX_ELEMENT* p_elements = reinterpret_cast<MESHX_ELEMENT*>(baked_elements.data());
57
58 /* Bake all Elements (Index 0 to N) */
59 for (size_t i = 0; i < elements.size(); ++i) {
60 size_t plat_idx = i;
61 auto& el = elements[i];
62
63 /* Clear and refresh model lists to prevent duplicates if bake is re-called */
64 el->get_sig_models().clear();
65 el->get_ven_models().clear();
66 el->list_sig_models();
67 el->list_ven_models();
68
69 auto& sig_models = el->get_sig_models();
70 auto& ven_models = el->get_ven_models();
71
72 /* 1. Pre-calculate counts after filtering */
73 size_t actual_sig_cnt = 0;
74 for (auto& m : sig_models) {
75 if (m->get_model_id() == MESHX_MODEL_ID_CONFIG_SRV && plat_idx > 0) continue;
76 actual_sig_cnt++;
77 }
78 size_t actual_ven_cnt = ven_models.size();
79
80 /* 2. Resize and Zero-Initialize model arrays ONCE to ensure pointer stability */
81 baked_sig_model_arrays[plat_idx].assign(actual_sig_cnt * sizeof(MESHX_MODEL), 0);
82 baked_ven_model_arrays[plat_idx].assign(actual_ven_cnt * sizeof(MESHX_MODEL), 0);
83
84 MESHX_LOGD(MODULE_ID_BLE_MESH_ELEMENT, "Baking Element %d: SIG models: %zu, Vendor models: %zu (Model Size: %zu)",
85 (int)plat_idx, actual_sig_cnt, actual_ven_cnt, sizeof(MESHX_MODEL));
86
87 /* 3. Populate SIG models */
88 size_t baked_sig_idx = 0;
89 for (auto& m : sig_models) {
90 m->set_parent_element(el.get());
91
92 /* Skip Config Server if not primary element to satisfy ESP-IDF requirements */
93 if (m->get_model_id() == MESHX_MODEL_ID_CONFIG_SRV && plat_idx > 0) {
94 MESHX_LOGW(MODULE_ID_COMMON, " Skipping Config Server (0x0000) on non-primary element %d", (int)plat_idx);
95 continue;
96 }
97
98 /* Get pointer to the baked slot for this model */
99 MESHX_MODEL* p_baked_base = reinterpret_cast<MESHX_MODEL*>(baked_sig_model_arrays[plat_idx].data());
100 MESHX_MODEL* p_baked = p_baked_base + baked_sig_idx;
101
102 /* Explicitly zero the slot again before calling platform create to prevent garbage */
103 memset(static_cast<void*>(p_baked), 0, sizeof(MESHX_MODEL));
104
105 /* Create the platform model directly into the baked slot */
106 meshx_err_t m_err = m->plat_model_create(p_baked);
107 if (m_err != MESHX_SUCCESS) {
108 MESHX_LOGE(MODULE_ID_BLE_MESH_ELEMENT, "Failed to create platform model for SIG model 0x%04x in element %d (err: %d)",
109 m->get_model_id(), (int)plat_idx, m_err);
110 continue;
111 }
112
113 /* Link the C++ object to the platform struct */
114 m->set_plat_model(p_baked);
115
116 // Debug: Verify the baked model state and check for garbage pointers
117 MESHX_LOGD(MODULE_ID_BLE_MESH_ELEMENT, " Model %zu ID: 0x%04x, Pub: %p, Slot Addr: %p",
118 baked_sig_idx, p_baked->model_id, (void*)p_baked->pub, (void*)p_baked);
119
120 if (p_baked->pub) {
121 uint32_t pub_ptr_val = (uint32_t)p_baked->pub;
122 if (pub_ptr_val < 0x3f000000 || pub_ptr_val > 0x3fffffff) {
123 MESHX_LOGE(MODULE_ID_BLE_MESH_ELEMENT, " CRITICAL: Garbage Pub pointer detected: %p at %p", (void*)p_baked->pub, (void*)&p_baked->pub);
124 }
125 }
126
127 baked_sig_idx++;
128 }
129
130 /* 4. Populate Vendor models */
131 size_t baked_ven_idx = 0;
132 for (auto& m : ven_models) {
133 m->set_parent_element(el.get());
134
135 /* Get pointer to the baked slot for this vendor model */
136 MESHX_MODEL* p_baked = reinterpret_cast<MESHX_MODEL*>(baked_ven_model_arrays[plat_idx].data()) + baked_ven_idx;
137 memset(static_cast<void*>(p_baked), 0, sizeof(MESHX_MODEL));
138
139 /* Create the platform model directly into the baked slot */
140 meshx_err_t m_err = m->plat_model_create(p_baked);
141 if (m_err != MESHX_SUCCESS) {
142 MESHX_LOGE(MODULE_ID_BLE_MESH_ELEMENT, "Failed to create platform model for Vendor model 0x%04x in element %d (err: %d)",
143 m->get_model_id(), (int)plat_idx, m_err);
144 continue;
145 }
146
147 m->set_plat_model(p_baked);
148 baked_ven_idx++;
149 }
150
151 /* 5. Finalize platform element structure */
152 uint16_t loc = 0;
153 uint8_t sig_cnt = (uint8_t)actual_sig_cnt;
154 uint8_t ven_cnt = (uint8_t)baked_ven_idx;
155 esp_ble_mesh_model_t* sig_ptr = (sig_cnt > 0) ? reinterpret_cast<esp_ble_mesh_model_t*>(baked_sig_model_arrays[plat_idx].data()) : nullptr;
156 esp_ble_mesh_model_t* ven_ptr = (ven_cnt > 0) ? reinterpret_cast<esp_ble_mesh_model_t*>(baked_ven_model_arrays[plat_idx].data()) : nullptr;
157
158 MESHX_ELEMENT* e = &p_elements[plat_idx];
159 memcpy((void*)&e->location, &loc, sizeof(e->location));
160 memcpy((void*)&e->sig_model_count, &sig_cnt, sizeof(e->sig_model_count));
161 memcpy((void*)&e->vnd_model_count, &ven_cnt, sizeof(e->vnd_model_count));
162 memcpy((void*)&e->sig_models, &sig_ptr, sizeof(e->sig_models));
163 memcpy((void*)&e->vnd_models, &ven_ptr, sizeof(e->vnd_models));
164
165 /* Register in registry for runtime callbacks/lookups */
166 el->on_baked(plat_idx);
168 }
169
170 /* 4. Finalize Composition Object */
171 baked_comp.cid = cid;
172 baked_comp.pid = pid;
173 baked_comp.vid = vid;
174 baked_comp.element_count = (uint16_t)total_elements;
175 baked_comp.elements = p_elements;
176
178 is_baked = true;
179
180 /* Update the device structure with the baked data */
181 pdev->elements = p_elements;
182 pdev->element_cnt = (uint16_t)total_elements;
183 pdev->element_idx = (uint16_t)total_elements;
184 pdev->composition = baked_comp_ptr;
185
186 return MESHX_SUCCESS;
187
188}
std::vector< uint8_t > baked_elements
Definition meshx_composition.hpp:112
std::vector< std::vector< uint8_t > > baked_ven_model_arrays
Definition meshx_composition.hpp:118
MESHX_COMPOSITION baked_comp
Definition meshx_composition.hpp:120
std::vector< std::vector< uint8_t > > baked_sig_model_arrays
Definition meshx_composition.hpp:117
void register_element(meshXElementIF *element)
Register an element instance.
Definition meshx_element_registry.hpp:43
static meshXElementRegistry & get_instance()
Definition meshx_element_registry.hpp:33
#define MESHX_MODEL_ID_CONFIG_SRV
Definition meshx_ble_mesh_cmn_def.h:46
meshx_err_t
MeshX Error Codes.
Definition meshx_err.h:43
@ MESHX_INVALID_STATE
Definition meshx_err.h:49
#define MESHX_LOGW(module_id, format,...)
Definition meshx_log.h:120
#define MESHX_LOGI(module_id, format,...)
Definition meshx_log.h:126
#define MESHX_LOGE(module_id, format,...)
Definition meshx_log.h:114
#define MESHX_LOGD(module_id, format,...)
Definition meshx_log.h:132
**This function is called by the parent element when a state change request *is received It validates the request and returns a result to the element not the model layer **return * MESHX_SUCCESS
Definition meshx_model_level.cpp:385
@ MODULE_ID_COMMON
Definition module_id.h:36
@ MODULE_ID_BLE_MESH_ELEMENT
Definition module_id.h:39

◆ clear_elements()

void meshXComposition::clear_elements ( )
inline

Clear all elements and reset state.

55 {
56 elements.clear();
57 is_baked = false;
58 baked_elements.clear();
61 }

◆ get_baked_composition()

MESHX_COMPOSITION * meshXComposition::get_baked_composition ( )
inline

Get the baked composition structure.

95{ return baked_comp_ptr; }

◆ get_baked_elements()

MESHX_ELEMENT * meshXComposition::get_baked_elements ( )
inline

Get the baked elements array.

88 {
89 return reinterpret_cast<MESHX_ELEMENT*>(baked_elements.data());
90 }

◆ get_elements()

std::vector< std::unique_ptr< meshXElementIF > > & meshXComposition::get_elements ( )
inline

Get the list of elements.

33{ return elements; }

◆ get_instance()

meshXComposition & meshXComposition::get_instance ( )
static

Get the singleton instance.

Returns
Reference to the meshXComposition instance
29 {
30 static meshXComposition instance;
31 return instance;
32}
meshXComposition()
Definition meshx_composition.hpp:98

◆ has_elements()

bool meshXComposition::has_elements ( ) const
inline

Check if there are any elements.

50{ return !elements.empty(); }

◆ has_model()

bool meshXComposition::has_model ( uint16_t model_id) const
inline

Check if any element in the composition contains a specific model.

Parameters
model_idThe model ID to search for.
Returns
true if found, false otherwise.
40 {
41 for (const auto& el : elements) {
42 if (el && el->has_model(model_id)) return true;
43 }
44 return false;
45 }

◆ is_composition_baked()

bool meshXComposition::is_composition_baked ( ) const
inline

Check if the composition is baked.

Returns
true if baked, false otherwise
83{ return is_baked; }

◆ operator=()

meshXComposition & meshXComposition::operator= ( const meshXComposition & )
privatedelete

◆ set_device_struct()

void meshXComposition::set_device_struct ( dev_struct_t * pdev)
inline

Set the device structure pointer.

Parameters
pdevPointer to the device structure
67{ this->pdev = pdev; }

Field Documentation

◆ baked_comp

MESHX_COMPOSITION meshXComposition::baked_comp
private

◆ baked_comp_ptr

MESHX_COMPOSITION* meshXComposition::baked_comp_ptr
private

◆ baked_elements

std::vector<uint8_t> meshXComposition::baked_elements
private

◆ baked_sig_model_arrays

std::vector<std::vector<uint8_t> > meshXComposition::baked_sig_model_arrays
private

◆ baked_ven_model_arrays

std::vector<std::vector<uint8_t> > meshXComposition::baked_ven_model_arrays
private

◆ elements

std::vector<std::unique_ptr<meshXElementIF> > meshXComposition::elements
private

◆ is_baked

bool meshXComposition::is_baked
private

◆ pdev

dev_struct_t* meshXComposition::pdev
private

The documentation for this class was generated from the following files: