From f872babe83cf106fd84ac5df12dda4cad23c8f0f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 31 Mar 2026 15:38:27 +0000 Subject: [PATCH 1/2] Initial plan From 0747ae6e219e268e7bb2246f067ddcab088ece2b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 31 Mar 2026 15:52:37 +0000 Subject: [PATCH 2/2] =?UTF-8?q?feat:=20=E5=B0=86AT=E5=92=8C=E6=A8=A1?= =?UTF-8?q?=E7=BB=84=E4=BB=A3=E7=A0=81=E4=B8=8E=E5=BA=95=E5=B1=82=E7=A1=AC?= =?UTF-8?q?=E4=BB=B6=E8=A7=A3=E8=80=A6=EF=BC=8C=E5=BB=BA=E7=AB=8B=E7=A1=AC?= =?UTF-8?q?=E4=BB=B6=E6=8A=BD=E8=B1=A1=E5=B1=82=EF=BC=8C=E7=94=9F=E6=88=90?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E6=89=8B=E5=86=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Agent-Logs-Url: https://github.com/zlun10/example_code/sessions/d3f6a716-5edd-4904-8457-f29ab546a1d4 Co-authored-by: zlun10 <165892790+zlun10@users.noreply.github.com> --- README.md | 432 +++++++++++++++++++++++++++++++++++++++++++ app/app_lowpower.c | 4 + dev/inc/module.h | 69 ++++--- dev/src/at.c | 11 +- dev/src/module.c | 93 +++++----- hal/inc/hal-at.h | 85 ++++++++- hal/inc/hal_module.h | 74 ++++++++ hal/src/hal-at.c | 30 ++- hal/src/hal_module.c | 82 ++++++++ 9 files changed, 799 insertions(+), 81 deletions(-) create mode 100644 hal/inc/hal_module.h create mode 100644 hal/src/hal_module.c diff --git a/README.md b/README.md index ec9c3f2..d3704e4 100644 --- a/README.md +++ b/README.md @@ -1 +1,433 @@ # README + +# 嵌入式无线对讲机控制器 — 开发手册 + +## 目录 + +1. [项目简介](#1-项目简介) +2. [代码架构](#2-代码架构) +3. [目录结构](#3-目录结构) +4. [模块说明](#4-模块说明) +5. [AT 命令层使用说明](#5-at-命令层使用说明) +6. [模组业务层使用说明](#6-模组业务层使用说明) +7. [移植指南](#7-移植指南) +8. [接口参考](#8-接口参考) + +--- + +## 1. 项目简介 + +本项目是基于 **CW32L011** MCU 的嵌入式无线对讲机控制程序,通过 AT 命令与无线模组通信,实现拨号、接听、挂断、广播、音量控制等功能。 + +**重构目标:** +- 将 AT 命令逻辑与底层硬件解耦,通过 HAL(硬件抽象层)隔离 +- 将模组业务逻辑与底层 GPIO/中断代码分离 +- 使得移植到其他芯片时,只需实现 `hal/` 目录下的接口函数,上层代码无需改动 + +--- + +## 2. 代码架构 + +``` +┌─────────────────────────────────────────────────┐ +│ 应用层 (app/ examples/) │ +│ main.c app_module.c app_lowpower.c ... │ +├─────────────────────────────────────────────────┤ +│ 设备层 (dev/) │ +│ at.c(AT 状态机) module.c(模组业务逻辑) │ +│ log.c sys_tick.c matrix.c │ +├────────────────────┬────────────────────────────┤ +│ 硬件抽象层 (hal/)│ 通用库 (lib/) │ +│ hal-at.h/c │ rb.c misc.c key.c ... │ +│ hal_module.h/c │ │ +│ hal-storage.h/c │ │ +├────────────────────┴────────────────────────────┤ +│ 驱动层 (drv/) │ +│ drv_uart.c drv_gpio.c drv_timer.c ... │ +├─────────────────────────────────────────────────┤ +│ 芯片 SDK (chip/cw32l011/) │ +│ StdDriver/ CMSIS/ │ +└─────────────────────────────────────────────────┘ +``` + +**各层职责:** + +| 层级 | 目录 | 职责 | 可移植性 | +|------|------|------|---------| +| 应用层 | `app/`, `examples/` | 业务逻辑、状态机、UI | 较高 | +| 设备层 | `dev/` | AT协议处理、模组事件管理 | **完全可移植** | +| HAL 层 | `hal/` | 硬件操作接口(需按平台实现) | 接口固定,实现可替换 | +| 驱动层 | `drv/` | 芯片外设驱动 | 芯片专用 | +| 芯片 SDK | `chip/` | 芯片厂商库 | 芯片专用 | + +--- + +## 3. 目录结构 + +``` +example_code/ +├── app/ 应用层 +│ ├── main.c 系统入口与初始化 +│ ├── app_module.c/h 模组应用层(对 dev/module 的封装) +│ ├── app_lowpower.c/h 低功耗管理 +│ └── app_sleep.c/h 休眠控制 +│ +├── dev/ 设备层(平台无关) +│ ├── inc/ +│ │ ├── at.h AT 命令接口 +│ │ ├── module.h 模组业务接口 +│ │ ├── log.h 日志接口 +│ │ └── sys_tick.h 系统滴答计时 +│ └── src/ +│ ├── at.c AT 命令状态机(仅调用 hal-at.h 接口) +│ ├── module.c 模组业务逻辑(仅调用 hal_module.h 接口) +│ ├── log.c +│ └── sys_tick.c +│ +├── hal/ 硬件抽象层(移植时修改此目录) +│ ├── inc/ +│ │ ├── hal-at.h AT UART 抽象接口 +│ │ ├── hal_module.h 模组硬件抽象接口 +│ │ └── hal-storage.h 存储抽象接口 +│ └── src/ +│ ├── hal-at.c CW32L011 AT UART 实现 +│ ├── hal_module.c CW32L011 模组 GPIO/ISR 实现 +│ └── hal-storage.c CW32L011 Flash 实现 +│ +├── drv/ 驱动层(CW32L011 专用) +│ ├── inc/drv_uart.h UART 驱动接口 +│ ├── inc/drv_gpio.h GPIO 驱动接口 +│ └── src/... +│ +├── lib/ 通用库(平台无关) +│ ├── rb.c/h 环形缓冲区 +│ ├── misc.c/h 工具函数(字符串、延时等) +│ ├── key.c/h 按键扫描库 +│ ├── storage.c/h 参数存储管理 +│ └── timer_affair.c/h 软件定时器 +│ +├── chip/cw32l011/ 芯片 SDK +│ ├── CMSIS/ ARM CMSIS 核心 +│ └── StdDriver/ CW32L011 外设驱动库 +│ +├── config/ +│ ├── config.h 系统参数结构体定义 +│ └── config.c +│ +└── examples/telephone/ 电话业务示例 + ├── telephone.h + └── telephone.c +``` + +--- + +## 4. 模块说明 + +### 4.1 AT 命令模块 (`dev/at.c`) + +AT 命令模块实现了与无线模组通信的完整状态机: + +- **状态机流程:** `AT_IDLE` → `AT_SEND` → `AT_WAIT_RECV` → `AT_IDLE` +- **队列化发送:** 所有 AT 命令通过环形缓冲区排队,按序执行 +- **超时重试:** 未收到响应时自动重试,最多 3 次 +- **多行响应:** 支持累积多行响应后统一解析 +- **事件上报:** 解析完成后通过事件队列通知上层 + +**与底层完全解耦:** `at.c` 只调用 `hal-at.h` 定义的接口,不包含任何芯片头文件。 + +### 4.2 模组业务模块 (`dev/module.c`) + +- 维护模组中断通知计数器(中断安全) +- 实现 `hal_module_notify_callback()`,供 HAL ISR 回调 +- 通过 `module_synch()` 将系统参数同步到模组 +- 所有硬件操作委托给 `hal_module.h` 接口 + +**与底层完全解耦:** `module.c` 不包含任何芯片头文件(无 `cw32l011_gpio.h` 等)。 + +### 4.3 AT HAL 层 (`hal/hal-at.c`) + +封装了所有 UART 相关的硬件操作: +- 初始化/反初始化 AT UART +- 格式化发送 AT 命令(自动追加 `\r\n`) +- 查询行接收状态,读取一行数据 +- 支持运行时更改波特率 + +### 4.4 模组 HAL 层 (`hal/hal_module.c`) + +封装了所有模组相关的 GPIO/中断操作: +- 模组硬件复位(RST 引脚控制) +- 模组通知引脚的中断配置(上升沿触发) +- CW32L011 GPIOB ISR 实现(包含 AT_ISR 和 PTT 唤醒) + +--- + +## 5. AT 命令层使用说明 + +### 5.1 初始化 + +```c +// 在应用初始化阶段调用(at.c 内部通过 HAL 完成 UART 初始化) +at_init(); +``` + +### 5.2 发送 AT 命令 + +```c +// 将命令入队(非阻塞) +at_send(AT_CMD_CALL); // 发起呼叫 +at_send(AT_CMD_HANGUP); // 挂断 +at_send(AT_CMD_BAT); // 查询电量 +at_send(AT_CMD_VOLUME); // 设置音量(从系统参数读取) +``` + +### 5.3 设置铃声 + +```c +// 必须在 AT_CMD_PLAYRING 命令之前设置铃声类型 +at_set_tone(TONE_RING_RX1); +at_send(AT_CMD_PLAYRING); +``` + +### 5.4 获取事件 + +```c +// 在主循环中轮询 AT 事件 +AT_evt_e evt; +while(at_evt_pop(&evt)) { + switch(evt) { + case AT_EVT_REFRESH_BAT: + // 电量已更新到 sysParam->bat + break; + case AT_EVT_POWER_OFF_ACT: + // 模组请求关机 + break; + case AT_EVT_SLEEP_ACT: + // 模组进入休眠 + break; + } +} +``` + +### 5.5 主循环 + +```c +// at_task() 必须在主循环中持续调用 +while(1) { + at_task(); +} +``` + +--- + +## 6. 模组业务层使用说明 + +### 6.1 初始化序列 + +```c +buadrate_scan(1); // 自动检测/对齐模组波特率 +at_init(); // 初始化 AT 模块(含 UART) +module_init(); // 初始化模组业务层(含中断通知引脚) +module_synch(); // 同步系统参数到模组 +``` + +### 6.2 主循环处理 + +```c +// app_module_task() 封装了通知轮询和 AT 任务 +void app_module_task(void) +{ + if(module_notify_poll()) { + at_send(AT_CMD_MODEFLAG); // 有通知时查询模组状态 + } + at_task(); +} +``` + +### 6.3 获取模组事件 + +```c +Module_evt_t evt; +while(app_module_evt_pop(&evt)) { + switch(evt.evt) { + case MODULE_EVT_CALL: break; // 发起呼叫 + case MODULE_EVT_RING: break; // 被叫响铃 + case MODULE_EVT_INCALL_ACT: break; // 进入通话 + case MODULE_EVT_EXIT_INCALL: break; // 通话结束 + case MODULE_EVT_HANGUP: break; // 挂断 + case MODULE_EVT_REFRESH_BAT: break; // 电量刷新 + case MODULE_EVT_POWER_OFF: break; // 关机请求 + case MODULE_EVT_SLEEP: break; // 进入休眠 + } +} +``` + +--- + +## 7. 移植指南 + +移植到新芯片/平台只需两步: + +### 7.1 实现 AT HAL 接口(`hal/src/hal-at.c`) + +```c +/* 以下函数需替换为目标平台的 UART 实现 */ + +void hal_at_init(void) +{ + /* 1. 获取目标波特率(可从系统参数或硬编码) */ + /* 2. 初始化 UART TX/RX 引脚 */ + /* 3. 配置 UART 参数(波特率、数据位、停止位、校验位) */ + /* 4. 使能接收中断 */ +} + +void hal_at_deInit(void) +{ + /* 禁用 UART 中断,关闭时钟,释放引脚 */ +} + +void hal_at_sendData(const char *format, ...) +{ + /* 格式化字符串后通过 UART 发送(追加 "\r\n") */ +} + +void hal_at_clear(void) +{ + /* 清空接收缓冲区 */ +} + +bool hal_at_is_line_ready(void) +{ + /* 返回是否已收到完整的一行数据("\r\n" 结尾) */ +} + +bool hal_at_get_line(char *out_buf, uint16_t buf_size) +{ + /* 将当前行数据复制到 out_buf,并清空内部缓冲区 */ + /* 返回 true 表示成功,false 表示无数据 */ +} + +void hal_at_reinit_baudrate(uint32_t baudrate) +{ + /* 以新波特率重新配置 UART(用于 AT+BAUDRATE 切换) */ +} +``` + +**接收中断实现要点:** +```c +/* 在 UART 接收中断中,逐字节写入行缓冲区 */ +/* 检测到 '\r\n' 时置 line_ready = true */ +void YOUR_UART_IRQHandler(void) +{ + uint8_t byte = read_uart_byte(); + /* 写入缓冲区,检测 \r\n 行结束符 */ +} +``` + +### 7.2 实现模组 HAL 接口(`hal/src/hal_module.c`) + +```c +/* 以下函数需替换为目标平台的 GPIO/中断实现 */ + +void hal_module_rst(void) +{ + /* 操作顺序: + * 1. 设置电源控制引脚为输出并拉高(使能电源) + * 2. 设置 RST 引脚为输出并拉低(复位有效) + * 3. 延时约 20ms + * 4. 将 RST 引脚拉高(释放复位) + */ +} + +void hal_module_notify_init(void) +{ + /* 将模组通知引脚配置为上升沿触发输入中断 + * 使能对应的 NVIC 中断通道 + */ +} + +void hal_module_notify_deInit(void) +{ + /* 禁用中断,释放引脚 */ +} + +void hal_module_notify_resume(void) +{ + /* 唤醒后将 RST 引脚配置为输出并拉高 */ +} + +/* 在目标平台的 GPIO 中断 ISR 中调用 hal_module_notify_callback() */ +void YOUR_GPIO_IRQHandler(void) +{ + if(/* 模组通知引脚触发 */) { + /* 清除中断标志 */ + hal_module_notify_callback(); /* 必须调用此函数通知 dev 层 */ + } +} +``` + +> **注意:** `hal_module_notify_callback()` 已在 `dev/src/module.c` 中实现, +> 移植时无需修改 `module.c`,只需在目标平台的 ISR 中调用它即可。 + +### 7.3 移植检查清单 + +- [ ] 实现 `hal/src/hal-at.c` 中的所有 7 个函数 +- [ ] 实现 `hal/src/hal_module.c` 中的所有 4 个函数 +- [ ] 在目标平台 ISR 中调用 `hal_module_notify_callback()` +- [ ] 确认 `HAL_AT_LINE_BUF_LEN`(`hal/inc/hal-at.h`)不小于模组最长单行响应 +- [ ] 根据实际硬件修改 `drv/src/drv_gpio.c` 中的 GPIO 引脚映射表 +- [ ] 根据实际硬件修改 `app/app_lowpower.c` 中的 `POWER_KEY_PORT/PIN` 定义 + +--- + +## 8. 接口参考 + +### 8.1 AT HAL 接口(`hal/inc/hal-at.h`) + +| 函数 | 说明 | +|------|------| +| `hal_at_init()` | 初始化 AT UART(从系统参数读取波特率) | +| `hal_at_deInit()` | 反初始化 AT UART | +| `hal_at_sendData(fmt, ...)` | 格式化发送 AT 命令(自动追加 `\r\n`) | +| `hal_at_clear()` | 清空接收缓冲区 | +| `hal_at_is_line_ready()` | 查询是否已收到完整行 | +| `hal_at_get_line(buf, size)` | 获取并消费一行接收数据 | +| `hal_at_reinit_baudrate(baud)` | 重新初始化 UART 波特率 | + +### 8.2 模组 HAL 接口(`hal/inc/hal_module.h`) + +| 函数 | 说明 | +|------|------| +| `hal_module_rst()` | 执行模组硬件复位 | +| `hal_module_notify_init()` | 初始化模组通知中断引脚 | +| `hal_module_notify_deInit()` | 反初始化模组通知中断引脚 | +| `hal_module_notify_resume()` | 唤醒后恢复 RST 引脚状态 | +| `hal_module_notify_callback()` | 中断通知回调(dev 层实现,HAL ISR 调用) | + +### 8.3 AT 命令接口(`dev/inc/at.h`) + +| 函数 | 说明 | +|------|------| +| `at_init()` | 初始化 AT 模块 | +| `at_deInit()` | 反初始化 AT 模块 | +| `at_send(cmd)` | 将 AT 命令入队 | +| `at_set_tone(tone)` | 设置铃声类型(在 `AT_CMD_PLAYRING` 前调用) | +| `at_task()` | AT 状态机驱动(主循环调用) | +| `at_evt_pop(evt)` | 从事件队列取出一个事件 | +| `at_clear()` | 清空 AT 接收缓冲区 | + +### 8.4 模组业务接口(`dev/inc/module.h`) + +| 函数 | 说明 | +|------|------| +| `module_init()` | 初始化模组业务层(含 HAL 通知引脚) | +| `module_deInit()` | 反初始化模组业务层 | +| `module_notify_poll()` | 查询并消费一个模组通知 | +| `module_notify_post(param)` | 软件触发一个模组通知(用于定时轮询) | +| `module_synch()` | 同步系统参数到模组 | +| `MODULE_RST()` | 执行模组硬件复位 | +| `module_notify_resume()` | 唤醒后恢复模组引脚状态 | + +--- + +*文档版本:重构后初始版本 v1.0.0 — 2026-03-31* + diff --git a/app/app_lowpower.c b/app/app_lowpower.c index 69aa242..7877aa1 100644 --- a/app/app_lowpower.c +++ b/app/app_lowpower.c @@ -20,6 +20,10 @@ #include "../app/app_sleep.h" #include "../examples/telephone/telephone.h" +/* 电源实体按键引脚(CW32L011 平台:GPIOC.13) */ +#define POWER_KEY_PORT CW_GPIOC +#define POWER_KEY_PIN GPIO_PIN_13 + #define POWER_KEY_IRQn GPIOC_IRQn typedef enum { diff --git a/dev/inc/module.h b/dev/inc/module.h index 5561cf9..526da00 100644 --- a/dev/inc/module.h +++ b/dev/inc/module.h @@ -1,51 +1,76 @@ #ifndef _MODULE_H #define _MODULE_H +/** + * @file module.h + * @brief 模组业务逻辑层接口 + * + * 本模块负责管理与无线模组(通过 AT 接口通信)相关的业务逻辑: + * - 模组硬件初始化(通过 HAL 层实现,与芯片解耦) + * - 模组中断通知的注册与查询 + * - 模组与系统参数的同步 + * + * 依赖关系: + * 本层仅依赖 hal_module.h(HAL 接口)和标准库, + * 不包含任何芯片专用头文件,保证可移植性。 + */ + #pragma anon_unions #include #include -#include "cw32l011_gpio.h" +/** + * @brief 模组状态标志位(与模组 AT+MODEFLAG 响应对应) + */ typedef struct { union { uint8_t bytes[4]; struct { - uint32_t call : 1; // bit 0 - 发起呼叫 - uint32_t ring : 1; // bit 1 - 被拨打响铃 - uint32_t talk_master : 1; // bit 2 - 作为主机正在通话中 - uint32_t talk_slave : 1; // bit 3 - 作为从机正在通话中 - uint32_t broadcast_m : 1; // bit 4 - 主机广播 - uint32_t broadcast_s : 1; // bit 5 - 从机广播 - uint32_t setting : 1; // bit 6 - 进入群组设置 - uint32_t invite : 1; // bit 7 - 进入群组邀请模式 - uint32_t hangup : 1; // bit 8 - 执行挂断中 - uint32_t powerOff : 1; // bit 9 - 模组请求关机 - uint32_t reserved : 22; // bit 10-31 + uint32_t call : 1; /* bit 0 - 发起呼叫 */ + uint32_t ring : 1; /* bit 1 - 被拨打响铃 */ + uint32_t talk_master : 1; /* bit 2 - 作为主机正在通话中 */ + uint32_t talk_slave : 1; /* bit 3 - 作为从机正在通话中 */ + uint32_t broadcast_m : 1; /* bit 4 - 主机广播 */ + uint32_t broadcast_s : 1; /* bit 5 - 从机广播 */ + uint32_t setting : 1; /* bit 6 - 进入群组设置 */ + uint32_t invite : 1; /* bit 7 - 进入群组邀请模式 */ + uint32_t hangup : 1; /* bit 8 - 执行挂断中 */ + uint32_t powerOff : 1; /* bit 9 - 模组请求关机 */ + uint32_t reserved : 22; /* bit 10-31 */ }; }; } modeflag_status_t; -// power实体按键 -#define POWER_KEY_PORT CW_GPIOC -#define POWER_KEY_PIN GPIO_PIN_13 - -// 模组的电源控制 -#define POWER_PORT CW_GPIOA -#define POWER_PIN GPIO_PIN_8 +/* ============================================================ + * 接口声明 + * ============================================================ */ -// evt +/** @brief 初始化模组业务层(含 HAL 通知引脚初始化) */ void module_init(void); + +/** @brief 反初始化模组业务层(含 HAL 通知引脚反初始化) */ void module_deInit(void); -// mode flag notify +/** @brief 查询是否有模组通知待处理(消费一个通知计数) */ bool module_notify_poll(void); + +/** @brief 主动投递一个模组通知(可用于软件触发,例如定时轮询) */ void module_notify_post(void *param); + +/** @brief 将系统参数同步到模组(发送一组 AT 命令) */ void module_synch(void); +/** @brief 执行模组硬件复位 */ void MODULE_RST(void); + +/** @brief 初始化模组中断通知引脚(内部使用) */ void module_notify_init(void); + +/** @brief 反初始化模组中断通知引脚(内部使用) */ void module_notify_deInit(void); + +/** @brief 唤醒后恢复模组 RST 引脚状态 */ void module_notify_resume(void); -#endif +#endif /* _MODULE_H */ diff --git a/dev/src/at.c b/dev/src/at.c index dce1b3a..fbbb869 100644 --- a/dev/src/at.c +++ b/dev/src/at.c @@ -15,7 +15,6 @@ #include "../../lib/misc.h" #include "../../lib/rb.h" -#include "../../drv/inc/drv_uart.h" #include "../../hal/inc/hal-at.h" #include "../../config/config.h" @@ -430,7 +429,7 @@ static void handle_bat(const char *at_buff) static void handle_baudrate(const char *at_buff) { (void) at_buff; // 未使用 - drv_atUart_init(MCU_BAUDRATE_INIT); + hal_at_reinit_baudrate(MCU_BAUDRATE_INIT); LOG_DEBUG("handle baudrate\n"); } @@ -504,12 +503,10 @@ void at_task(void) case AT_WAIT_RECV: { if((millis() - cxt->waitCnt) < cxt->waitTime) { - UartRcv_s *uart = getAtUart(); + if(hal_at_is_line_ready()) { + char line_buf[HAL_AT_LINE_BUF_LEN]; - if(uart->line_ready) { - char line_buf[UART_LINE_BUF_LEN]; - - if(drv_atUart_getLine(line_buf, sizeof(line_buf))) { + if(hal_at_get_line(line_buf, sizeof(line_buf))) { uint16_t line_len = strlen(line_buf); if((cxt->multi_line_len + line_len) < sizeof(cxt->multi_line_buf)) { memcpy(cxt->multi_line_buf + cxt->multi_line_len, line_buf, line_len); diff --git a/dev/src/module.c b/dev/src/module.c index 3735ced..8df9fa7 100644 --- a/dev/src/module.c +++ b/dev/src/module.c @@ -1,22 +1,27 @@ -/* -rst -- modlue MCRL -power out -- module power control -at_isr -- module rsq -*/ +/** + * @file module.c + * @brief 模组业务逻辑层实现 + * + * 本模块负责: + * 1. 通过 HAL 接口(hal_module.h)完成硬件初始化,不直接操作寄存器 + * 2. 维护模组中断通知计数器(中断安全) + * 3. 实现 hal_module_notify_callback(),供 HAL ISR 回调 + * 4. 提供 module_synch() 将系统参数下发到模组 + * + * 移植说明: + * 本文件无需修改。移植时只需实现 hal/src/hal_module.c 中的硬件接口。 + */ #include #include "../inc/module.h" -#include "../../drv/inc/drv_gpio.h" -#include "../../drv/inc/drv_uart.h" -#include "../../lib/misc.h" -#include "../../lib/storage.h" +#include "../../hal/inc/hal_module.h" #include "../../dev/inc/at.h" -#include "../../dev/inc/sys_tick.h" -#include "../../config/config.h" +/* 模组中断通知计数器(volatile,供中断安全访问) */ static volatile uint32_t module_notify_cnt = 0; -#define ISR_PORT CW_GPIOB -#define ISR_PIN GPIO_PIN_0 +/* ============================================================ + * 内部辅助函数 + * ============================================================ */ static void module_notify_clr(void) { @@ -25,30 +30,41 @@ static void module_notify_clr(void) __enable_irq(); } -void module_init(void) +/* ============================================================ + * HAL 回调实现(由 hal_module.c 中的 ISR 调用) + * ============================================================ */ + +/** + * @brief 模组中断通知回调 + * + * 在 ISR 上下文中被 hal_module.c 调用,递增通知计数。 + * hal_module.h 中声明此函数为需由 dev 层实现的回调。 + */ +void hal_module_notify_callback(void) { - module_notify_clr(); + module_notify_cnt++; } -void module_deInit(void) +/* ============================================================ + * 对外接口实现 + * ============================================================ */ + +void module_init(void) { module_notify_clr(); + hal_module_notify_init(); } -void GPIOB_IRQHandler(void) +void module_deInit(void) { - if(ISR_PORT->ISR & ISR_PIN) { - GPIOB_INTFLAG_CLR(ISR_PIN); - module_notify_cnt++; - } - - if(CW_GPIOB->ISR & GPIO_PIN_7) { // 还用作唤醒 - GPIOB_INTFLAG_CLR(GPIO_PIN_7); - } + hal_module_notify_deInit(); + module_notify_clr(); } void module_notify_post(void *param) { + /* param 为定时器事件回调的参数(StartTimerEvent 传入 NULL),暂未使用 */ + (void)param; __disable_irq(); module_notify_cnt++; __enable_irq(); @@ -70,39 +86,21 @@ bool module_notify_poll(void) void module_notify_init(void) { - GPIO_InitTypeDef GPIO_InitStruct = { 0 }; - GPIO_InitStruct.IT = GPIO_IT_RISING; - GPIO_InitStruct.Mode = GPIO_MODE_INPUT_PULLUP; - GPIO_InitStruct.Pins = ISR_PIN; - GPIO_Init(ISR_PORT, &GPIO_InitStruct); - - GPIOB_INTFLAG_CLR(ISR_PIN); - NVIC_EnableIRQ(GPIOB_IRQn); - NVIC_SetPriority(GPIOB_IRQn, 0); + hal_module_notify_init(); } void module_notify_deInit(void) { - GPIOB_INTFLAG_CLR(ISR_PIN); - NVIC_DisableIRQ(GPIOB_IRQn); - gpio_deinit(GPIO_AT_ISR); + hal_module_notify_deInit(); } void MODULE_RST(void) { - gpio_modecfg(GPIO_POWER_OUT, GPIO_MODE_OUT); - gpio_set(GPIO_POWER_OUT, GPIO_SET); - - gpio_modecfg(GPIO_RST, GPIO_MODE_OUT); - gpio_set(GPIO_RST, GPIO_RESET); - block_delayMs_4M(20); - gpio_set(GPIO_RST, GPIO_SET); + hal_module_rst(); } void module_synch(void) { - SysParam_t *sysParam = getSysParam(); - at_send(AT_CMD_SET_SLEEP); at_send(AT_CMD_VOLUME); at_send(AT_CMD_GIDSET); @@ -113,6 +111,5 @@ void module_synch(void) void module_notify_resume(void) { - gpio_modecfg(GPIO_RST, GPIO_MODE_OUT); - gpio_set(GPIO_RST, GPIO_SET); + hal_module_notify_resume(); } diff --git a/hal/inc/hal-at.h b/hal/inc/hal-at.h index eff511f..9e538ac 100644 --- a/hal/inc/hal-at.h +++ b/hal/inc/hal-at.h @@ -1,12 +1,93 @@ #ifndef _HAL_AT_H #define _HAL_AT_H +/** + * @file hal-at.h + * @brief AT 通信硬件抽象层(HAL)接口定义 + * + * 本文件定义了 AT 命令收发所需的硬件操作接口。 + * 移植到新芯片/平台时,只需在对应的 hal/src/hal-at.c 中实现这些函数, + * 上层 dev/src/at.c 及应用层代码无需任何修改。 + * + * 接口说明: + * - hal_at_init() : 初始化 AT UART 外设 + * - hal_at_deInit() : 反初始化 AT UART 外设 + * - hal_at_sendData() : 格式化发送 AT 命令字符串 + * - hal_at_clear() : 清空 AT 接收缓冲区 + * - hal_at_buff() : 获取 AT 接收原始缓冲区指针(可选) + * - hal_at_is_line_ready() : 查询是否已接收到完整的一行数据 + * - hal_at_get_line() : 获取并消费一行接收数据 + * - hal_at_reinit_baudrate() : 重新初始化 UART 波特率 + */ + #include +#include + +/** @brief 单行接收缓冲区最大长度(含终止符 '\0') */ +#define HAL_AT_LINE_BUF_LEN 100 +/** + * @brief 初始化 AT UART 外设 + * + * 从系统参数中读取波特率,初始化 UART 硬件,使能接收中断。 + */ void hal_at_init(void); + +/** + * @brief 反初始化 AT UART 外设 + * + * 禁用中断,关闭 UART 时钟,释放 GPIO 资源。 + */ void hal_at_deInit(void); + +/** + * @brief 格式化发送 AT 命令字符串(自动追加 "\r\n") + * + * @param format printf 风格格式字符串 + * @param ... 可变参数 + */ void hal_at_sendData(const char *format, ...); -uint8_t *hal_at_buff(void); + +/** + * @brief 清空 AT 接收缓冲区 + */ void hal_at_clear(void); -#endif +/** + * @brief 获取 AT 接收原始缓冲区指针 + * + * @return 指向内部行缓冲区的指针(只读) + */ +uint8_t *hal_at_buff(void); + +/** + * @brief 查询是否已接收到完整的一行数据(以 "\r\n" 结尾) + * + * @return true — 已有完整行数据可读 + * @return false — 尚未接收完整行 + */ +bool hal_at_is_line_ready(void); + +/** + * @brief 获取并消费一行接收数据 + * + * 将当前行数据复制到 out_buf,并清空内部行缓冲区。 + * 调用前应先通过 hal_at_is_line_ready() 确认数据就绪。 + * + * @param out_buf 输出缓冲区 + * @param buf_size 输出缓冲区大小(含终止符 '\0') + * @return true — 成功获取一行数据 + * @return false — 无数据或参数无效 + */ +bool hal_at_get_line(char *out_buf, uint16_t buf_size); + +/** + * @brief 重新初始化 UART 为指定波特率 + * + * 在波特率切换(AT+BAUDRATE 命令响应)后调用,以新波特率重新配置 UART。 + * + * @param baudrate 目标波特率 + */ +void hal_at_reinit_baudrate(uint32_t baudrate); + +#endif /* _HAL_AT_H */ diff --git a/hal/inc/hal_module.h b/hal/inc/hal_module.h new file mode 100644 index 0000000..56a44b6 --- /dev/null +++ b/hal/inc/hal_module.h @@ -0,0 +1,74 @@ +#ifndef _HAL_MODULE_H +#define _HAL_MODULE_H + +/** + * @file hal_module.h + * @brief 模组硬件抽象层(HAL)接口定义 + * + * 本文件定义了模组驱动所需的硬件操作接口。 + * 移植到新芯片/平台时,只需在对应的 hal/src/hal_module.c 中实现这些函数, + * 上层 dev/src/module.c 及应用层代码无需任何修改。 + * + * 接口说明: + * - hal_module_rst() : 执行模组硬件复位 + * - hal_module_notify_init() : 初始化模组中断通知引脚 + * - hal_module_notify_deInit() : 反初始化模组中断通知引脚 + * - hal_module_notify_resume() : 唤醒后恢复模组 RST 引脚 + * - hal_module_notify_callback() : 中断回调(由 dev 层实现,HAL ISR 调用) + * + * 移植说明: + * 1. 将 hal/src/hal_module.c 中的所有函数替换为目标平台的实现。 + * 2. 在目标平台的中断服务程序(ISR)中调用 hal_module_notify_callback()。 + */ + +#include + +/* ============================================================ + * HAL 接口声明 + * ============================================================ */ + +/** + * @brief 执行模组硬件复位 + * + * 操作顺序: + * 1. 使能模组电源 + * 2. 将 RST 引脚拉低(复位有效) + * 3. 延时约 20ms + * 4. 将 RST 引脚拉高(释放复位) + */ +void hal_module_rst(void); + +/** + * @brief 初始化模组中断通知引脚 + * + * 将指定引脚配置为上升沿触发中断,并使能对应 NVIC 通道。 + * 该引脚用于接收模组发出的状态变化通知。 + */ +void hal_module_notify_init(void); + +/** + * @brief 反初始化模组中断通知引脚 + * + * 禁用中断并释放引脚资源。 + */ +void hal_module_notify_deInit(void); + +/** + * @brief 唤醒后恢复模组 RST 引脚状态 + * + * 系统从低功耗模式唤醒后,需将 RST 引脚配置为输出并置高, + * 以确保模组正常工作。 + */ +void hal_module_notify_resume(void); + +/** + * @brief 模组中断通知回调函数(由 dev 层实现,HAL ISR 中调用) + * + * 当模组发出中断通知时,HAL 的中断服务程序(ISR)将调用此函数。 + * dev 层(module.c)负责实现此函数,用于更新内部通知计数器。 + * + * @note 此函数在中断上下文中执行,实现时应保持简短。 + */ +void hal_module_notify_callback(void); + +#endif /* _HAL_MODULE_H */ diff --git a/hal/src/hal-at.c b/hal/src/hal-at.c index fba2418..5b9d78c 100644 --- a/hal/src/hal-at.c +++ b/hal/src/hal-at.c @@ -1,5 +1,18 @@ +/** + * @file hal-at.c + * @brief AT 通信硬件抽象层(HAL)— CW32L011 平台实现 + * + * 本文件实现了 hal-at.h 中定义的所有 AT UART 操作接口, + * 依赖 CW32L011 的 UART 驱动(drv_uart)。 + * + * 移植说明: + * 将本文件中的所有函数替换为目标芯片/平台的对应 UART 实现即可。 + * 上层 dev/src/at.c 不需要做任何修改。 + */ + #include #include +#include #include "../inc/hal-at.h" #include "../../drv/inc/drv_uart.h" #include "../../config/config.h" @@ -8,13 +21,11 @@ void hal_at_init(void) { const SysParam_t *sysParam = getSysParam(); drv_atUart_init(sysParam->baudrate); - module_notify_init(); } void hal_at_deInit(void) { drv_atUart_deInit(); - module_notify_deInit(); } void hal_at_sendData(const char *format, ...) @@ -36,3 +47,18 @@ uint8_t *hal_at_buff(void) { return (uint8_t *) getAtUart()->line_buffer; } + +bool hal_at_is_line_ready(void) +{ + return getAtUart()->line_ready; +} + +bool hal_at_get_line(char *out_buf, uint16_t buf_size) +{ + return drv_atUart_getLine(out_buf, buf_size); +} + +void hal_at_reinit_baudrate(uint32_t baudrate) +{ + drv_atUart_init(baudrate); +} diff --git a/hal/src/hal_module.c b/hal/src/hal_module.c new file mode 100644 index 0000000..28e94fa --- /dev/null +++ b/hal/src/hal_module.c @@ -0,0 +1,82 @@ +/** + * @file hal_module.c + * @brief 模组硬件抽象层(HAL)— CW32L011 平台实现 + * + * 本文件实现了 hal_module.h 中定义的所有硬件操作接口, + * 依赖 CW32L011 的片上外设(GPIO、NVIC)和板级驱动(drv_gpio)。 + * + * 移植说明: + * 将本文件中的所有函数替换为目标芯片/平台的对应实现即可。 + * 上层 dev/src/module.c 及应用层代码不需要做任何修改。 + */ + +#include "../inc/hal_module.h" +#include "../../drv/inc/drv_gpio.h" +#include "../../lib/misc.h" +#include "cw32l011_gpio.h" + +/* 模组中断通知引脚(CW32L011 平台:GPIOB.0) */ +#define MODULE_ISR_PORT CW_GPIOB +#define MODULE_ISR_PIN GPIO_PIN_0 + +/* ============================================================ + * 接口实现 + * ============================================================ */ + +void hal_module_rst(void) +{ + /* 1. 使能模组电源 */ + gpio_modecfg(GPIO_POWER_OUT, GPIO_MODE_OUT); + gpio_set(GPIO_POWER_OUT, GPIO_SET); + + /* 2. 拉低 RST(复位有效),延时后释放 */ + gpio_modecfg(GPIO_RST, GPIO_MODE_OUT); + gpio_set(GPIO_RST, GPIO_RESET); + block_delayMs_4M(20); + gpio_set(GPIO_RST, GPIO_SET); +} + +void hal_module_notify_init(void) +{ + GPIO_InitTypeDef GPIO_InitStruct = { 0 }; + GPIO_InitStruct.IT = GPIO_IT_RISING; + GPIO_InitStruct.Mode = GPIO_MODE_INPUT_PULLUP; + GPIO_InitStruct.Pins = MODULE_ISR_PIN; + GPIO_Init(MODULE_ISR_PORT, &GPIO_InitStruct); + + GPIOB_INTFLAG_CLR(MODULE_ISR_PIN); + NVIC_EnableIRQ(GPIOB_IRQn); + NVIC_SetPriority(GPIOB_IRQn, 0); +} + +void hal_module_notify_deInit(void) +{ + GPIOB_INTFLAG_CLR(MODULE_ISR_PIN); + NVIC_DisableIRQ(GPIOB_IRQn); + gpio_deinit(GPIO_AT_ISR); +} + +void hal_module_notify_resume(void) +{ + gpio_modecfg(GPIO_RST, GPIO_MODE_OUT); + gpio_set(GPIO_RST, GPIO_SET); +} + +/* ============================================================ + * 中断服务程序(ISR) + * 说明:ISR 名称与芯片绑定,不可移植;移植时替换为目标平台的 ISR 名称即可。 + * ============================================================ */ + +void GPIOB_IRQHandler(void) +{ + /* 模组通知中断(GPIOB.0 上升沿) */ + if(MODULE_ISR_PORT->ISR & MODULE_ISR_PIN) { + GPIOB_INTFLAG_CLR(MODULE_ISR_PIN); + hal_module_notify_callback(); /* 通知 dev 层 */ + } + + /* PTT 按键唤醒引脚(GPIOB.7),仅清标志,无需额外处理 */ + if(CW_GPIOB->ISR & GPIO_PIN_7) { + GPIOB_INTFLAG_CLR(GPIO_PIN_7); + } +}