You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
FreeRTOS/FreeRTOS-Plus/Test/FreeRTOS-Cellular-Interface/Integration/comm_if_windows.c

1030 lines
35 KiB
C

/*
* FreeRTOS V202212.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 )
/* Comm port event. */
#define COMMPORT_EVT_RXCHAR ( 0x0001UL )
#define COMMPORT_EVT_TXEMPTY ( 0x0002UL )
/* COMM_IF_REOPEN_DELAY. */
#define COMM_IF_REOPEN_DELAY ( 100U )
/* 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; /* For receive callback function. */
EventGroupHandle_t pCommPortEvent; /* Notify RX TX events. */
} _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,
.pCommPortEvent = NULL
};
/* Indicate RX event is received in comm driver. */
static bool rxEvent = false;
static bool txEmptyEvent = 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;
_cellularCommContext_t * pCellularCommContext = _getCellularCommContext();
if( hComm == ( HANDLE ) INVALID_HANDLE_VALUE )
{
retValue = ERROR_INVALID_HANDLE;
}
while( retValue == 0 )
{
retWait = WaitCommEvent( hComm, &dwCommStatus, NULL );
if( ( retWait != FALSE ) && ( ( dwCommStatus & ( EV_RXCHAR | EV_TXEMPTY ) ) != 0 ) )
{
if( ( dwCommStatus & EV_RXCHAR ) != 0 )
{
/* The RXECHAR event. */
rxEvent = true;
}
if( ( dwCommStatus & EV_TXEMPTY ) != 0 )
{
/* The TXEMPTY event. */
txEmptyEvent = 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 );
( void ) xEventGroupSetBits( pCellularCommContext->pCommPortEvent,
COMMPORT_EVT_RXCHAR );
}
if( txEmptyEvent == true )
{
txEmptyEvent = false;
( void ) xEventGroupSetBits( pCellularCommContext->pCommPortEvent,
COMMPORT_EVT_TXEMPTY );
}
}
}
/* 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( pCommInterfaceHandle == NULL )
{
LogError( ( "Cellular comm pCommInterfaceHandle invalid" ) );
commIntRet = IOT_COMM_INTERFACE_BAD_PARAMETER;
}
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( COMM_IF_REOPEN_DELAY ) );
hComm = CreateFile( TEXT( CELLULAR_COMM_PATH ),
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED | FILE_FLAG_WRITE_THROUGH,
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 | EV_TXEMPTY );
if( Status == FALSE )
{
LogError( ( "Cellular SetCommMask fail %d", GetLastError() ) );
commIntRet = IOT_COMM_INTERFACE_FAILURE;
}
}
if( commIntRet == IOT_COMM_INTERFACE_SUCCESS )
{
pCellularCommContext->pCommPortEvent = xEventGroupCreate();
if( pCellularCommContext->pCommPortEvent == NULL )
{
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;
/* Clean the com port event group. */
if( pCellularCommContext->pCommPortEvent != NULL )
{
vEventGroupDelete( pCellularCommContext->pCommPortEvent );
pCellularCommContext->pCommPortEvent = 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 )
{
LogError( ( "Cellular close context is 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 )
{
LogError( ( "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 )
{
LogError( ( "Cellular close wait receiveCallbackThread %p fail %d",
pCellularCommContext->commReceiveCallbackThread, dwRes ) );
commIntRet = IOT_COMM_INTERFACE_FAILURE;
}
else
{
CloseHandle( pCellularCommContext->commReceiveCallbackThread );
}
}
pCellularCommContext->commReceiveCallbackThread = NULL;
/* Clean the com port event group. */
if( pCellularCommContext->pCommPortEvent != NULL )
{
vEventGroupDelete( pCellularCommContext->pCommPortEvent );
pCellularCommContext->pCommPortEvent = 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;
EventBits_t uxBits = 0;
if( pCellularCommContext == NULL )
{
LogError( ( "Cellular send comm interface handle invalid." ) );
commIntRet = IOT_COMM_INTERFACE_BAD_PARAMETER;
}
else if( ( pData == NULL ) || ( dataLength == 0 ) )
{
LogError( ( "Cellular send pData or dataLength invalid." ) );
commIntRet = IOT_COMM_INTERFACE_BAD_PARAMETER;
}
else if( pDataSentLength == NULL )
{
LogError( ( "Cellular send pDataSentLength invalid." ) );
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 );
if( Status == TRUE )
{
/* Waiting for TX empty. */
*pDataSentLength = ( uint32_t ) dwWritten;
/* Wait for notification from eventqueue. */
uxBits = xEventGroupWaitBits( ( pCellularCommContext->pCommPortEvent ),
( ( EventBits_t ) COMMPORT_EVT_TXEMPTY ),
pdTRUE,
pdFALSE,
pdMS_TO_TICKS( timeoutMilliseconds ) );
if( ( uxBits & COMMPORT_EVT_TXEMPTY ) == 0 )
{
LogError( ( "Cellular WriteFile fail timeout" ) );
commIntRet = IOT_COMM_INTERFACE_TIMEOUT;
}
}
else
{
/* WriteFile fail and error is not the ERROR_IO_PENDING. */
if( GetLastError() != ERROR_IO_PENDING )
{
LogError( ( "Cellular WriteFile fail %d", GetLastError() ) );
commIntRet = IOT_COMM_INTERFACE_FAILURE;
}
}
}
/* 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;
EventBits_t uxBits = 0;
if( pCellularCommContext == NULL )
{
LogError( ( "Cellular receive comm interface handle invalid." ) );
commIntRet = IOT_COMM_INTERFACE_BAD_PARAMETER;
}
else if( ( pBuffer == NULL ) || ( bufferLength == 0 ) )
{
LogError( ( "Cellular receive pBuffer or bufferLength invalid." ) );
commIntRet = IOT_COMM_INTERFACE_BAD_PARAMETER;
}
else if( pDataReceivedLength == NULL )
{
LogError( ( "Cellular receive pDataReceivedLength invalid." ) );
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 == TRUE ) && ( dwRead == 0 ) )
{
/* Wait for notification from eventqueue. */
uxBits = xEventGroupWaitBits( ( pCellularCommContext->pCommPortEvent ),
( ( EventBits_t ) COMMPORT_EVT_RXCHAR ),
pdTRUE,
pdFALSE,
pdMS_TO_TICKS( timeoutMilliseconds ) );
if( ( uxBits & COMMPORT_EVT_RXCHAR ) == 0 )
{
LogDebug( ( "Cellular ReadFile timeout" ) );
commIntRet = IOT_COMM_INTERFACE_TIMEOUT;
}
else
{
Status = ReadFile( hComm, pBuffer, bufferLength, &dwRead, &osRead );
}
}
if( Status == TRUE )
{
*pDataReceivedLength = ( uint32_t ) dwRead;
}
else
{
if( GetLastError() != ERROR_IO_PENDING )
{
LogError( ( "Cellular ReadFile fail %d", GetLastError() ) );
commIntRet = IOT_COMM_INTERFACE_FAILURE;
}
}
}
/* 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;
}
/*-----------------------------------------------------------*/