3.4.4. APP - Bluetooth Dual-Mode AT Moudle (char)

3.4.4.1. 概述

  • 主要功能是在普通数传BLE基础上增加了由上位机或其他MCU可以通过UART对接蓝牙芯片进行基本配置、状态获取、控制扫描、连接断开以及数据收发等操作。

  • AT控制透传支持ble主机或者ble从机,支持主从一体

Note

定义一套串口的控制协议,具体请查看协议文档《蓝牙AT_CHAR协议》

3.4.4.2. 工程配置

  • 先配置板级board_config.h

#ifndef BOARD_CONFIG_H
#define BOARD_CONFIG_H

#define CONFIG_BOARD_AW31N_DEMO
// #define CONFIG_BOARD_AW318N_DONGLE

#include "board_aw31n_demo_cfg.h"
#include "board_aw318n_dongle_cfg.h"

  • 配置app_config.h, 选择CONFIG_APP_AT_CHAR_COM,选择从机或者是主机

    • #define CONFIG_BT_GATT_CLIENT_NUM 1//max is 1 主机

    • #define CONFIG_BT_GATT_SERVER_NUM 1//max is 1 从机

//apps example 选择,只能选1个,要配置对应的board_config.h
#define CONFIG_APP_LE_TRANS               0 // LE's slave
#define CONFIG_APP_MULTI                  0 //蓝牙LE多连 支持2.4g code
#define CONFIG_APP_NONCONN_24G            0 //2.4G 非连接收发
#define CONFIG_APP_IDLE                   0 // 空闲任务 todo
#define CONFIG_APP_DONGLE                 1 //usb + 蓝牙(ble 主机),PC hid设备, 使用需要配置板级board_aw31n_dongle.h
#define CONFIG_APP_AT_CHAR_COM            0 //AT com 字符串格式命令
#elif CONFIG_APP_AT_CHAR_COM
//SDK 应用内存分配,谨慎修改
#define SYS_STACK_SIZE                    (0x600)  //中断堆栈大小
#define USR_STACK_SIZE                    (0x500)  //用户堆栈大小
#define SYS_HEAP_SIZE                     (0x2C0)  //malloc堆的大小
//bt ram, no bt set 0
#define BT_NK_RAM_SIZE                    (0x660 + CFG_BT_MSG_BUFSZIE)  //nk malloc堆的大小
#define BT_NV_RAM_SIZE                    (0xEC0)  //nv malloc堆的大小



#define CONFIG_BT_GATT_COMMON_ENABLE       1//
#define CONFIG_BT_SM_SUPPORT_ENABLE        0//
#define CONFIG_BT_GATT_CLIENT_NUM          0//max is 1
#define CONFIG_BT_GATT_SERVER_NUM          1//max is 1
#define CONFIG_BT_GATT_CONNECTION_NUM      (CONFIG_BT_GATT_SERVER_NUM + CONFIG_BT_GATT_CLIENT_NUM)
#define CONFIG_BLE_HIGH_SPEED              0 //BLE提速模式: 使能DLE+2M, payload要匹配pdu的包长
#define TCFG_AUTO_SHUT_DOWN_TIME		   0
  • 串口IO配置

apps/demo/transfer/board/bd47/board_aw31n_demo_cfg.h

#define UART_DB_TX_PIN                      IO_PORTA_06                            //AT_CHART串口,注意不要和通用串口复用IO
#define UART_DB_RX_PIN                      IO_PORTA_07
#define AT_UART_INDEX                       UART_NUM_1
#define TCFG_AT_UART_BAUDRATE  	            115200                                 //AT_CHAR串口波特率配置

3.4.4.3. 代码文件介绍

image-20240702105713254

3.4.4.4. 主要代码说明

  • 命令包头

at_char_cmds.c

static const char at_head_at_cmd[] = "AT+";
static const char at_head_at_chl[] = "AT>";

static const str_info_t at_head_str_table[] = {
INPUT_STR_INFO(STR_ID_HEAD_AT_CMD, at_head_at_cmd),
INPUT_STR_INFO(STR_ID_HEAD_AT_CHL, at_head_at_chl),
};
  • 命令类型:

at_char_cmds.c

static const char at_str_gver[]        = "GVER";
static const char at_str_gcfgver[]     = "GCFGVER";
static const char at_str_name[]        = "NAME";
static const char at_str_lbdaddr[]     = "LBDADDR";
static const char at_str_baud[]        = "BAUD";

static const char at_str_adv[]         = "ADV";
static const char at_str_advparam[]    = "ADVPARAM";
static const char at_str_advdata[]     = "ADVDATA";
static const char at_str_srdata[]      = "SRDATA";
static const char at_str_connparam[]   = "CONNPARAM";

static const char at_str_scan[]        = "SCAN";
static const char at_str_targetuuid[]  = "TARGETUUID";
static const char at_str_conn[]        = "CONN";
static const char at_str_disc[]        = "DISC";
static const char at_str_ota[]         = "OTA";
static const char at_str_conn_cannel[] = "CONN_CANNEL";
static const char at_str_power_off[]   = "POWEROFF";
static const char at_str_lowpower[]    = "LOWPOWER";

static const str_info_t at_cmd_str_table[] = {
        INPUT_STR_INFO(STR_ID_GVER, at_str_gver),
        INPUT_STR_INFO(STR_ID_GCFGVER, at_str_gcfgver),
        INPUT_STR_INFO(STR_ID_NAME, at_str_name),
        INPUT_STR_INFO(STR_ID_LBDADDR, at_str_lbdaddr),
        INPUT_STR_INFO(STR_ID_BAUD, at_str_baud),

        INPUT_STR_INFO(STR_ID_ADV, at_str_adv),
        INPUT_STR_INFO(STR_ID_ADVPARAM, at_str_advparam),
        INPUT_STR_INFO(STR_ID_ADVDATA, at_str_advdata),
        INPUT_STR_INFO(STR_ID_SRDATA, at_str_srdata),
        INPUT_STR_INFO(STR_ID_CONNPARAM, at_str_connparam),

        INPUT_STR_INFO(STR_ID_SCAN, at_str_scan),
        INPUT_STR_INFO(STR_ID_TARGETUUID, at_str_targetuuid),
        INPUT_STR_INFO(STR_ID_CONN, at_str_conn),
        INPUT_STR_INFO(STR_ID_DISC, at_str_disc),
        INPUT_STR_INFO(STR_ID_OTA, at_str_ota),
        INPUT_STR_INFO(STR_ID_CONN_CANNEL, at_str_conn_cannel),
        INPUT_STR_INFO(STR_ID_POWER_OFF, at_str_power_off),
        INPUT_STR_INFO(STR_ID_LOW_POWER, at_str_lowpower),

//    INPUT_STR_INFO(, ),
//    INPUT_STR_INFO(, ),
};
  • AT命令解析

at_char_cmds.c

static void at_packet_handler(uint8_t *packet, int size)
{
    at_param_t *par;
    const str_info_t *str_p;
    int ret = -1;
    uint8_t operator_type = AT_CMD_OPT_NULL; //
    uint8_t *parse_pt = packet;
    int parse_size = size;
    char buf[128] = {0};

#if FLOW_CONTROL
    if (cur_atcom_cid < 8) {
#if CONFIG_BT_GATT_CLIENT_NUM
        log_info("###le_client_data(%d):", size);
        /* put_buf(packet, size); */
        do {
            ret = ble_at_client_send_data(cur_atcom_cid, packet, size);
            os_time_dly(1);
        } while (ret != 0);
#endif
        return;
    } else if (cur_atcom_cid == 8) {
        log_info("###le_server_data(%d):", size);
        /* put_buf(packet, size); */
        do {
            ret = le_att_server_send_data(cur_atcom_cid, packet, size);
            os_time_dly(1);
        } while (ret != 0);
        return;
    }
#else
    if (cur_atcom_cid < 8) {
#if CONFIG_BT_GATT_CLIENT_NUM
        log_info("###le_client_data(%d):", size);
        /* put_buf(packet, size); */
        ble_at_client_send_data(cur_atcom_cid, packet, size);
#endif
        return;
    } else if (cur_atcom_cid == 8) {
#if CONFIG_BT_GATT_SERVER_NUM
        log_info("###le_server_data(%d):", size);
        /* put_buf(packet, size); */
        ble_at_server_send_data(cur_atcom_cid, packet, size);
#endif
        return;
    }
#endif
    else {
        ;
    }

    str_p = at_check_match_string(parse_pt, parse_size, at_head_str_table, sizeof(at_head_str_table));
    if (!str_p) {
        log_info("###1unknow at_head:%s", packet);
        at_respond_send_err(ERR_AT_CMD);
        return;
    }
    parse_pt   += str_p->str_len;
    parse_size -= str_p->str_len;

    if (str_p->str_id == STR_ID_HEAD_AT_CMD) {
        str_p = at_check_match_string(parse_pt, parse_size, at_cmd_str_table, sizeof(at_cmd_str_table));
        if (!str_p) {
            log_info("###2unknow at_cmd:%s", packet);
            at_respond_send_err(ERR_AT_CMD);
            return;
        }

        parse_pt    += str_p->str_len;
        parse_size -= str_p->str_len;
        if (parse_pt[0] == '=') {
            operator_type = AT_CMD_OPT_SET;
        } else if (parse_pt[0] == '?') {
            operator_type = AT_CMD_OPT_GET;
        }
        parse_pt++;
    }

    log_info("str_id:%d", str_p->str_id);
    put_buf(parse_pt, parse_size);

    par = parse_param_split(parse_pt, ',', '\r');

    switch (str_p->str_id) {
    case STR_ID_HEAD_AT_CHL:
        uint8_t tmp_cid = func_char_to_dec(par->data, '\0');
        if (tmp_cid == 9) {
            black_list_check(0, NULL);
        }
        log_info("STR_ID_HEAD_AT_CHL:%d\n", tmp_cid);
        AT_STRING_SEND("OK");  //响应
        cur_atcom_cid = tmp_cid;
        break;

    case STR_ID_ERROR:
        log_info("STR_ID_ERROR\n");
        break;

    case STR_ID_GVER:                   //2.1;
        log_info("STR_ID_GVER\n");
        AT_STRING_SEND(G_VERSION);
        AT_STRING_SEND("OK");  //响应
        break;

    case STR_ID_GCFGVER:                    //2.2
        log_info("STR_ID_GCFGVER\n");
        AT_STRING_SEND(CONFIG_VERSION);
        AT_STRING_SEND("OK");  //响应
        break;

    case STR_ID_NAME:
        log_info("STR_ID_NAME\n");
#if CONFIG_BT_GATT_SERVER_NUM
        if (operator_type == AT_CMD_OPT_SET) { //2.4
            ble_at_server_set_name(par->data, par->len);
            AT_STRING_SEND("OK");
        } else {                            //2.3
            sprintf(buf, "+NAME:");
            uint8_t len = 0;
            len = strlen(buf);

            len = ble_at_server_get_name((uint8_t *)&buf[0] + len) + len;
            at_cmd_send((uint8_t *)buf, len);
            AT_STRING_SEND("OK");
        }
#endif
        break;

    case STR_ID_LBDADDR:                        //2.5
        log_info("STR_ID_LBDADDR\n");
#if CONFIG_BT_GATT_SERVER_NUM
        if (operator_type == AT_CMD_OPT_GET) {
            char _buf[30] = "+LBDADDR:";
            uint8_t ble_addr[6] = {0};
            uint8_t len = 0;

            len = strlen(_buf);
            sprintf(buf, "+LBDADDR:");
            ble_at_server_get_address(ble_addr);
            hex_2_str(ble_addr, 6, (uint8_t *)&buf[0] + len);

            at_cmd_send((uint8_t *)buf, len + 12);
            AT_STRING_SEND("OK");
        } else {
            at_respond_send_err(ERR_AT_CMD);
        }
#endif
        break;

    case STR_ID_BAUD:
        log_info("STR_ID_BAUD\n");
        if (operator_type == AT_CMD_OPT_SET) {
            uart_baud = func_char_to_dec(par->data, '\0');
            log_info("set baud= %d", uart_baud);
            if (uart_baud == 9600 || uart_baud == 19200 || uart_baud == 38400 || uart_baud == 115200 ||
                uart_baud == 230400 || uart_baud == 460800 || uart_baud == 921600) {
                if (ct_uart_change_baud(uart_baud) > 0) {
                    AT_STRING_SEND("OK");
                } else {
                    at_respond_send_err(ERR_AT_CMD);
                }
            } else {
                at_respond_send_err(ERR_AT_CMD);
            }
        } else {                            //2.6
            sprintf(buf, "+BAUD:%d", uart_baud);
            at_cmd_send((uint8_t *)buf, strlen(buf));
            AT_STRING_SEND("OK");
        }

        break;

    case STR_ID_POWER_OFF:  //2.18
        log_info("STR_ID_POWER_OFF\n");
        AT_STRING_SEND("OK");
        // TODO ,需要返回错误码
        sys_timeout_add(NULL,  app_power_set_soft_poweroff, 100);
        break;

    case STR_ID_LOW_POWER:  //2.18
        log_info("STR_ID_LOW_POWER\n");
        uint8_t lp_state;
        if (operator_type == AT_CMD_OPT_SET) { //2.9
            AT_STRING_SEND("OK");
            lp_state = func_char_to_dec(par->data, '\0');
            log_info("set lowpower: %d\n", lp_state);
            at_set_low_power_mode(lp_state);
        } else {
            lp_state = at_get_low_power_mode();
            log_info("get lowpower: %d\n", lp_state);
            sprintf(buf, "+LOWPOWER:%d", lp_state);
            at_cmd_send((uint8_t *)buf, strlen(buf));
            AT_STRING_SEND("OK");
        }
        break;

    case STR_ID_ADV:
        log_info("STR_ID_ADV\n");
#if CONFIG_BT_GATT_SERVER_NUM
        uint8_t adv_state;
        if (operator_type == AT_CMD_OPT_SET) { //2.9
            adv_state = func_char_to_dec(par->data, '\0');
            ret = ble_at_server_adv_enable(adv_state);
            if (ret == 0) {
                AT_STRING_SEND("OK");
            } else {
                at_respond_send_err(ERR_AT_CMD);
            }
        } else {                            //2.8
            adv_state = ble_at_server_get_adv_state();  //0广播关闭,1打开

            sprintf(buf, "+ADV:%d", adv_state);
            at_cmd_send((uint8_t *)buf, strlen(buf));
            AT_STRING_SEND("OK");
        }
#endif
        break;


    case STR_ID_ADVPARAM:
        log_info("STR_ID_ADVPARAM\n");

#if CONFIG_BT_GATT_SERVER_NUM
        uint16_t adv_interval;
        if (operator_type == AT_CMD_OPT_SET) { //2.11
            adv_interval = func_char_to_dec(par->data, '\0');
            log_info("set_adv_interval: %d", adv_interval);
            ble_at_server_set_adv_interval(adv_interval);
            //ret = ble_op_set_adv_param(adv_interval, ADV_IND, ADV_CHANNEL_ALL);
            AT_STRING_SEND("OK");
        } else {                            //2.10
            adv_interval = ble_at_server_get_adv_interval();
            sprintf(buf, "+ADVPARAM:%d", adv_interval);
            at_cmd_send((uint8_t *)buf, strlen(buf));
            AT_STRING_SEND("OK");
        }
#endif
        break;

    case STR_ID_ADVDATA:
        log_info("STR_ID_ADVDATA\n");

#if CONFIG_BT_GATT_SERVER_NUM
        /* uint8_t i = 0; */
        if (operator_type == AT_CMD_OPT_SET) {
            uint8_t adv_data[35] = {0};
            uint8_t adv_data_len = 0;  //广播hex数据的长度

            //将par->data转换成hex
            adv_data_len = str_2_hex(par->data, par->len, adv_data);
            if (adv_data_len > 31) {
                ret = 1;
            } else {
                ret = ble_at_server_set_adv_data(adv_data, adv_data_len);
            }

            if (ret == 0) {
                AT_STRING_SEND("OK");
            } else {
                // TODO ,需要返回错误码
                at_respond_send_err(ERR_AT_CMD);
            }

        } else { //2.12
            uint8_t adv_data_len = 0;  //广播hex数据的长度
            uint8_t *adv_data = ble_at_server_get_adv_data(&adv_data_len);

            sprintf(buf, "+ADVDATA:");
            uint8_t len = 0;
            len = strlen(buf);
            if (adv_data_len) {
                hex_2_str(adv_data, adv_data_len, (uint8_t *)&buf[len]);
            }
            at_cmd_send((uint8_t *)buf, len + adv_data_len * 2);
            AT_STRING_SEND("OK");
        }
#endif
        break;

    case STR_ID_SRDATA:
        log_info("STR_ID_SRDATA\n");

#if CONFIG_BT_GATT_SERVER_NUM
        /* uint8_t i = 0; */
        if (operator_type == AT_CMD_OPT_SET) {
            uint8_t scan_rsp_data[35] = {0};
            uint8_t scan_rsp_data_len = 0;   //hex长度

            scan_rsp_data_len = str_2_hex(par->data, par->len, scan_rsp_data);

            if (scan_rsp_data_len > 31) {
                ret = 1;
            } else {
                ret = ble_at_server_set_rsp_data(scan_rsp_data, scan_rsp_data_len);
            }

            if (ret == 0) {
                AT_STRING_SEND("OK");
            } else {
                // TODO ,需要返回错误码
                at_respond_send_err(ERR_AT_CMD);
            }

        } else { //2.14
            uint8_t rsp_data_len = 0;  //广播hex数据的长度
            uint8_t *rsp_data = ble_at_server_get_rsp_data(&rsp_data_len);

            sprintf(buf, "+SRDATA:");
            uint8_t len = strlen(buf);

            if (rsp_data_len) {
                hex_2_str(rsp_data, rsp_data_len, (uint8_t *)&buf[0] + len);
            }

            log_info("rsp_data_len  = %d", rsp_data_len);
            at_cmd_send((uint8_t *)buf, len + rsp_data_len * 2);
            AT_STRING_SEND("OK");
        }
#endif
        break;

    case STR_ID_CONNPARAM:
        log_info("STR_ID_CONNPARAM\n");

#if CONFIG_BT_GATT_CLIENT_NUM
        uint16_t conn_param[4] = {0}; //interva_min, interva_max, conn_latency, conn_timeout;
        uint8_t i = 0;

        if (operator_type == AT_CMD_OPT_SET) {
            while (par) {  //遍历所有参数
                log_info("len=%d,par:%s", par->len, par->data);
                conn_param[i] = func_char_to_dec(par->data, '\0');  //获取参数
                if (par->next_offset) {
                    par = AT_PARAM_NEXT_P(par);
                } else {
                    break;
                }
                i++;
            }

            ret = ble_at_client_set_conn_param(conn_param);
            log_info("\n conn_param = %d %d %d %d", conn_param[0], conn_param[1], conn_param[2], conn_param[3]);
            if (ret == 0) {
                AT_STRING_SEND("OK");
            } else {
                // TODO ,需要返回错误码
                at_respond_send_err(ERR_AT_CMD);
            }

        } else {                    //2.16
            sprintf(buf, "+CONNPARAM:");
            uint8_t len = strlen(buf);

            ble_at_client_get_conn_param(conn_param);

            for (i = 0; i < sizeof(conn_param) / sizeof(conn_param[0]); i++) {
                sprintf(&buf[0] + len, "%d", conn_param[i]);
                len = strlen(buf);
                buf[len] = ',';
                len += 1;
            }
            len -= 1;     //清掉最后一个逗号

            at_cmd_send((uint8_t *)buf, len);
            AT_STRING_SEND("OK");
        }
#endif

        break;

    case STR_ID_SCAN:
        log_info("STR_ID_SCAN\n");
#if CONFIG_BT_GATT_CLIENT_NUM

        ret = ble_at_client_scan_enable(func_char_to_dec(par->data, '\0'));

        if (ret == 0) {
            AT_STRING_SEND("OK");
        } else {
            // TODO ,需要返回错误码
            at_respond_send_err(ERR_AT_CMD);
        }

#endif
        break;

    case STR_ID_TARGETUUID:  //2.19 TODO
        log_info("STR_ID_TARGETUUID\n");
#if CONFIG_BT_GATT_CLIENT_NUM
        uint16_t target_uuid_info[3];
        uint8_t par_index = 0;
        if (operator_type == AT_CMD_OPT_SET) {
            while (par) {  //遍历所有参数
                log_info("len=%d,par:%s", par->len, par->data);
                uint16_t uint16_res;
                str_2_hex(par->data, 2, (uint8_t *)&uint16_res + 1);
                str_2_hex(par->data + 2, 2, (uint8_t *)&uint16_res); //先填高位,在填低位
                target_uuid_info[par_index] = uint16_res;
                if (par->next_offset) {
                    par = AT_PARAM_NEXT_P(par);
                } else {
                    break;
                }
                par_index++;
            }

            ble_at_client_set_target_uuid16(target_uuid_info[0], target_uuid_info[1], target_uuid_info[2]);
            AT_STRING_SEND("OK");
        } else {
            at_respond_send_err(ERR_AT_CMD);
        }

#endif
        break;

    case STR_ID_CONN:           //2.20
        log_info("STR_ID_CONN\n");
#if CONFIG_BT_GATT_CLIENT_NUM
        struct create_conn_param_t create_conn_par;
        str_2_hex(par->data, par->len, create_conn_par.peer_address);
        put_buf(create_conn_par.peer_address, 6);

        ble_at_client_scan_enable(0);
        if (!ble_at_client_creat_connection(create_conn_par.peer_address, 0)) {
            AT_STRING_SEND("OK");
        } else {
            at_respond_send_err(ERR_AT_CMD);
        }
#endif
        break;

    case STR_ID_CONN_CANNEL:           //2.20
        log_info("STR_ID_CONN_CANNEL\n");
#if CONFIG_BT_GATT_CLIENT_NUM
        if (!ble_at_client_creat_cannel()) {
            AT_STRING_SEND("OK");
        } else {
            at_respond_send_err(ERR_AT_CMD);
        }
#endif
        break;

    case STR_ID_DISC:           //2.21
        log_info("STR_ID_DISC\n");
        u8 _tmp_cid = func_char_to_dec(par->data, '\0');
        if (_tmp_cid < 7) {
#if CONFIG_BT_GATT_CLIENT_NUM
            ble_at_client_disconnect(_tmp_cid);
#endif
        } else if (_tmp_cid == 8) {
#if CONFIG_BT_GATT_SERVER_NUM
            ble_at_server_disconnect();
#endif
        } else {
            // TODO ,需要返回错误码
            at_respond_send_err(ERR_AT_CMD);
            break;
        }
        AT_STRING_SEND("OK");
        break;

    case STR_ID_OTA:
        log_info("STR_ID_OTA\n");
        /* ret = 0; */
        AT_STRING_SEND(at_str_ok);
        break;

    default:
        break;
    }
}
  • 命令的参数获取与遍历

at_char_cmds.c

static at_param_t *parse_param_split(const uint8_t *packet, uint8_t split_char, uint8_t end_char)
{
    uint8_t char1;
    int i = 0;
    at_param_t *par = (at_param_t *)parse_buffer;

    if (*packet == end_char) {
        return NULL;
    }

    log_info("%s:%s", __FUNCTION__, packet);

    par->len = 0;

    while (1) {
        char1 = packet[i++];
        if (char1 == end_char) {
            par->data[par->len] = 0;
            par->next_offset = 0;
            break;
        } else if (char1 == split_char) {
            par->data[par->len] = 0;
            par->len++;
            par->next_offset = &par->data[par->len] - parse_buffer;

            //init next par
            par = (at_param_t *)&par->data[par->len];
            par->len = 0;
        } else {
            par->data[par->len++] = char1;
        }

        if (&par->data[par->len] - parse_buffer >= PARSE_BUFFER_SIZE) {
            log_error("parse_buffer over");
            par->next_offset = 0;
            break;
        }
    }

#if 0
    par = parse_buffer;
    log_info("param_split:");
    while (par) {
        log_info("len=%d,par:%s", par->len, par->data);
        if (par->next_offset) {
            par = AT_PARAM_NEXT_P(par);
        } else {
            break;
        }
    }
#endif

    return (void *)parse_buffer;
}

  • 默认信息配置

at_char_cmds.h

//默认参数
#define   G_VERSION                               "JL_test"
#define   CONFIG_VERSION                          "2021_02_04"
  • 在代码中添加新的命令(以查询、设置波特率为例)

at_char_cmds.h

  • 添加波特率枚举成员

enum {
        STR_ID_NULL = 0,
        STR_ID_HEAD_AT_CMD,
        STR_ID_HEAD_AT_CHL,

        STR_ID_OK = 0x10,
        STR_ID_ERROR,

        STR_ID_GVER = 0x20,
        STR_ID_GCFGVER,
        STR_ID_NAME,
        STR_ID_LBDADDR,
        STR_ID_BAUD,

        STR_ID_ADV,
        STR_ID_ADVPARAM,
        STR_ID_ADVDATA,
        STR_ID_SRDATA,
        STR_ID_CONNPARAM,

        STR_ID_SCAN,
        STR_ID_TARGETUUID,
        STR_ID_CONN,
        STR_ID_DISC,
        STR_ID_OTA,
        STR_ID_CONN_CANNEL,
        STR_ID_POWER_OFF,
        STR_ID_LOW_POWER,
        //    STR_ID_,
//    STR_ID_,
};
  • 添加波特率命令类型

static const char at_str_gver[] = "GVER";
static const char at_str_gcfgver[] = "GCFGVER";
...
  • 添加命令到命令列表

static const str_info_t at_cmd_str_table[] = {
        INPUT_STR_INFO(STR_ID_GVER, at_str_gver),
        INPUT_STR_INFO(STR_ID_GCFGVER, at_str_gcfgver),
        INPUT_STR_INFO(STR_ID_NAME, at_str_name),
        INPUT_STR_INFO(STR_ID_LBDADDR, at_str_lbdaddr),
        INPUT_STR_INFO(STR_ID_BAUD, at_str_baud),
        ...
  • 在at_packet_handler函数中添加命令的处理与响应

case STR_ID_BAUD:
    log_info("STR_ID_BAUD\n");
    {
        if (operator_type == AT_CMD_OPT_SET) { //2.7
            uart_baud = func_char_to_dec(par->data, '\0');
            log_info("set baud= %d", uart_baud);
            if (uart_baud == 9600 || uart_baud == 19200 || uart_baud == 38400 || uart_baud == 115200 ||
                uart_baud == 230400 || uart_baud == 460800 || uart_baud == 921600) {
                AT_STRING_SEND("OK");
                ct_uart_change_baud(uart_baud);
            } else { //TODO返回错误码
                at_respond_send_err(ERR_AT_CMD);
                            ...
  • 串口发数api, 用于发送响应信息

void at_cmd_send(uint8_t *packet, int size)
{
    log_info("###at_cmd_send(%d):", size);
    log_info_hexdump(packet, size);
    ct_uart_send_packet(packet, size);
    ct_uart_send_packet((uint8_t *)at_str_enter, 2);
}

3.4.4.5. case默认应用资源(默认使用AW31N DEMO开发板)

Note

demo默认占用外设资源如下,具体可以查看board_aw31n_demo_cfg.h

  • I/O口占用情况

PA口 I/O

默认占用情况

PA3

默认打印UART0引脚

PA6

AT CHAR 串口发送脚配置

PA7

AT CHAR 串口接收脚配置

PA8

adkey检测引脚

PA9

LED控制引脚

  • 硬件定时器占用情况

定时器

默认占用情况

TIMER0

暂无使用

TIMER1

暂无使用

TIMER2

暂无使用

TIMER3

暂无使用

  • 串口占用情况

串口

默认占用情况

UART0

SDK打印

UART1

AT CHAR串口

UART2

暂无使用

3.4.4.6. case默认应用功能现象

(默认使用AW31N DEMO开发板 打开ADKEY)

操作

现象结果

ble从机:设置是否允许运行低功耗模式:AT+LOWPOWER=[data]\r,进入低功耗后需要连续发送两条命令才能正常运行

发AT+LOWPOWER=1,进入低功耗,发AT+LOWPOWER=0,退出低功耗

ble从机:soft睡眠和唤醒:发送AT+POWEROFF\r后睡眠 发送00数据唤醒

ble从机:获取版本号:AT+GVER\r

JL_test

ble从机:获取配置版本号:AT+GCFGVER\r

2021_02_04

ble从机:获取设备名:AT+NAME?\r

NAME:ble_at_test

ble从机:获取本地蓝牙地址:AT+LBDADDR?\r

LBDADDR:eeaeb30df7f8(只是示例数据,可以使用nrf扫描mac地址是否相同)

ble从机:查询波特率:AT+BAUD?\r

BAUD:115200

ble从机:查询广播状态:AT+ADV?\r

ADV:1(如果是未连接就是1,使用nrf连接上后就是0)

ble从机:查询广播参数:AT+ADVPARAM?\r

ADVPARAM:800

ble从机:查询广播数据:AT+ADVDATA?

ADVDATA:020106030330af0c09626c655f61745f74657374

ble从机:查询扫描回复数据:AT+SRDATA?

SRDATA:0c09626c655f61745f74657374

ble从机:查询连接参数:AT+NAME=[name]\r

设置完收到OK,先用AT+NAME=你想设置的名字,然后使用AT+NAME?\r看看是否为你设置的名字

ble从机:设置波特率:AT+BAUD=[baud]\r(AT+BAUD=230400\r)

会收到OK(此时可能是乱码),软件上切换波特率查询信息收到正常说明波特率切换成功(用AT+BAUD?\r)

ble从机:设置广播参数:AT+ADVPARAM=[adv_interval]\r

会收到OK,使用AT+ADVPARAM?\r看看是否为你设置的连接间隔

ble从机:设置广播数据:AT+ADVDATA=[data]\r

设置完收到OK,使用AT+ADVDATA?\r看看是否为你设置的广播数据

ble从机:断开 BLE 设备:AT+DISC=8

先使用nrf连接上后进行断开操作测试

ble主机:查询连接参数:AT+CONNPARAM?\r

CONNPARAM:24,24,0,400

ble主机:设置连接参数:AT+CONNPARAM=[intervalMin], [intervalMax],[connLatency],[connTimeout]\r

设置完收到OK,使用AT+CONNPARAM?\r看看是否为你设置的连接数据

ble主机:设置扫描状态:AT+SCAN=[scan]

开关scan指令操作指令

ble主机:添加设置搜索目标服务:AT+TARGETUUID=[server_uuid,characteristic_uuid16,opt_type]\r

AT+TARGETUUID=ae30,ae05,0x20, 返回OK即正常

ble主机:创建连接 BLE 设备:AT+CONN=[ bdaddr ]\r

找到ble从机地址,发送指令发送连接请求,可以测试成功

ble主机:取消连接 BLE 设备:AT+CONN_CANNEL\r

先连接向ble从机发送连接请求后发送指令取消连接BLE设备

ble主机:断开 BLE 设备:AT+DISC=1

先连接ble从机后测试指令断开

opt_type:ATT行为

apps/include lib/bt include/le/att.h

#define ATT_PROPERTY_WRITE_WITHOUT_RESPONSE   0x04
#define ATT_PROPERTY_WRITE                    0x08
#define ATT_PROPERTY_NOTIFY                   0x10
#define ATT_PROPERTY_INDICATE                 0x20