﻿# 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.

-   [Introduction](#introduction)
-   [CustomerAppTask](#customerapptask)
-   [How to Override APIs](#how-to-override-apis)
-   [DataModelCallbacks and CustomerAppTask](#datamodelcallbacks-and-customerapptask)
-   [Sample Implementation](#sample-implementation)
-   [Override API Reference](#override-api-reference)

## CustomerAppTask

To implement custom app behavior you can override any Silicon Labs implemented
API in the CustomerAppTask file. Each sample app provides
[`CustomerAppTask.h`](https://github.com/project-chip/connectedhomeip/blob/master/examples/platform/silabs/customer/CustomerAppTask.h)
and
[`CustomerAppTask.cpp`](https://github.com/project-chip/connectedhomeip/blob/master/examples/platform/silabs/customer/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`](https://github.com/project-chip/connectedhomeip/blob/master/examples/platform/silabs/customer/CustomerAppTask.h)
and
[`CustomerAppTask.cpp`](https://github.com/project-chip/connectedhomeip/blob/master/examples/platform/silabs/customer/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](#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`](https://github.com/project-chip/connectedhomeip/blob/master/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](#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**

```cpp
#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**

```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. |
