MCUXpresso_LPC55S69/boards/lpcxpresso55s69/aws_examples/shadow_wifi_serial/cm33_core0/main_wifi_serial.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;
}