blob: c77f530815f53daec6bb5f22df4470ecf45aa5a1 [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);
53static void accept_primary_slot_image(void);
54
55/*
56 * Semihosting is a mechanism that enables code running on an ARM target
57 * to communicate and use the Input/Output facilities of a host computer
58 * that is running a debugger.
59 * There is an issue where if you use armclang at -O0 optimisation with
60 * no parameters specified in the main function, the initialisation code
61 * contains a breakpoint for semihosting by default. This will stop the
62 * code from running before main is reached.
63 * Semihosting can be disabled by defining __ARM_use_no_argv symbol
64 * (or using higher optimization level).
65 */
66#if defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
67__asm(" .global __ARM_use_no_argv\n");
68#endif
69
70/*
71 * With current clib settings there is no support for errno in case of Armclang
72 * but OTA sources require it.
73 */
74#if defined (__ARMCC_VERSION)
75int errno;
76#endif
77
78psa_key_handle_t xOTACodeVerifyKeyHandle = 0xAA;
79
80static void accept_primary_slot_image(void)
81{
82 psa_image_id_t running_image = \
83 (psa_image_id_t)FWU_CALCULATE_IMAGE_ID(FWU_IMAGE_ID_SLOT_ACTIVE,
84 FWU_IMAGE_TYPE_FULL,
85 0);
86 vLoggingPrintf("Accepting image by setting image_ok flag to 0x1 in MCUBOOT trailer");
87 if (psa_fwu_accept(running_image) != PSA_SUCCESS) {
88 vLoggingPrintf("Accept failed");
89 }
90}
91
92static bool is_first_boot(void)
93{
94 psa_status_t status = PSA_ERROR_GENERIC_ERROR;
95 const psa_storage_uid_t uid = FIRST_BOOT_ITS_UID;
96 uint8_t boot_pattern_in_its = 0;
97 size_t read_data_length = 0;
98
99 status = psa_its_get(uid, 0, 1, &boot_pattern_in_its,
100 &read_data_length);
101 if(status != PSA_SUCCESS) {
102 vLoggingPrintf("Could not read ITS to determine boot counter");
103 vLoggingPrintf("Assuming first boot");
104 return true;
105 }
106
107 if(boot_pattern_in_its == BOOT_PATTERN) {
108 vLoggingPrintf("Boot pattern in ITS matches, not first boot");
109 return false;
110 }
111 else {
112 vLoggingPrintf("Boot pattern in ITS doesn't match, first boot");
113 return true;
114 }
115}
116
117static void write_boot_pattern(void)
118{
119 psa_status_t status = PSA_ERROR_GENERIC_ERROR;
120 const psa_storage_uid_t uid = FIRST_BOOT_ITS_UID;
121 const psa_storage_create_flags_t flags = PSA_STORAGE_FLAG_NONE;
122 uint8_t first_boot_pattern = BOOT_PATTERN;
123
124 /* Write the pattern to ITS */
125 status = psa_its_set(uid, 1, &first_boot_pattern, flags);
126 if(status == PSA_SUCCESS) {
127 vLoggingPrintf("Boot pattern has been written to the ITS");
128 }
129 else {
130 vLoggingPrintf("Couldn't write boot pattern to ITS");
131 }
132}
133
134static void mainTask(void *pvParameters)
135{
136 uint32_t vad_status;
137 uint32_t vad_freq;
138 OtaState_t ota_state;
139 TickType_t base_tick, curr_tick;
140 char message[256];
141
142#ifdef VAD_AN552_NO_CONNECTIVITY
143 while(1) {
144 vad_an552_start_vad();
145
146 do {
147 vad_an552_query_vad(&vad_status);
148 } while (vad_status != VAD_VOICE_RECORDED);
149
150 vad_an552_get_freq(&vad_freq);
151
152 vLoggingPrintf("Voice detected with most energy at %d Hz", vad_freq);
153 }
154#else
155 while(1) {
156 vLoggingPrintf("==== Start OTA task ====");
157 DEMO_RUNNER_RunDemos();
158
159 do {
160 vTaskDelay(pdMS_TO_TICKS(10));
161 ota_state = OTA_GetState();
162 }
163 while (ota_state == OtaAgentStateInit ||
164 ota_state == OtaAgentStateReady ||
165 ota_state == OtaAgentStateStopped ||
166 ota_state == OtaAgentStateRequestingJob);
167
168 vTaskDelay(pdMS_TO_TICKS(5000));
169
170 if (OtaAgentStateWaitingForJob == OTA_GetState()) {
171 vLoggingPrintf("==== Stop OTA task ====");
172
173 OTA_Shutdown(0, 1);
174 while (xTaskGetHandle("iot_thread") != NULL) {
175 vTaskDelay(pdMS_TO_TICKS(100));
176 }
177
178 base_tick = xTaskGetTickCount();
179
180 vLoggingPrintf("==== Start listening ====");
181 vad_an552_start_vad();
182
183 while(1) {
184 vad_an552_query_vad(&vad_status);
185 if (vad_status == VAD_VOICE_RECORDED) {
186 vad_an552_get_freq(&vad_freq);
187
188 vLoggingPrintf("Voice detected with most energy at %d Hz",
189 vad_freq);
190 vLoggingPrintf("==== Send message to cloud ====");
191 sprintf(message, "Voice detected with most energy at %d Hz",
192 vad_freq);
193 publishToAWSTopic(message);
194
195 /* Message sending takes some time so timeout checked
196 * before restarting the mic algorithm. */
197 curr_tick = xTaskGetTickCount();
198 if ((curr_tick - base_tick) > pdMS_TO_TICKS(60000)) {
199 vad_an552_stop_vad();
200 break;
201 }
202
203 vLoggingPrintf("==== Start listening ====");
204 vad_an552_start_vad();
205 }
206
207 curr_tick = xTaskGetTickCount();
208 if ((curr_tick - base_tick) > pdMS_TO_TICKS(60000)) {
209 vLoggingPrintf("==== Stop listening ====");
210 vad_an552_stop_vad();
211 break;
212 }
213 }
214 } else {
215 /* OTA started, nothing to do */
216 while (1) {
217 vTaskDelay(pdMS_TO_TICKS(10000));
218 }
219 }
220 }
221#endif
222}
223
224int main()
225{
226 stdio_init();
227 vUARTLockInit();
228 tfm_ns_interface_init();
229
230 GetImageVersionPSA(FWU_IMAGE_TYPE_FULL);
231 vLoggingPrintf("Application firmware version: %d.%d.%d",
232 appFirmwareVersion.u.x.major,
233 appFirmwareVersion.u.x.minor,
234 appFirmwareVersion.u.x.build);
235
236#ifdef VAD_AN552_NO_CONNECTIVITY
237 xTaskCreate(mainTask, "main task", configMINIMAL_STACK_SIZE*2, NULL,
238 configMAX_PRIORITIES-2, NULL);
239#else
240 mbedtls_platform_set_calloc_free(prvCalloc, vPortFree);
241
242 if(is_first_boot()) {
243 accept_primary_slot_image();
244 vDevModeKeyProvisioning();
245 ota_privision_code_signing_key(&xOTACodeVerifyKeyHandle);
246 write_boot_pattern();
247 }
248
249 /* Initialise the RTOS's TCP/IP stack. The tasks that use the network
250 are created in the vApplicationIPNetworkEventHook() hook function
251 below. The hook function is called when the network connects. */
252 vApplicationIPInit();
253#endif
254
255 vLoggingPrintf("Starting FreeRTOS scheduler");
256#ifndef VAD_AN552_NO_CONNECTIVITY
257 vLoggingPrintf("Waiting for network");
258#endif
259 /* Start the scheduler itself. */
260 vTaskStartScheduler();
261
262 while (1)
263 {
264 }
265}
266
267void vApplicationIPNetworkEventHook(eIPCallbackEvent_t eNetworkEvent)
268{
269#ifndef VAD_AN552_NO_CONNECTIVITY
270 if (eNetworkEvent == eNetworkUp) {
271 vLoggingPrintf("Network connection established");
272 xTaskCreate(mainTask, "main task", configMINIMAL_STACK_SIZE*2, NULL,
273 configMAX_PRIORITIES-4, NULL);
274 }
275#endif
276}
277
278/* Functions needed for mbedtls build */
279static void * prvCalloc(size_t xNmemb,
280 size_t xSize)
281{
282 void * pvNew = pvPortMalloc(xNmemb * xSize);
283
284 if( NULL != pvNew ) {
285 memset(pvNew, 0, xNmemb * xSize);
286 }
287
288 return pvNew;
289}
290
291int mbedtls_hardware_poll(void *data,
292 unsigned char *output, size_t len, size_t *olen)
293{
294 psa_status_t status;
295
296 (void) (data);
297
298 if (output == NULL || olen == NULL) {
299 return -1;
300 }
301
302 status = psa_generate_random(output, len);
303 if (status != PSA_SUCCESS) {
304 return -1;
305 }
306
307 *olen = len;
308
309 return 0;
310}