diff --git a/examples/bridge-app/asr/BUILD.gn b/examples/bridge-app/asr/BUILD.gn index 19f8263e12bb7c..47a2a13f8fa3ec 100755 --- a/examples/bridge-app/asr/BUILD.gn +++ b/examples/bridge-app/asr/BUILD.gn @@ -72,6 +72,7 @@ asr_executable("bridge_app") { output_name = "chip-asr-bridge-example.out" sources = [ + "${chip_root}/examples/bridge-app/bridge-common/src/bridged-actions-stub.cpp", "${examples_plat_dir}/CHIPDeviceManager.cpp", "${examples_plat_dir}/init_Matter.cpp", "${examples_plat_dir}/init_asrPlatform.cpp", @@ -104,6 +105,7 @@ asr_executable("bridge_app") { "${examples_plat_dir}", "${asr_project_dir}/include", "${chip_root}/src/lib", + "${chip_root}/examples/bridge-app/bridge-common/include", ] defines = [ "ASR_NETWORK_LAYER_BLE=${chip_config_network_layer_ble}" ] diff --git a/examples/bridge-app/asr/src/AppTask.cpp b/examples/bridge-app/asr/src/AppTask.cpp index e792deb629eaf8..67669b20d6bb21 100644 --- a/examples/bridge-app/asr/src/AppTask.cpp +++ b/examples/bridge-app/asr/src/AppTask.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -52,6 +53,9 @@ constexpr EndpointId kNetworkCommissioningEndpointSecondary = 0xFFFE; app::Clusters::NetworkCommissioning::Instance sWiFiNetworkCommissioningInstance(kNetworkCommissioningEndpointMain /* Endpoint Id */, &(NetworkCommissioning::ASRWiFiDriver::GetInstance())); + +std::unique_ptr sActionsDelegateImpl; +std::unique_ptr sActionsServer; } // namespace void NetWorkCommissioningInstInit() @@ -62,6 +66,20 @@ void NetWorkCommissioningInstInit() emberAfEndpointEnableDisable(kNetworkCommissioningEndpointSecondary, false); } +void emberAfActionsClusterInitCallback(EndpointId endpoint) +{ + VerifyOrReturn(endpoint == 1, + ChipLogError(Zcl, "Actions cluster delegate is not implemented for endpoint with id %d.", endpoint)); + VerifyOrReturn(emberAfContainsServer(endpoint, app::Clusters::Actions::Id) == true, + ChipLogError(Zcl, "Endpoint %u does not support Actions cluster.", endpoint)); + VerifyOrReturn(!sActionsDelegateImpl && !sActionsServer); + + sActionsDelegateImpl = std::make_unique(); + sActionsServer = std::make_unique(endpoint, *sActionsDelegateImpl.get()); + + sActionsServer->Init(); +} + static DeviceCallbacks EchoCallbacks; CHIP_ERROR AppTask::StartAppTask() diff --git a/examples/bridge-app/bridge-common/include/bridged-actions-stub.h b/examples/bridge-app/bridge-common/include/bridged-actions-stub.h new file mode 100644 index 00000000000000..bfbb4531ffbf79 --- /dev/null +++ b/examples/bridge-app/bridge-common/include/bridged-actions-stub.h @@ -0,0 +1,80 @@ +/* + * + * Copyright (c) 2025 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace chip { +namespace app { +namespace Clusters { +namespace Actions { +class ActionsDelegateImpl : public Delegate +{ +private: + std::vector kActionList = { + ActionStructStorage(0, CharSpan::fromCharString("TurnOnLight"), ActionTypeEnum::kScene, 0, 0, ActionStateEnum::kInactive), + ActionStructStorage(1, CharSpan::fromCharString("TurnOffLight"), ActionTypeEnum::kScene, 1, 0, ActionStateEnum::kInactive), + ActionStructStorage(2, CharSpan::fromCharString("ToggleLight"), ActionTypeEnum::kScene, 2, 0, ActionStateEnum::kInactive) + }; + + std::vector firstEpList = { 0 }; + std::vector secondEpList = { 0, 1 }; + std::vector thirdEpList = { 1, 2, 3 }; + + std::vector kEndpointList = { + EndpointListStorage(0, CharSpan::fromCharString("On"), EndpointListTypeEnum::kOther, + DataModel::List(firstEpList.data(), firstEpList.size())), + EndpointListStorage(1, CharSpan::fromCharString("Off"), EndpointListTypeEnum::kOther, + DataModel::List(secondEpList.data(), secondEpList.size())), + EndpointListStorage(2, CharSpan::fromCharString("Toggle"), EndpointListTypeEnum::kOther, + DataModel::List(thirdEpList.data(), thirdEpList.size())) + }; + + CHIP_ERROR ReadActionAtIndex(uint16_t index, ActionStructStorage & action) override; + CHIP_ERROR ReadEndpointListAtIndex(uint16_t index, EndpointListStorage & epList) override; + bool HaveActionWithId(uint16_t actionId, uint16_t & actionIndex) override; + + Protocols::InteractionModel::Status HandleInstantAction(uint16_t actionId, Optional invokeId) override; + Protocols::InteractionModel::Status HandleInstantActionWithTransition(uint16_t actionId, uint16_t transitionTime, + Optional invokeId) override; + Protocols::InteractionModel::Status HandleStartAction(uint16_t actionId, Optional invokeId) override; + Protocols::InteractionModel::Status HandleStartActionWithDuration(uint16_t actionId, uint32_t duration, + Optional invokeId) override; + Protocols::InteractionModel::Status HandleStopAction(uint16_t actionId, Optional invokeId) override; + Protocols::InteractionModel::Status HandlePauseAction(uint16_t actionId, Optional invokeId) override; + Protocols::InteractionModel::Status HandlePauseActionWithDuration(uint16_t actionId, uint32_t duration, + Optional invokeId) override; + Protocols::InteractionModel::Status HandleResumeAction(uint16_t actionId, Optional invokeId) override; + Protocols::InteractionModel::Status HandleEnableAction(uint16_t actionId, Optional invokeId) override; + Protocols::InteractionModel::Status HandleEnableActionWithDuration(uint16_t actionId, uint32_t duration, + Optional invokeId) override; + Protocols::InteractionModel::Status HandleDisableAction(uint16_t actionId, Optional invokeId) override; + Protocols::InteractionModel::Status HandleDisableActionWithDuration(uint16_t actionId, uint32_t duration, + Optional invokeId) override; +}; +} // namespace Actions +} // namespace Clusters +} // namespace app +} // namespace chip diff --git a/examples/bridge-app/bridge-common/src/bridged-actions-stub.cpp b/examples/bridge-app/bridge-common/src/bridged-actions-stub.cpp new file mode 100644 index 00000000000000..ed9ac3d82712e0 --- /dev/null +++ b/examples/bridge-app/bridge-common/src/bridged-actions-stub.cpp @@ -0,0 +1,131 @@ +/* + * + * Copyright (c) 2025 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +using namespace chip; +using namespace chip::app; +using namespace chip::app::Clusters; +using namespace chip::app::Clusters::Actions; +using namespace chip::app::Clusters::Actions::Attributes; +using namespace chip::Protocols::InteractionModel; + +CHIP_ERROR ActionsDelegateImpl::ReadActionAtIndex(uint16_t index, ActionStructStorage & action) +{ + if (index >= kActionList.size()) + { + return CHIP_ERROR_PROVIDER_LIST_EXHAUSTED; + } + action = kActionList[index]; + return CHIP_NO_ERROR; +} + +CHIP_ERROR ActionsDelegateImpl::ReadEndpointListAtIndex(uint16_t index, EndpointListStorage & epList) +{ + if (index >= kEndpointList.size()) + { + return CHIP_ERROR_PROVIDER_LIST_EXHAUSTED; + } + epList = kEndpointList[index]; + return CHIP_NO_ERROR; +} + +bool ActionsDelegateImpl::HaveActionWithId(uint16_t actionId, uint16_t & actionIndex) +{ + for (size_t i = 0; i < kEndpointList.size(); i++) + { + if (kActionList[i].actionID == actionId) + { + actionIndex = (uint16_t) i; + return true; + } + } + return false; +} + +Status ActionsDelegateImpl::HandleInstantAction(uint16_t actionId, Optional invokeId) +{ + // Not implemented + return Status::NotFound; +} + +Status ActionsDelegateImpl::HandleInstantActionWithTransition(uint16_t actionId, uint16_t transitionTime, + Optional invokeId) +{ + // Not implemented + return Status::NotFound; +} + +Status ActionsDelegateImpl::HandleStartAction(uint16_t actionId, Optional invokeId) +{ + // Not implemented + return Status::NotFound; +} + +Status ActionsDelegateImpl::HandleStartActionWithDuration(uint16_t actionId, uint32_t duration, Optional invokeId) +{ + // Not implemented + return Status::NotFound; +} + +Status ActionsDelegateImpl::HandleStopAction(uint16_t actionId, Optional invokeId) +{ + // Not implemented + return Status::NotFound; +} + +Status ActionsDelegateImpl::HandlePauseAction(uint16_t actionId, Optional invokeId) +{ + // Not implemented + return Status::NotFound; +} + +Status ActionsDelegateImpl::HandlePauseActionWithDuration(uint16_t actionId, uint32_t duration, Optional invokeId) +{ + // Not implemented + return Status::NotFound; +} + +Status ActionsDelegateImpl::HandleResumeAction(uint16_t actionId, Optional invokeId) +{ + // Not implemented + return Status::NotFound; +} + +Status ActionsDelegateImpl::HandleEnableAction(uint16_t actionId, Optional invokeId) +{ + // Not implemented + return Status::NotFound; +} + +Status ActionsDelegateImpl::HandleEnableActionWithDuration(uint16_t actionId, uint32_t duration, Optional invokeId) +{ + // Not implemented + return Status::NotFound; +} + +Status ActionsDelegateImpl::HandleDisableAction(uint16_t actionId, Optional invokeId) +{ + // Not implemented + return Status::NotFound; +} + +Status ActionsDelegateImpl::HandleDisableActionWithDuration(uint16_t actionId, uint32_t duration, Optional invokeId) +{ + // Not implemented + return Status::NotFound; +} diff --git a/examples/bridge-app/esp32/main/CMakeLists.txt b/examples/bridge-app/esp32/main/CMakeLists.txt index de166919f80038..51f7df9d987959 100644 --- a/examples/bridge-app/esp32/main/CMakeLists.txt +++ b/examples/bridge-app/esp32/main/CMakeLists.txt @@ -20,12 +20,14 @@ get_filename_component(APP_COMMON_GEN_DIR ${CHIP_ROOT}/zzz_generated/app-common/ idf_component_register(PRIV_INCLUDE_DIRS "${CMAKE_CURRENT_LIST_DIR}/include" "${CHIP_ROOT}/examples/providers" + "${CHIP_ROOT}/examples/bridge-app/bridge-common/include" SRC_DIRS "${CMAKE_CURRENT_LIST_DIR}" "${APP_COMMON_GEN_DIR}/attributes" "${APP_COMMON_GEN_DIR}" "${CHIP_ROOT}/examples/platform/esp32/common" - "${CHIP_ROOT}/examples/providers") + "${CHIP_ROOT}/examples/providers" + "${CHIP_ROOT}/examples/bridge-app/bridge-common/src") include(${CHIP_ROOT}/src/app/chip_data_model.cmake) chip_configure_data_model(${COMPONENT_LIB} diff --git a/examples/bridge-app/esp32/main/DeviceCallbacks.cpp b/examples/bridge-app/esp32/main/DeviceCallbacks.cpp index 768771555f3252..4aa92d7f023a58 100644 --- a/examples/bridge-app/esp32/main/DeviceCallbacks.cpp +++ b/examples/bridge-app/esp32/main/DeviceCallbacks.cpp @@ -16,12 +16,6 @@ * limitations under the License. */ -#include -#include -#include -#include -#include -#include #include #include @@ -43,75 +37,3 @@ void AppDeviceCallbacks::PostAttributeChangeCallback(EndpointId endpointId, Clus clusterId, endpointId, attributeId); ESP_LOGI(TAG, "Current free heap: %d\n", heap_caps_get_free_size(MALLOC_CAP_8BIT)); } - -namespace { - -class ActionsAttrAccess : public AttributeAccessInterface -{ -public: - // Register for the Actions cluster on all endpoints. - ActionsAttrAccess() : AttributeAccessInterface(Optional::Missing(), Actions::Id) {} - - CHIP_ERROR Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) override; - -private: - static constexpr uint16_t ClusterRevision = 1; - - CHIP_ERROR ReadActionListAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder); - CHIP_ERROR ReadEndpointListAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder); - CHIP_ERROR ReadSetupUrlAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder); - CHIP_ERROR ReadClusterRevision(EndpointId endpoint, AttributeValueEncoder & aEncoder); -}; - -constexpr uint16_t ActionsAttrAccess::ClusterRevision; - -CHIP_ERROR ActionsAttrAccess::ReadActionListAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder) -{ - // Just return an empty list - return aEncoder.EncodeEmptyList(); -} - -CHIP_ERROR ActionsAttrAccess::ReadEndpointListAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder) -{ - // Just return an empty list - return aEncoder.EncodeEmptyList(); -} - -CHIP_ERROR ActionsAttrAccess::ReadSetupUrlAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder) -{ - static const char SetupUrl[] = "https://example.com"; - return aEncoder.Encode(chip::CharSpan::fromCharString(SetupUrl)); -} - -CHIP_ERROR ActionsAttrAccess::ReadClusterRevision(EndpointId endpoint, AttributeValueEncoder & aEncoder) -{ - return aEncoder.Encode(ClusterRevision); -} - -ActionsAttrAccess gAttrAccess; - -CHIP_ERROR ActionsAttrAccess::Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) -{ - VerifyOrDie(aPath.mClusterId == Actions::Id); - - switch (aPath.mAttributeId) - { - case ActionList::Id: - return ReadActionListAttribute(aPath.mEndpointId, aEncoder); - case EndpointLists::Id: - return ReadEndpointListAttribute(aPath.mEndpointId, aEncoder); - case SetupURL::Id: - return ReadSetupUrlAttribute(aPath.mEndpointId, aEncoder); - case ClusterRevision::Id: - return ReadClusterRevision(aPath.mEndpointId, aEncoder); - default: - break; - } - return CHIP_NO_ERROR; -} -} // anonymous namespace - -void MatterActionsPluginServerInitCallback(void) -{ - AttributeAccessInterfaceRegistry::Instance().Register(&gAttrAccess); -} diff --git a/examples/bridge-app/esp32/main/main.cpp b/examples/bridge-app/esp32/main/main.cpp index 4efb9e4acba57c..5256c93ff85520 100644 --- a/examples/bridge-app/esp32/main/main.cpp +++ b/examples/bridge-app/esp32/main/main.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -59,6 +60,9 @@ chip::DeviceLayer::ESP32DeviceInfoProvider gExampleDeviceInfoProvider; #else chip::DeviceLayer::DeviceInfoProviderImpl gExampleDeviceInfoProvider; #endif // CONFIG_ENABLE_ESP32_DEVICE_INFO_PROVIDER + +std::unique_ptr sActionsDelegateImpl; +std::unique_ptr sActionsServer; } // namespace extern const char TAG[] = "bridge-app"; @@ -395,6 +399,20 @@ static void InitServer(intptr_t context) Span(gLight2DataVersions), 1); } +void emberAfActionsClusterInitCallback(EndpointId endpoint) +{ + VerifyOrReturn(endpoint == 1, + ChipLogError(Zcl, "Actions cluster delegate is not implemented for endpoint with id %d.", endpoint)); + VerifyOrReturn(emberAfContainsServer(endpoint, app::Clusters::Actions::Id) == true, + ChipLogError(Zcl, "Endpoint %u does not support Actions cluster.", endpoint)); + VerifyOrReturn(!sActionsDelegateImpl && !sActionsServer); + + sActionsDelegateImpl = std::make_unique(); + sActionsServer = std::make_unique(endpoint, *sActionsDelegateImpl.get()); + + sActionsServer->Init(); +} + extern "C" void app_main() { // Initialize the ESP NVS layer. diff --git a/examples/bridge-app/telink/CMakeLists.txt b/examples/bridge-app/telink/CMakeLists.txt index e7984bc1332853..6be8546499a60d 100644 --- a/examples/bridge-app/telink/CMakeLists.txt +++ b/examples/bridge-app/telink/CMakeLists.txt @@ -33,7 +33,8 @@ target_include_directories(app PRIVATE ${TELINK_COMMON}/common/include ${TELINK_COMMON}/util/include ${TELINK_COMMON}/app/include - ${TELINK_COMMON}/zephyr_ext) + ${TELINK_COMMON}/zephyr_ext + ${CHIP_ROOT}/examples/bridge-app/bridge-common/include) target_sources(app PRIVATE src/AppTask.cpp @@ -48,7 +49,8 @@ target_sources(app PRIVATE ${TELINK_COMMON}/zephyr_ext/zephyr_key_pool.c ${TELINK_COMMON}/zephyr_ext/zephyr_led_pool.c ${TELINK_COMMON}/zephyr_ext/zephyr_pwm_pool.c - ${TELINK_COMMON}/zephyr_ext/zephyr_ws2812.c) + ${TELINK_COMMON}/zephyr_ext/zephyr_ws2812.c + ${CHIP_ROOT}/examples/bridge-app/bridge-common/src/bridged-actions-stub.cpp) chip_configure_data_model(app ZAP_FILE ${CMAKE_CURRENT_SOURCE_DIR}/../bridge-common/bridge-app.zap diff --git a/examples/bridge-app/telink/src/AppTask.cpp b/examples/bridge-app/telink/src/AppTask.cpp index f8360e8e860965..578558c880ffc0 100644 --- a/examples/bridge-app/telink/src/AppTask.cpp +++ b/examples/bridge-app/telink/src/AppTask.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include LOG_MODULE_DECLARE(app, CONFIG_CHIP_APP_LOG_LEVEL); @@ -30,8 +31,25 @@ LOG_MODULE_DECLARE(app, CONFIG_CHIP_APP_LOG_LEVEL); namespace { bool sTurnedOn; uint8_t sLevel; + +std::unique_ptr sActionsDelegateImpl; +std::unique_ptr sActionsServer; } // namespace +void emberAfActionsClusterInitCallback(chip::EndpointId endpoint) +{ + VerifyOrReturn(endpoint == 1, + ChipLogError(Zcl, "Actions cluster delegate is not implemented for endpoint with id %d.", endpoint)); + VerifyOrReturn(emberAfContainsServer(endpoint, chip::app::Clusters::Actions::Id) == true, + ChipLogError(Zcl, "Endpoint %u does not support Actions cluster.", endpoint)); + VerifyOrReturn(!sActionsDelegateImpl && !sActionsServer); + + sActionsDelegateImpl = std::make_unique(); + sActionsServer = std::make_unique(endpoint, *sActionsDelegateImpl.get()); + + sActionsServer->Init(); +} + AppTask AppTask::sAppTask; #include