810 lines
30 KiB
C
810 lines
30 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 packet handler functions to dispatch packet.
|
|
*/
|
|
|
|
#ifndef CELLULAR_DO_NOT_USE_CUSTOM_CONFIG
|
|
/* Include custom config file before other headers. */
|
|
#include "cellular_config.h"
|
|
#endif
|
|
#include "cellular_config_defaults.h"
|
|
|
|
/* Standard includes. */
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "cellular_platform.h"
|
|
#include "cellular_internal.h"
|
|
#include "cellular_pkthandler_internal.h"
|
|
#include "cellular_pktio_internal.h"
|
|
#include "cellular_types.h"
|
|
#include "cellular_common_internal.h"
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
#define MIN( a, b ) ( ( ( a ) < ( b ) ) ? ( a ) : ( b ) )
|
|
|
|
/* Windows simulator implementation. */
|
|
#if defined( _WIN32 ) || defined( _WIN64 )
|
|
#define strtok_r strtok_s
|
|
#endif
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
static CellularPktStatus_t _convertAndQueueRespPacket( CellularContext_t * pContext,
|
|
const void * pBuf );
|
|
static CellularPktStatus_t urcParseToken( CellularContext_t * pContext,
|
|
char * pInputLine );
|
|
static CellularPktStatus_t _processUrcPacket( CellularContext_t * pContext,
|
|
const char * pBuf );
|
|
static CellularPktStatus_t _Cellular_AtcmdRequestTimeoutWithCallbackRaw( CellularContext_t * pContext,
|
|
CellularAtReq_t atReq,
|
|
uint32_t timeoutMS );
|
|
static CellularPktStatus_t _Cellular_DataSendWithTimeoutDelayRaw( CellularContext_t * pContext,
|
|
CellularAtDataReq_t dataReq,
|
|
uint32_t timeoutMs,
|
|
uint32_t interDelayMS );
|
|
static void _Cellular_PktHandlerAcquirePktRequestMutex( CellularContext_t * pContext );
|
|
static void _Cellular_PktHandlerReleasePktRequestMutex( CellularContext_t * pContext );
|
|
static int _searchCompareFunc( const void * pInputToken,
|
|
const void * pBase );
|
|
static int _sortCompareFunc( const void * pElem1Ptr,
|
|
const void * pElem2Ptr );
|
|
static void _Cellular_ProcessGenericUrc( const CellularContext_t * pContext,
|
|
const char * pInputLine );
|
|
static CellularPktStatus_t _atParseGetHandler( CellularContext_t * pContext,
|
|
const char * pTokenPtr,
|
|
char * pSavePtr );
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
static CellularPktStatus_t _convertAndQueueRespPacket( CellularContext_t * pContext,
|
|
const void * pBuf )
|
|
{
|
|
CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_OK;
|
|
const CellularATCommandResponse_t * pAtResp = NULL;
|
|
|
|
if( ( pBuf != NULL ) )
|
|
{
|
|
pAtResp = ( const CellularATCommandResponse_t * ) pBuf;
|
|
PlatformMutex_Lock( &pContext->PktRespMutex );
|
|
|
|
if( pAtResp->status == false )
|
|
{
|
|
LogError( ( "_convertAndQueueRespPacket: AT response contains error" ) );
|
|
pktStatus = CELLULAR_PKT_STATUS_FAILURE;
|
|
}
|
|
|
|
if( ( pContext->pktRespCB != NULL ) && ( pktStatus == CELLULAR_PKT_STATUS_OK ) )
|
|
{
|
|
pktStatus = pContext->pktRespCB( pContext,
|
|
( const CellularATCommandResponse_t * ) pBuf,
|
|
pContext->pPktUsrData,
|
|
pContext->PktUsrDataLen );
|
|
}
|
|
|
|
/* Notify calling thread, Not blocking immediately comes back if the queue is full. */
|
|
/* This is platform dependent api. */
|
|
/* coverity[misra_c_2012_directive_4_6_violation] */
|
|
if( xQueueSend( pContext->pktRespQueue, ( void * ) &pktStatus, ( TickType_t ) 0 ) != pdPASS )
|
|
{
|
|
pktStatus = CELLULAR_PKT_STATUS_FAILURE;
|
|
LogError( ( "_convertAndQueueRespPacket: Got a response when the Resp Q is full!!" ) );
|
|
}
|
|
|
|
PlatformMutex_Unlock( &pContext->PktRespMutex );
|
|
}
|
|
else
|
|
{
|
|
pktStatus = CELLULAR_PKT_STATUS_BAD_PARAM;
|
|
}
|
|
|
|
return pktStatus;
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
static CellularPktStatus_t urcParseToken( CellularContext_t * pContext,
|
|
char * pInputLine )
|
|
{
|
|
CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_OK;
|
|
|
|
/* pInputLine = "+" pTokenPtr + ":" + pSavePtr.
|
|
* if string not start with "+", then pTokenPtr = pSavePtr = pInputPtr. */
|
|
char * pSavePtr = pInputLine, * pTokenPtr = pInputLine;
|
|
|
|
|
|
LogDebug( ( "Next URC token to parse [%s]", pInputLine ) );
|
|
|
|
/* First check for + at the beginning and advance to point to the next
|
|
* byte. Use that string to pass to strtok and retrieve the token. Once the
|
|
* token use is retrieved, get the function handler map and call that
|
|
* function. */
|
|
if( *pSavePtr == '+' )
|
|
{
|
|
pSavePtr++;
|
|
pTokenPtr = strtok_r( pSavePtr, ":", &pSavePtr );
|
|
|
|
if( pTokenPtr == NULL )
|
|
{
|
|
LogError( ( "_Cellular_AtParse : input string error, start with \"+\" but no token %s", pInputLine ) );
|
|
pktStatus = CELLULAR_PKT_STATUS_BAD_REQUEST;
|
|
}
|
|
}
|
|
|
|
if( pktStatus == CELLULAR_PKT_STATUS_OK )
|
|
{
|
|
/* Now get the handler function based on the token. */
|
|
pktStatus = _atParseGetHandler( pContext, pTokenPtr, pSavePtr );
|
|
}
|
|
|
|
return pktStatus;
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
/**
|
|
* @brief copy the URC log in the buffer to a heap memory and process it.
|
|
*/
|
|
static CellularPktStatus_t _processUrcPacket( CellularContext_t * pContext,
|
|
const char * pBuf )
|
|
{
|
|
CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_OK;
|
|
CellularATError_t atStatus = CELLULAR_AT_SUCCESS;
|
|
char * payload = NULL;
|
|
|
|
if( pBuf != NULL )
|
|
{
|
|
atStatus = Cellular_ATStrDup( &payload, pBuf );
|
|
|
|
if( atStatus == CELLULAR_AT_SUCCESS )
|
|
{
|
|
/* The payload is null terminated. */
|
|
pktStatus = urcParseToken( pContext, ( char * ) payload );
|
|
Platform_Free( payload );
|
|
}
|
|
else
|
|
{
|
|
pktStatus = CELLULAR_PKT_STATUS_FAILURE;
|
|
LogWarn( ( "Couldn't allocate memory of %u for urc", ( uint32_t ) strlen( pBuf ) ) );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pktStatus = CELLULAR_PKT_STATUS_BAD_PARAM;
|
|
}
|
|
|
|
return pktStatus;
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
static CellularPktStatus_t _Cellular_AtcmdRequestTimeoutWithCallbackRaw( CellularContext_t * pContext,
|
|
CellularAtReq_t atReq,
|
|
uint32_t timeoutMS )
|
|
{
|
|
CellularPktStatus_t respCode = CELLULAR_PKT_STATUS_OK;
|
|
CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_OK;
|
|
BaseType_t qRet = pdFALSE;
|
|
|
|
if( atReq.pAtCmd == NULL )
|
|
{
|
|
LogError( ( "PKT_STATUS_BAD_REQUEST, null AT param" ) );
|
|
pktStatus = CELLULAR_PKT_STATUS_BAD_REQUEST;
|
|
}
|
|
else
|
|
{
|
|
/* Fill in request info structure. */
|
|
pContext->pktRespCB = atReq.respCallback;
|
|
LogDebug( ( ">>>>>Start sending [%s]<<<<<", atReq.pAtCmd ) );
|
|
pContext->pPktUsrData = atReq.pData;
|
|
pContext->PktUsrDataLen = ( uint16_t ) atReq.dataLen;
|
|
pContext->pCurrentCmd = atReq.pAtCmd;
|
|
pktStatus = _Cellular_PktioSendAtCmd( pContext, atReq.pAtCmd, atReq.atCmdType, atReq.pAtRspPrefix );
|
|
|
|
if( pktStatus != CELLULAR_PKT_STATUS_OK )
|
|
{
|
|
LogError( ( "Can't send req packet" ) );
|
|
}
|
|
else
|
|
{
|
|
/* Wait for a response. */
|
|
/* This is platform dependent api. */
|
|
/* coverity[misra_c_2012_directive_4_6_violation] */
|
|
qRet = xQueueReceive( pContext->pktRespQueue, &respCode, pdMS_TO_TICKS( timeoutMS ) );
|
|
|
|
if( qRet == pdTRUE )
|
|
{
|
|
pktStatus = ( CellularPktStatus_t ) respCode;
|
|
|
|
if( pktStatus != CELLULAR_PKT_STATUS_OK )
|
|
{
|
|
LogError( ( "pkt_recv status=%d, error in AT cmd %s resp", pktStatus, atReq.pAtCmd ) );
|
|
} /* Ignore errors from callbacks as they will be handled elsewhere. */
|
|
}
|
|
else
|
|
{
|
|
pktStatus = CELLULAR_PKT_STATUS_TIMED_OUT;
|
|
LogError( ( "pkt_recv status=%d, AT cmd %s timed out", pktStatus, atReq.pAtCmd ) );
|
|
}
|
|
}
|
|
|
|
/* No command is waiting response. */
|
|
pContext->PktioAtCmdType = CELLULAR_AT_NO_COMMAND;
|
|
pContext->pktRespCB = NULL;
|
|
pContext->pCurrentCmd = NULL;
|
|
LogDebug( ( "<<<<<Exit sending [%s] status[%d]<<<<<", atReq.pAtCmd, pktStatus ) );
|
|
}
|
|
|
|
return pktStatus;
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
static CellularPktStatus_t _Cellular_DataSendWithTimeoutDelayRaw( CellularContext_t * pContext,
|
|
CellularAtDataReq_t dataReq,
|
|
uint32_t timeoutMs,
|
|
uint32_t interDelayMS )
|
|
{
|
|
CellularPktStatus_t respCode = CELLULAR_PKT_STATUS_OK;
|
|
CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_OK;
|
|
BaseType_t qStatus = pdFALSE;
|
|
uint32_t sendEndPatternLen = 0U;
|
|
|
|
if( ( dataReq.pData == NULL ) || ( dataReq.pSentDataLength == NULL ) )
|
|
{
|
|
LogError( ( "_Cellular_DataSendWithTimeoutDelayRaw, null input" ) );
|
|
pktStatus = CELLULAR_PKT_STATUS_BAD_REQUEST;
|
|
}
|
|
else
|
|
{
|
|
LogDebug( ( ">>>>>Start sending Data <<<<<" ) );
|
|
pContext->PktioAtCmdType = CELLULAR_AT_NO_RESULT;
|
|
/* Send the packet. */
|
|
*dataReq.pSentDataLength = _Cellular_PktioSendData( pContext, dataReq.pData, dataReq.dataLen );
|
|
|
|
if( *dataReq.pSentDataLength != dataReq.dataLen )
|
|
{
|
|
LogError( ( "_Cellular_DataSendWithTimeoutDelayRaw, incomplete data transfer" ) );
|
|
pktStatus = CELLULAR_PKT_STATUS_SEND_ERROR;
|
|
}
|
|
}
|
|
|
|
/* Some driver required wait for a minimum of delay before sending data. */
|
|
Platform_Delay( interDelayMS );
|
|
|
|
/* End pattern for specific modem. */
|
|
if( ( pktStatus == CELLULAR_PKT_STATUS_OK ) && ( dataReq.pEndPattern != NULL ) )
|
|
{
|
|
sendEndPatternLen = _Cellular_PktioSendData( pContext, dataReq.pEndPattern, dataReq.endPatternLen );
|
|
|
|
if( sendEndPatternLen != dataReq.endPatternLen )
|
|
{
|
|
LogError( ( "_Cellular_DataSendWithTimeoutDelayRaw, incomplete endpattern transfer" ) );
|
|
pktStatus = CELLULAR_PKT_STATUS_SEND_ERROR;
|
|
}
|
|
}
|
|
|
|
/* Wait for a response. */
|
|
if( pktStatus == CELLULAR_PKT_STATUS_OK )
|
|
{
|
|
qStatus = xQueueReceive( pContext->pktRespQueue, &respCode, pdMS_TO_TICKS( timeoutMs ) );
|
|
|
|
if( qStatus == pdTRUE )
|
|
{
|
|
pktStatus = ( CellularPktStatus_t ) respCode;
|
|
|
|
if( pktStatus == CELLULAR_PKT_STATUS_OK )
|
|
{
|
|
LogDebug( ( "Data sent successfully!" ) );
|
|
}
|
|
else
|
|
{
|
|
LogError( ( "pkt_recv status=%d, error in sending data", pktStatus ) );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pktStatus = CELLULAR_PKT_STATUS_TIMED_OUT;
|
|
LogError( ( "pkt_recv status=%d, data sending timed out", pktStatus ) );
|
|
}
|
|
|
|
pContext->PktioAtCmdType = CELLULAR_AT_NO_COMMAND;
|
|
LogDebug( ( "<<<<<Exit sending data ret[%d]>>>>>", pktStatus ) );
|
|
}
|
|
|
|
return pktStatus;
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
static void _Cellular_PktHandlerAcquirePktRequestMutex( CellularContext_t * pContext )
|
|
{
|
|
PlatformMutex_Lock( &pContext->pktRequestMutex );
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
static void _Cellular_PktHandlerReleasePktRequestMutex( CellularContext_t * pContext )
|
|
{
|
|
PlatformMutex_Unlock( &pContext->pktRequestMutex );
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
/* _searchCompareFunc is returning a variable with "int" data type because
|
|
* this is the Compare function used in bsearch() function.
|
|
* bsearch function syntax mandates the compare function should be of type int.
|
|
* Hence int data type is used instead of typedef datatype. */
|
|
/* coverity[misra_c_2012_directive_4_6_violation] */
|
|
static int _searchCompareFunc( const void * pInputToken,
|
|
const void * pBase )
|
|
{
|
|
/* _searchCompareFunc is returning a variable with "int" data type because
|
|
* this is the Compare function used in bsearch() function.
|
|
* bsearch function syntax mandates the compare function should be of type int.
|
|
* Hence int data type is used instead of typedef datatype. */
|
|
/* coverity[misra_c_2012_directive_4_6_violation] */
|
|
int compareValue = 0;
|
|
const char * pToken = ( const char * ) pInputToken;
|
|
const CellularAtParseTokenMap_t * pBasePtr = ( const CellularAtParseTokenMap_t * ) pBase;
|
|
uint32_t tokenLen = ( uint32_t ) strlen( pInputToken );
|
|
uint32_t strLen = ( uint32_t ) strlen( pBasePtr->pStrValue );
|
|
|
|
compareValue = strncmp( pToken,
|
|
pBasePtr->pStrValue,
|
|
MIN( tokenLen, strLen ) );
|
|
|
|
/* To avoid undefined behavior, the table should not contain duplicated item and
|
|
* compareValue is 0 only if the string is exactly the same. */
|
|
if( ( compareValue == 0 ) && ( tokenLen != strLen ) )
|
|
{
|
|
if( tokenLen > strLen )
|
|
{
|
|
compareValue = 1;
|
|
}
|
|
else
|
|
{
|
|
compareValue = -1;
|
|
}
|
|
}
|
|
|
|
return compareValue;
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
/* _sortCompareFunc is returning a variable with "int" data type because
|
|
* this is the Compare function used in qsort() function.
|
|
* qsort function syntax mandates the compare function should be of type int.
|
|
* Hence int data type is used instead of typedef datatype. */
|
|
/* coverity[misra_c_2012_directive_4_6_violation] */
|
|
static int _sortCompareFunc( const void * pElem1Ptr,
|
|
const void * pElem2Ptr )
|
|
{
|
|
/* _sortCompareFunc is returning a variable with "int" data type because
|
|
* this is the Compare function used in qsort() function.
|
|
* qsort function syntax mandates the compare function should be of type int.
|
|
* Hence int data type is used instead of typedef datatype. */
|
|
/* coverity[misra_c_2012_directive_4_6_violation] */
|
|
int compareValue = 0;
|
|
const CellularAtParseTokenMap_t * pElement1Ptr = ( const CellularAtParseTokenMap_t * ) pElem1Ptr;
|
|
const CellularAtParseTokenMap_t * pElement2Ptr = ( const CellularAtParseTokenMap_t * ) pElem2Ptr;
|
|
uint32_t element1PtrLen = ( uint32_t ) strlen( pElement1Ptr->pStrValue );
|
|
uint32_t element2PtrLen = ( uint32_t ) strlen( pElement2Ptr->pStrValue );
|
|
|
|
compareValue = strncmp( pElement1Ptr->pStrValue,
|
|
pElement2Ptr->pStrValue,
|
|
MIN( element1PtrLen, element2PtrLen ) );
|
|
|
|
/* To avoid undefined behavior, the table should not contain duplicated item and
|
|
* compareValue is 0 only if the string is exactly the same. */
|
|
if( ( compareValue == 0 ) && ( element1PtrLen != element2PtrLen ) )
|
|
{
|
|
if( element1PtrLen > element2PtrLen )
|
|
{
|
|
compareValue = 1;
|
|
}
|
|
else
|
|
{
|
|
compareValue = -1;
|
|
}
|
|
}
|
|
|
|
return compareValue;
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
static void _Cellular_ProcessGenericUrc( const CellularContext_t * pContext,
|
|
const char * pInputLine )
|
|
{
|
|
_Cellular_GenericCallback( pContext, pInputLine );
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
static CellularPktStatus_t _atParseGetHandler( CellularContext_t * pContext,
|
|
const char * pTokenPtr,
|
|
char * pSavePtr )
|
|
{
|
|
/* Now get the handler function based on the token. */
|
|
const CellularAtParseTokenMap_t * pElementPtr = NULL;
|
|
CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_OK;
|
|
const CellularAtParseTokenMap_t * pTokenMap = pContext->tokenTable.pCellularUrcHandlerTable;
|
|
uint32_t tokenMapSize = pContext->tokenTable.cellularPrefixToParserMapSize;
|
|
|
|
/* the unspecified behavior, which relates to the treatment of elements that compare as equal,
|
|
* can be avoided by ensuring that the comparison function never returns 0.
|
|
* When two elements are otherwise equal, the comparison function could
|
|
* return a value that indicates their relative order in the initial array.
|
|
* This the token table must be checked without duplicated string. The return value
|
|
* is 0 only if the string is exactly the same. */
|
|
/* coverity[misra_c_2012_rule_21_9_violation] */
|
|
pElementPtr = ( CellularAtParseTokenMap_t * ) bsearch( ( const void * ) pTokenPtr,
|
|
( const void * ) pTokenMap,
|
|
tokenMapSize,
|
|
sizeof( CellularAtParseTokenMap_t ),
|
|
_searchCompareFunc );
|
|
|
|
if( pElementPtr != NULL )
|
|
{
|
|
if( pElementPtr->parserFunc != NULL )
|
|
{
|
|
pElementPtr->parserFunc( pContext, pSavePtr );
|
|
}
|
|
else
|
|
{
|
|
LogWarn( ( "No URC Callback func avail %s", pTokenPtr ) );
|
|
pktStatus = CELLULAR_PKT_STATUS_FAILURE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* No URC callback function available, check for generic call back. */
|
|
LogDebug( ( "No URC Callback func avail %s, now trying generic URC Callback", pTokenPtr ) );
|
|
_Cellular_ProcessGenericUrc( pContext, pSavePtr );
|
|
}
|
|
|
|
return pktStatus;
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
void _Cellular_PktHandlerCleanup( CellularContext_t * pContext )
|
|
{
|
|
if( ( pContext != NULL ) && ( pContext->pktRespQueue != NULL ) )
|
|
{
|
|
/* Wait for response to finish. */
|
|
_Cellular_PktHandlerAcquirePktRequestMutex( pContext );
|
|
/* This is platform dependent api. */
|
|
/* coverity[misra_c_2012_directive_4_6_violation] */
|
|
( void ) vQueueDelete( pContext->pktRespQueue );
|
|
pContext->pktRespQueue = NULL;
|
|
_Cellular_PktHandlerReleasePktRequestMutex( pContext );
|
|
}
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
CellularPktStatus_t _Cellular_HandlePacket( CellularContext_t * pContext,
|
|
_atRespType_t atRespType,
|
|
const void * pBuf )
|
|
{
|
|
CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_OK;
|
|
|
|
if( pContext != NULL )
|
|
{
|
|
switch( atRespType )
|
|
{
|
|
case AT_SOLICITED:
|
|
pktStatus = _convertAndQueueRespPacket( pContext, pBuf );
|
|
break;
|
|
|
|
case AT_UNSOLICITED:
|
|
pktStatus = _processUrcPacket( pContext, pBuf );
|
|
break;
|
|
|
|
default:
|
|
pktStatus = CELLULAR_PKT_STATUS_BAD_PARAM;
|
|
LogError( ( "_Cellular_HandlePacket Callback type (%d) error", atRespType ) );
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pktStatus = CELLULAR_PKT_STATUS_INVALID_HANDLE;
|
|
}
|
|
|
|
return pktStatus;
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
CellularPktStatus_t _Cellular_PktHandler_AtcmdRequestWithCallback( CellularContext_t * pContext,
|
|
CellularAtReq_t atReq,
|
|
uint32_t timeoutMS )
|
|
{
|
|
CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_OK;
|
|
|
|
if( pContext == NULL )
|
|
{
|
|
LogError( ( "_Cellular_TimeoutAtcmdRequestWithCallback : Invalid cellular context" ) );
|
|
pktStatus = CELLULAR_PKT_STATUS_INVALID_HANDLE;
|
|
}
|
|
else
|
|
{
|
|
_Cellular_PktHandlerAcquirePktRequestMutex( pContext );
|
|
pktStatus = _Cellular_AtcmdRequestTimeoutWithCallbackRaw( pContext, atReq, timeoutMS );
|
|
_Cellular_PktHandlerReleasePktRequestMutex( pContext );
|
|
}
|
|
|
|
return pktStatus;
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
CellularPktStatus_t _Cellular_TimeoutAtcmdDataRecvRequestWithCallback( CellularContext_t * pContext,
|
|
CellularAtReq_t atReq,
|
|
uint32_t timeoutMS,
|
|
CellularATCommandDataPrefixCallback_t pktDataPrefixCallback,
|
|
void * pCallbackContext )
|
|
{
|
|
CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_OK;
|
|
|
|
if( pContext == NULL )
|
|
{
|
|
LogError( ( "_Cellular_TimeoutAtcmdDataRecvRequestWithCallback : Invalid cellular context" ) );
|
|
pktStatus = CELLULAR_PKT_STATUS_INVALID_HANDLE;
|
|
}
|
|
else
|
|
{
|
|
_Cellular_PktHandlerAcquirePktRequestMutex( pContext );
|
|
pContext->pktDataPrefixCB = pktDataPrefixCallback;
|
|
pContext->pDataPrefixCBContext = pCallbackContext;
|
|
pktStatus = _Cellular_AtcmdRequestTimeoutWithCallbackRaw( pContext, atReq, timeoutMS );
|
|
pContext->pktDataPrefixCB = NULL;
|
|
pContext->pDataPrefixCBContext = NULL;
|
|
_Cellular_PktHandlerReleasePktRequestMutex( pContext );
|
|
}
|
|
|
|
return pktStatus;
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
CellularPktStatus_t _Cellular_AtcmdDataSend( CellularContext_t * pContext,
|
|
CellularAtReq_t atReq,
|
|
CellularAtDataReq_t dataReq,
|
|
CellularATCommandDataSendPrefixCallback_t pktDataSendPrefixCallback,
|
|
void * pCallbackContext,
|
|
uint32_t atTimeoutMS,
|
|
uint32_t dataTimeoutMS,
|
|
uint32_t interDelayMS )
|
|
{
|
|
CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_OK;
|
|
|
|
if( pContext == NULL )
|
|
{
|
|
LogError( ( "_Cellular_TimeoutAtcmdDataSendRequestWithCallback : Invalid cellular context" ) );
|
|
pktStatus = CELLULAR_PKT_STATUS_INVALID_HANDLE;
|
|
}
|
|
else
|
|
{
|
|
_Cellular_PktHandlerAcquirePktRequestMutex( pContext );
|
|
pContext->pktDataSendPrefixCB = pktDataSendPrefixCallback;
|
|
pContext->pDataSendPrefixCBContext = pCallbackContext;
|
|
pktStatus = _Cellular_AtcmdRequestTimeoutWithCallbackRaw( pContext, atReq, atTimeoutMS );
|
|
pContext->pDataSendPrefixCBContext = NULL;
|
|
pContext->pktDataSendPrefixCB = NULL;
|
|
|
|
if( pktStatus == CELLULAR_PKT_STATUS_OK )
|
|
{
|
|
pktStatus = _Cellular_DataSendWithTimeoutDelayRaw( pContext, dataReq, dataTimeoutMS, interDelayMS );
|
|
}
|
|
|
|
_Cellular_PktHandlerReleasePktRequestMutex( pContext );
|
|
}
|
|
|
|
return pktStatus;
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
CellularPktStatus_t _Cellular_TimeoutAtcmdDataSendRequestWithCallback( CellularContext_t * pContext,
|
|
CellularAtReq_t atReq,
|
|
CellularAtDataReq_t dataReq,
|
|
uint32_t atTimeoutMS,
|
|
uint32_t dataTimeoutMS )
|
|
{
|
|
return _Cellular_AtcmdDataSend( pContext, atReq, dataReq, NULL, NULL, atTimeoutMS, dataTimeoutMS, 0U );
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
CellularPktStatus_t _Cellular_TimeoutAtcmdDataSendSuccessToken( CellularContext_t * pContext,
|
|
CellularAtReq_t atReq,
|
|
CellularAtDataReq_t dataReq,
|
|
uint32_t atTimeoutMS,
|
|
uint32_t dataTimeoutMS,
|
|
const char ** pCellularSrcTokenSuccessTable,
|
|
uint32_t cellularSrcTokenSuccessTableSize )
|
|
{
|
|
CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_OK;
|
|
|
|
if( pContext == NULL )
|
|
{
|
|
LogError( ( "_Cellular_TimeoutAtcmdDataSendSuccessToken : Invalid cellular context" ) );
|
|
pktStatus = CELLULAR_PKT_STATUS_INVALID_HANDLE;
|
|
}
|
|
else
|
|
{
|
|
_Cellular_PktHandlerAcquirePktRequestMutex( pContext );
|
|
pContext->tokenTable.pCellularSrcExtraTokenSuccessTable = pCellularSrcTokenSuccessTable;
|
|
pContext->tokenTable.cellularSrcExtraTokenSuccessTableSize = cellularSrcTokenSuccessTableSize;
|
|
pktStatus = _Cellular_AtcmdRequestTimeoutWithCallbackRaw( pContext, atReq, atTimeoutMS );
|
|
pContext->tokenTable.cellularSrcExtraTokenSuccessTableSize = 0;
|
|
pContext->tokenTable.pCellularSrcExtraTokenSuccessTable = NULL;
|
|
|
|
if( pktStatus == CELLULAR_PKT_STATUS_OK )
|
|
{
|
|
pktStatus = _Cellular_DataSendWithTimeoutDelayRaw( pContext, dataReq, dataTimeoutMS, 0U );
|
|
}
|
|
|
|
_Cellular_PktHandlerReleasePktRequestMutex( pContext );
|
|
}
|
|
|
|
return pktStatus;
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
CellularPktStatus_t _Cellular_PktHandlerInit( CellularContext_t * pContext )
|
|
{
|
|
CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_OK;
|
|
|
|
if( pContext != NULL )
|
|
{
|
|
/* Create the response queue which is used to post reponses to the sender. */
|
|
/* This is platform dependent api. */
|
|
/* coverity[misra_c_2012_directive_4_6_violation] */
|
|
/* coverity[misra_c_2012_rule_11_4_violation] */
|
|
pContext->pktRespQueue = xQueueCreate( 1, ( uint32_t ) sizeof( CellularPktStatus_t ) );
|
|
|
|
if( pContext->pktRespQueue == NULL )
|
|
{
|
|
pktStatus = CELLULAR_PKT_STATUS_FAILURE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pktStatus = CELLULAR_PKT_STATUS_FAILURE;
|
|
}
|
|
|
|
return pktStatus;
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
CellularPktStatus_t _Cellular_AtParseInit( const CellularContext_t * pContext )
|
|
{
|
|
uint32_t i = 0;
|
|
bool finit = true;
|
|
const CellularAtParseTokenMap_t * pTokenMap = NULL;
|
|
uint32_t tokenMapSize = 0;
|
|
int32_t result = 0;
|
|
CellularPktStatus_t pktStatus = CELLULAR_PKT_STATUS_OK;
|
|
|
|
if( ( pContext != NULL ) && ( pContext->tokenTable.pCellularUrcHandlerTable != NULL ) &&
|
|
( pContext->tokenTable.cellularPrefixToParserMapSize > 0U ) )
|
|
{
|
|
pTokenMap = pContext->tokenTable.pCellularUrcHandlerTable;
|
|
tokenMapSize = pContext->tokenTable.cellularPrefixToParserMapSize;
|
|
|
|
/* Check order of the sorted Map. */
|
|
for( i = 0; i < ( tokenMapSize - 1U ); i++ )
|
|
{
|
|
result = _sortCompareFunc( &pTokenMap[ i ], &pTokenMap[ i + 1U ] );
|
|
|
|
if( result >= 0 )
|
|
{
|
|
LogError( ( "AtParseFail for %u: %d %s %s", i, result,
|
|
pTokenMap[ i ].pStrValue, pTokenMap[ i + 1U ].pStrValue ) );
|
|
finit = false;
|
|
}
|
|
}
|
|
|
|
if( finit != true )
|
|
{
|
|
pktStatus = CELLULAR_PKT_STATUS_BAD_PARAM;
|
|
LogError( ( "AtParseFail URC token table is not sorted" ) );
|
|
}
|
|
|
|
configASSERT( finit == true );
|
|
|
|
for( i = 0; i < tokenMapSize; i++ )
|
|
{
|
|
LogDebug( ( "Callbacks setup for %u : %s", i, pTokenMap[ i ].pStrValue ) );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pktStatus = CELLULAR_PKT_STATUS_INVALID_HANDLE;
|
|
}
|
|
|
|
return pktStatus;
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
bool _Cellular_CreatePktRequestMutex( CellularContext_t * pContext )
|
|
{
|
|
bool status = false;
|
|
|
|
if( pContext != NULL )
|
|
{
|
|
status = PlatformMutex_Create( &pContext->pktRequestMutex, false );
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
bool _Cellular_CreatePktResponseMutex( CellularContext_t * pContext )
|
|
{
|
|
bool status = false;
|
|
|
|
if( pContext != NULL )
|
|
{
|
|
status = PlatformMutex_Create( &pContext->PktRespMutex, false );
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
void _Cellular_DestroyPktRequestMutex( CellularContext_t * pContext )
|
|
{
|
|
if( pContext != NULL )
|
|
{
|
|
PlatformMutex_Destroy( &pContext->pktRequestMutex );
|
|
}
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
void _Cellular_DestroyPktResponseMutex( CellularContext_t * pContext )
|
|
{
|
|
if( pContext != NULL )
|
|
{
|
|
PlatformMutex_Destroy( &pContext->PktRespMutex );
|
|
}
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|