cAT AT 命令解析器无端请求示例

功能说明

演示 cAT 库的无端请求(Unsolicited Response)功能,即服务器主动向客户端发送未经请求的响应,用于异步事件通知和多条响应发送。

本示例模拟无线扫描操作,接收单个 AT+START 命令后,系统返回多条扫描结果,最后发送 OK。

硬件连接

  • UART1_TX (PB2): 传输数据,连接到 USB-UART 转接器的 RX

  • UART1_RX (PB3): 接收数据,连接到 USB-UART 转接器的 TX

连接到 PC 串口工具,配置为 115200, 8N1, 无流控

示例内容

本示例演示以下功能:

  1. HOLD 状态返回: 命令处理器返回 CAT_RETURN_STATE_HOLD,暂时不发送 OK

  2. 多条异步响应: 通过 cat_trigger_unsolicited_read() 主动发送多条无端响应

  3. 异步事件处理: 模拟后台扫描操作,逐条返回扫描结果

  4. HOLD 状态退出: 扫描完成后调用 cat_hold_exit() 发送 OK 并退出 HOLD 状态

  5. 模式切换: 支持 WiFi (0) 和蓝牙 (1) 两种扫描模式

编译

重要提示:在编译前,请先确认您使用的开发板型号。SDK 目前支持以下开发板:

  • arcs_evb - ARCS EVB 评估板

  • arcs_mini - ARCS Mini 开发板

根据您的开发板型号,选择对应的编译命令:

在示例目录下执行编译:

# 使用 arcs_evb 开发板
./build.sh -C -DBOARD=arcs_evb

# 或使用 arcs_mini 开发板
./build.sh -C -DBOARD=arcs_mini

Note

如果在 SDK 根目录执行,需要指定示例路径:

# 使用 arcs_evb 开发板
./build.sh -C -S samples/<示例路径> -DBOARD=arcs_evb

# 或使用 arcs_mini 开发板
./build.sh -C -S samples/<示例路径> -DBOARD=arcs_mini

Note

确保已安装对应的工具链。

烧录

编译完成后,使用 SDK tools 目录下的 cskburn 工具烧录固件:

./tools/burn/cskburn -s /dev/ttyUSB0 -b 3000000 0x0 build/arcs.bin -C arcs

Note

烧录参数说明

  • -s /dev/ttyUSB0:串口设备路径,需要根据实际情况修改 - Linux 系统:通常是 /dev/ttyUSB0/dev/ttyACM0 - 可通过 ls /dev/tty* 命令查看可用串口设备 - 不同开发板或 USB 转串口芯片可能使用不同的设备名

  • -b 3000000:烧录波特率(3Mbps)

  • 0x0:烧录起始地址

  • build/arcs.bin:编译生成的固件路径

  • -C arcs:芯片类型

注意事项

  • 确保开发板已正确连接到电脑

  • 如果无法识别串口设备,请检查 USB 连接线是否正常,或尝试其他 USB 端口

预期输出

系统启动输出:

[I][cat_unsolicited] cAT AT Command Parser - Unsolicited Example
[I][cat_unsolicited] ============================================
[I][cat_uart] cAT UART adapter initialized on uart1 @ 115200 baud
[I][cat_unsolicited] AT command parser ready on uart1
[I][cat_unsolicited] Supported AT commands:
[I][cat_unsolicited]   +START - Start scanning (0=WiFi, 1=Bluetooth)
[I][cat_unsolicited]   +SCAN - Scan result record (unsolicited)
[I][cat_unsolicited]   #HELP - Print command list
[I][cat_unsolicited]   #QUIT - Quit the demo
[I][cat_uart] cAT UART task started

发送 AT+START=0 (WiFi 扫描) 后的输出:

[I][cat_unsolicited] Mode set to: 0 (WiFi)
[I][cat_unsolicited] Starting WiFi scan...
[I][cat_unsolicited] Sending scan result 0: RSSI=-10, SSID=wifi1
[I][cat_unsolicited] Sending scan result 1: RSSI=-50, SSID=wifi2
[I][cat_unsolicited] Sending scan result 2: RSSI=-20, SSID=wifi3
[I][cat_unsolicited] Scan complete, sent 3 results
+SCAN: -10,"wifi1"
+SCAN: -50,"wifi2"
+SCAN: -20,"wifi3"
OK

发送 AT+START=1 (蓝牙扫描) 后的输出:

[I][cat_unsolicited] Mode set to: 1 (Bluetooth)
[I][cat_unsolicited] Starting Bluetooth scan...
[I][cat_unsolicited] Sending scan result 0: RSSI=-20, SSID=bluetooth1
[I][cat_unsolicited] Scan complete, sent 1 results
+SCAN: -20,"bluetooth1"
OK

发送 AT+HELP 后的输出:

+HELP: +START(WR),+SCAN(TEST),#HELP(RUN),#QUIT(RUN)
OK

核心 API

API

说明

cat_uart_adapter_init()

初始化 UART 适配器

cat_uart_adapter_get_io()

获取 IO 接口

cat_uart_adapter_get_mutex()

获取互斥锁接口(支持递归锁)

cat_init()

初始化 AT 命令解析器

cat_trigger_unsolicited_read()

触发无端响应

cat_hold_exit()

退出 HOLD 状态

cat_uart_adapter_send_urc()

发送无端响应(备选)

关键代码

定义扫描结果数据:

/* 静态扫描结果 - 模拟 WiFi 和蓝牙 */
struct scan_results {
    int rssi;
    char ssid[16];
};

static const struct scan_results results[2][3] = {
    /* WiFi 结果 */
    {
        { .rssi = -10, .ssid = "wifi1" },
        { .rssi = -50, .ssid = "wifi2" },
        { .rssi = -20, .ssid = "wifi3" }
    },
    /* 蓝牙结果 */
    {
        { .rssi = -20, .ssid = "bluetooth1" },
        { .rssi = 0, .ssid = "" },
        { .rssi = 0, .ssid = "" }
    }
};

START 命令处理器(返回 HOLD 状态):

/* AT+START=<mode> - 启动扫描 */
static cat_return_state start_write(const struct cat_command *cmd, const uint8_t *data,
                                     const size_t data_size, const size_t args_num)
{
    LOGI("Starting %s scan...", (mode == 0) ? "WiFi" : "Bluetooth");

    /* 重置扫描状态 */
    scan_index = 0;
    scan_completed = false;

    /* 加载第一条扫描结果 */
    load_scan_results(scan_index);

    /* 触发第一条无端响应 */
    cat_trigger_unsolicited_read(&at, &scan_cmd);

    /* 返回 HOLD - 暂不发送 OK,等待异步操作完成 */
    return CAT_RETURN_STATE_HOLD;
}

SCAN 命令读取处理器(处理无端响应):

/* 无端读取回调 - 每条扫描结果调用一次 */
static cat_return_state scan_read(const struct cat_command *cmd, uint8_t *data,
                                   size_t *data_size, const size_t max_data_size)
{
    int max = (mode == 0) ? 3 : 1;

    if (scan_completed) {
        return CAT_RETURN_STATE_OK;
    }

    LOGI("Sending scan result %d: RSSI=%d, SSID=%s", scan_index, rssi, ssid);

    scan_index++;

    /* 如果还有更多结果,触发下一条 */
    if (scan_index < max) {
        load_scan_results(scan_index);
        cat_trigger_unsolicited_read(&at, &scan_cmd);
        return CAT_RETURN_STATE_DATA_NEXT;  /* 继续下一条 */
    }

    /* 最后一条结果 - 完成后退出 HOLD 状态 */
    LOGI("Scan complete, sent %d results", scan_index);
    scan_completed = true;
    
    cat_hold_exit(&at, CAT_STATUS_OK);     /* 发送 OK 并退出 HOLD */
    return CAT_RETURN_STATE_DATA_OK;       /* 最后一条数据 */
}

模式验证器:

/* MODE 变量的写入验证器 */
static int mode_write(const struct cat_variable *var, const size_t write_size)
{
    if (*(int *)var->data >= 2) {
        LOGE("Invalid mode: %d (must be 0 or 1)", *(int *)var->data);
        return -1;
    }
    LOGI("Mode set to: %d (%s)", *(int *)var->data,
         (*(int *)var->data == 0) ? "WiFi" : "Bluetooth");
    return 0;
}

SCAN 命令定义:

/* 定义扫描结果变量 */
static struct cat_variable scan_vars[] = {
    {
        .type = CAT_VAR_INT_DEC,
        .data = &rssi,
        .data_size = sizeof(rssi),
        .name = "RSSI",
        .access = CAT_VAR_ACCESS_READ_ONLY,
    },
    {
        .type = CAT_VAR_BUF_STRING,
        .data = ssid,
        .data_size = sizeof(ssid),
        .name = "SSID",
        .access = CAT_VAR_ACCESS_READ_ONLY,
    }
};

/* SCAN 命令 - 仅用于无端响应,标记为 only_test */
static struct cat_command scan_cmd = {
    .name = "+SCAN",
    .description = "Scan result record",
    .read = scan_read,
    .var = scan_vars,
    .var_num = sizeof(scan_vars) / sizeof(scan_vars[0])
};

注意事项

  1. 递归 Mutex: 示例使用递归互斥锁支持无端事件的触发。在 HOLD 状态的命令处理中调用 cat_trigger_unsolicited_read() 时,需要重新获取锁

  2. HOLD 状态管理:

    • 返回 CAT_RETURN_STATE_HOLD 使命令进入 HOLD 状态,暂停发送 OK

    • 返回 CAT_RETURN_STATE_DATA_NEXT 继续发送下一条响应

    • 返回 CAT_RETURN_STATE_DATA_OK 发送最后一条响应

    • 调用 cat_hold_exit() 退出 HOLD 状态并发送 OK

  3. 无端响应流程:

    1. 用户发送 AT+START=0
    2. start_write() 返回 HOLD,调用 cat_trigger_unsolicited_read()
    3. scan_read() 被调用发送第一条 +SCAN 结果
    4. 返回 DATA_NEXT,再次调用 cat_trigger_unsolicited_read()
    5. 重复直到最后一条结果
    6. 最后一条返回 DATA_OK 并调用 cat_hold_exit()
    7. 发送 OK 并退出 HOLD 状态
    
  4. 线程安全: UART 任务中所有 cAT 操作都受递归互斥锁保护,可安全调用 cat_trigger_unsolicited_read()

  5. 响应变量: 无端响应中的变量值必须在回调被调用前设置正确(如 rssissid

  6. 错误处理: 如果参数验证失败(mode >= 2),回调返回 -1 会导致命令返回 ERROR

命令参考

命令

说明

示例

AT+START=<mode>

开始扫描 (0=WiFi, 1=Bluetooth)

AT+START=0 → 多条 +SCAN + OK

AT+SCAN=?

显示 SCAN 格式

AT+SCAN=?+SCAN: RSSI(INT),SSID(STRING)

AT#HELP

列出所有命令

AT#HELP → 命令列表

AT#QUIT

退出示例

AT#QUITOK

扩展建议

  1. 实时扫描: 替换静态结果数据,接收来自实际 WiFi/蓝牙 驱动的扫描结果

  2. 扫描进度: 返回 DATA_NEXT 时可添加进度信息(如 “Scan 30% complete”)

  3. 超时处理: 在 HOLD 状态下实现扫描超时机制,防止命令无限期挂起

  4. 并发操作: 支持在扫描过程中处理其他 AT 命令(使用任务安全机制)

  5. 结果缓存: 存储扫描结果供后续查询,实现增量式结果返回

无端响应原理

无端响应是一种经典的 AT 命令扩展模式,允许设备在不进行直接查询的情况下主动通知主机事件发生。

典型应用场景:

  • 信号强度实时通知 (Signal Strength Unsolicited Result Code)

  • 来电提示 (Incoming Call Notification)

  • 短信接收通知 (SMS Reception Notification)

  • 网络状态变化 (Network Status Change)

  • 外设事件通知 (Peripheral Events)

本示例通过模拟扫描结果演示了这一模式的完整实现。