Merge branch 'add_mode_select' into 'release/v1.1'

components/esp-matter: Add mode select device type

See merge request app-frameworks/esp-matter!778
This commit is contained in:
Hrishikesh Dhayagude
2024-06-26 01:34:04 +08:00
12 changed files with 336 additions and 0 deletions
@@ -2188,5 +2188,47 @@ attribute_t *create_control_mode(cluster_t *cluster, uint8_t value)
} /* attribute */
} /* pump_configuration_and_control */
namespace mode_select {
namespace attribute {
attribute_t *create_mode_select_description(cluster_t *cluster, const char * value, uint16_t length)
{
if (length > k_max_mode_select_description_length) {
ESP_LOGE(TAG, "Could not create attribute, string length out of bound");
return NULL;
}
return esp_matter::attribute::create(cluster, ModeSelect::Attributes::Description::Id, ATTRIBUTE_FLAG_NONE,
esp_matter_char_str((char *)value, length),
k_max_mode_select_description_length);
}
attribute_t *create_standard_namespace(cluster_t *cluster, const nullable<uint16_t> value)
{
return esp_matter::attribute::create(cluster, ModeSelect::Attributes::StandardNamespace::Id, ATTRIBUTE_FLAG_NULLABLE, esp_matter_nullable_enum16(value));
}
attribute_t *create_supported_modes(cluster_t *cluster, const uint8_t * value, uint16_t length, uint16_t count)
{
return esp_matter::attribute::create(cluster, ModeSelect::Attributes::SupportedModes::Id, ATTRIBUTE_FLAG_NONE, esp_matter_array((uint8_t*)value, length, count));
}
attribute_t *create_current_mode(cluster_t *cluster, uint8_t value)
{
return esp_matter::attribute::create(cluster, ModeSelect::Attributes::CurrentMode::Id, ATTRIBUTE_FLAG_NONVOLATILE, esp_matter_uint8(value));
}
attribute_t *create_start_up_mode(cluster_t *cluster, nullable<uint8_t> value)
{
return esp_matter::attribute::create(cluster, ModeSelect::Attributes::StartUpMode::Id, ATTRIBUTE_FLAG_WRITABLE | ATTRIBUTE_FLAG_NULLABLE | ATTRIBUTE_FLAG_NONVOLATILE, esp_matter_nullable_uint8(value));
}
attribute_t *create_on_mode(cluster_t *cluster, nullable<uint8_t> value)
{
return esp_matter::attribute::create(cluster, ModeSelect::Attributes::OnMode::Id, ATTRIBUTE_FLAG_WRITABLE | ATTRIBUTE_FLAG_NULLABLE | ATTRIBUTE_FLAG_NONVOLATILE, esp_matter_nullable_uint8(value));
}
} /* attribute */
} /* mode_select */
} /* cluster */
} /* esp_matter */
@@ -531,5 +531,18 @@ attribute_t *create_control_mode(cluster_t *cluster, uint8_t value);
} /* attribute */
} /* pump_configuration_and_control */
namespace mode_select {
constexpr uint8_t k_max_mode_select_description_length = 64;
namespace attribute {
attribute_t *create_mode_select_description(cluster_t *cluster, const char * value, uint16_t length);
attribute_t *create_standard_namespace(cluster_t *cluster, const nullable<uint16_t> value);
attribute_t *create_supported_modes(cluster_t *cluster, const uint8_t * value, uint16_t length, uint16_t count);
attribute_t *create_current_mode(cluster_t *cluster, uint8_t value);
attribute_t *create_start_up_mode(cluster_t *cluster, nullable<uint8_t> value);
attribute_t *create_on_mode(cluster_t *cluster, nullable<uint8_t> value);
} /* attribute */
} /* mode_select */
} /* cluster */
} /* esp_matter */
@@ -319,6 +319,30 @@ esp_matter_attr_val_t esp_matter_nullable_enum8(nullable<uint8_t> val)
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 = {
@@ -622,6 +646,18 @@ static esp_err_t console_set_handler(int argc, char **argv)
uint8_t value = atoi(argv[3]);
val = esp_matter_enum8(value);
}
} else if (type == ESP_MATTER_VAL_TYPE_ENUM16) {
if (matter_attribute->IsNullable()) {
if (strncmp(argv[3], "null", sizeof("null")) == 0) {
val = esp_matter_nullable_enum16(nullable<uint16_t>());
} else {
uint16_t value = atoi(argv[3]);
val = esp_matter_nullable_enum16(value);
}
} else {
uint16_t value = atoi(argv[3]);
val = esp_matter_enum16(value);
}
} else {
ESP_LOGE(TAG, "Type not handled: %d", type);
return ESP_ERR_INVALID_ARG;
@@ -834,6 +870,20 @@ static esp_err_t console_get_handler(int argc, char **argv)
} else {
val = esp_matter_enum8(Traits::StorageToWorking(value));
}
} else if (type == ESP_MATTER_VAL_TYPE_ENUM16) {
using Traits = chip::app::NumericAttributeTraits<uint16_t>;
Traits::StorageType value;
uint8_t *read_able = Traits::ToAttributeStoreRepresentation(value);
get_val_raw(endpoint_id, cluster_id, attribute_id, read_able, sizeof(value));
if (matter_attribute->IsNullable()) {
if (Traits::IsNullValue(value)) {
val = esp_matter_nullable_enum16(nullable<uint16_t>());
} else {
val = esp_matter_nullable_enum16(Traits::StorageToWorking(value));
}
} else {
val = esp_matter_enum16(Traits::StorageToWorking(value));
}
} else {
ESP_LOGE(TAG, "Type not handled: %d", type);
return ESP_ERR_INVALID_ARG;
@@ -1573,6 +1623,22 @@ static esp_err_t get_attr_val_from_data(esp_matter_attr_val_t *val, EmberAfAttri
break;
}
case ZCL_ENUM16_ATTRIBUTE_TYPE: {
using Traits = chip::app::NumericAttributeTraits<uint16_t>;
Traits::StorageType attribute_value;
memcpy((uint16_t *)&attribute_value, value, sizeof(Traits::StorageType));
if (attribute_metadata->IsNullable()) {
if (Traits::IsNullValue(attribute_value)) {
*val = esp_matter_nullable_enum16(nullable<uint16_t>());
} else {
*val = esp_matter_nullable_enum16(attribute_value);
}
} else {
*val = esp_matter_enum16(attribute_value);
}
break;
}
case ZCL_BITMAP8_ATTRIBUTE_TYPE: {
using Traits = chip::app::NumericAttributeTraits<uint8_t>;
Traits::StorageType attribute_value;
@@ -78,6 +78,8 @@ typedef enum {
ESP_MATTER_VAL_TYPE_BITMAP16 = 17,
/** 32 bit bitmap */
ESP_MATTER_VAL_TYPE_BITMAP32 = 18,
/** 16 bit enum */
ESP_MATTER_VAL_TYPE_ENUM16 = 19,
/** nullable types **/
ESP_MATTER_VAL_TYPE_NULLABLE_INTEGER = ESP_MATTER_VAL_TYPE_INTEGER + ESP_MATTER_VAL_NULLABLE_BASE,
ESP_MATTER_VAL_TYPE_NULLABLE_FLOAT = ESP_MATTER_VAL_TYPE_FLOAT + ESP_MATTER_VAL_NULLABLE_BASE,
@@ -93,6 +95,7 @@ typedef enum {
ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP8 = ESP_MATTER_VAL_TYPE_BITMAP8 + ESP_MATTER_VAL_NULLABLE_BASE,
ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP16 = ESP_MATTER_VAL_TYPE_BITMAP16 + ESP_MATTER_VAL_NULLABLE_BASE,
ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP32= ESP_MATTER_VAL_TYPE_BITMAP32 + ESP_MATTER_VAL_NULLABLE_BASE,
ESP_MATTER_VAL_TYPE_NULLABLE_ENUM16 = ESP_MATTER_VAL_TYPE_ENUM16 + ESP_MATTER_VAL_NULLABLE_BASE,
} esp_matter_val_type_t;
/** ESP Matter Value */
@@ -277,6 +280,10 @@ esp_matter_attr_val_t esp_matter_nullable_uint64(nullable<uint64_t> val);
esp_matter_attr_val_t esp_matter_enum8(uint8_t val);
esp_matter_attr_val_t esp_matter_nullable_enum8(nullable<uint8_t> val);
/** 16 bit enum */
esp_matter_attr_val_t esp_matter_enum16(uint16_t val);
esp_matter_attr_val_t esp_matter_nullable_enum16(nullable<uint16_t> val);
/** 8 bit bitmap */
esp_matter_attr_val_t esp_matter_bitmap8(uint8_t val);
esp_matter_attr_val_t esp_matter_nullable_bitmap8(nullable<uint8_t> val);
@@ -1903,6 +1903,55 @@ cluster_t *create(endpoint_t *endpoint, config_t *config, uint8_t flags)
return cluster;
}
} /* pump_configuration_and_control */
namespace mode_select {
const function_generic_t function_list[] = {
(function_generic_t)emberAfModeSelectClusterServerInitCallback,
};
const int function_flags = CLUSTER_FLAG_INIT_FUNCTION;
cluster_t *create(endpoint_t *endpoint, config_t *config, uint8_t flags, uint32_t features)
{
cluster_t *cluster = cluster::create(endpoint, ModeSelect::Id, flags);
if (!cluster) {
ESP_LOGE(TAG, "Could not create cluster");
return NULL;
}
if (flags & CLUSTER_FLAG_SERVER) {
set_plugin_server_init_callback(cluster, MatterPumpConfigurationAndControlPluginServerInitCallback);
add_function_list(cluster, function_list, function_flags);
/* Attributes managed internally */
global::attribute::create_feature_map(cluster, 0);
#if CHIP_CONFIG_ENABLE_EVENTLIST_ATTRIBUTE
global::attribute::create_event_list(cluster, NULL, 0, 0);
#endif
attribute::create_supported_modes(cluster, NULL, 0, 0);
/** Attributes not managed internally **/
if (config) {
global::attribute::create_cluster_revision(cluster, config->cluster_revision);
attribute::create_mode_select_description(cluster, config->mode_select_description, strlen(config->mode_select_description));
attribute::create_standard_namespace(cluster, config->standard_namespace);
attribute::create_current_mode(cluster, config->current_mode);
} else {
ESP_LOGE(TAG, "Config is NULL. Cannot add some attributes.");
}
}
if (flags & CLUSTER_FLAG_CLIENT) {
create_default_binding_cluster(endpoint);
}
/* Commands */
command::create_change_to_mode(cluster);
/* Features */
if (features & feature::on_off::get_id()) {
feature::on_off::add(cluster, &(config->on_off));
}
return cluster;
}
} /* mode_select */
#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */
} /* cluster */
} /* esp_matter */
@@ -471,5 +471,35 @@ typedef struct config {
cluster_t *create(endpoint_t *endpoint, config_t *config, uint8_t flags);
} /* pump_configuration_and_control */
namespace mode_select {
typedef struct config {
uint16_t cluster_revision;
char mode_select_description[k_max_mode_select_description_length + 1];
const nullable<uint16_t> standard_namespace;
uint8_t current_mode;
feature::on_off::config_t on_off;
config() : cluster_revision(2), mode_select_description{0}, standard_namespace(), current_mode(0) {}
} config_t;
cluster_t *create(endpoint_t *endpoint, config_t *config, uint8_t flags, uint32_t features);
} /* mode_select */
} /* cluster */
} /* esp_matter */
// To avoid compilation error function is defined weak here
namespace chip {
namespace app {
namespace Clusters {
namespace ModeSelect {
void* __attribute__((weak)) getSupportedModesManager()
{
// weak func
return nullptr;
}
} /* chip */
} /* app */
} /* Clusters */
} /* ModeSelect */
@@ -80,6 +80,17 @@ void DispatchSingleClusterCommand(const ConcreteCommandPath &command_path, TLVRe
} /* namespace app */
} /* namespace chip */
static esp_err_t esp_matter_command_callback_change_to_mode(const ConcreteCommandPath &command_path, TLVReader &tlv_data, void *opaque_ptr)
{
chip::app::Clusters::ModeSelect::Commands::ChangeToMode::DecodableType command_data;
CHIP_ERROR error = Decode(tlv_data, command_data);
if (error == CHIP_NO_ERROR) {
emberAfModeSelectClusterChangeToModeCallback((CommandHandler *)opaque_ptr, command_path, command_data);
}
return ESP_OK;
}
static esp_err_t esp_matter_command_callback_key_set_write(const ConcreteCommandPath &command_path, TLVReader &tlv_data,
void *opaque_ptr)
{
@@ -2094,6 +2105,17 @@ command_t *create_go_to_tilt_percentage(cluster_t *cluster)
} /* command */
} /* window_covering */
namespace mode_select {
namespace command {
command_t *create_change_to_mode(cluster_t *cluster)
{
return esp_matter::command::create(cluster, ModeSelect::Commands::ChangeToMode::Id, COMMAND_FLAG_ACCEPTED, esp_matter_command_callback_change_to_mode);
}
} /* command */
} /* mode_select */
} /* cluster */
} /* esp_matter */
@@ -255,5 +255,11 @@ command_t *create_go_to_tilt_percentage(cluster_t *cluster);
} /* command */
} /* window_covering */
namespace mode_select {
namespace command {
command_t *create_change_to_mode(cluster_t *cluster);
} /* command */
} /* mode_select */
} /* cluster */
} /* esp_matter */
@@ -911,6 +911,49 @@ endpoint_t *add(endpoint_t *endpoint, config_t *config)
}
} /** pump **/
namespace mode_select_device {
uint32_t get_device_type_id()
{
return ESP_MATTER_MODE_SELECT_DEVICE_TYPE_ID;
}
uint8_t get_device_type_version()
{
return ESP_MATTER_MODE_SELECT_DEVICE_TYPE_VERSION;
}
endpoint_t *create(node_t *node, config_t *config, uint8_t flags, void *priv_data)
{
endpoint_t *endpoint = endpoint::create(node, flags, priv_data);
add(endpoint, config);
return endpoint;
}
esp_err_t add(endpoint_t *endpoint, config_t *config)
{
if (!endpoint) {
ESP_LOGE(TAG, "Endpoint cannot be NULL");
return ESP_ERR_INVALID_ARG;
}
esp_err_t err = add_device_type(endpoint, get_device_type_id(), get_device_type_version());
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to add device type id:%" PRIu32 ",err: %d", get_device_type_id(), err);
return err;
}
cluster_t *cluster = descriptor::create(endpoint, CLUSTER_FLAG_SERVER);
if (!cluster) {
return ESP_ERR_INVALID_STATE;
}
cluster = mode_select::create(endpoint, &(config->mode_select), CLUSTER_FLAG_SERVER, ESP_MATTER_NONE_FEATURE_ID);
if (!cluster) {
return ESP_ERR_INVALID_STATE;
}
return ESP_OK;
}
} /** mode_select_device **/
} /* endpoint */
namespace node {
@@ -74,6 +74,8 @@
#define ESP_MATTER_WINDOW_COVERING_DEVICE_TYPE_VERSION 2
#define ESP_MATTER_PUMP_DEVICE_TYPE_ID 0x0303
#define ESP_MATTER_PUMP_DEVICE_TYPE_VERSION 2
#define ESP_MATTER_MODE_SELECT_DEVICE_TYPE_ID 0x0027
#define ESP_MATTER_MODE_SELECT_DEVICE_TYPE_VERSION 1
namespace esp_matter {
@@ -417,6 +419,17 @@ endpoint_t *create(node_t *node, config_t *config, uint8_t flags, void *priv_dat
endpoint_t *add(endpoint_t *endpoint, config_t *config);
} /** pump **/
namespace mode_select_device {
typedef struct config {
cluster::mode_select::config_t mode_select;
} config_t;
uint32_t get_device_type_id();
uint8_t get_device_type_version();
endpoint_t *create(node_t *node, config_t *config, uint8_t flags, void *priv_data);
esp_err_t add(endpoint_t *endpoint, config_t *config);
} /** mode_select_device **/
} /* endpoint */
namespace node {
@@ -986,5 +986,32 @@ esp_err_t add(cluster_t *cluster, config_t *config)
} /* feature */
} /* time_format_localization */
namespace mode_select {
namespace feature {
namespace on_off {
uint32_t get_id()
{
return (uint32_t)ModeSelect::ModeSelectFeature::kDeponoff;
}
esp_err_t add(cluster_t *cluster, config_t *config)
{
if (!cluster) {
ESP_LOGE(TAG, "Cluster cannot be NULL");
return ESP_ERR_INVALID_ARG;
}
update_feature_map(cluster, get_id());
attribute::create_on_mode(cluster, config->on_mode);
return ESP_OK;
}
} /* on_off */
} /* feature */
} /* mode_select */
} /* cluster */
} /* esp_matter */
@@ -422,5 +422,23 @@ esp_err_t add(cluster_t *cluster, config_t *config);
} /* feature */
} /* time_format_localization */
namespace mode_select {
namespace feature {
namespace on_off {
typedef struct config {
nullable<uint8_t> on_mode;
config() : on_mode() {}
} config_t;
uint32_t get_id();
esp_err_t add(cluster_t *cluster, config_t *config);
} /* on_off */
} /* feature */
} /* mode_select */
} /* cluster */
} /* esp_matter */