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.
*/