图 10 - 板级架构类图
110 个板子是怎么组织在一起的?哪些是父类哪些是子类?
如果上方图无法显示,点这里看 PNG 版本

4 层继承结构
Board (抽象)
▲
┌──────────┼──────────┐
│ │ │
WifiBoard Ml307Board DualNetworkBoard
▲ ▲
┌───┴───┐ │
具体板子 (内部持有上面两个)
第 1 层:Board 抽象基类
定义"所有板子都得回答的问题":
GetAudioCodec()— 你用什么 codec?GetDisplay()— 你有屏吗?什么屏?GetLed()— 你有指示灯吗?什么样的?GetCamera()— 有摄像头吗?GetNetwork()— 你的网络栈?
凡是**纯虚函数(带 )的必须实现*,其它有默认实现可省。
第 2 层:网络栈维度的派生
WifiBoard:Wi-Fi 板的网络管理(Wi-Fi 凭证 / 配网 / 重连)Ml307Board:4G 板的 Modem 管理(AT 命令 / PPP / SIM 状态)DualNetworkBoard:双栈板的切换逻辑
第 3 层:具体板子
继承前面任一个,根据板子的硬件做最终实现:
CompactWifiBoard(面包板)继承WifiBoardEspBox3Board(Espressif Box 3)继承WifiBoardCompactMl307Board(4G 面包板)继承DualNetworkBoard
单例工厂
#define DECLARE_BOARD(BoardCls) \
void* create_board() { return new BoardCls(); }
class Board {
static Board& GetInstance() {
static Board* instance = (Board*)create_board();
return *instance;
}
};
每个 <name>_board.cc 文件末尾用 DECLARE_BOARD 宏注册一个全局 create_board() 函数。链接时只能有一个——所以 CMake 在编译期就把无关的板子排除掉,零运行时开销。
DualNetworkBoard 的"重启切换"哲学
为啥不在运行时切换网络栈?因为:
- 切换涉及关闭 socket、关闭网络驱动、重启另一套驱动;
- 还要重建 MQTT/WebSocket 连接、重新激活、重新建立 MCP 会话;
- 状态非常复杂,bug 风险高。
索性重启了事——4 秒搞定,比手忙脚乱切换还稳定。
一句话讲清
"Board 是个抽象接口,4 层继承:抽象 → 网络栈分类 → 具体板。每个板子用宏注册自己,CMake 编译期选其中一个;运行时永远不需要判断"现在是哪个板子"——多态搞定。"
关联章节
/09-boards整章