diff --git a/docs/doxygen/include/size_table.md b/docs/doxygen/include/size_table.md index 18d9c478..b27e6752 100644 --- a/docs/doxygen/include/size_table.md +++ b/docs/doxygen/include/size_table.md @@ -30,7 +30,7 @@ cellular_common.c
1.7K
-
1.5K
+
1.6K
cellular_pkthandler.c @@ -39,12 +39,12 @@ cellular_pktio.c -
2.0K
-
1.8K
+
2.1K
+
1.9K
Total estimates -
14.8K
-
13.4K
+
14.9K
+
13.6K
diff --git a/lexicon.txt b/lexicon.txt index 06db4451..ef820fd8 100644 --- a/lexicon.txt +++ b/lexicon.txt @@ -269,6 +269,7 @@ efhplmnwact eidrxlist eidrxsettingslist emerg +endcode endcond endif endpatternlen @@ -354,6 +355,7 @@ inet ingroup inidcate init +inputbuffercallback inputline inputwithprefix int @@ -377,6 +379,7 @@ isurc isvalidpdn isvalidsocket jan +keepprocess keylist keylistlen kselacq @@ -409,6 +412,7 @@ mcc md mem memorystatus +memset metadata min misra @@ -484,6 +488,7 @@ pbandcfg pbervalue pbuf pbuffer +pbufferlengthhandled pbytesread pc pcallbackcontext @@ -534,6 +539,7 @@ pgenericcallbackcontext ph phexdata pinputbuf +pinputbuffercallbackcontext pinputline pinputptr pinputstr @@ -656,6 +662,7 @@ pstr pstring pstrvalue ptemp +ptempline ptempstring ptestusrdata ptofree diff --git a/source/cellular_common.c b/source/cellular_common.c index fd15d401..ec92d3f5 100644 --- a/source/cellular_common.c +++ b/source/cellular_common.c @@ -1137,3 +1137,37 @@ CellularError_t _Cellular_RegisterUndefinedRespCallback( CellularContext_t * pCo } /*-----------------------------------------------------------*/ + +CellularError_t _Cellular_RegisterInputBufferCallback( CellularContext_t * pContext, + CellularInputBufferCallback_t inputBufferCallback, + void * pInputBufferCallbackContext ) +{ + CellularError_t cellularStatus = CELLULAR_SUCCESS; + + if( pContext == NULL ) + { + LogError( ( "_Cellular_RegisterUrcDataCallback: invalid context." ) ); + cellularStatus = CELLULAR_INVALID_HANDLE; + } + else + { + /* inputBufferCallback can be set to NULL to unregister the callback. */ + PlatformMutex_Lock( &pContext->PktRespMutex ); + pContext->inputBufferCallback = inputBufferCallback; + + if( pContext->inputBufferCallback != NULL ) + { + pContext->pInputBufferCallbackContext = pInputBufferCallbackContext; + } + else + { + pContext->pInputBufferCallbackContext = NULL; + } + + PlatformMutex_Unlock( &pContext->PktRespMutex ); + } + + return cellularStatus; +} + +/*-----------------------------------------------------------*/ diff --git a/source/cellular_pktio.c b/source/cellular_pktio.c index 6f6f9796..117c39ec 100644 --- a/source/cellular_pktio.c +++ b/source/cellular_pktio.c @@ -113,6 +113,14 @@ static uint32_t _handleRxDataEvent( CellularContext_t * pContext, CellularATCommandResponse_t ** ppAtResp ); static void _pktioReadThread( void * pUserData ); static void _PktioInitProcessReadThreadStatus( CellularContext_t * pContext ); +static bool _getNextLine( CellularContext_t * pContext, + char ** ppLine, + uint32_t * pBytesRead, + uint32_t currentLineLength, + CellularPktStatus_t pktStatus ); +static bool _preprocessInputBuffer( CellularContext_t * pContext, + char ** pLine, + uint32_t * pBytesRead ); /*-----------------------------------------------------------*/ @@ -818,6 +826,80 @@ static bool _findLineInStream( CellularContext_t * pContext, /*-----------------------------------------------------------*/ +static bool _preprocessInputBuffer( CellularContext_t * pContext, + char ** pLine, + uint32_t * pBytesRead ) +{ + char * pTempLine = *pLine; + bool keepProcess = true; + uint32_t bufferLength = 0; + CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_OK; + + if( pContext->inputBufferCallback != NULL ) + { + PlatformMutex_Lock( &pContext->PktRespMutex ); + pktStatus = pContext->inputBufferCallback( pContext->pInputBufferCallbackContext, + pTempLine, + *pBytesRead, + &bufferLength ); + PlatformMutex_Unlock( &pContext->PktRespMutex ); + + if( pktStatus == CELLULAR_PKT_STATUS_PREFIX_MISMATCH ) + { + /* Input buffer is not handled in the callback. pktio should keep processing + * the input buffer. */ + keepProcess = true; + } + else if( pktStatus == CELLULAR_PKT_STATUS_SIZE_MISMATCH ) + { + /* Input buffer is handled in the callback. The callback expects to be called + * again with more data received. pktio won't keep process this input buffer. */ + pContext->pPktioReadPtr = pTempLine; + pContext->partialDataRcvdLen = *pBytesRead; + keepProcess = false; + } + else if( pktStatus != CELLULAR_PKT_STATUS_OK ) + { + /* Modem returns unexpected response. */ + LogError( ( "Input buffer callback returns error %d. Clean the read buffer.", pktStatus ) ); + + /* Clean the read buffer and read pointer. */ + ( void ) memset( pContext->pktioReadBuf, 0, PKTIO_READ_BUFFER_SIZE + 1U ); + pContext->pPktioReadPtr = NULL; + pContext->partialDataRcvdLen = 0; + keepProcess = false; + } + else if( bufferLength > *pBytesRead ) + { + /* The input buffer callback returns incorrect buffer length. */ + LogError( ( "Input buffer callback returns bufferLength %u. Modem returns length %u. Clean the read buffer.", + bufferLength, *pBytesRead ) ); + + /* Clean the read buffer and read pointer. */ + ( void ) memset( pContext->pktioReadBuf, 0, PKTIO_READ_BUFFER_SIZE + 1U ); + pContext->pPktioReadPtr = NULL; + pContext->partialDataRcvdLen = 0; + keepProcess = false; + } + else + { + /* The input buffer is handled in the callback successfully. Move + * the read pointer forward. pktio will keep processing the line + * after. */ + pTempLine = &pTempLine[ bufferLength ]; + *pLine = pTempLine; + pContext->pPktioReadPtr = *pLine; + + /* Calculate remain bytes in the buffer. */ + *pBytesRead = *pBytesRead - bufferLength; + } + } + + return keepProcess; +} + +/*-----------------------------------------------------------*/ + static bool _preprocessLine( CellularContext_t * pContext, char * pLine, uint32_t * pBytesRead, @@ -992,8 +1074,17 @@ static void _handleAllReceived( CellularContext_t * pContext, bytesRead = bytesRead - 1U; } + /* Preprocess the input buffer in the callback function. pktio processes the + * input buffer in line. This function allows the porting to process the input + * buffer before pktio processing lines in the buffer. For example, porting + * can make use of input buffer callback to handle binary stream in URC. */ + keepProcess = _preprocessInputBuffer( pContext, &pTempLine, &bytesRead ); + /* Preprocess line. */ - keepProcess = _preprocessLine( pContext, pTempLine, &bytesRead, &pStartOfData ); + if( keepProcess == true ) + { + keepProcess = _preprocessLine( pContext, pTempLine, &bytesRead, &pStartOfData ); + } if( keepProcess == true ) { diff --git a/source/include/common/cellular_common.h b/source/include/common/cellular_common.h index 7c773b24..aecc5c5e 100644 --- a/source/include/common/cellular_common.h +++ b/source/include/common/cellular_common.h @@ -223,6 +223,25 @@ typedef CellularPktStatus_t ( * CellularATCommandDataSendPrefixCallback_t ) ( vo typedef CellularPktStatus_t ( * CellularUndefinedRespCallback_t )( void * pCallbackContext, const char * pLine ); +/** + * @ingroup cellular_common_datatypes_functionpointers + * @brief Callback used to process input buffer. + * + * @param[in] pInputBufferCallbackContext The pCallbackContext in CellularInputBufferCallback_t. + * @param[in] pBuffer The data buffer with modem response data. + * @param[in] bufferLength The length of the input buffer. + * @param[out] pBufferLengthHandled The length of the handled input buffer in pBuffer. + * + * @return CELLULAR_PKT_STATUS_OK if the operation is successful. + * CELLULAR_PKT_STATUS_SIZE_MISMATCH if more data is required. + * CELLULAR_PKT_STATUS_PREFIX_MISMATCH if the input buffer is not handled in the callback. + * Otherwise an error code indicating the cause of the error. + */ +typedef CellularPktStatus_t ( * CellularInputBufferCallback_t ) ( void * pInputBufferCallbackContext, + char * pBuffer, + uint32_t bufferLength, + uint32_t * pBufferLengthHandled ); + /*-----------------------------------------------------------*/ /** @@ -623,6 +642,24 @@ CellularError_t _Cellular_RegisterUndefinedRespCallback( CellularContext_t * pCo CellularUndefinedRespCallback_t undefinedRespCallback, void * pCallbackContext ); +/** + * @brief Register input buffer callback. + * + * Cellular module can register the callback function to handler the input buffer + * before pktio continue to process the line in the buffer. + * + * @param[in] pContext The opaque cellular context pointer created by Cellular_Init. + * @param[in] inputBufferCallback The callback function to handle the URC data. + * @param[in] pInputBufferCallbackContext The pInputBufferCallbackContext passed to the inputBufferCallback + * callback function if inputBufferCallback is not NULL. + * + * @return CELLULAR_SUCCESS if the operation is successful, otherwise an error code + * indicating the cause of the error. + */ +CellularError_t _Cellular_RegisterInputBufferCallback( CellularContext_t * pContext, + CellularInputBufferCallback_t inputBufferCallback, + void * pInputBufferCallbackContext ); + /* *INDENT-OFF* */ #ifdef __cplusplus } diff --git a/source/include/private/cellular_common_internal.h b/source/include/private/cellular_common_internal.h index 9eba8ef0..c7af9296 100644 --- a/source/include/private/cellular_common_internal.h +++ b/source/include/private/cellular_common_internal.h @@ -144,6 +144,8 @@ struct CellularContext _atRespType_t recvdMsgType; /**< The received AT response type. */ CellularUndefinedRespCallback_t undefinedRespCallback; /**< Undefined response callback function. */ void * pUndefinedRespCBContext; /**< The pCallbackContext passed to CellularUndefinedRespCallback_t. */ + CellularInputBufferCallback_t inputBufferCallback; /**< URC data preprocess callback function. */ + void * pInputBufferCallbackContext; /**< the callback context passed to inputBufferCallback. */ /* PktIo data handling. */ uint32_t dataLength; /**< The data length in pLine. */ diff --git a/test/unit-test/cellular_common_utest.c b/test/unit-test/cellular_common_utest.c index 107ce0ca..50fe3801 100644 --- a/test/unit-test/cellular_common_utest.c +++ b/test/unit-test/cellular_common_utest.c @@ -410,6 +410,20 @@ void MockPlatformMutex_Destroy( PlatformMutex_t * pMutex ) pMutex->created = false; } + +static CellularPktStatus_t prvDummyInputBufferCallback( void * pInputBufferCallbackContext, + char * pBuffer, + uint32_t bufferLength, + uint32_t * pBufferLengthHandled ) +{ + ( void ) pInputBufferCallbackContext; + ( void ) pBuffer; + ( void ) bufferLength; + ( void ) pBufferLengthHandled; + + return CELLULAR_PKT_STATUS_OK; +} + /* ========================================================================== */ /** @@ -1640,3 +1654,66 @@ void test__Cellular_RegisterUndefinedRespCallback_Happy_Path( void ) TEST_ASSERT_NULL( context.undefinedRespCallback ); TEST_ASSERT_NULL( context.pUndefinedRespCBContext ); } + +/** + * @brief _Cellular_RegisterInputBufferCallback - parameter null context. + * pContext parameter is NULL. Verify the return value. + */ +void test__Cellular_RegisterInputBufferCallback_Null_Context( void ) +{ + CellularError_t cellularStatus = CELLULAR_SUCCESS; + + /* API call. */ + cellularStatus = _Cellular_RegisterInputBufferCallback( NULL, NULL, NULL ); + + /* Validation. */ + TEST_ASSERT_EQUAL( CELLULAR_INVALID_HANDLE, cellularStatus ); +} + +/** + * @brief _Cellular_RegisterInputBufferCallback - parameter NULL callback. + * inputBufferCallback parameter is NULL. Verify the member variable is updated. + */ +void test__Cellular_RegisterInputBufferCallback_Null_Callback( void ) +{ + CellularError_t cellularStatus = CELLULAR_SUCCESS; + CellularContext_t cellularContext; + uint32_t inputBufferCallbackContext; + + /* Setup internal variable. */ + memset( &cellularContext, 0, sizeof( CellularContext_t ) ); + cellularContext.inputBufferCallback = prvDummyInputBufferCallback; + cellularContext.pInputBufferCallbackContext = &inputBufferCallbackContext; + + /* API call. */ + cellularStatus = _Cellular_RegisterInputBufferCallback( &cellularContext, NULL, &inputBufferCallbackContext ); + + /* Validation. */ + TEST_ASSERT_EQUAL( CELLULAR_SUCCESS, cellularStatus ); + TEST_ASSERT_EQUAL( NULL, cellularContext.inputBufferCallback ); + /* The callback context will be cleaned when inputBufferCallback is NULL. */ + TEST_ASSERT_EQUAL( NULL, cellularContext.pInputBufferCallbackContext ); +} + +/** + * @brief _Cellular_RegisterInputBufferCallback - Setup the URC data callback. + * Verify the URC data callback and callback context are set correctly. + */ +void test__Cellular_RegisterInputBufferCallback_Happy_Path( void ) +{ + CellularError_t cellularStatus = CELLULAR_SUCCESS; + CellularContext_t cellularContext; + uint32_t inputBufferCallbackContext; + + /* Setup internal variable. */ + memset( &cellularContext, 0, sizeof( CellularContext_t ) ); + cellularContext.inputBufferCallback = NULL; + + /* API call. */ + cellularStatus = _Cellular_RegisterInputBufferCallback( &cellularContext, prvDummyInputBufferCallback, &inputBufferCallbackContext ); + + /* Validation. */ + TEST_ASSERT_EQUAL( CELLULAR_SUCCESS, cellularStatus ); + TEST_ASSERT_EQUAL( prvDummyInputBufferCallback, cellularContext.inputBufferCallback ); + TEST_ASSERT_EQUAL( &inputBufferCallbackContext, cellularContext.pInputBufferCallbackContext ); +} diff --git a/test/unit-test/cellular_pktio_utest.c b/test/unit-test/cellular_pktio_utest.c index 16c77b88..8e798080 100644 --- a/test/unit-test/cellular_pktio_utest.c +++ b/test/unit-test/cellular_pktio_utest.c @@ -78,6 +78,20 @@ #define MAX_QIRD_STRING_PREFIX_STRING ( 14U ) /* The max data prefix string is "+QIRD: 1460\r\n" */ +/* URC data callback test string. */ +#define URC_DATA_CALLBACK_PREFIX_MISMATCH_STR "+URC_PREFIX_MISMATCH:\r\n" +#define URC_DATA_CALLBACK_OTHER_ERROR_STR "+URC_OTHER_ERROR:\r\n" +#define URC_DATA_CALLBACK_INCORRECT_BUFFER_LEN_STR "+URC_INCORRECT_LENGTH:\r\n" +#define URC_DATA_CALLBACK_MATCH_STR "+URC_DATA:123\r\n" +#define URC_DATA_CALLBACK_MATCH_STR_LENGTH 15 +#define URC_DATA_CALLBACK_LEFT_OVER_STR "+URC_STRING:123\r\n" + +#define URC_DATA_CALLBACK_MATCH_STR_PREFIX "+URC_PART_DATA:" +#define URC_DATA_CALLBACK_MATCH_STR_PREFIX_LENGTH 15 +#define URC_DATA_CALLBACK_MATCH_STR_PART1 URC_DATA_CALLBACK_MATCH_STR_PREFIX "14\r\n1234" +#define URC_DATA_CALLBACK_MATCH_STR_PART2 "1234567890\r\n" +#define URC_DATA_CALLBACK_MATCH_STR_PART_LENGTH 35 + struct _cellularCommContext { int test1; @@ -123,9 +137,15 @@ static int32_t customCallbackContext = 0; static commIfRecvType_t testCommIfRecvType = COMM_IF_RECV_NORMAL; static char * pCommIntfRecvCustomString = NULL; +static void ( * pCommIntfRecvCustomStringCallback )( void ) = NULL; static bool atCmdStatusUndefindTest = false; +static void * inputBufferCallbackContext = NULL; + +static int dataUrcPktHandlerCallbackIsCalled = 0; +static char * pInputBufferPkthandlerString; + /* Try to Keep this map in Alphabetical order. */ /* FreeRTOS Cellular Common Library porting interface. */ /* coverity[misra_c_2012_rule_8_7_violation] */ @@ -224,6 +244,7 @@ void setUp() testCommIfRecvType = COMM_IF_RECV_NORMAL; pCommIntfRecvCustomString = NULL; + pCommIntfRecvCustomStringCallback = NULL; } /* Called after each test method. */ @@ -613,6 +634,11 @@ static CellularCommInterfaceError_t prvCommIntfReceiveCustomString( CellularComm ( void ) strncpy( ( char * ) pBuffer, pCommIntfRecvCustomString, bufferLength ); *pDataReceivedLength = strlen( pCommIntfRecvCustomString ); + + if( pCommIntfRecvCustomStringCallback != NULL ) + { + pCommIntfRecvCustomStringCallback(); + } } else { @@ -875,6 +901,80 @@ CellularPktStatus_t undefinedRespCallback( void * pCallbackContext, return undefineReturnStatus; } +static CellularPktStatus_t cellularInputBufferCallback( void * pInputBufferCallbackContext, + char * pBuffer, + uint32_t bufferLength, + uint32_t * pInputBufferLength ) +{ + CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_FAILURE; + + /* Verify the callback context. */ + TEST_ASSERT_EQUAL( inputBufferCallbackContext, pInputBufferCallbackContext ); + + /* Verify the callback context. */ + if( strncmp( pBuffer, URC_DATA_CALLBACK_PREFIX_MISMATCH_STR, bufferLength ) == 0 ) + { + *pInputBufferLength = 0; + pktStatus = CELLULAR_PKT_STATUS_PREFIX_MISMATCH; + } + else if( strncmp( pBuffer, URC_DATA_CALLBACK_OTHER_ERROR_STR, bufferLength ) == 0 ) + { + *pInputBufferLength = 0; + pktStatus = CELLULAR_PKT_STATUS_FAILURE; + } + else if( strncmp( pBuffer, URC_DATA_CALLBACK_INCORRECT_BUFFER_LEN_STR, bufferLength ) == 0 ) + { + /* Return incorrect buffer length. */ + *pInputBufferLength = bufferLength + 1; + pktStatus = CELLULAR_PKT_STATUS_OK; + } + else if( strncmp( pBuffer, URC_DATA_CALLBACK_MATCH_STR, URC_DATA_CALLBACK_MATCH_STR_LENGTH ) == 0 ) + { + *pInputBufferLength = 15; + pktStatus = CELLULAR_PKT_STATUS_OK; + } + else if( strncmp( pBuffer, URC_DATA_CALLBACK_MATCH_STR_PREFIX, URC_DATA_CALLBACK_MATCH_STR_PREFIX_LENGTH ) == 0 ) + { + if( bufferLength < URC_DATA_CALLBACK_MATCH_STR_PART_LENGTH ) + { + pktStatus = CELLULAR_PKT_STATUS_SIZE_MISMATCH; + } + else if( bufferLength == URC_DATA_CALLBACK_MATCH_STR_PART_LENGTH ) + { + *pInputBufferLength = URC_DATA_CALLBACK_MATCH_STR_PART_LENGTH; + pktStatus = CELLULAR_PKT_STATUS_OK; + } + } + + return pktStatus; +} + +static CellularPktStatus_t prvDataUrcPktHandlerCallback( CellularContext_t * pContext, + _atRespType_t atRespType, + const void * pBuffer ) +{ + int compareResult; + + ( void ) pContext; + + dataUrcPktHandlerCallbackIsCalled = 1; + + /* Verify the atRespType is AT_UNSOLICITED. */ + TEST_ASSERT_EQUAL( AT_UNSOLICITED, atRespType ); + + /* Verify the pBuffer contains the same string passed in the test. */ + compareResult = strncmp( pBuffer, pInputBufferPkthandlerString, strlen( pBuffer ) ); + TEST_ASSERT_EQUAL( 0, compareResult ); + + return CELLULAR_PKT_STATUS_OK; +} + +static void prvInputBufferCommIntfRecvCallback( void ) +{ + pCommIntfRecvCustomString = URC_DATA_CALLBACK_MATCH_STR_PART2; +} + + /* ========================================================================== */ /** @@ -1280,6 +1380,292 @@ void test__Cellular_PktioInit_Thread_Rx_Data_Event_pktDataPrefixCB__Test( void ) TEST_ASSERT_EQUAL( CELLULAR_PKT_STATUS_OK, pktStatus ); } +/** + * @brief _preprocessInputBuffer - inputBufferCallback returns CELLULAR_PKT_STATUS_PREFIX_MISMATCH. + * + * CELLULAR_PKT_STATUS_PREFIX_MISMATCH is returned by the callback function. Verify + * that RX thread keep process the data. + * + * Coverage + * @code{c} + * if( pktStatus == CELLULAR_PKT_STATUS_PREFIX_MISMATCH ) + * { + * keepProcess = true; + * } + * @endcode + * ( pktStatus == CELLULAR_PKT_STATUS_PREFIX_MISMATCH ) is true. + */ +void test__Cellular_PktioInit_Thread_Rx_Data_Event__preprocessInputBuffer_prefix_mismatch( void ) +{ + CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_OK; + CellularContext_t context; + CellularCommInterface_t * pCommIntf = &CellularCommInterface; + + threadReturn = true; + memset( &context, 0, sizeof( CellularContext_t ) ); + + /* Assign the comm interface to pContext. */ + context.pCommIntf = pCommIntf; + context.pPktioShutdownCB = _shutdownCallback; + + /* copy the token table. */ + ( void ) memcpy( &context.tokenTable, &tokenTable, sizeof( CellularTokenTable_t ) ); + + /* RX data event for RX thread. */ + pktioEvtMask = PKTIO_EVT_MASK_RX_DATA; + + /* Setup the URC data callback for testing. */ + context.inputBufferCallback = cellularInputBufferCallback; + context.pInputBufferCallbackContext = NULL; + recvCount = 1; + atCmdType = CELLULAR_AT_NO_RESULT; + testCommIfRecvType = COMM_IF_RECV_CUSTOM_STRING; + pCommIntfRecvCustomString = URC_DATA_CALLBACK_PREFIX_MISMATCH_STR; + pInputBufferPkthandlerString = URC_DATA_CALLBACK_PREFIX_MISMATCH_STR; + dataUrcPktHandlerCallbackIsCalled = 0; + + /* API call. */ + pktStatus = _Cellular_PktioInit( &context, prvDataUrcPktHandlerCallback ); + + /* Verification. */ + TEST_ASSERT_EQUAL( CELLULAR_PKT_STATUS_OK, pktStatus ); + + /* This test verifies that the pktio rx thread will continue to process the + * data in the callback function. */ + TEST_ASSERT_EQUAL( 1, dataUrcPktHandlerCallbackIsCalled ); +} + +/** + * @brief _preprocessInputBuffer - inputBufferCallback returns other errors. + * + * Other error is returned by the callback function. Verify that RX thread stop + * processing the data. + * + * Coverage + * @code{c} + * else if( pktStatus != CELLULAR_PKT_STATUS_OK ) + * { + * ... + * ( void ) memset( pContext->pktioReadBuf, 0, PKTIO_READ_BUFFER_SIZE + 1U ); + * pContext->pPktioReadPtr = NULL; + * pContext->partialDataRcvdLen = 0; + * keepProcess = false; + * } + * @endcode + * ( pktStatus != CELLULAR_PKT_STATUS_OK ) is true. + */ +void test__Cellular_PktioInit_Thread_Rx_Data_Event__preprocessInputBuffer_other_error( void ) +{ + CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_OK; + CellularContext_t context; + CellularCommInterface_t * pCommIntf = &CellularCommInterface; + + threadReturn = true; + memset( &context, 0, sizeof( CellularContext_t ) ); + + /* Assign the comm interface to pContext. */ + context.pCommIntf = pCommIntf; + context.pPktioShutdownCB = _shutdownCallback; + + /* copy the token table. */ + ( void ) memcpy( &context.tokenTable, &tokenTable, sizeof( CellularTokenTable_t ) ); + + /* RX data event for RX thread. */ + pktioEvtMask = PKTIO_EVT_MASK_RX_DATA; + + /* Setup the URC data callback for testing. */ + context.inputBufferCallback = cellularInputBufferCallback; + context.pInputBufferCallbackContext = NULL; + recvCount = 1; + atCmdType = CELLULAR_AT_NO_RESULT; + testCommIfRecvType = COMM_IF_RECV_CUSTOM_STRING; + pCommIntfRecvCustomString = URC_DATA_CALLBACK_OTHER_ERROR_STR; + dataUrcPktHandlerCallbackIsCalled = 0; + + /* API call. */ + pktStatus = _Cellular_PktioInit( &context, prvDataUrcPktHandlerCallback ); + + /* Verification. */ + TEST_ASSERT_EQUAL( CELLULAR_PKT_STATUS_OK, pktStatus ); + + /* The pkthandler callback should not be called. */ + TEST_ASSERT_EQUAL( 0, dataUrcPktHandlerCallbackIsCalled ); +} + +/** + * @brief _preprocessInputBuffer - inputBufferCallback returns incorrect buffer length. + * + * Incorrect buffer length is returned by the callback function. Verify that RX + * thread stop processing the data. + * + * Coverage + * @code{c} + * else if( bufferLength > *pBytesRead ) + * { + * ... + * ( void ) memset( pContext->pktioReadBuf, 0, PKTIO_READ_BUFFER_SIZE + 1U ); + * pContext->pPktioReadPtr = NULL; + * pContext->partialDataRcvdLen = 0; + * keepProcess = false; + * } + * @endcode + * ( bufferLength > *pBytesRead ) is true. + */ +void test__Cellular_PktioInit_Thread_Rx_Data_Event__preprocessInputBuffer_incorrect_buffer_length( void ) +{ + CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_OK; + CellularContext_t context; + CellularCommInterface_t * pCommIntf = &CellularCommInterface; + + threadReturn = true; + memset( &context, 0, sizeof( CellularContext_t ) ); + + /* Assign the comm interface to pContext. */ + context.pCommIntf = pCommIntf; + context.pPktioShutdownCB = _shutdownCallback; + + /* copy the token table. */ + ( void ) memcpy( &context.tokenTable, &tokenTable, sizeof( CellularTokenTable_t ) ); + + /* RX data event for RX thread. */ + pktioEvtMask = PKTIO_EVT_MASK_RX_DATA; + + /* Setup the URC data callback for testing. */ + context.inputBufferCallback = cellularInputBufferCallback; + context.pInputBufferCallbackContext = NULL; + recvCount = 1; + atCmdType = CELLULAR_AT_NO_RESULT; + testCommIfRecvType = COMM_IF_RECV_CUSTOM_STRING; + pCommIntfRecvCustomString = URC_DATA_CALLBACK_INCORRECT_BUFFER_LEN_STR; + dataUrcPktHandlerCallbackIsCalled = 0; + + /* API call. */ + pktStatus = _Cellular_PktioInit( &context, prvDataUrcPktHandlerCallback ); + + /* Verification. */ + TEST_ASSERT_EQUAL( CELLULAR_PKT_STATUS_OK, pktStatus ); + + /* The pkthandler callback should not be called. */ + TEST_ASSERT_EQUAL( 0, dataUrcPktHandlerCallbackIsCalled ); +} + +/** + * @brief _preprocessInputBuffer - inputBufferCallback returns success. + * + * Callback function successfully handle the URC data line. Verify that RX + * thread keep processing the data after the URC data. + * + * Coverage + * @code{c} + * else + * { + * ... + * pTempLine = &pTempLine[ bufferLength ]; + * *pLine = pTempLine; + * pContext->pPktioReadPtr = *pLine; + * + * *pBytesRead = *pBytesRead - bufferLength; + * } + * @endcode + * The else case. + */ +void test__Cellular_PktioInit_Thread_Rx_Data_Event__preprocessInputBuffer_success( void ) +{ + CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_OK; + CellularContext_t context; + CellularCommInterface_t * pCommIntf = &CellularCommInterface; + + threadReturn = true; + memset( &context, 0, sizeof( CellularContext_t ) ); + + /* Assign the comm interface to pContext. */ + context.pCommIntf = pCommIntf; + context.pPktioShutdownCB = _shutdownCallback; + + /* copy the token table. */ + ( void ) memcpy( &context.tokenTable, &tokenTable, sizeof( CellularTokenTable_t ) ); + + /* RX data event for RX thread. */ + pktioEvtMask = PKTIO_EVT_MASK_RX_DATA; + + /* Setup the URC data callback for testing. */ + context.inputBufferCallback = cellularInputBufferCallback; + context.pInputBufferCallbackContext = NULL; + recvCount = 1; + atCmdType = CELLULAR_AT_NO_RESULT; + testCommIfRecvType = COMM_IF_RECV_CUSTOM_STRING; + pCommIntfRecvCustomString = URC_DATA_CALLBACK_MATCH_STR ""URC_DATA_CALLBACK_LEFT_OVER_STR; + pInputBufferPkthandlerString = URC_DATA_CALLBACK_LEFT_OVER_STR; + dataUrcPktHandlerCallbackIsCalled = 0; + + /* API call. */ + pktStatus = _Cellular_PktioInit( &context, prvDataUrcPktHandlerCallback ); + + /* Verification. */ + TEST_ASSERT_EQUAL( CELLULAR_PKT_STATUS_OK, pktStatus ); + + /* The pkthandler callback should not be called. */ + TEST_ASSERT_EQUAL( 1, dataUrcPktHandlerCallbackIsCalled ); +} + +/** + * @brief _preprocessInputBuffer - inputBufferCallback returns size mismatch. + * + * Callback function returns size mismatch. Verify that the RX thread stop processing + * the data and receive more data from comm interface. The callback function will be + * called again with more data. + * + * Coverage + * @code{c} + * else if( pktStatus == CELLULAR_PKT_STATUS_SIZE_MISMATCH ) + * { + * ... + * pContext->pPktioReadPtr = pTempLine; + * pContext->partialDataRcvdLen = *pBytesRead; + * keepProcess = false; + * } + * @endcode + * ( pktStatus == CELLULAR_PKT_STATUS_SIZE_MISMATCH ) is true. + */ +void test__Cellular_PktioInit_Thread_Rx_Data_Event__preprocessInputBuffer_size_mismatch( void ) +{ + CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_OK; + CellularContext_t context; + CellularCommInterface_t * pCommIntf = &CellularCommInterface; + + threadReturn = true; + memset( &context, 0, sizeof( CellularContext_t ) ); + + /* Assign the comm interface to pContext. */ + context.pCommIntf = pCommIntf; + context.pPktioShutdownCB = _shutdownCallback; + + /* copy the token table. */ + ( void ) memcpy( &context.tokenTable, &tokenTable, sizeof( CellularTokenTable_t ) ); + + /* RX data event for RX thread. */ + pktioEvtMask = PKTIO_EVT_MASK_RX_DATA; + + /* Setup the URC data callback for testing. */ + context.inputBufferCallback = cellularInputBufferCallback; + context.pInputBufferCallbackContext = NULL; + recvCount = 2; + atCmdType = CELLULAR_AT_NO_RESULT; + testCommIfRecvType = COMM_IF_RECV_CUSTOM_STRING; + pCommIntfRecvCustomString = URC_DATA_CALLBACK_MATCH_STR_PART1; + pCommIntfRecvCustomStringCallback = prvInputBufferCommIntfRecvCallback; + dataUrcPktHandlerCallbackIsCalled = 0; + + /* API call. */ + pktStatus = _Cellular_PktioInit( &context, prvDataUrcPktHandlerCallback ); + + /* Verification. */ + TEST_ASSERT_EQUAL( CELLULAR_PKT_STATUS_OK, pktStatus ); + + /* The pkthandler callback should not be called. */ + TEST_ASSERT_EQUAL( 0, dataUrcPktHandlerCallbackIsCalled ); +} + /** * @brief Test thread receiving rx data event with CELLULAR_AT_MULTI_WITH_PREFIX resp for _Cellular_PktioInit to return CELLULAR_PKT_STATUS_OK. */