From 37de41906c8c8c906dbda1b3f7bb36a08294a89c Mon Sep 17 00:00:00 2001 From: Ching-Hsin Lee Date: Fri, 7 Apr 2023 12:15:48 +0800 Subject: [PATCH] Adding _Cellular_RegisterUrcDataCallback in common layer * Adding _Cellular_RegisterUrcDataCallback to handle data stream in URC response --- docs/doxygen/include/size_table.md | 8 +- lexicon.txt | 3 + source/cellular_common.c | 34 +++++ source/cellular_pktio.c | 135 +++++++++++++++--- source/include/common/cellular_common.h | 37 +++++ .../private/cellular_common_internal.h | 2 + 6 files changed, 197 insertions(+), 22 deletions(-) diff --git a/docs/doxygen/include/size_table.md b/docs/doxygen/include/size_table.md index 18d9c478..349431b1 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.2K
2.0K
-
1.8K
Total estimates -
14.8K
-
13.4K
+
15.0K
+
13.7K
diff --git a/lexicon.txt b/lexicon.txt index 06db4451..5939942c 100644 --- a/lexicon.txt +++ b/lexicon.txt @@ -665,6 +665,8 @@ ptokentable ptr puk pundefinedrespcbcontext +purcdatacallbackcontext +purcdatalength puserdata pvportmalloc pwr @@ -859,6 +861,7 @@ unneccessary upperthreshold urat urc +urcdatacallback urcevent urcprocesscgev urcprocessciev diff --git a/source/cellular_common.c b/source/cellular_common.c index fd15d401..74b1ce09 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_RegisterUrcDataCallback( CellularContext_t * pContext, + CellularUrcDataCallback_t urcDataCallback, + void * pUrcDataCallbackContext ) +{ + CellularError_t cellularStatus = CELLULAR_SUCCESS; + + if( pContext == NULL ) + { + LogError( ( "_Cellular_RegisterUrcDataCallback: invalid context." ) ); + cellularStatus = CELLULAR_INVALID_HANDLE; + } + else + { + /* urcDataCallback can be set to NULL to unregister the callback. */ + PlatformMutex_Lock( &pContext->PktRespMutex ); + pContext->urcDataCallback = urcDataCallback; + + if( pContext->urcDataCallback != NULL ) + { + pContext->pUrcDataCallbackContext = pUrcDataCallbackContext; + } + else + { + pContext->pUrcDataCallbackContext = NULL; + } + + PlatformMutex_Unlock( &pContext->PktRespMutex ); + } + + return cellularStatus; +} + +/*-----------------------------------------------------------*/ diff --git a/source/cellular_pktio.c b/source/cellular_pktio.c index 6f6f9796..445a523a 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 _preprocessUrcData( CellularContext_t * pContext, + char ** pLine, + uint32_t * pBytesRead ); /*-----------------------------------------------------------*/ @@ -640,28 +648,40 @@ static CellularPktStatus_t _handleData( char * pStartOfData, if( bytesDataAndLeft >= pContext->dataLength ) { - /* Add data to the response linked list. */ - _saveRawData( pStartOfData, pAtResp, pContext->dataLength ); + /* There is no command waiting for response if pAtResp is NULL. The is the + * case that URC data is received from the buffer. */ + if( pAtResp != NULL ) + { + /* Add data to the response linked list. */ + _saveRawData( pStartOfData, pAtResp, pContext->dataLength ); - /* Advance pLine to a point after data. */ - *ppLine = &pStartOfData[ pContext->dataLength ]; + /* Advance pLine to a point after data. */ + *ppLine = &pStartOfData[ pContext->dataLength ]; - /* There are more bytes after the data. */ - *pBytesLeft = ( bytesDataAndLeft - pContext->dataLength ); + /* There are more bytes after the data. */ + *pBytesLeft = ( bytesDataAndLeft - pContext->dataLength ); - LogDebug( ( "_handleData : read buffer buffer %p start %p prefix %d left %d, read total %d", - pContext->pktioReadBuf, - pStartOfData, - bytesBeforeData, - *pBytesLeft, - bytesRead ) ); + LogDebug( ( "_handleData : read buffer buffer %p start %p prefix %d left %d, read total %d", + pContext->pktioReadBuf, + pStartOfData, + bytesBeforeData, + *pBytesLeft, + bytesRead ) ); - /* reset the data related variables. */ - pContext->dataLength = 0U; + /* reset the data related variables. */ + pContext->dataLength = 0U; - /* Set the pPktioReadPtr to indicate data already handled. */ - pContext->pPktioReadPtr = *ppLine; - pContext->partialDataRcvdLen = *pBytesLeft; + /* Set the pPktioReadPtr to indicate data already handled. */ + pContext->pPktioReadPtr = *ppLine; + pContext->partialDataRcvdLen = *pBytesLeft; + } + else + { + /* This the the URC data receive case. The data required by URC data callback + * is received. Leave the data mode by setting dataLength to 0. */ + *pBytesLeft = bytesRead; + pContext->dataLength = 0U; + } } else { @@ -818,6 +838,79 @@ static bool _findLineInStream( CellularContext_t * pContext, /*-----------------------------------------------------------*/ +static bool _preprocessUrcData( 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->urcDataCallback != NULL ) + { + PlatformMutex_Lock( &pContext->PktRespMutex ); + pktStatus = pContext->urcDataCallback( pContext->pUrcDataCallbackContext, + pTempLine, + *pBytesRead, + &bufferLength ); + PlatformMutex_Unlock( &pContext->PktRespMutex ); + + if( pktStatus == CELLULAR_PKT_STATUS_PREFIX_MISMATCH ) + { + /* This is not a URC data line. Return true to parse other data. */ + keepProcess = true; + } + else if( pktStatus == CELLULAR_PKT_STATUS_SIZE_MISMATCH ) + { + /* Partial URC data line is received. The prefix URC is waiting for more + * data to be received. */ + pContext->pPktioReadPtr = pTempLine; + pContext->partialDataRcvdLen = *pBytesRead; + keepProcess = false; + } + else if( pktStatus != CELLULAR_PKT_STATUS_OK ) + { + /* The Urc data callback function returns other error. This indicate that + * the token is corrupted and the reader buffer need to be dropped. */ + LogError( ( "CellularUrcDataCallback 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 Urc data callback function returns incorrect buffer length. */ + LogError( ( "CellularUrcDataCallback 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 + { + /* This is a complete URC data. The URC data is handled in the callback + * successfully. Move the read pointer forward. */ + 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 +1085,14 @@ static void _handleAllReceived( CellularContext_t * pContext, bytesRead = bytesRead - 1U; } + /* Preprocess Urc Data from the input buffer. */ + keepProcess = _preprocessUrcData( 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..aa0e1793 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 URC data buffer. + * + * @param[in] pUrcDataCallbackContext The pCallbackContext in _Cellular_TimeoutAtcmdDataRecvRequestWithCallback. + * @param[in] pBuffer The data buffer with modem response data. + * @param[in] bufferLength The length of the input buffer. + * @param[out] pUrcDataLength The length of the URC data in the buffer. + * + * @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 this is not a URC data buffer + * Otherwise an error code indicating the cause of the error. + */ +typedef CellularPktStatus_t ( * CellularUrcDataCallback_t ) ( void * pUrcDataCallbackContext, + char * pBuffer, + uint32_t bufferLength, + uint32_t * pUrcDataLength ); + /*-----------------------------------------------------------*/ /** @@ -623,6 +642,24 @@ CellularError_t _Cellular_RegisterUndefinedRespCallback( CellularContext_t * pCo CellularUndefinedRespCallback_t undefinedRespCallback, void * pCallbackContext ); +/** + * @brief Register URC data callback. + * + * Cellular module can register the callback function to handle URC data from input + * buffer. + * + * @param[in] pContext The opaque cellular context pointer created by Cellular_Init. + * @param[in] urcDataCallback The callback function to handle the URC data. + * @param[in] pUrcDataCallbackContext The pUrcDataCallbackContext passed to the urcDataCallback + * callback function if urcDataCallback is not NULL. + * + * @return CELLULAR_SUCCESS if the operation is successful, otherwise an error code + * indicating the cause of the error. + */ +CellularError_t _Cellular_RegisterUrcDataCallback( CellularContext_t * pContext, + CellularUrcDataCallback_t urcDataCallback, + void * pUrcDataCallbackContext ); + /* *INDENT-OFF* */ #ifdef __cplusplus } diff --git a/source/include/private/cellular_common_internal.h b/source/include/private/cellular_common_internal.h index 9eba8ef0..c95a42ab 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. */ + CellularUrcDataCallback_t urcDataCallback; /**< URC data preprocess callback function. */ + void * pUrcDataCallbackContext; /**< the callback context passed to urcDataCallback. */ /* PktIo data handling. */ uint32_t dataLength; /**< The data length in pLine. */