450 lines
14 KiB
C
450 lines
14 KiB
C
/*
|
|
* Lab-Project-coreMQTT-Agent 201215
|
|
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
* Copyright 2022-2023 NXP
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
* this software and associated documentation files (the "Software"), to deal in
|
|
* the Software without restriction, including without limitation the rights to
|
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
* the Software, and to permit persons to whom the Software is furnished to do so,
|
|
* subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in all
|
|
* copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
*
|
|
* http://www.FreeRTOS.org
|
|
* http://aws.amazon.com/freertos
|
|
*/
|
|
|
|
/* FreeRTOS kernel includes. */
|
|
#include "FreeRTOS.h"
|
|
#include "task.h"
|
|
#include "queue.h"
|
|
#include "timers.h"
|
|
|
|
#include "fsl_device_registers.h"
|
|
#include "fsl_debug_console.h"
|
|
#include "pin_mux.h"
|
|
#include "clock_config.h"
|
|
#include "board.h"
|
|
|
|
#include "ksdk_mbedtls.h"
|
|
#include "mflash_file.h"
|
|
#include "kvstore.h"
|
|
|
|
#include "mqtt_agent_task.h"
|
|
#include "aws_dev_mode_key_provisioning.h"
|
|
#include "core_pkcs11_config.h"
|
|
|
|
#include "aws_clientcredential.h"
|
|
#include "fsl_debug_console.h"
|
|
|
|
/* Serial MWM */
|
|
#include "serial_mwm.h"
|
|
|
|
#include "fsl_power.h"
|
|
/*******************************************************************************
|
|
* Definitions
|
|
******************************************************************************/
|
|
|
|
/**
|
|
* @brief Stack size and priority for shadow device sync task.
|
|
*/
|
|
#define appmainSHADOW_DEVICE_TASK_STACK_SIZE (320)
|
|
#define appmainSHADOW_DEVICE_TASK_PRIORITY (tskIDLE_PRIORITY + 1)
|
|
|
|
/**
|
|
* @brief Stack size and priority for shadow update application task.
|
|
*/
|
|
#define appmainSHADOW_UPDATE_TASK_STACK_SIZE (320)
|
|
#define appmainSHADOW_UPDATE_TASK_PRIORITY (tskIDLE_PRIORITY + 1)
|
|
|
|
/**
|
|
* @brief Stack size and priority for MQTT agent task.
|
|
* Stack size is capped to an adequate value based on requirements from MbedTLS stack
|
|
* for establishing a TLS connection. Task priority of MQTT agent is set to a priority
|
|
* higher than other MQTT application tasks, so that the agent can drain the queue
|
|
* as work is being produced.
|
|
*/
|
|
#define appmainMQTT_AGENT_TASK_STACK_SIZE (2048)
|
|
#define appmainMQTT_AGENT_TASK_PRIORITY (tskIDLE_PRIORITY + 2)
|
|
|
|
#define INIT_TASK_STACK_SIZE (512)
|
|
#define INIT_TASK_PRIORITY (tskIDLE_PRIORITY + 1)
|
|
|
|
/*******************************************************************************
|
|
* Prototypes
|
|
******************************************************************************/
|
|
extern void vShadowDeviceTask(void *pvParameters);
|
|
extern void vShadowUpdateTask(void *pvParameters);
|
|
extern int init_network(void);
|
|
int app_main(void);
|
|
void init_task(void *pvParameters);
|
|
|
|
/*******************************************************************************
|
|
* Variables
|
|
******************************************************************************/
|
|
|
|
static const mflash_file_t dir_template[] = {{.path = KVSTORE_FILE_PATH, .max_size = 3000},
|
|
{.path = pkcs11palFILE_NAME_CLIENT_CERTIFICATE, .max_size = 2000},
|
|
{.path = pkcs11palFILE_NAME_KEY, .max_size = 2000},
|
|
{.path = pkcs11palFILE_CODE_SIGN_PUBLIC_KEY, .max_size = 2000},
|
|
{0}};
|
|
|
|
/*******************************************************************************
|
|
* Code
|
|
******************************************************************************/
|
|
/*!
|
|
* @brief Application entry point.
|
|
*/
|
|
int main(void)
|
|
{
|
|
/* set BOD VBAT level to 1.65V */
|
|
POWER_SetBodVbatLevel(kPOWER_BodVbatLevel1650mv, kPOWER_BodHystLevel50mv, false);
|
|
/* attach main clock divide to FLEXCOMM0 (debug console) */
|
|
CLOCK_AttachClk(BOARD_DEBUG_UART_CLK_ATTACH);
|
|
|
|
/* attach main clock divide to FLEXCOMM2 */
|
|
CLOCK_AttachClk(kFRO12M_to_FLEXCOMM2);
|
|
|
|
BOARD_InitBootPins();
|
|
BOARD_BootClockPLL100M();
|
|
BOARD_InitDebugConsole();
|
|
|
|
if (CRYPTO_InitHardware() != 0)
|
|
{
|
|
PRINTF(("\r\nFailed to initialize MBEDTLS crypto.\r\n"));
|
|
|
|
while (1)
|
|
{
|
|
}
|
|
}
|
|
|
|
BaseType_t xResult;
|
|
xResult = xTaskCreate(init_task, "init_task", INIT_TASK_STACK_SIZE, NULL, INIT_TASK_PRIORITY, NULL);
|
|
|
|
if (xResult != pdPASS)
|
|
{
|
|
PRINTF("\r\nFailed to create init task.\r\n");
|
|
|
|
for (;;)
|
|
{
|
|
}
|
|
}
|
|
|
|
vTaskStartScheduler();
|
|
|
|
/* Should not reach here. */
|
|
for (;;)
|
|
{
|
|
}
|
|
}
|
|
|
|
void init_task(void *pvParameters)
|
|
{
|
|
(void)pvParameters;
|
|
|
|
/* Initialize file system. */
|
|
if (mflash_init(dir_template, true) != kStatus_Success)
|
|
{
|
|
PRINTF("\r\nFailed to initialize file system.\r\n");
|
|
|
|
for (;;)
|
|
{
|
|
}
|
|
}
|
|
|
|
/* A simple example to demonstrate key and certificate provisioning in
|
|
* microcontroller flash using PKCS#11 interface. This should be replaced
|
|
* by production ready key provisioning mechanism. */
|
|
CK_RV ret_prov = vDevModeKeyProvisioning();
|
|
if (ret_prov != CKR_OK)
|
|
{
|
|
PRINTF("\r\nDevice provisioning failed: %d\r\n", ret_prov);
|
|
for (;;)
|
|
{
|
|
}
|
|
}
|
|
|
|
/* Initialize network. */
|
|
if (init_network() != kStatus_Success)
|
|
{
|
|
PRINTF("\r\nInitialization of network failed.\r\n");
|
|
while (1)
|
|
{
|
|
}
|
|
}
|
|
|
|
BaseType_t xResult = pdFAIL;
|
|
|
|
xResult = KVStore_init();
|
|
|
|
if (xResult == pdFAIL)
|
|
{
|
|
configPRINTF(("Failed to initialize key value configuration store.\r\n"));
|
|
}
|
|
|
|
if (xResult == pdPASS)
|
|
{
|
|
xResult = xMQTTAgentInit(appmainMQTT_AGENT_TASK_STACK_SIZE, appmainMQTT_AGENT_TASK_PRIORITY);
|
|
}
|
|
|
|
if (xResult == pdPASS)
|
|
{
|
|
xResult = xTaskCreate(vShadowDeviceTask, "SHADOW_DEV", appmainSHADOW_DEVICE_TASK_STACK_SIZE, NULL,
|
|
appmainSHADOW_DEVICE_TASK_PRIORITY, NULL);
|
|
}
|
|
|
|
if (xResult == pdPASS)
|
|
{
|
|
xResult = xTaskCreate(vShadowUpdateTask, "SHADOW_APP", appmainSHADOW_UPDATE_TASK_STACK_SIZE, NULL,
|
|
appmainSHADOW_UPDATE_TASK_PRIORITY, NULL);
|
|
}
|
|
|
|
if (xResult != pdPASS)
|
|
{
|
|
PRINTF("\r\nApp main initialization failed.\r\n");
|
|
|
|
for (;;)
|
|
{
|
|
}
|
|
}
|
|
|
|
vTaskDelete(NULL);
|
|
}
|
|
|
|
/**
|
|
* @brief Loop forever if stack overflow is detected.
|
|
*
|
|
* If configCHECK_FOR_STACK_OVERFLOW is set to 1,
|
|
* this hook provides a location for applications to
|
|
* define a response to a stack overflow.
|
|
*
|
|
* Use this hook to help identify that a stack overflow
|
|
* has occurred.
|
|
*
|
|
*/
|
|
void vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName)
|
|
{
|
|
PRINTF("ERROR: stack overflow on task %s.\r\n", pcTaskName);
|
|
|
|
portDISABLE_INTERRUPTS();
|
|
|
|
/* Unused Parameters */
|
|
(void)xTask;
|
|
(void)pcTaskName;
|
|
|
|
/* Loop forever */
|
|
for (;;)
|
|
{
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Warn user if pvPortMalloc fails.
|
|
*
|
|
* Called if a call to pvPortMalloc() fails because there is insufficient
|
|
* free memory available in the FreeRTOS heap. pvPortMalloc() is called
|
|
* internally by FreeRTOS API functions that create tasks, queues, software
|
|
* timers, and semaphores. The size of the FreeRTOS heap is set by the
|
|
* configTOTAL_HEAP_SIZE configuration constant in FreeRTOSConfig.h.
|
|
*
|
|
*/
|
|
void vApplicationMallocFailedHook()
|
|
{
|
|
PRINTF("ERROR: Malloc failed to allocate memory\r\n");
|
|
taskDISABLE_INTERRUPTS();
|
|
|
|
/* Loop forever */
|
|
for (;;)
|
|
{
|
|
}
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
/* configUSE_STATIC_ALLOCATION is set to 1, so the application must provide an
|
|
* implementation of vApplicationGetIdleTaskMemory() to provide the memory that is
|
|
* used by the Idle task. */
|
|
void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer,
|
|
StackType_t **ppxIdleTaskStackBuffer,
|
|
uint32_t *pulIdleTaskStackSize)
|
|
{
|
|
/* If the buffers to be provided to the Idle task are declared inside this
|
|
* function then they must be declared static - otherwise they will be allocated on
|
|
* the stack and so not exists after this function exits. */
|
|
static StaticTask_t xIdleTaskTCB;
|
|
static StackType_t uxIdleTaskStack[configMINIMAL_STACK_SIZE];
|
|
|
|
/* Pass out a pointer to the StaticTask_t structure in which the Idle
|
|
* task's state will be stored. */
|
|
*ppxIdleTaskTCBBuffer = &xIdleTaskTCB;
|
|
|
|
/* Pass out the array that will be used as the Idle task's stack. */
|
|
*ppxIdleTaskStackBuffer = uxIdleTaskStack;
|
|
|
|
/* Pass out the size of the array pointed to by *ppxIdleTaskStackBuffer.
|
|
* Note that, as the array is necessarily of type StackType_t,
|
|
* configMINIMAL_STACK_SIZE is specified in words, not bytes. */
|
|
*pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
/**
|
|
* @brief This is to provide the memory that is used by the RTOS daemon/time task.
|
|
*
|
|
* If configUSE_STATIC_ALLOCATION is set to 1, so the application must provide an
|
|
* implementation of vApplicationGetTimerTaskMemory() to provide the memory that is
|
|
* used by the RTOS daemon/time task.
|
|
*/
|
|
void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer,
|
|
StackType_t **ppxTimerTaskStackBuffer,
|
|
uint32_t *pulTimerTaskStackSize)
|
|
{
|
|
/* If the buffers to be provided to the Timer task are declared inside this
|
|
* function then they must be declared static - otherwise they will be allocated on
|
|
* the stack and so not exists after this function exits. */
|
|
static StaticTask_t xTimerTaskTCB;
|
|
static StackType_t uxTimerTaskStack[configTIMER_TASK_STACK_DEPTH];
|
|
|
|
/* Pass out a pointer to the StaticTask_t structure in which the Idle
|
|
* task's state will be stored. */
|
|
*ppxTimerTaskTCBBuffer = &xTimerTaskTCB;
|
|
|
|
/* Pass out the array that will be used as the Timer task's stack. */
|
|
*ppxTimerTaskStackBuffer = uxTimerTaskStack;
|
|
|
|
/* Pass out the size of the array pointed to by *ppxTimerTaskStackBuffer.
|
|
* Note that, as the array is necessarily of type StackType_t,
|
|
* configMINIMAL_STACK_SIZE is specified in words, not bytes. */
|
|
*pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
static int wifi_reset_prov_mode()
|
|
{
|
|
int ret;
|
|
int c;
|
|
|
|
PRINTF("\r\nDo you want to reset the Wi-Fi module to provisioning mode?\r\n");
|
|
PRINTF("Press 'y' to reset Wi-Fi module.\r\n");
|
|
c = GETCHAR();
|
|
PRINTF("\r\n");
|
|
if (c == 'y')
|
|
{
|
|
PRINTF("Resetting Wi-Fi module...\r\n\r\n");
|
|
ret = mwm_wlan_prov();
|
|
if (ret < 0)
|
|
{
|
|
PRINTF("Wi-Fi reset failed!\r\n");
|
|
return -1;
|
|
}
|
|
vTaskDelay(pdMS_TO_TICKS(6000));
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int init_network(void)
|
|
{
|
|
/* Initialize Wi-Fi */
|
|
configPRINTF(("Initializing Wi-Fi...\r\n"));
|
|
|
|
int ret;
|
|
ret = mwm_init();
|
|
if (ret < 0)
|
|
{
|
|
PRINTF("Could not initialize Serial MWM\r\n");
|
|
return kStatus_Fail;
|
|
}
|
|
|
|
/* Get wlan status */
|
|
ret = mwm_wlan_status();
|
|
if (ret < 0)
|
|
{
|
|
PRINTF("Failed to get WLAN status.\r\n");
|
|
return kStatus_Fail;
|
|
}
|
|
|
|
if (ret == MWM_INITIALIZED)
|
|
{
|
|
/* start wlan */
|
|
ret = mwm_wlan_start();
|
|
if (ret < 0)
|
|
{
|
|
PRINTF("Could not start WLAN subsystem.\r\n");
|
|
return kStatus_Fail;
|
|
}
|
|
}
|
|
|
|
configPRINTF(("Wi-Fi initialized successfully.\r\n"));
|
|
|
|
/* Check connection status */
|
|
while (1)
|
|
{
|
|
/* Get wlan status */
|
|
ret = mwm_wlan_status();
|
|
if (ret < 0)
|
|
{
|
|
PRINTF("Failed to get WLAN status.\r\n");
|
|
return kStatus_Fail;
|
|
}
|
|
else if (ret == MWM_CONNECTED)
|
|
{
|
|
char ssid[33] = {0};
|
|
char ip_addr[16] = {0};
|
|
ret = mwm_wlan_info(ssid, ip_addr);
|
|
PRINTF("Wi-Fi is connected to: %s, IP Address: %s\r\n", ssid, ip_addr);
|
|
PRINTF(
|
|
"\r\nTo reset Wi-Fi module to provisioning mode connect to WLAN: %s, open address: http://%s in web "
|
|
"browser and select \"Reset to Provisioning\".\r\n",
|
|
ssid, ip_addr);
|
|
PRINTF("Then restart this application.\r\n\r\n");
|
|
break;
|
|
}
|
|
else if (ret == MWM_CONNECTING)
|
|
{
|
|
PRINTF("Wi-Fi is connecting...\r\n");
|
|
vTaskDelay(pdMS_TO_TICKS(4000));
|
|
}
|
|
else if (ret == MWM_AUTH_FAILED)
|
|
{
|
|
PRINTF("Connection failed: Wi-Fi authentication failed.\r\n");
|
|
ret = wifi_reset_prov_mode();
|
|
if (ret < 0)
|
|
{
|
|
return kStatus_Fail;
|
|
}
|
|
}
|
|
else if (ret == MWM_NETWORK_NOT_FOUND)
|
|
{
|
|
PRINTF("Connection failed: WLAN not found.\r\n");
|
|
ret = wifi_reset_prov_mode();
|
|
if (ret < 0)
|
|
{
|
|
return kStatus_Fail;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PRINTF("\r\nWi-Fi module is not configured for WLAN connection.\r\n");
|
|
PRINTF(
|
|
"Connect to Wi-Fi AP: Serial2Wifi, open address: http://192.168.10.1 in web browser and configure WLAN "
|
|
"connection.\r\n");
|
|
PRINTF("Press any key to continue.\r\n");
|
|
GETCHAR();
|
|
PRINTF("\r\n");
|
|
}
|
|
}
|
|
|
|
return kStatus_Success;
|
|
}
|