Verified Commit d410272c authored by Vincent Coubard's avatar Vincent Coubard
Browse files

Convert AWS iot abstraction to CMSIS RTOS


Signed-off-by: Vincent Coubard's avatarVincent Coubard <vincent.coubard@arm.com>
parent c1e2a4a1
/*
* FreeRTOS Platform V1.1.2
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
* Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
*
* 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
......@@ -31,54 +32,31 @@
#ifndef _IOT_PLATFORM_TYPES_AFR_H_
#define _IOT_PLATFORM_TYPES_AFR_H_
#include "timers.h"
typedef struct iot_mutex_internal
{
StaticSemaphore_t xMutex; /**< FreeRTOS mutex. */
BaseType_t recursive; /**< Type; used for indicating if this is reentrant or normal. */
} iot_mutex_internal_t;
#include "cmsis_os2.h"
/**
* @brief The native mutex type on AFR systems.
*/
typedef iot_mutex_internal_t _IotSystemMutex_t;
typedef struct iot_sem_internal
{
StaticSemaphore_t xSemaphore; /**< FreeRTOS semaphore. */
} iot_sem_internal_t;
typedef osMutexId_t _IotSystemMutex_t;
/**
* @brief The native semaphore type on AFR systems.
*/
typedef iot_sem_internal_t _IotSystemSemaphore_t;
typedef osSemaphoreId_t _IotSystemSemaphore_t;
/**
* @brief Holds information about an active detached thread so that we can
* delete the FreeRTOS task when it completes
* delete the task when it completes
*/
typedef struct threadInfo
{
void * pArgument; /**< @brief Argument to `threadRoutine`. */
void ( * threadRoutine )( void * ); /**< @brief Thread function to run. */
typedef struct threadInfo {
void *pArgument; /**< @brief Argument to `threadRoutine`. */
void (*threadRoutine)(void *); /**< @brief Thread function to run. */
osThreadId_t threadId; /**< Thread ID. */
} threadInfo_t;
/**
* @brief Holds information about an active timer.
*/
typedef struct timerInfo
{
TimerHandle_t timer; /**< @brief Underlying timer. */
void ( * threadRoutine )( void * ); /**< @brief Thread function to run on timer expiration. */
void * pArgument; /**< @brief First argument to threadRoutine. */
StaticTimer_t xTimerBuffer; /**< Memory that holds the FreeRTOS timer. */
TickType_t xTimerPeriod; /**< Period of this timer. */
} timerInfo_t;
/**
* @brief Represents an #IotTimer_t on AFR systems.
*/
typedef timerInfo_t _IotSystemTimer_t;
typedef osTimerId_t _IotSystemTimer_t;
#endif /* ifndef _IOT_PLATFORM_TYPES_POSIX_H_ */
/*
* FreeRTOS Platform V1.1.2
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
* Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
*
* 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
......@@ -25,7 +26,7 @@
/**
* @file iot_clock_freertos.c
* @brief Implementation of the functions in iot_clock.h for FreeRTOS systems.
* @brief Implementation of the functions in iot_clock.h for CMSIS systems.
*/
/* The config header is always included first. */
......@@ -33,11 +34,11 @@
/* Standard includes. */
#include <stdio.h>
#include "cmsis_os2.h"
/* Platform clock include. */
#include "platform/iot_platform_types_freertos.h"
#include "platform/iot_clock.h"
#include "task.h"
/* Configure logs for the functions in this file. */
#ifdef IOT_LOG_LEVEL_PLATFORM
......@@ -63,36 +64,21 @@
/*-----------------------------------------------------------*/
/* Private Callback function for timer expiry, delegate work to a Task to free
* up the timer task for managing other timers */
static void prvTimerCallback( TimerHandle_t xTimerHandle )
{
_IotSystemTimer_t * pxTimer = ( _IotSystemTimer_t * ) pvTimerGetTimerID( xTimerHandle );
/* The value of the timer ID, set in timer_create, should not be NULL. */
configASSERT( pxTimer != NULL );
/* Restart the timer if it is periodic. */
if( pxTimer->xTimerPeriod > 0 )
{
xTimerChangePeriod( xTimerHandle, pxTimer->xTimerPeriod, 0 );
}
/* Call timer Callback from this task */
pxTimer->threadRoutine( ( void * ) pxTimer->pArgument );
}
/*-----------------------------------------------------------*/
bool IotClock_GetTimestring( char * pBuffer,
size_t bufferSize,
size_t * pTimestringLength )
bool IotClock_GetTimestring(char *pBuffer,
size_t bufferSize,
size_t *pTimestringLength)
{
uint64_t milliSeconds = IotClock_GetTimeMs();
int timestringLength = 0;
configASSERT( pBuffer != NULL );
configASSERT( pTimestringLength != NULL );
if( pBuffer == NULL )
{
return false;
}
if( pTimestringLength == NULL )
{
return false;
}
/* Convert the localTime struct to a string. */
timestringLength = snprintf( pBuffer, bufferSize, "%llu", milliSeconds );
......@@ -113,29 +99,16 @@ bool IotClock_GetTimestring( char * pBuffer,
uint64_t IotClock_GetTimeMs( void )
{
TimeOut_t xCurrentTime = { 0 };
/* This must be unsigned because the behavior of signed integer overflow is undefined. */
uint64_t ullTickCount = 0ULL;
/* Get the current tick count and overflow count. vTaskSetTimeOutState()
* is used to get these values because they are both static in tasks.c. */
vTaskSetTimeOutState( &xCurrentTime );
/* Adjust the tick count for the number of times a TickType_t has overflowed. */
ullTickCount = ( uint64_t ) ( xCurrentTime.xOverflowCount ) << ( sizeof( TickType_t ) * 8 );
/* Add the current tick count. */
ullTickCount += xCurrentTime.xTimeOnEntering;
uint32_t tickCount = OS_Tick_GetCount();
/* Return the ticks converted to Milliseconds */
return ullTickCount * _MILLISECONDS_PER_TICK;
return tickCount * _MILLISECONDS_PER_TICK;
}
/*-----------------------------------------------------------*/
void IotClock_SleepMs( uint32_t sleepTimeMs )
{
vTaskDelay( pdMS_TO_TICKS( sleepTimeMs ) );
osDelay( pdMS_TO_TICKS( sleepTimeMs ) );
}
/*-----------------------------------------------------------*/
......@@ -145,26 +118,29 @@ bool IotClock_TimerCreate( IotTimer_t * pNewTimer,
void * pArgument )
{
_IotSystemTimer_t * pxTimer = ( _IotSystemTimer_t * ) pNewTimer;
osTimerId_t timerId = NULL;
configASSERT( pNewTimer != NULL );
configASSERT( expirationRoutine != NULL );
if( pNewTimer == NULL )
{
return false;
}
if( expirationRoutine == NULL )
{
return false;
}
IotLogDebug( "Creating new timer %p.", pNewTimer );
osTimerAttr_t timerAttr = { "timer", 0, NULL, 0 };
timerId = osTimerNew( expirationRoutine, osTimerOnce, &pArgument, &timerAttr );
if( timerId == NULL )
{
IotLogError( "Failed to create timer %p.", pNewTimer );
}
/* Set the timer expiration routine, argument and period */
pxTimer->threadRoutine = expirationRoutine;
pxTimer->pArgument = pArgument;
pxTimer->xTimerPeriod = 0;
/* Create a new FreeRTOS timer. This call will not fail because the
* memory for it has already been allocated, so the output parameter is
* also set. */
pxTimer->timer = ( TimerHandle_t ) xTimerCreateStatic( "timer", /* Timer name. */
portMAX_DELAY, /* Initial timer period. Timers are created disarmed. */
pdFALSE, /* Don't auto-reload timer. */
( void * ) pxTimer, /* Timer id. */
prvTimerCallback, /* Timer expiration callback. */
&pxTimer->xTimerBuffer ); /* Pre-allocated memory for timer. */
* pNewTimer = timerId;
return true;
}
......@@ -175,23 +151,19 @@ void IotClock_TimerDestroy( IotTimer_t * pTimer )
{
_IotSystemTimer_t * pTimerInfo = ( _IotSystemTimer_t * ) pTimer;
configASSERT( pTimerInfo != NULL );
configASSERT( pTimerInfo->timer != NULL );
if( pTimerInfo == NULL )
{
IotLogError( "Timer doesn't exist. Can't destroy it." );
}
IotLogDebug( "Destroying timer %p.", pTimer );
if( xTimerIsTimerActive( pTimerInfo->timer ) == pdTRUE )
if( osTimerIsRunning( * pTimerInfo ) == 1 )
{
/* Stop the FreeRTOS timer. Because the timer is statically allocated, no call
* to xTimerDelete is necessary. The timer is stopped so that it's not referenced
* anywhere. xTimerStop will not fail when it has unlimited block time. */
( void ) xTimerStop( pTimerInfo->timer, portMAX_DELAY );
/* Wait until the timer stop command is processed. */
while( xTimerIsTimerActive( pTimerInfo->timer ) == pdTRUE )
if( osTimerDelete( * pTimerInfo ) != osOK )
{
vTaskDelay( 1 );
}
IotLogError( "Failed to delete timer %p.", pTimer );
};
}
}
......@@ -202,21 +174,27 @@ bool IotClock_TimerArm( IotTimer_t * pTimer,
uint32_t periodMs )
{
_IotSystemTimer_t * pTimerInfo = ( _IotSystemTimer_t * ) pTimer;
_IotSystemTimer_t * pNewTimerInfo;
configASSERT( pTimerInfo != NULL );
if ( pTimerInfo == NULL ) {
IotLogError( "Timer doesn't exist. Can't Arm it." );
}
TimerHandle_t xTimerHandle = pTimerInfo->timer;
if( relativeTimeoutMs == periodMs )
{
IotLogDebug("Arming timer %p with period %llu.", pTimer, periodMs);
IotLogDebug( "Arming timer %p with timeout %llu and period %llu.",
pTimer,
relativeTimeoutMs,
periodMs );
osTimerStart( * pTimerInfo, pdMS_TO_TICKS( periodMs ) );
}
else
{
IotLogDebug( "Arming timer %p with timeout %llu and period %llu.", pTimer, relativeTimeoutMs, periodMs );
/* Set the timer period in ticks */
pTimerInfo->xTimerPeriod = pdMS_TO_TICKS( periodMs );
void *timerCallbackArg = { pTimer, periodMs, periodMs };
IotClock_TimerCreate( pNewTimerInfo, IotClock_TimerArm, timerCallbackArg );
/* Set the timer to expire after relativeTimeoutMs, and restart it. */
( void ) xTimerChangePeriod( xTimerHandle, pdMS_TO_TICKS( relativeTimeoutMs ), portMAX_DELAY );
osTimerStart( pNewTimerInfo, pdMS_TO_TICKS( relativeTimeoutMs ) );
}
return true;
}
......
/*
* FreeRTOS Platform V1.1.2
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
* Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
*
* 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
......@@ -35,9 +36,8 @@
/* Standard includes. */
#include <string.h>
/* FreeRTOS includes. */
#include "semphr.h"
#include "event_groups.h"
#include "cmsis_os2.h"
#include "iot_config.h"
/* Error handling include. */
#include "private/iot_error.h"
......@@ -86,9 +86,9 @@
typedef struct _networkConnection
{
Socket_t socket; /**< @brief FreeRTOS Secure Sockets handle. */
StaticSemaphore_t socketMutex; /**< @brief Prevents concurrent threads from sending on a socket. */
StaticEventGroup_t connectionFlags; /**< @brief Synchronizes with the receive task. */
TaskHandle_t receiveTask; /**< @brief Handle of the receive task, if any. */
osMutexId_t socketMutex; /**< @brief Prevents concurrent threads from sending on a socket. */
osEventFlagsId_t connectionFlags; /**< @brief Synchronizes with the receive task. */
osThreadId_t receiveTask; /**< @brief Handle of the receive task, if any. */
IotNetworkReceiveCallback_t receiveCallback; /**< @brief Network receive callback, if any. */
void * pReceiveContext; /**< @brief The context for the receive callback. */
bool bufferedByteValid; /**< @brief Used to determine if the buffered byte is valid. */
......@@ -143,7 +143,7 @@ static void _networkReceiveTask( void * pArgument )
{
bool destroyConnection = false;
int32_t socketStatus = 0;
EventBits_t connectionFlags = 0;
uint32_t connectionFlags = 0;
/* Cast network connection to the correct type. */
_networkConnection_t * pNetworkConnection = pArgument;
......@@ -163,7 +163,7 @@ static void _networkReceiveTask( void * pArgument )
1,
0 );
connectionFlags = xEventGroupGetBits( ( EventGroupHandle_t ) &( pNetworkConnection->connectionFlags ) );
connectionFlags = osEventFlagsGet( pNetworkConnection->connectionFlags );
if( ( connectionFlags & _FLAG_SHUTDOWN ) == _FLAG_SHUTDOWN )
{
......@@ -191,7 +191,7 @@ static void _networkReceiveTask( void * pArgument )
/* Check if the connection was destroyed by the receive callback. This
* does not need to be thread-safe because the destroy connection function
* may only be called once (per its API doc). */
connectionFlags = xEventGroupGetBits( ( EventGroupHandle_t ) &( pNetworkConnection->connectionFlags ) );
connectionFlags = osEventFlagsGet( pNetworkConnection->connectionFlags );
/* Break out of receive task loop if connection is closed or destroyed. */
if( ( connectionFlags & _FLAG_RECEIVE_TASK_CONNECTION_DESTROYED ) == _FLAG_RECEIVE_TASK_CONNECTION_DESTROYED )
......@@ -215,11 +215,10 @@ static void _networkReceiveTask( void * pArgument )
else
{
/* Set the flag to indicate that the receive task has exited. */
( void ) xEventGroupSetBits( ( EventGroupHandle_t ) &( pNetworkConnection->connectionFlags ),
_FLAG_RECEIVE_TASK_EXITED );
( void ) osEventFlagsSet( pNetworkConnection->connectionFlags, _FLAG_RECEIVE_TASK_EXITED );
}
vTaskDelete( NULL );
osThreadExit();
}
/*-----------------------------------------------------------*/
......@@ -319,8 +318,6 @@ IotNetworkError_t IotNetworkAfr_Create( void * pConnectionInfo,
Socket_t tcpSocket = SOCKETS_INVALID_SOCKET;
int32_t socketStatus = SOCKETS_ERROR_NONE;
SocketsSockaddr_t serverAddress = { 0 };
EventGroupHandle_t pConnectionFlags = NULL;
SemaphoreHandle_t pConnectionMutex = NULL;
const TickType_t receiveTimeout = pdMS_TO_TICKS( IOT_NETWORK_SOCKET_POLL_MS );
_networkConnection_t * pNewNetworkConnection = NULL;
......@@ -350,6 +347,22 @@ IotNetworkError_t IotNetworkAfr_Create( void * pConnectionInfo,
/* Clear the connection information. */
( void ) memset( pNewNetworkConnection, 0x00, sizeof( _networkConnection_t ) );
pNewNetworkConnection->socketMutex = osMutexNew( NULL );
if( pNewNetworkConnection->socketMutex == NULL )
{
IotLogError( "Failed to allocate memory for new network connection mutex." );
IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_NO_MEMORY );
}
pNewNetworkConnection->connectionFlags = osEventFlagsNew( NULL );
if( pNewNetworkConnection->connectionFlags == NULL)
{
IotLogError( "Failed to allocate memory for new network connection flags." );
IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_NO_MEMORY );
}
/* Create a new TCP socket. */
tcpSocket = SOCKETS_Socket( SOCKETS_AF_INET,
......@@ -421,6 +434,16 @@ IotNetworkError_t IotNetworkAfr_Create( void * pConnectionInfo,
/* Clear the connection information. */
if( pNewNetworkConnection != NULL )
{
if( pNewNetworkConnection->socketMutex != NULL )
{
osMutexDelete( pNewNetworkConnection->socketMutex );
}
if( pNewNetworkConnection->connectionFlags != NULL)
{
osEventFlagsDelete( pNewNetworkConnection->connectionFlags );
}
vPortFree( pNewNetworkConnection );
}
}
......@@ -429,15 +452,6 @@ IotNetworkError_t IotNetworkAfr_Create( void * pConnectionInfo,
/* Set the socket. */
pNewNetworkConnection->socket = tcpSocket;
/* Create the connection event flags and mutex. */
pConnectionFlags = xEventGroupCreateStatic( &( pNewNetworkConnection->connectionFlags ) );
pConnectionMutex = xSemaphoreCreateMutexStatic( &( pNewNetworkConnection->socketMutex ) );
/* Static event flags and mutex creation should never fail. The handles
* should point inside the connection object. */
configASSERT( pConnectionFlags == ( EventGroupHandle_t ) &( pNewNetworkConnection->connectionFlags ) );
configASSERT( pConnectionMutex == ( SemaphoreHandle_t ) &( pNewNetworkConnection->socketMutex ) );
/* Set the output parameter. */
*pNetworkConnection = pNewNetworkConnection;
}
......@@ -461,15 +475,18 @@ IotNetworkError_t IotNetworkAfr_SetReceiveCallback( void * pConnection,
pNetworkConnection->pReceiveContext = pContext;
/* No flags should be set. */
configASSERT( xEventGroupGetBits( ( EventGroupHandle_t ) &( pNetworkConnection->connectionFlags ) ) == 0 );
configASSERT( osEventFlagsGet( pNetworkConnection->connectionFlags ) == 0 );
/* Create task that waits for incoming data. */
if( xTaskCreate( _networkReceiveTask,
"NetRecv",
IOT_NETWORK_RECEIVE_TASK_STACK_SIZE,
pNetworkConnection,
IOT_NETWORK_RECEIVE_TASK_PRIORITY,
&( pNetworkConnection->receiveTask ) ) != pdPASS )
osThreadAttr_t attr = {
.stack_size = IOT_NETWORK_RECEIVE_TASK_STACK_SIZE,
.priority = osPriorityNormal
};
pNetworkConnection->receiveTask = osThreadNew( _networkReceiveTask, pNetworkConnection, &attr);
if( pNetworkConnection->receiveTask == NULL )
{
IotLogError( "Failed to create network receive task." );
......@@ -493,8 +510,7 @@ size_t IotNetworkAfr_Send( void * pConnection,
/* Only one thread at a time may send on the connection. Lock the socket
* mutex to prevent other threads from sending. */
if( xSemaphoreTake( ( QueueHandle_t ) &( pNetworkConnection->socketMutex ),
portMAX_DELAY ) == pdTRUE )
if( osMutexAcquire( pNetworkConnection->socketMutex, osWaitForever ) == osOK )
{
while( bytesRemaining > 0U )
{
......@@ -517,7 +533,7 @@ size_t IotNetworkAfr_Send( void * pConnection,
}
}
xSemaphoreGive( ( QueueHandle_t ) &( pNetworkConnection->socketMutex ) );
osMutexRelease( pNetworkConnection->socketMutex );
}
return bytesSent;
......@@ -649,20 +665,18 @@ IotNetworkError_t IotNetworkAfr_Close( void * pConnection )
_networkConnection_t * pNetworkConnection = ( _networkConnection_t * ) pConnection;
/* Set the shutdown flag so that the network receive task can stop polling. */
( void ) xEventGroupSetBits( ( EventGroupHandle_t ) &( pNetworkConnection->connectionFlags ),
_FLAG_SHUTDOWN );
( void ) osEventFlagsSet( pNetworkConnection->connectionFlags, _FLAG_SHUTDOWN );
/* If this function is not called from the receive task, wait for the receive task to exit. */
if( ( pNetworkConnection->receiveTask != NULL ) && ( xTaskGetCurrentTaskHandle() != pNetworkConnection->receiveTask ) )
if( ( pNetworkConnection->receiveTask != NULL ) && ( osThreadGetId() != pNetworkConnection->receiveTask ) )
{
/* Wait for the network receive task to exit so that the socket can be shutdown safely
* without causing the socket to block forever if there are pending reads or writes
* from other tasks. Do not clear the flag as IotNetworkAfr_Destroy checks it. */
( void ) xEventGroupWaitBits( ( EventGroupHandle_t ) &( pNetworkConnection->connectionFlags ),
_FLAG_RECEIVE_TASK_EXITED,
pdFALSE,
pdTRUE,
portMAX_DELAY );
( void ) osEventFlagsWait( pNetworkConnection->connectionFlags,
_FLAG_RECEIVE_TASK_EXITED,
osFlagsNoClear | osFlagsWaitAll,
osWaitForever );
}
/* Call Secure Sockets shutdown function to close connection. */
......@@ -685,11 +699,10 @@ IotNetworkError_t IotNetworkAfr_Destroy( void * pConnection )
_networkConnection_t * pNetworkConnection = ( _networkConnection_t * ) pConnection;
/* Check if this function is being called from the receive task. */
if( xTaskGetCurrentTaskHandle() == pNetworkConnection->receiveTask )
if( osThreadGetId() == pNetworkConnection->receiveTask )
{
/* Set the flag specifying that the connection is destroyed. */
( void ) xEventGroupSetBits( ( EventGroupHandle_t ) &( pNetworkConnection->connectionFlags ),
_FLAG_RECEIVE_TASK_CONNECTION_DESTROYED );
( void ) osEventFlagsSet( pNetworkConnection->connectionFlags, _FLAG_RECEIVE_TASK_CONNECTION_DESTROYED );
}
else
{
......@@ -697,8 +710,8 @@ IotNetworkError_t IotNetworkAfr_Destroy( void * pConnection )
* the receive task should have already exited. */
if( pNetworkConnection->receiveCallback != NULL )
{
EventBits_t connectionFlags;
connectionFlags = xEventGroupGetBits( ( EventGroupHandle_t ) &( pNetworkConnection->connectionFlags ) );
uint32_t connectionFlags;
connectionFlags = osEventFlagsGet( pNetworkConnection->connectionFlags );
configASSERT( ( connectionFlags & _FLAG_RECEIVE_TASK_EXITED ) == _FLAG_RECEIVE_TASK_EXITED );
......
/*
* FreeRTOS Platform V1.1.2
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
* Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
*
* 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
......@@ -30,8 +31,7 @@
/* The config header is always included first. */
#include "iot_config.h"
#include "semphr.h"
#include "cmsis_os2.h"
/* Platform threads include. */
#include "platform/iot_platform_types_freertos.h"
......@@ -57,7 +57,7 @@
* the usage of dynamic memory allocation.
*/
#ifndef IotThreads_Malloc
#include "FreeRTOS.h"
#include "RTOS_config.h"
/**
* @brief Memory allocation. This function should have the same signature
......@@ -66,7 +66,7 @@
#define IotThreads_Malloc pvPortMalloc
#endif
#ifndef IotThreads_Free
#include "FreeRTOS.h"
#include "RTOS_config.h"
/**
* @brief Free memory. This function should have the same signature as
......@@ -85,7 +85,7 @@ static void _threadRoutineWrapper( void * pArgument )
pThreadInfo->threadRoutine( pThreadInfo->pArgument );
IotThreads_Free( pThreadInfo );
vTaskDelete( NULL );
osThreadExit();
}
/*-----------------------------------------------------------*/
......@@ -96,6 +96,7 @@ bool Iot_CreateDetachedThread( IotThreadRoutine_t threadRoutine,
size_t stackSize )
{
bool status = true;
osMemoryPoolId_t threadMemPoolId;
configASSERT( threadRoutine != NULL );
......@@ -108,24 +109,30 @@ bool Iot_CreateDetachedThread( IotThreadRoutine_t threadRoutine,
status = false;
}
/* Create the FreeRTOS task that will run the thread. */
/* Create the CMSIS task that will run the thread. */
if( status )
{
pThreadInfo->threadRoutine = threadRoutine;
pThreadInfo->pArgument = pArgument;
if( xTaskCreate( _threadRoutineWrapper,
"iot_thread",
( configSTACK_DEPTH_TYPE ) stackSize,
pThreadInfo,
priority,
NULL ) != pdPASS )