固件:A12 命令处理器 + A13 USB 分帧 + A14 WiFi/MQTT(含 C1 配网)
- A12 单一命令处理器(cmd*.c):一行 JSON 进出、seq 全局判重(32 条按值)、
限幅 / 空槽一律拒 / 拒绝记事件;命令号与错误码冻结(进 flash)。新增 power 命令,
fan 改为只抬不压的下限(t_thermal_set_floor)。rail_set_mv 注明不拿锁,调用方包 xact。
- A13 USB-Serial-JTAG 分帧(ulink*.c):@C / @R 前缀 + CRC-16,日志行首 @ 垫空格,
任意切块可切;关掉 USB 副控制台(它绕开驱动写 FIFO)。PC 端客户端 tools/prlink.py。
- A14 + C1(netcfg / mlink / cmd_net):topic phonerail/<mac>/{cmd,rsp,tele,state},
mqtts(evse-ca 编进固件)、1 s 遥测、遗嘱离线;wifi / mqtt 配置只收 USB、存 NVS,
net 永不回显密码。
- 协议定稿写进需求文档 §10.8(A12 / A13 / A14 三节);N7 撤销改 D7(机架管理前后端)。
宿主机 23 个 ctest / 400 例全绿;板 B 已烧 0.1.0-a14,经 WiFi → 公网 → 8883 TLS 真连网验过。
固件 0xE2220 / 1 MB 分区只剩 12%,C2 前要重排分区表。
Co-Authored-By: Claude Opus 5.5 <[email protected]>
这个提交包含在:
@@ -0,0 +1,102 @@
|
||||
/* 网络配置与网络状态(A14 + C1,需求 IF-19 / §10.8)。
|
||||
|
||||
IF-19 原话:「凭据与服务端地址存 NVS,**不编译进固件** —— 新板上架时先用 IF-13 的
|
||||
USB 链路配网」。所以:
|
||||
· 配置由两条命令写入:`wifi`(SSID / 密码)与 `mqtt`(broker 地址 / 账号 / 遥测周期),
|
||||
**只收 USB 链路来的**(cmd.c 回 `link`)—— 经 WiFi 改 WiFi 配置,一次手误就把
|
||||
唯一的远程通道弄断了,而那时只能拆机插 USB;
|
||||
· 本模块只管「校验 + 在内存里持有一份 + 调存储后端 + 通知网络那一侧」,
|
||||
NVS 与 WiFi/MQTT 都在 ESP 胶水里(mlink_esp.c),这一半宿主机可测。
|
||||
|
||||
---- 密码永不外泄 --------------------------------------------------------
|
||||
`net` 命令、日志、status 里**一律不出现两个密码**,只报 `*_set: true/false`。
|
||||
回显密码的接口一旦存在,USB 那头随便接一台电脑就能把 WiFi 密码拿走。
|
||||
|
||||
---- 跨任务 --------------------------------------------------------------
|
||||
写者是执行器任务(命令处理器),读者是链路任务(网络胶水)。配置读写都在
|
||||
`hal_crit` 里整块拷贝(≈260 B 的 memcpy,关中断几微秒),读者永远拿到一份完整的。
|
||||
网络状态反过来:链路任务写、命令处理器读,同样整块拷贝。 */
|
||||
#ifndef NETCFG_H
|
||||
#define NETCFG_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "hal_err.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define NETCFG_SSID_MAX 32 /* 802.11 上限 */
|
||||
#define NETCFG_PASS_MAX 63 /* WPA2-PSK 口令上限(64 位十六进制 PSK 不支持) */
|
||||
#define NETCFG_URI_MAX 64
|
||||
#define NETCFG_USER_MAX 32
|
||||
#define NETCFG_MPASS_MAX 64
|
||||
|
||||
/* 遥测周期:上位机的卡死判据要看电流曲线(需求 §4.1),1 s 一个点够用。
|
||||
下限 200 ms:再密就是在拿执行器任务拼 JSON(一条 ≈1 KB)。 */
|
||||
#define NETCFG_TELE_DEFAULT_MS 1000
|
||||
#define NETCFG_TELE_MIN_MS 200
|
||||
#define NETCFG_TELE_MAX_MS 60000
|
||||
|
||||
/* ⚠️ 这个结构体**原样存进 NVS**(mlink_esp.c 带版本号存)。改字段就升版本号。 */
|
||||
typedef struct {
|
||||
char ssid[NETCFG_SSID_MAX + 1];
|
||||
char pass[NETCFG_PASS_MAX + 1];
|
||||
char uri[NETCFG_URI_MAX + 1];
|
||||
char user[NETCFG_USER_MAX + 1];
|
||||
char mpass[NETCFG_MPASS_MAX + 1];
|
||||
uint32_t tele_ms;
|
||||
} netcfg_t;
|
||||
|
||||
/* 存储后端:把整份配置持久化。返回非 HAL_OK = 没存下(内存里的也不改)。 */
|
||||
typedef hal_err_t (*netcfg_save_fn)(void *ctx, const netcfg_t *cfg);
|
||||
/* 配置变了。**在调用 set 的那个任务里**同步回调 —— 胶水应当只置个标志,
|
||||
真正的断开重连在它自己的任务里做(`esp_mqtt_client_stop()` 会阻塞)。 */
|
||||
typedef void (*netcfg_changed_fn)(void *ctx);
|
||||
|
||||
/* `loaded` 为 NULL = 出厂空配置(不连网)。save / changed 可为 NULL。 */
|
||||
void netcfg_init(const netcfg_t *loaded, netcfg_save_fn save, netcfg_changed_fn changed, void *ctx);
|
||||
void netcfg_get(netcfg_t *out);
|
||||
|
||||
/* 校验 → 存 → 改内存 → 通知。校验不过 HAL_ERR_ARG,存不下是 save 的错误码。
|
||||
`mqtt` 的 tele_ms 传 0 = 用默认值。 */
|
||||
hal_err_t netcfg_set_wifi(const char *ssid, const char *pass);
|
||||
hal_err_t netcfg_set_mqtt(const char *uri, const char *user, const char *mpass, uint32_t tele_ms);
|
||||
|
||||
/* 纯校验,给命令处理器先判一遍好回准确的错误。 */
|
||||
bool netcfg_wifi_ok(const char *ssid, const char *pass);
|
||||
bool netcfg_mqtt_ok(const char *uri, const char *user, const char *mpass, uint32_t tele_ms);
|
||||
|
||||
/* ---- 网络状态(胶水写、命令处理器读) ------------------------------------ */
|
||||
|
||||
typedef enum {
|
||||
NET_OFF = 0, /* 没配置 */
|
||||
NET_CONNECTING, /* 在连 / 在退避等待 */
|
||||
NET_UP,
|
||||
} net_state_t;
|
||||
|
||||
typedef struct {
|
||||
net_state_t wifi;
|
||||
net_state_t mqtt;
|
||||
char ip[16];
|
||||
int8_t rssi; /* dBm,WiFi 没连上时 0 */
|
||||
uint32_t wifi_drops; /* 掉线次数(不含首次连) */
|
||||
uint32_t mqtt_drops;
|
||||
uint32_t tele_sent;
|
||||
uint32_t tele_skipped; /* 该发遥测时命令队列满 / 上一条还没发完 */
|
||||
uint8_t wifi_reason; /* 最近一次断开的原因码(wifi_err_reason_t;201 = 找不到 AP,
|
||||
202 = 认证失败,15 = 四次握手超时 ≈ 口令错),0 = 没断过 */
|
||||
char id[13]; /* 板子 ID = STA MAC 的 12 位小写十六进制,topic 用它 */
|
||||
} net_status_t;
|
||||
|
||||
void net_status_set(const net_status_t *st);
|
||||
void net_status_get(net_status_t *st);
|
||||
const char *net_state_str(net_state_t s);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NETCFG_H */
|
||||
在新工单中引用
屏蔽一个用户