Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / examples / lighting-app / k32w / main / LightingManager.cpp
1 /*
2  *
3  *    Copyright (c) 2021 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 "AppTask.h"
23 #include "FreeRTOS.h"
24
25 #include "app_config.h"
26
27 LightingManager LightingManager::sLight;
28
29 TimerHandle_t sLightTimer; // FreeRTOS app sw timer.
30
31 int LightingManager::Init()
32 {
33     int err = CHIP_NO_ERROR;
34
35     // Create FreeRTOS sw timer for light timer.
36
37     sLightTimer = xTimerCreate("LightTmr",       // Just a text name, not used by the RTOS kernel
38                                1,                // == default timer period (mS)
39                                false,            // no timer reload (==one-shot)
40                                (void *) this,    // init timer id = light obj context
41                                TimerEventHandler // timer callback handler
42     );
43
44     if (sLightTimer == NULL)
45     {
46         K32W_LOG("light timer create failed");
47         assert(0);
48     }
49
50     mState                = kState_TurnOffCompleted;
51     mAutoTurnOnTimerArmed = false;
52     mAutoTurnOn           = false;
53     mAutoTurnOnDuration   = 0;
54
55     return err;
56 }
57
58 void LightingManager::SetCallbacks(Callback_fn_initiated aActionInitiated_CB, Callback_fn_completed aActionCompleted_CB)
59 {
60     mActionInitiated_CB = aActionInitiated_CB;
61     mActionCompleted_CB = aActionCompleted_CB;
62 }
63
64 bool LightingManager::IsActionInProgress()
65 {
66     return (mState == kState_TurnOnInitiated || mState == kState_TurnOffInitiated) ? true : false;
67 }
68
69 bool LightingManager::IsTurnedOff()
70 {
71     return (mState == kState_TurnOffCompleted) ? true : false;
72 }
73
74 void LightingManager::EnableAutoTurnOn(bool aOn)
75 {
76     mAutoTurnOn = aOn;
77 }
78
79 void LightingManager::SetAutoTurnOnDuration(uint32_t aDurationInSecs)
80 {
81     mAutoTurnOnDuration = aDurationInSecs;
82 }
83
84 bool LightingManager::InitiateAction(int32_t aActor, Action_t aAction)
85 {
86     bool action_initiated = false;
87     State_t new_state;
88
89     // Initiate ON/OFF Action only when the previous one is complete.
90     if (mState == kState_TurnOnCompleted && aAction == TURNOFF_ACTION)
91     {
92         action_initiated = true;
93
94         new_state = kState_TurnOffInitiated;
95     }
96     else if (mState == kState_TurnOffCompleted && aAction == TURNON_ACTION)
97     {
98         action_initiated = true;
99
100         new_state = kState_TurnOnInitiated;
101     }
102
103     if (action_initiated)
104     {
105         if (mAutoTurnOnTimerArmed && new_state == kState_TurnOnInitiated)
106         {
107             // If auto turnon timer has been armed and someone initiates turn on the ligth,
108             // cancel the timer and continue as normal.
109             mAutoTurnOnTimerArmed = false;
110
111             CancelTimer();
112         }
113
114         StartTimer(ACTUATOR_MOVEMENT_PERIOS_MS);
115
116         // Since the timer started successfully, update the state and trigger callback
117         mState = new_state;
118
119         if (mActionInitiated_CB)
120         {
121             mActionInitiated_CB(aAction, aActor);
122         }
123     }
124
125     return action_initiated;
126 }
127
128 void LightingManager::StartTimer(uint32_t aTimeoutMs)
129 {
130     if (xTimerIsTimerActive(sLightTimer))
131     {
132         K32W_LOG("light timer already started!");
133         // appError(err);
134         CancelTimer();
135     }
136
137     // timer is not active, change its period to required value.
138     // This also causes the timer to start.  FreeRTOS- Block for a maximum of
139     // 100 ticks if the  change period command cannot immediately be sent to the
140     // timer command queue.
141     if (xTimerChangePeriod(sLightTimer, aTimeoutMs / portTICK_PERIOD_MS, 100) != pdPASS)
142     {
143         K32W_LOG("light timer start() failed");
144         // appError(err);
145     }
146 }
147
148 void LightingManager::CancelTimer(void)
149 {
150     if (xTimerStop(sLightTimer, 0) == pdFAIL)
151     {
152         K32W_LOG("light timer stop() failed");
153         // appError(err);
154     }
155 }
156
157 void LightingManager::TimerEventHandler(TimerHandle_t xTimer)
158 {
159     // Get light obj context from timer id.
160     LightingManager * light = static_cast<LightingManager *>(pvTimerGetTimerID(xTimer));
161
162     // The timer event handler will be called in the context of the timer task
163     // once sLightTimer expires. Post an event to apptask queue with the actual handler
164     // so that the event can be handled in the context of the apptask.
165     AppEvent event;
166     event.Type               = AppEvent::kEventType_Timer;
167     event.TimerEvent.Context = light;
168
169     if (light->mAutoTurnOnTimerArmed)
170     {
171         event.Handler = AutoReTurnOnTimerEventHandler;
172         GetAppTask().PostEvent(&event);
173     }
174     else
175     {
176         event.Handler = ActuatorMovementTimerEventHandler;
177         GetAppTask().PostEvent(&event);
178     }
179 }
180
181 void LightingManager::AutoReTurnOnTimerEventHandler(AppEvent * aEvent)
182 {
183     LightingManager * light = static_cast<LightingManager *>(aEvent->TimerEvent.Context);
184     int32_t actor           = 0;
185
186     // Make sure auto light timer is still armed.
187     if (!light->mAutoTurnOnTimerArmed)
188     {
189         return;
190     }
191
192     light->mAutoTurnOnTimerArmed = false;
193
194     K32W_LOG("Auto Turn On has been triggered!");
195
196     light->InitiateAction(actor, TURNON_ACTION);
197 }
198
199 void LightingManager::ActuatorMovementTimerEventHandler(AppEvent * aEvent)
200 {
201     Action_t actionCompleted = INVALID_ACTION;
202
203     LightingManager * light = static_cast<LightingManager *>(aEvent->TimerEvent.Context);
204
205     if (light->mState == kState_TurnOnInitiated)
206     {
207         light->mState   = kState_TurnOnCompleted;
208         actionCompleted = TURNON_ACTION;
209     }
210     else if (light->mState == kState_TurnOffInitiated)
211     {
212         light->mState   = kState_TurnOffCompleted;
213         actionCompleted = TURNOFF_ACTION;
214     }
215
216     if (actionCompleted != INVALID_ACTION)
217     {
218         if (light->mActionCompleted_CB)
219         {
220             light->mActionCompleted_CB(actionCompleted);
221         }
222
223         if (light->mAutoTurnOn && actionCompleted == TURNOFF_ACTION)
224         {
225             // Start the timer for auto turn on
226             light->StartTimer(light->mAutoTurnOnDuration * 1000);
227
228             light->mAutoTurnOnTimerArmed = true;
229
230             K32W_LOG("Auto Turn On enabled. Will be triggered in %u seconds", light->mAutoTurnOnDuration);
231         }
232     }
233 }