Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / examples / lock-app / efr32 / src / BoltLockManager.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 "BoltLockManager.h"
21
22 #include "AppConfig.h"
23 #include "AppTask.h"
24 #include <FreeRTOS.h>
25
26 BoltLockManager BoltLockManager::sLock;
27
28 TimerHandle_t sLockTimer;
29
30 int BoltLockManager::Init()
31 {
32     // Create FreeRTOS sw timer for lock timer.
33     sLockTimer = xTimerCreate("lockTmr",        // 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 = lock obj context
37                               TimerEventHandler // timer callback handler
38     );
39
40     if (sLockTimer == NULL)
41     {
42         EFR32_LOG("sLockTimer timer create failed");
43         appError(CHIP_ERROR_MAX);
44     }
45
46     mState              = kState_LockingCompleted;
47     mAutoLockTimerArmed = false;
48     mAutoRelock         = false;
49     mAutoLockDuration   = 0;
50
51     return CHIP_NO_ERROR;
52 }
53
54 void BoltLockManager::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 BoltLockManager::IsActionInProgress()
61 {
62     return (mState == kState_LockingInitiated || mState == kState_UnlockingInitiated);
63 }
64
65 bool BoltLockManager::IsUnlocked()
66 {
67     return (mState == kState_UnlockingCompleted);
68 }
69
70 void BoltLockManager::EnableAutoRelock(bool aOn)
71 {
72     mAutoRelock = aOn;
73 }
74
75 void BoltLockManager::SetAutoLockDuration(uint32_t aDurationInSecs)
76 {
77     mAutoLockDuration = aDurationInSecs;
78 }
79
80 bool BoltLockManager::InitiateAction(int32_t aActor, Action_t aAction)
81 {
82     bool action_initiated = false;
83     State_t new_state;
84
85     // Initiate Lock/Unlock Action only when the previous one is complete.
86     if (mState == kState_LockingCompleted && aAction == UNLOCK_ACTION)
87     {
88         action_initiated = true;
89
90         new_state = kState_UnlockingInitiated;
91     }
92     else if (mState == kState_UnlockingCompleted && aAction == LOCK_ACTION)
93     {
94         action_initiated = true;
95
96         new_state = kState_LockingInitiated;
97     }
98
99     if (action_initiated)
100     {
101         if (mAutoLockTimerArmed && new_state == kState_LockingInitiated)
102         {
103             // If auto lock timer has been armed and someone initiates locking,
104             // cancel the timer and continue as normal.
105             mAutoLockTimerArmed = 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 BoltLockManager::StartTimer(uint32_t aTimeoutMs)
125 {
126     if (xTimerIsTimerActive(sLockTimer))
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(sLockTimer, (aTimeoutMs / portTICK_PERIOD_MS), 100) != pdPASS)
136     {
137         EFR32_LOG("sLockTimer timer start() failed");
138         appError(CHIP_ERROR_MAX);
139     }
140 }
141
142 void BoltLockManager::CancelTimer(void)
143 {
144     if (xTimerStop(sLockTimer, 0) == pdFAIL)
145     {
146         EFR32_LOG("Lock timer timer stop() failed");
147         appError(CHIP_ERROR_MAX);
148     }
149 }
150
151 void BoltLockManager::TimerEventHandler(TimerHandle_t xTimer)
152 {
153     // Get lock obj context from timer id.
154     BoltLockManager * lock = static_cast<BoltLockManager *>(pvTimerGetTimerID(xTimer));
155
156     // The timer event handler will be called in the context of the timer task
157     // once sLockTimer 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 = lock;
162     if (lock->mAutoLockTimerArmed)
163     {
164         event.Handler = AutoReLockTimerEventHandler;
165     }
166     else
167     {
168         event.Handler = ActuatorMovementTimerEventHandler;
169     }
170     GetAppTask().PostEvent(&event);
171 }
172
173 void BoltLockManager::AutoReLockTimerEventHandler(AppEvent * aEvent)
174 {
175     BoltLockManager * lock = static_cast<BoltLockManager *>(aEvent->TimerEvent.Context);
176     int32_t actor          = 0;
177
178     // Make sure auto lock timer is still armed.
179     if (!lock->mAutoLockTimerArmed)
180     {
181         return;
182     }
183
184     lock->mAutoLockTimerArmed = false;
185
186     EFR32_LOG("Auto Re-Lock has been triggered!");
187
188     lock->InitiateAction(actor, LOCK_ACTION);
189 }
190
191 void BoltLockManager::ActuatorMovementTimerEventHandler(AppEvent * aEvent)
192 {
193     Action_t actionCompleted = INVALID_ACTION;
194
195     BoltLockManager * lock = static_cast<BoltLockManager *>(aEvent->TimerEvent.Context);
196
197     if (lock->mState == kState_LockingInitiated)
198     {
199         lock->mState    = kState_LockingCompleted;
200         actionCompleted = LOCK_ACTION;
201     }
202     else if (lock->mState == kState_UnlockingInitiated)
203     {
204         lock->mState    = kState_UnlockingCompleted;
205         actionCompleted = UNLOCK_ACTION;
206     }
207
208     if (actionCompleted != INVALID_ACTION)
209     {
210         if (lock->mActionCompleted_CB)
211         {
212             lock->mActionCompleted_CB(actionCompleted);
213         }
214
215         if (lock->mAutoRelock && actionCompleted == UNLOCK_ACTION)
216         {
217             // Start the timer for auto relock
218             lock->StartTimer(lock->mAutoLockDuration * 1000);
219
220             lock->mAutoLockTimerArmed = true;
221
222             EFR32_LOG("Auto Re-lock enabled. Will be triggered in %u seconds", lock->mAutoLockDuration);
223         }
224     }
225 }