Skip to content

Commit 0aa2442

Browse files
authored
Add OperationalState to chef examples (project-chip#32495)
1 parent c554f44 commit 0aa2442

File tree

4 files changed

+368
-0
lines changed

4 files changed

+368
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
/*
2+
* Copyright (c) 2023 Project CHIP Authors
3+
* All rights reserved.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
#include <chef-operational-state-delegate-impl.h>
18+
#include <platform/CHIPDeviceLayer.h>
19+
20+
using namespace chip;
21+
using namespace chip::app;
22+
using namespace chip::app::Clusters;
23+
using namespace chip::app::Clusters::OperationalState;
24+
using namespace chip::app::Clusters::RvcOperationalState;
25+
26+
static void onOperationalStateTimerTick(System::Layer * systemLayer, void * data);
27+
28+
DataModel::Nullable<uint32_t> GenericOperationalStateDelegateImpl::GetCountdownTime()
29+
{
30+
if (mCountDownTime.IsNull())
31+
return DataModel::NullNullable;
32+
33+
return DataModel::MakeNullable((uint32_t) (mCountDownTime.Value() - mRunningTime));
34+
}
35+
36+
CHIP_ERROR GenericOperationalStateDelegateImpl::GetOperationalStateAtIndex(size_t index, GenericOperationalState & operationalState)
37+
{
38+
if (index >= mOperationalStateList.size())
39+
{
40+
return CHIP_ERROR_NOT_FOUND;
41+
}
42+
operationalState = mOperationalStateList[index];
43+
return CHIP_NO_ERROR;
44+
}
45+
46+
CHIP_ERROR GenericOperationalStateDelegateImpl::GetOperationalPhaseAtIndex(size_t index, MutableCharSpan & operationalPhase)
47+
{
48+
if (index >= mOperationalPhaseList.size())
49+
{
50+
return CHIP_ERROR_NOT_FOUND;
51+
}
52+
return CopyCharSpanToMutableCharSpan(mOperationalPhaseList[index], operationalPhase);
53+
}
54+
55+
void GenericOperationalStateDelegateImpl::HandlePauseStateCallback(GenericOperationalError & err)
56+
{
57+
OperationalState::OperationalStateEnum state =
58+
static_cast<OperationalState::OperationalStateEnum>(GetInstance()->GetCurrentOperationalState());
59+
60+
if (state == OperationalState::OperationalStateEnum::kStopped || state == OperationalState::OperationalStateEnum::kError)
61+
{
62+
err.Set(to_underlying(OperationalState::ErrorStateEnum::kCommandInvalidInState));
63+
return;
64+
}
65+
66+
// placeholder implementation
67+
auto error = GetInstance()->SetOperationalState(to_underlying(OperationalState::OperationalStateEnum::kPaused));
68+
if (error == CHIP_NO_ERROR)
69+
{
70+
err.Set(to_underlying(ErrorStateEnum::kNoError));
71+
}
72+
else
73+
{
74+
err.Set(to_underlying(ErrorStateEnum::kUnableToCompleteOperation));
75+
}
76+
}
77+
78+
void GenericOperationalStateDelegateImpl::HandleResumeStateCallback(GenericOperationalError & err)
79+
{
80+
OperationalState::OperationalStateEnum state =
81+
static_cast<OperationalState::OperationalStateEnum>(GetInstance()->GetCurrentOperationalState());
82+
83+
if (state == OperationalState::OperationalStateEnum::kStopped || state == OperationalState::OperationalStateEnum::kError)
84+
{
85+
err.Set(to_underlying(OperationalState::ErrorStateEnum::kCommandInvalidInState));
86+
return;
87+
}
88+
89+
// placeholder implementation
90+
auto error = GetInstance()->SetOperationalState(to_underlying(OperationalStateEnum::kRunning));
91+
if (error == CHIP_NO_ERROR)
92+
{
93+
err.Set(to_underlying(ErrorStateEnum::kNoError));
94+
}
95+
else
96+
{
97+
err.Set(to_underlying(ErrorStateEnum::kUnableToCompleteOperation));
98+
}
99+
}
100+
101+
void GenericOperationalStateDelegateImpl::HandleStartStateCallback(GenericOperationalError & err)
102+
{
103+
OperationalState::GenericOperationalError current_err(to_underlying(OperationalState::ErrorStateEnum::kNoError));
104+
GetInstance()->GetCurrentOperationalError(current_err);
105+
106+
if (current_err.errorStateID != to_underlying(OperationalState::ErrorStateEnum::kNoError))
107+
{
108+
err.Set(to_underlying(OperationalState::ErrorStateEnum::kUnableToStartOrResume));
109+
return;
110+
}
111+
112+
// placeholder implementation
113+
auto error = GetInstance()->SetOperationalState(to_underlying(OperationalStateEnum::kRunning));
114+
if (error == CHIP_NO_ERROR)
115+
{
116+
(void) DeviceLayer::SystemLayer().StartTimer(System::Clock::Seconds16(1), onOperationalStateTimerTick, this);
117+
err.Set(to_underlying(ErrorStateEnum::kNoError));
118+
}
119+
else
120+
{
121+
err.Set(to_underlying(ErrorStateEnum::kUnableToCompleteOperation));
122+
}
123+
}
124+
125+
void GenericOperationalStateDelegateImpl::HandleStopStateCallback(GenericOperationalError & err)
126+
{
127+
// placeholder implementation
128+
auto error = GetInstance()->SetOperationalState(to_underlying(OperationalStateEnum::kStopped));
129+
if (error == CHIP_NO_ERROR)
130+
{
131+
(void) DeviceLayer::SystemLayer().CancelTimer(onOperationalStateTimerTick, this);
132+
133+
OperationalState::GenericOperationalError current_err(to_underlying(OperationalState::ErrorStateEnum::kNoError));
134+
GetInstance()->GetCurrentOperationalError(current_err);
135+
136+
Optional<DataModel::Nullable<uint32_t>> totalTime((DataModel::Nullable<uint32_t>(mRunningTime + mPausedTime)));
137+
Optional<DataModel::Nullable<uint32_t>> pausedTime((DataModel::Nullable<uint32_t>(mPausedTime)));
138+
139+
GetInstance()->OnOperationCompletionDetected(static_cast<uint8_t>(current_err.errorStateID), totalTime, pausedTime);
140+
141+
mRunningTime = 0;
142+
mPausedTime = 0;
143+
err.Set(to_underlying(ErrorStateEnum::kNoError));
144+
}
145+
else
146+
{
147+
err.Set(to_underlying(ErrorStateEnum::kUnableToCompleteOperation));
148+
}
149+
}
150+
151+
static void onOperationalStateTimerTick(System::Layer * systemLayer, void * data)
152+
{
153+
GenericOperationalStateDelegateImpl * delegate = reinterpret_cast<GenericOperationalStateDelegateImpl *>(data);
154+
155+
OperationalState::Instance * instance = OperationalState::GetOperationalStateInstance();
156+
OperationalState::OperationalStateEnum state =
157+
static_cast<OperationalState::OperationalStateEnum>(instance->GetCurrentOperationalState());
158+
159+
auto countdown_time = delegate->GetCountdownTime();
160+
161+
if (countdown_time.IsNull() || (!countdown_time.IsNull() && countdown_time.Value() > 0))
162+
{
163+
if (state == OperationalState::OperationalStateEnum::kRunning)
164+
{
165+
delegate->mRunningTime++;
166+
}
167+
else if (state == OperationalState::OperationalStateEnum::kPaused)
168+
{
169+
delegate->mPausedTime++;
170+
}
171+
}
172+
173+
if (state == OperationalState::OperationalStateEnum::kRunning || state == OperationalState::OperationalStateEnum::kPaused)
174+
{
175+
(void) DeviceLayer::SystemLayer().StartTimer(System::Clock::Seconds16(1), onOperationalStateTimerTick, delegate);
176+
}
177+
else
178+
{
179+
(void) DeviceLayer::SystemLayer().CancelTimer(onOperationalStateTimerTick, delegate);
180+
}
181+
}
182+
183+
// Init Operational State cluster
184+
185+
static OperationalState::Instance * gOperationalStateInstance = nullptr;
186+
static OperationalStateDelegate * gOperationalStateDelegate = nullptr;
187+
188+
OperationalState::Instance * OperationalState::GetOperationalStateInstance()
189+
{
190+
return gOperationalStateInstance;
191+
}
192+
193+
void OperationalState::Shutdown()
194+
{
195+
if (gOperationalStateInstance != nullptr)
196+
{
197+
delete gOperationalStateInstance;
198+
gOperationalStateInstance = nullptr;
199+
}
200+
if (gOperationalStateDelegate != nullptr)
201+
{
202+
delete gOperationalStateDelegate;
203+
gOperationalStateDelegate = nullptr;
204+
}
205+
}
206+
207+
void emberAfOperationalStateClusterInitCallback(chip::EndpointId endpointId)
208+
{
209+
VerifyOrDie(endpointId == 1); // this cluster is only enabled for endpoint 1.
210+
VerifyOrDie(gOperationalStateInstance == nullptr && gOperationalStateDelegate == nullptr);
211+
212+
gOperationalStateDelegate = new OperationalStateDelegate;
213+
EndpointId operationalStateEndpoint = 0x01;
214+
gOperationalStateInstance = new OperationalState::Instance(gOperationalStateDelegate, operationalStateEndpoint);
215+
216+
gOperationalStateInstance->SetOperationalState(to_underlying(OperationalState::OperationalStateEnum::kStopped));
217+
218+
gOperationalStateInstance->Init();
219+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
/*
2+
*
3+
* Copyright (c) 2023 Project CHIP Authors
4+
* All rights reserved.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
#pragma once
20+
21+
#include <app-common/zap-generated/cluster-objects.h>
22+
#include <app/clusters/operational-state-server/operational-state-server.h>
23+
24+
#include <protocols/interaction_model/StatusCode.h>
25+
26+
namespace chip {
27+
namespace app {
28+
namespace Clusters {
29+
30+
namespace OperationalState {
31+
32+
// This is an application level delegate to handle operational state commands according to the specific business logic.
33+
class GenericOperationalStateDelegateImpl : public Delegate
34+
{
35+
public:
36+
uint32_t mRunningTime = 0;
37+
uint32_t mPausedTime = 0;
38+
app::DataModel::Nullable<uint32_t> mCountDownTime;
39+
40+
/**
41+
* Get the countdown time. This attribute is not used in this application.
42+
* @return The current countdown time.
43+
*/
44+
app::DataModel::Nullable<uint32_t> GetCountdownTime() override;
45+
46+
/**
47+
* Fills in the provided GenericOperationalState with the state at index `index` if there is one,
48+
* or returns CHIP_ERROR_NOT_FOUND if the index is out of range for the list of states.
49+
* Note: This is used by the SDK to populate the operational state list attribute. If the contents of this list changes,
50+
* the device SHALL call the Instance's ReportOperationalStateListChange method to report that this attribute has changed.
51+
* @param index The index of the state, with 0 representing the first state.
52+
* @param operationalState The GenericOperationalState is filled.
53+
*/
54+
CHIP_ERROR GetOperationalStateAtIndex(size_t index, GenericOperationalState & operationalState) override;
55+
56+
/**
57+
* Fills in the provided MutableCharSpan with the phase at index `index` if there is one,
58+
* or returns CHIP_ERROR_NOT_FOUND if the index is out of range for the list of phases.
59+
*
60+
* If CHIP_ERROR_NOT_FOUND is returned for index 0, that indicates that the PhaseList attribute is null
61+
* (there are no phases defined at all).
62+
*
63+
* Note: This is used by the SDK to populate the phase list attribute. If the contents of this list changes, the
64+
* device SHALL call the Instance's ReportPhaseListChange method to report that this attribute has changed.
65+
* @param index The index of the phase, with 0 representing the first phase.
66+
* @param operationalPhase The MutableCharSpan is filled.
67+
*/
68+
CHIP_ERROR GetOperationalPhaseAtIndex(size_t index, MutableCharSpan & operationalPhase) override;
69+
70+
// command callback
71+
/**
72+
* Handle Command Callback in application: Pause
73+
* @param[out] get operational error after callback.
74+
*/
75+
void HandlePauseStateCallback(GenericOperationalError & err) override;
76+
77+
/**
78+
* Handle Command Callback in application: Resume
79+
* @param[out] get operational error after callback.
80+
*/
81+
void HandleResumeStateCallback(GenericOperationalError & err) override;
82+
83+
/**
84+
* Handle Command Callback in application: Start
85+
* @param[out] get operational error after callback.
86+
*/
87+
void HandleStartStateCallback(GenericOperationalError & err) override;
88+
89+
/**
90+
* Handle Command Callback in application: Stop
91+
* @param[out] get operational error after callback.
92+
*/
93+
void HandleStopStateCallback(GenericOperationalError & err) override;
94+
95+
protected:
96+
Span<const GenericOperationalState> mOperationalStateList;
97+
Span<const CharSpan> mOperationalPhaseList;
98+
};
99+
100+
// This is an application level delegate to handle operational state commands according to the specific business logic.
101+
class OperationalStateDelegate : public GenericOperationalStateDelegateImpl
102+
{
103+
private:
104+
const GenericOperationalState opStateList[4] = {
105+
GenericOperationalState(to_underlying(OperationalStateEnum::kStopped)),
106+
GenericOperationalState(to_underlying(OperationalStateEnum::kRunning)),
107+
GenericOperationalState(to_underlying(OperationalStateEnum::kPaused)),
108+
GenericOperationalState(to_underlying(OperationalStateEnum::kError)),
109+
};
110+
111+
const uint32_t kExampleCountDown = 30;
112+
113+
public:
114+
OperationalStateDelegate()
115+
{
116+
GenericOperationalStateDelegateImpl::mOperationalStateList = Span<const GenericOperationalState>(opStateList);
117+
}
118+
119+
/**
120+
* Handle Command Callback in application: Start
121+
* @param[out] get operational error after callback.
122+
*/
123+
void HandleStartStateCallback(GenericOperationalError & err) override
124+
{
125+
mCountDownTime.SetNonNull(static_cast<uint32_t>(kExampleCountDown));
126+
GenericOperationalStateDelegateImpl::HandleStartStateCallback(err);
127+
}
128+
129+
/**
130+
* Handle Command Callback in application: Stop
131+
* @param[out] get operational error after callback.
132+
*/
133+
void HandleStopStateCallback(GenericOperationalError & err) override
134+
{
135+
GenericOperationalStateDelegateImpl::HandleStopStateCallback(err);
136+
mCountDownTime.SetNull();
137+
}
138+
};
139+
140+
Instance * GetOperationalStateInstance();
141+
142+
void Shutdown();
143+
144+
} // namespace OperationalState
145+
} // namespace Clusters
146+
} // namespace app
147+
} // namespace chip

examples/chef/linux/BUILD.gn

+1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ executable("${sample_name}") {
4343
"${project_dir}/common/chef-air-quality.cpp",
4444
"${project_dir}/common/chef-concentration-measurement.cpp",
4545
"${project_dir}/common/chef-fan-control-manager.cpp",
46+
"${project_dir}/common/chef-operational-state-delegate-impl.cpp",
4647
"${project_dir}/common/chef-resource-monitoring-delegates.cpp",
4748
"${project_dir}/common/chef-rvc-mode-delegate.cpp",
4849
"${project_dir}/common/chef-rvc-operational-state-delegate.cpp",

examples/chef/nrfconnect/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ target_sources(app PRIVATE
8484
${CHEF}/common/chef-air-quality.cpp
8585
${CHEF}/common/chef-concentration-measurement.cpp
8686
${CHEF}/common/chef-fan-control-manager.cpp
87+
${CHEF}/common/chef-operational-state-delegate-impl.cpp
8788
${CHEF}/common/chef-resource-monitoring-delegates.cpp
8889
${CHEF}/common/chef-rvc-mode-delegate.cpp
8990
${CHEF}/common/chef-rvc-operational-state-delegate.cpp

0 commit comments

Comments
 (0)