CellularLib: Processing Response as URC Only Instead of Both URC and Final Response

Hello,

const char * CellularSrcTokenErrorTable[] =
{ "ERROR", "BUSY", "NO CARRIER", "NO ANSWER", "NO DIALTONE", "ABORTED", "+CMS ERROR", "+CME ERROR", "SEND FAIL" };

const char * CellularUrcTokenWoPrefixTable[] =
{ "NORMAL POWER DOWN", "RDY", "NO CARRIER" };

When a final response like “NO CARRIER” is added to both tables above, if a “NO CARRIER” response is received for a sent AT command, this response will be processed as a URC.

To address this issue, if a command has been sent and a response is expected, the incoming response should first be searched and processed in the final response table.

As a solution, we can make a simple change as shown below.

static _atRespType_t _getMsgType( CellularContext_t * pContext,
                                  const char * pLine,
                                  const char * pRespPrefix )
{
    _atRespType_t atRespType = AT_UNDEFINED;
    CellularATError_t atStatus = CELLULAR_AT_SUCCESS;
    bool inputWithPrefix = false;
    bool inputWithSrcPrefix = false;

    /* Lock the response mutex when deciding message type. */
    PlatformMutex_Lock( &( pContext->PktRespMutex ) );

    if (pContext->PktioAtCmdType != CELLULAR_AT_NO_COMMAND) /* && (WE CAN CHECK FINAL RESPONSE IS RECEIVED) */
    {
        atRespType = AT_SOLICITED;
    }
    else if( _checkUrcTokenWoPrefix( pContext, pLine ) == true )
    {
        atRespType = AT_UNSOLICITED;
    }
    else
    {
        /* Check if prefix exist in pLine. */
        ( void ) Cellular_ATIsPrefixPresent( pLine, &inputWithPrefix );

        if( ( inputWithPrefix == true ) && ( pRespPrefix != NULL ) )
        {
            /* Check if this line contains prefix expected in AT command response. */
            atStatus = Cellular_ATStrStartWith( pLine, pRespPrefix, &inputWithSrcPrefix );
        }
    }

    if( ( atStatus == CELLULAR_AT_SUCCESS ) && ( atRespType == AT_UNDEFINED ) )
    {
        if( inputWithPrefix == true )
        {
            if( ( pContext->PktioAtCmdType != CELLULAR_AT_NO_COMMAND ) && ( inputWithSrcPrefix == true ) )
            {
                /* Celluar interface is sending AT command and this line contains
                 * expected prefix in the response. Return AT_SOLICITED here. */
                atRespType = AT_SOLICITED;
            }
            else
            {
                /* Lines with prefix are considered AT_UNSOLICITED unless the prefix
                 * is expected in AT command response. */
                atRespType = AT_UNSOLICITED;
            }
        }
        else
        {
            if( pContext->PktioAtCmdType != CELLULAR_AT_NO_COMMAND )
            {
                /* Cellular interface is waiting for AT command response from
                 * cellular modem. The token without prefix can be success or error
                 * token to indicate the AT command status. Return AT_SOLICITED
                 * here and this line will be parsed in _Cellular_ProcessLine later. */
                atRespType = AT_SOLICITED;
            }
            else
            {
                /* This line doesn't contain any prefix and cellular interface is
                 * not sending AT command. Therefore, this line is unexpected.
                 * Return AT_UNDEFINED here. */
                atRespType = AT_UNDEFINED;
            }
        }
    }

    PlatformMutex_Unlock( &( pContext->PktRespMutex ) );

    return atRespType;
}

What are your thoughts on this?

So in your case, a URC and a response can both have the same prefix? If yes, is it guaranteed that the modem won’t send a URC if the host is waiting for a command response? If yes, then we can move the URC checking at the end -

static _atRespType_t _getMsgType( CellularContext_t * pContext,
                                  const char * pLine,
                                  const char * pRespPrefix )
{
    _atRespType_t atRespType = AT_UNDEFINED;
    CellularATError_t atStatus = CELLULAR_AT_SUCCESS;
    bool inputWithPrefix = false;
    bool inputWithSrcPrefix = false;

    /* Lock the response mutex when deciding message type. */
    PlatformMutex_Lock( &( pContext->PktRespMutex ) );

    /* Check if prefix exist in pLine. */
    ( void ) Cellular_ATIsPrefixPresent( pLine, &inputWithPrefix );

    if( ( inputWithPrefix == true ) && ( pRespPrefix != NULL ) )
    {
        /* Check if this line contains prefix expected in AT command response. */
        atStatus = Cellular_ATStrStartWith( pLine, pRespPrefix, &inputWithSrcPrefix );
    }

    if( atStatus == CELLULAR_AT_SUCCESS )
    {
        if( inputWithPrefix == true )
        {
            if( ( pContext->PktioAtCmdType != CELLULAR_AT_NO_COMMAND ) && ( inputWithSrcPrefix == true ) )
            {
                /* Celluar interface is sending AT command and this line contains
                 * expected prefix in the response. Return AT_SOLICITED here. */
                atRespType = AT_SOLICITED;
            }
            else
            {
                /* Lines with prefix are considered AT_UNSOLICITED unless the prefix
                 * is expected in AT command response. */
                atRespType = AT_UNSOLICITED;
            }
        }
        else
        {
            if( pContext->PktioAtCmdType != CELLULAR_AT_NO_COMMAND )
            {
                /* Cellular interface is waiting for AT command response from
                 * cellular modem. The token without prefix can be success or error
                 * token to indicate the AT command status. Return AT_SOLICITED
                 * here and this line will be parsed in _Cellular_ProcessLine later. */
                atRespType = AT_SOLICITED;
            }
            else
            {
                /* This line doesn't contain any prefix and cellular interface is
                 * not sending AT command. Therefore, this line is unexpected.
                 * Return AT_UNDEFINED here. */
                atRespType = AT_UNDEFINED;
            }
        }
    }

    if( ( atStatus == CELLULAR_AT_SUCCESS ) && ( atRespType == AT_UNDEFINED ) )
    {
        if( _checkUrcTokenWoPrefix( pContext, pLine ) == true )
        {
            atRespType = AT_UNSOLICITED;
        }
    }

    PlatformMutex_Unlock( &( pContext->PktRespMutex ) );

    return atRespType;
}

Also, can your share the URC and Response syntax?

So in your case, a URC and a response can both have the same prefix?

Yes.

Is it guaranteed that the modem won’t send a URC if the host is waiting for a command response?

I think No. So my and ur solution will not give the right result.

Also, can your share the URC and Response syntax?

*When a call is initiated using the ATD command and it is successful, an OK response is received. If the call fails, a NO CARRIER response is returned.
*If the modem is connected to a call and the call is terminated for any reason (user, network, or the other party), a NO CARRIER message is sent as a URC.

In this case, what I want to understand is whether the received NO CARRIER response is a reply to the ATD command or a URC.

CellularError_t Cellular_Dial(CellularHandle_t cellularHandle, const char *pCallNumber)
{
    CellularContext_t *pContext = (CellularContext_t *)cellularHandle;
    CellularError_t cellularStatus;
    CellularPktStatus_t pktStatus;
    CellularAtReq_t atReq = {0};
    char cmdBuf[CELLULAR_AT_CMD_MAX_SIZE] = {'\0'};

    atReq.pAtCmd = cmdBuf;
    atReq.atCmdType = CELLULAR_AT_NO_RESULT;
    atReq.pAtRspPrefix = NULL;
    atReq.respCallback = NULL;
    atReq.pData = NULL;
    atReq.dataLen = 0;

    (void)snprintf(cmdBuf, CELLULAR_AT_CMD_MAX_SIZE, "ATD%s;", pCallNumber);

    /* Make sure library is open. */
    cellularStatus = _Cellular_CheckLibraryStatus(pContext);

    if (cellularStatus == CELLULAR_SUCCESS)
    {
        pktStatus = _Cellular_AtcmdRequestWithCallback(pContext, atReq);
        cellularStatus = _Cellular_TranslatePktStatus(pktStatus);
    }

    return cellularStatus;
}

Perhaps modifications can be made to the function above to handle the situation without disrupting the existing URC handling structure.

Because a URC can happen anytime, we need a way to differentiate if “NO CARRIER” is a URC or response to a command. You need to check with your modem vendor about how can we differentiate the two and then we can look into the best way to implement it.