Skip to content

Commit

Permalink
Pull request #502: UIC-2846: emulate attribute IdentifyType
Browse files Browse the repository at this point in the history
Merge in WMN_TOOLS/matter from feature/UIC-2846_Emulate_attribute_IdentifyType_for_spec_compliance to silabs

Squashed commit of the following:

commit 6cda15c319dd762e38f7d78de2bb6d25da6fee82
Author: Dennis Jensen <Dennis.Jensen@silabs.com>
Date:   Tue Jan 17 14:29:30 2023 +0100

    UIC-2846: emulate attribute IdentifyType

    Changes:
    * Added an interface for registering emulators for specific clusters.
    * Made two data variables/schemes in the cluster emulator for keeping control
    of clusters, attributes and commands to emulate.
    * Added unit tests of the cluster emulator. Problems with encoding, so
    that is not fully tested reading attributes through the emulator.
  • Loading branch information
unify-automated authored and jmartinez-silabs committed Apr 25, 2024
1 parent 1524843 commit 3564345
Show file tree
Hide file tree
Showing 11 changed files with 470 additions and 20 deletions.
2 changes: 2 additions & 0 deletions silabs_examples/unify-matter-bridge/linux/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ config("unify-config") {
include_dirs = [
"src",
"src/cluster_translator",
"src/cluster_translator/emulations",
"src/matter_node_state_monitor",
"src/matter_wrappers",
"src/device_type_mapper",
Expand All @@ -53,6 +54,7 @@ static_library("unify-matter-bridge-lib") {
"src/cluster_translator/group_command_translator.cpp",
"src/cluster_translator/group_translator.cpp",
"src/cluster_translator/cluster_emulator.cpp",
"src/cluster_translator/emulations/emulate_identify.cpp",
"src/demo_uic_cli.cpp",
"src/device_type_mapper/matter_device_translator.cpp",
"src/device_type_mapper/matter_device_type_selection.cpp",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "cluster_revision_table.hpp"
#include "sl_log.h"
#include <attribute_state_cache.hpp>

#define LOG_TAG "cluster_emulator"

namespace unify::matter_bridge {
Expand All @@ -26,7 +27,7 @@ namespace unify::matter_bridge {
using namespace chip::app;
using namespace chip::app::Clusters;

static uint32_t read_cluster_revision(const ConcreteReadAttributePath & aPath)
uint32_t ClusterEmulator::read_cluster_revision(const ConcreteReadAttributePath & aPath) const
{
if (zap_cluster_revisions.count(aPath.mClusterId))
{
Expand All @@ -38,8 +39,9 @@ static uint32_t read_cluster_revision(const ConcreteReadAttributePath & aPath)
}
}

static uint32_t read_feature_map_revision(const ConcreteReadAttributePath & aPath)
uint32_t ClusterEmulator::read_feature_map_revision(const ConcreteReadAttributePath & aPath) const
{
sl_log_debug(LOG_TAG, "Reading feature map for cluster %d", aPath.mClusterId);
switch (aPath.mClusterId)
{
case ColorControl::Id: {
Expand All @@ -57,6 +59,7 @@ static uint32_t read_feature_map_revision(const ConcreteReadAttributePath & aPat
}
break;
case OnOff::Id:
sl_log_debug(LOG_TAG, "Returning feature map for OnOff %d", ON_OFF_LIGHTING_FEATURE_MAP_MASK);
return ON_OFF_LIGHTING_FEATURE_MAP_MASK;
case LevelControl::Id:
/// Check if OnOff is supported
Expand All @@ -70,19 +73,33 @@ static uint32_t read_feature_map_revision(const ConcreteReadAttributePath & aPat
}

void ClusterEmulator::add_emulated_commands_and_attributes(
const std::unordered_map<std::string, node_state_monitor::cluster> & unify_clusters,
matter_cluster_builder & cluster_builder) const
const node_state_monitor::cluster & unify_cluster,
matter_cluster_builder & cluster_builder)
{
// We always need to add the feature map and cluster
cluster_builder.attributes.push_back(EmberAfAttributeMetadata{ ZCL_FEATURE_MAP_SERVER_ATTRIBUTE_ID, ZCL_BITMAP32_ATTRIBUTE_TYPE,
4, ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE), ZAP_EMPTY_DEFAULT() });
cluster_builder.attributes.push_back(EmberAfAttributeMetadata{ ZCL_CLUSTER_REVISION_SERVER_ATTRIBUTE_ID,
ZCL_INT16U_ATTRIBUTE_TYPE, 2,
ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE), ZAP_EMPTY_DEFAULT() });

// Add emulation for commands and attributes for the cluster
auto it = cluster_emulators_string_map.find(unify_cluster.cluster_name);
if (it != cluster_emulators_string_map.end()) {
auto emulated_result = it->second->emulate(unify_cluster, cluster_builder, cluster_emulators_attribute_id_map, cluster_emulators_command_id_map);
if (emulated_result != CHIP_NO_ERROR) {
sl_log_error(LOG_TAG, "Failed to add emulated commands and attributes for cluster %s", unify_cluster.cluster_name.c_str());
}
}
}

bool ClusterEmulator::is_command_emulated(const ConcreteCommandPath &) const
{
bool ClusterEmulator::is_command_emulated(const ConcreteCommandPath & cPath) const
{
auto it = cluster_emulators_command_id_map.find(cPath.mClusterId);
if (it != cluster_emulators_command_id_map.end())
{
return it->second.find(cPath.mCommandId) != it->second.end();
}
return false;
}

Expand All @@ -99,33 +116,56 @@ bool ClusterEmulator::is_attribute_emulated(const ConcreteAttributePath & aPath)
;
}

auto it = cluster_emulators_attribute_id_map.find(aPath.mClusterId);
if (it != cluster_emulators_attribute_id_map.end())
{
return it->second.find(aPath.mAttributeId) != it->second.end();
}

return false;
}

CHIP_ERROR ClusterEmulator::invoke_command(CommandHandlerInterface::HandlerContext & handlerContext) const
{
if (is_command_emulated(handlerContext.mRequestPath))
{
return cluster_emulators_command_id_map.at(handlerContext.mRequestPath.mClusterId).at(handlerContext.mRequestPath.mCommandId)->command(handlerContext);
}

return CHIP_ERROR_NOT_IMPLEMENTED;
}

CHIP_ERROR ClusterEmulator::read_attribute(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) const
CHIP_ERROR ClusterEmulator::read_attribute(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder)
{
sl_log_debug(LOG_TAG, "Reading attribute %d", aPath.mAttributeId);
switch (aPath.mAttributeId)
{
case 0xFFFD: // Cluster Revision
return aEncoder.Encode(read_cluster_revision(aPath));
case 0xFFFC: // FeatureMap
return aEncoder.Encode(read_feature_map_revision(aPath));
case ZCL_CLUSTER_REVISION_SERVER_ATTRIBUTE_ID: // Cluster Revision
return aEncoder.Encode(this->read_cluster_revision(aPath));
case ZCL_FEATURE_MAP_SERVER_ATTRIBUTE_ID: // FeatureMap
return aEncoder.Encode(this->read_feature_map_revision(aPath));
case 0xFFFE: // EventList
return aEncoder.Encode(0);
default:;
;
}

sl_log_debug(LOG_TAG, "Cluster specific attribute emulation attribute id %d for cluster id", aPath.mAttributeId, aPath.mClusterId);
if (is_attribute_emulated(aPath))
{
return cluster_emulators_attribute_id_map.at(aPath.mClusterId).at(aPath.mAttributeId)->read_attribute(aPath, aEncoder);
}

return CHIP_ERROR_INVALID_ARGUMENT;
}

CHIP_ERROR ClusterEmulator::write_attribute(const ConcreteDataAttributePath & aPath, AttributeValueDecoder & aDecoder) const
{
if (is_attribute_emulated(aPath))
{
return cluster_emulators_attribute_id_map.at(aPath.mClusterId).at(aPath.mAttributeId)->write_attribute(aPath, aDecoder);
}

return CHIP_ERROR_NOT_IMPLEMENTED;
}
} // namespace unify::matter_bridge
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@

#include "matter_endpoint_builder.hpp"
#include "unify_node_state_monitor.hpp"

// Emulation of commands and attributes
#include "emulator.hpp"
#include "emulate_identify.hpp"


namespace unify::matter_bridge {

/**
Expand All @@ -28,15 +34,18 @@ namespace unify::matter_bridge {
class ClusterEmulator
{
public:
ClusterEmulator() {
cluster_emulators_string_map["Identify"] = new EmulateIdentify();
};

/**
* @brief Add command and attributes to the clusters on the endpoint
*
* This function will all the commands and clusters to endpoint descriptor
* which the endpoint_builder holds. Which commands an attributes are
* emulated can be checked with is_command_emulated and is_attribute_emulated
*/
void add_emulated_commands_and_attributes(const std::unordered_map<std::string, node_state_monitor::cluster> & unify_clusters,
matter_cluster_builder &) const;
void add_emulated_commands_and_attributes(const node_state_monitor::cluster & unify_clusters, matter_cluster_builder &);

/**
* @brief Check if a command is emulated
Expand All @@ -58,10 +67,10 @@ class ClusterEmulator
* @brief Execute an emulated command
*
* @param handlerContext
* @return
* @return
* - CHIP_ERROR_OK if the command was successfully emulated.
* - CHIP_ERROR_NOT_IMPLEMENTED If the command is not emulated
*
*
*/
CHIP_ERROR invoke_command(chip::app::CommandHandlerInterface::HandlerContext & handlerContext) const;

Expand All @@ -75,20 +84,29 @@ class ClusterEmulator
* - CHIP_ERROR_NOT_IMPLEMENTED If the attribute is not emulated
*/
CHIP_ERROR read_attribute(const chip::app::ConcreteReadAttributePath & aPath,
chip::app::AttributeValueEncoder & aEncoder) const;
chip::app::AttributeValueEncoder & aEncoder);

/**
* @brief Write an emulated attribute
*
* @param aPath
* @param aDecoder
* @return
* @return
* - CHIP_ERROR_OK write was successfully emulated.
* - CHIP_ERROR_WRITE_FAILED the attribute is not writable.
* - CHIP_ERROR_NOT_IMPLEMENTED If the attribute is not emulated
*/
CHIP_ERROR write_attribute(const chip::app::ConcreteDataAttributePath & aPath,
chip::app::AttributeValueDecoder & aDecoder) const;

private:
// Emulation functions
uint32_t read_feature_map_revision(const ConcreteReadAttributePath & aPath) const;
uint32_t read_cluster_revision(const ConcreteReadAttributePath & aPath) const;

std::map<chip::ClusterId, std::map<chip::AttributeId, EmulatorInterface *>> cluster_emulators_attribute_id_map;
std::map<chip::ClusterId, std::map<chip::CommandId, EmulatorInterface *>> cluster_emulators_command_id_map;
std::map<std::string, EmulatorInterface *> cluster_emulators_string_map;
};

} // namespace unify::matter_bridge
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/******************************************************************************
* # License
* <b>Copyright 2023 Silicon Laboratories Inc. www.silabs.com</b>
******************************************************************************
* The licensor of this software is Silicon Laboratories Inc. Your use of this
* software is governed by the terms of Silicon Labs Master Software License
* Agreement (MSLA) available at
* www.silabs.com/about-us/legal/master-software-license-agreement. This
* software is distributed to you in Source Code format and is governed by the
* sections of the MSLA applicable to Source Code.
*
*****************************************************************************/

#include "emulate_identify.hpp"

// UIC
#include "sl_log.h"

// Matter
#include <app-common/zap-generated/cluster-enums.h>

// Standard library
#include <map>

namespace unify::matter_bridge {

using namespace chip::app;
using namespace chip::app::Clusters;

#define LOG_TAG "EmulateIdentify"

CHIP_ERROR EmulateIdentify::emulate(
const node_state_monitor::cluster & unify_cluster, matter_cluster_builder & cluster_builder,
std::map<chip::ClusterId, std::map<chip::AttributeId, EmulatorInterface *>> & emulation_attribute_handler_map,
std::map<chip::ClusterId, std::map<chip::CommandId, EmulatorInterface *>> & emulation_command_handler)
{
// Identify cluster emulation handler registered for IdentifyType attribute
sl_log_debug(LOG_TAG, "Emulating IdentifyType attribute for Identify cluster");
emulation_attribute_handler_map[Identify::Id][Identify::Attributes::IdentifyType::Id] = this;

// Add IdentifyType attribute to the matter cluster
cluster_builder.attributes.push_back(EmberAfAttributeMetadata{ Identify::Attributes::IdentifyType::Id, ZCL_ENUM8_ATTRIBUTE_ID,
1, ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE), ZAP_EMPTY_DEFAULT() });

return CHIP_NO_ERROR;
}

CHIP_ERROR EmulateIdentify::read_attribute(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder)
{
sl_log_debug(LOG_TAG, "Read IdentifyType attribute");

// IdentifyType is a mandatory attribute we default it to None
if (aPath.mAttributeId == Identify::Attributes::IdentifyType::Id)
{
return aEncoder.Encode(Identify::IdentifyIdentifyType::EMBER_ZCL_IDENTIFY_IDENTIFY_TYPE_NONE);
}

sl_log_warning(LOG_TAG, "Emulation identify activated for unknown attribute id %d under cluster id %d", aPath.mAttributeId,
aPath.mClusterId);
return CHIP_ERROR_INVALID_ARGUMENT;
}

} // namespace unify::matter_bridge
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/******************************************************************************
* # License
* <b>Copyright 2023 Silicon Laboratories Inc. www.silabs.com</b>
******************************************************************************
* The licensor of this software is Silicon Laboratories Inc. Your use of this
* software is governed by the terms of Silicon Labs Master Software License
* Agreement (MSLA) available at
* www.silabs.com/about-us/legal/master-software-license-agreement. This
* software is distributed to you in Source Code format and is governed by the
* sections of the MSLA applicable to Source Code.
*
*****************************************************************************/

#ifndef EMULATE_IDENTIFY_HPP
#define EMULATE_IDENTIFY_HPP

// Emulator interface
#include "emulator.hpp"

namespace unify::matter_bridge {

using namespace chip::app;
using namespace chip::app::Clusters;

class EmulateIdentify : public EmulatorInterface
{
public:
/**
* @brief Emulate Identify cluster this will emulate defined commands and
* attributes
*
* @param unify_cluster
* @param cluster_builder
* @param emulation_handler_map
* @return CHIP_ERROR
*/
CHIP_ERROR
emulate(const node_state_monitor::cluster & unify_cluster, matter_cluster_builder & cluster_builder,
std::map<chip::ClusterId, std::map<chip::AttributeId, EmulatorInterface *>> & emulation_attribute_handler_map,
std::map<chip::ClusterId, std::map<chip::CommandId, EmulatorInterface *>> & emulation_command_handler) override;

/**
* @brief Read the emulated IdentifyType attribute
*
* @param aPath
* @param aEncoder
* @return CHIP_ERROR
*/
CHIP_ERROR read_attribute(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) override;
};

} // namespace unify::matter_bridge

#endif // EMULATE_IDENTIFY_HPP
Loading

0 comments on commit 3564345

Please sign in to comment.