Skip to content

Commit 3643d79

Browse files
committed
Move ChangeToMode command processing to common layer
1 parent 0e0ee4e commit 3643d79

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
@@ -38,6 +38,8 @@
3838
#include <app/clusters/mode-base-server/mode-base-cluster-objects.h>
3939
#include <app/clusters/on-off-server/on-off-server.h>
4040
#include <lib/core/DataModelTypes.h>
41+
#include <lib/support/TypeTraits.h>
42+
#include <platform/CHIPDeviceLayer.h>
4143

4244
class OvenManager
4345
{
@@ -66,8 +68,8 @@ class OvenManager
6668
kCookSurfaceState_NoAction,
6769
} State;
6870

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

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

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

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

Lines changed: 41 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -173,16 +173,15 @@ void OvenManager::OnOffAttributeChangeHandler(EndpointId endpointId, AttributeId
173173
switch (endpointId)
174174
{
175175
case kCookTopEndpoint:
176-
InitiateAction(AppEvent::kEventType_CookTop, *value ? OvenManager::ON_ACTION : OvenManager::OFF_ACTION, value);
176+
InitiateAction(AppEvent::kEventType_CookTop, *value ? OvenManager::ON_ACTION : OvenManager::OFF_ACTION, value, kCookTopEndpoint);
177177
// Update CookSurface states accordingly
178178
mCookSurfaceEndpoint1.SetOnOffState(*value);
179179
mCookSurfaceEndpoint2.SetOnOffState(*value);
180180
break;
181181
case kCookSurfaceEndpoint1:
182182
case kCookSurfaceEndpoint2:
183183
// Handle On/Off attribute changes for the cook surface endpoints
184-
InitiateCookSurfaceAction(AppEvent::kEventType_CookSurface, *value ? OvenManager::ON_ACTION : OvenManager::OFF_ACTION,
185-
value, endpointId);
184+
InitiateAction(AppEvent::kEventType_CookSurface, *value ? OvenManager::ON_ACTION : OvenManager::OFF_ACTION, value, endpointId);
186185
{
187186
bool cookSurfaceEndpoint1State;
188187
bool cookSurfaceEndpoint2State;
@@ -215,84 +214,75 @@ void OvenManager::SetCallbacks(Callback_fn_initiated aActionInitiated_CB, Callba
215214
mActionCompleted_CB = aActionCompleted_CB;
216215
}
217216

218-
bool OvenManager::InitiateAction(int32_t aActor, Action_t aAction, uint8_t * aValue)
217+
bool OvenManager::InitiateAction(int32_t aActor, Action_t aAction, uint8_t * aValue, chip::EndpointId endpointId)
219218
{
220219
bool action_initiated = false;
221220
State_t new_state;
221+
State_t * currentState = nullptr;
222+
uint8_t eventType;
222223

223-
// Initiate Turn On/Off Action only when the previous one is complete.
224-
if (mCookTopState == kCookTopState_OffCompleted && aAction == ON_ACTION)
225-
{
226-
action_initiated = true;
227-
new_state = kCookTopState_OnInitiated;
228-
}
229-
else if (mCookTopState == kCookTopState_OnCompleted && aAction == OFF_ACTION)
230-
{
231-
action_initiated = true;
232-
new_state = kCookTopState_OffInitiated;
233-
}
234-
235-
if (action_initiated && (aAction == ON_ACTION || aAction == OFF_ACTION))
224+
// Determine which state to manage based on endpoint
225+
if (endpointId == kCookTopEndpoint)
236226
{
237-
mCookTopState = new_state;
238-
239-
AppEvent event;
240-
event.Type = AppEvent::kEventType_CookTop;
241-
event.OvenEvent.Context = this;
242-
event.Handler = ActuatorMovementHandler;
243-
AppTask::GetAppTask().PostEvent(&event);
227+
currentState = &mCookTopState;
228+
eventType = AppEvent::kEventType_CookTop;
244229
}
245-
246-
if (action_initiated && mActionInitiated_CB)
247-
{
248-
mActionInitiated_CB(aAction, aActor, aValue);
249-
}
250-
251-
return action_initiated;
252-
}
253-
254-
bool OvenManager::InitiateCookSurfaceAction(int32_t aActor, Action_t aAction, uint8_t * aValue, chip::EndpointId endpointId)
255-
{
256-
bool action_initiated = false;
257-
State_t new_state;
258-
State_t * currentState = nullptr;
259-
260-
// Get the appropriate state pointer based on endpoint
261-
if (endpointId == kCookSurfaceEndpoint1)
230+
else if (endpointId == kCookSurfaceEndpoint1)
262231
{
263232
currentState = &mCookSurfaceState1;
233+
eventType = AppEvent::kEventType_CookSurface;
264234
}
265235
else if (endpointId == kCookSurfaceEndpoint2)
266236
{
267237
currentState = &mCookSurfaceState2;
238+
eventType = AppEvent::kEventType_CookSurface;
268239
}
269240
else
270241
{
271242
return false; // Invalid endpoint
272243
}
273244

274-
// Initiate Turn On/Off Action only when the previous one is complete.
275-
if (*currentState == kCookSurfaceState_OffCompleted && aAction == ON_ACTION)
245+
// Determine the appropriate state transitions based on endpoint type
246+
if (endpointId == kCookTopEndpoint)
276247
{
277-
action_initiated = true;
278-
new_state = kCookSurfaceState_OnInitiated;
248+
// CookTop state transitions
249+
if (*currentState == kCookTopState_OffCompleted && aAction == ON_ACTION)
250+
{
251+
action_initiated = true;
252+
new_state = kCookTopState_OnInitiated;
253+
}
254+
else if (*currentState == kCookTopState_OnCompleted && aAction == OFF_ACTION)
255+
{
256+
action_initiated = true;
257+
new_state = kCookTopState_OffInitiated;
258+
}
279259
}
280-
else if (*currentState == kCookSurfaceState_OnCompleted && aAction == OFF_ACTION)
260+
else
281261
{
282-
action_initiated = true;
283-
new_state = kCookSurfaceState_OffInitiated;
262+
// CookSurface state transitions
263+
if (*currentState == kCookSurfaceState_OffCompleted && aAction == ON_ACTION)
264+
{
265+
action_initiated = true;
266+
new_state = kCookSurfaceState_OnInitiated;
267+
}
268+
else if (*currentState == kCookSurfaceState_OnCompleted && aAction == OFF_ACTION)
269+
{
270+
action_initiated = true;
271+
new_state = kCookSurfaceState_OffInitiated;
272+
}
284273
}
285274

286275
if (action_initiated && (aAction == ON_ACTION || aAction == OFF_ACTION))
287276
{
288277
*currentState = new_state;
289278

290279
AppEvent event;
291-
event.Type = AppEvent::kEventType_CookSurface;
280+
event.Type = eventType;
292281
event.OvenEvent.Context = this;
293282
event.OvenEvent.Action = aAction;
294283
event.OvenEvent.Actor = endpointId; // Store endpoint ID in Actor field
295-
event.Handler = ActuatorMovementHandler;
284+
event.Handler = ActuatorMovementHandler;
285+
296286
AppTask::GetAppTask().PostEvent(&event);
297287
}
298288

@@ -370,26 +360,7 @@ void OvenManager::ActuatorMovementHandler(AppEvent * aEvent)
370360
}
371361
}
372362

373-
// ---------------- Oven Mode Handling ----------------
374-
375-
namespace {
376-
struct BlockedTransition
377-
{
378-
uint8_t fromMode;
379-
uint8_t toMode;
380-
};
381-
382-
// Disallowed OvenMode Transitions.
383-
static constexpr BlockedTransition kBlockedTransitions[] = {
384-
{ to_underlying(TemperatureControlledCabinet::OvenModeDelegate::OvenModes::kModeGrill),
385-
to_underlying(TemperatureControlledCabinet::OvenModeDelegate::OvenModes::kModeProofing) },
386-
{ to_underlying(TemperatureControlledCabinet::OvenModeDelegate::OvenModes::kModeProofing),
387-
to_underlying(TemperatureControlledCabinet::OvenModeDelegate::OvenModes::kModeClean) },
388-
{ to_underlying(TemperatureControlledCabinet::OvenModeDelegate::OvenModes::kModeClean),
389-
to_underlying(TemperatureControlledCabinet::OvenModeDelegate::OvenModes::kModeBake) },
390-
};
391-
392-
static bool IsTransitionBlocked(uint8_t fromMode, uint8_t toMode)
363+
bool OvenManager::IsTransitionBlocked(uint8_t fromMode, uint8_t toMode)
393364
{
394365
for (auto const & bt : kBlockedTransitions)
395366
{
@@ -400,58 +371,3 @@ static bool IsTransitionBlocked(uint8_t fromMode, uint8_t toMode)
400371
}
401372
return false;
402373
}
403-
} // namespace
404-
405-
void OvenManager::ProcessOvenModeChange(chip::EndpointId endpointId, uint8_t newMode,
406-
chip::app::Clusters::ModeBase::Commands::ChangeToModeResponse::Type & response)
407-
{
408-
using namespace chip::app::Clusters;
409-
using chip::Protocols::InteractionModel::Status;
410-
ChipLogProgress(AppServer, "OvenManager::ProcessOvenModeChange ep=%u newMode=%u", endpointId, newMode);
411-
412-
// Verify newMode is among supported modes
413-
bool supported = mTemperatureControlledCabinetEndpoint.GetOvenModeDelegate().IsSupportedMode(newMode);
414-
if (!supported)
415-
{
416-
response.status = to_underlying(ModeBase::StatusCode::kUnsupportedMode);
417-
return;
418-
}
419-
420-
// Read Current Oven Mode
421-
uint8_t currentMode;
422-
Status attrStatus = OvenMode::Attributes::CurrentMode::Get(endpointId, &currentMode);
423-
if (attrStatus != Status::Success)
424-
{
425-
ChipLogError(AppServer, "OvenManager: Failed to read CurrentMode");
426-
response.status = to_underlying(ModeBase::StatusCode::kGenericFailure);
427-
response.statusText.SetValue(CharSpan::fromCharString("Read CurrentMode failed"));
428-
return;
429-
}
430-
431-
// No action needed if current mode is the same as new mode
432-
if (currentMode == newMode)
433-
{
434-
response.status = to_underlying(ModeBase::StatusCode::kSuccess);
435-
return;
436-
}
437-
438-
// Check if the mode transition is possible
439-
if (IsTransitionBlocked(currentMode, newMode))
440-
{
441-
ChipLogProgress(AppServer, "OvenManager: Blocked transition %u -> %u", currentMode, newMode);
442-
response.status = to_underlying(ModeBase::StatusCode::kGenericFailure);
443-
response.statusText.SetValue(CharSpan::fromCharString("Transition blocked"));
444-
return;
445-
}
446-
447-
// Write new mode
448-
Status writeStatus = OvenMode::Attributes::CurrentMode::Set(endpointId, newMode);
449-
if (writeStatus != Status::Success)
450-
{
451-
ChipLogError(AppServer, "OvenManager: Failed to write CurrentMode");
452-
response.status = to_underlying(ModeBase::StatusCode::kGenericFailure);
453-
response.statusText.SetValue(CharSpan::fromCharString("Write CurrentMode failed"));
454-
return;
455-
}
456-
response.status = to_underlying(ModeBase::StatusCode::kSuccess);
457-
}

0 commit comments

Comments
 (0)