Skip to content

Commit 4e25100

Browse files
Add clusters handlers
1 parent 0716a33 commit 4e25100

File tree

4 files changed

+713
-0
lines changed

4 files changed

+713
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,370 @@
1+
/*
2+
* Copyright (c) 2024 Project CHIP Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#include "energy-calendar-server.h"
18+
19+
#include <app/AttributeAccessInterface.h>
20+
#include <app/AttributeAccessInterfaceRegistry.h>
21+
#include <app/ConcreteAttributePath.h>
22+
#include <app/InteractionModelEngine.h>
23+
#include <app/util/attribute-storage.h>
24+
#include <ThreadStackManager.h>
25+
26+
using namespace chip;
27+
using namespace chip::app;
28+
using namespace chip::app::DataModel;
29+
using namespace chip::app::Clusters;
30+
using namespace chip::app::Clusters::EnergyCalendar;
31+
using namespace chip::app::Clusters::EnergyCalendar::Attributes;
32+
using chip::Protocols::InteractionModel::Status;
33+
34+
namespace chip {
35+
namespace app {
36+
namespace Clusters {
37+
namespace EnergyCalendar {
38+
39+
constexpr uint32_t kSecInOneDay = 60*60*24;
40+
41+
static TransitionDayOfWeekBitmap GetWeekDate(uint32_t date)
42+
{
43+
tm calendarTime{};
44+
time_t tm = date;
45+
localtime_r(&tm, &calendarTime);
46+
return (TransitionDayOfWeekBitmap)(calendarTime.tm_wday);
47+
}
48+
49+
static uint32_t GetCurrentTime(void)
50+
{
51+
System::Clock::Timestamp time = System::SystemClock().GetMonotonicTimestamp();
52+
using cast = std::chrono::duration<std::uint64_t>;
53+
uint64_t msec = std::chrono::duration_cast< cast >(time).count();
54+
55+
uint32_t sec = (msec / 1000) % kSecInOneDay;
56+
return sec;
57+
}
58+
59+
void LockThreadTask(void)
60+
{
61+
chip::DeviceLayer::ThreadStackMgr().LockThreadStack();
62+
}
63+
64+
void UnlockThreadTask(void)
65+
{
66+
chip::DeviceLayer::ThreadStackMgr().UnlockThreadStack();
67+
}
68+
69+
Status CalendarProvider::SetCommonAttributes(DataModel::Nullable<uint32_t> CalendarID,
70+
DataModel::Nullable<std::string> Name,
71+
DataModel::Nullable<uint32_t> ProviderID,
72+
DataModel::Nullable<uint32_t> EventID)
73+
{
74+
bool change;
75+
76+
change = calendarID != CalendarID;
77+
if (change)
78+
{
79+
calendarID.SetNonNull(*CalendarID);
80+
//MatterReportingAttributeChangeCallback(_endpoint, EnergyCalendar::Id, CalendarID::Id);
81+
}
82+
83+
change = Name != name;
84+
if (change)
85+
{
86+
name.SetNonNull(*Name);
87+
//MatterReportingAttributeChangeCallback(_endpoint, EnergyCalendar::Id, Name::Id);
88+
}
89+
90+
change = ProviderID != providerID;
91+
if (change)
92+
{
93+
providerID.SetNonNull(*ProviderID);
94+
//MatterReportingAttributeChangeCallback(_endpoint, EnergyCalendar::Id, ProviderID::Id);
95+
}
96+
97+
change = EventID != eventID;
98+
if (change)
99+
{
100+
eventID.SetNonNull(*EventID);
101+
//MatterReportingAttributeChangeCallback(_endpoint, EnergyCalendar::Id, EventID::Id);
102+
}
103+
104+
return Status::Success;
105+
}
106+
107+
Status CalendarProvider::SetCalendarPeriod(DataModel::Nullable<uint32_t> StartDate,
108+
DataModel::DecodableList<Structs::CalendarPeriodStruct::Type> CalendarPeriods)
109+
{
110+
bool change;
111+
112+
LockThreadTask();
113+
114+
change = StartDate != startDate;
115+
if (change)
116+
{
117+
startDate.SetNonNull(*StartDate);
118+
//MatterReportingAttributeChangeCallback(_endpoint, EnergyCalendar::Id, StartDate::Id);
119+
}
120+
121+
calendarPeriods = CalendarPeriods;
122+
//MatterReportingAttributeChangeCallback(_endpoint, EnergyCalendar::Id, CalendarPeriods::Id);
123+
124+
UnlockThreadTask();
125+
return Status::Success;
126+
}
127+
128+
Status CalendarProvider::SetSpecialDays(DataModel::DecodableList<Structs::DayStruct::Type> SpecialDays)
129+
{
130+
LockThreadTask();
131+
132+
specialDays = SpecialDays;
133+
//MatterReportingAttributeChangeCallback(_endpoint, EnergyCalendar::Id, SpecialDays::Id);
134+
135+
UnlockThreadTask();
136+
return Status::Success;
137+
}
138+
139+
Status CalendarProvider::SetCurrentAndNextDays(
140+
DataModel::Nullable<Structs::DayStruct::Type> &CurrentDay,
141+
DataModel::Nullable<Structs::DayStruct::Type> &NextDay)
142+
{
143+
bool change;
144+
145+
LockThreadTask();
146+
147+
change = CurrentDay != currentDay;
148+
if (change)
149+
{
150+
currentDay.SetNonNull(*CurrentDay);
151+
//MatterReportingAttributeChangeCallback(_endpoint, EnergyCalendar::Id, CurrentDay::Id);
152+
}
153+
154+
change = NextDay != nextDay;
155+
if (change)
156+
{
157+
nextDay.SetNonNull(*NextDay);
158+
//MatterReportingAttributeChangeCallback(_endpoint, EnergyCalendar::Id, NextDay::Id);
159+
}
160+
161+
UnlockThreadTask();
162+
return Status::Success;
163+
}
164+
165+
Status CalendarProvider::SetPeakPeriods(
166+
DataModel::Nullable<Structs::PeakPeriodStruct::Type> &CurrentPeakPeriod,
167+
DataModel::Nullable<Structs::PeakPeriodStruct::Type> &NextPeakPeriod)
168+
{
169+
bool change;
170+
LockThreadTask();
171+
172+
change = CurrentPeakPeriod != currentPeakPeriod;
173+
if (change)
174+
{
175+
currentPeakPeriod.SetNonNull(*CurrentPeakPeriod);
176+
//MatterReportingAttributeChangeCallback(_endpoint, EnergyCalendar::Id, CurrentPeakPeriod::Id);
177+
}
178+
179+
change = NextPeakPeriod != nextPeakPeriod;
180+
if (change)
181+
{
182+
nextPeakPeriod.SetNonNull(*NextPeakPeriod);
183+
//MatterReportingAttributeChangeCallback(_endpoint, EnergyCalendar::Id, NextPeakPeriod::Id);
184+
}
185+
186+
UnlockThreadTask();
187+
return Status::Success;
188+
}
189+
190+
Status CalendarProvider::UpdateDays(void)
191+
{
192+
Status status;
193+
DataModel::Nullable<Structs::DayStruct::Type> currentDay;
194+
DataModel::Nullable<Structs::DayStruct::Type> nextDay;
195+
196+
status = GetDays(_endpoint, currentDay, nextDay);
197+
if (status == Status::Success)
198+
{
199+
status = SetCurrentAndNextDays(currentDay, nextDay);
200+
}
201+
202+
return status;
203+
}
204+
205+
206+
EnergyCalendarServer::EnergyCalendarServer() :
207+
AttributeAccessInterface(NullOptional, EnergyCalendar::Id), feature(0), calendars({nullptr})
208+
{
209+
uint32_t time = GetCurrentTime();
210+
211+
chip::DeviceLayer::SystemLayer().StartTimer(chip::System::Clock::Seconds16(kSecInOneDay - time), MidnightTimerCallback, this);
212+
}
213+
214+
EnergyCalendarServer::EnergyCalendarServer(Feature aFeature) :
215+
AttributeAccessInterface(NullOptional, EnergyCalendar::Id), feature(aFeature), calendars({nullptr})
216+
{
217+
uint32_t time = GetCurrentTime();
218+
219+
chip::DeviceLayer::SystemLayer().StartTimer(chip::System::Clock::Seconds16(kSecInOneDay - time), MidnightTimerCallback, this);
220+
}
221+
222+
bool EnergyCalendarServer::HasFeature(Feature aFeature) const
223+
{
224+
return feature.Has(aFeature);
225+
}
226+
227+
Status EnergyCalendarServer::AddCalendarProvider(CalendarProvider *provider)
228+
{
229+
for (int i = 0; i < kNumSupportedEndpoints; ++i)
230+
{
231+
if (calendars[i] == nullptr)
232+
{
233+
calendars[i] = provider;
234+
return Status::Success;
235+
}
236+
}
237+
return Status::ResourceExhausted;
238+
}
239+
240+
CalendarProvider *EnergyCalendarServer::GetProvider(EndpointId ep)
241+
{
242+
for (int i = 0; i < kNumSupportedEndpoints; ++i)
243+
{
244+
if (calendars[i] != nullptr && calendars[i]->endpoint() == ep)
245+
{
246+
return calendars[i];
247+
}
248+
}
249+
return nullptr;
250+
}
251+
252+
DataModel::Nullable<Structs::TransitionStruct::Type> EnergyCalendarServer::GetTransition(EndpointId ep)
253+
{
254+
CalendarProvider *provider = GetProvider(ep);
255+
if (provider == nullptr || provider->GetCurrentDay().IsNull())
256+
{
257+
return DataModel::Nullable<Structs::TransitionStruct::Type>();
258+
}
259+
260+
Structs::DayStruct::Type & currentDay = provider->GetCurrentDay().Value();
261+
262+
uint32_t time = GetCurrentTime();
263+
264+
auto transition = currentDay.transitions.begin();
265+
uint32_t next_tr_time = kSecInOneDay;
266+
267+
const Structs::TransitionStruct::Type *current = nullptr;
268+
269+
while(transition != currentDay.transitions.end())
270+
{
271+
auto tr_time = transition->transitionTime;
272+
if (tr_time <= time && (current == nullptr || current->transitionTime < tr_time))
273+
{
274+
current = transition;
275+
}
276+
if ((time > tr_time) && (time < next_tr_time))
277+
{
278+
next_tr_time = time;
279+
}
280+
}
281+
return DataModel::Nullable<Structs::TransitionStruct::Type>(*current);
282+
}
283+
284+
// AttributeAccessInterface
285+
CHIP_ERROR EnergyCalendarServer::Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder)
286+
{
287+
CalendarProvider *provider = GetProvider(aPath.mEndpointId);
288+
switch (aPath.mAttributeId)
289+
{
290+
case CalendarID::Id:
291+
return aEncoder.Encode(provider->GetCalendarID());
292+
case Name::Id:
293+
return aEncoder.Encode(provider->GetName());
294+
case ProviderID::Id:
295+
return aEncoder.Encode(provider->GetProviderID());
296+
case EventID::Id:
297+
return aEncoder.Encode(provider->GetEventID());
298+
case StartDate::Id:
299+
return aEncoder.Encode(provider->GetStartDate());
300+
case CalendarPeriods::Id:
301+
return aEncoder.Encode(provider->GetCalendarPeriods());
302+
case SpecialDays::Id:
303+
return aEncoder.Encode(provider->GetSpecialDays());
304+
/* Date relative attributes */
305+
case CurrentDay::Id:
306+
return aEncoder.Encode(provider->GetCurrentDay());
307+
case NextDay::Id:
308+
return aEncoder.Encode(provider->GetNextDay());
309+
case CurrentTransition::Id:
310+
return aEncoder.Encode(GetTransition(aPath.mEndpointId));
311+
case CurrentPeakPeriod::Id:
312+
return aEncoder.Encode(provider->GetCurrentPeakPeriod());
313+
case NextPeakPeriod::Id:
314+
return aEncoder.Encode(provider->GetNextPeakPeriod());
315+
/* FeatureMap - is held locally */
316+
case FeatureMap::Id:
317+
return aEncoder.Encode(feature);
318+
}
319+
320+
/* Allow all other unhandled attributes to fall through to Ember */
321+
return CHIP_NO_ERROR;
322+
}
323+
324+
CHIP_ERROR EnergyCalendarServer::Write(const ConcreteDataAttributePath & aPath, AttributeValueDecoder & aDecoder)
325+
{
326+
switch (aPath.mAttributeId)
327+
{
328+
default:
329+
// Unknown attribute; return error. None of the other attributes for
330+
// this cluster are writable, so should not be ending up in this code to
331+
// start with.
332+
return CHIP_IM_GLOBAL_STATUS(UnsupportedAttribute);
333+
}
334+
}
335+
336+
//void EnergyCalendarServer::InvokeCommand(HandlerContext & handlerContext)
337+
//{
338+
// //using namespace Commands;
339+
//
340+
// //switch (handlerContext.mRequestPath.mCommandId)
341+
// //{
342+
// //}
343+
// return;
344+
//}
345+
346+
void EnergyCalendarServer::MidnightTimerCallback(chip::System::Layer *, void * callbackContext)
347+
{
348+
EnergyCalendarServer *instance = (EnergyCalendarServer*)callbackContext;
349+
350+
for (int i = 0; i < kNumSupportedEndpoints; ++i)
351+
{
352+
if (instance->calendars[i] != nullptr)
353+
{
354+
instance->calendars[i]->UpdateDays();
355+
}
356+
}
357+
358+
uint32_t time = GetCurrentTime();
359+
chip::DeviceLayer::SystemLayer().StartTimer(chip::System::Clock::Seconds16(kSecInOneDay - time), MidnightTimerCallback, callbackContext);
360+
}
361+
362+
} // namespace EnergyCalendar
363+
} // namespace Clusters
364+
} // namespace app
365+
} // namespace chip
366+
367+
// -----------------------------------------------------------------------------
368+
// Plugin initialization
369+
370+
void MatterEnergyCalendarPluginServerInitCallback() {}

0 commit comments

Comments
 (0)