From 38a88369c4c23cdd8c2631ec7f64a982d57aa0ec Mon Sep 17 00:00:00 2001 From: Michael Vermeer Date: Tue, 10 Feb 2026 15:35:08 -0500 Subject: [PATCH 1/7] Added AT command raw function with timeout specified --- source/cellular_common_api.c | 18 +++++++++++++- source/include/cellular_api.h | 27 +++++++++++++++++++++ source/include/common/cellular_common_api.h | 13 ++++++++++ 3 files changed, 57 insertions(+), 1 deletion(-) diff --git a/source/cellular_common_api.c b/source/cellular_common_api.c index 1afd55f5..b46cc269 100644 --- a/source/cellular_common_api.c +++ b/source/cellular_common_api.c @@ -334,6 +334,22 @@ CellularError_t Cellular_CommonATCommandRaw( CellularHandle_t cellularHandle, CellularATCommandResponseReceivedCallback_t responseReceivedCallback, void * pData, uint16_t dataLen ) +{ + return Cellular_CommonATCommandRawTimeout( cellularHandle, pATCommandPrefix, pATCommandPayload, atCommandType, + responseReceivedCallback, pData, dataLen, + CELLULAR_AT_COMMAND_RAW_TIMEOUT_MS ); +} + +/*-----------------------------------------------------------*/ + +CellularError_t Cellular_CommonATCommandRawTimeout( CellularHandle_t cellularHandle, + const char * pATCommandPrefix, + const char * pATCommandPayload, + CellularATCommandType_t atCommandType, + CellularATCommandResponseReceivedCallback_t responseReceivedCallback, + void * pData, + uint16_t dataLen, + uint32_t timeoutMS ) { CellularContext_t * pContext = ( CellularContext_t * ) cellularHandle; CellularError_t cellularStatus = CELLULAR_SUCCESS; @@ -363,7 +379,7 @@ CellularError_t Cellular_CommonATCommandRaw( CellularHandle_t cellularHandle, pktStatus = _Cellular_TimeoutAtcmdRequestWithCallback( pContext, atReqGetResult, - CELLULAR_AT_COMMAND_RAW_TIMEOUT_MS ); + timeoutMS ); cellularStatus = _Cellular_TranslatePktStatus( pktStatus ); } diff --git a/source/include/cellular_api.h b/source/include/cellular_api.h index fb615635..cfef0484 100644 --- a/source/include/cellular_api.h +++ b/source/include/cellular_api.h @@ -524,6 +524,33 @@ CellularError_t Cellular_ATCommandRaw( CellularHandle_t cellularHandle, void * pData, uint16_t dataLen ); +/** + * @brief Send the raw AT command to the module with specified timeout. + * + * @param[in] cellularHandle The opaque cellular context pointer created by Cellular_Init. + * @param[in] pATCommandPrefix The AT command response prefix. NULL if the response + * has no prefix. + * @param[in] pATCommandPayload The AT command to send. It should be a NULL terminated + * string. + * @param[in] atCommandType Type of AT command. + * @param[in] responseReceivedCallback Callback to be invoked when a response for the + * command is received. + * @param[in] pData The pData pointer will be passed in responseReceivedCallback. + * @param[in] dataLen The dataLen value will be passed in responseReceivedCallback. + * @param[in] timeoutMS The timeout value to wait for the response from cellular modem. + * + * @return CELLULAR_SUCCESS if the operation is successful, otherwise an error + * code indicating the cause of the error. + */ +CellularError_t Cellular_ATCommandRawTimeout( CellularHandle_t cellularHandle, + const char * pATCommandPrefix, + const char * pATCommandPayload, + CellularATCommandType_t atCommandType, + CellularATCommandResponseReceivedCallback_t responseReceivedCallback, + void * pData, + uint16_t dataLen, + uint32_t timeoutMS ); + /** * @brief Create a socket. * diff --git a/source/include/common/cellular_common_api.h b/source/include/common/cellular_common_api.h index 73405971..c9aa81f3 100644 --- a/source/include/common/cellular_common_api.h +++ b/source/include/common/cellular_common_api.h @@ -110,6 +110,19 @@ CellularError_t Cellular_CommonATCommandRaw( CellularHandle_t cellularHandle, void * pData, uint16_t dataLen ); +/** + * @brief This function is the common implementation of FreeRTOS Cellular Library API. + * Reference Cellular_ATCommandRawTimeout in cellular_api.h for definition. + */ +CellularError_t Cellular_CommonATCommandRawTimeout( CellularHandle_t cellularHandle, + const char * pATCommandPrefix, + const char * pATCommandPayload, + CellularATCommandType_t atCommandType, + CellularATCommandResponseReceivedCallback_t responseReceivedCallback, + void * pData, + uint16_t dataLen, + uint32_t timeoutMS ); + /** * @brief This function is the common implementation of FreeRTOS Cellular Library API. * Reference Cellular_CreateSocket in cellular_api.h for definition. From 9a2aa791470ea3966a7faccce53830e577af1e6a Mon Sep 17 00:00:00 2001 From: Michael Vermeer Date: Fri, 13 Feb 2026 09:55:28 -0500 Subject: [PATCH 2/7] Added Cellular_GetRfFunctionality() function --- source/include/cellular_api.h | 12 ++++++++++++ source/include/cellular_types.h | 11 +++++++++++ 2 files changed, 23 insertions(+) diff --git a/source/include/cellular_api.h b/source/include/cellular_api.h index cfef0484..abb367cd 100644 --- a/source/include/cellular_api.h +++ b/source/include/cellular_api.h @@ -126,6 +126,18 @@ CellularError_t Cellular_RfOn( CellularHandle_t cellularHandle ); */ CellularError_t Cellular_RfOff( CellularHandle_t cellularHandle ); +/** + * @brief Get whether RF is on. + * + * @param[in] cellularHandle The opaque cellular context pointer created by Cellular_Init. + * @param[out] pRfFunctionality Out parameter to provide the RF functionality status. + * + * @return CELLULAR_SUCCESS if the operation is successful, otherwise an error + * code indicating the cause of the error. + */ +CellularError_t Cellular_GetRfFunctionality( CellularHandle_t cellularHandle, + CellularRfFunctionality_t * pRfFunctionality ); + /** * @brief Get SIM card status (activated/Pin set etc.). * diff --git a/source/include/cellular_types.h b/source/include/cellular_types.h index 46118b09..93e1a30e 100644 --- a/source/include/cellular_types.h +++ b/source/include/cellular_types.h @@ -592,6 +592,17 @@ typedef enum CellularPSMEnterMode CELLULAR_PSM_ENTER_MODE_IMMEDIATE /**< Enter PSM immediately after the RRC connection release is received. */ } CellularPSMEnterMode_t; +/** + * @ingroup cellular_datatypes_enums + * @brief Represents RF functionality modes. + */ +typedef enum CellularRfFunctionality +{ + CELLULAR_RF_FUNCTIONALITY_OFF, /**< RF functionality is off (minimum functionality). */ + CELLULAR_RF_FUNCTIONALITY_ON, /**< RF functionality is on (full functionality - RF and SIM). */ + CELLULAR_RF_FUNCTIONALITY_SIM_ONLY, /**< RF functionality is off but SIM interface enabled. */ +} CellularRfFunctionality_t; + /** * @ingroup cellular_datatypes_enums * @brief Represents Network Operator mode which places network operator specific requirements defined on top of 3GPP requirements. From 83d76ca96077527a2b1fe66beeef5a2a8b01f146 Mon Sep 17 00:00:00 2001 From: Michael Vermeer Date: Fri, 13 Feb 2026 12:22:26 -0500 Subject: [PATCH 3/7] Added function retrieve request PSM settings, in addition to network PSM settings --- source/include/cellular_api.h | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/source/include/cellular_api.h b/source/include/cellular_api.h index abb367cd..2eb2128c 100644 --- a/source/include/cellular_api.h +++ b/source/include/cellular_api.h @@ -433,10 +433,10 @@ CellularError_t Cellular_RegisterUrcGenericCallback( CellularHandle_t cellularHa void * pCallbackContext ); /** - * @brief Get current PSM settings. + * @brief Get current network PSM settings. * * @param[in] cellularHandle The opaque cellular context pointer created by Cellular_Init. - * @param[out] pPsmSettings Out parameter to provide the PSM settings. + * @param[out] pPsmSettings Out parameter to provide the PSM settings. NOTE: Values are NOT encoded * * @return CELLULAR_SUCCESS if the operation is successful, otherwise an error * code indicating the cause of the error. @@ -444,6 +444,18 @@ CellularError_t Cellular_RegisterUrcGenericCallback( CellularHandle_t cellularHa CellularError_t Cellular_GetPsmSettings( CellularHandle_t cellularHandle, CellularPsmSettings_t * pPsmSettings ); +/** + * @brief Get current requested PSM settings (network ultimately chooses PSM settings for Active time, etc). + * + * @param[in] cellularHandle The opaque cellular context pointer created by Cellular_Init. + * @param[out] pPsmSettings Out parameter to provide the PSM settings. NOTE: Values are encoded uint8 + * + * @return CELLULAR_SUCCESS if the operation is successful, otherwise an error + * code indicating the cause of the error. + */ +CellularError_t Cellular_GetRequestedPsmSettings( CellularHandle_t cellularHandle, + CellularPsmSettings_t * pPsmSettings ); + /** * @brief Set PSM settings. * From 28bcda118e5da30a31e47918a7fb577ec6dda4d0 Mon Sep 17 00:00:00 2001 From: Michael Vermeer Date: Fri, 20 Feb 2026 13:11:47 -0500 Subject: [PATCH 4/7] Added Cellular_SimAndRfOff() function to API --- source/include/cellular_api.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/source/include/cellular_api.h b/source/include/cellular_api.h index 2eb2128c..853dfe48 100644 --- a/source/include/cellular_api.h +++ b/source/include/cellular_api.h @@ -126,6 +126,16 @@ CellularError_t Cellular_RfOn( CellularHandle_t cellularHandle ); */ CellularError_t Cellular_RfOff( CellularHandle_t cellularHandle ); +/** + * @brief Turn off SIM card and turn off RF i.e. minimum functionality mode. + * + * @param[in] cellularHandle The opaque cellular context pointer created by Cellular_Init. + * + * @return CELLULAR_SUCCESS if the operation is successful, otherwise an error + * code indicating the cause of the error. + */ +CellularError_t Cellular_SimAndRfOff( CellularHandle_t cellularHandle ); + /** * @brief Get whether RF is on. * From 21936783e78cc408b76818a9af76cd3e1658cc53 Mon Sep 17 00:00:00 2001 From: Michael Vermeer Date: Mon, 2 Mar 2026 15:52:14 -0500 Subject: [PATCH 5/7] Added support for AT+CEREG=4 --- source/cellular_3gpp_api.c | 21 +- source/cellular_3gpp_urc_handler.c | 342 ++++++++++++++++-- .../private/cellular_common_internal.h | 32 ++ 3 files changed, 356 insertions(+), 39 deletions(-) diff --git a/source/cellular_3gpp_api.c b/source/cellular_3gpp_api.c index c668f149..b23171a7 100644 --- a/source/cellular_3gpp_api.c +++ b/source/cellular_3gpp_api.c @@ -823,20 +823,15 @@ static CellularPktStatus_t _Cellular_RecvFuncGetNetworkReg( CellularContext_t * /* Assumption is that the data is null terminated so we don't need the dataLen. */ _Cellular_LockAtDataMutex( pContext ); - if( regResponseIsUrc( pPregLine ) == true ) - { - /* Remove the prefix for URC handler. */ - atCoreStatus = Cellular_ATRemovePrefix( &pPregLine ); - pktStatus = _Cellular_TranslateAtCoreStatus( atCoreStatus ); + bool isUrc = regResponseIsUrc( pPregLine ); - if( pktStatus == CELLULAR_PKT_STATUS_OK ) - { - pktStatus = _Cellular_ParseRegStatus( pContext, pPregLine, true, regType ); - } - } - else + /* Remove the prefix for URC handler. */ + atCoreStatus = Cellular_ATRemovePrefix( &pPregLine ); + pktStatus = _Cellular_TranslateAtCoreStatus( atCoreStatus ); + + if( pktStatus == CELLULAR_PKT_STATUS_OK ) { - pktStatus = _Cellular_ParseRegStatus( pContext, pPregLine, false, regType ); + pktStatus = _Cellular_ParseRegStatus( pContext, pPregLine, isUrc, regType ); } _Cellular_UnlockAtDataMutex( pContext ); @@ -2132,6 +2127,8 @@ void _Cellular_InitAtData( CellularContext_t * pContext, pLibAtData->cellId = 0xFFFFFFFFU; pLibAtData->rat = CELLULAR_RAT_INVALID; pLibAtData->rac = 0xFF; + pLibAtData->periodicTauValue = 0xFFFFFFFFU; + pLibAtData->activeTimeValue = 0xFFFFFFFFU; } /*-----------------------------------------------------------*/ diff --git a/source/cellular_3gpp_urc_handler.c b/source/cellular_3gpp_urc_handler.c index 7efdaa20..68e87cb1 100644 --- a/source/cellular_3gpp_urc_handler.c +++ b/source/cellular_3gpp_urc_handler.c @@ -49,34 +49,58 @@ /*-----------------------------------------------------------*/ +#define CELLULAR_REG_POS_URC_MODE ( 1U ) /* Only specified when queried, not in URC */ #define CELLULAR_REG_POS_STAT ( 2U ) #define CELLULAR_REG_POS_LAC_TAC ( 3U ) #define CELLULAR_REG_POS_CELL_ID ( 4U ) #define CELLULAR_REG_POS_RAT ( 5U ) #define CELLULAR_REG_POS_REJ_TYPE ( 6U ) #define CELLULAR_REG_POS_REJ_CAUSE ( 7U ) +#define CELLULAR_REG_POS_URC_ACTIVE_TIME ( 8U ) +#define CELLULAR_REG_POS_URC_PERIODIC_TAU_RAU ( 9U ) + +#define CELLULAR_REG_URC_MODE_DISABLED ( 0U ) +#define CELLULAR_REG_URC_MODE_STAT_ENABLED ( 1U ) +#define CELLULAR_REG_URC_MODE_STAT_LOCATION_ENABLED ( 2U ) +#define CELLULAR_REG_URC_MODE_STAT_LOCATION_PSM_ENABLED ( 4U ) +#define CELLULAR_REG_URC_MODE_UNKNOWN ( 0xFFU ) /*-----------------------------------------------------------*/ +static CellularATError_t _parseUrcModeInRegStatus( const char * pToken, + uint8_t * urcMode ); static CellularPktStatus_t _parseRegStatusInRegStatusParsing( CellularContext_t * pContext, CellularNetworkRegType_t regType, const char * pToken, cellularAtData_t * pLibAtData ); static CellularPktStatus_t _parseLacTacInRegStatus( CellularNetworkRegType_t regType, const char * pToken, - cellularAtData_t * pLibAtData ); + cellularAtData_t * pLibAtData, + bool allowEmpty ); static CellularPktStatus_t _parseCellIdInRegStatus( const char * pToken, - cellularAtData_t * pLibAtData ); + cellularAtData_t * pLibAtData, + bool allowEmpty ); static CellularPktStatus_t _parseRatInfoInRegStatus( const char * pToken, - cellularAtData_t * pLibAtData ); + cellularAtData_t * pLibAtData, + bool allowEmpty ); static CellularPktStatus_t _parseRejectTypeInRegStatus( CellularNetworkRegType_t regType, const char * pToken, - cellularAtData_t * pLibAtData ); + cellularAtData_t * pLibAtData, + bool allowEmpty ); static CellularPktStatus_t _parseRejectCauseInRegStatus( CellularNetworkRegType_t regType, const char * pToken, - cellularAtData_t * pLibAtData ); + cellularAtData_t * pLibAtData, + bool allowEmpty ); +static CellularPktStatus_t _parseActiveTimeInRegStatus( const char * pToken, + cellularAtData_t * pLibAtData, + bool allowEmpty ); +static CellularPktStatus_t _parsePeriodicTauInRegStatus( const char * pToken, + cellularAtData_t * pLibAtData, + bool allowEmpty ); static CellularPktStatus_t _regStatusSwitchParsingFunc( CellularContext_t * pContext, uint8_t i, CellularNetworkRegType_t regType, + bool isUrc, + uint8_t urcMode, const char * pToken, cellularAtData_t * pLibAtData ); static void _regStatusGenerateLog( char * pRegPayload, @@ -91,6 +115,39 @@ static bool _Cellular_RegEventStatus( const cellularAtData_t * pLibAtData, /*-----------------------------------------------------------*/ +static CellularATError_t _parseUrcModeInRegStatus( const char * pToken, + uint8_t * urcMode ) +{ + int32_t var = 0; + CellularATError_t atCoreStatus = CELLULAR_AT_SUCCESS; + + if( urcMode == NULL ) + { + atCoreStatus = CELLULAR_AT_BAD_PARAMETER; + } + else + { + atCoreStatus = Cellular_ATStrtoi( pToken, 10, &var ); + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + if( ( var < 0 ) || ( var > 4 ) ) + { + atCoreStatus = CELLULAR_AT_ERROR; + LogError( ( "Error in processing URC mode in reg status. Token '%s'", pToken ) ); + } + else + { + *urcMode = ( uint8_t ) var; + } + } + } + + return atCoreStatus; +} + +/*-----------------------------------------------------------*/ + static CellularPktStatus_t _parseRegStatusInRegStatusParsing( CellularContext_t * pContext, CellularNetworkRegType_t regType, const char * pToken, @@ -168,13 +225,26 @@ static CellularPktStatus_t _parseRegStatusInRegStatusParsing( CellularContext_t static CellularPktStatus_t _parseLacTacInRegStatus( CellularNetworkRegType_t regType, const char * pToken, - cellularAtData_t * pLibAtData ) + cellularAtData_t * pLibAtData, + bool allowEmpty ) { int32_t tempValue = 0; uint16_t var = 0; CellularATError_t atCoreStatus = CELLULAR_AT_SUCCESS; CellularPktStatus_t packetStatus = CELLULAR_PKT_STATUS_OK; + if( ( pToken != NULL ) && ( pToken[0] == '\0' ) ) + { + if( allowEmpty == true ) + { + return packetStatus; + } + else + { + LogDebug( ( "Unexpected empty LAC/TAC in Registration Status" ) ); + } + } + atCoreStatus = Cellular_ATStrtoi( pToken, 16, &tempValue ); if( atCoreStatus == CELLULAR_AT_SUCCESS ) @@ -214,12 +284,25 @@ static CellularPktStatus_t _parseLacTacInRegStatus( CellularNetworkRegType_t reg /*-----------------------------------------------------------*/ static CellularPktStatus_t _parseCellIdInRegStatus( const char * pToken, - cellularAtData_t * pLibAtData ) + cellularAtData_t * pLibAtData, + bool allowEmpty ) { int32_t tempValue = 0; CellularATError_t atCoreStatus = CELLULAR_AT_SUCCESS; CellularPktStatus_t packetStatus = CELLULAR_PKT_STATUS_OK; + if( ( pToken != NULL ) && ( pToken[0] == '\0' ) ) + { + if( allowEmpty == true ) + { + return packetStatus; + } + else + { + LogDebug( ( "Unexpected empty Cell ID in Registration Status" ) ); + } + } + atCoreStatus = Cellular_ATStrtoi( pToken, 16, &tempValue ); if( atCoreStatus == CELLULAR_AT_SUCCESS ) @@ -230,7 +313,7 @@ static CellularPktStatus_t _parseCellIdInRegStatus( const char * pToken, } else { - LogError( ( "Error in processing Cell Id. Token %s", pToken ) ); + LogError( ( "Error in processing Cell Id. Token '%s'", pToken ) ); atCoreStatus = CELLULAR_AT_ERROR; } } @@ -242,12 +325,25 @@ static CellularPktStatus_t _parseCellIdInRegStatus( const char * pToken, /*-----------------------------------------------------------*/ static CellularPktStatus_t _parseRatInfoInRegStatus( const char * pToken, - cellularAtData_t * pLibAtData ) + cellularAtData_t * pLibAtData, + bool allowEmpty ) { int32_t var = 0; CellularATError_t atCoreStatus = CELLULAR_AT_SUCCESS; CellularPktStatus_t packetStatus = CELLULAR_PKT_STATUS_OK; + if( ( pToken != NULL ) && ( pToken[0] == '\0' ) ) + { + if( allowEmpty == true ) + { + return packetStatus; + } + else + { + LogDebug( ( "Unexpected empty RAT Info in Registration Status" ) ); + } + } + atCoreStatus = Cellular_ATStrtoi( pToken, 10, &var ); if( atCoreStatus == CELLULAR_AT_SUCCESS ) @@ -255,7 +351,7 @@ static CellularPktStatus_t _parseRatInfoInRegStatus( const char * pToken, if( var >= ( int32_t ) CELLULAR_RAT_MAX ) { atCoreStatus = CELLULAR_AT_ERROR; - LogError( ( "Error in processing RAT. Token %s", pToken ) ); + LogError( ( "Error in processing RAT. Token '%s'", pToken ) ); } else if( ( var == ( int32_t ) CELLULAR_RAT_GSM ) || ( var == ( int32_t ) CELLULAR_RAT_EDGE ) || ( var == ( int32_t ) CELLULAR_RAT_CATM1 ) || ( var == ( int32_t ) CELLULAR_RAT_NBIOT ) ) @@ -284,13 +380,26 @@ static CellularPktStatus_t _parseRatInfoInRegStatus( const char * pToken, static CellularPktStatus_t _parseRejectTypeInRegStatus( CellularNetworkRegType_t regType, const char * pToken, - cellularAtData_t * pLibAtData ) + cellularAtData_t * pLibAtData, + bool allowEmpty ) { int32_t tempValue = 0; uint8_t rejType = 0; CellularATError_t atCoreStatus = CELLULAR_AT_SUCCESS; CellularPktStatus_t packetStatus = CELLULAR_PKT_STATUS_OK; + if( ( pToken != NULL ) && ( pToken[0] == '\0' ) ) + { + if( allowEmpty == true ) + { + return packetStatus; + } + else + { + LogDebug( ( "Unexpected empty Reject Type in Registration Status" ) ); + } + } + atCoreStatus = Cellular_ATStrtoi( pToken, 10, &tempValue ); if( atCoreStatus == CELLULAR_AT_SUCCESS ) @@ -336,13 +445,26 @@ static CellularPktStatus_t _parseRejectTypeInRegStatus( CellularNetworkRegType_t static CellularPktStatus_t _parseRejectCauseInRegStatus( CellularNetworkRegType_t regType, const char * pToken, - cellularAtData_t * pLibAtData ) + cellularAtData_t * pLibAtData, + bool allowEmpty ) { int32_t tempValue = 0; uint8_t rejCause = 0; CellularATError_t atCoreStatus = CELLULAR_AT_SUCCESS; CellularPktStatus_t packetStatus = CELLULAR_PKT_STATUS_OK; + if( ( pToken != NULL ) && ( pToken[0] == '\0' ) ) + { + if( allowEmpty == true ) + { + return packetStatus; + } + else + { + LogDebug( ( "Unexpected empty Reject Cause in Registration Status" ) ); + } + } + atCoreStatus = Cellular_ATStrtoi( pToken, 10, &tempValue ); if( atCoreStatus == CELLULAR_AT_SUCCESS ) @@ -386,47 +508,185 @@ static CellularPktStatus_t _parseRejectCauseInRegStatus( CellularNetworkRegType_ /*-----------------------------------------------------------*/ +static CellularPktStatus_t _parseActiveTimeInRegStatus( const char * pToken, + cellularAtData_t * pLibAtData, + bool allowEmpty ) +{ + int32_t tempValue = 0; + CellularATError_t atCoreStatus = CELLULAR_AT_SUCCESS; + CellularPktStatus_t packetStatus = CELLULAR_PKT_STATUS_OK; + + if( ( pToken != NULL ) && ( pToken[0] == '\0' ) ) + { + if( allowEmpty == true ) + { + pLibAtData->activeTimeValue = 0xFFFFFFFF; + return packetStatus; + } + else + { + LogWarn( ( "Unexpected empty Active Time in Registration Status" ) ); + } + } + + atCoreStatus = Cellular_ATStrtoi( pToken, 2, &tempValue ); + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + if( ( tempValue >= 0 ) && ( tempValue <= UINT8_MAX ) ) + { + pLibAtData->activeTimeValue = ( uint32_t ) tempValue; + } + else + { + LogError( ( "Error in processing Active Time value. Token '%s'", pToken ) ); + atCoreStatus = CELLULAR_AT_ERROR; + } + } + + packetStatus = _Cellular_TranslateAtCoreStatus( atCoreStatus ); + return packetStatus; +} + +/*-----------------------------------------------------------*/ + +static CellularPktStatus_t _parsePeriodicTauInRegStatus( const char * pToken, + cellularAtData_t * pLibAtData, + bool allowEmpty ) +{ + int32_t tempValue = 0; + CellularATError_t atCoreStatus = CELLULAR_AT_SUCCESS; + CellularPktStatus_t packetStatus = CELLULAR_PKT_STATUS_OK; + + if( ( pToken != NULL ) && ( pToken[0] == '\0' ) ) + { + if( allowEmpty == true ) + { + pLibAtData->periodicTauValue = 0xFFFFFFFF; + return packetStatus; + } + else + { + LogWarn( ( "Unexpected empty Periodic TAU in Registration Status" ) ); + } + } + + atCoreStatus = Cellular_ATStrtoi( pToken, 2, &tempValue ); + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + if( ( tempValue >= 0 ) && ( tempValue <= UINT8_MAX ) ) + { + pLibAtData->periodicTauValue = ( uint32_t ) tempValue; + } + else + { + LogError( ( "Error in processing Periodic TAU value. Token '%s'", pToken ) ); + atCoreStatus = CELLULAR_AT_ERROR; + } + } + + packetStatus = _Cellular_TranslateAtCoreStatus( atCoreStatus ); + return packetStatus; +} + +/*-----------------------------------------------------------*/ + static CellularPktStatus_t _regStatusSwitchParsingFunc( CellularContext_t * pContext, uint8_t i, CellularNetworkRegType_t regType, + bool isUrc, + uint8_t urcMode, const char * pToken, cellularAtData_t * pLibAtData ) { CellularPktStatus_t packetStatus = CELLULAR_PKT_STATUS_OK; + bool isUrcOrUrcModePSM = ( ( isUrc == true ) || ( urcMode == CELLULAR_REG_URC_MODE_STAT_LOCATION_PSM_ENABLED ) ); + + if( ( urcMode != CELLULAR_REG_URC_MODE_UNKNOWN ) && ( isUrc == true ) ) + { + LogWarn( ( "Unexpected known URC mode and isURC in Registration Status, i: %hhu, regType: %d, urcMode: %hhu", i, regType, urcMode ) ); + } + + if( ( urcMode == CELLULAR_REG_URC_MODE_STAT_LOCATION_PSM_ENABLED ) && ( regType == CELLULAR_REG_TYPE_CREG ) ) + { + LogWarn( ( "Unexpected PSM URC mode in CREG Registration Status, i: %hhu", i ) ); + } switch( i ) { + case CELLULAR_REG_POS_URC_MODE: + LogError( ( "Unexpected URC Mode Position in Registration: %s", + ( ( pToken != NULL ) ? pToken : "" ) ) ) ; + break; + /* Parsing network Registration status in CREG or CGREG or CEREG response. */ case CELLULAR_REG_POS_STAT: packetStatus = _parseRegStatusInRegStatusParsing( pContext, regType, pToken, pLibAtData ); break; + /* Parsing Location Area Code (LAC) or Tracking Area Code (TAC). */ case CELLULAR_REG_POS_LAC_TAC: - packetStatus = _parseLacTacInRegStatus( regType, pToken, pLibAtData ); + packetStatus = _parseLacTacInRegStatus( regType, pToken, pLibAtData, isUrcOrUrcModePSM /* allowEmpty= */ ); break; /* Parsing Cell ID. */ case CELLULAR_REG_POS_CELL_ID: - packetStatus = _parseCellIdInRegStatus( pToken, pLibAtData ); + packetStatus = _parseCellIdInRegStatus( pToken, pLibAtData, isUrcOrUrcModePSM /* allowEmpty= */ ); break; /* Parsing RAT Information. */ case CELLULAR_REG_POS_RAT: - packetStatus = _parseRatInfoInRegStatus( pToken, pLibAtData ); + packetStatus = _parseRatInfoInRegStatus( pToken, pLibAtData, isUrcOrUrcModePSM /* allowEmpty= */ ); break; /* Parsing Reject Type. */ case CELLULAR_REG_POS_REJ_TYPE: - packetStatus = _parseRejectTypeInRegStatus( regType, pToken, pLibAtData ); + packetStatus = _parseRejectTypeInRegStatus( regType, pToken, pLibAtData, isUrcOrUrcModePSM /* allowEmpty= */ ); break; /* Parsing the Reject Cause. */ case CELLULAR_REG_POS_REJ_CAUSE: - packetStatus = _parseRejectCauseInRegStatus( regType, pToken, pLibAtData ); + packetStatus = _parseRejectCauseInRegStatus( regType, pToken, pLibAtData, isUrcOrUrcModePSM /* allowEmpty= */ ); + break; + + /* Parsing the URC Active Time */ + case CELLULAR_REG_POS_URC_ACTIVE_TIME: + if( regType == CELLULAR_REG_TYPE_CGREG ) + { + /* Not currently supported */ + LogWarn( ( "CGREG Active Time Unsupported in Registration Status" ) ); + } + else if( regType == CELLULAR_REG_TYPE_CREG ) + { + LogError( ( "Unexpected Active Time in CREG Registration Status" ) ); + } + else + { + packetStatus = _parseActiveTimeInRegStatus( pToken, pLibAtData, true /* allowEmpty= */ ); + } + break; + + /* Parsing the URC Periodic TAU / RAU */ + case CELLULAR_REG_POS_URC_PERIODIC_TAU_RAU: + if( regType == CELLULAR_REG_TYPE_CGREG ) + { + /* Not currently supported */ + LogWarn( ( "CGREG Periodic RAU Unsupported in Registration Status" ) ); + } + else if( regType == CELLULAR_REG_TYPE_CREG ) + { + LogError( ( "Unexpected Periodic TAU / RAU in CREG Registration Status" ) ); + } + else + { + packetStatus = _parsePeriodicTauInRegStatus( pToken, pLibAtData, true /* allowEmpty= */ ); + } break; default: - LogDebug( ( "Unknown Parameter Position in Registration URC" ) ); + // TODO (MV): Return to debug + LogError( ( "Unknown Parameter Position in Registration URC: %hhu", i ) ); break; } @@ -450,7 +710,8 @@ static void _regStatusGenerateLog( char * pRegPayload, } else if( regType == CELLULAR_REG_TYPE_CEREG ) { - LogDebug( ( "URC: CEREG: %s", pRegPayload ) ); + // TODO (MV): Return this to debug + LogInfo( ( "URC: CEREG: %s", pRegPayload ) ); } else { @@ -541,7 +802,7 @@ CellularPktStatus_t _Cellular_ParseRegStatus( CellularContext_t * pContext, bool isUrc, CellularNetworkRegType_t regType ) { - uint8_t i = 0; + uint8_t i = 0, urcMode = CELLULAR_REG_URC_MODE_UNKNOWN; char * pRegStr = NULL, * pToken = NULL; cellularAtData_t * pLibAtData = NULL; CellularPktStatus_t packetStatus = CELLULAR_PKT_STATUS_OK; @@ -561,13 +822,16 @@ CellularPktStatus_t _Cellular_ParseRegStatus( CellularContext_t * pContext, { pLibAtData = &pContext->libAtData; - if( isUrc == true ) - { - i++; - } - pRegStr = pRegPayload; + // TODO (MV): Remove + LogError( ( "%s '%s'", + ( ( regType == CELLULAR_REG_TYPE_CREG ) ? "CREG" : + ( ( regType == CELLULAR_REG_TYPE_CEREG ) ? "CEREG" : + ( ( regType == CELLULAR_REG_TYPE_CGREG ) ? "CGREG" : + ( ( regType == CELLULAR_REG_TYPE_UNKNOWN ) ? "unknown" : "" ) ) ) ), + ( ( pRegPayload != NULL ) ? pRegPayload : "" ) ) ); + atCoreStatus = Cellular_ATRemoveAllDoubleQuote( pRegStr ); if( atCoreStatus == CELLULAR_AT_SUCCESS ) @@ -580,6 +844,23 @@ CellularPktStatus_t _Cellular_ParseRegStatus( CellularContext_t * pContext, atCoreStatus = Cellular_ATGetNextTok( &pRegStr, &pToken ); } + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + /* If not URC then first token will be the URC mode () */ + if( isUrc != true ) + { + atCoreStatus = _parseUrcModeInRegStatus( pToken, &urcMode ); + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + /* Get next token after URC mode */ + atCoreStatus = Cellular_ATGetNextTok( &pRegStr, &pToken ); + } + } + + i++; + } + if( atCoreStatus == CELLULAR_AT_SUCCESS ) { /* Backup the previous regStatus. */ @@ -589,8 +870,15 @@ CellularPktStatus_t _Cellular_ParseRegStatus( CellularContext_t * pContext, while( pToken != NULL ) { i++; - packetStatus = _regStatusSwitchParsingFunc( pContext, i, regType, - pToken, pLibAtData ); + packetStatus = _regStatusSwitchParsingFunc( pContext, i, regType, isUrc, + urcMode, pToken, pLibAtData ); + + if( packetStatus != CELLULAR_PKT_STATUS_OK ) + { + LogError( ("Failed to parse item %hhu: '%s', regType: %d, urcMode: %hhu, isURC: %s", + i, ( (pToken != NULL) ? pToken : "" ), regType, urcMode, + ( ( isUrc == true ) ? "true" : "false" ) ) ); + } /* Getting next token to parse. */ if( Cellular_ATGetNextTok( &pRegStr, &pToken ) != CELLULAR_AT_SUCCESS ) diff --git a/source/include/private/cellular_common_internal.h b/source/include/private/cellular_common_internal.h index 86a91aa4..afcc6b79 100644 --- a/source/include/private/cellular_common_internal.h +++ b/source/include/private/cellular_common_internal.h @@ -95,6 +95,38 @@ typedef struct cellularAtData uint16_t lac; /**< Registered network operator Location Area Code. */ uint16_t rac; /**< Registered network operator Routing Area Code. */ uint16_t tac; /**< Registered network operator Tracking Area Code. */ + + /* + * Bits 5 to 1 represent the binary coded timer value + * Bits 6 to 8 define the timer value unit as follows: + * Bits + * 8 7 6 + * 0 0 0 value is incremented in multiples of 10 minutes + * 0 0 1 value is incremented in multiples of 1 hour + * 0 1 0 value is incremented in multiples of 10 hours + * 0 1 1 value is incremented in multiples of 2 seconds + * 1 0 0 value is incremented in multiples of 30 seconds + * 1 0 1 value is incremented in multiples of 1 minute + * + * e.g. "00001010" equals to 100 minutes. + * first uint8_t is used for PSM set, whole uint32_t is used for PSM get. + */ + uint32_t periodicTauValue; /**< TAU (T3412) value encoded as per spec (as shown above). 0xFFFFFFFF if unknown. */ + + /* + * Bits 5 to 1 represent the binary coded timer value. + * Bits 6 to 8 define the timer value unit as follows: + * Bits + * 8 7 6 + * 0 0 0 value is incremented in multiples of 2 seconds + * 0 0 1 value is incremented in multiples of 1 minute + * 0 1 0 value is incremented in multiples of decihours + * 1 1 1 value indicates that the timer is deactivated. + * + * "00001111" equals to 30 seconds. + * first uint8_t is used for PSM set, whole uint32_t is used for PSM get. + */ + uint32_t activeTimeValue; /**< Active Time (T3324) value encoded as per spec (as shown above). 0xFFFFFFFF if unknown. */ } cellularAtData_t; /** From 046f3b91b371355d8f90a5e15955691481ba8334 Mon Sep 17 00:00:00 2001 From: Michael Vermeer Date: Mon, 2 Mar 2026 16:56:38 -0500 Subject: [PATCH 6/7] Removed early return strategy to be compliant with rest of code --- source/cellular_3gpp_urc_handler.c | 316 ++++++++++++++++------------- 1 file changed, 175 insertions(+), 141 deletions(-) diff --git a/source/cellular_3gpp_urc_handler.c b/source/cellular_3gpp_urc_handler.c index 68e87cb1..481d3de8 100644 --- a/source/cellular_3gpp_urc_handler.c +++ b/source/cellular_3gpp_urc_handler.c @@ -232,12 +232,13 @@ static CellularPktStatus_t _parseLacTacInRegStatus( CellularNetworkRegType_t reg uint16_t var = 0; CellularATError_t atCoreStatus = CELLULAR_AT_SUCCESS; CellularPktStatus_t packetStatus = CELLULAR_PKT_STATUS_OK; + bool skipParsing = false; if( ( pToken != NULL ) && ( pToken[0] == '\0' ) ) { if( allowEmpty == true ) { - return packetStatus; + skipParsing = true; } else { @@ -245,39 +246,43 @@ static CellularPktStatus_t _parseLacTacInRegStatus( CellularNetworkRegType_t reg } } - atCoreStatus = Cellular_ATStrtoi( pToken, 16, &tempValue ); - - if( atCoreStatus == CELLULAR_AT_SUCCESS ) + if( skipParsing != true ) { - if( ( tempValue >= 0 ) && ( tempValue <= UINT16_MAX ) ) - { - var = ( uint16_t ) tempValue; - } - else - { - atCoreStatus = CELLULAR_AT_ERROR; - } - } + atCoreStatus = Cellular_ATStrtoi( pToken, 16, &tempValue ); - if( atCoreStatus == CELLULAR_AT_SUCCESS ) - { - /* Parsing Location area code for CREG or CGREG. */ - if( ( regType == CELLULAR_REG_TYPE_CREG ) || ( regType == CELLULAR_REG_TYPE_CGREG ) ) - { - pLibAtData->lac = ( uint16_t ) var; - } - /* Parsing Tracking area code for CEREG. */ - else if( regType == CELLULAR_REG_TYPE_CEREG ) + if( atCoreStatus == CELLULAR_AT_SUCCESS ) { - pLibAtData->tac = ( uint16_t ) var; + if( ( tempValue >= 0 ) && ( tempValue <= UINT16_MAX ) ) + { + var = ( uint16_t ) tempValue; + } + else + { + atCoreStatus = CELLULAR_AT_ERROR; + } } - else + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) { - /* Empty else MISRA 15.7 */ + /* Parsing Location area code for CREG or CGREG. */ + if( ( regType == CELLULAR_REG_TYPE_CREG ) || ( regType == CELLULAR_REG_TYPE_CGREG ) ) + { + pLibAtData->lac = ( uint16_t ) var; + } + /* Parsing Tracking area code for CEREG. */ + else if( regType == CELLULAR_REG_TYPE_CEREG ) + { + pLibAtData->tac = ( uint16_t ) var; + } + else + { + /* Empty else MISRA 15.7 */ + } } + + packetStatus = _Cellular_TranslateAtCoreStatus( atCoreStatus ); } - packetStatus = _Cellular_TranslateAtCoreStatus( atCoreStatus ); return packetStatus; } @@ -290,12 +295,13 @@ static CellularPktStatus_t _parseCellIdInRegStatus( const char * pToken, int32_t tempValue = 0; CellularATError_t atCoreStatus = CELLULAR_AT_SUCCESS; CellularPktStatus_t packetStatus = CELLULAR_PKT_STATUS_OK; + bool skipParsing = false; if( ( pToken != NULL ) && ( pToken[0] == '\0' ) ) { if( allowEmpty == true ) { - return packetStatus; + skipParsing = true; } else { @@ -303,22 +309,26 @@ static CellularPktStatus_t _parseCellIdInRegStatus( const char * pToken, } } - atCoreStatus = Cellular_ATStrtoi( pToken, 16, &tempValue ); - - if( atCoreStatus == CELLULAR_AT_SUCCESS ) + if( skipParsing != true ) { - if( tempValue >= 0 ) - { - pLibAtData->cellId = ( uint32_t ) tempValue; - } - else + atCoreStatus = Cellular_ATStrtoi( pToken, 16, &tempValue ); + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) { - LogError( ( "Error in processing Cell Id. Token '%s'", pToken ) ); - atCoreStatus = CELLULAR_AT_ERROR; + if( tempValue >= 0 ) + { + pLibAtData->cellId = ( uint32_t ) tempValue; + } + else + { + LogError( ( "Error in processing Cell Id. Token '%s'", pToken ) ); + atCoreStatus = CELLULAR_AT_ERROR; + } } + + packetStatus = _Cellular_TranslateAtCoreStatus( atCoreStatus ); } - packetStatus = _Cellular_TranslateAtCoreStatus( atCoreStatus ); return packetStatus; } @@ -331,12 +341,13 @@ static CellularPktStatus_t _parseRatInfoInRegStatus( const char * pToken, int32_t var = 0; CellularATError_t atCoreStatus = CELLULAR_AT_SUCCESS; CellularPktStatus_t packetStatus = CELLULAR_PKT_STATUS_OK; + bool skipParsing = false; if( ( pToken != NULL ) && ( pToken[0] == '\0' ) ) { if( allowEmpty == true ) { - return packetStatus; + skipParsing = true; } else { @@ -344,35 +355,39 @@ static CellularPktStatus_t _parseRatInfoInRegStatus( const char * pToken, } } - atCoreStatus = Cellular_ATStrtoi( pToken, 10, &var ); - - if( atCoreStatus == CELLULAR_AT_SUCCESS ) + if( skipParsing != true ) { - if( var >= ( int32_t ) CELLULAR_RAT_MAX ) - { - atCoreStatus = CELLULAR_AT_ERROR; - LogError( ( "Error in processing RAT. Token '%s'", pToken ) ); - } - else if( ( var == ( int32_t ) CELLULAR_RAT_GSM ) || ( var == ( int32_t ) CELLULAR_RAT_EDGE ) || - ( var == ( int32_t ) CELLULAR_RAT_CATM1 ) || ( var == ( int32_t ) CELLULAR_RAT_NBIOT ) ) - { - /* MISRA Ref 10.5.1 [Essential type casting] */ - /* More details at: https://github.com/FreeRTOS/FreeRTOS-Cellular-Interface/blob/main/MISRA.md#rule-105 */ - /* coverity[misra_c_2012_rule_10_5_violation] */ - pLibAtData->rat = ( CellularRat_t ) var; - } - else if( var == ( int32_t ) CELLULAR_RAT_LTE ) - { - /* Some cellular module use 7 : CELLULAR_RAT_LTE to indicate CAT-M1. */ - pLibAtData->rat = ( CellularRat_t ) CELLULAR_RAT_LTE; - } - else + atCoreStatus = Cellular_ATStrtoi( pToken, 10, &var ); + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) { - pLibAtData->rat = CELLULAR_RAT_INVALID; + if( var >= ( int32_t ) CELLULAR_RAT_MAX ) + { + atCoreStatus = CELLULAR_AT_ERROR; + LogError( ( "Error in processing RAT. Token '%s'", pToken ) ); + } + else if( ( var == ( int32_t ) CELLULAR_RAT_GSM ) || ( var == ( int32_t ) CELLULAR_RAT_EDGE ) || + ( var == ( int32_t ) CELLULAR_RAT_CATM1 ) || ( var == ( int32_t ) CELLULAR_RAT_NBIOT ) ) + { + /* MISRA Ref 10.5.1 [Essential type casting] */ + /* More details at: https://github.com/FreeRTOS/FreeRTOS-Cellular-Interface/blob/main/MISRA.md#rule-105 */ + /* coverity[misra_c_2012_rule_10_5_violation] */ + pLibAtData->rat = ( CellularRat_t ) var; + } + else if( var == ( int32_t ) CELLULAR_RAT_LTE ) + { + /* Some cellular module use 7 : CELLULAR_RAT_LTE to indicate CAT-M1. */ + pLibAtData->rat = ( CellularRat_t ) CELLULAR_RAT_LTE; + } + else + { + pLibAtData->rat = CELLULAR_RAT_INVALID; + } } + + packetStatus = _Cellular_TranslateAtCoreStatus( atCoreStatus ); } - packetStatus = _Cellular_TranslateAtCoreStatus( atCoreStatus ); return packetStatus; } @@ -387,12 +402,13 @@ static CellularPktStatus_t _parseRejectTypeInRegStatus( CellularNetworkRegType_t uint8_t rejType = 0; CellularATError_t atCoreStatus = CELLULAR_AT_SUCCESS; CellularPktStatus_t packetStatus = CELLULAR_PKT_STATUS_OK; + bool skipParsing = false; if( ( pToken != NULL ) && ( pToken[0] == '\0' ) ) { if( allowEmpty == true ) { - return packetStatus; + skipParsing = true; } else { @@ -400,44 +416,48 @@ static CellularPktStatus_t _parseRejectTypeInRegStatus( CellularNetworkRegType_t } } - atCoreStatus = Cellular_ATStrtoi( pToken, 10, &tempValue ); - - if( atCoreStatus == CELLULAR_AT_SUCCESS ) + if( skipParsing != true ) { - if( ( tempValue >= 0 ) && ( tempValue <= ( int32_t ) UINT8_MAX ) ) - { - rejType = ( uint8_t ) tempValue; - } - else - { - atCoreStatus = CELLULAR_AT_ERROR; - } - } + atCoreStatus = Cellular_ATStrtoi( pToken, 10, &tempValue ); - if( atCoreStatus == CELLULAR_AT_SUCCESS ) - { - if( regType == CELLULAR_REG_TYPE_CREG ) + if( atCoreStatus == CELLULAR_AT_SUCCESS ) { - /* Reject Type is only stored if the registration status is denied. */ - if( pLibAtData->csRegStatus == REGISTRATION_STATUS_REGISTRATION_DENIED ) + if( ( tempValue >= 0 ) && ( tempValue <= ( int32_t ) UINT8_MAX ) ) { - pLibAtData->csRejectType = rejType; + rejType = ( uint8_t ) tempValue; } - } - else if( ( regType == CELLULAR_REG_TYPE_CGREG ) || ( regType == CELLULAR_REG_TYPE_CEREG ) ) - { - if( pLibAtData->psRegStatus == REGISTRATION_STATUS_REGISTRATION_DENIED ) + else { - pLibAtData->psRejectType = rejType; + atCoreStatus = CELLULAR_AT_ERROR; } } - else + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) { - /* Empty else MISRA 15.7 */ + if( regType == CELLULAR_REG_TYPE_CREG ) + { + /* Reject Type is only stored if the registration status is denied. */ + if( pLibAtData->csRegStatus == REGISTRATION_STATUS_REGISTRATION_DENIED ) + { + pLibAtData->csRejectType = rejType; + } + } + else if( ( regType == CELLULAR_REG_TYPE_CGREG ) || ( regType == CELLULAR_REG_TYPE_CEREG ) ) + { + if( pLibAtData->psRegStatus == REGISTRATION_STATUS_REGISTRATION_DENIED ) + { + pLibAtData->psRejectType = rejType; + } + } + else + { + /* Empty else MISRA 15.7 */ + } } + + packetStatus = _Cellular_TranslateAtCoreStatus( atCoreStatus ); } - packetStatus = _Cellular_TranslateAtCoreStatus( atCoreStatus ); return packetStatus; } @@ -452,12 +472,13 @@ static CellularPktStatus_t _parseRejectCauseInRegStatus( CellularNetworkRegType_ uint8_t rejCause = 0; CellularATError_t atCoreStatus = CELLULAR_AT_SUCCESS; CellularPktStatus_t packetStatus = CELLULAR_PKT_STATUS_OK; + bool skipParsing = false; if( ( pToken != NULL ) && ( pToken[0] == '\0' ) ) { if( allowEmpty == true ) { - return packetStatus; + skipParsing = true; } else { @@ -465,43 +486,46 @@ static CellularPktStatus_t _parseRejectCauseInRegStatus( CellularNetworkRegType_ } } - atCoreStatus = Cellular_ATStrtoi( pToken, 10, &tempValue ); - - if( atCoreStatus == CELLULAR_AT_SUCCESS ) + if( skipParsing != true ) { - if( ( tempValue >= 0 ) && ( tempValue <= ( int32_t ) UINT8_MAX ) ) - { - rejCause = ( uint8_t ) tempValue; - } - else - { - atCoreStatus = CELLULAR_AT_ERROR; - } - } + atCoreStatus = Cellular_ATStrtoi( pToken, 10, &tempValue ); - if( atCoreStatus == CELLULAR_AT_SUCCESS ) - { - if( regType == CELLULAR_REG_TYPE_CREG ) + if( atCoreStatus == CELLULAR_AT_SUCCESS ) { - if( pLibAtData->csRegStatus == REGISTRATION_STATUS_REGISTRATION_DENIED ) + if( ( tempValue >= 0 ) && ( tempValue <= ( int32_t ) UINT8_MAX ) ) { - pLibAtData->csRejCause = rejCause; + rejCause = ( uint8_t ) tempValue; } - } - else if( ( regType == CELLULAR_REG_TYPE_CGREG ) || ( regType == CELLULAR_REG_TYPE_CEREG ) ) - { - if( pLibAtData->psRegStatus == REGISTRATION_STATUS_REGISTRATION_DENIED ) + else { - pLibAtData->psRejCause = rejCause; + atCoreStatus = CELLULAR_AT_ERROR; } } - else + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) { - /* Empty else MISRA 15.7 */ + if( regType == CELLULAR_REG_TYPE_CREG ) + { + if( pLibAtData->csRegStatus == REGISTRATION_STATUS_REGISTRATION_DENIED ) + { + pLibAtData->csRejCause = rejCause; + } + } + else if( ( regType == CELLULAR_REG_TYPE_CGREG ) || ( regType == CELLULAR_REG_TYPE_CEREG ) ) + { + if( pLibAtData->psRegStatus == REGISTRATION_STATUS_REGISTRATION_DENIED ) + { + pLibAtData->psRejCause = rejCause; + } + } + else + { + /* Empty else MISRA 15.7 */ + } } - } - packetStatus = _Cellular_TranslateAtCoreStatus( atCoreStatus ); + packetStatus = _Cellular_TranslateAtCoreStatus( atCoreStatus ); + } return packetStatus; } @@ -515,13 +539,14 @@ static CellularPktStatus_t _parseActiveTimeInRegStatus( const char * pToken, int32_t tempValue = 0; CellularATError_t atCoreStatus = CELLULAR_AT_SUCCESS; CellularPktStatus_t packetStatus = CELLULAR_PKT_STATUS_OK; + bool skipParsing = false; if( ( pToken != NULL ) && ( pToken[0] == '\0' ) ) { if( allowEmpty == true ) { pLibAtData->activeTimeValue = 0xFFFFFFFF; - return packetStatus; + skipParsing = true; } else { @@ -529,22 +554,26 @@ static CellularPktStatus_t _parseActiveTimeInRegStatus( const char * pToken, } } - atCoreStatus = Cellular_ATStrtoi( pToken, 2, &tempValue ); - - if( atCoreStatus == CELLULAR_AT_SUCCESS ) + if( skipParsing != true ) { - if( ( tempValue >= 0 ) && ( tempValue <= UINT8_MAX ) ) - { - pLibAtData->activeTimeValue = ( uint32_t ) tempValue; - } - else + atCoreStatus = Cellular_ATStrtoi( pToken, 2, &tempValue ); + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) { - LogError( ( "Error in processing Active Time value. Token '%s'", pToken ) ); - atCoreStatus = CELLULAR_AT_ERROR; + if( ( tempValue >= 0 ) && ( tempValue <= UINT8_MAX ) ) + { + pLibAtData->activeTimeValue = ( uint32_t ) tempValue; + } + else + { + LogError( ( "Error in processing Active Time value. Token '%s'", pToken ) ); + atCoreStatus = CELLULAR_AT_ERROR; + } } + + packetStatus = _Cellular_TranslateAtCoreStatus( atCoreStatus ); } - packetStatus = _Cellular_TranslateAtCoreStatus( atCoreStatus ); return packetStatus; } @@ -557,13 +586,14 @@ static CellularPktStatus_t _parsePeriodicTauInRegStatus( const char * pToken, int32_t tempValue = 0; CellularATError_t atCoreStatus = CELLULAR_AT_SUCCESS; CellularPktStatus_t packetStatus = CELLULAR_PKT_STATUS_OK; + bool skipParsing = false; if( ( pToken != NULL ) && ( pToken[0] == '\0' ) ) { if( allowEmpty == true ) { pLibAtData->periodicTauValue = 0xFFFFFFFF; - return packetStatus; + skipParsing = true; } else { @@ -571,22 +601,26 @@ static CellularPktStatus_t _parsePeriodicTauInRegStatus( const char * pToken, } } - atCoreStatus = Cellular_ATStrtoi( pToken, 2, &tempValue ); - - if( atCoreStatus == CELLULAR_AT_SUCCESS ) + if( skipParsing != true ) { - if( ( tempValue >= 0 ) && ( tempValue <= UINT8_MAX ) ) - { - pLibAtData->periodicTauValue = ( uint32_t ) tempValue; - } - else + atCoreStatus = Cellular_ATStrtoi( pToken, 2, &tempValue ); + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) { - LogError( ( "Error in processing Periodic TAU value. Token '%s'", pToken ) ); - atCoreStatus = CELLULAR_AT_ERROR; + if( ( tempValue >= 0 ) && ( tempValue <= UINT8_MAX ) ) + { + pLibAtData->periodicTauValue = ( uint32_t ) tempValue; + } + else + { + LogError( ( "Error in processing Periodic TAU value. Token '%s'", pToken ) ); + atCoreStatus = CELLULAR_AT_ERROR; + } } + + packetStatus = _Cellular_TranslateAtCoreStatus( atCoreStatus ); } - packetStatus = _Cellular_TranslateAtCoreStatus( atCoreStatus ); return packetStatus; } From e4158a75f27baa2fd2b50df73f49929ec290c422 Mon Sep 17 00:00:00 2001 From: Michael Vermeer Date: Tue, 10 Mar 2026 16:12:42 -0400 Subject: [PATCH 7/7] Final tweaks and fixes --- source/cellular_3gpp_api.c | 3 ++- source/cellular_3gpp_urc_handler.c | 40 +++++++++++++----------------- 2 files changed, 19 insertions(+), 24 deletions(-) diff --git a/source/cellular_3gpp_api.c b/source/cellular_3gpp_api.c index b23171a7..fc8dae18 100644 --- a/source/cellular_3gpp_api.c +++ b/source/cellular_3gpp_api.c @@ -796,6 +796,7 @@ static CellularPktStatus_t _Cellular_RecvFuncGetNetworkReg( CellularContext_t * CellularATError_t atCoreStatus = CELLULAR_AT_SUCCESS; CellularNetworkRegType_t regType = CELLULAR_REG_TYPE_UNKNOWN; CellularATCommandLine_t * pCommandLine = NULL; + bool isUrc = false; if( pContext == NULL ) { @@ -823,7 +824,7 @@ static CellularPktStatus_t _Cellular_RecvFuncGetNetworkReg( CellularContext_t * /* Assumption is that the data is null terminated so we don't need the dataLen. */ _Cellular_LockAtDataMutex( pContext ); - bool isUrc = regResponseIsUrc( pPregLine ); + isUrc = regResponseIsUrc( pPregLine ); /* Remove the prefix for URC handler. */ atCoreStatus = Cellular_ATRemovePrefix( &pPregLine ); diff --git a/source/cellular_3gpp_urc_handler.c b/source/cellular_3gpp_urc_handler.c index 481d3de8..07dcbd4a 100644 --- a/source/cellular_3gpp_urc_handler.c +++ b/source/cellular_3gpp_urc_handler.c @@ -131,14 +131,14 @@ static CellularATError_t _parseUrcModeInRegStatus( const char * pToken, if( atCoreStatus == CELLULAR_AT_SUCCESS ) { - if( ( var < 0 ) || ( var > 4 ) ) + if( ( var >= 0 ) && ( var <= UINT8_MAX ) ) { - atCoreStatus = CELLULAR_AT_ERROR; - LogError( ( "Error in processing URC mode in reg status. Token '%s'", pToken ) ); + *urcMode = ( uint8_t ) var; } else { - *urcMode = ( uint8_t ) var; + atCoreStatus = CELLULAR_AT_ERROR; + LogError( ( "Error in processing URC mode in reg status. Token '%s'", pToken ) ); } } } @@ -292,7 +292,7 @@ static CellularPktStatus_t _parseCellIdInRegStatus( const char * pToken, cellularAtData_t * pLibAtData, bool allowEmpty ) { - int32_t tempValue = 0; + uint32_t tempValue = 0; CellularATError_t atCoreStatus = CELLULAR_AT_SUCCESS; CellularPktStatus_t packetStatus = CELLULAR_PKT_STATUS_OK; bool skipParsing = false; @@ -311,19 +311,15 @@ static CellularPktStatus_t _parseCellIdInRegStatus( const char * pToken, if( skipParsing != true ) { - atCoreStatus = Cellular_ATStrtoi( pToken, 16, &tempValue ); + atCoreStatus = Cellular_ATStrtoui( pToken, 16, &tempValue ); if( atCoreStatus == CELLULAR_AT_SUCCESS ) { - if( tempValue >= 0 ) - { - pLibAtData->cellId = ( uint32_t ) tempValue; - } - else - { - LogError( ( "Error in processing Cell Id. Token '%s'", pToken ) ); - atCoreStatus = CELLULAR_AT_ERROR; - } + pLibAtData->cellId = tempValue; + } + else + { + LogError( ( "Error in processing Cell Id. Token '%s'", pToken ) ); } packetStatus = _Cellular_TranslateAtCoreStatus( atCoreStatus ); @@ -666,12 +662,12 @@ static CellularPktStatus_t _regStatusSwitchParsingFunc( CellularContext_t * pCon /* Parsing Cell ID. */ case CELLULAR_REG_POS_CELL_ID: - packetStatus = _parseCellIdInRegStatus( pToken, pLibAtData, isUrcOrUrcModePSM /* allowEmpty= */ ); + packetStatus = _parseCellIdInRegStatus( pToken, pLibAtData, isUrcOrUrcModePSM /* allowEmpty= */ ); break; /* Parsing RAT Information. */ case CELLULAR_REG_POS_RAT: - packetStatus = _parseRatInfoInRegStatus( pToken, pLibAtData, isUrcOrUrcModePSM /* allowEmpty= */ ); + packetStatus = _parseRatInfoInRegStatus( pToken, pLibAtData, isUrcOrUrcModePSM /* allowEmpty= */ ); break; /* Parsing Reject Type. */ @@ -719,8 +715,7 @@ static CellularPktStatus_t _regStatusSwitchParsingFunc( CellularContext_t * pCon break; default: - // TODO (MV): Return to debug - LogError( ( "Unknown Parameter Position in Registration URC: %hhu", i ) ); + LogDebug( ( "Unknown Parameter Position in Registration URC: %hhu", i ) ); break; } @@ -744,8 +739,7 @@ static void _regStatusGenerateLog( char * pRegPayload, } else if( regType == CELLULAR_REG_TYPE_CEREG ) { - // TODO (MV): Return this to debug - LogInfo( ( "URC: CEREG: %s", pRegPayload ) ); + LogDebug( ( "URC: CEREG: %s", pRegPayload ) ); } else { @@ -858,8 +852,8 @@ CellularPktStatus_t _Cellular_ParseRegStatus( CellularContext_t * pContext, pRegStr = pRegPayload; - // TODO (MV): Remove - LogError( ( "%s '%s'", + // FUTURE: Remove once satisfied with Registration Status parsing, currently at error level to guarantee logging + LogError( ( "%s: '%s'", ( ( regType == CELLULAR_REG_TYPE_CREG ) ? "CREG" : ( ( regType == CELLULAR_REG_TYPE_CEREG ) ? "CEREG" : ( ( regType == CELLULAR_REG_TYPE_CGREG ) ? "CGREG" :