Add cellular library submodule path and demo (#695)

* [Cellular] Add cellulr lib submodule and demo app

* [Cellular] Fix memory violation in transport layer and add using LoggingPrintf

* Update FreeRTOS Cellular Interface

* Change the mbedtls usage in FreeRTOS-Plus

* [Cellular] Fix missing spell

* [Cellular] Add manifest.yml

* Fix missing spell

* Update manifest.yml

* [Cellular] Add integration test

* Modify the demo log level to LOG_INFO

* Update cellular interface

* The modification of the folder structure for cellular library

* Rename the naming of demo

* Adjust the location of using_mbedtls and socket_wrapper

* Adjust project setting for relocating using_mbedtls and socket_wrapper

* Turn off PSM mode

* Add start marker for CI validation.

* The modification for mbedtls platform send/recv function for cellular

* Change the project file due to the changes of mbedtls platform send/recv function for cellular

* Fix missing newline and remove unused file

* Add missing configuration.

* Make cellular and freertos tcp plus use the same transport implementation

* Add comment for the macro MBEDTLS_SSL_SEND and MBEDTLS_SSL_RECV

* Make changes from the github comment.
This commit is contained in:
andysun2015 2021-11-10 11:38:44 +08:00 committed by GitHub
parent 223d2d0e21
commit 957fb26dbe
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
142 changed files with 45928 additions and 14758 deletions

View file

@ -0,0 +1,233 @@
/*
* FreeRTOS V202107.00
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. 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
* 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.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*/
#include <stdbool.h>
#include "cellular_platform.h"
/*-----------------------------------------------------------*/
typedef QueueHandle_t SemaphoreHandle_t;
typedef struct threadInfo
{
void * pArgument; /**< @brief Argument to `threadRoutine`. */
void ( * threadRoutine )( void * ); /**< @brief Thread function to run. */
} threadInfo_t;
/*-----------------------------------------------------------*/
/**
* @brief Sends provided buffer to network using transport send.
*
* @param[in] pArgument Argument passed to threadRoutine function.
*
*/
static void prvThreadRoutineWrapper( void * pArgument );
/**
* @brief Lock mutex with timeout.
*
* @param[in] pMutex Mutex to lock.
* @param[in] timeout Timeout value to lock mutex.
*
* @return true if mutex is locked successfully. Otherwise false.
*/
static bool prIotMutexTimedLock( PlatformMutex_t * pMutex,
TickType_t timeout );
/*-----------------------------------------------------------*/
static void prvThreadRoutineWrapper( void * pArgument )
{
threadInfo_t * pThreadInfo = ( threadInfo_t * ) pArgument;
/* Run the thread routine. */
pThreadInfo->threadRoutine( pThreadInfo->pArgument );
Platform_Free( pThreadInfo );
vTaskDelete( NULL );
}
/*-----------------------------------------------------------*/
static bool prIotMutexTimedLock( PlatformMutex_t * pMutex,
TickType_t timeout )
{
BaseType_t lockResult = pdTRUE;
configASSERT( pMutex != NULL );
LogDebug( ( "Locking mutex %p.", pMutex ) );
/* Call the correct FreeRTOS mutex take function based on mutex type. */
if( pMutex->recursive == pdTRUE )
{
lockResult = xSemaphoreTakeRecursive( ( SemaphoreHandle_t ) &pMutex->xMutex, timeout );
}
else
{
lockResult = xSemaphoreTake( ( SemaphoreHandle_t ) &pMutex->xMutex, timeout );
}
return( lockResult == pdTRUE );
}
/*-----------------------------------------------------------*/
bool Platform_CreateDetachedThread( void ( * threadRoutine )( void * ),
void * pArgument,
int32_t priority,
size_t stackSize )
{
bool status = true;
threadInfo_t * pThreadInfo = NULL;
configASSERT( threadRoutine != NULL );
LogDebug( ( "Creating new thread." ) );
pThreadInfo = Platform_Malloc( sizeof( threadInfo_t ) );
if( pThreadInfo == NULL )
{
LogDebug( ( "Unable to allocate memory for threadRoutine %p.", threadRoutine ) );
status = false;
}
/* Create the FreeRTOS task that will run the thread. */
if( status == true )
{
pThreadInfo->threadRoutine = threadRoutine;
pThreadInfo->pArgument = pArgument;
if( xTaskCreate( prvThreadRoutineWrapper,
"Cellular_Thread",
( configSTACK_DEPTH_TYPE ) stackSize,
pThreadInfo,
priority,
NULL ) != pdPASS )
{
/* Task creation failed. */
LogWarn( ( "Failed to create thread." ) );
Platform_Free( pThreadInfo );
status = false;
}
else
{
LogDebug( ( "New thread created." ) );
}
}
return status;
}
/*-----------------------------------------------------------*/
bool PlatformMutex_Create( PlatformMutex_t * pNewMutex,
bool recursive )
{
SemaphoreHandle_t xSemaphore = NULL;
bool retMutexCreate = false;
configASSERT( pNewMutex != NULL );
LogDebug( ( "Creating new mutex %p.", pNewMutex ) );
if( recursive == true )
{
xSemaphore = xSemaphoreCreateRecursiveMutexStatic( &pNewMutex->xMutex );
}
else
{
xSemaphore = xSemaphoreCreateMutexStatic( &pNewMutex->xMutex );
}
/* Remember the type of mutex. */
if( recursive == true )
{
pNewMutex->recursive = pdTRUE;
}
else
{
pNewMutex->recursive = pdFALSE;
}
/* Check the handle value returned by the mutex create function. */
if( xSemaphore == NULL )
{
retMutexCreate = false;
}
else
{
retMutexCreate = true;
}
return retMutexCreate;
}
/*-----------------------------------------------------------*/
void PlatformMutex_Destroy( PlatformMutex_t * pMutex )
{
configASSERT( pMutex != NULL );
vSemaphoreDelete( ( SemaphoreHandle_t ) &pMutex->xMutex );
}
/*-----------------------------------------------------------*/
void PlatformMutex_Lock( PlatformMutex_t * pMutex )
{
prIotMutexTimedLock( pMutex, portMAX_DELAY );
}
/*-----------------------------------------------------------*/
bool PlatformMutex_TryLock( PlatformMutex_t * pMutex )
{
return prIotMutexTimedLock( pMutex, 0 );
}
/*-----------------------------------------------------------*/
void PlatformMutex_Unlock( PlatformMutex_t * pMutex )
{
configASSERT( pMutex != NULL );
LogDebug( ( "Unlocking mutex %p.", pMutex ) );
/* Call the correct FreeRTOS mutex unlock function based on mutex type. */
if( pMutex->recursive == pdTRUE )
{
( void ) xSemaphoreGiveRecursive( ( SemaphoreHandle_t ) &pMutex->xMutex );
}
else
{
( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &pMutex->xMutex );
}
}
/*-----------------------------------------------------------*/

View file

@ -0,0 +1,169 @@
/*
* FreeRTOS V202107.00
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. 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
* 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.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*/
#ifndef __CELLULAR_PLATFORM_H__
#define __CELLULAR_PLATFORM_H__
#include "FreeRTOS.h"
#include "queue.h"
#include "semphr.h"
#include "event_groups.h"
#include <stdint.h>
#include <stdbool.h>
/*-----------------------------------------------------------*/
/**
* @brief Cellular library log configuration.
*
* Cellular library use CellularLogLevel macro for logging.
* The prototye of these logging function is similar with printf with return type ignored.
*
*/
#include "logging_levels.h"
#ifndef LIBRARY_LOG_NAME
#define LIBRARY_LOG_NAME "CELLULAR"
#endif
/* Prototype for the function used to print to console on Windows simulator
* of FreeRTOS.
* The function prints to the console before the network is connected;
* then a UDP port after the network has connected. */
extern void vLoggingPrintf( const char * pcFormatString,
... );
/* Map the SdkLog macro to the logging function to enable logging
* on Windows simulator. */
#ifndef SdkLog
#define SdkLog( message ) vLoggingPrintf message
#endif
#ifndef LIBRARY_LOG_LEVEL
#define LIBRARY_LOG_LEVEL LOG_ERROR
#endif
#include "logging_stack.h"
/*-----------------------------------------------------------*/
/**
* @brief Cellular library platform thread API and configuration.
*
* Cellular library create a detached thread by this API.
* The threadRoutine should be called with pArgument in the created thread.
*
* PLATFORM_THREAD_DEFAULT_STACK_SIZE and PLATFORM_THREAD_DEFAULT_PRIORITY defines
* the platform related stack size and priority.
*/
bool Platform_CreateDetachedThread( void ( * threadRoutine )( void * ),
void * pArgument,
int32_t priority,
size_t stackSize );
#define PLATFORM_THREAD_DEFAULT_STACK_SIZE ( 2048U )
#define PLATFORM_THREAD_DEFAULT_PRIORITY ( tskIDLE_PRIORITY + 5U )
/*-----------------------------------------------------------*/
/**
* @brief Cellular library platform mutex APIs.
*
* Cellular library use platform mutex to protect resource.
*
* The IotMutex_ functions can be referenced as function prototype for
* PlatfromMutex_ prefix function in the following link.
* https://docs.aws.amazon.com/freertos/latest/lib-ref/c-sdk/platform/platform_threads_functions.html
*
*/
typedef struct PlatformMutex
{
StaticSemaphore_t xMutex; /**< FreeRTOS mutex. */
BaseType_t recursive; /**< Type; used for indicating if this is reentrant or normal. */
} PlatformMutex_t;
bool PlatformMutex_Create( PlatformMutex_t * pNewMutex,
bool recursive );
void PlatformMutex_Destroy( PlatformMutex_t * pMutex );
void PlatformMutex_Lock( PlatformMutex_t * pMutex );
bool PlatformMutex_TryLock( PlatformMutex_t * pMutex );
void PlatformMutex_Unlock( PlatformMutex_t * pMutex );
/*-----------------------------------------------------------*/
/**
* @brief Cellular library platform memory allocation APIs.
*
* Cellular library use platform memory allocation APIs to allocate memory dynamically.
* The FreeRTOS memory management document can be referenced for these APIs.
* https://www.freertos.org/a00111.html
*
*/
#define Platform_Malloc pvPortMalloc
#define Platform_Free vPortFree
/*-----------------------------------------------------------*/
/**
* @brief Cellular library platform event group APIs.
*
* Cellular library use platform event group for process synchronization.
*
* The EventGroup functions in the following link can be referenced as function prototype.
* https://www.freertos.org/event-groups-API.html
*
*/
#define PlatformEventGroupHandle_t EventGroupHandle_t
#define PlatformEventGroup_Delete vEventGroupDelete
#define PlatformEventGroup_ClearBits xEventGroupClearBits
#define PlatformEventGroup_Create xEventGroupCreate
#define PlatformEventGroup_GetBits xEventGroupGetBits
#define PlatformEventGroup_SetBits xEventGroupSetBits
#define PlatformEventGroup_SetBitsFromISR xEventGroupSetBitsFromISR
#define PlatformEventGroup_WaitBits xEventGroupWaitBits
#define PlatformEventGroup_EventBits EventBits_t
#define PlatformTickType TickType_t
/*-----------------------------------------------------------*/
/**
* @brief Cellular library platform delay function.
*
* Cellular library use platform delay function for waiting events.
*
* The delay functions in the following link can be referenced as function prototype.
* https://www.freertos.org/a00127.html
*
*/
#define Platform_Delay( delayMs ) vTaskDelay( pdMS_TO_TICKS( delayMs ) )
#endif /* __CELLULAR_PLATFORM_H__ */

View file

@ -0,0 +1,217 @@
/*
* FreeRTOS V202107.00
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. 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
* 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.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/**
* @file cellular_setup.c
* @brief Setup cellular connectivity for board with cellular module.
*/
/* FreeRTOS include. */
#include <FreeRTOS.h>
#include "task.h"
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
/* Demo Specific configs. */
#include "demo_config.h"
/* The config header is always included first. */
#ifndef CELLULAR_DO_NOT_USE_CUSTOM_CONFIG
/* Include custom config file before other headers. */
#include "cellular_config.h"
#endif
#include "cellular_config_defaults.h"
#include "cellular_types.h"
#include "cellular_api.h"
#include "cellular_comm_interface.h"
/*-----------------------------------------------------------*/
#ifndef CELLULAR_APN
#error "CELLULAR_APN is not defined in cellular_config.h"
#endif
#define CELLULAR_SIM_CARD_WAIT_INTERVAL_MS ( 500UL )
#define CELLULAR_MAX_SIM_RETRY ( 5U )
#define CELLULAR_PDN_CONNECT_WAIT_INTERVAL_MS ( 1000UL )
/*-----------------------------------------------------------*/
/* the default Cellular comm interface in system. */
extern CellularCommInterface_t CellularCommInterface;
/*-----------------------------------------------------------*/
/* Secure socket needs application to provide the cellular handle and pdn context id. */
/* User of secure sockets cellular should provide this variable. */
CellularHandle_t CellularHandle = NULL;
/* User of secure sockets cellular should provide this variable. */
uint8_t CellularSocketPdnContextId = CELLULAR_PDN_CONTEXT_ID;
/*-----------------------------------------------------------*/
bool setupCellular( void )
{
bool cellularRet = true;
CellularError_t cellularStatus = CELLULAR_SUCCESS;
CellularSimCardStatus_t simStatus = { 0 };
CellularServiceStatus_t serviceStatus = { 0 };
CellularCommInterface_t * pCommIntf = &CellularCommInterface;
uint8_t tries = 0;
CellularPdnConfig_t pdnConfig = { CELLULAR_PDN_CONTEXT_IPV4, CELLULAR_PDN_AUTH_NONE, CELLULAR_APN, "", "" };
CellularPdnStatus_t PdnStatusBuffers = { 0 };
char localIP[ CELLULAR_IP_ADDRESS_MAX_SIZE ] = { '\0' };
uint32_t timeoutCountLimit = ( CELLULAR_PDN_CONNECT_TIMEOUT / CELLULAR_PDN_CONNECT_WAIT_INTERVAL_MS ) + 1U;
uint32_t timeoutCount = 0;
uint8_t NumStatus = 1;
CellularPsmSettings_t psmSettings = { 0 };
/* Initialize Cellular Comm Interface. */
cellularStatus = Cellular_Init( &CellularHandle, pCommIntf );
if( cellularStatus == CELLULAR_SUCCESS )
{
/* wait until SIM is ready */
for( tries = 0; tries < CELLULAR_MAX_SIM_RETRY; tries++ )
{
cellularStatus = Cellular_GetSimCardStatus( CellularHandle, &simStatus );
if( ( cellularStatus == CELLULAR_SUCCESS ) &&
( ( simStatus.simCardState == CELLULAR_SIM_CARD_INSERTED ) &&
( simStatus.simCardLockState == CELLULAR_SIM_CARD_READY ) ) )
{
/* Turn of PSM because this is demo to showcase MQTT instead of PSM mode. */
psmSettings.mode = 0;
cellularStatus = cellularStatus = Cellular_SetPsmSettings( CellularHandle, &psmSettings );
if( cellularStatus != CELLULAR_SUCCESS )
{
configPRINTF( ( ">>> Cellular_SetPsmSettings failure <<<\r\n" ) );
}
else
{
configPRINTF( ( ">>> Cellular SIM okay <<<\r\n" ) );
}
break;
}
else
{
configPRINTF( ( ">>> Cellular SIM card state %d, Lock State %d <<<\r\n",
simStatus.simCardState,
simStatus.simCardLockState ) );
}
vTaskDelay( pdMS_TO_TICKS( CELLULAR_SIM_CARD_WAIT_INTERVAL_MS ) );
}
}
/* Setup the PDN config. */
if( cellularStatus == CELLULAR_SUCCESS )
{
cellularStatus = Cellular_SetPdnConfig( CellularHandle, CellularSocketPdnContextId, &pdnConfig );
}
else
{
configPRINTF( ( ">>> Cellular SIM failure <<<\r\n" ) );
}
/* Rescan network. */
if( cellularStatus == CELLULAR_SUCCESS )
{
cellularStatus = Cellular_RfOff( CellularHandle );
}
if( cellularStatus == CELLULAR_SUCCESS )
{
cellularStatus = Cellular_RfOn( CellularHandle );
}
/* Get service status. */
if( cellularStatus == CELLULAR_SUCCESS )
{
while( timeoutCount < timeoutCountLimit )
{
cellularStatus = Cellular_GetServiceStatus( CellularHandle, &serviceStatus );
if( ( cellularStatus == CELLULAR_SUCCESS ) &&
( ( serviceStatus.psRegistrationStatus == REGISTRATION_STATUS_REGISTERED_HOME ) ||
( serviceStatus.psRegistrationStatus == REGISTRATION_STATUS_ROAMING_REGISTERED ) ) )
{
configPRINTF( ( ">>> Cellular module registered <<<\r\n" ) );
break;
}
else
{
configPRINTF( ( ">>> Cellular GetServiceStatus failed %d, ps registration status %d <<<\r\n",
cellularStatus, serviceStatus.psRegistrationStatus ) );
}
timeoutCount++;
if( timeoutCount >= timeoutCountLimit )
{
cellularStatus = CELLULAR_INVALID_HANDLE;
configPRINTF( ( ">>> Cellular module can't be registered <<<\r\n" ) );
}
vTaskDelay( pdMS_TO_TICKS( CELLULAR_PDN_CONNECT_WAIT_INTERVAL_MS ) );
}
}
if( cellularStatus == CELLULAR_SUCCESS )
{
cellularStatus = Cellular_ActivatePdn( CellularHandle, CellularSocketPdnContextId );
}
if( cellularStatus == CELLULAR_SUCCESS )
{
cellularStatus = Cellular_GetIPAddress( CellularHandle, CellularSocketPdnContextId, localIP, sizeof( localIP ) );
}
if( cellularStatus == CELLULAR_SUCCESS )
{
cellularStatus = Cellular_GetPdnStatus( CellularHandle, &PdnStatusBuffers, CellularSocketPdnContextId, &NumStatus );
}
if( ( cellularStatus == CELLULAR_SUCCESS ) && ( PdnStatusBuffers.state == 1 ) )
{
configPRINTF( ( ">>> Cellular module registered, IP address %s <<<\r\n", localIP ) );
cellularRet = true;
}
else
{
cellularRet = false;
}
return cellularRet;
}
/*-----------------------------------------------------------*/

View file

@ -0,0 +1,912 @@
/*
* FreeRTOS V202107.00
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. 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
* 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.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/**
* @file comm_if_windows.c
* @brief Windows Simulator file for cellular comm interface
*/
/*-----------------------------------------------------------*/
/* Windows include file for COM port I/O. */
#include <windows.h>
/* Platform layer includes. */
#include "cellular_platform.h"
/* Cellular comm interface include file. */
#include "cellular_config.h"
#include "cellular_config_defaults.h"
#include "cellular_comm_interface.h"
/*-----------------------------------------------------------*/
/* Define the COM port used as comm interface. */
#ifndef CELLULAR_COMM_INTERFACE_PORT
#error "Define CELLULAR_COMM_INTERFACE_PORT in cellular_config.h"
#endif
#define CELLULAR_COMM_PATH "\\\\.\\"CELLULAR_COMM_INTERFACE_PORT
/* Define the simulated UART interrupt number. */
#define portINTERRUPT_UART ( 2UL )
/* Define the read write buffer size. */
#define COMM_TX_BUFFER_SIZE ( 8192 )
#define COMM_RX_BUFFER_SIZE ( 8192 )
/* Receive thread timeout in ms. */
#define COMM_RECV_THREAD_TIMEOUT ( 5000 )
/* Write operation timeout in ms. */
#define COMM_WRITE_OPERATION_TIMEOUT ( 500 )
/* Comm status. */
#define CELLULAR_COMM_OPEN_BIT ( 0x01U )
/* Comm task event. */
#define COMMTASK_EVT_MASK_STARTED ( 0x0001UL )
#define COMMTASK_EVT_MASK_ABORT ( 0x0002UL )
#define COMMTASK_EVT_MASK_ABORTED ( 0x0004UL )
#define COMMTASK_EVT_MASK_ALL_EVENTS \
( COMMTASK_EVT_MASK_STARTED \
| COMMTASK_EVT_MASK_ABORT \
| COMMTASK_EVT_MASK_ABORTED )
#define COMMTASK_POLLING_TIME_MS ( 1UL )
/* Platform thread stack size and priority. */
#define COMM_IF_THREAD_DEFAULT_STACK_SIZE ( 2048U )
#define COMM_IF_THREAD_DEFAULT_PRIORITY ( tskIDLE_PRIORITY + 5U )
/*-----------------------------------------------------------*/
typedef struct _cellularCommContext
{
CellularCommInterfaceReceiveCallback_t commReceiveCallback;
HANDLE commReceiveCallbackThread;
uint8_t commStatus;
void * pUserData;
HANDLE commFileHandle;
CellularCommInterface_t * pCommInterface;
bool commTaskThreadStarted;
EventGroupHandle_t pCommTaskEvent;
} _cellularCommContext_t;
/*-----------------------------------------------------------*/
/**
* @brief CellularCommInterfaceOpen_t implementation.
*/
static CellularCommInterfaceError_t _prvCommIntfOpen( CellularCommInterfaceReceiveCallback_t receiveCallback,
void * pUserData,
CellularCommInterfaceHandle_t * pCommInterfaceHandle );
/**
* @brief CellularCommInterfaceSend_t implementation.
*/
static CellularCommInterfaceError_t _prvCommIntfSend( CellularCommInterfaceHandle_t commInterfaceHandle,
const uint8_t * pData,
uint32_t dataLength,
uint32_t timeoutMilliseconds,
uint32_t * pDataSentLength );
/**
* @brief CellularCommInterfaceRecv_t implementation.
*/
static CellularCommInterfaceError_t _prvCommIntfReceive( CellularCommInterfaceHandle_t commInterfaceHandle,
uint8_t * pBuffer,
uint32_t bufferLength,
uint32_t timeoutMilliseconds,
uint32_t * pDataReceivedLength );
/**
* @brief CellularCommInterfaceClose_t implementation.
*/
static CellularCommInterfaceError_t _prvCommIntfClose( CellularCommInterfaceHandle_t commInterfaceHandle );
/**
* @brief Get default comm interface context.
*
* @return On success, SOCKETS_ERROR_NONE is returned. If an error occurred, error code defined
* in sockets_wrapper.h is returned.
*/
static _cellularCommContext_t * _getCellularCommContext( void );
/**
* @brief UART interrupt handler.
*
* @return pdTRUE if the operation is successful, otherwise
* an error code indicating the cause of the error.
*/
static uint32_t prvProcessUartInt( void );
/**
* @brief Set COM port timeout settings.
*
* @param[in] hComm COM handle returned by CreateFile.
*
* @return On success, IOT_COMM_INTERFACE_SUCCESS is returned. If an error occurred, error code defined
* in CellularCommInterfaceError_t is returned.
*/
static CellularCommInterfaceError_t _setupCommTimeout( HANDLE hComm );
/**
* @brief Set COM port control settings.
*
* @param[in] hComm COM handle returned by CreateFile.
*
* @return On success, IOT_COMM_INTERFACE_SUCCESS is returned. If an error occurred, error code defined
* in CellularCommInterfaceError_t is returned.
*/
static CellularCommInterfaceError_t _setupCommSettings( HANDLE hComm );
/**
* @brief Thread routine to generate simulated interrupt.
*
* @param[in] pUserData Pointer to _cellularCommContext_t allocated in comm interface open.
*/
static void commTaskThread( void * pUserData );
/**
* @brief Helper function to setup and create commTaskThread.
*
* @param[in] pCellularCommContext Cellular comm interface context allocated in open.
*
* @return On success, IOT_COMM_INTERFACE_SUCCESS is returned. If an error occurred, error code defined
* in CellularCommInterfaceError_t is returned.
*/
static CellularCommInterfaceError_t setupCommTaskThread( _cellularCommContext_t * pCellularCommContext );
/**
* @brief Helper function to clean commTaskThread.
*
* @param[in] pCellularCommContext Cellular comm interface context allocated in open.
*
* @return On success, IOT_COMM_INTERFACE_SUCCESS is returned. If an error occurred, error code defined
* in CellularCommInterfaceError_t is returned.
*/
static CellularCommInterfaceError_t cleanCommTaskThread( _cellularCommContext_t * pCellularCommContext );
/*-----------------------------------------------------------*/
CellularCommInterface_t CellularCommInterface =
{
.open = _prvCommIntfOpen,
.send = _prvCommIntfSend,
.recv = _prvCommIntfReceive,
.close = _prvCommIntfClose
};
static _cellularCommContext_t _iotCellularCommContext =
{
.commReceiveCallback = NULL,
.commReceiveCallbackThread = NULL,
.pCommInterface = &CellularCommInterface,
.commFileHandle = NULL,
.pUserData = NULL,
.commStatus = 0U,
.commTaskThreadStarted = false,
.pCommTaskEvent = NULL
};
/* Indicate RX event is received in comm driver. */
static bool rxEvent = false;
/*-----------------------------------------------------------*/
static _cellularCommContext_t * _getCellularCommContext( void )
{
return &_iotCellularCommContext;
}
/*-----------------------------------------------------------*/
static uint32_t prvProcessUartInt( void )
{
_cellularCommContext_t * pCellularCommContext = _getCellularCommContext();
CellularCommInterfaceError_t callbackRet = IOT_COMM_INTERFACE_FAILURE;
uint32_t retUartInt = pdTRUE;
if( pCellularCommContext->commReceiveCallback != NULL )
{
callbackRet = pCellularCommContext->commReceiveCallback( pCellularCommContext->pUserData,
( CellularCommInterfaceHandle_t ) pCellularCommContext );
}
if( callbackRet == IOT_COMM_INTERFACE_SUCCESS )
{
retUartInt = pdTRUE;
}
else
{
retUartInt = pdFALSE;
}
return retUartInt;
}
/*-----------------------------------------------------------*/
/**
* @brief Communication receiver thread function.
*
* @param[in] pArgument windows COM port handle.
* @return 0 if thread function exit without error. Others for error.
*/
DWORD WINAPI _CellularCommReceiveCBThreadFunc( LPVOID pArgument )
{
DWORD dwCommStatus = 0;
HANDLE hComm = ( HANDLE ) pArgument;
BOOL retWait = FALSE;
DWORD retValue = 0;
if( hComm == ( HANDLE ) INVALID_HANDLE_VALUE )
{
retValue = ERROR_INVALID_HANDLE;
}
while( retValue == 0 )
{
retWait = WaitCommEvent( hComm, &dwCommStatus, NULL );
if( ( retWait != FALSE ) && ( ( dwCommStatus & EV_RXCHAR ) != 0 ) )
{
if( ( dwCommStatus & EV_RXCHAR ) != 0 )
{
rxEvent = true;
}
}
else
{
if( ( GetLastError() == ERROR_INVALID_HANDLE ) || ( GetLastError() == ERROR_OPERATION_ABORTED ) )
{
/* COM port closed. */
LogInfo( ( "Cellular COM port %p closed", hComm ) );
}
else
{
LogInfo( ( "Cellular receiver thread wait comm error %p %d", hComm, GetLastError() ) );
}
retValue = GetLastError();
break;
}
}
return retValue;
}
/*-----------------------------------------------------------*/
static CellularCommInterfaceError_t _setupCommTimeout( HANDLE hComm )
{
CellularCommInterfaceError_t commIntRet = IOT_COMM_INTERFACE_SUCCESS;
COMMTIMEOUTS xCommTimeouts = { 0 };
BOOL Status = TRUE;
/* Set ReadIntervalTimeout to MAXDWORD and zero values for both
* ReadTotalTimeoutConstant and ReadTotalTimeoutMultiplier to return
* immediately with the bytes that already been received. */
xCommTimeouts.ReadIntervalTimeout = MAXDWORD;
xCommTimeouts.ReadTotalTimeoutConstant = 0;
xCommTimeouts.ReadTotalTimeoutMultiplier = 0;
xCommTimeouts.WriteTotalTimeoutConstant = COMM_WRITE_OPERATION_TIMEOUT;
xCommTimeouts.WriteTotalTimeoutMultiplier = 0;
Status = SetCommTimeouts( hComm, &xCommTimeouts );
if( Status == FALSE )
{
LogError( ( "Cellular SetCommTimeouts fail %d", GetLastError() ) );
commIntRet = IOT_COMM_INTERFACE_FAILURE;
}
return commIntRet;
}
/*-----------------------------------------------------------*/
static CellularCommInterfaceError_t _setupCommSettings( HANDLE hComm )
{
CellularCommInterfaceError_t commIntRet = IOT_COMM_INTERFACE_SUCCESS;
DCB dcbSerialParams = { 0 };
BOOL Status = TRUE;
( void ) memset( &dcbSerialParams, 0, sizeof( dcbSerialParams ) );
dcbSerialParams.DCBlength = sizeof( dcbSerialParams );
dcbSerialParams.BaudRate = CBR_115200;
dcbSerialParams.fBinary = 1;
dcbSerialParams.ByteSize = 8;
dcbSerialParams.StopBits = ONESTOPBIT;
dcbSerialParams.Parity = NOPARITY;
dcbSerialParams.fOutxCtsFlow = FALSE;
dcbSerialParams.fOutxDsrFlow = FALSE;
dcbSerialParams.fDtrControl = DTR_CONTROL_ENABLE;
dcbSerialParams.fRtsControl = RTS_CONTROL_ENABLE;
Status = SetCommState( hComm, &dcbSerialParams );
if( Status == FALSE )
{
LogError( ( "Cellular SetCommState fail %d", GetLastError() ) );
commIntRet = IOT_COMM_INTERFACE_FAILURE;
}
return commIntRet;
}
/*-----------------------------------------------------------*/
static void commTaskThread( void * pUserData )
{
_cellularCommContext_t * pCellularCommContext = ( _cellularCommContext_t * ) pUserData;
EventBits_t uxBits = 0;
/* Inform thread ready. */
LogInfo( ( "Cellular commTaskThread started" ) );
if( pCellularCommContext != NULL )
{
( void ) xEventGroupSetBits( pCellularCommContext->pCommTaskEvent,
COMMTASK_EVT_MASK_STARTED );
}
while( true )
{
/* Wait for notification from eventqueue. */
uxBits = xEventGroupWaitBits( ( pCellularCommContext->pCommTaskEvent ),
( ( EventBits_t ) COMMTASK_EVT_MASK_ABORT ),
pdTRUE,
pdFALSE,
pdMS_TO_TICKS( COMMTASK_POLLING_TIME_MS ) );
if( ( uxBits & ( EventBits_t ) COMMTASK_EVT_MASK_ABORT ) != 0U )
{
LogDebug( ( "Abort received, cleaning up!" ) );
break;
}
else
{
/* Polling the global share variable to trigger the interrupt. */
if( rxEvent == true )
{
rxEvent = false;
vPortGenerateSimulatedInterrupt( portINTERRUPT_UART );
}
}
}
/* Inform thread ready. */
if( pCellularCommContext != NULL )
{
( void ) xEventGroupSetBits( pCellularCommContext->pCommTaskEvent, COMMTASK_EVT_MASK_ABORTED );
}
LogInfo( ( "Cellular commTaskThread exit" ) );
}
/*-----------------------------------------------------------*/
static CellularCommInterfaceError_t setupCommTaskThread( _cellularCommContext_t * pCellularCommContext )
{
BOOL Status = TRUE;
EventBits_t uxBits = 0;
CellularCommInterfaceError_t commIntRet = IOT_COMM_INTERFACE_SUCCESS;
pCellularCommContext->pCommTaskEvent = xEventGroupCreate();
if( pCellularCommContext->pCommTaskEvent != NULL )
{
/* Create the FreeRTOS thread to generate the simulated interrupt. */
Status = Platform_CreateDetachedThread( commTaskThread,
( void * ) pCellularCommContext,
COMM_IF_THREAD_DEFAULT_PRIORITY,
COMM_IF_THREAD_DEFAULT_STACK_SIZE );
if( Status != true )
{
commIntRet = IOT_COMM_INTERFACE_FAILURE;
}
}
else
{
commIntRet = IOT_COMM_INTERFACE_FAILURE;
}
if( commIntRet == IOT_COMM_INTERFACE_SUCCESS )
{
uxBits = xEventGroupWaitBits( ( pCellularCommContext->pCommTaskEvent ),
( ( EventBits_t ) COMMTASK_EVT_MASK_STARTED | ( EventBits_t ) COMMTASK_EVT_MASK_ABORTED ),
pdTRUE,
pdFALSE,
portMAX_DELAY );
if( ( uxBits & ( EventBits_t ) COMMTASK_EVT_MASK_STARTED ) == COMMTASK_EVT_MASK_STARTED )
{
pCellularCommContext->commTaskThreadStarted = true;
}
else
{
commIntRet = IOT_COMM_INTERFACE_FAILURE;
pCellularCommContext->commTaskThreadStarted = false;
}
}
return commIntRet;
}
/*-----------------------------------------------------------*/
static CellularCommInterfaceError_t cleanCommTaskThread( _cellularCommContext_t * pCellularCommContext )
{
EventBits_t uxBits = 0;
CellularCommInterfaceError_t commIntRet = IOT_COMM_INTERFACE_SUCCESS;
/* Wait for the commTaskThreadStarted exit. */
if( ( pCellularCommContext->commTaskThreadStarted == true ) && ( pCellularCommContext->pCommTaskEvent != NULL ) )
{
( void ) xEventGroupSetBits( pCellularCommContext->pCommTaskEvent,
COMMTASK_EVT_MASK_ABORT );
uxBits = xEventGroupWaitBits( ( pCellularCommContext->pCommTaskEvent ),
( ( EventBits_t ) COMMTASK_EVT_MASK_ABORTED ),
pdTRUE,
pdFALSE,
portMAX_DELAY );
if( ( uxBits & ( EventBits_t ) COMMTASK_EVT_MASK_ABORTED ) != COMMTASK_EVT_MASK_ABORTED )
{
LogDebug( ( "Cellular close wait commTaskThread fail" ) );
commIntRet = IOT_COMM_INTERFACE_FAILURE;
}
pCellularCommContext->commTaskThreadStarted = false;
}
/* Clean the event group. */
if( pCellularCommContext->pCommTaskEvent != NULL )
{
vEventGroupDelete( pCellularCommContext->pCommTaskEvent );
pCellularCommContext->pCommTaskEvent = NULL;
}
return commIntRet;
}
/*-----------------------------------------------------------*/
static CellularCommInterfaceError_t _prvCommIntfOpen( CellularCommInterfaceReceiveCallback_t receiveCallback,
void * pUserData,
CellularCommInterfaceHandle_t * pCommInterfaceHandle )
{
CellularCommInterfaceError_t commIntRet = IOT_COMM_INTERFACE_SUCCESS;
HANDLE hComm = ( HANDLE ) INVALID_HANDLE_VALUE;
BOOL Status = TRUE;
_cellularCommContext_t * pCellularCommContext = _getCellularCommContext();
DWORD dwRes = 0;
if( pCellularCommContext == NULL )
{
commIntRet = IOT_COMM_INTERFACE_FAILURE;
}
else if( ( pCellularCommContext->commStatus & CELLULAR_COMM_OPEN_BIT ) != 0 )
{
LogError( ( "Cellular comm interface opened already" ) );
commIntRet = IOT_COMM_INTERFACE_FAILURE;
}
else
{
/* Clear the context. */
memset( pCellularCommContext, 0, sizeof( _cellularCommContext_t ) );
pCellularCommContext->pCommInterface = &CellularCommInterface;
/* If CreateFile fails, the return value is INVALID_HANDLE_VALUE. */
hComm = CreateFile( TEXT( CELLULAR_COMM_PATH ),
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL );
}
/* Comm port is just closed. Wait 1 second and retry. */
if( ( hComm == ( HANDLE ) INVALID_HANDLE_VALUE ) && ( GetLastError() == 5 ) )
{
vTaskDelay( pdMS_TO_TICKS( 1000UL ) );
hComm = CreateFile( TEXT( CELLULAR_COMM_PATH ),
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL );
}
if( hComm == ( HANDLE ) INVALID_HANDLE_VALUE )
{
LogError( ( "Cellular open COM port fail %d", GetLastError() ) );
commIntRet = IOT_COMM_INTERFACE_FAILURE;
}
else
{
Status = SetupComm( hComm, COMM_TX_BUFFER_SIZE, COMM_RX_BUFFER_SIZE );
if( Status == FALSE )
{
LogError( ( "Cellular setup COM port fail %d", GetLastError() ) );
commIntRet = IOT_COMM_INTERFACE_FAILURE;
}
}
if( commIntRet == IOT_COMM_INTERFACE_SUCCESS )
{
commIntRet = _setupCommTimeout( hComm );
}
if( commIntRet == IOT_COMM_INTERFACE_SUCCESS )
{
commIntRet = _setupCommSettings( hComm );
}
if( commIntRet == IOT_COMM_INTERFACE_SUCCESS )
{
Status = SetCommMask( hComm, EV_RXCHAR );
if( Status == FALSE )
{
LogError( ( "Cellular SetCommMask fail %d", GetLastError() ) );
commIntRet = IOT_COMM_INTERFACE_FAILURE;
}
}
if( commIntRet == IOT_COMM_INTERFACE_SUCCESS )
{
pCellularCommContext->commReceiveCallback = receiveCallback;
commIntRet = setupCommTaskThread( pCellularCommContext );
}
if( commIntRet == IOT_COMM_INTERFACE_SUCCESS )
{
vPortSetInterruptHandler( portINTERRUPT_UART, prvProcessUartInt );
pCellularCommContext->commReceiveCallbackThread =
CreateThread( NULL, 0, _CellularCommReceiveCBThreadFunc, hComm, 0, NULL );
/* CreateThread return NULL for error. */
if( pCellularCommContext->commReceiveCallbackThread == NULL )
{
LogError( ( "Cellular CreateThread fail %d", GetLastError() ) );
commIntRet = IOT_COMM_INTERFACE_FAILURE;
}
}
if( commIntRet == IOT_COMM_INTERFACE_SUCCESS )
{
pCellularCommContext->pUserData = pUserData;
pCellularCommContext->commFileHandle = hComm;
*pCommInterfaceHandle = ( CellularCommInterfaceHandle_t ) pCellularCommContext;
pCellularCommContext->commStatus |= CELLULAR_COMM_OPEN_BIT;
}
else
{
/* Comm interface open fail. Clean the data. */
if( hComm != ( HANDLE ) INVALID_HANDLE_VALUE )
{
( void ) CloseHandle( hComm );
hComm = INVALID_HANDLE_VALUE;
commIntRet = IOT_COMM_INTERFACE_FAILURE;
}
/* Wait for the commReceiveCallbackThread exit. */
if( pCellularCommContext->commReceiveCallbackThread != NULL )
{
dwRes = WaitForSingleObject( pCellularCommContext->commReceiveCallbackThread, COMM_RECV_THREAD_TIMEOUT );
if( dwRes != WAIT_OBJECT_0 )
{
LogDebug( ( "Cellular close wait receiveCallbackThread %p fail %d",
pCellularCommContext->commReceiveCallbackThread, dwRes ) );
}
}
pCellularCommContext->commReceiveCallbackThread = NULL;
/* Wait for the commTaskThreadStarted exit. */
( void ) cleanCommTaskThread( pCellularCommContext );
}
return commIntRet;
}
/*-----------------------------------------------------------*/
static CellularCommInterfaceError_t _prvCommIntfClose( CellularCommInterfaceHandle_t commInterfaceHandle )
{
CellularCommInterfaceError_t commIntRet = IOT_COMM_INTERFACE_SUCCESS;
_cellularCommContext_t * pCellularCommContext = ( _cellularCommContext_t * ) commInterfaceHandle;
HANDLE hComm = NULL;
BOOL Status = TRUE;
DWORD dwRes = 0;
if( pCellularCommContext == NULL )
{
commIntRet = IOT_COMM_INTERFACE_FAILURE;
}
else if( ( pCellularCommContext->commStatus & CELLULAR_COMM_OPEN_BIT ) == 0 )
{
LogError( ( "Cellular close comm interface is not opened before." ) );
commIntRet = IOT_COMM_INTERFACE_FAILURE;
}
else
{
/* clean the receive callback. */
pCellularCommContext->commReceiveCallback = NULL;
/* Close the COM port. */
hComm = pCellularCommContext->commFileHandle;
if( hComm != ( HANDLE ) INVALID_HANDLE_VALUE )
{
Status = CloseHandle( hComm );
if( Status == FALSE )
{
LogDebug( ( "Cellular close CloseHandle %p fail", hComm ) );
commIntRet = IOT_COMM_INTERFACE_FAILURE;
}
}
else
{
commIntRet = IOT_COMM_INTERFACE_FAILURE;
}
pCellularCommContext->commFileHandle = NULL;
/* Wait for the thread exit. */
if( pCellularCommContext->commReceiveCallbackThread != NULL )
{
dwRes = WaitForSingleObject( pCellularCommContext->commReceiveCallbackThread, COMM_RECV_THREAD_TIMEOUT );
if( dwRes != WAIT_OBJECT_0 )
{
LogDebug( ( "Cellular close wait receiveCallbackThread %p fail %d",
pCellularCommContext->commReceiveCallbackThread, dwRes ) );
commIntRet = IOT_COMM_INTERFACE_FAILURE;
}
else
{
CloseHandle( pCellularCommContext->commReceiveCallbackThread );
}
}
pCellularCommContext->commReceiveCallbackThread = NULL;
/* Clean the commTaskThread. */
( void ) cleanCommTaskThread( pCellularCommContext );
/* clean the data structure. */
pCellularCommContext->commStatus &= ~( CELLULAR_COMM_OPEN_BIT );
}
return commIntRet;
}
/*-----------------------------------------------------------*/
static CellularCommInterfaceError_t _prvCommIntfSend( CellularCommInterfaceHandle_t commInterfaceHandle,
const uint8_t * pData,
uint32_t dataLength,
uint32_t timeoutMilliseconds,
uint32_t * pDataSentLength )
{
CellularCommInterfaceError_t commIntRet = IOT_COMM_INTERFACE_SUCCESS;
_cellularCommContext_t * pCellularCommContext = ( _cellularCommContext_t * ) commInterfaceHandle;
HANDLE hComm = NULL;
OVERLAPPED osWrite = { 0 };
DWORD dwRes = 0;
DWORD dwWritten = 0;
BOOL Status = TRUE;
if( pCellularCommContext == NULL )
{
commIntRet = IOT_COMM_INTERFACE_BAD_PARAMETER;
}
else if( ( pCellularCommContext->commStatus & CELLULAR_COMM_OPEN_BIT ) == 0 )
{
LogError( ( "Cellular send comm interface is not opened before." ) );
commIntRet = IOT_COMM_INTERFACE_FAILURE;
}
else
{
hComm = pCellularCommContext->commFileHandle;
osWrite.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
if( osWrite.hEvent == NULL )
{
LogError( ( "Cellular CreateEvent fail %d", GetLastError() ) );
commIntRet = IOT_COMM_INTERFACE_FAILURE;
}
}
if( commIntRet == IOT_COMM_INTERFACE_SUCCESS )
{
Status = WriteFile( hComm, pData, dataLength, &dwWritten, &osWrite );
/* WriteFile fail and error is not the ERROR_IO_PENDING. */
if( ( Status == FALSE ) && ( GetLastError() != ERROR_IO_PENDING ) )
{
LogError( ( "Cellular WriteFile fail %d", GetLastError() ) );
commIntRet = IOT_COMM_INTERFACE_FAILURE;
}
if( Status == TRUE )
{
*pDataSentLength = ( uint32_t ) dwWritten;
}
}
/* Handle pending I/O. */
if( ( commIntRet == IOT_COMM_INTERFACE_SUCCESS ) && ( Status == FALSE ) )
{
dwRes = WaitForSingleObject( osWrite.hEvent, timeoutMilliseconds );
switch( dwRes )
{
case WAIT_OBJECT_0:
if( GetOverlappedResult( hComm, &osWrite, &dwWritten, FALSE ) == FALSE )
{
LogError( ( "Cellular GetOverlappedResult fail %d", GetLastError() ) );
commIntRet = IOT_COMM_INTERFACE_FAILURE;
}
break;
case STATUS_TIMEOUT:
LogError( ( "Cellular WaitForSingleObject timeout" ) );
commIntRet = IOT_COMM_INTERFACE_TIMEOUT;
break;
default:
LogError( ( "Cellular WaitForSingleObject fail %d", dwRes ) );
commIntRet = IOT_COMM_INTERFACE_FAILURE;
break;
}
*pDataSentLength = ( uint32_t ) dwWritten;
}
if( osWrite.hEvent != NULL )
{
Status = CloseHandle( osWrite.hEvent );
if( Status == FALSE )
{
LogDebug( ( "Cellular send CloseHandle fail" ) );
}
}
return commIntRet;
}
/*-----------------------------------------------------------*/
static CellularCommInterfaceError_t _prvCommIntfReceive( CellularCommInterfaceHandle_t commInterfaceHandle,
uint8_t * pBuffer,
uint32_t bufferLength,
uint32_t timeoutMilliseconds,
uint32_t * pDataReceivedLength )
{
CellularCommInterfaceError_t commIntRet = IOT_COMM_INTERFACE_SUCCESS;
_cellularCommContext_t * pCellularCommContext = ( _cellularCommContext_t * ) commInterfaceHandle;
HANDLE hComm = NULL;
OVERLAPPED osRead = { 0 };
BOOL Status = TRUE;
DWORD dwRes = 0;
DWORD dwRead = 0;
if( pCellularCommContext == NULL )
{
commIntRet = IOT_COMM_INTERFACE_BAD_PARAMETER;
}
else if( ( pCellularCommContext->commStatus & CELLULAR_COMM_OPEN_BIT ) == 0 )
{
LogError( ( "Cellular read comm interface is not opened before." ) );
commIntRet = IOT_COMM_INTERFACE_FAILURE;
}
else
{
hComm = pCellularCommContext->commFileHandle;
osRead.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
if( osRead.hEvent == NULL )
{
LogError( ( "Cellular CreateEvent fail %d", GetLastError() ) );
commIntRet = IOT_COMM_INTERFACE_FAILURE;
}
}
if( commIntRet == IOT_COMM_INTERFACE_SUCCESS )
{
Status = ReadFile( hComm, pBuffer, bufferLength, &dwRead, &osRead );
if( ( Status == FALSE ) && ( GetLastError() != ERROR_IO_PENDING ) )
{
LogError( ( "Cellular ReadFile fail %d", GetLastError() ) );
commIntRet = IOT_COMM_INTERFACE_FAILURE;
}
if( Status == TRUE )
{
*pDataReceivedLength = ( uint32_t ) dwRead;
}
}
/* Handle pending I/O. */
if( ( commIntRet == IOT_COMM_INTERFACE_SUCCESS ) && ( Status == FALSE ) )
{
dwRes = WaitForSingleObject( osRead.hEvent, timeoutMilliseconds );
switch( dwRes )
{
case WAIT_OBJECT_0:
if( GetOverlappedResult( hComm, &osRead, &dwRead, FALSE ) == FALSE )
{
LogError( ( "Cellular receive GetOverlappedResult fail %d", GetLastError() ) );
commIntRet = IOT_COMM_INTERFACE_FAILURE;
}
break;
case STATUS_TIMEOUT:
LogError( ( "Cellular receive WaitForSingleObject timeout" ) );
commIntRet = IOT_COMM_INTERFACE_TIMEOUT;
break;
default:
LogError( ( "Cellular receive WaitForSingleObject fail %d", dwRes ) );
commIntRet = IOT_COMM_INTERFACE_FAILURE;
break;
}
*pDataReceivedLength = ( uint32_t ) dwRead;
}
if( osRead.hEvent != NULL )
{
Status = CloseHandle( osRead.hEvent );
if( Status == FALSE )
{
LogDebug( ( "Cellular recv CloseHandle fail" ) );
}
}
return commIntRet;
}
/*-----------------------------------------------------------*/

View file

@ -0,0 +1,346 @@
/*
* FreeRTOS V202107.00
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. 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
* 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.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/***
* See https://www.FreeRTOS.org/coremqtt for configuration and usage instructions.
***/
/* Standard includes. */
#include <stdio.h>
#include <time.h>
/* Visual studio intrinsics used so the __debugbreak() function is available
* should an assert get hit. */
#include <intrin.h>
/* FreeRTOS includes. */
#include <FreeRTOS.h>
#include "task.h"
/* TCP/IP stack includes. */
#include "FreeRTOS_IP.h"
#include "FreeRTOS_Sockets.h"
/* Demo logging includes. */
#include "logging.h"
/* Demo Specific configs. */
#include "demo_config.h"
/* FreeRTOS Cellular Library init and setup cellular network registration. */
extern bool setupCellular( void );
/* The MQTT demo entry function. */
extern void vStartSimpleMQTTDemo( void );
/* The task function to setup cellular with thread ready environment. */
static void CellularDemoTask( void * pvParameters );
/*
* Just seeds the simple pseudo random number generator.
*
* !!! NOTE !!!
* This is not a secure method of generating random numbers and production
* devices should use a true random number generator (TRNG).
*/
static void prvSRand( UBaseType_t ulSeed );
/*
* Miscellaneous initialization including preparing the logging and seeding the
* random number generator.
*/
static void prvMiscInitialisation( void );
/* Set the following constant to pdTRUE to log using the method indicated by the
* name of the constant, or pdFALSE to not log using the method indicated by the
* name of the constant. Options include to standard out (xLogToStdout), to a disk
* file (xLogToFile), and to a UDP port (xLogToUDP). If xLogToUDP is set to pdTRUE
* then UDP messages are sent to the IP address configured as the UDP logging server
* address (see the configUDP_LOGGING_ADDR0 definitions in FreeRTOSConfig.h) and
* the port number set by configPRINT_PORT in FreeRTOSConfig.h. */
const BaseType_t xLogToStdout = pdTRUE, xLogToFile = pdFALSE, xLogToUDP = pdFALSE;
/* Used by the pseudo random number generator. */
static UBaseType_t ulNextRand;
/*-----------------------------------------------------------*/
int main( void )
{
/***
* See https://www.FreeRTOS.org/iot-device-shadow for configuration and usage instructions.
***/
/* Miscellaneous initialization including preparing the logging and seeding
* the random number generator. */
prvMiscInitialisation();
/* Start the RTOS scheduler. */
vTaskStartScheduler();
/* If all is well, the scheduler will now be running, and the following
* line will never be reached. If the following line does execute, then
* there was insufficient FreeRTOS heap memory available for the idle and/or
* timer tasks to be created. See the memory management section on the
* FreeRTOS web site for more details (this is standard text that is not
* really applicable to the Win32 simulator port). */
for( ; ; )
{
__debugbreak();
}
}
/*-----------------------------------------------------------*/
/* Called by FreeRTOS+TCP when the network connects or disconnects. Disconnect
* events are only received if implemented in the MAC driver. */
void vApplicationIPNetworkEventHook( eIPCallbackEvent_t eNetworkEvent )
{
( void ) eNetworkEvent;
}
/*-----------------------------------------------------------*/
void vAssertCalled( const char * pcFile,
uint32_t ulLine )
{
volatile uint32_t ulBlockVariable = 0UL;
volatile char * pcFileName = ( volatile char * ) pcFile;
volatile uint32_t ulLineNumber = ulLine;
( void ) pcFileName;
( void ) ulLineNumber;
printf( "vAssertCalled( %s, %u\n", pcFile, ulLine );
/* Setting ulBlockVariable to a non-zero value in the debugger will allow
* this function to be exited. */
taskDISABLE_INTERRUPTS();
{
while( ulBlockVariable == 0UL )
{
__debugbreak();
}
}
taskENABLE_INTERRUPTS();
}
/*-----------------------------------------------------------*/
UBaseType_t uxRand( void )
{
const uint32_t ulMultiplier = 0x015a4e35UL, ulIncrement = 1UL;
/*
* Utility function to generate a pseudo random number.
*
* !!!NOTE!!!
* This is not a secure method of generating a random number. Production
* devices should use a True Random Number Generator (TRNG).
*/
ulNextRand = ( ulMultiplier * ulNextRand ) + ulIncrement;
return( ( int ) ( ulNextRand >> 16UL ) & 0x7fffUL );
}
/*-----------------------------------------------------------*/
static void prvSRand( UBaseType_t ulSeed )
{
/* Utility function to seed the pseudo random number generator. */
ulNextRand = ulSeed;
}
/*-----------------------------------------------------------*/
static void CellularDemoTask( void * pvParameters )
{
bool retCellular = true;
( void ) pvParameters;
/* Setup cellular. */
retCellular = setupCellular();
if( retCellular == false )
{
configPRINTF( ( "Cellular failed to initialize.\r\n" ) );
}
/* Stop here if we fail to initialize cellular. */
configASSERT( retCellular == true );
/* Run the MQTT demo. */
/* Demos that use the network are created after the network is
* up. */
LogInfo( ( "---------STARTING DEMO---------\r\n" ) );
vStartSimpleMQTTDemo();
vTaskDelete( NULL );
}
/*-----------------------------------------------------------*/
static void prvMiscInitialisation( void )
{
vLoggingInit( xLogToStdout, xLogToFile, xLogToUDP, 0U, configPRINT_PORT );
/* FreeRTOS Cellular Library init needs thread ready environment.
* CellularDemoTask invoke setupCellular to init FreeRTOS Cellular Library and register network.
* Then it runs the MQTT demo. */
xTaskCreate( CellularDemoTask, /* Function that implements the task. */
"CellularDemo", /* Text name for the task - only used for debugging. */
democonfigDEMO_STACKSIZE, /* Size of stack (in words, not bytes) to allocate for the task. */
NULL, /* Task parameter - not used in this case. */
democonfigDEMO_PRIORITY, /* Task priority, must be between 0 and configMAX_PRIORITIES - 1. */
NULL ); /* Used to pass out a handle to the created task - not used in this case. */
}
/*-----------------------------------------------------------*/
#if ( ipconfigUSE_LLMNR != 0 ) || ( ipconfigUSE_NBNS != 0 ) || ( ipconfigDHCP_REGISTER_HOSTNAME == 1 )
const char * pcApplicationHostnameHook( void )
{
/* Assign the name "FreeRTOS" to this network node. This function will
* be called during the DHCP: the machine will be registered with an IP
* address plus this name. */
return mainHOST_NAME;
}
#endif
/*-----------------------------------------------------------*/
#if ( ipconfigUSE_LLMNR != 0 ) || ( ipconfigUSE_NBNS != 0 )
BaseType_t xApplicationDNSQueryHook( const char * pcName )
{
BaseType_t xReturn;
/* Determine if a name lookup is for this node. Two names are given
* to this node: that returned by pcApplicationHostnameHook() and that set
* by mainDEVICE_NICK_NAME. */
if( _stricmp( pcName, pcApplicationHostnameHook() ) == 0 )
{
xReturn = pdPASS;
}
else if( _stricmp( pcName, mainDEVICE_NICK_NAME ) == 0 )
{
xReturn = pdPASS;
}
else
{
xReturn = pdFAIL;
}
return xReturn;
}
#endif /* if ( ipconfigUSE_LLMNR != 0 ) || ( ipconfigUSE_NBNS != 0 ) */
/*-----------------------------------------------------------*/
/*
* Callback that provides the inputs necessary to generate a randomized TCP
* Initial Sequence Number per RFC 6528. THIS IS ONLY A DUMMY IMPLEMENTATION
* THAT RETURNS A PSEUDO RANDOM NUMBER SO IS NOT INTENDED FOR USE IN PRODUCTION
* SYSTEMS.
*/
extern uint32_t ulApplicationGetNextSequenceNumber( uint32_t ulSourceAddress,
uint16_t usSourcePort,
uint32_t ulDestinationAddress,
uint16_t usDestinationPort )
{
( void ) ulSourceAddress;
( void ) usSourcePort;
( void ) ulDestinationAddress;
( void ) usDestinationPort;
return uxRand();
}
/*-----------------------------------------------------------*/
/*
* Set *pulNumber to a random number, and return pdTRUE. When the random number
* generator is broken, it shall return pdFALSE.
* The macros ipconfigRAND32() and configRAND32() are not in use
* anymore in FreeRTOS+TCP.
*
* THIS IS ONLY A DUMMY IMPLEMENTATION THAT RETURNS A PSEUDO RANDOM NUMBER SO IS
* NOT INTENDED FOR USE IN PRODUCTION SYSTEMS.
*/
BaseType_t xApplicationGetRandomNumber( uint32_t * pulNumber )
{
*pulNumber = uxRand();
return pdTRUE;
}
/*-----------------------------------------------------------*/
/* 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;
}
/*-----------------------------------------------------------*/
/* configUSE_STATIC_ALLOCATION and configUSE_TIMERS are both set to 1, so the
* application must provide an implementation of vApplicationGetTimerTaskMemory()
* to provide the memory that is used by the Timer service 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 Timer
* 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;
}
/*-----------------------------------------------------------*/