Skip to content

Commit be7cdfd

Browse files
committed
Move ChangeToMode command processing to common layer
1 parent f120dc2 commit be7cdfd

File tree

3 files changed

+111
-132
lines changed

3 files changed

+111
-132
lines changed

examples/oven-app/oven-app-common/src/OvenEndpoint.cpp

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,50 @@ CHIP_ERROR OvenModeDelegate::Init()
9696
void OvenModeDelegate::HandleChangeToMode(uint8_t NewMode, ModeBase::Commands::ChangeToModeResponse::Type & response)
9797
{
9898
ChipLogProgress(Zcl, "OvenModeDelegate forwarding mode change to OvenManager (ep=%u newMode=%u)", mEndpointId, NewMode);
99-
OvenManager::GetInstance().ProcessOvenModeChange(mEndpointId, NewMode, response);
99+
// Verify newMode is among supported modes
100+
bool supported = IsSupportedMode(NewMode);
101+
if (!supported)
102+
{
103+
response.status = to_underlying(ModeBase::StatusCode::kUnsupportedMode);
104+
return;
105+
}
106+
107+
// Read Current Oven Mode
108+
uint8_t currentMode;
109+
Status attrStatus = OvenMode::Attributes::CurrentMode::Get(mEndpointId, &currentMode);
110+
if (attrStatus != Status::Success)
111+
{
112+
ChipLogError(AppServer, "OvenManager: Failed to read CurrentMode");
113+
response.status = to_underlying(ModeBase::StatusCode::kGenericFailure);
114+
response.statusText.SetValue(CharSpan::fromCharString("Read CurrentMode failed"));
115+
return;
116+
}
117+
118+
// No action needed if current mode is the same as new mode
119+
if (currentMode == NewMode)
120+
{
121+
response.status = to_underlying(ModeBase::StatusCode::kSuccess);
122+
return;
123+
}
124+
125+
if (OvenManager::GetInstance().IsTransitionBlocked(currentMode, NewMode))
126+
{
127+
ChipLogProgress(AppServer, "OvenManager: Blocked transition %u -> %u", currentMode, NewMode);
128+
response.status = to_underlying(ModeBase::StatusCode::kGenericFailure);
129+
response.statusText.SetValue(CharSpan::fromCharString("Transition blocked"));
130+
return;
131+
}
132+
133+
// Write new mode
134+
Status writeStatus = OvenMode::Attributes::CurrentMode::Set(mEndpointId, NewMode);
135+
if (writeStatus != Status::Success)
136+
{
137+
ChipLogError(AppServer, "OvenManager: Failed to write CurrentMode");
138+
response.status = to_underlying(ModeBase::StatusCode::kGenericFailure);
139+
response.statusText.SetValue(CharSpan::fromCharString("Write CurrentMode failed"));
140+
return;
141+
}
142+
response.status = to_underlying(ModeBase::StatusCode::kSuccess);
100143
}
101144

102145
CHIP_ERROR OvenModeDelegate::GetModeLabelByIndex(uint8_t modeIndex, MutableCharSpan & label)

examples/oven-app/silabs/include/OvenManager.h

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@
3737
#include <app/clusters/mode-base-server/mode-base-cluster-objects.h>
3838
#include <app/clusters/on-off-server/on-off-server.h>
3939
#include <lib/core/DataModelTypes.h>
40+
#include <lib/support/TypeTraits.h>
41+
#include <platform/CHIPDeviceLayer.h>
4042

4143
class OvenManager
4244
{
@@ -65,8 +67,8 @@ class OvenManager
6567
kCookSurfaceState_NoAction,
6668
} State;
6769

68-
bool InitiateAction(int32_t aActor, Action_t aAction, uint8_t * aValue);
69-
bool InitiateCookSurfaceAction(int32_t aActor, Action_t aAction, uint8_t * aValue, chip::EndpointId endpointId);
70+
71+
bool InitiateAction(int32_t aActor, Action_t aAction, uint8_t * aValue, chip::EndpointId endpointId = kCookTopEndpoint);
7072
typedef void (*Callback_fn_initiated)(Action_t, int32_t aActor, uint8_t * value);
7173
typedef void (*Callback_fn_completed)(Action_t);
7274
void SetCallbacks(Callback_fn_initiated aActionInitiated_CB, Callback_fn_completed aActionCompleted_CB);
@@ -118,13 +120,31 @@ class OvenManager
118120
void OvenModeAttributeChangeHandler(chip::EndpointId endpointId, chip::AttributeId attributeId, uint8_t * value, uint16_t size);
119121

120122
/**
121-
* @brief Central handler for OvenMode delegate requests. Applies validation, blocked-transition policy,
122-
* and writes the CurrentMode attribute if allowed.
123+
* @brief Checks if a transition between two oven modes is blocked.
124+
*
125+
* @param fromMode The current mode.
126+
* @param toMode The desired mode.
127+
* @return True if the transition is blocked, false otherwise.
123128
*/
124-
void ProcessOvenModeChange(chip::EndpointId endpointId, uint8_t newMode,
125-
chip::app::Clusters::ModeBase::Commands::ChangeToModeResponse::Type & response);
129+
bool IsTransitionBlocked(uint8_t fromMode, uint8_t toMode);
126130

127131
private:
132+
struct BlockedTransition
133+
{
134+
uint8_t fromMode;
135+
uint8_t toMode;
136+
};
137+
138+
// Disallowed OvenMode Transitions.
139+
static constexpr BlockedTransition kBlockedTransitions[3] = {
140+
{ chip::to_underlying(chip::app::Clusters::TemperatureControlledCabinet::OvenModeDelegate::OvenModes::kModeGrill),
141+
chip::to_underlying(chip::app::Clusters::TemperatureControlledCabinet::OvenModeDelegate::OvenModes::kModeProofing) },
142+
{ chip::to_underlying(chip::app::Clusters::TemperatureControlledCabinet::OvenModeDelegate::OvenModes::kModeProofing),
143+
chip::to_underlying(chip::app::Clusters::TemperatureControlledCabinet::OvenModeDelegate::OvenModes::kModeClean) },
144+
{ chip::to_underlying(chip::app::Clusters::TemperatureControlledCabinet::OvenModeDelegate::OvenModes::kModeClean),
145+
chip::to_underlying(chip::app::Clusters::TemperatureControlledCabinet::OvenModeDelegate::OvenModes::kModeBake) },
146+
};
147+
128148
static OvenManager sOvenMgr;
129149
chip::app::Clusters::AppSupportedTemperatureLevelsDelegate mTemperatureControlDelegate;
130150

examples/oven-app/silabs/src/OvenManager.cpp

Lines changed: 41 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -153,16 +153,15 @@ void OvenManager::OnOffAttributeChangeHandler(EndpointId endpointId, AttributeId
153153
switch (endpointId)
154154
{
155155
case kCookTopEndpoint:
156-
InitiateAction(AppEvent::kEventType_CookTop, *value ? OvenManager::ON_ACTION : OvenManager::OFF_ACTION, value);
156+
InitiateAction(AppEvent::kEventType_CookTop, *value ? OvenManager::ON_ACTION : OvenManager::OFF_ACTION, value, kCookTopEndpoint);
157157
// Update CookSurface states accordingly
158158
mCookSurfaceEndpoint1.SetOnOffState(*value);
159159
mCookSurfaceEndpoint2.SetOnOffState(*value);
160160
break;
161161
case kCookSurfaceEndpoint1:
162162
case kCookSurfaceEndpoint2:
163163
// Handle On/Off attribute changes for the cook surface endpoints
164-
InitiateCookSurfaceAction(AppEvent::kEventType_CookSurface, *value ? OvenManager::ON_ACTION : OvenManager::OFF_ACTION,
165-
value, endpointId);
164+
InitiateAction(AppEvent::kEventType_CookSurface, *value ? OvenManager::ON_ACTION : OvenManager::OFF_ACTION, value, endpointId);
166165
{
167166
bool cookSurfaceEndpoint1State;
168167
bool cookSurfaceEndpoint2State;
@@ -195,84 +194,75 @@ void OvenManager::SetCallbacks(Callback_fn_initiated aActionInitiated_CB, Callba
195194
mActionCompleted_CB = aActionCompleted_CB;
196195
}
197196

198-
bool OvenManager::InitiateAction(int32_t aActor, Action_t aAction, uint8_t * aValue)
197+
bool OvenManager::InitiateAction(int32_t aActor, Action_t aAction, uint8_t * aValue, chip::EndpointId endpointId)
199198
{
200199
bool action_initiated = false;
201200
State_t new_state;
201+
State_t * currentState = nullptr;
202+
uint8_t eventType;
202203

203-
// Initiate Turn On/Off Action only when the previous one is complete.
204-
if (mCookTopState == kCookTopState_OffCompleted && aAction == ON_ACTION)
205-
{
206-
action_initiated = true;
207-
new_state = kCookTopState_OnInitiated;
208-
}
209-
else if (mCookTopState == kCookTopState_OnCompleted && aAction == OFF_ACTION)
210-
{
211-
action_initiated = true;
212-
new_state = kCookTopState_OffInitiated;
213-
}
214-
215-
if (action_initiated && (aAction == ON_ACTION || aAction == OFF_ACTION))
204+
// Determine which state to manage based on endpoint
205+
if (endpointId == kCookTopEndpoint)
216206
{
217-
mCookTopState = new_state;
218-
219-
AppEvent event;
220-
event.Type = AppEvent::kEventType_CookTop;
221-
event.OvenEvent.Context = this;
222-
event.Handler = ActuatorMovementHandler;
223-
AppTask::GetAppTask().PostEvent(&event);
207+
currentState = &mCookTopState;
208+
eventType = AppEvent::kEventType_CookTop;
224209
}
225-
226-
if (action_initiated && mActionInitiated_CB)
227-
{
228-
mActionInitiated_CB(aAction, aActor, aValue);
229-
}
230-
231-
return action_initiated;
232-
}
233-
234-
bool OvenManager::InitiateCookSurfaceAction(int32_t aActor, Action_t aAction, uint8_t * aValue, chip::EndpointId endpointId)
235-
{
236-
bool action_initiated = false;
237-
State_t new_state;
238-
State_t * currentState = nullptr;
239-
240-
// Get the appropriate state pointer based on endpoint
241-
if (endpointId == kCookSurfaceEndpoint1)
210+
else if (endpointId == kCookSurfaceEndpoint1)
242211
{
243212
currentState = &mCookSurfaceState1;
213+
eventType = AppEvent::kEventType_CookSurface;
244214
}
245215
else if (endpointId == kCookSurfaceEndpoint2)
246216
{
247217
currentState = &mCookSurfaceState2;
218+
eventType = AppEvent::kEventType_CookSurface;
248219
}
249220
else
250221
{
251222
return false; // Invalid endpoint
252223
}
253224

254-
// Initiate Turn On/Off Action only when the previous one is complete.
255-
if (*currentState == kCookSurfaceState_OffCompleted && aAction == ON_ACTION)
225+
// Determine the appropriate state transitions based on endpoint type
226+
if (endpointId == kCookTopEndpoint)
256227
{
257-
action_initiated = true;
258-
new_state = kCookSurfaceState_OnInitiated;
228+
// CookTop state transitions
229+
if (*currentState == kCookTopState_OffCompleted && aAction == ON_ACTION)
230+
{
231+
action_initiated = true;
232+
new_state = kCookTopState_OnInitiated;
233+
}
234+
else if (*currentState == kCookTopState_OnCompleted && aAction == OFF_ACTION)
235+
{
236+
action_initiated = true;
237+
new_state = kCookTopState_OffInitiated;
238+
}
259239
}
260-
else if (*currentState == kCookSurfaceState_OnCompleted && aAction == OFF_ACTION)
240+
else
261241
{
262-
action_initiated = true;
263-
new_state = kCookSurfaceState_OffInitiated;
242+
// CookSurface state transitions
243+
if (*currentState == kCookSurfaceState_OffCompleted && aAction == ON_ACTION)
244+
{
245+
action_initiated = true;
246+
new_state = kCookSurfaceState_OnInitiated;
247+
}
248+
else if (*currentState == kCookSurfaceState_OnCompleted && aAction == OFF_ACTION)
249+
{
250+
action_initiated = true;
251+
new_state = kCookSurfaceState_OffInitiated;
252+
}
264253
}
265254

266255
if (action_initiated && (aAction == ON_ACTION || aAction == OFF_ACTION))
267256
{
268257
*currentState = new_state;
269258

270259
AppEvent event;
271-
event.Type = AppEvent::kEventType_CookSurface;
260+
event.Type = eventType;
272261
event.OvenEvent.Context = this;
273262
event.OvenEvent.Action = aAction;
274263
event.OvenEvent.Actor = endpointId; // Store endpoint ID in Actor field
275-
event.Handler = ActuatorMovementHandler;
264+
event.Handler = ActuatorMovementHandler;
265+
276266
AppTask::GetAppTask().PostEvent(&event);
277267
}
278268

@@ -350,26 +340,7 @@ void OvenManager::ActuatorMovementHandler(AppEvent * aEvent)
350340
}
351341
}
352342

353-
// ---------------- Oven Mode Handling ----------------
354-
355-
namespace {
356-
struct BlockedTransition
357-
{
358-
uint8_t fromMode;
359-
uint8_t toMode;
360-
};
361-
362-
// Disallowed OvenMode Transitions.
363-
static constexpr BlockedTransition kBlockedTransitions[] = {
364-
{ to_underlying(TemperatureControlledCabinet::OvenModeDelegate::OvenModes::kModeGrill),
365-
to_underlying(TemperatureControlledCabinet::OvenModeDelegate::OvenModes::kModeProofing) },
366-
{ to_underlying(TemperatureControlledCabinet::OvenModeDelegate::OvenModes::kModeProofing),
367-
to_underlying(TemperatureControlledCabinet::OvenModeDelegate::OvenModes::kModeClean) },
368-
{ to_underlying(TemperatureControlledCabinet::OvenModeDelegate::OvenModes::kModeClean),
369-
to_underlying(TemperatureControlledCabinet::OvenModeDelegate::OvenModes::kModeBake) },
370-
};
371-
372-
static bool IsTransitionBlocked(uint8_t fromMode, uint8_t toMode)
343+
bool OvenManager::IsTransitionBlocked(uint8_t fromMode, uint8_t toMode)
373344
{
374345
for (auto const & bt : kBlockedTransitions)
375346
{
@@ -380,58 +351,3 @@ static bool IsTransitionBlocked(uint8_t fromMode, uint8_t toMode)
380351
}
381352
return false;
382353
}
383-
} // namespace
384-
385-
void OvenManager::ProcessOvenModeChange(chip::EndpointId endpointId, uint8_t newMode,
386-
chip::app::Clusters::ModeBase::Commands::ChangeToModeResponse::Type & response)
387-
{
388-
using namespace chip::app::Clusters;
389-
using chip::Protocols::InteractionModel::Status;
390-
ChipLogProgress(AppServer, "OvenManager::ProcessOvenModeChange ep=%u newMode=%u", endpointId, newMode);
391-
392-
// Verify newMode is among supported modes
393-
bool supported = mTemperatureControlledCabinetEndpoint.GetOvenModeDelegate().IsSupportedMode(newMode);
394-
if (!supported)
395-
{
396-
response.status = to_underlying(ModeBase::StatusCode::kUnsupportedMode);
397-
return;
398-
}
399-
400-
// Read Current Oven Mode
401-
uint8_t currentMode;
402-
Status attrStatus = OvenMode::Attributes::CurrentMode::Get(endpointId, &currentMode);
403-
if (attrStatus != Status::Success)
404-
{
405-
ChipLogError(AppServer, "OvenManager: Failed to read CurrentMode");
406-
response.status = to_underlying(ModeBase::StatusCode::kGenericFailure);
407-
response.statusText.SetValue(CharSpan::fromCharString("Read CurrentMode failed"));
408-
return;
409-
}
410-
411-
// No action needed if current mode is the same as new mode
412-
if (currentMode == newMode)
413-
{
414-
response.status = to_underlying(ModeBase::StatusCode::kSuccess);
415-
return;
416-
}
417-
418-
// Check if the mode transition is possible
419-
if (IsTransitionBlocked(currentMode, newMode))
420-
{
421-
ChipLogProgress(AppServer, "OvenManager: Blocked transition %u -> %u", currentMode, newMode);
422-
response.status = to_underlying(ModeBase::StatusCode::kGenericFailure);
423-
response.statusText.SetValue(CharSpan::fromCharString("Transition blocked"));
424-
return;
425-
}
426-
427-
// Write new mode
428-
Status writeStatus = OvenMode::Attributes::CurrentMode::Set(endpointId, newMode);
429-
if (writeStatus != Status::Success)
430-
{
431-
ChipLogError(AppServer, "OvenManager: Failed to write CurrentMode");
432-
response.status = to_underlying(ModeBase::StatusCode::kGenericFailure);
433-
response.statusText.SetValue(CharSpan::fromCharString("Write CurrentMode failed"));
434-
return;
435-
}
436-
response.status = to_underlying(ModeBase::StatusCode::kSuccess);
437-
}

0 commit comments

Comments
 (0)