client: Use EncodableToTLV class for encoding command data field and attribute value

This commit is contained in:
WanqQixiang
2024-08-15 17:44:25 +08:00
parent 652b0e7829
commit 37ad275215
7 changed files with 105 additions and 85 deletions
+39 -47
View File
@@ -33,6 +33,7 @@
#include "app/CommandPathParams.h"
#include "app/CommandSender.h"
#include "app/InteractionModelEngine.h"
#include "app/data-model/EncodableToTLV.h"
using namespace chip::app::Clusters;
using chip::DeviceProxy;
@@ -220,6 +221,8 @@ void binding_init()
}
namespace interaction {
using chip::app::DataModel::EncodableToTLV;
namespace invoke {
using command_data_tag = chip::app::CommandDataIB::Tag;
@@ -230,6 +233,22 @@ esp_err_t send_request(void *ctx, peer_device_t *remote_device, const CommandPat
const char *command_data_json_str, custom_command_callback::on_success_callback_t on_success,
custom_command_callback::on_error_callback_t on_error,
const Optional<uint16_t> &timed_invoke_timeout_ms, const Optional<Timeout> &response_timeout)
{
custom_encodable_type type(command_data_json_str, custom_encodable_type::interaction_type::k_invoke_cmd);
return send_request(ctx, remote_device, command_path, type, on_success, on_error, timed_invoke_timeout_ms, response_timeout);
}
esp_err_t send_group_request(const uint8_t fabric_index, const CommandPathParams &command_path,
const char *command_data_json_str)
{
custom_encodable_type type(command_data_json_str, custom_encodable_type::interaction_type::k_invoke_cmd);
return send_group_request(fabric_index, command_path, type);
}
esp_err_t send_request(void *ctx, peer_device_t *remote_device, const CommandPathParams &command_path,
const EncodableToTLV &encodable, custom_command_callback::on_success_callback_t on_success,
custom_command_callback::on_error_callback_t on_error,
const Optional<uint16_t> &timed_invoke_timeout_ms, const Optional<Timeout> &response_timeout)
{
if (!remote_device->GetSecureSession().HasValue() || remote_device->GetSecureSession().Value()->IsGroupSession()) {
ESP_LOGE(TAG, "Invalid Session Type");
@@ -256,26 +275,8 @@ esp_err_t send_request(void *ctx, peer_device_t *remote_device, const CommandPat
ESP_LOGE(TAG, "No memory for command sender");
return ESP_ERR_NO_MEM;
}
chip::app::CommandSender::PrepareCommandParameters prepare_command_params;
if (command_sender->PrepareCommand(command_path, prepare_command_params) != CHIP_NO_ERROR) {
ESP_LOGE(TAG, "Failed to prepare command");
return ESP_FAIL;
}
TLVWriter *writer = command_sender->GetCommandDataIBTLVWriter();
if (writer == nullptr) {
ESP_LOGE(TAG, "No TLV writer in command sender");
return ESP_ERR_INVALID_STATE;
}
esp_err_t err = json_to_tlv(command_data_json_str, *writer, ContextTag(command_data_tag::kFields));
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to convert json string to TLV");
return err;
}
chip::app::CommandSender::FinishCommandParameters finish_command_params(timed_invoke_timeout_ms);
if (command_sender->FinishCommand(finish_command_params) != CHIP_NO_ERROR) {
ESP_LOGE(TAG, "Failed to finish command");
return ESP_FAIL;
}
chip::app::CommandSender::AddRequestDataParameters add_request_data_params(timed_invoke_timeout_ms);
command_sender->AddRequestData(command_path, encodable, add_request_data_params);
if (command_sender->SendCommandRequest(remote_device->GetSecureSession().Value(), response_timeout) !=
CHIP_NO_ERROR) {
ESP_LOGE(TAG, "Failed to send command request");
@@ -287,7 +288,7 @@ esp_err_t send_request(void *ctx, peer_device_t *remote_device, const CommandPat
}
esp_err_t send_group_request(const uint8_t fabric_index, const CommandPathParams &command_path,
const char *command_data_json_str)
const EncodableToTLV &encodeable)
{
if (!command_path.mFlags.Has(chip::app::CommandPathFlags::kGroupIdValid)) {
ESP_LOGE(TAG, "Invalid CommandPathFlags");
@@ -301,26 +302,8 @@ esp_err_t send_group_request(const uint8_t fabric_index, const CommandPathParams
ESP_LOGE(TAG, "No memory for command sender");
return ESP_ERR_NO_MEM;
}
chip::app::CommandSender::PrepareCommandParameters prepare_command_params;
if (command_sender->PrepareCommand(command_path, prepare_command_params) != CHIP_NO_ERROR) {
ESP_LOGE(TAG, "Failed to prepare command");
return ESP_FAIL;
}
TLVWriter *writer = command_sender->GetCommandDataIBTLVWriter();
if (writer == nullptr) {
ESP_LOGE(TAG, "No TLV writer in command sender");
return ESP_ERR_INVALID_STATE;
}
esp_err_t err = json_to_tlv(command_data_json_str, *writer, ContextTag(command_data_tag::kFields));
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to convert json string to TLV");
return err;
}
chip::app::CommandSender::FinishCommandParameters finish_command_params;
if (command_sender->FinishCommand(finish_command_params) != CHIP_NO_ERROR) {
ESP_LOGE(TAG, "Failed to finish command");
return ESP_FAIL;
}
chip::app::CommandSender::AddRequestDataParameters add_request_data_params;
command_sender->AddRequestData(command_path, encodeable, add_request_data_params);
if (command_sender->SendGroupCommandRequest(SessionHandle(session)) != CHIP_NO_ERROR) {
ESP_LOGE(TAG, "Failed to send command request");
return ESP_FAIL;
@@ -545,7 +528,7 @@ private:
WriteClient::Callback &m_callback;
};
static esp_err_t encode_attribute_value(uint8_t *encoded_buf, size_t encoded_buf_size, const char *attr_val_json_str,
static esp_err_t encode_attribute_value(uint8_t *encoded_buf, size_t encoded_buf_size, const EncodableToTLV &encodable,
TLVReader &out_reader)
{
TLVWriter writer;
@@ -554,9 +537,9 @@ static esp_err_t encode_attribute_value(uint8_t *encoded_buf, size_t encoded_buf
esp_err_t err = ESP_OK;
writer.Init(encoded_buf, encoded_buf_size);
if ((err = json_to_tlv(attr_val_json_str, writer, chip::TLV::AnonymousTag())) != ESP_OK) {
ESP_LOGE(TAG, "Failed to parse attribute value");
return err;
if (encodable.EncodeTo(writer, chip::TLV::AnonymousTag()) != CHIP_NO_ERROR) {
ESP_LOGE(TAG, "Failed to encode attribute value");
return ESP_FAIL;
}
if (writer.Finalize() != CHIP_NO_ERROR) {
ESP_LOGE(TAG, "Failed to finalize tlv writer");
@@ -584,7 +567,7 @@ static esp_err_t encode_attribute_value(uint8_t *encoded_buf, size_t encoded_buf
}
esp_err_t send_request(client::peer_device_t *remote_device, AttributePathParams &attr_path,
const char *attr_val_json_str, WriteClient::Callback &callback,
const chip::app::DataModel::EncodableToTLV &encodable, WriteClient::Callback &callback,
const chip::Optional<uint16_t> &timeout_ms)
{
esp_err_t err = ESP_OK;
@@ -617,7 +600,7 @@ esp_err_t send_request(client::peer_device_t *remote_device, AttributePathParams
return ESP_ERR_NO_MEM;
}
TLVReader attr_val_reader;
err = encode_attribute_value(encoded_buf.Get(), k_encoded_buf_size, attr_val_json_str, attr_val_reader);
err = encode_attribute_value(encoded_buf.Get(), k_encoded_buf_size, encodable, attr_val_reader);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to encode attribute value to a TLV reader");
return err;
@@ -634,6 +617,15 @@ esp_err_t send_request(client::peer_device_t *remote_device, AttributePathParams
write_client.release();
client_deleter_callback.release();
return ESP_OK;
}
esp_err_t send_request(client::peer_device_t *remote_device, AttributePathParams &attr_path,
const char *attr_val_json_str, WriteClient::Callback &callback,
const chip::Optional<uint16_t> &timeout_ms)
{
custom_encodable_type type(attr_val_json_str, custom_encodable_type::interaction_type::k_write_attr);
return send_request(remote_device, attr_path, type, callback, timeout_ms);
}
} // namespace write
+58
View File
@@ -14,9 +14,13 @@
#pragma once
#include <json_to_tlv.h>
#include <app-common/zap-generated/cluster-objects.h>
#include <app/data-model/EncodableToTLV.h>
#include <cassert>
#include <esp_err.h>
#include <esp_matter_core.h>
#include <string.h>
namespace esp_matter {
namespace client {
@@ -35,6 +39,44 @@ using chip::Messaging::ExchangeManager;
using chip::System::Clock::Timeout;
using chip::TLV::TLVReader;
using client::peer_device_t;
using chip::app::DataModel::EncodableToTLV;
class custom_encodable_type : public EncodableToTLV
{
public:
const char *k_empty_command_data = "{}";
const char *k_null_attribute_data = "null";
enum interaction_type {
k_invoke_cmd = 0,
k_write_attr,
};
custom_encodable_type(const char *json_str, interaction_type usage)
{
if (json_str) {
m_json_str = strdup(json_str);
} else {
if (usage == k_invoke_cmd) {
m_json_str = strdup("{}");
} else if (usage == k_write_attr) {
m_json_str = strdup("null");
}
}
assert(m_json_str);
}
~custom_encodable_type() { free(m_json_str); }
CHIP_ERROR EncodeTo(chip::TLV::TLVWriter & writer, chip::TLV::Tag tag) const override
{
if (json_to_tlv(m_json_str, writer, tag) != ESP_OK) {
return CHIP_ERROR_INTERNAL;
}
return CHIP_NO_ERROR;
}
private:
char *m_json_str = NULL;
};
/** Command invoke APIs
*
@@ -108,6 +150,18 @@ esp_err_t send_request(void *ctx, peer_device_t *remote_device, const CommandPat
esp_err_t send_group_request(const uint8_t fabric_index, const CommandPathParams &command_path,
const char *command_data_json_str);
esp_err_t send_request(void *ctx, peer_device_t *remote_device, const CommandPathParams &command_path,
const chip::app::DataModel::EncodableToTLV &encodable,
custom_command_callback::on_success_callback_t on_success,
custom_command_callback::on_error_callback_t on_error,
const Optional<uint16_t> &timed_invoke_timeout_ms,
const Optional<Timeout> &response_timeout = chip::NullOptional);
esp_err_t send_group_request(const uint8_t fabric_index, const CommandPathParams &command_path,
const chip::app::DataModel::EncodableToTLV &encodable);
} // namespace invoke
/** Attribute/event read API
@@ -127,6 +181,10 @@ namespace write {
esp_err_t send_request(client::peer_device_t *remote_device, AttributePathParams &attr_path,
const char *attr_val_json_str, WriteClient::Callback &callback,
const chip::Optional<uint16_t> &timeout_ms);
esp_err_t send_request(client::peer_device_t *remote_device, AttributePathParams &attr_path,
const chip::app::DataModel::EncodableToTLV &encodable, WriteClient::Callback &callback,
const chip::Optional<uint16_t> &timeout_ms);
} // namespace write
namespace subscribe {
-8
View File
@@ -20,14 +20,6 @@ menu "ESP Matter Controller"
help
Enable the matter commissioner in the ESP Matter controller.
config ESP_MATTER_CONTROLLER_JSON_STRING_BUFFER_LEN
int "Max JSON string buffer length"
depends on ESP_MATTER_CONTROLLER_ENABLE
default 1024
help
Max JSON string buffer length. This buffer will be used to store the command data field
for cluster-invoked command or attribute value for write-attribute command.
choice ESP_MATTER_COMMISSIONER_ATTESTATION_TRUST_STORE
prompt "Attestation Trust Store"
depends on ESP_MATTER_COMMISSIONER_ENABLE
@@ -259,10 +259,6 @@ esp_err_t send_invoke_cluster_command(uint64_t destination_id, uint16_t endpoint
uint32_t command_id, const char *command_data_field,
chip::Optional<uint16_t> timed_invoke_timeout_ms)
{
if (command_data_field && strlen(command_data_field) >= k_command_data_field_buffer_size) {
ESP_LOGE(TAG, "The command data field buffer is too small for this command, please increase the buffer size");
return ESP_ERR_INVALID_ARG;
}
cluster_command *cmd = chip::Platform::New<cluster_command>(destination_id, endpoint_id, cluster_id, command_id,
command_data_field, timed_invoke_timeout_ms);
if (!cmd) {
@@ -31,9 +31,7 @@ using chip::Messaging::ExchangeManager;
using chip::TLV::TLVReader;
using esp_matter::client::peer_device_t;
using esp_matter::client::interaction::invoke::custom_command_callback;
constexpr char k_empty_command_data_field[] = "{}";
constexpr size_t k_command_data_field_buffer_size = CONFIG_ESP_MATTER_CONTROLLER_JSON_STRING_BUFFER_LEN;
using esp_matter::client::interaction::custom_encodable_type;
/** Cluster command class to send an invoke interaction command to a server **/
class cluster_command {
@@ -47,19 +45,13 @@ public:
, m_endpoint_id(endpoint_id)
, m_cluster_id(cluster_id)
, m_command_id(command_id)
, m_command_data_field(command_data_field, custom_encodable_type::interaction_type::k_invoke_cmd)
, m_timed_invoke_timeout_ms(timed_invoke_timeout_ms)
, on_device_connected_cb(on_device_connected_fcn, this)
, on_device_connection_failure_cb(on_device_connection_failure_fcn, this)
, on_success_cb(on_success)
, on_error_cb(on_error)
{
if (command_data_field) {
strncpy(m_command_data_field, command_data_field, k_command_data_field_buffer_size - 1);
m_command_data_field[strnlen(command_data_field, k_command_data_field_buffer_size - 1)] = 0;
} else {
strcpy(m_command_data_field, k_empty_command_data_field);
m_command_data_field[strlen(k_empty_command_data_field)] = 0;
}
}
~cluster_command() {}
@@ -73,7 +65,7 @@ private:
uint16_t m_endpoint_id;
uint32_t m_cluster_id;
uint32_t m_command_id;
char m_command_data_field[k_command_data_field_buffer_size];
custom_encodable_type m_command_data_field;
chip::Optional<uint16_t> m_timed_invoke_timeout_ms;
static void on_device_connected_fcn(void *context, ExchangeManager &exchangeMgr,
@@ -46,7 +46,7 @@ void write_command::on_device_connected_fcn(void *context, ExchangeManager &exch
{
write_command *cmd = (write_command *)context;
chip::OperationalDeviceProxy device_proxy(&exchangeMgr, sessionHandle);
esp_err_t err = interaction::write::send_request(&device_proxy, cmd->m_attr_path, cmd->m_attr_val_str,
esp_err_t err = interaction::write::send_request(&device_proxy, cmd->m_attr_path, cmd->m_attr_val,
cmd->m_chunked_callback, chip::NullOptional);
if (err != ESP_OK) {
chip::Platform::Delete(cmd);
@@ -33,9 +33,7 @@ using chip::app::WriteClient;
using chip::Messaging::ExchangeManager;
using chip::TLV::TLVElementType;
using esp_matter::client::peer_device_t;
constexpr char *k_null_attribute_val_str = "null";
constexpr size_t k_attr_val_str_buf_size = CONFIG_ESP_MATTER_CONTROLLER_JSON_STRING_BUFFER_LEN;
using esp_matter::client::interaction::custom_encodable_type;
/** Write command class to send a write interaction command to a server **/
class write_command : public WriteClient::Callback {
@@ -46,17 +44,9 @@ public:
: m_node_id(node_id)
, m_attr_path(endpoint_id, cluster_id, attribute_id)
, m_chunked_callback(this)
, m_attr_val(attribute_val_str, custom_encodable_type::interaction_type::k_write_attr)
, on_device_connected_cb(on_device_connected_fcn, this)
, on_device_connection_failure_cb(on_device_connection_failure_fcn, this)
{
if (attribute_val_str) {
strncpy(m_attr_val_str, attribute_val_str, k_attr_val_str_buf_size - 1);
m_attr_val_str[strnlen(attribute_val_str, k_attr_val_str_buf_size - 1)] = 0;
} else {
strcpy(m_attr_val_str, k_null_attribute_val_str);
m_attr_val_str[strlen(k_null_attribute_val_str)] = 0;
}
}
, on_device_connection_failure_cb(on_device_connection_failure_fcn, this) {}
~write_command() {}
@@ -86,7 +76,7 @@ private:
uint64_t m_node_id;
AttributePathParams m_attr_path;
ChunkedWriteCallback m_chunked_callback;
char m_attr_val_str[k_attr_val_str_buf_size];
custom_encodable_type m_attr_val;
static void on_device_connected_fcn(void *context, ExchangeManager &exchangeMgr,
const SessionHandle &sessionHandle);