1103 lines
34 KiB
C
1103 lines
34 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 common AT commnad library.
|
|
*/
|
|
|
|
#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 <stdlib.h>
|
|
#include <limits.h>
|
|
|
|
#include "cellular_platform.h"
|
|
#include "cellular_types.h"
|
|
#include "cellular_internal.h"
|
|
#include "cellular_common_internal.h"
|
|
#include "cellular_pkthandler_internal.h"
|
|
#include "cellular_pktio_internal.h"
|
|
#include "cellular_at_core.h"
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
#define SIGNAL_QUALITY_CSQ_UNKNOWN ( 99 )
|
|
#define SIGNAL_QUALITY_CSQ_RSSI_MIN ( 0 )
|
|
#define SIGNAL_QUALITY_CSQ_RSSI_MAX ( 31 )
|
|
#define SIGNAL_QUALITY_CSQ_BER_MIN ( 0 )
|
|
#define SIGNAL_QUALITY_CSQ_BER_MAX ( 7 )
|
|
#define SIGNAL_QUALITY_CSQ_RSSI_BASE ( -113 )
|
|
#define SIGNAL_QUALITY_CSQ_RSSI_STEP ( 2 )
|
|
|
|
/* Only supports a single cellular instance. */
|
|
#define CELLULAR_CONTEXT_MAX ( 1U )
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
/**
|
|
* @brief Parameters in Signal Bars Look up table for measuring Signal Bars.
|
|
*/
|
|
typedef struct signalBarsTable
|
|
{
|
|
int8_t upperThreshold;
|
|
uint8_t bars;
|
|
} signalBarsTable_t;
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
static CellularContext_t * _Cellular_AllocContext( void );
|
|
static void _Cellular_FreeContext( CellularContext_t * pContext );
|
|
static void _shutdownCallback( CellularContext_t * pContext );
|
|
static CellularError_t libOpen( CellularContext_t * pContext );
|
|
static void libClose( CellularContext_t * pContext );
|
|
static bool _Cellular_CreateLibStatusMutex( CellularContext_t * pContext );
|
|
static void _Cellular_DestroyLibStatusMutex( CellularContext_t * pContext );
|
|
/* Internal function of _Cellular_CreateSocket to reduce complexity. */
|
|
static void createSocketSetSocketData( uint8_t contextId,
|
|
uint8_t socketId,
|
|
CellularSocketDomain_t socketDomain,
|
|
CellularSocketType_t socketType,
|
|
CellularSocketProtocol_t socketProtocol,
|
|
CellularSocketContext_t * pSocketData );
|
|
static uint8_t _getSignalBars( int16_t compareValue,
|
|
CellularRat_t rat );
|
|
static CellularError_t checkInitParameter( const CellularHandle_t * pCellularHandle,
|
|
const CellularCommInterface_t * pCommInterface,
|
|
const CellularTokenTable_t * pTokenTable );
|
|
|
|
static void _Cellular_SetShutdownCallback( CellularContext_t * pContext,
|
|
_pPktioShutdownCallback_t shutdownCb );
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
#if ( CELLULAR_CONFIG_STATIC_ALLOCATION_CONTEXT == 1 )
|
|
static CellularContext_t cellularStaticContextTable[ CELLULAR_CONTEXT_MAX ] = { 0 };
|
|
#endif
|
|
|
|
static CellularContext_t * cellularContextTable[ CELLULAR_CONTEXT_MAX ] = { 0 };
|
|
|
|
#if ( CELLULAR_CONFIG_STATIC_SOCKET_CONTEXT_ALLOCATION == 1 )
|
|
static CellularSocketContext_t cellularStaticSocketDataTable[ CELLULAR_NUM_SOCKET_MAX ] = { 0 };
|
|
#endif
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
static CellularContext_t * _Cellular_AllocContext( void )
|
|
{
|
|
CellularContext_t * pContext = NULL;
|
|
uint8_t i = 0;
|
|
|
|
taskENTER_CRITICAL();
|
|
|
|
for( i = 0; i < CELLULAR_CONTEXT_MAX; i++ )
|
|
{
|
|
if( cellularContextTable[ i ] == NULL )
|
|
{
|
|
#if ( CELLULAR_CONFIG_STATIC_ALLOCATION_CONTEXT == 1 )
|
|
{
|
|
pContext = &cellularStaticContextTable[ i ];
|
|
}
|
|
#else
|
|
{
|
|
pContext = ( CellularContext_t * ) Platform_Malloc( sizeof( CellularContext_t ) );
|
|
}
|
|
#endif
|
|
|
|
if( pContext != NULL )
|
|
{
|
|
( void ) memset( pContext, 0, sizeof( CellularContext_t ) );
|
|
cellularContextTable[ i ] = pContext;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
taskEXIT_CRITICAL();
|
|
|
|
return pContext;
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
static void _Cellular_FreeContext( CellularContext_t * pContext )
|
|
{
|
|
uint8_t i = 0;
|
|
|
|
taskENTER_CRITICAL();
|
|
|
|
for( i = 0; i < CELLULAR_CONTEXT_MAX; i++ )
|
|
{
|
|
if( cellularContextTable[ i ] == pContext )
|
|
{
|
|
cellularContextTable[ i ] = NULL;
|
|
#if ( CELLULAR_CONFIG_STATIC_ALLOCATION_CONTEXT == 0 )
|
|
{
|
|
Platform_Free( pContext );
|
|
}
|
|
#endif
|
|
break;
|
|
}
|
|
}
|
|
|
|
taskEXIT_CRITICAL();
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
static void _shutdownCallback( CellularContext_t * pContext )
|
|
{
|
|
pContext->bLibShutdown = true;
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
static CellularError_t libOpen( CellularContext_t * pContext )
|
|
{
|
|
CellularError_t cellularStatus = CELLULAR_SUCCESS;
|
|
CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_OK;
|
|
|
|
configASSERT( pContext != NULL );
|
|
|
|
PlatformMutex_Lock( &pContext->libStatusMutex );
|
|
|
|
( CellularPktStatus_t ) _Cellular_AtParseInit( pContext );
|
|
_Cellular_LockAtDataMutex( pContext );
|
|
_Cellular_InitAtData( pContext, 0 );
|
|
_Cellular_UnlockAtDataMutex( pContext );
|
|
_Cellular_SetShutdownCallback( pContext, _shutdownCallback );
|
|
pktStatus = _Cellular_PktHandlerInit( pContext );
|
|
|
|
if( pktStatus == CELLULAR_PKT_STATUS_OK )
|
|
{
|
|
pktStatus = _Cellular_PktioInit( pContext, _Cellular_HandlePacket );
|
|
|
|
if( pktStatus != CELLULAR_PKT_STATUS_OK )
|
|
{
|
|
LogError( ( "pktio failed to initialize" ) );
|
|
_Cellular_PktioShutdown( pContext );
|
|
_Cellular_PktHandlerCleanup( pContext );
|
|
}
|
|
}
|
|
|
|
if( pktStatus != CELLULAR_PKT_STATUS_OK )
|
|
{
|
|
cellularStatus = _Cellular_TranslatePktStatus( pktStatus );
|
|
}
|
|
|
|
if( cellularStatus == CELLULAR_SUCCESS )
|
|
{
|
|
/* CellularLib open finished. */
|
|
pContext->bLibOpened = true;
|
|
pContext->bLibShutdown = false;
|
|
}
|
|
|
|
PlatformMutex_Unlock( &pContext->libStatusMutex );
|
|
|
|
return cellularStatus;
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
static void libClose( CellularContext_t * pContext )
|
|
{
|
|
bool bOpened = false;
|
|
uint8_t i = 0;
|
|
|
|
configASSERT( pContext != NULL );
|
|
|
|
PlatformMutex_Lock( &pContext->libStatusMutex );
|
|
bOpened = pContext->bLibOpened;
|
|
|
|
/* Indicate that CellularLib is in the process of closing. */
|
|
pContext->bLibClosing = true;
|
|
PlatformMutex_Unlock( &pContext->libStatusMutex );
|
|
|
|
if( bOpened == true )
|
|
{
|
|
/* Shut down the utilities. */
|
|
_Cellular_PktioShutdown( pContext );
|
|
_Cellular_PktHandlerCleanup( pContext );
|
|
}
|
|
|
|
PlatformMutex_Lock( &pContext->libStatusMutex );
|
|
pContext->bLibShutdown = false;
|
|
pContext->bLibOpened = false;
|
|
pContext->bLibClosing = false;
|
|
|
|
/* Remove all created sockets. */
|
|
for( i = 0; i < CELLULAR_NUM_SOCKET_MAX; i++ )
|
|
{
|
|
if( pContext->pSocketData[ i ] != NULL )
|
|
{
|
|
#if ( CELLULAR_CONFIG_STATIC_SOCKET_CONTEXT_ALLOCATION == 0 )
|
|
{
|
|
Platform_Free( pContext->pSocketData[ i ] );
|
|
}
|
|
#endif
|
|
pContext->pSocketData[ i ] = NULL;
|
|
}
|
|
}
|
|
|
|
PlatformMutex_Unlock( &pContext->libStatusMutex );
|
|
LogDebug( ( "CELLULARLib closed" ) );
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
static bool _Cellular_CreateLibStatusMutex( CellularContext_t * pContext )
|
|
{
|
|
bool status = false;
|
|
|
|
status = PlatformMutex_Create( &pContext->libStatusMutex, false );
|
|
|
|
return status;
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
static void _Cellular_DestroyLibStatusMutex( CellularContext_t * pContext )
|
|
{
|
|
PlatformMutex_Destroy( &pContext->libStatusMutex );
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
/* Internal function of _Cellular_CreateSocket to reduce complexity. */
|
|
static void createSocketSetSocketData( uint8_t contextId,
|
|
uint8_t socketId,
|
|
CellularSocketDomain_t socketDomain,
|
|
CellularSocketType_t socketType,
|
|
CellularSocketProtocol_t socketProtocol,
|
|
CellularSocketContext_t * pSocketData )
|
|
{
|
|
( void ) memset( pSocketData, 0, sizeof( CellularSocketContext_t ) );
|
|
pSocketData->socketState = SOCKETSTATE_ALLOCATED;
|
|
pSocketData->socketId = socketId;
|
|
pSocketData->contextId = contextId;
|
|
pSocketData->socketDomain = socketDomain;
|
|
pSocketData->socketType = socketType;
|
|
pSocketData->socketProtocol = socketProtocol;
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
static uint8_t _getSignalBars( int16_t compareValue,
|
|
CellularRat_t rat )
|
|
{
|
|
uint8_t i = 0, tableSize = 0, barsValue = CELLULAR_INVALID_SIGNAL_BAR_VALUE;
|
|
const signalBarsTable_t * pSignalBarsTable = NULL;
|
|
|
|
|
|
/* Look up Table for Mapping Signal Bars with RSSI value in dBm of GSM Signal.
|
|
* The upper RSSI threshold is maintained in decreasing order to return the signal Bars. */
|
|
static const signalBarsTable_t gsmSignalBarsTable[] =
|
|
{
|
|
{ -104, 1 },
|
|
{ -98, 2 },
|
|
{ -89, 3 },
|
|
{ -80, 4 },
|
|
{ 0, 5 },
|
|
};
|
|
|
|
/* Look up Table for Mapping Signal Bars with RSRP value in dBm of LTE CAT M1 Signal.
|
|
* The upper RSRP threshold is maintained in decreasing order to return the signal Bars. */
|
|
static const signalBarsTable_t lteCATMSignalBarsTable[] =
|
|
{
|
|
{ -115, 1 },
|
|
{ -105, 2 },
|
|
{ -95, 3 },
|
|
{ -85, 4 },
|
|
{ 0, 5 },
|
|
};
|
|
|
|
/* Look up Table for Mapping Signal Bars with RSRP value in dBm of LTE CAT NB1 Signal.
|
|
* The upper RSRP threshold is maintained in decreasing order to return the signal Bars. */
|
|
static const signalBarsTable_t lteNBIotSignalBarsTable[] =
|
|
{
|
|
{ -115, 1 },
|
|
{ -105, 2 },
|
|
{ -95, 3 },
|
|
{ -85, 4 },
|
|
{ 0, 5 },
|
|
};
|
|
|
|
if( ( rat == CELLULAR_RAT_GSM ) || ( rat == CELLULAR_RAT_EDGE ) )
|
|
{
|
|
pSignalBarsTable = gsmSignalBarsTable;
|
|
tableSize = ( uint8_t ) ARRY_SIZE( gsmSignalBarsTable );
|
|
}
|
|
|
|
if( ( rat == CELLULAR_RAT_CATM1 ) || ( rat == CELLULAR_RAT_LTE ) )
|
|
{
|
|
pSignalBarsTable = lteCATMSignalBarsTable;
|
|
tableSize = ( uint8_t ) ARRY_SIZE( lteCATMSignalBarsTable );
|
|
}
|
|
|
|
if( rat == CELLULAR_RAT_NBIOT )
|
|
{
|
|
pSignalBarsTable = lteNBIotSignalBarsTable;
|
|
tableSize = ( uint8_t ) ARRY_SIZE( lteNBIotSignalBarsTable );
|
|
}
|
|
|
|
for( i = 0; i < tableSize; i++ )
|
|
{
|
|
if( compareValue <= pSignalBarsTable[ i ].upperThreshold )
|
|
{
|
|
barsValue = pSignalBarsTable[ i ].bars;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return barsValue;
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
static CellularError_t checkInitParameter( const CellularHandle_t * pCellularHandle,
|
|
const CellularCommInterface_t * pCommInterface,
|
|
const CellularTokenTable_t * pTokenTable )
|
|
{
|
|
CellularError_t cellularStatus = CELLULAR_SUCCESS;
|
|
|
|
if( pCellularHandle == NULL )
|
|
{
|
|
LogError( ( "Invalid CellularHandler pointer." ) );
|
|
cellularStatus = CELLULAR_INVALID_HANDLE;
|
|
}
|
|
else if( ( pCommInterface == NULL ) || ( pCommInterface->open == NULL ) ||
|
|
( pCommInterface->close == NULL ) || ( pCommInterface->send == NULL ) ||
|
|
( pCommInterface->recv == NULL ) )
|
|
{
|
|
LogError( ( "All the functions in the CellularCommInterface should be valid." ) );
|
|
cellularStatus = CELLULAR_BAD_PARAMETER;
|
|
}
|
|
else if( ( pTokenTable == NULL ) || ( pTokenTable->pCellularUrcHandlerTable == NULL ) ||
|
|
( pTokenTable->pCellularSrcTokenErrorTable == NULL ) ||
|
|
( pTokenTable->pCellularSrcTokenSuccessTable == NULL ) ||
|
|
( pTokenTable->pCellularUrcTokenWoPrefixTable == NULL ) )
|
|
{
|
|
LogError( ( "All the token tables in the CellularTokenTable should be valid." ) );
|
|
cellularStatus = CELLULAR_BAD_PARAMETER;
|
|
}
|
|
else
|
|
{
|
|
/* Empty Else MISRA 15.7 */
|
|
}
|
|
|
|
return cellularStatus;
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
static void _Cellular_SetShutdownCallback( CellularContext_t * pContext,
|
|
_pPktioShutdownCallback_t shutdownCb )
|
|
{
|
|
pContext->pPktioShutdownCB = shutdownCb;
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
/* Checks whether Cellular Library is opened. */
|
|
CellularError_t _Cellular_CheckLibraryStatus( CellularContext_t * pContext )
|
|
{
|
|
CellularError_t cellularStatus = CELLULAR_SUCCESS;
|
|
|
|
if( pContext == NULL )
|
|
{
|
|
cellularStatus = CELLULAR_INVALID_HANDLE;
|
|
}
|
|
else
|
|
{
|
|
PlatformMutex_Lock( &pContext->libStatusMutex );
|
|
|
|
if( pContext->bLibOpened == false )
|
|
{
|
|
cellularStatus = CELLULAR_LIBRARY_NOT_OPEN;
|
|
}
|
|
|
|
PlatformMutex_Unlock( &pContext->libStatusMutex );
|
|
}
|
|
|
|
if( cellularStatus == CELLULAR_SUCCESS )
|
|
{
|
|
PlatformMutex_Lock( &pContext->libStatusMutex );
|
|
|
|
if( ( pContext->bLibShutdown == true ) || ( pContext->bLibClosing == true ) )
|
|
{
|
|
LogError( ( "Cellular Lib indicated a failure[%d][%d]", pContext->bLibShutdown, pContext->bLibClosing ) );
|
|
cellularStatus = CELLULAR_INTERNAL_FAILURE;
|
|
}
|
|
|
|
PlatformMutex_Unlock( &pContext->libStatusMutex );
|
|
}
|
|
|
|
return cellularStatus;
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
CellularError_t _Cellular_TranslatePktStatus( CellularPktStatus_t status )
|
|
{
|
|
CellularError_t cellularStatus = CELLULAR_INTERNAL_FAILURE;
|
|
|
|
switch( status )
|
|
{
|
|
case CELLULAR_PKT_STATUS_OK:
|
|
cellularStatus = CELLULAR_SUCCESS;
|
|
break;
|
|
|
|
case CELLULAR_PKT_STATUS_TIMED_OUT:
|
|
cellularStatus = CELLULAR_TIMEOUT;
|
|
break;
|
|
|
|
case CELLULAR_PKT_STATUS_FAILURE:
|
|
case CELLULAR_PKT_STATUS_BAD_REQUEST:
|
|
case CELLULAR_PKT_STATUS_BAD_RESPONSE:
|
|
case CELLULAR_PKT_STATUS_SIZE_MISMATCH:
|
|
default:
|
|
LogError( ( "_Cellular_TranslatePktStatus: Status %d", status ) );
|
|
cellularStatus = CELLULAR_INTERNAL_FAILURE;
|
|
break;
|
|
}
|
|
|
|
return cellularStatus;
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
CellularPktStatus_t _Cellular_TranslateAtCoreStatus( CellularATError_t status )
|
|
{
|
|
CellularPktStatus_t pktStatus;
|
|
|
|
switch( status )
|
|
{
|
|
case CELLULAR_AT_SUCCESS:
|
|
pktStatus = CELLULAR_PKT_STATUS_OK;
|
|
break;
|
|
|
|
case CELLULAR_AT_BAD_PARAMETER:
|
|
pktStatus = CELLULAR_PKT_STATUS_BAD_PARAM;
|
|
break;
|
|
|
|
case CELLULAR_AT_NO_MEMORY:
|
|
case CELLULAR_AT_UNSUPPORTED:
|
|
case CELLULAR_AT_MODEM_ERROR:
|
|
case CELLULAR_AT_ERROR:
|
|
case CELLULAR_AT_UNKNOWN:
|
|
default:
|
|
LogError( ( "_Cellular_TranslateAtCoreStatus: Status %d", status ) );
|
|
pktStatus = CELLULAR_PKT_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
return pktStatus;
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
CellularError_t _Cellular_CreateSocketData( CellularContext_t * pContext,
|
|
uint8_t contextId,
|
|
CellularSocketDomain_t socketDomain,
|
|
CellularSocketType_t socketType,
|
|
CellularSocketProtocol_t socketProtocol,
|
|
CellularSocketHandle_t * pSocketHandle )
|
|
{
|
|
CellularError_t cellularStatus = CELLULAR_SUCCESS;
|
|
CellularSocketContext_t * pSocketData = NULL;
|
|
uint8_t socketId = 0;
|
|
|
|
taskENTER_CRITICAL();
|
|
|
|
for( socketId = 0; socketId < CELLULAR_NUM_SOCKET_MAX; socketId++ )
|
|
{
|
|
if( pContext->pSocketData[ socketId ] == NULL )
|
|
{
|
|
#if ( CELLULAR_CONFIG_STATIC_SOCKET_CONTEXT_ALLOCATION == 1 )
|
|
{
|
|
pSocketData = &cellularStaticSocketDataTable[ socketId ];
|
|
}
|
|
#else
|
|
{
|
|
pSocketData = ( CellularSocketContext_t * ) Platform_Malloc( sizeof( CellularSocketContext_t ) );
|
|
}
|
|
#endif
|
|
|
|
if( pSocketData != NULL )
|
|
{
|
|
createSocketSetSocketData( contextId, socketId, socketDomain,
|
|
socketType, socketProtocol, pSocketData );
|
|
pContext->pSocketData[ socketId ] = pSocketData;
|
|
*pSocketHandle = ( CellularSocketHandle_t ) pSocketData;
|
|
}
|
|
else
|
|
{
|
|
cellularStatus = CELLULAR_NO_MEMORY;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
taskEXIT_CRITICAL();
|
|
|
|
if( cellularStatus == CELLULAR_NO_MEMORY )
|
|
{
|
|
LogError( ( "_Cellular_CreateSocket, Out of memory" ) );
|
|
}
|
|
else if( socketId >= CELLULAR_NUM_SOCKET_MAX )
|
|
{
|
|
LogError( ( "_Cellular_CreateSocket, No free socket slots are available" ) );
|
|
cellularStatus = CELLULAR_NO_MEMORY;
|
|
}
|
|
else
|
|
{
|
|
/* Empty Else MISRA 15.7 */
|
|
}
|
|
|
|
return cellularStatus;
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
CellularError_t _Cellular_RemoveSocketData( CellularContext_t * pContext,
|
|
CellularSocketHandle_t socketHandle )
|
|
{
|
|
CellularError_t cellularStatus = CELLULAR_SUCCESS;
|
|
uint8_t socketId;
|
|
|
|
if( socketHandle->socketState == SOCKETSTATE_CONNECTING )
|
|
{
|
|
LogWarn( ( "_Cellular_RemoveSocket, socket is connecting state [%u]", socketHandle->socketId ) );
|
|
}
|
|
|
|
taskENTER_CRITICAL();
|
|
|
|
if( pContext != NULL )
|
|
{
|
|
for( socketId = 0; socketId < CELLULAR_NUM_SOCKET_MAX; socketId++ )
|
|
{
|
|
if( pContext->pSocketData[ socketId ] == socketHandle )
|
|
{
|
|
pContext->pSocketData[ socketId ] = NULL;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( socketId == CELLULAR_NUM_SOCKET_MAX )
|
|
{
|
|
cellularStatus = CELLULAR_BAD_PARAMETER;
|
|
}
|
|
|
|
#if ( CELLULAR_CONFIG_STATIC_SOCKET_CONTEXT_ALLOCATION == 0 )
|
|
else
|
|
{
|
|
Platform_Free( socketHandle );
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
cellularStatus = CELLULAR_INVALID_HANDLE;
|
|
}
|
|
|
|
taskEXIT_CRITICAL();
|
|
|
|
return cellularStatus;
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
CellularError_t _Cellular_IsValidSocket( const CellularContext_t * pContext,
|
|
uint32_t sockIndex )
|
|
{
|
|
CellularError_t cellularStatus = CELLULAR_SUCCESS;
|
|
|
|
if( pContext == NULL )
|
|
{
|
|
cellularStatus = CELLULAR_INVALID_HANDLE;
|
|
}
|
|
else
|
|
{
|
|
if( ( sockIndex >= CELLULAR_NUM_SOCKET_MAX ) || ( pContext->pSocketData[ sockIndex ] == NULL ) )
|
|
{
|
|
LogError( ( "_Cellular_IsValidSocket, invalid socket handle %u", sockIndex ) );
|
|
cellularStatus = CELLULAR_BAD_PARAMETER;
|
|
}
|
|
}
|
|
|
|
return cellularStatus;
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
CellularError_t _Cellular_IsValidPdn( uint8_t contextId )
|
|
{
|
|
CellularError_t cellularStatus = CELLULAR_SUCCESS;
|
|
|
|
if( ( contextId > CELLULAR_PDN_CONTEXT_ID_MAX ) || ( contextId < CELLULAR_PDN_CONTEXT_ID_MIN ) )
|
|
{
|
|
LogError( ( "_Cellular_IsValidPdn: ContextId out of range %d",
|
|
contextId ) );
|
|
cellularStatus = CELLULAR_BAD_PARAMETER;
|
|
}
|
|
|
|
return cellularStatus;
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
CellularError_t _Cellular_ConvertCsqSignalRssi( int16_t csqRssi,
|
|
int16_t * pRssiValue )
|
|
{
|
|
CellularError_t cellularStatus = CELLULAR_SUCCESS;
|
|
int16_t rssiValue = 0;
|
|
|
|
if( pRssiValue == NULL )
|
|
{
|
|
cellularStatus = CELLULAR_BAD_PARAMETER;
|
|
}
|
|
|
|
if( cellularStatus == CELLULAR_SUCCESS )
|
|
{
|
|
if( csqRssi == ( SIGNAL_QUALITY_CSQ_UNKNOWN ) )
|
|
{
|
|
rssiValue = CELLULAR_INVALID_SIGNAL_VALUE;
|
|
}
|
|
else if( ( csqRssi < SIGNAL_QUALITY_CSQ_RSSI_MIN ) || ( csqRssi > SIGNAL_QUALITY_CSQ_RSSI_MAX ) )
|
|
{
|
|
cellularStatus = CELLULAR_BAD_PARAMETER;
|
|
}
|
|
else
|
|
{
|
|
rssiValue = SIGNAL_QUALITY_CSQ_RSSI_BASE + ( csqRssi * SIGNAL_QUALITY_CSQ_RSSI_STEP );
|
|
}
|
|
}
|
|
|
|
if( cellularStatus == CELLULAR_SUCCESS )
|
|
{
|
|
*pRssiValue = rssiValue;
|
|
}
|
|
|
|
return cellularStatus;
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
CellularError_t _Cellular_ConvertCsqSignalBer( int16_t csqBer,
|
|
int16_t * pBerValue )
|
|
{
|
|
CellularError_t cellularStatus = CELLULAR_SUCCESS;
|
|
int16_t berValue = 0;
|
|
|
|
static const uint16_t rxqualValueToBerTable[] =
|
|
{
|
|
14, /* Assumed value 0.14%. */
|
|
28, /* Assumed value 0.28%.*/
|
|
57, /* Assumed value 0.57%. */
|
|
113, /* Assumed value 1.13%. */
|
|
226, /* Assumed value 2.26%. */
|
|
453, /* Assumed value 4.53%. */
|
|
905, /* Assumed value 9.05%. */
|
|
1810 /* Assumed value 18.10%. */
|
|
};
|
|
|
|
if( pBerValue == NULL )
|
|
{
|
|
cellularStatus = CELLULAR_BAD_PARAMETER;
|
|
}
|
|
|
|
if( cellularStatus == CELLULAR_SUCCESS )
|
|
{
|
|
if( csqBer == ( ( int16_t ) SIGNAL_QUALITY_CSQ_UNKNOWN ) )
|
|
{
|
|
berValue = CELLULAR_INVALID_SIGNAL_VALUE;
|
|
}
|
|
else if( ( csqBer < SIGNAL_QUALITY_CSQ_BER_MIN ) || ( csqBer > SIGNAL_QUALITY_CSQ_BER_MAX ) )
|
|
{
|
|
cellularStatus = CELLULAR_BAD_PARAMETER;
|
|
}
|
|
else
|
|
{
|
|
berValue = ( int16_t ) rxqualValueToBerTable[ csqBer ];
|
|
}
|
|
}
|
|
|
|
if( cellularStatus == CELLULAR_SUCCESS )
|
|
{
|
|
*pBerValue = berValue;
|
|
}
|
|
|
|
return cellularStatus;
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
CellularError_t _Cellular_GetModuleContext( const CellularContext_t * pContext,
|
|
void ** ppModuleContext )
|
|
{
|
|
CellularError_t cellularStatus = CELLULAR_SUCCESS;
|
|
|
|
if( pContext == NULL )
|
|
{
|
|
cellularStatus = CELLULAR_INVALID_HANDLE;
|
|
}
|
|
else
|
|
{
|
|
*ppModuleContext = pContext->pModueContext;
|
|
}
|
|
|
|
return cellularStatus;
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
CellularError_t _Cellular_ComputeSignalBars( CellularRat_t rat,
|
|
CellularSignalInfo_t * pSignalInfo )
|
|
{
|
|
CellularError_t cellularStatus = CELLULAR_SUCCESS;
|
|
|
|
if( pSignalInfo == NULL )
|
|
{
|
|
cellularStatus = CELLULAR_BAD_PARAMETER;
|
|
}
|
|
else
|
|
{
|
|
if( ( rat == CELLULAR_RAT_GSM ) || ( rat == CELLULAR_RAT_EDGE ) )
|
|
{
|
|
pSignalInfo->bars = _getSignalBars( pSignalInfo->rssi, rat );
|
|
LogDebug( ( "_computeSignalBars: RSSI %d Bars %d", pSignalInfo->rssi, pSignalInfo->bars ) );
|
|
}
|
|
else if( ( rat == CELLULAR_RAT_LTE ) || ( rat == CELLULAR_RAT_CATM1 ) || ( rat == CELLULAR_RAT_NBIOT ) )
|
|
{
|
|
pSignalInfo->bars = _getSignalBars( pSignalInfo->rsrp, rat );
|
|
LogDebug( ( "_computeSignalBars: RSRP %d Bars %d", pSignalInfo->rsrp, pSignalInfo->bars ) );
|
|
}
|
|
else
|
|
{
|
|
cellularStatus = CELLULAR_UNKNOWN;
|
|
pSignalInfo->bars = CELLULAR_INVALID_SIGNAL_BAR_VALUE;
|
|
}
|
|
}
|
|
|
|
return cellularStatus;
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
CellularError_t _Cellular_GetCurrentRat( CellularContext_t * pContext,
|
|
CellularRat_t * pRat )
|
|
{
|
|
CellularError_t cellularStatus = CELLULAR_SUCCESS;
|
|
|
|
cellularStatus = _Cellular_CheckLibraryStatus( pContext );
|
|
|
|
if( cellularStatus != CELLULAR_SUCCESS )
|
|
{
|
|
LogDebug( ( "_Cellular_CheckLibraryStatus failed" ) );
|
|
}
|
|
else if( pRat == NULL )
|
|
{
|
|
cellularStatus = CELLULAR_BAD_PARAMETER;
|
|
}
|
|
else
|
|
{
|
|
_Cellular_LockAtDataMutex( pContext );
|
|
*pRat = pContext->libAtData.rat;
|
|
_Cellular_UnlockAtDataMutex( pContext );
|
|
}
|
|
|
|
return cellularStatus;
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
void _Cellular_NetworkRegistrationCallback( const CellularContext_t * pContext,
|
|
CellularUrcEvent_t urcEvent,
|
|
const CellularServiceStatus_t * pServiceStatus )
|
|
{
|
|
if( ( pContext != NULL ) && ( pContext->cbEvents.networkRegistrationCallback != NULL ) )
|
|
{
|
|
pContext->cbEvents.networkRegistrationCallback( urcEvent, pServiceStatus,
|
|
pContext->cbEvents.pNetworkRegistrationCallbackContext );
|
|
}
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
void _Cellular_PdnEventCallback( const CellularContext_t * pContext,
|
|
CellularUrcEvent_t urcEvent,
|
|
uint8_t contextId )
|
|
{
|
|
if( ( pContext != NULL ) && ( pContext->cbEvents.pdnEventCallback != NULL ) )
|
|
{
|
|
pContext->cbEvents.pdnEventCallback( urcEvent, contextId, pContext->cbEvents.pPdnEventCallbackContext );
|
|
}
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
void _Cellular_SignalStrengthChangedCallback( const CellularContext_t * pContext,
|
|
CellularUrcEvent_t urcEvent,
|
|
const CellularSignalInfo_t * pSignalInfo )
|
|
{
|
|
if( ( pContext != NULL ) && ( pContext->cbEvents.signalStrengthChangedCallback != NULL ) )
|
|
{
|
|
pContext->cbEvents.signalStrengthChangedCallback( urcEvent, pSignalInfo,
|
|
pContext->cbEvents.pSignalStrengthChangedCallbackContext );
|
|
}
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
void _Cellular_GenericCallback( const CellularContext_t * pContext,
|
|
const char * pRawData )
|
|
{
|
|
if( ( pContext != NULL ) && ( pContext->cbEvents.genericCallback != NULL ) )
|
|
{
|
|
pContext->cbEvents.genericCallback( pRawData, pContext->cbEvents.pGenericCallbackContext );
|
|
}
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
void _Cellular_ModemEventCallback( const CellularContext_t * pContext,
|
|
CellularModemEvent_t modemEvent )
|
|
{
|
|
if( ( pContext != NULL ) && ( pContext->cbEvents.modemEventCallback != NULL ) )
|
|
{
|
|
pContext->cbEvents.modemEventCallback( modemEvent, pContext->cbEvents.pModemEventCallbackContext );
|
|
}
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
CellularSocketContext_t * _Cellular_GetSocketData( const CellularContext_t * pContext,
|
|
uint32_t sockIndex )
|
|
{
|
|
CellularSocketContext_t * pSocketData = NULL;
|
|
|
|
if( pContext == NULL )
|
|
{
|
|
LogError( ( "Invalid context" ) );
|
|
}
|
|
else
|
|
{
|
|
if( ( sockIndex >= CELLULAR_NUM_SOCKET_MAX ) || ( pContext->pSocketData[ sockIndex ] == NULL ) )
|
|
{
|
|
LogError( ( "_Cellular_GetSocketData, invalid socket handle %u", sockIndex ) );
|
|
}
|
|
else
|
|
{
|
|
pSocketData = pContext->pSocketData[ sockIndex ];
|
|
}
|
|
}
|
|
|
|
return pSocketData;
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
CellularError_t _Cellular_LibInit( CellularHandle_t * pCellularHandle,
|
|
const CellularCommInterface_t * pCommInterface,
|
|
const CellularTokenTable_t * pTokenTable )
|
|
{
|
|
CellularError_t cellularStatus = CELLULAR_SUCCESS;
|
|
CellularContext_t * pContext = NULL;
|
|
bool bLibStatusMutexCreateSuccess = false;
|
|
bool bAtDataMutexCreateSuccess = false;
|
|
bool bPktRequestMutexCreateSuccess = false;
|
|
bool bPktResponseMutexCreateSuccess = false;
|
|
|
|
cellularStatus = checkInitParameter( pCellularHandle, pCommInterface, pTokenTable );
|
|
|
|
if( cellularStatus != CELLULAR_SUCCESS )
|
|
{
|
|
LogError( ( "_Cellular_CommonInit checkInitParameter failed" ) );
|
|
}
|
|
else
|
|
{
|
|
pContext = _Cellular_AllocContext();
|
|
|
|
if( pContext == NULL )
|
|
{
|
|
LogError( ( "CellularContext_t allocation failed" ) );
|
|
cellularStatus = CELLULAR_NO_MEMORY;
|
|
}
|
|
else
|
|
{
|
|
/* Assign the comm interface to pContext. */
|
|
pContext->pCommIntf = pCommInterface;
|
|
|
|
/* copy the token table. */
|
|
( void ) memcpy( &pContext->tokenTable, pTokenTable, sizeof( CellularTokenTable_t ) );
|
|
}
|
|
}
|
|
|
|
/* Defines the Mutexes and Semophores. */
|
|
if( cellularStatus == CELLULAR_SUCCESS )
|
|
{
|
|
if( _Cellular_CreateLibStatusMutex( pContext ) != true )
|
|
{
|
|
LogError( ( "Could not create CellularLib status mutex" ) );
|
|
cellularStatus = CELLULAR_RESOURCE_CREATION_FAIL;
|
|
}
|
|
else
|
|
{
|
|
bLibStatusMutexCreateSuccess = true;
|
|
}
|
|
}
|
|
|
|
if( cellularStatus == CELLULAR_SUCCESS )
|
|
{
|
|
if( _Cellular_CreateAtDataMutex( pContext ) != true )
|
|
{
|
|
LogError( ( "Could not create CELLULAR AT Data mutex " ) );
|
|
cellularStatus = CELLULAR_RESOURCE_CREATION_FAIL;
|
|
}
|
|
else
|
|
{
|
|
bAtDataMutexCreateSuccess = true;
|
|
}
|
|
}
|
|
|
|
if( cellularStatus == CELLULAR_SUCCESS )
|
|
{
|
|
if( _Cellular_CreatePktRequestMutex( pContext ) != true )
|
|
{
|
|
LogError( ( "Could not create CELLULAR Pkt Req mutex " ) );
|
|
cellularStatus = CELLULAR_RESOURCE_CREATION_FAIL;
|
|
}
|
|
else
|
|
{
|
|
bPktRequestMutexCreateSuccess = true;
|
|
}
|
|
}
|
|
|
|
if( cellularStatus == CELLULAR_SUCCESS )
|
|
{
|
|
if( _Cellular_CreatePktResponseMutex( pContext ) != true )
|
|
{
|
|
LogError( ( "Could not create CELLULAR Pkt Resp mutex " ) );
|
|
cellularStatus = CELLULAR_RESOURCE_CREATION_FAIL;
|
|
}
|
|
else
|
|
{
|
|
bPktResponseMutexCreateSuccess = true;
|
|
}
|
|
}
|
|
|
|
/* Configure the library. */
|
|
if( cellularStatus == CELLULAR_SUCCESS )
|
|
{
|
|
cellularStatus = libOpen( pContext );
|
|
}
|
|
|
|
if( cellularStatus != CELLULAR_SUCCESS )
|
|
{
|
|
if( bPktResponseMutexCreateSuccess == true )
|
|
{
|
|
_Cellular_DestroyPktResponseMutex( pContext );
|
|
}
|
|
|
|
if( bPktRequestMutexCreateSuccess == true )
|
|
{
|
|
_Cellular_DestroyPktRequestMutex( pContext );
|
|
}
|
|
|
|
if( bAtDataMutexCreateSuccess == true )
|
|
{
|
|
_Cellular_DestroyAtDataMutex( pContext );
|
|
}
|
|
|
|
if( bLibStatusMutexCreateSuccess == true )
|
|
{
|
|
_Cellular_DestroyLibStatusMutex( pContext );
|
|
}
|
|
|
|
if( pContext != NULL )
|
|
{
|
|
_Cellular_FreeContext( pContext );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*pCellularHandle = pContext;
|
|
}
|
|
|
|
return cellularStatus;
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
CellularError_t _Cellular_LibCleanup( CellularHandle_t cellularHandle )
|
|
{
|
|
CellularContext_t * pContext = ( CellularContext_t * ) cellularHandle;
|
|
CellularError_t cellularStatus = CELLULAR_SUCCESS;
|
|
|
|
if( pContext == NULL )
|
|
{
|
|
cellularStatus = CELLULAR_INVALID_HANDLE;
|
|
}
|
|
else
|
|
{
|
|
libClose( pContext );
|
|
|
|
_Cellular_DestroyLibStatusMutex( pContext );
|
|
_Cellular_DestroyAtDataMutex( pContext );
|
|
_Cellular_DestroyPktRequestMutex( pContext );
|
|
_Cellular_DestroyPktResponseMutex( pContext );
|
|
_Cellular_FreeContext( pContext );
|
|
}
|
|
|
|
return cellularStatus;
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
CellularPktStatus_t _Cellular_AtcmdRequestWithCallback( CellularContext_t * pContext,
|
|
CellularAtReq_t atReq )
|
|
{
|
|
/* Parameters are checked in this function. */
|
|
return _Cellular_TimeoutAtcmdRequestWithCallback( pContext, atReq, ( uint32_t ) PACKET_REQ_TIMEOUT_MS );
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
CellularPktStatus_t _Cellular_TimeoutAtcmdRequestWithCallback( CellularContext_t * pContext,
|
|
CellularAtReq_t atReq,
|
|
uint32_t timeoutMS )
|
|
{
|
|
return _Cellular_PktHandler_AtcmdRequestWithCallback( pContext, atReq, timeoutMS );
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|