Initial commit: CCU621_M firmware project with BLE debug link support.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-08 17:28:36 +08:00
commit 9ceb218f80
1597 changed files with 724159 additions and 0 deletions
@@ -0,0 +1,184 @@
# 4G 模块 AT 指令与配置功能说明(EC200A)
本目录实现 **Quectel EC200A** 与 MCU 的 AT 交互:**蜂窝注册 → PDP → TCP/TLS 业务**,以及 **FTP(S) 远程升级****GetDiagnostics 日志上传**。下文按 **AT 流程**、**透传 / 非透传**(含 **TCP 与 FTP 分 PDP**)、**FTP 升级与日志两套状态机**、**plat_comm / OCPP 衔接**、**配置宏与排障** 说明。
---
## 目录与文件速览
| 文件 | 作用 |
|------|------|
| `ec200a_4g_cfg.h` | 透传开关、TCP/FTP **分 PDP**、PlatComm FTP 与平台间隔、**QFREAD 分片**、**QFTPGET(COM) 分片收包**(与 QFREAD 同思路的轮询等待)、**QFWRITE 分片轮询**、**UFS 单次读写块 `EC200A_FTP_UFS_RW_CHUNK_BYTES`(默认 4096)**、FTP 期间是否暂缓 **QISEND**、日志块大小、日志收尾到 **QISEND** 前延时等 |
| `ec200a_4g.h` / `ec200a_4g.c` | 初始化状态机、UART 收发、`QIOPEN`/`QSSLOPEN`、非透传 **`QISEND`/`QIRD`**(明文 TCP)与 **`QSSLSEND`/`QSSLRECV`**`wss`/`QSSLOPEN`)、软重连等 |
| `ec200a_4g_ftp.h` / `ec200a_4g_ftp.c` | **`u8_ec200a_4g_ftp_update`**(固件升级)、**`u8_ec200a_4g_ftp_log_upload`**(诊断日志)、**`v_ftp_ctrl_init`** |
上层业务(如 OCPP WebSocket)经 **`bs_connect_impl.c`** 的 **`v_bs_send` / `u16_bs_recv`** 接入 4GFTP 调度由 **`bs_public_impl.c`** 的 **`v_ftp_update_action`** 在 PlatComm 中周期调用。OCPP 侧置位 **`u8_updata_flag`**、**`u8_log_file_upload`** 等与 **`BS_ocpp_ctrl.c`** 协同(见第四节)。
---
## 一、AT 指令流程(蜂窝初始化与建链)
### 1.1 前置:`v_4g_data_init`
应用解析配置里的服务器 URL(域名、端口、APN、`ws://`/`wss://`)填入 **`S_4G_CONFIG_PARA`**,再调用 **`v_4g_data_init`**,内部 **`s8_cat_reboot(0)`** 完成模组上电/复位类动作,随后周期性调用 **`s8_ec200a_4g_init`** 推进状态机。
### 1.2 主初始化路径(`s8_ec200a_4g_init`
状态枚举 **`E_EC200A_4G_INIT_STEP`**,典型顺序:命令模式 → SIM → CCID → CFUN → CGREG → **业务 PDP `QICSGP`/`QIACT``EC200A_TCP_PDP_CTX_ID`** → 可选 TLS 配置 → **`QIOPEN`/`QSSLOPEN`** → 完成。
非透传在打开 Socket 前会 **`s8_ec200a_qisde_apply()`**`AT+QISDE`),再 **`s8_ec200a_qiopen_accumulate`** 等。
### 1.3 建链与 access_mode
- **`EC200A_TCP_QIOPEN_ACCESS_MODE`**:透传为 **2**(等 `CONNECT`),缓冲模式为 **0**(轮询 `+QIOPEN`/`+QSSLOPEN` 错误码)。
- 业务 Socket 使用 **`EC200A_TCP_PDP_CTX_ID`**(默认 **1**),与 FTP 所用 PDP **必须不同**(见 `ec200a_4g_cfg.h` 编译期校验)。
### 1.4 超时与恢复
状态机末尾根据 **`u8_out_cnt`** 累加;过久会打日志、回退 **`STEP_SWCHTO_CMD_MODE`** 并可能 **`s8_cat_reboot`**。非透传下 TCP 断连可先做 **QICLOSE+QIOPEN 软重连**,连续失败后再全量 **`v_bs_4G_data_init`**(见 `ec200a_4g_cfg.h`**`EC200A_TCP_SOFT_REOPEN_FAIL_MAX`**)。
---
## 二、透传与非透传(缓冲模式)
### 2.1 配置关系(`ec200a_4g_cfg.h` 摘要)
| 宏 | 作用 |
|----|------|
| **`EC200A_TCP_USE_TRANSPARENT_MODE`** | **1** 透传;**0** 缓冲(`QISEND`/`QIRD` |
| **`EC200A_TCP_PDP_CTX_ID` / `EC200A_FTP_PDP_CTX_ID`** | 业务 TCP 与 FTP **分 PDP**(默认 1 / 2),**禁止相等** |
| **`EC200A_FTP_TO_PLATFORM_GAP_MS`** | 每轮 PlatComm 内 **`v_ftp_update_action` 一步之后**、平台收发循环前的间隔 (ms),减轻 FTP AT 与 **QISEND** 粘连 |
| **`EC200A_FTP_QFREAD_*`** | 非透传下 **`AT+QFREAD`**(日志读 UFS)及 **`AT+QFTPGET``COM:`** 固件分片:应答在单周期内 **短 `mSleep` + 收包累加** 直至 `\r\nOK`**QFTPGET** 侧等待轮次约为 **`EC200A_FTP_QFREAD_TOTAL_WAITS` 的 12 倍**(FTP 拉网侧数据较慢,见 `s16_qftpget_com_at_slice` |
| **`EC200A_FTP_UFS_RW_CHUNK_BYTES`** | 模组 UFS 单次 **`AT+QFREAD` / `AT+QFWRITE`** 数据负载,同时也是 **固件 `AT+QFTPGET="…","COM:",off,len` 的单片长度**(默认 **4096 = 1024×4**);须为 Flash **`PACKET_SIZE`(1024)** 的整数倍(编译期校验)。固件下载每片经 **CONNECT 负载** 解析后,按 **`upgrade_write_packet`** 与 **`QFREAD` 读 UFS 写 Flash** 相同的 **flash_base + 1024 子包** 逻辑写入 |
| **`EC200A_FTP_QFWRITE_*`** | 非透传下 **`AT+QFWRITE`**CONNECT→发负载→`\r\nOK` 跨多轮 PlatComm **短等轮询**`QFWRITE_WAIT_MS` / `QFWRITE_WAITS_PER_PLAT_ROUND` / `QFWRITE_TOTAL_WAITS`),避免单周期长时间阻塞 UART |
| **`EC200A_FTP_LOG_CHUNK_SIZE` / `EC200A_FTP_LOG_QFWRITE_MAX_BYTES`** | 默认与 **`EC200A_FTP_UFS_RW_CHUNK_BYTES`** 对齐;日志从 FATFS 读块与单次 QFWRITE 负载一致,**一步一块**、包间回到 AT 态 |
| **`EC200A_BLOCK_QISEND_DURING_4G_FTP`** | **1**(默认):`u8_updata_flag` 且 4G 模组 FTP 时 **`v_bs_send`/`ws_send` 暂缓 QISEND**QFTPPUT 大文件期间避免与 AT 抢 UART;**0** 尝试穿插(仍可能 `no prompt >`)。**勿**仅用 `u8_log_file_upload` 判暂缓(recv 早于 CallResult 置位会挡应答)。 |
| **`EC200A_FTP_LOG_DONE_TO_QISEND_DELAY_MS`** | 日志上传收尾(**`QFTPCLOSE`**、`v_ftp_ctrl_init`、排空 RX)后,首帧 OCPP **QISEND** 前短延时,减轻 **`break off=0`** |
| **`EC200A_FTP_LOG_DONE_REQUEST_BS_RENEW`** | 日志上传 **`STEP_FTP_INIT_OK`**:是否 **`v_set_bs_renew`**(默认 **0**,不重连 OCPP);置 **1** 时 FTP 后软重开 TCP 并 **重登** |
| **`EC200A_TCP_APP_RW_MAX`** / **`EC200A_QIRD_AT_READ_MAX`** / **`EC200A_QISEND_AT_LEN_MAX`** | 应用单次读写与 Quectel AT 上限(1500 / 1460)钳位 |
### 2.2 平台统一收发(`bs_connect_impl.c`
**`u8_netType == 0`4G** 时:`v_bs_send` → 透传 **`v_4g_send_data`** / 非透传 **`v_ec200a_tcp_app_send`**`u16_bs_recv` 同理。
非透传 **`s8_ec200a_qisend_once`**:先发 **`AT+QISEND=id,len`**,等 **`>`**,再发二进制负载,再等 **`SEND OK`**;发送前 **`ec200a_modem_uart_rx_drain`** 减轻粘连。详见源码注释与历史版本本文档附录(若需可从版本管理拷贝为 `4G模块AT指令配置功能说明_appendix.md`)。
### 2.3 TCP 与 FTP 的关系(重点)
| 维度 | 说明 |
|------|------|
| **PDP** | 业务 TCP 与 FTP 使用 **不同 context**FTP 侧 **`QIDEACT`/`QIACT`** 只作用 **`EC200A_FTP_PDP_CTX_ID`****不拆**业务 TCP 所在 PDP。 |
| **UART** | 物理 **一根** 串口;**`QISEND`/`QIRD`/`QFTP*`/`QFREAD`/`QFWRITE`** 均为 **分时串行**。 |
| **“并存”** | 模组协议栈内 TCP 与 FTP 会话可同时存在;MCU **交替发 AT**,单时刻 UART 上只有一种事务。 |
| **PlatComm 与联网穿插** | **`plat_comm_task.c`**4G FTP 活跃时 **相邻两周期交替**——一周期只做 **联网**`v_plat_comm_network_round`:双路 `recv` + 各平台 `send_ctrl`),下一周期只做 **FTP 一步**`v_plat_comm_ftp_round``recv`**`v_ftp_update_action`** → **`EC200A_FTP_TO_PLATFORM_GAP_MS`**)。配合 **QFTPGET(COM) / QFREAD / QFWRITE 分包 + 短等**FTP 传输期间 **OCPP 仍可周期性收发包**(非透传路径)。 |
---
## 三、FTP:固件升级与日志上传(两套路径)
**`u8_ec200a_4g_ftp_update`** 与 **`u8_ec200a_4g_ftp_log_upload`** 共用全局 **`e_ec200a_ftp_init_step`** 与同一套 **`STEP_FTP_*`** 枚举,但 **跳转序列不同**;进入任一路径前通常 **`v_ftp_ctrl_init()`** 将步进复位到 **`STEP_FTP_SWCHTO_CMD_MODE`**(或由业务在 **`GetDiagnostics_res`** 等里显式调用)。
**`v_ftp_update_action``bs_public_impl.c`** 分支逻辑:
1.**`s_bs_task_ctrl.ocpp_data.u8_log_file_upload == 1`**(且编译开启 OCPP):走 **`u8_ec200a_4g_ftp_log_upload()`**(4G);网线且未实现日志 FTP 时会清标志并上报失败。
2. **否则**:走 **`u8_ec200a_4g_ftp_update()`**(4G 固件)或 LwIP 升级状态机。
因此 **`u8_log_file_upload` 必须与 `u8_updata_flag` 配合正确**:若误清 **`u8_log_file_upload`**,会在 **`u8_updata_flag` 仍为 1** 时误入 **固件升级** 分支,出现日志里的 **`[FTP-UPG]`** 与 **`RX pkt(0)/(3)`** 等异常(**`BS_ocpp_ctrl.c`** 中已去掉在 **`u8_updata_flag==0` 时无条件清 `u8_log_file_upload`** 的逻辑)。
### 3.1 固件远程升级(`u8_ec200a_4g_ftp_update`
- **入口**PlatComm 周期调用 **`v_ftp_update_action`** → **`u8_ec200a_4g_ftp_update()`**(当 **`u8_log_file_upload==0`** 且 **`t_ftp_update_info.u8_netType==0`**)。
- **日志标签****`[FTP-UPG] step=…`**(与日志上传的 **`ftp test …`** 区分)。
- **配置****`T_FTP_UPDATE_INFO t_ftp_update_info`**(URL、主机、端口、路径、**固件文件名**、账号等)。
**远端对象路径**:由 **`s32_ftp_fill_remote_get_object()`** 将 **`u8_path` + `u8_file_name`** 拼成 **`s_ftp_remote_get_obj`**(如 `/home/ftpuser/ftpfile/firmware/CCU601E.bin`),供 **`QFTPSIZE`** 与 **`QFTPGET`** 使用,**避免仅 CWD 到绝对路径失败时无法取文件**。
**`QFTPCWD`**:路径过长则跳过;先 **`AT+QFTPCWD="<path>"`**,失败再试 **去掉前导 `/`**;仍失败则 **打日志并返回成功步进(1**,后续依赖 **全路径 `QFTPSIZE` / `QFTPGET`**
**与源码一致的步骤顺序(摘要)**
| 顺序 | 枚举步 | 行为要点 |
|------|--------|----------|
| 1 | `STEP_FTP_SWCHTO_CMD_MODE` | **`s8_work_mode_cmd`**:退出透传、**`AT`** |
| 23 | `SET_CGREG` / `QUERY_CGREG` | PS 注册 |
| 45 | `SET_QIDEACT` / `SET_QIACT` | 仅 **FTP PDP**:去激活 → **`QICSGP`+`QIACT`** |
| 610 | `FTP_CFG_*` | **`QFTPCFG`**contextid、account、filetype、transmode、rsptimeout |
| 11 | `QFTPOPEN` | 登录 FTP 服务器 |
| 12 | `QFTPCWD` | 切换远程目录(失败时仍可继续,见上) |
| 13 | `GET_QFTPSIZE` | **`QFTPSIZE`** 对 **`s_ftp_remote_get_obj`** 取远程大小 → **`u32_file_size`**;成功则按 **`EC200A_FTP_UFS_RW_CHUNK_BYTES`** 计算 **`u16_packSize` / `u16_packNum`****`u16_packIndex=0`** |
| 14 | `QFDEL` | 清模组 **UFS** 旧文件(与日志/杂项共用空间,仍建议执行) |
| 15 | `GET_QFTPGET` | 循环 **`AT+QFTPGET="<remote>","COM:",offset,len`****非透传** 用 **`s16_qftpget_com_at_slice`**(与 **`s16_qfread_at_slice`** 同思路等 **OK**);**透传** 用 **`s16_4g_Send_Recv_Ftp_Get`**。首片前 **`v_upgrade_header_data(0)`****`parse_4g_ftp_response`** 取 CONNECT 与 **OK** 间二进制,按与 **`s8_ec200a_qfread`** 相同的 **`flash_base` + 1024 子包** 调 **`upgrade_write_packet`**。**返回 0** 表示尚有分片;**1** 表示全部写完 |
| 16 | `STEP_FTP_SAVE` / `INIT_OK` | **`v_upgrade_header_data(1)`** + **`v_sys_reboot()`** |
**已不再作为升级主路径****`QFLST``QFOPEN``QFSEEK``QFREAD`(从 UFS 整包下载后再读)**;源码中相关 **`case`** 仍保留,供其它场景或对照,**正常 OCPP 固件升级不会走入**。
**超时**:全局 **`u8_out_cnt`** 超过约 **3 分钟****`u8_updata_flag`**、打 **`FTP TO, exit upg`****`QUERY_CGREG`** 另有 **120 次** 强制跳转。
### 3.2 GetDiagnostics 日志上传(`u8_ec200a_4g_ftp_log_upload`
- **入口****`u8_log_file_upload==1`** 时由 **`v_ftp_update_action`** 调用。
- **日志标签****`ftp test <步号>`**。
- **典型流程**:命令模式 → **UFS `QFDEL`** → 本地日志信息(**`s8_get_log_info`**:按 **`EC200A_FTP_LOG_CHUNK_SIZE`** 等收紧 **`u16_packSize`**)→ **`QFOPEN`** 在 UFS 上覆盖打开日志文件 → **`STEP_FTP_FTP_WRITE_LOG_UFS`****`QFSEEK` + `QFWRITE`** 从 FATFS **按块(默认 4096** 写入模组 UFS**`QFWRITE` 在单周期内仅短等轮询**,未收齐 **CONNECT/OK****`s8_ec200a_write_log_data` 返回进行中**,下一 FTP 半周期续传(**不采用整段 `QFUPL` 透传写文件`**,避免长时间占 UART)→ **`QFLST`** →(与升级类似的)**CGREG / FTP PDP `QIDEACT`/`QIACT`** → **`QFTPCFG` 链** → **`QFTPOPEN`/`QFTPCWD`** → **`QFTPPUT`** 上传到远端 → **`AT+QFTPCLOSE`****`s8_ec200a_qftpclose`**)→ **`STEP_FTP_INIT_OK`** 等待若干周期 → 清 **`u8_updata_flag`**、**`u8_log_file_upload`**、**`v_ftp_ctrl_init`**,并在非透传下 **排空 RX + `EC200A_FTP_LOG_DONE_TO_QISEND_DELAY_MS` 延时 + 再 drain**,减轻紧接着的 **Uploaded** / **StatusNotification** 出现 **`break off=0`**。
**`EC200A_FTP_LOG_CHUNK_SIZE` / `EC200A_FTP_LOG_QFWRITE_MAX_BYTES`**:默认与 **`EC200A_FTP_UFS_RW_CHUNK_BYTES`** 一致;控制从 FATFS 单次读取与单次 **QFWRITE** 负载。注意 **读缓冲 + 过滤缓冲** 的 RAM 占用(过滤后长度 ≤ 当块读长)。
### 3.3 与「误走升级分支」的鉴别
| 现象 | 含义 |
|------|------|
| 日志 **`[FTP-UPG]`** + **`QFTPGET(COM)` / `step``GET_QFTPGET`** | 正在跑 **`u8_ec200a_4g_ftp_update`** |
| 日志 **`ftp test`** | 正在跑 **`u8_ec200a_4g_ftp_log_upload`** |
| GetDiagnostics 后出现 **`[FTP-UPG]`** 且 **`RX pkt(0)/(3)`** 卡进度 | 多为 **`u8_log_file_upload` 被清 0** 仍 **`u8_updata_flag==1`**,已按上节在 OCPP 侧修复 |
---
## 四、与 plat_comm、OCPP、互斥策略的衔接
### 4.1 `plat_comm_task.c`
- **`u8_ftp_transfer_active`**:任一路 **`u8_updata_flag!=0`**;若开启 OCPP,在 **4G****`u8_log_file_upload==1`** 时,即使 **`u8_updata_flag` 仍为 0**GetDiagnostics **CallResult 尚未置位 `updata_flag`** 的窗口),也视为 **FTP 活跃**,以便调度 **`v_ftp_update_action`** 跑日志状态机。
- **`ftp4g`****`u8_ftp_transfer_active && t_ftp_update_info.u8_netType==0`**。为真时:使用 **静态相位 `s_plat_comm_net_ftp_phase`** —— **奇偶半周期交替**:一半周期只跑 **`v_plat_comm_network_round`**(联网收发),另一半周期只跑 **`v_plat_comm_ftp_round`**(开头双路 **`v_bs_recv_data`** → **`v_ftp_update_action` 一步** → **`EC200A_FTP_TO_PLATFORM_GAP_MS`**)。这样 **FTP 与 OCPP 不在同一 PlatComm 周期内叠执行**,与 **`QFTPGET(COM)`/`QFREAD`/`QFWRITE` 分包 + 短等** 叠加后,**FTP 传输过程中仍可稳定进行联网数据收发**。
- **网线 FTP****`u8_ftp_transfer_active && netType!=0`** 时独占整周期 **`continue`**(与 4G 交替策略不同)。
### 4.2 `u8_bs_ftp_ocpp_strict_mux``plat_comm_task.h` / `v_plat_data_init`
- **默认 0**:不在 FTP 期间强行拦截 OCPP **`v_bs_send`**;大文件上传请依赖 **`EC200A_BLOCK_QISEND_DURING_4G_FTP`(默认已 1)** 暂缓 QISEND,否则易 **`no prompt >`**。若仍要业务帧与 FTP 硬穿插可 **`#define EC200A_BLOCK_QISEND_DURING_4G_FTP 0`** 并拉大 **`EC200A_FTP_TO_PLATFORM_GAP_MS`**,或运行时置 **`u8_bs_ftp_ocpp_strict_mux=1`**。
- **为 1****`bs_connect_impl.c`** 在 **模组 FTP 传输请求有效** 且目标为 OCPP 通道时 **return** 掉发送;**`bs_public_impl.c`** 在 OCPP **4G TX busy** 时暂缓 **`v_ftp_update_action`**。与 **GetDiagnostics****「先 CallResult / Uploading,再置 `u8_updata_flag`」** 顺序配合使用(见 **`BS_ocpp_ctrl.c`**)。
### 4.3 OCPP 要点(文件在 `ocpp/`,此处仅列衔接)
- **GetDiagnostics****`GetDiagnostics_mag`** 解析 URL 并置 **`u8_log_file_upload`****`GetDiagnostics_res`** 准备 **`fileName`**、**`v_ftp_ctrl_init`****不在组帧前**置 **`u8_updata_flag`**,避免与 strict mux 组合导致 **CallResult 发不出**。**`send_mag`** 在 **CallResult `ws_send` 成功** 后置 **`u8_diag_notify_pending=Uploading`****`ocpp_send_mag_ctrl`** 在 **Uploading****`send_mag` 之后** 再置 **`u8_updata_flag=1`**。与 **4G 分包 FTP、PlatComm 半周期交替** 的衔接说明见 **`ocpp/OCPP功能模块说明.md`** **第 9.1 节**
- **`v_ocpp_private_logic`**:不再在 **`u8_updata_flag==0`** 时无条件 **`u8_log_file_upload=0`**,避免误切 **固件升级** 分支。
### 4.4 透传模式下的 FTP
透传(**`EC200A_TCP_USE_TRANSPARENT_MODE==1`**)下,**日志写 UFS 的 `QFOPEN`/`QFSEEK`/`QFWRITE` 路径不参与编译**(相关步进会失败或超时退出);**固件升级** 仍使用 **`QFTPGET``COM:`** 分片 + **`s16_4g_Send_Recv_Ftp_Get`**,与缓冲模式相比 UART 占用特征不同,需单独测试。
---
## 五、配置与排障建议
| 问题倾向 | 建议 |
|-----------|------|
| **`4G QISEND: no prompt >` / `break off=0`** | 保持 **`EC200A_BLOCK_QISEND_DURING_4G_FTP=1`**(默认);增大 **`EC200A_FTP_TO_PLATFORM_GAP_MS`**;确认 **日志已走 `QFOPEN+QFSEEK+QFWRITE` 分包**(勿再依赖长时 **`QFUPL`** 透传);固件已走 **`QFTPGET(COM)`** 分片;可调 **`EC200A_FTP_UFS_RW_CHUNK_BYTES`**(须为 1024 倍数)、**`EC200A_FTP_QFREAD_*`**(同时影响 QFTPGET 片内等待上限);或 **`u8_bs_ftp_ocpp_strict_mux=1`** |
| **`QSSLOPEN` 成功但 `AT+QISEND` 立刻 ERROR** | **`wss` 须用 `AT+QSSLSEND` / `AT+QSSLRECV`**,不能对 SSL socket 发 **`QISEND`/`QIRD`**(固件 `ec200a_4g.c` 已按 `use_tls` 分支) |
| **`QFTPCWD` 失败但需升级** | 当前实现会在 CWD 失败后仍继续;若仍 **QFTPSIZE/QFTPGET** 失败,核对 **FTP 上实际路径****`s_ftp_remote_get_obj`** 拼接是否一致(含前导 `/` |
| **日志上传结束后首包 OCPP 失败** | 确认 **`QFTPCLOSE`**;调大 **`EC200A_FTP_LOG_DONE_TO_QISEND_DELAY_MS`**;若确认 TCP 已死且可接受重登,再设 **`EC200A_FTP_LOG_DONE_REQUEST_BS_RENEW=1`** |
| **GetDiagnostics 走成 `[FTP-UPG]`** | 确认 **`u8_log_file_upload`** 未被异常清除;**`v_ftp_update_action`** 是否进入 **`u8_log_file_upload` 分支** |
| **双 PDP** | 修改 context 时同时覆盖 **TCP/FTP** 两宏且保持 **不等** |
| **QIRD ERROR** | 检查 **`want`** 是否超 **1500**(已由宏钳位) |
---
## 六、自检清单(FTP 升级相关)
- [ ] **`EC200A_TCP_PDP_CTX_ID``EC200A_FTP_PDP_CTX_ID`**
- [ ] 固件升级日志为 **`[FTP-UPG]`****`QFTPSIZE`** 使用 **远端全路径****`QFTPGET(COM)`** 分片日志 **`pkt i/N`****全部片完成后** 直接进入 **`STEP_FTP_SAVE`**(不经 **UFS QFLST/QFREAD** 主路径)
- [ ] 日志上传为 **`ftp test`**,写 UFS 阶段为 **`QFOPEN` + 循环 `QFSEEK`/`QFWRITE`(块长默认 4096)**,上传结束有 **`QFTPCLOSE`** 与收尾 **drain + 延时**
- [ ] PlatComm**4G FTP** 时周期头 **recv + FTP + gap**,且 **每平台 send 后 recv**
- [ ] OCPP**CallResult → Uploading → `u8_updata_flag`** 顺序;**不误清 `u8_log_file_upload`**
---
*路径:`CCU601E_D/app/plat_comm/4g_module/4G模块AT指令配置功能说明.md`*
*若需保留旧版「2.5 QISEND/QIRD 字节级长说明」,可从版本管理历史中拷贝为 `4G模块AT指令配置功能说明_appendix.md`。*
File diff suppressed because it is too large Load Diff
+82
View File
@@ -0,0 +1,82 @@
/**
* @file bs_wh_gm5.h
* @brief WH-GM5 4G 模组 AT 驱动
*
* 负责模组初始化、APN/Socket 配置、信号查询及串口通信。
* 通信串口:USART6COM_PORT_BS)。
*/
#ifndef _BS_WH_GM5_H_
#define _BS_WH_GM5_H_
#include "publicdata/type.h"
#include "main.h"
#include "publicdata/publicdata.h"
#include "usart.h"
#include "plat_comm/plat_comm_task.h"
#define COM_PORT_BS E_USART_6 //4G 模组 WH-GM5 通信串口
typedef enum
{
STEP_SWCHTO_CMD_MODE = 0, //切换到指令模式
STEP_MODE_NET_ON, //设置工作模式为网络透传模式(默认net)
STEP_UAT_ON, //使能串口AT指令(默认ON)
STEP_UAT_SET_PACK_TIME,
STEP_SET_PWD, //设置指令密码(默认usr.cn)
STEP_SET_APN, //设置APN
STEP_SET_SDPEN, //设置套接字分发
STEP_SCKA_ON, //设置socketA使能(默认ON)
STEP_SET_SCKA_PARA, //设置socketA参数
STEP_SCKB_ON, //设置socketB使能(默认ON)
STEP_SCKB_OFF, //设置socketB关闭(OFF)
STEP_SET_SCKB_PARA, //设置socketB参数
STEP_HEART_OFF, //设置心跳包不使能
STEP_SAVE, //保存当前设置并重启
STEP_INIT_OK, //设置完成
}E_WH_GM5_INIT_STEP;
typedef struct
{
U8_T u8_Sim_Type; //APN类型(0:移动,1:联通,2:电信)
U8_T u8_socketB_en; //socketB使能 默认套接字分发功能使能 - 使能分发时,组帧解帧需要添加帧头;不使能直接透传模式,将数据上送平台,但无法区分多平台
U8_T *socketA_IP; //域名或者IP+端口号 例如 www.baidu.com:1234
U8_T *socketB_IP; //is NULL 则不存在socket
U8_T *apn_str;
U16_T socketA_port; //端口号
U16_T socketB_port;
U8_T use_tls; //是否启用模块内置 TLS0=TCP1=TLSwss
}S_4G_CONFIG_PARA;
typedef struct
{
U8_T u8_out_cnt; //超时计数
E_WH_GM5_INIT_STEP e_wh_gm5_init_step; //无线通信模块初始化步骤标志
U8_T u8_Sim_Card[NUM_20]; //SIM卡号
U8_T u8_4g_Version[NUM_20]; //4g版本
S_4G_CONFIG_PARA s_4g_para;
}S_4G_CTRL_DATA;
//结构体1 -- 用于内部逻辑控制和数据存储
//结构体2 -- 用于联网参数存储-获取
S8_T s8_UAT_check_signal_quality(void);
S8_T s8_check_number(U8_T *data); //查询SIM卡号
S8_T s8_check_socket_LinkState(U8_T u8_id);
S8_T s8_WH_GM5_init(void);
U8_T u8_UAT_CheckConnState(void); //通过串口AT指令(密码ieszt)查询模块网络连接状态
void v_wh_gm5_data_init(S_4G_CONFIG_PARA *s_4g_para);
void v_4g_uart_cache_clear(void);
U8_T v_GM5_get_sim(U8_T *data); /**< 获取 SIM 卡号,有数据返回 1 */
#endif
File diff suppressed because it is too large Load Diff
+99
View File
@@ -0,0 +1,99 @@
#ifndef EC200A_4G_H
#define EC200A_4G_H
#ifdef __cplusplus /*C++编译环境下兼容C语言*/
extern "C" {
#endif
/*------ Exported includes(头文件) ----------------------*/
#include "main.h"
#include "plat_comm/4g_module/ec200a_4g_cfg.h"
/*------ Exported struct(结构体定义) --------------------*/
typedef enum
{
STEP_SWCHTO_CMD_MODE = 0, //切换到指令模式
STEP_QUERY_SIM_STATE, //查询SIM卡状态
STEP_QUERY_CCID, //查询sim卡号
STEP_SET_CFUN, //设置功能模式
STEP_SET_CGREG, //设置PS域 网络注册状态
STEP_QUERY_CGREG, //查询PS域 网络注册状态
STEP_SET_QICSGP_APN, //设置TCP场景参数 设置APN
STEP_SET_CGQMIN, //设置服务质量参数(最低可接受的)
STEP_SET_CGQREQ, //设置服务质量参数(请求的)
STEP_QUERY_CSQ, //查询信号强度
STEP_SET_QIACT, //激活PDP场景
STEP_SET_SSL_CFG, //TLS 配置(QSSLCFG 等,仅在需要 TLS 时执行)
STEP_SET_SOCKET_AND_OPEN, //设置socket 参数并打开(TCP 或 TLS
STEP_SAVE, //保存当前设置并重启
STEP_INIT_OK, //设置完成
STEP_INIT_DEBUG, // 调试
}E_EC200A_4G_INIT_STEP;
typedef struct
{
U8_T u8_Sim_Type; //APN类型(0:移动,1:联通,2:电信)
U8_T u8_socketB_en; //socketB使能 默认套接字分发功能使能 - 使能分发时,组帧解帧需要添加帧头;不使能直接透传模式,将数据上送平台,但无法区分多平台
U8_T *socketA_IP; //域名或者IP+端口号 例如 www.baidu.com:1234
U8_T *socketB_IP; //is NULL 则不存在socket
U8_T *apn_str;
U16_T socketA_port; //端口号
U16_T socketB_port;
U8_T use_tls; //是否启用模块内置 TLS0=TCP1=TLSwss
}S_4G_CONFIG_PARA;
typedef struct
{
U8_T u8_out_cnt; //超时计数
U8_T u8_csq; //信号强度
E_EC200A_4G_INIT_STEP e_4g_init_step; //无线通信模块初始化步骤标志
U8_T u8_Sim_Card[NUM_20]; //SIM卡号
U8_T u8_4g_Version[NUM_20]; //4g版本
U32_T u32_outtime; //超时计数 单位秒
U8_T u8_tcp_socket_id; // 非透传:QISEND/QIRD 使用的 connectID(明文 TCP=0TLS 与 QSSLOPEN 的 clientID 一致)
S_4G_CONFIG_PARA s_4g_para;
}S_4G_CTRL_DATA;
/*------ Exported variables(变量定义) -------------------*/
/*------ Exported function prototypes (函数声明) -------*/
S8_T s8_ec200a_4g_init(void);
void v_4g_data_init(S_4G_CONFIG_PARA *s_4g_para);
void v_4g_send_data(U8_T u8_id, U8_T *u8_sendBuf , U16_T u16_len);
U16_T u16_4g_recv_data(U8_T *u8_recvBuf ,U16_T u16_len);
/** 排空模组 RX FIFO(丢弃);FTP / QISEND 等共用 UART 去粘连 */
void v_4g_uart_rx_discard_fifo(void);
#if !EC200A_TCP_USE_TRANSPARENT_MODE
/** 非透传:经 AT+QISEND 发送 TCP/TLS 负载(按 EC200A_TCP_APP_RW_MAX 分包;详见 ec200a_4g.c */
void v_ec200a_tcp_app_send(U8_T u8_id, U8_T *u8_sendBuf, U16_T u16_len);
/** 非透传:AT+QIRD 读模组 Socket 缓冲(单次至多 EC200A_TCP_APP_RW_MAX;大帧需上层循环) */
U16_T u16_ec200a_tcp_app_recv(U8_T *u8_recvBuf, U16_T u16_len);
/** 模组已在 STEP_INIT_OK 且 PDP 正常时,仅 AT+QICLOSE/QSSLCLOSE + QIOPEN/QSSLOPEN 重建业务 Socket(不拆 PDP */
S8_T s8_ec200a_tcp_socket_close(void);
S8_T s8_ec200a_tcp_socket_soft_reopen(void);
#endif
U8_T u8_ec200a_modem_tcp_stack_ok(void);
U8_T u8_get_sim_card(U8_T *u8_data ,U8_T buf_len);
U8_T u8_UAT_check_signal_quality(void);
void v_4g_log_data_send_data(U8_T *u8_sendBuf , U16_T u16_len);
S8_T s8_ec200a_qiact(void);
/** 按 context_id 配置/激活/去激活 PDP,供 FTP 与业务 TCP 分场景(见 ec200a_4g_cfg.h */
S8_T s8_ec200a_qicsgp_ctx(U8_T context_id);
S8_T s8_ec200a_qiact_ctx(U8_T context_id);
S8_T s8_ec200a_qideact_ctx(U8_T context_id);
#ifdef __cplusplus
}
#endif
#endif /* EC200A_4G_H */
+172
View File
@@ -0,0 +1,172 @@
#ifndef EC200A_4G_CFG_H
#define EC200A_4G_CFG_H
#include "usart.h"
/**
* @file ec200a_4g_cfg.h
* @brief EC200A 模组:串口选择、TCP/FTP/TLS 场景、FTP 轮询与 UFS 块长、非透传 TCP 分包与缓冲派生。
* 可在包含本头或 `ec200a_4g.h` 之前用 `#define 宏名 值` 覆盖下列默认值。
*/
/* ========== 模组 UART 与调试(`ec200a_4g.c` 发送/排空等共用) ========== */
/** 1:在 `v_4g_send_data` / `u16_4g_recv_data` 等路径打印调试信息;0:关闭。开启时 printf 须走调试口,勿与模组口 COM_PORT_BS 共用 TX。 */
#ifndef TEST_BS_PRINTF_FLAG
#define TEST_BS_PRINTF_FLAG (0)
#endif
/** 与 Quectel 模组通信的 USART 逻辑编号(见 `usart.h` 中 `E_USART_ID`,默认 UART12 接 4G)。 */
#ifndef COM_PORT_BS
#define COM_PORT_BS E_USART_6
#endif
/** `v_4g_send_data` 第一形参占位 ID;当前实现未区分多路,固定 0xFF 即可。 */
#ifndef ID_4G
#define ID_4G (0xFFU)
#endif
/* -------------------------------------------------------------------------- */
/* 1) 透传 / QIOPEN 访问模式 */
/* -------------------------------------------------------------------------- */
/** Socket 数据路径:1 = UART 透传数据态;0 = 缓冲/命令模式(AT+QISEND / AT+QIRD)。 */
#ifndef EC200A_TCP_USE_TRANSPARENT_MODE
#define EC200A_TCP_USE_TRANSPARENT_MODE (0)
#endif
/** AT+QIOPEN / AT+QSSLOPEN 最后一参「access_mode」:透传为 2,缓冲模式为 0(随 `EC200A_TCP_USE_TRANSPARENT_MODE` 自动选择)。 */
#if EC200A_TCP_USE_TRANSPARENT_MODE
#define EC200A_TCP_QIOPEN_ACCESS_MODE (2)
#else
#define EC200A_TCP_QIOPEN_ACCESS_MODE (0)
#endif
/* -------------------------------------------------------------------------- */
/* 2) PDP:业务 TCP vs FTPTLS 与业务 TCP 同 PDP */
/* -------------------------------------------------------------------------- */
/** 业务 TCPQIOPEN/QSSLOPEN、模组 QIACT)使用的 PDP context ID。 */
#ifndef EC200A_TCP_PDP_CTX_ID
#define EC200A_TCP_PDP_CTX_ID (1U)
#endif
/** FTPQFTPCFG、QICSGP、QIACT、QIDEACT)使用的 PDP context ID;须与 `EC200A_TCP_PDP_CTX_ID` 不同,避免 FTP 去激活时拆掉业务 TCP。 */
#ifndef EC200A_FTP_PDP_CTX_ID
#define EC200A_FTP_PDP_CTX_ID (2U)
#endif
/* 编译期约束:TCP 与 FTP 不得共用同一 PDP,否则 FTP 侧 QIDEACT/重配会拆掉业务 TCP。 */
#if (EC200A_TCP_PDP_CTX_ID) == (EC200A_FTP_PDP_CTX_ID)
#error EC200A_FTP_PDP_CTX_ID must not equal EC200A_TCP_PDP_CTX_ID
#endif
/** TLSQSSL*)使用的 PDP 与业务 TCP 相同,与 `EC200A_TCP_PDP_CTX_ID` 保持一致。 */
#define EC200A_SSL_PDP_CTX_ID EC200A_TCP_PDP_CTX_ID
/** AT+QSSLCFG 等命令中的 SSL context 编号(模组侧 ctx)。 */
#ifndef EC200A_SSL_CTX_ID
#define EC200A_SSL_CTX_ID (1)
#endif
/** AT+QSSLOPEN 使用的 clientID / 套接字索引(与明文 TCP 的 connectID 区分)。 */
#ifndef EC200A_SSL_CLIENT_ID
#define EC200A_SSL_CLIENT_ID (4)
#endif
/* -------------------------------------------------------------------------- */
/* 3) FTPAT+QFREAD / AT+QFWRITE 轮询(单次 sleep 与总等待次数) */
/* -------------------------------------------------------------------------- */
/** QFREAD/QFWRITE 收 UART 时,每轮循环内单次 `mSleep` 间隔(毫秒)。 */
#ifndef EC200A_FTP_UART_SLICE_WAIT_MS
#define EC200A_FTP_UART_SLICE_WAIT_MS (25U)
#endif
/** 单次 `s16_qfread_at_slice` 调用内,最多执行「sleep + 收包」的次数;超时仍未见应答则本次读失败。 */
#ifndef EC200A_FTP_QFREAD_TOTAL_WAITS
#define EC200A_FTP_QFREAD_TOTAL_WAITS (80U)
#endif
/** 单次 `s8_ec200a_qfwrite_log_bin` 调用内,等待 CONNECT/OK 等阶段的最多次数;超出则本次写失败。 */
#ifndef EC200A_FTP_QFWRITE_TOTAL_WAITS
#define EC200A_FTP_QFWRITE_TOTAL_WAITS (200U)
#endif
/* -------------------------------------------------------------------------- */
/* 4) GetDiagnostics / UFSQFUPL 与单次读写块长 */
/* -------------------------------------------------------------------------- */
/** `AT+QFUPL` 第三参数:UART 侧无数据输入超时(秒),手册范围 1~65535;分片发送时须大于单 PlatComm 周期可能间隔。 */
#ifndef EC200A_FTP_QFUPL_AT_TIMEOUT_SEC
#define EC200A_FTP_QFUPL_AT_TIMEOUT_SEC (120U)
#endif
/** QFUPL 数据态下,单次向模组 UART 写入负载的上限(字节);0 表示按整块发送的旧策略(由上层决定)。 */
#ifndef EC200A_FTP_QFUPL_UART_SLICE_MAX
#define EC200A_FTP_QFUPL_UART_SLICE_MAX (512U)
#endif
/** 模组 UFS 单次 `AT+QFREAD` / `AT+QFWRITE` 数据负载(字节)。FTP 升级 QFREAD 缓冲、日志 FAT 读块与 QFWRITE 上限均以此为界;须为 Flash `PACKET_SIZE` 的倍数且 ≤65535。 */
#ifndef EC200A_FTP_UFS_RW_CHUNK_BYTES
#define EC200A_FTP_UFS_RW_CHUNK_BYTES (4096U)
#endif
#if !EC200A_TCP_USE_TRANSPARENT_MODE
/* -------------------------------------------------------------------------- */
/* 5) 非透传 TCP:软重连、QISDE、应用分包、模组 AT 上限与接收环形区派生尺寸 */
/* -------------------------------------------------------------------------- */
/** 连续「仅 QICLOSE+QIOPEN 软重连」失败达到此次数后,才走全量 `v_bs_4G_data_init` 类驻网恢复。 */
#ifndef EC200A_TCP_SOFT_REOPEN_FAIL_MAX
#define EC200A_TCP_SOFT_REOPEN_FAIL_MAX (5U)
#endif
/** AT+QISDE1 将 QISEND 的 TCP 负载回显到模组 UART(调试用);0 关闭(初始化通常下发 AT+QISDE=0)。 */
#ifndef EC200A_QISDE_ECHO
#define EC200A_QISDE_ECHO (0U)
#endif
/** 应用层单次 TCP 读/写意向上限(字节);`ec200a_4g.c` 内会再钳位到 `EC200A_QIRD_AT_READ_MAX` / `EC200A_QISEND_AT_LEN_MAX`。 */
#ifndef EC200A_TCP_APP_RW_MAX
#define EC200A_TCP_APP_RW_MAX (2048U)
#endif
/** AT+QIRD 第二参数「欲读长度」上限(Quectel 文档常见上限 1500);超过模组可能直接 ERROR。 */
#ifndef EC200A_QIRD_AT_READ_MAX
#define EC200A_QIRD_AT_READ_MAX (1500U)
#endif
/** AT+QISEND 单次发送负载上限(字节,Quectel 常见上限 1460)。 */
#ifndef EC200A_QISEND_AT_LEN_MAX
#define EC200A_QISEND_AT_LEN_MAX (1460U)
#endif
/** 读到 +QIRD: 0(缓冲无数据)后额外延时(毫秒),减轻空轮询;0 表示不延时。 */
#ifndef EC200A_QIRD_EMPTY_POLL_DELAY_MS
#define EC200A_QIRD_EMPTY_POLL_DELAY_MS (0U)
#endif
/** 存放 AT+QIRD 应答及 +QIRD: 前缀等 URC 的缓冲上限:`EC200A_TCP_APP_RW_MAX` + 固定余量(字节)。 */
#define EC200A_QIRD_RSP_MAX ((EC200A_TCP_APP_RW_MAX) + 384U)
/** 非透传下 QIOPEN/QSSLOPEN 应答在单任务内拼接用的累计缓冲大小(字节)。 */
#define EC200A_QIOPEN_ACCUM_SZ (640U)
#if EC200A_QISDE_ECHO
/** QISDE=1 时:等待 `>` / SEND OK 的环形接收区容量(字节),需容纳回显的应用数据。 */
#define EC200A_QISEND_WAIT_RB_SZ ((EC200A_TCP_APP_RW_MAX) * 2U + 512U)
/** QISDE=1 时:`memmove` 收缩接收区时保留的尾部字节数,避免截断半条 URC。 */
#define EC200A_QISEND_RB_TAIL_KEEP ((EC200A_TCP_APP_RW_MAX) / 2U + 256U)
#else
/** QISDE=0 时:等待 QISEND 提示与应答的接收缓冲容量(字节)。 */
#define EC200A_QISEND_WAIT_RB_SZ (896U)
/** QISDE=0 时:接收区收缩时保留的尾部字节数(字节)。 */
#define EC200A_QISEND_RB_TAIL_KEEP (384U)
#endif
#endif /* !EC200A_TCP_USE_TRANSPARENT_MODE */
#endif /* EC200A_4G_CFG_H */
File diff suppressed because it is too large Load Diff
+27
View File
@@ -0,0 +1,27 @@
#ifndef EC200A_4G_FTP_H
#define EC200A_4G_FTP_H
#ifdef __cplusplus /*C++编译环境下兼容C语言*/
extern "C" {
#endif
/*------ Exported includes(头文件) ----------------------*/
#include "publicdata/type.h"
/*------ Exported macro(宏定义) -------------------------*/
/*------ Exported struct(结构体定义) --------------------*/
/*------ Exported variables(变量定义) -------------------*/
/*------ Exported function prototypes (函数声明) -------*/
U8_T u8_ec200a_4g_ftp_update();
U8_T u8_ec200a_4g_ftp_log_upload();
void v_ftp_ctrl_init();
#ifdef __cplusplus
}
#endif
#endif /* EC200A_4G_FTP_H */