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