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

514 lines
19 KiB
C

/*
* FreeRTOS-Cellular-Interface v1.1.0
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*/
/**
* @brief FreeRTOS Cellular Library 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 <stdio.h>
#include <string.h>
#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 ) )
{
/* The variable length is checked. */
/* 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 ) )
{
/* The variable length is checked. */
/* 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 )
{
socketHandle->contextId = *pOptionValue;
}
else
{
LogError( ( "Cellular_SocketSetSockOpt: Cannot change the contextID in this state %d",
socketHandle->socketState ) );
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->pModueContext );
}
/* 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
{
pContext->cbEvents.networkRegistrationCallback = networkRegistrationCallback;
pContext->cbEvents.pNetworkRegistrationCallbackContext = pCallbackContext;
}
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
{
pContext->cbEvents.pdnEventCallback = pdnEventCallback;
pContext->cbEvents.pPdnEventCallbackContext = pCallbackContext;
}
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
{
pContext->cbEvents.signalStrengthChangedCallback = signalStrengthChangedCallback;
pContext->cbEvents.pSignalStrengthChangedCallbackContext = pCallbackContext;
}
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
{
pContext->cbEvents.genericCallback = genericCallback;
pContext->cbEvents.pGenericCallbackContext = pCallbackContext;
}
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
{
pContext->cbEvents.modemEventCallback = modemEventCallback;
pContext->cbEvents.pModemEventCallbackContext = pCallbackContext;
}
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_AtcmdRequestWithCallback( pContext, atReqGetResult );
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;
}
/*-----------------------------------------------------------*/