@@ -12,11 +12,17 @@
// See the License for the specific language governing permissions and
// limitations under the License.
# include <esp_check.h>
# include <esp_matter_commissioner.h>
# include <esp_matter_controller_utils.h>
# include <esp_matter_controller_write_command.h>
# include <json_parser.h>
using namespace chip : : app : : Clusters ;
using chip : : ByteSpan ;
using chip : : DeviceProxy ;
using chip : : app : : DataModel : : List ;
using chip : : Platform : : New ;
static const char * TAG = " write_command " ;
@@ -30,7 +36,7 @@ void write_command<T>::on_device_connected_fcn(void *context, ExchangeManager &e
write_command < T > * cmd = ( write_command < T > * ) context ;
CHIP_ERROR err = CHIP_NO_ERROR ;
WriteClient * write_client =
chip : : Platform : : New < WriteClient > ( & exchangeMgr , & ( cmd - > get_chunked_write_callback ( ) ) , chip : : NullOptional , false ) ;
New < WriteClient > ( & exchangeMgr , & ( cmd - > get_chunked_write_callback ( ) ) , chip : : NullOptional , false ) ;
if ( ! write_client ) {
ESP_LOGE ( TAG , " Failed to alloc memory for WriteClient " ) ;
chip : : Platform : : Delete ( cmd ) ;
@@ -81,22 +87,16 @@ static esp_err_t write_attribute(uint64_t node_id, uint16_t endpoint_id, uint32_
switch ( attribute_id ) {
case OnOff : : Attributes : : OnTime : : Id :
case OnOff : : Attributes : : OffWaitTime : : Id : {
write_command < uint16_t > * cmd = chip : : Platform : : New < write_command < uint16_t > > (
node_id , endpoint_id , OnOff : : Id , attribute_id , ( uint16_t ) strtol ( attribute_val_str , NULL , 10 ) ) ;
if ( ! cmd ) {
ESP_LOGE ( TAG , " Failed to alloc memory for write_command " ) ;
return ESP_ERR_NO_MEM ;
}
write_command < uint16_t > * cmd = New < write_command < uint16_t > > ( node_id , endpoint_id , OnOff : : Id , attribute_id ,
( uint16_t ) strtol ( attribute_val_str , NULL , 10 ) ) ;
ESP_RETURN_ON_FALSE ( cmd , ESP_ERR_NO_MEM , TAG , " Failed to alloc memory for write_command " ) ;
return cmd - > send_command ( ) ;
break ;
}
case OnOff : : Attributes : : StartUpOnOff : : Id : {
write_command < uint8_t > * cmd = chip : : Platform : : New < write_command < uint8_t > > (
node_id , endpoint_id , OnOff : : Id , attribute_id , ( uint8_t ) strtol ( attribute_val_str , NULL , 10 ) ) ;
if ( ! cmd ) {
ESP_LOGE ( TAG , " Failed to alloc memory for write_command " ) ;
return ESP_ERR_NO_MEM ;
}
write_command < uint8_t > * cmd = New < write_command < uint8_t > > ( node_id , endpoint_id , OnOff : : Id , attribute_id ,
( uint8_t ) strtol ( attribute_val_str , NULL , 10 ) ) ;
ESP_RETURN_ON_FALSE ( cmd , ESP_ERR_NO_MEM , TAG , " Failed to alloc memory for write_command " ) ;
return cmd - > send_command ( ) ;
break ;
}
@@ -118,12 +118,9 @@ static esp_err_t write_attribute(uint64_t node_id, uint16_t endpoint_id, uint32_
case LevelControl : : Attributes : : OnOffTransitionTime : : Id :
case LevelControl : : Attributes : : OnTransitionTime : : Id :
case LevelControl : : Attributes : : OffTransitionTime : : Id : {
write_command < uint16_t > * cmd = chip : : Platform : : New < write_command < uint16_t > > (
write_command < uint16_t > * cmd = New < write_command < uint16_t > > (
node_id , endpoint_id , LevelControl : : Id , attribute_id , ( uint16_t ) strtol ( attribute_val_str , NULL , 10 ) ) ;
if ( ! cmd ) {
ESP_LOGE ( TAG , " Failed to alloc memory for write_command " ) ;
return ESP_ERR_NO_MEM ;
}
ESP_RETURN_ON_FALSE ( cmd , ESP_ERR_NO_MEM , TAG , " Failed to alloc memory for write_command " ) ;
return cmd - > send_command ( ) ;
break ;
}
@@ -131,12 +128,9 @@ static esp_err_t write_attribute(uint64_t node_id, uint16_t endpoint_id, uint32_
case LevelControl : : Attributes : : DefaultMoveRate : : Id :
case LevelControl : : Attributes : : Options : : Id :
case LevelControl : : Attributes : : StartUpCurrentLevel : : Id : {
write_command < uint8_t > * cmd = chip : : Platform : : New < write_command < uint8_t > > (
node_id , endpoint_id , LevelControl : : Id , attribute_id , ( uint8_t ) strtol ( attribute_val_str , NULL , 10 ) ) ;
if ( ! cmd ) {
ESP_LOGE ( TAG , " Failed to alloc memory for write_command " ) ;
return ESP_ERR_NO_MEM ;
}
write_command < uint8_t > * cmd = New < write_command < uint8_t > > ( node_id , endpoint_id , LevelControl : : Id , attribute_id ,
( uint8_t ) strtol ( attribute_val_str , NULL , 10 ) ) ;
ESP_RETURN_ON_FALSE ( cmd , ESP_ERR_NO_MEM , TAG , " Failed to alloc memory for write_command " ) ;
return cmd - > send_command ( ) ;
break ;
}
@@ -156,22 +150,16 @@ static esp_err_t write_attribute(uint64_t node_id, uint16_t endpoint_id, uint32_
esp_err_t err = ESP_OK ;
switch ( attribute_id ) {
case ColorControl : : Attributes : : StartUpColorTemperatureMireds : : Id : {
write_command < uint16_t > * cmd = chip : : Platform : : New < write_command < uint16_t > > (
write_command < uint16_t > * cmd = New < write_command < uint16_t > > (
node_id , endpoint_id , ColorControl : : Id , attribute_id , ( uint16_t ) strtol ( attribute_val_str , NULL , 10 ) ) ;
if ( ! cmd ) {
ESP_LOGE ( TAG , " Failed to alloc memory for write_command " ) ;
return ESP_ERR_NO_MEM ;
}
ESP_RETURN_ON_FALSE ( cmd , ESP_ERR_NO_MEM , TAG , " Failed to alloc memory for write_command " ) ;
return cmd - > send_command ( ) ;
break ;
}
case ColorControl : : Attributes : : Options : : Id : {
write_command < uint8_t > * cmd = chip : : Platform : : New < write_command < uint8_t > > (
node_id , endpoint_id , ColorControl : : Id , attribute_id , ( uint8_t ) strtol ( attribute_val_str , NULL , 10 ) ) ;
if ( ! cmd ) {
ESP_LOGE ( TAG , " Failed to alloc memory for write_command " ) ;
return ESP_ERR_NO_MEM ;
}
write_command < uint8_t > * cmd = New < write_command < uint8_t > > ( node_id , endpoint_id , ColorControl : : Id , attribute_id ,
( uint8_t ) strtol ( attribute_val_str , NULL , 10 ) ) ;
ESP_RETURN_ON_FALSE ( cmd , ESP_ERR_NO_MEM , TAG , " Failed to alloc memory for write_command " ) ;
return cmd - > send_command ( ) ;
break ;
}
@@ -183,6 +171,287 @@ static esp_err_t write_attribute(uint64_t node_id, uint16_t endpoint_id, uint32_
}
} // namespace color_control
namespace access_control {
using AccessControl : : AuthMode ;
using AccessControl : : Privilege ;
constexpr size_t k_max_acl_entries = CHIP_CONFIG_EXAMPLE_ACCESS_CONTROL_MAX_ENTRIES_PER_FABRIC ;
constexpr size_t k_max_subjects_per_acl = CHIP_CONFIG_EXAMPLE_ACCESS_CONTROL_MAX_SUBJECTS_PER_ENTRY ;
constexpr size_t k_max_targets_per_acl = CHIP_CONFIG_EXAMPLE_ACCESS_CONTROL_MAX_TARGETS_PER_ENTRY ;
using acl_obj = AccessControl : : Structs : : AccessControlEntry : : Type ;
using acl_target_obj = AccessControl : : Structs : : Target : : Type ;
typedef struct acl_attr {
acl_obj acl_array [ k_max_acl_entries ] ;
uint64_t subjects_array [ k_max_acl_entries ] [ k_max_subjects_per_acl ] ;
acl_target_obj targets_array [ k_max_acl_entries ] [ k_max_targets_per_acl ] ;
} acl_attr_t ;
static void acl_attr_free ( void * ctx )
{
acl_attr_t * attr_ptr = reinterpret_cast < acl_attr_t * > ( ctx ) ;
chip : : Platform : : Delete ( attr_ptr ) ;
}
static esp_err_t parse_acl_json ( char * json_str , acl_attr_t * acl , size_t * acl_size )
{
jparse_ctx_t jctx ;
ESP_RETURN_ON_FALSE ( json_parse_start ( & jctx , json_str , strlen ( json_str ) ) = = 0 , ESP_ERR_INVALID_ARG , TAG ,
" ACL json string is wrong " ) ;
size_t acl_index = 0 ;
while ( acl_index < k_max_acl_entries & & json_arr_get_object ( & jctx , acl_index ) = = 0 ) {
int int_val ;
// FabricIndex
if ( json_obj_get_int ( & jctx , " fabricIndex " , & int_val ) = = 0 ) {
acl - > acl_array [ acl_index ] . fabricIndex = int_val ;
}
// Privilege
ESP_RETURN_ON_FALSE ( json_obj_get_int ( & jctx , " privilege " , & int_val ) = = 0 , ESP_ERR_INVALID_ARG , TAG ,
" ACL json string is wrong on privilege " ) ;
acl - > acl_array [ acl_index ] . privilege = Privilege ( int_val ) ;
// AuthMode
ESP_RETURN_ON_FALSE ( json_obj_get_int ( & jctx , " authMode " , & int_val ) = = 0 , ESP_ERR_INVALID_ARG , TAG ,
" ACL json string is wrong on authMode " ) ;
acl - > acl_array [ acl_index ] . authMode = AuthMode ( int_val ) ;
// Subjects
int subjects_num = 0 ;
if ( json_obj_get_array ( & jctx , " subjects " , & subjects_num ) = = 0 & & subjects_num > 0 ) {
ESP_RETURN_ON_FALSE ( subjects_num < = k_max_subjects_per_acl , ESP_ERR_INVALID_ARG , TAG ,
" ACL json string is wrong on subjects length " ) ;
for ( size_t subj_index = 0 ; subj_index < subjects_num ; + + subj_index ) {
int64_t subject_val ;
ESP_RETURN_ON_FALSE ( json_arr_get_int64 ( & jctx , subj_index , & subject_val ) = = 0 , ESP_ERR_INVALID_ARG , TAG ,
" ACL json string is wrong subject value " ) ;
acl - > subjects_array [ acl_index ] [ subj_index ] = subject_val ;
}
acl - > acl_array [ acl_index ] . subjects . SetNonNull ( acl - > subjects_array [ acl_index ] , subjects_num ) ;
json_obj_leave_array ( & jctx ) ;
} else {
acl - > acl_array [ acl_index ] . subjects . SetNull ( ) ;
}
// Targets
int targets_num = 0 ;
if ( json_obj_get_array ( & jctx , " targets " , & targets_num ) = = 0 & & targets_num > 0 ) {
ESP_RETURN_ON_FALSE ( targets_num < = k_max_targets_per_acl , ESP_ERR_INVALID_ARG , TAG ,
" ACL json string is wrong on targets length " ) ;
for ( size_t targ_index = 0 ; targ_index < targets_num ; + + targ_index ) {
ESP_RETURN_ON_FALSE ( json_arr_get_object ( & jctx , targ_index ) = = 0 , ESP_ERR_INVALID_ARG , TAG ,
" Failed to get target at index %d " , targ_index ) ;
int64_t cluster_val , device_type_val ;
int endpoint_val ;
bool exist_cluster , exist_endpoint , exist_device_type ;
exist_cluster = json_obj_get_int64 ( & jctx , " cluster " , & cluster_val ) = = 0 ;
exist_endpoint = json_obj_get_int ( & jctx , " endpoint " , & endpoint_val ) = = 0 ;
exist_device_type = json_obj_get_int64 ( & jctx , " deviceType " , & device_type_val ) = = 0 ;
if ( ( ! exist_cluster & & ! exist_endpoint & & ! exist_device_type ) | |
( exist_endpoint & & exist_device_type ) ) {
ESP_LOGE ( TAG , " ACL json string is wrong targets value, skip " ) ;
json_arr_leave_object ( & jctx ) ;
continue ;
}
// Cluster
if ( exist_cluster ) {
acl - > targets_array [ acl_index ] [ targ_index ] . cluster . SetNonNull ( static_cast < uint32_t > ( cluster_val ) ) ;
} else {
acl - > targets_array [ acl_index ] [ targ_index ] . cluster . SetNull ( ) ;
}
// Endpoint
if ( exist_endpoint ) {
acl - > targets_array [ acl_index ] [ targ_index ] . endpoint . SetNonNull ( static_cast < uint16_t > ( endpoint_val ) ) ;
} else {
acl - > targets_array [ acl_index ] [ targ_index ] . endpoint . SetNull ( ) ;
}
// DeviceType
if ( exist_device_type ) {
acl - > targets_array [ acl_index ] [ targ_index ] . deviceType . SetNonNull (
static_cast < uint32_t > ( device_type_val ) ) ;
} else {
acl - > targets_array [ acl_index ] [ targ_index ] . deviceType . SetNull ( ) ;
}
json_arr_leave_object ( & jctx ) ;
}
acl - > acl_array [ acl_index ] . targets . SetNonNull ( acl - > targets_array [ acl_index ] , targets_num ) ;
json_obj_leave_array ( & jctx ) ;
} else {
acl - > acl_array [ acl_index ] . targets . SetNull ( ) ;
}
// Leave Object
json_arr_leave_object ( & jctx ) ;
acl_index + + ;
}
* acl_size = acl_index ;
return ESP_OK ;
}
// The extension data may be used to store arbitrary TLV-encoded data related to a fabric’ s ACL Entries.
constexpr size_t k_max_extension_entries = CHIP_CONFIG_EXAMPLE_ACCESS_CONTROL_MAX_ENTRIES_PER_FABRIC ;
constexpr size_t k_max_extension_data_len = 128 ;
using extension_obj = AccessControl : : Structs : : ExtensionEntry : : Type ;
typedef struct extension_attr {
extension_obj extension_array [ k_max_extension_entries ] ;
uint8_t data_array [ k_max_extension_entries ] [ k_max_extension_data_len ] ;
} extension_attr_t ;
static void extension_attr_free ( void * ctx )
{
extension_attr_t * attr = reinterpret_cast < extension_attr_t * > ( ctx ) ;
chip : : Platform : : Delete ( attr ) ;
}
static esp_err_t parse_extension_json ( char * json_str , extension_attr_t * extension , size_t * extension_size )
{
jparse_ctx_t jctx ;
ESP_RETURN_ON_FALSE ( json_parse_start ( & jctx , json_str , strlen ( json_str ) ) = = 0 , ESP_ERR_INVALID_ARG , TAG ,
" Extension json string is wrong " ) ;
size_t index = 0 ;
while ( index < k_max_extension_entries & & json_arr_get_object ( & jctx , index ) = = 0 ) {
int fabric_index ;
if ( json_obj_get_int ( & jctx , " fabricIndex " , & fabric_index ) = = 0 ) {
extension - > extension_array [ index ] . fabricIndex = fabric_index ;
}
char data_oct_str [ k_max_extension_data_len * 2 + 1 ] = { 0 } ;
if ( json_obj_get_string ( & jctx , " data " , data_oct_str , k_max_extension_data_len * 2 + 1 ) ! = 0 ) {
ESP_LOGE ( TAG , " Failed to parse the data json octstring " ) ;
return ESP_ERR_INVALID_ARG ;
} else {
size_t data_len = oct_str_to_byte_arr ( data_oct_str , extension - > data_array [ index ] ) ;
ESP_RETURN_ON_FALSE ( data_len > 0 , ESP_ERR_INVALID_ARG , TAG ,
" Failed to convert the data octstring to byte array " ) ;
extension - > extension_array [ index ] . data = ByteSpan ( extension - > data_array [ index ] , data_len ) ;
}
json_arr_leave_object ( & jctx ) ;
index + + ;
}
* extension_size = index ;
return ESP_OK ;
}
static esp_err_t write_attribute ( uint64_t node_id , uint16_t endpoint_id , uint32_t attribute_id , char * attribute_val_str )
{
esp_err_t err = ESP_OK ;
switch ( attribute_id ) {
case AccessControl : : Attributes : : Acl : : Id : {
size_t acl_size = 0 ;
acl_attr_t * attr_val = New < acl_attr_t > ( ) ;
ESP_RETURN_ON_FALSE ( attr_val , ESP_ERR_NO_MEM , TAG , " Failed to alloc acl_attr_t " ) ;
ESP_RETURN_ON_ERROR ( parse_acl_json ( attribute_val_str , attr_val , & acl_size ) , TAG ,
" Failed to parse the acl json string " ) ;
List < acl_obj > access_control_list ( attr_val - > acl_array , acl_size ) ;
write_command < List < acl_obj > > * cmd = New < write_command < List < acl_obj > > > ( node_id , endpoint_id , AccessControl : : Id ,
attribute_id , access_control_list ) ;
ESP_RETURN_ON_FALSE ( cmd , ESP_ERR_NO_MEM , TAG , " Failed to alloc memory for write_command " ) ;
cmd - > set_attribute_free_handler ( acl_attr_free , attr_val ) ;
return cmd - > send_command ( ) ;
break ;
}
case AccessControl : : Attributes : : Extension : : Id : {
size_t extension_size = 0 ;
extension_attr_t * attr_val = New < extension_attr_t > ( ) ;
ESP_RETURN_ON_FALSE ( attr_val , ESP_ERR_NO_MEM , TAG , " Failed to alloc extension_attr_t " ) ;
ESP_RETURN_ON_ERROR ( parse_extension_json ( attribute_val_str , attr_val , & extension_size ) , TAG ,
" Failed to parse the acl json string " ) ;
List < extension_obj > extension_list ( attr_val - > extension_array , extension_size ) ;
write_command < List < extension_obj > > * cmd = New < write_command < List < extension_obj > > > (
node_id , endpoint_id , AccessControl : : Id , attribute_id , extension_list ) ;
cmd - > set_attribute_free_handler ( extension_attr_free , attr_val ) ;
return cmd - > send_command ( ) ;
break ;
}
default :
err = ESP_ERR_NOT_SUPPORTED ;
break ;
}
return err ;
}
} // namespace access_control
namespace binding {
using binding_obj = Binding : : Structs : : TargetStruct : : Type ;
typedef struct binding_attr {
binding_obj binding_array [ CONFIG_MAX_BINDINGS ] ;
} binding_attr_t ;
static void binding_attr_free ( void * ctx )
{
binding_attr_t * attr_ptr = reinterpret_cast < binding_attr_t * > ( ctx ) ;
chip : : Platform : : Delete ( attr_ptr ) ;
}
static esp_err_t parse_binding_json ( char * json_str , binding_attr_t * binding , size_t * binding_size )
{
jparse_ctx_t jctx ;
ESP_RETURN_ON_FALSE ( json_parse_start ( & jctx , json_str , strlen ( json_str ) ) = = 0 , ESP_ERR_INVALID_ARG , TAG ,
" Binding Table json string is wrong " ) ;
size_t index = 0 ;
while ( index < CONFIG_MAX_BINDINGS & & json_arr_get_object ( & jctx , index ) = = 0 ) {
int int_val ;
int64_t int64_val ;
// Fabric
if ( json_obj_get_int ( & jctx , " fabricIndex " , & int_val ) = = 0 ) {
binding - > binding_array [ index ] . fabricIndex = int_val ;
}
if ( json_obj_get_int64 ( & jctx , " node " , & int64_val ) = = 0 ) {
// Unicast Binding
binding - > binding_array [ index ] . node . SetValue ( int64_val ) ;
binding - > binding_array [ index ] . group . ClearValue ( ) ;
ESP_RETURN_ON_FALSE ( json_obj_get_int ( & jctx , " endpoint " , & int_val ) = = 0 , ESP_ERR_INVALID_ARG , TAG ,
" Binding Table json string is wrong " ) ;
binding - > binding_array [ index ] . endpoint . SetValue ( int_val ) ;
ESP_RETURN_ON_FALSE ( json_obj_get_int ( & jctx , " cluster " , & int_val ) = = 0 , ESP_ERR_INVALID_ARG , TAG ,
" Binding Table json string is wrong " ) ;
binding - > binding_array [ index ] . cluster . SetValue ( int_val ) ;
} else if ( json_obj_get_int64 ( & jctx , " group " , & int64_val ) = = 0 ) {
// Group binding
binding - > binding_array [ index ] . group . SetValue ( int64_val ) ;
binding - > binding_array [ index ] . node . ClearValue ( ) ;
binding - > binding_array [ index ] . endpoint . ClearValue ( ) ;
binding - > binding_array [ index ] . cluster . ClearValue ( ) ;
} else {
ESP_LOGE ( TAG , " Binding Table json string is wrong " ) ;
return ESP_ERR_INVALID_ARG ;
}
json_arr_leave_object ( & jctx ) ;
index + + ;
}
* binding_size = index ;
return ESP_OK ;
}
static esp_err_t write_attribute ( uint64_t node_id , uint16_t endpoint_id , uint32_t attribute_id , char * attribute_val_str )
{
esp_err_t err = ESP_OK ;
switch ( attribute_id ) {
case Binding : : Attributes : : Binding : : Id : {
size_t binding_size = 0 ;
binding_attr_t * attr_val = chip : : Platform : : New < binding_attr_t > ( ) ;
ESP_RETURN_ON_FALSE ( attr_val , ESP_ERR_NO_MEM , TAG , " Failed to alloc binding_attr_t " ) ;
ESP_RETURN_ON_ERROR ( parse_binding_json ( attribute_val_str , attr_val , & binding_size ) , TAG ,
" Failed to parse binding json string " ) ;
List < binding_obj > binding_list ( attr_val - > binding_array , binding_size ) ;
write_command < List < binding_obj > > * cmd =
New < write_command < List < binding_obj > > > ( node_id , endpoint_id , Binding : : Id , attribute_id , binding_list ) ;
ESP_RETURN_ON_FALSE ( cmd , ESP_ERR_NO_MEM , TAG , " Failed to alloc memory for write_command " ) ;
cmd - > set_attribute_free_handler ( binding_attr_free , attr_val ) ;
return cmd - > send_command ( ) ;
break ;
}
default :
err = ESP_ERR_NOT_SUPPORTED ;
break ;
}
return err ;
}
} // namespace binding
} // namespace clusters
esp_err_t send_write_attr_command ( uint64_t node_id , uint16_t endpoint_id , uint32_t cluster_id , uint32_t attribute_id ,
@@ -198,6 +467,12 @@ esp_err_t send_write_attr_command(uint64_t node_id, uint16_t endpoint_id, uint32
case ColorControl : : Id :
return clusters : : color_control : : write_attribute ( node_id , endpoint_id , attribute_id , attribute_val_str ) ;
break ;
case AccessControl : : Id :
return clusters : : access_control : : write_attribute ( node_id , endpoint_id , attribute_id , attribute_val_str ) ;
break ;
case Binding : : Id :
return clusters : : binding : : write_attribute ( node_id , endpoint_id , attribute_id , attribute_val_str ) ;
break ;
default :
return ESP_ERR_NOT_SUPPORTED ;
}