文件
phonerail/firmware/main/netcfg.h
T
zhou yang和Claude Opus 5.5 ece65f7c19 固件 0.1.19~0.1.21-c5:配网热点(SoftAP + 网页)、风扇 40 ℃ 以下断电
- 0.1.19 配网热点:没配 WiFi / 连续 60 s 连不上时自己开 SoftAP,192.168.4.1 网页里加删 WiFi、改 MQTT;
  配置拼成 wifi / mqtt 命令走唯一的命令处理器(新链路号 3 CMD_LINK_AP),MQTT 仍不收配置命令
- 0.1.20 热点口令固定 88888888
- 0.1.21 风扇:板温 >=40 ℃ 上电、<38 ℃ 断电,40~65 ℃ 线性调速;fan 命令加可选 sec(下限到点自动交回)
- mqtt 命令加 keep_pass;net 回应加 ap;status 的 fan 加 left
- 新增 test_prov(13 例),test_t_thermal +3;29 ctest 全绿

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-06 14:35:44 +08:00

131 行
6.2 KiB
C
原始文件 Blame 文件历史

此文件含有模棱两可的 Unicode 字符
此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。
/* 网络配置与网络状态(A14 + C1,需求 IF-19 / §10.8)。
IF-19 原话:「凭据与服务端地址存 NVS,**不编译进固件** —— 新板上架时先用 IF-13 的
USB 链路配网」。所以:
· 配置由两条命令写入:`wifi`(SSID / 密码,**最多存 NETCFG_WIFI_N 组**,0.1.9)与
`mqtt`(broker 地址 / 账号 / 遥测周期),
**不收 MQTT 来的**(cmd.c 回 `link`)—— 经 WiFi 改 WiFi 配置,一次手误就把
唯一的远程通道弄断了。收的是两条「人在板子旁边」的链路:USB,和 0.1.19 起
连不上 WiFi 时自己开的配网热点(prov.h —— 所以弄断了也不用再拆机插 USB);
· 本模块只管「校验 + 在内存里持有一份 + 调存储后端 + 通知网络那一侧」,
NVS 与 WiFi/MQTT 都在 ESP 胶水里(mlink_esp.c),这一半宿主机可测。
---- 密码永不外泄 --------------------------------------------------------
`net` 命令、日志、status 里**一律不出现两个密码**,只报 `*_set: true/false`。
回显密码的接口一旦存在,USB 那头随便接一台电脑就能把 WiFi 密码拿走。
---- 跨任务 --------------------------------------------------------------
写者是执行器任务(命令处理器),读者是链路任务(网络胶水)。配置读写都在
`hal_crit` 里整块拷贝(≈560 B 的 memcpy,关中断十几微秒),读者永远拿到一份完整的。
网络状态反过来:链路任务写、命令处理器读,同样整块拷贝。
---- 多组 WiFi(0.1.9,2026-09-28 用户要求)-------------------------------
`wifi` 命令 = **加一组或改同名那组的口令**,`"del":true` = 删同名那组;满了回 `state`。
连不上就按表里的顺序轮着换下一组(mlink_esp.c)。表里的空位(ssid 为空)一律跳过,
`netcfg_init` 会把它们挤到末尾。 */
#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
#define NETCFG_WIFI_N 4 /* 存几组 WiFi */
typedef struct {
char ssid[NETCFG_SSID_MAX + 1]; /* 空 = 空位 */
char pass[NETCFG_PASS_MAX + 1];
} netcfg_wifi_t;
/* ⚠️ 这个结构体**原样存进 NVS**(mlink_esp.c 带版本号存)。改字段就升版本号。 */
typedef struct {
netcfg_wifi_t wifi[NETCFG_WIFI_N]; /* 按加入的顺序,空位都在末尾 */
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 的错误码。
`set_wifi`:同名的改口令,否则加到末尾;表满了 HAL_ERR_STATE。
`del_wifi`:没有同名的 HAL_ERR_ARG。
`mqtt` 的 tele_ms 传 0 = 用默认值。 */
hal_err_t netcfg_set_wifi(const char *ssid, const char *pass);
hal_err_t netcfg_del_wifi(const char *ssid);
hal_err_t netcfg_set_mqtt(const char *uri, const char *user, const char *mpass, uint32_t tele_ms);
/* 表里有几组(空位在末尾,所以有效的就是 [0, n))。 */
int netcfg_wifi_count(const netcfg_t *cfg);
/* 名为 ssid 的那组在第几个,没有 −1。 */
int netcfg_wifi_find(const netcfg_t *cfg, const char *ssid);
/* 纯校验,给命令处理器先判一遍好回准确的错误。 */
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 = 没断过 */
uint8_t wifi_idx; /* 正在连 / 已连上的是表里第几组(net 回应的 ssid 取它) */
char id[13]; /* 板子 ID = STA MAC 的 12 位小写十六进制,topic 用它 */
/* 配网热点(prov.h,0.1.19)。ap_pass 是热点自己的口令,`net` 会报(见 cmd_net.c)。 */
bool ap_on;
uint8_t ap_why; /* prov_why_t */
uint8_t ap_sta; /* 热点上连着几台 */
char ap_ssid[20];
char ap_pass[12];
} 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 */