Skip to content

Commit f921e2a

Browse files
authored
feat(zigbee): use std::vector for memory allocation and explicit initalization
1 parent 031f117 commit f921e2a

File tree

1 file changed

+141
-113
lines changed

1 file changed

+141
-113
lines changed

libraries/Zigbee/src/ZigbeeEP.cpp

+141-113
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ ZigbeeEP::ZigbeeEP(uint8_t endpoint) {
1919
_ep_config.endpoint = 0;
2020
_cluster_list = nullptr;
2121
_on_identify = nullptr;
22+
_read_model = nullptr; // Explicitly initialize here
23+
_read_manufacturer = nullptr; // Explicitly initialize here
24+
2225
_time_status = 0;
2326
if (!lock) {
2427
lock = xSemaphoreCreateBinary();
@@ -33,43 +36,51 @@ void ZigbeeEP::setVersion(uint8_t version) {
3336
}
3437

3538
bool ZigbeeEP::setManufacturerAndModel(const char *name, const char *model) {
36-
constexpr size_t ZB_MAX_NAME_LENGTH = 32;
39+
constexpr size_t ZB_MAX_NAME_LENGTH = 32;
40+
41+
// Validate input lengths
42+
size_t name_length = strlen(name);
43+
size_t model_length = strlen(model);
44+
if (name_length > ZB_MAX_NAME_LENGTH || model_length > ZB_MAX_NAME_LENGTH) {
45+
log_e("Manufacturer or model name is too long");
46+
return false;
47+
}
3748

38-
// Convert manufacturer to ZCL string
39-
size_t name_length = strlen(name);
40-
size_t model_length = strlen(model);
41-
if (name_length > ZB_MAX_NAME_LENGTH || model_length > ZB_MAX_NAME_LENGTH) {
42-
log_e("Manufacturer or model name is too long");
43-
return false;
44-
}
45-
// Allocate an array of size length + 2 (1 for the length, 1 for null terminator)
46-
char zb_name[ZB_MAX_NAME_LENGTH + 2];
47-
char zb_model[ZB_MAX_NAME_LENGTH + 2];
48-
// Store the length as the first element
49-
zb_name[0] = static_cast<char>(name_length); // Cast size_t to char
50-
zb_model[0] = static_cast<char>(model_length);
51-
// Use memcpy to copy the characters to the result array
52-
memcpy(zb_name + 1, name, name_length);
53-
memcpy(zb_model + 1, model, model_length);
54-
// Null-terminate the array
55-
zb_name[name_length + 1] = '\0';
56-
zb_model[model_length + 1] = '\0';
57-
58-
// Get the basic cluster and update the manufacturer and model attributes
59-
esp_zb_attribute_list_t *basic_cluster = esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_BASIC, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
60-
if (basic_cluster == nullptr) {
61-
log_e("Failed to get basic cluster");
62-
return false;
63-
}
64-
esp_err_t ret_name = esp_zb_basic_cluster_add_attr(basic_cluster, ESP_ZB_ZCL_ATTR_BASIC_MANUFACTURER_NAME_ID, (void *)zb_name);
65-
if (ret_name != ESP_OK) {
66-
log_e("Failed to set manufacturer: 0x%x: %s", ret_name, esp_err_to_name(ret_name));
67-
}
68-
esp_err_t ret_model = esp_zb_basic_cluster_add_attr(basic_cluster, ESP_ZB_ZCL_ATTR_BASIC_MODEL_IDENTIFIER_ID, (void *)zb_model);
69-
if (ret_model != ESP_OK) {
70-
log_e("Failed to set model: 0x%x: %s", ret_model, esp_err_to_name(ret_model));
71-
}
72-
return ret_name == ESP_OK && ret_model == ESP_OK;
49+
// Use std::vector<char> for dynamic memory management - free() is for free when out of scope
50+
std::vector<char> zb_name(name_length + 2); // +2 for length byte and null terminator
51+
std::vector<char> zb_model(model_length + 2);
52+
53+
// Convert manufacturer to ZCL string
54+
zb_name[0] = static_cast<char>(name_length); // Store the length as the first element
55+
memcpy(zb_name.data() + 1, name, name_length);
56+
zb_name[name_length + 1] = '\0'; // Null-terminate the array
57+
58+
// Convert model to ZCL string
59+
zb_model[0] = static_cast<char>(model_length);
60+
memcpy(zb_model.data() + 1, model, model_length);
61+
zb_model[model_length + 1] = '\0';
62+
63+
// Get the basic cluster and update the manufacturer and model attributes
64+
esp_zb_attribute_list_t *basic_cluster = esp_zb_cluster_list_get_cluster(
65+
_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_BASIC, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
66+
if (!basic_cluster) {
67+
log_e("Failed to get basic cluster");
68+
return false;
69+
}
70+
71+
esp_err_t ret_name = esp_zb_basic_cluster_add_attr(
72+
basic_cluster, ESP_ZB_ZCL_ATTR_BASIC_MANUFACTURER_NAME_ID, zb_name.data());
73+
if (ret_name != ESP_OK) {
74+
log_e("Failed to set manufacturer: 0x%x: %s", ret_name, esp_err_to_name(ret_name));
75+
}
76+
77+
esp_err_t ret_model = esp_zb_basic_cluster_add_attr(
78+
basic_cluster, ESP_ZB_ZCL_ATTR_BASIC_MODEL_IDENTIFIER_ID, zb_model.data());
79+
if (ret_model != ESP_OK) {
80+
log_e("Failed to set model: 0x%x: %s", ret_model, esp_err_to_name(ret_model));
81+
}
82+
83+
return ret_name == ESP_OK && ret_model == ESP_OK;
7384
}
7485

7586
bool ZigbeeEP::setPowerSource(zb_power_source_t power_source, uint8_t battery_percentage) {
@@ -146,79 +157,77 @@ bool ZigbeeEP::reportBatteryPercentage() {
146157
}
147158

148159
char *ZigbeeEP::readManufacturer(uint8_t endpoint, uint16_t short_addr, esp_zb_ieee_addr_t ieee_addr) {
149-
/* Read peer Manufacture Name & Model Identifier */
150-
esp_zb_zcl_read_attr_cmd_t read_req;
151-
152-
if (short_addr != 0) {
153-
read_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT;
154-
read_req.zcl_basic_cmd.dst_addr_u.addr_short = short_addr;
155-
} else {
156-
read_req.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT;
157-
memcpy(read_req.zcl_basic_cmd.dst_addr_u.addr_long, ieee_addr, sizeof(esp_zb_ieee_addr_t));
158-
}
160+
/* Read peer Manufacturer Name */
161+
esp_zb_zcl_read_attr_cmd_t read_req;
162+
163+
if (short_addr != 0) {
164+
read_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT;
165+
read_req.zcl_basic_cmd.dst_addr_u.addr_short = short_addr;
166+
} else {
167+
read_req.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT;
168+
memcpy(read_req.zcl_basic_cmd.dst_addr_u.addr_long, ieee_addr, sizeof(esp_zb_ieee_addr_t));
169+
}
159170

160-
read_req.zcl_basic_cmd.src_endpoint = _endpoint;
161-
read_req.zcl_basic_cmd.dst_endpoint = endpoint;
162-
read_req.clusterID = ESP_ZB_ZCL_CLUSTER_ID_BASIC;
171+
read_req.zcl_basic_cmd.src_endpoint = _endpoint;
172+
read_req.zcl_basic_cmd.dst_endpoint = endpoint;
173+
read_req.clusterID = ESP_ZB_ZCL_CLUSTER_ID_BASIC;
163174

164-
uint16_t attributes[] = {
165-
ESP_ZB_ZCL_ATTR_BASIC_MANUFACTURER_NAME_ID,
166-
};
167-
read_req.attr_number = ZB_ARRAY_LENTH(attributes);
168-
read_req.attr_field = attributes;
175+
uint16_t attributes[] = {
176+
ESP_ZB_ZCL_ATTR_BASIC_MANUFACTURER_NAME_ID,
177+
};
178+
read_req.attr_number = ZB_ARRAY_LENTH(attributes);
179+
read_req.attr_field = attributes;
169180

170-
if (_read_manufacturer != nullptr) {
181+
// Free previously allocated memory for _read_manufacturer
171182
free(_read_manufacturer);
172-
}
173-
_read_manufacturer = nullptr;
183+
_read_manufacturer = nullptr;
174184

175-
esp_zb_lock_acquire(portMAX_DELAY);
176-
esp_zb_zcl_read_attr_cmd_req(&read_req);
177-
esp_zb_lock_release();
185+
esp_zb_lock_acquire(portMAX_DELAY);
186+
esp_zb_zcl_read_attr_cmd_req(&read_req);
187+
esp_zb_lock_release();
178188

179-
//Wait for response or timeout
180-
if (xSemaphoreTake(lock, ZB_CMD_TIMEOUT) != pdTRUE) {
181-
log_e("Error while reading manufacturer");
182-
}
183-
return _read_manufacturer;
189+
// Wait for response or timeout
190+
if (xSemaphoreTake(lock, ZB_CMD_TIMEOUT) != pdTRUE) {
191+
log_e("Error while reading manufacturer");
192+
}
193+
return _read_manufacturer;
184194
}
185195

186196
char *ZigbeeEP::readModel(uint8_t endpoint, uint16_t short_addr, esp_zb_ieee_addr_t ieee_addr) {
187-
/* Read peer Manufacture Name & Model Identifier */
188-
esp_zb_zcl_read_attr_cmd_t read_req;
197+
/* Read peer Model Identifier */
198+
esp_zb_zcl_read_attr_cmd_t read_req;
199+
200+
if (short_addr != 0) {
201+
read_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT;
202+
read_req.zcl_basic_cmd.dst_addr_u.addr_short = short_addr;
203+
} else {
204+
read_req.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT;
205+
memcpy(read_req.zcl_basic_cmd.dst_addr_u.addr_long, ieee_addr, sizeof(esp_zb_ieee_addr_t));
206+
}
189207

190-
if (short_addr != 0) {
191-
read_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT;
192-
read_req.zcl_basic_cmd.dst_addr_u.addr_short = short_addr;
193-
} else {
194-
read_req.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT;
195-
memcpy(read_req.zcl_basic_cmd.dst_addr_u.addr_long, ieee_addr, sizeof(esp_zb_ieee_addr_t));
196-
}
208+
read_req.zcl_basic_cmd.src_endpoint = _endpoint;
209+
read_req.zcl_basic_cmd.dst_endpoint = endpoint;
210+
read_req.clusterID = ESP_ZB_ZCL_CLUSTER_ID_BASIC;
197211

198-
read_req.zcl_basic_cmd.src_endpoint = _endpoint;
199-
read_req.zcl_basic_cmd.dst_endpoint = endpoint;
200-
read_req.clusterID = ESP_ZB_ZCL_CLUSTER_ID_BASIC;
212+
uint16_t attributes[] = {
213+
ESP_ZB_ZCL_ATTR_BASIC_MODEL_IDENTIFIER_ID,
214+
};
215+
read_req.attr_number = ZB_ARRAY_LENTH(attributes);
216+
read_req.attr_field = attributes;
201217

202-
uint16_t attributes[] = {
203-
ESP_ZB_ZCL_ATTR_BASIC_MODEL_IDENTIFIER_ID,
204-
};
205-
read_req.attr_number = ZB_ARRAY_LENTH(attributes);
206-
read_req.attr_field = attributes;
207-
208-
if (_read_model != nullptr) {
218+
// Free previously allocated memory for _read_model
209219
free(_read_model);
210-
}
211-
_read_model = nullptr;
220+
_read_model = nullptr;
212221

213-
esp_zb_lock_acquire(portMAX_DELAY);
214-
esp_zb_zcl_read_attr_cmd_req(&read_req);
215-
esp_zb_lock_release();
222+
esp_zb_lock_acquire(portMAX_DELAY);
223+
esp_zb_zcl_read_attr_cmd_req(&read_req);
224+
esp_zb_lock_release();
216225

217-
//Wait for response or timeout
218-
if (xSemaphoreTake(lock, ZB_CMD_TIMEOUT) != pdTRUE) {
219-
log_e("Error while reading model");
220-
}
221-
return _read_model;
226+
// Wait for response or timeout
227+
if (xSemaphoreTake(lock, ZB_CMD_TIMEOUT) != pdTRUE) {
228+
log_e("Error while reading model");
229+
}
230+
return _read_model;
222231
}
223232

224233
void ZigbeeEP::printBoundDevices() {
@@ -246,25 +255,44 @@ void ZigbeeEP::printBoundDevices(Print &print) {
246255
}
247256

248257
void ZigbeeEP::zbReadBasicCluster(const esp_zb_zcl_attribute_t *attribute) {
249-
/* Basic cluster attributes */
250-
if (attribute->id == ESP_ZB_ZCL_ATTR_BASIC_MANUFACTURER_NAME_ID && attribute->data.type == ESP_ZB_ZCL_ATTR_TYPE_CHAR_STRING && attribute->data.value) {
251-
zbstring_t *zbstr = (zbstring_t *)attribute->data.value;
252-
char string[zbstr->len + 1];
253-
memcpy(string, zbstr->data, zbstr->len);
254-
string[zbstr->len] = '\0';
255-
log_i("Peer Manufacturer is \"%s\"", string);
256-
_read_manufacturer = string;
257-
xSemaphoreGive(lock);
258-
}
259-
if (attribute->id == ESP_ZB_ZCL_ATTR_BASIC_MODEL_IDENTIFIER_ID && attribute->data.type == ESP_ZB_ZCL_ATTR_TYPE_CHAR_STRING && attribute->data.value) {
260-
zbstring_t *zbstr = (zbstring_t *)attribute->data.value;
261-
char string[zbstr->len + 1];
262-
memcpy(string, zbstr->data, zbstr->len);
263-
string[zbstr->len] = '\0';
264-
log_i("Peer Model is \"%s\"", string);
265-
_read_model = string;
266-
xSemaphoreGive(lock);
267-
}
258+
/* Basic cluster attributes */
259+
if (attribute->id == ESP_ZB_ZCL_ATTR_BASIC_MANUFACTURER_NAME_ID &&
260+
attribute->data.type == ESP_ZB_ZCL_ATTR_TYPE_CHAR_STRING &&
261+
attribute->data.value) {
262+
zbstring_t *zbstr = (zbstring_t *)attribute->data.value;
263+
264+
// Use std::vector<char> for automatic memory management
265+
std::vector<char> string(zbstr->len + 1); // Allocate space for the string and null terminator
266+
memcpy(string.data(), zbstr->data, zbstr->len);
267+
string[zbstr->len] = '\0'; // Null-terminate the string
268+
269+
log_i("Peer Manufacturer is \"%s\"", string.data());
270+
271+
// Update _read_manufacturer with a dynamically allocated copy
272+
free(_read_manufacturer); // Free any previously allocated memory
273+
_read_manufacturer = strdup(string.data()); // Duplicate the string for persistent storage
274+
275+
xSemaphoreGive(lock);
276+
}
277+
278+
if (attribute->id == ESP_ZB_ZCL_ATTR_BASIC_MODEL_IDENTIFIER_ID &&
279+
attribute->data.type == ESP_ZB_ZCL_ATTR_TYPE_CHAR_STRING &&
280+
attribute->data.value) {
281+
zbstring_t *zbstr = (zbstring_t *)attribute->data.value;
282+
283+
// Use std::vector<char> for automatic memory management
284+
std::vector<char> string(zbstr->len + 1); // Allocate space for the string and null terminator
285+
memcpy(string.data(), zbstr->data, zbstr->len);
286+
string[zbstr->len] = '\0'; // Null-terminate the string
287+
288+
log_i("Peer Model is \"%s\"", string.data());
289+
290+
// Update _read_model with a dynamically allocated copy
291+
free(_read_model); // Free any previously allocated memory
292+
_read_model = strdup(string.data()); // Duplicate the string for persistent storage
293+
294+
xSemaphoreGive(lock);
295+
}
268296
}
269297

270298
void ZigbeeEP::zbIdentify(const esp_zb_zcl_set_attr_value_message_t *message) {

0 commit comments

Comments
 (0)