Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding _Cellular_RegisterInputBufferCallback in common layer #137

Merged
merged 10 commits into from
May 23, 2023
10 changes: 5 additions & 5 deletions docs/doxygen/include/size_table.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
<tr>
<td>cellular_common.c</td>
<td><center>1.7K</center></td>
<td><center>1.5K</center></td>
<td><center>1.6K</center></td>
</tr>
<tr>
<td>cellular_pkthandler.c</td>
Expand All @@ -39,12 +39,12 @@
</tr>
<tr>
<td>cellular_pktio.c</td>
<td><center>2.0K</center></td>
<td><center>1.8K</center></td>
<td><center>2.1K</center></td>
<td><center>1.9K</center></td>
</tr>
<tr>
<td><b>Total estimates</b></td>
<td><b><center>14.8K</center></b></td>
<td><b><center>13.4K</center></b></td>
<td><b><center>14.9K</center></b></td>
<td><b><center>13.6K</center></b></td>
</tr>
</table>
7 changes: 7 additions & 0 deletions lexicon.txt
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,7 @@ efhplmnwact
eidrxlist
eidrxsettingslist
emerg
endcode
endcond
endif
endpatternlen
Expand Down Expand Up @@ -354,6 +355,7 @@ inet
ingroup
inidcate
init
inputbuffercallback
inputline
inputwithprefix
int
Expand All @@ -377,6 +379,7 @@ isurc
isvalidpdn
isvalidsocket
jan
keepprocess
keylist
keylistlen
kselacq
Expand Down Expand Up @@ -409,6 +412,7 @@ mcc
md
mem
memorystatus
memset
metadata
min
misra
Expand Down Expand Up @@ -484,6 +488,7 @@ pbandcfg
pbervalue
pbuf
pbuffer
pbufferlengthhandled
pbytesread
pc
pcallbackcontext
Expand Down Expand Up @@ -534,6 +539,7 @@ pgenericcallbackcontext
ph
phexdata
pinputbuf
pinputbuffercallbackcontext
pinputline
pinputptr
pinputstr
Expand Down Expand Up @@ -656,6 +662,7 @@ pstr
pstring
pstrvalue
ptemp
ptempline
ptempstring
ptestusrdata
ptofree
Expand Down
34 changes: 34 additions & 0 deletions source/cellular_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

/*-----------------------------------------------------------*/
93 changes: 92 additions & 1 deletion source/cellular_pktio.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 );

/*-----------------------------------------------------------*/

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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 )
{
Expand Down
37 changes: 37 additions & 0 deletions source/include/common/cellular_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 );

/*-----------------------------------------------------------*/

/**
Expand Down Expand Up @@ -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
}
Expand Down
2 changes: 2 additions & 0 deletions source/include/private/cellular_common_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand Down
77 changes: 77 additions & 0 deletions test/unit-test/cellular_common_utest.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

/* ========================================================================== */

/**
Expand Down Expand Up @@ -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 );
}
Loading