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. 代码文件介绍
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, |
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