Files
esp-matter/components/esp_matter/data_model/esp_matter_attribute_utils.cpp
T
Shubham Patil a2926640e9 components/esp-matter: propogate error code from attribute update/report
and refactoring

attribute::update and attribute::report were eating up the error code
returned by set_val and returning ESP_OK. This hide all the errors
reported by set_val.

attribute::update and attribute::report are identical with a simple
delta of whether to call the attribute callback or not. So, refactored
it into as helper function.
2026-03-10 12:27:30 +05:30

734 lines
24 KiB
C++

// Copyright 2021 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "esp_check.h"
#include "esp_err.h"
#include "esp_matter_data_model.h"
#include "app/AttributePathParams.h"
#include "data_model_provider/esp_matter_data_model_provider.h"
#include <cstdint>
#include <esp_log.h>
#include <esp_matter.h>
#include <esp_matter_attribute_utils.h>
#include <esp_matter_console.h>
#include <esp_matter_core.h>
#include <esp_matter_mem.h>
#include <esp_matter_data_model_priv.h>
#include <string.h>
#include <app/util/attribute-storage.h>
#include <app/util/attribute-table.h>
#include <app/reporting/reporting.h>
#include <protocols/interaction_model/Constants.h>
#include "support/CodeUtils.h"
using chip::AttributeId;
using chip::ClusterId;
using chip::EndpointId;
using chip::Protocols::InteractionModel::Status;
using namespace esp_matter;
static const char *TAG = "esp_matter_attribute";
esp_matter_attr_val_t esp_matter_invalid(void *val)
{
esp_matter_attr_val_t attr_val = {
.type = ESP_MATTER_VAL_TYPE_INVALID,
.val = {
.p = val,
},
};
return attr_val;
}
esp_matter_attr_val_t esp_matter_bool(bool val)
{
esp_matter_attr_val_t attr_val = {
.type = ESP_MATTER_VAL_TYPE_BOOLEAN,
.val = {
.b = val,
},
};
return attr_val;
}
esp_matter_attr_val_t esp_matter_int(int val)
{
esp_matter_attr_val_t attr_val = {
.type = ESP_MATTER_VAL_TYPE_INTEGER,
.val = {
.i = val,
},
};
return attr_val;
}
esp_matter_attr_val_t esp_matter_nullable_bool(nullable<bool> val)
{
esp_matter_attr_val_t attr_val = {
.type = ESP_MATTER_VAL_TYPE_NULLABLE_BOOLEAN,
};
if (val.is_null()) {
chip::app::NumericAttributeTraits<bool>::SetNull(*(uint8_t *)(&(attr_val.val.b)));
} else {
attr_val.val.b = val.value();
}
return attr_val;
}
esp_matter_attr_val_t esp_matter_nullable_int(nullable<int> val)
{
esp_matter_attr_val_t attr_val = {
.type = ESP_MATTER_VAL_TYPE_NULLABLE_INTEGER,
};
if (val.is_null()) {
chip::app::NumericAttributeTraits<int>::SetNull(attr_val.val.i);
} else {
attr_val.val.i = val.value();
}
return attr_val;
}
esp_matter_attr_val_t esp_matter_float(float val)
{
esp_matter_attr_val_t attr_val = {
.type = ESP_MATTER_VAL_TYPE_FLOAT,
.val = {
.f = val,
},
};
return attr_val;
}
esp_matter_attr_val_t esp_matter_nullable_float(nullable<float> val)
{
esp_matter_attr_val_t attr_val = {
.type = ESP_MATTER_VAL_TYPE_NULLABLE_FLOAT,
};
if (val.is_null()) {
chip::app::NumericAttributeTraits<float>::SetNull(attr_val.val.f);
} else {
attr_val.val.f = val.value();
}
return attr_val;
}
esp_matter_attr_val_t esp_matter_int8(int8_t val)
{
esp_matter_attr_val_t attr_val = {
.type = ESP_MATTER_VAL_TYPE_INT8,
.val = {
.i8 = val,
},
};
return attr_val;
}
esp_matter_attr_val_t esp_matter_nullable_int8(nullable<int8_t> val)
{
esp_matter_attr_val_t attr_val = {
.type = ESP_MATTER_VAL_TYPE_NULLABLE_INT8,
};
if (val.is_null()) {
chip::app::NumericAttributeTraits<int8_t>::SetNull(attr_val.val.i8);
} else {
attr_val.val.i8 = val.value();
}
return attr_val;
}
esp_matter_attr_val_t esp_matter_uint8(uint8_t val)
{
esp_matter_attr_val_t attr_val = {
.type = ESP_MATTER_VAL_TYPE_UINT8,
.val = {
.u8 = val,
},
};
return attr_val;
}
esp_matter_attr_val_t esp_matter_nullable_uint8(nullable<uint8_t> val)
{
esp_matter_attr_val_t attr_val = {
.type = ESP_MATTER_VAL_TYPE_NULLABLE_UINT8,
};
if (val.is_null()) {
chip::app::NumericAttributeTraits<uint8_t>::SetNull(attr_val.val.u8);
} else {
attr_val.val.u8 = val.value();
}
return attr_val;
}
esp_matter_attr_val_t esp_matter_int16(int16_t val)
{
esp_matter_attr_val_t attr_val = {
.type = ESP_MATTER_VAL_TYPE_INT16,
.val = {
.i16 = val,
},
};
return attr_val;
}
esp_matter_attr_val_t esp_matter_nullable_int16(nullable<int16_t> val)
{
esp_matter_attr_val_t attr_val = {
.type = ESP_MATTER_VAL_TYPE_NULLABLE_INT16,
};
if (val.is_null()) {
chip::app::NumericAttributeTraits<int16_t>::SetNull(attr_val.val.i16);
} else {
attr_val.val.i16 = val.value();
}
return attr_val;
}
esp_matter_attr_val_t esp_matter_uint16(uint16_t val)
{
esp_matter_attr_val_t attr_val = {
.type = ESP_MATTER_VAL_TYPE_UINT16,
.val = {
.u16 = val,
},
};
return attr_val;
}
esp_matter_attr_val_t esp_matter_nullable_uint16(nullable<uint16_t> val)
{
esp_matter_attr_val_t attr_val = {
.type = ESP_MATTER_VAL_TYPE_NULLABLE_UINT16,
};
if (val.is_null()) {
chip::app::NumericAttributeTraits<uint16_t>::SetNull(attr_val.val.u16);
} else {
attr_val.val.u16 = val.value();
}
return attr_val;
}
esp_matter_attr_val_t esp_matter_int32(int32_t val)
{
esp_matter_attr_val_t attr_val = {
.type = ESP_MATTER_VAL_TYPE_INT32,
.val = {
.i32 = val,
},
};
return attr_val;
}
esp_matter_attr_val_t esp_matter_nullable_int32(nullable<int32_t> val)
{
esp_matter_attr_val_t attr_val = {
.type = ESP_MATTER_VAL_TYPE_NULLABLE_INT32,
};
if (val.is_null()) {
chip::app::NumericAttributeTraits<int32_t>::SetNull(attr_val.val.i32);
} else {
attr_val.val.i32 = val.value();
}
return attr_val;
}
esp_matter_attr_val_t esp_matter_uint32(uint32_t val)
{
esp_matter_attr_val_t attr_val = {
.type = ESP_MATTER_VAL_TYPE_UINT32,
.val = {
.u32 = val,
},
};
return attr_val;
}
esp_matter_attr_val_t esp_matter_nullable_uint32(nullable<uint32_t> val)
{
esp_matter_attr_val_t attr_val = {
.type = ESP_MATTER_VAL_TYPE_NULLABLE_UINT32,
};
if (val.is_null()) {
chip::app::NumericAttributeTraits<uint32_t>::SetNull(attr_val.val.u32);
} else {
attr_val.val.u32 = val.value();
}
return attr_val;
}
esp_matter_attr_val_t esp_matter_int64(int64_t val)
{
esp_matter_attr_val_t attr_val = {
.type = ESP_MATTER_VAL_TYPE_INT64,
.val = {
.i64 = val,
},
};
return attr_val;
}
esp_matter_attr_val_t esp_matter_nullable_int64(nullable<int64_t> val)
{
esp_matter_attr_val_t attr_val = {
.type = ESP_MATTER_VAL_TYPE_NULLABLE_INT64,
};
if (val.is_null()) {
chip::app::NumericAttributeTraits<int64_t>::SetNull(attr_val.val.i64);
} else {
attr_val.val.i64 = val.value();
}
return attr_val;
}
esp_matter_attr_val_t esp_matter_uint64(uint64_t val)
{
esp_matter_attr_val_t attr_val = {
.type = ESP_MATTER_VAL_TYPE_UINT64,
.val = {
.u64 = val,
},
};
return attr_val;
}
esp_matter_attr_val_t esp_matter_nullable_uint64(nullable<uint64_t> val)
{
esp_matter_attr_val_t attr_val = {
.type = ESP_MATTER_VAL_TYPE_NULLABLE_UINT64,
};
if (val.is_null()) {
chip::app::NumericAttributeTraits<uint64_t>::SetNull(attr_val.val.u64);
} else {
attr_val.val.u64 = val.value();
}
return attr_val;
}
esp_matter_attr_val_t esp_matter_enum8(uint8_t val)
{
esp_matter_attr_val_t attr_val = {
.type = ESP_MATTER_VAL_TYPE_ENUM8,
.val = {
.u8 = val,
},
};
return attr_val;
}
esp_matter_attr_val_t esp_matter_nullable_enum8(nullable<uint8_t> val)
{
esp_matter_attr_val_t attr_val = {
.type = ESP_MATTER_VAL_TYPE_NULLABLE_ENUM8,
};
if (val.is_null()) {
chip::app::NumericAttributeTraits<uint8_t>::SetNull(attr_val.val.u8);
} else {
attr_val.val.u8 = val.value();
}
return attr_val;
}
esp_matter_attr_val_t esp_matter_enum16(uint16_t val)
{
esp_matter_attr_val_t attr_val = {
.type = ESP_MATTER_VAL_TYPE_ENUM16,
.val = {
.u16 = val,
},
};
return attr_val;
}
esp_matter_attr_val_t esp_matter_nullable_enum16(nullable<uint16_t> val)
{
esp_matter_attr_val_t attr_val = {
.type = ESP_MATTER_VAL_TYPE_NULLABLE_ENUM16,
};
if (val.is_null()) {
chip::app::NumericAttributeTraits<uint16_t>::SetNull(attr_val.val.u16);
} else {
attr_val.val.u16 = val.value();
}
return attr_val;
}
esp_matter_attr_val_t esp_matter_bitmap8(uint8_t val)
{
esp_matter_attr_val_t attr_val = {
.type = ESP_MATTER_VAL_TYPE_BITMAP8,
.val = {
.u8 = val,
},
};
return attr_val;
}
esp_matter_attr_val_t esp_matter_nullable_bitmap8(nullable<uint8_t> val)
{
esp_matter_attr_val_t attr_val = {
.type = ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP8,
};
if (val.is_null()) {
chip::app::NumericAttributeTraits<uint8_t>::SetNull(attr_val.val.u8);
} else {
attr_val.val.u8 = val.value();
}
return attr_val;
}
esp_matter_attr_val_t esp_matter_bitmap16(uint16_t val)
{
esp_matter_attr_val_t attr_val = {
.type = ESP_MATTER_VAL_TYPE_BITMAP16,
.val = {
.u16 = val,
},
};
return attr_val;
}
esp_matter_attr_val_t esp_matter_nullable_bitmap16(nullable<uint16_t> val)
{
esp_matter_attr_val_t attr_val = {
.type = ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP16,
};
if (val.is_null()) {
chip::app::NumericAttributeTraits<uint16_t>::SetNull(attr_val.val.u16);
} else {
attr_val.val.u16 = val.value();
}
return attr_val;
}
esp_matter_attr_val_t esp_matter_bitmap32(uint32_t val)
{
esp_matter_attr_val_t attr_val = {
.type = ESP_MATTER_VAL_TYPE_BITMAP32,
.val = {
.u32 = val,
},
};
return attr_val;
}
esp_matter_attr_val_t esp_matter_nullable_bitmap32(nullable<uint32_t> val)
{
esp_matter_attr_val_t attr_val = {
.type = ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP32,
};
if (val.is_null()) {
chip::app::NumericAttributeTraits<uint32_t>::SetNull(attr_val.val.u32);
} else {
attr_val.val.u32 = val.value();
}
return attr_val;
}
esp_matter_attr_val_t esp_matter_char_str(char *val, uint16_t data_size)
{
uint16_t data_size_len = 1; /* Number of bytes used to store the length */
esp_matter_attr_val_t attr_val = {
.type = ESP_MATTER_VAL_TYPE_CHAR_STRING,
.val = {
.a = {
.b = (uint8_t *)val,
.s = data_size,
.t = (uint16_t)(data_size + data_size_len),
},
},
};
return attr_val;
}
esp_matter_attr_val_t esp_matter_long_char_str(char *val, uint16_t data_size)
{
uint16_t data_size_len = 2; /* Number of bytes used to store the length */
esp_matter_attr_val_t attr_val = {
.type = ESP_MATTER_VAL_TYPE_LONG_CHAR_STRING,
.val = {
.a = {
.b = (uint8_t *)val,
.s = data_size,
.t = (uint16_t)(data_size + data_size_len),
},
},
};
return attr_val;
}
esp_matter_attr_val_t esp_matter_octet_str(uint8_t *val, uint16_t data_size)
{
uint16_t data_size_len = 1; /* Number of bytes used to store the length */
esp_matter_attr_val_t attr_val = {
.type = ESP_MATTER_VAL_TYPE_OCTET_STRING,
.val = {
.a = {
.b = val,
.s = data_size,
.t = (uint16_t)(data_size + data_size_len),
},
},
};
return attr_val;
}
esp_matter_attr_val_t esp_matter_long_octet_str(uint8_t *val, uint16_t data_size)
{
uint16_t data_size_len = 2; /* Number of bytes used to store the length */
esp_matter_attr_val_t attr_val = {
.type = ESP_MATTER_VAL_TYPE_LONG_OCTET_STRING,
.val = {
.a = {
.b = val,
.s = data_size,
.t = (uint16_t)(data_size + data_size_len),
},
},
};
return attr_val;
}
esp_matter_attr_val_t esp_matter_array(uint8_t *val, uint16_t data_size, uint16_t count)
{
uint16_t data_size_len = 2; /* Number of bytes used to store the length */
esp_matter_attr_val_t attr_val = {
.type = ESP_MATTER_VAL_TYPE_ARRAY,
.val = {
.a = {
.b = val,
.s = data_size,
.t = (uint16_t)(data_size + data_size_len),
},
},
};
return attr_val;
}
namespace esp_matter {
namespace attribute {
bool val_is_null(esp_matter_attr_val_t *val)
{
switch (val->type) {
case ESP_MATTER_VAL_TYPE_NULLABLE_BOOLEAN:
return chip::app::NumericAttributeTraits<bool>::IsNullValue(*(uint8_t *)(&(val->val.b)));
break;
case ESP_MATTER_VAL_TYPE_NULLABLE_INTEGER:
return chip::app::NumericAttributeTraits<int>::IsNullValue(val->val.i);
break;
case ESP_MATTER_VAL_TYPE_NULLABLE_UINT8:
case ESP_MATTER_VAL_TYPE_NULLABLE_ENUM8:
case ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP8:
return chip::app::NumericAttributeTraits<uint8_t>::IsNullValue(val->val.u8);
break;
case ESP_MATTER_VAL_TYPE_NULLABLE_UINT16:
case ESP_MATTER_VAL_TYPE_NULLABLE_ENUM16:
case ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP16:
return chip::app::NumericAttributeTraits<uint16_t>::IsNullValue(val->val.u16);
break;
case ESP_MATTER_VAL_TYPE_NULLABLE_UINT32:
case ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP32:
return chip::app::NumericAttributeTraits<uint32_t>::IsNullValue(val->val.u32);
break;
case ESP_MATTER_VAL_TYPE_NULLABLE_UINT64:
return chip::app::NumericAttributeTraits<uint64_t>::IsNullValue(val->val.u64);
break;
case ESP_MATTER_VAL_TYPE_NULLABLE_INT8:
return chip::app::NumericAttributeTraits<int8_t>::IsNullValue(val->val.i8);
break;
case ESP_MATTER_VAL_TYPE_NULLABLE_INT16:
return chip::app::NumericAttributeTraits<int16_t>::IsNullValue(val->val.i16);
break;
case ESP_MATTER_VAL_TYPE_NULLABLE_INT32:
return chip::app::NumericAttributeTraits<int32_t>::IsNullValue(val->val.i32);
break;
case ESP_MATTER_VAL_TYPE_NULLABLE_INT64:
return chip::app::NumericAttributeTraits<int64_t>::IsNullValue(val->val.i64);
break;
case ESP_MATTER_VAL_TYPE_NULLABLE_FLOAT:
return chip::app::NumericAttributeTraits<float>::IsNullValue(val->val.f);
break;
default:
return false;
break;
}
return false;
}
void val_print(uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, esp_matter_attr_val_t *val, bool is_read)
{
char action = (is_read) ? 'R' : 'W';
VerifyOrReturn(!val_is_null(val), ESP_LOGI(TAG, "********** %c : Endpoint 0x%04" PRIX16 "'s Cluster 0x%08" PRIX32 "'s Attribute 0x%08" PRIX32 " is null **********", action,
endpoint_id, cluster_id, attribute_id));
if (val->type == ESP_MATTER_VAL_TYPE_BOOLEAN) {
ESP_LOGI(TAG, "********** %c : Endpoint 0x%04" PRIX16 "'s Cluster 0x%08" PRIX32 "'s Attribute 0x%08" PRIX32 " is %d **********", action,
endpoint_id, cluster_id, attribute_id, val->val.b);
} else if (val->type == ESP_MATTER_VAL_TYPE_INTEGER || val->type == ESP_MATTER_VAL_TYPE_NULLABLE_INTEGER) {
ESP_LOGI(TAG, "********** %c : Endpoint 0x%04" PRIX16 "'s Cluster 0x%08" PRIX32 "'s Attribute 0x%08" PRIX32 " is %d **********", action,
endpoint_id, cluster_id, attribute_id, val->val.i);
} else if (val->type == ESP_MATTER_VAL_TYPE_FLOAT || val->type == ESP_MATTER_VAL_TYPE_NULLABLE_FLOAT) {
ESP_LOGI(TAG, "********** %c : Endpoint 0x%04" PRIX16 "'s Cluster 0x%08" PRIX32 "'s Attribute 0x%08" PRIX32 " is %f **********", action,
endpoint_id, cluster_id, attribute_id, val->val.f);
} else if (val->type == ESP_MATTER_VAL_TYPE_INT8 || val->type == ESP_MATTER_VAL_TYPE_NULLABLE_INT8) {
ESP_LOGI(TAG, "********** %c : Endpoint 0x%04" PRIX16 "'s Cluster 0x%08" PRIX32 "'s Attribute 0x%08" PRIX32 " is %i **********", action,
endpoint_id, cluster_id, attribute_id, val->val.i8);
} else if (val->type == ESP_MATTER_VAL_TYPE_UINT8 || val->type == ESP_MATTER_VAL_TYPE_BITMAP8
|| val->type == ESP_MATTER_VAL_TYPE_ENUM8 || val->type == ESP_MATTER_VAL_TYPE_NULLABLE_UINT8
|| val->type == ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP8 || val->type == ESP_MATTER_VAL_TYPE_NULLABLE_ENUM8) {
ESP_LOGI(TAG, "********** %c : Endpoint 0x%04" PRIX16 "'s Cluster 0x%08" PRIX32 "'s Attribute 0x%08" PRIX32 " is %u **********", action,
endpoint_id, cluster_id, attribute_id, val->val.u8);
} else if (val->type == ESP_MATTER_VAL_TYPE_INT16 || val->type == ESP_MATTER_VAL_TYPE_NULLABLE_INT16) {
ESP_LOGI(TAG, "********** %c : Endpoint 0x%04" PRIX16 "'s Cluster 0x%08" PRIX32 "'s Attribute 0x%08" PRIX32 " is %" PRIi16 " **********", action,
endpoint_id, cluster_id, attribute_id, val->val.i16);
} else if (val->type == ESP_MATTER_VAL_TYPE_UINT16 || val->type == ESP_MATTER_VAL_TYPE_BITMAP16
|| val->type == ESP_MATTER_VAL_TYPE_ENUM16 || val->type == ESP_MATTER_VAL_TYPE_NULLABLE_UINT16
|| val->type == ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP16 || val->type == ESP_MATTER_VAL_TYPE_NULLABLE_ENUM16) {
ESP_LOGI(TAG, "********** %c : Endpoint 0x%04" PRIX16 "'s Cluster 0x%08" PRIX32 "'s Attribute 0x%08" PRIX32 " is %" PRIu16 " **********", action,
endpoint_id, cluster_id, attribute_id, val->val.u16);
} else if (val->type == ESP_MATTER_VAL_TYPE_INT32 || val->type == ESP_MATTER_VAL_TYPE_NULLABLE_INT32) {
ESP_LOGI(TAG, "********** %c : Endpoint 0x%04" PRIX16 "'s Cluster 0x%08" PRIX32 "'s Attribute 0x%08" PRIX32 " is %" PRIi32 " **********", action,
endpoint_id, cluster_id, attribute_id, val->val.i32);
} else if (val->type == ESP_MATTER_VAL_TYPE_UINT32 || val->type == ESP_MATTER_VAL_TYPE_BITMAP32
|| val->type == ESP_MATTER_VAL_TYPE_NULLABLE_UINT32 || val->type == ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP32) {
ESP_LOGI(TAG, "********** %c : Endpoint 0x%04" PRIX16 "'s Cluster 0x%08" PRIX32 "'s Attribute 0x%08" PRIX32 " is %" PRIu32 " **********", action,
endpoint_id, cluster_id, attribute_id, val->val.u32);
} else if (val->type == ESP_MATTER_VAL_TYPE_INT64 || val->type == ESP_MATTER_VAL_TYPE_NULLABLE_INT64) {
ESP_LOGI(TAG, "********** %c : Endpoint 0x%04" PRIX16 "'s Cluster 0x%08" PRIX32 "'s Attribute 0x%08" PRIX32 " is %" PRIi64 " **********", action,
endpoint_id, cluster_id, attribute_id, val->val.i64);
} else if (val->type == ESP_MATTER_VAL_TYPE_UINT64 || val->type == ESP_MATTER_VAL_TYPE_NULLABLE_UINT64) {
ESP_LOGI(TAG, "********** %c : Endpoint 0x%04" PRIX16 "'s Cluster 0x%08" PRIX32 "'s Attribute 0x%08" PRIX32 " is %" PRIu64 " **********", action,
endpoint_id, cluster_id, attribute_id, val->val.u64);
} else if (val->type == ESP_MATTER_VAL_TYPE_CHAR_STRING) {
const char *b = val->val.a.b ? (const char *)val->val.a.b : "(empty)";
uint16_t s = val->val.a.b ? val->val.a.s : strlen("(empty)");
ESP_LOGI(TAG, "********** %c : Endpoint 0x%04" PRIX16 "'s Cluster 0x%08" PRIX32 "'s Attribute 0x%08" PRIX32 " is %.*s **********", action,
endpoint_id, cluster_id, attribute_id, s, b);
} else if (val->type == ESP_MATTER_VAL_TYPE_LONG_CHAR_STRING) {
const char *b = val->val.a.b ? (const char *)val->val.a.b : "(empty)";
uint16_t s = val->val.a.b ? val->val.a.s : strlen("(empty)");
ESP_LOGI(TAG, "********** %c : Endpoint 0x%04" PRIX16 "'s Cluster 0x%08" PRIX32 "'s Attribute 0x%08" PRIX32 " is %.*s **********", action,
endpoint_id, cluster_id, attribute_id, s, b);
} else {
ESP_LOGI(TAG, "********** %c : Endpoint 0x%04" PRIX16 "'s Cluster 0x%08" PRIX32 "'s Attribute 0x%08" PRIX32 " is <invalid type: %d> **********", action,
endpoint_id, cluster_id, attribute_id, val->type);
}
}
static esp_err_t update_or_report(uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, esp_matter_attr_val_t *val, bool call_attribute_callbacks)
{
VerifyOrReturnError(val, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "val cannot be NULL"));
attribute_t *attr = get(endpoint_id, cluster_id, attribute_id);
VerifyOrReturnError(attr, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Failed to get attribute handle"));
lock::ScopedChipStackLock lock(portMAX_DELAY);
/* Here, the val_print function gets called on attribute write.*/
attribute::val_print(endpoint_id, cluster_id, attribute_id, val, false);
esp_err_t err = attribute::set_val(attr, val, call_attribute_callbacks);
if (err == ESP_OK) {
data_model::provider::get_instance().Temporary_ReportAttributeChanged(
chip::app::AttributePathParams(endpoint_id, cluster_id, attribute_id));
} else if (err == ESP_ERR_NOT_FINISHED) {
// new value is same as older value, skip reporting to IM engine
err = ESP_OK;
} else {
ESP_LOGE(TAG, "Failed to set attribute value for path: 0x%x/0x%" PRIx32 "/0x%" PRIX32 " err: %d",
endpoint_id, cluster_id, attribute_id, err);
}
return err;
}
esp_err_t update(uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, esp_matter_attr_val_t *val)
{
return update_or_report(endpoint_id, cluster_id, attribute_id, val, true /* call_attribute_callbacks */);
}
esp_err_t report(uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, esp_matter_attr_val_t *val)
{
return update_or_report(endpoint_id, cluster_id, attribute_id, val, false /* call_attribute_callbacks */);
}
bool val_compare(const esp_matter_attr_val_t *val1, const esp_matter_attr_val_t *val2)
{
if (val1 == nullptr || val2 == nullptr) {
return val1 == val2;
}
if (val1->type != val2->type) {
return false;
}
switch ((val1->type & (~ESP_MATTER_VAL_NULLABLE_BASE))) {
case ESP_MATTER_VAL_TYPE_CHAR_STRING:
case ESP_MATTER_VAL_TYPE_OCTET_STRING:
case ESP_MATTER_VAL_TYPE_LONG_CHAR_STRING:
case ESP_MATTER_VAL_TYPE_LONG_OCTET_STRING: {
uint16_t null_len =
(val1->type == ESP_MATTER_VAL_TYPE_CHAR_STRING || val1->type == ESP_MATTER_VAL_TYPE_OCTET_STRING) ? UINT8_MAX : UINT16_MAX;
if (val1->val.a.s != val2->val.a.s) {
return false;
}
if (val1->val.a.s == null_len || val1->val.a.s == 0) {
return true;
}
return memcmp(val1->val.a.b, val2->val.a.b, val1->val.a.s) == 0;
break;
}
case ESP_MATTER_VAL_TYPE_UINT8:
case ESP_MATTER_VAL_TYPE_ENUM8:
case ESP_MATTER_VAL_TYPE_BITMAP8:
return val1->val.u8 == val2->val.u8;
break;
case ESP_MATTER_VAL_TYPE_UINT16:
case ESP_MATTER_VAL_TYPE_ENUM16:
case ESP_MATTER_VAL_TYPE_BITMAP16:
return val1->val.u16 == val2->val.u16;
break;
case ESP_MATTER_VAL_TYPE_UINT32:
case ESP_MATTER_VAL_TYPE_BITMAP32:
return val1->val.u32 == val2->val.u32;
break;
case ESP_MATTER_VAL_TYPE_UINT64:
return val1->val.u64 == val2->val.u64;
break;
case ESP_MATTER_VAL_TYPE_INT8:
return val1->val.i8 == val2->val.i8;
break;
case ESP_MATTER_VAL_TYPE_INT16:
return val1->val.i16 == val2->val.i16;
break;
case ESP_MATTER_VAL_TYPE_INT32:
return val1->val.i32 == val2->val.i32;
break;
case ESP_MATTER_VAL_TYPE_INT64:
return val1->val.i64 == val2->val.i64;
break;
case ESP_MATTER_VAL_TYPE_BOOLEAN:
return val1->val.b == val2->val.b;
break;
case ESP_MATTER_VAL_TYPE_FLOAT:
return val1->val.f == val2->val.f;
break;
default:
ESP_LOGE(TAG, "Unsupported type to compare");
}
return false;
}
} /* attribute */
} /* esp_matter */