/* * FreeRTOS-Cellular-Interface v1.3.0 * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * https://www.FreeRTOS.org * https://github.com/FreeRTOS */ /** * @brief FreeRTOS Cellular Library APIs implementation without AT commands. */ /* The config header is always included first. */ #ifndef CELLULAR_DO_NOT_USE_CUSTOM_CONFIG /* Include custom config file before other headers. */ #include "cellular_config.h" #endif #include "cellular_config_defaults.h" /* Standard includes. */ #include #include #include "cellular_platform.h" #include "cellular_types.h" #include "cellular_api.h" #include "cellular_internal.h" #include "cellular_common_internal.h" #include "cellular_pkthandler_internal.h" #include "cellular_pktio_internal.h" #include "cellular_common_portable.h" #include "cellular_common_api.h" /*-----------------------------------------------------------*/ static CellularError_t _socketSetSockOptLevelTransport( CellularSocketOption_t option, CellularSocketHandle_t socketHandle, const uint8_t * pOptionValue, uint32_t optionValueLength ); /*-----------------------------------------------------------*/ /* Internal function of Cellular_SocketSetSockOpt to reduce complexity. */ static CellularError_t _socketSetSockOptLevelTransport( CellularSocketOption_t option, CellularSocketHandle_t socketHandle, const uint8_t * pOptionValue, uint32_t optionValueLength ) { CellularError_t cellularStatus = CELLULAR_SUCCESS; const uint32_t * pTimeoutMs = NULL; if( option == CELLULAR_SOCKET_OPTION_SEND_TIMEOUT ) { if( optionValueLength == sizeof( uint32_t ) ) { /* MISRA Ref 11.3 [Misaligned access] */ /* More details at: https://github.com/FreeRTOS/FreeRTOS-Cellular-Interface/blob/main/MISRA.md#rule-113 */ /* coverity[misra_c_2012_rule_11_3_violation] */ pTimeoutMs = ( const uint32_t * ) pOptionValue; socketHandle->sendTimeoutMs = *pTimeoutMs; } else { cellularStatus = CELLULAR_INTERNAL_FAILURE; } } else if( option == CELLULAR_SOCKET_OPTION_RECV_TIMEOUT ) { if( optionValueLength == sizeof( uint32_t ) ) { /* MISRA Ref 11.3 [Misaligned access] */ /* More details at: https://github.com/FreeRTOS/FreeRTOS-Cellular-Interface/blob/main/MISRA.md#rule-113 */ /* coverity[misra_c_2012_rule_11_3_violation] */ pTimeoutMs = ( const uint32_t * ) pOptionValue; socketHandle->recvTimeoutMs = *pTimeoutMs; } else { cellularStatus = CELLULAR_INTERNAL_FAILURE; } } else if( option == CELLULAR_SOCKET_OPTION_PDN_CONTEXT_ID ) { if( ( socketHandle->socketState == SOCKETSTATE_ALLOCATED ) && ( optionValueLength == sizeof( uint8_t ) ) ) { socketHandle->contextId = *pOptionValue; } else { LogError( ( "Cellular_SocketSetSockOpt: Cannot change the contextID in this state %d or length %d is invalid.", socketHandle->socketState, optionValueLength ) ); cellularStatus = CELLULAR_INTERNAL_FAILURE; } } else if( option == CELLULAR_SOCKET_OPTION_SET_LOCAL_PORT ) { if( ( socketHandle->socketState == SOCKETSTATE_ALLOCATED ) && ( optionValueLength == sizeof( uint16_t ) ) ) { /* MISRA Ref 11.3 [Misaligned access] */ /* More details at: https://github.com/FreeRTOS/FreeRTOS-Cellular-Interface/blob/main/MISRA.md#rule-113 */ /* coverity[misra_c_2012_rule_11_3_violation] */ socketHandle->localPort = *( ( uint16_t * ) pOptionValue ); } else { LogError( ( "Cellular_SocketSetSockOpt: Cannot change the localPort in this state %d or length %d is invalid.", socketHandle->socketState, optionValueLength ) ); cellularStatus = CELLULAR_INTERNAL_FAILURE; } } else { LogError( ( "Cellular_SocketSetSockOpt: Option not supported" ) ); cellularStatus = CELLULAR_UNSUPPORTED; } return cellularStatus; } /*-----------------------------------------------------------*/ CellularError_t Cellular_CommonInit( CellularHandle_t * pCellularHandle, const CellularCommInterface_t * pCommInterface, const CellularTokenTable_t * pTokenTable ) { CellularError_t cellularStatus = CELLULAR_SUCCESS; CellularContext_t * pContext = NULL; /* Init the common library. */ cellularStatus = _Cellular_LibInit( pCellularHandle, pCommInterface, pTokenTable ); /* Init the module. */ if( cellularStatus == CELLULAR_SUCCESS ) { pContext = *pCellularHandle; cellularStatus = Cellular_ModuleInit( pContext, &pContext->pModuleContext ); } /* Setup UE, URC and query register status. */ if( cellularStatus == CELLULAR_SUCCESS ) { cellularStatus = Cellular_ModuleEnableUE( pContext ); } if( cellularStatus == CELLULAR_SUCCESS ) { cellularStatus = Cellular_ModuleEnableUrc( pContext ); } return cellularStatus; } /*-----------------------------------------------------------*/ CellularError_t Cellular_CommonCleanup( CellularHandle_t cellularHandle ) { CellularContext_t * pContext = ( CellularContext_t * ) cellularHandle; CellularError_t cellularStatus = CELLULAR_SUCCESS; if( pContext == NULL ) { cellularStatus = CELLULAR_INVALID_HANDLE; } else { ( void ) Cellular_ModuleCleanUp( pContext ); ( void ) _Cellular_LibCleanup( cellularHandle ); } return cellularStatus; } /*-----------------------------------------------------------*/ CellularError_t Cellular_CommonRegisterUrcNetworkRegistrationEventCallback( CellularHandle_t cellularHandle, CellularUrcNetworkRegistrationCallback_t networkRegistrationCallback, void * pCallbackContext ) { 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_CheckLibraryStatus failed" ) ); } else { PlatformMutex_Lock( &pContext->PktRespMutex ); pContext->cbEvents.networkRegistrationCallback = networkRegistrationCallback; pContext->cbEvents.pNetworkRegistrationCallbackContext = pCallbackContext; PlatformMutex_Unlock( &pContext->PktRespMutex ); } return cellularStatus; } /*-----------------------------------------------------------*/ CellularError_t Cellular_CommonRegisterUrcPdnEventCallback( CellularHandle_t cellularHandle, CellularUrcPdnEventCallback_t pdnEventCallback, void * pCallbackContext ) { 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_CheckLibraryStatus failed" ) ); } else { PlatformMutex_Lock( &pContext->PktRespMutex ); pContext->cbEvents.pdnEventCallback = pdnEventCallback; pContext->cbEvents.pPdnEventCallbackContext = pCallbackContext; PlatformMutex_Unlock( &pContext->PktRespMutex ); } return cellularStatus; } /*-----------------------------------------------------------*/ CellularError_t Cellular_CommonRegisterUrcSignalStrengthChangedCallback( CellularHandle_t cellularHandle, CellularUrcSignalStrengthChangedCallback_t signalStrengthChangedCallback, void * pCallbackContext ) { 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_CheckLibraryStatus failed" ) ); } else { PlatformMutex_Lock( &pContext->PktRespMutex ); pContext->cbEvents.signalStrengthChangedCallback = signalStrengthChangedCallback; pContext->cbEvents.pSignalStrengthChangedCallbackContext = pCallbackContext; PlatformMutex_Unlock( &pContext->PktRespMutex ); } return cellularStatus; } /*-----------------------------------------------------------*/ CellularError_t Cellular_CommonRegisterUrcGenericCallback( CellularHandle_t cellularHandle, CellularUrcGenericCallback_t genericCallback, void * pCallbackContext ) { 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_CheckLibraryStatus failed" ) ); } else { PlatformMutex_Lock( &pContext->PktRespMutex ); pContext->cbEvents.genericCallback = genericCallback; pContext->cbEvents.pGenericCallbackContext = pCallbackContext; PlatformMutex_Unlock( &pContext->PktRespMutex ); } return cellularStatus; } /*-----------------------------------------------------------*/ CellularError_t Cellular_CommonRegisterModemEventCallback( CellularHandle_t cellularHandle, CellularModemEventCallback_t modemEventCallback, void * pCallbackContext ) { 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_CheckLibraryStatus failed" ) ); } else { PlatformMutex_Lock( &pContext->PktRespMutex ); pContext->cbEvents.modemEventCallback = modemEventCallback; pContext->cbEvents.pModemEventCallbackContext = pCallbackContext; PlatformMutex_Unlock( &pContext->PktRespMutex ); } return cellularStatus; } /*-----------------------------------------------------------*/ CellularError_t Cellular_CommonATCommandRaw( CellularHandle_t cellularHandle, const char * pATCommandPrefix, const char * pATCommandPayload, CellularATCommandType_t atCommandType, CellularATCommandResponseReceivedCallback_t responseReceivedCallback, void * pData, uint16_t dataLen ) { CellularContext_t * pContext = ( CellularContext_t * ) cellularHandle; CellularError_t cellularStatus = CELLULAR_SUCCESS; CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_OK; CellularAtReq_t atReqGetResult = { 0 }; /* pContext is checked in _Cellular_CheckLibraryStatus function. */ cellularStatus = _Cellular_CheckLibraryStatus( pContext ); if( cellularStatus != CELLULAR_SUCCESS ) { LogDebug( ( "_Cellular_CheckLibraryStatus failed" ) ); } else if( pATCommandPayload == NULL ) { LogError( ( "Cellular_ATCommandRaw: Input parameter is NULL" ) ); cellularStatus = CELLULAR_BAD_PARAMETER; } else { atReqGetResult.atCmdType = atCommandType; atReqGetResult.pAtRspPrefix = ( const char * ) pATCommandPrefix; atReqGetResult.pAtCmd = ( const char * ) pATCommandPayload; atReqGetResult.pData = pData; atReqGetResult.dataLen = dataLen; atReqGetResult.respCallback = responseReceivedCallback; pktStatus = _Cellular_TimeoutAtcmdRequestWithCallback( pContext, atReqGetResult, CELLULAR_AT_COMMAND_RAW_TIMEOUT_MS ); cellularStatus = _Cellular_TranslatePktStatus( pktStatus ); } return cellularStatus; } /*-----------------------------------------------------------*/ CellularError_t Cellular_CommonCreateSocket( CellularHandle_t cellularHandle, uint8_t pdnContextId, CellularSocketDomain_t socketDomain, CellularSocketType_t socketType, CellularSocketProtocol_t socketProtocol, CellularSocketHandle_t * pSocketHandle ) { 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_CheckLibraryStatus failed" ) ); } else if( pSocketHandle == NULL ) { LogError( ( "pSocketHandle is NULL" ) ); cellularStatus = CELLULAR_BAD_PARAMETER; } else if( _Cellular_IsValidPdn( pdnContextId ) != CELLULAR_SUCCESS ) { LogError( ( "_Cellular_IsValidPdn failed" ) ); cellularStatus = CELLULAR_INVALID_HANDLE; } else { cellularStatus = _Cellular_CreateSocketData( pContext, pdnContextId, socketDomain, socketType, socketProtocol, pSocketHandle ); } return cellularStatus; } /*-----------------------------------------------------------*/ CellularError_t Cellular_CommonSocketSetSockOpt( CellularHandle_t cellularHandle, CellularSocketHandle_t socketHandle, CellularSocketOptionLevel_t optionLevel, CellularSocketOption_t option, const uint8_t * pOptionValue, uint32_t optionValueLength ) { 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_CheckLibraryStatus failed" ) ); } else if( socketHandle == NULL ) { cellularStatus = CELLULAR_INVALID_HANDLE; } else if( ( pOptionValue == NULL ) || ( optionValueLength == 0U ) ) { LogError( ( "Cellular_SocketSetSockOpt: Invalid parameter" ) ); cellularStatus = CELLULAR_BAD_PARAMETER; } else { if( optionLevel == CELLULAR_SOCKET_OPTION_LEVEL_IP ) { LogError( ( "Cellular_SocketSetSockOpt: Option not supported" ) ); cellularStatus = CELLULAR_UNSUPPORTED; } else /* optionLevel CELLULAR_SOCKET_OPTION_LEVEL_TRANSPORT. */ { cellularStatus = _socketSetSockOptLevelTransport( option, socketHandle, pOptionValue, optionValueLength ); } } return cellularStatus; } /*-----------------------------------------------------------*/ CellularError_t Cellular_CommonSocketRegisterDataReadyCallback( CellularHandle_t cellularHandle, CellularSocketHandle_t socketHandle, CellularSocketDataReadyCallback_t dataReadyCallback, void * pCallbackContext ) { 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_CheckLibraryStatus failed" ) ); } else if( socketHandle == NULL ) { cellularStatus = CELLULAR_INVALID_HANDLE; } else { socketHandle->dataReadyCallback = dataReadyCallback; socketHandle->pDataReadyCallbackContext = pCallbackContext; } return cellularStatus; } /*-----------------------------------------------------------*/ CellularError_t Cellular_CommonSocketRegisterSocketOpenCallback( CellularHandle_t cellularHandle, CellularSocketHandle_t socketHandle, CellularSocketOpenCallback_t socketOpenCallback, void * pCallbackContext ) { 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_CheckLibraryStatus failed" ) ); } else if( socketHandle == NULL ) { cellularStatus = CELLULAR_INVALID_HANDLE; } else { socketHandle->openCallback = socketOpenCallback; socketHandle->pOpenCallbackContext = pCallbackContext; } return cellularStatus; } /*-----------------------------------------------------------*/ CellularError_t Cellular_CommonSocketRegisterClosedCallback( CellularHandle_t cellularHandle, CellularSocketHandle_t socketHandle, CellularSocketClosedCallback_t closedCallback, void * pCallbackContext ) { 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_CheckLibraryStatus failed" ) ); } else if( socketHandle == NULL ) { cellularStatus = CELLULAR_INVALID_HANDLE; } else { socketHandle->closedCallback = closedCallback; socketHandle->pClosedCallbackContext = pCallbackContext; } return cellularStatus; } /*-----------------------------------------------------------*/