Skip to content
Open
Show file tree
Hide file tree
Changes from 36 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
f24e3f0
Oven App skeleton code with all endpoint initialisations
arun-silabs Oct 16, 2025
90e0388
Restyled by whitespace
restyled-commits Oct 16, 2025
65a5c48
Restyled by clang-format
restyled-commits Oct 16, 2025
1a8dd8d
Address copilot review
arun-silabs Oct 21, 2025
8c86d55
Restyled by clang-format
restyled-commits Oct 21, 2025
204d3a1
Apply suggestions from code review
arun-silabs Oct 21, 2025
ec3943e
Apply suggestions from code review
arun-silabs Oct 21, 2025
2b9505f
Address copilot review comments
arun-silabs Oct 22, 2025
03aa29e
Address review comments and modify the file structures accordingly
arun-silabs Oct 23, 2025
ebf324e
Restyled by gn
restyled-commits Oct 23, 2025
6d73e62
Add required TODOs and optimize the skeleton code
arun-silabs Oct 23, 2025
9f63524
Restyled by whitespace
restyled-commits Oct 23, 2025
d5f86e9
Restyled by clang-format
restyled-commits Oct 23, 2025
00952f3
Cleanup comments
arun-silabs Oct 23, 2025
df13ff4
Address review comments
arun-silabs Oct 28, 2025
3f5eaec
Commands implementation
arun-silabs Oct 26, 2025
dde3035
Add logic to handle the oven-mode change
arun-silabs Oct 26, 2025
c36c1ca
Clean-up the command handling logic
arun-silabs Oct 27, 2025
efdc6e3
Restyled by whitespace
restyled-commits Oct 27, 2025
f1aacf6
Restyled by clang-format
restyled-commits Oct 27, 2025
caad0fb
Address review comments
arun-silabs Oct 28, 2025
c9545d8
Address review comments
arun-silabs Oct 29, 2025
b1e9be0
Restyled by whitespace
restyled-commits Oct 29, 2025
0e0ee4e
Restyled by clang-format
restyled-commits Oct 29, 2025
3643d79
Move ChangeToMode command processing to common layer
arun-silabs Oct 29, 2025
49a6cbb
Restyled by whitespace
restyled-commits Oct 29, 2025
17e72b9
Restyled by clang-format
restyled-commits Oct 29, 2025
5826f8f
Handle review comments
arun-silabs Nov 4, 2025
232fe4f
Rebase with main branch
arun-silabs Nov 5, 2025
50bfb9c
Restyled by whitespace
restyled-commits Nov 5, 2025
efceeac
Restyled by clang-format
restyled-commits Nov 5, 2025
d3cb6fa
Apply suggestions from code review
arun-silabs Nov 5, 2025
ba72490
Address review comments
arun-silabs Nov 5, 2025
f68c4e2
Fix zap issue
arun-silabs Nov 5, 2025
fbc02c4
Restyled by clang-format
restyled-commits Nov 5, 2025
52cb237
Remove redundant cook surface init
arun-silabs Nov 5, 2025
1baad61
Address review comments
arun-silabs Nov 5, 2025
6d426f9
Restyled by clang-format
restyled-commits Nov 5, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 30 additions & 2 deletions examples/oven-app/oven-app-common/include/CookSurfaceEndpoint.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,40 @@ class CookSurfaceEndpoint
*/
CHIP_ERROR Init();

void HandleOffCommand();
/**
* @brief Gets the current On/Off state from server.
* @param state Reference to store the current On/Off state.
*
* Note: This helper reads the OnOff attribute from the CHIP attribute storage and
* therefore must be invoked from the CHIP/DeviceLayer task context or while holding
* the CHIP stack lock (DeviceLayer::PlatformMgr().LockChipStack()). Calling this
* API from an arbitrary thread can cause asserts / crashes in the CHIP stack.
* If you are not in the CHIP task, schedule work onto the CHIP task using
* PlatformMgr().ScheduleWork(...) and call this helper from there.
*
* @return Returns Status::Success on success, or an error code on failure.
*/

Copy link

Copilot AI Nov 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Extra blank line between documentation and function declaration. Remove the blank line on line 55 to maintain consistency with standard documentation formatting practices.

Suggested change

Copilot uses AI. Check for mistakes.
chip::Protocols::InteractionModel::Status GetOnOffState(bool & state);

/**
* @brief Set On/Off state for the CookSurface.
* @param state Desired On/Off state.
*
* Note: This helper writes the OnOff attribute to the CHIP attribute storage and
* therefore must be invoked from the CHIP/DeviceLayer task context or while holding
* the CHIP stack lock (DeviceLayer::PlatformMgr().LockChipStack()). Calling this
* API from an arbitrary thread can cause asserts / crashes in the CHIP stack.
* If you are not in the CHIP task, schedule work onto the CHIP task using
* PlatformMgr().ScheduleWork(...) and call this helper from there.
*
* @return Returns Status::Success on success, or an error code on failure.
*/
chip::Protocols::InteractionModel::Status SetOnOffState(bool state);

EndpointId GetEndpointId() const { return mEndpointId; }

private:
bool currentOnOffState = false;
EndpointId mEndpointId = kInvalidEndpointId;
};

Expand Down
15 changes: 14 additions & 1 deletion examples/oven-app/oven-app-common/include/CookTopEndpoint.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,20 @@ class CookTopEndpoint
*/
CHIP_ERROR Init();

void HandleOffCommand();
/**
* @brief Set On/Off state for the CookTop
* @param state Desired On/Off state.
*
* Note: This helper writes the OnOff attribute to the CHIP attribute storage and
* therefore must be invoked from the CHIP/DeviceLayer task context or while holding
* the CHIP stack lock (DeviceLayer::PlatformMgr().LockChipStack()). Calling this
* API from an arbitrary thread can cause asserts / crashes in the CHIP stack.
* If you are not in the CHIP task, schedule work onto the CHIP task using
* PlatformMgr().ScheduleWork(...) and call this helper from there.
*
* @return Returns Status::Success on success, or an error code on failure.
*/
chip::Protocols::InteractionModel::Status SetOnOffState(bool state);

private:
bool currentOnOffState = false;
Expand Down
20 changes: 18 additions & 2 deletions examples/oven-app/oven-app-common/include/OvenEndpoint.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,17 @@ class OvenModeDelegate : public ModeBase::Delegate
CHIP_ERROR GetModeValueByIndex(uint8_t modeIndex, uint8_t & value) override;
CHIP_ERROR GetModeTagsByIndex(uint8_t modeIndex, DataModel::List<detail::Structs::ModeTagStruct::Type> & tags) override;

/**
* @brief Checks if the provided mode is supported.
*
* @param mode The mode to check.
* @return true if the mode is supported, false otherwise.
*/
bool IsSupportedMode(uint8_t mode);

private:
EndpointId mEndpointId;

// Static arrays moved to implementation file to reduce header size
static const detail::Structs::ModeTagStruct::Type sModeTagsBake[];
static const detail::Structs::ModeTagStruct::Type sModeTagsConvection[];
static const detail::Structs::ModeTagStruct::Type sModeTagsGrill[];
Expand All @@ -77,8 +84,10 @@ class OvenModeDelegate : public ModeBase::Delegate
class TemperatureControlledCabinetEndpoint
{
public:
static constexpr uint8_t kModeBaseFeatures = 0; // No specific features for ModeBase::Instance
TemperatureControlledCabinetEndpoint(EndpointId endpointId) :
mEndpointId(endpointId), mOvenModeDelegate(mEndpointId), mOvenModeInstance(&mOvenModeDelegate, mEndpointId, OvenMode::Id, 0)
mEndpointId(endpointId), mOvenModeDelegate(mEndpointId),
mOvenModeInstance(&mOvenModeDelegate, mEndpointId, OvenMode::Id, kModeBaseFeatures)
{}

/**
Expand All @@ -89,6 +98,13 @@ class TemperatureControlledCabinetEndpoint
*/
CHIP_ERROR Init();

/**
* @brief Get the oven mode delegate instance.
*
* @return Reference to the oven mode delegate.
*/
OvenModeDelegate & GetOvenModeDelegate() { return mOvenModeDelegate; }

private:
EndpointId mEndpointId = kInvalidEndpointId;
OvenModeDelegate mOvenModeDelegate;
Expand Down
16 changes: 14 additions & 2 deletions examples/oven-app/oven-app-common/src/CookSurfaceEndpoint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,26 @@
*/

#include "CookSurfaceEndpoint.h"
#include <lib/core/CHIPError.h>
#include <app/clusters/on-off-server/on-off-server.h>
#include <protocols/interaction_model/StatusCode.h>

using namespace chip;
using namespace chip::app::Clusters;
using namespace chip::app::Clusters::CookSurface;

CHIP_ERROR CookSurfaceEndpoint::Init()
{
// Placeholder for user Init
return CHIP_NO_ERROR;
}

void CookSurfaceEndpoint::HandleOffCommand() {}
chip::Protocols::InteractionModel::Status CookSurfaceEndpoint::GetOnOffState(bool & state)
{
return OnOffServer::Instance().getOnOffValue(mEndpointId, &state);
}

chip::Protocols::InteractionModel::Status CookSurfaceEndpoint::SetOnOffState(bool state)
{
CommandId commandId = state ? OnOff::Commands::On::Id : OnOff::Commands::Off::Id;
return OnOffServer::Instance().setOnOffValue(mEndpointId, commandId, false);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be encased in a chipTaskLock ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not necessarily if it is called from ChipTask. I have added the function usage in header file (

* Note: This helper writes the OnOff attribute to the CHIP attribute storage and
)
ScheduleWork or ChipTaskLock should only be used if this function is called from AppTask

}
7 changes: 6 additions & 1 deletion examples/oven-app/oven-app-common/src/CookTopEndpoint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,12 @@ using namespace chip::app::Clusters::CookTop;

CHIP_ERROR CookTopEndpoint::Init()
{
// Placeholder for user Init
return CHIP_NO_ERROR;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again please add a comment as why this function is needed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a placeholder function similar to one in CookSurface, added a comment.

}

void CookTopEndpoint::HandleOffCommand() {}
chip::Protocols::InteractionModel::Status CookTopEndpoint::SetOnOffState(bool state)
{
CommandId commandId = state ? OnOff::Commands::On::Id : OnOff::Commands::Off::Id;
return OnOffServer::Instance().setOnOffValue(mEndpointId, commandId, false);
}
103 changes: 78 additions & 25 deletions examples/oven-app/oven-app-common/src/OvenEndpoint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@
*/

#include "OvenEndpoint.h"
#include <app-common/zap-generated/attributes/Accessors.h>
#include <app-common/zap-generated/cluster-objects.h>

#include "OvenManager.h"
#include <app/clusters/mode-base-server/mode-base-cluster-objects.h>
#include <lib/core/CHIPError.h>
#include <lib/support/CodeUtils.h>
Expand All @@ -29,59 +32,55 @@ using namespace chip::app::Clusters::Oven;
using namespace chip::app::Clusters::OvenMode;
using namespace chip::app::Clusters::TemperatureControlledCabinet;
using chip::Protocols::InteractionModel::Status;
using detail::Structs::ModeTagStruct::Type;

// Static member definitions
const detail::Structs::ModeTagStruct::Type OvenModeDelegate::sModeTagsBake[1] = { { .value = to_underlying(ModeTag::kBake) } };
const Type OvenModeDelegate::sModeTagsBake[1] = { { .value = to_underlying(ModeTag::kBake) } };

const detail::Structs::ModeTagStruct::Type OvenModeDelegate::sModeTagsConvection[1] = { { .value = to_underlying(
ModeTag::kConvection) } };
const Type OvenModeDelegate::sModeTagsConvection[1] = { { .value = to_underlying(ModeTag::kConvection) } };

const detail::Structs::ModeTagStruct::Type OvenModeDelegate::sModeTagsGrill[1] = { { .value = to_underlying(ModeTag::kGrill) } };
const Type OvenModeDelegate::sModeTagsGrill[1] = { { .value = to_underlying(ModeTag::kGrill) } };
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do we need an array of 1 ? What is this logic and why is this needed ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This logic is for adding a unique tag to all the oven-modes.
those length‑1 arrays hold the single ModeTag value for each oven mode so we can give a DataModel::List view (which expects contiguous storage + a size) to the ModeOptionStruct entries.


const detail::Structs::ModeTagStruct::Type OvenModeDelegate::sModeTagsRoast[1] = { { .value = to_underlying(ModeTag::kRoast) } };
const Type OvenModeDelegate::sModeTagsRoast[1] = { { .value = to_underlying(ModeTag::kRoast) } };

const detail::Structs::ModeTagStruct::Type OvenModeDelegate::sModeTagsClean[1] = { { .value = to_underlying(ModeTag::kClean) } };
const Type OvenModeDelegate::sModeTagsClean[1] = { { .value = to_underlying(ModeTag::kClean) } };

const detail::Structs::ModeTagStruct::Type OvenModeDelegate::sModeTagsConvectionBake[1] = { { .value = to_underlying(
ModeTag::kConvectionBake) } };
const Type OvenModeDelegate::sModeTagsConvectionBake[1] = { { .value = to_underlying(ModeTag::kConvectionBake) } };

const detail::Structs::ModeTagStruct::Type OvenModeDelegate::sModeTagsConvectionRoast[1] = { { .value = to_underlying(
ModeTag::kConvectionRoast) } };
const Type OvenModeDelegate::sModeTagsConvectionRoast[1] = { { .value = to_underlying(ModeTag::kConvectionRoast) } };

const detail::Structs::ModeTagStruct::Type OvenModeDelegate::sModeTagsWarming[1] = { { .value =
to_underlying(ModeTag::kWarming) } };
const Type OvenModeDelegate::sModeTagsWarming[1] = { { .value = to_underlying(ModeTag::kWarming) } };

const detail::Structs::ModeTagStruct::Type OvenModeDelegate::sModeTagsProofing[1] = { { .value =
to_underlying(ModeTag::kProofing) } };
const Type OvenModeDelegate::sModeTagsProofing[1] = { { .value = to_underlying(ModeTag::kProofing) } };

const detail::Structs::ModeOptionStruct::Type OvenModeDelegate::skModeOptions[to_underlying(OvenModes::kModeCount)] = {
{ .label = CharSpan::fromCharString("Bake"),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

again this is unreadable 😢 , there must be a cleaner and more concise way to achieve the desired result.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

simplified the declarations by adding this : using detail::Structs::ModeOptionStruct::Type

.mode = to_underlying(OvenModes::kModeBake),
.modeTags = DataModel::List<const detail::Structs::ModeTagStruct::Type>(sModeTagsBake) },
.modeTags = DataModel::List<const Type>(sModeTagsBake) },
{ .label = CharSpan::fromCharString("Convection"),
.mode = to_underlying(OvenModes::kModeConvection),
.modeTags = DataModel::List<const detail::Structs::ModeTagStruct::Type>(sModeTagsConvection) },
.modeTags = DataModel::List<const Type>(sModeTagsConvection) },
{ .label = CharSpan::fromCharString("Grill"),
.mode = to_underlying(OvenModes::kModeGrill),
.modeTags = DataModel::List<const detail::Structs::ModeTagStruct::Type>(sModeTagsGrill) },
.modeTags = DataModel::List<const Type>(sModeTagsGrill) },
{ .label = CharSpan::fromCharString("Roast"),
.mode = to_underlying(OvenModes::kModeRoast),
.modeTags = DataModel::List<const detail::Structs::ModeTagStruct::Type>(sModeTagsRoast) },
.modeTags = DataModel::List<const Type>(sModeTagsRoast) },
{ .label = CharSpan::fromCharString("Clean"),
.mode = to_underlying(OvenModes::kModeClean),
.modeTags = DataModel::List<const detail::Structs::ModeTagStruct::Type>(sModeTagsClean) },
.modeTags = DataModel::List<const Type>(sModeTagsClean) },
{ .label = CharSpan::fromCharString("Convection Bake"),
.mode = to_underlying(OvenModes::kModeConvectionBake),
.modeTags = DataModel::List<const detail::Structs::ModeTagStruct::Type>(sModeTagsConvectionBake) },
.modeTags = DataModel::List<const Type>(sModeTagsConvectionBake) },
{ .label = CharSpan::fromCharString("Convection Roast"),
.mode = to_underlying(OvenModes::kModeConvectionRoast),
.modeTags = DataModel::List<const detail::Structs::ModeTagStruct::Type>(sModeTagsConvectionRoast) },
.modeTags = DataModel::List<const Type>(sModeTagsConvectionRoast) },
{ .label = CharSpan::fromCharString("Warming"),
.mode = to_underlying(OvenModes::kModeWarming),
.modeTags = DataModel::List<const detail::Structs::ModeTagStruct::Type>(sModeTagsWarming) },
.modeTags = DataModel::List<const Type>(sModeTagsWarming) },
{ .label = CharSpan::fromCharString("Proofing"),
.mode = to_underlying(OvenModes::kModeProofing),
.modeTags = DataModel::List<const detail::Structs::ModeTagStruct::Type>(sModeTagsProofing) }
.modeTags = DataModel::List<const Type>(sModeTagsProofing) }
};

CHIP_ERROR OvenModeDelegate::Init()
Expand All @@ -92,8 +91,50 @@ CHIP_ERROR OvenModeDelegate::Init()

void OvenModeDelegate::HandleChangeToMode(uint8_t NewMode, ModeBase::Commands::ChangeToModeResponse::Type & response)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Didn't we have a mode enum somewhere in another header file ? is so we should use it instead of the generic uint8_t

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HandleChangeToMode is a function given by the delegate. In the delegate, it has uint8_t as the parameter type.
For oven modes, we have added a mode enum instead of having the modes as some static constants.

{
ChipLogProgress(Zcl, "OvenModeDelegate::HandleChangeToMode: NewMode=%d", NewMode);
// TODO: Implement logic to change the oven mode.
ChipLogProgress(Zcl, "OvenModeDelegate forwarding mode change to OvenManager (ep=%u newMode=%u)", mEndpointId, NewMode);
// Verify newMode is among supported modes
bool supported = IsSupportedMode(NewMode);
if (!supported)
{
response.status = to_underlying(ModeBase::StatusCode::kUnsupportedMode);
return;
}

// Read Current Oven Mode
uint8_t currentMode;
Status attrStatus = OvenMode::Attributes::CurrentMode::Get(mEndpointId, &currentMode);
if (attrStatus != Status::Success)
{
ChipLogError(AppServer, "OvenManager: Failed to read CurrentMode");
response.status = to_underlying(ModeBase::StatusCode::kGenericFailure);
response.statusText.SetValue(CharSpan::fromCharString("Read CurrentMode failed"));
return;
}

// No action needed if current mode is the same as new mode
if (currentMode == NewMode)
{
response.status = to_underlying(ModeBase::StatusCode::kSuccess);
return;
}

if (OvenManager::GetInstance().IsTransitionBlocked(currentMode, NewMode))
{
ChipLogProgress(AppServer, "OvenManager: Blocked transition %u -> %u", currentMode, NewMode);
response.status = to_underlying(ModeBase::StatusCode::kGenericFailure);
response.statusText.SetValue(CharSpan::fromCharString("Transition blocked"));
return;
}

// Write new mode
Status writeStatus = OvenMode::Attributes::CurrentMode::Set(mEndpointId, NewMode);
if (writeStatus != Status::Success)
{
ChipLogError(AppServer, "OvenManager: Failed to write CurrentMode");
response.status = to_underlying(ModeBase::StatusCode::kGenericFailure);
response.statusText.SetValue(CharSpan::fromCharString("Write CurrentMode failed"));
return;
}
response.status = to_underlying(ModeBase::StatusCode::kSuccess);
}

Expand Down Expand Up @@ -135,3 +176,15 @@ CHIP_ERROR OvenEndpoint::Init()
{
return CHIP_NO_ERROR;
}

bool OvenModeDelegate::IsSupportedMode(uint8_t mode)
{
for (auto const & opt : skModeOptions)
{
if (opt.mode == mode)
{
return true;
}
}
return false;
}
1 change: 1 addition & 0 deletions examples/oven-app/silabs/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ if (wifi_soc) {
"${examples_plat_dir}",
"${chip_root}/src/lib",
"${examples_common_plat_dir}",
"${example_oven_dir}/oven-app-common/include",
]

defines = []
Expand Down
4 changes: 4 additions & 0 deletions examples/oven-app/silabs/include/AppEvent.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@ struct AppEvent : public BaseAppEvent
enum AppEventTypes
{
kEventType_Oven = BaseAppEvent::kEventType_Max + 1,
kEventType_CookTop,
kEventType_CookSurface,
kEventType_Install,
kEventType_UIUpdate,
};

union
Expand All @@ -35,6 +38,7 @@ struct AppEvent : public BaseAppEvent
{
uint8_t Action;
int32_t Actor;
void * Context;
} OvenEvent;
};
};
10 changes: 1 addition & 9 deletions examples/oven-app/silabs/include/AppTask.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@

#include "AppEvent.h"
#include "BaseApplication.h"
#include "OvenManager.h"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this needed here ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is not needed, removed it.


#include "FreeRTOS.h"
#include "timers.h" // provides FreeRTOS timer support
Expand Down Expand Up @@ -87,13 +88,4 @@ class AppTask : public BaseApplication
* @return CHIP_ERROR
*/
CHIP_ERROR AppInit() override;

/**
* @brief PB0 Button event processing function
* Press and hold will trigger a factory reset timer start
* Press and release will restart BLEAdvertising if not commissioned
*
* @param aEvent button event being processed
*/
static void ButtonHandler(AppEvent * aEvent);
};
Loading
Loading