2021-11-30 14:51:24 +01:00

704 lines
24 KiB
C

/*
* FreeRTOS-Cellular-Interface v1.1.0
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*/
/**
* @brief FreeRTOS Cellular Library URC handler implemenation with 3GPP URC.
*/
#ifndef CELLULAR_DO_NOT_USE_CUSTOM_CONFIG
/* Include custom config file before other headers. */
#include "cellular_config.h"
#endif
#include "cellular_config_defaults.h"
/* Standard includes. */
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include "cellular_platform.h"
#include "cellular_types.h"
#include "cellular_internal.h"
#include "cellular_common_internal.h"
#include "cellular_common_api.h"
/*-----------------------------------------------------------*/
#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 )
/*-----------------------------------------------------------*/
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 );
static CellularPktStatus_t _parseCellIdInRegStatus( const char * pToken,
cellularAtData_t * pLibAtData );
static CellularPktStatus_t _parseRatInfoInRegStatus( const char * pToken,
cellularAtData_t * pLibAtData );
static CellularPktStatus_t _parseRejectTypeInRegStatus( CellularNetworkRegType_t regType,
const char * pToken,
cellularAtData_t * pLibAtData );
static CellularPktStatus_t _parseRejectCauseInRegStatus( CellularNetworkRegType_t regType,
const char * pToken,
cellularAtData_t * pLibAtData );
static CellularPktStatus_t _regStatusSwitchParsingFunc( CellularContext_t * pContext,
uint8_t i,
CellularNetworkRegType_t regType,
const char * pToken,
cellularAtData_t * pLibAtData );
static void _regStatusGenerateLog( char * pRegPayload,
CellularNetworkRegType_t regType );
static void _regStatusGenerateEvent( const CellularContext_t * pContext,
CellularNetworkRegType_t regType,
const cellularAtData_t * pLibAtData );
static bool _Cellular_RegEventStatus( const cellularAtData_t * pLibAtData,
CellularNetworkRegType_t regType,
CellularNetworkRegistrationStatus_t prevCsRegStatus,
CellularNetworkRegistrationStatus_t prevPsRegStatus );
/*-----------------------------------------------------------*/
static CellularPktStatus_t _parseRegStatusInRegStatusParsing( CellularContext_t * pContext,
CellularNetworkRegType_t regType,
const char * pToken,
cellularAtData_t * pLibAtData )
{
int32_t tempValue = 0;
CellularATError_t atCoreStatus = CELLULAR_AT_SUCCESS;
CellularPktStatus_t packetStatus = CELLULAR_PKT_STATUS_OK;
CellularNetworkRegistrationStatus_t regStatus = REGISTRATION_STATUS_UNKNOWN;
if( ( regType != CELLULAR_REG_TYPE_CREG ) && ( regType != CELLULAR_REG_TYPE_CEREG ) &&
( regType != CELLULAR_REG_TYPE_CGREG ) )
{
packetStatus = CELLULAR_PKT_STATUS_BAD_PARAM;
}
else
{
atCoreStatus = Cellular_ATStrtoi( pToken, 10, &tempValue );
if( atCoreStatus == CELLULAR_AT_SUCCESS )
{
if( ( tempValue >= 0 ) && ( tempValue < ( int32_t ) REGISTRATION_STATUS_MAX ) )
{
/* tempValue range is checked before casting. */
/* coverity[misra_c_2012_rule_10_5_violation] */
regStatus = ( CellularNetworkRegistrationStatus_t ) tempValue;
}
else
{
atCoreStatus = CELLULAR_AT_ERROR;
}
}
packetStatus = _Cellular_TranslateAtCoreStatus( atCoreStatus );
}
if( packetStatus == CELLULAR_PKT_STATUS_OK )
{
if( regType == CELLULAR_REG_TYPE_CREG )
{
pLibAtData->csRegStatus = regStatus;
}
else
{
pLibAtData->psRegStatus = regStatus;
}
if( regStatus == REGISTRATION_STATUS_REGISTERED_HOME )
{
LogDebug( ( "Netowrk registration : HOME" ) );
}
else if( regStatus == REGISTRATION_STATUS_ROAMING_REGISTERED )
{
LogDebug( ( "Netowrk registration : ROAMING" ) );
}
else if( regStatus == REGISTRATION_STATUS_REGISTRATION_DENIED )
{
/* clear the atlib data if the registration failed. */
LogDebug( ( "Netowrk registration : DEINED" ) );
_Cellular_InitAtData( pContext, 1 );
}
else
{
/* clear the atlib data if the registration failed. */
LogDebug( ( "Netowrk registration : OTHERS" ) );
_Cellular_InitAtData( pContext, 1 );
}
}
return packetStatus;
}
/*-----------------------------------------------------------*/
static CellularPktStatus_t _parseLacTacInRegStatus( CellularNetworkRegType_t regType,
const char * pToken,
cellularAtData_t * pLibAtData )
{
int32_t tempValue = 0;
uint16_t var = 0;
CellularATError_t atCoreStatus = CELLULAR_AT_SUCCESS;
CellularPktStatus_t packetStatus = CELLULAR_PKT_STATUS_OK;
atCoreStatus = Cellular_ATStrtoi( pToken, 16, &tempValue );
if( atCoreStatus == CELLULAR_AT_SUCCESS )
{
if( ( tempValue >= 0 ) && ( tempValue <= UINT16_MAX ) )
{
var = ( uint16_t ) tempValue;
}
else
{
atCoreStatus = CELLULAR_AT_ERROR;
}
}
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 )
{
pLibAtData->tac = ( uint16_t ) var;
}
else
{
/* Empty else MISRA 15.7 */
}
}
packetStatus = _Cellular_TranslateAtCoreStatus( atCoreStatus );
return packetStatus;
}
/*-----------------------------------------------------------*/
static CellularPktStatus_t _parseCellIdInRegStatus( const char * pToken,
cellularAtData_t * pLibAtData )
{
int32_t tempValue = 0;
CellularATError_t atCoreStatus = CELLULAR_AT_SUCCESS;
CellularPktStatus_t packetStatus = CELLULAR_PKT_STATUS_OK;
atCoreStatus = Cellular_ATStrtoi( 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;
}
}
packetStatus = _Cellular_TranslateAtCoreStatus( atCoreStatus );
return packetStatus;
}
/*-----------------------------------------------------------*/
static CellularPktStatus_t _parseRatInfoInRegStatus( const char * pToken,
cellularAtData_t * pLibAtData )
{
int32_t var = 0;
CellularATError_t atCoreStatus = CELLULAR_AT_SUCCESS;
CellularPktStatus_t packetStatus = CELLULAR_PKT_STATUS_OK;
atCoreStatus = Cellular_ATStrtoi( pToken, 10, &var );
if( atCoreStatus == CELLULAR_AT_SUCCESS )
{
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 ) )
{
/* Variable "var" is ensured that it is valid and within
* a valid range. Hence, assigning the value of the variable to
* rat with a enum cast. */
/* 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 );
return packetStatus;
}
/*-----------------------------------------------------------*/
static CellularPktStatus_t _parseRejectTypeInRegStatus( CellularNetworkRegType_t regType,
const char * pToken,
cellularAtData_t * pLibAtData )
{
int32_t tempValue = 0;
uint8_t rejType = 0;
CellularATError_t atCoreStatus = CELLULAR_AT_SUCCESS;
CellularPktStatus_t packetStatus = CELLULAR_PKT_STATUS_OK;
atCoreStatus = Cellular_ATStrtoi( pToken, 10, &tempValue );
if( atCoreStatus == CELLULAR_AT_SUCCESS )
{
if( ( tempValue >= 0 ) && ( tempValue <= ( int32_t ) UINT8_MAX ) )
{
rejType = ( uint8_t ) tempValue;
}
else
{
atCoreStatus = CELLULAR_AT_ERROR;
}
}
if( atCoreStatus == CELLULAR_AT_SUCCESS )
{
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 );
return packetStatus;
}
/*-----------------------------------------------------------*/
static CellularPktStatus_t _parseRejectCauseInRegStatus( CellularNetworkRegType_t regType,
const char * pToken,
cellularAtData_t * pLibAtData )
{
int32_t tempValue = 0;
uint8_t rejCause = 0;
CellularATError_t atCoreStatus = CELLULAR_AT_SUCCESS;
CellularPktStatus_t packetStatus = CELLULAR_PKT_STATUS_OK;
atCoreStatus = Cellular_ATStrtoi( pToken, 10, &tempValue );
if( atCoreStatus == CELLULAR_AT_SUCCESS )
{
if( ( tempValue >= 0 ) && ( tempValue <= ( int32_t ) UINT8_MAX ) )
{
rejCause = ( uint8_t ) tempValue;
}
else
{
atCoreStatus = CELLULAR_AT_ERROR;
}
}
if( atCoreStatus == CELLULAR_AT_SUCCESS )
{
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 );
return packetStatus;
}
/*-----------------------------------------------------------*/
static CellularPktStatus_t _regStatusSwitchParsingFunc( CellularContext_t * pContext,
uint8_t i,
CellularNetworkRegType_t regType,
const char * pToken,
cellularAtData_t * pLibAtData )
{
CellularPktStatus_t packetStatus = CELLULAR_PKT_STATUS_OK;
switch( i )
{
/* Parsing network Registration status in CREG or CGREG or CEREG response. */
case CELLULAR_REG_POS_STAT:
packetStatus = _parseRegStatusInRegStatusParsing( pContext, regType, pToken, pLibAtData );
break;
case CELLULAR_REG_POS_LAC_TAC:
packetStatus = _parseLacTacInRegStatus( regType, pToken, pLibAtData );
break;
/* Parsing Cell ID. */
case CELLULAR_REG_POS_CELL_ID:
packetStatus = _parseCellIdInRegStatus( pToken, pLibAtData );
break;
/* Parsing RAT Information. */
case CELLULAR_REG_POS_RAT:
packetStatus = _parseRatInfoInRegStatus( pToken, pLibAtData );
break;
/* Parsing Reject Type. */
case CELLULAR_REG_POS_REJ_TYPE:
packetStatus = _parseRejectTypeInRegStatus( regType, pToken, pLibAtData );
break;
/* Parsing the Reject Cause. */
case CELLULAR_REG_POS_REJ_CAUSE:
packetStatus = _parseRejectCauseInRegStatus( regType, pToken, pLibAtData );
break;
default:
LogDebug( ( "Unknown Parameter Position in Registration URC" ) );
break;
}
return packetStatus;
}
/*-----------------------------------------------------------*/
static void _regStatusGenerateLog( char * pRegPayload,
CellularNetworkRegType_t regType )
{
( void ) pRegPayload;
if( regType == CELLULAR_REG_TYPE_CREG )
{
LogDebug( ( "URC: CREG: %s", pRegPayload ) );
}
else if( regType == CELLULAR_REG_TYPE_CGREG )
{
LogDebug( ( "URC: CGREG: %s", pRegPayload ) );
}
else if( regType == CELLULAR_REG_TYPE_CEREG )
{
LogDebug( ( "URC: CEREG: %s", pRegPayload ) );
}
else
{
LogDebug( ( " URC: Unknown " ) );
}
}
/*-----------------------------------------------------------*/
static void _regStatusGenerateEvent( const CellularContext_t * pContext,
CellularNetworkRegType_t regType,
const cellularAtData_t * pLibAtData )
{
CellularServiceStatus_t serviceStatus;
( void ) memset( &serviceStatus, 0, sizeof( CellularServiceStatus_t ) );
serviceStatus.rat = pLibAtData->rat;
serviceStatus.csRegistrationStatus = pLibAtData->csRegStatus;
serviceStatus.psRegistrationStatus = pLibAtData->psRegStatus;
serviceStatus.csRejectionCause = pLibAtData->csRejCause;
serviceStatus.csRejectionType = pLibAtData->csRejectType;
serviceStatus.psRejectionCause = pLibAtData->psRejCause;
serviceStatus.psRejectionType = pLibAtData->psRejectType;
/* Data should be obtained from COPS commmand. User should obtain with APIs. */
( void ) strcpy( serviceStatus.plmnInfo.mcc, "FFF" );
( void ) strcpy( serviceStatus.plmnInfo.mnc, "FFF" );
( void ) strcpy( serviceStatus.operatorName, "FFF" );
serviceStatus.operatorNameFormat = OPERATOR_NAME_FORMAT_NOT_PRESENT;
serviceStatus.networkRegistrationMode = REGISTRATION_MODE_UNKNOWN;
if( pContext->cbEvents.networkRegistrationCallback != NULL )
{
if( regType == CELLULAR_REG_TYPE_CREG )
{
_Cellular_NetworkRegistrationCallback( pContext, CELLULAR_URC_EVENT_NETWORK_CS_REGISTRATION, &serviceStatus );
}
else
{
_Cellular_NetworkRegistrationCallback( pContext, CELLULAR_URC_EVENT_NETWORK_PS_REGISTRATION, &serviceStatus );
}
}
}
/*-----------------------------------------------------------*/
/* check registration event change to decide to generate event. */
static bool _Cellular_RegEventStatus( const cellularAtData_t * pLibAtData,
CellularNetworkRegType_t regType,
CellularNetworkRegistrationStatus_t prevCsRegStatus,
CellularNetworkRegistrationStatus_t prevPsRegStatus )
{
bool retEventChanged = false;
switch( regType )
{
case CELLULAR_REG_TYPE_CREG:
if( pLibAtData->csRegStatus != prevCsRegStatus )
{
retEventChanged = true;
}
break;
case CELLULAR_REG_TYPE_CGREG:
case CELLULAR_REG_TYPE_CEREG:
if( pLibAtData->psRegStatus != prevPsRegStatus )
{
retEventChanged = true;
}
break;
default:
LogInfo( ( "_Cellular_RegEventStatus : unknown reg type " ) );
break;
}
return retEventChanged;
}
/*-----------------------------------------------------------*/
CellularPktStatus_t _Cellular_ParseRegStatus( CellularContext_t * pContext,
char * pRegPayload,
bool isUrc,
CellularNetworkRegType_t regType )
{
uint8_t i = 0;
char * pRegStr = NULL, * pToken = NULL;
cellularAtData_t * pLibAtData = NULL;
CellularPktStatus_t packetStatus = CELLULAR_PKT_STATUS_OK;
CellularATError_t atCoreStatus = CELLULAR_AT_SUCCESS;
CellularNetworkRegistrationStatus_t prevCsRegStatus = REGISTRATION_STATUS_UNKNOWN;
CellularNetworkRegistrationStatus_t prevPsRegStatus = REGISTRATION_STATUS_UNKNOWN;
if( pContext == NULL )
{
packetStatus = CELLULAR_PKT_STATUS_FAILURE;
}
else if( pRegPayload == NULL )
{
packetStatus = CELLULAR_PKT_STATUS_BAD_PARAM;
}
else
{
pLibAtData = &pContext->libAtData;
if( isUrc == true )
{
i++;
}
pRegStr = pRegPayload;
atCoreStatus = Cellular_ATRemoveAllDoubleQuote( pRegStr );
if( atCoreStatus == CELLULAR_AT_SUCCESS )
{
atCoreStatus = Cellular_ATRemoveAllWhiteSpaces( pRegStr );
}
if( atCoreStatus == CELLULAR_AT_SUCCESS )
{
atCoreStatus = Cellular_ATGetNextTok( &pRegStr, &pToken );
}
if( atCoreStatus == CELLULAR_AT_SUCCESS )
{
/* Backup the previous regStatus. */
prevCsRegStatus = pLibAtData->csRegStatus;
prevPsRegStatus = pLibAtData->psRegStatus;
while( pToken != NULL )
{
i++;
packetStatus = _regStatusSwitchParsingFunc( pContext, i, regType,
pToken, pLibAtData );
/* Getting next token to parse. */
if( Cellular_ATGetNextTok( &pRegStr, &pToken ) != CELLULAR_AT_SUCCESS )
{
break;
}
}
}
/* Generate logs. */
if( isUrc == true )
{
_regStatusGenerateLog( pRegPayload, regType );
}
/* If Registration Status changed, generate the event. */
if( ( _Cellular_RegEventStatus( pLibAtData, regType, prevCsRegStatus, prevPsRegStatus ) == true ) )
{
_regStatusGenerateEvent( pContext, regType, pLibAtData );
}
if( atCoreStatus != CELLULAR_AT_SUCCESS )
{
packetStatus = _Cellular_TranslateAtCoreStatus( atCoreStatus );
}
}
return packetStatus;
}
/*-----------------------------------------------------------*/
CellularPktStatus_t Cellular_CommonUrcProcessCreg( CellularContext_t * pContext,
char * pInputLine )
{
CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_OK;
if( pContext != NULL )
{
_Cellular_LockAtDataMutex( pContext );
pktStatus = _Cellular_ParseRegStatus( pContext, pInputLine, true, CELLULAR_REG_TYPE_CREG );
if( pktStatus != CELLULAR_PKT_STATUS_OK )
{
LogDebug( ( "Creg Parse failure" ) );
}
_Cellular_UnlockAtDataMutex( pContext );
}
else
{
pktStatus = CELLULAR_PKT_STATUS_INVALID_HANDLE;
}
return pktStatus;
}
/*-----------------------------------------------------------*/
CellularPktStatus_t Cellular_CommonUrcProcessCgreg( CellularContext_t * pContext,
char * pInputLine )
{
CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_OK;
if( pContext != NULL )
{
_Cellular_LockAtDataMutex( pContext );
pktStatus = _Cellular_ParseRegStatus( pContext, pInputLine, true, CELLULAR_REG_TYPE_CGREG );
if( pktStatus != CELLULAR_PKT_STATUS_OK )
{
LogDebug( ( "Cgreg Parse failure" ) );
}
_Cellular_UnlockAtDataMutex( pContext );
}
else
{
pktStatus = CELLULAR_PKT_STATUS_INVALID_HANDLE;
}
return pktStatus;
}
/*-----------------------------------------------------------*/
CellularPktStatus_t Cellular_CommonUrcProcessCereg( CellularContext_t * pContext,
char * pInputLine )
{
CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_OK;
if( pContext != NULL )
{
_Cellular_LockAtDataMutex( pContext );
pktStatus = _Cellular_ParseRegStatus( pContext, pInputLine, true, CELLULAR_REG_TYPE_CEREG );
if( pktStatus != CELLULAR_PKT_STATUS_OK )
{
LogDebug( ( "Cereg Parse failure" ) );
}
_Cellular_UnlockAtDataMutex( pContext );
}
else
{
pktStatus = CELLULAR_PKT_STATUS_INVALID_HANDLE;
}
return pktStatus;
}
/*-----------------------------------------------------------*/