From a4eca7fc755329d4e104f27db2a54eccc44acb0c Mon Sep 17 00:00:00 2001 From: Rohit Jadhav Date: Mon, 17 Jun 2024 17:07:59 +0530 Subject: [PATCH] components/esp-matter: Add mode select device type --- .../esp_matter/esp_matter_attribute.cpp | 42 ++++++++++++ components/esp_matter/esp_matter_attribute.h | 13 ++++ .../esp_matter/esp_matter_attribute_utils.cpp | 66 +++++++++++++++++++ .../esp_matter/esp_matter_attribute_utils.h | 7 ++ components/esp_matter/esp_matter_cluster.cpp | 49 ++++++++++++++ components/esp_matter/esp_matter_cluster.h | 30 +++++++++ components/esp_matter/esp_matter_command.cpp | 22 +++++++ components/esp_matter/esp_matter_command.h | 6 ++ components/esp_matter/esp_matter_endpoint.cpp | 43 ++++++++++++ components/esp_matter/esp_matter_endpoint.h | 13 ++++ components/esp_matter/esp_matter_feature.cpp | 27 ++++++++ components/esp_matter/esp_matter_feature.h | 18 +++++ 12 files changed, 336 insertions(+) diff --git a/components/esp_matter/esp_matter_attribute.cpp b/components/esp_matter/esp_matter_attribute.cpp index 2b508293c..4d71ef9ec 100644 --- a/components/esp_matter/esp_matter_attribute.cpp +++ b/components/esp_matter/esp_matter_attribute.cpp @@ -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 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 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 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 */ diff --git a/components/esp_matter/esp_matter_attribute.h b/components/esp_matter/esp_matter_attribute.h index 176c548ec..776dfeee5 100644 --- a/components/esp_matter/esp_matter_attribute.h +++ b/components/esp_matter/esp_matter_attribute.h @@ -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 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 value); +attribute_t *create_on_mode(cluster_t *cluster, nullable value); +} /* attribute */ +} /* mode_select */ + } /* cluster */ } /* esp_matter */ diff --git a/components/esp_matter/esp_matter_attribute_utils.cpp b/components/esp_matter/esp_matter_attribute_utils.cpp index 72fe6bf78..b7480e813 100644 --- a/components/esp_matter/esp_matter_attribute_utils.cpp +++ b/components/esp_matter/esp_matter_attribute_utils.cpp @@ -319,6 +319,30 @@ esp_matter_attr_val_t esp_matter_nullable_enum8(nullable 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 val) +{ + esp_matter_attr_val_t attr_val = { + .type = ESP_MATTER_VAL_TYPE_NULLABLE_ENUM16, + }; + if (val.is_null()) { + chip::app::NumericAttributeTraits::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()); + } 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; + 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()); + } 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; + 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()); + } 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; Traits::StorageType attribute_value; diff --git a/components/esp_matter/esp_matter_attribute_utils.h b/components/esp_matter/esp_matter_attribute_utils.h index ee16428e6..e6563a7ef 100644 --- a/components/esp_matter/esp_matter_attribute_utils.h +++ b/components/esp_matter/esp_matter_attribute_utils.h @@ -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 val); esp_matter_attr_val_t esp_matter_enum8(uint8_t val); esp_matter_attr_val_t esp_matter_nullable_enum8(nullable 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 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 val); diff --git a/components/esp_matter/esp_matter_cluster.cpp b/components/esp_matter/esp_matter_cluster.cpp index e7a7c98d5..01bd021d9 100644 --- a/components/esp_matter/esp_matter_cluster.cpp +++ b/components/esp_matter/esp_matter_cluster.cpp @@ -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 */ diff --git a/components/esp_matter/esp_matter_cluster.h b/components/esp_matter/esp_matter_cluster.h index f0dfb9a54..15e26a017 100644 --- a/components/esp_matter/esp_matter_cluster.h +++ b/components/esp_matter/esp_matter_cluster.h @@ -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 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 */ diff --git a/components/esp_matter/esp_matter_command.cpp b/components/esp_matter/esp_matter_command.cpp index 995c61312..39d82f25a 100644 --- a/components/esp_matter/esp_matter_command.cpp +++ b/components/esp_matter/esp_matter_command.cpp @@ -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 */ diff --git a/components/esp_matter/esp_matter_command.h b/components/esp_matter/esp_matter_command.h index df962a1c4..162c6dabd 100644 --- a/components/esp_matter/esp_matter_command.h +++ b/components/esp_matter/esp_matter_command.h @@ -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 */ diff --git a/components/esp_matter/esp_matter_endpoint.cpp b/components/esp_matter/esp_matter_endpoint.cpp index cf4a9cc0c..37ef83c7b 100644 --- a/components/esp_matter/esp_matter_endpoint.cpp +++ b/components/esp_matter/esp_matter_endpoint.cpp @@ -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 { diff --git a/components/esp_matter/esp_matter_endpoint.h b/components/esp_matter/esp_matter_endpoint.h index 4b7ce0422..848575276 100644 --- a/components/esp_matter/esp_matter_endpoint.h +++ b/components/esp_matter/esp_matter_endpoint.h @@ -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 { diff --git a/components/esp_matter/esp_matter_feature.cpp b/components/esp_matter/esp_matter_feature.cpp index c65328363..bcaa97ab5 100644 --- a/components/esp_matter/esp_matter_feature.cpp +++ b/components/esp_matter/esp_matter_feature.cpp @@ -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 */ diff --git a/components/esp_matter/esp_matter_feature.h b/components/esp_matter/esp_matter_feature.h index 2b445499f..7f3394828 100644 --- a/components/esp_matter/esp_matter_feature.h +++ b/components/esp_matter/esp_matter_feature.h @@ -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 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 */