Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / examples / lighting-app / efr32 / src / LightingManager.cpp
1 /*
2  *
3  *    Copyright (c) 2020 Project CHIP Authors
4  *    Copyright (c) 2019 Google LLC.
5  *    All rights reserved.
6  *
7  *    Licensed under the Apache License, Version 2.0 (the "License");
8  *    you may not use this file except in compliance with the License.
9  *    You may obtain a copy of the License at
10  *
11  *        http://www.apache.org/licenses/LICENSE-2.0
12  *
13  *    Unless required by applicable law or agreed to in writing, software
14  *    distributed under the License is distributed on an "AS IS" BASIS,
15  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  *    See the License for the specific language governing permissions and
17  *    limitations under the License.
18  */
19
20 #include "LightingManager.h"
21
22 #include "AppConfig.h"
23 #include "AppTask.h"
24 #include <FreeRTOS.h>
25
26 LightingManager LightingManager::sLight;
27
28 TimerHandle_t sLightTimer;
29
30 int LightingManager::Init()
31 {
32     // Create FreeRTOS sw timer for light timer.
33     sLightTimer = xTimerCreate("lightTmr",       // Just a text name, not used by the RTOS kernel
34                                1,                // == default timer period (mS)
35                                false,            // no timer reload (==one-shot)
36                                (void *) this,    // init timer id = light obj context
37                                TimerEventHandler // timer callback handler
38     );
39
40     if (sLightTimer == NULL)
41     {
42         EFR32_LOG("sLightTimer timer create failed");
43         appError(CHIP_ERROR_MAX);
44     }
45
46     mState                 = kState_OffCompleted;
47     mAutoTurnOffTimerArmed = false;
48     mAutoTurnOff           = false;
49     mAutoTurnOffDuration   = 0;
50
51     return CHIP_NO_ERROR;
52 }
53
54 void LightingManager::SetCallbacks(Callback_fn_initiated aActionInitiated_CB, Callback_fn_completed aActionCompleted_CB)
55 {
56     mActionInitiated_CB = aActionInitiated_CB;
57     mActionCompleted_CB = aActionCompleted_CB;
58 }
59
60 bool LightingManager::IsActionInProgress()
61 {
62     return (mState == kState_OffInitiated || mState == kState_OnInitiated);
63 }
64
65 bool LightingManager::IsLightOn()
66 {
67     return (mState == kState_OnCompleted);
68 }
69
70 void LightingManager::EnableAutoTurnOff(bool aOn)
71 {
72     mAutoTurnOff = aOn;
73 }
74
75 void LightingManager::SetAutoTurnOffDuration(uint32_t aDurationInSecs)
76 {
77     mAutoTurnOffDuration = aDurationInSecs;
78 }
79
80 bool LightingManager::InitiateAction(int32_t aActor, Action_t aAction)
81 {
82     bool action_initiated = false;
83     State_t new_state;
84
85     // Initiate Turn On/Off Action only when the previous one is complete.
86     if (mState == kState_OffCompleted && aAction == ON_ACTION)
87     {
88         action_initiated = true;
89
90         new_state = kState_OnInitiated;
91     }
92     else if (mState == kState_OnCompleted && aAction == OFF_ACTION)
93     {
94         action_initiated = true;
95
96         new_state = kState_OffInitiated;
97     }
98
99     if (action_initiated)
100     {
101         if (mAutoTurnOffTimerArmed && new_state == kState_OffInitiated)
102         {
103             // If auto turn off timer has been armed and someone initiates turning off,
104             // cancel the timer and continue as normal.
105             mAutoTurnOffTimerArmed = false;
106
107             CancelTimer();
108         }
109
110         StartTimer(ACTUATOR_MOVEMENT_PERIOS_MS);
111
112         // Since the timer started successfully, update the state and trigger callback
113         mState = new_state;
114
115         if (mActionInitiated_CB)
116         {
117             mActionInitiated_CB(aAction, aActor);
118         }
119     }
120
121     return action_initiated;
122 }
123
124 void LightingManager::StartTimer(uint32_t aTimeoutMs)
125 {
126     if (xTimerIsTimerActive(sLightTimer))
127     {
128         EFR32_LOG("app timer already started!");
129         CancelTimer();
130     }
131
132     // timer is not active, change its period to required value (== restart).
133     // FreeRTOS- Block for a maximum of 100 ticks if the change period command
134     // cannot immediately be sent to the timer command queue.
135     if (xTimerChangePeriod(sLightTimer, (aTimeoutMs / portTICK_PERIOD_MS), 100) != pdPASS)
136     {
137         EFR32_LOG("sLightTimer timer start() failed");
138         appError(CHIP_ERROR_MAX);
139     }
140 }
141
142 void LightingManager::CancelTimer(void)
143 {
144     if (xTimerStop(sLightTimer, 0) == pdFAIL)
145     {
146         EFR32_LOG("sLightTimer stop() failed");
147         appError(CHIP_ERROR_MAX);
148     }
149 }
150
151 void LightingManager::TimerEventHandler(TimerHandle_t xTimer)
152 {
153     // Get light obj context from timer id.
154     LightingManager * light = static_cast<LightingManager *>(pvTimerGetTimerID(xTimer));
155
156     // The timer event handler will be called in the context of the timer task
157     // once sLightTimer expires. Post an event to apptask queue with the actual handler
158     // so that the event can be handled in the context of the apptask.
159     AppEvent event;
160     event.Type               = AppEvent::kEventType_Timer;
161     event.TimerEvent.Context = light;
162     if (light->mAutoTurnOffTimerArmed)
163     {
164         event.Handler = AutoTurnOffTimerEventHandler;
165     }
166     else
167     {
168         event.Handler = ActuatorMovementTimerEventHandler;
169     }
170     GetAppTask().PostEvent(&event);
171 }
172
173 void LightingManager::AutoTurnOffTimerEventHandler(AppEvent * aEvent)
174 {
175     LightingManager * light = static_cast<LightingManager *>(aEvent->TimerEvent.Context);
176     int32_t actor           = 0;
177
178     // Make sure auto turn off timer is still armed.
179     if (!light->mAutoTurnOffTimerArmed)
180     {
181         return;
182     }
183
184     light->mAutoTurnOffTimerArmed = false;
185
186     EFR32_LOG("Auto Turn Off has been triggered!");
187
188     light->InitiateAction(actor, OFF_ACTION);
189 }
190
191 void LightingManager::ActuatorMovementTimerEventHandler(AppEvent * aEvent)
192 {
193     Action_t actionCompleted = INVALID_ACTION;
194
195     LightingManager * light = static_cast<LightingManager *>(aEvent->TimerEvent.Context);
196
197     if (light->mState == kState_OffInitiated)
198     {
199         light->mState   = kState_OffCompleted;
200         actionCompleted = OFF_ACTION;
201     }
202     else if (light->mState == kState_OnInitiated)
203     {
204         light->mState   = kState_OnCompleted;
205         actionCompleted = ON_ACTION;
206     }
207
208     if (actionCompleted != INVALID_ACTION)
209     {
210         if (light->mActionCompleted_CB)
211         {
212             light->mActionCompleted_CB(actionCompleted);
213         }
214
215         if (light->mAutoTurnOff && actionCompleted == ON_ACTION)
216         {
217             // Start the timer for auto turn off
218             light->StartTimer(light->mAutoTurnOffDuration * 1000);
219
220             light->mAutoTurnOffTimerArmed = true;
221
222             EFR32_LOG("Auto Turn off enabled. Will be triggered in %u seconds", light->mAutoTurnOffDuration);
223         }
224     }
225 }