From 8b9046655eed2afef313b01005583009b576e052 Mon Sep 17 00:00:00 2001 From: ActoryOu Date: Mon, 3 Oct 2022 16:04:49 +0800 Subject: [PATCH 1/4] Update README. --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 7f92204..4197ce9 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,12 @@ -## My Project +# FreeRTOS Cellular Interface Reference Implementation U-Blox Sara-R4 -TODO: Fill this README out! +## Introduction -Be sure to: +This repository provides the reference implementation as cellular module ports for [U-Blox Sara-R4](https://www.u-blox.com/en/product/sara-r4-series). This repository should be used with [FreeRTOS-Cellular-Interface](https://github.com/FreeRTOS/FreeRTOS-Cellular-Interface). See [FreeRTOS-Cellular-Interface README](https://github.com/FreeRTOS/FreeRTOS-Cellular-Interface/blob/main/README.md) for more details. -* Change the title in this README -* Edit your repository description on GitHub +## How Does Community Members to Contribute a Cellular Module Port + +We provide a repository, [FreeRTOS-Cellular-Interface-Community-Supported-Ports](https://github.com/FreeRTOS/FreeRTOS-Cellular-Interface-Community-Supported-Ports), for community members to contribute their modules. See [How to Contribute a Cellular Module Port](https://github.com/FreeRTOS/FreeRTOS-Cellular-Interface-Community-Supported-Ports#how-to-contribute-a-cellular-module-port) for more details. ## Security @@ -13,5 +14,4 @@ See [CONTRIBUTING](CONTRIBUTING.md#security-issue-notifications) for more inform ## License -This library is licensed under the MIT-0 License. See the LICENSE file. - +This library is licensed under the MIT-0 License. See the [LICENSE](https://github.com/FreeRTOS/freertos-cellular-interface-reference-implementation-ublox-sara-r4/blob/main/LICENSE) file. From 2ffe17c0d27b3d4b1480d8098fbc9dbfb7f0662c Mon Sep 17 00:00:00 2001 From: ActoryOu Date: Mon, 3 Oct 2022 16:05:29 +0800 Subject: [PATCH 2/4] Add SARA-R4 reference implementations. --- source/cellular_r4.c | 562 ++++++ source/cellular_r4.h | 164 ++ source/cellular_r4_api.c | 2906 ++++++++++++++++++++++++++++++ source/cellular_r4_urc_handler.c | 656 +++++++ source/cellular_r4_wrapper.c | 263 +++ 5 files changed, 4551 insertions(+) create mode 100644 source/cellular_r4.c create mode 100644 source/cellular_r4.h create mode 100644 source/cellular_r4_api.c create mode 100644 source/cellular_r4_urc_handler.c create mode 100644 source/cellular_r4_wrapper.c diff --git a/source/cellular_r4.c b/source/cellular_r4.c new file mode 100644 index 0000000..741425d --- /dev/null +++ b/source/cellular_r4.c @@ -0,0 +1,562 @@ +/* + * FreeRTOS-Cellular-Interface v1.3.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 + */ + +#include "cellular_config.h" +#include "cellular_config_defaults.h" + +#include + +#include "cellular_platform.h" +#include "cellular_common.h" +#include "cellular_common_portable.h" +#include "cellular_r4.h" + +/*-----------------------------------------------------------*/ + +#define ENBABLE_MODULE_UE_RETRY_COUNT ( 3U ) +#define ENBABLE_MODULE_UE_RETRY_TIMEOUT ( 5000U ) +#define ENBABLE_MODULE_UE_REBOOT_POLL_TIME ( 2000U ) +#define ENBABLE_MODULE_UE_REBOOT_MAX_TIME ( 25000U ) + +/*-----------------------------------------------------------*/ + +static CellularError_t sendAtCommandWithRetryTimeout( CellularContext_t * pContext, + const CellularAtReq_t * pAtReq ); + +/*-----------------------------------------------------------*/ + +static cellularModuleContext_t cellularHl7802Context = { 0 }; + +/* FreeRTOS Cellular Common Library porting interface. */ +/* coverity[misra_c_2012_rule_8_7_violation] */ +const char * CellularSrcTokenErrorTable[] = +{ "ERROR", "BUSY", "NO CARRIER", "NO ANSWER", "NO DIALTONE", "ABORTED", "+CMS ERROR", "+CME ERROR", "SEND FAIL" }; +/* FreeRTOS Cellular Common Library porting interface. */ +/* coverity[misra_c_2012_rule_8_7_violation] */ +uint32_t CellularSrcTokenErrorTableSize = sizeof( CellularSrcTokenErrorTable ) / sizeof( char * ); + +/* FreeRTOS Cellular Common Library porting interface. */ +/* coverity[misra_c_2012_rule_8_7_violation] */ +const char * CellularSrcTokenSuccessTable[] = +{ "OK", "@" }; +/* FreeRTOS Cellular Common Library porting interface. */ +/* coverity[misra_c_2012_rule_8_7_violation] */ +uint32_t CellularSrcTokenSuccessTableSize = sizeof( CellularSrcTokenSuccessTable ) / sizeof( char * ); + +/* FreeRTOS Cellular Common Library porting interface. */ +/* coverity[misra_c_2012_rule_8_7_violation] */ +const char * CellularUrcTokenWoPrefixTable[] = +{ "RDY" }; +/* FreeRTOS Cellular Common Library porting interface. */ +/* coverity[misra_c_2012_rule_8_7_violation] */ +uint32_t CellularUrcTokenWoPrefixTableSize = sizeof( CellularUrcTokenWoPrefixTable ) / sizeof( char * ); + +/*-----------------------------------------------------------*/ + +static CellularError_t sendAtCommandWithRetryTimeout( CellularContext_t * pContext, + const CellularAtReq_t * pAtReq ) +{ + CellularError_t cellularStatus = CELLULAR_SUCCESS; + CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_OK; + uint8_t tryCount = 0; + + if( pAtReq == NULL ) + { + cellularStatus = CELLULAR_BAD_PARAMETER; + } + else + { + for( ; tryCount < ENBABLE_MODULE_UE_RETRY_COUNT; tryCount++ ) + { + pktStatus = _Cellular_TimeoutAtcmdRequestWithCallback( pContext, *pAtReq, ENBABLE_MODULE_UE_RETRY_TIMEOUT ); + cellularStatus = _Cellular_TranslatePktStatus( pktStatus ); + + if( cellularStatus == CELLULAR_SUCCESS ) + { + break; + } + } + } + + return cellularStatus; +} + +/*-----------------------------------------------------------*/ + +/* FreeRTOS Cellular Common Library porting interface. */ +/* coverity[misra_c_2012_rule_8_7_violation] */ +CellularError_t Cellular_ModuleInit( const CellularContext_t * pContext, + void ** ppModuleContext ) +{ + CellularError_t cellularStatus = CELLULAR_SUCCESS; + uint32_t i = 0; + + if( pContext == NULL ) + { + cellularStatus = CELLULAR_INVALID_HANDLE; + } + else if( ppModuleContext == NULL ) + { + cellularStatus = CELLULAR_BAD_PARAMETER; + } + else + { + /* Initialize the module context. */ + ( void ) memset( &cellularHl7802Context, 0, sizeof( cellularModuleContext_t ) ); + + for( i = 0; i < TCP_SESSION_TABLE_LEGNTH; i++ ) + { + cellularHl7802Context.pSessionMap[ i ] = INVALID_SOCKET_INDEX; + } + + *ppModuleContext = ( void * ) &cellularHl7802Context; + } + + return cellularStatus; +} + +/*-----------------------------------------------------------*/ + +/* FreeRTOS Cellular Common Library porting interface. */ +/* coverity[misra_c_2012_rule_8_7_violation] */ +CellularError_t Cellular_ModuleCleanUp( const CellularContext_t * pContext ) +{ + CellularError_t cellularStatus = CELLULAR_SUCCESS; + + if( pContext == NULL ) + { + cellularStatus = CELLULAR_INVALID_HANDLE; + } + + return cellularStatus; +} + +/*-----------------------------------------------------------*/ + +/* Parse AT response for current MNO profile */ +static CellularPktStatus_t _Cellular_RecvFuncGetCurrentMNOProfile( CellularContext_t * pContext, + const CellularATCommandResponse_t * pAtResp, + void * pData, + uint16_t dataLen ) +{ + char * pInputLine = NULL; + CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_OK; + CellularATError_t atCoreStatus = CELLULAR_AT_SUCCESS; + MNOProfileType_t * pCurrentMNOProfile = ( MNOProfileType_t * ) pData; + char * pToken = NULL; + int32_t tempValue = 0; + + if( pContext == NULL ) + { + LogError( ( "_Cellular_RecvFuncGetCurrentMNOProfile: Invalid handle" ) ); + pktStatus = CELLULAR_PKT_STATUS_INVALID_HANDLE; + } + else if( ( pData == NULL ) || ( dataLen != sizeof( MNOProfileType_t ) ) ) + { + LogError( ( "_Cellular_RecvFuncGetCurrentMNOProfile: Invalid param" ) ); + pktStatus = CELLULAR_PKT_STATUS_BAD_PARAM; + } + else if( ( pAtResp == NULL ) || ( pAtResp->pItm == NULL ) || ( pAtResp->pItm->pLine == NULL ) ) + { + LogError( ( "_Cellular_RecvFuncGetCurrentMNOProfile: Input Line passed is NULL" ) ); + pktStatus = CELLULAR_PKT_STATUS_FAILURE; + } + else + { + pInputLine = pAtResp->pItm->pLine; + + /* Remove prefix. */ + atCoreStatus = Cellular_ATRemovePrefix( &pInputLine ); + + /* Remove leading space. */ + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + atCoreStatus = Cellular_ATRemoveLeadingWhiteSpaces( &pInputLine ); + } + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + atCoreStatus = Cellular_ATGetNextTok( &pInputLine, &pToken ); + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + atCoreStatus = Cellular_ATStrtoi( pToken, 10, &tempValue ); + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + if( ( tempValue >= MNO_PROFILE_SW_DEFAULT ) && ( tempValue <= MNO_PROFILE_STANDARD_EUROPE ) ) + { + *pCurrentMNOProfile = tempValue; + LogInfo( ( "_Cellular_RecvFuncGetCurrentMNOProfile: pCurrentMNOProfile [%d]", *pCurrentMNOProfile ) ); + } + } + else + { + atCoreStatus = CELLULAR_AT_ERROR; + } + } + } + + pktStatus = _Cellular_TranslateAtCoreStatus( atCoreStatus ); + } + + return pktStatus; +} + +/*-----------------------------------------------------------*/ +/* Get modem's current MNO profile */ +static CellularError_t _Cellular_GetCurrentMNOProfile( CellularContext_t * pContext, + MNOProfileType_t * pCurrentMNOProfile ) +{ + CellularError_t cellularStatus = CELLULAR_SUCCESS; + CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_OK; + CellularAtReq_t atReqGetCurrentMNOProfile = + { + "AT+UMNOPROF?", + CELLULAR_AT_WITH_PREFIX, + "+UMNOPROF", + _Cellular_RecvFuncGetCurrentMNOProfile, + NULL, + sizeof( MNOProfileType_t ), + }; + + atReqGetCurrentMNOProfile.pData = pCurrentMNOProfile; + + /* Internal function. Callee check parameters. */ + pktStatus = _Cellular_AtcmdRequestWithCallback( pContext, atReqGetCurrentMNOProfile ); + cellularStatus = _Cellular_TranslatePktStatus( pktStatus ); + + return cellularStatus; +} + +/*-----------------------------------------------------------*/ + +/* Reboot modem and wait for ready state. */ + +CellularError_t rebootCellularModem( CellularContext_t * pContext, + bool disablePsm, + bool disableEidrx ) +{ + CellularError_t cellularStatus = CELLULAR_SUCCESS; + CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_OK; + uint32_t count = 0; + + CellularAtReq_t atReqGetNoResult = + { + "AT+CFUN=15", + CELLULAR_AT_NO_RESULT, + NULL, + NULL, + NULL, + 0 + }; + + LogInfo( ( "rebootCellularModem: Rebooting Modem." ) ); + cellularStatus = sendAtCommandWithRetryTimeout( pContext, &atReqGetNoResult ); + Platform_Delay( ENBABLE_MODULE_UE_REBOOT_POLL_TIME ); + count = count + ENBABLE_MODULE_UE_REBOOT_POLL_TIME; + + /* wait for modem after reboot*/ + while( count < ENBABLE_MODULE_UE_REBOOT_MAX_TIME ) + { + LogInfo( ( "rebootCellularModem: Use ATE0 command to test modem status." ) ); + + atReqGetNoResult.pAtCmd = "ATE0"; + + pktStatus = _Cellular_TimeoutAtcmdRequestWithCallback( pContext, atReqGetNoResult, ENBABLE_MODULE_UE_REBOOT_POLL_TIME ); + cellularStatus = _Cellular_TranslatePktStatus( pktStatus ); + + if( cellularStatus == CELLULAR_SUCCESS ) + { + LogInfo( ( "rebootCellularModem: Modem is now available." ) ); + + Platform_Delay( ENBABLE_MODULE_UE_REBOOT_POLL_TIME * 3 ); + + /* Query current PSM settings. */ + atReqGetNoResult.pAtCmd = "AT+CPSMS?"; + cellularStatus = sendAtCommandWithRetryTimeout( pContext, &atReqGetNoResult ); + + if( disablePsm && ( cellularStatus == CELLULAR_SUCCESS ) ) + { + LogInfo( ( "rebootCellularModem: Disable +CPSMS setting." ) ); + atReqGetNoResult.pAtCmd = "AT+CPSMS=0"; + cellularStatus = sendAtCommandWithRetryTimeout( pContext, &atReqGetNoResult ); + } + + if( disableEidrx && ( cellularStatus == CELLULAR_SUCCESS ) ) + { + LogInfo( ( "rebootCellularModem: Disable +CEDRXS setting." ) ); + atReqGetNoResult.pAtCmd = "AT+CEDRXS=0,4"; + cellularStatus = sendAtCommandWithRetryTimeout( pContext, &atReqGetNoResult ); + } + + break; + } + else + { + LogWarn( ( "rebootCellularModem: Modem is not ready. Retry sending ATE0." ) ); + } + + count = count + ENBABLE_MODULE_UE_REBOOT_POLL_TIME; + } + + return cellularStatus; +} + +/*-----------------------------------------------------------*/ + +/* FreeRTOS Cellular Common Library porting interface. */ +/* coverity[misra_c_2012_rule_8_7_violation] */ +CellularError_t Cellular_ModuleEnableUE( CellularContext_t * pContext ) +{ + CellularError_t cellularStatus = CELLULAR_SUCCESS; + CellularAtReq_t atReqGetNoResult = + { + NULL, + CELLULAR_AT_NO_RESULT, + NULL, + NULL, + NULL, + 0 + }; + CellularAtReq_t atReqGetWithResult = + { + NULL, + CELLULAR_AT_WO_PREFIX, + NULL, + NULL, + NULL, + 0 + }; + char pAtCmdBuf[ CELLULAR_AT_CMD_MAX_SIZE ] = { 0 }; + + if( pContext != NULL ) + { + /* Disable echo. */ + atReqGetWithResult.pAtCmd = "ATE0"; + cellularStatus = sendAtCommandWithRetryTimeout( pContext, &atReqGetWithResult ); + + if( cellularStatus == CELLULAR_SUCCESS ) + { + /* Disable DTR function. */ + atReqGetNoResult.pAtCmd = "AT&D0"; + cellularStatus = sendAtCommandWithRetryTimeout( pContext, &atReqGetNoResult ); + } + + #ifndef CELLULAR_CONFIG_DISABLE_FLOW_CONTROL + if( cellularStatus == CELLULAR_SUCCESS ) + { + /* Enable RTS/CTS hardware flow control. */ + atReqGetNoResult.pAtCmd = "AT+IFC=2,2"; + cellularStatus = sendAtCommandWithRetryTimeout( pContext, &atReqGetNoResult ); + } + #endif + + if( cellularStatus == CELLULAR_SUCCESS ) + { + /* Report verbose mobile termination error. */ + atReqGetNoResult.pAtCmd = "AT+CMEE=2"; + cellularStatus = sendAtCommandWithRetryTimeout( pContext, &atReqGetNoResult ); + } + + if( cellularStatus == CELLULAR_SUCCESS ) + { + /* Setup mobile network operator profiles. */ + /* Setting +UMNOPROF profile will automatically select suitable values for +URAT and +UBANDMASK. */ + + /* Check current MNO profile first to avoid unneccessary modem reboot. */ + MNOProfileType_t currentMNOProfile = MNO_PROFILE_NOT_SET; + cellularStatus = _Cellular_GetCurrentMNOProfile( pContext, ¤tMNOProfile ); + + LogInfo( ( "Cellular_ModuleEnableUE: currentMNOProfile = [%d], desiredProfile = [%d]", currentMNOProfile, CELLULAR_CONFIG_SARA_R4_SET_MNO_PROFILE ) ); + + if( cellularStatus == CELLULAR_SUCCESS ) + { + /* Set MNO profile if not set already */ + if( ( currentMNOProfile != CELLULAR_CONFIG_SARA_R4_SET_MNO_PROFILE ) && ( CELLULAR_CONFIG_SARA_R4_SET_MNO_PROFILE != MNO_PROFILE_NOT_SET ) ) + { + atReqGetNoResult.pAtCmd = pAtCmdBuf; + ( void ) snprintf( ( char * ) atReqGetNoResult.pAtCmd, CELLULAR_AT_CMD_MAX_SIZE, "%s%d", "AT+COPS=2;+UMNOPROF=", CELLULAR_CONFIG_SARA_R4_SET_MNO_PROFILE ); + cellularStatus = sendAtCommandWithRetryTimeout( pContext, &atReqGetNoResult ); + + if( cellularStatus == CELLULAR_SUCCESS ) + { + cellularStatus = rebootCellularModem( pContext, true, true ); + } + } + + #ifdef CELLULAR_CONFIG_SARA_R4_REBOOT_ON_INIT + else + { + cellularStatus = rebootCellularModem( pContext, true, true ); + } + #endif + } + } + + if( cellularStatus == CELLULAR_SUCCESS ) + { + atReqGetNoResult.pAtCmd = "AT+COPS=0"; + cellularStatus = sendAtCommandWithRetryTimeout( pContext, &atReqGetNoResult ); + } + + if( cellularStatus == CELLULAR_SUCCESS ) + { + atReqGetNoResult.pAtCmd = "AT+CFUN=1"; + cellularStatus = sendAtCommandWithRetryTimeout( pContext, &atReqGetNoResult ); + } + } + + return cellularStatus; +} + +/*-----------------------------------------------------------*/ + +/* FreeRTOS Cellular Common Library porting interface. */ +/* coverity[misra_c_2012_rule_8_7_violation] */ +CellularError_t Cellular_ModuleEnableUrc( CellularContext_t * pContext ) +{ + CellularError_t cellularStatus = CELLULAR_SUCCESS; + CellularAtReq_t atReqGetNoResult = + { + NULL, + CELLULAR_AT_NO_RESULT, + NULL, + NULL, + NULL, + 0 + }; + + atReqGetNoResult.pAtCmd = "AT+COPS=3,2"; + ( void ) _Cellular_AtcmdRequestWithCallback( pContext, atReqGetNoResult ); + + atReqGetNoResult.pAtCmd = "AT+CREG=2"; + ( void ) _Cellular_AtcmdRequestWithCallback( pContext, atReqGetNoResult ); + + atReqGetNoResult.pAtCmd = "AT+CGREG=2"; + ( void ) _Cellular_AtcmdRequestWithCallback( pContext, atReqGetNoResult ); + + atReqGetNoResult.pAtCmd = "AT+CEREG=2"; + ( void ) _Cellular_AtcmdRequestWithCallback( pContext, atReqGetNoResult ); + + atReqGetNoResult.pAtCmd = "AT+CTZR=1"; + ( void ) _Cellular_AtcmdRequestWithCallback( pContext, atReqGetNoResult ); + + /* TODO: +CGEV URC enable. */ + /* atReqGetNoResult.pAtCmd = "AT+CGEREP=2,0"; */ + /* (void)_Cellular_AtcmdRequestWithCallback(pContext, atReqGetNoResult); */ + + /* Power saving mode URC enable. */ + atReqGetNoResult.pAtCmd = "AT+UPSMR=1"; + ( void ) _Cellular_AtcmdRequestWithCallback( pContext, atReqGetNoResult ); + + /* Mobile termination event reporting +CIEV URC enable. */ + atReqGetNoResult.pAtCmd = "AT+CMER=1,0,0,2,1"; + ( void ) _Cellular_AtcmdRequestWithCallback( pContext, atReqGetNoResult ); + + /* Enable signal level change indication via +CIEV URC. (To enable all indications, set to 4095) */ + atReqGetNoResult.pAtCmd = "AT+UCIND=2"; + ( void ) _Cellular_AtcmdRequestWithCallback( pContext, atReqGetNoResult ); + + /* Enable greeting message "RDY" on modem bootup. */ + atReqGetNoResult.pAtCmd = "AT+CSGT=1,\"RDY\""; + ( void ) _Cellular_AtcmdRequestWithCallback( pContext, atReqGetNoResult ); + + return cellularStatus; +} + +/*-----------------------------------------------------------*/ + +uint32_t _Cellular_GetSocketId( CellularContext_t * pContext, + uint8_t sessionId ) +{ + cellularModuleContext_t * pModuleContext = NULL; + uint32_t socketIndex = INVALID_SOCKET_INDEX; + CellularError_t cellularStatus = CELLULAR_SUCCESS; + + if( pContext != NULL ) + { + cellularStatus = _Cellular_GetModuleContext( pContext, ( void ** ) &pModuleContext ); + } + else + { + cellularStatus = CELLULAR_BAD_PARAMETER; + } + + if( ( cellularStatus == CELLULAR_SUCCESS ) && ( sessionId <= ( ( uint8_t ) MAX_TCP_SESSION_ID ) ) ) + { + socketIndex = pModuleContext->pSessionMap[ sessionId ]; + } + + return socketIndex; +} + +/*-----------------------------------------------------------*/ + +uint32_t _Cellular_GetSessionId( CellularContext_t * pContext, + uint32_t socketIndex ) +{ + cellularModuleContext_t * pModuleContext = NULL; + CellularError_t cellularStatus = CELLULAR_SUCCESS; + uint32_t sessionId = INVALID_SESSION_ID; + + if( pContext == NULL ) + { + LogError( ( "_Cellular_GetSessionId invalid cellular context" ) ); + cellularStatus = CELLULAR_BAD_PARAMETER; + } + else if( socketIndex == INVALID_SOCKET_INDEX ) + { + LogError( ( "_Cellular_GetSessionId invalid socketIndex" ) ); + cellularStatus = CELLULAR_BAD_PARAMETER; + } + else + { + cellularStatus = _Cellular_GetModuleContext( pContext, ( void ** ) &pModuleContext ); + } + + if( cellularStatus == CELLULAR_SUCCESS ) + { + for( sessionId = 0; sessionId < TCP_SESSION_TABLE_LEGNTH; sessionId++ ) + { + if( pModuleContext->pSessionMap[ sessionId ] == socketIndex ) + { + break; + } + } + + /* Mapping is not found in the session mapping table. */ + if( sessionId == TCP_SESSION_TABLE_LEGNTH ) + { + sessionId = INVALID_SESSION_ID; + } + } + else + { + sessionId = INVALID_SESSION_ID; + } + + return sessionId; +} diff --git a/source/cellular_r4.h b/source/cellular_r4.h new file mode 100644 index 0000000..b5640cb --- /dev/null +++ b/source/cellular_r4.h @@ -0,0 +1,164 @@ +/* + * FreeRTOS-Cellular-Interface v1.3.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 + */ + +#ifndef __CELLULAR_R4_H__ +#define __CELLULAR_R4_H__ + +/* *INDENT-OFF* */ +#ifdef __cplusplus + extern "C" { +#endif +/* *INDENT-ON* */ + +/*-----------------------------------------------------------*/ + +#define MIN_TCP_SESSION_ID ( 0 ) +#define MAX_TCP_SESSION_ID ( 6 ) +#define TCP_SESSION_TABLE_LEGNTH ( MAX_TCP_SESSION_ID + 1 ) + +#define INVALID_SOCKET_INDEX ( UINT32_MAX ) +#define INVALID_SESSION_ID ( UINT32_MAX ) + +/*-----------------------------------------------------------*/ + +typedef struct cellularModuleContext +{ + uint32_t pSessionMap[ TCP_SESSION_TABLE_LEGNTH ]; +} cellularModuleContext_t; + +/*-----------------------------------------------------------*/ + +uint32_t _Cellular_GetSocketId( CellularContext_t * pContext, + uint8_t sessionId ); + +uint32_t _Cellular_GetSessionId( CellularContext_t * pContext, + uint32_t socketIndex ); + +CellularError_t rebootCellularModem( CellularContext_t * pContext, + bool disablePsm, + bool disableEidrx ); + +/*-----------------------------------------------------------*/ + +/** + * @brief Cellular MNO profiles. + */ +typedef enum MNOProfileType +{ + MNO_PROFILE_SW_DEFAULT = 0, + MNO_PROFILE_SIM_ICCID_IMSI_SELECT = 1, + MNO_PROFILE_ATT = 2, + MNO_PROFILE_VERIZON = 3, + MNO_PROFILE_TELSTRA = 4, + MNO_PROFILE_TMOBILE = 5, + MNO_PROFILE_CHINA_TELECOM = 6, + MNO_PROFILE_SPRINT = 8, + MNO_PROFILE_VODAFONE = 19, + MNO_PROFILE_GLOBAL = 90, + MNO_PROFILE_STANDARD_EUROPE = 100, + MNO_PROFILE_NOT_SET = 999 +} MNOProfileType_t; + +/*-----------------------------------------------------------*/ + +/* Select network MNO profile. Default value is MNO_PROFILE_NOT_SET */ +#ifndef CELLULAR_CONFIG_SARA_R4_SET_MNO_PROFILE + #define CELLULAR_CONFIG_SARA_R4_SET_MNO_PROFILE ( MNO_PROFILE_NOT_SET ) +#endif + +/* + * By default socket is closed in normal mode i.e. flag is 0. + * In normal mode, +USOCL can take time to close socket (Max timeout is 120 sec). + * To avoid wait, socket can be closed in async mode via flag. + * In mode, socket close will be notified via +UUSOCL URC. + * Drawback of mode is that if try to deactivate context (e.g. AT+CGACT=0,1). + * prior to socket close URC, AT command will result in ERROR. + */ +#define CELLULAR_CONFIG_SET_SOCKET_CLOSE_ASYNC_MODE ( 0U ) + +/*-----------------------------------------------------------*/ + +/* MAX valid PDP contexts */ +#define MAX_PDP_CONTEXTS ( 4U ) + +#define DEFAULT_BEARER_CONTEXT_ID ( 1U ) /* SARA-R4 default bearer context */ + +#define CELULAR_PDN_CONTEXT_TYPE_MAX_SIZE ( 7U ) /* The length of IP type e.g. IPV4V6. */ + +/*-----------------------------------------------------------*/ + +/* +CGDCONT PDN context definition tokens */ +#define CELLULAR_PDN_STATUS_POS_CONTEXT_ID ( 0U ) +#define CELLULAR_PDN_STATUS_POS_CONTEXT_TYPE ( 1U ) +#define CELLULAR_PDN_STATUS_POS_APN_NAME ( 2U ) +#define CELLULAR_PDN_STATUS_POS_IP_ADDRESS ( 3U ) + +/* +CGACT PDN context activation tokens */ +#define CELLULAR_PDN_ACT_STATUS_POS_CONTEXT_ID ( 0U ) +#define CELLULAR_PDN_ACT_STATUS_POS_CONTEXT_STATE ( 1U ) + +/** + * @brief Context info from +CGDCONT (Context IP type, APN name, IP Address) + */ +typedef struct CellularPdnContextInfo +{ + bool contextsPresent[ MAX_PDP_CONTEXTS ]; /**< Context present in +CGDCONT response or not. */ + char ipType[ MAX_PDP_CONTEXTS ][ CELULAR_PDN_CONTEXT_TYPE_MAX_SIZE ]; /**< PDN Context type. */ + char apnName[ MAX_PDP_CONTEXTS ][ CELLULAR_APN_MAX_SIZE ]; /**< APN name. */ + char ipAddress[ MAX_PDP_CONTEXTS ][ CELLULAR_IP_ADDRESS_MAX_SIZE ]; /**< IP address. */ +} CellularPdnContextInfo_t; + +/** + * @brief Context state from +CGACT + */ +typedef struct CellularPdnContextActInfo +{ + bool contextsPresent[ MAX_PDP_CONTEXTS ]; /**< Context present in +CGACT response or not. */ + bool contextActState[ MAX_PDP_CONTEXTS ]; /**< Context active state from +CGACT response. */ +} CellularPdnContextActInfo_t; + +/*-----------------------------------------------------------*/ + +extern CellularAtParseTokenMap_t CellularUrcHandlerTable[]; +extern uint32_t CellularUrcHandlerTableSize; + +extern const char * CellularSrcTokenErrorTable[]; +extern uint32_t CellularSrcTokenErrorTableSize; + +extern const char * CellularSrcTokenSuccessTable[]; +extern uint32_t CellularSrcTokenSuccessTableSize; + +extern const char * CellularUrcTokenWoPrefixTable[]; +extern uint32_t CellularUrcTokenWoPrefixTableSize; + +/*-----------------------------------------------------------*/ + +/* *INDENT-OFF* */ +#ifdef __cplusplus + } +#endif +/* *INDENT-ON* */ + +#endif /* ifndef __CELLULAR_R4_H__ */ diff --git a/source/cellular_r4_api.c b/source/cellular_r4_api.c new file mode 100644 index 0000000..741d0ae --- /dev/null +++ b/source/cellular_r4_api.c @@ -0,0 +1,2906 @@ +/* + * FreeRTOS-Cellular-Interface v1.3.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 + */ +#include "cellular_config.h" +#include "cellular_config_defaults.h" + +/* Standard includes. */ +#include +#include +#include + +/* Cellular includes. */ +#include "cellular_platform.h" +#include "cellular_types.h" +#include "cellular_api.h" +#include "cellular_common_api.h" +#include "cellular_common.h" +#include "cellular_at_core.h" + +/* Cellular module incliudes. */ +#include "cellular_r4.h" + +/*-----------------------------------------------------------*/ + +/* TODO : confirm the value. */ +#define PDN_ACT_PACKET_REQ_TIMEOUT_MS ( 150000UL ) + +#define PDN_DEACT_PACKET_REQ_TIMEOUT_MS ( 40000UL ) + +#define GPRS_ATTACH_REQ_TIMEOUT_MS ( 180000UL ) + +#define DNS_QUERY_REQ_TIMEOUT_MS ( 120000UL ) + +#define SOCKET_CLOSE_PACKET_REQ_TIMEOUT_MS ( 120000U ) + +#define SOCKET_CONNECT_PACKET_REQ_TIMEOUT_MS ( 120000U ) + +#define CELLULAR_AT_CMD_TYPICAL_MAX_SIZE ( 32U ) + +#define DATA_SEND_TIMEOUT_MS ( 10000U ) + +#define PACKET_REQ_TIMEOUT_MS ( 10000U ) + +#define DATA_READ_TIMEOUT_MS ( 50000UL ) + +#define SOCKET_DATA_PREFIX_TOKEN "+USORD: " +#define SOCKET_DATA_PREFIX_TOKEN_LEN ( 8U ) +#define SOCKET_DATA_PREFIX_STRING_LENGTH ( SOCKET_DATA_PREFIX_TOKEN_LEN + 9U ) +#define RAT_PRIOIRTY_LIST_LENGTH ( 3U ) + +/** + * @brief Parameters involved in receiving data through sockets + */ +typedef struct _socketDataRecv +{ + uint32_t * pDataLen; + uint8_t * pData; +} _socketDataRecv_t; + +/*-----------------------------------------------------------*/ + +static CellularPktStatus_t socketRecvDataPrefix( void * pCallbackContext, + char * pLine, + uint32_t lineLength, + char ** ppDataStart, + uint32_t * pDataLength ); +static CellularATError_t getDataFromResp( const CellularATCommandResponse_t * pAtResp, + const _socketDataRecv_t * pDataRecv, + uint32_t outBufSize ); +static CellularPktStatus_t _Cellular_RecvFuncData( CellularContext_t * pContext, + const CellularATCommandResponse_t * pAtResp, + void * pData, + uint16_t dataLen ); +static CellularError_t storeAccessModeAndAddress( CellularContext_t * pContext, + CellularSocketHandle_t socketHandle, + CellularSocketAccessMode_t dataAccessMode, + const CellularSocketAddress_t * pRemoteSocketAddress ); +static CellularPktStatus_t _Cellular_RecvFuncGetSocketId( CellularContext_t * pContext, + const CellularATCommandResponse_t * pAtResp, + void * pData, + uint16_t dataLen ); +static CellularError_t _Cellular_GetSocketNumber( CellularHandle_t cellularHandle, + CellularSocketHandle_t socketHandle, + uint8_t * pSessionId ); + +CellularError_t Cellular_SetPdnConfig( CellularHandle_t cellularHandle, + uint8_t contextId, + const CellularPdnConfig_t * pPdnConfig ); + +static CellularError_t _Cellular_GetPacketSwitchStatus( CellularHandle_t cellularHandle, + bool * pPacketSwitchStatus ); + +static CellularError_t _Cellular_GetContextActivationStatus( CellularHandle_t cellularHandle, + CellularPdnContextActInfo_t * pPdpContextsActInfo ); + +static bool _parseExtendedSignalQuality( char * pQcsqPayload, + CellularSignalInfo_t * pSignalInfo ); +static bool _parseSignalQuality( char * pQcsqPayload, + CellularSignalInfo_t * pSignalInfo ); +static CellularPktStatus_t _Cellular_RecvFuncGetSignalInfo( CellularContext_t * pContext, + const CellularATCommandResponse_t * pAtResp, + void * pData, + uint16_t dataLen ); +static CellularError_t controlSignalStrengthIndication( CellularContext_t * pContext, + bool enable ); + +CellularError_t Cellular_SetPsmSettings( CellularHandle_t cellularHandle, + const CellularPsmSettings_t * pPsmSettings ); + +static CellularError_t _Cellular_isSockOptSupport( CellularSocketOptionLevel_t optionLevel, + CellularSocketOption_t option ); + +/*-----------------------------------------------------------*/ + +static CellularPktStatus_t socketRecvDataPrefix( void * pCallbackContext, + char * pLine, + uint32_t lineLength, + char ** ppDataStart, + uint32_t * pDataLength ) +{ + char * pToken = NULL; + int32_t tempValue = 0; + CellularATError_t atResult = CELLULAR_AT_SUCCESS; + CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_OK; + char pLocalLine[ SOCKET_DATA_PREFIX_STRING_LENGTH + 1 ] = { '\0' }; + char * pDataStart = pLocalLine; + + ( void ) lineLength; + + /* pCallbackContext is not used in this function. It should be NULL. */ + if( ( pLine == NULL ) || ( ppDataStart == NULL ) || ( pDataLength == NULL ) || ( pCallbackContext != NULL ) ) + { + LogError( ( "socketRecvData: Bad parameters" ) ); + pktStatus = CELLULAR_PKT_STATUS_BAD_PARAM; + } + else if( strncmp( pLine, SOCKET_DATA_PREFIX_TOKEN, SOCKET_DATA_PREFIX_TOKEN_LEN ) != 0 ) + { + /* Prefix string which is not SOCKET_DATA_PREFIX_TOKEN does't indicate data start. + * Set data length to 0.*/ + *ppDataStart = NULL; + *pDataLength = 0; + } + else + { + /* The string length of "+USORD: [,],"". */ + strncpy( pLocalLine, pLine, SOCKET_DATA_PREFIX_STRING_LENGTH ); + pDataStart = &pLocalLine[ SOCKET_DATA_PREFIX_TOKEN_LEN ]; + + /* Skip the socket number. */ + atResult = Cellular_ATGetNextTok( &pDataStart, &pToken ); + + /* Parse the receive data length. */ + if( ( atResult == CELLULAR_AT_SUCCESS ) && ( pDataStart[ 0 ] == '"' ) ) + { + /* Peek the next symbol. If it is \", then length is ommited. Received byte is 0. */ + LogDebug( ( "socketRecvData: 0 received bytes." ) ); + *pDataLength = 0U; + *ppDataStart = NULL; + } + else if( atResult == CELLULAR_AT_SUCCESS ) + { + /* Parse the length. */ + atResult = Cellular_ATGetNextTok( &pDataStart, &pToken ); + + if( atResult == CELLULAR_AT_SUCCESS ) + { + atResult = Cellular_ATStrtoi( pToken, 10, &tempValue ); + + if( ( tempValue < 0 ) && ( ( uint32_t ) tempValue > CELLULAR_MAX_RECV_DATA_LEN ) ) + { + LogError( ( "socketRecvData: Bad parameters" ) ); + atResult = CELLULAR_AT_ERROR; + } + } + + if( atResult == CELLULAR_AT_SUCCESS ) + { + /* Change +USROD: ,," to +USROD: ,,\r. */ + pDataStart = &pLine[ pDataStart - pLocalLine ]; + + if( pDataStart[ 0 ] == '\"' ) + { + *pDataStart = '\r'; + *ppDataStart = ( char * ) &pDataStart[ 1 ]; + *pDataLength = ( uint32_t ) tempValue; + } + } + } + else + { + LogDebug( ( "socketRecvDataPrefix : pLine [%s] with lineLength [%d] is not data prefix", pLine, lineLength ) ); + } + } + + return pktStatus; +} + +/*-----------------------------------------------------------*/ + +static CellularATError_t getDataFromResp( const CellularATCommandResponse_t * pAtResp, + const _socketDataRecv_t * pDataRecv, + uint32_t outBufSize ) +{ + CellularATError_t atCoreStatus = CELLULAR_AT_SUCCESS; + const char * pInputLine = NULL; + uint32_t dataLenToCopy = 0; + + /* Check if the received data size is greater than the output buffer size. */ + if( *pDataRecv->pDataLen > outBufSize ) + { + LogError( ( "Data is turncated, received data length %u, out buffer size %u", + *pDataRecv->pDataLen, outBufSize ) ); + dataLenToCopy = outBufSize; + *pDataRecv->pDataLen = outBufSize; + } + else + { + dataLenToCopy = *pDataRecv->pDataLen; + } + + /* Data is stored in the next intermediate response. */ + pInputLine = pAtResp->pItm->pNext->pLine; + + if( ( pInputLine != NULL ) && ( dataLenToCopy > 0U ) ) + { + /* Copy the data to the out buffer. */ + ( void ) memcpy( ( void * ) pDataRecv->pData, ( const void * ) pInputLine, dataLenToCopy ); + } + else + { + LogError( ( "Receive Data: paramerter error, data pointer %p, data to copy %u", + pInputLine, dataLenToCopy ) ); + atCoreStatus = CELLULAR_AT_BAD_PARAMETER; + } + + return atCoreStatus; +} + +/*-----------------------------------------------------------*/ + +/* FreeRTOS Cellular Library types. */ +/* coverity[misra_c_2012_rule_8_13_violation] */ +static CellularPktStatus_t _Cellular_RecvFuncData( CellularContext_t * pContext, + const CellularATCommandResponse_t * pAtResp, + void * pData, + uint16_t dataLen ) +{ + CellularATError_t atCoreStatus = CELLULAR_AT_SUCCESS; + CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_OK; + char * pInputLine = NULL, * pToken = NULL; + const _socketDataRecv_t * pDataRecv = ( _socketDataRecv_t * ) pData; + int32_t tempValue = 0; + + if( pContext == NULL ) + { + LogError( ( "Receive Data: invalid context" ) ); + pktStatus = CELLULAR_PKT_STATUS_FAILURE; + } + else if( ( pAtResp == NULL ) || ( pAtResp->pItm == NULL ) || ( pAtResp->pItm->pLine == NULL ) ) + { + LogError( ( "Receive Data: response is invalid" ) ); + pktStatus = CELLULAR_PKT_STATUS_FAILURE; + } + else if( ( pDataRecv == NULL ) || ( pDataRecv->pData == NULL ) || ( pDataRecv->pDataLen == NULL ) ) + { + LogError( ( "Receive Data: Bad parameters" ) ); + pktStatus = CELLULAR_PKT_STATUS_BAD_PARAM; + } + else + { + pInputLine = pAtResp->pItm->pLine; /* The first item is the data prefix. */ + + /* Check the data prefix token "+USORD: ". */ + if( strncmp( pInputLine, SOCKET_DATA_PREFIX_TOKEN, SOCKET_DATA_PREFIX_TOKEN_LEN ) != 0 ) + { + LogError( ( "response item error in prefix CONNECT" ) ); + atCoreStatus = CELLULAR_AT_ERROR; + } + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + if( pAtResp->pItm->pNext == NULL ) + { + /* Modem return +USORD: 0,"". No data returned since there is no data + * length field in modem response. */ + *pDataRecv->pDataLen = 0; + } + else + { + /* Parse the data length. */ + atCoreStatus = Cellular_ATGetNextTok( &pInputLine, &pToken ); + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + atCoreStatus = Cellular_ATGetNextTok( &pInputLine, &pToken ); + } + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + atCoreStatus = Cellular_ATStrtoi( pToken, 10, &tempValue ); + + if( tempValue >= 0 ) + { + *pDataRecv->pDataLen = ( uint32_t ) tempValue; + } + else + { + atCoreStatus = CELLULAR_AT_ERROR; + } + } + + /* Process the data buffer. Modem may also return +USORD: 0,0,"" with 0 data length. + * Process the data response only when data length is greater than 0. */ + if( ( atCoreStatus == CELLULAR_AT_SUCCESS ) && ( *pDataRecv->pDataLen > 0U ) ) + { + atCoreStatus = getDataFromResp( pAtResp, pDataRecv, dataLen ); + } + } + } + + pktStatus = _Cellular_TranslateAtCoreStatus( atCoreStatus ); + } + + return pktStatus; +} + +/*-----------------------------------------------------------*/ + +static CellularError_t storeAccessModeAndAddress( CellularContext_t * pContext, + CellularSocketHandle_t socketHandle, + CellularSocketAccessMode_t dataAccessMode, + const CellularSocketAddress_t * pRemoteSocketAddress ) +{ + CellularError_t cellularStatus = CELLULAR_SUCCESS; + + /* pContext is checked in _Cellular_CheckLibraryStatus function. */ + cellularStatus = _Cellular_CheckLibraryStatus( pContext ); + + if( cellularStatus != CELLULAR_SUCCESS ) + { + cellularStatus = CELLULAR_INVALID_HANDLE; + } + else if( ( pRemoteSocketAddress == NULL ) || ( socketHandle == NULL ) ) + { + LogDebug( ( "storeAccessModeAndAddress: Invalid socket address" ) ); + cellularStatus = CELLULAR_BAD_PARAMETER; + } + else if( socketHandle->socketState != SOCKETSTATE_ALLOCATED ) + { + LogError( ( "storeAccessModeAndAddress, bad socket state %d", + socketHandle->socketState ) ); + cellularStatus = CELLULAR_INTERNAL_FAILURE; + } + else if( dataAccessMode != CELLULAR_ACCESSMODE_BUFFER ) + { + LogError( ( "storeAccessModeAndAddress, Access mode not supported %d", + dataAccessMode ) ); + cellularStatus = CELLULAR_UNSUPPORTED; + } + else + { + socketHandle->remoteSocketAddress.port = pRemoteSocketAddress->port; + socketHandle->dataMode = dataAccessMode; + socketHandle->remoteSocketAddress.ipAddress.ipAddressType = + pRemoteSocketAddress->ipAddress.ipAddressType; + ( void ) strncpy( socketHandle->remoteSocketAddress.ipAddress.ipAddress, + pRemoteSocketAddress->ipAddress.ipAddress, + CELLULAR_IP_ADDRESS_MAX_SIZE + 1U ); + } + + return cellularStatus; +} + +/*-----------------------------------------------------------*/ + +/* FreeRTOS Cellular Library types. */ +/* coverity[misra_c_2012_rule_8_13_violation] */ +static CellularPktStatus_t _Cellular_RecvFuncGetSocketId( CellularContext_t * pContext, + const CellularATCommandResponse_t * pAtResp, + void * pData, + uint16_t dataLen ) +{ + char * pInputLine = NULL; + uint8_t * pSessionId = pData; + CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_OK; + CellularATError_t atCoreStatus = CELLULAR_AT_SUCCESS; + int32_t tempValue = 0; + + if( pContext == NULL ) + { + LogError( ( "GetSocketId: Invalid handle" ) ); + pktStatus = CELLULAR_PKT_STATUS_INVALID_HANDLE; + } + else if( ( pSessionId == NULL ) || ( dataLen != sizeof( uint8_t ) ) ) + { + LogError( ( "GetSocketId: Bad parameters" ) ); + pktStatus = CELLULAR_PKT_STATUS_BAD_PARAM; + } + else if( ( pAtResp == NULL ) || ( pAtResp->pItm == NULL ) || ( pAtResp->pItm->pLine == NULL ) ) + { + LogError( ( "GetSocketId: Input Line passed is NULL" ) ); + pktStatus = CELLULAR_PKT_STATUS_FAILURE; + } + else + { + pInputLine = pAtResp->pItm->pLine; + atCoreStatus = Cellular_ATRemovePrefix( &pInputLine ); + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + atCoreStatus = Cellular_ATRemoveAllWhiteSpaces( pInputLine ); + } + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + atCoreStatus = Cellular_ATStrtoi( pInputLine, 10, &tempValue ); + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + if( ( tempValue >= MIN_TCP_SESSION_ID ) && ( tempValue <= MAX_TCP_SESSION_ID ) ) + { + *pSessionId = ( uint8_t ) tempValue; + } + else + { + atCoreStatus = CELLULAR_AT_ERROR; + } + } + } + + pktStatus = _Cellular_TranslateAtCoreStatus( atCoreStatus ); + } + + return pktStatus; +} + +/*-----------------------------------------------------------*/ + +static CellularError_t _Cellular_GetSocketNumber( CellularHandle_t cellularHandle, + CellularSocketHandle_t socketHandle, + uint8_t * pSessionId ) +{ + CellularContext_t * pContext = ( CellularContext_t * ) cellularHandle; + CellularError_t cellularStatus = CELLULAR_SUCCESS; + CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_OK; + CellularAtReq_t atReqSocketConnect = + { + "AT+USOCR=6,0", + CELLULAR_AT_WITH_PREFIX, + "+USOCR", + _Cellular_RecvFuncGetSocketId, + NULL, + sizeof( uint8_t ), + }; + + ( void ) socketHandle; + + atReqSocketConnect.pData = pSessionId; + + /* Internal function. Caller checks parameters. */ + + if( cellularStatus == CELLULAR_SUCCESS ) + { + pktStatus = _Cellular_AtcmdRequestWithCallback( pContext, atReqSocketConnect ); + + if( pktStatus != CELLULAR_PKT_STATUS_OK ) + { + LogError( ( "_Cellular_GetSocketNumber: get socekt number failed PktRet: %d", pktStatus ) ); + cellularStatus = _Cellular_TranslatePktStatus( pktStatus ); + } + } + + return cellularStatus; +} + +/*-----------------------------------------------------------*/ + +/* FreeRTOS Cellular Library API. */ +/* coverity[misra_c_2012_rule_8_7_violation] */ +/* coverity[misra_c_2012_rule_8_13_violation] */ +CellularError_t Cellular_SocketRecv( CellularHandle_t cellularHandle, + CellularSocketHandle_t socketHandle, + /* coverity[misra_c_2012_rule_8_13_violation] */ + uint8_t * pBuffer, + uint32_t bufferLength, + /* coverity[misra_c_2012_rule_8_13_violation] */ + uint32_t * pReceivedDataLength ) +{ + CellularContext_t * pContext = ( CellularContext_t * ) cellularHandle; + CellularError_t cellularStatus = CELLULAR_SUCCESS; + CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_OK; + char cmdBuf[ CELLULAR_AT_CMD_TYPICAL_MAX_SIZE ] = { '\0' }; + uint32_t recvTimeout = DATA_READ_TIMEOUT_MS; + uint32_t recvLen = bufferLength; + _socketDataRecv_t dataRecv = { 0 }; + CellularAtReq_t atReqSocketRecv = + { + NULL, + CELLULAR_AT_MULTI_DATA_WO_PREFIX, + "+USORD", + _Cellular_RecvFuncData, + NULL, + 0, + }; + uint32_t sessionId = 0; + + dataRecv.pDataLen = pReceivedDataLength; + dataRecv.pData = pBuffer; + + atReqSocketRecv.pAtCmd = cmdBuf; + atReqSocketRecv.pData = ( void * ) &dataRecv; + atReqSocketRecv.dataLen = bufferLength; + + cellularStatus = _Cellular_CheckLibraryStatus( pContext ); + + if( cellularStatus != CELLULAR_SUCCESS ) + { + LogError( ( "Cellular_SocketRecv: _Cellular_CheckLibraryStatus failed." ) ); + } + else if( socketHandle == NULL ) + { + LogError( ( "Cellular_SocketRecv: Invalid socketHandle." ) ); + cellularStatus = CELLULAR_INVALID_HANDLE; + } + else if( ( pBuffer == NULL ) || ( pReceivedDataLength == NULL ) || ( bufferLength == 0U ) ) + { + LogError( ( "Cellular_SocketRecv: Bad input Param." ) ); + cellularStatus = CELLULAR_BAD_PARAMETER; + } + else if( socketHandle->socketState != SOCKETSTATE_CONNECTED ) + { + /* Check the socket connection state. */ + LogInfo( ( "Cellular_SocketRecv: socket state %d is not connected.", socketHandle->socketState ) ); + + if( ( socketHandle->socketState == SOCKETSTATE_ALLOCATED ) || ( socketHandle->socketState == SOCKETSTATE_CONNECTING ) ) + { + cellularStatus = CELLULAR_SOCKET_NOT_CONNECTED; + } + else + { + cellularStatus = CELLULAR_SOCKET_CLOSED; + } + } + else + { + sessionId = _Cellular_GetSessionId( pContext, socketHandle->socketId ); + + if( sessionId == INVALID_SESSION_ID ) + { + LogError( ( "Cellular_SocketRecv : invalid session ID for socket index %u", + socketHandle->socketId ) ); + cellularStatus = CELLULAR_INVALID_HANDLE; + } + } + + if( cellularStatus == CELLULAR_SUCCESS ) + { + /* Update recvLen to maximum module length. */ + if( CELLULAR_MAX_RECV_DATA_LEN <= bufferLength ) + { + recvLen = ( uint32_t ) CELLULAR_MAX_RECV_DATA_LEN; + } + + /* Update receive timeout to default timeout if not set with setsocketopt. */ + if( recvLen > 0 ) + { + if( socketHandle->recvTimeoutMs != 0U ) + { + recvTimeout = socketHandle->recvTimeoutMs; + } + + /* The return value of snprintf is not used. + * The max length of the string is fixed and checked offline. */ + /* coverity[misra_c_2012_rule_21_6_violation]. */ + ( void ) snprintf( cmdBuf, CELLULAR_AT_CMD_TYPICAL_MAX_SIZE, + "%s%u,%u", "AT+USORD=", sessionId, recvLen ); + pktStatus = _Cellular_TimeoutAtcmdDataRecvRequestWithCallback( pContext, + atReqSocketRecv, + recvTimeout, + socketRecvDataPrefix, + NULL ); + + if( pktStatus != CELLULAR_PKT_STATUS_OK ) + { + /* Reset data handling parameters. */ + LogError( ( "Cellular_SocketRecv: Data Receive fail, pktStatus: %d", pktStatus ) ); + cellularStatus = _Cellular_TranslatePktStatus( pktStatus ); + } + } + } + + return cellularStatus; +} + +/*-----------------------------------------------------------*/ + +static CellularPktStatus_t socketSendDataPrefix( void * pCallbackContext, + char * pLine, + uint32_t * pBytesRead ) +{ + CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_OK; + + if( ( pLine == NULL ) || ( pBytesRead == NULL ) ) + { + LogError( ( "socketSendDataPrefix: pLine is invalid or pBytesRead is invalid" ) ); + pktStatus = CELLULAR_PKT_STATUS_BAD_PARAM; + } + else if( pCallbackContext != NULL ) + { + LogError( ( "socketSendDataPrefix: pCallbackContext is not NULL" ) ); + pktStatus = CELLULAR_PKT_STATUS_BAD_PARAM; + } + else if( *pBytesRead != 1U ) + { + LogDebug( ( "socketSendDataPrefix: pBytesRead %u %s is not 1", *pBytesRead, pLine ) ); + } + else + { + /* After the data prefix, there should not be any data in stream. + * Cellular commmon processes AT command in lines. Add a '\0' after '@'. */ + if( strcmp( pLine, "@" ) == 0 ) + { + pLine[ 1 ] = '\n'; + *pBytesRead = 2; + } + } + + return pktStatus; +} + +/*-----------------------------------------------------------*/ + +/* FreeRTOS Cellular Library API. */ +/* coverity[misra_c_2012_rule_8_7_violation] */ +/* coverity[misra_c_2012_rule_8_13_violation] */ +CellularError_t Cellular_SocketSend( CellularHandle_t cellularHandle, + CellularSocketHandle_t socketHandle, + const uint8_t * pData, + uint32_t dataLength, + /* coverity[misra_c_2012_rule_8_13_violation] */ + uint32_t * pSentDataLength ) +{ + CellularContext_t * pContext = ( CellularContext_t * ) cellularHandle; + CellularError_t cellularStatus = CELLULAR_SUCCESS; + CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_OK; + uint32_t sendTimeout = DATA_SEND_TIMEOUT_MS; + char cmdBuf[ CELLULAR_AT_CMD_TYPICAL_MAX_SIZE ] = { '\0' }; + CellularAtReq_t atReqSocketSend = { 0 }; + CellularAtDataReq_t atDataReqSocketSend = { 0 }; + uint32_t sessionId = 0; + + atReqSocketSend.atCmdType = CELLULAR_AT_NO_RESULT; + atReqSocketSend.pAtCmd = cmdBuf; + + atDataReqSocketSend.pData = pData; + atDataReqSocketSend.dataLen = dataLength; + atDataReqSocketSend.pSentDataLength = pSentDataLength; + + /* pContext is checked in _Cellular_CheckLibraryStatus function. */ + cellularStatus = _Cellular_CheckLibraryStatus( pContext ); + + if( cellularStatus != CELLULAR_SUCCESS ) + { + LogDebug( ( "Cellular_SocketSend: _Cellular_CheckLibraryStatus failed" ) ); + } + else if( socketHandle == NULL ) + { + cellularStatus = CELLULAR_INVALID_HANDLE; + } + else if( ( pData == NULL ) || ( pSentDataLength == NULL ) || ( dataLength == 0U ) ) + { + LogDebug( ( "Cellular_SocketSend: Invalid parameter" ) ); + cellularStatus = CELLULAR_BAD_PARAMETER; + } + else if( socketHandle->socketState != SOCKETSTATE_CONNECTED ) + { + /* Check the socket connection state. */ + LogInfo( ( "Cellular_SocketSend: socket state %d is not connected.", socketHandle->socketState ) ); + + if( ( socketHandle->socketState == SOCKETSTATE_ALLOCATED ) || ( socketHandle->socketState == SOCKETSTATE_CONNECTING ) ) + { + cellularStatus = CELLULAR_SOCKET_NOT_CONNECTED; + } + else + { + cellularStatus = CELLULAR_SOCKET_CLOSED; + } + } + else + { + sessionId = _Cellular_GetSessionId( pContext, socketHandle->socketId ); + + if( sessionId == INVALID_SESSION_ID ) + { + LogError( ( "Cellular_SocketSend : invalid session ID for socket index %u", + socketHandle->socketId ) ); + cellularStatus = CELLULAR_INVALID_HANDLE; + } + } + + if( cellularStatus == CELLULAR_SUCCESS ) + { + /* Send data length check. */ + if( dataLength > ( uint32_t ) CELLULAR_MAX_SEND_DATA_LEN ) + { + atDataReqSocketSend.dataLen = ( uint32_t ) CELLULAR_MAX_SEND_DATA_LEN; + } + + /* Check send timeout. If not set by setsockopt, use default value. */ + if( socketHandle->sendTimeoutMs != 0U ) + { + sendTimeout = socketHandle->sendTimeoutMs; + } + + /* The return value of snprintf is not used. + * The max length of the string is fixed and checked offline. */ + /* coverity[misra_c_2012_rule_21_6_violation]. */ + ( void ) snprintf( cmdBuf, CELLULAR_AT_CMD_TYPICAL_MAX_SIZE, "%s%u,%u", + "AT+USOWR=", sessionId, atDataReqSocketSend.dataLen ); + + pktStatus = _Cellular_AtcmdDataSend( pContext, atReqSocketSend, atDataReqSocketSend, + socketSendDataPrefix, NULL, + PACKET_REQ_TIMEOUT_MS, sendTimeout, 200U ); + + if( pktStatus != CELLULAR_PKT_STATUS_OK ) + { + if( socketHandle->socketState == SOCKETSTATE_DISCONNECTED ) + { + LogInfo( ( "Cellular_SocketSend: Data send fail, socket already closed" ) ); + cellularStatus = CELLULAR_SOCKET_CLOSED; + } + else + { + LogError( ( "Cellular_SocketSend: Data send fail, PktRet: %d", pktStatus ) ); + cellularStatus = _Cellular_TranslatePktStatus( pktStatus ); + } + } + } + + return cellularStatus; +} + +/*-----------------------------------------------------------*/ + +/* FreeRTOS Cellular Library API. */ +/* coverity[misra_c_2012_rule_8_7_violation] */ +CellularError_t Cellular_SocketClose( CellularHandle_t cellularHandle, + CellularSocketHandle_t socketHandle ) +{ + CellularContext_t * pContext = ( CellularContext_t * ) cellularHandle; + CellularError_t cellularStatus = CELLULAR_SUCCESS; + CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_OK; + char cmdBuf[ CELLULAR_AT_CMD_TYPICAL_MAX_SIZE ] = { '\0' }; + CellularAtReq_t atReqSocketClose = + { + NULL, + CELLULAR_AT_NO_RESULT, + NULL, + NULL, + NULL, + 0, + }; + uint32_t sessionId = INVALID_SESSION_ID; + cellularModuleContext_t * pModuleContext = NULL; + + atReqSocketClose.pAtCmd = cmdBuf; + + /* pContext is checked in _Cellular_CheckLibraryStatus function. */ + cellularStatus = _Cellular_CheckLibraryStatus( pContext ); + + if( cellularStatus != CELLULAR_SUCCESS ) + { + LogDebug( ( "Cellular_SocketClose: _Cellular_CheckLibraryStatus failed" ) ); + } + else if( socketHandle == NULL ) + { + cellularStatus = CELLULAR_INVALID_HANDLE; + } + else + { + if( socketHandle->socketState == SOCKETSTATE_CONNECTING ) + { + LogWarn( ( "Cellular_SocketClose: Socket state is SOCKETSTATE_CONNECTING." ) ); + } + + cellularStatus = _Cellular_GetModuleContext( pContext, ( void ** ) &pModuleContext ); + } + + if( cellularStatus == CELLULAR_SUCCESS ) + { + sessionId = _Cellular_GetSessionId( pContext, socketHandle->socketId ); + + if( sessionId == INVALID_SESSION_ID ) + { + LogError( ( "Cellular_SocketClose : invalid session ID for socket index %u", + socketHandle->socketId ) ); + cellularStatus = CELLULAR_INVALID_HANDLE; + } + } + + if( cellularStatus == CELLULAR_SUCCESS ) + { + /* Remove the mapping. */ + pModuleContext->pSessionMap[ sessionId ] = INVALID_SOCKET_INDEX; + + /* Close the socket. */ + if( socketHandle->socketState == SOCKETSTATE_CONNECTED ) + { + ( void ) snprintf( cmdBuf, CELLULAR_AT_CMD_TYPICAL_MAX_SIZE, "%s%u,%d", + "AT+USOCL=", sessionId, CELLULAR_CONFIG_SET_SOCKET_CLOSE_ASYNC_MODE ); + pktStatus = _Cellular_TimeoutAtcmdRequestWithCallback( pContext, atReqSocketClose, SOCKET_CLOSE_PACKET_REQ_TIMEOUT_MS ); + + /* Delete the socket config. */ + if( pktStatus != CELLULAR_PKT_STATUS_OK ) + { + LogWarn( ( "Cellular_SocketClose: AT+USOCL fail, PktRet: %d", pktStatus ) ); + } + } + + /* Ignore the result from the info, and force to remove the socket. */ + cellularStatus = _Cellular_RemoveSocketData( pContext, socketHandle ); + } + + return cellularStatus; +} + +/*-----------------------------------------------------------*/ + +/* FreeRTOS Cellular Library API. */ +/* coverity[misra_c_2012_rule_8_7_violation] */ +CellularError_t Cellular_SocketConnect( CellularHandle_t cellularHandle, + CellularSocketHandle_t socketHandle, + CellularSocketAccessMode_t dataAccessMode, + const CellularSocketAddress_t * pRemoteSocketAddress ) +{ + CellularContext_t * pContext = ( CellularContext_t * ) cellularHandle; + CellularError_t cellularStatus = CELLULAR_SUCCESS; + CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_OK; + char cmdBuf[ CELLULAR_AT_CMD_MAX_SIZE ] = { '\0' }; + uint8_t sessionId = 0; + CellularAtReq_t atReqSocketConnect = + { + NULL, + CELLULAR_AT_NO_RESULT, + NULL, + NULL, + NULL, + 0, + }; + cellularModuleContext_t * pModuleContext = NULL; + + atReqSocketConnect.pAtCmd = cmdBuf; + + /* Make sure the library is open. */ + cellularStatus = _Cellular_CheckLibraryStatus( pContext ); + + if( cellularStatus != CELLULAR_SUCCESS ) + { + LogError( ( "Cellular_SocketConnect: _Cellular_CheckLibraryStatus failed." ) ); + } + else if( pRemoteSocketAddress == NULL ) + { + LogError( ( "Cellular_SocketConnect: Invalid socket address." ) ); + cellularStatus = CELLULAR_BAD_PARAMETER; + } + else if( socketHandle == NULL ) + { + LogError( ( "Cellular_SocketConnect: Invalid socket handle." ) ); + cellularStatus = CELLULAR_INVALID_HANDLE; + } + else if( socketHandle->socketProtocol != CELLULAR_SOCKET_PROTOCOL_TCP ) + { + LogError( ( "Cellular_SocketConnect: Invalid socket protocol." ) ); + cellularStatus = CELLULAR_BAD_PARAMETER; + } + else if( ( socketHandle->socketState == SOCKETSTATE_CONNECTED ) || ( socketHandle->socketState == SOCKETSTATE_CONNECTING ) ) + { + LogError( ( "Cellular_SocketConnect: Not allowed in state %d.", socketHandle->socketState ) ); + cellularStatus = CELLULAR_NOT_ALLOWED; + } + else + { + cellularStatus = storeAccessModeAndAddress( pContext, socketHandle, dataAccessMode, pRemoteSocketAddress ); + } + + if( cellularStatus == CELLULAR_SUCCESS ) + { + cellularStatus = _Cellular_GetModuleContext( pContext, ( void ** ) &pModuleContext ); + } + + /* Set socket config and get session id. The session id is defined by the modem. */ + if( cellularStatus == CELLULAR_SUCCESS ) + { + /* Builds the Socket connect command. */ + cellularStatus = _Cellular_GetSocketNumber( pContext, socketHandle, &sessionId ); + + if( cellularStatus == CELLULAR_SUCCESS ) + { + /* Create the reverse table to store the socketIndex to sessionId. */ + pModuleContext->pSessionMap[ sessionId ] = socketHandle->socketId; + } + } + + /* Start the tcp connection. */ + if( cellularStatus == CELLULAR_SUCCESS ) + { + /* The return value of snprintf is not used. + * The max length of the string is fixed and checked offline. */ + /* coverity[misra_c_2012_rule_21_6_violation]. */ + ( void ) snprintf( cmdBuf, CELLULAR_AT_CMD_MAX_SIZE, + "AT+USOCO=%u,\"%s\",%d,1", + sessionId, + socketHandle->remoteSocketAddress.ipAddress.ipAddress, + socketHandle->remoteSocketAddress.port ); + + /* Set the socket state to connecting state. If cellular modem returns error, + * revert the state to allocated state. */ + socketHandle->socketState = SOCKETSTATE_CONNECTING; + + pktStatus = _Cellular_TimeoutAtcmdRequestWithCallback( pContext, atReqSocketConnect, + SOCKET_CONNECT_PACKET_REQ_TIMEOUT_MS ); + + if( pktStatus != CELLULAR_PKT_STATUS_OK ) + { + LogError( ( "Cellular_SocketConnect: Socket connect failed, cmdBuf:%s, PktRet: %d", cmdBuf, pktStatus ) ); + cellularStatus = _Cellular_TranslatePktStatus( pktStatus ); + + /* Revert the state to allocated state. */ + socketHandle->socketState = SOCKETSTATE_ALLOCATED; + } + } + + return cellularStatus; +} + +/*-----------------------------------------------------------*/ + +/* FreeRTOS Cellular Library API. */ +/* coverity[misra_c_2012_rule_8_7_violation] */ +CellularError_t Cellular_GetSimCardStatus( CellularHandle_t cellularHandle, + CellularSimCardStatus_t * pSimCardStatus ) +{ + CellularContext_t * pContext = ( CellularContext_t * ) cellularHandle; + CellularError_t cellularStatus = CELLULAR_SUCCESS; + + /* pContext is checked in _Cellular_CheckLibraryStatus function. */ + cellularStatus = _Cellular_CheckLibraryStatus( pContext ); + + if( cellularStatus != CELLULAR_SUCCESS ) + { + LogDebug( ( "Cellular_GetSimCardStatus: _Cellular_CheckLibraryStatus failed" ) ); + } + else if( pSimCardStatus == NULL ) + { + LogWarn( ( "Cellular_GetSimCardStatus: Bad input Parameter " ) ); + cellularStatus = CELLULAR_BAD_PARAMETER; + } + else + { + /* Parameters are checked in this API. */ + pSimCardStatus->simCardState = CELLULAR_SIM_CARD_UNKNOWN; + pSimCardStatus->simCardLockState = CELLULAR_SIM_CARD_LOCK_UNKNOWN; + + cellularStatus = Cellular_CommonGetSimCardLockStatus( cellularHandle, pSimCardStatus ); + + if( cellularStatus == CELLULAR_SUCCESS ) + { + if( ( pSimCardStatus->simCardLockState != CELLULAR_SIM_CARD_INVALID ) && + ( pSimCardStatus->simCardLockState != CELLULAR_SIM_CARD_LOCK_UNKNOWN ) ) + { + pSimCardStatus->simCardState = CELLULAR_SIM_CARD_INSERTED; + } + else + { + pSimCardStatus->simCardState = CELLULAR_SIM_CARD_UNKNOWN; + } + + LogInfo( ( "Cellular_GetSimCardStatus, Sim Insert State[%d], Lock State[%d]", + pSimCardStatus->simCardState, pSimCardStatus->simCardLockState ) ); + } + } + + return cellularStatus; +} + +/*-----------------------------------------------------------*/ + +/* FreeRTOS Cellular Library API. */ +/* coverity[misra_c_2012_rule_8_7_violation] */ +CellularError_t Cellular_DeactivatePdn( CellularHandle_t cellularHandle, + uint8_t contextId ) +{ + CellularContext_t * pContext = ( CellularContext_t * ) cellularHandle; + CellularError_t cellularStatus = CELLULAR_SUCCESS; + CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_OK; + char cmdBuf[ CELLULAR_AT_CMD_MAX_SIZE ] = { '\0' }; + bool packetSwitchStatus = false; + uint32_t i = 0; + + CellularServiceStatus_t serviceStatus = { 0 }; + CellularPdnContextActInfo_t pdpContextsActInfo = { 0 }; + + CellularAtReq_t atReqDeactPdn = + { + NULL, + CELLULAR_AT_NO_RESULT, + NULL, + NULL, + NULL, + 0, + }; + + atReqDeactPdn.pAtCmd = cmdBuf; + + cellularStatus = _Cellular_IsValidPdn( contextId ); + + if( cellularStatus == CELLULAR_SUCCESS ) + { + /* Make sure the library is open. */ + cellularStatus = _Cellular_CheckLibraryStatus( pContext ); + } + + if( cellularStatus == CELLULAR_SUCCESS ) + { + /* Get current network operator settings. */ + cellularStatus = Cellular_CommonGetServiceStatus( cellularHandle, &serviceStatus ); + + if( cellularStatus == CELLULAR_SUCCESS ) + { + /* Check the current status of context. */ + cellularStatus = _Cellular_GetContextActivationStatus( cellularHandle, &pdpContextsActInfo ); + } + + if( cellularStatus == CELLULAR_SUCCESS ) + { + LogDebug( ( "Cellular_DeactivatePdn: Listing operator and context details below." ) ); + + for( i = 0U; i < ( MAX_PDP_CONTEXTS - 1 ); i++ ) + { + /* Print only those contexts that are present in +CGACT response */ + if( pdpContextsActInfo.contextsPresent[ i ] ) + { + LogDebug( ( "Context [%d], Act State [%d], Operator [%d]\r\n", i + 1, + pdpContextsActInfo.contextActState[ i ], serviceStatus.rat ) ); + } + } + + /* Deactivate context if active */ + if( pdpContextsActInfo.contextActState[ contextId - 1 ] == true ) + { + /* Don't deactivate LTE default bearer context */ + /* Otherwise sending AT command "+CGACT=0,1" for deactivation will result in ERROR */ + if( ( serviceStatus.rat >= CELLULAR_RAT_LTE ) && ( contextId == DEFAULT_BEARER_CONTEXT_ID ) ) + { + LogInfo( ( "Cellular_DeactivatePdn: Default Bearer context %d Active. Not allowed to deactivate.", contextId ) ); + cellularStatus = CELLULAR_NOT_ALLOWED; + } + else + { + ( void ) snprintf( cmdBuf, CELLULAR_AT_CMD_MAX_SIZE, "%s=0,%u", "AT+CGACT", contextId ); + pktStatus = _Cellular_TimeoutAtcmdRequestWithCallback( pContext, atReqDeactPdn, PDN_DEACT_PACKET_REQ_TIMEOUT_MS ); + cellularStatus = _Cellular_TranslatePktStatus( pktStatus ); + } + + if( ( cellularStatus != CELLULAR_SUCCESS ) && ( cellularStatus != CELLULAR_NOT_ALLOWED ) ) + { + LogError( ( "Cellular_DeactivatePdn: can't deactivate PDN, PktRet: %d", pktStatus ) ); + + /* Sometimes +CGACT deactivation fails in 2G. Then check packet switch attach. If attached, detach packet switch. */ + if( ( serviceStatus.rat == CELLULAR_RAT_GSM ) || ( serviceStatus.rat == CELLULAR_RAT_EDGE ) ) + { + cellularStatus = _Cellular_GetPacketSwitchStatus( cellularHandle, &packetSwitchStatus ); + + if( ( cellularStatus == CELLULAR_SUCCESS ) && ( packetSwitchStatus == true ) ) + { + LogError( ( "Deactivate Packet switch" ) ); + ( void ) snprintf( cmdBuf, CELLULAR_AT_CMD_MAX_SIZE, "%s", "AT+CGATT=0" ); + pktStatus = _Cellular_TimeoutAtcmdRequestWithCallback( pContext, atReqDeactPdn, GPRS_ATTACH_REQ_TIMEOUT_MS ); + cellularStatus = _Cellular_TranslatePktStatus( pktStatus ); + } + else if( cellularStatus != CELLULAR_SUCCESS ) + { + LogError( ( "Packet switch query failed" ) ); + pktStatus = CELLULAR_PKT_STATUS_FAILURE; + cellularStatus = _Cellular_TranslatePktStatus( pktStatus ); + } + else + { + LogInfo( ( "Packet switch detached" ) ); + } + } + } + } + else + { + LogInfo( ( "Cellular_DeactivatePdn: Context id [%d] is already deactive", contextId ) ); + } + } + else + { + LogError( ( "Cellular_DeactivatePdn: Unable to list operator and context details." ) ); + } + } + + return cellularStatus; +} + +/*-----------------------------------------------------------*/ + +/* FreeRTOS Cellular Library prototype. */ +/* coverity[misra_c_2012_rule_8_13_violation] */ +static CellularPktStatus_t _Cellular_RecvFuncPacketSwitchStatus( CellularContext_t * pContext, + const CellularATCommandResponse_t * pAtResp, + void * pData, + uint16_t dataLen ) +{ + char * pInputLine = NULL; + CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_OK; + CellularATError_t atCoreStatus = CELLULAR_AT_SUCCESS; + bool * pPacketSwitchStatus = ( bool * ) pData; + + if( pContext == NULL ) + { + LogError( ( "PacketSwitchStatus: Invalid handle" ) ); + pktStatus = CELLULAR_PKT_STATUS_INVALID_HANDLE; + } + else if( ( pData == NULL ) || ( dataLen != sizeof( bool ) ) ) + { + LogError( ( "GetPacketSwitchStatus: Invalid param" ) ); + pktStatus = CELLULAR_PKT_STATUS_BAD_PARAM; + } + else if( ( pAtResp == NULL ) || ( pAtResp->pItm == NULL ) || ( pAtResp->pItm->pLine == NULL ) ) + { + LogError( ( "GetPacketSwitchStatus: Input Line passed is NULL" ) ); + pktStatus = CELLULAR_PKT_STATUS_FAILURE; + } + else + { + pInputLine = pAtResp->pItm->pLine; + + /* Remove prefix. */ + atCoreStatus = Cellular_ATRemovePrefix( &pInputLine ); + + /* Remove leading space. */ + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + atCoreStatus = Cellular_ATRemoveLeadingWhiteSpaces( &pInputLine ); + } + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + if( *pInputLine == '0' ) + { + *pPacketSwitchStatus = false; + } + else if( *pInputLine == '1' ) + { + *pPacketSwitchStatus = true; + } + else + { + atCoreStatus = CELLULAR_AT_ERROR; + } + } + + pktStatus = _Cellular_TranslateAtCoreStatus( atCoreStatus ); + } + + return pktStatus; +} + +/*-----------------------------------------------------------*/ + +/* Get PDN context Activation state */ + +static CellularPktStatus_t _Cellular_RecvFuncGetPdpContextActState( CellularContext_t * pContext, + const CellularATCommandResponse_t * pAtResp, + void * pData, + uint16_t dataLen ) +{ + char * pRespLine = NULL; + CellularPdnContextActInfo_t * pPDPContextsActInfo = ( CellularPdnContextActInfo_t * ) pData; + CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_OK; + CellularATError_t atCoreStatus = CELLULAR_AT_SUCCESS; + const CellularATCommandLine_t * pCommnadItem = NULL; + uint8_t tokenIndex = 0; + uint8_t contextId = 0; + int32_t tempValue = 0; + char * pToken = NULL; + + if( pContext == NULL ) + { + LogError( ( "_Cellular_RecvFuncGetPdpContextActState: invalid context" ) ); + pktStatus = CELLULAR_PKT_STATUS_FAILURE; + } + else if( ( pPDPContextsActInfo == NULL ) || ( dataLen != sizeof( CellularPdnContextActInfo_t ) ) ) + { + pktStatus = CELLULAR_PKT_STATUS_BAD_PARAM; + } + else if( pAtResp == NULL ) + { + LogError( ( "_Cellular_RecvFuncGetPdpContextActState: Response is invalid" ) ); + pktStatus = CELLULAR_PKT_STATUS_FAILURE; + } + else if( ( pAtResp->pItm == NULL ) || ( pAtResp->pItm->pLine == NULL ) ) + { + LogError( ( "_Cellular_RecvFuncGetPdpContextActState: no PDN context available" ) ); + pktStatus = CELLULAR_PKT_STATUS_OK; + } + else + { + pRespLine = pAtResp->pItm->pLine; + + pCommnadItem = pAtResp->pItm; + + while( pCommnadItem != NULL ) + { + pRespLine = pCommnadItem->pLine; + LogDebug( ( "_Cellular_RecvFuncGetPdpContextActState: pRespLine [%s]", pRespLine ) ); + + /* Removing all the Spaces in the AT Response. */ + atCoreStatus = Cellular_ATRemoveAllWhiteSpaces( pRespLine ); + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + atCoreStatus = Cellular_ATRemovePrefix( &pRespLine ); + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + atCoreStatus = Cellular_ATRemoveAllDoubleQuote( pRespLine ); + } + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + atCoreStatus = Cellular_ATGetNextTok( &pRespLine, &pToken ); + } + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + tokenIndex = 0; + + while( ( pToken != NULL ) && ( atCoreStatus == CELLULAR_AT_SUCCESS ) ) + { + switch( tokenIndex ) + { + case ( CELLULAR_PDN_ACT_STATUS_POS_CONTEXT_ID ): + LogDebug( ( "_Cellular_RecvFuncGetPdpContextActState: Context Id pToken: %s", pToken ) ); + atCoreStatus = Cellular_ATStrtoi( pToken, 10, &tempValue ); + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + if( ( tempValue >= ( int32_t ) CELLULAR_PDN_CONTEXT_ID_MIN ) && + ( tempValue <= ( int32_t ) MAX_PDP_CONTEXTS ) ) + { + contextId = ( uint8_t ) tempValue; + pPDPContextsActInfo->contextsPresent[ contextId - 1 ] = true; + LogDebug( ( "_Cellular_RecvFuncGetPdpContextActState: Context Id: %d", contextId ) ); + } + else + { + LogError( ( "_Cellular_RecvFuncGetPdpContextActState: Invalid Context Id. Token %s", pToken ) ); + atCoreStatus = CELLULAR_AT_ERROR; + } + } + + break; + + case ( CELLULAR_PDN_ACT_STATUS_POS_CONTEXT_STATE ): + LogDebug( ( "_Cellular_RecvFuncGetPdpContextActState: Context pToken: %s", pToken ) ); + atCoreStatus = Cellular_ATStrtoi( pToken, 10, &tempValue ); + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + pPDPContextsActInfo->contextActState[ contextId - 1 ] = ( bool ) tempValue; + LogDebug( ( "_Cellular_RecvFuncGetPdpContextActState: Context : %d", pPDPContextsActInfo->contextActState[ contextId - 1 ] ) ); + } + + break; + + default: + break; + } + + tokenIndex++; + + if( Cellular_ATGetNextTok( &pRespLine, &pToken ) != CELLULAR_AT_SUCCESS ) + { + break; + } + } + } + } + + pktStatus = _Cellular_TranslateAtCoreStatus( atCoreStatus ); + + if( pktStatus != CELLULAR_PKT_STATUS_OK ) + { + LogError( ( "_Cellular_RecvFuncGetPdpContextActState: parse %s failed", pRespLine ) ); + break; + } + + pCommnadItem = pCommnadItem->pNext; + } + } + + return pktStatus; +} + +/*-----------------------------------------------------------*/ + +/* Check activation status of particular context. */ + +static CellularError_t _Cellular_GetContextActivationStatus( CellularHandle_t cellularHandle, + CellularPdnContextActInfo_t * pPdpContextsActInfo ) +{ + CellularContext_t * pContext = ( CellularContext_t * ) cellularHandle; + CellularError_t cellularStatus = CELLULAR_SUCCESS; + CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_OK; + + CellularAtReq_t atReqPacketSwitchStatus = + { + "AT+CGACT?", + CELLULAR_AT_MULTI_WITH_PREFIX, + "+CGACT", + _Cellular_RecvFuncGetPdpContextActState, + NULL, + sizeof( CellularPdnContextActInfo_t ), + }; + + atReqPacketSwitchStatus.pData = pPdpContextsActInfo; + + /* Internal function. Callee check parameters. */ + pktStatus = _Cellular_AtcmdRequestWithCallback( pContext, atReqPacketSwitchStatus ); + cellularStatus = _Cellular_TranslatePktStatus( pktStatus ); + + return cellularStatus; +} + +/*-----------------------------------------------------------*/ + +static CellularError_t _Cellular_GetPacketSwitchStatus( CellularHandle_t cellularHandle, + bool * pPacketSwitchStatus ) +{ + CellularContext_t * pContext = ( CellularContext_t * ) cellularHandle; + CellularError_t cellularStatus = CELLULAR_SUCCESS; + CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_OK; + CellularAtReq_t atReqPacketSwitchStatus = + { + "AT+CGATT?", + CELLULAR_AT_WITH_PREFIX, + "+CGATT", + _Cellular_RecvFuncPacketSwitchStatus, + NULL, + sizeof( bool ), + }; + + atReqPacketSwitchStatus.pData = pPacketSwitchStatus; + + /* Internal function. Callee check parameters. */ + pktStatus = _Cellular_TimeoutAtcmdRequestWithCallback( pContext, atReqPacketSwitchStatus, PDN_ACT_PACKET_REQ_TIMEOUT_MS ); + cellularStatus = _Cellular_TranslatePktStatus( pktStatus ); + + return cellularStatus; +} + +/*-----------------------------------------------------------*/ + +/* FreeRTOS Cellular Library API. */ +/* coverity[misra_c_2012_rule_8_7_violation] */ +CellularError_t Cellular_ActivatePdn( CellularHandle_t cellularHandle, + uint8_t contextId ) +{ + CellularContext_t * pContext = ( CellularContext_t * ) cellularHandle; + CellularError_t cellularStatus = CELLULAR_SUCCESS; + CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_OK; + char cmdBuf[ CELLULAR_AT_CMD_MAX_SIZE ] = { '\0' }; + uint32_t i = 0; + + CellularPdnContextActInfo_t pdpContextsActInfo = { 0 }; + + CellularAtReq_t atReqActPdn = + { + NULL, + CELLULAR_AT_NO_RESULT, + NULL, + NULL, + NULL, + 0, + }; + + cellularStatus = _Cellular_IsValidPdn( contextId ); + + atReqActPdn.pAtCmd = cmdBuf; + + if( cellularStatus == CELLULAR_SUCCESS ) + { + /* Make sure the library is open. */ + cellularStatus = _Cellular_CheckLibraryStatus( pContext ); + } + + if( cellularStatus == CELLULAR_SUCCESS ) + { + /* Check the current status of context. If not activated, activate the PDN context ID. */ + cellularStatus = _Cellular_GetContextActivationStatus( cellularHandle, &pdpContextsActInfo ); + + if( cellularStatus == CELLULAR_SUCCESS ) + { + LogDebug( ( "Cellular_ActivatePdn: Listing operator and context details below." ) ); + + for( i = 0U; i < ( MAX_PDP_CONTEXTS - 1 ); i++ ) + { + /* Print only those contexts that are present in +CGACT response */ + if( pdpContextsActInfo.contextsPresent[ i ] ) + { + LogDebug( ( "Cellular_ActivatePdn: Context [%d], Act State [%d]\r\n", i + 1, + pdpContextsActInfo.contextActState[ i ] ) ); + } + } + } + + /* Activate context if not already active */ + if( pdpContextsActInfo.contextActState[ contextId - 1 ] == false ) + { + if( pktStatus == CELLULAR_PKT_STATUS_OK ) + { + ( void ) snprintf( cmdBuf, CELLULAR_AT_CMD_MAX_SIZE, "%s=1,%u", "AT+CGACT", contextId ); + pktStatus = _Cellular_TimeoutAtcmdRequestWithCallback( pContext, atReqActPdn, PDN_ACT_PACKET_REQ_TIMEOUT_MS ); + } + + if( pktStatus != CELLULAR_PKT_STATUS_OK ) + { + LogError( ( "Cellular_ActivatePdn: can't activate PDN, PktRet: %d", pktStatus ) ); + cellularStatus = _Cellular_TranslatePktStatus( pktStatus ); + } + } + else + { + LogInfo( ( "Cellular_ActivatePdn: Context id [%d] is already active", contextId ) ); + } + } + + return cellularStatus; +} + +/*-----------------------------------------------------------*/ + +/* FreeRTOS Cellular Library API. */ +/* coverity[misra_c_2012_rule_8_7_violation] */ +/* coverity[misra_c_2012_rule_8_13_violation] */ +CellularError_t Cellular_GetPdnStatus( CellularHandle_t cellularHandle, + CellularPdnStatus_t * pPdnStatusBuffers, + uint8_t numStatusBuffers, + uint8_t * pNumStatus ) +{ + CellularContext_t * pContext = ( CellularContext_t * ) cellularHandle; + CellularError_t cellularStatus = CELLULAR_SUCCESS; + uint8_t i = 0; + + CellularPdnContextActInfo_t pdpContextsActInfo = { 0 }; + + if( cellularStatus == CELLULAR_SUCCESS ) + { + /* Make sure the library is open. */ + cellularStatus = _Cellular_CheckLibraryStatus( pContext ); + } + + if( ( pPdnStatusBuffers == NULL ) || ( pNumStatus == NULL ) || ( numStatusBuffers < 1u ) ) + { + cellularStatus = CELLULAR_BAD_PARAMETER; + LogWarn( ( "_Cellular_GetPdnStatus: Bad input Parameter " ) ); + } + + if( cellularStatus == CELLULAR_SUCCESS ) + { + *pNumStatus = 0U; + + /* Check the current status of contexts. */ + cellularStatus = _Cellular_GetContextActivationStatus( cellularHandle, &pdpContextsActInfo ); + + if( cellularStatus == CELLULAR_SUCCESS ) + { + LogDebug( ( "Cellular_GetPdnStatus: Listing operator and context details below." ) ); + + for( i = 0U; i < ( MAX_PDP_CONTEXTS - 1 ); i++ ) + { + /* Print only those contexts that are present in +CGACT response. */ + if( pdpContextsActInfo.contextsPresent[ i ] ) + { + LogDebug( ( "Context [%d], Act State [%d]\r\n", i + 1, pdpContextsActInfo.contextActState[ i ] ) ); + + if( *pNumStatus < numStatusBuffers ) + { + pPdnStatusBuffers[ *pNumStatus ].contextId = i + 1U; + pPdnStatusBuffers[ *pNumStatus ].state = pdpContextsActInfo.contextActState[ i ]; + *pNumStatus = *pNumStatus + 1U; + } + } + } + } + } + + return cellularStatus; +} + +/*-----------------------------------------------------------*/ + +/* FreeRTOS Cellular Library API. */ +/* coverity[misra_c_2012_rule_8_7_violation] */ +CellularError_t Cellular_SetRatPriority( CellularHandle_t cellularHandle, + const CellularRat_t * pRatPriorities, + uint8_t ratPrioritiesLength ) +{ + CellularContext_t * pContext = ( CellularContext_t * ) cellularHandle; + uint8_t i = 0; + CellularError_t cellularStatus = CELLULAR_SUCCESS; + CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_OK; + char cmdBuf[ CELLULAR_AT_CMD_MAX_SIZE ] = { '\0' }; + + CellularAtReq_t atReqSetRatPriority = + { + NULL, + CELLULAR_AT_NO_RESULT, + NULL, + NULL, + NULL, + 0, + }; + + cellularStatus = _Cellular_CheckLibraryStatus( pContext ); + + atReqSetRatPriority.pAtCmd = cmdBuf; + + if( cellularStatus != CELLULAR_SUCCESS ) + { + LogDebug( ( "Cellular_SetRatPriority: _Cellular_CheckLibraryStatus failed" ) ); + } + else if( ( pRatPriorities == NULL ) || ( ratPrioritiesLength == 0U ) || + ( ratPrioritiesLength > ( uint8_t ) CELLULAR_MAX_RAT_PRIORITY_COUNT ) ) + { + LogWarn( ( "Cellular_SetRatPriority: Bad input Parameter " ) ); + cellularStatus = CELLULAR_BAD_PARAMETER; + } + else + { + /* In case of +UMNOPROF=0, AT+URAT set commad is not allowed */ + if( CELLULAR_CONFIG_SARA_R4_SET_MNO_PROFILE != 0 ) + { + ( void ) strcpy( cmdBuf, "AT+CFUN=4;+URAT=" ); + + while( i < ratPrioritiesLength ) + { + if( ( pRatPriorities[ i ] == CELLULAR_RAT_GSM ) || ( pRatPriorities[ i ] == CELLULAR_RAT_EDGE ) ) + { + ( void ) strcat( cmdBuf, "9" ); + } + else if( pRatPriorities[ i ] == CELLULAR_RAT_CATM1 ) + { + ( void ) strcat( cmdBuf, "7" ); + } + else if( pRatPriorities[ i ] == CELLULAR_RAT_NBIOT ) + { + ( void ) strcat( cmdBuf, "8" ); + } + else + { + cellularStatus = CELLULAR_BAD_PARAMETER; + break; + } + + i++; + + if( i < ratPrioritiesLength ) + { + ( void ) strcat( cmdBuf, "," ); + } + } + + ( void ) strcat( cmdBuf, ";+CFUN=1" ); + + if( cellularStatus == CELLULAR_SUCCESS ) + { + pktStatus = _Cellular_AtcmdRequestWithCallback( pContext, atReqSetRatPriority ); + cellularStatus = _Cellular_TranslatePktStatus( pktStatus ); + } + } + else + { + LogDebug( ( "Cellular_SetRatPriority: Automatic selection as UMNOPROF profile is 0" ) ); + } + } + + return cellularStatus; +} + +/*-----------------------------------------------------------*/ + +/* Get modem RAT priority setting. */ +/* coverity[misra_c_2012_rule_8_13_violation] */ +static CellularPktStatus_t _Cellular_RecvFuncGetRatPriority( CellularContext_t * pContext, + const CellularATCommandResponse_t * pAtResp, + void * pData, + uint16_t dataLen ) +{ + char * pInputLine = NULL, * pToken = NULL; + CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_OK; + CellularATError_t atCoreStatus = CELLULAR_AT_SUCCESS; + CellularRat_t * pRatPriorities = NULL; + uint8_t ratIndex = 0; + uint32_t maxRatPriorityLength = ( dataLen > RAT_PRIOIRTY_LIST_LENGTH ? RAT_PRIOIRTY_LIST_LENGTH : dataLen ); + + if( pContext == NULL ) + { + LogError( ( "_Cellular_RecvFuncGetRatPriority: Invalid context" ) ); + pktStatus = CELLULAR_PKT_STATUS_FAILURE; + } + else if( ( pAtResp == NULL ) || ( pAtResp->pItm == NULL ) || + ( pAtResp->pItm->pLine == NULL ) || ( pData == NULL ) || ( dataLen == 0U ) ) + { + LogError( ( "_Cellular_RecvFuncGetRatPriority: Invalid param" ) ); + pktStatus = CELLULAR_PKT_STATUS_BAD_PARAM; + } + else + { + pInputLine = pAtResp->pItm->pLine; + pRatPriorities = ( CellularRat_t * ) pData; + + atCoreStatus = Cellular_ATRemovePrefix( &pInputLine ); + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + atCoreStatus = Cellular_ATRemoveAllWhiteSpaces( pInputLine ); + } + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + memset( pRatPriorities, CELLULAR_RAT_INVALID, dataLen ); + + /* pInputLine : 7,8,9. */ + atCoreStatus = Cellular_ATGetNextTok( &pInputLine, &pToken ); + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + while( pToken != NULL && ratIndex < maxRatPriorityLength ) + { + LogDebug( ( "_Cellular_RecvFuncGetRatPriority: pToken [%s]", pToken ) ); + + if( strcmp( pToken, "7" ) == 0 ) + { + pRatPriorities[ ratIndex ] = CELLULAR_RAT_CATM1; + LogDebug( ( "_Cellular_RecvFuncGetRatPriority: CELLULAR_RAT_CATM1" ) ); + } + else if( strcmp( pToken, "8" ) == 0 ) + { + pRatPriorities[ ratIndex ] = CELLULAR_RAT_NBIOT; + LogDebug( ( "_Cellular_RecvFuncGetRatPriority: CELLULAR_RAT_NBIOT" ) ); + } + else if( strcmp( pToken, "9" ) == 0 ) + { + pRatPriorities[ ratIndex ] = CELLULAR_RAT_GSM; /* or CELLULAR_RAT_EDGE */ + LogDebug( ( "_Cellular_RecvFuncGetRatPriority: CELLULAR_RAT_GSM" ) ); + } + else + { + LogDebug( ( "_Cellular_RecvFuncGetRatPriority: Invalid RAT string [%s]", pToken ) ); + } + + ratIndex++; + + if( Cellular_ATGetNextTok( &pInputLine, &pToken ) != CELLULAR_AT_SUCCESS ) + { + break; + } + } + } + } + + pktStatus = _Cellular_TranslateAtCoreStatus( atCoreStatus ); + } + + return pktStatus; +} + +/*-----------------------------------------------------------*/ + +/* FreeRTOS Cellular Library API. */ +/* coverity[misra_c_2012_rule_8_7_violation] */ +CellularError_t Cellular_GetRatPriority( CellularHandle_t cellularHandle, + CellularRat_t * pRatPriorities, + uint8_t ratPrioritiesLength, + uint8_t * pReceiveRatPrioritesLength ) +{ + CellularContext_t * pContext = ( CellularContext_t * ) cellularHandle; + CellularError_t cellularStatus = CELLULAR_SUCCESS; + CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_OK; + uint8_t ratIndex = 0; + + CellularAtReq_t atReqSetRatPriority = + { + "AT+URAT?", + CELLULAR_AT_WITH_PREFIX, + "+URAT", + _Cellular_RecvFuncGetRatPriority, + NULL, + 0U, + }; + + atReqSetRatPriority.pData = pRatPriorities; + atReqSetRatPriority.dataLen = ( uint16_t ) ratPrioritiesLength; + + cellularStatus = _Cellular_CheckLibraryStatus( pContext ); + + if( cellularStatus != CELLULAR_SUCCESS ) + { + LogDebug( ( "Cellular_GetRatPriority: _Cellular_CheckLibraryStatus failed" ) ); + } + else if( ( pRatPriorities == NULL ) || ( ratPrioritiesLength == 0U ) || + ( ratPrioritiesLength > ( uint8_t ) CELLULAR_MAX_RAT_PRIORITY_COUNT ) || + ( pReceiveRatPrioritesLength == NULL ) ) + { + LogWarn( ( "Cellular_GetRatPriority: Bad input Parameter " ) ); + cellularStatus = CELLULAR_BAD_PARAMETER; + } + else + { + /* In case of +UMNOPROF=0, AT+URAT? read commad is not allowed */ + if( CELLULAR_CONFIG_SARA_R4_SET_MNO_PROFILE != 0 ) + { + pktStatus = _Cellular_AtcmdRequestWithCallback( pContext, atReqSetRatPriority ); + + if( pktStatus == CELLULAR_PKT_STATUS_OK ) + { + for( ratIndex = 0; ratIndex < ratPrioritiesLength; ratIndex++ ) + { + if( pRatPriorities[ ratIndex ] == CELLULAR_RAT_INVALID ) + { + break; + } + } + + *pReceiveRatPrioritesLength = ratIndex; + } + + cellularStatus = _Cellular_TranslatePktStatus( pktStatus ); + } + else + { + LogDebug( ( "Cellular_GetRatPriority: Automatic selection as UMNOPROF profile is 0" ) ); + + pRatPriorities[ ratIndex++ ] = CELLULAR_RAT_CATM1; + pRatPriorities[ ratIndex++ ] = CELLULAR_RAT_NBIOT; + pRatPriorities[ ratIndex++ ] = CELLULAR_RAT_GSM; + *pReceiveRatPrioritesLength = RAT_PRIOIRTY_LIST_LENGTH; + } + } + + return cellularStatus; +} + +/*-----------------------------------------------------------*/ + +static bool _parseExtendedSignalQuality( char * pQcsqPayload, + CellularSignalInfo_t * pSignalInfo ) +{ + char * pToken = NULL, * pTmpQcsqPayload = pQcsqPayload; + int32_t tempValue = 0; + bool parseStatus = true; + CellularATError_t atCoreStatus = CELLULAR_AT_SUCCESS; + + if( ( pSignalInfo == NULL ) || ( pQcsqPayload == NULL ) ) + { + LogError( ( "_parseExtendedSignalQuality: Invalid Input Parameters" ) ); + parseStatus = false; + } + + /* +CESQ: ,,,,,. */ + + /* Skip . */ + atCoreStatus = Cellular_ATGetNextTok( &pTmpQcsqPayload, &pToken ); + + /* Parse . */ + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + atCoreStatus = Cellular_ATGetNextTok( &pTmpQcsqPayload, &pToken ); + } + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + atCoreStatus = Cellular_ATStrtoi( pToken, 10, &tempValue ); + + if( ( atCoreStatus == CELLULAR_AT_SUCCESS ) && ( tempValue <= INT16_MAX ) && ( tempValue >= INT16_MIN ) ) + { + /* + * Bit Error Rate (BER): + * 0..7: as RXQUAL values in the table in 3GPP TS 45.008 [124], subclause 8.2.4 + * 99: not known or not detectable + */ + if( ( tempValue >= 0 ) && ( tempValue <= 7 ) ) + { + pSignalInfo->ber = ( int16_t ) tempValue; + } + else + { + pSignalInfo->ber = CELLULAR_INVALID_SIGNAL_VALUE; + } + } + else + { + LogError( ( "_parseExtendedSignalQuality: Error in processing BER. Token %s", pToken ) ); + atCoreStatus = CELLULAR_AT_ERROR; + } + } + + /* Skip . */ + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + atCoreStatus = Cellular_ATGetNextTok( &pTmpQcsqPayload, &pToken ); + } + + /* Skip . */ + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + atCoreStatus = Cellular_ATGetNextTok( &pTmpQcsqPayload, &pToken ); + } + + /* Parse . */ + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + atCoreStatus = Cellular_ATGetNextTok( &pTmpQcsqPayload, &pToken ); + } + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + atCoreStatus = Cellular_ATStrtoi( pToken, 10, &tempValue ); + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + /* + * Reference Signal Received Quality (RSRQ): + * 0: less than -19.5 dB + * 1..33: from -19.5 dB to -3.5 dB with 0.5 dB steps + * 34: -3 dB or greater + * 255: not known or not detectable + */ + if( ( tempValue >= 0 ) && ( tempValue <= 34 ) ) + { + pSignalInfo->rsrq = ( int16_t ) ( ( -20 ) + ( tempValue * 0.5 ) ); + } + else + { + pSignalInfo->rsrq = CELLULAR_INVALID_SIGNAL_VALUE; + } + } + else + { + LogError( ( "_parseExtendedSignalQuality: Error in processing RSRP. Token %s", pToken ) ); + parseStatus = false; + } + } + + /* Parse . */ + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + atCoreStatus = Cellular_ATGetNextTok( &pTmpQcsqPayload, &pToken ); + } + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + atCoreStatus = Cellular_ATStrtoi( pToken, 10, &tempValue ); + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + /* + * Reference Signal Received Power(RSRP) : + * 0 : less than - 140 dBm + * 1..96 : from - 140 dBm to - 45 dBm with 1 dBm steps + * 97 : -44 dBm or greater + * 255 : not known or not detectable + */ + if( ( tempValue >= 0 ) && ( tempValue <= 97 ) ) + { + pSignalInfo->rsrp = ( int16_t ) ( ( -141 ) + ( tempValue ) ); + } + else + { + pSignalInfo->rsrp = CELLULAR_INVALID_SIGNAL_VALUE; + } + } + else + { + LogError( ( "_parseExtendedSignalQuality: Error in processing RSRP. Token %s", pToken ) ); + parseStatus = false; + } + } + + return parseStatus; +} + +/*-----------------------------------------------------------*/ + +static bool _parseSignalQuality( char * pQcsqPayload, + CellularSignalInfo_t * pSignalInfo ) +{ + char * pToken = NULL, * pTmpQcsqPayload = pQcsqPayload; + int32_t tempValue = 0; + bool parseStatus = true; + CellularATError_t atCoreStatus = CELLULAR_AT_SUCCESS; + + if( ( pSignalInfo == NULL ) || ( pQcsqPayload == NULL ) ) + { + LogError( ( "_parseSignalQuality: Invalid Input Parameters" ) ); + parseStatus = false; + } + + /* +CSQ: ,. */ + + /* Parse . */ + atCoreStatus = Cellular_ATGetNextTok( &pTmpQcsqPayload, &pToken ); + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + atCoreStatus = Cellular_ATStrtoi( pToken, 10, &tempValue ); + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + /* + * The allowed range is 0-31 and 99. + * 0 RSSI of the network <= -113 dBm + * 1 -111 dBm + * 2...30 -109 dBm <= RSSI of the network <= -53 dBm + * 31 -51 dBm <= RSSI of the network + * 99 Not known or not detectable + */ + if( ( tempValue >= 0 ) && ( tempValue <= 31 ) ) + { + pSignalInfo->rssi = ( int16_t ) ( ( -113 ) + ( tempValue * 2 ) ); + } + else if( tempValue == 99 ) + { + pSignalInfo->rssi = -113; + } + else + { + pSignalInfo->rssi = CELLULAR_INVALID_SIGNAL_VALUE; + } + } + else + { + LogError( ( "_parseSignalQuality: Error in processing RSSI. Token %s", pToken ) ); + parseStatus = false; + } + } + + /* Parse . */ + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + atCoreStatus = Cellular_ATGetNextTok( &pTmpQcsqPayload, &pToken ); + } + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + atCoreStatus = Cellular_ATStrtoi( pToken, 10, &tempValue ); + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + /* + * The allowed range is 0-7 and 99 : + * In 2G RAT CS dedicated and GPRS packet transfer mode indicates the Bit Error Rate (BER) as specified in 3GPP TS 45.008 + */ + if( ( tempValue >= 0 ) && ( tempValue <= 7 ) ) + { + pSignalInfo->ber = ( int16_t ) tempValue; + } + else + { + pSignalInfo->ber = CELLULAR_INVALID_SIGNAL_VALUE; + } + } + else + { + LogError( ( "_parseSignalQuality: Error in processing ber. Token %s", pToken ) ); + parseStatus = false; + } + } + + return parseStatus; +} + +/*-----------------------------------------------------------*/ + +/* parse signal strength response */ + +static CellularPktStatus_t _Cellular_RecvFuncGetSignalInfo( CellularContext_t * pContext, + const CellularATCommandResponse_t * pAtResp, + void * pData, + uint16_t dataLen ) +{ + char * pInputLine = NULL; + CellularSignalInfo_t * pSignalInfo = ( CellularSignalInfo_t * ) pData; + bool parseStatus = true; + CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_OK; + CellularATError_t atCoreStatus = CELLULAR_AT_SUCCESS; + bool isExtendedResponse = false; + + if( pContext == NULL ) + { + pktStatus = CELLULAR_PKT_STATUS_INVALID_HANDLE; + } + else if( ( pSignalInfo == NULL ) || ( dataLen != sizeof( CellularSignalInfo_t ) ) ) + { + pktStatus = CELLULAR_PKT_STATUS_BAD_PARAM; + } + else if( ( pAtResp == NULL ) || ( pAtResp->pItm == NULL ) || ( pAtResp->pItm->pLine == NULL ) ) + { + LogError( ( "GetSignalInfo: Input Line passed is NULL" ) ); + pktStatus = CELLULAR_PKT_STATUS_FAILURE; + } + else + { + pInputLine = pAtResp->pItm->pLine; + + if( strstr( pInputLine, "+CESQ" ) ) + { + LogDebug( ( "GetSignalInfo: ExtendedResponse received." ) ); + isExtendedResponse = true; + } + + atCoreStatus = Cellular_ATRemovePrefix( &pInputLine ); + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + atCoreStatus = Cellular_ATRemoveAllWhiteSpaces( pInputLine ); + } + + if( atCoreStatus != CELLULAR_AT_SUCCESS ) + { + pktStatus = _Cellular_TranslateAtCoreStatus( atCoreStatus ); + } + } + + if( pktStatus == CELLULAR_PKT_STATUS_OK ) + { + if( isExtendedResponse ) + { + parseStatus = _parseExtendedSignalQuality( pInputLine, pSignalInfo ); + } + else + { + parseStatus = _parseSignalQuality( pInputLine, pSignalInfo ); + } + + if( parseStatus != true ) + { + pSignalInfo->rssi = CELLULAR_INVALID_SIGNAL_VALUE; + pSignalInfo->rsrp = CELLULAR_INVALID_SIGNAL_VALUE; + pSignalInfo->rsrq = CELLULAR_INVALID_SIGNAL_VALUE; + pSignalInfo->ber = CELLULAR_INVALID_SIGNAL_VALUE; + pSignalInfo->bars = CELLULAR_INVALID_SIGNAL_BAR_VALUE; + pktStatus = CELLULAR_PKT_STATUS_FAILURE; + } + } + + return pktStatus; +} + +/*-----------------------------------------------------------*/ + +CellularError_t Cellular_GetSignalInfo( CellularHandle_t cellularHandle, + CellularSignalInfo_t * pSignalInfo ) +{ + CellularContext_t * pContext = ( CellularContext_t * ) cellularHandle; + CellularError_t cellularStatus = CELLULAR_SUCCESS; + CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_OK; + CellularRat_t rat = CELLULAR_RAT_INVALID; + CellularAtReq_t atReqQuerySignalInfo = + { + "AT+CSQ", + CELLULAR_AT_WITH_PREFIX, + "+CSQ", + _Cellular_RecvFuncGetSignalInfo, + NULL, + sizeof( CellularSignalInfo_t ), + }; + CellularAtReq_t atReqQueryExtendedSignalInfo = + { + "AT+CESQ", + CELLULAR_AT_WITH_PREFIX, + "+CESQ", + _Cellular_RecvFuncGetSignalInfo, + NULL, + sizeof( CellularSignalInfo_t ), + }; + + cellularStatus = _Cellular_CheckLibraryStatus( pContext ); + atReqQuerySignalInfo.pData = pSignalInfo; + atReqQueryExtendedSignalInfo.pData = pSignalInfo; + + if( cellularStatus != CELLULAR_SUCCESS ) + { + LogDebug( ( "Cellular_GetSignalInfo: _Cellular_CheckLibraryStatus failed" ) ); + } + else if( pSignalInfo == NULL ) + { + cellularStatus = CELLULAR_BAD_PARAMETER; + } + else + { + cellularStatus = _Cellular_GetCurrentRat( pContext, &rat ); + } + + if( cellularStatus == CELLULAR_SUCCESS ) + { + /* Get +CSQ response */ + pktStatus = _Cellular_AtcmdRequestWithCallback( pContext, atReqQuerySignalInfo ); + + if( pktStatus == CELLULAR_PKT_STATUS_OK ) + { + /* Get +CESQ response */ + pktStatus = _Cellular_AtcmdRequestWithCallback( pContext, atReqQueryExtendedSignalInfo ); + + if( pktStatus == CELLULAR_PKT_STATUS_OK ) + { + /* If the convert failed, the API will return CELLULAR_INVALID_SIGNAL_BAR_VALUE in bars field. */ + ( void ) _Cellular_ComputeSignalBars( rat, pSignalInfo ); + } + + cellularStatus = _Cellular_TranslatePktStatus( pktStatus ); + } + } + + return cellularStatus; +} + +/*-----------------------------------------------------------*/ + +/* FreeRTOS Cellular Library API. */ +/* coverity[misra_c_2012_rule_8_7_violation] */ +CellularError_t Cellular_SetDns( CellularHandle_t cellularHandle, + uint8_t contextId, + const char * pDnsServerAddress ) +{ + /* Modem use dynamic DNS addresses. Return unsupported. */ + ( void ) cellularHandle; + ( void ) contextId; + ( void ) pDnsServerAddress; + return CELLULAR_UNSUPPORTED; +} + +/*-----------------------------------------------------------*/ + +static CellularError_t controlSignalStrengthIndication( CellularContext_t * pContext, + bool enable ) +{ + CellularError_t cellularStatus = CELLULAR_SUCCESS; + CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_OK; + char cmdBuf[ CELLULAR_AT_CMD_TYPICAL_MAX_SIZE ] = { '\0' }; + uint8_t enable_value = 0; + CellularAtReq_t atReqControlSignalStrengthIndication = + { + NULL, + CELLULAR_AT_NO_RESULT, + NULL, + NULL, + NULL, + 0, + }; + + atReqControlSignalStrengthIndication.pAtCmd = cmdBuf; + + if( enable == true ) + { + enable_value = 1; + } + else + { + enable_value = 0; + } + + cellularStatus = _Cellular_CheckLibraryStatus( pContext ); + + if( cellularStatus == CELLULAR_SUCCESS ) + { + if( enable_value ) + { + /* Enable signal level change indication via +CIEV URC.*/ + ( void ) snprintf( cmdBuf, CELLULAR_AT_CMD_TYPICAL_MAX_SIZE, "AT+UCIND=2" ); + pktStatus = _Cellular_AtcmdRequestWithCallback( pContext, atReqControlSignalStrengthIndication ); + } + else + { + /* Disable signal level change indication via +CIEV URC.*/ + ( void ) snprintf( cmdBuf, CELLULAR_AT_CMD_TYPICAL_MAX_SIZE, "AT+UCIND=0" ); + pktStatus = _Cellular_AtcmdRequestWithCallback( pContext, atReqControlSignalStrengthIndication ); + } + + cellularStatus = _Cellular_TranslatePktStatus( pktStatus ); + } + + return cellularStatus; +} + +/*-----------------------------------------------------------*/ + +/* FreeRTOS Cellular Library API. */ +/* coverity[misra_c_2012_rule_8_7_violation] */ +CellularError_t Cellular_RegisterUrcSignalStrengthChangedCallback( CellularHandle_t cellularHandle, + CellularUrcSignalStrengthChangedCallback_t signalStrengthChangedCallback, + void * pCallbackContext ) +{ + CellularError_t cellularStatus = CELLULAR_SUCCESS; + CellularContext_t * pContext = ( CellularContext_t * ) cellularHandle; + + /* pContext is checked in the common library. */ + cellularStatus = Cellular_CommonRegisterUrcSignalStrengthChangedCallback( + cellularHandle, signalStrengthChangedCallback, pCallbackContext ); + + if( cellularStatus == CELLULAR_SUCCESS ) + { + if( signalStrengthChangedCallback != NULL ) + { + cellularStatus = controlSignalStrengthIndication( pContext, true ); + } + else + { + cellularStatus = controlSignalStrengthIndication( pContext, false ); + } + } + + return cellularStatus; +} + +/*-----------------------------------------------------------*/ + +/* Resolve Domain name to IP address */ + +static CellularPktStatus_t _Cellular_RecvFuncResolveDomainToIpAddress( CellularContext_t * pContext, + const CellularATCommandResponse_t * pAtResp, + void * pData, + uint16_t dataLen ) +{ + char * pRespLine = NULL; + char * pResolvedIpAddress = ( char * ) pData; + CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_OK; + CellularATError_t atCoreStatus = CELLULAR_AT_SUCCESS; + const CellularATCommandLine_t * pCommnadItem = NULL; + char * pToken = NULL; + + if( pContext == NULL ) + { + LogError( ( "_Cellular_RecvFuncResolveDomainToIpAddress: invalid context" ) ); + pktStatus = CELLULAR_PKT_STATUS_FAILURE; + } + else if( ( pResolvedIpAddress == NULL ) || ( dataLen != CELLULAR_IP_ADDRESS_MAX_SIZE ) ) + { + pktStatus = CELLULAR_PKT_STATUS_BAD_PARAM; + } + else if( pAtResp == NULL ) + { + LogError( ( "_Cellular_RecvFuncResolveDomainToIpAddress: Response is invalid" ) ); + pktStatus = CELLULAR_PKT_STATUS_FAILURE; + } + else if( ( pAtResp->pItm == NULL ) || ( pAtResp->pItm->pLine == NULL ) ) + { + LogError( ( "_Cellular_RecvFuncResolveDomainToIpAddress: Address not resolved" ) ); + pktStatus = CELLULAR_PKT_STATUS_OK; + } + else + { + pRespLine = pAtResp->pItm->pLine; + + pCommnadItem = pAtResp->pItm; + + while( pCommnadItem != NULL ) + { + pRespLine = pCommnadItem->pLine; + LogDebug( ( "_Cellular_RecvFuncResolveDomainToIpAddress: pRespLine [%s]", pRespLine ) ); + + /* Removing all the Spaces in the AT Response. */ + atCoreStatus = Cellular_ATRemoveAllWhiteSpaces( pRespLine ); + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + atCoreStatus = Cellular_ATRemovePrefix( &pRespLine ); + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + atCoreStatus = Cellular_ATRemoveAllDoubleQuote( pRespLine ); + } + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + atCoreStatus = Cellular_ATGetNextTok( &pRespLine, &pToken ); + } + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + ( void ) strncpy( pResolvedIpAddress, pToken, dataLen ); + + LogDebug( ( "_Cellular_RecvFuncResolveDomainToIpAddress: Resolved IP Address: [%s]", pResolvedIpAddress ) ); + } + } + + pktStatus = _Cellular_TranslateAtCoreStatus( atCoreStatus ); + + if( pktStatus != CELLULAR_PKT_STATUS_OK ) + { + LogError( ( "_Cellular_RecvFuncResolveDomainToIpAddress: parse %s failed", pRespLine ) ); + break; + } + + pCommnadItem = pCommnadItem->pNext; + } + } + + return pktStatus; +} + + + +/*-----------------------------------------------------------*/ + +/* FreeRTOS Cellular Library API. */ +/* coverity[misra_c_2012_rule_8_7_violation] */ +CellularError_t Cellular_GetHostByName( CellularHandle_t cellularHandle, + uint8_t contextId, + const char * pcHostName, + char * pResolvedAddress ) +{ + CellularContext_t * pContext = ( CellularContext_t * ) cellularHandle; + CellularError_t cellularStatus = CELLULAR_SUCCESS; + CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_OK; + char cmdBuf[ CELLULAR_AT_CMD_MAX_SIZE ] = { '\0' }; + + CellularAtReq_t atReqQueryDns = + { + NULL, + CELLULAR_AT_MULTI_WITH_PREFIX, + "+UDNSRN", + _Cellular_RecvFuncResolveDomainToIpAddress, + NULL, + CELLULAR_IP_ADDRESS_MAX_SIZE, + }; + + ( void ) contextId; + + /* pContext is checked in _Cellular_CheckLibraryStatus function. */ + cellularStatus = _Cellular_CheckLibraryStatus( pContext ); + + atReqQueryDns.pAtCmd = cmdBuf; + atReqQueryDns.pData = pResolvedAddress; + + if( cellularStatus != CELLULAR_SUCCESS ) + { + LogDebug( ( "Cellular_GetHostByName: _Cellular_CheckLibraryStatus failed" ) ); + } + else if( ( pcHostName == NULL ) || ( pResolvedAddress == NULL ) ) + { + LogError( ( "Cellular_GetHostByName: Bad input Parameter " ) ); + cellularStatus = CELLULAR_BAD_PARAMETER; + } + + if( cellularStatus == CELLULAR_SUCCESS ) + { + ( void ) snprintf( cmdBuf, CELLULAR_AT_CMD_MAX_SIZE, + "AT+UDNSRN=0,\"%s\"", pcHostName ); + + pktStatus = _Cellular_TimeoutAtcmdRequestWithCallback( pContext, atReqQueryDns, DNS_QUERY_REQ_TIMEOUT_MS ); + + if( pktStatus != CELLULAR_PKT_STATUS_OK ) + { + LogError( ( "Cellular_GetHostByName: couldn't resolve host name" ) ); + cellularStatus = _Cellular_TranslatePktStatus( pktStatus ); + } + } + + return cellularStatus; +} + +/*-----------------------------------------------------------*/ + +/* Get PDN context APN name*/ + +static CellularPktStatus_t _Cellular_RecvFuncGetPdpContextSettings( CellularContext_t * pContext, + const CellularATCommandResponse_t * pAtResp, + void * pData, + uint16_t dataLen ) +{ + char * pRespLine = NULL; + CellularPdnContextInfo_t * pPDPContextsInfo = ( CellularPdnContextInfo_t * ) pData; + CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_OK; + CellularATError_t atCoreStatus = CELLULAR_AT_SUCCESS; + const CellularATCommandLine_t * pCommnadItem = NULL; + uint8_t tokenIndex = 0; + uint8_t contextId = 0; + int32_t tempValue = 0; + char * pToken = NULL; + + if( pContext == NULL ) + { + LogError( ( "_Cellular_RecvFuncGetPdpContextSettings: invalid context" ) ); + pktStatus = CELLULAR_PKT_STATUS_FAILURE; + } + else if( ( pPDPContextsInfo == NULL ) || ( dataLen != sizeof( CellularPdnContextInfo_t ) ) ) + { + pktStatus = CELLULAR_PKT_STATUS_BAD_PARAM; + } + else if( pAtResp == NULL ) + { + LogError( ( "_Cellular_RecvFuncGetPdpContextSettings: Response is invalid" ) ); + pktStatus = CELLULAR_PKT_STATUS_FAILURE; + } + else if( ( pAtResp->pItm == NULL ) || ( pAtResp->pItm->pLine == NULL ) ) + { + LogError( ( "_Cellular_RecvFuncGetPdpContextSettings: no PDN context available" ) ); + pktStatus = CELLULAR_PKT_STATUS_OK; + } + else + { + pRespLine = pAtResp->pItm->pLine; + + pCommnadItem = pAtResp->pItm; + + while( pCommnadItem != NULL ) + { + pRespLine = pCommnadItem->pLine; + LogDebug( ( "_Cellular_RecvFuncGetPdpContextSettings: pRespLine [%s]", pRespLine ) ); + + /* Removing all the Spaces in the AT Response. */ + atCoreStatus = Cellular_ATRemoveAllWhiteSpaces( pRespLine ); + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + atCoreStatus = Cellular_ATRemovePrefix( &pRespLine ); + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + atCoreStatus = Cellular_ATRemoveAllDoubleQuote( pRespLine ); + } + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + atCoreStatus = Cellular_ATGetNextTok( &pRespLine, &pToken ); + } + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + tokenIndex = 0; + + while( ( pToken != NULL ) && ( atCoreStatus == CELLULAR_AT_SUCCESS ) ) + { + switch( tokenIndex ) + { + case ( CELLULAR_PDN_STATUS_POS_CONTEXT_ID ): + LogDebug( ( "_Cellular_RecvFuncGetPdpContextSettings: Context Id pToken: %s", pToken ) ); + atCoreStatus = Cellular_ATStrtoi( pToken, 10, &tempValue ); + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + if( ( tempValue >= ( int32_t ) CELLULAR_PDN_CONTEXT_ID_MIN ) && + ( tempValue <= ( int32_t ) MAX_PDP_CONTEXTS ) ) + { + contextId = ( uint8_t ) tempValue; + pPDPContextsInfo->contextsPresent[ contextId - 1 ] = true; + LogDebug( ( "_Cellular_RecvFuncGetPdpContextSettings: Context Id: %d", contextId ) ); + } + else + { + LogError( ( "_Cellular_RecvFuncGetPdpContextSettings: Invalid Context Id. Token %s", pToken ) ); + atCoreStatus = CELLULAR_AT_ERROR; + } + } + + break; + + case ( CELLULAR_PDN_STATUS_POS_CONTEXT_TYPE ): + LogDebug( ( "_Cellular_RecvFuncGetPdpContextSettings: Context Type pToken: %s", pToken ) ); + + ( void ) memcpy( ( void * ) pPDPContextsInfo->ipType[ contextId - 1 ], + ( void * ) pToken, CELULAR_PDN_CONTEXT_TYPE_MAX_SIZE + 1U ); + break; + + case ( CELLULAR_PDN_STATUS_POS_APN_NAME ): + LogDebug( ( "_Cellular_RecvFuncGetPdpContextSettings: Context APN name pToken: %s", pToken ) ); + + ( void ) memcpy( ( void * ) pPDPContextsInfo->apnName[ contextId - 1 ], + ( void * ) pToken, CELLULAR_APN_MAX_SIZE + 1U ); + break; + + case ( CELLULAR_PDN_STATUS_POS_IP_ADDRESS ): + LogDebug( ( "_Cellular_RecvFuncGetPdpContextSettings: Context IP address pToken: %s", pToken ) ); + + ( void ) memcpy( ( void * ) pPDPContextsInfo->ipAddress[ contextId - 1 ], + ( void * ) pToken, CELLULAR_IP_ADDRESS_MAX_SIZE + 1U ); + break; + + default: + break; + } + + tokenIndex++; + + if( Cellular_ATGetNextTok( &pRespLine, &pToken ) != CELLULAR_AT_SUCCESS ) + { + break; + } + } + } + } + + pktStatus = _Cellular_TranslateAtCoreStatus( atCoreStatus ); + + if( pktStatus != CELLULAR_PKT_STATUS_OK ) + { + LogError( ( "_Cellular_RecvFuncGetPdpContextSettings: parse %s failed", pRespLine ) ); + break; + } + + pCommnadItem = pCommnadItem->pNext; + } + } + + return pktStatus; +} + +/*-----------------------------------------------------------*/ + +/* Set PDN APN name and Authentication setting */ + +CellularError_t Cellular_SetPdnConfig( CellularHandle_t cellularHandle, + uint8_t contextId, + const CellularPdnConfig_t * pPdnConfig ) +{ + CellularContext_t * pContext = ( CellularContext_t * ) cellularHandle; + CellularError_t cellularStatus = CELLULAR_SUCCESS; + CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_OK; + char cmdBuf[ CELLULAR_AT_CMD_MAX_SIZE ] = { '\0' }; + char pPdpTypeStr[ CELULAR_PDN_CONTEXT_TYPE_MAX_SIZE ] = { '\0' }; + uint32_t i = 0; + + CellularPdnContextInfo_t pdpContextsInfo = { 0 }; + CellularPdnContextInfo_t * pPdpContextsInfo = &pdpContextsInfo; + + CellularAtReq_t atReqSetPdn = + { + NULL, + CELLULAR_AT_NO_RESULT, + NULL, + NULL, + NULL, + 0, + }; + + atReqSetPdn.pAtCmd = cmdBuf; + + if( pPdnConfig == NULL ) + { + LogDebug( ( "Cellular_SetPdnConfig: Input parameter is NULL" ) ); + cellularStatus = CELLULAR_BAD_PARAMETER; + } + else + { + switch( pPdnConfig->pdnContextType ) + { + case CELLULAR_PDN_CONTEXT_IPV4: + ( void ) strncpy( pPdpTypeStr, "IP", 3U ); /* 3U is the length of "IP" + '\0'. */ + break; + + case CELLULAR_PDN_CONTEXT_IPV6: + ( void ) strncpy( pPdpTypeStr, "IPV6", 5U ); /* 5U is the length of "IPV6" + '\0'. */ + break; + + case CELLULAR_PDN_CONTEXT_IPV4V6: + ( void ) strncpy( pPdpTypeStr, "IPV4V6", 7U ); /* 7U is the length of "IPV4V6" + '\0'. */ + break; + + default: + LogDebug( ( "Cellular_SetPdnConfig: Invalid pdn context type %d", + CELLULAR_PDN_CONTEXT_IPV4V6 ) ); + cellularStatus = CELLULAR_BAD_PARAMETER; + break; + } + } + + if( cellularStatus == CELLULAR_SUCCESS ) + { + cellularStatus = _Cellular_IsValidPdn( contextId ); + } + + if( cellularStatus == CELLULAR_SUCCESS ) + { + /* Make sure the library is open. */ + cellularStatus = _Cellular_CheckLibraryStatus( pContext ); + } + + if( cellularStatus == CELLULAR_SUCCESS ) + { + /* Check current APN name and IP type of contextId first to avoid unneccessary network de-registration. */ + /* TODO: This implementation currently assumes only one context in list. Need to add complete contexts list parsing */ + + CellularAtReq_t atReqGetCurrentApnName = + { + "AT+CGDCONT?", + CELLULAR_AT_MULTI_WITH_PREFIX, + "+CGDCONT", + _Cellular_RecvFuncGetPdpContextSettings, + NULL, + sizeof( CellularPdnContextInfo_t ), + }; + atReqGetCurrentApnName.pData = pPdpContextsInfo; + + pktStatus = _Cellular_AtcmdRequestWithCallback( pContext, atReqGetCurrentApnName ); + cellularStatus = _Cellular_TranslatePktStatus( pktStatus ); + + if( cellularStatus == CELLULAR_SUCCESS ) + { + LogDebug( ( "Cellular_SetPdnConfig: Listing operator and context details below." ) ); + + for( i = 0U; i < ( MAX_PDP_CONTEXTS - 1 ); i++ ) + { + /* Print only those contexts that are present in +CGDCONT response */ + if( pdpContextsInfo.contextsPresent[ i ] ) + { + LogDebug( ( "Context [%d], IP Type [%s], APN Name [%s], IP Address [%s]\r\n", i + 1, + pdpContextsInfo.ipType[ i ], ( char * ) pdpContextsInfo.apnName, + ( char * ) pdpContextsInfo.ipAddress ) ); + } + } + } + } + + if( cellularStatus == CELLULAR_SUCCESS ) + { + /* Form the AT command. */ + + /* The return value of snprintf is not used. + * The max length of the string is fixed and checked offline. */ + /* coverity[misra_c_2012_rule_21_6_violation]. */ + + if( ( strstr( pdpContextsInfo.apnName[ contextId - 1 ], pPdnConfig->apnName ) == NULL ) || ( strcmp( pdpContextsInfo.ipType[ contextId - 1 ], pPdpTypeStr ) != 0 ) ) + { + if( strcmp( pdpContextsInfo.ipType[ contextId - 1 ], pPdpTypeStr ) != 0 ) + { + LogInfo( ( "Cellular_SetPdnConfig: Setting new IPv (Module IPv:%s != %s)\r\n", pdpContextsInfo.ipType[ contextId - 1 ], pPdpTypeStr ) ); + } + + if( strstr( pdpContextsInfo.apnName[ contextId - 1 ], pPdnConfig->apnName ) == NULL ) + { + LogInfo( ( "Cellular_SetPdnConfig: Setting new APN (Module APN:%s != %s)\r\n", pdpContextsInfo.apnName[ contextId - 1 ], pPdnConfig->apnName ) ); + } + + /* TODO: Add support if + UAUTHREQ is PAP / CHAP */ + ( void ) snprintf( cmdBuf, CELLULAR_AT_CMD_MAX_SIZE, "%s%d,\"%s\",\"%s\",,0,0;%s%d,%d%s", /*,\"%s\",\"%s\" TODO: add if +UAUTHREQ is PAP/CHAP */ + "AT+COPS=2;+CGDCONT=", + contextId, + pPdpTypeStr, + pPdnConfig->apnName, + "+UAUTHREQ=", + contextId, + pPdnConfig->pdnAuthType, + ";+COPS=0" ); + /*pPdnConfig->username, */ + /*pPdnConfig->password); */ + + pktStatus = _Cellular_AtcmdRequestWithCallback( pContext, atReqSetPdn ); + + if( pktStatus != CELLULAR_PKT_STATUS_OK ) + { + LogError( ( "Cellular_SetPdnConfig: can't set PDN, cmdBuf:%s, PktRet: %d", cmdBuf, pktStatus ) ); + cellularStatus = _Cellular_TranslatePktStatus( pktStatus ); + } + } + else + { + LogInfo( ( "Cellular_SetPdnConfig: APN and IPv already set.\r\n" ) ); + } + } + + return cellularStatus; +} + +/*-----------------------------------------------------------*/ + +/* FreeRTOS Cellular Library API. */ +/* coverity[misra_c_2012_rule_8_7_violation] */ +CellularError_t Cellular_SetPsmSettings( CellularHandle_t cellularHandle, + const CellularPsmSettings_t * pPsmSettings ) +{ + CellularContext_t * pContext = ( CellularContext_t * ) cellularHandle; + CellularError_t cellularStatus = CELLULAR_SUCCESS; + CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_OK; + char cmdBuf[ CELLULAR_AT_CMD_MAX_SIZE ] = { '\0' }; + + CellularAtReq_t atReqSetPsm = + { + NULL, + CELLULAR_AT_NO_RESULT, + NULL, + NULL, + NULL, + 0 + }; + + atReqSetPsm.pAtCmd = cmdBuf; + + cellularStatus = _Cellular_CheckLibraryStatus( pContext ); + + if( cellularStatus != CELLULAR_SUCCESS ) + { + LogError( ( "Cellular_SetPsmSettings: _Cellular_CheckLibraryStatus failed" ) ); + } + else if( pPsmSettings == NULL ) + { + LogError( ( "Cellular_SetPsmSettings : Bad parameter" ) ); + cellularStatus = CELLULAR_BAD_PARAMETER; + } + else + { + if( pPsmSettings->mode == 1 ) + { + /* + * SARA-R4: To change the command setting issue AT+COPS=2 or AT+CFUN=0 to deregister the module from + * network, issue the +CPSMS command and reboot the module in order to apply the new configuration. */ + /* After PSM mode active, press "PWR_ON" key to awake modem or T3412 timer is expired. */ + ( void ) snprintf( cmdBuf, CELLULAR_AT_CMD_MAX_SIZE, "AT+CFUN=0" ); + pktStatus = _Cellular_AtcmdRequestWithCallback( pContext, atReqSetPsm ); + + if( pktStatus == CELLULAR_PKT_STATUS_OK ) + { + cellularStatus = Cellular_CommonSetPsmSettings( cellularHandle, pPsmSettings ); + + if( cellularStatus == CELLULAR_SUCCESS ) + { + cellularStatus = rebootCellularModem( pContext, false, true ); + } + else + { + LogError( ( "Cellular_SetPsmSettings: Unable to set PSM settings." ) ); + } + } + } + else + { + cellularStatus = Cellular_CommonSetPsmSettings( cellularHandle, pPsmSettings ); + } + } + + return cellularStatus; +} + +/*-----------------------------------------------------------*/ + +static CellularError_t _Cellular_isSockOptSupport( CellularSocketOptionLevel_t optionLevel, + CellularSocketOption_t option ) +{ + CellularError_t err = CELLULAR_UNSUPPORTED; + + if( ( optionLevel == CELLULAR_SOCKET_OPTION_LEVEL_TRANSPORT ) && + ( ( option == CELLULAR_SOCKET_OPTION_SEND_TIMEOUT ) || + ( option == CELLULAR_SOCKET_OPTION_RECV_TIMEOUT ) || + ( option == CELLULAR_SOCKET_OPTION_PDN_CONTEXT_ID ) ) ) + { + err = CELLULAR_SUCCESS; + } + else + { + LogWarn( ( "Cellular_SocketSetSockOpt: Option [Level:option=%d:%d] not supported in SARA R4", + optionLevel, option ) ); + } + + return err; +} + +/*-----------------------------------------------------------*/ + +/* FreeRTOS Cellular Library API. */ +/* coverity[misra_c_2012_rule_8_7_violation] */ +CellularError_t Cellular_SetEidrxSettings( CellularHandle_t cellularHandle, + const CellularEidrxSettings_t * pEidrxSettings ) +{ + CellularContext_t * pContext = ( CellularContext_t * ) cellularHandle; + CellularError_t cellularStatus = CELLULAR_SUCCESS; + CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_OK; + char cmdBuf[ CELLULAR_AT_CMD_MAX_SIZE ] = { '\0' }; + + CellularAtReq_t atReqSetEidrx = + { + NULL, + CELLULAR_AT_NO_RESULT, + NULL, + NULL, + NULL, + 0 + }; + + atReqSetEidrx.pAtCmd = cmdBuf; + + cellularStatus = _Cellular_CheckLibraryStatus( pContext ); + + if( cellularStatus != CELLULAR_SUCCESS ) + { + LogError( ( "Cellular_SetEidrxSettings: _Cellular_CheckLibraryStatus failed" ) ); + } + else if( pEidrxSettings == NULL ) + { + LogError( ( "Cellular_SetEidrxSettings : Bad parameter" ) ); + cellularStatus = CELLULAR_BAD_PARAMETER; + } + else + { + if( ( pEidrxSettings->mode == 1 ) || ( pEidrxSettings->mode == 2 ) ) + { + /* + * SARA-R4: To change the command setting issue AT+COPS=2 or AT+CFUN=0 to deregister the module from + * network, issue the +CEDRXS command and reboot the module in order to apply the new configuration. + */ + ( void ) snprintf( cmdBuf, CELLULAR_AT_CMD_MAX_SIZE, "AT+CFUN=0" ); + pktStatus = _Cellular_AtcmdRequestWithCallback( pContext, atReqSetEidrx ); + + if( pktStatus == CELLULAR_PKT_STATUS_OK ) + { + cellularStatus = Cellular_CommonSetEidrxSettings( cellularHandle, pEidrxSettings ); + + if( cellularStatus == CELLULAR_SUCCESS ) + { + cellularStatus = rebootCellularModem( pContext, true, false ); + } + else + { + LogError( ( "Cellular_SetEidrxSettings: Unable to set Eidrx settings." ) ); + } + } + } + else + { + cellularStatus = Cellular_CommonSetEidrxSettings( cellularHandle, pEidrxSettings ); + } + } + + return cellularStatus; +} + +/*-----------------------------------------------------------*/ + +CellularError_t Cellular_Init( CellularHandle_t * pCellularHandle, + const CellularCommInterface_t * pCommInterface ) +{ + CellularTokenTable_t cellularTokenTable = { 0 }; + + cellularTokenTable.pCellularUrcHandlerTable = CellularUrcHandlerTable; + cellularTokenTable.cellularPrefixToParserMapSize = CellularUrcHandlerTableSize; + cellularTokenTable.pCellularSrcTokenErrorTable = CellularSrcTokenErrorTable; + cellularTokenTable.cellularSrcTokenErrorTableSize = CellularSrcTokenErrorTableSize; + cellularTokenTable.pCellularSrcTokenSuccessTable = CellularSrcTokenSuccessTable; + cellularTokenTable.cellularSrcTokenSuccessTableSize = CellularSrcTokenSuccessTableSize; + cellularTokenTable.pCellularUrcTokenWoPrefixTable = CellularUrcTokenWoPrefixTable; + cellularTokenTable.cellularUrcTokenWoPrefixTableSize = CellularUrcTokenWoPrefixTableSize; + cellularTokenTable.pCellularSrcExtraTokenSuccessTable = NULL; + cellularTokenTable.cellularSrcExtraTokenSuccessTableSize = 0; + + return Cellular_CommonInit( pCellularHandle, pCommInterface, &cellularTokenTable ); +} + +/*-----------------------------------------------------------*/ + +/* FreeRTOS Cellular Library API. */ +CellularError_t Cellular_SocketSetSockOpt( CellularHandle_t cellularHandle, + CellularSocketHandle_t socketHandle, + CellularSocketOptionLevel_t optionLevel, + CellularSocketOption_t option, + const uint8_t * pOptionValue, + uint32_t optionValueLength ) +{ + CellularError_t err = CELLULAR_SUCCESS; + + err = _Cellular_isSockOptSupport( optionLevel, option ); + + if( err == CELLULAR_SUCCESS ) + { + err = Cellular_CommonSocketSetSockOpt( cellularHandle, socketHandle, optionLevel, option, + pOptionValue, optionValueLength ); + } + + return err; +} + +/*-----------------------------------------------------------*/ diff --git a/source/cellular_r4_urc_handler.c b/source/cellular_r4_urc_handler.c new file mode 100644 index 0000000..1030886 --- /dev/null +++ b/source/cellular_r4_urc_handler.c @@ -0,0 +1,656 @@ +/* + * FreeRTOS-Cellular-Interface v1.3.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 + */ + +#include "cellular_config.h" +#include "cellular_config_defaults.h" + +/* Standard includes. */ +#include +#include +#include + +#include "cellular_platform.h" +#include "cellular_types.h" +#include "cellular_common.h" +#include "cellular_common_api.h" +#include "cellular_common_portable.h" + +/* Cellular module includes. */ +#include "cellular_r4.h" + +/*-----------------------------------------------------------*/ + +/* +UUPSMR URC */ +#define PSM_MODE_EXIT ( 0U ) +#define PSM_MODE_ENTER ( 1U ) +#define PSM_MODE_PREVENT_ENTRY ( 2U ) +#define PSM_MODE_PREVENT_DEEP_ENTRY ( 3U ) + +/* +CIEV URC */ +#define CIEV_POS_MIN ( 1U ) +#define CIEV_POS_SIGNAL ( 2U ) +#define CIEV_POS_SERVICE ( 3U ) +#define CIEV_POS_CALL ( 6U ) +#define CIEV_POS_MAX ( 12U ) + +/*-----------------------------------------------------------*/ + +static void _cellular_UrcProcessUusoco( CellularContext_t * pContext, + char * pInputLine ); +static void _cellular_UrcProcessUusord( CellularContext_t * pContext, + char * pInputLine ); +static void _cellular_UrcProcessUusocl( CellularContext_t * pContext, + char * pInputLine ); + +static void _cellular_UrcProcessUupsmr( CellularContext_t * pContext, + char * pInputLine ); +static void _cellular_UrcProcessCiev( CellularContext_t * pContext, + char * pInputLine ); +static void _Cellular_ProcessModemRdy( CellularContext_t * pContext, + char * pInputLine ); +static CellularPktStatus_t _parseUrcIndicationCsq( CellularContext_t * pContext, + char * pUrcStr ); +static void _Cellular_UrcProcessCereg( CellularContext_t * pContext, + char * pInputLine ); +static void _Cellular_UrcProcessCgreg( CellularContext_t * pContext, + char * pInputLine ); +static void _Cellular_UrcProcessCreg( CellularContext_t * pContext, + char * pInputLine ); + +/*-----------------------------------------------------------*/ + +/* Try to Keep this map in Alphabetical order. */ +/* FreeRTOS Cellular Common Library porting interface. */ +/* coverity[misra_c_2012_rule_8_7_violation] */ +CellularAtParseTokenMap_t CellularUrcHandlerTable[] = +{ + { "CEREG", _Cellular_UrcProcessCereg }, + { "CGREG", _Cellular_UrcProcessCgreg }, + /*{ "CGEV", _cellular_UrcProcessCgev }, / * TODO: PS event reporting URC. * / */ + { "CIEV", _cellular_UrcProcessCiev }, /* PS ACT/DEACT and Signal strength status change indication URC. */ + { "CREG", _Cellular_UrcProcessCreg }, + { "RDY", _Cellular_ProcessModemRdy }, /* Modem bootup indication. */ + { "UUPSMR", _cellular_UrcProcessUupsmr }, /* Power saving mode indication URC. */ + { "UUSOCL", _cellular_UrcProcessUusocl }, /* Socket close URC. */ + { "UUSOCO", _cellular_UrcProcessUusoco }, /* Socket connect URC. */ + { "UUSORD", _cellular_UrcProcessUusord } /* Socket receive URC. */ +}; + +/* FreeRTOS Cellular Common Library porting interface. */ +/* coverity[misra_c_2012_rule_8_7_violation] */ +uint32_t CellularUrcHandlerTableSize = sizeof( CellularUrcHandlerTable ) / sizeof( CellularAtParseTokenMap_t ); + +/*-----------------------------------------------------------*/ + +/* Parse PS ACT/DEACT from +CIEV URC indication. */ +/* This URC does not tell which context ID number is ACT/DEACT. */ + +static CellularPktStatus_t _parseUrcIndicationCall( const CellularContext_t * pContext, + char * pUrcStr ) +{ + CellularATError_t atCoreStatus = CELLULAR_AT_SUCCESS; + CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_OK; + int32_t isActivated = 0; + /* In SARA-R4, usually context 1 is used for PS. */ + uint8_t contextId = 1; + + if( ( pContext == NULL ) || ( pUrcStr == NULL ) ) + { + atCoreStatus = CELLULAR_AT_BAD_PARAMETER; + } + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + atCoreStatus = Cellular_ATStrtoi( pUrcStr, 10, &isActivated ); + } + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + if( ( isActivated >= INT16_MIN ) && ( isActivated <= ( int32_t ) INT16_MAX ) ) + { + LogDebug( ( "_parseUrcIndicationCall: PS status isActivated=[%d]", isActivated ) ); + + /* Handle the callback function. */ + if( isActivated ) + { + LogDebug( ( "_parseUrcIndicationCall: PDN activated. Context Id %d", contextId ) ); + _Cellular_PdnEventCallback( pContext, CELLULAR_URC_EVENT_PDN_ACTIVATED, contextId ); + } + else + { + LogDebug( ( "_parseUrcIndicationCall: PDN deactivated. Context Id %d", contextId ) ); + _Cellular_PdnEventCallback( pContext, CELLULAR_URC_EVENT_PDN_DEACTIVATED, contextId ); + } + } + else + { + atCoreStatus = CELLULAR_AT_ERROR; + } + } + + if( atCoreStatus != CELLULAR_AT_SUCCESS ) + { + pktStatus = _Cellular_TranslateAtCoreStatus( atCoreStatus ); + } + + return pktStatus; +} + +/*-----------------------------------------------------------*/ + +/* Parse signal level from +CIEV URC indication. */ +/* This URC only gives bar level and not the exact RSSI value. */ + +static CellularPktStatus_t _parseUrcIndicationCsq( CellularContext_t * pContext, + char * pUrcStr ) +{ + CellularATError_t atCoreStatus = CELLULAR_AT_SUCCESS; + CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_OK; + int32_t retStrtoi = 0; + int16_t csqBarLevel = CELLULAR_INVALID_SIGNAL_BAR_VALUE; + CellularSignalInfo_t signalInfo = { 0 }; + + if( ( pContext == NULL ) || ( pUrcStr == NULL ) ) + { + atCoreStatus = CELLULAR_AT_BAD_PARAMETER; + } + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + atCoreStatus = Cellular_ATStrtoi( pUrcStr, 10, &retStrtoi ); + } + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + if( ( retStrtoi >= INT16_MIN ) && ( retStrtoi <= ( int32_t ) INT16_MAX ) ) + { + csqBarLevel = retStrtoi; + } + else + { + atCoreStatus = CELLULAR_AT_ERROR; + } + } + + /* Handle the callback function. */ + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + LogDebug( ( "_parseUrcIndicationCsq: SIGNAL Strength Bar level [%d]", csqBarLevel ) ); + signalInfo.rssi = CELLULAR_INVALID_SIGNAL_VALUE; + signalInfo.rsrp = CELLULAR_INVALID_SIGNAL_VALUE; + signalInfo.rsrq = CELLULAR_INVALID_SIGNAL_VALUE; + signalInfo.ber = CELLULAR_INVALID_SIGNAL_VALUE; + signalInfo.bars = csqBarLevel; + _Cellular_SignalStrengthChangedCallback( pContext, CELLULAR_URC_EVENT_SIGNAL_CHANGED, &signalInfo ); + } + + if( atCoreStatus != CELLULAR_AT_SUCCESS ) + { + pktStatus = _Cellular_TranslateAtCoreStatus( atCoreStatus ); + } + + return pktStatus; +} + +/*-----------------------------------------------------------*/ + +static void _cellular_UrcProcessCiev( CellularContext_t * pContext, + char * pInputLine ) +{ + char * pUrcStr = NULL, * pToken = NULL; + CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_OK; + CellularATError_t atCoreStatus = CELLULAR_AT_SUCCESS; + int32_t tempValue = 0; + uint8_t indicatorDescr = 0; + + /* Check context status. */ + if( pContext == NULL ) + { + pktStatus = CELLULAR_PKT_STATUS_FAILURE; + } + else if( pInputLine == NULL ) + { + pktStatus = CELLULAR_PKT_STATUS_BAD_PARAM; + } + else + { + pUrcStr = pInputLine; + atCoreStatus = Cellular_ATRemoveAllDoubleQuote( pUrcStr ); + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + atCoreStatus = Cellular_ATRemoveLeadingWhiteSpaces( &pUrcStr ); + } + + /* Extract indicator */ + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + atCoreStatus = Cellular_ATGetNextTok( &pUrcStr, &pToken ); + } + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + atCoreStatus = Cellular_ATStrtoi( pToken, 10, &tempValue ); + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + if( ( tempValue >= ( ( int32_t ) CIEV_POS_MIN ) ) && ( tempValue <= ( ( int32_t ) CIEV_POS_MAX ) ) ) + { + indicatorDescr = ( uint8_t ) tempValue; + + switch( indicatorDescr ) + { + case CIEV_POS_SIGNAL: + LogDebug( ( "_cellular_UrcProcessCiev: CIEV_POS_SIGNAL" ) ); + /* This URC only gives bar level and not the exact RSSI value. */ + + /* + * o 0: < -105 dBm + * o 1 : < -93 dBm + * o 2 : < -81 dBm + * o 3 : < -69 dBm + * o 4 : < -57 dBm + * o 5 : >= -57 dBm + */ + /* Parse the signal Bar level from string. */ + pktStatus = _parseUrcIndicationCsq( pContext, pUrcStr ); + break; + + case CIEV_POS_CALL: + LogDebug( ( "_cellular_UrcProcessCiev: CIEV_POS_CALL" ) ); + /* Parse PS ACT/DEACT from +CIEV URC indication. */ + /* This URC does not tell which context ID number is ACT/DEACT. */ + pktStatus = _parseUrcIndicationCall( ( const CellularContext_t * ) pContext, pUrcStr ); + break; + + default: + break; + } + } + else + { + LogError( ( "_cellular_UrcProcessCiev: parsing failed" ) ); + atCoreStatus = CELLULAR_AT_ERROR; + } + } + } + + if( atCoreStatus != CELLULAR_AT_SUCCESS ) + { + pktStatus = _Cellular_TranslateAtCoreStatus( atCoreStatus ); + } + } + + if( pktStatus != CELLULAR_PKT_STATUS_OK ) + { + LogDebug( ( "_cellular_UrcProcessCiev: Parse failure" ) ); + } +} + +/*-----------------------------------------------------------*/ + +static void _cellular_UrcProcessUupsmr( CellularContext_t * pContext, + char * pInputLine ) +{ + CellularATError_t atCoreStatus = CELLULAR_AT_SUCCESS; + char * pLocalInputLine = pInputLine; + char * pToken = NULL; + uint8_t psmState = 0; + int32_t tempValue = 0; + + if( ( pContext != NULL ) && ( pInputLine != NULL ) ) + { + /* The inputline is in this format +UUPSMR: [,] */ + atCoreStatus = Cellular_ATGetNextTok( &pLocalInputLine, &pToken ); + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + atCoreStatus = Cellular_ATStrtoi( pToken, 10, &tempValue ); + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + if( ( tempValue >= ( ( int32_t ) PSM_MODE_EXIT ) ) && ( tempValue <= ( ( int32_t ) PSM_MODE_PREVENT_DEEP_ENTRY ) ) ) + { + psmState = ( uint8_t ) tempValue; + + switch( psmState ) + { + case PSM_MODE_EXIT: + LogInfo( ( "_cellular_UrcProcessUupsmr: PSM_MODE_EXIT" ) ); + break; + + case PSM_MODE_ENTER: + LogInfo( ( "_cellular_UrcProcessUupsmr: PSM_MODE_ENTER event received" ) ); + /* Call the callback function. Indicate the upper layer about the PSM state change. */ + _Cellular_ModemEventCallback( pContext, CELLULAR_MODEM_EVENT_PSM_ENTER ); + break; + + case PSM_MODE_PREVENT_ENTRY: + LogInfo( ( "_cellular_UrcProcessUupsmr: PSM_MODE_PREVENT_ENTRY" ) ); + break; + + case PSM_MODE_PREVENT_DEEP_ENTRY: + LogInfo( ( "_cellular_UrcProcessUupsmr: PSM_MODE_PREVENT_DEEP_ENTRY" ) ); + break; + } + } + else + { + LogError( ( "_cellular_UrcProcessUupsmr: parsing failed" ) ); + atCoreStatus = CELLULAR_AT_ERROR; + } + } + } + } +} + +/*-----------------------------------------------------------*/ + +static void _cellular_UrcProcessUusoco( CellularContext_t * pContext, + char * pInputLine ) +{ + CellularATError_t atCoreStatus = CELLULAR_AT_SUCCESS; + char * pLocalInputLine = pInputLine; + char * pToken = NULL; + CellularSocketContext_t * pSocketData = NULL; + uint8_t sessionId = 0; + uint8_t socketError = 0; + uint32_t socketIndex = 0; + int32_t tempValue = 0; + + if( ( pContext != NULL ) && ( pInputLine != NULL ) ) + { + /* The inputline is in this format +UUSOCO: , + * socket_error = 0 : no error, others : error. */ + atCoreStatus = Cellular_ATGetNextTok( &pLocalInputLine, &pToken ); + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + atCoreStatus = Cellular_ATStrtoi( pToken, 10, &tempValue ); + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + if( ( tempValue >= MIN_TCP_SESSION_ID ) && ( tempValue <= MAX_TCP_SESSION_ID ) ) + { + sessionId = ( uint8_t ) tempValue; + socketIndex = _Cellular_GetSocketId( pContext, sessionId ); + } + else + { + LogError( ( "parsing _cellular_UrcProcessKtcpInd session ID failed" ) ); + atCoreStatus = CELLULAR_AT_ERROR; + } + } + } + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + atCoreStatus = Cellular_ATGetNextTok( &pLocalInputLine, &pToken ); + } + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + atCoreStatus = Cellular_ATStrtoi( pToken, 10, &tempValue ); + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + if( ( tempValue >= 0 ) && ( tempValue <= UINT8_MAX ) ) + { + socketError = ( uint8_t ) tempValue; + } + else + { + LogError( ( "parsing _cellular_UrcProcessUusoco socket error failed" ) ); + atCoreStatus = CELLULAR_AT_ERROR; + } + } + } + + /* Call the callback function of this session. */ + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + pSocketData = _Cellular_GetSocketData( pContext, socketIndex ); + + if( pSocketData == NULL ) + { + LogError( ( "_cellular_UrcProcessUusoco : invalid socket index %u", socketIndex ) ); + } + else + { + if( socketError == 0 ) + { + pSocketData->socketState = SOCKETSTATE_CONNECTED; + LogDebug( ( "Notify session %d with socket opened\r\n", sessionId ) ); + + if( pSocketData->openCallback != NULL ) + { + pSocketData->openCallback( CELLULAR_URC_SOCKET_OPENED, + pSocketData, pSocketData->pOpenCallbackContext ); + } + } + else + { + if( pSocketData->openCallback != NULL ) + { + pSocketData->openCallback( CELLULAR_URC_SOCKET_OPEN_FAILED, + pSocketData, pSocketData->pOpenCallbackContext ); + } + } + } + } + } +} + +/*-----------------------------------------------------------*/ + +static void _cellular_UrcProcessUusord( CellularContext_t * pContext, + char * pInputLine ) +{ + CellularATError_t atCoreStatus = CELLULAR_AT_SUCCESS; + char * pLocalInputLine = pInputLine; + char * pToken = NULL; + CellularSocketContext_t * pSocketData = NULL; + uint8_t sessionId = 0; + uint32_t socketIndex = 0; + int32_t tempValue = 0; + + if( ( pContext != NULL ) && ( pInputLine != NULL ) ) + { + /* The inputline is in this format +UUSOCO: , */ + atCoreStatus = Cellular_ATGetNextTok( &pLocalInputLine, &pToken ); + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + atCoreStatus = Cellular_ATStrtoi( pToken, 10, &tempValue ); + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + if( ( tempValue >= MIN_TCP_SESSION_ID ) && ( tempValue <= MAX_TCP_SESSION_ID ) ) + { + sessionId = ( uint8_t ) tempValue; + socketIndex = _Cellular_GetSocketId( pContext, sessionId ); + } + else + { + LogError( ( "parsing _cellular_UrcProcessUusord session ID failed" ) ); + atCoreStatus = CELLULAR_AT_ERROR; + } + } + } + + /* Skip data length. */ + + /* Call the callback function of this session. */ + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + if( socketIndex == INVALID_SOCKET_INDEX ) + { + LogWarn( ( "_cellular_UrcProcessUusord : unknown session data received. " + "The session %u may not be closed properly in previous execution.", sessionId ) ); + } + else + { + pSocketData = _Cellular_GetSocketData( pContext, socketIndex ); + + if( pSocketData == NULL ) + { + LogError( ( "_cellular_UrcProcessUusord : invalid socket index %d", socketIndex ) ); + } + else + { + /* Indicate the upper layer about the data reception. */ + if( pSocketData->dataReadyCallback != NULL ) + { + pSocketData->dataReadyCallback( pSocketData, pSocketData->pDataReadyCallbackContext ); + } + else + { + LogDebug( ( "_cellular_UrcProcessUusord: Data ready callback not set!!" ) ); + } + } + } + } + } +} + +/*-----------------------------------------------------------*/ + +static void _cellular_UrcProcessUusocl( CellularContext_t * pContext, + char * pInputLine ) +{ + CellularATError_t atCoreStatus = CELLULAR_AT_SUCCESS; + char * pLocalInputLine = pInputLine; + char * pToken = NULL; + CellularSocketContext_t * pSocketData = NULL; + uint8_t sessionId = 0; + uint32_t socketIndex = 0; + int32_t tempValue = 0; + + if( ( pContext != NULL ) && ( pInputLine != NULL ) ) + { + /* The inputline is in this format +UUSOCL: */ + atCoreStatus = Cellular_ATGetNextTok( &pLocalInputLine, &pToken ); + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + atCoreStatus = Cellular_ATStrtoi( pToken, 10, &tempValue ); + + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + if( ( tempValue >= MIN_TCP_SESSION_ID ) && ( tempValue <= MAX_TCP_SESSION_ID ) ) + { + sessionId = ( uint8_t ) tempValue; + socketIndex = _Cellular_GetSocketId( pContext, sessionId ); + } + else + { + LogError( ( "parsing _cellular_UrcProcessUusocl session ID failed" ) ); + atCoreStatus = CELLULAR_AT_ERROR; + } + } + } + + /* Call the callback function of this session. */ + if( atCoreStatus == CELLULAR_AT_SUCCESS ) + { + if( socketIndex == INVALID_SOCKET_INDEX ) + { + LogWarn( ( "_cellular_UrcProcessUusocl : unknown session closed URC received. " + "The session %u may not be closed properly in previous execution.", sessionId ) ); + } + else + { + pSocketData = _Cellular_GetSocketData( pContext, socketIndex ); + + if( pSocketData == NULL ) + { + LogError( ( "_cellular_UrcProcessUusocl : invalid socket index %d", socketIndex ) ); + } + else + { + /* Change the socket state to disconnected. */ + pSocketData->socketState = SOCKETSTATE_DISCONNECTED; + + /* Indicate the upper layer about the data reception. */ + if( pSocketData->closedCallback != NULL ) + { + pSocketData->closedCallback( pSocketData, pSocketData->pClosedCallbackContext ); + } + else + { + LogDebug( ( "_cellular_UrcProcessUusord: Data ready callback not set!!" ) ); + } + } + } + } + } +} + +/*-----------------------------------------------------------*/ + +/* Modem bootup indication. */ + +static void _Cellular_ProcessModemRdy( CellularContext_t * pContext, + char * pInputLine ) +{ + /* The token is the pInputLine. No need to process the pInputLine. */ + ( void ) pInputLine; + + if( pContext == NULL ) + { + LogWarn( ( "_Cellular_ProcessModemRdy: Context not set" ) ); + } + else + { + LogDebug( ( "_Cellular_ProcessModemRdy: Modem Ready event received" ) ); + _Cellular_ModemEventCallback( pContext, CELLULAR_MODEM_EVENT_BOOTUP_OR_REBOOT ); + } +} + +/*-----------------------------------------------------------*/ + +static void _Cellular_UrcProcessCereg( CellularContext_t * pContext, + char * pInputLine ) +{ + ( void ) Cellular_CommonUrcProcessCereg( pContext, pInputLine ); +} + +/*-----------------------------------------------------------*/ + +static void _Cellular_UrcProcessCgreg( CellularContext_t * pContext, + char * pInputLine ) +{ + ( void ) Cellular_CommonUrcProcessCgreg( pContext, pInputLine ); +} + +/*-----------------------------------------------------------*/ + +static void _Cellular_UrcProcessCreg( CellularContext_t * pContext, + char * pInputLine ) +{ + ( void ) Cellular_CommonUrcProcessCreg( pContext, pInputLine ); +} + +/*-----------------------------------------------------------*/ diff --git a/source/cellular_r4_wrapper.c b/source/cellular_r4_wrapper.c new file mode 100644 index 0000000..b0eb9ce --- /dev/null +++ b/source/cellular_r4_wrapper.c @@ -0,0 +1,263 @@ +/* + * FreeRTOS-Cellular-Interface v1.3.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 + */ + +/* The config header is always included first. */ +#include "cellular_config.h" +#include "cellular_config_defaults.h" + +/* Standard includes. */ +#include +#include + +#include "cellular_platform.h" +#include "cellular_types.h" +#include "cellular_api.h" +#include "cellular_common.h" +#include "cellular_common_api.h" + +/*-----------------------------------------------------------*/ + +/* FreeRTOS Cellular Library API. */ +/* coverity[misra_c_2012_rule_8_7_violation] */ +CellularError_t Cellular_Cleanup( CellularHandle_t cellularHandle ) +{ + return Cellular_CommonCleanup( cellularHandle ); +} + +/*-----------------------------------------------------------*/ + +/* FreeRTOS Cellular Library API. */ +/* coverity[misra_c_2012_rule_8_7_violation] */ +CellularError_t Cellular_RegisterUrcNetworkRegistrationEventCallback( CellularHandle_t cellularHandle, + CellularUrcNetworkRegistrationCallback_t networkRegistrationCallback, + void * pCallbackContext ) +{ + return Cellular_CommonRegisterUrcNetworkRegistrationEventCallback( cellularHandle, networkRegistrationCallback, pCallbackContext ); +} + +/*-----------------------------------------------------------*/ + +/* FreeRTOS Cellular Library API. */ +/* coverity[misra_c_2012_rule_8_7_violation] */ +CellularError_t Cellular_RegisterUrcPdnEventCallback( CellularHandle_t cellularHandle, + CellularUrcPdnEventCallback_t pdnEventCallback, + void * pCallbackContext ) +{ + return Cellular_CommonRegisterUrcPdnEventCallback( cellularHandle, pdnEventCallback, pCallbackContext ); +} + +/*-----------------------------------------------------------*/ + +/* FreeRTOS Cellular Library API. */ +/* coverity[misra_c_2012_rule_8_7_violation] */ +CellularError_t Cellular_RegisterUrcGenericCallback( CellularHandle_t cellularHandle, + CellularUrcGenericCallback_t genericCallback, + void * pCallbackContext ) +{ + return Cellular_CommonRegisterUrcGenericCallback( cellularHandle, genericCallback, pCallbackContext ); +} + +/*-----------------------------------------------------------*/ + +/* FreeRTOS Cellular Library API. */ +/* coverity[misra_c_2012_rule_8_7_violation] */ +CellularError_t Cellular_RegisterModemEventCallback( CellularHandle_t cellularHandle, + CellularModemEventCallback_t modemEventCallback, + void * pCallbackContext ) +{ + return Cellular_CommonRegisterModemEventCallback( cellularHandle, modemEventCallback, pCallbackContext ); +} + +/*-----------------------------------------------------------*/ + +/* FreeRTOS Cellular Library API. */ +/* coverity[misra_c_2012_rule_8_7_violation] */ +CellularError_t Cellular_ATCommandRaw( CellularHandle_t cellularHandle, + const char * pATCommandPrefix, + const char * pATCommandPayload, + CellularATCommandType_t atCommandType, + CellularATCommandResponseReceivedCallback_t responseReceivedCallback, + void * pData, + uint16_t dataLen ) +{ + return Cellular_CommonATCommandRaw( cellularHandle, pATCommandPrefix, pATCommandPayload, atCommandType, + responseReceivedCallback, pData, dataLen ); +} + +/*-----------------------------------------------------------*/ + +/* FreeRTOS Cellular Library API. */ +/* coverity[misra_c_2012_rule_8_7_violation] */ +CellularError_t Cellular_CreateSocket( CellularHandle_t cellularHandle, + uint8_t pdnContextId, + CellularSocketDomain_t socketDomain, + CellularSocketType_t socketType, + CellularSocketProtocol_t socketProtocol, + CellularSocketHandle_t * pSocketHandle ) +{ + return Cellular_CommonCreateSocket( cellularHandle, pdnContextId, socketDomain, socketType, + socketProtocol, pSocketHandle ); +} + +/*-----------------------------------------------------------*/ + +/* FreeRTOS Cellular Library API. */ +/* coverity[misra_c_2012_rule_8_7_violation] */ +CellularError_t Cellular_SocketRegisterDataReadyCallback( CellularHandle_t cellularHandle, + CellularSocketHandle_t socketHandle, + CellularSocketDataReadyCallback_t dataReadyCallback, + void * pCallbackContext ) +{ + return Cellular_CommonSocketRegisterDataReadyCallback( cellularHandle, socketHandle, + dataReadyCallback, pCallbackContext ); +} + +/*-----------------------------------------------------------*/ + +/* FreeRTOS Cellular Library API. */ +/* coverity[misra_c_2012_rule_8_7_violation] */ +CellularError_t Cellular_SocketRegisterSocketOpenCallback( CellularHandle_t cellularHandle, + CellularSocketHandle_t socketHandle, + CellularSocketOpenCallback_t socketOpenCallback, + void * pCallbackContext ) +{ + return Cellular_CommonSocketRegisterSocketOpenCallback( cellularHandle, socketHandle, + socketOpenCallback, pCallbackContext ); +} + +/*-----------------------------------------------------------*/ + +/* FreeRTOS Cellular Library API. */ +/* coverity[misra_c_2012_rule_8_7_violation] */ +CellularError_t Cellular_SocketRegisterClosedCallback( CellularHandle_t cellularHandle, + CellularSocketHandle_t socketHandle, + CellularSocketClosedCallback_t closedCallback, + void * pCallbackContext ) +{ + return Cellular_CommonSocketRegisterClosedCallback( cellularHandle, socketHandle, + closedCallback, pCallbackContext ); +} + +/*-----------------------------------------------------------*/ + +/* FreeRTOS Cellular Library API. */ +/* coverity[misra_c_2012_rule_8_7_violation] */ +CellularError_t Cellular_RfOn( CellularHandle_t cellularHandle ) +{ + return Cellular_CommonRfOn( cellularHandle ); +} + +/*-----------------------------------------------------------*/ + +/* FreeRTOS Cellular Library API. */ +/* coverity[misra_c_2012_rule_8_7_violation] */ +CellularError_t Cellular_RfOff( CellularHandle_t cellularHandle ) +{ + return Cellular_CommonRfOff( cellularHandle ); +} + +/*-----------------------------------------------------------*/ + +/* FreeRTOS Cellular Library API. */ +/* coverity[misra_c_2012_rule_8_7_violation] */ +CellularError_t Cellular_GetIPAddress( CellularHandle_t cellularHandle, + uint8_t contextId, + char * pBuffer, + uint32_t bufferLength ) +{ + return Cellular_CommonGetIPAddress( cellularHandle, contextId, pBuffer, bufferLength ); +} + +/*-----------------------------------------------------------*/ + +/* FreeRTOS Cellular Library API. */ +/* coverity[misra_c_2012_rule_8_7_violation] */ +CellularError_t Cellular_GetModemInfo( CellularHandle_t cellularHandle, + CellularModemInfo_t * pModemInfo ) +{ + return Cellular_CommonGetModemInfo( cellularHandle, pModemInfo ); +} + +/*-----------------------------------------------------------*/ + +/* FreeRTOS Cellular Library API. */ +/* coverity[misra_c_2012_rule_8_7_violation] */ +CellularError_t Cellular_GetRegisteredNetwork( CellularHandle_t cellularHandle, + CellularPlmnInfo_t * pNetworkInfo ) +{ + return Cellular_CommonGetRegisteredNetwork( cellularHandle, pNetworkInfo ); +} + +/*-----------------------------------------------------------*/ + +/* FreeRTOS Cellular Library API. */ +/* coverity[misra_c_2012_rule_8_7_violation] */ +CellularError_t Cellular_GetNetworkTime( CellularHandle_t cellularHandle, + CellularTime_t * pNetworkTime ) +{ + return Cellular_CommonGetNetworkTime( cellularHandle, pNetworkTime ); +} + +/*-----------------------------------------------------------*/ + +/* FreeRTOS Cellular Library API. */ +/* coverity[misra_c_2012_rule_8_7_violation] */ +CellularError_t Cellular_GetServiceStatus( CellularHandle_t cellularHandle, + CellularServiceStatus_t * pServiceStatus ) +{ + return Cellular_CommonGetServiceStatus( cellularHandle, pServiceStatus ); +} + +/*-----------------------------------------------------------*/ + +/* FreeRTOS Cellular Library API. */ +/* coverity[misra_c_2012_rule_8_7_violation] */ +CellularError_t Cellular_GetSimCardInfo( CellularHandle_t cellularHandle, + CellularSimCardInfo_t * pSimCardInfo ) +{ + return Cellular_CommonGetSimCardInfo( cellularHandle, pSimCardInfo ); +} + +/*-----------------------------------------------------------*/ + +/* FreeRTOS Cellular Library API. */ +/* coverity[misra_c_2012_rule_8_7_violation] */ +CellularError_t Cellular_GetPsmSettings( CellularHandle_t cellularHandle, + CellularPsmSettings_t * pPsmSettings ) +{ + return Cellular_CommonGetPsmSettings( cellularHandle, pPsmSettings ); +} + +/*-----------------------------------------------------------*/ + +/* FreeRTOS Cellular Library API. */ +/* coverity[misra_c_2012_rule_8_7_violation] */ +CellularError_t Cellular_GetEidrxSettings( CellularHandle_t cellularHandle, + CellularEidrxSettingsList_t * pEidrxSettingsList ) +{ + return Cellular_CommonGetEidrxSettings( cellularHandle, pEidrxSettingsList ); +} + +/*-----------------------------------------------------------*/ From f1234a8891352bcd59ff2c6f6113df0241a4006b Mon Sep 17 00:00:00 2001 From: ActoryOu Date: Mon, 3 Oct 2022 17:13:30 +0800 Subject: [PATCH 3/4] Update License to MIT and add use case in README. --- LICENSE | 30 ++++++++++++++++++------------ README.md | 8 ++++++-- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/LICENSE b/LICENSE index 1bb4f21..0f54a4b 100644 --- a/LICENSE +++ b/LICENSE @@ -1,15 +1,21 @@ -Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +MIT License -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. +Copyright (c) 2022 Amazon.com, Inc. or its affiliates -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. +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. \ No newline at end of file diff --git a/README.md b/README.md index 4197ce9..fe1779e 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,13 @@ -# FreeRTOS Cellular Interface Reference Implementation U-Blox Sara-R4 +# FreeRTOS Cellular Interface Reference U-Blox Sara-R4 ## Introduction This repository provides the reference implementation as cellular module ports for [U-Blox Sara-R4](https://www.u-blox.com/en/product/sara-r4-series). This repository should be used with [FreeRTOS-Cellular-Interface](https://github.com/FreeRTOS/FreeRTOS-Cellular-Interface). See [FreeRTOS-Cellular-Interface README](https://github.com/FreeRTOS/FreeRTOS-Cellular-Interface/blob/main/README.md) for more details. +## Use Case + +There is also an use case at [MQTT_Mutual_Auth_Demo_with_SARA_R4](https://github.com/FreeRTOS/FreeRTOS/tree/main/FreeRTOS-Plus/Demo/FreeRTOS_Cellular_Interface_Windows_Simulator/MQTT_Mutual_Auth_Demo_with_SARA_R4) as a demonstration to run BG96 with FreeRTOS Windows Simulator. + ## How Does Community Members to Contribute a Cellular Module Port We provide a repository, [FreeRTOS-Cellular-Interface-Community-Supported-Ports](https://github.com/FreeRTOS/FreeRTOS-Cellular-Interface-Community-Supported-Ports), for community members to contribute their modules. See [How to Contribute a Cellular Module Port](https://github.com/FreeRTOS/FreeRTOS-Cellular-Interface-Community-Supported-Ports#how-to-contribute-a-cellular-module-port) for more details. @@ -14,4 +18,4 @@ See [CONTRIBUTING](CONTRIBUTING.md#security-issue-notifications) for more inform ## License -This library is licensed under the MIT-0 License. See the [LICENSE](https://github.com/FreeRTOS/freertos-cellular-interface-reference-implementation-ublox-sara-r4/blob/main/LICENSE) file. +The FreeRTOS Cellular Interface library is distributed under MIT open source license. The code in this repository is licensed under the MIT License. See the [LICENSE](https://github.com/FreeRTOS/FreeRTOS-Cellular-Interface-Reference-ublox-SARA-R4/blob/main/LICENSE) file. From 8d1f610e555154f6485ca421845ec28f5b26f326 Mon Sep 17 00:00:00 2001 From: ActoryOu Date: Tue, 4 Oct 2022 10:41:48 +0800 Subject: [PATCH 4/4] Add Lab prefix. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fe1779e..a6ebef4 100644 --- a/README.md +++ b/README.md @@ -18,4 +18,4 @@ See [CONTRIBUTING](CONTRIBUTING.md#security-issue-notifications) for more inform ## License -The FreeRTOS Cellular Interface library is distributed under MIT open source license. The code in this repository is licensed under the MIT License. See the [LICENSE](https://github.com/FreeRTOS/FreeRTOS-Cellular-Interface-Reference-ublox-SARA-R4/blob/main/LICENSE) file. +The FreeRTOS Cellular Interface library is distributed under MIT open source license. The code in this repository is licensed under the MIT License. See the [LICENSE](LICENSE) file.