AppTask.cpp 18 KB

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