1 /*
2  * FreeRTOS V202212.00
3  * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of
6  * this software and associated documentation files (the "Software"), to deal in
7  * the Software without restriction, including without limitation the rights to
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9  * the Software, and to permit persons to whom the Software is furnished to do so,
10  * subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in all
13  * copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  *
22  * https://www.FreeRTOS.org
23  * https://github.com/FreeRTOS
24  *
25  */
26 
27 
28 /**
29  * @file comm_if_windows.c
30  * @brief Windows Simulator file for cellular comm interface
31  */
32 
33 /*-----------------------------------------------------------*/
34 
35 /* Windows include file for COM port I/O. */
36 #include <windows.h>
37 
38 /* Platform layer includes. */
39 #include "cellular_platform.h"
40 
41 /* Cellular comm interface include file. */
42 #include "cellular_config.h"
43 #include "cellular_config_defaults.h"
44 #include "cellular_comm_interface.h"
45 
46 /*-----------------------------------------------------------*/
47 
48 /* Define the COM port used as comm interface. */
49 #ifndef CELLULAR_COMM_INTERFACE_PORT
50     #error "Define CELLULAR_COMM_INTERFACE_PORT in cellular_config.h"
51 #endif
52 #define CELLULAR_COMM_PATH                   "\\\\.\\"CELLULAR_COMM_INTERFACE_PORT
53 
54 /* Define the simulated UART interrupt number. */
55 #define portINTERRUPT_UART                   ( 2UL )
56 
57 /* Define the read write buffer size. */
58 #define COMM_TX_BUFFER_SIZE                  ( 8192 )
59 #define COMM_RX_BUFFER_SIZE                  ( 8192 )
60 
61 /* Receive thread timeout in ms. */
62 #define COMM_RECV_THREAD_TIMEOUT             ( 5000 )
63 
64 /* Write operation timeout in ms. */
65 #define COMM_WRITE_OPERATION_TIMEOUT         ( 500 )
66 
67 /* Comm status. */
68 #define CELLULAR_COMM_OPEN_BIT               ( 0x01U )
69 
70 /* Comm task event. */
71 #define COMMTASK_EVT_MASK_STARTED            ( 0x0001UL )
72 #define COMMTASK_EVT_MASK_ABORT              ( 0x0002UL )
73 #define COMMTASK_EVT_MASK_ABORTED            ( 0x0004UL )
74 #define COMMTASK_EVT_MASK_ALL_EVENTS \
75     ( COMMTASK_EVT_MASK_STARTED      \
76       | COMMTASK_EVT_MASK_ABORT      \
77       | COMMTASK_EVT_MASK_ABORTED )
78 #define COMMTASK_POLLING_TIME_MS             ( 1UL )
79 
80 /* Comm port event. */
81 #define COMMPORT_EVT_RXCHAR                  ( 0x0001UL )
82 #define COMMPORT_EVT_TXEMPTY                 ( 0x0002UL )
83 
84 /* COMM_IF_REOPEN_DELAY. */
85 #define COMM_IF_REOPEN_DELAY                 ( 100U )
86 
87 /* Platform thread stack size and priority. */
88 #define COMM_IF_THREAD_DEFAULT_STACK_SIZE    ( 2048U )
89 #define COMM_IF_THREAD_DEFAULT_PRIORITY      ( tskIDLE_PRIORITY + 5U )
90 
91 /*-----------------------------------------------------------*/
92 
93 typedef struct _cellularCommContext
94 {
95     CellularCommInterfaceReceiveCallback_t commReceiveCallback;
96     HANDLE commReceiveCallbackThread;
97     uint8_t commStatus;
98     void * pUserData;
99     HANDLE commFileHandle;
100     CellularCommInterface_t * pCommInterface;
101     bool commTaskThreadStarted;
102     EventGroupHandle_t pCommTaskEvent; /* For receive callback function. */
103     EventGroupHandle_t pCommPortEvent; /* Notify RX TX events. */
104 } _cellularCommContext_t;
105 
106 /*-----------------------------------------------------------*/
107 
108 /**
109  * @brief CellularCommInterfaceOpen_t implementation.
110  */
111 static CellularCommInterfaceError_t _prvCommIntfOpen( CellularCommInterfaceReceiveCallback_t receiveCallback,
112                                                       void * pUserData,
113                                                       CellularCommInterfaceHandle_t * pCommInterfaceHandle );
114 
115 /**
116  * @brief CellularCommInterfaceSend_t implementation.
117  */
118 static CellularCommInterfaceError_t _prvCommIntfSend( CellularCommInterfaceHandle_t commInterfaceHandle,
119                                                       const uint8_t * pData,
120                                                       uint32_t dataLength,
121                                                       uint32_t timeoutMilliseconds,
122                                                       uint32_t * pDataSentLength );
123 
124 /**
125  * @brief CellularCommInterfaceRecv_t implementation.
126  */
127 static CellularCommInterfaceError_t _prvCommIntfReceive( CellularCommInterfaceHandle_t commInterfaceHandle,
128                                                          uint8_t * pBuffer,
129                                                          uint32_t bufferLength,
130                                                          uint32_t timeoutMilliseconds,
131                                                          uint32_t * pDataReceivedLength );
132 
133 /**
134  * @brief CellularCommInterfaceClose_t implementation.
135  */
136 static CellularCommInterfaceError_t _prvCommIntfClose( CellularCommInterfaceHandle_t commInterfaceHandle );
137 
138 /**
139  * @brief Get default comm interface context.
140  *
141  * @return On success, SOCKETS_ERROR_NONE is returned. If an error occurred, error code defined
142  * in sockets_wrapper.h is returned.
143  */
144 static _cellularCommContext_t * _getCellularCommContext( void );
145 
146 /**
147  * @brief UART interrupt handler.
148  *
149  * @return pdTRUE if the operation is successful, otherwise
150  * an error code indicating the cause of the error.
151  */
152 static uint32_t prvProcessUartInt( void );
153 
154 /**
155  * @brief Set COM port timeout settings.
156  *
157  * @param[in] hComm COM handle returned by CreateFile.
158  *
159  * @return On success, IOT_COMM_INTERFACE_SUCCESS is returned. If an error occurred, error code defined
160  * in CellularCommInterfaceError_t is returned.
161  */
162 static CellularCommInterfaceError_t _setupCommTimeout( HANDLE hComm );
163 
164 /**
165  * @brief Set COM port control settings.
166  *
167  * @param[in] hComm COM handle returned by CreateFile.
168  *
169  * @return On success, IOT_COMM_INTERFACE_SUCCESS is returned. If an error occurred, error code defined
170  * in CellularCommInterfaceError_t is returned.
171  */
172 static CellularCommInterfaceError_t _setupCommSettings( HANDLE hComm );
173 
174 /**
175  * @brief Thread routine to generate simulated interrupt.
176  *
177  * @param[in] pUserData Pointer to _cellularCommContext_t allocated in comm interface open.
178  */
179 static void commTaskThread( void * pUserData );
180 
181 /**
182  * @brief Helper function to setup and create commTaskThread.
183  *
184  * @param[in] pCellularCommContext Cellular comm interface context allocated in open.
185  *
186  * @return On success, IOT_COMM_INTERFACE_SUCCESS is returned. If an error occurred, error code defined
187  * in CellularCommInterfaceError_t is returned.
188  */
189 static CellularCommInterfaceError_t setupCommTaskThread( _cellularCommContext_t * pCellularCommContext );
190 
191 /**
192  * @brief Helper function to clean commTaskThread.
193  *
194  * @param[in] pCellularCommContext Cellular comm interface context allocated in open.
195  *
196  * @return On success, IOT_COMM_INTERFACE_SUCCESS is returned. If an error occurred, error code defined
197  * in CellularCommInterfaceError_t is returned.
198  */
199 static CellularCommInterfaceError_t cleanCommTaskThread( _cellularCommContext_t * pCellularCommContext );
200 
201 /*-----------------------------------------------------------*/
202 
203 CellularCommInterface_t CellularCommInterface =
204 {
205     .open  = _prvCommIntfOpen,
206     .send  = _prvCommIntfSend,
207     .recv  = _prvCommIntfReceive,
208     .close = _prvCommIntfClose
209 };
210 
211 static _cellularCommContext_t _iotCellularCommContext =
212 {
213     .commReceiveCallback       = NULL,
214     .commReceiveCallbackThread = NULL,
215     .pCommInterface            = &CellularCommInterface,
216     .commFileHandle            = NULL,
217     .pUserData                 = NULL,
218     .commStatus                = 0U,
219     .commTaskThreadStarted     = false,
220     .pCommTaskEvent            = NULL,
221     .pCommPortEvent            = NULL
222 };
223 
224 /* Indicate RX event is received in comm driver. */
225 static bool rxEvent = false;
226 
227 static bool txEmptyEvent = false;
228 
229 /*-----------------------------------------------------------*/
230 
_getCellularCommContext(void)231 static _cellularCommContext_t * _getCellularCommContext( void )
232 {
233     return &_iotCellularCommContext;
234 }
235 
236 /*-----------------------------------------------------------*/
237 
prvProcessUartInt(void)238 static uint32_t prvProcessUartInt( void )
239 {
240     _cellularCommContext_t * pCellularCommContext = _getCellularCommContext();
241     CellularCommInterfaceError_t callbackRet = IOT_COMM_INTERFACE_FAILURE;
242     uint32_t retUartInt = pdTRUE;
243 
244     if( pCellularCommContext->commReceiveCallback != NULL )
245     {
246         callbackRet = pCellularCommContext->commReceiveCallback( pCellularCommContext->pUserData,
247                                                                  ( CellularCommInterfaceHandle_t ) pCellularCommContext );
248     }
249 
250     if( callbackRet == IOT_COMM_INTERFACE_SUCCESS )
251     {
252         retUartInt = pdTRUE;
253     }
254     else
255     {
256         retUartInt = pdFALSE;
257     }
258 
259     return retUartInt;
260 }
261 
262 /*-----------------------------------------------------------*/
263 
264 /**
265  * @brief Communication receiver thread function.
266  *
267  * @param[in] pArgument windows COM port handle.
268  * @return 0 if thread function exit without error. Others for error.
269  */
_CellularCommReceiveCBThreadFunc(LPVOID pArgument)270 DWORD WINAPI _CellularCommReceiveCBThreadFunc( LPVOID pArgument )
271 {
272     DWORD dwCommStatus = 0;
273     HANDLE hComm = ( HANDLE ) pArgument;
274     BOOL retWait = FALSE;
275     DWORD retValue = 0;
276     _cellularCommContext_t * pCellularCommContext = _getCellularCommContext();
277 
278     if( hComm == ( HANDLE ) INVALID_HANDLE_VALUE )
279     {
280         retValue = ERROR_INVALID_HANDLE;
281     }
282 
283     while( retValue == 0 )
284     {
285         retWait = WaitCommEvent( hComm, &dwCommStatus, NULL );
286 
287         if( ( retWait != FALSE ) && ( ( dwCommStatus & ( EV_RXCHAR | EV_TXEMPTY ) ) != 0 ) )
288         {
289             if( ( dwCommStatus & EV_RXCHAR ) != 0 )
290             {
291                 /* The RXECHAR event. */
292                 rxEvent = true;
293             }
294 
295             if( ( dwCommStatus & EV_TXEMPTY ) != 0 )
296             {
297                 /* The TXEMPTY event. */
298                 txEmptyEvent = true;
299             }
300         }
301         else
302         {
303             if( ( GetLastError() == ERROR_INVALID_HANDLE ) || ( GetLastError() == ERROR_OPERATION_ABORTED ) )
304             {
305                 /* COM port closed. */
306                 LogInfo( ( "Cellular COM port %p closed", hComm ) );
307             }
308             else
309             {
310                 LogInfo( ( "Cellular receiver thread wait comm error %p %d", hComm, GetLastError() ) );
311             }
312 
313             retValue = GetLastError();
314 
315             break;
316         }
317     }
318 
319     return retValue;
320 }
321 
322 /*-----------------------------------------------------------*/
323 
_setupCommTimeout(HANDLE hComm)324 static CellularCommInterfaceError_t _setupCommTimeout( HANDLE hComm )
325 {
326     CellularCommInterfaceError_t commIntRet = IOT_COMM_INTERFACE_SUCCESS;
327     COMMTIMEOUTS xCommTimeouts = { 0 };
328     BOOL Status = TRUE;
329 
330     /* Set ReadIntervalTimeout to MAXDWORD and zero values for both
331      * ReadTotalTimeoutConstant and ReadTotalTimeoutMultiplier to return
332      * immediately with the bytes that already been received. */
333     xCommTimeouts.ReadIntervalTimeout = MAXDWORD;
334     xCommTimeouts.ReadTotalTimeoutConstant = 0;
335     xCommTimeouts.ReadTotalTimeoutMultiplier = 0;
336     xCommTimeouts.WriteTotalTimeoutConstant = COMM_WRITE_OPERATION_TIMEOUT;
337     xCommTimeouts.WriteTotalTimeoutMultiplier = 0;
338     Status = SetCommTimeouts( hComm, &xCommTimeouts );
339 
340     if( Status == FALSE )
341     {
342         LogError( ( "Cellular SetCommTimeouts fail %d", GetLastError() ) );
343         commIntRet = IOT_COMM_INTERFACE_FAILURE;
344     }
345 
346     return commIntRet;
347 }
348 
349 /*-----------------------------------------------------------*/
350 
_setupCommSettings(HANDLE hComm)351 static CellularCommInterfaceError_t _setupCommSettings( HANDLE hComm )
352 {
353     CellularCommInterfaceError_t commIntRet = IOT_COMM_INTERFACE_SUCCESS;
354     DCB dcbSerialParams = { 0 };
355     BOOL Status = TRUE;
356 
357     ( void ) memset( &dcbSerialParams, 0, sizeof( dcbSerialParams ) );
358     dcbSerialParams.DCBlength = sizeof( dcbSerialParams );
359     dcbSerialParams.BaudRate = CBR_115200;
360     dcbSerialParams.fBinary = 1;
361     dcbSerialParams.ByteSize = 8;
362     dcbSerialParams.StopBits = ONESTOPBIT;
363     dcbSerialParams.Parity = NOPARITY;
364 
365     dcbSerialParams.fOutxCtsFlow = FALSE;
366     dcbSerialParams.fOutxDsrFlow = FALSE;
367     dcbSerialParams.fDtrControl = DTR_CONTROL_ENABLE;
368     dcbSerialParams.fRtsControl = RTS_CONTROL_ENABLE;
369 
370     Status = SetCommState( hComm, &dcbSerialParams );
371 
372     if( Status == FALSE )
373     {
374         LogError( ( "Cellular SetCommState fail %d", GetLastError() ) );
375         commIntRet = IOT_COMM_INTERFACE_FAILURE;
376     }
377 
378     return commIntRet;
379 }
380 
381 /*-----------------------------------------------------------*/
382 
commTaskThread(void * pUserData)383 static void commTaskThread( void * pUserData )
384 {
385     _cellularCommContext_t * pCellularCommContext = ( _cellularCommContext_t * ) pUserData;
386     EventBits_t uxBits = 0;
387 
388     /* Inform thread ready. */
389     LogInfo( ( "Cellular commTaskThread started" ) );
390 
391     if( pCellularCommContext != NULL )
392     {
393         ( void ) xEventGroupSetBits( pCellularCommContext->pCommTaskEvent,
394                                      COMMTASK_EVT_MASK_STARTED );
395     }
396 
397     while( true )
398     {
399         /* Wait for notification from eventqueue. */
400         uxBits = xEventGroupWaitBits( ( pCellularCommContext->pCommTaskEvent ),
401                                       ( ( EventBits_t ) COMMTASK_EVT_MASK_ABORT ),
402                                       pdTRUE,
403                                       pdFALSE,
404                                       pdMS_TO_TICKS( COMMTASK_POLLING_TIME_MS ) );
405 
406         if( ( uxBits & ( EventBits_t ) COMMTASK_EVT_MASK_ABORT ) != 0U )
407         {
408             LogDebug( ( "Abort received, cleaning up!" ) );
409             break;
410         }
411         else
412         {
413             /* Polling the global share variable to trigger the interrupt. */
414             if( rxEvent == true )
415             {
416                 rxEvent = false;
417                 vPortGenerateSimulatedInterrupt( portINTERRUPT_UART );
418                 ( void ) xEventGroupSetBits( pCellularCommContext->pCommPortEvent,
419                                              COMMPORT_EVT_RXCHAR );
420             }
421 
422             if( txEmptyEvent == true )
423             {
424                 txEmptyEvent = false;
425                 ( void ) xEventGroupSetBits( pCellularCommContext->pCommPortEvent,
426                                              COMMPORT_EVT_TXEMPTY );
427             }
428         }
429     }
430 
431     /* Inform thread ready. */
432     if( pCellularCommContext != NULL )
433     {
434         ( void ) xEventGroupSetBits( pCellularCommContext->pCommTaskEvent, COMMTASK_EVT_MASK_ABORTED );
435     }
436 
437     LogInfo( ( "Cellular commTaskThread exit" ) );
438 }
439 
440 /*-----------------------------------------------------------*/
441 
setupCommTaskThread(_cellularCommContext_t * pCellularCommContext)442 static CellularCommInterfaceError_t setupCommTaskThread( _cellularCommContext_t * pCellularCommContext )
443 {
444     BOOL Status = TRUE;
445     EventBits_t uxBits = 0;
446     CellularCommInterfaceError_t commIntRet = IOT_COMM_INTERFACE_SUCCESS;
447 
448     pCellularCommContext->pCommTaskEvent = xEventGroupCreate();
449 
450     if( pCellularCommContext->pCommTaskEvent != NULL )
451     {
452         /* Create the FreeRTOS thread to generate the simulated interrupt. */
453         Status = Platform_CreateDetachedThread( commTaskThread,
454                                                 ( void * ) pCellularCommContext,
455                                                 COMM_IF_THREAD_DEFAULT_PRIORITY,
456                                                 COMM_IF_THREAD_DEFAULT_STACK_SIZE );
457 
458         if( Status != true )
459         {
460             commIntRet = IOT_COMM_INTERFACE_FAILURE;
461         }
462     }
463     else
464     {
465         commIntRet = IOT_COMM_INTERFACE_FAILURE;
466     }
467 
468     if( commIntRet == IOT_COMM_INTERFACE_SUCCESS )
469     {
470         uxBits = xEventGroupWaitBits( ( pCellularCommContext->pCommTaskEvent ),
471                                       ( ( EventBits_t ) COMMTASK_EVT_MASK_STARTED | ( EventBits_t ) COMMTASK_EVT_MASK_ABORTED ),
472                                       pdTRUE,
473                                       pdFALSE,
474                                       portMAX_DELAY );
475 
476         if( ( uxBits & ( EventBits_t ) COMMTASK_EVT_MASK_STARTED ) == COMMTASK_EVT_MASK_STARTED )
477         {
478             pCellularCommContext->commTaskThreadStarted = true;
479         }
480         else
481         {
482             commIntRet = IOT_COMM_INTERFACE_FAILURE;
483             pCellularCommContext->commTaskThreadStarted = false;
484         }
485     }
486 
487     return commIntRet;
488 }
489 
490 /*-----------------------------------------------------------*/
491 
cleanCommTaskThread(_cellularCommContext_t * pCellularCommContext)492 static CellularCommInterfaceError_t cleanCommTaskThread( _cellularCommContext_t * pCellularCommContext )
493 {
494     EventBits_t uxBits = 0;
495     CellularCommInterfaceError_t commIntRet = IOT_COMM_INTERFACE_SUCCESS;
496 
497     /* Wait for the commTaskThreadStarted exit. */
498     if( ( pCellularCommContext->commTaskThreadStarted == true ) && ( pCellularCommContext->pCommTaskEvent != NULL ) )
499     {
500         ( void ) xEventGroupSetBits( pCellularCommContext->pCommTaskEvent,
501                                      COMMTASK_EVT_MASK_ABORT );
502         uxBits = xEventGroupWaitBits( ( pCellularCommContext->pCommTaskEvent ),
503                                       ( ( EventBits_t ) COMMTASK_EVT_MASK_ABORTED ),
504                                       pdTRUE,
505                                       pdFALSE,
506                                       portMAX_DELAY );
507 
508         if( ( uxBits & ( EventBits_t ) COMMTASK_EVT_MASK_ABORTED ) != COMMTASK_EVT_MASK_ABORTED )
509         {
510             LogDebug( ( "Cellular close wait commTaskThread fail" ) );
511             commIntRet = IOT_COMM_INTERFACE_FAILURE;
512         }
513 
514         pCellularCommContext->commTaskThreadStarted = false;
515     }
516 
517     /* Clean the event group. */
518     if( pCellularCommContext->pCommTaskEvent != NULL )
519     {
520         vEventGroupDelete( pCellularCommContext->pCommTaskEvent );
521         pCellularCommContext->pCommTaskEvent = NULL;
522     }
523 
524     return commIntRet;
525 }
526 
527 /*-----------------------------------------------------------*/
528 
_prvCommIntfOpen(CellularCommInterfaceReceiveCallback_t receiveCallback,void * pUserData,CellularCommInterfaceHandle_t * pCommInterfaceHandle)529 static CellularCommInterfaceError_t _prvCommIntfOpen( CellularCommInterfaceReceiveCallback_t receiveCallback,
530                                                       void * pUserData,
531                                                       CellularCommInterfaceHandle_t * pCommInterfaceHandle )
532 {
533     CellularCommInterfaceError_t commIntRet = IOT_COMM_INTERFACE_SUCCESS;
534     HANDLE hComm = ( HANDLE ) INVALID_HANDLE_VALUE;
535     BOOL Status = TRUE;
536     _cellularCommContext_t * pCellularCommContext = _getCellularCommContext();
537     DWORD dwRes = 0;
538 
539     if( pCommInterfaceHandle == NULL )
540     {
541         LogError( ( "Cellular comm pCommInterfaceHandle invalid" ) );
542         commIntRet = IOT_COMM_INTERFACE_BAD_PARAMETER;
543     }
544     else if( ( pCellularCommContext->commStatus & CELLULAR_COMM_OPEN_BIT ) != 0 )
545     {
546         LogError( ( "Cellular comm interface opened already" ) );
547         commIntRet = IOT_COMM_INTERFACE_FAILURE;
548     }
549     else
550     {
551         /* Clear the context. */
552         memset( pCellularCommContext, 0, sizeof( _cellularCommContext_t ) );
553         pCellularCommContext->pCommInterface = &CellularCommInterface;
554 
555         /* If CreateFile fails, the return value is INVALID_HANDLE_VALUE. */
556         hComm = CreateFile( TEXT( CELLULAR_COMM_PATH ),
557                             GENERIC_READ | GENERIC_WRITE,
558                             0,
559                             NULL,
560                             OPEN_EXISTING,
561                             FILE_FLAG_OVERLAPPED,
562                             NULL );
563     }
564 
565     /* Comm port is just closed. Wait 1 second and retry. */
566     if( ( hComm == ( HANDLE ) INVALID_HANDLE_VALUE ) && ( GetLastError() == 5 ) )
567     {
568         vTaskDelay( pdMS_TO_TICKS( COMM_IF_REOPEN_DELAY ) );
569         hComm = CreateFile( TEXT( CELLULAR_COMM_PATH ),
570                             GENERIC_READ | GENERIC_WRITE,
571                             0,
572                             NULL,
573                             OPEN_EXISTING,
574                             FILE_FLAG_OVERLAPPED | FILE_FLAG_WRITE_THROUGH,
575                             NULL );
576     }
577 
578     if( hComm == ( HANDLE ) INVALID_HANDLE_VALUE )
579     {
580         LogError( ( "Cellular open COM port fail %d", GetLastError() ) );
581         commIntRet = IOT_COMM_INTERFACE_FAILURE;
582     }
583     else
584     {
585         Status = SetupComm( hComm, COMM_TX_BUFFER_SIZE, COMM_RX_BUFFER_SIZE );
586 
587         if( Status == FALSE )
588         {
589             LogError( ( "Cellular setup COM port fail %d", GetLastError() ) );
590             commIntRet = IOT_COMM_INTERFACE_FAILURE;
591         }
592     }
593 
594     if( commIntRet == IOT_COMM_INTERFACE_SUCCESS )
595     {
596         commIntRet = _setupCommTimeout( hComm );
597     }
598 
599     if( commIntRet == IOT_COMM_INTERFACE_SUCCESS )
600     {
601         commIntRet = _setupCommSettings( hComm );
602     }
603 
604     if( commIntRet == IOT_COMM_INTERFACE_SUCCESS )
605     {
606         Status = SetCommMask( hComm, EV_RXCHAR | EV_TXEMPTY );
607 
608         if( Status == FALSE )
609         {
610             LogError( ( "Cellular SetCommMask fail %d", GetLastError() ) );
611             commIntRet = IOT_COMM_INTERFACE_FAILURE;
612         }
613     }
614 
615     if( commIntRet == IOT_COMM_INTERFACE_SUCCESS )
616     {
617         pCellularCommContext->pCommPortEvent = xEventGroupCreate();
618 
619         if( pCellularCommContext->pCommPortEvent == NULL )
620         {
621             LogError( ( "Cellular SetCommMask fail %d", GetLastError() ) );
622             commIntRet = IOT_COMM_INTERFACE_FAILURE;
623         }
624     }
625 
626     if( commIntRet == IOT_COMM_INTERFACE_SUCCESS )
627     {
628         pCellularCommContext->commReceiveCallback = receiveCallback;
629         commIntRet = setupCommTaskThread( pCellularCommContext );
630     }
631 
632     if( commIntRet == IOT_COMM_INTERFACE_SUCCESS )
633     {
634         vPortSetInterruptHandler( portINTERRUPT_UART, prvProcessUartInt );
635         pCellularCommContext->commReceiveCallbackThread =
636             CreateThread( NULL, 0, _CellularCommReceiveCBThreadFunc, hComm, 0, NULL );
637 
638         /* CreateThread return NULL for error. */
639         if( pCellularCommContext->commReceiveCallbackThread == NULL )
640         {
641             LogError( ( "Cellular CreateThread fail %d", GetLastError() ) );
642             commIntRet = IOT_COMM_INTERFACE_FAILURE;
643         }
644     }
645 
646     if( commIntRet == IOT_COMM_INTERFACE_SUCCESS )
647     {
648         pCellularCommContext->pUserData = pUserData;
649         pCellularCommContext->commFileHandle = hComm;
650         *pCommInterfaceHandle = ( CellularCommInterfaceHandle_t ) pCellularCommContext;
651         pCellularCommContext->commStatus |= CELLULAR_COMM_OPEN_BIT;
652     }
653     else
654     {
655         /* Comm interface open fail. Clean the data. */
656         if( hComm != ( HANDLE ) INVALID_HANDLE_VALUE )
657         {
658             ( void ) CloseHandle( hComm );
659             hComm = INVALID_HANDLE_VALUE;
660             commIntRet = IOT_COMM_INTERFACE_FAILURE;
661         }
662 
663         /* Wait for the commReceiveCallbackThread exit. */
664         if( pCellularCommContext->commReceiveCallbackThread != NULL )
665         {
666             dwRes = WaitForSingleObject( pCellularCommContext->commReceiveCallbackThread, COMM_RECV_THREAD_TIMEOUT );
667 
668             if( dwRes != WAIT_OBJECT_0 )
669             {
670                 LogDebug( ( "Cellular close wait receiveCallbackThread %p fail %d",
671                             pCellularCommContext->commReceiveCallbackThread, dwRes ) );
672             }
673         }
674 
675         pCellularCommContext->commReceiveCallbackThread = NULL;
676 
677         /* Clean the com port event group. */
678         if( pCellularCommContext->pCommPortEvent != NULL )
679         {
680             vEventGroupDelete( pCellularCommContext->pCommPortEvent );
681             pCellularCommContext->pCommPortEvent = NULL;
682         }
683 
684         /* Wait for the commTaskThreadStarted exit. */
685         ( void ) cleanCommTaskThread( pCellularCommContext );
686     }
687 
688     return commIntRet;
689 }
690 
691 /*-----------------------------------------------------------*/
692 
_prvCommIntfClose(CellularCommInterfaceHandle_t commInterfaceHandle)693 static CellularCommInterfaceError_t _prvCommIntfClose( CellularCommInterfaceHandle_t commInterfaceHandle )
694 {
695     CellularCommInterfaceError_t commIntRet = IOT_COMM_INTERFACE_SUCCESS;
696     _cellularCommContext_t * pCellularCommContext = ( _cellularCommContext_t * ) commInterfaceHandle;
697     HANDLE hComm = NULL;
698     BOOL Status = TRUE;
699     DWORD dwRes = 0;
700 
701     if( pCellularCommContext == NULL )
702     {
703         LogError( ( "Cellular close context is NULL" ) );
704         commIntRet = IOT_COMM_INTERFACE_FAILURE;
705     }
706     else if( ( pCellularCommContext->commStatus & CELLULAR_COMM_OPEN_BIT ) == 0 )
707     {
708         LogError( ( "Cellular close comm interface is not opened before." ) );
709         commIntRet = IOT_COMM_INTERFACE_FAILURE;
710     }
711     else
712     {
713         /* clean the receive callback. */
714         pCellularCommContext->commReceiveCallback = NULL;
715 
716         /* Close the COM port. */
717         hComm = pCellularCommContext->commFileHandle;
718 
719         if( hComm != ( HANDLE ) INVALID_HANDLE_VALUE )
720         {
721             Status = CloseHandle( hComm );
722 
723             if( Status == FALSE )
724             {
725                 LogError( ( "Cellular close CloseHandle %p fail", hComm ) );
726                 commIntRet = IOT_COMM_INTERFACE_FAILURE;
727             }
728         }
729         else
730         {
731             commIntRet = IOT_COMM_INTERFACE_FAILURE;
732         }
733 
734         pCellularCommContext->commFileHandle = NULL;
735 
736         /* Wait for the thread exit. */
737         if( pCellularCommContext->commReceiveCallbackThread != NULL )
738         {
739             dwRes = WaitForSingleObject( pCellularCommContext->commReceiveCallbackThread, COMM_RECV_THREAD_TIMEOUT );
740 
741             if( dwRes != WAIT_OBJECT_0 )
742             {
743                 LogError( ( "Cellular close wait receiveCallbackThread %p fail %d",
744                             pCellularCommContext->commReceiveCallbackThread, dwRes ) );
745                 commIntRet = IOT_COMM_INTERFACE_FAILURE;
746             }
747             else
748             {
749                 CloseHandle( pCellularCommContext->commReceiveCallbackThread );
750             }
751         }
752 
753         pCellularCommContext->commReceiveCallbackThread = NULL;
754 
755         /* Clean the com port event group. */
756         if( pCellularCommContext->pCommPortEvent != NULL )
757         {
758             vEventGroupDelete( pCellularCommContext->pCommPortEvent );
759             pCellularCommContext->pCommPortEvent = NULL;
760         }
761 
762         /* Clean the commTaskThread. */
763         ( void ) cleanCommTaskThread( pCellularCommContext );
764 
765         /* clean the data structure. */
766         pCellularCommContext->commStatus &= ~( CELLULAR_COMM_OPEN_BIT );
767     }
768 
769     return commIntRet;
770 }
771 
772 /*-----------------------------------------------------------*/
773 
_prvCommIntfSend(CellularCommInterfaceHandle_t commInterfaceHandle,const uint8_t * pData,uint32_t dataLength,uint32_t timeoutMilliseconds,uint32_t * pDataSentLength)774 static CellularCommInterfaceError_t _prvCommIntfSend( CellularCommInterfaceHandle_t commInterfaceHandle,
775                                                       const uint8_t * pData,
776                                                       uint32_t dataLength,
777                                                       uint32_t timeoutMilliseconds,
778                                                       uint32_t * pDataSentLength )
779 {
780     CellularCommInterfaceError_t commIntRet = IOT_COMM_INTERFACE_SUCCESS;
781     _cellularCommContext_t * pCellularCommContext = ( _cellularCommContext_t * ) commInterfaceHandle;
782     HANDLE hComm = NULL;
783     OVERLAPPED osWrite = { 0 };
784     DWORD dwRes = 0;
785     DWORD dwWritten = 0;
786     BOOL Status = TRUE;
787     EventBits_t uxBits = 0;
788 
789     if( pCellularCommContext == NULL )
790     {
791         LogError( ( "Cellular send comm interface handle invalid." ) );
792         commIntRet = IOT_COMM_INTERFACE_BAD_PARAMETER;
793     }
794     else if( ( pData == NULL ) || ( dataLength == 0 ) )
795     {
796         LogError( ( "Cellular send pData or dataLength invalid." ) );
797         commIntRet = IOT_COMM_INTERFACE_BAD_PARAMETER;
798     }
799     else if( pDataSentLength == NULL )
800     {
801         LogError( ( "Cellular send pDataSentLength invalid." ) );
802         commIntRet = IOT_COMM_INTERFACE_BAD_PARAMETER;
803     }
804     else if( ( pCellularCommContext->commStatus & CELLULAR_COMM_OPEN_BIT ) == 0 )
805     {
806         LogError( ( "Cellular send comm interface is not opened before." ) );
807         commIntRet = IOT_COMM_INTERFACE_FAILURE;
808     }
809     else
810     {
811         hComm = pCellularCommContext->commFileHandle;
812         osWrite.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
813 
814         if( osWrite.hEvent == NULL )
815         {
816             LogError( ( "Cellular CreateEvent fail %d", GetLastError() ) );
817             commIntRet = IOT_COMM_INTERFACE_FAILURE;
818         }
819     }
820 
821     if( commIntRet == IOT_COMM_INTERFACE_SUCCESS )
822     {
823         Status = WriteFile( hComm, pData, dataLength, &dwWritten, &osWrite );
824 
825         if( Status == TRUE )
826         {
827             /* Waiting for TX empty. */
828             *pDataSentLength = ( uint32_t ) dwWritten;
829 
830             /* Wait for notification from eventqueue. */
831             uxBits = xEventGroupWaitBits( ( pCellularCommContext->pCommPortEvent ),
832                                           ( ( EventBits_t ) COMMPORT_EVT_TXEMPTY ),
833                                           pdTRUE,
834                                           pdFALSE,
835                                           pdMS_TO_TICKS( timeoutMilliseconds ) );
836 
837             if( ( uxBits & COMMPORT_EVT_TXEMPTY ) == 0 )
838             {
839                 LogError( ( "Cellular WriteFile fail timeout" ) );
840                 commIntRet = IOT_COMM_INTERFACE_TIMEOUT;
841             }
842         }
843         else
844         {
845             /* WriteFile fail and error is not the ERROR_IO_PENDING. */
846             if( GetLastError() != ERROR_IO_PENDING )
847             {
848                 LogError( ( "Cellular WriteFile fail %d", GetLastError() ) );
849                 commIntRet = IOT_COMM_INTERFACE_FAILURE;
850             }
851         }
852     }
853 
854     /* Handle pending I/O. */
855     if( ( commIntRet == IOT_COMM_INTERFACE_SUCCESS ) && ( Status == FALSE ) )
856     {
857         dwRes = WaitForSingleObject( osWrite.hEvent, timeoutMilliseconds );
858 
859         switch( dwRes )
860         {
861             case WAIT_OBJECT_0:
862 
863                 if( GetOverlappedResult( hComm, &osWrite, &dwWritten, FALSE ) == FALSE )
864                 {
865                     LogError( ( "Cellular GetOverlappedResult fail %d", GetLastError() ) );
866                     commIntRet = IOT_COMM_INTERFACE_FAILURE;
867                 }
868 
869                 break;
870 
871             case STATUS_TIMEOUT:
872                 LogError( ( "Cellular WaitForSingleObject timeout" ) );
873                 commIntRet = IOT_COMM_INTERFACE_TIMEOUT;
874                 break;
875 
876             default:
877                 LogError( ( "Cellular WaitForSingleObject fail %d", dwRes ) );
878                 commIntRet = IOT_COMM_INTERFACE_FAILURE;
879                 break;
880         }
881 
882         *pDataSentLength = ( uint32_t ) dwWritten;
883     }
884 
885     if( osWrite.hEvent != NULL )
886     {
887         Status = CloseHandle( osWrite.hEvent );
888 
889         if( Status == FALSE )
890         {
891             LogDebug( ( "Cellular send CloseHandle fail" ) );
892         }
893     }
894 
895     return commIntRet;
896 }
897 
898 /*-----------------------------------------------------------*/
899 
_prvCommIntfReceive(CellularCommInterfaceHandle_t commInterfaceHandle,uint8_t * pBuffer,uint32_t bufferLength,uint32_t timeoutMilliseconds,uint32_t * pDataReceivedLength)900 static CellularCommInterfaceError_t _prvCommIntfReceive( CellularCommInterfaceHandle_t commInterfaceHandle,
901                                                          uint8_t * pBuffer,
902                                                          uint32_t bufferLength,
903                                                          uint32_t timeoutMilliseconds,
904                                                          uint32_t * pDataReceivedLength )
905 {
906     CellularCommInterfaceError_t commIntRet = IOT_COMM_INTERFACE_SUCCESS;
907     _cellularCommContext_t * pCellularCommContext = ( _cellularCommContext_t * ) commInterfaceHandle;
908     HANDLE hComm = NULL;
909     OVERLAPPED osRead = { 0 };
910     BOOL Status = TRUE;
911     DWORD dwRes = 0;
912     DWORD dwRead = 0;
913     EventBits_t uxBits = 0;
914 
915     if( pCellularCommContext == NULL )
916     {
917         LogError( ( "Cellular receive comm interface handle invalid." ) );
918         commIntRet = IOT_COMM_INTERFACE_BAD_PARAMETER;
919     }
920     else if( ( pBuffer == NULL ) || ( bufferLength == 0 ) )
921     {
922         LogError( ( "Cellular receive pBuffer or bufferLength invalid." ) );
923         commIntRet = IOT_COMM_INTERFACE_BAD_PARAMETER;
924     }
925     else if( pDataReceivedLength == NULL )
926     {
927         LogError( ( "Cellular receive pDataReceivedLength invalid." ) );
928         commIntRet = IOT_COMM_INTERFACE_BAD_PARAMETER;
929     }
930     else if( ( pCellularCommContext->commStatus & CELLULAR_COMM_OPEN_BIT ) == 0 )
931     {
932         LogError( ( "Cellular read comm interface is not opened before." ) );
933         commIntRet = IOT_COMM_INTERFACE_FAILURE;
934     }
935     else
936     {
937         hComm = pCellularCommContext->commFileHandle;
938         osRead.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
939 
940         if( osRead.hEvent == NULL )
941         {
942             LogError( ( "Cellular CreateEvent fail %d", GetLastError() ) );
943             commIntRet = IOT_COMM_INTERFACE_FAILURE;
944         }
945     }
946 
947     if( commIntRet == IOT_COMM_INTERFACE_SUCCESS )
948     {
949         Status = ReadFile( hComm, pBuffer, bufferLength, &dwRead, &osRead );
950 
951         if( ( Status == TRUE ) && ( dwRead == 0 ) )
952         {
953             /* Wait for notification from eventqueue. */
954             uxBits = xEventGroupWaitBits( ( pCellularCommContext->pCommPortEvent ),
955                                           ( ( EventBits_t ) COMMPORT_EVT_RXCHAR ),
956                                           pdTRUE,
957                                           pdFALSE,
958                                           pdMS_TO_TICKS( timeoutMilliseconds ) );
959 
960             if( ( uxBits & COMMPORT_EVT_RXCHAR ) == 0 )
961             {
962                 LogDebug( ( "Cellular ReadFile timeout" ) );
963                 commIntRet = IOT_COMM_INTERFACE_TIMEOUT;
964             }
965             else
966             {
967                 Status = ReadFile( hComm, pBuffer, bufferLength, &dwRead, &osRead );
968             }
969         }
970 
971         if( Status == TRUE )
972         {
973             *pDataReceivedLength = ( uint32_t ) dwRead;
974         }
975         else
976         {
977             if( GetLastError() != ERROR_IO_PENDING )
978             {
979                 LogError( ( "Cellular ReadFile fail %d", GetLastError() ) );
980                 commIntRet = IOT_COMM_INTERFACE_FAILURE;
981             }
982         }
983     }
984 
985     /* Handle pending I/O. */
986     if( ( commIntRet == IOT_COMM_INTERFACE_SUCCESS ) && ( Status == FALSE ) )
987     {
988         dwRes = WaitForSingleObject( osRead.hEvent, timeoutMilliseconds );
989 
990         switch( dwRes )
991         {
992             case WAIT_OBJECT_0:
993 
994                 if( GetOverlappedResult( hComm, &osRead, &dwRead, FALSE ) == FALSE )
995                 {
996                     LogError( ( "Cellular receive GetOverlappedResult fail %d", GetLastError() ) );
997                     commIntRet = IOT_COMM_INTERFACE_FAILURE;
998                 }
999 
1000                 break;
1001 
1002             case STATUS_TIMEOUT:
1003                 LogError( ( "Cellular receive WaitForSingleObject timeout" ) );
1004                 commIntRet = IOT_COMM_INTERFACE_TIMEOUT;
1005                 break;
1006 
1007             default:
1008                 LogError( ( "Cellular receive WaitForSingleObject fail %d", dwRes ) );
1009                 commIntRet = IOT_COMM_INTERFACE_FAILURE;
1010                 break;
1011         }
1012 
1013         *pDataReceivedLength = ( uint32_t ) dwRead;
1014     }
1015 
1016     if( osRead.hEvent != NULL )
1017     {
1018         Status = CloseHandle( osRead.hEvent );
1019 
1020         if( Status == FALSE )
1021         {
1022             LogDebug( ( "Cellular recv CloseHandle fail" ) );
1023         }
1024     }
1025 
1026     return commIntRet;
1027 }
1028 
1029 /*-----------------------------------------------------------*/
1030