Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / examples / lock-app / k32w / main / AppTask.cpp
1 /*
2  *
3  *    Copyright (c) 2020 Project CHIP Authors
4  *    Copyright (c) 2020 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 #include "AppTask.h"
20 #include "AppEvent.h"
21 #include "Server.h"
22 #include "support/ErrorStr.h"
23
24 #include "OnboardingCodesUtil.h"
25 #include <platform/CHIPDeviceLayer.h>
26 #include <platform/internal/DeviceNetworkInfo.h>
27
28 #include "attribute-storage.h"
29 #include "gen/attribute-id.h"
30 #include "gen/attribute-type.h"
31 #include "gen/cluster-id.h"
32
33 #include "Keyboard.h"
34 #include "LED.h"
35 #include "LEDWidget.h"
36 #include "TimersManager.h"
37 #include "app_config.h"
38
39 constexpr uint32_t kFactoryResetTriggerTimeout = 6000;
40 constexpr uint8_t kAppEventQueueSize           = 10;
41
42 TimerHandle_t sFunctionTimer; // FreeRTOS app sw timer.
43
44 static SemaphoreHandle_t sCHIPEventLock;
45 static QueueHandle_t sAppEventQueue;
46
47 static LEDWidget sStatusLED;
48 static LEDWidget sLockLED;
49
50 static bool sIsThreadProvisioned     = false;
51 static bool sIsThreadEnabled         = false;
52 static bool sHaveBLEConnections      = false;
53 static bool sHaveServiceConnectivity = false;
54
55 static uint32_t eventMask = 0;
56
57 using namespace ::chip::DeviceLayer;
58
59 AppTask AppTask::sAppTask;
60
61 int AppTask::StartAppTask()
62 {
63     int err = CHIP_NO_ERROR;
64
65     sAppEventQueue = xQueueCreate(kAppEventQueueSize, sizeof(AppEvent));
66     if (sAppEventQueue == NULL)
67     {
68         K32W_LOG("Failed to allocate app event queue");
69         assert(false);
70     }
71
72     return err;
73 }
74
75 int AppTask::Init()
76 {
77     CHIP_ERROR err = CHIP_NO_ERROR;
78
79     // Init ZCL Data Model and start server
80     InitServer();
81
82     // QR code will be used with CHIP Tool
83     PrintOnboardingCodes(chip::RendezvousInformationFlags::kBLE);
84
85     TMR_Init();
86
87     /* HW init leds */
88     LED_Init();
89
90     /* start with all LEDS turnedd off */
91     sStatusLED.Init(SYSTEM_STATE_LED);
92
93     sLockLED.Init(LOCK_STATE_LED);
94     sLockLED.Set(!BoltLockMgr().IsUnlocked());
95
96     /* intialize the Keyboard and button press calback */
97     KBD_Init(KBD_Callback);
98
99     // Create FreeRTOS sw timer for Function Selection.
100     sFunctionTimer = xTimerCreate("FnTmr",          // Just a text name, not used by the RTOS kernel
101                                   1,                // == default timer period (mS)
102                                   false,            // no timer reload (==one-shot)
103                                   (void *) this,    // init timer id = app task obj context
104                                   TimerEventHandler // timer callback handler
105     );
106     if (sFunctionTimer == NULL)
107     {
108         K32W_LOG("app_timer_create() failed");
109         assert(err == CHIP_NO_ERROR);
110     }
111
112     err = BoltLockMgr().Init();
113     if (err != CHIP_NO_ERROR)
114     {
115         K32W_LOG("BoltLockMgr().Init() failed");
116         assert(err == CHIP_NO_ERROR);
117     }
118
119     BoltLockMgr().SetCallbacks(ActionInitiated, ActionCompleted);
120
121     sCHIPEventLock = xSemaphoreCreateMutex();
122     if (sCHIPEventLock == NULL)
123     {
124         K32W_LOG("xSemaphoreCreateMutex() failed");
125         assert(err == CHIP_NO_ERROR);
126     }
127
128     // Print the current software version
129     char currentFirmwareRev[ConfigurationManager::kMaxFirmwareRevisionLength + 1] = { 0 };
130     size_t currentFirmwareRevLen;
131     err = ConfigurationMgr().GetFirmwareRevision(currentFirmwareRev, sizeof(currentFirmwareRev), currentFirmwareRevLen);
132     if (err != CHIP_NO_ERROR)
133     {
134         K32W_LOG("Get version error");
135         assert(err == CHIP_NO_ERROR);
136     }
137
138     K32W_LOG("Current Firmware Version: %s", currentFirmwareRev);
139
140     return err;
141 }
142
143 void AppTask::AppTaskMain(void * pvParameter)
144 {
145     int err;
146     AppEvent event;
147
148     err = sAppTask.Init();
149     if (err != CHIP_NO_ERROR)
150     {
151         K32W_LOG("AppTask.Init() failed");
152         assert(err == CHIP_NO_ERROR);
153     }
154
155     while (true)
156     {
157         BaseType_t eventReceived = xQueueReceive(sAppEventQueue, &event, pdMS_TO_TICKS(10));
158         while (eventReceived == pdTRUE)
159         {
160             sAppTask.DispatchEvent(&event);
161             eventReceived = xQueueReceive(sAppEventQueue, &event, 0);
162         }
163
164         // Collect connectivity and configuration state from the CHIP stack.  Because the
165         // CHIP event loop is being run in a separate task, the stack must be locked
166         // while these values are queried.  However we use a non-blocking lock request
167         // (TryLockChipStack()) to avoid blocking other UI activities when the CHIP
168         // task is busy (e.g. with a long crypto operation).
169         if (PlatformMgr().TryLockChipStack())
170         {
171             sIsThreadProvisioned     = ConnectivityMgr().IsThreadProvisioned();
172             sIsThreadEnabled         = ConnectivityMgr().IsThreadEnabled();
173             sHaveBLEConnections      = (ConnectivityMgr().NumBLEConnections() != 0);
174             sHaveServiceConnectivity = ConnectivityMgr().HaveServiceConnectivity();
175             PlatformMgr().UnlockChipStack();
176         }
177
178         // Update the status LED if factory reset has not been initiated.
179         //
180         // If system has "full connectivity", keep the LED On constantly.
181         //
182         // If thread and service provisioned, but not attached to the thread network yet OR no
183         // connectivity to the service OR subscriptions are not fully established
184         // THEN blink the LED Off for a short period of time.
185         //
186         // If the system has ble connection(s) uptill the stage above, THEN blink the LEDs at an even
187         // rate of 100ms.
188         //
189         // Otherwise, blink the LED ON for a very short time.
190         if (sAppTask.mFunction != kFunction_FactoryReset)
191         {
192             if (sHaveServiceConnectivity)
193             {
194                 sStatusLED.Set(true);
195             }
196             else if (sIsThreadProvisioned && sIsThreadEnabled)
197             {
198                 sStatusLED.Blink(950, 50);
199             }
200             else if (sHaveBLEConnections)
201             {
202                 sStatusLED.Blink(100, 100);
203             }
204             else
205             {
206                 sStatusLED.Blink(50, 950);
207             }
208         }
209
210         sStatusLED.Animate();
211         sLockLED.Animate();
212
213         HandleKeyboard();
214     }
215 }
216
217 void AppTask::ButtonEventHandler(uint8_t pin_no, uint8_t button_action)
218 {
219     if ((pin_no != RESET_BUTTON) && (pin_no != LOCK_BUTTON) && (pin_no != JOIN_BUTTON) && (pin_no != BLE_BUTTON))
220     {
221         return;
222     }
223
224     AppEvent button_event;
225     button_event.Type               = AppEvent::kEventType_Button;
226     button_event.ButtonEvent.PinNo  = pin_no;
227     button_event.ButtonEvent.Action = button_action;
228
229     if (pin_no == RESET_BUTTON)
230     {
231         button_event.Handler = ResetActionEventHandler;
232     }
233     else if (pin_no == LOCK_BUTTON)
234     {
235         button_event.Handler = LockActionEventHandler;
236     }
237     else if (pin_no == JOIN_BUTTON)
238     {
239         button_event.Handler = JoinHandler;
240     }
241     else if (pin_no == BLE_BUTTON)
242     {
243         button_event.Handler = BleHandler;
244     }
245
246     sAppTask.PostEvent(&button_event);
247 }
248
249 void AppTask::KBD_Callback(uint8_t events)
250 {
251     eventMask = eventMask | (uint32_t)(1 << events);
252 }
253
254 void AppTask::HandleKeyboard(void)
255 {
256     uint8_t keyEvent = 0xFF;
257     uint8_t pos      = 0;
258
259     while (eventMask)
260     {
261         for (pos = 0; pos < (8 * sizeof(eventMask)); pos++)
262         {
263             if (eventMask & (1 << pos))
264             {
265                 keyEvent  = pos;
266                 eventMask = eventMask & ~(1 << pos);
267                 break;
268             }
269         }
270
271         switch (keyEvent)
272         {
273         case gKBD_EventPB1_c:
274             ButtonEventHandler(RESET_BUTTON, RESET_BUTTON_PUSH);
275             break;
276         case gKBD_EventPB2_c:
277             ButtonEventHandler(LOCK_BUTTON, LOCK_BUTTON_PUSH);
278             break;
279         case gKBD_EventPB3_c:
280             ButtonEventHandler(JOIN_BUTTON, JOIN_BUTTON_PUSH);
281             break;
282         case gKBD_EventPB4_c:
283             ButtonEventHandler(BLE_BUTTON, BLE_BUTTON_PUSH);
284             break;
285         default:
286             break;
287         }
288     }
289 }
290
291 void AppTask::TimerEventHandler(TimerHandle_t xTimer)
292 {
293     AppEvent event;
294     event.Type               = AppEvent::kEventType_Timer;
295     event.TimerEvent.Context = (void *) xTimer;
296     event.Handler            = FunctionTimerEventHandler;
297     sAppTask.PostEvent(&event);
298 }
299
300 void AppTask::FunctionTimerEventHandler(AppEvent * aEvent)
301 {
302     if (aEvent->Type != AppEvent::kEventType_Timer)
303         return;
304
305     K32W_LOG("Device will factory reset...");
306
307     // Actually trigger Factory Reset
308     ConfigurationMgr().InitiateFactoryReset();
309 }
310
311 void AppTask::ResetActionEventHandler(AppEvent * aEvent)
312 {
313     if (aEvent->ButtonEvent.PinNo != RESET_BUTTON)
314         return;
315
316     if (sAppTask.mResetTimerActive)
317     {
318         sAppTask.CancelTimer();
319         sAppTask.mFunction = kFunction_NoneSelected;
320
321         /* restore initial state for the LED indicating Lock state */
322         if (BoltLockMgr().IsUnlocked())
323         {
324             sLockLED.Set(false);
325         }
326         else
327         {
328             sLockLED.Set(true);
329         }
330
331         K32W_LOG("Factory Reset was cancelled!");
332     }
333     else
334     {
335         uint32_t resetTimeout = kFactoryResetTriggerTimeout;
336
337         if (sAppTask.mFunction != kFunction_NoneSelected)
338         {
339             K32W_LOG("Another function is scheduled. Could not initiate Factory Reset!");
340             return;
341         }
342
343         K32W_LOG("Factory Reset Triggered. Push the RESET button within %u ms to cancel!", resetTimeout);
344         sAppTask.mFunction = kFunction_FactoryReset;
345
346         /* LEDs will start blinking to signal that a Factory Reset was scheduled */
347         sStatusLED.Set(false);
348         sLockLED.Set(false);
349
350         sStatusLED.Blink(500);
351         sLockLED.Blink(500);
352
353         sAppTask.StartTimer(kFactoryResetTriggerTimeout);
354     }
355 }
356
357 void AppTask::LockActionEventHandler(AppEvent * aEvent)
358 {
359     BoltLockManager::Action_t action;
360     int err        = CHIP_NO_ERROR;
361     int32_t actor  = 0;
362     bool initiated = false;
363
364     if (sAppTask.mFunction != kFunction_NoneSelected)
365     {
366         K32W_LOG("Another function is scheduled. Could not initiate Lock/Unlock!");
367         return;
368     }
369
370     if (aEvent->Type == AppEvent::kEventType_Lock)
371     {
372         action = static_cast<BoltLockManager::Action_t>(aEvent->LockEvent.Action);
373         actor  = aEvent->LockEvent.Actor;
374     }
375     else if (aEvent->Type == AppEvent::kEventType_Button)
376     {
377         if (BoltLockMgr().IsUnlocked())
378         {
379             action = BoltLockManager::LOCK_ACTION;
380         }
381         else
382         {
383             action = BoltLockManager::UNLOCK_ACTION;
384         }
385     }
386     else
387     {
388         err = CHIP_ERROR_MAX;
389     }
390
391     if (err == CHIP_NO_ERROR)
392     {
393         initiated = BoltLockMgr().InitiateAction(actor, action);
394
395         if (!initiated)
396         {
397             K32W_LOG("Action is already in progress or active.");
398         }
399     }
400 }
401
402 void AppTask::ThreadStart()
403 {
404     chip::DeviceLayer::Internal::DeviceNetworkInfo networkInfo;
405
406     memset(networkInfo.ThreadNetworkName, 0, chip::DeviceLayer::Internal::kMaxThreadNetworkNameLength + 1);
407     memcpy(networkInfo.ThreadNetworkName, "OpenThread", 10);
408
409     networkInfo.ThreadExtendedPANId[0] = 0xde;
410     networkInfo.ThreadExtendedPANId[1] = 0xad;
411     networkInfo.ThreadExtendedPANId[2] = 0x00;
412     networkInfo.ThreadExtendedPANId[3] = 0xbe;
413     networkInfo.ThreadExtendedPANId[4] = 0xef;
414     networkInfo.ThreadExtendedPANId[5] = 0x00;
415     networkInfo.ThreadExtendedPANId[6] = 0xca;
416     networkInfo.ThreadExtendedPANId[7] = 0xfe;
417
418     networkInfo.ThreadMasterKey[0]  = 0x00;
419     networkInfo.ThreadMasterKey[1]  = 0x11;
420     networkInfo.ThreadMasterKey[2]  = 0x22;
421     networkInfo.ThreadMasterKey[3]  = 0x33;
422     networkInfo.ThreadMasterKey[4]  = 0x44;
423     networkInfo.ThreadMasterKey[5]  = 0x55;
424     networkInfo.ThreadMasterKey[6]  = 0x66;
425     networkInfo.ThreadMasterKey[7]  = 0x77;
426     networkInfo.ThreadMasterKey[8]  = 0x88;
427     networkInfo.ThreadMasterKey[9]  = 0x99;
428     networkInfo.ThreadMasterKey[10] = 0xAA;
429     networkInfo.ThreadMasterKey[11] = 0xBB;
430     networkInfo.ThreadMasterKey[12] = 0xCC;
431     networkInfo.ThreadMasterKey[13] = 0xDD;
432     networkInfo.ThreadMasterKey[14] = 0xEE;
433     networkInfo.ThreadMasterKey[15] = 0xFF;
434
435     networkInfo.ThreadPANId   = 0xabcd;
436     networkInfo.ThreadChannel = 15;
437
438     networkInfo.FieldPresent.ThreadExtendedPANId = true;
439     networkInfo.FieldPresent.ThreadMeshPrefix    = false;
440     networkInfo.FieldPresent.ThreadPSKc          = false;
441     networkInfo.NetworkId                        = 0;
442     networkInfo.FieldPresent.NetworkId           = true;
443
444     ThreadStackMgr().SetThreadEnabled(false);
445     ThreadStackMgr().SetThreadProvision(networkInfo);
446     ThreadStackMgr().SetThreadEnabled(true);
447 }
448
449 void AppTask::JoinHandler(AppEvent * aEvent)
450 {
451     if (aEvent->ButtonEvent.PinNo != JOIN_BUTTON)
452         return;
453
454     if (sAppTask.mFunction != kFunction_NoneSelected)
455     {
456         K32W_LOG("Another function is scheduled. Could not initiate Thread Join!");
457         return;
458     }
459
460     /* hard-code Thread Commissioning Parameters for the moment.
461      * In a future PR, these parameters will be sent via BLE.
462      */
463     ThreadStart();
464 }
465
466 void AppTask::BleHandler(AppEvent * aEvent)
467 {
468     if (aEvent->ButtonEvent.PinNo != BLE_BUTTON)
469         return;
470
471     if (sAppTask.mFunction != kFunction_NoneSelected)
472     {
473         K32W_LOG("Another function is scheduled. Could not toggle BLE state!");
474         return;
475     }
476
477     if (ConnectivityMgr().IsBLEAdvertisingEnabled())
478     {
479         ConnectivityMgr().SetBLEAdvertisingEnabled(false);
480         K32W_LOG("Stopped BLE Advertising!");
481     }
482     else
483     {
484         ConnectivityMgr().SetBLEAdvertisingEnabled(true);
485
486         if (OpenDefaultPairingWindow(chip::ResetAdmins::kNo) == CHIP_NO_ERROR)
487         {
488             K32W_LOG("Started BLE Advertising!");
489         }
490         else
491         {
492             K32W_LOG("OpenDefaultPairingWindow() failed");
493         }
494     }
495 }
496
497 void AppTask::CancelTimer()
498 {
499     if (xTimerStop(sFunctionTimer, 0) == pdFAIL)
500     {
501         K32W_LOG("app timer stop() failed");
502     }
503
504     mResetTimerActive = false;
505 }
506
507 void AppTask::StartTimer(uint32_t aTimeoutInMs)
508 {
509     if (xTimerIsTimerActive(sFunctionTimer))
510     {
511         K32W_LOG("app timer already started!");
512         CancelTimer();
513     }
514
515     // timer is not active, change its period to required value (== restart).
516     // FreeRTOS- Block for a maximum of 100 ticks if the change period command
517     // cannot immediately be sent to the timer command queue.
518     if (xTimerChangePeriod(sFunctionTimer, aTimeoutInMs / portTICK_PERIOD_MS, 100) != pdPASS)
519     {
520         K32W_LOG("app timer start() failed");
521     }
522
523     mResetTimerActive = true;
524 }
525
526 void AppTask::ActionInitiated(BoltLockManager::Action_t aAction, int32_t aActor)
527 {
528     // If the action has been initiated by the lock, update the bolt lock trait
529     // and start flashing the LEDs rapidly to indicate action initiation.
530     if (aAction == BoltLockManager::LOCK_ACTION)
531     {
532         K32W_LOG("Lock Action has been initiated")
533     }
534     else if (aAction == BoltLockManager::UNLOCK_ACTION)
535     {
536         K32W_LOG("Unlock Action has been initiated")
537     }
538
539     sAppTask.mFunction = kFunctionLockUnlock;
540     sLockLED.Blink(50, 50);
541 }
542
543 void AppTask::ActionCompleted(BoltLockManager::Action_t aAction)
544 {
545     // if the action has been completed by the lock, update the bolt lock trait.
546     // Turn on the lock LED if in a LOCKED state OR
547     // Turn off the lock LED if in an UNLOCKED state.
548     if (aAction == BoltLockManager::LOCK_ACTION)
549     {
550         K32W_LOG("Lock Action has been completed")
551         sLockLED.Set(true);
552     }
553     else if (aAction == BoltLockManager::UNLOCK_ACTION)
554     {
555         K32W_LOG("Unlock Action has been completed")
556         sLockLED.Set(false);
557     }
558
559     sAppTask.mFunction = kFunction_NoneSelected;
560 }
561
562 void AppTask::PostLockActionRequest(int32_t aActor, BoltLockManager::Action_t aAction)
563 {
564     AppEvent event;
565     event.Type             = AppEvent::kEventType_Lock;
566     event.LockEvent.Actor  = aActor;
567     event.LockEvent.Action = aAction;
568     event.Handler          = LockActionEventHandler;
569     PostEvent(&event);
570 }
571
572 void AppTask::PostEvent(const AppEvent * aEvent)
573 {
574     if (sAppEventQueue != NULL)
575     {
576         if (!xQueueSend(sAppEventQueue, aEvent, 1))
577         {
578             K32W_LOG("Failed to post event to app task event queue");
579         }
580     }
581 }
582
583 void AppTask::DispatchEvent(AppEvent * aEvent)
584 {
585     if (aEvent->Handler)
586     {
587         aEvent->Handler(aEvent);
588     }
589     else
590     {
591         K32W_LOG("Event received with no handler. Dropping event.");
592     }
593 }
594
595 void AppTask::UpdateClusterState(void)
596 {
597     uint8_t newValue = !BoltLockMgr().IsUnlocked();
598
599     // write the new on/off value
600     EmberAfStatus status = emberAfWriteAttribute(1, ZCL_ON_OFF_CLUSTER_ID, ZCL_ON_OFF_ATTRIBUTE_ID, CLUSTER_MASK_SERVER,
601                                                  (uint8_t *) &newValue, ZCL_BOOLEAN_ATTRIBUTE_TYPE);
602     if (status != EMBER_ZCL_STATUS_SUCCESS)
603     {
604         ChipLogError(NotSpecified, "ERR: updating on/off %x", status);
605     }
606 }