From f345b68d0b6e4f27f27893497f7543b9901cd94f Mon Sep 17 00:00:00 2001 From: Michael Duggan Date: Wed, 27 May 2026 11:08:18 -0400 Subject: [PATCH 01/12] fix old references prior to project upgrades refactor --- .../custom-matter-device.md | 23 ++++++------- sld295-matter-api-reference/attributes.md | 14 ++++---- sld295-matter-api-reference/event.md | 4 ++- sld295-matter-api-reference/index.md | 2 ++ .../images/ClusterLogic6.jpg | Bin 84560 -> 0 bytes .../images/ClusterLogic6.png | Bin 0 -> 18514 bytes .../matter-application-cluster-logic.md | 32 ++++++++---------- .../matter-event-timer-guide.md | 14 ++++---- .../matter-scenes-quick-start-guide.md | 18 ++++------ 9 files changed, 51 insertions(+), 56 deletions(-) delete mode 100644 sld601-matter-application-development/images/ClusterLogic6.jpg create mode 100644 sld601-matter-application-development/images/ClusterLogic6.png diff --git a/sld250-matter-references/custom-matter-device.md b/sld250-matter-references/custom-matter-device.md index 30342b2..5d714f5 100644 --- a/sld250-matter-references/custom-matter-device.md +++ b/sld250-matter-references/custom-matter-device.md @@ -55,11 +55,12 @@ disable the Level Control cluster. ## Receiving Matter Commands All Matter commands reach the application through the intermediate function -`MatterPostAttributeChangeCallback()`. When a request is made by a Matter client, -the information contained in the request is forwarded to a Matter application -through this function. The command can then be dissected using conditional logic -to call the proper application functions based on the most recent command -received. +`MatterPostAttributeChangeCallback()`, which routes through CustomerAppTask +implementation of `DMPostAttributeChangeCallback` so that user overrides are +applied. When a request is made by a Matter client, the information contained +in the request is forwarded to a Matter application through this function. The +command can then be dissected using conditional logic to call the proper +application functions based on the most recent command received. ## Adding a Cluster to a ZAP Configuration @@ -79,12 +80,10 @@ is set to enabled. Set the default value of this attribute as 1. Navigate to the commands tab in zap and enable the MoveToLevel command. Now save the current zap configuration, and run the generate.py script above. -## React to Level Control Cluster Commands in ZclCallbacks +## React to Level Control Cluster Commands -In the MatterPostAttributeCallback function in ZclCallbacks, add the following -line of code or a similar line. This will give the application the ability to react to -MoveToLevel commands. You can define platform-specific behavior for a -MoveToLevel action. +In a new custom implementation of `DMPostAttributeChangeCallbackImpl()` in `src/CustomerAppTask.cpp`, add the following line of code or a similar line. This will +give the application the ability to react to MoveToLevel commands. You can define platform-specific behavior for a MoveToLevel action. ```cpp else if (clusterId == LevelControl::Id) @@ -94,10 +93,8 @@ MoveToLevel action. if (attributeId == LevelControl::Attributes::CurrentLevel::Id) { - action_type = LightingManager::MOVE_TO_LEVEL; + sLightLED.SetLevel(*value); } - - LightMgr().InitiateActionLight(AppEvent::kEventType_Light, action_type, endpoint, *value); } ``` diff --git a/sld295-matter-api-reference/attributes.md b/sld295-matter-api-reference/attributes.md index 4e6654d..5333777 100644 --- a/sld295-matter-api-reference/attributes.md +++ b/sld295-matter-api-reference/attributes.md @@ -4,13 +4,16 @@ Attributes represent the current state of a device. For instance if the device i ## Attribute Changes -When a ZCL attribute is updated in the data model, the framework will call the `postAttributeChangeCallback`. If this callback is implemented by the device it will be informed of the attribute change. The device may react to the attribute change. For example, in `MatterPostAttributeChangeCallback` in `DataModelCallbacks.cpp` in [onoff-plug-app/src](https://github.com/SiliconLabs/matter_extension/tree/main/examples/onoff-plug-app/src), say we want to add some custom handler code to control an RGB LED when on/off attribute in the `On-Off` Cluster changes: +When a ZCL attribute is updated in the data model, the framework invokes the post-attribute-change path. The Silicon Labs Matter stack routes this as follows: `MatterPostAttributeChangeCallback` in `BaseApplication.cpp` → `AppTask::DMPostAttributeChangeCallback` in `autogen/AppTask.cpp` → your optional `DMPostAttributeChangeCallbackImpl()` override in `CustomerAppTask`. + +If this callback is implemented by the device it will be informed of the attribute change. The device may react to the attribute change. For example, in `DMPostAttributeChangeCallback` in `AppTask.cpp` in [onoff-plug-app/src](https://github.com/SiliconLabs/matter_extension/tree/main/examples/onoff-plug-app/src), say we want to add some custom handler code to control an RGB LED when on/off attribute in the `On-Off` Cluster changes, implement the following in +`DMPostAttributeChangeCallbackImpl` in `src/CustomerAppTask.cpp`: ```cpp -void MatterPostAttributeChangeCallback(const chip::app::ConcreteAttributePath & attributePath, - uint8_t type, - uint16_t size, - uint8_t * value) +void DMPostAttributeChangeCallbackImpl(const chip::app::ConcreteAttributePath & attributePath, + uint8_t type, + uint16_t size, + uint8_t * value) { ClusterId clusterId = attributePath.mClusterId; AttributeId attributeId = attributePath.mAttributeId; @@ -18,7 +21,6 @@ void MatterPostAttributeChangeCallback(const chip::app::ConcreteAttributePath & if (clusterId == OnOff::Id && attributeId == OnOff::Attributes::OnOff::Id) { - /* Custom code */ if (*value) { // turn on LED sl_led_turn_on((sl_led_t *)&sl_simple_rgb_pwm_led_rgb_led0); diff --git a/sld295-matter-api-reference/event.md b/sld295-matter-api-reference/event.md index b20191b..1ac4b73 100644 --- a/sld295-matter-api-reference/event.md +++ b/sld295-matter-api-reference/event.md @@ -2,7 +2,9 @@ Events are records of past state transitions such as a light device's on-off attribute changing from on to off. -The autogenerated file [```include/AppEvent.h```](https://github.com/SiliconLabs/matter_extension/blob/main/examples/template/include/AppEvent.h) houses the definition of the event object used by the application. It contains the event types, the structures for each event, and event handler. +The autogenerated file [```include/AppEvent.h```](https://github.com/SiliconLabs/matter_extension/blob/main/third_party/matter_sdk/examples/template/silabs/include/AppEvent.h) houses the definition of the event object used by the application. It contains the event types, the structures for each event, and event handler. + +Custom event posting and handlers belong in `CustomerAppTask` overrides, not in `autogen/AppTask.cpp`. ## Header File diff --git a/sld295-matter-api-reference/index.md b/sld295-matter-api-reference/index.md index b8c604a..85702b4 100644 --- a/sld295-matter-api-reference/index.md +++ b/sld295-matter-api-reference/index.md @@ -20,3 +20,5 @@ CHIP_ERROR AppTask::Init() ``` The ```AppTask.cpp``` file may also contain event handlers and helper code useful to the application. + +If you wish to customize initialization, override `AppInitImpl()` in `src/CustomerAppTask.cpp`. Default initialization logic lives in `autogen/AppTask.cpp`, override the corresponding `*Impl()` hooks in `CustomerAppTask` to customize behavior. diff --git a/sld601-matter-application-development/images/ClusterLogic6.jpg b/sld601-matter-application-development/images/ClusterLogic6.jpg deleted file mode 100644 index cc951aa0b2cf7ce204a88b3625a56003981f23a3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 84560 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 diff --git a/sld601-matter-application-development/images/ClusterLogic6.png b/sld601-matter-application-development/images/ClusterLogic6.png new file mode 100644 index 0000000000000000000000000000000000000000..30132290a75df84c3debb3afb40117a47effd2e2 GIT binary patch literal 18514 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 literal 0 HcmV?d00001 diff --git a/sld601-matter-application-development/matter-application-cluster-logic.md b/sld601-matter-application-development/matter-application-cluster-logic.md index 6f25f04..59da079 100644 --- a/sld601-matter-application-development/matter-application-cluster-logic.md +++ b/sld601-matter-application-development/matter-application-cluster-logic.md @@ -60,7 +60,12 @@ Additionally, a corresponding component is automatically added to your project. ## Step 4: Add Application Logic -Locate your project's `src/AppTask.cpp` file. This file acts as the central hub for application-specific logic, initialization, and event processing in a Matter application on Silicon Labs platforms. Start by adding two helper functions: a one-shot timer to expire in 10 seconds and the `OnOffTmrExpiryHandler` handler function. +Application logic centers on AppTask, but Matter projects split responsibilities: + +- `autogen/AppTask.cpp`: default implementation, regenerated on project upgrade (do not edit for application logic, use as reference only). +- `src/CustomerAppTask.cpp` and `include/CustomerAppTask.h`: your custom logic, add custom code and override `*Impl()` hooks here. + +In `src/CustomerAppTask.cpp`, add two helper functions: a one-shot timer to expire in 10 seconds and the `OnOffTmrExpiryHandler` handler function. ```C++ #include "app-common/zap-generated/attributes/Accessors.h" @@ -87,43 +92,36 @@ void OnOffTmrStart(){ } ``` -Make sure to include `app-common/zap-generated/attributes/Accessors.h` in your `AppTask.cpp` file so you can access cluster attributes. +Make sure to include `app-common/zap-generated/attributes/Accessors.h` in `CustomerAppTask.cpp` so you can access cluster attributes. -Next we will need an AppTask function to initiate the timer. Add the following function to your AppTask.cpp file: +Next we will need an AppTask function to initiate the timer. Declare `OnOffAttributeWriteStartTimer()` in `include/CustomerAppTask.h` and define it in `src/CustomerAppTask.cpp`: ```C++ -void AppTask::OnOffAttributeWriteStartTimer() +void OnOffAttributeWriteStartTimer() { OnOffTmrStart(); } ``` -This function will have to be defined in AppTask.h as well as part of the AppTask class. - -Now, locate the `MatterPostAttributeChangeCallback()` function in the `src/DataModelCallbacks.cpp` file. This function is invoked by the application framework after an attribute value has been changed. Because you are modifying the OnOff attribute in the `OnOffTmrExpiryHandler()` function, use this callback to re-initiate the timer so that the attribute continues to toggle. To achieve this, call `AppTask::OnOffAttributeWriteStartTimer()`, which is part of the AppTask context. - -To implement this functionality, first obtain the AppTask instance using `AppTask::GetAppTask()`. Modify the `MatterPostAttributeChangeCallback()` function as shown below: +Because you modify the OnOff attribute in `OnOffTmrExpiryHandler()`, restart the timer whenever the OnOff attribute changes. Override `DMPostAttributeChangeCallbackImpl()` in `CustomerAppTask` (the SDK routes attribute changes through `MatterPostAttributeChangeCallback` in `BaseApplication.cpp`, then `AppTask::DMPostAttributeChangeCallback` in autogen): ```C++ -void MatterPostAttributeChangeCallback(const chip::app::ConcreteAttributePath & attributePath, uint8_t type, uint16_t size, - uint8_t * value) +void DMPostAttributeChangeCallbackImpl(const chip::app::ConcreteAttributePath & attributePath, uint8_t type, uint16_t size, + uint8_t * value) { ClusterId clusterId = attributePath.mClusterId; AttributeId attributeId = attributePath.mAttributeId; - - // Auto-generated code if (clusterId == OnOff::Id && attributeId == OnOff::Attributes::OnOff::Id){ - AppTask::GetAppTask().OnOffAttributeWriteStartTimer(); + OnOffAttributeWriteStartTimer(); } } ``` -Make sure to #include "AppTask.h" at the top of the `DataModelCallbacks.cpp` file to call the `AppTask::GetAppTask()` function. For more information on the AppTask, refer to AppTask.h. -Finally, add a call to `OnOffTmrStart()` at the end of the `AppTask::AppInit()` function to start the attribute write sequence. The following image illustrates the code flow: +Finally, add a call to `OnOffTmrStart()` at the end of your `AppInitImpl()` override in `CustomerAppTask.cpp` to start the attribute write sequence. The following image illustrates the code flow: -![Code Flow](./images/ClusterLogic6.jpg) +![Code Flow](./images/ClusterLogic6.png) In the flowchart above, `OnOffAttributeWriteStartTimer()` calls `OnOffTmrStart()` to restart the timer. diff --git a/sld601-matter-application-development/matter-event-timer-guide.md b/sld601-matter-application-development/matter-event-timer-guide.md index 7314026..a112649 100644 --- a/sld601-matter-application-development/matter-event-timer-guide.md +++ b/sld601-matter-application-development/matter-event-timer-guide.md @@ -3,7 +3,7 @@ ## Event Handler -The Matter event handler uses the FreeRTOS queue to transport a message from the producer to the consumer area. Events can be used to create an asynchronous message processing or an inter-task message communication. +The Matter event handler uses the FreeRTOS queue to transport a message from the producer to the consumer area. Events can be used to create asynchronous message processing or inter-task communication. Custom event posting and handlers belong in `CustomerAppTask` overrides, not in `autogen/AppTask.cpp`. Steps to make an event work: @@ -53,16 +53,16 @@ struct AppEvent ## Queue Posting -When creating an event and pushing it to the event queue at minimum, **Handler** and **Type** must be defined in order for the event to work. +When creating an event and pushing it to the event queue at minimum, **Handler** and **Type** must be defined in order for the event to work. The example below would live in a `CustomerAppTask` override when customizing behavior. ```C++ -void AppTask::CreateObserverEvent(void) +void CreateObserverEvent(void) { AppEvent active_mode_event = {}; active_mode_event.Type = AppEvent::kEventType_Observer; active_mode_event.Handler = SilabsSensors::SendSensorsValues; - sAppTask.PostEvent(&active_mode_event); + AppInstance().PostEvent(&active_mode_event); } ``` @@ -87,7 +87,7 @@ void AppTask::AppTaskMain(void * pvParameter) AppEvent event; QueueHandle_t sAppEventQueue = *(static_cast(pvParameter)); - CHIP_ERROR err = sAppTask.Init(); + CHIP_ERROR err = AppInstance().Init(); if (err != CHIP_NO_ERROR) { SILABS_LOG("AppTask.Init() failed"); @@ -95,10 +95,10 @@ void AppTask::AppTaskMain(void * pvParameter) } #if !(defined(CHIP_CONFIG_ENABLE_ICD_SERVER) && CHIP_CONFIG_ENABLE_ICD_SERVER) - sAppTask.StartStatusLEDTimer(); + AppInstance().StartStatusLEDTimer(); #endif - sAppTask.RegisterObserver(); + AppInstance().RegisterObserver(); SILABS_LOG("App Task started"); diff --git a/sld601-matter-application-development/matter-scenes-quick-start-guide.md b/sld601-matter-application-development/matter-scenes-quick-start-guide.md index 1637fab..625fc83 100644 --- a/sld601-matter-application-development/matter-scenes-quick-start-guide.md +++ b/sld601-matter-application-development/matter-scenes-quick-start-guide.md @@ -165,9 +165,9 @@ public: ### Step 3 Implement Callbacks -Make the following additions to the src/DataModelCallbacks.cpp file: +Make the following additions to `src/CustomerAppTask.cpp`: -:::collapsed{summary="Click to expand and view the DataModelCallbacks.cpp file"} +:::collapsed{summary="Click to expand and view the CustomerAppTask.cpp additions"} ```c++ // Color Transformer #include "ColorTransformer.h" @@ -192,7 +192,7 @@ bool xyFlag = false; ``` ::: -Then, inside `MatterPostAttributeChangeCallback` in _src/DataModelCallbacks.cpp_, implement the on/off functionality of the LED: +Then, inside `DMPostAttributeChangeCallbackImpl()` in _src/CustomerAppTask.cpp_, implement the on/off functionality of the LED: ```c++ if (clusterId == OnOff::Id && attributeId == OnOff::Attributes::OnOff::Id) @@ -208,9 +208,6 @@ if (clusterId == OnOff::Id && attributeId == OnOff::Attributes::OnOff::Id) #ifdef DIC_ENABLE dic_sendmsg("light/state", (const char *) (value ? (*value ? "on" : "off") : "invalid")); #endif // DIC_ENABLE - LightMgr().InitiateAction(AppEvent::kEventType_Light, *value ? LightingManager::ON_ACTION : LightingManager::OFF_ACTION); - - } ``` @@ -247,7 +244,7 @@ else if (clusterId == ColorControl::Id) } ``` -Lastly, it is necessary to initialize the LED. In src/AppTask.cpp, add the following: +Lastly, it is necessary to initialize the LED. In your `AppInitImpl()` override in `src/CustomerAppTask.cpp`. Add the following: ```c++ #include "sl_simple_rgb_pwm_led.h" @@ -255,15 +252,12 @@ Lastly, it is necessary to initialize the LED. In src/AppTask.cpp, add the follo #include "sl_led.h" ``` -Then, inside the init function `AppTask::Init()` of src/AppTask.cpp, add the following: +Then, inside `AppInitImpl()`: ```c++ -CHIP_ERROR AppTask::Init() +CHIP_ERROR AppInitImpl() { CHIP_ERROR err = CHIP_NO_ERROR; - - sLightLED.Set(LightMgr().IsLightOn()); - /* code to add */ // Initialize LED sl_led_init((sl_led_t *)&sl_simple_rgb_pwm_led_rgb_led0); From 87d56845565ddebc43ee0dde496ece51a705559c Mon Sep 17 00:00:00 2001 From: Michael Duggan Date: Thu, 28 May 2026 12:00:52 -0400 Subject: [PATCH 02/12] updates --- sld295-matter-api-reference/attributes.md | 2 +- sld57-matter-landing-page/index.md | 2 +- .../matter-application-cluster-logic.md | 3 +-- .../matter-event-timer-guide.md | 4 ++-- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/sld295-matter-api-reference/attributes.md b/sld295-matter-api-reference/attributes.md index 5333777..08d0288 100644 --- a/sld295-matter-api-reference/attributes.md +++ b/sld295-matter-api-reference/attributes.md @@ -6,7 +6,7 @@ Attributes represent the current state of a device. For instance if the device i When a ZCL attribute is updated in the data model, the framework invokes the post-attribute-change path. The Silicon Labs Matter stack routes this as follows: `MatterPostAttributeChangeCallback` in `BaseApplication.cpp` → `AppTask::DMPostAttributeChangeCallback` in `autogen/AppTask.cpp` → your optional `DMPostAttributeChangeCallbackImpl()` override in `CustomerAppTask`. -If this callback is implemented by the device it will be informed of the attribute change. The device may react to the attribute change. For example, in `DMPostAttributeChangeCallback` in `AppTask.cpp` in [onoff-plug-app/src](https://github.com/SiliconLabs/matter_extension/tree/main/examples/onoff-plug-app/src), say we want to add some custom handler code to control an RGB LED when on/off attribute in the `On-Off` Cluster changes, implement the following in +If this callback is implemented by the device it will be informed of the attribute change. The device may react to the attribute change. For example, in `DMPostAttributeChangeCallback` in `AppTask.cpp` in [onoff-plug-app/src](https://github.com/SiliconLabsSoftware/matter_sdk/blob/main/examples/onoff-plug-app/silabs/src/AppTask.cpp), say we want to add some custom handler code to control an RGB LED when on/off attribute in the `On-Off` Cluster changes, implement the following in `DMPostAttributeChangeCallbackImpl` in `src/CustomerAppTask.cpp`: ```cpp diff --git a/sld57-matter-landing-page/index.md b/sld57-matter-landing-page/index.md index af928f4..e171fe8 100644 --- a/sld57-matter-landing-page/index.md +++ b/sld57-matter-landing-page/index.md @@ -31,7 +31,7 @@ Want to get a Matter application up and running quickly? Here's a high-level ove 4. **[Optional] Customize Matter App Behavior and Logic** - Use Project Configurator and other Studio tools to customize your app logic: [Developing with Project Configurator](https://docs.silabs.com/ssv6ug/latest/ssv6-configure-project/) - - If necessary, add custom source files for your application logic + - Put application-specific behavior in `src/CustomerAppTask.cpp` by overriding `*Impl()` hooks, defaults live in `autogen/AppTask.cpp` (reference only, regenerated on upgrade). Add other helper classes under `src/` as needed. - Follow documentation to develop a custom matter device with ZAP and corresponding callbacks: [Custom Matter Device Development](/matter/{build-docspace-version}/matter-references/custom-matter-device) 5. **Build and Flash** diff --git a/sld601-matter-application-development/matter-application-cluster-logic.md b/sld601-matter-application-development/matter-application-cluster-logic.md index 59da079..486a131 100644 --- a/sld601-matter-application-development/matter-application-cluster-logic.md +++ b/sld601-matter-application-development/matter-application-cluster-logic.md @@ -53,8 +53,7 @@ Now that the On/Off cluster has been successfully added to the Sample Door Lock - Attributes, commands, and events for the cluster are added to your application’s data model. - Code is generated for attribute storage, command handling, and event notification. -- Callback stubs are generated for you to implement application-specific behavior. -- You interact with the cluster by filling in these stubs and using the generated data structures. +- Implement application-specific behavior in `src/CustomerAppTask.cpp` by overriding `*Impl()` hooks (for example `DMPostAttributeChangeCallbackImpl()`) or by adding custom hooks, not by editing `autogen/AppTask.cpp`. Additionally, a corresponding component is automatically added to your project. This occurs because enabling a cluster in ZAP updates your project configuration to include the necessary software components and libraries required to support that cluster’s functionality. For clusters, this functionality is implemented in the `/third_party/matter_sdk/src/app/clusters` directory. For the On/Off cluster, the server command handlers and related logic can be found in the `/on-off-server/on-off-server.cpp` file. diff --git a/sld601-matter-application-development/matter-event-timer-guide.md b/sld601-matter-application-development/matter-event-timer-guide.md index a112649..de0ab6e 100644 --- a/sld601-matter-application-development/matter-event-timer-guide.md +++ b/sld601-matter-application-development/matter-event-timer-guide.md @@ -130,10 +130,10 @@ chip::DeviceLayer::PlatformMgr().UnlockChipStack(); ### Callback -Timer callback. +Timer callback. Implement in `src/CustomerAppTask.cpp`. ```C++ -void AppTask::TestCallback(System::Layer * layer, void * aAppState) +void TestCallback(System::Layer * layer, void * aAppState) { // Do something } From 0670b2a2d66e5518c63ebd663e7cbdd0afe01621 Mon Sep 17 00:00:00 2001 From: Michael Duggan Date: Thu, 28 May 2026 12:05:11 -0400 Subject: [PATCH 03/12] fix app instance --- .../matter-event-timer-guide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sld601-matter-application-development/matter-event-timer-guide.md b/sld601-matter-application-development/matter-event-timer-guide.md index de0ab6e..63402b3 100644 --- a/sld601-matter-application-development/matter-event-timer-guide.md +++ b/sld601-matter-application-development/matter-event-timer-guide.md @@ -107,7 +107,7 @@ void AppTask::AppTaskMain(void * pvParameter) BaseType_t eventReceived = xQueueReceive(sAppEventQueue, &event, portMAX_DELAY); while (eventReceived == pdTRUE) { - sAppTask.DispatchEvent(&event); + AppInstance().DispatchEvent(&event); eventReceived = xQueueReceive(sAppEventQueue, &event, 0); } } From cb905308070f83cfe73336a067ed3c17c9d59929 Mon Sep 17 00:00:00 2001 From: Michael Duggan Date: Thu, 28 May 2026 14:04:10 -0400 Subject: [PATCH 04/12] support both app states --- .../custom-matter-device.md | 36 ++++++-- sld295-matter-api-reference/attributes.md | 34 ++++++++ sld295-matter-api-reference/event.md | 2 +- sld295-matter-api-reference/index.md | 35 +++++++- sld57-matter-landing-page/index.md | 2 +- .../matter-application-cluster-logic.md | 42 +++++++++- .../matter-event-timer-guide.md | 75 ++++++++++++++++- .../matter-scenes-quick-start-guide.md | 83 +++++++++++++++++++ 8 files changed, 292 insertions(+), 17 deletions(-) diff --git a/sld250-matter-references/custom-matter-device.md b/sld250-matter-references/custom-matter-device.md index 5d714f5..892e107 100644 --- a/sld250-matter-references/custom-matter-device.md +++ b/sld250-matter-references/custom-matter-device.md @@ -55,12 +55,13 @@ disable the Level Control cluster. ## Receiving Matter Commands All Matter commands reach the application through the intermediate function -`MatterPostAttributeChangeCallback()`, which routes through CustomerAppTask -implementation of `DMPostAttributeChangeCallback` so that user overrides are -applied. When a request is made by a Matter client, the information contained -in the request is forwarded to a Matter application through this function. The -command can then be dissected using conditional logic to call the proper -application functions based on the most recent command received. +`MatterPostAttributeChangeCallback()`. When a request is made by a Matter client, +the information contained in the request is forwarded to a Matter application +through this function. The command can then be dissected using conditional logic +to call the proper application functions based on the most recent command +received. + +Which file you edit depends on your sample app — see [Application customization models](/matter/{build-docspace-version}/matter-api-reference/#application-customization-models). New architecture apps route attribute changes through `CustomerAppTask` and `DMPostAttributeChangeCallbackImpl()`. Legacy architecture apps implement `MatterPostAttributeChangeCallback()` directly in `src/DataModelCallbacks.cpp`. ## Adding a Cluster to a ZAP Configuration @@ -82,7 +83,9 @@ the current zap configuration, and run the generate.py script above. ## React to Level Control Cluster Commands -In a new custom implementation of `DMPostAttributeChangeCallbackImpl()` in `src/CustomerAppTask.cpp`, add the following line of code or a similar line. This will +### New architecture + +In a custom implementation of `DMPostAttributeChangeCallbackImpl()` in `src/CustomerAppTask.cpp`, add the following line of code or a similar line. This will give the application the ability to react to MoveToLevel commands. You can define platform-specific behavior for a MoveToLevel action. ```cpp @@ -98,6 +101,25 @@ give the application the ability to react to MoveToLevel commands. You can defin } ``` +### Legacy architecture + +In `MatterPostAttributeChangeCallback()` in `src/DataModelCallbacks.cpp`, add the following line of code or a similar line: + + ```cpp + else if (clusterId == LevelControl::Id) + { + ChipLogProgress(Zcl, "Level Control attribute ID: " ChipLogFormatMEI " Type: %u Value: %u, length %u", + ChipLogValueMEI(attributeId), type, *value, size); + + if (attributeId == LevelControl::Attributes::CurrentLevel::Id) + { + action_type = LightingManager::MOVE_TO_LEVEL; + } + + LightMgr().InitiateActionLight(AppEvent::kEventType_Light, action_type, endpoint, *value); + } + ``` + ## Send a MoveToLevel Command and Read the CurrentLevel Attribute Rebuild the application and load the new executable on your EFR32 device. Send diff --git a/sld295-matter-api-reference/attributes.md b/sld295-matter-api-reference/attributes.md index 08d0288..04ba0bb 100644 --- a/sld295-matter-api-reference/attributes.md +++ b/sld295-matter-api-reference/attributes.md @@ -4,6 +4,10 @@ Attributes represent the current state of a device. For instance if the device i ## Attribute Changes +Which instructions apply depends on your sample app — see [Application customization models](./index.md#application-customization-models). + +### New architecture + When a ZCL attribute is updated in the data model, the framework invokes the post-attribute-change path. The Silicon Labs Matter stack routes this as follows: `MatterPostAttributeChangeCallback` in `BaseApplication.cpp` → `AppTask::DMPostAttributeChangeCallback` in `autogen/AppTask.cpp` → your optional `DMPostAttributeChangeCallbackImpl()` override in `CustomerAppTask`. If this callback is implemented by the device it will be informed of the attribute change. The device may react to the attribute change. For example, in `DMPostAttributeChangeCallback` in `AppTask.cpp` in [onoff-plug-app/src](https://github.com/SiliconLabsSoftware/matter_sdk/blob/main/examples/onoff-plug-app/silabs/src/AppTask.cpp), say we want to add some custom handler code to control an RGB LED when on/off attribute in the `On-Off` Cluster changes, implement the following in @@ -36,6 +40,36 @@ void DMPostAttributeChangeCallbackImpl(const chip::app::ConcreteAttributePath & } ``` +### Legacy architecture + +When a ZCL attribute is updated in the data model, the framework calls `MatterPostAttributeChangeCallback()` in `src/DataModelCallbacks.cpp`. If this callback is implemented by the device it will be informed of the attribute change. For example, to control an RGB LED when the On/Off attribute changes: + +```cpp +void MatterPostAttributeChangeCallback(const chip::app::ConcreteAttributePath & attributePath, + uint8_t type, + uint16_t size, + uint8_t * value) +{ + ClusterId clusterId = attributePath.mClusterId; + AttributeId attributeId = attributePath.mAttributeId; + ChipLogProgress(Zcl, "Cluster callback: " ChipLogFormatMEI, ChipLogValueMEI(clusterId)); + + if (clusterId == OnOff::Id && attributeId == OnOff::Attributes::OnOff::Id) + { + if (*value) + { // turn on LED + sl_led_turn_on((sl_led_t *)&sl_simple_rgb_pwm_led_rgb_led0); + } + else + {// turn off LED + sl_led_turn_off((sl_led_t *)&sl_simple_rgb_pwm_led_rgb_led0); + } + } + + //... +} +``` + ## Header File This file contains the high level namespaces and constant definitions for Attributes. In Simplicity Studio, this will be generated in the autogen/zap-generated/ folder of the matter project. diff --git a/sld295-matter-api-reference/event.md b/sld295-matter-api-reference/event.md index 1ac4b73..22f766c 100644 --- a/sld295-matter-api-reference/event.md +++ b/sld295-matter-api-reference/event.md @@ -4,7 +4,7 @@ Events are records of past state transitions such as a light device's on-off att The autogenerated file [```include/AppEvent.h```](https://github.com/SiliconLabs/matter_extension/blob/main/third_party/matter_sdk/examples/template/silabs/include/AppEvent.h) houses the definition of the event object used by the application. It contains the event types, the structures for each event, and event handler. -Custom event posting and handlers belong in `CustomerAppTask` overrides, not in `autogen/AppTask.cpp`. +**New architecture:** Custom event posting and handlers belong in `CustomerAppTask` overrides, not in `autogen/AppTask.cpp`. ## Header File diff --git a/sld295-matter-api-reference/index.md b/sld295-matter-api-reference/index.md index 85702b4..38e9e5e 100644 --- a/sld295-matter-api-reference/index.md +++ b/sld295-matter-api-reference/index.md @@ -11,14 +11,41 @@ This section covers the various Application Programming Interfaces (APIs) that a ## Application APIs +### Application customization models + +Matter Extension 2.9.0 migrates a subset of sample apps to CRTP based architecture, which removes app manager and DataModelCallbacks files. All other sample apps keep the previous architecture until the patch release. + +Check your project in Project Explorer: + +| If you see… | Architecture | Where to add custom logic | +|---|---|---| +| `src/CustomerAppTask.cpp` and `autogen/AppTask.cpp` | **New** | Override `*Impl()` hooks in `CustomerAppTask`, do not edit `autogen/AppTask.cpp` | +| `src/DataModelCallbacks.cpp` and editable `src/AppTask.cpp` | **Legacy** | Callbacks in `DataModelCallbacks.cpp`, init and app logic in `src/AppTask.cpp` | + +**Sample apps on the new architecture in 2.9.0:** + +| Sample app | Notes | +|---|---| +| Lighting (`lighting-app`) | | +| Zigbee Matter Light (`zigbee-matter-light`) | | +| On/Off Plug (`onoff-plug-app`) | | +| Thermostat | | +| Lock (`lock-app`) | | +| Light Switch (`light-switch-app`) | | +| Rangehood (`rangehood-app`) | | +| Platform Template (`platform-app`) | | +| Air Quality Sensor (`air-quality-sensor-app`) | | + +All other Silicon Labs Matter sample apps in this release use the legacy model. Pages below label steps as **New architecture** or **Legacy architecture** where they differ. + ### Initialization -The application 'Init' sequence lives in the ```AppTask.cpp``` file, and is called at the beginning of the application to ensure that all components are properly initialized and ready to operate. It sets up necessary callbacks, initializes hardware components, and handles any errors that may occur during the process. This function is crucial for the stable operation of the application. +**New architecture:** Default initialization lives in `autogen/AppTask.cpp`. Override `AppInitImpl()` and other `*Impl()` hooks in `src/CustomerAppTask.cpp` to customize behavior. + +**Legacy architecture:** The application Init sequence lives in `src/AppTask.cpp` and is called at the beginning of the application to ensure that all components are properly initialized and ready to operate. It sets up necessary callbacks, initializes hardware components, and handles any errors that may occur during the process. ```cpp CHIP_ERROR AppTask::Init() ``` -The ```AppTask.cpp``` file may also contain event handlers and helper code useful to the application. - -If you wish to customize initialization, override `AppInitImpl()` in `src/CustomerAppTask.cpp`. Default initialization logic lives in `autogen/AppTask.cpp`, override the corresponding `*Impl()` hooks in `CustomerAppTask` to customize behavior. +The `AppTask.cpp` file may also contain event handlers and helper code useful to the application. diff --git a/sld57-matter-landing-page/index.md b/sld57-matter-landing-page/index.md index e171fe8..5fd1326 100644 --- a/sld57-matter-landing-page/index.md +++ b/sld57-matter-landing-page/index.md @@ -31,7 +31,7 @@ Want to get a Matter application up and running quickly? Here's a high-level ove 4. **[Optional] Customize Matter App Behavior and Logic** - Use Project Configurator and other Studio tools to customize your app logic: [Developing with Project Configurator](https://docs.silabs.com/ssv6ug/latest/ssv6-configure-project/) - - Put application-specific behavior in `src/CustomerAppTask.cpp` by overriding `*Impl()` hooks, defaults live in `autogen/AppTask.cpp` (reference only, regenerated on upgrade). Add other helper classes under `src/` as needed. + - Customize app behavior using the model your sample app provides — see [Application customization models](/matter/{build-docspace-version}/matter-api-reference/#application-customization-models). Refactored apps use `CustomerAppTask` and `autogen/AppTask.cpp`, all other apps use `DataModelCallbacks.cpp` and `src/AppTask.cpp`. - Follow documentation to develop a custom matter device with ZAP and corresponding callbacks: [Custom Matter Device Development](/matter/{build-docspace-version}/matter-references/custom-matter-device) 5. **Build and Flash** diff --git a/sld601-matter-application-development/matter-application-cluster-logic.md b/sld601-matter-application-development/matter-application-cluster-logic.md index 486a131..df466e4 100644 --- a/sld601-matter-application-development/matter-application-cluster-logic.md +++ b/sld601-matter-application-development/matter-application-cluster-logic.md @@ -53,13 +53,18 @@ Now that the On/Off cluster has been successfully added to the Sample Door Lock - Attributes, commands, and events for the cluster are added to your application’s data model. - Code is generated for attribute storage, command handling, and event notification. -- Implement application-specific behavior in `src/CustomerAppTask.cpp` by overriding `*Impl()` hooks (for example `DMPostAttributeChangeCallbackImpl()`) or by adding custom hooks, not by editing `autogen/AppTask.cpp`. +- **New architecture**: implement application-specific behavior in `src/CustomerAppTask.cpp` by overriding `*Impl()` hooks (for example `DMPostAttributeChangeCallbackImpl()`), not by editing `autogen/AppTask.cpp`. +- **Legacy architecture**: callback stubs are generated for you to implement in `src/DataModelCallbacks.cpp`, interact with the cluster by filling in these stubs and using the generated data structures. Additionally, a corresponding component is automatically added to your project. This occurs because enabling a cluster in ZAP updates your project configuration to include the necessary software components and libraries required to support that cluster’s functionality. For clusters, this functionality is implemented in the `/third_party/matter_sdk/src/app/clusters` directory. For the On/Off cluster, the server command handlers and related logic can be found in the `/on-off-server/on-off-server.cpp` file. ## Step 4: Add Application Logic -Application logic centers on AppTask, but Matter projects split responsibilities: +This guide uses the Lock sample app, which is on the **new architecture** in 2.9.0. See [Application customization models](/matter/{build-docspace-version}/matter-api-reference/#application-customization-models) to confirm which model your project uses. + +### New architecture + +Application logic centers on AppTask, but refactored Matter projects split responsibilities: - `autogen/AppTask.cpp`: default implementation, regenerated on project upgrade (do not edit for application logic, use as reference only). - `src/CustomerAppTask.cpp` and `include/CustomerAppTask.h`: your custom logic, add custom code and override `*Impl()` hooks here. @@ -124,6 +129,39 @@ Finally, add a call to `OnOffTmrStart()` at the end of your `AppInitImpl()` over In the flowchart above, `OnOffAttributeWriteStartTimer()` calls `OnOffTmrStart()` to restart the timer. +### Legacy architecture + +Locate your project's `src/AppTask.cpp` file. Start by adding the same timer helper functions as above in `AppTask.cpp`. + +Make sure to include `app-common/zap-generated/attributes/Accessors.h` in your `AppTask.cpp` file so you can access cluster attributes. + +Add the timer start function to `AppTask.cpp` and declare it in `AppTask.h`: + +```C++ +void AppTask::OnOffAttributeWriteStartTimer() +{ + OnOffTmrStart(); +} +``` + +Locate `MatterPostAttributeChangeCallback()` in `src/DataModelCallbacks.cpp`. Because you modify the OnOff attribute in `OnOffTmrExpiryHandler()`, use this callback to re-initiate the timer: + +```C++ +void MatterPostAttributeChangeCallback(const chip::app::ConcreteAttributePath & attributePath, uint8_t type, uint16_t size, + uint8_t * value) +{ + ClusterId clusterId = attributePath.mClusterId; + AttributeId attributeId = attributePath.mAttributeId; + + if (clusterId == OnOff::Id && attributeId == OnOff::Attributes::OnOff::Id){ + AppTask::GetAppTask().OnOffAttributeWriteStartTimer(); + } + +} +``` + +Include `AppTask.h` at the top of `DataModelCallbacks.cpp`. Finally, add a call to `OnOffTmrStart()` at the end of `AppTask::Init()` in `src/AppTask.cpp`. + ## Step 5: Interact with the On/Off Cluster After building your project, flash the compiled firmware onto your target board. Once the device is running, you should observe log messages approximately every 10 seconds indicating that the OnOff cluster's OnOff attribute is being written to. This confirms that the cluster is active and functioning as expected. diff --git a/sld601-matter-application-development/matter-event-timer-guide.md b/sld601-matter-application-development/matter-event-timer-guide.md index 63402b3..35a27c1 100644 --- a/sld601-matter-application-development/matter-event-timer-guide.md +++ b/sld601-matter-application-development/matter-event-timer-guide.md @@ -3,7 +3,9 @@ ## Event Handler -The Matter event handler uses the FreeRTOS queue to transport a message from the producer to the consumer area. Events can be used to create asynchronous message processing or inter-task communication. Custom event posting and handlers belong in `CustomerAppTask` overrides, not in `autogen/AppTask.cpp`. +The Matter event handler uses the FreeRTOS queue to transport a message from the producer to the consumer area. Events can be used to create asynchronous message processing or inter-task communication. + +Which instructions apply depends on your sample app — see [Application customization models](/matter/{build-docspace-version}/matter-api-reference/#application-customization-models). Steps to make an event work: @@ -53,7 +55,11 @@ struct AppEvent ## Queue Posting -When creating an event and pushing it to the event queue at minimum, **Handler** and **Type** must be defined in order for the event to work. The example below would live in a `CustomerAppTask` override when customizing behavior. +When creating an event and pushing it to the event queue at minimum, **Handler** and **Type** must be defined in order for the event to work. + +### New architecture + +Custom event posting and handlers belong in `CustomerAppTask` overrides, not in `autogen/AppTask.cpp`. ```C++ void CreateObserverEvent(void) @@ -66,6 +72,21 @@ void CreateObserverEvent(void) } ``` +### Legacy architecture + +Post events from `src/AppTask.cpp`: + +```C++ +void AppTask::CreateObserverEvent(void) +{ + AppEvent active_mode_event = {}; + active_mode_event.Type = AppEvent::kEventType_Observer; + active_mode_event.Handler = SilabsSensors::SendSensorsValues; + + sAppTask.PostEvent(&active_mode_event); +} +``` + ## Callback Observer event callback @@ -81,6 +102,8 @@ void SilabsSensors::SendSensorsValues(AppEvent * aEvent) **AppTaskMain** is dispatching all the events from the event list. +### New architecture + ```C++ void AppTask::AppTaskMain(void * pvParameter) { @@ -114,6 +137,41 @@ void AppTask::AppTaskMain(void * pvParameter) } ``` +### Legacy architecture + +```C++ +void AppTask::AppTaskMain(void * pvParameter) +{ + AppEvent event; + QueueHandle_t sAppEventQueue = *(static_cast(pvParameter)); + + CHIP_ERROR err = sAppTask.Init(); + if (err != CHIP_NO_ERROR) + { + SILABS_LOG("AppTask.Init() failed"); + appError(err); + } + +#if !(defined(CHIP_CONFIG_ENABLE_ICD_SERVER) && CHIP_CONFIG_ENABLE_ICD_SERVER) + sAppTask.StartStatusLEDTimer(); +#endif + + sAppTask.RegisterObserver(); + + SILABS_LOG("App Task started"); + + while (true) + { + BaseType_t eventReceived = xQueueReceive(sAppEventQueue, &event, portMAX_DELAY); + while (eventReceived == pdTRUE) + { + sAppTask.DispatchEvent(&event); + eventReceived = xQueueReceive(sAppEventQueue, &event, 0); + } + } +} +``` + ## Matter Timer ### Start @@ -130,6 +188,8 @@ chip::DeviceLayer::PlatformMgr().UnlockChipStack(); ### Callback +### New architecture + Timer callback. Implement in `src/CustomerAppTask.cpp`. ```C++ @@ -139,4 +199,15 @@ void TestCallback(System::Layer * layer, void * aAppState) } ``` +### Legacy architecture + +Timer callback. Implement in `src/AppTask.cpp`. + +```C++ +void AppTask::TestCallback(System::Layer * layer, void * aAppState) +{ + // Do something +} +``` + If you need a periodic timer, you can recall `StartTimer()` in the callback. diff --git a/sld601-matter-application-development/matter-scenes-quick-start-guide.md b/sld601-matter-application-development/matter-scenes-quick-start-guide.md index 625fc83..d7ea4c0 100644 --- a/sld601-matter-application-development/matter-scenes-quick-start-guide.md +++ b/sld601-matter-application-development/matter-scenes-quick-start-guide.md @@ -165,6 +165,10 @@ public: ### Step 3 Implement Callbacks +This guide uses the Lighting sample app, which is on the **new architecture** in 2.9.0. See [Application customization models](/matter/{build-docspace-version}/matter-api-reference/#application-customization-models) to confirm which model your project uses. + +#### New architecture + Make the following additions to `src/CustomerAppTask.cpp`: :::collapsed{summary="Click to expand and view the CustomerAppTask.cpp additions"} @@ -277,6 +281,85 @@ CHIP_ERROR AppInitImpl() This initializes the LED to be white. +#### Legacy architecture + +Make the following additions to `src/DataModelCallbacks.cpp`: + +:::collapsed{summary="Click to expand and view the DataModelCallbacks.cpp file"} +```c++ +// Color Transformer +#include "ColorTransformer.h" + +// Customer Application +#include "sl_simple_rgb_pwm_led.h" +#include "sl_simple_rgb_pwm_led_instances.h" +#include "sl_led.h" +. +. +// Initialize color mode x-y +uint16_t cx = 0xFFFF; +uint16_t cy = 0xFFFF; + +// Initialize RGB +uint16_t r = 0xFFFF; +uint16_t g = 0xFFFF; +uint16_t b = 0xFFFF; + +// Initialize xy color mode flag +bool xyFlag = false; +``` +::: + +Then, inside `MatterPostAttributeChangeCallback` in _src/DataModelCallbacks.cpp_, implement the on/off functionality of the LED: + +```c++ +if (clusterId == OnOff::Id && attributeId == OnOff::Attributes::OnOff::Id) + { +/* code to add */ + if (*value) { // turn on LED + sl_led_turn_on((sl_led_t *)&sl_simple_rgb_pwm_led_rgb_led0); + } else {// turn off LED + sl_led_turn_off((sl_led_t *)&sl_simple_rgb_pwm_led_rgb_led0); + } +/* ----------- */ + +#ifdef DIC_ENABLE + dic_sendmsg("light/state", (const char *) (value ? (*value ? "on" : "off") : "invalid")); +#endif // DIC_ENABLE + LightMgr().InitiateAction(AppEvent::kEventType_Light, *value ? LightingManager::ON_ACTION : LightingManager::OFF_ACTION); + + + } +``` + +Use the same Color Control cluster handling as in the **New architecture** section above. + +Lastly, initialize the LED in `src/AppTask.cpp`. Add the same includes, then inside `AppTask::Init()`: + +```c++ +CHIP_ERROR AppTask::Init() +{ + CHIP_ERROR err = CHIP_NO_ERROR; + + sLightLED.Set(LightMgr().IsLightOn()); + +/* code to add */ + // Initialize LED + sl_led_init((sl_led_t *)&sl_simple_rgb_pwm_led_rgb_led0); + + // Set initial color to white and turn off + uint16_t red = 255; // max red + uint16_t green = 255; // no green + uint16_t blue = 255; // max blue + sl_led_set_rgb_color(&sl_simple_rgb_pwm_led_rgb_led0, red, green, blue); + sl_led_turn_off((sl_led_t *)&sl_simple_rgb_pwm_led_rgb_led0); +/* ----------- */ + +// Update the LCD with the Stored value. Show QR Code if not provisioned + return err; +} +``` + ### Step 4: Build and Flash Build the project and flash the binary to as many Matter devices as you wish to have in your scene. This demo includes two lighting devices. Ensure that the devices have been flashed with a bootloader prior to flashing the application for the first time. From fff1772825b7063d375856e3cdea8cfa93d89c69 Mon Sep 17 00:00:00 2001 From: Michael Duggan Date: Thu, 28 May 2026 14:18:45 -0400 Subject: [PATCH 05/12] some cleanup --- sld250-matter-references/custom-matter-device.md | 6 ++++-- .../matter-application-cluster-logic.md | 10 ++++++---- .../matter-scenes-quick-start-guide.md | 2 ++ 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/sld250-matter-references/custom-matter-device.md b/sld250-matter-references/custom-matter-device.md index 892e107..163ba77 100644 --- a/sld250-matter-references/custom-matter-device.md +++ b/sld250-matter-references/custom-matter-device.md @@ -103,8 +103,10 @@ give the application the ability to react to MoveToLevel commands. You can defin ### Legacy architecture -In `MatterPostAttributeChangeCallback()` in `src/DataModelCallbacks.cpp`, add the following line of code or a similar line: - +In the MatterPostAttributeCallback function in ZclCallbacks, add the following +line of code or a similar line. This will give the application the ability to react to +MoveToLevel commands. You can define platform-specific behavior for a +MoveToLevel action. ```cpp else if (clusterId == LevelControl::Id) { diff --git a/sld601-matter-application-development/matter-application-cluster-logic.md b/sld601-matter-application-development/matter-application-cluster-logic.md index df466e4..eb01d59 100644 --- a/sld601-matter-application-development/matter-application-cluster-logic.md +++ b/sld601-matter-application-development/matter-application-cluster-logic.md @@ -54,7 +54,7 @@ Now that the On/Off cluster has been successfully added to the Sample Door Lock - Attributes, commands, and events for the cluster are added to your application’s data model. - Code is generated for attribute storage, command handling, and event notification. - **New architecture**: implement application-specific behavior in `src/CustomerAppTask.cpp` by overriding `*Impl()` hooks (for example `DMPostAttributeChangeCallbackImpl()`), not by editing `autogen/AppTask.cpp`. -- **Legacy architecture**: callback stubs are generated for you to implement in `src/DataModelCallbacks.cpp`, interact with the cluster by filling in these stubs and using the generated data structures. +- **Legacy architecture**: Callback stubs are generated for you to implement application-specific behavior. You interact with the cluster by filling in these stubs and using the generated data structures. Additionally, a corresponding component is automatically added to your project. This occurs because enabling a cluster in ZAP updates your project configuration to include the necessary software components and libraries required to support that cluster’s functionality. For clusters, this functionality is implemented in the `/third_party/matter_sdk/src/app/clusters` directory. For the On/Off cluster, the server command handlers and related logic can be found in the `/on-off-server/on-off-server.cpp` file. @@ -131,7 +131,7 @@ In the flowchart above, `OnOffAttributeWriteStartTimer()` calls `OnOffTmrStart() ### Legacy architecture -Locate your project's `src/AppTask.cpp` file. Start by adding the same timer helper functions as above in `AppTask.cpp`. +Locate your project's src/AppTask.cpp file. This file acts as the central hub for application-specific logic, initialization, and event processing in a Matter application on Silicon Labs platforms. Start by adding two helper functions: a one-shot timer to expire in 10 seconds and the OnOffTmrExpiryHandler handler function. Make sure to include `app-common/zap-generated/attributes/Accessors.h` in your `AppTask.cpp` file so you can access cluster attributes. @@ -144,7 +144,7 @@ void AppTask::OnOffAttributeWriteStartTimer() } ``` -Locate `MatterPostAttributeChangeCallback()` in `src/DataModelCallbacks.cpp`. Because you modify the OnOff attribute in `OnOffTmrExpiryHandler()`, use this callback to re-initiate the timer: +Now, locate the MatterPostAttributeChangeCallback() function in the src/DataModelCallbacks.cpp file. This function is invoked by the application framework after an attribute value has been changed. Because you are modifying the OnOff attribute in the OnOffTmrExpiryHandler() function, use this callback to re-initiate the timer so that the attribute continues to toggle. To achieve this, call AppTask::OnOffAttributeWriteStartTimer(), which is part of the AppTask context. ```C++ void MatterPostAttributeChangeCallback(const chip::app::ConcreteAttributePath & attributePath, uint8_t type, uint16_t size, @@ -160,7 +160,9 @@ void MatterPostAttributeChangeCallback(const chip::app::ConcreteAttributePath & } ``` -Include `AppTask.h` at the top of `DataModelCallbacks.cpp`. Finally, add a call to `OnOffTmrStart()` at the end of `AppTask::Init()` in `src/AppTask.cpp`. +Make sure to #include "AppTask.h" at the top of the DataModelCallbacks.cpp file to call the AppTask::GetAppTask() function. For more information on the AppTask, refer to AppTask.h. + +Finally, add a call to OnOffTmrStart() at the end of the AppTask::AppInit() function to start the attribute write sequence. ## Step 5: Interact with the On/Off Cluster diff --git a/sld601-matter-application-development/matter-scenes-quick-start-guide.md b/sld601-matter-application-development/matter-scenes-quick-start-guide.md index d7ea4c0..13f3cae 100644 --- a/sld601-matter-application-development/matter-scenes-quick-start-guide.md +++ b/sld601-matter-application-development/matter-scenes-quick-start-guide.md @@ -360,6 +360,8 @@ CHIP_ERROR AppTask::Init() } ``` +This initializes the LED to be white. + ### Step 4: Build and Flash Build the project and flash the binary to as many Matter devices as you wish to have in your scene. This demo includes two lighting devices. Ensure that the devices have been flashed with a bootloader prior to flashing the application for the first time. From 6067e9c7bb2d130344395785fdeb36105e1664a9 Mon Sep 17 00:00:00 2001 From: Michael Duggan Date: Thu, 28 May 2026 15:40:13 -0400 Subject: [PATCH 06/12] make a bulleted list of apps --- sld295-matter-api-reference/index.md | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/sld295-matter-api-reference/index.md b/sld295-matter-api-reference/index.md index 38e9e5e..414a53c 100644 --- a/sld295-matter-api-reference/index.md +++ b/sld295-matter-api-reference/index.md @@ -24,17 +24,15 @@ Check your project in Project Explorer: **Sample apps on the new architecture in 2.9.0:** -| Sample app | Notes | -|---|---| -| Lighting (`lighting-app`) | | -| Zigbee Matter Light (`zigbee-matter-light`) | | -| On/Off Plug (`onoff-plug-app`) | | -| Thermostat | | -| Lock (`lock-app`) | | -| Light Switch (`light-switch-app`) | | -| Rangehood (`rangehood-app`) | | -| Platform Template (`platform-app`) | | -| Air Quality Sensor (`air-quality-sensor-app`) | | +- Lighting (`lighting-app`) +- Zigbee Matter Light (`zigbee-matter-light`) +- On/Off Plug (`onoff-plug-app`) +- Thermostat +- Lock (`lock-app`) +- Light Switch (`light-switch-app`) +- Rangehood (`rangehood-app`) +- Platform Template (`platform-app`) +- Air Quality Sensor (`air-quality-sensor-app`) All other Silicon Labs Matter sample apps in this release use the legacy model. Pages below label steps as **New architecture** or **Legacy architecture** where they differ. From dc77d9d1465a27b927457a045e059ce7b748d436 Mon Sep 17 00:00:00 2001 From: Michael Duggan Date: Thu, 28 May 2026 15:41:31 -0400 Subject: [PATCH 07/12] rm outdated app name --- sld295-matter-api-reference/index.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/sld295-matter-api-reference/index.md b/sld295-matter-api-reference/index.md index 414a53c..fe59742 100644 --- a/sld295-matter-api-reference/index.md +++ b/sld295-matter-api-reference/index.md @@ -24,15 +24,15 @@ Check your project in Project Explorer: **Sample apps on the new architecture in 2.9.0:** -- Lighting (`lighting-app`) -- Zigbee Matter Light (`zigbee-matter-light`) -- On/Off Plug (`onoff-plug-app`) +- Lighting +- Zigbee Matter Light +- On/Off Plug - Thermostat -- Lock (`lock-app`) -- Light Switch (`light-switch-app`) -- Rangehood (`rangehood-app`) -- Platform Template (`platform-app`) -- Air Quality Sensor (`air-quality-sensor-app`) +- Lock +- Light Switch +- Rangehood +- Platform Template +- Air Quality Sensor All other Silicon Labs Matter sample apps in this release use the legacy model. Pages below label steps as **New architecture** or **Legacy architecture** where they differ. From 3739436305ff81e41c7644807c3943d914cd5df2 Mon Sep 17 00:00:00 2001 From: Michael Duggan Date: Fri, 29 May 2026 09:02:03 -0400 Subject: [PATCH 08/12] expand CRTP --- sld295-matter-api-reference/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sld295-matter-api-reference/index.md b/sld295-matter-api-reference/index.md index fe59742..72d5958 100644 --- a/sld295-matter-api-reference/index.md +++ b/sld295-matter-api-reference/index.md @@ -13,7 +13,7 @@ This section covers the various Application Programming Interfaces (APIs) that a ### Application customization models -Matter Extension 2.9.0 migrates a subset of sample apps to CRTP based architecture, which removes app manager and DataModelCallbacks files. All other sample apps keep the previous architecture until the patch release. +Matter Extension 2.9.0 migrates a subset of sample apps to the Curiously Recurring Template Pattern (CRTP) based architecture, which removes app manager and DataModelCallbacks files. All other sample apps keep the previous architecture until the patch release. Check your project in Project Explorer: From ca3b308ea026ded20275125f316dcec84f381d6d Mon Sep 17 00:00:00 2001 From: Michael Duggan Date: Mon, 8 Jun 2026 08:27:32 -0400 Subject: [PATCH 09/12] address review comments --- sld250-matter-references/custom-matter-device.md | 4 ++-- sld295-matter-api-reference/attributes.md | 4 ++-- sld295-matter-api-reference/event.md | 2 +- sld295-matter-api-reference/index.md | 2 +- sld57-matter-landing-page/index.md | 2 +- .../matter-application-cluster-logic.md | 4 ++-- .../matter-event-timer-guide.md | 8 ++++---- .../matter-scenes-quick-start-guide.md | 4 ++-- 8 files changed, 15 insertions(+), 15 deletions(-) diff --git a/sld250-matter-references/custom-matter-device.md b/sld250-matter-references/custom-matter-device.md index 163ba77..839a2e8 100644 --- a/sld250-matter-references/custom-matter-device.md +++ b/sld250-matter-references/custom-matter-device.md @@ -61,7 +61,7 @@ through this function. The command can then be dissected using conditional logic to call the proper application functions based on the most recent command received. -Which file you edit depends on your sample app — see [Application customization models](/matter/{build-docspace-version}/matter-api-reference/#application-customization-models). New architecture apps route attribute changes through `CustomerAppTask` and `DMPostAttributeChangeCallbackImpl()`. Legacy architecture apps implement `MatterPostAttributeChangeCallback()` directly in `src/DataModelCallbacks.cpp`. +Which file you edit depends on your sample app — see [Application Customization Models](/matter/{build-docspace-version}/matter-api-reference/#application-customization-models). New architecture apps route attribute changes through `CustomerAppTask` and `DMPostAttributeChangeCallbackImpl()`. Legacy architecture apps implement `MatterPostAttributeChangeCallback()` directly in `src/DataModelCallbacks.cpp`. ## Adding a Cluster to a ZAP Configuration @@ -83,7 +83,7 @@ the current zap configuration, and run the generate.py script above. ## React to Level Control Cluster Commands -### New architecture +### New Architecture In a custom implementation of `DMPostAttributeChangeCallbackImpl()` in `src/CustomerAppTask.cpp`, add the following line of code or a similar line. This will give the application the ability to react to MoveToLevel commands. You can define platform-specific behavior for a MoveToLevel action. diff --git a/sld295-matter-api-reference/attributes.md b/sld295-matter-api-reference/attributes.md index 04ba0bb..bf2c206 100644 --- a/sld295-matter-api-reference/attributes.md +++ b/sld295-matter-api-reference/attributes.md @@ -4,9 +4,9 @@ Attributes represent the current state of a device. For instance if the device i ## Attribute Changes -Which instructions apply depends on your sample app — see [Application customization models](./index.md#application-customization-models). +Which instructions apply depends on your sample app — see [Application Customization Models](./index.md#application-customization-models). -### New architecture +### New Architecture When a ZCL attribute is updated in the data model, the framework invokes the post-attribute-change path. The Silicon Labs Matter stack routes this as follows: `MatterPostAttributeChangeCallback` in `BaseApplication.cpp` → `AppTask::DMPostAttributeChangeCallback` in `autogen/AppTask.cpp` → your optional `DMPostAttributeChangeCallbackImpl()` override in `CustomerAppTask`. diff --git a/sld295-matter-api-reference/event.md b/sld295-matter-api-reference/event.md index 22f766c..29758be 100644 --- a/sld295-matter-api-reference/event.md +++ b/sld295-matter-api-reference/event.md @@ -2,7 +2,7 @@ Events are records of past state transitions such as a light device's on-off attribute changing from on to off. -The autogenerated file [```include/AppEvent.h```](https://github.com/SiliconLabs/matter_extension/blob/main/third_party/matter_sdk/examples/template/silabs/include/AppEvent.h) houses the definition of the event object used by the application. It contains the event types, the structures for each event, and event handler. +The autogenerated file [```include/AppEvent.h```](https://github.com/SiliconLabs/matter_extension/blob/main/third_party/matter_sdk/examples/template/silabs/include/AppEvent.h) contains the definition of the event object used by the application. It includes the event types, the structures for each event, and event handler. **New architecture:** Custom event posting and handlers belong in `CustomerAppTask` overrides, not in `autogen/AppTask.cpp`. diff --git a/sld295-matter-api-reference/index.md b/sld295-matter-api-reference/index.md index 72d5958..055766f 100644 --- a/sld295-matter-api-reference/index.md +++ b/sld295-matter-api-reference/index.md @@ -11,7 +11,7 @@ This section covers the various Application Programming Interfaces (APIs) that a ## Application APIs -### Application customization models +### Application Customization Models Matter Extension 2.9.0 migrates a subset of sample apps to the Curiously Recurring Template Pattern (CRTP) based architecture, which removes app manager and DataModelCallbacks files. All other sample apps keep the previous architecture until the patch release. diff --git a/sld57-matter-landing-page/index.md b/sld57-matter-landing-page/index.md index 5fd1326..96f1cc2 100644 --- a/sld57-matter-landing-page/index.md +++ b/sld57-matter-landing-page/index.md @@ -31,7 +31,7 @@ Want to get a Matter application up and running quickly? Here's a high-level ove 4. **[Optional] Customize Matter App Behavior and Logic** - Use Project Configurator and other Studio tools to customize your app logic: [Developing with Project Configurator](https://docs.silabs.com/ssv6ug/latest/ssv6-configure-project/) - - Customize app behavior using the model your sample app provides — see [Application customization models](/matter/{build-docspace-version}/matter-api-reference/#application-customization-models). Refactored apps use `CustomerAppTask` and `autogen/AppTask.cpp`, all other apps use `DataModelCallbacks.cpp` and `src/AppTask.cpp`. + - Customize app behavior using the model your sample app provides — see [Application Customization Models](/matter/{build-docspace-version}/matter-api-reference/#application-customization-models). Refactored apps use `CustomerAppTask` and `autogen/AppTask.cpp`, all other apps use `DataModelCallbacks.cpp` and `src/AppTask.cpp`. - Follow documentation to develop a custom matter device with ZAP and corresponding callbacks: [Custom Matter Device Development](/matter/{build-docspace-version}/matter-references/custom-matter-device) 5. **Build and Flash** diff --git a/sld601-matter-application-development/matter-application-cluster-logic.md b/sld601-matter-application-development/matter-application-cluster-logic.md index eb01d59..0f22b24 100644 --- a/sld601-matter-application-development/matter-application-cluster-logic.md +++ b/sld601-matter-application-development/matter-application-cluster-logic.md @@ -60,9 +60,9 @@ Additionally, a corresponding component is automatically added to your project. ## Step 4: Add Application Logic -This guide uses the Lock sample app, which is on the **new architecture** in 2.9.0. See [Application customization models](/matter/{build-docspace-version}/matter-api-reference/#application-customization-models) to confirm which model your project uses. +This guide uses the Lock sample app, which is on the **new architecture** in 2.9.0. See [Application Customization Models](/matter/{build-docspace-version}/matter-api-reference/#application-customization-models) to confirm which model your project uses. -### New architecture +### New Architecture Application logic centers on AppTask, but refactored Matter projects split responsibilities: diff --git a/sld601-matter-application-development/matter-event-timer-guide.md b/sld601-matter-application-development/matter-event-timer-guide.md index 35a27c1..2744634 100644 --- a/sld601-matter-application-development/matter-event-timer-guide.md +++ b/sld601-matter-application-development/matter-event-timer-guide.md @@ -5,7 +5,7 @@ The Matter event handler uses the FreeRTOS queue to transport a message from the producer to the consumer area. Events can be used to create asynchronous message processing or inter-task communication. -Which instructions apply depends on your sample app — see [Application customization models](/matter/{build-docspace-version}/matter-api-reference/#application-customization-models). +Which instructions apply depends on your sample app — see [Application Customization Models](/matter/{build-docspace-version}/matter-api-reference/#application-customization-models). Steps to make an event work: @@ -57,7 +57,7 @@ struct AppEvent When creating an event and pushing it to the event queue at minimum, **Handler** and **Type** must be defined in order for the event to work. -### New architecture +### New Architecture Custom event posting and handlers belong in `CustomerAppTask` overrides, not in `autogen/AppTask.cpp`. @@ -102,7 +102,7 @@ void SilabsSensors::SendSensorsValues(AppEvent * aEvent) **AppTaskMain** is dispatching all the events from the event list. -### New architecture +### New Architecture ```C++ void AppTask::AppTaskMain(void * pvParameter) @@ -188,7 +188,7 @@ chip::DeviceLayer::PlatformMgr().UnlockChipStack(); ### Callback -### New architecture +### New Architecture Timer callback. Implement in `src/CustomerAppTask.cpp`. diff --git a/sld601-matter-application-development/matter-scenes-quick-start-guide.md b/sld601-matter-application-development/matter-scenes-quick-start-guide.md index 13f3cae..3185a4b 100644 --- a/sld601-matter-application-development/matter-scenes-quick-start-guide.md +++ b/sld601-matter-application-development/matter-scenes-quick-start-guide.md @@ -165,9 +165,9 @@ public: ### Step 3 Implement Callbacks -This guide uses the Lighting sample app, which is on the **new architecture** in 2.9.0. See [Application customization models](/matter/{build-docspace-version}/matter-api-reference/#application-customization-models) to confirm which model your project uses. +This guide uses the Lighting sample app, which is on the **new architecture** in 2.9.0. See [Application Customization Models](/matter/{build-docspace-version}/matter-api-reference/#application-customization-models) to confirm which model your project uses. -#### New architecture +#### New Architecture Make the following additions to `src/CustomerAppTask.cpp`: From 22bdd2080355989e4fd2eb13b36bbf54df2ccf9e Mon Sep 17 00:00:00 2001 From: Michael Duggan Date: Mon, 8 Jun 2026 08:50:35 -0400 Subject: [PATCH 10/12] fix wording --- .../matter-application-cluster-logic.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sld601-matter-application-development/matter-application-cluster-logic.md b/sld601-matter-application-development/matter-application-cluster-logic.md index 0f22b24..3c99165 100644 --- a/sld601-matter-application-development/matter-application-cluster-logic.md +++ b/sld601-matter-application-development/matter-application-cluster-logic.md @@ -96,7 +96,7 @@ void OnOffTmrStart(){ } ``` -Make sure to include `app-common/zap-generated/attributes/Accessors.h` in `CustomerAppTask.cpp` so you can access cluster attributes. +Include `app-common/zap-generated/attributes/Accessors.h` in `CustomerAppTask.cpp`, so that you can access cluster attributes. Next we will need an AppTask function to initiate the timer. Declare `OnOffAttributeWriteStartTimer()` in `include/CustomerAppTask.h` and define it in `src/CustomerAppTask.cpp`: From 317e63d43a88d23dd1ceb9a1a78c74351e8b192e Mon Sep 17 00:00:00 2001 From: Michael Duggan Date: Mon, 8 Jun 2026 09:36:00 -0400 Subject: [PATCH 11/12] update custom-matter-device.md --- sld250-matter-references/custom-matter-device.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sld250-matter-references/custom-matter-device.md b/sld250-matter-references/custom-matter-device.md index 839a2e8..d15f653 100644 --- a/sld250-matter-references/custom-matter-device.md +++ b/sld250-matter-references/custom-matter-device.md @@ -61,7 +61,7 @@ through this function. The command can then be dissected using conditional logic to call the proper application functions based on the most recent command received. -Which file you edit depends on your sample app — see [Application Customization Models](/matter/{build-docspace-version}/matter-api-reference/#application-customization-models). New architecture apps route attribute changes through `CustomerAppTask` and `DMPostAttributeChangeCallbackImpl()`. Legacy architecture apps implement `MatterPostAttributeChangeCallback()` directly in `src/DataModelCallbacks.cpp`. +Depending on your sample application, edit the files. For more information, refer to [Application Customization Models](/matter/{build-docspace-version}/matter-api-reference/#application-customization-models). New architecture apps route attribute changes through `CustomerAppTask` and `DMPostAttributeChangeCallbackImpl()`. Legacy architecture apps implement `MatterPostAttributeChangeCallback()` directly in `src/DataModelCallbacks.cpp`. ## Adding a Cluster to a ZAP Configuration @@ -85,8 +85,7 @@ the current zap configuration, and run the generate.py script above. ### New Architecture -In a custom implementation of `DMPostAttributeChangeCallbackImpl()` in `src/CustomerAppTask.cpp`, add the following line of code or a similar line. This will -give the application the ability to react to MoveToLevel commands. You can define platform-specific behavior for a MoveToLevel action. +In a custom implementation of `DMPostAttributeChangeCallbackImpl()` in `src/CustomerAppTask.cpp`, add the following or similar code. This enables the application to react to the MoveToLevel commands. ```cpp else if (clusterId == LevelControl::Id) From af6b9106673837dbcaa72bff7cca197905cfcb44 Mon Sep 17 00:00:00 2001 From: Michael Duggan Date: Mon, 8 Jun 2026 11:06:00 -0400 Subject: [PATCH 12/12] address review comments --- sld250-matter-references/custom-matter-device.md | 2 +- sld295-matter-api-reference/attributes.md | 7 +++---- sld295-matter-api-reference/event.md | 2 +- sld295-matter-api-reference/index.md | 4 ++-- .../matter-application-cluster-logic.md | 4 ++-- .../matter-event-timer-guide.md | 10 +++++----- .../matter-scenes-quick-start-guide.md | 12 ++++++------ 7 files changed, 20 insertions(+), 21 deletions(-) diff --git a/sld250-matter-references/custom-matter-device.md b/sld250-matter-references/custom-matter-device.md index d15f653..c481d0b 100644 --- a/sld250-matter-references/custom-matter-device.md +++ b/sld250-matter-references/custom-matter-device.md @@ -100,7 +100,7 @@ In a custom implementation of `DMPostAttributeChangeCallbackImpl()` in `src/Cust } ``` -### Legacy architecture +### Legacy Architecture In the MatterPostAttributeCallback function in ZclCallbacks, add the following line of code or a similar line. This will give the application the ability to react to diff --git a/sld295-matter-api-reference/attributes.md b/sld295-matter-api-reference/attributes.md index bf2c206..8fad91c 100644 --- a/sld295-matter-api-reference/attributes.md +++ b/sld295-matter-api-reference/attributes.md @@ -4,14 +4,13 @@ Attributes represent the current state of a device. For instance if the device i ## Attribute Changes -Which instructions apply depends on your sample app — see [Application Customization Models](./index.md#application-customization-models). +Depending on your sample app, instructions apply. For more information, refer to [Application customization models](./index.md#application-customization-models). ### New Architecture When a ZCL attribute is updated in the data model, the framework invokes the post-attribute-change path. The Silicon Labs Matter stack routes this as follows: `MatterPostAttributeChangeCallback` in `BaseApplication.cpp` → `AppTask::DMPostAttributeChangeCallback` in `autogen/AppTask.cpp` → your optional `DMPostAttributeChangeCallbackImpl()` override in `CustomerAppTask`. -If this callback is implemented by the device it will be informed of the attribute change. The device may react to the attribute change. For example, in `DMPostAttributeChangeCallback` in `AppTask.cpp` in [onoff-plug-app/src](https://github.com/SiliconLabsSoftware/matter_sdk/blob/main/examples/onoff-plug-app/silabs/src/AppTask.cpp), say we want to add some custom handler code to control an RGB LED when on/off attribute in the `On-Off` Cluster changes, implement the following in -`DMPostAttributeChangeCallbackImpl` in `src/CustomerAppTask.cpp`: +If this callback is implemented by the device, it is informed of the attribute change. The device may react to the attribute change. For example, in `DMPostAttributeChangeCallback` function the in `AppTask.cpp` file ([onoff-plug-app/src](https://github.com/SiliconLabsSoftware/matter_sdk/blob/main/examples/onoff-plug-app/silabs/src/AppTask.cpp)), if you want to add a custom handler code to control an RGB LED when on/off attribute in the `On-Off` Cluster changes, implement the following in `DMPostAttributeChangeCallbackImpl` in `src/CustomerAppTask.cpp`: ```cpp void DMPostAttributeChangeCallbackImpl(const chip::app::ConcreteAttributePath & attributePath, @@ -40,7 +39,7 @@ void DMPostAttributeChangeCallbackImpl(const chip::app::ConcreteAttributePath & } ``` -### Legacy architecture +### Legacy Architecture When a ZCL attribute is updated in the data model, the framework calls `MatterPostAttributeChangeCallback()` in `src/DataModelCallbacks.cpp`. If this callback is implemented by the device it will be informed of the attribute change. For example, to control an RGB LED when the On/Off attribute changes: diff --git a/sld295-matter-api-reference/event.md b/sld295-matter-api-reference/event.md index 29758be..6bbcf3a 100644 --- a/sld295-matter-api-reference/event.md +++ b/sld295-matter-api-reference/event.md @@ -4,7 +4,7 @@ Events are records of past state transitions such as a light device's on-off att The autogenerated file [```include/AppEvent.h```](https://github.com/SiliconLabs/matter_extension/blob/main/third_party/matter_sdk/examples/template/silabs/include/AppEvent.h) contains the definition of the event object used by the application. It includes the event types, the structures for each event, and event handler. -**New architecture:** Custom event posting and handlers belong in `CustomerAppTask` overrides, not in `autogen/AppTask.cpp`. +**New architecture:** Custom event posting and handlers are overridden in the `CustomerAppTask` file, not in `autogen/AppTask.cpp`. ## Header File diff --git a/sld295-matter-api-reference/index.md b/sld295-matter-api-reference/index.md index 055766f..5195cce 100644 --- a/sld295-matter-api-reference/index.md +++ b/sld295-matter-api-reference/index.md @@ -38,9 +38,9 @@ All other Silicon Labs Matter sample apps in this release use the legacy model. ### Initialization -**New architecture:** Default initialization lives in `autogen/AppTask.cpp`. Override `AppInitImpl()` and other `*Impl()` hooks in `src/CustomerAppTask.cpp` to customize behavior. +**New architecture:** Default initialization is included in `autogen/AppTask.cpp`. Override `AppInitImpl()` and other `*Impl()` hooks in `src/CustomerAppTask.cpp` to customize behavior. -**Legacy architecture:** The application Init sequence lives in `src/AppTask.cpp` and is called at the beginning of the application to ensure that all components are properly initialized and ready to operate. It sets up necessary callbacks, initializes hardware components, and handles any errors that may occur during the process. +**Legacy architecture:** The application Init sequence is included in `src/AppTask.cpp` and is called at the beginning of the application to ensure that all components are properly initialized and ready to operate. It sets up necessary callbacks, initializes hardware components, and handles any errors that may occur during the process. ```cpp CHIP_ERROR AppTask::Init() diff --git a/sld601-matter-application-development/matter-application-cluster-logic.md b/sld601-matter-application-development/matter-application-cluster-logic.md index 3c99165..3178f64 100644 --- a/sld601-matter-application-development/matter-application-cluster-logic.md +++ b/sld601-matter-application-development/matter-application-cluster-logic.md @@ -129,11 +129,11 @@ Finally, add a call to `OnOffTmrStart()` at the end of your `AppInitImpl()` over In the flowchart above, `OnOffAttributeWriteStartTimer()` calls `OnOffTmrStart()` to restart the timer. -### Legacy architecture +### Legacy Architecture Locate your project's src/AppTask.cpp file. This file acts as the central hub for application-specific logic, initialization, and event processing in a Matter application on Silicon Labs platforms. Start by adding two helper functions: a one-shot timer to expire in 10 seconds and the OnOffTmrExpiryHandler handler function. -Make sure to include `app-common/zap-generated/attributes/Accessors.h` in your `AppTask.cpp` file so you can access cluster attributes. +Include `app-common/zap-generated/attributes/Accessors.h` in your `AppTask.cpp` file, so that you can access cluster attributes. Add the timer start function to `AppTask.cpp` and declare it in `AppTask.h`: diff --git a/sld601-matter-application-development/matter-event-timer-guide.md b/sld601-matter-application-development/matter-event-timer-guide.md index 2744634..3131c0b 100644 --- a/sld601-matter-application-development/matter-event-timer-guide.md +++ b/sld601-matter-application-development/matter-event-timer-guide.md @@ -5,7 +5,7 @@ The Matter event handler uses the FreeRTOS queue to transport a message from the producer to the consumer area. Events can be used to create asynchronous message processing or inter-task communication. -Which instructions apply depends on your sample app — see [Application Customization Models](/matter/{build-docspace-version}/matter-api-reference/#application-customization-models). +Depending on your sample app, instructions apply. See [Application Customization Models](/matter/{build-docspace-version}/matter-api-reference/#application-customization-models). Steps to make an event work: @@ -59,7 +59,7 @@ When creating an event and pushing it to the event queue at minimum, **Handler** ### New Architecture -Custom event posting and handlers belong in `CustomerAppTask` overrides, not in `autogen/AppTask.cpp`. +Custom event posting and handlers are overridden in the `CustomerAppTask` file, not in `autogen/AppTask.cpp`. ```C++ void CreateObserverEvent(void) @@ -72,7 +72,7 @@ void CreateObserverEvent(void) } ``` -### Legacy architecture +### Legacy Architecture Post events from `src/AppTask.cpp`: @@ -137,7 +137,7 @@ void AppTask::AppTaskMain(void * pvParameter) } ``` -### Legacy architecture +### Legacy Architecture ```C++ void AppTask::AppTaskMain(void * pvParameter) @@ -199,7 +199,7 @@ void TestCallback(System::Layer * layer, void * aAppState) } ``` -### Legacy architecture +### Legacy Architecture Timer callback. Implement in `src/AppTask.cpp`. diff --git a/sld601-matter-application-development/matter-scenes-quick-start-guide.md b/sld601-matter-application-development/matter-scenes-quick-start-guide.md index 3185a4b..f1e2e21 100644 --- a/sld601-matter-application-development/matter-scenes-quick-start-guide.md +++ b/sld601-matter-application-development/matter-scenes-quick-start-guide.md @@ -196,7 +196,7 @@ bool xyFlag = false; ``` ::: -Then, inside `DMPostAttributeChangeCallbackImpl()` in _src/CustomerAppTask.cpp_, implement the on/off functionality of the LED: +Inside `DMPostAttributeChangeCallbackImpl()` in _src/CustomerAppTask.cpp_, implement the on/off functionality of the LED: ```c++ if (clusterId == OnOff::Id && attributeId == OnOff::Attributes::OnOff::Id) @@ -248,7 +248,7 @@ else if (clusterId == ColorControl::Id) } ``` -Lastly, it is necessary to initialize the LED. In your `AppInitImpl()` override in `src/CustomerAppTask.cpp`. Add the following: +It is necessary to initialize the LED. To do so, override AppInitImpl() in src/CustomerAppTask.cpp and add the following: ```c++ #include "sl_simple_rgb_pwm_led.h" @@ -256,7 +256,7 @@ Lastly, it is necessary to initialize the LED. In your `AppInitImpl()` override #include "sl_led.h" ``` -Then, inside `AppInitImpl()`: +Inside `AppInitImpl()`: ```c++ CHIP_ERROR AppInitImpl() @@ -281,7 +281,7 @@ CHIP_ERROR AppInitImpl() This initializes the LED to be white. -#### Legacy architecture +#### Legacy Architecture Make the following additions to `src/DataModelCallbacks.cpp`: @@ -310,7 +310,7 @@ bool xyFlag = false; ``` ::: -Then, inside `MatterPostAttributeChangeCallback` in _src/DataModelCallbacks.cpp_, implement the on/off functionality of the LED: +Inside `MatterPostAttributeChangeCallback` in _src/DataModelCallbacks.cpp_, implement the on/off functionality of the LED: ```c++ if (clusterId == OnOff::Id && attributeId == OnOff::Attributes::OnOff::Id) @@ -334,7 +334,7 @@ if (clusterId == OnOff::Id && attributeId == OnOff::Attributes::OnOff::Id) Use the same Color Control cluster handling as in the **New architecture** section above. -Lastly, initialize the LED in `src/AppTask.cpp`. Add the same includes, then inside `AppTask::Init()`: +Initialize the LED in `src/AppTask.cpp`. Add the same includes, then inside `AppTask::Init()`: ```c++ CHIP_ERROR AppTask::Init()