blob: 881dcf7a87f83324040761b32cb20e07243d65c9 [file] [log] [blame]
Mark Horvathbc58a682021-11-16 13:53:49 +01001/*
2 * Copyright (c) 2017-2022 Arm Limited
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "stdio.h"
18#include "string.h"
19#include "stdbool.h"
20#include "uart_stdout.h"
21#include "print_log.h"
22
23#include "FreeRTOS.h"
24#include "task.h"
25#include "FreeRTOS_IP.h"
26
27#include "psa/protected_storage.h"
28#include "psa/crypto.h"
29#include "psa/update.h"
30#include "psa/internal_trusted_storage.h"
31#include "vad_an552.h"
32
33#include "aws_dev_mode_key_provisioning.h"
34#include "ota_provision.h"
35
36#include "version/application_version.h"
37#include "aws_demo.h"
38#include "ota.h"
39
40#define FIRST_BOOT_ITS_UID (1U)
41#define BOOT_PATTERN (0x55)
42
43extern uint32_t tfm_ns_interface_init(void);
44extern void vApplicationIPInit(void);
45extern int mbedtls_platform_set_calloc_free(
46 void* (*calloc_func)(size_t, size_t),
47 void (*free_func)(void *));
48extern void publishToAWSTopic(const char *msg);
49
50static void* prvCalloc(size_t xNmemb, size_t xSize);
51static bool is_first_boot(void);
52static void write_boot_pattern(void);
Mark Horvathbc58a682021-11-16 13:53:49 +010053
54/*
55 * Semihosting is a mechanism that enables code running on an ARM target
56 * to communicate and use the Input/Output facilities of a host computer
57 * that is running a debugger.
58 * There is an issue where if you use armclang at -O0 optimisation with
59 * no parameters specified in the main function, the initialisation code
60 * contains a breakpoint for semihosting by default. This will stop the
61 * code from running before main is reached.
62 * Semihosting can be disabled by defining __ARM_use_no_argv symbol
63 * (or using higher optimization level).
64 */
65#if defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
66__asm(" .global __ARM_use_no_argv\n");
67#endif
68
69/*
70 * With current clib settings there is no support for errno in case of Armclang
71 * but OTA sources require it.
72 */
73#if defined (__ARMCC_VERSION)
74int errno;
75#endif
76
77psa_key_handle_t xOTACodeVerifyKeyHandle = 0xAA;
78
Mark Horvathbc58a682021-11-16 13:53:49 +010079
80static bool is_first_boot(void)
81{
82 psa_status_t status = PSA_ERROR_GENERIC_ERROR;
83 const psa_storage_uid_t uid = FIRST_BOOT_ITS_UID;
84 uint8_t boot_pattern_in_its = 0;
85 size_t read_data_length = 0;
86
87 status = psa_its_get(uid, 0, 1, &boot_pattern_in_its,
88 &read_data_length);
89 if(status != PSA_SUCCESS) {
90 vLoggingPrintf("Could not read ITS to determine boot counter");
91 vLoggingPrintf("Assuming first boot");
92 return true;
93 }
94
95 if(boot_pattern_in_its == BOOT_PATTERN) {
96 vLoggingPrintf("Boot pattern in ITS matches, not first boot");
97 return false;
98 }
99 else {
100 vLoggingPrintf("Boot pattern in ITS doesn't match, first boot");
101 return true;
102 }
103}
104
105static void write_boot_pattern(void)
106{
107 psa_status_t status = PSA_ERROR_GENERIC_ERROR;
108 const psa_storage_uid_t uid = FIRST_BOOT_ITS_UID;
109 const psa_storage_create_flags_t flags = PSA_STORAGE_FLAG_NONE;
110 uint8_t first_boot_pattern = BOOT_PATTERN;
111
112 /* Write the pattern to ITS */
113 status = psa_its_set(uid, 1, &first_boot_pattern, flags);
114 if(status == PSA_SUCCESS) {
115 vLoggingPrintf("Boot pattern has been written to the ITS");
116 }
117 else {
118 vLoggingPrintf("Couldn't write boot pattern to ITS");
119 }
120}
121
122static void mainTask(void *pvParameters)
123{
124 uint32_t vad_status;
125 uint32_t vad_freq;
126 OtaState_t ota_state;
127 TickType_t base_tick, curr_tick;
128 char message[256];
129
130#ifdef VAD_AN552_NO_CONNECTIVITY
131 while(1) {
132 vad_an552_start_vad();
133
134 do {
135 vad_an552_query_vad(&vad_status);
136 } while (vad_status != VAD_VOICE_RECORDED);
137
138 vad_an552_get_freq(&vad_freq);
139
140 vLoggingPrintf("Voice detected with most energy at %d Hz", vad_freq);
141 }
142#else
143 while(1) {
144 vLoggingPrintf("==== Start OTA task ====");
145 DEMO_RUNNER_RunDemos();
146
147 do {
148 vTaskDelay(pdMS_TO_TICKS(10));
149 ota_state = OTA_GetState();
150 }
151 while (ota_state == OtaAgentStateInit ||
152 ota_state == OtaAgentStateReady ||
153 ota_state == OtaAgentStateStopped ||
154 ota_state == OtaAgentStateRequestingJob);
155
156 vTaskDelay(pdMS_TO_TICKS(5000));
157
158 if (OtaAgentStateWaitingForJob == OTA_GetState()) {
159 vLoggingPrintf("==== Stop OTA task ====");
160
161 OTA_Shutdown(0, 1);
162 while (xTaskGetHandle("iot_thread") != NULL) {
163 vTaskDelay(pdMS_TO_TICKS(100));
164 }
165
166 base_tick = xTaskGetTickCount();
167
168 vLoggingPrintf("==== Start listening ====");
169 vad_an552_start_vad();
170
171 while(1) {
172 vad_an552_query_vad(&vad_status);
173 if (vad_status == VAD_VOICE_RECORDED) {
174 vad_an552_get_freq(&vad_freq);
175
176 vLoggingPrintf("Voice detected with most energy at %d Hz",
177 vad_freq);
178 vLoggingPrintf("==== Send message to cloud ====");
179 sprintf(message, "Voice detected with most energy at %d Hz",
180 vad_freq);
181 publishToAWSTopic(message);
182
183 /* Message sending takes some time so timeout checked
184 * before restarting the mic algorithm. */
185 curr_tick = xTaskGetTickCount();
186 if ((curr_tick - base_tick) > pdMS_TO_TICKS(60000)) {
187 vad_an552_stop_vad();
188 break;
189 }
190
191 vLoggingPrintf("==== Start listening ====");
192 vad_an552_start_vad();
193 }
194
195 curr_tick = xTaskGetTickCount();
196 if ((curr_tick - base_tick) > pdMS_TO_TICKS(60000)) {
197 vLoggingPrintf("==== Stop listening ====");
198 vad_an552_stop_vad();
199 break;
200 }
201 }
202 } else {
203 /* OTA started, nothing to do */
204 while (1) {
205 vTaskDelay(pdMS_TO_TICKS(10000));
206 }
207 }
208 }
209#endif
210}
211
212int main()
213{
214 stdio_init();
215 vUARTLockInit();
216 tfm_ns_interface_init();
Bence Balogh3be9fdd2022-11-23 11:42:25 +0100217 GetImageVersionPSA(FWU_COMPONENT_ID_FULL);
Mark Horvathbc58a682021-11-16 13:53:49 +0100218 vLoggingPrintf("Application firmware version: %d.%d.%d",
219 appFirmwareVersion.u.x.major,
220 appFirmwareVersion.u.x.minor,
221 appFirmwareVersion.u.x.build);
222
223#ifdef VAD_AN552_NO_CONNECTIVITY
224 xTaskCreate(mainTask, "main task", configMINIMAL_STACK_SIZE*2, NULL,
225 configMAX_PRIORITIES-2, NULL);
226#else
227 mbedtls_platform_set_calloc_free(prvCalloc, vPortFree);
228
229 if(is_first_boot()) {
Mark Horvathbc58a682021-11-16 13:53:49 +0100230 vDevModeKeyProvisioning();
231 ota_privision_code_signing_key(&xOTACodeVerifyKeyHandle);
232 write_boot_pattern();
233 }
234
235 /* Initialise the RTOS's TCP/IP stack. The tasks that use the network
236 are created in the vApplicationIPNetworkEventHook() hook function
237 below. The hook function is called when the network connects. */
238 vApplicationIPInit();
239#endif
240
241 vLoggingPrintf("Starting FreeRTOS scheduler");
242#ifndef VAD_AN552_NO_CONNECTIVITY
243 vLoggingPrintf("Waiting for network");
244#endif
245 /* Start the scheduler itself. */
246 vTaskStartScheduler();
247
248 while (1)
249 {
250 }
251}
252
253void vApplicationIPNetworkEventHook(eIPCallbackEvent_t eNetworkEvent)
254{
255#ifndef VAD_AN552_NO_CONNECTIVITY
256 if (eNetworkEvent == eNetworkUp) {
257 vLoggingPrintf("Network connection established");
258 xTaskCreate(mainTask, "main task", configMINIMAL_STACK_SIZE*2, NULL,
259 configMAX_PRIORITIES-4, NULL);
260 }
261#endif
262}
263
264/* Functions needed for mbedtls build */
265static void * prvCalloc(size_t xNmemb,
266 size_t xSize)
267{
268 void * pvNew = pvPortMalloc(xNmemb * xSize);
269
270 if( NULL != pvNew ) {
271 memset(pvNew, 0, xNmemb * xSize);
272 }
273
274 return pvNew;
275}
276
277int mbedtls_hardware_poll(void *data,
278 unsigned char *output, size_t len, size_t *olen)
279{
280 psa_status_t status;
281
282 (void) (data);
283
284 if (output == NULL || olen == NULL) {
285 return -1;
286 }
287
288 status = psa_generate_random(output, len);
289 if (status != PSA_SUCCESS) {
290 return -1;
291 }
292
293 *olen = len;
294
295 return 0;
296}