/* * 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 /* 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; } /*-----------------------------------------------------------*/