diff --git a/components/esp_matter/esp_matter_attribute.cpp b/components/esp_matter/esp_matter_attribute.cpp index eda99c528..bb2df97de 100644 --- a/components/esp_matter/esp_matter_attribute.cpp +++ b/components/esp_matter/esp_matter_attribute.cpp @@ -14,6 +14,8 @@ #include +static const char *TAG = "esp_matter_attribute"; + esp_matter_attribute_t *esp_matter_attribute_create_cluster_revision(esp_matter_cluster_t *cluster, uint16_t value) { return esp_matter_attribute_create(cluster, ZCL_CLUSTER_REVISION_SERVER_ATTRIBUTE_ID, @@ -348,10 +350,18 @@ esp_matter_attribute_t *esp_matter_attribute_create_max_group_keys_per_fabric(es ESP_MATTER_ATTRIBUTE_FLAG_NONE, esp_matter_uint16(value)); } -esp_matter_attribute_t *esp_matter_attribute_create_identify_time(esp_matter_cluster_t *cluster, uint16_t value) +esp_matter_attribute_t *esp_matter_attribute_create_identify_time(esp_matter_cluster_t *cluster, uint16_t value, + uint16_t min, uint16_t max) { - return esp_matter_attribute_create(cluster, ZCL_IDENTIFY_TIME_ATTRIBUTE_ID, ESP_MATTER_ATTRIBUTE_FLAG_WRITABLE, - esp_matter_uint16(value)); + esp_matter_attribute_t *attribute = esp_matter_attribute_create(cluster, ZCL_IDENTIFY_TIME_ATTRIBUTE_ID, + ESP_MATTER_ATTRIBUTE_FLAG_WRITABLE, + esp_matter_uint16(value)); + if (!attribute) { + ESP_LOGE(TAG, "Could not create attribute"); + return NULL; + } + esp_matter_attribute_add_bounds(attribute, esp_matter_uint16(min), esp_matter_uint16(max)); + return attribute; } esp_matter_attribute_t *esp_matter_attribute_create_identify_type(esp_matter_cluster_t *cluster, uint8_t value) @@ -414,10 +424,18 @@ esp_matter_attribute_t *esp_matter_attribute_create_on_level(esp_matter_cluster_ esp_matter_uint8(value)); } -esp_matter_attribute_t *esp_matter_attribute_create_options(esp_matter_cluster_t *cluster, uint8_t value) +esp_matter_attribute_t *esp_matter_attribute_create_options(esp_matter_cluster_t *cluster, uint8_t value, uint8_t min, + uint8_t max) { - return esp_matter_attribute_create(cluster, ZCL_OPTIONS_ATTRIBUTE_ID, ESP_MATTER_ATTRIBUTE_FLAG_WRITABLE, - esp_matter_bitmap8(value)); + esp_matter_attribute_t *attribute = esp_matter_attribute_create(cluster, ZCL_OPTIONS_ATTRIBUTE_ID, + ESP_MATTER_ATTRIBUTE_FLAG_WRITABLE, + esp_matter_bitmap8(value)); + if (!attribute) { + ESP_LOGE(TAG, "Could not create attribute"); + return NULL; + } + esp_matter_attribute_add_bounds(attribute, esp_matter_bitmap8(min), esp_matter_bitmap8(max)); + return attribute; } esp_matter_attribute_t *esp_matter_attribute_create_current_hue(esp_matter_cluster_t *cluster, uint8_t value) @@ -489,16 +507,33 @@ esp_matter_attribute_t *esp_matter_attribute_create_occupied_heating_setpoint(es } esp_matter_attribute_t *esp_matter_attribute_create_control_sequence_of_operation(esp_matter_cluster_t *cluster, - uint8_t value) + uint8_t value, uint8_t min, + uint8_t max) { - return esp_matter_attribute_create(cluster, ZCL_CONTROL_SEQUENCE_OF_OPERATION_ATTRIBUTE_ID, - ESP_MATTER_ATTRIBUTE_FLAG_WRITABLE, esp_matter_enum8(value)); + esp_matter_attribute_t *attribute = esp_matter_attribute_create(cluster, + ZCL_CONTROL_SEQUENCE_OF_OPERATION_ATTRIBUTE_ID, + ESP_MATTER_ATTRIBUTE_FLAG_WRITABLE, + esp_matter_enum8(value)); + if (!attribute) { + ESP_LOGE(TAG, "Could not create attribute"); + return NULL; + } + esp_matter_attribute_add_bounds(attribute, esp_matter_enum8(min), esp_matter_enum8(max)); + return attribute; } -esp_matter_attribute_t *esp_matter_attribute_create_system_mode(esp_matter_cluster_t *cluster, uint8_t value) +esp_matter_attribute_t *esp_matter_attribute_create_system_mode(esp_matter_cluster_t *cluster, uint8_t value, + uint8_t min, uint8_t max) { - return esp_matter_attribute_create(cluster, ZCL_SYSTEM_MODE_ATTRIBUTE_ID, ESP_MATTER_ATTRIBUTE_FLAG_WRITABLE, - esp_matter_enum8(value)); + esp_matter_attribute_t *attribute = esp_matter_attribute_create(cluster, ZCL_SYSTEM_MODE_ATTRIBUTE_ID, + ESP_MATTER_ATTRIBUTE_FLAG_WRITABLE, + esp_matter_enum8(value)); + if (!attribute) { + ESP_LOGE(TAG, "Could not create attribute"); + return NULL; + } + esp_matter_attribute_add_bounds(attribute, esp_matter_enum8(min), esp_matter_enum8(max)); + return attribute; } esp_matter_attribute_t *esp_matter_attribute_create_lock_state(esp_matter_cluster_t *cluster, uint8_t value) @@ -525,10 +560,18 @@ esp_matter_attribute_t *esp_matter_attribute_create_auto_relock_time(esp_matter_ esp_matter_bitmap32(value)); } -esp_matter_attribute_t *esp_matter_attribute_create_operating_mode(esp_matter_cluster_t *cluster, uint8_t value) +esp_matter_attribute_t *esp_matter_attribute_create_operating_mode(esp_matter_cluster_t *cluster, uint8_t value, + uint8_t min, uint8_t max) { - return esp_matter_attribute_create(cluster, ZCL_OPERATING_MODE_ATTRIBUTE_ID, ESP_MATTER_ATTRIBUTE_FLAG_NONE, - esp_matter_enum8(value)); + esp_matter_attribute_t *attribute = esp_matter_attribute_create(cluster, ZCL_OPERATING_MODE_ATTRIBUTE_ID, + ESP_MATTER_ATTRIBUTE_FLAG_NONE, + esp_matter_enum8(value)); + if (!attribute) { + ESP_LOGE(TAG, "Could not create attribute"); + return NULL; + } + esp_matter_attribute_add_bounds(attribute, esp_matter_enum8(min), esp_matter_enum8(max)); + return attribute; } esp_matter_attribute_t *esp_matter_attribute_create_supported_operating_modes(esp_matter_cluster_t *cluster, diff --git a/components/esp_matter/esp_matter_attribute.h b/components/esp_matter/esp_matter_attribute.h index 1038e4c41..9b9137027 100644 --- a/components/esp_matter/esp_matter_attribute.h +++ b/components/esp_matter/esp_matter_attribute.h @@ -123,7 +123,8 @@ esp_matter_attribute_t *esp_matter_attribute_create_max_group_keys_per_fabric(es uint16_t value); /** cluster: identify */ -esp_matter_attribute_t *esp_matter_attribute_create_identify_time(esp_matter_cluster_t *cluster, uint16_t value); +esp_matter_attribute_t *esp_matter_attribute_create_identify_time(esp_matter_cluster_t *cluster, uint16_t value, + uint16_t min, uint16_t max); esp_matter_attribute_t *esp_matter_attribute_create_identify_type(esp_matter_cluster_t *cluster, uint8_t value); /** cluster: groups */ @@ -142,7 +143,8 @@ esp_matter_attribute_t *esp_matter_attribute_create_on_off(esp_matter_cluster_t /** cluster: level control */ esp_matter_attribute_t *esp_matter_attribute_create_current_level(esp_matter_cluster_t *cluster, uint8_t value); esp_matter_attribute_t *esp_matter_attribute_create_on_level(esp_matter_cluster_t *cluster, uint8_t value); -esp_matter_attribute_t *esp_matter_attribute_create_options(esp_matter_cluster_t *cluster, uint8_t value); +esp_matter_attribute_t *esp_matter_attribute_create_options(esp_matter_cluster_t *cluster, uint8_t value, uint8_t min, + uint8_t max); /** cluster: color control */ esp_matter_attribute_t *esp_matter_attribute_create_current_hue(esp_matter_cluster_t *cluster, uint8_t value); @@ -163,15 +165,18 @@ esp_matter_attribute_t *esp_matter_attribute_create_occupied_cooling_setpoint(es esp_matter_attribute_t *esp_matter_attribute_create_occupied_heating_setpoint(esp_matter_cluster_t *cluster, uint16_t value); esp_matter_attribute_t *esp_matter_attribute_create_control_sequence_of_operation(esp_matter_cluster_t *cluster, - uint8_t value); -esp_matter_attribute_t *esp_matter_attribute_create_system_mode(esp_matter_cluster_t *cluster, uint8_t value); + uint8_t value, uint8_t min, + uint8_t max); +esp_matter_attribute_t *esp_matter_attribute_create_system_mode(esp_matter_cluster_t *cluster, uint8_t value, + uint8_t min, uint8_t max); /** cluster: door lock */ esp_matter_attribute_t *esp_matter_attribute_create_lock_state(esp_matter_cluster_t *cluster, uint8_t value); esp_matter_attribute_t *esp_matter_attribute_create_lock_type(esp_matter_cluster_t *cluster, uint8_t value); esp_matter_attribute_t *esp_matter_attribute_create_actuator_enabled(esp_matter_cluster_t *cluster, bool value); esp_matter_attribute_t *esp_matter_attribute_create_auto_relock_time(esp_matter_cluster_t *cluster, uint32_t value); -esp_matter_attribute_t *esp_matter_attribute_create_operating_mode(esp_matter_cluster_t *cluster, uint8_t value); +esp_matter_attribute_t *esp_matter_attribute_create_operating_mode(esp_matter_cluster_t *cluster, uint8_t value, + uint8_t min, uint8_t max); esp_matter_attribute_t *esp_matter_attribute_create_supported_operating_modes(esp_matter_cluster_t *cluster, uint16_t value); diff --git a/components/esp_matter/esp_matter_attribute_utils.cpp b/components/esp_matter/esp_matter_attribute_utils.cpp index 72e18ad61..8bfb45356 100644 --- a/components/esp_matter/esp_matter_attribute_utils.cpp +++ b/components/esp_matter/esp_matter_attribute_utils.cpp @@ -76,6 +76,9 @@ static esp_err_t esp_matter_attribute_console_handler(int argc, char **argv) } else if (type == ESP_MATTER_VAL_TYPE_CHAR_STRING) { char *value = argv[4]; val = esp_matter_char_str(value, strlen(value)); + } else if (type == ESP_MATTER_VAL_TYPE_BITMAP8) { + uint8_t value = atoi(argv[4]); + val = esp_matter_bitmap8(value); } else { ESP_LOGE(TAG, "Type not handled: %d", type); return ESP_ERR_INVALID_ARG; @@ -135,6 +138,10 @@ static esp_err_t esp_matter_attribute_console_handler(int argc, char **argv) int data_count = 0; memcpy(&data_count, &value[0], data_size_len); val = esp_matter_char_str((char *)(value + data_size_len), data_count); + } else if (type == ESP_MATTER_VAL_TYPE_BITMAP8) { + uint8_t value = 0; + esp_matter_attribute_get_val_raw(endpoint_id, cluster_id, attribute_id, (uint8_t *)&value, sizeof(value)); + val = esp_matter_bitmap8(value); } else { ESP_LOGE(TAG, "Type not handled: %d", type); return ESP_ERR_INVALID_ARG; @@ -440,117 +447,8 @@ static esp_matter_val_type_t get_val_type_from_attribute_type(int attribute_type return ESP_MATTER_VAL_TYPE_INVALID; } -esp_err_t esp_matter_attribute_get_type_and_val_default(esp_matter_attr_val_t *val, - EmberAfAttributeType *attribute_type, uint16_t *attribute_size, - EmberAfDefaultOrMinMaxAttributeValue *default_value) -{ - switch (val->type) { - case ESP_MATTER_VAL_TYPE_BOOLEAN: - *attribute_type = ZCL_BOOLEAN_ATTRIBUTE_TYPE; - *attribute_size = sizeof(bool); - *default_value = (uint16_t)val->val.b; - break; - - case ESP_MATTER_VAL_TYPE_INTEGER: - *attribute_type = ZCL_INT16U_ATTRIBUTE_TYPE; - *attribute_size = sizeof(uint16_t); - *default_value = (uint16_t)val->val.i; - break; - - case ESP_MATTER_VAL_TYPE_FLOAT: - *attribute_type = ZCL_SINGLE_ATTRIBUTE_TYPE; - *attribute_size = sizeof(float); - *default_value = (uint8_t *)&val->val.f; - break; - - case ESP_MATTER_VAL_TYPE_ARRAY: - *attribute_type = ZCL_ARRAY_ATTRIBUTE_TYPE; - *attribute_size = val->val.a.t; - *default_value = (uint8_t *)val->val.a.b; - break; - - case ESP_MATTER_VAL_TYPE_CHAR_STRING: - *attribute_type = ZCL_CHAR_STRING_ATTRIBUTE_TYPE; - *attribute_size = val->val.a.t; - *default_value = (uint8_t *)val->val.a.b; - break; - - case ESP_MATTER_VAL_TYPE_OCTET_STRING: - *attribute_type = ZCL_OCTET_STRING_ATTRIBUTE_TYPE; - *attribute_size = val->val.a.t; - *default_value = (uint8_t *)val->val.a.b; - break; - - case ESP_MATTER_VAL_TYPE_INT8: - *attribute_type = ZCL_INT8S_ATTRIBUTE_TYPE; - *attribute_size = sizeof(int8_t); - *default_value = (uint16_t)val->val.i8; - break; - - case ESP_MATTER_VAL_TYPE_UINT8: - *attribute_type = ZCL_INT8U_ATTRIBUTE_TYPE; - *attribute_size = sizeof(uint8_t); - *default_value = (uint16_t)val->val.u8; - break; - - case ESP_MATTER_VAL_TYPE_INT16: - *attribute_type = ZCL_INT16S_ATTRIBUTE_TYPE; - *attribute_size = sizeof(int16_t); - *default_value = (int16_t)val->val.i16; - break; - - case ESP_MATTER_VAL_TYPE_UINT16: - *attribute_type = ZCL_INT16U_ATTRIBUTE_TYPE; - *attribute_size = sizeof(uint16_t); - *default_value = (uint16_t)val->val.u16; - break; - - case ESP_MATTER_VAL_TYPE_UINT32: - *attribute_type = ZCL_INT32U_ATTRIBUTE_TYPE; - *attribute_size = sizeof(uint32_t); - *default_value = (uint8_t *)&val->val.u32; - break; - - case ESP_MATTER_VAL_TYPE_UINT64: - *attribute_type = ZCL_INT64U_ATTRIBUTE_TYPE; - *attribute_size = sizeof(uint64_t); - *default_value = (uint8_t *)&val->val.u64; - break; - - case ESP_MATTER_VAL_TYPE_ENUM8: - *attribute_type = ZCL_ENUM8_ATTRIBUTE_TYPE; - *attribute_size = sizeof(uint8_t); - *default_value = (uint16_t)val->val.u8; - break; - - case ESP_MATTER_VAL_TYPE_BITMAP8: - *attribute_type = ZCL_BITMAP8_ATTRIBUTE_TYPE; - *attribute_size = sizeof(uint8_t); - *default_value = (uint16_t)val->val.u8; - break; - - case ESP_MATTER_VAL_TYPE_BITMAP16: - *attribute_type = ZCL_BITMAP16_ATTRIBUTE_TYPE; - *attribute_size = sizeof(uint16_t); - *default_value = (uint16_t)val->val.u16; - break; - - case ESP_MATTER_VAL_TYPE_BITMAP32: - *attribute_type = ZCL_BITMAP32_ATTRIBUTE_TYPE; - *attribute_size = sizeof(uint32_t); - *default_value = (uint8_t *)&val->val.u32; - break; - - default: - ESP_LOGE(TAG, "esp_matter_attr_val_type_t not handled: %d", val->type); - break; - } - - return ESP_OK; -} - -static esp_err_t get_data_from_attr_val(esp_matter_attr_val_t *val, EmberAfAttributeType *attribute_type, - uint16_t *attribute_size, uint8_t *value) +esp_err_t get_data_from_attr_val(esp_matter_attr_val_t *val, EmberAfAttributeType *attribute_type, + uint16_t *attribute_size, uint8_t *value) { switch (val->type) { case ESP_MATTER_VAL_TYPE_BOOLEAN: @@ -980,7 +878,7 @@ esp_err_t esp_matter_attribute_update(int endpoint_id, int cluster_id, int attri if (emberAfContainsServer(endpoint_id, cluster_id)) { status = emberAfWriteServerAttribute(endpoint_id, cluster_id, attribute_id, value, attribute_type); if (status != EMBER_ZCL_STATUS_SUCCESS) { - ESP_LOGE(TAG, "Error updating attribute to matter"); + ESP_LOGE(TAG, "Error updating attribute to matter: 0x%X", status); free(value); if (lock_status == ESP_MATTER_LOCK_SUCCESS) { esp_matter_chip_stack_unlock(); diff --git a/components/esp_matter/esp_matter_attribute_utils.h b/components/esp_matter/esp_matter_attribute_utils.h index 4f88469d0..ac438d898 100644 --- a/components/esp_matter/esp_matter_attribute_utils.h +++ b/components/esp_matter/esp_matter_attribute_utils.h @@ -101,6 +101,15 @@ typedef struct { esp_matter_val_t val; } esp_matter_attr_val_t; +/* ESP Matter Attribute Bounds */ +typedef struct esp_matter_attr_bounds { + /* Minimum Value */ + esp_matter_attr_val_t min; + /* Maximum Value */ + esp_matter_attr_val_t max; + /** TODO: Step Value might be needed here later */ +} esp_matter_attr_bounds_t; + /*** Attribute val APIs ***/ /** Invalid */ esp_matter_attr_val_t esp_matter_invalid(void *val); diff --git a/components/esp_matter/esp_matter_cluster.cpp b/components/esp_matter/esp_matter_cluster.cpp index 553f753ab..941c8a9db 100644 --- a/components/esp_matter/esp_matter_cluster.cpp +++ b/components/esp_matter/esp_matter_cluster.cpp @@ -600,7 +600,7 @@ esp_matter_cluster_t *esp_matter_cluster_create_identify(esp_matter_endpoint_t * /* Attributes not managed internally */ esp_matter_attribute_create_cluster_revision(cluster, config->cluster_revision); - esp_matter_attribute_create_identify_time(cluster, config->identify_time); + esp_matter_attribute_create_identify_time(cluster, config->identify_time, 0x0, 0xFE); esp_matter_attribute_create_identify_type(cluster, config->identify_type); /* Commands */ @@ -745,7 +745,7 @@ esp_matter_cluster_t *esp_matter_cluster_create_level_control(esp_matter_endpoin esp_matter_attribute_create_cluster_revision(cluster, config->cluster_revision); esp_matter_attribute_create_current_level(cluster, config->current_level); esp_matter_attribute_create_on_level(cluster, config->on_level); - esp_matter_attribute_create_options(cluster, config->options); + esp_matter_attribute_create_options(cluster, config->options, 0x0, 0x3); /* Commands */ esp_matter_command_create_move_to_level(cluster); @@ -858,8 +858,8 @@ esp_matter_cluster_t *esp_matter_cluster_create_thermostat(esp_matter_endpoint_t esp_matter_attribute_create_local_temperature(cluster, config->local_temperature); esp_matter_attribute_create_occupied_cooling_setpoint(cluster, config->occupied_cooling_setpoint); esp_matter_attribute_create_occupied_heating_setpoint(cluster, config->occupied_heating_setpoint); - esp_matter_attribute_create_control_sequence_of_operation(cluster, config->control_sequence_of_operation); - esp_matter_attribute_create_system_mode(cluster, config->system_mode); + esp_matter_attribute_create_control_sequence_of_operation(cluster, config->control_sequence_of_operation, 0x0, 0x5); + esp_matter_attribute_create_system_mode(cluster, config->system_mode, 0x0, 0x7); /* Commands */ esp_matter_command_create_setpoint_raise_lower(cluster); @@ -892,7 +892,7 @@ esp_matter_cluster_t *esp_matter_cluster_create_door_lock(esp_matter_endpoint_t esp_matter_attribute_create_lock_type(cluster, config->lock_type); esp_matter_attribute_create_actuator_enabled(cluster, config->actuator_enabled); esp_matter_attribute_create_auto_relock_time(cluster, config->auto_relock_time); - esp_matter_attribute_create_operating_mode(cluster, config->operating_mode); + esp_matter_attribute_create_operating_mode(cluster, config->operating_mode, 0x0, 0x4); esp_matter_attribute_create_supported_operating_modes(cluster, config->supported_operating_modes); /* Commands */ diff --git a/components/esp_matter/esp_matter_core.cpp b/components/esp_matter/esp_matter_core.cpp index bd03e97ec..618355a91 100644 --- a/components/esp_matter/esp_matter_core.cpp +++ b/components/esp_matter/esp_matter_core.cpp @@ -58,6 +58,9 @@ typedef struct esp_matter_attribute { int attribute_id; uint8_t flags; esp_matter_attr_val_t val; + esp_matter_attr_bounds_t *bounds; + EmberAfDefaultOrMinMaxAttributeValue default_value; + uint16_t default_value_size; struct esp_matter_attribute *next; } _esp_matter_attribute_t; @@ -96,7 +99,7 @@ typedef struct esp_matter_node { static _esp_matter_node_t *node = NULL; -static int esp_matter_cluster_get_count(_esp_matter_cluster_t *current) +static int cluster_get_count(_esp_matter_cluster_t *current) { int count = 0; while (current) { @@ -106,7 +109,7 @@ static int esp_matter_cluster_get_count(_esp_matter_cluster_t *current) return count; } -static int esp_matter_attribute_get_count(_esp_matter_attribute_t *current) +static int attribute_get_count(_esp_matter_attribute_t *current) { int count = 0; while (current) { @@ -116,7 +119,7 @@ static int esp_matter_attribute_get_count(_esp_matter_attribute_t *current) return count; } -static int esp_matter_command_get_count(_esp_matter_command_t *current, int command_flag) +static int command_get_count(_esp_matter_command_t *current, int command_flag) { int count = 0; while (current) { @@ -128,7 +131,7 @@ static int esp_matter_command_get_count(_esp_matter_command_t *current, int comm return count; } -static int esp_matter_endpoint_get_next_index() +static int endpoint_get_next_index() { int endpoint_id = 0; for (int index = 0; index < MAX_ENDPOINT_COUNT; index++) { @@ -140,6 +143,108 @@ static int esp_matter_endpoint_get_next_index() return 0xFFFF; } +extern esp_err_t get_data_from_attr_val(esp_matter_attr_val_t *val, EmberAfAttributeType *attribute_type, + uint16_t *attribute_size, uint8_t *value); + +static esp_err_t attribute_free_default_value(esp_matter_attribute_t *attribute) +{ + if (!attribute) { + ESP_LOGE(TAG, "Attribute cannot be NULL"); + return ESP_FAIL; + } + _esp_matter_attribute_t *current_attribute = (_esp_matter_attribute_t *)attribute; + + /* Free value if data is more than 2 bytes or if it is min max attribute */ + if (current_attribute->flags & ESP_MATTER_ATTRIBUTE_FLAG_MIN_MAX) { + if (current_attribute->default_value_size > 2) { + if (current_attribute->default_value.ptrToMinMaxValue->defaultValue.ptrToDefaultValue) { + free((void *)current_attribute->default_value.ptrToMinMaxValue->defaultValue.ptrToDefaultValue); + } + if (current_attribute->default_value.ptrToMinMaxValue->minValue.ptrToDefaultValue) { + free((void *)current_attribute->default_value.ptrToMinMaxValue->minValue.ptrToDefaultValue); + } + if (current_attribute->default_value.ptrToMinMaxValue->maxValue.ptrToDefaultValue) { + free((void *)current_attribute->default_value.ptrToMinMaxValue->maxValue.ptrToDefaultValue); + } + } + free((void *)current_attribute->default_value.ptrToMinMaxValue); + } else if (current_attribute->default_value_size > 2) { + if (current_attribute->default_value.ptrToDefaultValue) { + free((void *)current_attribute->default_value.ptrToDefaultValue); + } + } + return ESP_OK; +} + +static EmberAfDefaultAttributeValue get_default_value_from_data(esp_matter_attr_val_t *val, + EmberAfAttributeType attribute_type, + uint16_t attribute_size) +{ + EmberAfDefaultAttributeValue default_value = (uint16_t)0; + uint8_t *value = (uint8_t *)calloc(1, attribute_size); + if (!value) { + ESP_LOGE(TAG, "Could not allocate value buffer for default value"); + return default_value; + } + get_data_from_attr_val(val, &attribute_type, &attribute_size, value); + + if (attribute_size > 2) { + /* Directly set the pointer */ + default_value = value; + } else { + /* This data is 2 bytes or less. This should be represented as uint16. Copy the bytes appropriately + for 0 or 1 or 2 bytes to be converted to uint16. Then free the allocated buffer. */ + uint16_t int_value = 0; + if (attribute_size == 2) { + memcpy(&int_value, value, attribute_size); + } else if (attribute_size == 1) { + int_value = (uint16_t)*value; + } + default_value = int_value; + free(value); + } + return default_value; +} + +static esp_err_t attribute_set_default_value_from_current_val(esp_matter_attribute_t *attribute) +{ + if (!attribute) { + ESP_LOGE(TAG, "Attribute cannot be NULL"); + return ESP_FAIL; + } + _esp_matter_attribute_t *current_attribute = (_esp_matter_attribute_t *)attribute; + esp_matter_attr_val_t *val = ¤t_attribute->val; + + /* Get size */ + EmberAfAttributeType attribute_type = 0; + uint16_t attribute_size = 0; + get_data_from_attr_val(val, &attribute_type, &attribute_size, NULL); + + /* Get and set value */ + if (current_attribute->flags & ESP_MATTER_ATTRIBUTE_FLAG_MIN_MAX) { + EmberAfAttributeMinMaxValue *temp_value = (EmberAfAttributeMinMaxValue *)calloc(1, + sizeof(EmberAfAttributeMinMaxValue)); + if (!temp_value) { + ESP_LOGE(TAG, "Could not allocate ptrToMinMaxValue for default value"); + return ESP_FAIL; + } + temp_value->defaultValue = get_default_value_from_data(val, attribute_type, attribute_size); + temp_value->minValue = get_default_value_from_data(¤t_attribute->bounds->min, + attribute_type, attribute_size); + temp_value->maxValue = get_default_value_from_data(¤t_attribute->bounds->max, + attribute_type, attribute_size); + current_attribute->default_value.ptrToMinMaxValue = temp_value; + } else if (attribute_size > 2) { + EmberAfDefaultAttributeValue temp_value = get_default_value_from_data(val, attribute_type, attribute_size); + current_attribute->default_value.ptrToDefaultValue = temp_value.ptrToDefaultValue; + } else { + EmberAfDefaultAttributeValue temp_value = get_default_value_from_data(val, attribute_type, attribute_size); + current_attribute->default_value.defaultValue = temp_value.defaultValue; + } + current_attribute->default_value_size = attribute_size; + return ESP_OK; +} + static esp_err_t esp_matter_endpoint_disable(esp_matter_endpoint_t *endpoint) { if (!endpoint) { @@ -188,11 +293,6 @@ static esp_err_t esp_matter_endpoint_disable(esp_matter_endpoint_t *endpoint) return ESP_OK; } -extern esp_err_t esp_matter_attribute_get_type_and_val_default(esp_matter_attr_val_t *val, - EmberAfAttributeType *attribute_type, - uint16_t *attribute_size, - EmberAfDefaultOrMinMaxAttributeValue *default_value); - esp_err_t esp_matter_endpoint_enable(esp_matter_endpoint_t *endpoint) { if (!endpoint) { @@ -212,7 +312,7 @@ esp_err_t esp_matter_endpoint_enable(esp_matter_endpoint_t *endpoint) /* Clusters */ _esp_matter_cluster_t *cluster = current_endpoint->cluster_list; - int cluster_count = esp_matter_cluster_get_count(cluster); + int cluster_count = cluster_get_count(cluster); int cluster_index = 0; DataVersion *data_versions_ptr = (DataVersion *)calloc(1, cluster_count * sizeof(DataVersion)); @@ -253,7 +353,7 @@ esp_err_t esp_matter_endpoint_enable(esp_matter_endpoint_t *endpoint) while (cluster) { /* Attributes */ attribute = cluster->attribute_list; - attribute_count = esp_matter_attribute_get_count(attribute); + attribute_count = attribute_get_count(attribute); attribute_index = 0; matter_attributes = (EmberAfAttributeMetadata *)calloc(1, attribute_count * sizeof(EmberAfAttributeMetadata)); @@ -266,10 +366,9 @@ esp_err_t esp_matter_endpoint_enable(esp_matter_endpoint_t *endpoint) while (attribute) { matter_attributes[attribute_index].attributeId = attribute->attribute_id; matter_attributes[attribute_index].mask = attribute->flags; - esp_matter_attribute_get_type_and_val_default(&attribute->val, - &matter_attributes[attribute_index].attributeType, - &matter_attributes[attribute_index].size, - &matter_attributes[attribute_index].defaultValue); + matter_attributes[attribute_index].defaultValue = attribute->default_value; + get_data_from_attr_val(&attribute->val, &matter_attributes[attribute_index].attributeType, + &matter_attributes[attribute_index].size, NULL); matter_clusters[cluster_index].clusterSize += matter_attributes[attribute_index].size; attribute = attribute->next; @@ -287,7 +386,7 @@ esp_err_t esp_matter_endpoint_enable(esp_matter_endpoint_t *endpoint) /* Client Generated Commands */ command_flag = ESP_MATTER_COMMAND_FLAG_CLIENT_GENERATED; command = cluster->command_list; - command_count = esp_matter_command_get_count(command, command_flag); + command_count = command_get_count(command, command_flag); if (command_count > 0) { command_index = 0; client_generated_command_ids = (CommandId *)calloc(1, (command_count + 1) * sizeof(CommandId)); @@ -309,7 +408,7 @@ esp_err_t esp_matter_endpoint_enable(esp_matter_endpoint_t *endpoint) /* Server Generated Commands */ command_flag = ESP_MATTER_COMMAND_FLAG_SERVER_GENERATED; command = cluster->command_list; - command_count = esp_matter_command_get_count(command, command_flag); + command_count = command_get_count(command, command_flag); if (command_count > 0) { command_index = 0; server_generated_command_ids = (CommandId *)calloc(1, (command_count + 1) * sizeof(CommandId)); @@ -355,7 +454,7 @@ esp_err_t esp_matter_endpoint_enable(esp_matter_endpoint_t *endpoint) endpoint_type->clusterCount = cluster_count; /* Add Endpoint */ - endpoint_index = esp_matter_endpoint_get_next_index(); + endpoint_index = endpoint_get_next_index(); status = emberAfSetDynamicEndpoint(endpoint_index, current_endpoint->endpoint_id, endpoint_type, current_endpoint->device_type_id, 1, chip::Span(data_versions)); @@ -828,6 +927,56 @@ esp_err_t esp_matter_attribute_set_val(esp_matter_attribute_t *attribute, esp_ma return ESP_OK; } +esp_err_t esp_matter_attribute_add_bounds(esp_matter_attribute_t *attribute, esp_matter_attr_val_t min, + esp_matter_attr_val_t max) +{ + if (!attribute) { + ESP_LOGE(TAG, "Attribute cannot be NULL"); + return ESP_ERR_INVALID_ARG; + } + _esp_matter_attribute_t *current_attribute = (_esp_matter_attribute_t *)attribute; + + /* Check if bounds can be set */ + if (current_attribute->val.type == ESP_MATTER_VAL_TYPE_CHAR_STRING + || current_attribute->val.type == ESP_MATTER_VAL_TYPE_OCTET_STRING + || current_attribute->val.type == ESP_MATTER_VAL_TYPE_ARRAY) { + ESP_LOGE(TAG, "Bounds cannot be set for string/array type attributes"); + return ESP_ERR_INVALID_ARG; + } + if ((current_attribute->val.type != min.type) || (current_attribute->val.type != max.type)) { + ESP_LOGE(TAG, "Cannot set bounds because of val type mismatch: expected: %d, min: %d, max: %d", + current_attribute->val.type, min.type, max.type); + return ESP_ERR_INVALID_ARG; + } + + /* Free the default value before setting the new bounds */ + attribute_free_default_value(attribute); + + /* Allocate and set */ + current_attribute->bounds = (esp_matter_attr_bounds_t *)calloc(1, sizeof(esp_matter_attr_bounds_t)); + if (!current_attribute->bounds) { + ESP_LOGE(TAG, "Could not allocate bounds"); + return ESP_ERR_NO_MEM; + } + memcpy((void *)¤t_attribute->bounds->min, (void *)&min, sizeof(esp_matter_attr_val_t)); + memcpy((void *)¤t_attribute->bounds->max, (void *)&max, sizeof(esp_matter_attr_val_t)); + current_attribute->flags |= ESP_MATTER_ATTRIBUTE_FLAG_MIN_MAX; + + /* Set the default value again after setting the bounds and the flag */ + attribute_set_default_value_from_current_val(attribute); + return ESP_OK; +} + +esp_matter_attr_bounds_t *esp_matter_attribute_get_bounds(esp_matter_attribute_t *attribute) +{ + if (!attribute) { + ESP_LOGE(TAG, "Attribute cannot be NULL"); + return NULL; + } + _esp_matter_attribute_t *current_attribute = (_esp_matter_attribute_t *)attribute; + return current_attribute->bounds; +} + esp_matter_command_callback_t esp_matter_command_get_callback(esp_matter_command_t *command) { if (!command) { @@ -873,6 +1022,9 @@ static esp_err_t esp_matter_attribute_delete(esp_matter_attribute_t *attribute) } _esp_matter_attribute_t *current_attribute = (_esp_matter_attribute_t *)attribute; + /* Default value needs to be deleted first since it uses the current val. */ + attribute_free_default_value(attribute); + /* Delete val here, if required */ if (current_attribute->val.type == ESP_MATTER_VAL_TYPE_CHAR_STRING || current_attribute->val.type == ESP_MATTER_VAL_TYPE_OCTET_STRING @@ -883,6 +1035,11 @@ static esp_err_t esp_matter_attribute_delete(esp_matter_attribute_t *attribute) } } + /* Free bounds */ + if (current_attribute->bounds) { + free(current_attribute->bounds); + } + /* Free */ free(current_attribute); return ESP_OK; @@ -910,6 +1067,7 @@ esp_matter_attribute_t *esp_matter_attribute_create(esp_matter_cluster_t *cluste attribute->flags = flags; attribute->flags |= ESP_MATTER_ATTRIBUTE_FLAG_EXTERNAL_STORAGE; esp_matter_attribute_set_val((esp_matter_attribute_t *)attribute, &val); + attribute_set_default_value_from_current_val((esp_matter_attribute_t *)attribute); /* Add */ _esp_matter_attribute_t *previous_attribute = NULL; diff --git a/components/esp_matter/esp_matter_core.h b/components/esp_matter/esp_matter_core.h index 74b7d2662..4e85364d9 100644 --- a/components/esp_matter/esp_matter_core.h +++ b/components/esp_matter/esp_matter_core.h @@ -123,6 +123,9 @@ esp_err_t esp_matter_attribute_set_val(esp_matter_attribute_t *attribute, esp_ma esp_err_t esp_matter_attribute_get_val(esp_matter_attribute_t *attribute, esp_matter_attr_val_t *val); esp_err_t esp_matter_attribute_get_val_raw(int endpoint_id, int cluster_id, int attribute_id, uint8_t *value, uint16_t attribute_size); +esp_err_t esp_matter_attribute_add_bounds(esp_matter_attribute_t *attribute, esp_matter_attr_val_t min, + esp_matter_attr_val_t max); +esp_matter_attr_bounds_t *esp_matter_attribute_get_bounds(esp_matter_attribute_t *attribute); /** Command APIs */ esp_matter_command_t *esp_matter_command_create(esp_matter_cluster_t *cluster, int command_id, uint8_t flags,