Extending Base App Implementation#

Introduction#

Silicon Labs Matter sample apps that support project upgrades use the Curiously Recurring Template Pattern (CRTP) so you can customize application behavior without editing the default AppTask implementation. Override *Impl() hooks in CustomerAppTask instead of modifying AppTask.cpp directly.

CustomerAppTask#

To implement custom app behavior you can override any Silicon Labs implemented API in the CustomerAppTask file. Each sample app provides CustomerAppTask.h and CustomerAppTask.cpp for that purpose. The base implementation and the full set of overridable *Impl() APIs live in that example’s source tree under include/AppTaskImpl.h and src/AppTask.cpp. Any *Impl() you do not override keeps the Silicon Labs default behavior.

To customize behavior, copy CustomerAppTask.h and CustomerAppTask.cpp from examples/platform/silabs/customer/ into your app’s include/ and src/ folders, then update the corresponding paths in BUILD.gn.

How to Override APIs#

CustomerAppTask derives from the base AppTask through the Curiously Recurring Template Pattern (CRTP). You override only the *Impl() methods you need; the base declares one *Impl() per overridable API. Steps:

  1. Find the method to override in the base API (see Override API reference below).

  2. Declare the same method signature in CustomerAppTask in your CustomerAppTask.h under private:. Match the base *Impl() signature exactly — note that *Impl() overrides are non-static instance methods even when the public dispatcher (e.g. ButtonEventHandler) is static.

  3. Implement the method in CustomerAppTask.cpp.

  4. Build. The CRTP layer automatically routes each call to your *Impl() if present, otherwise to the Silicon Labs default.

DataModelCallbacks and CustomerAppTask#

What used to live in DataModelCallbacks.cpp before Matter Extension 2.9.0 now lives in AppTask.cpp. The Matter SDK’s MatterPostAttributeChangeCallback is implemented in examples/platform/silabs/BaseApplication.cpp and forwards to AppTask::DMPostAttributeChangeCallback (defined in AppTask.cpp), which you can customize via DMPostAttributeChangeCallbackImpl() in CustomerAppTask.

Forwarding into AppTask still goes through CRTP as in How to Override APIs.

  • Methods that already exist in the AppTask — Customize them by overriding the matching *Impl() method in CustomerAppTask. Do not edit AppTask.cpp for app-specific behavior.

  • New custom data model methods — Add them in CustomerAppTask directly. Do not add new application logic in autogenerated sources; those edits will not survive regeneration or project upgrades.

Sample Implementation#

The following shows a minimal example CustomerAppTask that overrides AppInitImpl() and ButtonEventHandlerImpl() from the lighting app implementation.

CustomerAppTask.h

#pragma once
#include "AppTaskImpl.h"

/**
 * Minimal AppTaskImpl-derived class. Override only the *Impl() methods you need;
 * add AppInitImpl(), GetAppTask(), and sAppTask as required by the CRTP base.
 */
class CustomerAppTask : public AppTaskImpl<CustomerAppTask>
{
public:
    static CustomerAppTask & GetAppTask() { return sAppTask; }

private:
    friend class AppTaskImpl<CustomerAppTask>;
    CHIP_ERROR AppInitImpl();
    void ButtonEventHandlerImpl(uint8_t button, uint8_t btnAction);
    static CustomerAppTask sAppTask;
};

CustomerAppTask.cpp

#include "CustomerAppTask.h"
#include "AppTask.h"
#include "AppConfig.h"
#include "AppEvent.h"
#include <platform/CHIPDeviceLayer.h>
#include <platform/silabs/platformAbstraction/SilabsPlatform.h>

using namespace ::chip::DeviceLayer::Silabs;

#define APP_FUNCTION_BUTTON 0
#define APP_LIGHT_SWITCH     1

CustomerAppTask CustomerAppTask::sAppTask;

AppTask & AppTask::GetAppTask()
{
    return CustomerAppTask::GetAppTask();
}

CHIP_ERROR CustomerAppTask::AppInitImpl()
{
    SILABS_LOG("CustomerAppTask: custom implementation (AppInitImpl)");
    CHIP_ERROR err = this->AppTask::AppInit();
    if (err == CHIP_NO_ERROR)
    {
        // Override the SDK default button handler registered in AppTask::AppInit().
        chip::DeviceLayer::Silabs::GetPlatform().SetButtonsCb(CustomerAppTask::ButtonEventHandler);
    }
    return err;
}

void CustomerAppTask::ButtonEventHandlerImpl(uint8_t button, uint8_t btnAction)
{
    SILABS_LOG("CustomerAppTask: custom implementation (ButtonEventHandlerImpl)");
    AppEvent button_event           = {};
    button_event.Type               = AppEvent::kEventType_Button;
    button_event.ButtonEvent.Action = btnAction;
    if (button == APP_LIGHT_SWITCH && btnAction == static_cast<uint8_t>(SilabsPlatform::ButtonAction::ButtonPressed))
    {
        button_event.Handler = LightActionEventHandler;
        AppTask::GetAppTask().PostEvent(&button_event);
    }
    else if (button == APP_FUNCTION_BUTTON)
    {
        button_event.Handler = BaseApplication::ButtonHandler;
        AppTask::GetAppTask().PostEvent(&button_event);
    }
}

Override API Reference#

CHIP_ERROR StartAppTask() is declared on AppTask only. It is not an *Impl() hook: platform code (for example MatterConfig) calls AppTask::GetAppTask().StartAppTask() with static type AppTask &, which runs the implementation in AppTask.cpp (creating the FreeRTOS app task via BaseApplication::StartAppTask(...)). To change startup behavior, edit AppTask::StartAppTask() or BaseApplication::StartAppTask in your product sources.

The base API and default AppTask behavior for each sample app are maintained under that app’s include/AppTaskImpl.h and src/AppTask.cpp. Use those files as the reference for overridable methods and app configuration.

File

Purpose

include/AppTaskImpl.h

Declarations of every overridable *Impl() method. Copy the signatures you need from here into CustomerAppTask.h.

src/AppTask.cpp

Silicon Labs default implementation of AppTask. This is what runs for any *Impl() you do not override. Use as reference when customizing behavior.