Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/Flipper-Zero/STM32CubeWB.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'Projects/P-NUCLEO-WB55.Nucleo/Applications/Thread/Thread_Ota_Server/STM32_WPAN/App/app_thread.c')
-rw-r--r--Projects/P-NUCLEO-WB55.Nucleo/Applications/Thread/Thread_Ota_Server/STM32_WPAN/App/app_thread.c1473
1 files changed, 1473 insertions, 0 deletions
diff --git a/Projects/P-NUCLEO-WB55.Nucleo/Applications/Thread/Thread_Ota_Server/STM32_WPAN/App/app_thread.c b/Projects/P-NUCLEO-WB55.Nucleo/Applications/Thread/Thread_Ota_Server/STM32_WPAN/App/app_thread.c
new file mode 100644
index 000000000..c183ab869
--- /dev/null
+++ b/Projects/P-NUCLEO-WB55.Nucleo/Applications/Thread/Thread_Ota_Server/STM32_WPAN/App/app_thread.c
@@ -0,0 +1,1473 @@
+/* USER CODE BEGIN Header */
+/**
+ ******************************************************************************
+ * File Name : App/app_thread.c
+ * Description : Thread Application.
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; Copyright (c) 2019 STMicroelectronics.
+ * All rights reserved.</center></h2>
+ *
+ * This software component is licensed by ST under Ultimate Liberty license
+ * SLA0044, the "License"; You may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at:
+ * www.st.com/SLA0044
+ *
+ ******************************************************************************
+ */
+/* USER CODE END Header */
+
+/* Includes ------------------------------------------------------------------*/
+#include "app_common.h"
+#include "utilities_common.h"
+#include "app_entry.h"
+#include "dbg_trace.h"
+#include "app_thread.h"
+#include "stm32wbxx_core_interface_def.h"
+#include "openthread_api_wb.h"
+#include "shci.h"
+#include "stm_logging.h"
+#include "app_conf.h"
+#include "stm32_lpm.h"
+#include "stm32_seq.h"
+#if (CFG_USB_INTERFACE_ENABLE != 0)
+#include "vcp.h"
+#include "vcp_conf.h"
+#endif /* (CFG_USB_INTERFACE_ENABLE != 0) */
+
+/* Private includes -----------------------------------------------------------*/
+/* USER CODE BEGIN Includes */
+
+/* USER CODE END Includes */
+
+/* Private typedef -----------------------------------------------------------*/
+/* USER CODE BEGIN PTD */
+/**
+ * @brief APP_THREAD Status structures definition
+ */
+typedef enum
+{
+ APP_THREAD_OK = 0x00,
+ APP_THREAD_ERROR = 0x01,
+} APP_THREAD_StatusTypeDef;
+/* USER CODE END PTD */
+
+/* Private defines -----------------------------------------------------------*/
+#define C_SIZE_CMD_STRING 256U
+#define C_PANID 0x1111U
+#define C_CHANNEL_NB 15U
+
+/* USER CODE BEGIN PD */
+#define C_RESSOURCE_FUOTA_PROVISIONING "FUOTA_PROVISIONING"
+#define C_RESSOURCE_FUOTA_PARAMETERS "FUOTA_PARAMETERS"
+#define C_RESSOURCE_FUOTA_SEND "FUOTA_SEND"
+
+/* Following CoAP ressource is requested to reboot on Thread_Ota application */
+#define C_RESSOURCE_FUOTA_REBOOT "FUOTA_REBOOT"
+
+/* Keyword found at the end of Thread Ota compatible application binaries */
+#define FUOTA_MAGIC_KEYWORD_APP 0x94448A29
+
+/* Keyword found at the end of encrypted Copro Wireless binaries */
+#define FUOTA_MAGIC_KEYWORD_COPRO_WIRELESS 0xD3A12C5E
+
+/* Define Address for Application FW Update */
+#define FUOTA_APP_FW_BINARY_ADDRESS (FLASH_BASE + CFG_APP_START_SECTOR_INDEX*0x1000)
+
+/* Define Address for Copro Wireless FW Update */
+#define FUOTA_COPRO_FW_BINARY_ADDRESS (FLASH_BASE + CFG_APP_START_SECTOR_INDEX*0x1000)
+
+#define FUOTA_NUMBER_WORDS_64BITS 50
+#define FUOTA_PAYLOAD_SIZE (FUOTA_NUMBER_WORDS_64BITS * 8)
+
+typedef void (*CoapRespHandlerCallback) (otCoapHeader * pHeader, otMessage * pMessage,const otMessageInfo * pMessageInfo,otError Result);
+/* USER CODE END PD */
+
+/* Private macros ------------------------------------------------------------*/
+/* USER CODE BEGIN PM */
+
+/* USER CODE END PM */
+
+/* Private function prototypes -----------------------------------------------*/
+static void APP_THREAD_CheckWirelessFirmwareInfo(void);
+static void APP_THREAD_DeviceConfig(void);
+static void APP_THREAD_StateNotif(uint32_t NotifFlags, void *pContext);
+static void APP_THREAD_TraceError(const char * pMess, uint32_t ErrCode);
+#if (CFG_FULL_LOW_POWER == 0)
+static void Send_CLI_To_M0(void);
+#endif /* (CFG_FULL_LOW_POWER == 0) */
+static void Send_CLI_Ack_For_OT(void);
+static void HostTxCb( void );
+static void Wait_Getting_Ack_From_M0(void);
+static void Receive_Ack_From_M0(void);
+static void Receive_Notification_From_M0(void);
+#if (CFG_HW_LPUART1_ENABLED == 1)
+extern void MX_LPUART1_UART_Init(void);
+#endif
+#if (CFG_HW_USART1_ENABLED == 1)
+extern void MX_USART1_UART_Init(void);
+#endif
+#if (CFG_USB_INTERFACE_ENABLE != 0)
+static uint32_t ProcessCmdString(uint8_t* buf , uint32_t len);
+#else
+#if (CFG_FULL_LOW_POWER == 0)
+static void RxCpltCallback(void);
+#endif /* (CFG_FULL_LOW_POWER == 0) */
+#endif /* (CFG_USB_INTERFACE_ENABLE != 0) */
+
+/* USER CODE BEGIN PFP */
+static void APP_THREAD_CoapSendRequest(otCoapResource* pCoapRessource,
+ otCoapType CoapType,
+ otCoapCode CoapCode,
+ otIp6Address* Ip6Address,
+ const char* StringAddress,
+ APP_THREAD_CoapAddressTypeDef_t CoapAddressType,
+ uint8_t* Payload,
+ uint16_t Size,
+ CoapRespHandlerCallback RespHandlerCb);
+
+static void APP_THREAD_DummyReqHandler(void * p_context,
+ otCoapHeader * pHeader,
+ otMessage * pMessage,
+ const otMessageInfo * pMessageInfo);
+static void APP_THREAD_ProvisioningRespHandler(otCoapHeader * pHeader,
+ otMessage * pMessage,
+ const otMessageInfo * pMessageInfo,
+ otError Result);
+static void APP_THREAD_CoapDummyRespHandler(void * p_context,
+ otCoapHeader * pHeader,
+ otMessage * pMessage,
+ const otMessageInfo * pMessageInfo,
+ otError Result);
+
+static void APP_THREAD_CoapRespHandlerFuotaSend(otCoapHeader * pHeader,
+ otMessage * pMessage,
+ const otMessageInfo * pMessageInfo,
+ otError Result);
+static void APP_THREAD_CoapRespHandlerFuotaReboot(otCoapHeader * pHeader,
+ otMessage * pMessage,
+ const otMessageInfo * pMessageInfo,
+ otError Result);
+static void APP_THREAD_CoapRespHandlerFuotaParameters(otCoapHeader * pHeader,
+ otMessage * pMessage,
+ const otMessageInfo * pMessageInfo,
+ otError Result);
+
+static void APP_THREAD_FuotaSetParamApp(void);
+static void APP_THREAD_FuotaSetParamCoproWireless(void);
+static APP_THREAD_StatusTypeDef APP_THREAD_SetOtaContext(APP_THREAD_OtaFileTypeDef_t file_type);
+static void APP_THREAD_FuotaProvisioning(void);
+static void APP_THREAD_FuotaSend(void);
+static uint32_t APP_THREAD_GetBinSize(void);
+static void APP_THREAD_FuotaParameters(void);
+static void APP_THREAD_FuotaReboot(void);
+
+/* USER CODE END PFP */
+
+/* Private variables -----------------------------------------------*/
+#if (CFG_USB_INTERFACE_ENABLE != 0)
+static uint8_t TmpString[C_SIZE_CMD_STRING];
+static uint8_t VcpRxBuffer[sizeof(TL_CmdSerial_t)]; /* Received Data over USB are stored in this buffer */
+static uint8_t VcpTxBuffer[sizeof(TL_EvtPacket_t) + 254U]; /* Transmit buffer over USB */
+#else
+#if (CFG_FULL_LOW_POWER == 0)
+static uint8_t aRxBuffer[C_SIZE_CMD_STRING];
+#endif /* (CFG_FULL_LOW_POWER == 0) */
+#endif /* (CFG_USB_INTERFACE_ENABLE != 0) */
+
+#if (CFG_FULL_LOW_POWER == 0)
+static uint8_t CommandString[C_SIZE_CMD_STRING];
+#endif /* (CFG_FULL_LOW_POWER == 0) */
+static __IO uint16_t indexReceiveChar = 0;
+static __IO uint16_t CptReceiveCmdFromUser = 0;
+
+static TL_CmdPacket_t *p_thread_otcmdbuffer;
+static TL_EvtPacket_t *p_thread_notif_M0_to_M4;
+static __IO uint32_t CptReceiveMsgFromM0 = 0;
+PLACE_IN_SECTION("MB_MEM1") ALIGN(4) static TL_TH_Config_t ThreadConfigBuffer;
+PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static TL_CmdPacket_t ThreadOtCmdBuffer;
+PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static uint8_t ThreadNotifRspEvtBuffer[sizeof(TL_PacketHeader_t) + TL_EVT_HDR_SIZE + 255U];
+PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static TL_CmdPacket_t ThreadCliCmdBuffer;
+
+/* USER CODE BEGIN PV */
+static otCoapResource OT_RessourceFuotaProvisioning = {C_RESSOURCE_FUOTA_PROVISIONING, APP_THREAD_DummyReqHandler, NULL, NULL};
+static otCoapResource OT_RessourceFuotaParameters = {C_RESSOURCE_FUOTA_PARAMETERS, APP_THREAD_DummyReqHandler, NULL, NULL};
+static otCoapResource OT_RessourceFuotaSend = {C_RESSOURCE_FUOTA_SEND, APP_THREAD_DummyReqHandler, NULL, NULL};
+static otCoapResource OT_RessourceFuotaReboot = {C_RESSOURCE_FUOTA_REBOOT, APP_THREAD_DummyReqHandler, NULL, NULL};
+
+static uint8_t OT_Command = 0;
+static otMessageInfo OT_MessageInfo = {0};
+static otCoapHeader OT_Header = {0};
+static otMessage* pOT_Message = NULL;
+static uint16_t OT_BufferIdSend = 1U;
+
+static otIp6Address OT_PeerAddress = { .mFields.m8 = { 0 } };
+
+static uint64_t FuotaTransferArray[FUOTA_NUMBER_WORDS_64BITS] = {0};
+
+static APP_THREAD_OtaContext_t OtaContext;
+/* USER CODE END PV */
+
+/* Functions Definition ------------------------------------------------------*/
+
+void APP_THREAD_Init( void )
+{
+ /* USER CODE BEGIN APP_THREAD_INIT_1 */
+ APP_DBG("Thread_Ota_Server Application");
+ /* USER CODE END APP_THREAD_INIT_1 */
+
+ SHCI_CmdStatus_t ThreadInitStatus;
+
+ /* Check the compatibility with the Coprocessor Wireless Firmware loaded */
+ APP_THREAD_CheckWirelessFirmwareInfo();
+
+#if (CFG_USB_INTERFACE_ENABLE != 0)
+ VCP_Init(&VcpTxBuffer[0], &VcpRxBuffer[0]);
+#endif /* (CFG_USB_INTERFACE_ENABLE != 0) */
+
+ /* Register cmdbuffer */
+ APP_THREAD_RegisterCmdBuffer(&ThreadOtCmdBuffer);
+
+ /**
+ * Do not allow standby in the application
+ */
+ UTIL_LPM_SetOffMode(1 << CFG_LPM_APP_THREAD, UTIL_LPM_DISABLE);
+
+ /* Init config buffer and call TL_THREAD_Init */
+ APP_THREAD_TL_THREAD_INIT();
+
+ /* Configure UART for sending CLI command from M4 */
+ APP_THREAD_Init_UART_CLI();
+
+ /* Send Thread start system cmd to M0 */
+ ThreadInitStatus = SHCI_C2_THREAD_Init();
+
+ /* Prevent unused argument(s) compilation warning */
+ UNUSED(ThreadInitStatus);
+
+ /* Register task */
+ /* Create the different tasks */
+ UTIL_SEQ_RegTask( 1<<(uint32_t)CFG_TASK_MSG_FROM_M0_TO_M4, UTIL_SEQ_RFU, APP_THREAD_ProcessMsgM0ToM4);
+
+ /* USER CODE BEGIN INIT TASKS */
+ UTIL_SEQ_RegTask( 1<<(uint32_t)CFG_TASK_BUTTON_SW1, UTIL_SEQ_RFU, APP_THREAD_FuotaSetParamApp);
+ UTIL_SEQ_RegTask( 1<<(uint32_t)CFG_TASK_BUTTON_SW3, UTIL_SEQ_RFU, APP_THREAD_FuotaSetParamCoproWireless);
+ UTIL_SEQ_RegTask( 1<<(uint32_t)CFG_TASK_FUOTA_SEND, UTIL_SEQ_RFU, APP_THREAD_FuotaSend);
+ UTIL_SEQ_RegTask( 1<<(uint32_t)CFG_TASK_FUOTA_PARAMETERS, UTIL_SEQ_RFU, APP_THREAD_FuotaParameters);
+ UTIL_SEQ_RegTask( 1<<(uint32_t)CFG_TASK_FUOTA_REBOOT, UTIL_SEQ_RFU, APP_THREAD_FuotaReboot);
+ /* USER CODE END INIT TASKS */
+
+ /* Initialize and configure the Thread device*/
+ APP_THREAD_DeviceConfig();
+
+ /* USER CODE BEGIN APP_THREAD_INIT_2 */
+
+ /* USER CODE END APP_THREAD_INIT_2 */
+}
+
+/**
+ * @brief Trace the error or the warning reported.
+ * @param ErrId :
+ * @param ErrCode
+ * @retval None
+ */
+void APP_THREAD_Error(uint32_t ErrId, uint32_t ErrCode)
+{
+ /* USER CODE BEGIN APP_THREAD_Error_1 */
+
+ /* USER CODE END APP_THREAD_Error_1 */
+ switch(ErrId)
+ {
+ case ERR_REC_MULTI_MSG_FROM_M0 :
+ APP_THREAD_TraceError("ERROR : ERR_REC_MULTI_MSG_FROM_M0 ", ErrCode);
+ break;
+ case ERR_THREAD_SET_STATE_CB :
+ APP_THREAD_TraceError("ERROR : ERR_THREAD_SET_STATE_CB ",ErrCode);
+ break;
+ case ERR_THREAD_SET_CHANNEL :
+ APP_THREAD_TraceError("ERROR : ERR_THREAD_SET_CHANNEL ",ErrCode);
+ break;
+ case ERR_THREAD_SET_PANID :
+ APP_THREAD_TraceError("ERROR : ERR_THREAD_SET_PANID ",ErrCode);
+ break;
+ case ERR_THREAD_IPV6_ENABLE :
+ APP_THREAD_TraceError("ERROR : ERR_THREAD_IPV6_ENABLE ",ErrCode);
+ break;
+ case ERR_THREAD_START :
+ APP_THREAD_TraceError("ERROR: ERR_THREAD_START ", ErrCode);
+ break;
+ case ERR_THREAD_ERASE_PERSISTENT_INFO :
+ APP_THREAD_TraceError("ERROR : ERR_THREAD_ERASE_PERSISTENT_INFO ",ErrCode);
+ break;
+ case ERR_THREAD_CHECK_WIRELESS :
+ APP_THREAD_TraceError("ERROR : ERR_THREAD_CHECK_WIRELESS ",ErrCode);
+ break;
+ /* USER CODE BEGIN APP_THREAD_Error_2 */
+ case ERR_THREAD_COAP_START :
+ APP_THREAD_TraceError("ERROR : ERR_THREAD_COAP_START ",ErrCode);
+ break;
+ case ERR_THREAD_COAP_ADD_RESSOURCE :
+ APP_THREAD_TraceError("ERROR : ERR_THREAD_COAP_ADD_RESSOURCE ",ErrCode);
+ break;
+ case ERR_THREAD_MESSAGE_READ :
+ APP_THREAD_TraceError("ERROR : ERR_THREAD_MESSAGE_READ ",ErrCode);
+ break;
+ case ERR_THREAD_COAP_SEND_RESPONSE :
+ APP_THREAD_TraceError("ERROR : ERR_THREAD_COAP_SEND_RESPONSE ",ErrCode);
+ break;
+ case ERR_THREAD_COAP_APPEND :
+ APP_THREAD_TraceError("ERROR : ERR_THREAD_COAP_APPEND ",ErrCode);
+ break;
+ case ERR_THREAD_COAP_SEND_REQUEST :
+ APP_THREAD_TraceError("ERROR : ERR_THREAD_COAP_SEND_REQUEST ",ErrCode);
+ break;
+ case ERR_THREAD_MSG_COMPARE_FAILED:
+ APP_THREAD_TraceError("ERROR : ERR_THREAD_MSG_COMPARE_FAILED ",ErrCode);
+ break;
+ /* USER CODE END APP_THREAD_Error_2 */
+ default :
+ APP_THREAD_TraceError("ERROR Unknown ", 0);
+ break;
+ }
+}
+
+/*************************************************************
+ *
+ * LOCAL FUNCTIONS
+ *
+ *************************************************************/
+
+/**
+ * @brief Thread initialization.
+ * @param None
+ * @retval None
+ */
+static void APP_THREAD_DeviceConfig(void)
+{
+ otError error;
+ error = otInstanceErasePersistentInfo(NULL);
+ if (error != OT_ERROR_NONE)
+ {
+ APP_THREAD_Error(ERR_THREAD_ERASE_PERSISTENT_INFO,error);
+ }
+ otInstanceFinalize(NULL);
+ otInstanceInitSingle();
+ error = otSetStateChangedCallback(NULL, APP_THREAD_StateNotif, NULL);
+ if (error != OT_ERROR_NONE)
+ {
+ APP_THREAD_Error(ERR_THREAD_SET_STATE_CB,error);
+ }
+ error = otLinkSetChannel(NULL, C_CHANNEL_NB);
+ if (error != OT_ERROR_NONE)
+ {
+ APP_THREAD_Error(ERR_THREAD_SET_CHANNEL,error);
+ }
+ error = otLinkSetPanId(NULL, C_PANID);
+ if (error != OT_ERROR_NONE)
+ {
+ APP_THREAD_Error(ERR_THREAD_SET_PANID,error);
+ }
+ error = otIp6SetEnabled(NULL, true);
+ if (error != OT_ERROR_NONE)
+ {
+ APP_THREAD_Error(ERR_THREAD_IPV6_ENABLE,error);
+ }
+ error = otThreadSetEnabled(NULL, true);
+ if (error != OT_ERROR_NONE)
+ {
+ APP_THREAD_Error(ERR_THREAD_START,error);
+ }
+
+ /* USER CODE BEGIN DEVICECONFIG */
+ /* Start the COAP server */
+ error = otCoapStart(NULL, OT_DEFAULT_COAP_PORT);
+ if (error != OT_ERROR_NONE)
+ {
+ APP_THREAD_Error(ERR_THREAD_COAP_START,error);
+ }
+ /* Add COAP resources */
+ error = otCoapAddResource(NULL, &OT_RessourceFuotaProvisioning);
+ if (error != OT_ERROR_NONE)
+ {
+ APP_THREAD_Error(ERR_THREAD_COAP_ADD_RESSOURCE,error);
+ }
+ error = otCoapAddResource(NULL, &OT_RessourceFuotaSend);
+ if (error != OT_ERROR_NONE)
+ {
+ APP_THREAD_Error(ERR_THREAD_COAP_ADD_RESSOURCE,error);
+ }
+ /* USER CODE END DEVICECONFIG */
+}
+
+/**
+ * @brief Thread notification when the state changes.
+ * @param aFlags : Define the item that has been modified
+ * aContext: Context
+ *
+ * @retval None
+ */
+static void APP_THREAD_StateNotif(uint32_t NotifFlags, void *pContext)
+{
+ /* Prevent unused argument(s) compilation warning */
+ UNUSED(pContext);
+
+ /* USER CODE BEGIN APP_THREAD_STATENOTIF */
+
+ /* USER CODE END APP_THREAD_STATENOTIF */
+
+ if ((NotifFlags & (uint32_t)OT_CHANGED_THREAD_ROLE) == (uint32_t)OT_CHANGED_THREAD_ROLE)
+ {
+ switch (otThreadGetDeviceRole(NULL))
+ {
+ case OT_DEVICE_ROLE_DISABLED:
+ /* USER CODE BEGIN OT_DEVICE_ROLE_DISABLED */
+ BSP_LED_Off(LED2);
+ BSP_LED_Off(LED3);
+ /* USER CODE END OT_DEVICE_ROLE_DISABLED */
+ break;
+ case OT_DEVICE_ROLE_DETACHED:
+ /* USER CODE BEGIN OT_DEVICE_ROLE_DETACHED */
+ BSP_LED_Off(LED2);
+ BSP_LED_Off(LED3);
+ /* USER CODE END OT_DEVICE_ROLE_DETACHED */
+ break;
+ case OT_DEVICE_ROLE_CHILD:
+ /* USER CODE BEGIN OT_DEVICE_ROLE_CHILD */
+ BSP_LED_Off(LED2);
+ BSP_LED_On(LED3);
+ /* USER CODE END OT_DEVICE_ROLE_CHILD */
+ break;
+ case OT_DEVICE_ROLE_ROUTER :
+ /* USER CODE BEGIN OT_DEVICE_ROLE_ROUTER */
+ BSP_LED_Off(LED2);
+ BSP_LED_On(LED3);
+ /* USER CODE END OT_DEVICE_ROLE_ROUTER */
+ break;
+ case OT_DEVICE_ROLE_LEADER :
+ /* USER CODE BEGIN OT_DEVICE_ROLE_LEADER */
+ BSP_LED_On(LED2);
+ BSP_LED_Off(LED3);
+ /* USER CODE END OT_DEVICE_ROLE_LEADER */
+ break;
+ default:
+ /* USER CODE BEGIN DEFAULT */
+ BSP_LED_Off(LED2);
+ BSP_LED_Off(LED3);
+ /* USER CODE END DEFAULT */
+ break;
+ }
+ }
+}
+
+/**
+ * @brief Warn the user that an error has occurred.In this case,
+ * the LEDs on the Board will start blinking.
+ *
+ * @param pMess : Message associated to the error.
+ * @param ErrCode: Error code associated to the module (OpenThread or other module if any)
+ * @retval None
+ */
+static void APP_THREAD_TraceError(const char * pMess, uint32_t ErrCode)
+{
+ /* USER CODE BEGIN TRACE_ERROR */
+ APP_DBG("**** Fatal error = %s (Err = %d)", pMess, ErrCode);
+ while(1U == 1U)
+ {
+ BSP_LED_Toggle(LED1);
+ HAL_Delay(500U);
+ BSP_LED_Toggle(LED2);
+ HAL_Delay(500U);
+ BSP_LED_Toggle(LED3);
+ HAL_Delay(500U);
+ }
+ /* USER CODE END TRACE_ERROR */
+}
+
+/**
+ * @brief Check if the Coprocessor Wireless Firmware loaded supports Thread
+ * and display associated informations
+ * @param None
+ * @retval None
+ */
+static void APP_THREAD_CheckWirelessFirmwareInfo(void)
+{
+ WirelessFwInfo_t wireless_info_instance;
+ WirelessFwInfo_t* p_wireless_info = &wireless_info_instance;
+
+ if (SHCI_GetWirelessFwInfo(p_wireless_info) != SHCI_Success)
+ {
+ APP_THREAD_Error((uint32_t)ERR_THREAD_CHECK_WIRELESS, (uint32_t)ERR_INTERFACE_FATAL);
+ }
+ else
+ {
+ APP_DBG("**********************************************************");
+ APP_DBG("WIRELESS COPROCESSOR FW:");
+ /* Print version */
+ APP_DBG("VERSION ID = %d.%d.%d", p_wireless_info->VersionMajor, p_wireless_info->VersionMinor, p_wireless_info->VersionSub);
+
+ switch(p_wireless_info->StackType)
+ {
+ case INFO_STACK_TYPE_THREAD_FTD :
+ APP_DBG("FW Type : Thread FTD");
+ break;
+ case INFO_STACK_TYPE_THREAD_MTD :
+ APP_DBG("FW Type : Thread MTD");
+ break;
+ case INFO_STACK_TYPE_BLE_THREAD_FTD_STATIC :
+ APP_DBG("FW Type : Static Concurrent Mode BLE/Thread");
+ break;
+ default :
+ /* No Thread device supported ! */
+ APP_THREAD_Error((uint32_t)ERR_THREAD_CHECK_WIRELESS, (uint32_t)ERR_INTERFACE_FATAL);
+ break;
+ }
+ APP_DBG("**********************************************************");
+ }
+}
+/* USER CODE BEGIN FD_LOCAL_FUNCTIONS */
+/**
+ * @brief Send a CoAP request with defined parameters.
+ *
+ * @param[in] pCoapRessource A pointer to a otCoapResource.
+ * @param[in] CoapType otCoapType.
+ * @param[in] otCoapCode otCoapCode.
+ * @param[in] Ip6Address A pointer to otIp6Address.
+ * @param[in] StringAddress A pointer to a NULL-terminated string representing the address. Example: "FF03::1" for Multicast.
+ * @param[in] CoapAddressType Decide to use IP6Address or StringAddress.
+ * @param[in] Payload A pointer to payload.
+ * @param[in] Size Size of the transfer in bytes.
+ * @param[in] RespHandlerCb Callback function called in case of confirmable message.
+ *
+ * @retval none.
+ */
+static void APP_THREAD_CoapSendRequest(otCoapResource* pCoapRessource,
+ otCoapType CoapType,
+ otCoapCode CoapCode,
+ otIp6Address* Ip6Address,
+ const char* StringAddress,
+ APP_THREAD_CoapAddressTypeDef_t CoapAddressType,
+ uint8_t* Payload,
+ uint16_t Size,
+ CoapRespHandlerCallback RespHandlerCb)
+{
+ otError error = OT_ERROR_NONE;
+ OT_BufferIdSend = 0;
+
+ do{
+ otCoapHeaderInit(&OT_Header, CoapType, CoapCode);
+ otCoapHeaderSetMessageId(&OT_Header,OT_BufferIdSend);
+ otCoapHeaderGenerateToken(&OT_Header, 2U);
+
+ error = otCoapHeaderAppendUriPathOptions(&OT_Header, pCoapRessource->mUriPath);
+ if (error != OT_ERROR_NONE)
+ {
+ APP_THREAD_Error(ERR_THREAD_COAP_APEND_URI,error);
+ }
+
+ if(CoapCode != OT_COAP_CODE_GET)
+ {
+ otCoapHeaderSetPayloadMarker(&OT_Header);
+ }
+
+ pOT_Message = otCoapNewMessage(NULL, &OT_Header);
+ if (pOT_Message == NULL)
+ {
+ APP_THREAD_Error(ERR_THREAD_COAP_NEW_MSG,error);
+ break;
+ }
+
+ if(CoapCode != OT_COAP_CODE_GET)
+ {
+ error = otMessageAppend(pOT_Message, Payload, Size);
+ if (error != OT_ERROR_NONE)
+ {
+ APP_THREAD_Error(ERR_THREAD_COAP_APPEND,error);
+ break;
+ }
+ }
+
+ memset(&OT_MessageInfo, 0, sizeof(OT_MessageInfo));
+ OT_MessageInfo.mInterfaceId = OT_NETIF_INTERFACE_ID_THREAD;
+ OT_MessageInfo.mPeerPort = OT_DEFAULT_COAP_PORT;
+
+ if(CoapAddressType == APP_THREAD_COAP_STRING_ADDRESS)
+ {
+ otIp6AddressFromString(StringAddress, &OT_MessageInfo.mPeerAddr);
+ }
+ else if (CoapAddressType == APP_THREAD_COAP_IP6_ADDRESS)
+ {
+ memcpy(&OT_MessageInfo.mPeerAddr, Ip6Address, sizeof(OT_MessageInfo.mPeerAddr));
+ }
+ else
+ {
+ /* ERROR : should never be in a not defined address type */
+ APP_THREAD_Error(ERR_THREAD_BAD_ADDRESS_TYPE, 0);
+ }
+
+ error = otCoapSendRequest(NULL,
+ pOT_Message,
+ &OT_MessageInfo,
+ &APP_THREAD_CoapDummyRespHandler,
+ (void*)RespHandlerCb);
+
+ }while(false);
+ if (error != OT_ERROR_NONE && pOT_Message != NULL)
+ {
+ otMessageFree(pOT_Message);
+ APP_THREAD_Error(ERR_THREAD_COAP_SEND_REQUEST,error);
+ }
+}
+
+/**
+ * @brief Dummy request handler
+ *
+ * @param None
+ * @retval None
+ */
+static void APP_THREAD_DummyReqHandler(void * p_context,
+ otCoapHeader * pHeader,
+ otMessage * pMessage,
+ const otMessageInfo * pMessageInfo)
+{
+}
+
+/**
+ * @brief This function manages the response handler for provisioning.
+ *
+ * @param pHeader header
+ * @param pMessage message pointer
+ * @param pMessageInfo message info pointer
+ * @param Result error code
+ * @retval None
+ */
+static void APP_THREAD_ProvisioningRespHandler(otCoapHeader * pHeader,
+ otMessage * pMessage,
+ const otMessageInfo * pMessageInfo,
+ otError Result)
+{
+ if (Result == OT_ERROR_NONE)
+ {
+ if ((otMessageRead(pMessage, otMessageGetOffset(pMessage), &OT_Command, sizeof(OT_Command)) == sizeof(OT_Command)))
+ {
+ /* Retrieve the Message */
+ if (otMessageRead(pMessage,
+ otMessageGetOffset(pMessage) + sizeof(OT_Command),
+ &OT_PeerAddress,
+ sizeof(OT_PeerAddress)) != sizeof(OT_PeerAddress))
+ {
+ APP_THREAD_Error(ERR_THREAD_MESSAGE_READ, 0);
+ }
+ APP_DBG("\r -> Succesfully retrieved Remote device address \n");
+
+ /* Notify provisioning OK */
+ UTIL_SEQ_SetTask(TASK_FUOTA_PARAMETERS, CFG_SCH_PRIO_1);
+ }
+ }
+ else
+ {
+ APP_DBG("WARNING: APP_THREAD_CoapDataRespHandler fail with ERROR code = %d",Result);
+ }
+}
+
+/**
+ * @brief This function manages the response handler for FUOTA binary datas.
+ *
+ * @param pHeader header
+ * @param pMessage message pointer
+ * @param pMessageInfo message info pointer
+ * @param Result error code
+ * @retval None
+ */
+static void APP_THREAD_CoapRespHandlerFuotaSend(otCoapHeader * pHeader,
+ otMessage * pMessage,
+ const otMessageInfo * pMessageInfo,
+ otError Result)
+{
+ if (Result == OT_ERROR_NONE)
+ {
+ UTIL_SEQ_SetEvt(EVENT_TRANSFER_64BITS_DONE);
+ }
+ else
+ {
+ APP_DBG("APP_THREAD_CoapRespHandlerFuotaSend : WARNING Result %d", Result);
+ }
+}
+
+/**
+ * @brief This function is used to handle a dummy response handler
+ *
+ * @param p_context context
+ * @param pHeader coap header
+ * @param pMessage message
+ * @paramp pMessageInfo otMessage information
+ * @param Result error status
+ * @retval None
+ */
+static void APP_THREAD_CoapDummyRespHandler(void * p_context,
+ otCoapHeader * pHeader,
+ otMessage * pMessage,
+ const otMessageInfo * pMessageInfo,
+ otError Result)
+{
+ /* Prevent unused argument(s) compilation warning */
+ UNUSED(p_context);
+ UNUSED(pHeader);
+ UNUSED(pMessage);
+ UNUSED(pMessageInfo);
+ UNUSED(Result);
+}
+
+/**
+ * @brief Set FUOTA parameters for APP FW.
+ * @param None
+ * @retval None
+ */
+static void APP_THREAD_FuotaSetParamApp(void)
+{
+ APP_THREAD_StatusTypeDef status;
+
+ status = APP_THREAD_SetOtaContext(APP_THREAD_OTA_FILE_TYPE_FW_APP);
+
+ if (status == APP_THREAD_OK)
+ {
+ APP_THREAD_FuotaProvisioning();
+ }
+ else
+ {
+ APP_DBG("WARNING: Setting Ota Context failed, do not send FUOTA PROVISIONING");
+ }
+}
+
+/**
+ * @brief Set FUOTA parameters for Copro Wireless FW.
+ * @param None
+ * @retval None
+ */
+static void APP_THREAD_FuotaSetParamCoproWireless(void)
+{
+ APP_THREAD_StatusTypeDef status;
+
+ status = APP_THREAD_SetOtaContext(APP_THREAD_OTA_FILE_TYPE_FW_COPRO_WIRELESS);
+
+ if (status == APP_THREAD_OK)
+ {
+ APP_THREAD_FuotaProvisioning();
+ }
+ else
+ {
+ APP_DBG("WARNING: Setting Ota Context failed, do not send FUOTA PROVISIONING");
+ }
+}
+
+/**
+ * @brief Set Ota Context.
+ * @param None
+ * @retval None
+ */
+static APP_THREAD_StatusTypeDef APP_THREAD_SetOtaContext(APP_THREAD_OtaFileTypeDef_t file_type)
+{
+ if (file_type == APP_THREAD_OTA_FILE_TYPE_FW_APP)
+ {
+ OtaContext.file_type = APP_THREAD_OTA_FILE_TYPE_FW_APP;
+ /* Set base address for FUOTA download */
+ OtaContext.base_address = FUOTA_APP_FW_BINARY_ADDRESS;
+ OtaContext.magic_keyword = FUOTA_MAGIC_KEYWORD_APP;
+ }
+ else if (file_type == APP_THREAD_OTA_FILE_TYPE_FW_COPRO_WIRELESS)
+ {
+ OtaContext.file_type = APP_THREAD_OTA_FILE_TYPE_FW_COPRO_WIRELESS;
+ /* Set base address for FUOTA download */
+ OtaContext.base_address = FUOTA_COPRO_FW_BINARY_ADDRESS;
+ OtaContext.magic_keyword = FUOTA_MAGIC_KEYWORD_COPRO_WIRELESS;
+ }
+ else
+ {
+ APP_DBG("WARNING: Unrecognized file_type = %d", file_type);
+ return APP_THREAD_ERROR;
+ }
+
+ /* Set binary size */
+ OtaContext.binary_size = APP_THREAD_GetBinSize();
+
+ /* Return the function status */
+ return APP_THREAD_OK;
+}
+
+/**
+ * @brief Sends Provisioning request.
+ * @param None
+ * @retval None
+ */
+static void APP_THREAD_FuotaProvisioning(void)
+{
+ APP_DBG("Send FUOTA PROVISONING request");
+
+ uint8_t l_provisioning_data = 0x1;
+
+ /* Send a MULTICAST CONFIRMABLE GET Request */
+ APP_THREAD_CoapSendRequest(&OT_RessourceFuotaProvisioning,
+ OT_COAP_TYPE_NON_CONFIRMABLE,
+ OT_COAP_CODE_GET,
+ NULL,
+ MULICAST_FTD_MED,
+ APP_THREAD_COAP_STRING_ADDRESS,
+ &l_provisioning_data,
+ sizeof(l_provisioning_data),
+ &APP_THREAD_ProvisioningRespHandler);
+}
+
+static uint32_t APP_THREAD_GetBinSize(void)
+{
+ uint32_t flash_current_offset = 0;
+ uint64_t read64 = 0;
+ bool binary_parsing_on_going = TRUE;
+ bool error_keyword_or_size = FALSE;
+ uint32_t first_secure_sector_idx;
+ uint32_t maximum_reachable_offset;
+ uint32_t fuota_bin_size = 0;
+
+ first_secure_sector_idx = (READ_BIT(FLASH->SFR, FLASH_SFR_SFSA) >> FLASH_SFR_SFSA_Pos);
+ APP_DBG("SFSA set to %dth sector", first_secure_sector_idx);
+
+ /* Compute Maximum reachable address */
+ maximum_reachable_offset = (first_secure_sector_idx * 0x1000) - 1;
+ APP_DBG("maximum_reachable_offset = 0x%x", maximum_reachable_offset);
+
+ while(binary_parsing_on_going == TRUE){
+ read64 = *(uint64_t*)(OtaContext.base_address + flash_current_offset);
+
+ /* Test if current word contains magic keyword */
+ if((read64 & 0x00000000FFFFFFFF) == OtaContext.magic_keyword)
+ {
+ binary_parsing_on_going = FALSE;
+ }
+ else if (((read64 & 0xFFFFFFFF00000000) >> 32) == OtaContext.magic_keyword)
+ {
+ binary_parsing_on_going = FALSE;
+ }
+
+ flash_current_offset += 8;
+
+ /* Test current offset is still below SFSA (Non-Secure Memory Address) */
+ if(flash_current_offset > maximum_reachable_offset)
+ {
+ error_keyword_or_size = TRUE;
+ binary_parsing_on_going = FALSE;
+ }
+ }
+
+ if(error_keyword_or_size == TRUE)
+ {
+ APP_DBG("Error: FUOTA Keyword not found in FLASH memory, aborting!");
+ APP_THREAD_Error(ERR_THREAD_FUOTA_NO_KEYWORD, 0);
+ }
+ else
+ {
+ fuota_bin_size = flash_current_offset;
+ }
+
+ return fuota_bin_size;
+}
+
+/**
+ * @brief Task associated to FUOTA parameters to be sent.
+ * @param None
+ * @retval None
+ */
+static void APP_THREAD_FuotaParameters(void)
+{
+ APP_DBG("FUOTA PROVISIONING OK, Set FUOTA PARAMETERS");
+
+ if(OtaContext.file_type == APP_THREAD_OTA_FILE_TYPE_FW_APP)
+ {
+ APP_DBG("\r File type = FW_APP");
+ }
+ else if (OtaContext.file_type == APP_THREAD_OTA_FILE_TYPE_FW_COPRO_WIRELESS)
+ {
+ APP_DBG("\r File type = FW_COPRO_WIRELESS");
+ }
+ else
+ {
+ APP_DBG("FUOTA_PARAMETERS: File Type not recognized");
+ APP_THREAD_Error(ERR_THREAD_FUOTA_FILE_TYPE_NOT_RECOGNIZED, 0);
+ }
+
+ APP_DBG("\r Binary size = %d bytes", OtaContext.binary_size);
+ APP_DBG("\r Magic keyword = 0x%x", OtaContext.magic_keyword);
+ APP_DBG("\r Base address = 0x%x", OtaContext.base_address);
+
+ /* Send a CONFIRMABLE PUT Request */
+ APP_THREAD_CoapSendRequest(&OT_RessourceFuotaParameters,
+ OT_COAP_TYPE_CONFIRMABLE,
+ OT_COAP_CODE_PUT,
+ &OT_PeerAddress,
+ NULL,
+ APP_THREAD_COAP_IP6_ADDRESS,
+ (uint8_t*)&OtaContext,
+ sizeof(OtaContext),
+ &APP_THREAD_CoapRespHandlerFuotaParameters);
+}
+
+/**
+ * @brief Task associated to FUOTA binary data sending.
+ * @param None
+ * @retval None
+ */
+static void APP_THREAD_FuotaSend(void)
+{
+ uint32_t flash_current_offset = 0x0;
+ bool binary_transfer_on_going = TRUE;
+ uint32_t l_debug_count = 0;
+ uint32_t l_current_index_progress = 0;
+ uint32_t FuotaProgressArray[100] = {0};
+ uint32_t FuotaTransferArraySize = 0;
+ uint32_t l_start_transfer_time = 0;
+ uint32_t l_end_transfer_time = 0;
+ double l_transfer_time = 0;
+ double l_transfer_throughput = 0;
+ uint8_t l_Fuota_progress_multiplied = 0;
+
+ APP_DBG("FUOTA PARAMETERS SET, START FUOTA BINARY TRANSFER");
+
+ /* Number of elements in OtaContext.binary_size */
+ FuotaTransferArraySize = OtaContext.binary_size / FUOTA_PAYLOAD_SIZE;
+ APP_DBG("\r -> %d elements of %d bytes to be transferred", FuotaTransferArraySize, FUOTA_PAYLOAD_SIZE);
+ if(FuotaTransferArraySize < 100)
+ {
+ l_Fuota_progress_multiplied = 1;
+ FuotaTransferArraySize = FuotaTransferArraySize * 10;
+ }
+ for (int index = 1; index < 100; index++)
+ {
+ FuotaProgressArray[index] = (FuotaTransferArraySize / 100) * index;
+ }
+
+ l_start_transfer_time = HAL_GetTick();
+
+ while(binary_transfer_on_going == TRUE){
+
+ /* Get data to be sent */
+ /* Read data from flash memory */
+ memcpy(FuotaTransferArray, (uint8_t*)(OtaContext.base_address + flash_current_offset), FUOTA_PAYLOAD_SIZE);
+
+ /* Send a CONFIRMABLE PUT Request */
+ APP_THREAD_CoapSendRequest(&OT_RessourceFuotaSend,
+ OT_COAP_TYPE_CONFIRMABLE,
+ OT_COAP_CODE_PUT,
+ &OT_PeerAddress,
+ NULL,
+ APP_THREAD_COAP_IP6_ADDRESS,
+ (uint8_t*)&FuotaTransferArray,
+ FUOTA_PAYLOAD_SIZE,
+ &APP_THREAD_CoapRespHandlerFuotaSend);
+
+ UTIL_SEQ_WaitEvt(EVENT_TRANSFER_64BITS_DONE);
+
+ /* Test if magic Keyword is in FuotaTransferArray */
+ for (int index = 0; index < FUOTA_NUMBER_WORDS_64BITS; ++index) {
+ if((FuotaTransferArray[index] & 0x00000000FFFFFFFF) == OtaContext.magic_keyword)
+ {
+ APP_DBG("1 - FUOTA_MAGIC_KEYWORD found at flash_current_offset = %d", (flash_current_offset + (index*8)));
+ binary_transfer_on_going = FALSE;
+ }
+ else
+ if (((FuotaTransferArray[index] & 0xFFFFFFFF00000000) >> 32) == OtaContext.magic_keyword)
+ {
+ APP_DBG("2 - FUOTA_MAGIC_KEYWORD found at flash_current_offset = %d", (flash_current_offset + (index*8)));
+ binary_transfer_on_going = FALSE;
+ }
+ }
+
+ flash_current_offset += FUOTA_PAYLOAD_SIZE;
+
+ /* Display Transfer Progress */
+ if(l_debug_count == FuotaProgressArray[l_current_index_progress+1])
+ {
+ l_current_index_progress += 1;
+ if(l_Fuota_progress_multiplied == 1)
+ {
+ APP_DBG("FUOTA Transfer %d%...", l_current_index_progress*10);
+ }
+ else
+ {
+ APP_DBG("FUOTA Transfer %d%...", l_current_index_progress);
+ }
+ }
+
+ l_debug_count++;
+ }
+
+ l_end_transfer_time = HAL_GetTick();
+ l_transfer_time = (double)(l_end_transfer_time - l_start_transfer_time) / 1000;
+ l_transfer_throughput = (((double)OtaContext.binary_size/l_transfer_time) / 1000) * 8;
+
+ APP_DBG("**************************************************************");
+ APP_DBG(" FUOTA_SERVER : END OF TRANSFER COMPLETED");
+ APP_DBG(" - Payload size = %d bytes", FUOTA_PAYLOAD_SIZE);
+ APP_DBG(" - Transfer time = %.2f seconds", l_transfer_time);
+ APP_DBG(" - Average throughput = %.2f kbit/s", l_transfer_throughput);
+ APP_DBG("**************************************************************");
+
+ /* Notify end of transfer to Thread_Ota ? */
+}
+
+/**
+ * @brief Task associated to the push button.
+ * @param None
+ * @retval None
+ */
+static void APP_THREAD_FuotaReboot(void)
+{
+ uint32_t l_data = 0x1;
+ APP_DBG("Send a request to current OTA application to reboot on Thread_Ota");
+
+ /* Send a CONFIRMABLE PUT Request */
+ APP_THREAD_CoapSendRequest(&OT_RessourceFuotaReboot,
+ OT_COAP_TYPE_CONFIRMABLE,
+ OT_COAP_CODE_PUT,
+ NULL,
+ MULICAST_FTD_MED,
+ APP_THREAD_COAP_STRING_ADDRESS,
+ (uint8_t*)&l_data,
+ sizeof(l_data),
+ &APP_THREAD_CoapRespHandlerFuotaReboot);
+
+ UTIL_SEQ_WaitEvt(EVENT_FUOTA_REBOOT_RESP_DONE);
+
+ APP_DBG("Reboot request ACK from OTA application");
+}
+
+/**
+ * @brief This function manages the response handler for the request of reboot on Thread_Ota.
+ *
+ * @param pHeader header
+ * @param pMessage message pointer
+ * @param pMessageInfo message info pointer
+ * @param Result error code
+ * @retval None
+ */
+static void APP_THREAD_CoapRespHandlerFuotaReboot(otCoapHeader * pHeader,
+ otMessage * pMessage,
+ const otMessageInfo * pMessageInfo,
+ otError Result)
+{
+ if (Result == OT_ERROR_NONE)
+ {
+ UTIL_SEQ_SetEvt(EVENT_FUOTA_REBOOT_RESP_DONE);
+ }
+ else
+ {
+ APP_DBG("APP_THREAD_CoapRespHandlerFuotaReboot : WARNING Result %d", Result);
+ }
+}
+
+/**
+ * @brief This function manages the response handler for the request of reboot on Thread_Ota.
+ *
+ * @param pHeader header
+ * @param pMessage message pointer
+ * @param pMessageInfo message info pointer
+ * @param Result error code
+ * @retval None
+ */
+static void APP_THREAD_CoapRespHandlerFuotaParameters(otCoapHeader * pHeader,
+ otMessage * pMessage,
+ const otMessageInfo * pMessageInfo,
+ otError Result)
+{
+ if (Result == OT_ERROR_NONE)
+ {
+ /* Read Message */
+ if (otMessageRead(pMessage, otMessageGetOffset(pMessage), &OT_Command, sizeof(OT_Command)) == sizeof(OT_Command))
+ {
+ if (OT_Command == APP_THREAD_OK)
+ {
+ APP_DBG("FUOTA PARAMETERS: Correct ACK received");
+ UTIL_SEQ_SetTask(TASK_FUOTA_SEND, CFG_SCH_PRIO_0);
+ }
+ else if (OT_Command == APP_THREAD_ERROR)
+ {
+ APP_DBG("FUOTA PARAMETERS: Bad ACK received");
+ APP_DBG("\r -> STOP FUOTA process!");
+ }
+ else
+ {
+ APP_DBG("FUOTA PARAMETERS: Unrecognized ACK received");
+ APP_DBG("\r -> STOP FUOTA process!");
+ }
+ }
+ else
+ {
+ APP_DBG("WARNING : APP_THREAD_CoapRespHandlerFuotaParameters otMessageRead failed!");
+ }
+ }
+ else
+ {
+ APP_DBG("APP_THREAD_CoapRespHandlerFuotaReboot : WARNING Result %d", Result);
+ }
+}
+
+/* USER CODE END FD_LOCAL_FUNCTIONS */
+
+/*************************************************************
+ *
+ * WRAP FUNCTIONS
+ *
+ *************************************************************/
+
+void APP_THREAD_RegisterCmdBuffer(TL_CmdPacket_t* p_buffer)
+{
+ p_thread_otcmdbuffer = p_buffer;
+}
+
+Thread_OT_Cmd_Request_t* THREAD_Get_OTCmdPayloadBuffer(void)
+{
+ return (Thread_OT_Cmd_Request_t*)p_thread_otcmdbuffer->cmdserial.cmd.payload;
+}
+
+Thread_OT_Cmd_Request_t* THREAD_Get_OTCmdRspPayloadBuffer(void)
+{
+ return (Thread_OT_Cmd_Request_t*)((TL_EvtPacket_t *)p_thread_otcmdbuffer)->evtserial.evt.payload;
+}
+
+Thread_OT_Cmd_Request_t* THREAD_Get_NotificationPayloadBuffer(void)
+{
+ return (Thread_OT_Cmd_Request_t*)(p_thread_notif_M0_to_M4)->evtserial.evt.payload;
+}
+
+/**
+ * @brief This function is used to transfer the Ot commands from the
+ * M4 to the M0.
+ *
+ * @param None
+ * @return None
+ */
+void Ot_Cmd_Transfer(void)
+{
+ /* OpenThread OT command cmdcode range 0x280 .. 0x3DF = 352 */
+ p_thread_otcmdbuffer->cmdserial.cmd.cmdcode = 0x280U;
+ /* Size = otCmdBuffer->Size (Number of OT cmd arguments : 1 arg = 32bits so multiply by 4 to get size in bytes)
+ * + ID (4 bytes) + Size (4 bytes) */
+ uint32_t l_size = ((Thread_OT_Cmd_Request_t*)(p_thread_otcmdbuffer->cmdserial.cmd.payload))->Size * 4U + 8U;
+ p_thread_otcmdbuffer->cmdserial.cmd.plen = l_size;
+
+ TL_OT_SendCmd();
+
+ /* Wait completion of cmd */
+ Wait_Getting_Ack_From_M0();
+}
+
+/**
+ * @brief This function is called when acknowledge from OT command is received from the M0+.
+ *
+ * @param Otbuffer : a pointer to TL_EvtPacket_t
+ * @return None
+ */
+void TL_OT_CmdEvtReceived( TL_EvtPacket_t * Otbuffer )
+{
+ /* Prevent unused argument(s) compilation warning */
+ UNUSED(Otbuffer);
+
+ Receive_Ack_From_M0();
+}
+
+/**
+ * @brief This function is called when notification from M0+ is received.
+ *
+ * @param Notbuffer : a pointer to TL_EvtPacket_t
+ * @return None
+ */
+void TL_THREAD_NotReceived( TL_EvtPacket_t * Notbuffer )
+{
+ p_thread_notif_M0_to_M4 = Notbuffer;
+
+ Receive_Notification_From_M0();
+}
+
+/**
+ * @brief This function is called before sending any ot command to the M0
+ * core. The purpose of this function is to be able to check if
+ * there are no notifications coming from the M0 core which are
+ * pending before sending a new ot command.
+ * @param None
+ * @retval None
+ */
+void Pre_OtCmdProcessing(void)
+{
+ UTIL_SEQ_WaitEvt(EVENT_SYNCHRO_BYPASS_IDLE);
+}
+
+/**
+ * @brief This function waits for getting an acknowledgment from the M0.
+ *
+ * @param None
+ * @retval None
+ */
+static void Wait_Getting_Ack_From_M0(void)
+{
+ UTIL_SEQ_WaitEvt(EVENT_ACK_FROM_M0_EVT);
+}
+
+/**
+ * @brief Receive an acknowledgment from the M0+ core.
+ * Each command send by the M4 to the M0 are acknowledged.
+ * This function is called under interrupt.
+ * @param None
+ * @retval None
+ */
+static void Receive_Ack_From_M0(void)
+{
+ UTIL_SEQ_SetEvt(EVENT_ACK_FROM_M0_EVT);
+}
+
+/**
+ * @brief Receive a notification from the M0+ through the IPCC.
+ * This function is called under interrupt.
+ * @param None
+ * @retval None
+ */
+static void Receive_Notification_From_M0(void)
+{
+ CptReceiveMsgFromM0++;
+ UTIL_SEQ_SetTask(TASK_MSG_FROM_M0_TO_M4,CFG_SCH_PRIO_0);
+}
+
+#if (CFG_USB_INTERFACE_ENABLE != 0)
+#else
+#if (CFG_FULL_LOW_POWER == 0)
+static void RxCpltCallback(void)
+{
+ /* Filling buffer and wait for '\r' char */
+ if (indexReceiveChar < C_SIZE_CMD_STRING)
+ {
+ CommandString[indexReceiveChar++] = aRxBuffer[0];
+ if (aRxBuffer[0] == '\r')
+ {
+ CptReceiveCmdFromUser = 1U;
+
+ /* UART task scheduling*/
+ UTIL_SEQ_SetTask(1U << CFG_TASK_SEND_CLI_TO_M0, CFG_SCH_PRIO_0);
+ }
+ }
+
+ /* Once a character has been sent, put back the device in reception mode */
+ HW_UART_Receive_IT(CFG_CLI_UART, aRxBuffer, 1U, RxCpltCallback);
+}
+#endif /* (CFG_FULL_LOW_POWER == 0) */
+#endif /* (CFG_USB_INTERFACE_ENABLE != 0) */
+
+#if (CFG_USB_INTERFACE_ENABLE != 0)
+/**
+ * @brief Process the command strings.
+ * As soon as a complete command string has been received, the task
+ * in charge of sending the command to the M0 is scheduled
+ * @param None
+ * @retval None
+ */
+static uint32_t ProcessCmdString( uint8_t* buf , uint32_t len )
+{
+ uint32_t i,j,tmp_start;
+ tmp_start = 0;
+ uint32_t res = 0;
+
+ i= 0;
+ while ((buf[i] != '\r') && (i < len))
+ {
+ i++;
+ }
+
+ if (i != len)
+ {
+ memcpy(CommandString, buf,(i+1));
+ indexReceiveChar = i + 1U; /* Length of the buffer containing the command string */
+ UTIL_SEQ_SetTask(1U << CFG_TASK_SEND_CLI_TO_M0, CFG_SCH_PRIO_0);
+ tmp_start = i;
+ for (j = 0; j < (len - tmp_start - 1U) ; j++)
+ {
+ buf[j] = buf[tmp_start + j + 1U];
+ }
+ res = len - tmp_start - 1U;
+ }
+ else
+ {
+ res = len;
+ }
+ return res; /* Remaining characters in the temporary buffer */
+}
+#endif/* (CFG_USB_INTERFACE_ENABLE != 0) */
+
+#if (CFG_FULL_LOW_POWER == 0)
+/**
+ * @brief Process sends receive CLI command to M0.
+ * @param None
+ * @retval None
+ */
+static void Send_CLI_To_M0(void)
+{
+ memset(ThreadCliCmdBuffer.cmdserial.cmd.payload, 0x0U, 255U);
+ memcpy(ThreadCliCmdBuffer.cmdserial.cmd.payload, CommandString, indexReceiveChar);
+ ThreadCliCmdBuffer.cmdserial.cmd.plen = indexReceiveChar;
+ ThreadCliCmdBuffer.cmdserial.cmd.cmdcode = 0x0;
+
+ /* Clear receive buffer, character counter and command complete */
+ CptReceiveCmdFromUser = 0;
+ indexReceiveChar = 0;
+ memset(CommandString, 0, C_SIZE_CMD_STRING);
+
+ TL_CLI_SendCmd();
+}
+#endif /* (CFG_FULL_LOW_POWER == 0) */
+
+/**
+ * @brief Send notification for CLI TL Channel.
+ * @param None
+ * @retval None
+ */
+static void Send_CLI_Ack_For_OT(void)
+{
+
+ /* Notify M0 that characters have been sent to UART */
+ TL_THREAD_CliSendAck();
+}
+
+/**
+ * @brief Perform initialization of CLI UART interface.
+ * @param None
+ * @retval None
+ */
+void APP_THREAD_Init_UART_CLI(void)
+{
+#if (CFG_FULL_LOW_POWER == 0)
+ UTIL_SEQ_RegTask( 1<<CFG_TASK_SEND_CLI_TO_M0, UTIL_SEQ_RFU,Send_CLI_To_M0);
+#endif /* (CFG_FULL_LOW_POWER == 0) */
+
+#if (CFG_USB_INTERFACE_ENABLE != 0)
+#else
+#if (CFG_FULL_LOW_POWER == 0)
+ MX_USART1_UART_Init();
+ HW_UART_Receive_IT(CFG_CLI_UART, aRxBuffer, 1, RxCpltCallback);
+#endif /* (CFG_FULL_LOW_POWER == 0) */
+#endif /* (CFG_USB_INTERFACE_ENABLE != 0) */
+}
+
+/**
+ * @brief Perform initialization of TL for THREAD.
+ * @param None
+ * @retval None
+ */
+void APP_THREAD_TL_THREAD_INIT(void)
+{
+ ThreadConfigBuffer.p_ThreadOtCmdRspBuffer = (uint8_t*)&ThreadOtCmdBuffer;
+ ThreadConfigBuffer.p_ThreadNotAckBuffer = (uint8_t*)ThreadNotifRspEvtBuffer;
+ ThreadConfigBuffer.p_ThreadCliRspBuffer = (uint8_t*)&ThreadCliCmdBuffer;
+
+ TL_THREAD_Init( &ThreadConfigBuffer );
+}
+
+/**
+ * @brief This function is called when notification on CLI TL Channel from M0+ is received.
+ *
+ * @param Notbuffer : a pointer to TL_EvtPacket_t
+ * @return None
+ */
+void TL_THREAD_CliNotReceived( TL_EvtPacket_t * Notbuffer )
+{
+ TL_CmdPacket_t* l_CliBuffer = (TL_CmdPacket_t*)Notbuffer;
+ uint8_t l_size = l_CliBuffer->cmdserial.cmd.plen;
+
+ /* WORKAROUND: if string to output is "> " then respond directly to M0 and do not output it */
+ if (strcmp((const char *)l_CliBuffer->cmdserial.cmd.payload, "> ") != 0)
+ {
+ /* Write to CLI UART */
+#if (CFG_USB_INTERFACE_ENABLE != 0)
+ VCP_SendData( l_CliBuffer->cmdserial.cmd.payload, l_size, HostTxCb);
+#else
+ HW_UART_Transmit_IT(CFG_CLI_UART, l_CliBuffer->cmdserial.cmd.payload, l_size, HostTxCb);
+#endif /*USAGE_OF_VCP */
+ }
+ else
+ {
+ Send_CLI_Ack_For_OT();
+ }
+}
+
+/**
+ * @brief End of transfer callback for CLI UART sending.
+ *
+ * @param Notbuffer : a pointer to TL_EvtPacket_t
+ * @return None
+ */
+void HostTxCb(void)
+{
+ Send_CLI_Ack_For_OT();
+}
+
+/**
+ * @brief Process the messages coming from the M0.
+ * @param None
+ * @retval None
+ */
+void APP_THREAD_ProcessMsgM0ToM4(void)
+{
+ if (CptReceiveMsgFromM0 != 0)
+ {
+ /* If CptReceiveMsgFromM0 is > 1. it means that we did not serve all the events from the radio */
+ if (CptReceiveMsgFromM0 > 1U)
+ {
+ APP_THREAD_Error(ERR_REC_MULTI_MSG_FROM_M0, 0);
+ }
+ else
+ {
+ OpenThread_CallBack_Processing();
+ }
+ /* Reset counter */
+ CptReceiveMsgFromM0 = 0;
+ }
+}
+
+#if (CFG_USB_INTERFACE_ENABLE != 0)
+/**
+ * @brief This function is called when thereare some data coming
+ * from the Hyperterminal via the USB port
+ * Data received over USB OUT endpoint are sent over CDC interface
+ * through this function.
+ * @param Buf: Buffer of data received
+ * @param Len: Number of data received (in bytes)
+ * @retval Number of characters remaining in the buffer and not yet processed
+ */
+void VCP_DataReceived(uint8_t* Buf , uint32_t *Len)
+{
+ uint32_t i,flag_continue_checking = TRUE;
+ uint32_t char_remaining = 0;
+ static uint32_t len_total = 0;
+
+ /* Copy the characteres in the temporary buffer */
+ for (i = 0; i < *Len; i++)
+ {
+ TmpString[len_total++] = Buf[i];
+ }
+
+ /* Process the buffer commands one by one */
+ /* A command is limited by a \r caracaters */
+ while (flag_continue_checking == TRUE)
+ {
+ char_remaining = ProcessCmdString(TmpString,len_total);
+ /* If char_remaining is equal to len_total, it means that the command string is not yet
+ * completed.
+ * If char_remaining is equal to 0, it means that the command string has
+ * been entirely processed.
+ */
+ if ((char_remaining == 0) || (char_remaining == len_total))
+ {
+ flag_continue_checking = FALSE;
+ }
+ len_total = char_remaining;
+ }
+}
+#endif /* (CFG_USB_INTERFACE_ENABLE != 0) */
+
+/* USER CODE BEGIN FD_WRAP_FUNCTIONS */
+
+/* USER CODE END FD_WRAP_FUNCTIONS */
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/