summaryrefslogtreecommitdiff
path: root/FreeRTOS-Plus/Test/FreeRTOS-Cellular-Interface/Integration/comm_if_windows.c
diff options
context:
space:
mode:
Diffstat (limited to 'FreeRTOS-Plus/Test/FreeRTOS-Cellular-Interface/Integration/comm_if_windows.c')
-rw-r--r--FreeRTOS-Plus/Test/FreeRTOS-Cellular-Interface/Integration/comm_if_windows.c1028
1 files changed, 1028 insertions, 0 deletions
diff --git a/FreeRTOS-Plus/Test/FreeRTOS-Cellular-Interface/Integration/comm_if_windows.c b/FreeRTOS-Plus/Test/FreeRTOS-Cellular-Interface/Integration/comm_if_windows.c
new file mode 100644
index 000000000..2c77c2b73
--- /dev/null
+++ b/FreeRTOS-Plus/Test/FreeRTOS-Cellular-Interface/Integration/comm_if_windows.c
@@ -0,0 +1,1028 @@
+/*
+ * Amazon FreeRTOS Cellular Preview Release
+ * 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.
+ *
+ * http://aws.amazon.com/freertos
+ * http://www.FreeRTOS.org
+ */
+
+
+/**
+ * @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;
+}
+
+/*-----------------------------------------------------------*/