diff --git a/.github/workflows/examples-cc13xx_26xx.yaml b/.github/workflows/examples-cc13xx_26xx.yaml index b486415dbcc1ee..53c813d0b4c433 100644 --- a/.github/workflows/examples-cc13xx_26xx.yaml +++ b/.github/workflows/examples-cc13xx_26xx.yaml @@ -105,7 +105,7 @@ jobs: run: | .environment/pigweed-venv/bin/python3 scripts/tools/memory/gh_sizes.py \ cc13x4_26x4 LP_EM_CC1354P10_6 lighting-app \ - out/artifacts/ti-cc13x4_26x4-lighting-mtd/chip-LP_EM_CC1354P10_6-lighting-example.out \ + out/artifacts/ti-cc13x4_26x4-lighting-ftd/chip-LP_EM_CC1354P10_6-lighting-example.out \ /tmp/bloat_reports/ - name: Uploading Size Reports uses: ./.github/actions/upload-size-reports diff --git a/docs/guides/fabric_synchronization_guide.md b/docs/guides/fabric_synchronization_guide.md index 5944105512776d..50fa3202f8ba84 100644 --- a/docs/guides/fabric_synchronization_guide.md +++ b/docs/guides/fabric_synchronization_guide.md @@ -98,6 +98,12 @@ Run the Fabric Synchronization script: In Ecosystem 1 Fabric-Admin console: +Pair the local bridge of Ecosystem 1 with node ID 1: + +``` +fabricsync add-local-bridge 1 +``` + Pair the Ecosystem 2 bridge to Ecosystem 1 with node ID 2: ``` @@ -130,8 +136,8 @@ Pair the Light Example with node ID 3 using its payload number: pairing already-discovered 3 20202021 5543 ``` -After the device is successfully added, you will observe the following on -Ecosystem 2 with the newly assigned Node ID: +After the device is successfully added, you will observe the following message +on Ecosystem 2 with the newly assigned Node ID: ``` >>> New device with Node ID: 0x3 has been successfully added. diff --git a/examples/all-clusters-app/all-clusters-common/include/static-supported-modes-manager.h b/examples/all-clusters-app/all-clusters-common/include/static-supported-modes-manager.h index b4ce50b8cd49a3..168482e0303704 100644 --- a/examples/all-clusters-app/all-clusters-common/include/static-supported-modes-manager.h +++ b/examples/all-clusters-app/all-clusters-common/include/static-supported-modes-manager.h @@ -31,7 +31,7 @@ namespace ModeSelect { * This implementation statically defines the options. */ -class StaticSupportedModesManager : public chip::app::Clusters::ModeSelect::SupportedModesManager +class StaticSupportedModesManager : public SupportedModesManager { using ModeOptionStructType = Structs::ModeOptionStruct::Type; using storage_value_type = const ModeOptionStructType; @@ -52,8 +52,6 @@ class StaticSupportedModesManager : public chip::app::Clusters::ModeSelect::Supp static const EndpointSpanPair supportedOptionsByEndpoints[MATTER_DM_MODE_SELECT_CLUSTER_SERVER_ENDPOINT_COUNT]; public: - static const StaticSupportedModesManager instance; - SupportedModesManager::ModeOptionsProvider getModeOptionsProvider(EndpointId endpointId) const override; Protocols::InteractionModel::Status getModeOptionByMode(EndpointId endpointId, uint8_t mode, @@ -62,12 +60,8 @@ class StaticSupportedModesManager : public chip::app::Clusters::ModeSelect::Supp ~StaticSupportedModesManager(){}; StaticSupportedModesManager() {} - - static inline const StaticSupportedModesManager & getStaticSupportedModesManagerInstance() { return instance; } }; -const SupportedModesManager * getSupportedModesManager(); - } // namespace ModeSelect } // namespace Clusters } // namespace app diff --git a/examples/all-clusters-app/all-clusters-common/src/static-supported-modes-manager.cpp b/examples/all-clusters-app/all-clusters-common/src/static-supported-modes-manager.cpp index 4060d4be85ec9c..94345600cf53fd 100644 --- a/examples/all-clusters-app/all-clusters-common/src/static-supported-modes-manager.cpp +++ b/examples/all-clusters-app/all-clusters-common/src/static-supported-modes-manager.cpp @@ -39,8 +39,6 @@ const StaticSupportedModesManager::EndpointSpanPair EndpointSpanPair(1, Span(StaticSupportedModesManager::coffeeOptions)) // Options for Endpoint 1 }; -const StaticSupportedModesManager StaticSupportedModesManager::instance = StaticSupportedModesManager(); - SupportedModesManager::ModeOptionsProvider StaticSupportedModesManager::getModeOptionsProvider(EndpointId endpointId) const { for (auto & endpointSpanPair : supportedOptionsByEndpoints) @@ -76,8 +74,3 @@ Status StaticSupportedModesManager::getModeOptionByMode(unsigned short endpointI ChipLogProgress(Zcl, "Cannot find the mode %u", mode); return Status::InvalidCommand; } - -const ModeSelect::SupportedModesManager * ModeSelect::getSupportedModesManager() -{ - return &StaticSupportedModesManager::instance; -} diff --git a/examples/all-clusters-app/ameba/main/chipinterface.cpp b/examples/all-clusters-app/ameba/main/chipinterface.cpp index 2a35d86eadc3a2..99ed719f0fab28 100644 --- a/examples/all-clusters-app/ameba/main/chipinterface.cpp +++ b/examples/all-clusters-app/ameba/main/chipinterface.cpp @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #if CONFIG_ENABLE_AMEBA_TEST_EVENT_TRIGGER @@ -77,6 +78,7 @@ app::Clusters::NetworkCommissioning::Instance &(NetworkCommissioning::AmebaWiFiDriver::GetInstance())); app::Clusters::TemperatureControl::AppSupportedTemperatureLevelsDelegate sAppSupportedTemperatureLevelsDelegate; +Clusters::ModeSelect::StaticSupportedModesManager sStaticSupportedModesManager; } // namespace void NetWorkCommissioningInstInit() @@ -181,6 +183,7 @@ static void InitServer(intptr_t context) InitManualOperation(); #endif app::Clusters::TemperatureControl::SetInstance(&sAppSupportedTemperatureLevelsDelegate); + Clusters::ModeSelect::setSupportedModesManager(&sStaticSupportedModesManager); MatterMicrowaveOvenServerInit(); #if CONFIG_ENABLE_AMEBA_TEST_EVENT_TRIGGER static SmokeCOTestEventTriggerHandler sSmokeCOTestEventTriggerHandler; diff --git a/examples/all-clusters-app/asr/src/AppTask.cpp b/examples/all-clusters-app/asr/src/AppTask.cpp index 1a829ca3de1798..ef3c86d2720436 100644 --- a/examples/all-clusters-app/asr/src/AppTask.cpp +++ b/examples/all-clusters-app/asr/src/AppTask.cpp @@ -42,6 +42,7 @@ #include #include #include +#include #include using chip::Protocols::InteractionModel::Status; @@ -66,6 +67,7 @@ app::Clusters::NetworkCommissioning::Instance sWiFiNetworkCommissioningInstance(kNetworkCommissioningEndpointMain /* Endpoint Id */, &(NetworkCommissioning::ASRWiFiDriver::GetInstance())); app::Clusters::TemperatureControl::AppSupportedTemperatureLevelsDelegate sAppSupportedTemperatureLevelsDelegate; +app::Clusters::ModeSelect::StaticSupportedModesManager sStaticSupportedModesManager; } // namespace AppTask AppTask::sAppTask; @@ -131,6 +133,7 @@ CHIP_ERROR AppTask::Init() #endif /* CONFIG_NETWORK_LAYER_BLE */ app::Clusters::TemperatureControl::SetInstance(&sAppSupportedTemperatureLevelsDelegate); + app::Clusters::ModeSelect::setSupportedModesManager(&sStaticSupportedModesManager); return CHIP_NO_ERROR; } diff --git a/examples/all-clusters-app/cc13x4_26x4/main/AppTask.cpp b/examples/all-clusters-app/cc13x4_26x4/main/AppTask.cpp index 88099f009f2dac..c9a54347657c3d 100644 --- a/examples/all-clusters-app/cc13x4_26x4/main/AppTask.cpp +++ b/examples/all-clusters-app/cc13x4_26x4/main/AppTask.cpp @@ -49,6 +49,7 @@ #include #include +#include #include #include @@ -73,6 +74,7 @@ static Button_Handle sAppRightHandle; static DeviceInfoProviderImpl sExampleDeviceInfoProvider; AppTask AppTask::sAppTask; +app::Clusters::ModeSelect::StaticSupportedModesManager sStaticSupportedModesManager; constexpr EndpointId kNetworkCommissioningEndpointSecondary = 0xFFFE; @@ -334,6 +336,7 @@ int AppTask::Init() // QR code will be used with CHIP Tool PrintOnboardingCodes(RendezvousInformationFlags(RendezvousInformationFlag::kBLE)); + app::Clusters::ModeSelect::setSupportedModesManager(&sStaticSupportedModesManager); return 0; } diff --git a/examples/all-clusters-app/esp32/main/CMakeLists.txt b/examples/all-clusters-app/esp32/main/CMakeLists.txt index 3e80b995c55b5f..9dfd4ffc50b6c9 100644 --- a/examples/all-clusters-app/esp32/main/CMakeLists.txt +++ b/examples/all-clusters-app/esp32/main/CMakeLists.txt @@ -40,7 +40,6 @@ set(SRC_DIRS_LIST "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/platform/esp32/ota" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/platform/esp32/common" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/platform/esp32/shell_extension" - "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/platform/esp32/mode-support" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/server" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/icd/server" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/util" @@ -112,8 +111,6 @@ set(SRC_DIRS_LIST ) -set(EXCLUDE_SRCS "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/all-clusters-app/all-clusters-common/src/static-supported-modes-manager.cpp") - if (CONFIG_ENABLE_PW_RPC) # Append additional directories for RPC build set(PRIV_INCLUDE_DIRS_LIST "${PRIV_INCLUDE_DIRS_LIST}" @@ -143,8 +140,7 @@ if (CONFIG_ENABLE_ICD_SERVER) endif() idf_component_register(PRIV_INCLUDE_DIRS ${PRIV_INCLUDE_DIRS_LIST} - SRC_DIRS ${SRC_DIRS_LIST} - EXCLUDE_SRCS ${EXCLUDE_SRCS}) + SRC_DIRS ${SRC_DIRS_LIST}) get_filename_component(CHIP_ROOT ${CMAKE_SOURCE_DIR}/third_party/connectedhomeip REALPATH) diff --git a/examples/all-clusters-app/esp32/main/main.cpp b/examples/all-clusters-app/esp32/main/main.cpp index af94d2b2d36afe..6a0d0d389a92e2 100644 --- a/examples/all-clusters-app/esp32/main/main.cpp +++ b/examples/all-clusters-app/esp32/main/main.cpp @@ -41,8 +41,8 @@ #include #include #include -#include #include +#include #include #if CONFIG_HAVE_DISPLAY @@ -95,6 +95,7 @@ class AppCallbacks : public AppDelegate AppCallbacks sCallbacks; app::Clusters::TemperatureControl::AppSupportedTemperatureLevelsDelegate sAppSupportedTemperatureLevelsDelegate; +app::Clusters::ModeSelect::StaticSupportedModesManager sStaticSupportedModesManager; constexpr EndpointId kNetworkCommissioningEndpointSecondary = 0xFFFE; @@ -122,15 +123,9 @@ static void InitServer(intptr_t context) #if CONFIG_DEVICE_TYPE_M5STACK SetupPretendDevices(); #endif - CHIP_ERROR err = - app::Clusters::ModeSelect::StaticSupportedModesManager::getStaticSupportedModesManagerInstance().InitEndpointArray( - FIXED_ENDPOINT_COUNT); - if (err != CHIP_NO_ERROR) - { - ESP_LOGE(TAG, "Failed to initialize endpoint array for supported-modes, err:%" CHIP_ERROR_FORMAT, err.Format()); - } app::Clusters::TemperatureControl::SetInstance(&sAppSupportedTemperatureLevelsDelegate); + app::Clusters::ModeSelect::setSupportedModesManager(&sStaticSupportedModesManager); } // #include diff --git a/examples/all-clusters-app/infineon/psoc6/src/AppTask.cpp b/examples/all-clusters-app/infineon/psoc6/src/AppTask.cpp index 143e25e87e0114..bb499d20098abc 100644 --- a/examples/all-clusters-app/infineon/psoc6/src/AppTask.cpp +++ b/examples/all-clusters-app/infineon/psoc6/src/AppTask.cpp @@ -41,6 +41,7 @@ #include #include #include +#include #include /* OTA related includes */ @@ -98,6 +99,7 @@ OTAImageProcessorImpl gImageProcessor; #endif chip::app::Clusters::TemperatureControl::AppSupportedTemperatureLevelsDelegate sAppSupportedTemperatureLevelsDelegate; +chip::app::Clusters::ModeSelect::StaticSupportedModesManager sStaticSupportedModesManager; } // namespace using namespace ::chip; @@ -141,6 +143,7 @@ static void InitServer(intptr_t context) GetAppTask().InitOTARequestor(); #endif chip::app::Clusters::TemperatureControl::SetInstance(&sAppSupportedTemperatureLevelsDelegate); + chip::app::Clusters::ModeSelect::setSupportedModesManager(&sStaticSupportedModesManager); } CHIP_ERROR AppTask::StartAppTask() diff --git a/examples/all-clusters-app/linux/main-common.cpp b/examples/all-clusters-app/linux/main-common.cpp index edddc6a8a7d62e..badda7f3b68b40 100644 --- a/examples/all-clusters-app/linux/main-common.cpp +++ b/examples/all-clusters-app/linux/main-common.cpp @@ -58,6 +58,7 @@ #include #include #include +#include #include #include #include @@ -80,6 +81,7 @@ AllClustersCommandDelegate sAllClustersCommandDelegate; Clusters::WindowCovering::WindowCoveringManager sWindowCoveringManager; Clusters::TemperatureControl::AppSupportedTemperatureLevelsDelegate sAppSupportedTemperatureLevelsDelegate; +Clusters::ModeSelect::StaticSupportedModesManager sStaticSupportedModesManager; Clusters::ValveConfigurationAndControl::ValveControlDelegate sValveDelegate; Clusters::TimeSynchronization::ExtendedTimeSyncDelegate sTimeSyncDelegate; @@ -246,6 +248,7 @@ void ApplicationInit() MatterDishwasherAlarmServerInit(); #endif Clusters::TemperatureControl::SetInstance(&sAppSupportedTemperatureLevelsDelegate); + Clusters::ModeSelect::setSupportedModesManager(&sStaticSupportedModesManager); Clusters::ValveConfigurationAndControl::SetDefaultDelegate(chip::EndpointId(1), &sValveDelegate); Clusters::TimeSynchronization::SetDefaultDelegate(&sTimeSyncDelegate); diff --git a/examples/all-clusters-app/mbed/main/AppTask.cpp b/examples/all-clusters-app/mbed/main/AppTask.cpp index b497ea7919a0a3..f67876b1da5b57 100644 --- a/examples/all-clusters-app/mbed/main/AppTask.cpp +++ b/examples/all-clusters-app/mbed/main/AppTask.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -45,7 +46,8 @@ using namespace ::chip::Credentials; namespace { app::Clusters::TemperatureControl::AppSupportedTemperatureLevelsDelegate sAppSupportedTemperatureLevelsDelegate; -} +app::Clusters::ModeSelect::StaticSupportedModesManager sStaticSupportedModesManager; +} // namespace AppTask AppTask::sAppTask; @@ -90,6 +92,7 @@ int AppTask::Init() return EXIT_FAILURE; } app::Clusters::TemperatureControl::SetInstance(&sAppSupportedTemperatureLevelsDelegate); + app::Clusters::ModeSelect::setSupportedModesManager(&sStaticSupportedModesManager); return 0; } diff --git a/examples/all-clusters-app/nrfconnect/main/AppTask.cpp b/examples/all-clusters-app/nrfconnect/main/AppTask.cpp index 3551087a969411..067e8113c4138a 100644 --- a/examples/all-clusters-app/nrfconnect/main/AppTask.cpp +++ b/examples/all-clusters-app/nrfconnect/main/AppTask.cpp @@ -35,6 +35,7 @@ #include #include +#include #include #ifdef CONFIG_CHIP_WIFI @@ -95,6 +96,7 @@ bool sIsNetworkEnabled = false; bool sHaveBLEConnections = false; app::Clusters::TemperatureControl::AppSupportedTemperatureLevelsDelegate sAppSupportedTemperatureLevelsDelegate; +app::Clusters::ModeSelect::StaticSupportedModesManager sStaticSupportedModesManager; #ifdef CONFIG_CHIP_CRYPTO_PSA chip::Crypto::PSAOperationalKeystore sPSAOperationalKeystore{}; @@ -257,6 +259,7 @@ CHIP_ERROR AppTask::Init() } app::Clusters::TemperatureControl::SetInstance(&sAppSupportedTemperatureLevelsDelegate); + app::Clusters::ModeSelect::setSupportedModesManager(&sStaticSupportedModesManager); return err; } diff --git a/examples/all-clusters-app/nxp/mw320/main.cpp b/examples/all-clusters-app/nxp/mw320/main.cpp index 5f2df7b501e88d..82d335cccbb6b3 100644 --- a/examples/all-clusters-app/nxp/mw320/main.cpp +++ b/examples/all-clusters-app/nxp/mw320/main.cpp @@ -41,6 +41,7 @@ #include #include #include +#include #include #include @@ -121,6 +122,7 @@ static struct wlan_network sta_network; static struct wlan_network uap_network; chip::app::Clusters::TemperatureControl::AppSupportedTemperatureLevelsDelegate sAppSupportedTemperatureLevelsDelegate; +chip::app::Clusters::ModeSelect::StaticSupportedModesManager sStaticSupportedModesManager; const int TASK_MAIN_PRIO = OS_PRIO_3; const int TASK_MAIN_STACK_SIZE = 800; @@ -1083,6 +1085,7 @@ static void run_chip_srv(System::Layer * aSystemLayer, void * aAppState) // binding -- chip::app::Clusters::TemperatureControl::SetInstance(&sAppSupportedTemperatureLevelsDelegate); + chip::app::Clusters::ModeSelect::setSupportedModesManager(&sStaticSupportedModesManager); return; } diff --git a/examples/all-clusters-app/telink/src/AppTask.cpp b/examples/all-clusters-app/telink/src/AppTask.cpp index 03b81fb434a8ef..909f89af2236ab 100644 --- a/examples/all-clusters-app/telink/src/AppTask.cpp +++ b/examples/all-clusters-app/telink/src/AppTask.cpp @@ -18,10 +18,12 @@ #include "AppTask.h" #include "binding-handler.h" +#include LOG_MODULE_DECLARE(app, CONFIG_CHIP_APP_LOG_LEVEL); AppTask AppTask::sAppTask; +chip::app::Clusters::ModeSelect::StaticSupportedModesManager sStaticSupportedModesManager; CHIP_ERROR AppTask::Init(void) { @@ -35,5 +37,6 @@ CHIP_ERROR AppTask::Init(void) return err; } + chip::app::Clusters::ModeSelect::setSupportedModesManager(&sStaticSupportedModesManager); return CHIP_NO_ERROR; } diff --git a/examples/all-clusters-app/tizen/src/main.cpp b/examples/all-clusters-app/tizen/src/main.cpp index 49c9f06ad9b8f6..191138c1f32424 100644 --- a/examples/all-clusters-app/tizen/src/main.cpp +++ b/examples/all-clusters-app/tizen/src/main.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -40,6 +41,7 @@ NetworkCommissioning::TizenEthernetDriver sEthernetDriver; Clusters::NetworkCommissioning::Instance sEthernetNetworkCommissioningInstance(kNetworkCommissioningEndpointMain, &sEthernetDriver); app::Clusters::TemperatureControl::AppSupportedTemperatureLevelsDelegate sAppSupportedTemperatureLevelsDelegate; +Clusters::ModeSelect::StaticSupportedModesManager sStaticSupportedModesManager; } // namespace void ApplicationInit() @@ -49,6 +51,7 @@ void ApplicationInit() sEthernetNetworkCommissioningInstance.Init(); app::Clusters::TemperatureControl::SetInstance(&sAppSupportedTemperatureLevelsDelegate); + Clusters::ModeSelect::setSupportedModesManager(&sStaticSupportedModesManager); } void ApplicationShutdown() {} diff --git a/examples/all-clusters-minimal-app/ameba/main/chipinterface.cpp b/examples/all-clusters-minimal-app/ameba/main/chipinterface.cpp index abb0791ac9a132..61f7db147f807d 100644 --- a/examples/all-clusters-minimal-app/ameba/main/chipinterface.cpp +++ b/examples/all-clusters-minimal-app/ameba/main/chipinterface.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #if CONFIG_ENABLE_OTA_REQUESTOR @@ -64,6 +65,7 @@ namespace { // Network Commissioning constexpr EndpointId kNetworkCommissioningEndpointMain = 0; constexpr EndpointId kNetworkCommissioningEndpointSecondary = 0xFFFE; +Clusters::ModeSelect::StaticSupportedModesManager sStaticSupportedModesManager; app::Clusters::NetworkCommissioning::Instance sWiFiNetworkCommissioningInstance(kNetworkCommissioningEndpointMain /* Endpoint Id */, &(NetworkCommissioning::AmebaWiFiDriver::GetInstance())); @@ -170,6 +172,7 @@ static void InitServer(intptr_t context) // QR code will be used with CHIP Tool PrintOnboardingCodes(chip::RendezvousInformationFlags(chip::RendezvousInformationFlag::kBLE)); } + Clusters::ModeSelect::setSupportedModesManager(&sStaticSupportedModesManager); } extern "C" void ChipTest(void) diff --git a/examples/all-clusters-minimal-app/asr/src/AppTask.cpp b/examples/all-clusters-minimal-app/asr/src/AppTask.cpp index f9d05c2157382d..7e33211b8a978b 100644 --- a/examples/all-clusters-minimal-app/asr/src/AppTask.cpp +++ b/examples/all-clusters-minimal-app/asr/src/AppTask.cpp @@ -42,6 +42,7 @@ #include #include #include +#include #include "init_Matter.h" #include "lega_rtos_api.h" @@ -60,6 +61,7 @@ QueueHandle_t sAppEventQueue; constexpr EndpointId kNetworkCommissioningEndpointMain = 0; constexpr EndpointId kNetworkCommissioningEndpointSecondary = 0xFFFE; +app::Clusters::ModeSelect::StaticSupportedModesManager sStaticSupportedModesManager; app::Clusters::NetworkCommissioning::Instance sWiFiNetworkCommissioningInstance(kNetworkCommissioningEndpointMain /* Endpoint Id */, &(NetworkCommissioning::ASRWiFiDriver::GetInstance())); @@ -120,6 +122,7 @@ CHIP_ERROR AppTask::Init() sLightLED.Init(LIGHT_LED); + app::Clusters::ModeSelect::setSupportedModesManager(&sStaticSupportedModesManager); return CHIP_NO_ERROR; } diff --git a/examples/all-clusters-minimal-app/esp32/main/main.cpp b/examples/all-clusters-minimal-app/esp32/main/main.cpp index 993dc609300943..4972e775bd6f31 100644 --- a/examples/all-clusters-minimal-app/esp32/main/main.cpp +++ b/examples/all-clusters-minimal-app/esp32/main/main.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #if CONFIG_HAVE_DISPLAY #include "DeviceWithDisplay.h" @@ -74,6 +75,7 @@ extern const char TAG[] = "all-clusters-minimal-app"; static AppDeviceCallbacks EchoCallbacks; static AppDeviceCallbacksDelegate sAppDeviceCallbacksDelegate; +app::Clusters::ModeSelect::StaticSupportedModesManager sStaticSupportedModesManager; namespace { class AppCallbacks : public AppDelegate @@ -116,6 +118,7 @@ static void InitServer(intptr_t context) #if CONFIG_DEVICE_TYPE_M5STACK SetupPretendDevices(); #endif + app::Clusters::ModeSelect::setSupportedModesManager(&sStaticSupportedModesManager); } extern "C" void app_main() diff --git a/examples/all-clusters-minimal-app/infineon/psoc6/src/AppTask.cpp b/examples/all-clusters-minimal-app/infineon/psoc6/src/AppTask.cpp index 169b2f88acb7ab..56327c56dd9b94 100644 --- a/examples/all-clusters-minimal-app/infineon/psoc6/src/AppTask.cpp +++ b/examples/all-clusters-minimal-app/infineon/psoc6/src/AppTask.cpp @@ -41,6 +41,7 @@ #include #include #include +#include /* OTA related includes */ #if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR @@ -87,6 +88,7 @@ StaticQueue_t sAppEventQueueStruct; StackType_t appStack[APP_TASK_STACK_SIZE / sizeof(StackType_t)]; StaticTask_t appTaskStruct; +chip::app::Clusters::ModeSelect::StaticSupportedModesManager sStaticSupportedModesManager; #if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR DefaultOTARequestor gRequestorCore; @@ -138,6 +140,7 @@ static void InitServer(intptr_t context) #if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR GetAppTask().InitOTARequestor(); #endif + chip::app::Clusters::ModeSelect::setSupportedModesManager(&sStaticSupportedModesManager); } CHIP_ERROR AppTask::StartAppTask() diff --git a/examples/all-clusters-minimal-app/linux/main-common.cpp b/examples/all-clusters-minimal-app/linux/main-common.cpp index f0bf3cafe8553c..d99927cea0487e 100644 --- a/examples/all-clusters-minimal-app/linux/main-common.cpp +++ b/examples/all-clusters-minimal-app/linux/main-common.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -37,6 +38,7 @@ using namespace chip::DeviceLayer; namespace { static LowPowerManager lowPowerManager; +Clusters::ModeSelect::StaticSupportedModesManager sStaticSupportedModesManager; } // namespace void OnIdentifyStart(::Identify *) @@ -81,7 +83,10 @@ static Identify gIdentify1 = { OnTriggerEffect, }; -void ApplicationInit() {} +void ApplicationInit() +{ + Clusters::ModeSelect::setSupportedModesManager(&sStaticSupportedModesManager); +} void ApplicationShutdown() {} diff --git a/examples/all-clusters-minimal-app/mbed/main/AppTask.cpp b/examples/all-clusters-minimal-app/mbed/main/AppTask.cpp index 62317774c1520c..eb1188b93aa759 100644 --- a/examples/all-clusters-minimal-app/mbed/main/AppTask.cpp +++ b/examples/all-clusters-minimal-app/mbed/main/AppTask.cpp @@ -27,6 +27,7 @@ #include #include +#include static LEDWidget sStatusLED(MBED_CONF_APP_SYSTEM_STATE_LED); @@ -43,6 +44,7 @@ using namespace ::chip::DeviceLayer; using namespace ::chip::Credentials; AppTask AppTask::sAppTask; +app::Clusters::ModeSelect::StaticSupportedModesManager sStaticSupportedModesManager; int AppTask::Init() { @@ -85,6 +87,7 @@ int AppTask::Init() return EXIT_FAILURE; } + app::Clusters::ModeSelect::setSupportedModesManager(&sStaticSupportedModesManager); return 0; } diff --git a/examples/all-clusters-minimal-app/nrfconnect/main/AppTask.cpp b/examples/all-clusters-minimal-app/nrfconnect/main/AppTask.cpp index 86bfe7a9aa132b..be858eae561921 100644 --- a/examples/all-clusters-minimal-app/nrfconnect/main/AppTask.cpp +++ b/examples/all-clusters-minimal-app/nrfconnect/main/AppTask.cpp @@ -30,6 +30,7 @@ #include #include +#include #if CONFIG_CHIP_OTA_REQUESTOR #include "OTAUtil.h" @@ -63,6 +64,7 @@ static k_timer sFunctionTimer; LEDWidget sStatusLED; FactoryResetLEDsWrapper<3> sFactoryResetLEDs{ { FACTORY_RESET_SIGNAL_LED, FACTORY_RESET_SIGNAL_LED1, FACTORY_RESET_SIGNAL_LED2 } }; +app::Clusters::ModeSelect::StaticSupportedModesManager sStaticSupportedModesManager; bool sIsNetworkProvisioned = false; bool sIsNetworkEnabled = false; @@ -198,6 +200,7 @@ CHIP_ERROR AppTask::Init() { LOG_ERR("PlatformMgr().StartEventLoopTask() failed"); } + app::Clusters::ModeSelect::setSupportedModesManager(&sStaticSupportedModesManager); return err; } diff --git a/examples/all-clusters-minimal-app/telink/src/AppTask.cpp b/examples/all-clusters-minimal-app/telink/src/AppTask.cpp index 55d46154f98fad..ee78fddf5b3d94 100644 --- a/examples/all-clusters-minimal-app/telink/src/AppTask.cpp +++ b/examples/all-clusters-minimal-app/telink/src/AppTask.cpp @@ -18,10 +18,12 @@ #include "AppTask.h" #include "binding-handler.h" +#include LOG_MODULE_DECLARE(app, CONFIG_CHIP_APP_LOG_LEVEL); AppTask AppTask::sAppTask; +chip::app::Clusters::ModeSelect::StaticSupportedModesManager sStaticSupportedModesManager; CHIP_ERROR AppTask::Init() { @@ -35,5 +37,6 @@ CHIP_ERROR AppTask::Init() return err; } + chip::app::Clusters::ModeSelect::setSupportedModesManager(&sStaticSupportedModesManager); return CHIP_NO_ERROR; } diff --git a/examples/all-clusters-minimal-app/tizen/src/main.cpp b/examples/all-clusters-minimal-app/tizen/src/main.cpp index fd2a345c952dd8..2d37747fe82c12 100644 --- a/examples/all-clusters-minimal-app/tizen/src/main.cpp +++ b/examples/all-clusters-minimal-app/tizen/src/main.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -36,6 +37,7 @@ constexpr EndpointId kNetworkCommissioningEndpointMain = 0; constexpr EndpointId kNetworkCommissioningEndpointSecondary = 0xFFFE; NetworkCommissioning::TizenEthernetDriver sEthernetDriver; +Clusters::ModeSelect::StaticSupportedModesManager sStaticSupportedModesManager; Clusters::NetworkCommissioning::Instance sEthernetNetworkCommissioningInstance(kNetworkCommissioningEndpointMain, &sEthernetDriver); } // namespace @@ -45,6 +47,7 @@ void ApplicationInit() emberAfEndpointEnableDisable(kNetworkCommissioningEndpointSecondary, false); sEthernetNetworkCommissioningInstance.Init(); + Clusters::ModeSelect::setSupportedModesManager(&sStaticSupportedModesManager); } void ApplicationShutdown(){}; diff --git a/examples/fabric-admin/commands/clusters/ClusterCommand.h b/examples/fabric-admin/commands/clusters/ClusterCommand.h index ab2a535da41cc5..edf2302219fa1c 100644 --- a/examples/fabric-admin/commands/clusters/ClusterCommand.h +++ b/examples/fabric-admin/commands/clusters/ClusterCommand.h @@ -84,7 +84,7 @@ class ClusterCommand : public InteractionModelCommands, public ModelCommand, pub if (data != nullptr) { LogErrorOnFailure(RemoteDataModelLogger::LogCommandAsJSON(path, data)); - DeviceMgr().HandleCommandResponse(path, data); + DeviceMgr().HandleCommandResponse(path, *data); } } diff --git a/examples/fabric-admin/commands/clusters/ReportCommand.cpp b/examples/fabric-admin/commands/clusters/ReportCommand.cpp index ff52a30e661342..2fdb965ddc844c 100644 --- a/examples/fabric-admin/commands/clusters/ReportCommand.cpp +++ b/examples/fabric-admin/commands/clusters/ReportCommand.cpp @@ -46,7 +46,7 @@ void ReportCommand::OnAttributeData(const app::ConcreteDataAttributePath & path, LogErrorOnFailure(RemoteDataModelLogger::LogAttributeAsJSON(path, data)); - DeviceMgr().HandleAttributeData(path, data); + DeviceMgr().HandleAttributeData(path, *data); } void ReportCommand::OnEventData(const app::EventHeader & eventHeader, TLV::TLVReader * data, const app::StatusIB * status) @@ -73,5 +73,5 @@ void ReportCommand::OnEventData(const app::EventHeader & eventHeader, TLV::TLVRe LogErrorOnFailure(RemoteDataModelLogger::LogEventAsJSON(eventHeader, data)); - DeviceMgr().HandleEventData(eventHeader, data); + DeviceMgr().HandleEventData(eventHeader, *data); } diff --git a/examples/fabric-admin/commands/fabric-sync/FabricSyncCommand.cpp b/examples/fabric-admin/commands/fabric-sync/FabricSyncCommand.cpp index 704996d189d9c2..6a7b5be05bb3bd 100644 --- a/examples/fabric-admin/commands/fabric-sync/FabricSyncCommand.cpp +++ b/examples/fabric-admin/commands/fabric-sync/FabricSyncCommand.cpp @@ -64,13 +64,16 @@ void FabricSyncAddBridgeCommand::OnCommissioningComplete(NodeId deviceId, CHIP_E DeviceMgr().SubscribeRemoteFabricBridge(); - // After successful commissioning of the Commissionee, initiate Reverse Commissioning - // via the Commissioner Control Cluster. However, we must first verify that the - // remote Fabric-Bridge supports Fabric Synchronization. - // - // Note: The Fabric-Admin MUST NOT send the RequestCommissioningApproval command - // if the remote Fabric-Bridge lacks Fabric Synchronization support. - DeviceLayer::PlatformMgr().ScheduleWork(CheckFabricBridgeSynchronizationSupport, 0); + if (DeviceMgr().IsLocalBridgeReady()) + { + // After successful commissioning of the Commissionee, initiate Reverse Commissioning + // via the Commissioner Control Cluster. However, we must first verify that the + // remote Fabric-Bridge supports Fabric Synchronization. + // + // Note: The Fabric-Admin MUST NOT send the RequestCommissioningApproval command + // if the remote Fabric-Bridge lacks Fabric Synchronization support. + DeviceLayer::PlatformMgr().ScheduleWork(CheckFabricBridgeSynchronizationSupport, 0); + } } else { diff --git a/examples/fabric-admin/device_manager/DeviceManager.cpp b/examples/fabric-admin/device_manager/DeviceManager.cpp index fe0c8aea4da5cb..ad8def646a0594 100644 --- a/examples/fabric-admin/device_manager/DeviceManager.cpp +++ b/examples/fabric-admin/device_manager/DeviceManager.cpp @@ -144,7 +144,6 @@ void DeviceManager::OpenRemoteDeviceCommissioningWindow(EndpointId remoteEndpoin commandBuilder.Add("pairing open-commissioning-window "); commandBuilder.AddFormat("%lu %d %d %d %d %d", mRemoteBridgeNodeId, remoteEndpointId, kEnhancedCommissioningMethod, kWindowTimeout, kIteration, discriminator); - commandBuilder.Add(" --setup-pin 20202021"); PushCommand(commandBuilder.c_str()); } @@ -215,8 +214,8 @@ void DeviceManager::SubscribeRemoteFabricBridge() // Prepare and push the commissioner control subscribe command commandBuilder.Add("commissionercontrol subscribe-event commissioning-request-result "); - commandBuilder.AddFormat("%d %d %lu %d --is-urgent true", kSubscribeMinInterval, kSubscribeMaxInterval, mRemoteBridgeNodeId, - kRootEndpointId); + commandBuilder.AddFormat("%d %d %lu %d --is-urgent true --keepSubscriptions true", kSubscribeMinInterval, kSubscribeMaxInterval, + mRemoteBridgeNodeId, kRootEndpointId); PushCommand(commandBuilder.c_str()); } @@ -238,6 +237,25 @@ void DeviceManager::ReadSupportedDeviceCategories() PushCommand(commandBuilder.c_str()); } +void DeviceManager::HandleReadSupportedDeviceCategories(chip::TLV::TLVReader & data) +{ + ChipLogProgress(NotSpecified, "Attribute SupportedDeviceCategories detected."); + + BitMask value; + CHIP_ERROR error = app::DataModel::Decode(data, value); + if (error != CHIP_NO_ERROR) + { + ChipLogError(NotSpecified, "Failed to decode attribute value. Error: %" CHIP_ERROR_FORMAT, error.Format()); + return; + } + + if (value.Has(CommissionerControl::SupportedDeviceCategoryBitmap::kFabricSynchronization)) + { + ChipLogProgress(NotSpecified, "Remote Fabric-Bridge supports Fabric Synchronization, start reverse commissioning."); + RequestCommissioningApproval(); + } +} + void DeviceManager::RequestCommissioningApproval() { ChipLogProgress(NotSpecified, "Starting reverse commissioning for bridge device: NodeId: " ChipLogFormatX64, @@ -255,12 +273,12 @@ void DeviceManager::RequestCommissioningApproval() PushCommand(commandBuilder.c_str()); } -void DeviceManager::HandleCommissioningRequestResult(TLV::TLVReader * data) +void DeviceManager::HandleCommissioningRequestResult(TLV::TLVReader & data) { ChipLogProgress(NotSpecified, "CommissioningRequestResult event received."); CommissionerControl::Events::CommissioningRequestResult::DecodableType value; - CHIP_ERROR error = app::DataModel::Decode(*data, value); + CHIP_ERROR error = app::DataModel::Decode(data, value); if (error != CHIP_NO_ERROR) { ChipLogError(NotSpecified, "Failed to decode event value. Error: %" CHIP_ERROR_FORMAT, error.Format()); @@ -284,82 +302,12 @@ void DeviceManager::HandleCommissioningRequestResult(TLV::TLVReader * data) SendCommissionNodeRequest(value.requestId, kResponseTimeoutSeconds); } -void DeviceManager::SendCommissionNodeRequest(uint64_t requestId, uint16_t responseTimeoutSeconds) -{ - ChipLogProgress(NotSpecified, "Request the Commissioner Control Server to begin commissioning a previously approved request."); - - StringBuilder commandBuilder; - commandBuilder.Add("commissionercontrol commission-node "); - commandBuilder.AddFormat("%lu %u %lu %d", requestId, responseTimeoutSeconds, mRemoteBridgeNodeId, kRootEndpointId); - - PushCommand(commandBuilder.c_str()); -} - -void DeviceManager::HandleReverseOpenCommissioningWindow(TLV::TLVReader * data) +void DeviceManager::HandleAttributePartsListUpdate(chip::TLV::TLVReader & data) { - CommissionerControl::Commands::ReverseOpenCommissioningWindow::DecodableType value; - CHIP_ERROR error = app::DataModel::Decode(*data, value); - if (error != CHIP_NO_ERROR) - { - ChipLogError(NotSpecified, "Failed to decode command response value. Error: %" CHIP_ERROR_FORMAT, error.Format()); - return; - } - - // Log all fields - ChipLogProgress(NotSpecified, "DecodableType fields:"); - ChipLogProgress(NotSpecified, " commissioningTimeout: %u", value.commissioningTimeout); - ChipLogProgress(NotSpecified, " discriminator: %u", value.discriminator); - ChipLogProgress(NotSpecified, " iterations: %u", value.iterations); - - char verifierHex[Crypto::kSpake2p_VerifierSerialized_Length * 2 + 1]; - Encoding::BytesToHex(value.PAKEPasscodeVerifier.data(), value.PAKEPasscodeVerifier.size(), verifierHex, sizeof(verifierHex), - Encoding::HexFlags::kNullTerminate); - ChipLogProgress(NotSpecified, " PAKEPasscodeVerifier: %s", verifierHex); - - char saltHex[Crypto::kSpake2p_Max_PBKDF_Salt_Length * 2 + 1]; - Encoding::BytesToHex(value.salt.data(), value.salt.size(), saltHex, sizeof(saltHex), Encoding::HexFlags::kNullTerminate); - ChipLogProgress(NotSpecified, " salt: %s", saltHex); - - OpenDeviceCommissioningWindow(mLocalBridgeNodeId, value.commissioningTimeout, value.iterations, value.discriminator, saltHex, - verifierHex); -} - -void DeviceManager::HandleAttributeData(const app::ConcreteDataAttributePath & path, TLV::TLVReader * data) -{ - if (path.mClusterId == CommissionerControl::Id && - path.mAttributeId == CommissionerControl::Attributes::SupportedDeviceCategories::Id) - { - ChipLogProgress(NotSpecified, "Attribute SupportedDeviceCategories detected."); - - BitMask value; - CHIP_ERROR error = app::DataModel::Decode(*data, value); - if (error != CHIP_NO_ERROR) - { - ChipLogError(NotSpecified, "Failed to decode attribute value. Error: %" CHIP_ERROR_FORMAT, error.Format()); - return; - } - - if (value.Has(CommissionerControl::SupportedDeviceCategoryBitmap::kFabricSynchronization)) - { - ChipLogProgress(NotSpecified, "Remote Fabric-Bridge supports Fabric Synchronization, start reverse commissioning."); - RequestCommissioningApproval(); - } - - return; - } - - if (path.mClusterId != Descriptor::Id || path.mAttributeId != Descriptor::Attributes::PartsList::Id) - { - return; - } - - ChipLogProgress(NotSpecified, "Attribute change detected:"); - ChipLogProgress( - NotSpecified, "Endpoint: %u, Cluster: " ChipLogFormatMEI ", Attribute: " ChipLogFormatMEI ", DataVersion: %" PRIu32, - path.mEndpointId, ChipLogValueMEI(path.mClusterId), ChipLogValueMEI(path.mAttributeId), path.mDataVersion.ValueOr(0)); + ChipLogProgress(NotSpecified, "Attribute PartsList change detected:"); app::DataModel::DecodableList value; - CHIP_ERROR error = app::DataModel::Decode(*data, value); + CHIP_ERROR error = app::DataModel::Decode(data, value); if (error != CHIP_NO_ERROR) { ChipLogError(NotSpecified, "Failed to decode attribute value. Error: %" CHIP_ERROR_FORMAT, error.Format()); @@ -413,7 +361,7 @@ void DeviceManager::HandleAttributeData(const app::ConcreteDataAttributePath & p for (const auto & endpoint : addedEndpoints) { // print to console - fprintf(stderr, "A new devie is added on Endpoint: %u\n", endpoint); + fprintf(stderr, "A new device is added on Endpoint: %u\n", endpoint); if (mAutoSyncEnabled) { @@ -457,7 +405,63 @@ void DeviceManager::HandleAttributeData(const app::ConcreteDataAttributePath & p } } -void DeviceManager::HandleEventData(const app::EventHeader & header, TLV::TLVReader * data) +void DeviceManager::SendCommissionNodeRequest(uint64_t requestId, uint16_t responseTimeoutSeconds) +{ + ChipLogProgress(NotSpecified, "Request the Commissioner Control Server to begin commissioning a previously approved request."); + + StringBuilder commandBuilder; + commandBuilder.Add("commissionercontrol commission-node "); + commandBuilder.AddFormat("%lu %u %lu %d", requestId, responseTimeoutSeconds, mRemoteBridgeNodeId, kRootEndpointId); + + PushCommand(commandBuilder.c_str()); +} + +void DeviceManager::HandleReverseOpenCommissioningWindow(TLV::TLVReader & data) +{ + CommissionerControl::Commands::ReverseOpenCommissioningWindow::DecodableType value; + CHIP_ERROR error = app::DataModel::Decode(data, value); + if (error != CHIP_NO_ERROR) + { + ChipLogError(NotSpecified, "Failed to decode command response value. Error: %" CHIP_ERROR_FORMAT, error.Format()); + return; + } + + // Log all fields + ChipLogProgress(NotSpecified, "DecodableType fields:"); + ChipLogProgress(NotSpecified, " commissioningTimeout: %u", value.commissioningTimeout); + ChipLogProgress(NotSpecified, " discriminator: %u", value.discriminator); + ChipLogProgress(NotSpecified, " iterations: %u", value.iterations); + + char verifierHex[Crypto::kSpake2p_VerifierSerialized_Length * 2 + 1]; + Encoding::BytesToHex(value.PAKEPasscodeVerifier.data(), value.PAKEPasscodeVerifier.size(), verifierHex, sizeof(verifierHex), + Encoding::HexFlags::kNullTerminate); + ChipLogProgress(NotSpecified, " PAKEPasscodeVerifier: %s", verifierHex); + + char saltHex[Crypto::kSpake2p_Max_PBKDF_Salt_Length * 2 + 1]; + Encoding::BytesToHex(value.salt.data(), value.salt.size(), saltHex, sizeof(saltHex), Encoding::HexFlags::kNullTerminate); + ChipLogProgress(NotSpecified, " salt: %s", saltHex); + + OpenDeviceCommissioningWindow(mLocalBridgeNodeId, value.commissioningTimeout, value.iterations, value.discriminator, saltHex, + verifierHex); +} + +void DeviceManager::HandleAttributeData(const app::ConcreteDataAttributePath & path, TLV::TLVReader & data) +{ + if (path.mClusterId == CommissionerControl::Id && + path.mAttributeId == CommissionerControl::Attributes::SupportedDeviceCategories::Id) + { + HandleReadSupportedDeviceCategories(data); + return; + } + + if (path.mClusterId == Descriptor::Id && path.mAttributeId == Descriptor::Attributes::PartsList::Id) + { + HandleAttributePartsListUpdate(data); + return; + } +} + +void DeviceManager::HandleEventData(const app::EventHeader & header, TLV::TLVReader & data) { if (header.mPath.mClusterId == CommissionerControl::Id && header.mPath.mEventId == CommissionerControl::Events::CommissioningRequestResult::Id) @@ -466,7 +470,7 @@ void DeviceManager::HandleEventData(const app::EventHeader & header, TLV::TLVRea } } -void DeviceManager::HandleCommandResponse(const app::ConcreteCommandPath & path, TLV::TLVReader * data) +void DeviceManager::HandleCommandResponse(const app::ConcreteCommandPath & path, TLV::TLVReader & data) { ChipLogProgress(NotSpecified, "Command Response received."); diff --git a/examples/fabric-admin/device_manager/DeviceManager.h b/examples/fabric-admin/device_manager/DeviceManager.h index b6c7dc0e657b51..d3b47c4b332276 100644 --- a/examples/fabric-admin/device_manager/DeviceManager.h +++ b/examples/fabric-admin/device_manager/DeviceManager.h @@ -150,11 +150,11 @@ class DeviceManager : public PairingDelegate void ReadSupportedDeviceCategories(); - void HandleAttributeData(const chip::app::ConcreteDataAttributePath & path, chip::TLV::TLVReader * data); + void HandleAttributeData(const chip::app::ConcreteDataAttributePath & path, chip::TLV::TLVReader & data); - void HandleEventData(const chip::app::EventHeader & header, chip::TLV::TLVReader * data); + void HandleEventData(const chip::app::EventHeader & header, chip::TLV::TLVReader & data); - void HandleCommandResponse(const chip::app::ConcreteCommandPath & path, chip::TLV::TLVReader * data); + void HandleCommandResponse(const chip::app::ConcreteCommandPath & path, chip::TLV::TLVReader & data); void OnDeviceRemoved(chip::NodeId deviceId, CHIP_ERROR err) override; @@ -163,11 +163,15 @@ class DeviceManager : public PairingDelegate void RequestCommissioningApproval(); - void HandleCommissioningRequestResult(chip::TLV::TLVReader * data); + void HandleReadSupportedDeviceCategories(chip::TLV::TLVReader & data); + + void HandleCommissioningRequestResult(chip::TLV::TLVReader & data); + + void HandleAttributePartsListUpdate(chip::TLV::TLVReader & data); void SendCommissionNodeRequest(uint64_t requestId, uint16_t responseTimeoutSeconds); - void HandleReverseOpenCommissioningWindow(chip::TLV::TLVReader * data); + void HandleReverseOpenCommissioningWindow(chip::TLV::TLVReader & data); static DeviceManager sInstance; diff --git a/examples/light-switch-app/cc13x4_26x4/.gn b/examples/light-switch-app/cc13x4_26x4/.gn new file mode 100644 index 00000000000000..cf974b2eb1df22 --- /dev/null +++ b/examples/light-switch-app/cc13x4_26x4/.gn @@ -0,0 +1,30 @@ +# Copyright (c) 2020 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. + +import("//build_overrides/build.gni") + +# The location of the build configuration file. +buildconfig = "${build_root}/config/BUILDCONFIG.gn" + +# CHIP uses angle bracket includes. +check_system_includes = true + +default_args = { + target_cpu = "arm" + target_os = "freertos" + + import("//args.gni") + pw_build_PIP_REQUIREMENTS += + [ "${chip_root}/scripts/setup/requirements.ti.txt" ] +} diff --git a/examples/light-switch-app/cc13x4_26x4/BUILD.gn b/examples/light-switch-app/cc13x4_26x4/BUILD.gn new file mode 100644 index 00000000000000..2994ab5dccb6ea --- /dev/null +++ b/examples/light-switch-app/cc13x4_26x4/BUILD.gn @@ -0,0 +1,117 @@ +# Copyright (c) 2020 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. + +import("//build_overrides/build.gni") +import("//build_overrides/chip.gni") +import("//build_overrides/openthread.gni") +import("//build_overrides/ti_simplelink_sdk.gni") + +import("${build_root}/config/defaults.gni") + +import("${chip_root}/src/platform/device.gni") + +import("${ti_simplelink_sdk_build_root}/ti_simplelink_executable.gni") +import("${ti_simplelink_sdk_build_root}/ti_simplelink_sdk.gni") + +assert(current_os == "freertos") + +project_dir = "${chip_root}/examples/light-switch-app/cc13x4_26x4" + +ti_simplelink_sdk("sdk") { + include_dirs = [ "${project_dir}/include" ] + public_configs = [ ":light-switch_app_config" ] +} + +ti_sysconfig("sysconfig") { + sources = [ "${project_dir}/chip.syscfg" ] + + outputs = [ + "ti_radio_config.c", + "ti_radio_config.h", + "ti_drivers_config.c", + "ti_drivers_config.h", + "ti_ble_config.c", + "ti_ble_config.h", + "ti_dmm_application_policy.c", + "ti_dmm_application_policy.h", + + # CCFG generation disabled for OTA-able application + #"ti_devices_config.c", + #"ti_devices_config.h", + ] + + public_configs = [ ":sdk_cc13x4_26x4_dmm_config" ] + + cflags = [ + "-Wno-comment", + "@" + rebase_path("${target_gen_dir}/sysconfig/ti_utils_build_compiler.opt", + root_build_dir), + ] +} + +ti_simplelink_executable("light-switch_app") { + output_name = "chip-${ti_simplelink_board}-light-switch-example.out" + + sources = [ + "${chip_root}/examples/providers/DeviceInfoProviderImpl.cpp", + "${chip_root}/src/app/clusters/general-diagnostics-server/GenericFaultTestEventTriggerHandler.cpp", + "${project_dir}/src/AppTask.cpp", + "${project_dir}/src/BindingHandler.cpp", + "${project_dir}/src/LightSwitchManager.cpp", + "${project_dir}/src/ZclCallbacks.cpp", + "${project_dir}/src/main.cpp", + ] + + public = [ + "${chip_root}/src/platform/cc13xx_26xx/DefaultTestEventTriggerDelegate.h", + ] + + deps = [ + ":sdk", + ":sysconfig", + "${chip_root}/examples/light-switch-app/light-switch-common", + "${chip_root}/examples/platform/cc13x4_26x4:cc13x4_26x4-attestation-credentials", + "${chip_root}/src/lib", + "${chip_root}/third_party/openthread:openthread", + ] + defines = [] + if (custom_factory_data) { + defines += [ "CC13XX_26XX_FACTORY_DATA" ] + } + + if (chip_enable_icd_server) { + defines += [ "TI_ICD_ENABLE_SERVER" ] + } + + include_dirs = [ + "${project_dir}", + "${chip_root}/examples/providers/", + ] + + cflags = [ + "-Wno-implicit-fallthrough", + "-Wno-sign-compare", + "-Wconversion", + ] + + output_dir = root_out_dir +} + +group("cc13x4_26x4") { + deps = [ ":light-switch_app" ] +} + +group("default") { + deps = [ ":cc13x4_26x4" ] +} diff --git a/examples/light-switch-app/cc13x4_26x4/README.md b/examples/light-switch-app/cc13x4_26x4/README.md new file mode 100644 index 00000000000000..a27c702714c5a8 --- /dev/null +++ b/examples/light-switch-app/cc13x4_26x4/README.md @@ -0,0 +1,311 @@ +# Matter Light Switch Example Application + +An example application showing the use of [Matter][matter] on the Texas +Instruments CC13XX_26XX family of Wireless MCUs. + +--- + +- [Matter Light Switch Example Application](#matter-light-switch-example-application) + - [Introduction](#introduction) + - [Device UI](#device-ui) + - [Building](#building) + - [Preparation](#preparation) + - [Compilation](#compilation) + - [Programming](#programming) + - [Code Composer Studio](#code-composer-studio) + - [UniFlash](#uniflash) + - [Viewing Logging Output](#viewing-logging-output) + - [Running the Example](#running-the-example) + - [TI Support](#ti-support) + +--- + +## Introduction + +The CC13XX_26XX light-switch example application provides a working +demonstration of a connected light-switch device. This uses the open-source +Matter implementation and the Texas Instruments SimpleLinkā„¢ CC13XX and CC26XX +software development kit. + +This example is enabled to build for CC1354P10 devices. + +The light-switch example is intended to serve both as a means to explore the +workings of Matter, as well as a template for creating real products based on +the Texas Instruments devices. + +## Device UI + +| Action | Functionality | +| ------------------------------------------------ | ---------------------------------- | +| Left Button (`BTN-1`) Press (less than 1000 ms) | Turns connected bulb off | +| Left Button (`BTN-1`) Press (more than 1000 ms) | Factory Reset | +| Right Button (`BTN-2`) Press (less than 1000 ms) | Turns connected bulb on | +| Right Button (`BTN-2`) Press (more than 1000 ms) | BLE Advertisement (Enable/Disable) | + +## Building + +### Preparation + +Some initial setup is necessary for preparing the build environment. This +section will need to be done when migrating to new versions of the SDK. This +guide assumes that the environment is linux based, and recommends Ubuntu 20.04. + +- Download and install [SysConfig][sysconfig]. This can be done simply with + the following commands. + + ``` + $ cd ~ + $ wget https://dr-download.ti.com/software-development/ide-configuration-compiler-or-debugger/MD-nsUM6f7Vvb/1.18.1.3343/sysconfig-1.18.1_3343-setup.run + $ chmod +x sysconfig-1.18.1_3343-setup.run + $ ./sysconfig-1.18.1_3343-setup.run + ``` + +- Run the bootstrap script to setup the build environment. +- Note, a recursive submodule checkout is required to utilize TI's Openthread + reference commit. +- Note, in order to build the chip-tool and ota-provider examples, a recursive + submodule checkout is required for the linux platform as seen in the command + below. + + ``` + $ cd ~/connectedhomeip + $ source ./scripts/bootstrap.sh + $ ./scripts/checkout_submodules.py --shallow --platform cc13xx_26xx linux --recursive + + ``` + +### Compilation + +It is necessary to activate the environment in every new shell. Then run GN and +Ninja to build the executable. + +- Activate the build environment with the repository activate script. + + ``` + $ cd ~/connectedhomeip + $ source ./scripts/activate.sh + + ``` + +- Run the build to produce a default executable. By default on Linux both the + TI SimpleLink SDK and Sysconfig are located in a `ti` folder in the user's + home directory, and you must provide the absolute path to them. For example + `/home/username/ti/sysconfig_1.18.1`. On Windows the default directory is + `C:\ti`. Take note of this install path, as it will be used in the next + step. + + ``` + $ cd ~/connectedhomeip/examples/lock-app/cc13x4_26x4 + $ gn gen out/debug --args="ti_sysconfig_root=\"$HOME/ti/sysconfig_1.18.1\"" + $ ninja -C out/debug + + ``` + + If you would like to define arguments on the command line you may add them + to the GN call. + + ``` + gn gen out/debug --args="ti_sysconfig_root=\"$HOME/ti/sysconfig_1.18.1\" target_defines=[\"CC13X4_26X4_ATTESTATION_CREDENTIALS=1\"] chip_generate_link_map_file=true" + + ``` + +## Programming + +Loading the built image onto a LaunchPad is supported through two methods; +Uniflash and Code Composer Studio (CCS). UniFlash can be used to load the image. +Code Composer Studio can be used to load the image and debug the source code. + +### Code Composer Studio + +Programming with CCS will allow for a full debug environment within the IDE. +This is accomplished by creating a target connection to the XDS110 debugger and +starting a project-less debug session. The CCS IDE will attempt to find the +source files on the local machine based on the debug information embedded within +the ELF. CCS may prompt you to find the source code if the image was built on +another machine or the source code is located in a different location than is +recorded within the ELF. + +Download and install [Code Composer Studio][ccs]. + +First open CCS and create a new workspace. + +Create a target connection (sometimes called the CCXML) for your target SoC and +debugger as described in the [Manual Method][ccs_manual_method] section of the +CCS User's Guide. + +Next initiate a project-less debug session as described in the [Manual +Launch][ccs_manual_launch] section of the CCS User's Guide. + +CCS should switch to the debug view described in the [After +Launch][ccs_after_launch] section of the User's Guide. The SoC core will likely +be disconnected and symbols will not be loaded. Connect to the core as described +in the [Debug View][ccs_debug_view] section of the User's Guide. Once the core +is connected, use the `Load` button on the toolbar to load the ELF image. + +Note that the default configuration of the CCXML uses 2-wire cJTAG instead of +the full 4-wire JTAG connection to match the default jumper configuration of the +LaunchPad. + +### UniFlash + +Uniflash is Texas Instrument's uniform programming tool for embedded processors. +This will allow you to erase, flash, and inspect the SoC without setting up a +debugging environment. + +Download and install [UniFlash][uniflash]. + +First open UniFlash. Debug probes connected to the computer will usually be +displayed under the Detected Devices due to the automatic device detection +feature. If your device does not show up in this view it my be disconnected, or +you may have to create a New Configuration. If you already have a CCXML for your +SoC and debug connection you can use that in the section at the bottom. Once +your device is selected, click the `Start` button within the section to launch +the session. + +Select the ELF image to load on the device with the `Browse` button. This file +is placed in the `out/debug` folder by this guide and ends with the `*.out` file +extension. For OTA enabled applications, the standalone image will instead end +with the `*-mcuboot.hex` file extension. This this is a combined image with +application and `MCUBoot` included. The flag to enable or disable the OTA +feature is determined by "chip_enable_ota_requestor" in the application's +args.gni file. + +Finally click the `Load Image` button to load the executable image onto the +device. You should be able to see the log output over the XDS110 User UART. + +Note that programming the device through JTAG sets the Halt-in-Boot flag and may +cause issues when performing a software reset. This flag can be reset by +power-cycling the LaunchPad. + +## Viewing Logging Output + +By default the log output will be sent to the Application/User UART. Open a +terminal emulator to that port to see the output with the following options: + +| Parameter | Value | +| ------------ | -------- | +| Speed (baud) | `115200` | +| Data bits | `8` | +| Stop bits | `1` | +| Parity | `None` | +| Flow control | `None` | + +## Running the Example + +Once a device has been flashed with this example, it can now join and operate in +an existing Matter network. The following sections assume that a Matter network +is already active, and has at least one [OpenThread Border +Router][ot_border_router_setup]. + +For insight into what other components are needed to run this example, please +refer to our [Matter Getting Started Guide][matter-e2e-faq]. + +The steps below should be followed to commission the light-switch device onto +the network and control it once it has been commissioned. + +**Step 0** + +Set up the CHIP tool by following the instructions outlined in our [Matter +Getting Started Guide][matter-e2e-faq]. + +**Step 1** + +First, you will need to have a lighting app device setup and commissioned into +the Matter network. Look through the README.md file for lighting app for +building and commissioning instructions for the default lighting app. + +Commission the light-switch device onto the Matter network. Run the following +command on the CHIP tool: + +``` + +./chip-tool pairing ble-thread hex: 20202021 3840 + +``` + +Interacting with the application begins by enabling BLE advertisements and then +pairing the device into a Thread network. To provision this example onto a +Matter network, the device must be discoverable over Bluetooth LE. + +On the LaunchPad, press and hold the right button, labeled `BTN-2`, for more +than 1 second. Upon release, the Bluetooth LE advertising will begin. Once the +device is fully provisioned, BLE advertising will stop. + +Once the device has been successfully commissioned, you will see the following +message on the CHIP tool output: + +``` + +[1677648218.370754][39785:39790] CHIP:CTL: Received CommissioningComplete response, errorCode=0 +[1677648218.370821][39785:39790] CHIP:CTL: Successfully finished commissioning step 'SendComplete' + +``` + +An accompanying message will be seen from the device: + +``` + +Commissioning complete, notify platform driver to persist network credentials. + +``` + +You can check if the light-switch is able to receive commands from CHIP-TOOL by +using this command: + +``` +./chip-tool basicinformation read vendor-id 0 +``` + +**Step 2** + +Send commands to the light-switch app. + +Here is how you can bind the light-switch app to a lighting app device: + +Tell the lighting device to give the light-switch device access to it's onoff +cluster (replace <> with lighting/light-switch node IDs): + +``` +./chip-tool accesscontrol write acl '[{"fabricIndex": 1, "privilege": 5, "authMode": 2, "subjects": [112233], "targets": null}, {"fabricIndex": 1, "privilege": 3, "authMode": 2, "subjects": [], "targets": [{"cluster": 6, "endpoint": 1, "deviceType": null}]}]' 0 + +``` + +Tell the light-switch device to bind to the onoff cluster on the lighting device +(replace <> with lighting/light-switch node IDs): + +``` +./chip-tool binding write binding '[{"fabricIndex": 1, "node": , "endpoint": 1, "cluster": 6}]' 1 + +``` + +Now you can press the Right BTN on the light-switch device and it will turn ON +the RED LED on the lighting device. Press the Left BTN on the light-switch +device to turn OFF the RED LED on the lighting device. If the devices aren't +bound properly the light-switch will display on UART that the Switch On/Off +operation has been completed but the lighting device's LEDs will not turn on/off +accordingly. + +## TI Support + +For technical support, please consider creating a post on TI's [E2E forum][e2e]. +Additionally, we welcome any feedback. + +[matter]: https://csa-iot.org/all-solutions/matter/ +[ccs]: https://www.ti.com/tool/CCSTUDIO +[ccs_after_launch]: + https://software-dl.ti.com/ccs/esd/documents/users_guide/ccs_debug-main.html?configuration#after-launch +[ccs_debug_view]: + https://software-dl.ti.com/ccs/esd/documents/users_guide/ccs_debug-main.html?configuration#debug-view +[ccs_manual_launch]: + https://software-dl.ti.com/ccs/esd/documents/users_guide/ccs_debug-main.html?configuration#manual-launch +[ccs_manual_method]: + https://software-dl.ti.com/ccs/esd/documents/users_guide/ccs_debug-main.html?configuration#manual-method +[e2e]: + https://e2e.ti.com/support/wireless-connectivity/zigbee-thread-group/zigbee-and-thread/f/zigbee-thread-forum +[matter-e2e-faq]: + https://e2e.ti.com/support/wireless-connectivity/zigbee-thread-group/zigbee-and-thread/f/zigbee-thread-forum/1082428/faq-cc2652r7-matter----getting-started-guide +[sysconfig]: https://www.ti.com/tool/SYSCONFIG +[ti_thread_dnd]: + https://www.ti.com/wireless-connectivity/thread/design-development.html +[ot_border_router_setup]: https://openthread.io/guides/border-router/build +[uniflash]: https://www.ti.com/tool/download/UNIFLASH diff --git a/examples/light-switch-app/cc13x4_26x4/args.gni b/examples/light-switch-app/cc13x4_26x4/args.gni new file mode 100644 index 00000000000000..1223bfef03d761 --- /dev/null +++ b/examples/light-switch-app/cc13x4_26x4/args.gni @@ -0,0 +1,74 @@ +# Copyright (c) 2020 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. + +import("//build_overrides/chip.gni") +import("//build_overrides/freertos.gni") +import("${chip_root}/config/standalone/args.gni") +import("${chip_root}/examples/platform/cc13x4_26x4/args.gni") + +ti_simplelink_sdk_target = get_label_info(":sdk", "label_no_toolchain") +ti_simplelink_sysconfig_target = + get_label_info(":sysconfig", "label_no_toolchain") + +ti_simplelink_board = "LP_EM_CC1354P10_6" + +# Size Optimizations +# use -Os instead of -Og, LWIP release build +optimize_debug_level = "s" +lwip_debug = false + +chip_enable_ota_requestor = true + +chip_openthread_ftd = true + +ot_ti_lib_dir = "" +openthread_external_platform = + "${chip_root}/third_party/openthread/platforms/ti:libopenthread-ti" + +# When using TI Certified Openthread libs set to ${chip_root}/third_party/openthread/platforms/ti:ot-ti-cert +# For source builds, set to empty string. +chip_openthread_target = + "${chip_root}/third_party/openthread/platforms/ti:ot-ti-cert" + +# Enable CHIP Logging +chip_progress_logging = true +chip_detail_logging = true +chip_automation_logging = true + +# BLE options +chip_config_network_layer_ble = true + +# Disable lock tracking, since our FreeRTOS configuration does not set +# INCLUDE_xSemaphoreGetMutexHolder +chip_stack_lock_tracking = "none" + +matter_device_vid = "0xFFF1" +matter_device_pid = "0x8004" +matter_software_ver = "0x0001" +matter_software_ver_str = "1.0.1+1" + +custom_factory_data = false + +# ICD Default configurations +# when enabled the device will be configured as a sleepy end device +chip_enable_icd_server = false +chip_persist_subscriptions = false +chip_subscription_timeout_resumption = false + +freertos_root = "//third_party/connectedhomeip/third_party/ti_simplelink_sdk/repo_cc13xx_cc26xx/source/third_party/freertos" + +if (chip_openthread_target != "") { + openthread_root = + "//third_party/connectedhomeip/third_party/openthread/ot-ti/openthread" +} diff --git a/examples/light-switch-app/cc13x4_26x4/build_overrides b/examples/light-switch-app/cc13x4_26x4/build_overrides new file mode 120000 index 00000000000000..e578e73312ebd1 --- /dev/null +++ b/examples/light-switch-app/cc13x4_26x4/build_overrides @@ -0,0 +1 @@ +../../build_overrides \ No newline at end of file diff --git a/examples/light-switch-app/cc13x4_26x4/chip.syscfg b/examples/light-switch-app/cc13x4_26x4/chip.syscfg new file mode 100644 index 00000000000000..e4ae2b6acfbbd2 --- /dev/null +++ b/examples/light-switch-app/cc13x4_26x4/chip.syscfg @@ -0,0 +1,241 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * All rights reserved. + * + * 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. + */ + + +/* Modules */ +var AESCCM = scripting.addModule("/ti/drivers/AESCCM"); +var AESECB = scripting.addModule("/ti/drivers/AESECB"); +var Button = scripting.addModule("/ti/drivers/apps/Button"); +var LED = scripting.addModule("/ti/drivers/apps/LED"); +var NVS = scripting.addModule("/ti/drivers/NVS"); +var RF = scripting.addModule("/ti/drivers/RF"); +var RFDesign = scripting.addModule("ti/devices/radioconfig/rfdesign"); +var RFCustom = scripting.addModule("/ti/devices/radioconfig/custom"); +var TRNG = scripting.addModule("/ti/drivers/TRNG"); +var SHA2 = scripting.addModule("/ti/drivers/SHA2"); +var UART2 = scripting.addModule("/ti/drivers/UART2"); +var ble = scripting.addModule("/ti/ble5stack/ble"); +var dmm = scripting.addModule("/ti/dmm/dmm"); +var AESCTRDRBG = scripting.addModule("/ti/drivers/AESCTRDRBG"); +var ECDH = scripting.addModule("/ti/drivers/ECDH"); + +/* Instances */ +var AESCCM1 = AESCCM.addInstance(); +var AESECB1 = AESECB.addInstance(); +var AESECB2 = AESECB.addInstance(); +var Button1 = Button.addInstance(); +var Button2 = Button.addInstance(); +var NVS1 = NVS.addInstance(); +var NVS2 = NVS.addInstance(); +var SHA21 = SHA2.addInstance(); +var LED1 = LED.addInstance(); +var LED2 = LED.addInstance(); +var TRNG1 = TRNG.addInstance(); +var TRNG2 = TRNG.addInstance(); +var TRNG3 = TRNG.addInstance(); +var UART2 = UART2.addInstance(); +var AESCTRDRBG1 = AESCTRDRBG.addInstance(); +var ECDH1 = ECDH.addInstance(); + +AESCTRDRBG1.$name = "CONFIG_AESCTRDRBG_0"; + +AESCCM1.$name = "CONFIG_AESCCM0"; + +AESECB1.$name = "CONFIG_AESECB0"; +AESECB2.$name = "CONFIG_AESECB_1"; + +ECDH1.$name = "CONFIG_ECDH0"; + +/* Left Button */ +Button1.$name = "CONFIG_BTN_LEFT"; +Button1.$hardware = system.deviceData.board.components["BTN-1"]; +Button1.gpioPin.$name = "CONFIG_GPIO_BTN1"; +Button1.gpioPin.pull = "Pull Up"; +Button1.gpioPin.interruptTrigger = "Falling Edge"; + +/* Left Button */ +Button2.$name = "CONFIG_BTN_RIGHT"; +Button2.$hardware = system.deviceData.board.components["BTN-2"]; +Button2.gpioPin.$name = "CONFIG_GPIO_BTN2"; +Button2.gpioPin.pull = "Pull Up"; +Button2.gpioPin.interruptTrigger = "Falling Edge"; + +/* ======== CCFG ======== */ +var CCFG = scripting.addModule("/ti/devices/CCFG"); +const ccfgSettings = system.getScript("/ti/common/lprf_ccfg_settings.js").ccfgSettings; +for(var setting in ccfgSettings) +{ + CCFG[setting] = ccfgSettings[setting]; +} + +/* disable CCFG for OTA-able application */ +CCFG.enableCodeGeneration = false; + + +/* NVS */ +NVS1.$name = "CONFIG_NVSINTERNAL"; +NVS1.internalFlash.regionBase = 0xFB800; +NVS1.internalFlash.regionSize = 0x2800; + + +NVS2.$name = "CONFIG_NVSEXTERNAL"; +NVS2.nvsType = "External"; // NVS Region Type +NVS2.$hardware = system.deviceData.board.components.MX25R8035F; + +/* RF */ +/* if an antenna component exists, assign it to the rf instance */ +if (system.deviceData.board && system.deviceData.board.components.RF) { + RF.$hardware = system.deviceData.board.components.RF; +} + +const rfDesignSettings = system.getScript("/ti/common/lprf_rf_design_settings.js").rfDesignSettings; +for(var setting in rfDesignSettings) +{ + RFDesign[setting] = rfDesignSettings[setting]; +} + + + +/* Handling for RF frontend characterization */ +if(RFDesign.rfDesign.match(/LP_CC2652PSIP/)) +{ + RFCustom.ieee = ["ieee154p10"]; + var rfCodeExportConfig = RFCustom.radioConfigieee154p10.codeExportConfig +} +else +{ + RFCustom.ieee = ["ieee154"]; + var rfCodeExportConfig = RFCustom.radioConfigieee154.codeExportConfig +} + +var cmdList = [ + "cmdIeeeTx", + "cmdIeeeRx", + "cmdIeeeCsma", + "cmdIeeeEdScan", + "cmdIeeeRxAck", + "cmdTxTest" +]; + +rfCodeExportConfig.useConst = true; +rfCodeExportConfig.useMulti = true; +rfCodeExportConfig.symGenMethod = "Custom"; + +const deviceId = system.deviceData.deviceId; + +// Add high PA options if present +if(deviceId.match(/CC(265[12]R|2674R|1352R1|1354R)/)) +{ + cmdList.push("cmdRadioSetup"); + rfCodeExportConfig.cmdRadioSetup = "RF_cmdIeeeRadioSetup"; +} +else if(deviceId.match(/CC(265[12]P|2674P|1352P)/)) +{ + cmdList.push("cmdRadioSetupPa"); + rfCodeExportConfig.cmdRadioSetupPa = "RF_cmdIeeeRadioSetup"; + rfCodeExportConfig.paExport = "combined"; +} +else if(deviceId.match(/CC(265[34]|1354)P/)) +{ + cmdList.push("cmdRadioSetupPa"); + rfCodeExportConfig.cmdRadioSetupPa = "RF_cmdIeeeRadioSetup"; + // currently not characterized for high PA +} +else +{ + throw new Error("Could not match platform to any known platform types"); +} + +rfCodeExportConfig.cmdList_ieee_15_4 = cmdList; + +/* Red LED */ +LED1.$name = "CONFIG_LED_RED"; +LED1.$hardware = system.deviceData.board.components.LED_RED; +LED1.gpioPin.$name = "CONFIG_GPIO_RLED"; +LED1.gpioPin.mode = "Output"; + +/* Green LED */ +LED2.$name = "CONFIG_LED_GREEN"; +LED2.$hardware = system.deviceData.board.components.LED_GREEN; +LED2.gpioPin.$name = "CONFIG_GPIO_GLED"; +LED2.gpioPin.mode = "Output"; + +/* Debug UART */ +UART2.$hardware = system.deviceData.board.components.XDS110UART; +UART2.$name = "CONFIG_UART2_DEBUG"; + +/* TRNG */ +TRNG1.$name = "CONFIG_TRNG_0"; +TRNG2.$name = "CONFIG_TRNG_THREAD"; +TRNG3.$name = "CONFIG_TRNG_APP"; + +/* BLE */ +ble.addressMode = "ADDRMODE_RP_WITH_PUBLIC_ID"; +ble.maxConnNum = 1; +ble.numOfAdvSets = 1; +ble.lockProject = true; +ble.oneLibSizeOpt = true; +ble.maxPDUSize = 255; +ble.radioConfig.codeExportConfig.$name = "ti_devices_radioconfig_code_export_param1"; +ble.connUpdateParamsPeripheral.$name = "ti_ble5stack_general_ble_conn_update_params0"; +ble.connUpdateParamsPeripheral.reqMinConnInt = 30; +ble.connUpdateParamsPeripheral.reqMaxConnInt = 50; + +ble.advSet1.$name = "ti_ble5stack_broadcaster_advertisement_set0"; +ble.advSet1.advParam1.$name = "ti_ble5stack_broadcaster_advertisement_params0"; + +ble.rfDesign = "LP_EM_CC1354P10_6"; + +ble.thorPg = 2; +/* DMM */ +dmm.project = "ti_thread_thermostat_remote_display"; +dmm.stackRoles = ["blePeripheral","threadFTD"]; +dmm.lockStackRoles = true; +dmm.numApplicationStates = 10; +dmm.applicationState0 = "ANY"; +dmm.applicationState1 = "DMMPOLICY_BLE_IDLE"; +dmm.applicationState2 = "DMMPOLICY_BLE_ADV"; +dmm.applicationState3 = "DMMPOLICY_BLE_CONNECTING"; +dmm.applicationState4 = "DMMPOLICY_BLE_HIGH_BANDWIDTH"; +dmm.applicationState5 = "DMMPOLICY_BLE_CONNECTED"; +dmm.applicationState6 = "DMMPOLICY_BLE_OAD"; +dmm.applicationState7 = "DMMPOLICY_THREAD_IDLE"; +dmm.applicationState8 = "DMMPOLICY_THREAD_LINK_EST"; +dmm.applicationState9 = "DMMPOLICY_THREAD_DATA"; +dmm.policyArray.create(4); +dmm.policyArray[0].$name = "ti_dmm_policy_dmm_policy0"; +dmm.policyArray[0].blePeripheral.$name = "ti_dmm_policy_stack_dmm_stack_ble0"; +dmm.policyArray[0].blePeripheral.applicationStates = ["applicationState6"]; +dmm.policyArray[0].threadFTD.$name = "ti_dmm_policy_stack_dmm_stack_thread0"; +dmm.policyArray[0].threadFTD.pause = "DMMPOLICY_PAUSED"; +dmm.policyArray[1].$name = "ti_dmm_policy_dmm_policy1"; +dmm.policyArray[1].blePeripheral.$name = "ti_dmm_policy_stack_dmm_stack_ble1"; +dmm.policyArray[1].blePeripheral.applicationStates = ["applicationState3","applicationState4"]; +dmm.policyArray[1].blePeripheral.weight = 25; +dmm.policyArray[1].blePeripheral.appliedActivity = ["DMMPOLICY_APPLIED_ACTIVITY_BLE_CONNECTION"]; +dmm.policyArray[1].threadFTD.$name = "ti_dmm_policy_stack_dmm_stack_thread1"; +dmm.policyArray[2].$name = "ti_dmm_policy_dmm_policy2"; +dmm.policyArray[2].blePeripheral.$name = "ti_dmm_policy_stack_dmm_stack_ble2"; +dmm.policyArray[2].threadFTD.$name = "ti_dmm_policy_stack_dmm_stack_thread2"; +dmm.policyArray[2].threadFTD.weight = 30; +dmm.policyArray[2].threadFTD.applicationStates = ["applicationState8"]; +dmm.policyArray[2].threadFTD.appliedActivity = ["DMMPOLICY_APPLIED_ACTIVITY_ALL"]; +dmm.policyArray[3].$name = "ti_dmm_policy_dmm_policy3"; +dmm.policyArray[3].blePeripheral.$name = "ti_dmm_policy_stack_dmm_stack_ble3"; +dmm.policyArray[3].threadFTD.$name = "ti_dmm_policy_stack_dmm_stack_thread3"; +dmm.policyArray[3].threadFTD.weight = 1; diff --git a/examples/light-switch-app/cc13x4_26x4/include/CHIPProjectConfig.h b/examples/light-switch-app/cc13x4_26x4/include/CHIPProjectConfig.h new file mode 100644 index 00000000000000..88e08c63321770 --- /dev/null +++ b/examples/light-switch-app/cc13x4_26x4/include/CHIPProjectConfig.h @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2019 Google LLC. + * All rights reserved. + * + * 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. + */ + +/** + * @file + * Example project configuration file for CHIP. + * + * This is a place to put application or project-specific overrides + * to the default configuration values for general CHIP features. + * + */ + +#ifndef CHIP_PROJECT_CONFIG_H +#define CHIP_PROJECT_CONFIG_H + +#if BUILD_RELEASE // release build +// Note: Default Pairing/PIN/Serial Numbers being used. These should not be enabled for production builds +#endif // BUILD_RELEASE + +// Use a default pairing code if one hasn't been provisioned in flash. +#define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE 20202021 +#define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR 0xF00 + +/** + * CHIP_DEVICE_CONFIG_TEST_SERIAL_NUMBER + * + * Enables the use of a hard-coded default serial number if none + * is found in CHIP NV storage. + */ +#define CHIP_DEVICE_CONFIG_TEST_SERIAL_NUMBER "TEST_SN" + +/** + * CHIP_DEVICE_CONFIG_DEVICE_HARDWARE_VERSION + * + * The hardware version number assigned to device or product by the device vendor. This + * number is scoped to the device product id, and typically corresponds to a revision of the + * physical device, a change to its packaging, and/or a change to its marketing presentation. + * This value is generally *not* incremented for device software versions. + */ +#ifndef CHIP_DEVICE_CONFIG_DEVICE_HARDWARE_VERSION +#define CHIP_DEVICE_CONFIG_DEVICE_HARDWARE_VERSION 1 +#endif + +/** + * Values set by args.gni: + * CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID + * CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_ID + * CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING + * CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION + */ + +/** + * CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE + * + * Enable support for CHIP-over-BLE (CHIPOBLE). + */ +#define CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE 1 + +/** + * CHIP_DEVICE_CONFIG_EVENT_LOGGING_DEBUG_BUFFER_SIZE + * + * A size, in bytes, of the individual debug event logging buffer. + */ +#define CHIP_DEVICE_CONFIG_EVENT_LOGGING_DEBUG_BUFFER_SIZE (512) + +#define MATTER_CC13XX_26XX_PLATFORM_LOG_ENABLED 1 + +/** + * CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT + * + * Enable the OpenThread SRP client to allow for CHIP device discovery. + */ +#define CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT 1 + +/** + * CHIP_CONFIG_EVENT_LOGGING_DEFAULT_IMPORTANCE + * + * For a development build, set the default importance of events to be logged as Debug. + * Since debug is the lowest importance level, this means all standard, critical, info and + * debug importance level vi events get logged. + */ +#if BUILD_RELEASE +#define CHIP_CONFIG_EVENT_LOGGING_DEFAULT_IMPORTANCE chip::Profiles::DataManagement::Production +#else +#define CHIP_CONFIG_EVENT_LOGGING_DEFAULT_IMPORTANCE chip::Profiles::DataManagement::Debug +#endif // BUILD_RELEASE + +#define CHIP_DEVICE_CONFIG_ENABLE_EXTENDED_DISCOVERY 1 + +/** + * @def CHIP_IM_MAX_NUM_COMMAND_HANDLER + * + * @brief Defines the maximum number of CommandHandler, limits the number of active commands transactions on server. + */ +#define CHIP_IM_MAX_NUM_COMMAND_HANDLER 2 + +/** + * @def CHIP_IM_MAX_NUM_WRITE_HANDLER + * + * @brief Defines the maximum number of WriteHandler, limits the number of active write transactions on server. + */ +#define CHIP_IM_MAX_NUM_WRITE_HANDLER 2 + +#endif // CHIP_PROJECT_CONFIG_H diff --git a/examples/light-switch-app/cc13x4_26x4/src/AppConfig.h b/examples/light-switch-app/cc13x4_26x4/src/AppConfig.h new file mode 100644 index 00000000000000..a818b21d641875 --- /dev/null +++ b/examples/light-switch-app/cc13x4_26x4/src/AppConfig.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2020 Project CHIP Authors + * All rights reserved. + * + * 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. + */ + +#ifndef APP_CONFIG_H +#define APP_CONFIG_H + +// Logging +#ifdef __cplusplus +extern "C" { +#endif + +int cc13xx_26xxLogInit(void); +void cc13xx_26xxLog(const char * aFormat, ...); +#define PLAT_LOG(...) cc13xx_26xxLog(__VA_ARGS__); + +#define ACTUATOR_MOVEMENT_PERIOD_MS 1000 + +#ifdef __cplusplus +} +#endif +#endif // APP_CONFIG_H diff --git a/examples/light-switch-app/cc13x4_26x4/src/AppEvent.h b/examples/light-switch-app/cc13x4_26x4/src/AppEvent.h new file mode 100644 index 00000000000000..07f414bd414dc7 --- /dev/null +++ b/examples/light-switch-app/cc13x4_26x4/src/AppEvent.h @@ -0,0 +1,86 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * All rights reserved. + * + * 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. + */ + +#ifndef APP_EVENT_H +#define APP_EVENT_H + +struct AppEvent; +typedef void (*EventHandler)(AppEvent *); + +struct AppEvent +{ + enum AppEventType + { + kEventType_None = 0, + kEventType_ButtonLeft, + kEventType_ButtonRight, + kEventType_AppEvent, + kEventType_IdentifyStart, + kEventType_IdentifyStop, + kEventType_Light, + kEventType_Timer, + kEventType_Identify, + }; + + enum AppEventButtonType + { + kAppEventButtonType_None = 0, + kAppEventButtonType_Clicked, + kAppEventButtonType_LongClicked, + }; + + enum AppEventIdentifyType + { + kAppEventIdentifyType_Blink = 0, + kAppEventIdentifyType_Breathe, + kAppEventIdentifyType_Okay, + kAppEventIdentifyType_Finish, + kAppEventIdentifyType_Stop, + }; + + enum AppEventType Type; + + union + { + struct + { + enum AppEventButtonType Type; + } ButtonEvent; + + struct + { + void * Context; + } TimerEvent; + + struct + { + uint8_t Action; + int32_t Actor; + void * Context; + } LightSwitchEvent; + + struct + { + enum AppEventIdentifyType Type; + } IdentifyEvent; + }; + + EventHandler Handler; +}; + +#endif // APP_EVENT_H diff --git a/examples/light-switch-app/cc13x4_26x4/src/AppTask.cpp b/examples/light-switch-app/cc13x4_26x4/src/AppTask.cpp new file mode 100644 index 00000000000000..eec72be98096b7 --- /dev/null +++ b/examples/light-switch-app/cc13x4_26x4/src/AppTask.cpp @@ -0,0 +1,722 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * All rights reserved. + * + * 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 "AppTask.h" +#include "AppConfig.h" +#include "AppEvent.h" +#include +#include + +#include "FreeRTOS.h" + +#include +#include +#include + +#include +#include + +#if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR +#include +#include +#include +#include +#include +#endif + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +/* syscfg */ +#include + +#define APP_TASK_STACK_SIZE (4096) +#define APP_TASK_PRIORITY 4 +#define APP_EVENT_QUEUE_SIZE 10 + +#define IDENTIFY_TRIGGER_EFFECT_BLINK 0 +#define IDENTIFY_TRIGGER_EFFECT_BREATHE 1 +#define IDENTIFY_TRIGGER_EFFECT_OKAY 2 +#define IDENTIFY_TRIGGER_EFFECT_FINISH_STOP 3 + +static uint32_t identify_trigger_effect = IDENTIFY_TRIGGER_EFFECT_FINISH_STOP; + +#define SWITCH_APPLICATION_IDENTIFY_ENDPOINT 1 + +#if (CHIP_CONFIG_ENABLE_ICD_SERVER == 1) +#define LED_ENABLE 0 +#else +#define LED_ENABLE 1 +#endif +#define BUTTON_ENABLE 1 + +#define OTAREQUESTOR_INIT_TIMER_DELAY_MS 10000 + +using namespace ::chip; +using namespace ::chip::app; +using namespace ::chip::Credentials; +using namespace ::chip::DeviceLayer; + +static TaskHandle_t sAppTaskHandle; +static QueueHandle_t sAppEventQueue; + +#if (LED_ENABLE == 1) +static LED_Handle sAppRedHandle; +static LED_Handle sAppGreenHandle; +#endif +static Button_Handle sAppLeftHandle; +static Button_Handle sAppRightHandle; + +static DeviceInfoProviderImpl sExampleDeviceInfoProvider; + +AppTask AppTask::sAppTask; + +void uiSwitchOnStart(void); +void uiSwitchOnDone(void); +void uiSwitchOffStart(void); +void uiSwitchOffDone(void); + +#if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR +void StartTimer(uint32_t aTimeoutMs); +void CancelTimer(void); +#endif + +uint8_t sTestEventTriggerEnableKey[TestEventTriggerDelegate::kEnableKeyLength] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff }; + +#if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR +static DefaultOTARequestor sRequestorCore; +static DefaultOTARequestorStorage sRequestorStorage; +static DefaultOTARequestorDriver sRequestorUser; +static BDXDownloader sDownloader; +static OTAImageProcessorImpl sImageProcessor; + +void InitializeOTARequestor(void) +{ + // Initialize and interconnect the Requestor and Image Processor objects + SetRequestorInstance(&sRequestorCore); + + sRequestorStorage.Init(Server::GetInstance().GetPersistentStorage()); + sRequestorCore.Init(Server::GetInstance(), sRequestorStorage, sRequestorUser, sDownloader); + sImageProcessor.SetOTADownloader(&sDownloader); + sDownloader.SetImageProcessorDelegate(&sImageProcessor); + sRequestorUser.Init(&sRequestorCore, &sImageProcessor); +} + +TimerHandle_t sOTAInitTimer = 0; +#endif + +// The OTA Init Timer is only started upon the first Thread State Change +// detected if the device is already on a Thread Network, or during the AppTask +// Init sequence if the device is not yet on a Thread Network. Once the timer +// has been started once, it does not need to be started again so the flag will +// be set to false. +bool isAppStarting = true; + +::Identify stIdentify = { SWITCH_APPLICATION_IDENTIFY_ENDPOINT, AppTask::IdentifyStartHandler, AppTask::IdentifyStopHandler, + Clusters::Identify::IdentifyTypeEnum::kVisibleIndicator, AppTask::TriggerIdentifyEffectHandler }; + +int AppTask::StartAppTask() +{ + int ret = 0; + + sAppEventQueue = xQueueCreate(APP_EVENT_QUEUE_SIZE, sizeof(AppEvent)); + if (sAppEventQueue == NULL) + { + PLAT_LOG("Failed to allocate app event queue"); + while (1) + ; + } + + // Start App task. + if (xTaskCreate(AppTaskMain, "APP", APP_TASK_STACK_SIZE / sizeof(StackType_t), NULL, APP_TASK_PRIORITY, &sAppTaskHandle) != + pdPASS) + { + PLAT_LOG("Failed to create app task"); + while (1) + ; + } + return ret; +} + +// Identify take action +void identify_TakeAction(void) +{ +#if (LED_ENABLE == 1) + LED_setOn(sAppGreenHandle, LED_BRIGHTNESS_MAX); + LED_startBlinking(sAppGreenHandle, 1000, LED_BLINK_FOREVER); +#endif // LED_ENABLE +} + +// Identify stop action +void identify_StopAction(void) +{ +#if (LED_ENABLE == 1) + LED_stopBlinking(sAppGreenHandle); + LED_setOff(sAppGreenHandle); +#endif // LED_ENABLE +} + +void DeviceEventCallback(const ChipDeviceEvent * event, intptr_t arg) +{ + switch (event->Type) + { + case DeviceEventType::kCHIPoBLEConnectionEstablished: + PLAT_LOG("CHIPoBLE connection established"); + break; + + case DeviceEventType::kCHIPoBLEConnectionClosed: + PLAT_LOG("CHIPoBLE disconnected"); + break; + + case DeviceEventType::kCommissioningComplete: + PLAT_LOG("Commissioning complete"); + break; + case DeviceEventType::kThreadStateChange: + PLAT_LOG("Thread State Change"); + bool isThreadAttached = ThreadStackMgrImpl().IsThreadAttached(); + + if (isThreadAttached) + { + PLAT_LOG("Device is on the Thread Network"); +#if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR + if (isAppStarting) + { + StartTimer(OTAREQUESTOR_INIT_TIMER_DELAY_MS); + isAppStarting = false; + } +#endif + } + break; + } +} + +#if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR +void OTAInitTimerEventHandler(TimerHandle_t xTimer) +{ + InitializeOTARequestor(); +} +#endif + +int AppTask::Init() +{ + cc13xx_26xxLogInit(); + + // Init Chip memory management before the stack + Platform::MemoryInit(); + + PLAT_LOG("Software Version: %d", CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION); + PLAT_LOG("Software Version String: %s", CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING); + + CHIP_ERROR ret = PlatformMgr().InitChipStack(); + if (ret != CHIP_NO_ERROR) + { + PLAT_LOG("PlatformMgr().InitChipStack() failed"); + while (1) + ; + } +#if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR + // Create FreeRTOS sw timer for OTA timer. + sOTAInitTimer = xTimerCreate("OTAInitTmr", // Just a text name, not used by the RTOS kernel + OTAREQUESTOR_INIT_TIMER_DELAY_MS, // timer period (mS) + false, // no timer reload (==one-shot) + (void *) this, // init timer id = light obj context + OTAInitTimerEventHandler // timer callback handler + ); + + if (sOTAInitTimer == NULL) + { + PLAT_LOG("sOTAInitTimer timer create failed"); + } + else + { + PLAT_LOG("sOTAInitTimer timer created successfully "); + } +#endif + + ret = ThreadStackMgr().InitThreadStack(); + if (ret != CHIP_NO_ERROR) + { + PLAT_LOG("ThreadStackMgr().InitThreadStack() failed"); + while (1) + ; + } +#if CHIP_DEVICE_CONFIG_THREAD_FTD + ret = ConnectivityMgr().SetThreadDeviceType(ConnectivityManager::kThreadDeviceType_Router); +#elif CHIP_CONFIG_ENABLE_ICD_SERVER + ret = ConnectivityMgr().SetThreadDeviceType(ConnectivityManager::kThreadDeviceType_SleepyEndDevice); +#else + ret = ConnectivityMgr().SetThreadDeviceType(ConnectivityManager::kThreadDeviceType_MinimalEndDevice); +#endif + + if (ret != CHIP_NO_ERROR) + { + PLAT_LOG("ConnectivityMgr().SetThreadDeviceType() failed"); + while (1) + ; + } + + ret = ThreadStackMgrImpl().StartThreadTask(); + if (ret != CHIP_NO_ERROR) + { + PLAT_LOG("ThreadStackMgr().StartThreadTask() failed"); + while (1) + ; + } + + // Initialize device attestation config +#ifdef CC13X4_26X4_ATTESTATION_CREDENTIALS +#ifdef CC13XX_26XX_FACTORY_DATA + SetDeviceInstanceInfoProvider(&mFactoryDataProvider); + SetDeviceAttestationCredentialsProvider(&mFactoryDataProvider); + SetCommissionableDataProvider(&mFactoryDataProvider); +#else + SetDeviceAttestationCredentialsProvider(CC13X4_26X4::GetCC13X4_26X4DacProvider()); +#endif +#else + SetDeviceAttestationCredentialsProvider(Examples::GetExampleDACProvider()); +#endif + + // Init ZCL Data Model and start server + PLAT_LOG("Initialize Server"); + static CommonCaseDeviceServerInitParams initParams; + static DefaultTestEventTriggerDelegate sTestEventTriggerDelegate{ ByteSpan(sTestEventTriggerEnableKey) }; + initParams.testEventTriggerDelegate = &sTestEventTriggerDelegate; + (void) initParams.InitializeStaticResourcesBeforeServerInit(); + + // Initialize info provider + sExampleDeviceInfoProvider.SetStorageDelegate(initParams.persistentStorageDelegate); + SetDeviceInfoProvider(&sExampleDeviceInfoProvider); + + Server::GetInstance().Init(initParams); + + ret = PlatformMgr().StartEventLoopTask(); + if (ret != CHIP_NO_ERROR) + { + PLAT_LOG("PlatformMgr().StartEventLoopTask() failed"); + while (1) + ; + } + + PlatformMgr().AddEventHandler(DeviceEventCallback, reinterpret_cast(nullptr)); + + uiInit(); + + PlatformMgr().LockChipStack(); + { + ret = LightSwitchMgr().Init(); + } + + PlatformMgr().UnlockChipStack(); + + if (ret != CHIP_NO_ERROR) + { + PLAT_LOG("LightSwitchMgr().Init() failed"); + while (1) + ; + } + + LightSwitchMgr().SetCallbacks(ActionInitiated, ActionCompleted); + + ConfigurationMgr().LogDeviceConfig(); + + bool isThreadEnabled = ThreadStackMgrImpl().IsThreadEnabled(); + if (!isThreadEnabled && isAppStarting) + { +#if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR + PLAT_LOG("Thread is Disabled, enable OTA Requestor"); + StartTimer(OTAREQUESTOR_INIT_TIMER_DELAY_MS); + isAppStarting = false; +#endif + } + + // QR code will be used with CHIP Tool + PrintOnboardingCodes(RendezvousInformationFlags(RendezvousInformationFlag::kBLE)); + + return 0; +} + +void AppTask::AppTaskMain(void * pvParameter) +{ + AppEvent event; + + sAppTask.Init(); + + while (1) + { + /* Task pend until we have stuff to do */ + if (xQueueReceive(sAppEventQueue, &event, portMAX_DELAY) == pdTRUE) + { + sAppTask.DispatchEvent(&event); + } + } +} + +#if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR +void StartTimer(uint32_t aTimeoutMs) +{ + PLAT_LOG("Start OTA Init Timer") + if (xTimerIsTimerActive(sOTAInitTimer)) + { + PLAT_LOG("app timer already started!"); + CancelTimer(); + } + + // timer is not active, change its period to required value (== restart). + // FreeRTOS- Block for a maximum of 100 ticks if the change period command + // cannot immediately be sent to the timer command queue. + if (xTimerChangePeriod(sOTAInitTimer, pdMS_TO_TICKS(aTimeoutMs), 100) != pdPASS) + { + PLAT_LOG("sOTAInitTimer timer start() failed"); + } +} + +void CancelTimer(void) +{ + if (xTimerStop(sOTAInitTimer, 0) == pdFAIL) + { + PLAT_LOG("sOTAInitTimer stop() failed"); + } +} +#endif +void AppTask::ActionInitiated(LightSwitchManager::Action_t aAction, int32_t aActor) +{ + if (aAction == LightSwitchManager::SWITCH_ON_ACTION) + { + uiSwitchOnStart(); + } + else if (aAction == LightSwitchManager::SWITCH_OFF_ACTION) + { + uiSwitchOffStart(); + } +} + +void AppTask::ActionCompleted(LightSwitchManager::Action_t aAction) +{ + if (aAction == LightSwitchManager::SWITCH_ON_ACTION) + { + uiSwitchOnDone(); + } + else if (aAction == LightSwitchManager::SWITCH_OFF_ACTION) + { + uiSwitchOffDone(); + } +} + +void AppTask::PostEvent(const AppEvent * aEvent) +{ + if (sAppEventQueue != NULL) + { + BaseType_t status; + if (xPortIsInsideInterrupt()) + { + BaseType_t higherPrioTaskWoken = pdFALSE; + status = xQueueSendFromISR(sAppEventQueue, aEvent, &higherPrioTaskWoken); + +#ifdef portYIELD_FROM_ISR + portYIELD_FROM_ISR(higherPrioTaskWoken); +#elif portEND_SWITCHING_ISR // portYIELD_FROM_ISR or portEND_SWITCHING_ISR + portEND_SWITCHING_ISR(higherPrioTaskWoken); +#else // portYIELD_FROM_ISR or portEND_SWITCHING_ISR +#error "Must have portYIELD_FROM_ISR or portEND_SWITCHING_ISR" +#endif // portYIELD_FROM_ISR or portEND_SWITCHING_ISR + } + else + { + status = xQueueSend(sAppEventQueue, aEvent, 1); + } + + if (status != pdTRUE) + { + PLAT_LOG("Failed to post event to app task event queue"); + } + } + else + { + PLAT_LOG("Event Queue is NULL should never happen"); + } +} + +void AppTask::DispatchEvent(AppEvent * aEvent) +{ + int32_t actor; + + switch (aEvent->Type) + { + case AppEvent::kEventType_ButtonLeft: + if (AppEvent::kAppEventButtonType_Clicked == aEvent->ButtonEvent.Type) + { + actor = AppEvent::kEventType_ButtonLeft; + LightSwitchMgr().InitiateAction(actor, LightSwitchManager::SWITCH_OFF_ACTION); + } + else if (AppEvent::kAppEventButtonType_LongClicked == aEvent->ButtonEvent.Type) + { + chip::Server::GetInstance().ScheduleFactoryReset(); + } + break; + + case AppEvent::kEventType_ButtonRight: + if (AppEvent::kAppEventButtonType_Clicked == aEvent->ButtonEvent.Type) + { + actor = AppEvent::kEventType_ButtonRight; + LightSwitchMgr().InitiateAction(actor, LightSwitchManager::SWITCH_ON_ACTION); + } + else if (AppEvent::kAppEventButtonType_LongClicked == aEvent->ButtonEvent.Type) + { + // Enable BLE advertisements + if (!ConnectivityMgr().IsBLEAdvertisingEnabled()) + { + if (Server::GetInstance().GetCommissioningWindowManager().OpenBasicCommissioningWindow() == CHIP_NO_ERROR) + { + PLAT_LOG("Enabled BLE Advertisements"); + } + else + { + PLAT_LOG("OpenBasicCommissioningWindow() failed"); + } + } + else + { + // Disable BLE advertisements + ConnectivityMgr().SetBLEAdvertisingEnabled(false); + PLAT_LOG("Disabled BLE Advertisements"); + } + } + break; + + case AppEvent::kEventType_IdentifyStart: + switch (identify_trigger_effect) + { + case IDENTIFY_TRIGGER_EFFECT_BLINK: + identify_TakeAction(); + break; + case IDENTIFY_TRIGGER_EFFECT_BREATHE: + identify_TakeAction(); + break; + case IDENTIFY_TRIGGER_EFFECT_OKAY: + identify_TakeAction(); + break; + default: + break; + } + PLAT_LOG("Identify started"); + break; + + case AppEvent::kEventType_Identify: + // blink LED + PLAT_LOG("Identify cmd received, will blink green led three times now"); +#if (LED_ENABLE == 1) + LED_startBlinking(sAppGreenHandle, 250, 3); +#endif + break; + + case AppEvent::kEventType_IdentifyStop: +#if (LED_ENABLE == 1) + LED_stopBlinking(sAppGreenHandle); + LED_setOff(sAppGreenHandle); +#endif + PLAT_LOG("Identify stopped"); + break; + + case AppEvent::kEventType_AppEvent: + if (NULL != aEvent->Handler) + { + aEvent->Handler(aEvent); + } + break; + + case AppEvent::kEventType_None: + default: + break; + } +} + +void AppTask::IdentifyStartHandler(::Identify *) +{ + AppEvent event; + event.Type = AppEvent::kEventType_IdentifyStart; + sAppTask.PostEvent(&event); +} + +void AppTask::IdentifyStopHandler(::Identify *) +{ + AppEvent event; + event.Type = AppEvent::kEventType_IdentifyStop; + sAppTask.PostEvent(&event); +} + +void AppTask::TriggerIdentifyEffectHandler(::Identify * identify) +{ + switch (identify->mCurrentEffectIdentifier) + { + case Clusters::Identify::EffectIdentifierEnum::kBlink: + PLAT_LOG("Starting blink identifier effect"); + identify_trigger_effect = IDENTIFY_TRIGGER_EFFECT_BLINK; + IdentifyStartHandler(identify); + break; + case Clusters::Identify::EffectIdentifierEnum::kBreathe: + PLAT_LOG("Starting breathe identifier effect"); + identify_trigger_effect = IDENTIFY_TRIGGER_EFFECT_BREATHE; + IdentifyStartHandler(identify); + break; + case Clusters::Identify::EffectIdentifierEnum::kOkay: + PLAT_LOG("Starting okay identifier effect"); + identify_trigger_effect = IDENTIFY_TRIGGER_EFFECT_OKAY; + IdentifyStartHandler(identify); + break; + case Clusters::Identify::EffectIdentifierEnum::kChannelChange: + PLAT_LOG("Channel Change identifier effect not implemented"); + break; + case Clusters::Identify::EffectIdentifierEnum::kFinishEffect: + PLAT_LOG("Finish identifier effect"); + identify_trigger_effect = IDENTIFY_TRIGGER_EFFECT_FINISH_STOP; + IdentifyStopHandler(identify); + break; + case Clusters::Identify::EffectIdentifierEnum::kStopEffect: + PLAT_LOG("Stop identifier effect"); + identify_trigger_effect = IDENTIFY_TRIGGER_EFFECT_FINISH_STOP; + IdentifyStopHandler(identify); + break; + default: + PLAT_LOG("No identifier effect"); + } +} + +#if (BUTTON_ENABLE == 1) +void AppTask::ButtonLeftEventHandler(Button_Handle handle, Button_EventMask events) +{ + AppEvent event; + event.Type = AppEvent::kEventType_ButtonLeft; + + if (events & Button_EV_CLICKED) + { + event.ButtonEvent.Type = AppEvent::kAppEventButtonType_Clicked; + } + else if (events & Button_EV_LONGCLICKED) + { + event.ButtonEvent.Type = AppEvent::kAppEventButtonType_LongClicked; + } + // button callbacks are in ISR context + if (xQueueSendFromISR(sAppEventQueue, &event, NULL) != pdPASS) + { + /* Failed to post the message */ + } +} + +void AppTask::ButtonRightEventHandler(Button_Handle handle, Button_EventMask events) +{ + AppEvent event; + event.Type = AppEvent::kEventType_ButtonRight; + + if (events & Button_EV_CLICKED) + { + event.ButtonEvent.Type = AppEvent::kAppEventButtonType_Clicked; + } + else if (events & Button_EV_LONGCLICKED) + { + event.ButtonEvent.Type = AppEvent::kAppEventButtonType_LongClicked; + } + // button callbacks are in ISR context + if (xQueueSendFromISR(sAppEventQueue, &event, NULL) != pdPASS) + { + /* Failed to post the message */ + } +} +#endif // BUTTON_ENABLE + +// Action initiated callback +void uiSwitchOnStart(void) +{ + PLAT_LOG("Switch On initiated"); +} + +// Action completed callback +void uiSwitchOnDone(void) +{ + PLAT_LOG("Switch On completed"); +} + +// Action initiated callback +void uiSwitchOffStart(void) +{ + PLAT_LOG("Switch Off initiated"); +} + +// Action completed callback +void uiSwitchOffDone(void) +{ + PLAT_LOG("Switch Off completed"); +} + +void AppTask::uiInit(void) +{ +#if (LED_ENABLE == 1) + + LED_Params ledParams; + + // Initialize LEDs + PLAT_LOG("Initialize LEDs"); + LED_init(); + + LED_Params_init(&ledParams); // default PWM LED + sAppRedHandle = LED_open(CONFIG_LED_RED, &ledParams); + LED_setOff(sAppRedHandle); + + LED_Params_init(&ledParams); // default PWM LED + sAppGreenHandle = LED_open(CONFIG_LED_GREEN, &ledParams); + LED_setOff(sAppGreenHandle); +#endif // LED ENABLE + +#if (BUTTON_ENABLE == 1) + Button_Params buttonParams; + + // Initialize buttons + PLAT_LOG("Initialize buttons"); + Button_init(); + + Button_Params_init(&buttonParams); + buttonParams.buttonEventMask = Button_EV_CLICKED | Button_EV_LONGCLICKED; + buttonParams.longPressDuration = 1000U; // ms + sAppLeftHandle = Button_open(CONFIG_BTN_LEFT, &buttonParams); + Button_setCallback(sAppLeftHandle, ButtonLeftEventHandler); + + Button_Params_init(&buttonParams); + buttonParams.buttonEventMask = Button_EV_CLICKED | Button_EV_LONGCLICKED; + buttonParams.longPressDuration = 1000U; // ms + sAppRightHandle = Button_open(CONFIG_BTN_RIGHT, &buttonParams); + Button_setCallback(sAppRightHandle, ButtonRightEventHandler); +#endif // BUTTON ENABLE +} diff --git a/examples/light-switch-app/cc13x4_26x4/src/AppTask.h b/examples/light-switch-app/cc13x4_26x4/src/AppTask.h new file mode 100644 index 00000000000000..85eb6e5203ead0 --- /dev/null +++ b/examples/light-switch-app/cc13x4_26x4/src/AppTask.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2019 Google LLC. + * All rights reserved. + * + * 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 "FreeRTOS.h" +#include "semphr.h" +#include "task.h" + +#include "AppEvent.h" +#include "LightSwitchManager.h" + +#include + +#ifdef CC13XX_26XX_FACTORY_DATA +#include +#endif + +// Application-defined error codes in the CHIP_ERROR space. +#define APP_ERROR_EVENT_QUEUE_FAILED CHIP_APPLICATION_ERROR(0x01) +#define APP_ERROR_CREATE_TASK_FAILED CHIP_APPLICATION_ERROR(0x02) +#define APP_ERROR_UNHANDLED_EVENT CHIP_APPLICATION_ERROR(0x03) +#define APP_ERROR_CREATE_TIMER_FAILED CHIP_APPLICATION_ERROR(0x04) +#define APP_ERROR_START_TIMER_FAILED CHIP_APPLICATION_ERROR(0x05) +#define APP_ERROR_STOP_TIMER_FAILED CHIP_APPLICATION_ERROR(0x06) +#define APP_ERROR_ALLOCATION_FAILED CHIP_APPLICATION_ERROR(0x07) + +struct Identify; + +class AppTask +{ + +public: + int StartAppTask(); + static void AppTaskMain(void * pvParameter); + + static AppTask & GetAppTask() { return sAppTask; } + void PostEvent(const AppEvent * event); + + static void IdentifyStartHandler(::Identify *); + static void IdentifyStopHandler(::Identify *); + static void TriggerIdentifyEffectHandler(::Identify * identify); + +private: + friend AppTask & GetAppTask(void); + + int Init(); + + static void ActionInitiated(LightSwitchManager::Action_t aAction, int32_t aActor); + static void ActionCompleted(LightSwitchManager::Action_t aAction); + + void DispatchEvent(AppEvent * event); + void uiInit(void); + static void ButtonLeftEventHandler(Button_Handle handle, Button_EventMask events); + static void ButtonRightEventHandler(Button_Handle handle, Button_EventMask events); + static void TimerEventHandler(void * p_context); + + enum Function_t + { + kFunction_NoneSelected = 0, + kFunction_SoftwareUpdate = 0, + kFunction_FactoryReset, + + kFunction_Invalid + } Function; + + Function_t mFunction; + bool mFunctionTimerActive; + + static AppTask sAppTask; + + // bool mSyncClusterToButtonAction; +#ifdef CC13XX_26XX_FACTORY_DATA + chip::DeviceLayer::FactoryDataProvider mFactoryDataProvider; +#endif +}; + +inline AppTask & GetAppTask(void) +{ + return AppTask::sAppTask; +} diff --git a/examples/light-switch-app/cc13x4_26x4/src/BindingHandler.cpp b/examples/light-switch-app/cc13x4_26x4/src/BindingHandler.cpp new file mode 100644 index 00000000000000..67fd1c9ed1dbea --- /dev/null +++ b/examples/light-switch-app/cc13x4_26x4/src/BindingHandler.cpp @@ -0,0 +1,163 @@ +/* + * + * Copyright (c) 2020 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 "BindingHandler.h" + +#include "AppConfig.h" +#include "app/CommandSender.h" +#include "app/clusters/bindings/BindingManager.h" +#include "app/server/Server.h" +#include "controller/InvokeInteraction.h" +#include "platform/CHIPDeviceLayer.h" +#include +#include +#include + +using namespace chip; +using namespace chip::app; + +namespace { + +void ProcessOnOffUnicastBindingCommand(CommandId commandId, const EmberBindingTableEntry & binding, + Messaging::ExchangeManager * exchangeMgr, const SessionHandle & sessionHandle) +{ + auto onSuccess = [](const ConcreteCommandPath & commandPath, const StatusIB & status, const auto & dataResponse) { + ChipLogProgress(NotSpecified, "OnOff command succeeds"); + }; + auto onFailure = [](CHIP_ERROR error) { + ChipLogError(NotSpecified, "OnOff command failed: %" CHIP_ERROR_FORMAT, error.Format()); + }; + + switch (commandId) + { + case Clusters::OnOff::Commands::Toggle::Id: + Clusters::OnOff::Commands::Toggle::Type toggleCommand; + Controller::InvokeCommandRequest(exchangeMgr, sessionHandle, binding.remote, toggleCommand, onSuccess, onFailure); + break; + + case Clusters::OnOff::Commands::On::Id: + Clusters::OnOff::Commands::On::Type onCommand; + Controller::InvokeCommandRequest(exchangeMgr, sessionHandle, binding.remote, onCommand, onSuccess, onFailure); + break; + + case Clusters::OnOff::Commands::Off::Id: + Clusters::OnOff::Commands::Off::Type offCommand; + Controller::InvokeCommandRequest(exchangeMgr, sessionHandle, binding.remote, offCommand, onSuccess, onFailure); + break; + } +} + +void ProcessOnOffGroupBindingCommand(CommandId commandId, const EmberBindingTableEntry & binding) +{ + Messaging::ExchangeManager & exchangeMgr = Server::GetInstance().GetExchangeManager(); + switch (commandId) + { + case Clusters::OnOff::Commands::Toggle::Id: + Clusters::OnOff::Commands::Toggle::Type toggleCommand; + Controller::InvokeGroupCommandRequest(&exchangeMgr, binding.fabricIndex, binding.groupId, toggleCommand); + break; + + case Clusters::OnOff::Commands::On::Id: + Clusters::OnOff::Commands::On::Type onCommand; + Controller::InvokeGroupCommandRequest(&exchangeMgr, binding.fabricIndex, binding.groupId, onCommand); + + break; + + case Clusters::OnOff::Commands::Off::Id: + Clusters::OnOff::Commands::Off::Type offCommand; + Controller::InvokeGroupCommandRequest(&exchangeMgr, binding.fabricIndex, binding.groupId, offCommand); + break; + } +} + +void LightSwitchChangedHandler(const EmberBindingTableEntry & binding, OperationalDeviceProxy * peer_device, void * context) +{ + VerifyOrReturn(context != nullptr, ChipLogError(NotSpecified, "OnDeviceConnectedFn: context is null")); + BindingCommandData * data = static_cast(context); + if (binding.type == MATTER_MULTICAST_BINDING && data->isGroup) + { + switch (data->clusterId) + { + case Clusters::OnOff::Id: + + ProcessOnOffGroupBindingCommand(data->commandId, binding); + + break; + } + } + else if (binding.type == MATTER_UNICAST_BINDING && !data->isGroup) + { + switch (data->clusterId) + { + case Clusters::OnOff::Id: + VerifyOrDie(peer_device != nullptr && peer_device->ConnectionReady()); + ProcessOnOffUnicastBindingCommand(data->commandId, binding, peer_device->GetExchangeManager(), + peer_device->GetSecureSession().Value()); + break; + } + } +} + +void LightSwitchContextReleaseHandler(void * context) +{ + VerifyOrReturn(context != nullptr, ChipLogError(NotSpecified, "LightSwitchContextReleaseHandler: context is null")); + Platform::Delete(static_cast(context)); +} + +void InitBindingHandlerInternal(intptr_t arg) +{ + ChipLogProgress(NotSpecified, "Initializing Binding Handler"); + auto & server = chip::Server::GetInstance(); + if (CHIP_NO_ERROR != + BindingManager::GetInstance().Init( + { &server.GetFabricTable(), server.GetCASESessionManager(), &server.GetPersistentStorage() })) + { + ChipLogError(NotSpecified, "InitBindingHandlerInternal failed"); + } + chip::BindingManager::GetInstance().RegisterBoundDeviceChangedHandler(LightSwitchChangedHandler); + chip::BindingManager::GetInstance().RegisterBoundDeviceContextReleaseHandler(LightSwitchContextReleaseHandler); +} + +} // namespace + +/******************************************************** + * Switch functions + *********************************************************/ + +void SwitchWorkerFunction(intptr_t context) +{ + VerifyOrReturn(context != 0, ChipLogError(NotSpecified, "SwitchWorkerFunction - Invalid work data")); + BindingCommandData * data = reinterpret_cast(context); + BindingManager::GetInstance().NotifyBoundClusterChanged(data->localEndpointId, data->clusterId, static_cast(data)); +} + +void BindingWorkerFunction(intptr_t context) +{ + VerifyOrReturn(context != 0, ChipLogError(NotSpecified, "BindingWorkerFunction - Invalid work data")); + EmberBindingTableEntry * entry = reinterpret_cast(context); + AddBindingEntry(*entry); + Platform::Delete(entry); +} + +CHIP_ERROR InitBindingHandler() +{ + // The initialization of binding manager will try establishing connection with unicast peers + // so it requires the Server instance to be correctly initialized. Post the init function to + // the event queue so that everything is ready when initialization is conducted. + chip::DeviceLayer::PlatformMgr().ScheduleWork(InitBindingHandlerInternal); + return CHIP_NO_ERROR; +} diff --git a/examples/light-switch-app/cc13x4_26x4/src/BindingHandler.h b/examples/light-switch-app/cc13x4_26x4/src/BindingHandler.h new file mode 100644 index 00000000000000..aed08be25eb5bc --- /dev/null +++ b/examples/light-switch-app/cc13x4_26x4/src/BindingHandler.h @@ -0,0 +1,33 @@ +/* + * + * Copyright (c) 2020 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 "app-common/zap-generated/ids/Clusters.h" +#include "app-common/zap-generated/ids/Commands.h" +#include "lib/core/CHIPError.h" + +CHIP_ERROR InitBindingHandler(); +void SwitchWorkerFunction(intptr_t context); +void BindingWorkerFunction(intptr_t context); + +struct BindingCommandData +{ + chip::EndpointId localEndpointId = 1; + chip::CommandId commandId; + chip::ClusterId clusterId; + bool isGroup = false; +}; diff --git a/examples/light-switch-app/cc13x4_26x4/src/LightSwitchManager.cpp b/examples/light-switch-app/cc13x4_26x4/src/LightSwitchManager.cpp new file mode 100644 index 00000000000000..020378f3e388f9 --- /dev/null +++ b/examples/light-switch-app/cc13x4_26x4/src/LightSwitchManager.cpp @@ -0,0 +1,193 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2019 Google LLC. + * All rights reserved. + * + * 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 "LightSwitchManager.h" +#include "BindingHandler.h" + +#include "AppConfig.h" +#include "AppTask.h" +#include + +#include +#include +#include +#include +#include + +using namespace chip; +using namespace chip::app; +using namespace chip::app::Clusters; +using namespace ::chip::DeviceLayer; + +LightSwitchManager LightSwitchManager::sLightSwitch; + +TimerHandle_t sSwitchTimer; + +CHIP_ERROR LightSwitchManager::Init() +{ + // Create FreeRTOS sw timer for light timer. + sSwitchTimer = xTimerCreate("switchTmr", // Just a text name, not used by the RTOS kernel + 1, // == default timer period (mS) + false, // no timer reload (==one-shot) + (void *) this, // init timer id = light obj context + TimerEventHandler // timer callback handler + ); + + if (sSwitchTimer == NULL) + { + PLAT_LOG("sSwitchTimer timer create failed"); + return APP_ERROR_CREATE_TIMER_FAILED; + } + + // Configure Bindings + CHIP_ERROR error = InitBindingHandler(); + if (error != CHIP_NO_ERROR) + { + PLAT_LOG("InitBindingHandler() failed!"); + return APP_ERROR_CREATE_TIMER_FAILED; + } + + mState = kState_SwitchOffCompleted; + + return CHIP_NO_ERROR; +} + +void LightSwitchManager::SetCallbacks(Callback_fn_initiated aActionInitiated_CB, Callback_fn_completed aActionCompleted_CB) +{ + mActionInitiated_CB = aActionInitiated_CB; + mActionCompleted_CB = aActionCompleted_CB; +} + +bool LightSwitchManager::InitiateAction(int32_t aActor, Action_t aAction) +{ + bool action_initiated = false; + + State_t new_state; + + BindingCommandData * data = Platform::New(); + + data->clusterId = chip::app::Clusters::OnOff::Id; + + // need to create logic to separate this + data->isGroup = false; + + // Initiate Switch On/Off Action only when the previous one is complete. + if ((mState == kState_SwitchOffCompleted || mState == kState_SwitchOnCompleted) && aAction == SWITCH_ON_ACTION) + { + action_initiated = true; + new_state = kState_SwitchOnInitiated; + data->commandId = chip::app::Clusters::OnOff::Commands::On::Id; + } + else if ((mState == kState_SwitchOffCompleted || mState == kState_SwitchOnCompleted) && aAction == SWITCH_OFF_ACTION) + { + action_initiated = true; + new_state = kState_SwitchOffInitiated; + data->commandId = chip::app::Clusters::OnOff::Commands::Off::Id; + } + + if (action_initiated) + { + StartTimer(ACTUATOR_MOVEMENT_PERIOD_MS); + // Since the timer started successfully, update the state and trigger callback + mState = new_state; + + if (mActionInitiated_CB) + { + mActionInitiated_CB(aAction, aActor); + } + } + // Platform::Delete(data); + return action_initiated; +} + +void LightSwitchManager::StartTimer(uint32_t aTimeoutMs) +{ + if (xTimerIsTimerActive(sSwitchTimer)) + { + PLAT_LOG("app timer already started!"); + CancelTimer(); + } + // timer is not active, change its period to required value (== restart). + // FreeRTOS- Block for a maximum of 100 ticks if the change period command + // cannot immediately be sent to the timer command queue. + if (xTimerChangePeriod(sSwitchTimer, pdMS_TO_TICKS(aTimeoutMs), 100) != pdPASS) + { + PLAT_LOG("sSwitchTimer timer start() failed"); + } +} + +void LightSwitchManager::CancelTimer(void) +{ + if (xTimerStop(sSwitchTimer, 0) == pdFAIL) + { + PLAT_LOG("sSwitchTimer stop() failed"); + } +} + +void LightSwitchManager::TimerEventHandler(TimerHandle_t xTimer) +{ + // Get light obj context from timer id. + LightSwitchManager * lightswitch = static_cast(pvTimerGetTimerID(xTimer)); + // The timer event handler will be called in the context of the timer task + // once sLightTimer expires. Post an event to apptask queue with the actual handler + // so that the event can be handled in the context of the apptask. + AppEvent event; + event.Type = AppEvent::kEventType_AppEvent; + event.LightSwitchEvent.Context = lightswitch; + event.Handler = ActuatorMovementTimerEventHandler; + AppTask::GetAppTask().PostEvent(&event); +} + +void LightSwitchManager::ActuatorMovementTimerEventHandler(AppEvent * aEvent) +{ + Action_t actionCompleted = INVALID_ACTION; + BindingCommandData * data = Platform::New(); + data->clusterId = chip::app::Clusters::OnOff::Id; + + LightSwitchManager * lightswitch = static_cast(aEvent->LightSwitchEvent.Context); + if (lightswitch->mState == kState_SwitchOffInitiated) + { + lightswitch->mState = kState_SwitchOffCompleted; + actionCompleted = SWITCH_OFF_ACTION; + data->commandId = chip::app::Clusters::OnOff::Commands::Off::Id; + } + else if (lightswitch->mState == kState_SwitchOnInitiated) + { + lightswitch->mState = kState_SwitchOnCompleted; + actionCompleted = SWITCH_ON_ACTION; + data->commandId = chip::app::Clusters::OnOff::Commands::On::Id; + } + + if (actionCompleted != INVALID_ACTION) + { + DeviceLayer::PlatformMgr().ScheduleWork(SwitchWorkerFunction, reinterpret_cast(data)); + + if (lightswitch->mActionCompleted_CB) + { + lightswitch->mActionCompleted_CB(actionCompleted); + } + } +} + +void LightSwitchManager::IdentifyEventHandler() +{ + AppEvent event; + event.Type = AppEvent::kEventType_Identify; + AppTask::GetAppTask().PostEvent(&event); +} diff --git a/examples/light-switch-app/cc13x4_26x4/src/LightSwitchManager.h b/examples/light-switch-app/cc13x4_26x4/src/LightSwitchManager.h new file mode 100644 index 00000000000000..05db8172df1df4 --- /dev/null +++ b/examples/light-switch-app/cc13x4_26x4/src/LightSwitchManager.h @@ -0,0 +1,87 @@ +/* + * + * Copyright (c) 2019 Google LLC. + * All rights reserved. + * + * 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 "AppEvent.h" + +#include "FreeRTOS.h" +#include "timers.h" // provides FreeRTOS timer support +#include + +#include +#include + +using namespace ::chip; + +class LightSwitchManager +{ +public: + enum Action_t + { + SWITCH_ON_ACTION = 0, + SWITCH_OFF_ACTION, + INVALID_ACTION + } Action; + + enum State_t + { + kState_SwitchOffInitiated = 0, + kState_SwitchOffCompleted, + kState_SwitchOnInitiated, + kState_SwitchOnCompleted, + } State; + + CHIP_ERROR Init(); + + bool InitiateAction(int32_t aActor, Action_t aAction); + + typedef void (*Callback_fn_initiated)(Action_t, int32_t aActor); + typedef void (*Callback_fn_completed)(Action_t); + void SetCallbacks(Callback_fn_initiated aActionInitiated_CB, Callback_fn_completed aActionCompleted_CB); + + bool SwitchOn(chip::EndpointId endpointId); + bool SwitchOff(chip::EndpointId endpointId); + + void IdentifyEventHandler(); + +private: + friend LightSwitchManager & LightSwitchMgr(void); + State_t mState; + + Callback_fn_initiated mActionInitiated_CB; + Callback_fn_completed mActionCompleted_CB; + + void CancelTimer(void); + void StartTimer(uint32_t aTimeoutMs); + + static void TimerEventHandler(TimerHandle_t xTimer); + static void ActuatorMovementTimerEventHandler(AppEvent * aEvent); + + static LightSwitchManager sLightSwitch; +}; + +inline LightSwitchManager & LightSwitchMgr(void) +{ + return LightSwitchManager::sLightSwitch; +} diff --git a/examples/light-switch-app/cc13x4_26x4/src/ZclCallbacks.cpp b/examples/light-switch-app/cc13x4_26x4/src/ZclCallbacks.cpp new file mode 100644 index 00000000000000..0ef772323fe39c --- /dev/null +++ b/examples/light-switch-app/cc13x4_26x4/src/ZclCallbacks.cpp @@ -0,0 +1,57 @@ +/* + * + * Copyright (c) 2020 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. + */ + +/** + * @file + * This file implements the handler for data model messages. + */ + +#include "AppConfig.h" +#include "LightSwitchManager.h" + +#include +#include +#include +#include + +using namespace ::chip; +using namespace ::chip::app::Clusters; + +void MatterPostAttributeChangeCallback(const chip::app::ConcreteAttributePath & attributePath, uint8_t type, uint16_t size, + uint8_t * value) +{ + ClusterId clusterId = attributePath.mClusterId; + AttributeId attributeId = attributePath.mAttributeId; + (void) attributeId; + ChipLogProgress(Zcl, "Cluster callback: " ChipLogFormatMEI, ChipLogValueMEI(clusterId)); + + if (clusterId == OnOffSwitchConfiguration::Id) + { + ChipLogProgress(Zcl, "OnOffSwitchConfiguration attribute ID: " ChipLogFormatMEI " Type: %u Value: %u, length %u", + ChipLogValueMEI(attributeId), type, *value, size); + } + else if (clusterId == Identify::Id) + { + ChipLogProgress(Zcl, "Identify attribute ID: " ChipLogFormatMEI " Type: %u Value: %u, length %u", + ChipLogValueMEI(attributeId), type, *value, size); + } + else if (clusterId == Groups::Id) + { + ChipLogProgress(Zcl, "Groups attribute ID: " ChipLogFormatMEI " Type: %u Value: %u, length %u", + ChipLogValueMEI(attributeId), type, *value, size); + } +} diff --git a/examples/light-switch-app/cc13x4_26x4/src/main.cpp b/examples/light-switch-app/cc13x4_26x4/src/main.cpp new file mode 100644 index 00000000000000..d2635ed96e2e28 --- /dev/null +++ b/examples/light-switch-app/cc13x4_26x4/src/main.cpp @@ -0,0 +1,96 @@ +/* + * + * Copyright (c) 2020 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 +#include + +#include + +#include "AppConfig.h" +#include "AppTask.h" + +#include + +/* Driver Header files */ +#include +#include +#include + +#include +#include +#include +#include + +#include +#define TOTAL_ICALL_HEAP_SIZE (0xc600) + +using namespace ::chip; +using namespace ::chip::Inet; +using namespace ::chip::DeviceLayer; + +__attribute__((section(".heap"))) uint8_t GlobalHeapZoneBuffer[TOTAL_ICALL_HEAP_SIZE]; +uint32_t heapSize = TOTAL_ICALL_HEAP_SIZE; + +// ================================================================================ +// FreeRTOS Callbacks +// ================================================================================ +/* Wrapper functions for using the queue registry regardless of whether it is enabled or disabled */ +extern "C" void vQueueAddToRegistryWrapper(QueueHandle_t xQueue, const char * pcQueueName) +{ + /* This function is intentionally left empty as the Queue Registry is disabled */ +} + +extern "C" void vQueueUnregisterQueueWrapper(QueueHandle_t xQueue) +{ + /* This function is intentionally left empty as the Queue Registry is disabled */ +} + +// ================================================================================ +// Main Code +// ================================================================================ +int main(void) +{ + Board_init(); + bpool((void *) GlobalHeapZoneBuffer, TOTAL_ICALL_HEAP_SIZE); + + GPIO_init(); + + NVS_init(); + + ECDH_init(); + + ECDSA_init(); + + AESECB_init(); + + SHA2_init(); + + int ret = GetAppTask().StartAppTask(); + if (ret != 0) + { + // can't log until the kernel is started + // PLAT_LOG("GetAppTask().StartAppTask() failed"); + while (1) + ; + } + + vTaskStartScheduler(); + + // Should never get here. + while (1) + ; +} diff --git a/examples/light-switch-app/cc13x4_26x4/third_party/connectedhomeip b/examples/light-switch-app/cc13x4_26x4/third_party/connectedhomeip new file mode 120000 index 00000000000000..c866b86874994d --- /dev/null +++ b/examples/light-switch-app/cc13x4_26x4/third_party/connectedhomeip @@ -0,0 +1 @@ +../../../.. \ No newline at end of file diff --git a/examples/placeholder/linux/include/static-supported-modes-manager.h b/examples/placeholder/linux/include/static-supported-modes-manager.h index b4ce50b8cd49a3..168482e0303704 100644 --- a/examples/placeholder/linux/include/static-supported-modes-manager.h +++ b/examples/placeholder/linux/include/static-supported-modes-manager.h @@ -31,7 +31,7 @@ namespace ModeSelect { * This implementation statically defines the options. */ -class StaticSupportedModesManager : public chip::app::Clusters::ModeSelect::SupportedModesManager +class StaticSupportedModesManager : public SupportedModesManager { using ModeOptionStructType = Structs::ModeOptionStruct::Type; using storage_value_type = const ModeOptionStructType; @@ -52,8 +52,6 @@ class StaticSupportedModesManager : public chip::app::Clusters::ModeSelect::Supp static const EndpointSpanPair supportedOptionsByEndpoints[MATTER_DM_MODE_SELECT_CLUSTER_SERVER_ENDPOINT_COUNT]; public: - static const StaticSupportedModesManager instance; - SupportedModesManager::ModeOptionsProvider getModeOptionsProvider(EndpointId endpointId) const override; Protocols::InteractionModel::Status getModeOptionByMode(EndpointId endpointId, uint8_t mode, @@ -62,12 +60,8 @@ class StaticSupportedModesManager : public chip::app::Clusters::ModeSelect::Supp ~StaticSupportedModesManager(){}; StaticSupportedModesManager() {} - - static inline const StaticSupportedModesManager & getStaticSupportedModesManagerInstance() { return instance; } }; -const SupportedModesManager * getSupportedModesManager(); - } // namespace ModeSelect } // namespace Clusters } // namespace app diff --git a/examples/placeholder/linux/static-supported-modes-manager.cpp b/examples/placeholder/linux/static-supported-modes-manager.cpp index 4060d4be85ec9c..94345600cf53fd 100644 --- a/examples/placeholder/linux/static-supported-modes-manager.cpp +++ b/examples/placeholder/linux/static-supported-modes-manager.cpp @@ -39,8 +39,6 @@ const StaticSupportedModesManager::EndpointSpanPair EndpointSpanPair(1, Span(StaticSupportedModesManager::coffeeOptions)) // Options for Endpoint 1 }; -const StaticSupportedModesManager StaticSupportedModesManager::instance = StaticSupportedModesManager(); - SupportedModesManager::ModeOptionsProvider StaticSupportedModesManager::getModeOptionsProvider(EndpointId endpointId) const { for (auto & endpointSpanPair : supportedOptionsByEndpoints) @@ -76,8 +74,3 @@ Status StaticSupportedModesManager::getModeOptionByMode(unsigned short endpointI ChipLogProgress(Zcl, "Cannot find the mode %u", mode); return Status::InvalidCommand; } - -const ModeSelect::SupportedModesManager * ModeSelect::getSupportedModesManager() -{ - return &StaticSupportedModesManager::instance; -} diff --git a/examples/platform/esp32/mode-support/static-supported-modes-manager.cpp b/examples/platform/esp32/mode-support/static-supported-modes-manager.cpp index d06a8b8b7dc809..fc9a94cbb307c4 100644 --- a/examples/platform/esp32/mode-support/static-supported-modes-manager.cpp +++ b/examples/platform/esp32/mode-support/static-supported-modes-manager.cpp @@ -33,8 +33,6 @@ using List = app::DataModel::List; SupportedModesManager::ModeOptionsProvider * StaticSupportedModesManager::epModeOptionsProviderList = nullptr; -const StaticSupportedModesManager StaticSupportedModesManager::instance = StaticSupportedModesManager(); - int StaticSupportedModesManager::mSize = 0; CHIP_ERROR StaticSupportedModesManager::InitEndpointArray(int size) @@ -194,11 +192,6 @@ Status StaticSupportedModesManager::getModeOptionByMode(unsigned short endpointI return Status::InvalidCommand; } -const ModeSelect::SupportedModesManager * ModeSelect::getSupportedModesManager() -{ - return &StaticSupportedModesManager::getStaticSupportedModesManagerInstance(); -} - void StaticSupportedModesManager::FreeSupportedModes(EndpointId endpointId) const { if (epModeOptionsProviderList[endpointId].begin() != nullptr) diff --git a/examples/platform/esp32/mode-support/static-supported-modes-manager.h b/examples/platform/esp32/mode-support/static-supported-modes-manager.h index 8d6bb3c665ff0c..658b25625471c5 100644 --- a/examples/platform/esp32/mode-support/static-supported-modes-manager.h +++ b/examples/platform/esp32/mode-support/static-supported-modes-manager.h @@ -25,7 +25,7 @@ namespace app { namespace Clusters { namespace ModeSelect { -class StaticSupportedModesManager : public chip::app::Clusters::ModeSelect::SupportedModesManager +class StaticSupportedModesManager : public SupportedModesManager { private: using ModeOptionStructType = Structs::ModeOptionStruct::Type; @@ -36,8 +36,6 @@ class StaticSupportedModesManager : public chip::app::Clusters::ModeSelect::Supp void FreeSupportedModes(EndpointId endpointId) const; - static const StaticSupportedModesManager instance; - public: // InitEndpointArray should be called only once in the application. Memory allocated to the // epModeOptionsProviderList will be needed for the lifetime of the program, so it's never deallocated. @@ -68,12 +66,8 @@ class StaticSupportedModesManager : public chip::app::Clusters::ModeSelect::Supp FreeSupportedModes(i); } } - - static inline const StaticSupportedModesManager & getStaticSupportedModesManagerInstance() { return instance; } }; -const SupportedModesManager * getSupportedModesManager(); - } // namespace ModeSelect } // namespace Clusters } // namespace app diff --git a/examples/rvc-app/rvc-common/pics/rvc-app-pics-values b/examples/rvc-app/rvc-common/pics/rvc-app-pics-values index c38f0c1b7e00a0..4ad084ec618dd4 100644 --- a/examples/rvc-app/rvc-common/pics/rvc-app-pics-values +++ b/examples/rvc-app/rvc-common/pics/rvc-app-pics-values @@ -20,7 +20,7 @@ RVCOPSTATE.S.E01=1 RVCOPSTATE.S.C00.Rsp=1 RVCOPSTATE.S.C03.Rsp=1 RVCOPSTATE.S.C04.Tx=1 -RVCOPSTATE.S.C128.Rsp=1 +RVCOPSTATE.S.C80.Rsp=1 RVCOPSTATE.S.M.ST_STOPPED=1 RVCOPSTATE.S.M.ST_RUNNING=1 RVCOPSTATE.S.M.ST_PAUSED=1 @@ -77,4 +77,4 @@ SEAR.S.M.HAS_MANUAL_SKIP_STATE_CONTROL=1 SEAR.S.M.INVALID_STATE_FOR_SKIP=1 SEAR.S.M.NO_SELAREA_FOR_SKIP=1 SEAR.S.M.VALID_STATE_FOR_SKIP=1 -SEAR.S.M.HAS_MANUAL_OPERATING_STATE_CONTROL=1 \ No newline at end of file +SEAR.S.M.HAS_MANUAL_OPERATING_STATE_CONTROL=1 diff --git a/examples/shell/cc13x4_26x4/main/AppTask.cpp b/examples/shell/cc13x4_26x4/main/AppTask.cpp index 86432279d5c8ad..3f5ff1e659126c 100644 --- a/examples/shell/cc13x4_26x4/main/AppTask.cpp +++ b/examples/shell/cc13x4_26x4/main/AppTask.cpp @@ -41,6 +41,7 @@ #include #include +#include /* syscfg */ #include @@ -54,6 +55,7 @@ using namespace ::chip::DeviceLayer; using chip::Shell::Engine; AppTask AppTask::sAppTask; +Clusters::ModeSelect::StaticSupportedModesManager sStaticSupportedModesManager; static TaskHandle_t sAppTaskHandle; @@ -171,6 +173,7 @@ CHIP_ERROR AppTask::Init() #if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR InitializeOTARequestor(); #endif + Clusters::ModeSelect::setSupportedModesManager(&sStaticSupportedModesManager); return err; } diff --git a/src/app/clusters/ecosystem-information-server/ecosystem-information-server.cpp b/src/app/clusters/ecosystem-information-server/ecosystem-information-server.cpp index c51a5165f3ca9d..2ce82394a57464 100644 --- a/src/app/clusters/ecosystem-information-server/ecosystem-information-server.cpp +++ b/src/app/clusters/ecosystem-information-server/ecosystem-information-server.cpp @@ -128,6 +128,13 @@ EcosystemDeviceStruct::Builder & EcosystemDeviceStruct::Builder::AddUniqueLocati return *this; } +EcosystemDeviceStruct::Builder & EcosystemDeviceStruct::Builder::SetFabricIndex(FabricIndex aFabricIndex) +{ + VerifyOrDie(!mIsAlreadyBuilt); + mFabricIndex = aFabricIndex; + return *this; +} + std::unique_ptr EcosystemDeviceStruct::Builder::Build() { VerifyOrReturnValue(!mIsAlreadyBuilt, nullptr, ChipLogError(Zcl, "Build() already called")); @@ -136,6 +143,8 @@ std::unique_ptr EcosystemDeviceStruct::Builder::Build() VerifyOrReturnValue(!mDeviceTypes.empty(), nullptr, ChipLogError(Zcl, "No device types added")); VerifyOrReturnValue(mUniqueLocationIds.size() <= kUniqueLocationIdsListMaxSize, nullptr, ChipLogError(Zcl, "Too many location ids")); + VerifyOrReturnValue(mFabricIndex >= kMinValidFabricIndex, nullptr, ChipLogError(Zcl, "Fabric index is invalid")); + VerifyOrReturnValue(mFabricIndex <= kMaxValidFabricIndex, nullptr, ChipLogError(Zcl, "Fabric index is invalid")); for (auto & locationId : mUniqueLocationIds) { @@ -145,12 +154,12 @@ std::unique_ptr EcosystemDeviceStruct::Builder::Build() // std::make_unique does not have access to private constructor we workaround with using new std::unique_ptr ret{ new EcosystemDeviceStruct( std::move(mDeviceName), mDeviceNameLastEditEpochUs, mBridgedEndpoint, mOriginalEndpoint, std::move(mDeviceTypes), - std::move(mUniqueLocationIds), mUniqueLocationIdsLastEditEpochUs) }; + std::move(mUniqueLocationIds), mUniqueLocationIdsLastEditEpochUs, mFabricIndex) }; mIsAlreadyBuilt = true; return ret; } -CHIP_ERROR EcosystemDeviceStruct::Encode(const AttributeValueEncoder::ListEncodeHelper & aEncoder, const FabricIndex & aFabricIndex) +CHIP_ERROR EcosystemDeviceStruct::Encode(const AttributeValueEncoder::ListEncodeHelper & aEncoder) { Structs::EcosystemDeviceStruct::Type deviceStruct; if (!mDeviceName.empty()) @@ -172,9 +181,7 @@ CHIP_ERROR EcosystemDeviceStruct::Encode(const AttributeValueEncoder::ListEncode deviceStruct.uniqueLocationIDs = DataModel::List(locationIds.data(), locationIds.size()); deviceStruct.uniqueLocationIDsLastEdit = mUniqueLocationIdsLastEditEpochUs; - - // TODO(#33223) this is a hack, use mFabricIndex when it exists. - deviceStruct.SetFabricIndex(aFabricIndex); + deviceStruct.SetFabricIndex(mFabricIndex); return aEncoder.Encode(deviceStruct); } @@ -226,12 +233,9 @@ CHIP_ERROR EcosystemLocationStruct::Encode(const AttributeValueEncoder::ListEnco const std::string & aUniqueLocationId, const FabricIndex & aFabricIndex) { Structs::EcosystemLocationStruct::Type locationStruct; - VerifyOrDie(!aUniqueLocationId.empty()); locationStruct.uniqueLocationID = CharSpan(aUniqueLocationId.c_str(), aUniqueLocationId.size()); locationStruct.locationDescriptor = GetEncodableLocationDescriptorStruct(mLocationDescriptor); locationStruct.locationDescriptorLastEdit = mLocationDescriptorLastEditEpochUs; - - // TODO(#33223) this is a hack, use mFabricIndex when it exists. locationStruct.SetFabricIndex(aFabricIndex); return aEncoder.Encode(locationStruct); } @@ -266,16 +270,20 @@ CHIP_ERROR EcosystemInformationServer::AddDeviceInfo(EndpointId aEndpoint, std:: } CHIP_ERROR EcosystemInformationServer::AddLocationInfo(EndpointId aEndpoint, const std::string & aLocationId, - std::unique_ptr aLocation) + FabricIndex aFabricIndex, std::unique_ptr aLocation) { VerifyOrReturnError(aLocation, CHIP_ERROR_INVALID_ARGUMENT); VerifyOrReturnError((aEndpoint != kRootEndpointId && aEndpoint != kInvalidEndpointId), CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(!aLocationId.empty(), CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(aFabricIndex >= kMinValidFabricIndex, CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(aFabricIndex <= kMaxValidFabricIndex, CHIP_ERROR_INVALID_ARGUMENT); - auto & deviceInfo = mDevicesMap[aEndpoint]; - VerifyOrReturnError((deviceInfo.mLocationDirectory.find(aLocationId) == deviceInfo.mLocationDirectory.end()), + auto & deviceInfo = mDevicesMap[aEndpoint]; + EcosystemLocationKey key = { .mUniqueLocationId = aLocationId, .mFabricIndex = aFabricIndex }; + VerifyOrReturnError((deviceInfo.mLocationDirectory.find(key) == deviceInfo.mLocationDirectory.end()), CHIP_ERROR_INVALID_ARGUMENT); VerifyOrReturnError((deviceInfo.mLocationDirectory.size() < kLocationDirectoryMaxSize), CHIP_ERROR_NO_MEMORY); - deviceInfo.mLocationDirectory[aLocationId] = std::move(aLocation); + deviceInfo.mLocationDirectory[key] = std::move(aLocation); return CHIP_NO_ERROR; } @@ -352,11 +360,10 @@ CHIP_ERROR EcosystemInformationServer::EncodeDeviceDirectoryAttribute(EndpointId return aEncoder.EncodeEmptyList(); } - FabricIndex fabricIndex = aEncoder.AccessingFabricIndex(); return aEncoder.EncodeList([&](const auto & encoder) -> CHIP_ERROR { for (auto & device : deviceInfo.mDeviceDirectory) { - ReturnErrorOnFailure(device->Encode(encoder, fabricIndex)); + ReturnErrorOnFailure(device->Encode(encoder)); } return CHIP_NO_ERROR; }); @@ -379,11 +386,10 @@ CHIP_ERROR EcosystemInformationServer::EncodeLocationStructAttribute(EndpointId return aEncoder.EncodeEmptyList(); } - FabricIndex fabricIndex = aEncoder.AccessingFabricIndex(); return aEncoder.EncodeList([&](const auto & encoder) -> CHIP_ERROR { - for (auto & [id, device] : deviceInfo.mLocationDirectory) + for (auto & [key, device] : deviceInfo.mLocationDirectory) { - ReturnErrorOnFailure(device->Encode(encoder, id, fabricIndex)); + ReturnErrorOnFailure(device->Encode(encoder, key.mUniqueLocationId, key.mFabricIndex)); } return CHIP_NO_ERROR; }); diff --git a/src/app/clusters/ecosystem-information-server/ecosystem-information-server.h b/src/app/clusters/ecosystem-information-server/ecosystem-information-server.h index dce12e745bf14e..d4f4d7dc3a6fc1 100644 --- a/src/app/clusters/ecosystem-information-server/ecosystem-information-server.h +++ b/src/app/clusters/ecosystem-information-server/ecosystem-information-server.h @@ -49,6 +49,7 @@ class EcosystemDeviceStruct Builder & SetOriginalEndpoint(EndpointId aOriginalEndpoint); Builder & AddDeviceType(Structs::DeviceTypeStruct::Type aDeviceType); Builder & AddUniqueLocationId(std::string aUniqueLocationId, uint64_t aUniqueLocationIdsLastEditEpochUs); + Builder & SetFabricIndex(FabricIndex aFabricIndex); // Upon success this object will have moved all ownership of underlying // types to EcosystemDeviceStruct and should not be used afterwards. @@ -62,21 +63,25 @@ class EcosystemDeviceStruct std::vector mDeviceTypes; std::vector mUniqueLocationIds; uint64_t mUniqueLocationIdsLastEditEpochUs = 0; + FabricIndex mFabricIndex = kUndefinedFabricIndex; bool mIsAlreadyBuilt = false; }; - CHIP_ERROR Encode(const AttributeValueEncoder::ListEncodeHelper & aEncoder, const FabricIndex & aFabricIndex); + CHIP_ERROR Encode(const AttributeValueEncoder::ListEncodeHelper & aEncoder); private: // Constructor is intentionally private. This is to ensure that it is only constructed with // values that conform to the spec. explicit EcosystemDeviceStruct(std::string && aDeviceName, uint64_t aDeviceNameLastEditEpochUs, EndpointId aBridgedEndpoint, EndpointId aOriginalEndpoint, std::vector && aDeviceTypes, - std::vector && aUniqueLocationIds, uint64_t aUniqueLocationIdsLastEditEpochUs) : + std::vector && aUniqueLocationIds, uint64_t aUniqueLocationIdsLastEditEpochUs, + FabricIndex aFabricIndex) : mDeviceName(std::move(aDeviceName)), mDeviceNameLastEditEpochUs(aDeviceNameLastEditEpochUs), mBridgedEndpoint(aBridgedEndpoint), mOriginalEndpoint(aOriginalEndpoint), mDeviceTypes(std::move(aDeviceTypes)), - mUniqueLocationIds(std::move(aUniqueLocationIds)), mUniqueLocationIdsLastEditEpochUs(aUniqueLocationIdsLastEditEpochUs) + mUniqueLocationIds(std::move(aUniqueLocationIds)), mUniqueLocationIdsLastEditEpochUs(aUniqueLocationIdsLastEditEpochUs), + mFabricIndex(aFabricIndex) + {} const std::string mDeviceName; @@ -86,10 +91,7 @@ class EcosystemDeviceStruct std::vector mDeviceTypes; std::vector mUniqueLocationIds; uint64_t mUniqueLocationIdsLastEditEpochUs; - // TODO(#33223) This structure needs to contain fabric index to be spec compliant. - // To keep initial PR smaller, we are going to assume that all entries - // here are for any fabric. This will allow follow up PR introducing - // fabric scoped to be more throughly reviewed with focus on fabric scoping. + FabricIndex mFabricIndex; }; struct LocationDescriptorStruct @@ -134,15 +136,11 @@ class EcosystemLocationStruct mLocationDescriptor(aLocationDescriptor), mLocationDescriptorLastEditEpochUs(aLocationDescriptorLastEditEpochUs) {} // EcosystemLocationStruct is used as a value in a key-value map. - // Because UniqueLocationId is manditory when an entry exist, and - // it is unique, we use it as a key to the key-value pair and is why it is + // Because UniqueLocationId and FabricIndex are mandatory when an entry exist, + // and needs to be unique, we use it as a key to the key-value pair and is why it is // not explicitly in this struct. LocationDescriptorStruct mLocationDescriptor; uint64_t mLocationDescriptorLastEditEpochUs; - // TODO(#33223) This structure needs to contain fabric index to be spec compliant. - // To keep initial PR smaller, we are going to assume that all entries - // here are for any fabric. This will allow follow up PR introducing - // fabric scoped to be more throughly reviewed with focus on fabric scoping. }; class EcosystemInformationServer @@ -186,7 +184,7 @@ class EcosystemInformationServer * @return #CHIP_NO_ERROR on success. * @return Other CHIP_ERROR associated with issue. */ - CHIP_ERROR AddLocationInfo(EndpointId aEndpoint, const std::string & aLocationId, + CHIP_ERROR AddLocationInfo(EndpointId aEndpoint, const std::string & aLocationId, FabricIndex aFabricIndex, std::unique_ptr aLocation); /** @@ -203,12 +201,22 @@ class EcosystemInformationServer CHIP_ERROR ReadAttribute(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder); private: + struct EcosystemLocationKey + { + bool operator<(const EcosystemLocationKey & other) const + { + return mUniqueLocationId < other.mUniqueLocationId || + (mUniqueLocationId == other.mUniqueLocationId && mFabricIndex < other.mFabricIndex); + } + std::string mUniqueLocationId; + FabricIndex mFabricIndex; + }; + struct DeviceInfo { Optional mRemovedOn = NullOptional; std::vector> mDeviceDirectory; - // Map key is using the UniqueLocationId - std::map> mLocationDirectory; + std::map> mLocationDirectory; }; CHIP_ERROR EncodeRemovedOnAttribute(EndpointId aEndpoint, AttributeValueEncoder & aEncoder); diff --git a/src/app/clusters/mode-select-server/mode-select-server.cpp b/src/app/clusters/mode-select-server/mode-select-server.cpp index c5fb49708aa663..5f247bb4b2e95d 100644 --- a/src/app/clusters/mode-select-server/mode-select-server.cpp +++ b/src/app/clusters/mode-select-server/mode-select-server.cpp @@ -49,6 +49,17 @@ using BootReasonType = GeneralDiagnostics::BootReasonEnum; static InteractionModel::Status verifyModeValue(const EndpointId endpointId, const uint8_t newMode); +static ModeSelect::SupportedModesManager * sSupportedModesManager = nullptr; + +const SupportedModesManager * ModeSelect::getSupportedModesManager() +{ + return sSupportedModesManager; +} + +void ModeSelect::setSupportedModesManager(ModeSelect::SupportedModesManager * aSupportedModesManager) +{ + sSupportedModesManager = aSupportedModesManager; +} namespace { inline bool areStartUpModeAndCurrentModeNonVolatile(EndpointId endpoint); @@ -71,6 +82,12 @@ CHIP_ERROR ModeSelectAttrAccess::Read(const ConcreteReadAttributePath & aPath, A if (ModeSelect::Attributes::SupportedModes::Id == aPath.mAttributeId) { + if (gSupportedModeManager == nullptr) + { + ChipLogError(Zcl, "ModeSelect: SupportedModesManager is NULL"); + aEncoder.EncodeEmptyList(); + return CHIP_NO_ERROR; + } const ModeSelect::SupportedModesManager::ModeOptionsProvider modeOptionsProvider = gSupportedModeManager->getModeOptionsProvider(aPath.mEndpointId); if (modeOptionsProvider.begin() == nullptr) @@ -104,8 +121,14 @@ bool emberAfModeSelectClusterChangeToModeCallback(CommandHandler * commandHandle uint8_t newMode = commandData.newMode; // Check that the newMode matches one of the supported options const ModeSelect::Structs::ModeOptionStruct::Type * modeOptionPtr; - Status checkSupportedModeStatus = - ModeSelect::getSupportedModesManager()->getModeOptionByMode(endpointId, newMode, &modeOptionPtr); + const ModeSelect::SupportedModesManager * gSupportedModeManager = ModeSelect::getSupportedModesManager(); + if (gSupportedModeManager == nullptr) + { + ChipLogError(Zcl, "ModeSelect: SupportedModesManager is NULL"); + commandHandler->AddStatus(commandPath, Status::Failure); + return true; + } + Status checkSupportedModeStatus = gSupportedModeManager->getModeOptionByMode(endpointId, newMode, &modeOptionPtr); if (Status::Success != checkSupportedModeStatus) { ChipLogProgress(Zcl, "ModeSelect: Failed to find the option with mode %u", newMode); @@ -265,5 +288,11 @@ static InteractionModel::Status verifyModeValue(const EndpointId endpointId, con return InteractionModel::Status::Success; } const ModeSelect::Structs::ModeOptionStruct::Type * modeOptionPtr; - return ModeSelect::getSupportedModesManager()->getModeOptionByMode(endpointId, newMode, &modeOptionPtr); + const ModeSelect::SupportedModesManager * gSupportedModeManager = ModeSelect::getSupportedModesManager(); + if (gSupportedModeManager == nullptr) + { + ChipLogError(Zcl, "ModeSelect: SupportedModesManager is NULL"); + return Status::Failure; + } + return gSupportedModeManager->getModeOptionByMode(endpointId, newMode, &modeOptionPtr); } diff --git a/src/app/clusters/mode-select-server/supported-modes-manager.h b/src/app/clusters/mode-select-server/supported-modes-manager.h index 3c36f188cb4a0e..72312685549389 100644 --- a/src/app/clusters/mode-select-server/supported-modes-manager.h +++ b/src/app/clusters/mode-select-server/supported-modes-manager.h @@ -84,6 +84,8 @@ class SupportedModesManager const SupportedModesManager * getSupportedModesManager(); +void setSupportedModesManager(SupportedModesManager * aSupportedModesManager); + } // namespace ModeSelect } // namespace Clusters } // namespace app diff --git a/src/app/tests/suites/certification/PICS.yaml b/src/app/tests/suites/certification/PICS.yaml index 1fc182bd9ba867..c575bd348fc518 100644 --- a/src/app/tests/suites/certification/PICS.yaml +++ b/src/app/tests/suites/certification/PICS.yaml @@ -9740,7 +9740,7 @@ PICS: id: RVCOPSTATE.S.C03.Rsp - label: "Does the device implement receiving the GoHome command?" - id: RVCOPSTATE.S.C128.Rsp + id: RVCOPSTATE.S.C80.Rsp #Commands generated - label: diff --git a/src/app/tests/suites/certification/Test_TC_ICDM_3_2.yaml b/src/app/tests/suites/certification/Test_TC_ICDM_3_2.yaml deleted file mode 100644 index f6104a53d411d1..00000000000000 --- a/src/app/tests/suites/certification/Test_TC_ICDM_3_2.yaml +++ /dev/null @@ -1,346 +0,0 @@ -# Copyright (c) 2024 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. -# Auto-generated scripts for harness use only, please review before automation. The endpoints and cluster names are currently set to default - -name: 217.2.3. [TC-ICDM-3.2] Verify RegisterClient command with DUT as Server - -PICS: - - ICDM.S - - ICDM.S.C00.Rsp - - ICDM.S.C02.Rsp - -config: - nodeId: 0x12344321 - cluster: "Basic Information" - endpoint: 0 - -tests: - - label: "Preconditions" - verification: | - 1.Commission DUT to TH (can be skipped if done in a preceding test). - 2a.TH reads from the DUT the RegisteredClients attribute. - 2b.If list of registered clients is not empty, unregister existing client(s) - 2c.TH reads from the DUT the RegisteredClients attribute. Verify that the DUT response contains empty list of registered clients. - disabled: true - - - label: - "Step 1a: TH sends RegisterClient command. - CheckInNodeID: - registering clients node ID (CheckInNodeID1) - MonitoredSubject: - monitored subject ID (MonitorSubID1) - Key: shared secret between the - client and the ICD (Key1)" - PICS: ICDM.S.C00.Rsp - verification: | - ./chip-tool icdmanagement register-client 1 1 hex:1234567890abcdef1234567890abcdef 1 0 - - [1702418857.289325][1350:1352] CHIP:DMG: Received Command Response Data, Endpoint=0 Cluster=0x0000_0046 Command=0x0000_0001 - [1702418857.289426][1350:1352] CHIP:TOO: Endpoint: 0 Cluster: 0x0000_0046 Command 0x0000_0001 - [1702418857.289635][1350:1352] CHIP:TOO: RegisterClientResponse: { - [1702418857.289725][1350:1352] CHIP:TOO: ICDCounter: 1321491095 - [1702418857.289781][1350:1352] CHIP:TOO: } - disabled: true - - - label: "Step 1b: TH reads from the DUT the RegisteredClients attribute." - PICS: ICDM.S.A0003 - verification: | - ./chip-tool icdmanagement read registered-clients 1 0 - - [1702418868.283920][1353:1355] CHIP:TOO: Endpoint: 0 Cluster: 0x0000_0046 Attribute 0x0000_0003 DataVersion: 4124981277 - [1702418868.284152][1353:1355] CHIP:TOO: RegisteredClients: 2 entries - [1702418868.284338][1353:1355] CHIP:TOO: [1]: { - [1702418868.284396][1353:1355] CHIP:TOO: CheckInNodeID: 112233 - [1702418868.284449][1353:1355] CHIP:TOO: MonitoredSubject: 112233 - [1702418868.284525][1353:1355] CHIP:TOO: FabricIndex: 1 - [1702418868.284577][1353:1355] CHIP:TOO: } - [1702418868.284647][1353:1355] CHIP:TOO: [2]: { - [1702418868.284700][1353:1355] CHIP:TOO: CheckInNodeID: 1 - [1702418868.284751][1353:1355] CHIP:TOO: MonitoredSubject: 1 - [1702418868.284801][1353:1355] CHIP:TOO: FabricIndex: 1 - [1702418868.284849][1353:1355] CHIP:TOO: } - disabled: true - - - label: "Step 1c: Power cycle DUT" - verification: | - Power cycle DUT - disabled: true - - - label: "Step 1d: TH reads from the DUT the RegisteredClients attribute." - PICS: ICDM.S.A0003(RegisteredClients) - verification: | - ./chip-tool icdmanagement read registered-clients 1 0 - - [1702418876.828984][1356:1358] CHIP:TOO: Endpoint: 0 Cluster: 0x0000_0046 Attribute 0x0000_0003 DataVersion: 4124981277 - [1702418876.829201][1356:1358] CHIP:TOO: RegisteredClients: 2 entries - [1702418876.829372][1356:1358] CHIP:TOO: [1]: { - [1702418876.829426][1356:1358] CHIP:TOO: CheckInNodeID: 112233 - [1702418876.829535][1356:1358] CHIP:TOO: MonitoredSubject: 112233 - [1702418876.829609][1356:1358] CHIP:TOO: FabricIndex: 1 - [1702418876.829655][1356:1358] CHIP:TOO: } - [1702418876.829719][1356:1358] CHIP:TOO: [2]: { - [1702418876.829766][1356:1358] CHIP:TOO: CheckInNodeID: 1 - [1702418876.829867][1356:1358] CHIP:TOO: MonitoredSubject: 1 - [1702418876.829912][1356:1358] CHIP:TOO: FabricIndex: 1 - [1702418876.829955][1356:1358] CHIP:TOO: } - disabled: true - - - label: - "Step 2a: Setup the TH such that is has administrator privileges for - the ICDM cluster." - verification: | - chip-tool default with admin privilege. - disabled: true - - - label: - "Step 2b: TH sends RegisterClient command with same CheckInNodeID as - in Step 1a and different MonitoredSubject and Key. - CheckInNodeID: - registering clients node ID (CheckInNodeID1) - MonitoredSubject: - monitored subject ID (MonitorSubID2) - Key: shared secret between the - client and the ICD (Key2)" - PICS: ICDM.S.C00.Rsp - verification: | - ./chip-tool icdmanagement register-client 1 2 hex:abcdef1234567890abcdef1234567890 1 0 - - [1702418883.807797][1359:1361] CHIP:DMG: Received Command Response Data, Endpoint=0 Cluster=0x0000_0046 Command=0x0000_0001 - [1702418883.807919][1359:1361] CHIP:TOO: Endpoint: 0 Cluster: 0x0000_0046 Command 0x0000_0001 - [1702418883.808188][1359:1361] CHIP:TOO: RegisterClientResponse: { - [1702418883.808260][1359:1361] CHIP:TOO: ICDCounter: 1321491095 - [1702418883.808316][1359:1361] CHIP:TOO: } - disabled: true - - - label: "Step 2c: TH reads from the DUT the ICDCounter attribute." - PICS: ICDM.S.A0004 - verification: | - ./chip-tool icdmanagement read icdcounter 1 0 - - [1702418902.706877][1365:1367] CHIP:TOO: Endpoint: 0 Cluster: 0x0000_0046 Attribute 0x0000_0004 DataVersion: 4124981277 - [1702418902.706989][1365:1367] CHIP:TOO: ICDCounter: 1321491095 - disabled: true - - - label: "Step 2d: TH reads from the DUT the RegisteredClients attribute." - PICS: ICDM.S.A0003 - verification: | - ./chip-tool icdmanagement read registered-clients 1 0 - - [1702418891.793516][1362:1364] CHIP:TOO: Endpoint: 0 Cluster: 0x0000_0046 Attribute 0x0000_0003 DataVersion: 4124981277 - [1702418891.793737][1362:1364] CHIP:TOO: RegisteredClients: 2 entries - [1702418891.793959][1362:1364] CHIP:TOO: [1]: { - [1702418891.794016][1362:1364] CHIP:TOO: CheckInNodeID: 112233 - [1702418891.794065][1362:1364] CHIP:TOO: MonitoredSubject: 112233 - [1702418891.794133][1362:1364] CHIP:TOO: FabricIndex: 1 - [1702418891.794179][1362:1364] CHIP:TOO: } - [1702418891.794290][1362:1364] CHIP:TOO: [2]: { - [1702418891.794344][1362:1364] CHIP:TOO: CheckInNodeID: 1 - [1702418891.794390][1362:1364] CHIP:TOO: MonitoredSubject: 2 - [1702418891.794483][1362:1364] CHIP:TOO: FabricIndex: 1 - [1702418891.794531][1362:1364] CHIP:TOO: } - disabled: true - - - label: - "Step 2e: TH sends UnregisterClient command with the CheckInNodeID - (CheckInNodeID1)." - PICS: ICDM.S.C02.Rsp - verification: | - ./chip-tool icdmanagement unregister-client 1 1 0 - - [1702419153.281757][1380:1382] CHIP:DMG: InvokeResponseMessage = - [1702419153.281885][1380:1382] CHIP:DMG: { - [1702419153.282005][1380:1382] CHIP:DMG: suppressResponse = false, - [1702419153.282061][1380:1382] CHIP:DMG: InvokeResponseIBs = - [1702419153.282126][1380:1382] CHIP:DMG: [ - [1702419153.282177][1380:1382] CHIP:DMG: InvokeResponseIB = - [1702419153.282243][1380:1382] CHIP:DMG: { - [1702419153.282296][1380:1382] CHIP:DMG: CommandStatusIB = - [1702419153.282357][1380:1382] CHIP:DMG: { - [1702419153.282576][1380:1382] CHIP:DMG: CommandPathIB = - [1702419153.282650][1380:1382] CHIP:DMG: { - [1702419153.282725][1380:1382] CHIP:DMG: EndpointId = 0x0, - [1702419153.282812][1380:1382] CHIP:DMG: ClusterId = 0x46, - [1702419153.282895][1380:1382] CHIP:DMG: CommandId = 0x2, - [1702419153.282973][1380:1382] CHIP:DMG: }, - [1702419153.283183][1380:1382] CHIP:DMG: - [1702419153.283246][1380:1382] CHIP:DMG: StatusIB = - [1702419153.283327][1380:1382] CHIP:DMG: { - [1702419153.283409][1380:1382] CHIP:DMG: status = 0x00 (SUCCESS), - [1702419153.283490][1380:1382] CHIP:DMG: }, - [1702419153.283562][1380:1382] CHIP:DMG: - [1702419153.283626][1380:1382] CHIP:DMG: }, - [1702419153.283699][1380:1382] CHIP:DMG: - [1702419153.283751][1380:1382] CHIP:DMG: }, - [1702419153.283811][1380:1382] CHIP:DMG: - [1702419153.283859][1380:1382] CHIP:DMG: ], - [1702419153.283919][1380:1382] CHIP:DMG: - [1702419153.283966][1380:1382] CHIP:DMG: InteractionModelRevision = 11 - [1702419153.284013][1380:1382] CHIP:DMG: }, - [1702419153.284182][1380:1382] CHIP:DMG: Received Command Response Status for Endpoint=0 Cluster=0x0000_0046 Command=0x0000_0002 Status=0x0 - disabled: true - - - label: "Step 2f: TH reads from the DUT the RegisteredClients attribute." - PICS: ICDM.S.A0003 - verification: | - ./chip-tool icdmanagement read registered-clients 1 0 - - [1702419210.157158][1385:1387] CHIP:TOO: Endpoint: 0 Cluster: 0x0000_0046 Attribute 0x0000_0003 DataVersion: 4124981277 - [1702419210.157311][1385:1387] CHIP:TOO: RegisteredClients: 1 entries - [1702419210.157489][1385:1387] CHIP:TOO: [1]: { - [1702419210.157543][1385:1387] CHIP:TOO: CheckInNodeID: 112233 - [1702419210.157591][1385:1387] CHIP:TOO: MonitoredSubject: 112233 - [1702419210.157662][1385:1387] CHIP:TOO: FabricIndex: 1 - [1702419210.157730][1385:1387] CHIP:TOO: } - disabled: true - - - label: - "Step 2g: Clear the THs administrator privileges for the ICDM cluster." - verification: | - ./chip-tool accesscontrol write acl '[{"fabricIndex": 1, "privilege": 4, "authMode": 2, "subjects": [112233], "targets": null } ]' 1 0 - disabled: true - - - label: - "Step 3a: TH sends RegisterClient command. - CheckInNodeID: - registering clients node ID (CheckInNodeID3) - MonitoredSubject: - monitored subject ID (MonitorSubID3) - Key: shared secret between the - client and the ICD (Key3) - VerificationKey: verification key - (VerificationKey3)" - PICS: ICDM.S.C00.Rsp - verification: | - ./chip-tool icdmanagement register-client 3 3 hex:3334567890abcdef3334567890abcdef 1 0 --VerificationKey hex:abcdef1234567890abcdef1234567890 - - [1702433488.601132][2043:2045] CHIP:DMG: Received Command Response Data, Endpoint=0 Cluster=0x0000_0046 Command=0x0000_0001 - [1702433488.601231][2043:2045] CHIP:TOO: Endpoint: 0 Cluster: 0x0000_0046 Command 0x0000_0001 - [1702433488.601414][2043:2045] CHIP:TOO: RegisterClientResponse: { - [1702433488.601478][2043:2045] CHIP:TOO: ICDCounter: 228745926 - [1702433488.601531][2043:2045] CHIP:TOO: } - disabled: true - - - label: "Step 3b: TH reads from the DUT the RegisteredClients attribute." - PICS: ICDM.S.A0003 - verification: | - ./chip-tool icdmanagement read registered-clients 1 0 - - [1702433698.808800][2095:2097] CHIP:TOO: Endpoint: 0 Cluster: 0x0000_0046 Attribute 0x0000_0003 DataVersion: 2083795792 - [1702433698.808939][2095:2097] CHIP:TOO: RegisteredClients: 2 entries - [1702433698.809081][2095:2097] CHIP:TOO: [1]: { - [1702433698.809126][2095:2097] CHIP:TOO: CheckInNodeID: 112233 - [1702433698.809167][2095:2097] CHIP:TOO: MonitoredSubject: 112233 - [1702433698.809226][2095:2097] CHIP:TOO: FabricIndex: 1 - [1702433698.809266][2095:2097] CHIP:TOO: } - [1702433698.809319][2095:2097] CHIP:TOO: [2]: { - [1702433698.809359][2095:2097] CHIP:TOO: CheckInNodeID: 3 - [1702433698.809399][2095:2097] CHIP:TOO: MonitoredSubject: 3 - [1702433698.809514][2095:2097] CHIP:TOO: FabricIndex: 1 - [1702433698.809559][2095:2097] CHIP:TOO: } - disabled: true - - - label: - "Step 4: TH sends RegisterClient command with same CheckInNodeID as in - Step 3a and different MonitoredSubject and Key, and an invalid - VerificationKey - CheckInNodeID: registering clients node ID - (CheckInNodeID3) - MonitoredSubject: monitored subject ID - (MonitorSubID4) - Key: shared secret between the client and the ICD - (Key4) - VerificationKey: invalid verification key (VerificationKey4)" - PICS: ICDM.S.C00.Rsp - verification: | - ./chip-tool icdmanagement register-client 3 4 hex:3334567890abcdef3334567890abcdef 1 0 --VerificationKey hex:abcdef1234567890 - - [1703266655.434604][2378:2381] CHIP:DMG: Received Command Response Status for Endpoint=0 Cluster=0x0000_0046 Command=0x0000_0000 Status=0x1 - [1703266655.434688][2378:2381] CHIP:TOO: Error: IM Error 0x00000501: General error: 0x01 (FAILURE) - disabled: true - - - label: - "Step 5: TH sends RegisterClient command with same CheckInNodeID as in - Step 3a and different MonitoredSubject, Key, and VerificationKey - - CheckInNodeID: registering clients node ID (CheckInNodeID3) - - MonitoredSubject: monitored subject ID (MonitorSubID5) - Key: shared - secret between the client and the ICD (Key5) - VerificationKey: valid - verification key (VerificationKey5)" - PICS: ICDM.S.C00.Rsp - verification: | - ./chip-tool icdmanagement register-client 3 5 hex:3334567890abcdef3334567890abcdef 1 0 --VerificationKey hex:abcdef1234567890abcdef1234500000 - - [1703266705.829853][2551:2553] CHIP:DMG: Received Command Response Status for Endpoint=0 Cluster=0x0000_0046 Command=0x0000_0000 Status=0x1 - [1703266705.829994][2551:2553] CHIP:TOO: Error: IM Error 0x00000501: General error: 0x01 (FAILURE) - disabled: true - - - label: - "Step 6a: TH sends RegisterClient command with same CheckInNodeID and - VerificationKey as in Step 3a and different MonitoredSubject and Key - - CheckInNodeID: registering clients node ID (CheckInNodeID3) - - MonitoredSubject: monitored subject ID (MonitorSubID6) - Key: shared - secret between the client and the ICD (Key6) - VerificationKey: - verification key (VerificationKey3)" - PICS: ICDM.S.C00.Rsp - verification: | - ./chip-tool icdmanagement register-client 3 6 hex:3334567890abcdef3334567890abcdef 1 0 --VerificationKey hex:abcdef1234567890abcdef1234567890 - - [1703267703.849366][2694:2696] CHIP:TOO: Endpoint: 0 Cluster: 0x0000_0046 Command 0x0000_0001 - [1703267703.849532][2694:2696] CHIP:TOO: RegisterClientResponse: { - [1703267703.849587][2694:2696] CHIP:TOO: ICDCounter: 228745930 - [1703267703.849633][2694:2696] CHIP:TOO: } - disabled: true - - - label: "Step 6b: TH reads from the DUT the RegisteredClients attribute." - PICS: ICDM.S.A0003 - verification: | - ./chip-tool icdmanagement read registered-clients 1 0 - - [1702433698.808800][2095:2097] CHIP:TOO: Endpoint: 0 Cluster: 0x0000_0046 Attribute 0x0000_0003 DataVersion: 2083795792 - [1702433698.808939][2095:2097] CHIP:TOO: RegisteredClients: 2 entries - [1702433698.809081][2095:2097] CHIP:TOO: [1]: { - [1702433698.809126][2095:2097] CHIP:TOO: CheckInNodeID: 112233 - [1702433698.809167][2095:2097] CHIP:TOO: MonitoredSubject: 112233 - [1702433698.809226][2095:2097] CHIP:TOO: FabricIndex: 1 - [1702433698.809266][2095:2097] CHIP:TOO: } - [1702433698.809319][2095:2097] CHIP:TOO: [2]: { - [1702433698.809359][2095:2097] CHIP:TOO: CheckInNodeID: 3 - [1702433698.809399][2095:2097] CHIP:TOO: MonitoredSubject: 6 - [1702433698.809514][2095:2097] CHIP:TOO: FabricIndex: 1 - [1702433698.809559][2095:2097] CHIP:TOO: } - disabled: true - - - label: - "Step 6c: TH sends UnregisterClient command with the CheckInNodeID - (CheckInNodeID3) and VerificationKey (VerificationKey3)." - PICS: ICDM.S.C02.Rsp - verification: | - ./chip-tool icdmanagement unregister-client 3 3 0 - - [1702419153.281757][1380:1382] CHIP:DMG: InvokeResponseMessage = - [1702419153.281885][1380:1382] CHIP:DMG: { - [1702419153.282005][1380:1382] CHIP:DMG: suppressResponse = false, - [1702419153.282061][1380:1382] CHIP:DMG: InvokeResponseIBs = - [1702419153.282126][1380:1382] CHIP:DMG: [ - [1702419153.282177][1380:1382] CHIP:DMG: InvokeResponseIB = - [1702419153.282243][1380:1382] CHIP:DMG: { - [1702419153.282296][1380:1382] CHIP:DMG: CommandStatusIB = - [1702419153.282357][1380:1382] CHIP:DMG: { - [1702419153.282576][1380:1382] CHIP:DMG: CommandPathIB = - [1702419153.282650][1380:1382] CHIP:DMG: { - [1702419153.282725][1380:1382] CHIP:DMG: EndpointId = 0x0, - [1702419153.282812][1380:1382] CHIP:DMG: ClusterId = 0x46, - [1702419153.282895][1380:1382] CHIP:DMG: CommandId = 0x2, - [1702419153.282973][1380:1382] CHIP:DMG: }, - [1702419153.283183][1380:1382] CHIP:DMG: - [1702419153.283246][1380:1382] CHIP:DMG: StatusIB = - [1702419153.283327][1380:1382] CHIP:DMG: { - [1702419153.283409][1380:1382] CHIP:DMG: status = 0x00 (SUCCESS), - [1702419153.283490][1380:1382] CHIP:DMG: }, - [1702419153.283562][1380:1382] CHIP:DMG: - [1702419153.283626][1380:1382] CHIP:DMG: }, - [1702419153.283699][1380:1382] CHIP:DMG: - [1702419153.283751][1380:1382] CHIP:DMG: }, - [1702419153.283811][1380:1382] CHIP:DMG: - [1702419153.283859][1380:1382] CHIP:DMG: ], - [1702419153.283919][1380:1382] CHIP:DMG: - [1702419153.283966][1380:1382] CHIP:DMG: InteractionModelRevision = 11 - [1702419153.284013][1380:1382] CHIP:DMG: }, - [1702419153.284182][1380:1382] CHIP:DMG: Received Command Response Status for Endpoint=0 Cluster=0x0000_0046 Command=0x0000_0002 Status=0x0 - disabled: true diff --git a/src/app/tests/suites/certification/ci-pics-values b/src/app/tests/suites/certification/ci-pics-values index f64941bb688890..9109f30bec4d73 100644 --- a/src/app/tests/suites/certification/ci-pics-values +++ b/src/app/tests/suites/certification/ci-pics-values @@ -2532,7 +2532,7 @@ RVCOPSTATE.S.C01.Rsp=0 RVCOPSTATE.S.C02.Rsp=0 RVCOPSTATE.S.C03.Rsp=1 RVCOPSTATE.S.C04.Tx=1 -RVCOPSTATE.S.C128.Rsp=1 +RVCOPSTATE.S.C80.Rsp=1 RVCOPSTATE.S.M.ST_STOPPED=1 RVCOPSTATE.S.M.ST_RUNNING=1 RVCOPSTATE.S.M.ST_PAUSED=1 @@ -2618,6 +2618,7 @@ PIXIT.RVCRUNM.MODE_CHANGE_OK=0 # RVCOPSTATE.S.C02.Rsp=0 # RVCOPSTATE.S.C03.Rsp=1 # RVCOPSTATE.S.C04.Tx=1 +# RVCOPSTATE.S.C80.Rsp=1 # RVCOPSTATE.S.C128.Rsp=1 # RVCOPSTATE.C.C00.Tx=1 # RVCOPSTATE.C.C01.Tx=1 diff --git a/src/app/tests/suites/manualTests.json b/src/app/tests/suites/manualTests.json index 5edf1cbe71a264..8048c7b3be6e22 100644 --- a/src/app/tests/suites/manualTests.json +++ b/src/app/tests/suites/manualTests.json @@ -117,7 +117,7 @@ "GeneralCommissioning": ["Test_TC_CGEN_2_2"], "GeneralDiagnostics": ["Test_TC_DGGEN_2_2"], "Identify": ["Test_TC_I_3_2"], - "IcdManagement": ["Test_TC_ICDM_3_2", "Test_TC_ICDM_5_1"], + "IcdManagement": ["Test_TC_ICDM_4_1", "Test_TC_ICDM_5_1"], "IlluminanceMeasurement": [], "InteractionDataModel": [ "Test_TC_IDM_1_1", diff --git a/src/controller/python/chip/exceptions/__init__.py b/src/controller/python/chip/exceptions/__init__.py index c7f692e9284d26..b293a68eac9434 100644 --- a/src/controller/python/chip/exceptions/__init__.py +++ b/src/controller/python/chip/exceptions/__init__.py @@ -39,21 +39,17 @@ class ChipStackException(Exception): class ChipStackError(ChipStackException): - def __init__(self, chip_error: PyChipError, msg=None): - self._chip_error = chip_error - self.msg = msg if msg else "Chip Stack Error %d" % chip_error.code + def __init__(self, code: int, msg=None): + self.code = code + self.msg = msg if msg else "Chip Stack Error %d" % self.code @classmethod def from_chip_error(cls, chip_error: PyChipError) -> ChipStackError: - return cls(chip_error, str(chip_error)) - - @property - def chip_error(self) -> PyChipError | None: - return self._chip_error + return cls(chip_error.code, str(chip_error)) @property def err(self) -> int: - return self._chip_error.code + return self.code def __str__(self): return self.msg diff --git a/src/controller/python/chip/native/__init__.py b/src/controller/python/chip/native/__init__.py index 518339017b587c..2528aeca32bd1b 100644 --- a/src/controller/python/chip/native/__init__.py +++ b/src/controller/python/chip/native/__init__.py @@ -69,7 +69,7 @@ class ErrorSDKPart(enum.IntEnum): class PyChipError(ctypes.Structure): ''' The ChipError for Python library. - We are using the following struct for passing the infomations of CHIP_ERROR between C++ and Python: + We are using the following struct for passing the information of CHIP_ERROR between C++ and Python: ```c struct PyChipError @@ -88,6 +88,10 @@ def raise_on_error(self) -> None: if exception is not None: # Ensure exception is not None to avoid mypy error and only raise valid exceptions raise exception + @classmethod + def from_code(cls, code): + return cls(code=code, line=0, file=ctypes.c_void_p()) + @property def is_success(self) -> bool: return self.code == 0 diff --git a/src/darwin/Framework/CHIP/MTRDeviceController.mm b/src/darwin/Framework/CHIP/MTRDeviceController.mm index 3483ff33320c31..322593312ccea4 100644 --- a/src/darwin/Framework/CHIP/MTRDeviceController.mm +++ b/src/darwin/Framework/CHIP/MTRDeviceController.mm @@ -120,7 +120,7 @@ @implementation MTRDeviceController { MTRDeviceAttestationDelegateBridge * _deviceAttestationDelegateBridge; MTRDeviceControllerFactory * _factory; NSMapTable * _nodeIDToDeviceMap; - os_unfair_lock _deviceMapLock; // protects nodeIDToDeviceMap + os_unfair_lock _underlyingDeviceMapLock; MTRCommissionableBrowser * _commissionableBrowser; MTRAttestationTrustStoreBridge * _attestationTrustStoreBridge; @@ -134,12 +134,17 @@ @implementation MTRDeviceController { MTRP256KeypairBridge _operationalKeypairBridge; } +- (os_unfair_lock_t)deviceMapLock +{ + return &_underlyingDeviceMapLock; +} + - (instancetype)initForSubclasses { if (self = [super init]) { // nothing, as superclass of MTRDeviceController is NSObject } - + _underlyingDeviceMapLock = OS_UNFAIR_LOCK_INIT; return self; } @@ -250,7 +255,7 @@ - (instancetype)initWithFactory:(MTRDeviceControllerFactory *)factory _chipWorkQueue = queue; _factory = factory; - _deviceMapLock = OS_UNFAIR_LOCK_INIT; + _underlyingDeviceMapLock = OS_UNFAIR_LOCK_INIT; _nodeIDToDeviceMap = [NSMapTable strongToWeakObjectsMapTable]; _serverEndpoints = [[NSMutableArray alloc] init]; _commissionableBrowser = nil; @@ -301,7 +306,7 @@ - (instancetype)initWithFactory:(MTRDeviceControllerFactory *)factory - (NSString *)description { - return [NSString stringWithFormat:@"", self, _uniqueIdentifier]; + return [NSString stringWithFormat:@"<%@: %p uuid %@>", NSStringFromClass(self.class), self, _uniqueIdentifier]; } - (BOOL)isRunning @@ -317,7 +322,7 @@ - (void)shutdown return; } - MTR_LOG("Shutting down MTRDeviceController: %@", self); + MTR_LOG("Shutting down %@: %@", NSStringFromClass(self.class), self); [self cleanupAfterStartup]; } @@ -329,11 +334,11 @@ - (void)cleanupAfterStartup // do the secure session shutdowns. Since we don't want to hold the lock // while calling out into arbitrary invalidation code, snapshot the list of // devices before we start invalidating. - MTR_LOG("cleanupAfterStartup MTRDeviceController: %@", self); - os_unfair_lock_lock(&_deviceMapLock); + MTR_LOG("%s: %@", __PRETTY_FUNCTION__, self); + os_unfair_lock_lock(self.deviceMapLock); NSEnumerator * devices = [_nodeIDToDeviceMap objectEnumerator]; [_nodeIDToDeviceMap removeAllObjects]; - os_unfair_lock_unlock(&_deviceMapLock); + os_unfair_lock_unlock(self.deviceMapLock); for (MTRDevice * device in devices) { [device invalidate]; @@ -347,7 +352,7 @@ - (void)cleanupAfterStartup // in a very specific way that only MTRDeviceControllerFactory knows about. - (void)shutDownCppController { - MTR_LOG("shutDownCppController MTRDeviceController: %p", self); + MTR_LOG("%s: %p", __PRETTY_FUNCTION__, self); assertChipStackLockedByCurrentThread(); // Shut down all our endpoints. @@ -634,7 +639,7 @@ - (BOOL)startup:(MTRDeviceControllerStartupParamsInternal *)startupParams [_controllerDataStore fetchAttributeDataForAllDevices:^(NSDictionary *> * _Nonnull clusterDataByNode) { MTR_LOG("%@ Loaded attribute values for %lu nodes from storage for controller uuid %@", self, static_cast(clusterDataByNode.count), self->_uniqueIdentifier); - std::lock_guard lock(self->_deviceMapLock); + std::lock_guard lock(*self.deviceMapLock); NSMutableArray * deviceList = [NSMutableArray array]; for (NSNumber * nodeID in clusterDataByNode) { NSDictionary * clusterData = clusterDataByNode[nodeID]; @@ -654,7 +659,7 @@ - (BOOL)startup:(MTRDeviceControllerStartupParamsInternal *)startupParams }); }]; } - MTR_LOG("MTRDeviceController startup: %@", self); + MTR_LOG("%@ startup: %@", NSStringFromClass(self.class), self); return YES; } @@ -1004,7 +1009,7 @@ - (MTRBaseDevice *)baseDeviceForNodeID:(NSNumber *)nodeID // If prefetchedClusterData is not provided, load attributes individually from controller data store - (MTRDevice *)_setupDeviceForNodeID:(NSNumber *)nodeID prefetchedClusterData:(NSDictionary *)prefetchedClusterData { - os_unfair_lock_assert_owner(&_deviceMapLock); + os_unfair_lock_assert_owner(self.deviceMapLock); MTRDevice * deviceToReturn = [[MTRDevice_Concrete alloc] initWithNodeID:nodeID controller:self]; // If we're not running, don't add the device to our map. That would @@ -1043,7 +1048,7 @@ - (MTRDevice *)_setupDeviceForNodeID:(NSNumber *)nodeID prefetchedClusterData:(N - (MTRDevice *)deviceForNodeID:(NSNumber *)nodeID { - std::lock_guard lock(_deviceMapLock); + std::lock_guard lock(*self.deviceMapLock); MTRDevice * deviceToReturn = [_nodeIDToDeviceMap objectForKey:nodeID]; if (!deviceToReturn) { deviceToReturn = [self _setupDeviceForNodeID:nodeID prefetchedClusterData:nil]; @@ -1054,7 +1059,7 @@ - (MTRDevice *)deviceForNodeID:(NSNumber *)nodeID - (void)removeDevice:(MTRDevice *)device { - std::lock_guard lock(_deviceMapLock); + std::lock_guard lock(*self.deviceMapLock); auto * nodeID = device.nodeID; MTRDevice * deviceToRemove = [_nodeIDToDeviceMap objectForKey:nodeID]; if (deviceToRemove == device) { @@ -1068,7 +1073,7 @@ - (void)removeDevice:(MTRDevice *)device #ifdef DEBUG - (NSDictionary *)unitTestGetDeviceAttributeCounts { - std::lock_guard lock(_deviceMapLock); + std::lock_guard lock(*self.deviceMapLock); NSMutableDictionary * deviceAttributeCounts = [NSMutableDictionary dictionary]; for (NSNumber * nodeID in _nodeIDToDeviceMap) { deviceAttributeCounts[nodeID] = @([[_nodeIDToDeviceMap objectForKey:nodeID] unitTestAttributeCount]); @@ -1169,7 +1174,7 @@ - (BOOL)addServerEndpoint:(MTRServerEndpoint *)endpoint } if (![endpoint associateWithController:self]) { - MTR_LOG_ERROR("%@ Failed to associate MTRServerEndpoint with MTRDeviceController", self); + MTR_LOG_ERROR("%@ Failed to associate MTRServerEndpoint with %@", self, NSStringFromClass(self.class)); [_factory removeServerEndpoint:endpoint]; return NO; } @@ -1289,7 +1294,7 @@ - (BOOL)checkIsRunning:(NSError * __autoreleasing *)error return YES; } - MTR_LOG_ERROR("MTRDeviceController: %@ Error: %s", self, [kErrorNotRunning UTF8String]); + MTR_LOG_ERROR("%@: %@ Error: %s", NSStringFromClass(self.class), self, [kErrorNotRunning UTF8String]); if (error) { *error = [MTRError errorForCHIPErrorCode:CHIP_ERROR_INCORRECT_STATE]; } @@ -1508,9 +1513,9 @@ - (void)operationalInstanceAdded:(chip::NodeId)nodeID { // Don't use deviceForNodeID here, because we don't want to create the // device if it does not already exist. - os_unfair_lock_lock(&_deviceMapLock); + os_unfair_lock_lock(self.deviceMapLock); MTRDevice * device = [_nodeIDToDeviceMap objectForKey:@(nodeID)]; - os_unfair_lock_unlock(&_deviceMapLock); + os_unfair_lock_unlock(self.deviceMapLock); if (device == nil) { return; diff --git a/src/darwin/Framework/CHIP/MTRDeviceController_Concrete.mm b/src/darwin/Framework/CHIP/MTRDeviceController_Concrete.mm index d53d94b83db946..0ea7bf9232d766 100644 --- a/src/darwin/Framework/CHIP/MTRDeviceController_Concrete.mm +++ b/src/darwin/Framework/CHIP/MTRDeviceController_Concrete.mm @@ -82,8 +82,6 @@ #include #include -#import - typedef void (^SyncWorkQueueBlock)(void); typedef id (^SyncWorkQueueBlockWithReturnValue)(void); typedef BOOL (^SyncWorkQueueBlockWithBoolReturnValue)(void); @@ -103,8 +101,6 @@ @interface MTRDeviceController_Concrete () @property (nonatomic, readwrite) NSUUID * uniqueIdentifier; @property (nonatomic, readonly) dispatch_queue_t chipWorkQueue; @property (nonatomic, readonly, nullable) MTRDeviceControllerFactory * factory; -@property (nonatomic, readonly, nullable) NSMapTable * nodeIDToDeviceMap; -@property (nonatomic, readonly) os_unfair_lock deviceMapLock; @property (nonatomic, readonly, nullable) id otaProviderDelegate; @property (nonatomic, readonly, nullable) dispatch_queue_t otaProviderDelegateQueue; @property (nonatomic, readonly, nullable) MTRCommissionableBrowser * commissionableBrowser; @@ -270,11 +266,9 @@ - (instancetype)initWithFactory:(MTRDeviceControllerFactory *)factory _otaProviderDelegate = otaProviderDelegate; _otaProviderDelegateQueue = otaProviderDelegateQueue; - _chipWorkQueue = queue; _factory = factory; - _deviceMapLock = OS_UNFAIR_LOCK_INIT; - _nodeIDToDeviceMap = [NSMapTable strongToWeakObjectsMapTable]; + self.nodeIDToDeviceMap = [NSMapTable strongToWeakObjectsMapTable]; _serverEndpoints = [[NSMutableArray alloc] init]; _commissionableBrowser = nil; @@ -323,7 +317,7 @@ - (instancetype)initWithFactory:(MTRDeviceControllerFactory *)factory - (NSString *)description { - return [NSString stringWithFormat:@"", self, _uniqueIdentifier]; + return [NSString stringWithFormat:@"<%@: %p uuid %@>", NSStringFromClass(self.class), self, _uniqueIdentifier]; } - (BOOL)isRunning @@ -339,7 +333,7 @@ - (void)shutdown return; } - MTR_LOG("Shutting down MTRDeviceController: %@", self); + MTR_LOG("Shutting down %@: %@", NSStringFromClass(self.class), self); [self cleanupAfterStartup]; } @@ -351,11 +345,11 @@ - (void)cleanupAfterStartup // do the secure session shutdowns. Since we don't want to hold the lock // while calling out into arbitrary invalidation code, snapshot the list of // devices before we start invalidating. - MTR_LOG("cleanupAfterStartup MTRDeviceController: %@", self); - os_unfair_lock_lock(&_deviceMapLock); - NSEnumerator * devices = [_nodeIDToDeviceMap objectEnumerator]; - [_nodeIDToDeviceMap removeAllObjects]; - os_unfair_lock_unlock(&_deviceMapLock); + MTR_LOG("%s: %@", __PRETTY_FUNCTION__, self); + os_unfair_lock_lock(self.deviceMapLock); + NSEnumerator * devices = [self.nodeIDToDeviceMap objectEnumerator]; + [self.nodeIDToDeviceMap removeAllObjects]; + os_unfair_lock_unlock(self.deviceMapLock); for (MTRDevice * device in devices) { [device invalidate]; @@ -369,7 +363,7 @@ - (void)cleanupAfterStartup // in a very specific way that only MTRDeviceControllerFactory knows about. - (void)shutDownCppController { - MTR_LOG("shutDownCppController MTRDeviceController: %p", self); + MTR_LOG("%s: %p", __PRETTY_FUNCTION__, self); assertChipStackLockedByCurrentThread(); // Shut down all our endpoints. @@ -654,7 +648,7 @@ - (BOOL)startup:(MTRDeviceControllerStartupParamsInternal *)startupParams [_controllerDataStore fetchAttributeDataForAllDevices:^(NSDictionary *> * _Nonnull clusterDataByNode) { MTR_LOG("%@ Loaded attribute values for %lu nodes from storage for controller uuid %@", self, static_cast(clusterDataByNode.count), self->_uniqueIdentifier); - std::lock_guard lock(self->_deviceMapLock); + std::lock_guard lock(*self.deviceMapLock); NSMutableArray * deviceList = [NSMutableArray array]; for (NSNumber * nodeID in clusterDataByNode) { NSDictionary * clusterData = clusterDataByNode[nodeID]; @@ -674,7 +668,7 @@ - (BOOL)startup:(MTRDeviceControllerStartupParamsInternal *)startupParams }); }]; } - MTR_LOG("MTRDeviceController startup: %@", self); + MTR_LOG("%s: startup: %@", __PRETTY_FUNCTION__, self); return YES; } @@ -1024,15 +1018,15 @@ - (MTRBaseDevice *)baseDeviceForNodeID:(NSNumber *)nodeID // If prefetchedClusterData is not provided, load attributes individually from controller data store - (MTRDevice *)_setupDeviceForNodeID:(NSNumber *)nodeID prefetchedClusterData:(NSDictionary *)prefetchedClusterData { - os_unfair_lock_assert_owner(&_deviceMapLock); + os_unfair_lock_assert_owner(self.deviceMapLock); - MTRDevice * deviceToReturn = [[MTRDevice alloc] initWithNodeID:nodeID controller:self]; + MTRDevice * deviceToReturn = [[MTRDevice_Concrete alloc] initWithNodeID:nodeID controller:self]; // If we're not running, don't add the device to our map. That would // create a cycle that nothing would break. Just return the device, // which will be in exactly the state it would be in if it were created // while we were running and then we got shut down. if ([self isRunning]) { - [_nodeIDToDeviceMap setObject:deviceToReturn forKey:nodeID]; + [self.nodeIDToDeviceMap setObject:deviceToReturn forKey:nodeID]; } if (prefetchedClusterData) { @@ -1063,8 +1057,8 @@ - (MTRDevice *)_setupDeviceForNodeID:(NSNumber *)nodeID prefetchedClusterData:(N - (MTRDevice *)deviceForNodeID:(NSNumber *)nodeID { - std::lock_guard lock(_deviceMapLock); - MTRDevice * deviceToReturn = [_nodeIDToDeviceMap objectForKey:nodeID]; + std::lock_guard lock(*self.deviceMapLock); + MTRDevice * deviceToReturn = [self.nodeIDToDeviceMap objectForKey:nodeID]; if (!deviceToReturn) { deviceToReturn = [self _setupDeviceForNodeID:nodeID prefetchedClusterData:nil]; } @@ -1074,12 +1068,12 @@ - (MTRDevice *)deviceForNodeID:(NSNumber *)nodeID - (void)removeDevice:(MTRDevice *)device { - std::lock_guard lock(_deviceMapLock); + std::lock_guard lock(*self.deviceMapLock); auto * nodeID = device.nodeID; - MTRDevice * deviceToRemove = [_nodeIDToDeviceMap objectForKey:nodeID]; + MTRDevice * deviceToRemove = [self.nodeIDToDeviceMap objectForKey:nodeID]; if (deviceToRemove == device) { [deviceToRemove invalidate]; - [_nodeIDToDeviceMap removeObjectForKey:nodeID]; + [self.nodeIDToDeviceMap removeObjectForKey:nodeID]; } else { MTR_LOG_ERROR("%@ Error: Cannot remove device %p with nodeID %llu", self, device, nodeID.unsignedLongLongValue); } @@ -1088,10 +1082,10 @@ - (void)removeDevice:(MTRDevice *)device #ifdef DEBUG - (NSDictionary *)unitTestGetDeviceAttributeCounts { - std::lock_guard lock(_deviceMapLock); + std::lock_guard lock(*self.deviceMapLock); NSMutableDictionary * deviceAttributeCounts = [NSMutableDictionary dictionary]; - for (NSNumber * nodeID in _nodeIDToDeviceMap) { - deviceAttributeCounts[nodeID] = @([[_nodeIDToDeviceMap objectForKey:nodeID] unitTestAttributeCount]); + for (NSNumber * nodeID in self.nodeIDToDeviceMap) { + deviceAttributeCounts[nodeID] = @([[self.nodeIDToDeviceMap objectForKey:nodeID] unitTestAttributeCount]); } return deviceAttributeCounts; } @@ -1189,7 +1183,7 @@ - (BOOL)addServerEndpoint:(MTRServerEndpoint *)endpoint } if (![endpoint associateWithController:self]) { - MTR_LOG_ERROR("%@ Failed to associate MTRServerEndpoint with MTRDeviceController", self); + MTR_LOG_ERROR("%@ Failed to associate MTRServerEndpoint with %@", self, NSStringFromClass(self.class)); [_factory removeServerEndpoint:endpoint]; return NO; } @@ -1309,7 +1303,7 @@ - (BOOL)checkIsRunning:(NSError * __autoreleasing *)error return YES; } - MTR_LOG_ERROR("MTRDeviceController: %@ Error: %s", self, [kDeviceControllerErrorNotRunning UTF8String]); + MTR_LOG_ERROR("%@: %@ Error: %s", NSStringFromClass(self.class), self, [kDeviceControllerErrorNotRunning UTF8String]); if (error) { *error = [MTRError errorForCHIPErrorCode:CHIP_ERROR_INCORRECT_STATE]; } @@ -1540,9 +1534,9 @@ - (void)operationalInstanceAdded:(chip::NodeId)nodeID { // Don't use deviceForNodeID here, because we don't want to create the // device if it does not already exist. - os_unfair_lock_lock(&_deviceMapLock); - MTRDevice * device = [_nodeIDToDeviceMap objectForKey:@(nodeID)]; - os_unfair_lock_unlock(&_deviceMapLock); + os_unfair_lock_lock(self.deviceMapLock); + MTRDevice * device = [self.nodeIDToDeviceMap objectForKey:@(nodeID)]; + os_unfair_lock_unlock(self.deviceMapLock); if (device == nil) { return; diff --git a/src/darwin/Framework/CHIP/MTRDeviceController_Internal.h b/src/darwin/Framework/CHIP/MTRDeviceController_Internal.h index d943775d43475d..85d2c2e069ee2c 100644 --- a/src/darwin/Framework/CHIP/MTRDeviceController_Internal.h +++ b/src/darwin/Framework/CHIP/MTRDeviceController_Internal.h @@ -29,6 +29,8 @@ #include #include +#import + #import "MTRBaseDevice.h" #import "MTRDeviceController.h" #import "MTRDeviceControllerDataStore.h" @@ -63,6 +65,9 @@ NS_ASSUME_NONNULL_BEGIN @interface MTRDeviceController () +@property (nonatomic, readwrite, nullable) NSMapTable * nodeIDToDeviceMap; +@property (readonly, assign) os_unfair_lock_t deviceMapLock; + - (instancetype)initForSubclasses; #pragma mark - MTRDeviceControllerFactory methods @@ -270,6 +275,7 @@ NS_ASSUME_NONNULL_BEGIN #pragma mark - Device-specific data and SDK access // DeviceController will act as a central repository for this opaque dictionary that MTRDevice manages - (MTRDevice *)deviceForNodeID:(NSNumber *)nodeID; +- (MTRDevice *)_setupDeviceForNodeID:(NSNumber *)nodeID prefetchedClusterData:(nullable NSDictionary *)prefetchedClusterData; - (void)removeDevice:(MTRDevice *)device; /** diff --git a/src/darwin/Framework/CHIP/MTRDeviceController_XPC.mm b/src/darwin/Framework/CHIP/MTRDeviceController_XPC.mm index 1d91ae0d5d5f9a..157a38199f025e 100644 --- a/src/darwin/Framework/CHIP/MTRDeviceController_XPC.mm +++ b/src/darwin/Framework/CHIP/MTRDeviceController_XPC.mm @@ -15,6 +15,7 @@ */ #import "MTRDeviceController_XPC.h" + #import "MTRDefines_Internal.h" #import "MTRDeviceController_Internal.h" #import "MTRDevice_XPC.h" @@ -45,7 +46,7 @@ @implementation MTRDeviceController_XPC - (id)initWithUniqueIdentifier:(NSUUID *)UUID xpConnectionBlock:(NSXPCConnection * (^)(void) )connectionBlock { if (self = [super initForSubclasses]) { - MTR_LOG("Setting up XPC Controller for UUID: %@ with connection block: %p", UUID, connectionBlock); + MTR_LOG("Setting up XPC Controller for UUID: %@ with connection block: %p", UUID, connectionBlock); if (UUID == nil) { MTR_LOG_ERROR("MTRDeviceController_XPC initWithUniqueIdentifier failed, nil UUID"); @@ -66,8 +67,16 @@ - (id)initWithUniqueIdentifier:(NSUUID *)UUID xpConnectionBlock:(NSXPCConnection self.xpcConnection.exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(MTRXPCClientProtocol)]; self.xpcConnection.exportedObject = self; - MTR_LOG("Resuming new XPC connection"); - [self.xpcConnection resume]; + self.xpcConnection.interruptionHandler = ^{ + MTR_LOG_ERROR("XPC Connection for device controller interrupted: %@", UUID); + }; + + self.xpcConnection.invalidationHandler = ^{ + MTR_LOG_ERROR("XPC Connection for device controller invalidated: %@", UUID); + }; + + MTR_LOG("Activating new XPC connection"); + [self.xpcConnection activate]; } else { MTR_LOG_ERROR("Failed to set up XPC Connection"); return nil; @@ -111,6 +120,24 @@ - (nullable instancetype)initWithParameters:(MTRDeviceControllerAbstractParamete return nil; } +// If prefetchedClusterData is not provided, load attributes individually from controller data store +- (MTRDevice *)_setupDeviceForNodeID:(NSNumber *)nodeID prefetchedClusterData:(NSDictionary *)prefetchedClusterData +{ + MTR_LOG("%s", __PRETTY_FUNCTION__); + os_unfair_lock_assert_owner(self.deviceMapLock); + + MTRDevice * deviceToReturn = [[MTRDevice_XPC alloc] initWithNodeID:nodeID controller:self]; + // If we're not running, don't add the device to our map. That would + // create a cycle that nothing would break. Just return the device, + // which will be in exactly the state it would be in if it were created + // while we were running and then we got shut down. + if ([self isRunning]) { + [self.nodeIDToDeviceMap setObject:deviceToReturn forKey:nodeID]; + } + MTR_LOG("%s: returning XPC device for node id %@", __PRETTY_FUNCTION__, nodeID); + return deviceToReturn; +} + #pragma mark - XPC Action Overrides MTR_DEVICECONTROLLER_SIMPLE_REMOTE_XPC_GETTER(isRunning, BOOL, NO, getIsRunningWithReply) diff --git a/src/darwin/Framework/CHIP/MTRDevice_XPC.mm b/src/darwin/Framework/CHIP/MTRDevice_XPC.mm index 95f69cb7d4dc90..69eba5bc6f5ea4 100644 --- a/src/darwin/Framework/CHIP/MTRDevice_XPC.mm +++ b/src/darwin/Framework/CHIP/MTRDevice_XPC.mm @@ -82,41 +82,59 @@ @implementation MTRDevice_XPC -#pragma mark - Client Callbacks +#pragma mark - Client Callbacks (MTRDeviceDelegate) + +// required methods for MTRDeviceDelegates - (oneway void)device:(NSNumber *)nodeID stateChanged:(MTRDeviceState)state { + MTR_LOG("%s", __PRETTY_FUNCTION__); [self _callDelegatesWithBlock:^(id delegate) { [delegate device:self stateChanged:state]; }]; } + - (oneway void)device:(NSNumber *)nodeID receivedAttributeReport:(NSArray *> *)attributeReport { + MTR_LOG("%s", __PRETTY_FUNCTION__); [self _callDelegatesWithBlock:^(id delegate) { [delegate device:self receivedAttributeReport:attributeReport]; }]; } + - (oneway void)device:(NSNumber *)nodeID receivedEventReport:(NSArray *> *)eventReport { + MTR_LOG("%s", __PRETTY_FUNCTION__); [self _callDelegatesWithBlock:^(id delegate) { [delegate device:self receivedEventReport:eventReport]; }]; } + +// optional methods for MTRDeviceDelegates - check for implementation before calling - (oneway void)deviceBecameActive:(NSNumber *)nodeID { + MTR_LOG("%s", __PRETTY_FUNCTION__); [self _callDelegatesWithBlock:^(id delegate) { - [delegate deviceBecameActive:self]; + if ([delegate respondsToSelector:@selector(deviceBecameActive:)]) { + [delegate deviceBecameActive:self]; + } }]; } + - (oneway void)deviceCachePrimed:(NSNumber *)nodeID { [self _callDelegatesWithBlock:^(id delegate) { - [delegate deviceCachePrimed:self]; + if ([delegate respondsToSelector:@selector(deviceCachePrimed:)]) { + [delegate deviceCachePrimed:self]; + } }]; } + - (oneway void)deviceConfigurationChanged:(NSNumber *)nodeID { [self _callDelegatesWithBlock:^(id delegate) { - [delegate deviceConfigurationChanged:self]; + if ([delegate respondsToSelector:@selector(deviceConfigurationChanged:)]) { + [delegate deviceConfigurationChanged:self]; + } }]; } diff --git a/src/platform/Darwin/DnssdContexts.cpp b/src/platform/Darwin/DnssdContexts.cpp index 4e88df40ee596d..ff869911e98e48 100644 --- a/src/platform/Darwin/DnssdContexts.cpp +++ b/src/platform/Darwin/DnssdContexts.cpp @@ -247,6 +247,7 @@ void MdnsContexts::Delete(GenericContext * context) if (context->serviceRef != nullptr) { DNSServiceRefDeallocate(context->serviceRef); + context->serviceRef = nullptr; } chip::Platform::Delete(context); } diff --git a/src/python_testing/TC_BRBINFO_4_1.py b/src/python_testing/TC_BRBINFO_4_1.py index 8e920d8bc6013e..ea230150c27fdb 100644 --- a/src/python_testing/TC_BRBINFO_4_1.py +++ b/src/python_testing/TC_BRBINFO_4_1.py @@ -15,10 +15,10 @@ # limitations under the License. # -# This test requires a TH_SERVER application. Please specify with --string-arg th_server_app_path: -# TH_SERVER must support following arguments: --secured-device-port --discriminator --passcode --KVS +# This test requires a TH_ICD_SERVER application. Please specify with --string-arg th_icd_server_app_path: +# TH_ICD_SERVER must support following arguments: --secured-device-port --discriminator --passcode --KVS # E.g: python3 src/python_testing/TC_BRBINFO_4_1.py --commissioning-method on-network --qr-code MT:-24J042C00KA0648G00 \ -# --string-arg th_server_app_path:out/linux-x64-lit-icd/lit-icd-app +# --string-arg th_icd_server_app_path:out/linux-x64-lit-icd/lit-icd-app import logging import os @@ -62,7 +62,8 @@ def steps_TC_BRBINFO_4_1(self) -> list[TestStep]: TestStep("1a", "TH reads from the ICD the A_IDLE_MODE_DURATION, A_ACTIVE_MODE_DURATION, and ACTIVE_MODE_THRESHOLD attributes"), TestStep("1b", "Simple KeepActive command w/ subscription. ActiveChanged event received by TH contains PromisedActiveDuration"), TestStep("2", "Sends 3x KeepActive commands w/ subscription. ActiveChanged event received ONCE and contains PromisedActiveDuration"), - TestStep("3", "KeepActive not returned after 60 minutes of offline ICD"), + TestStep("3", "TH waits for check-in from TH_ICD to confirm no additional ActiveChanged events are recieved"), + TestStep("4", "KeepActive not returned after 60 minutes of offline ICD"), ] return steps @@ -110,9 +111,10 @@ async def setup_class(self): super().setup_class() self.app_process = None - app = self.user_params.get("th_server_app_path", None) + self.app_process_paused = False + app = self.user_params.get("th_icd_server_app_path", None) if not app: - asserts.fail('This test requires a TH_SERVER app. Specify app path with --string-arg th_server_app_path:') + asserts.fail('This test requires a TH_ICD_SERVER app. Specify app path with --string-arg th_icd_server_app_path:') self.kvs = f'kvs_{str(uuid.uuid4())}' self.port = 5543 @@ -129,6 +131,7 @@ async def setup_class(self): logging.info("Commissioning of ICD to fabric one (TH)") self.icd_nodeid = 1111 + self.default_controller.EnableICDRegistration(self.default_controller.GenerateICDRegistrationParameters()) await self.default_controller.CommissionOnNetwork(nodeId=self.icd_nodeid, setupPinCode=passcode, filterType=ChipDeviceCtrl.DiscoveryFilterType.LONG_DISCRIMINATOR, filter=discriminator) logging.info("Commissioning of ICD to fabric two (DUT)") @@ -138,9 +141,10 @@ async def setup_class(self): params.commissioningParameters.setupManualCode, params.commissioningParameters.setupQRCode) def teardown_class(self): - # In case the th_server_app_path does not exist, then we failed the test + # In case the th_icd_server_app_path does not exist, then we failed the test # and there is nothing to remove if self.app_process is not None: + self.resume_th_icd_server(check_state=False) logging.warning("Stopping app with SIGTERM") self.app_process.send_signal(signal.SIGTERM.value) self.app_process.wait() @@ -150,6 +154,24 @@ def teardown_class(self): super().teardown_class() + def pause_th_icd_server(self, check_state): + if check_state: + asserts.assert_false(self.app_process_paused, "ICD TH Server unexpectedly is already paused") + if self.app_process_paused: + return + # stops (halts) the ICD server process by sending a SIGTOP signal + self.app_process.send_signal(signal.SIGSTOP.value) + self.app_process_paused = True + + def resume_th_icd_server(self, check_state): + if check_state: + asserts.assert_true(self.app_process_paused, "ICD TH Server unexpectedly is already running") + if not self.app_process_paused: + return + # resumes (continues) the ICD server process by sending a SIGCONT signal + self.app_process.send_signal(signal.SIGCONT.value) + self.app_process_paused = False + # # BRBINFO 4.1 Test Body # @@ -232,58 +254,54 @@ async def test_TC_BRBINFO_4_1(self): self.step("2") - stay_active_duration_ms = 1500 - logging.info(f"Sending KeepActiveCommand({stay_active_duration_ms}ms)") - await self._send_keep_active_command(stay_active_duration_ms, dynamic_endpoint_id) - - logging.info("Waiting for ActiveChanged from DUT...") - timeout_s = idle_mode_duration_s + max(active_mode_duration_ms, stay_active_duration_ms)/1000 - promised_active_duration_ms = await self._wait_for_active_changed_event(timeout_s) - - # wait for active time duration - sleep_time_s = max(stay_active_duration_ms, promised_active_duration_ms)/1000 - time.sleep(sleep_time_s) - # ICD now should be in idle mode - + # Prevent icd app from sending any check-in messages. + self.pause_th_icd_server(check_state=True) # sends 3x keep active commands - logging.info(f"Step3 Sending first KeepActiveCommand({stay_active_duration_ms})") + stay_active_duration_ms = 2000 + logging.info(f"Sending first KeepActiveCommand({stay_active_duration_ms})") await self._send_keep_active_command(stay_active_duration_ms, dynamic_endpoint_id) - time.sleep(0.1) - logging.info(f"Step3 Sending second KeepActiveCommand({stay_active_duration_ms})") + logging.info(f"Sending second KeepActiveCommand({stay_active_duration_ms})") await self._send_keep_active_command(stay_active_duration_ms, dynamic_endpoint_id) - time.sleep(0.1) - logging.info(f"Step3 Sending third KeepActiveCommand({stay_active_duration_ms})") + logging.info(f"Sending third KeepActiveCommand({stay_active_duration_ms})") await self._send_keep_active_command(stay_active_duration_ms, dynamic_endpoint_id) - time.sleep(0.1) + self.resume_th_icd_server(check_state=True) logging.info("Waiting for ActiveChanged from DUT...") promised_active_duration_ms = await self._wait_for_active_changed_event((idle_mode_duration_s + max(active_mode_duration_ms, stay_active_duration_ms))/1000) - - asserts.assert_equal(self.q.qSize(), 0, "More than one event received from DUT") + asserts.assert_equal(self.q.qsize(), 0, "More than one event received from DUT") self.step("3") + await self.default_controller.WaitForActive(self.icd_nodeid, stayActiveDurationMs=5000) + asserts.assert_equal(self.q.qsize(), 0, "More than one event received from DUT") + + self.step("4") + logging.info("TH waiting for checkin from TH_ICD...") + await self.default_controller.WaitForActive(self.icd_nodeid, stayActiveDurationMs=10000) stay_active_duration_ms = 10000 logging.info(f"Sending KeepActiveCommand({stay_active_duration_ms})") await self._send_keep_active_command(stay_active_duration_ms, dynamic_endpoint_id) - # stops (halts) the ICD server process by sending a SIGTOP signal - self.app_process.send_signal(signal.SIGSTOP.value) + self.pause_th_icd_server(check_state=True) + # If we are seeing assertion below fail test assumption is likely incorrect. + # Test assumes after TH waits for check-in from TH_ICD it has enough time to + # call the KeepActive command and pause the app to prevent it from checking in + # after DUT recieved the KeepActive command. Should this assumption be incorrect + # we could look into using existing ICDTestEventTriggerEvent, or adding test + # event trigger that will help suppress check-ins from the TH_ICD_SERVER. + asserts.assert_equal(self.q.qsize(), 0, "") if not self.is_ci: logging.info("Waiting for 60 minutes") - self._timeout time.sleep(60*60) - # resumes (continues) the ICD server process by sending a SIGCONT signal - self.app_process.send_signal(signal.SIGCONT.value) + self.resume_th_icd_server(check_state=True) - # wait for active changed event, expect no event will be sent - event_timeout = (idle_mode_duration_s + max(active_mode_duration_ms, stay_active_duration_ms))/1000 - try: - promised_active_duration_ms = self.q.get(block=True, timeout=event_timeout) - finally: - asserts.assert_true(queue.Empty(), "ActiveChanged event received when not expected") + logging.info("TH waiting for first checkin from TH_ICD...") + await self.default_controller.WaitForActive(self.icd_nodeid, stayActiveDurationMs=10000) + logging.info("TH waiting for second checkin from TH_ICD...") + await self.default_controller.WaitForActive(self.icd_nodeid, stayActiveDurationMs=10000) + asserts.assert_equal(self.q.qsize(), 0, "More than one event received from DUT") if __name__ == "__main__": diff --git a/src/python_testing/TC_CADMIN_1_9.py b/src/python_testing/TC_CADMIN_1_9.py index f37e3723ed1055..c3d67b9bf60ace 100644 --- a/src/python_testing/TC_CADMIN_1_9.py +++ b/src/python_testing/TC_CADMIN_1_9.py @@ -31,6 +31,7 @@ from chip import ChipDeviceCtrl from chip.ChipDeviceCtrl import CommissioningParameters from chip.exceptions import ChipStackError +from chip.native import PyChipError from matter_testing_support import MatterBaseTest, TestStep, async_test_body, default_matter_test_main from mobly import asserts @@ -74,7 +75,7 @@ async def CommissionOnNetwork( await self.th2.CommissionOnNetwork( nodeId=self.dut_node_id, setupPinCode=setup_code, filterType=ChipDeviceCtrl.DiscoveryFilterType.LONG_DISCRIMINATOR, filter=self.discriminator) - errcode = ctx.exception.chip_error + errcode = PyChipError.from_code(ctx.exception.err) return errcode async def CommissionAttempt( diff --git a/src/python_testing/TC_CGEN_2_4.py b/src/python_testing/TC_CGEN_2_4.py index 7d9d075dc16cb9..09fbc6d593a53e 100644 --- a/src/python_testing/TC_CGEN_2_4.py +++ b/src/python_testing/TC_CGEN_2_4.py @@ -38,6 +38,7 @@ from chip import ChipDeviceCtrl from chip.ChipDeviceCtrl import CommissioningParameters from chip.exceptions import ChipStackError +from chip.native import PyChipError from matter_testing_support import MatterBaseTest, async_test_body, default_matter_test_main from mobly import asserts @@ -78,7 +79,7 @@ async def CommissionToStageSendCompleteAndCleanup( await self.th2.CommissionOnNetwork( nodeId=self.dut_node_id, setupPinCode=params.setupPinCode, filterType=ChipDeviceCtrl.DiscoveryFilterType.LONG_DISCRIMINATOR, filter=self.discriminator) - errcode = ctx.exception.chip_error + errcode = PyChipError.from_code(ctx.exception.err) asserts.assert_true(errcode.sdk_part == expectedErrorPart, 'Unexpected error type returned from CommissioningComplete') asserts.assert_true(errcode.sdk_code == expectedErrCode, 'Unexpected error code returned from CommissioningComplete') revokeCmd = Clusters.AdministratorCommissioning.Commands.RevokeCommissioning() diff --git a/src/python_testing/TC_ICDM_3_2.py b/src/python_testing/TC_ICDM_3_2.py new file mode 100644 index 00000000000000..5a194420c3619e --- /dev/null +++ b/src/python_testing/TC_ICDM_3_2.py @@ -0,0 +1,419 @@ + +# +# Copyright (c) 2023 Project CHIP Authors +# All rights reserved. +# +# 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. +# + +# See https://github.com/project-chip/connectedhomeip/blob/master/docs/testing/python.md#defining-the-ci-test-arguments +# for details about the block below. +# +# === BEGIN CI TEST ARGUMENTS === +# test-runner-runs: run1 +# test-runner-run/run1/app: ${LIT_ICD_APP} +# test-runner-run/run1/factoryreset: True +# test-runner-run/run1/quiet: True +# test-runner-run/run1/app-args: --discriminator 1234 --KVS kvs1 --trace-to json:${TRACE_APP}.json +# test-runner-run/run1/script-args: --storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --PICS src/app/tests/suites/certification/ci-pics-values --trace-to json:${TRACE_TEST_JSON}.json --trace-to perfetto:${TRACE_TEST_PERFETTO}.perfetto +# === END CI TEST ARGUMENTS === + +import logging +import time +from dataclasses import dataclass + +import chip.clusters as Clusters +from chip.interaction_model import InteractionModelError, Status +from matter_testing_support import MatterBaseTest, TestStep, async_test_body, default_matter_test_main +from mobly import asserts + +logger = logging.getLogger(__name__) + +# ========================== +# Constants +# ========================== + +kRootEndpointId = 0 + +cluster = Clusters.Objects.IcdManagement +commands = cluster.Commands +ClientTypeEnum = cluster.Enums.ClientTypeEnum +attributes = cluster.Attributes + + +@dataclass +class Client: + checkInNodeID: int + subjectId: int + key: bytes + clientType: ClientTypeEnum + + +# +# Test Input Data +# +kIncorrectKey = b"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1a" +kInvalidKey = b"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e1g" + +client1 = Client( + checkInNodeID=1, + subjectId=1, + key=b"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", + clientType=ClientTypeEnum.kEphemeral +) + +client2 = Client( + checkInNodeID=1, + subjectId=2, + key=b"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1e", + clientType=ClientTypeEnum.kEphemeral +) + +client3 = Client( + checkInNodeID=1, + subjectId=3, + key=b"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1d", + clientType=ClientTypeEnum.kEphemeral +) + +client4 = Client( + checkInNodeID=1, + subjectId=4, + key=b"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1c", + clientType=ClientTypeEnum.kEphemeral +) + +client5 = Client( + checkInNodeID=5, + subjectId=5, + key=b"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1b", + clientType=ClientTypeEnum.kEphemeral +) + +client6 = Client( + checkInNodeID=5, + subjectId=6, + key=b"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1a", + clientType=ClientTypeEnum.kEphemeral +) + +client7 = Client( + checkInNodeID=5, + subjectId=7, + key=b"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x0f", + clientType=ClientTypeEnum.kEphemeral +) + +client8 = Client( + checkInNodeID=5, + subjectId=8, + key=b"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x0e", + clientType=ClientTypeEnum.kEphemeral +) + + +class TC_ICDM_3_2(MatterBaseTest): + + # + # Class Helper functions + # + async def _read_icdm_attribute_expect_success(self, attribute): + return await self.read_single_attribute_check_success(endpoint=kRootEndpointId, cluster=cluster, attribute=attribute) + + async def _send_single_icdm_command(self, command): + return await self.send_single_cmd(command, endpoint=kRootEndpointId) + # + # Test Harness Helpers + # + + def desc_TC_ICDM_3_2(self) -> str: + """Returns a description of this test""" + return "[TC-ICDM-3.2] Verify RegisterClient Command with DUT as Server" + + def steps_TC_ICDM_3_2(self) -> list[TestStep]: + steps = [ + TestStep(0, "Commissioning, already done", is_commissioning=True), + TestStep(1, "TH reads from the DUT the RegisteredClients attribute. RegisteredClients is empty."), + TestStep("2a", "TH sends RegisterClient command."), + TestStep("2b", "TH reads from the DUT the RegisteredClients attribute."), + TestStep("2c", "Power cycle DUT."), + TestStep("2d", "TH waits for {PIXIT.WAITTIME.REBOOT}"), + TestStep("2e", "TH reads from the DUT the RegisteredClients attribute."), + TestStep("3a", "TH sends RegisterClient command with same CheckInNodeID1 as in Step 1a and different MonitorSubID2 and Key2."), + TestStep("3b", "TH reads from the DUT the RegisteredClients attribute."), + TestStep("4a", "TH sends RegisterClient command with same CheckInNodeID1 as in Step 1a and different MonitorSubID3 and Key3, and an invalid VerificationKey3."), + TestStep("4b", "TH reads from the DUT the RegisteredClients attribute."), + TestStep("5a", "TH sends RegisterClient command with same CheckInNodeID1 as in Step 1a and different MonitorSubID4 and Key4, and a valid wrong VerificationKey4."), + TestStep("5b", "TH reads from the DUT the RegisteredClients attribute."), + TestStep("6a", "TH sends UnregisterClient command with CheckInNodeID1."), + TestStep("6b", "TH reads from the DUT the RegisteredClients attribute."), + TestStep(7, "Set the TH to Manage privilege for ICDM cluster."), + TestStep("8a", "TH sends RegisterClient command."), + TestStep("8b", "TH sends RegisterClient command with same CheckInNodeID5 as in Step 6a and different MonitorSubID6 and Key6, and an invalid VerificationKey6."), + TestStep("8c", "TH sends RegisterClient command with same CheckInNodeID5 as in Step 6a and different MonitorSubID7 and Key7, and an valid wrong VerificationKey7."), + TestStep("8d", "TH sends RegisterClient command with same CheckInNodeID5 and VerificationKey5 as in Step 6a and different MonitorSubID9 and Key9."), + TestStep(9, "TH sends UnregisterClient command with the CheckInNodeID5 and VerificationKey5."), + ] + return steps + + def pics_TC_ICDM_3_2(self) -> list[str]: + """ This function returns a list of PICS for this test case that must be True for the test to be run""" + pics = [ + "ICDM.S", + "ICDM.S.F00" + ] + return pics + + # + # ICDM 3.2 Test Body + # + + @ async_test_body + async def test_TC_ICDM_3_2(self): + is_ci = self.check_pics("PICS_SDK_CI_ONLY") + + if not is_ci: + asserts.assert_true('PIXIT.WAITTIME.REBOOT' in self.matter_test_config.global_test_params, + "PIXIT.WAITTIME.REBOOT must be included on the command line in " + "the --int-arg flag as PIXIT.WAITTIME.REBOOT:") + + wait_time_reboot = self.matter_test_config.global_test_params['PIXIT.WAITTIME.REBOOT'] + if wait_time_reboot == 0: + asserts.fail("PIXIT.WAITTIME.REBOOT shall be higher than 0.") + + # Pre-Condition: Commissioning + self.step(0) + + # Empty RegisteredClients attribute for all registrations + self.step(1) + registeredClients = await self._read_icdm_attribute_expect_success( + attributes.RegisteredClients) + + for client in registeredClients: + try: + await self._send_single_icdm_command(commands.UnregisterClient(checkInNodeID=client.checkInNodeID)) + except InteractionModelError as e: + asserts.assert_equal( + e.status, Status.Success, "Unexpected error returned") + + try: + self.step("2a") + try: + await self._send_single_icdm_command(commands.RegisterClient(checkInNodeID=client1.checkInNodeID, monitoredSubject=client1.subjectId, key=client1.key, clientType=client1.clientType)) + except InteractionModelError as e: + asserts.assert_equal( + e.status, Status.Success, "Unexpected error returned") + + self.step("2b") + registeredClients = await self._read_icdm_attribute_expect_success( + attributes.RegisteredClients) + # Validate list size + asserts.assert_equal(len(registeredClients), 1, + "The expected length of RegisteredClients is 1. List has the wrong size.") + + # Validate entry values + asserts.assert_equal( + registeredClients[0].checkInNodeID, client1.checkInNodeID, "The read attribute does not match the registered value.") + asserts.assert_equal( + registeredClients[0].monitoredSubject, client1.subjectId, "The read attribute does not match the registered value.") + asserts.assert_equal( + registeredClients[0].clientType, client1.clientType, "The read attribute does not match the registered value.") + + # Reboot + self.step("2c") + if not is_ci: + self.wait_for_user_input(prompt_msg="Restart DUT. Press Enter when restart has been initiated.") + + self.step("2d") + if not is_ci: + time.sleep(wait_time_reboot) + + self.step("2e") + registeredClients = await self._read_icdm_attribute_expect_success( + attributes.RegisteredClients) + # Validate list size + asserts.assert_equal(len(registeredClients), 1, + "The expected length of RegisteredClients is 1. List has the wrong size.") + + # Validate entry values + asserts.assert_equal( + registeredClients[0].checkInNodeID, client1.checkInNodeID, "The read attribute does not match the registered value.") + asserts.assert_equal( + registeredClients[0].monitoredSubject, client1.subjectId, "The read attribute does not match the registered value.") + asserts.assert_equal( + registeredClients[0].clientType, client1.clientType, "The read attribute does not match the registered value.") + + self.step("3a") + try: + await self._send_single_icdm_command(commands.RegisterClient(checkInNodeID=client2.checkInNodeID, monitoredSubject=client2.subjectId, key=client2.key, clientType=client2.clientType)) + except InteractionModelError as e: + asserts.assert_equal( + e.status, Status.Success, "Unexpected error returned") + + self.step("3b") + registeredClients = await self._read_icdm_attribute_expect_success( + attributes.RegisteredClients) + # Validate list size + asserts.assert_equal(len(registeredClients), 1, + "The expected length of RegisteredClients is 1. List has the wrong size.") + + # Validate entry values + asserts.assert_equal( + registeredClients[0].checkInNodeID, client2.checkInNodeID, "The read attribute does not match the registered value.") + asserts.assert_equal( + registeredClients[0].monitoredSubject, client2.subjectId, "The read attribute does not match the registered value.") + asserts.assert_equal( + registeredClients[0].clientType, client2.clientType, "The read attribute does not match the registered value.") + + self.step("4a") + try: + await self._send_single_icdm_command(commands.RegisterClient(checkInNodeID=client3.checkInNodeID, monitoredSubject=client3.subjectId, key=client3.key, clientType=client3.clientType, verificationKey=kInvalidKey)) + except InteractionModelError as e: + asserts.assert_equal( + e.status, Status.Success, "Unexpected error returned") + + self.step("4b") + registeredClients = await self._read_icdm_attribute_expect_success( + attributes.RegisteredClients) + # Validate list size + asserts.assert_equal(len(registeredClients), 1, + "The expected length of RegisteredClients is 1. List has the wrong size.") + + # Validate entry values + asserts.assert_equal( + registeredClients[0].checkInNodeID, client3.checkInNodeID, "The read attribute does not match the registered value.") + asserts.assert_equal( + registeredClients[0].monitoredSubject, client3.subjectId, "The read attribute does not match the registered value.") + asserts.assert_equal( + registeredClients[0].clientType, client3.clientType, "The read attribute does not match the registered value.") + + self.step("5a") + try: + await self._send_single_icdm_command(commands.RegisterClient(checkInNodeID=client4.checkInNodeID, monitoredSubject=client4.subjectId, key=client4.key, clientType=client4.clientType, verificationKey=kIncorrectKey)) + except InteractionModelError as e: + asserts.assert_equal( + e.status, Status.Success, "Unexpected error returned") + + self.step("5b") + registeredClients = await self._read_icdm_attribute_expect_success( + attributes.RegisteredClients) + # Validate list size + asserts.assert_equal(len(registeredClients), 1, + "The expected length of RegisteredClients is 1. List has the wrong size.") + + # Validate entry values + asserts.assert_equal( + registeredClients[0].checkInNodeID, client4.checkInNodeID, "The read attribute does not match the registered value.") + asserts.assert_equal( + registeredClients[0].monitoredSubject, client4.subjectId, "The read attribute does not match the registered value.") + asserts.assert_equal( + registeredClients[0].clientType, client4.clientType, "The read attribute does not match the registered value.") + + self.step("6a") + try: + await self._send_single_icdm_command(commands.UnregisterClient(checkInNodeID=client4.checkInNodeID)) + except InteractionModelError as e: + asserts.assert_equal( + e.status, Status.Success, "Unexpected error returned") + + self.step("6b") + registeredClients = await self._read_icdm_attribute_expect_success( + attributes.RegisteredClients) + asserts.assert_equal(len(registeredClients), 0, + "The RegisteredClients list must be empty. List has the wrong size.") + + self.step(7) + ac = Clusters.AccessControl + previousAcl = await self.read_single_attribute_check_success(cluster=ac, attribute=ac.Attributes.Acl) + newAcls = [] + + # Set Admin permissions on Access Control cluster + newAclEntry = ac.Structs.AccessControlEntryStruct(privilege=ac.Enums.AccessControlEntryPrivilegeEnum.kAdminister, + authMode=ac.Enums.AccessControlEntryAuthModeEnum.kCase, + subjects=previousAcl[0].subjects, targets=[ac.Structs.AccessControlTargetStruct( + cluster=Clusters.AccessControl.id)], fabricIndex=previousAcl[0].fabricIndex + ) + newAcls.append(newAclEntry) + + # Set Manage permissions on ICD Management cluster + newAclEntry = ac.Structs.AccessControlEntryStruct(privilege=ac.Enums.AccessControlEntryPrivilegeEnum.kManage, + authMode=ac.Enums.AccessControlEntryAuthModeEnum.kCase, + subjects=previousAcl[0].subjects, targets=[ac.Structs.AccessControlTargetStruct( + cluster=Clusters.IcdManagement.id)], fabricIndex=previousAcl[0].fabricIndex + ) + newAcls.append(newAclEntry) + + try: + await self.default_controller.WriteAttribute(nodeid=self.dut_node_id, attributes=[(0, ac.Attributes.Acl(newAcls))]) + except InteractionModelError as e: + asserts.assert_equal( + e.status, Status.Success, "Unexpected error returned") + + self.step("8a") + try: + await self._send_single_icdm_command(commands.RegisterClient(checkInNodeID=client5.checkInNodeID, monitoredSubject=client5.subjectId, key=client5.key, clientType=client5.clientType)) + except InteractionModelError as e: + asserts.assert_equal( + e.status, Status.Success, "Unexpected error returned") + + self.step("8b") + try: + await self._send_single_icdm_command(commands.RegisterClient(checkInNodeID=client6.checkInNodeID, monitoredSubject=client6.subjectId, key=client6.key, clientType=client6.clientType, verificationKey=kInvalidKey)) + except InteractionModelError as e: + asserts.assert_equal( + e.status, Status.Failure, "Unexpected error returned") + + self.step("8c") + try: + await self._send_single_icdm_command(commands.RegisterClient(checkInNodeID=client7.checkInNodeID, monitoredSubject=client7.subjectId, key=client7.key, clientType=client7.clientType, verificationKey=kIncorrectKey)) + except InteractionModelError as e: + asserts.assert_equal( + e.status, Status.Failure, "Unexpected error returned") + + self.step("8d") + try: + await self._send_single_icdm_command(commands.RegisterClient(checkInNodeID=client8.checkInNodeID, monitoredSubject=client8.subjectId, key=client8.key, clientType=client8.clientType, verificationKey=client5.key)) + except InteractionModelError as e: + asserts.assert_equal( + e.status, Status.Success, "Unexpected error returned") + + self.step(9) + try: + await self._send_single_icdm_command(commands.UnregisterClient(checkInNodeID=client8.checkInNodeID, verificationKey=client8.key)) + except InteractionModelError as e: + asserts.assert_equal( + e.status, Status.Success, "Unexpected error returned") + + # Post-Condition steps + finally: + # Reset ACLs + try: + await self.default_controller.WriteAttribute(nodeid=self.dut_node_id, attributes=[(0, ac.Attributes.Acl(previousAcl))]) + except InteractionModelError as e: + asserts.assert_equal( + e.status, Status.Success, "Unexpected error returned") + + # Clear all RegisteredClients + registeredClients = await self._read_icdm_attribute_expect_success( + attributes.RegisteredClients) + + for client in registeredClients: + try: + await self._send_single_icdm_command(commands.UnregisterClient(checkInNodeID=client.checkInNodeID)) + except InteractionModelError as e: + asserts.assert_equal( + e.status, Status.Success, "Unexpected error returned") + + +if __name__ == "__main__": + default_matter_test_main() diff --git a/src/python_testing/TC_RVCCLEANM_2_2.py b/src/python_testing/TC_RVCCLEANM_2_2.py index 8aaae7ff78738f..e3a92033b3bdf4 100644 --- a/src/python_testing/TC_RVCCLEANM_2_2.py +++ b/src/python_testing/TC_RVCCLEANM_2_2.py @@ -27,13 +27,22 @@ # test-runner-run/run1/script-args: --storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --PICS examples/rvc-app/rvc-common/pics/rvc-app-pics-values --endpoint 1 --trace-to json:${TRACE_TEST_JSON}.json --trace-to perfetto:${TRACE_TEST_PERFETTO}.perfetto # === END CI TEST ARGUMENTS === +import enum from time import sleep import chip.clusters as Clusters -from matter_testing_support import MatterBaseTest, async_test_body, default_matter_test_main +from matter_testing_support import MatterBaseTest, async_test_body, default_matter_test_main, type_matches from mobly import asserts +class RvcStatusEnum(enum.IntEnum): + # TODO remove this class once InvalidInMode response code is implemented in python SDK + Success = 0x0 + UnsupportedMode = 0x1 + GenericFailure = 0x2 + InvalidInMode = 0x3 + + class TC_RVCCLEANM_2_2(MatterBaseTest): def __init__(self, *args): @@ -64,6 +73,11 @@ async def read_clean_supported_modes(self) -> Clusters.Objects.RvcCleanMode.Attr Clusters.RvcCleanMode.Attributes.SupportedModes) return ret + async def read_feature_map_attribute(self): + ret = await self.read_mod_attribute_expect_success(Clusters.RvcCleanMode, + Clusters.RvcCleanMode.Attributes.FeatureMap) + return ret + async def send_clean_change_to_mode_cmd(self, newMode) -> Clusters.Objects.RvcCleanMode.Commands.ChangeToModeResponse: ret = await self.send_single_cmd(cmd=Clusters.Objects.RvcCleanMode.Commands.ChangeToMode(newMode=newMode), endpoint=self.endpoint) return ret @@ -90,6 +104,9 @@ def write_to_app_pipe(self, command): @async_test_body async def test_TC_RVCCLEANM_2_2(self): + # TODO Replace 0x8000 with python object of RVCCLEAN FEATURE bit map when implemented + # 0x8000 corresponds to 16 bit DIRECTMODECH Feature map + self.directmodech_bit_mask = 0x8000 self.endpoint = self.matter_test_config.endpoint self.is_ci = self.check_pics("PICS_SDK_CI_ONLY") if self.is_ci: @@ -157,11 +174,22 @@ async def test_TC_RVCCLEANM_2_2(self): self.new_clean_mode_th = mode break - self.print_step(7, "Send ChangeToMode command") + self.print_step("7a", "Read FeatureMap Attribute") + feature_map = await self.read_feature_map_attribute() + directmode_enabled = feature_map & self.directmodech_bit_mask + + self.print_step("7b", "Send ChangeToMode command") response = await self.send_clean_change_to_mode_cmd(self.new_clean_mode_th) - asserts.assert_equal(response.status, 3, - "The response should contain a ChangeToModeResponse command " - "with the Status set to InvalidInMode(0x03).") + asserts.assert_true(type_matches(response, Clusters.RvcCleanMode.Commands.ChangeToModeResponse), + "The response should ChangeToModeResponse command") + if directmode_enabled: + asserts.assert_equal(response.status, RvcStatusEnum.Success, + "The response should contain a ChangeToModeResponse command " + "with the Status set to Success(0x0).") + else: + asserts.assert_equal(response.status, RvcStatusEnum.InvalidInMode, + "The response should contain a ChangeToModeResponse command " + "with the Status set to InvalidInMode(0x03).") if __name__ == "__main__": diff --git a/src/python_testing/TC_RVCOPSTATE_2_4.py b/src/python_testing/TC_RVCOPSTATE_2_4.py index b680453b06c287..7f03d33b196833 100644 --- a/src/python_testing/TC_RVCOPSTATE_2_4.py +++ b/src/python_testing/TC_RVCOPSTATE_2_4.py @@ -114,7 +114,7 @@ async def test_TC_RVCOPSTATE_2_4(self): asserts.assert_true(self.check_pics("RVCOPSTATE.S.A0004"), "RVCOPSTATE.S.A0004 must be supported") asserts.assert_true(self.check_pics("RVCOPSTATE.S.C04.Tx"), "RVCOPSTATE.S.C04.Tx must be supported") - asserts.assert_true(self.check_pics("RVCOPSTATE.S.C128.Rsp"), "RVCOPSTATE.S.C128.Rsp must be supported") + asserts.assert_true(self.check_pics("RVCOPSTATE.S.C80.Rsp"), "RVCOPSTATE.S.C80.Rsp must be supported") op_states = Clusters.OperationalState.Enums.OperationalStateEnum rvc_op_states = Clusters.RvcOperationalState.Enums.OperationalStateEnum @@ -170,16 +170,16 @@ async def test_TC_RVCOPSTATE_2_4(self): if self.check_pics("PICS_M_ST_SEEKING_CHARGER"): step_name = "Manually put the device in the SEEKING CHARGER operational state" - self.print_step(8, step_name) + self.print_step(11, step_name) if self.is_ci: await self.send_run_change_to_mode_cmd(rvc_app_run_mode_cleaning) await self.send_run_change_to_mode_cmd(rvc_app_run_mode_idle) else: self.wait_for_user_input(prompt_msg=f"{step_name}, and press Enter when ready.") - await self.read_operational_state_with_check(9, rvc_op_states.kSeekingCharger) + await self.read_operational_state_with_check(12, rvc_op_states.kSeekingCharger) - await self.send_go_home_cmd_with_check(10, op_errors.kNoError) + await self.send_go_home_cmd_with_check(13, op_errors.kNoError) if __name__ == "__main__": diff --git a/src/python_testing/TC_RVCRUNM_2_2.py b/src/python_testing/TC_RVCRUNM_2_2.py index dca866adb9f62e..b0d1233010f932 100644 --- a/src/python_testing/TC_RVCRUNM_2_2.py +++ b/src/python_testing/TC_RVCRUNM_2_2.py @@ -27,6 +27,7 @@ # test-runner-run/run1/script-args: --storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --PICS examples/rvc-app/rvc-common/pics/rvc-app-pics-values --endpoint 1 --trace-to json:${TRACE_TEST_JSON}.json --trace-to perfetto:${TRACE_TEST_PERFETTO}.perfetto --int-arg PIXIT.RVCRUNM.MODE_A:1 PIXIT.RVCRUNM.MODE_B:2 # === END CI TEST ARGUMENTS === +import enum from time import sleep import chip.clusters as Clusters @@ -38,17 +39,25 @@ # --int-arg PIXIT.RVCRUNM.MODE_A: PIXIT.RVCRUNM.MODE_B: +class RvcStatusEnum(enum.IntEnum): + # TODO remove this class once InvalidInMode response code is implemented in python SDK + Success = 0x0 + UnsupportedMode = 0x1 + GenericFailure = 0x2 + InvalidInMode = 0x3 + + def error_enum_to_text(error_enum): try: return f'{Clusters.RvcRunMode.Enums.ModeTag(error_enum).name} 0x{error_enum:02x}' except AttributeError: - if error_enum == 0: + if error_enum == RvcStatusEnum.Success: return "Success(0x00)" - elif error_enum == 0x1: + elif error_enum == RvcStatusEnum.UnsupportedMode: return "UnsupportedMode(0x01)" - elif error_enum == 0x2: + elif error_enum == RvcStatusEnum.GenericFailure: return "GenericFailure(0x02)" - elif error_enum == 0x3: + elif error_enum == RvcStatusEnum.InvalidInMode: return "InvalidInMode(0x03)" raise AttributeError("Unknown Enum value") @@ -122,6 +131,9 @@ async def test_TC_RVCRUNM_2_2(self): "PIXIT.RVCRUNM.MODE_A: \n" "PIXIT.RVCRUNM.MODE_B:") + # TODO Replace 0x8000 with python object of RVCRUN FEATURE bit when implemented + # 0x8000 corresponds to 16 bit DIRECTMODECH Feature map + self.directmodech_bit_mask = 0x8000 self.endpoint = self.matter_test_config.endpoint self.is_ci = self.check_pics("PICS_SDK_CI_ONLY") self.mode_a = self.matter_test_config.global_test_params['PIXIT.RVCRUNM.MODE_A'] @@ -193,15 +205,23 @@ async def test_TC_RVCRUNM_2_2(self): asserts.assert_true(idle_tag_present, "The device must be in a mode with the Idle (0x4000) mode tag.") self.print_step(5, "Send ChangeToMode MODE_A command") - await self.send_change_to_mode_with_check(self.mode_a, 0) + await self.send_change_to_mode_with_check(self.mode_a, RvcStatusEnum.Success) # This step is not described in the test plan, but it ought to be await self.read_current_mode_with_check(self.mode_a) - self.print_step(6, "Send ChangeToMode MODE_B command") - await self.send_change_to_mode_with_check(self.mode_b, 3) + self.print_step("6a", "Read Attribute FeatureMap") + feature_map = await self.read_mod_attribute_expect_success(cluster=Clusters.RvcRunMode, + attribute=Clusters.RvcRunMode.Attributes.FeatureMap) + directmode_enabled = feature_map & self.directmodech_bit_mask + + self.print_step('6b', "Send ChangeToMode MODE_B command") + if directmode_enabled: + await self.send_change_to_mode_with_check(self.mode_b, RvcStatusEnum.Success) + else: + await self.send_change_to_mode_with_check(self.mode_b, RvcStatusEnum.InvalidInMode) self.print_step(7, "Send ChangeToMode idle command") - await self.send_change_to_mode_with_check(self.idle_mode_dut, 0) + await self.send_change_to_mode_with_check(self.idle_mode_dut, RvcStatusEnum.Success) # This step is not described in the test plan, but it ought to be await self.read_current_mode_with_check(self.idle_mode_dut) @@ -228,12 +248,12 @@ async def test_TC_RVCRUNM_2_2(self): "Expected RVCOPSTATE's OperationalState attribute to be one of Stopped(0x00), Paused(0x02), Charging(0x41) or Docked(0x42)") self.print_step(11, "Send ChangeToMode MODE_B command") - await self.send_change_to_mode_with_check(self.mode_b, 0) + await self.send_change_to_mode_with_check(self.mode_b, RvcStatusEnum.Success) # This step is not described in the test plan, but it ought to be await self.read_current_mode_with_check(self.mode_b) self.print_step(12, "Send ChangeToMode idle command") - await self.send_change_to_mode_with_check(self.idle_mode_dut, 0) + await self.send_change_to_mode_with_check(self.idle_mode_dut, RvcStatusEnum.Success) # This step is not described in the test plan, but it ought to be await self.read_current_mode_with_check(self.idle_mode_dut) diff --git a/src/python_testing/matter_testing_support.py b/src/python_testing/matter_testing_support.py index eac2d12302640d..b3f0072d83d929 100644 --- a/src/python_testing/matter_testing_support.py +++ b/src/python_testing/matter_testing_support.py @@ -27,6 +27,7 @@ import random import re import sys +import textwrap import time import typing import uuid @@ -1139,12 +1140,60 @@ def on_fail(self, record): self.failed = True if self.runner_hook and not self.is_commissioning: exception = record.termination_signal.exception - step_duration = (datetime.now(timezone.utc) - self.step_start_time) / timedelta(microseconds=1) - test_duration = (datetime.now(timezone.utc) - self.test_start_time) / timedelta(microseconds=1) + + try: + step_duration = (datetime.now(timezone.utc) - self.step_start_time) / timedelta(microseconds=1) + except AttributeError: + # If we failed during setup, these may not be populated + step_duration = 0 + try: + test_duration = (datetime.now(timezone.utc) - self.test_start_time) / timedelta(microseconds=1) + except AttributeError: + test_duration = 0 # TODO: I have no idea what logger, logs, request or received are. Hope None works because I have nothing to give self.runner_hook.step_failure(logger=None, logs=None, duration=step_duration, request=None, received=None) self.runner_hook.test_stop(exception=exception, duration=test_duration) + def extract_error_text() -> tuple[str, str]: + no_stack_trace = ("Stack Trace Unavailable", "") + if not record.termination_signal.stacktrace: + return no_stack_trace + trace = record.termination_signal.stacktrace.splitlines() + if not trace: + return no_stack_trace + + if isinstance(exception, signals.TestError): + # Exception gets raised by the mobly framework, so the proximal error is one line back in the stack trace + assert_candidates = [idx for idx, line in enumerate(trace) if "asserts" in line and "asserts.py" not in line] + if not assert_candidates: + return "Unknown error, please see stack trace above", "" + assert_candidate_idx = assert_candidates[-1] + else: + # Normal assert is on the Last line + assert_candidate_idx = -1 + probable_error = trace[assert_candidate_idx] + + # Find the file marker immediately above the probable error + file_candidates = [idx for idx, line in enumerate(trace[:assert_candidate_idx]) if "File" in line] + if not file_candidates: + return probable_error, "Unknown file" + return probable_error.strip(), trace[file_candidates[-1]].strip() + + probable_error, probable_file = extract_error_text() + logging.error(textwrap.dedent(f""" + + ****************************************************************** + * + * Test {self.current_test_info.name} failed for the following reason: + * {exception} + * + * {probable_file} + * {probable_error} + * + ******************************************************************* + + """)) + def on_pass(self, record): ''' Called by Mobly on test pass