软件

AT指令框架学习笔记

示例代码:

思考:

/* 名称 | 查询格式 | 查询返回格式 | 设置格式 | 设置返回格式 */
{"CIPSEND", "", "", "=%d,%d", "> "}
{NULL, NULL, NULL, NULL, "+CIPSEND: %d"}
    graph TB

    a(Command Write) --> c(dma Write)
    c --> d(wait send finish)
    d --> e(Uart send finish)
    e -->f(Finish)
uint8_t Buffer[BUFFER_SIZE];
char Payload[PAYLOAD_SIZE];
extern UART_HandleTypeDef huart3;

CommandTypedef AtCommand[] =
{
    /* name|query transmit format|query receive format|set tranmmit format|set receive format */
    {"AT",      "",         "",                             NULL,                       NULL    },
    {"CGMI",    "",         "%s",                           NULL,                       NULL    },
    {"CGMM",    "",         "%s",                           NULL,                       NULL    },
    {"CGSN",    "=1",       "+CGSN:%s",                     NULL,                       NULL    },
    {"CFUN",    "?",        "+CFUN:%d",                     "=%d",                      ""      },
    {"CSQ",     "",         "+CSQ:%d,%*d",                  NULL,                       NULL    },
    {"NBAND",   "?",        "+NBAND:%d",                    "=%d",                      ""      },
    {"CGACT",   "?",        "+CGACT:%*d,%d",                "=%d,%d",                   ""      },
    {"CGATT",   "?",        "+CGATT:%d",                    NULL,                       NULL    },
    {"CEREG",   "?",        "+CEREG:%*d,%d",                "=%d",                      ""      },
    {"CSCON",   "?",        "+CSCON:%*d,%d",                "=%d",                      ""      },
    {"CGPADDR", "",         "+CGPADDR:%*d,%d.%d.%d.%d",      NULL,                       NULL   },
    {"NCONFIG", "?",        "+NCONFIG:%*11s,%s",            "=%s,%s",                   ""      },
    {"CPSMS",   "?",        "+CPSMS:%d",                    "=%d",                      NULL    },
    {"NMGS",    NULL,        NULL,                          "=%u,%s",                   ""      },
    {"NNMI",    "?",        "+NNMI:%u",                     "=%u",                      ""      },
    {"NCDP",    "?",        "+NCDP:%u.%u.%u.%u,%u",         "=%u.%u.%u.%u,%u",          ""      },
    {"NMSTATUS","?",        "+NMSTATUS:%*s",                NULL,                       NULL    },
    {"NNMI",    NULL,       "+NNMI:%u,%s",                  NULL,                       NULL    },
    {"CCLK",    "?",        "+CCLK:%u/%u/%u,%u:%u:%u+%u",   NULL,                       NULL    },
    {"NCCID",   "?",        "+NCCID:%s",                    NULL,                       NULL    },
};

/* AT_OK的正则表达式对照组 */
static const char *atOkPattern = "\r\nOK\r\n";
/* AT_ERROR的正则表达式对照组 */
static const char *atErrorPattern = "\r\nERROR\r\n";


/**
  * @brief  AT 查询指令或执行指令
    @param  command 指令名
            ... 额外的参数(与query receive format 匹配)
  * @retval skip
  */
AT_StatusTypedef atreadCommand(AtCommandListTypedef command, ...) {

    uint16_t len;
    size_t index;

    /* 从AT指令表中取出对应指令应该具有的发送格式,然后加上"AT+"前缀 */
    len = sprintf(Payload, "AT+%s%s\r\n",
                  AtCommand[command].Name, AtCommand[command].pQueryTransmitFormat);
    serial_write(&huart3, (uint8_t *)Payload, len);
    /* 发送完成之后进入接收模式 */
    len = serial_read(&huart3, Buffer, BUFFER_SIZE, 1000);

    /* 没有收到任何数据,返回 未响应 */
    /* 此处应该是指令格式有误,AT解释器不处理该指令,因检查指令拼写*/
    if(len == 0)
        return AT_NO_RESPONSE;

    /* 匹配到返回数据中有OK,认为指令执行成功 */
    if(re_match(atOkPattern, (char *)Buffer) != -1)
    {
        /* 将Buffer索引起点设置在2的位置,避开开头的\r\n转义字符 */
        index = 2;
        va_list list;
        va_start(list, command);
        vsscanf((char *)(Buffer + index), AtCommand[command].pQueryReceiveFormat, list);
        va_end(list);
        return AT_OK;
    }

    /* 匹配到返回数据中有ERROR */
    /* 此处正常情况下不会发生,若发生,应该是发送的指令格式有误,应该检查指令表 */
    if(re_match(atErrorPattern, (char *)Buffer) != -1)
        return AT_ERROR;

    /* 对于解析不了的返回格式错误,意味着传输过程中出现了意外 */
    /* 正常情况下此处也不该发生 */
    return AT_FORMAT_WRONG;
}

/**
  * @brief  AT 设置指令
  * @param  command,指令名
  *         ..., 额外的参数(与set tranmmit format匹配)
  * @retval skip
  */
AT_StatusTypedef atsendCommand(AtCommandListTypedef command, ...) {

    size_t len = 0;

    len += sprintf(Payload, "AT+%s", AtCommand[command].Name);
    va_list list;
    va_start(list, command);
    len += vsprintf(Payload + len, AtCommand[command].pSetTransmitFormat, list);
    va_end(list);
    len += sprintf(Payload + len, "\r\n");
    atCommandWrite((uint8_t*)Payload, len, 1000);
    len = atCommandRead(Buffer, 5000);

    /* 这里的返回情况和At_ReadCommand一样 */
    if(len == 0)
        return AT_NO_RESPONSE;

    if(re_match(atOkPattern, (char *)Buffer) != -1)     // 需要引用正则匹配库
    {
        return AT_OK;
    }
    if(re_match(atErrorPattern, (char *)Buffer) != -1)
        return AT_ERROR;

    return AT_FORMAT_WRONG;
}

AT_StatusTypedef atwaitCommand(AtCommandListTypedef command, uint32_t timeout, ...) {

    uint16_t len;
    uint8_t index;

    len = serial_read(&huart3, Buffer, BUFFER_SIZE, timeout);

    if(len == 0)
        return AT_NO_RESPONSE;
    if(re_match(AtCommand[command].Name, (char *)Buffer) != -1)
    {
        index = 2;
        va_list list;
        va_start(list, timeout);
        vsscanf((char *)(Buffer + index), AtCommand[command].pQueryReceiveFormat, list);
        va_end(list);
        return AT_OK;
    }
    if(re_match(atErrorPattern, (char *)Buffer) != -1)
        return AT_ERROR;

    return AT_FORMAT_WRONG;
}

AT_StatusTypedef atSendNoATCommand(AtCommandListTypedef command, uchar *buffer, size_t length) {

    uint16_t len;
    if(AtCommand[command].Name != NULL) {

        len += sprintf(Payload, "AT+%s", AtCommand[command].Name);
    }
    memcpy(Payload + len, buffer, length);
    len += length;
    atCommandWrite((uint8_t*)Payload, len, 1000);
    len = atCommandRead(Buffer, 5000);

    /* 这里的返回情况和At_ReadCommand一样 */
    if(len == 0)
        return AT_NO_RESPONSE;

    if(AtCommand[command].pSetReceiveFormat != NULL) {

        if(re_match(AtCommand[command].pSetReceiveFormat, (char *)Buffer) != -1)        // 需要引用正则匹配库
        {
            return AT_OK;
        }
    }
    else {

        if(re_match(atOkPattern, (char *)Buffer) != -1)     // 需要引用正则匹配库
        {
            return AT_OK;
        }
        if(re_match(atErrorPattern, (char *)Buffer) != -1)
            return AT_ERROR;
    }

    return AT_FORMAT_WRONG;
}


bool atCommandWrite(uchar *buff, size_t len, uint32_t timeout) {

    return dmaWrite(buff, len, timeout);
}

size_t atCommandRead(uchar *buff, uint32_t timeout) {

    return dmaRead(buff, timeout);
}


/********************* HAL Library 实现 ********************/
bool dmaWrite(uchar *buff, size_t len, uint32_t timeout) {

    bool ret = false;

    if((buff == NULL) || (len == 0))
        return ret;

    bsp_dmaWrite(buff, len);            // 拷贝

    /* 等待DMA发送成功事件 */
    if(xSemaphoreTake(dmaSendTI_Semaphore, (TickType_t)timeout)) {

        /*到这里我们获取到信号量,现在可以访问共享资源了*/

        /* code */
        ret = true;

        /* 完成访问共享资源后,必须释放信号量*/
        xSemaphoreGive(dmaSendTI_Semaphore);
    }
    else {

        /* 没有获取到信号量,这里处理异常情况。*/
        while(1);
    }

    return ret;
}

uint32_t dmaRead(uchar *buffer, uint32_t timeout) {

    uint32_t ret = 0;

    if(xSemaphoreTake(dmaSendIR_Semaphore, (TickType_t)timeout)) {

        /*到这里我们获取到信号量,现在可以访问共享资源了*/
        ret = dmaFIFORead(buffer, timeout);

        /* 完成访问共享资源后,必须释放信号量*/
        xSemaphoreGive(dmaSendIR_Semaphore);
    }
    else {

        while(1);
    }

    return ret;
}


void DMA1_IRQHandler (void) {

    xSemaphoreFromISR(dmaSendTI_Semaphore);
}
//AT指令列表,必须要和atCommand一一对应
typedef enum
{
    AT = 0,
    AT_CGMI,
    AT_CGMM,
    AT_CGSN,
    AT_CFUN,
    AT_CSQ,
    AT_NBAND,
    AT_CGACT,
    AT_CGATT,
    AT_CEREG,
    AT_CSCON,
    AT_CGPADDR,
    AT_NCONFIG,
    AT_CPSMS,
    AT_NMGS,
    AT_NNMI,
    AT_NCDP,
    AT_NMSTATUS,
    AT_NNMI_RESP,
    AT_CCLK,
    AT_NCCID,
} AtCommandListTypedef;

/* At指令解析与打包的格式 */
typedef struct
{
    /* 为NULL表示该指令不具有相应的数据 */
    const char *Name;                   //指令名
    const char *pQueryTransmitFormat;   //查询模式下应该具有的格式
    const char *pQueryReceiveFormat;    //查询模式下接收的数据格式
    const char *pSetTransmitFormat;     //设置模式下应该具有的发送格式
    const char *pSetReceiveFormat;      //设置模式下接收的数据格式
} CommandTypedef;

/* AT命令执行结果 */
typedef enum
{
    AT_OK = 0,
    AT_ERROR,
    AT_NO_RESPONSE,
    AT_FORMAT_WRONG,
} AT_StatusTypedef;

AT_StatusTypedef atset_command(AtCommandListTypedef command, ...);
AT_StatusTypedef atread_command(AtCommandListTypedef command, ...);
AT_StatusTypedef atwait_command(AtCommandListTypedef command, uint32_t timeout,...);
AT_StatusTypedef atsend_data(AtCommandListTypedef command, uchar *buffer, size_t len);

回复

This is just a placeholder img.