软件架构设计方案

一、概述

本文档给出 Viper V2 产品中 MCU1(Cortex-M7)的软件架构设计方案。

核心分层思想:

SOC板级芯片能力在 Adapter/hal 层封装

产品外设基础能力在 Module 层实现

通用业务逻辑流程在Service 层实现

产品功能逻辑实现在 Application 层实现

目的

  • 目的:为什么要对 MCU1 建立分层的软件架构,架构要解决什么问题、达成什么目标。
  • 架构图与分层结构:MCU1 软件由哪几层组成,每层放什么,模块如何划分。
  • 各层职责:每层的准确定位、职责清单与明确禁止事项。
  • 核心设计原则:全项目统一遵守的架构约束,及其在 Viper V2 产品上的落地。
  • 分层调用关系:运行期调用链、初始化装配关系、并发模型,落实高内聚、低耦合。
  • 如何判断放置哪一层:新功能、新模块的落层判断方法与规则,避免后期层次腐化。

范围与边界

对象 是否在范围内 说明
MCU1(M7) ✅ 本文档全部覆盖 Viper V2 的时序控制核心,承担产品业务、通用服务、外设与器件能力封装
MCU0(DCLS) ❌ 不在范围内 安全控制核,负责引导、镜像认证加密、时钟电源配置与上电加载
Q8 DSP ❌ 不在范围内 信号处理核,负责频谱与点云 peaks 解算

MCU1 硬件功能背景

芯片接口与板级外设

  • MCU1 是 Viper V2 的时序控制核心,其使用的芯片总线接口单元包括 HSADC、CAPCOM、AWG&DAC、HKADC、HKDAC、2.5G XGMAC、I2C、SPI、UART、PVT Monitor 等;
  • Viper V2 产品外设包括转镜电机与驱动板、Chirp Laser驱动板、IMU单元、主控FPGA板,电源电压/温度监控、看门狗芯片、NetWork网络单元、 LiDAR采集处理单元。

img

关键实时性约束

以下约束直接决定了分层中哪些能力必须下沉到 Module/Adapter 层、哪些必须留在 Application/Service 层,是架构设计的硬性输入。

约束 架构影响
棱镜 20Hz 扫描周期,4 个面,每面有效扫描 80°,盲区 10°/面 单个扫描周期内必须完成”点云输出模式 ↔ 状态信息监测模式”的硬切换,调度逻辑必须集中在 Application 的 scan_ctrl 中,且切换动作须是无阻塞、无浮点重计算的
盲区时间约 5.5ms 盲区内要串行完成多项监测采集 + 结果输出,因此各监测采集必须模块化、可并发触发,且数据结构需预先分配
激光—采样对齐精度 ≤ 60ps 运行时禁止切换 Acquisition PLL 派生时钟,时钟配置只能在启动阶段完成——时钟与 PLL 相关能力必须收敛在 Adapter/sdk 并加保护
点云 UDP 零拷贝低延迟传输(双 Buffer 2×1500B + 信号量) 传输路径上禁止任何 memcpy 与阻塞等待,Payload报文组装(service/transport)与网卡发送(modules/net)必须以 Buffer 所有权交接
看门狗喂养频率 80Hz 看门狗喂养收敛到单一服务(service/ska),禁止多处散喂

二、核心设计原则

职责要单一,依赖要单向,变化要隔离。

分层的本质是:通过明确各层的职责边界和依赖方向,隔离变化的传播,降低维护成本。

分层的意义是:把系统中不同类型的变化,控制在各自应该存在的边界以内;减少降低可控风险,增强系统稳定 —— 这也是软件架构真正的价值所在。

分层不是为了目录好看或显得专业,而是解决嵌入式项目长期维护的问题。

要解决的问题

变化类型 典型场景 Viper V2 MCU1 中的收敛边界
平台变化 SoC 更换、SDK 升级、RTOS 替换、启动文件调整、时钟树调整 收敛在 Adapter(sdk / hal / osif / bsp)层
板级变化 GPIO 引脚调整、UART/SPI/I2C 实例变更、DMA 通道变化、中断映射调整 收敛在Module 的 driver 子层
外设变化 IMU单元 / 电源监测芯片 / 电机驱动板/看门狗芯片切换 收敛在 Module 层的对应外设模块(pubif对外接口不变,driver更换实现)
业务变化 状态机调整、扫描策略升级、监测判定逻辑变更、参数定义变更 收敛在 Application 与 Service 层

核心设计原则

  1. 单一职责:一个模块只做一类事,不混职责——避免一边读传感器,一边做业务判断再顺手转发协议。
  2. 高内聚、低耦合:内部逻辑紧密相关,对外暴露接口尽量少,改内部不影响上层功能。
  3. 接口清晰:通过稳定接口交互,而非 extern 全局变量到处穿透;头文件声明清晰 API,输入输出、生命周期、错误码明确。
  4. 隐藏实现细节:上层只关心”做什么”,不关心是 SPI 还是 I2C、是 DMA 还是轮询、是哪个 HSADC 通道。
  5. 禁止越层访问:不能绕过中间层下探。Application 不直接访问HAL层,Service 不直接访问寄存器,Module 不越过 HAL 触碰厂商 SDK 私有 API。
  6. 可替换:换 SoC 时 Application 保持不改,换外设器件时业务保持不动,换SOC板卡时 Modules/Service 尽量稳定。
  7. 面向接口编程:依赖稳定抽象而非具体实现——上层依赖”能力”,不依赖”某个具体实现细节”。

HAL 与 Module 的职责边界

这是最关键的一条边界规则,也是本次架构划分与传统”按芯片外设建模块”做法的根本区别。

  1. 芯片能力一律在 HAL:凡是芯片提供的、带有寄存器与硬件时序属性的能力(ADC 采样、波形发生、捕获比较、PVT电压温度监测、以太网收发……),一律由厂商在 BSP/SDK 给出接口,MCU侧统一在 HAL 层做二次封装。Modules 层不得直接访问 SDK 私有 API接口。
  2. 产品语义一律在 Module:凡是”产品要做什么”的封装,一律在 Module 层基于 HAL 接口实现。模块命名必须体现产品语义(laser、motor、chip_monitor),不得以芯片外设命名(不得出现 hsadc 模块、awg 模块、xgmac 模块)。
  3. 判据:把这个能力换一颗芯片还成立吗?成立 → 属 Module(如”转镜电机”);不成立 → 属 HAL(如”HW ADC 通道 3 的采样”)。
  4. 一份芯片能力只封装一次:同一芯片能力被多个 Module 复用时,HAL 只提供一份封装,Module 之间共享该 HAL 接口,不各自重写寄存器访问。
  5. Module 内部分为三层:每个模块内部按 pubif / middle / driver 三层——pubif 暴露模块能力接口,middle 承载私有协议与关键框架(可选),driver 调用 HAL 芯片能力接口并屏蔽硬件时序。

三、总体软件架构

架构总览

下面是Viper V2 MCU1 软件分层架构总览:

  • 自上而下为 Application、Service、Module、Adapter 四层主链;
  • 右侧为可复用的Middleware中间层,底部为硬件芯片层;
  • 向下实线箭头表示标准 API 的单向调用方向,向上虚线箭头表示注册回调与事件的异步上报;
  • Module 层中每个模块都展开为 pubif / middle / driver 三层,并在 driver 子层标出其依赖的 HAL 芯片能力。

software architecture

分层描述:

  • Adapter:适配层,主要负责SOC芯片平台的硬件适配和RTOS的适配。相同芯片使用同一分支管理。

    • common:芯片平台优先需要适配的基础能力,包括logger,assert,delay、cli组件和其他和芯片编译配置强相关组件。
    • hal:对芯片的总线通信接口进行封装,确保对外提供的api一致,起到屏蔽硬件差异的作用。
    • osif:对操作系统的能力抽象和封装,确保对外提供的api一致,起到屏蔽os差异的作用。
  • Middleware:使用到的第三方库和自己实现的基础能力库。所有项目使用同一分支管理。

  • Module:对产品外设模块的能力封装,单个modules对外提供该模块的所有能力接口,供上层调用。屏蔽相同模块不同硬件的差异。每个项目有个分支管理。

    • 每个module内部可以根据实际情况从上到下分为pubif,middle,driver三层 或者pubif,driver两层。
    • pubif是(public interface缩写)对外提供的接口
    • middle是这个模块的协议或者关键实现框架
    • driver为该模块的驱动实现
  • Service:可复用业务逻辑中的通用流程,作为稳定的业务支撑服务。不同项目维护不同分支。

  • Application:具体产品业务逻辑的不同实现,不同项目维护不同分支。

分层概述

层级 定位 职责 包含模块 代码路径
Application应用层 产品业务逻辑 实现 Viper V2 的业务应用:状态机、扫描调度、调制与点云编排、模式切换、监测决策等 int、sys、fsm、scan_ctrl、point_cloud、time、motor、laser、imu、ota application/
Service服务层 通用业务支撑服务 沉淀可被多个业务复用的通用流程:参数管理、数据存储、数据传输上报、固件升级、系统保活、日志上报等 config、storage、transport、ota、ska、ptp、log platform/service/
Module模块层 产品外设模块能力封装 基于 HAL 芯片能力接口实现产品语义能力;模块内部再分 pubif / middle / driver acquisition、laser、motor、chip_monitor、net、time、storage、imu、shm platform/module/
Middleware中间层 横向复用基础库 与业务、硬件均无关的可复用基础能力:纯 C 工具库、Debug调试库、第三方库 micro_libs、lwip、freertos platform/middleware/
Adapter适配层 芯片平台与板级适配 硬件SOC板卡适配1. osif 抽象操作系统能力2. common 沉淀基础能力、3. hal封装芯片总线接口4. bsp 厂商板级资源包、5. sdk 厂商 SDK支持包 hal(hsadc / awg_dac / hkadc / hkdac / ccu / pvt_mon / ethernet/.... platform/adapter/

芯片能力 → HAL 封装 → 产品模块

产品需求 芯片能力 HAL 封装 Module 实现
配置 AWG 模块产生激光器的调制波形 AWG & DAC hal/awg_dac modules/laser(激光器)
配置片上 PVT 监测模块完成芯片状态信息监测和管理 PVT Monitor hal/pvt_mon modules/chip_monitor(芯片状态监测)
配置 CAPCOM 用于转镜电机控制和角度解析 CAPCOM / CCU hal/timerhal/pwm modules/motor(转镜电机)
配置 HSADC 的采集和处理模式 HSADC + FFT + iDMA hal/hsadc modules/xxx(具体采集功能)
通过 2.5G XGMAC 传输点云、配置与日志 XGMAC hal/ethernet modules/net(网络通信)
通过 I2C / SPI 读取 IMU 与电源监测芯片 I2C / SPI hal/i2c、hal/spi modules/imu(IMU姿态检测)
其他外设模块 UART hal/uart modules/xxx(具体功能模块)
与外部计算单元交换采集数据与解算结果 共享内存 / IPC hal/ipc modules/shm(数据交互)

四、各层职责详解

application ** —— **应用层

职责:实现 Viper V2 的产品业务应用——系统初始化上电、产品状态机、扫描调度、调制与点云编排、数据模式切换、监测任务决策、故障状态机、ota升级等。

模块 中文名 职责 主要依赖
init 启动装配 系统入口与初始化编排:按 Adapter → Module → Service → Application 顺序完成各层初始化,再进入业务主循环;只做装配与顺序编排,不含业务决策 adapter、module、service
sys 系统服务 系统级公共业务:系统上电启动逻辑,电源管理逻辑,数据模式切换(ADC Raw Samples / FFT Amplitude / Point Cloud)、整机健康状态判定 service/config、service/log、module/chip_monitor
fsm 产品状态机 切换 MCU1 在配置态、点云输出模式、状态信息监测模式、Recovery 模式、OTA升级态之间的迁移;负责迁移前置条件检查、超时保护与失败回退 service/config、service/ska_monitor、module/*
scan_ctrl 扫描调度 维护棱镜扫描角度与 4 面 80° 探测区 / 10° 盲区的映射关系;按当前角度决定处于点云输出模式还是状态信息监测模式;生成触发时序请求 module/motor、service/ska_monitor
point_cloud 点云业务 接收经 module/shm 得到的解算结果,结合扫描角度组装点云业务对象并提交上报 module/shm、module/motor、service/transport
time 时间基准业务 为点云与诊断数据打时间戳;校验业务时间与主时钟的一致性,异常时触发重新同步 service/gptp、module/time
motor 电机业务 转镜电机运行策略:转速设定、启停与相位对齐的策略决策下发;电机异常时决定降级运行还是停机 module/motor
laser 激光器业务 调制波形的业务参数编排:波形选择、加载时机与生效原子性的策略层决策 module/laser、service/config
imu IMU 业务 IMU 数据的业务消费:80Hz 采集节拍的业务触发、姿态异常的业务判定与上报 module/imu、service/ska_monitor
IAP 升级业务 升级流程编排:接收升级包、校验结果处理、升级完成复位跳转与 recovery 判定 service/ota、module/storage

service **—— **服务层

职责:为应用层提供可复用的通用服务能力——参数管理、数据存储、协议处理与上报、固件升级、系统保活、日志上报等。

模块 中文名 职责 主要依赖
config 参数配置 运行参数的定义、默认值、合法性校验、运行时修改与固化写入非易失存储区;上电时从 Flash 加载参数到内存 module/storage、middleware/micro_libs
storage 数据存储 通用记录型数据存储抽象:故障记录、统计、运行日志的落盘与查询 module/storage
transport 点云与上报 对外通信的统一出口:点云 Payload 组装、状态信息重新组包、参数下发与升级镜像接收;双 Buffer(2×1500B)+ 信号量驱动零拷贝发送 module/net、middleware/lwip
iap IAP固件升级 IAP 流程:经 RGMII 自定义 UDP 接收固件镜像、CRC32 完整性校验、写入 Flash 指定扇区、升级完成复位跳转;Recovery 模式判定 module/net、module/storage、middleware/micro_libs
ska 系统保活监控 统一监控 RTOS 各系统任务的运行保活状态:按周期采集各任务的存活标志与运行时长,识别超时、阻塞与异常退出的任务并上报告警;集中管理看门狗喂狗——所有对外看门狗喂狗动作只由本服务一处执行,禁止各业务自行散喂 module/watchdog_ic、adapter/osif、service/log
monitor 状态监测调度 多速率任务调度:20Hz 监测周期、80Hz IMU 与看门狗周期、盲区窗口时间计算;按窗口派发各项状态监测采集并汇总结果提交交叉验证 module/motor、module/chip_monitor、module/imu、module/power_mon、module/temp_sensor、module/motor_board、module/chirp_laser_board、module/watchdog_ic
gptp 时间同步服务 接收外部 gPTP/PTP 时间报文并校准系统主时钟,对外提供统一的时间基准与时间戳查询接口 module/time、module/net
log 日志诊断 分级日志、故障码、运行诊断信息(含内存、任务栈水位、复位原因)的采集与上报 adapter/common、module/storage

module **—— **模块层

职责:基于 HAL 芯片能力接口实现产品外设功能能力。单个 module 对外提供该模块的所有能力接口,供上层调用,屏蔽相同产品能力在不同硬件实现上的差异。

模块内部三层

子层 定位 Viper V2 示例
pubif 对外提供的接口(public interface) md_laser_pubif.h:加载调制波形、启动输出、设置调制参数;md_motor_pubif.h:设置转速、电机启动、读取角度
middle 本模块的协议或关键实现框架 ABI 脉冲解码与角度标定、电机驱动板私有协议解析、调制波形管理与链式策略
driver 本模块的驱动,调用 HAL 芯片能力接口 调用 hal/awg_dac 完成波形内存写入与触发;调用hal/timer与 hal/pwm 配置 PWM 与捕获;调用 hal/hsadc 与 hal/dma 配置ADC采集与搬运

特别说明:并非每个模块都必须三层齐全——简单模块可只保留 pubif + driver,但对外暴露面必须统一收敛在 pubif。

具体模块

模块 中文名 职责 依赖的 HAL 能力 形态 备注
acquisition 采集链 HSADC 采集与处理模式配置:16 通道 1.25G、单次 5120 点、2× 降采样至 2560 点、4096 点 FFT;采集内存与 iDMA 取数通道管理;对外提供采集数据接入通道 hal/hsadc、hal/dma SoC 片上 需要
laser 激光器 激光器调制能力:波形内存加载、链式触发、幅度斜坡调制、偏置/增益输出配置;为 AWG&DAC 提供产品语义的调制封装 hal/awg_dac、hal/hkdac SoC 片上 需要
motor 转镜 / 多边形控制 转镜电机控制与角度解析:PWM 波形驱动电机稳定匀速转动、ABI 脉冲解码、角度标定与相位映射;对应硬件框图中的 Polygon control 与 Scanning angle parser,板件为 Polygon Control Board;角度是扫描调度与盲区判定的基础 hal/timer、hal/pwm SoC 片上 + 板级 需要
chip_monitor 芯片状态监测 片上芯片状态监测与管理:PVT 供电轨电压与 die 温度采集、HKADC 监测信号采样、越限判定与告警上报;盲区内按需提供监测信号采样能力 hal/pvt_mon、hal/hkadc SoC 片上 暂不需要
net 网络通信 2.5G 以太网通信能力:网卡初始化、描述符环管理、零拷贝双缓冲收发、IEEE1588 时间戳获取与 MACsec 状态 hal/ethernet SoC 片上 需要
time 时间同步 时间同步能力:接收外部 gPTP/PTP 时间报文并校准系统主时钟;维护高精度时间戳,为点云数据打时间戳 hal/ptp_ts、hal/ethernet SoC 片上 暂不需要
storage 非易失存储 固件镜像与参数区的页级读写、擦除、完整性校验;向上提供镜像区与参数区的语义化读写接口 hal/flash 板级 需要
imu 惯性单元 IMU 设备封装:I2C 读取 IMU0/IMU1 状态与姿态数据,80Hz 采集 hal/i2c 板级 暂不需要
shm 数据交互 与外部计算单元的数据通道:共享内存缓冲区管理、双向数据交换、跨核中断通知 hal/ipc SoC 内部 需要
timer_manager 系统时基定时器 稳定系统的时间保证 hal/timer SoC 片上 需要

middleware **—— **库层

职责:沉淀与业务、硬件均无关的可复用基础能力,是横向复用层,不在垂直调用链上——Application、Service、Module、Adapter 均可直接引用;库之间禁止互相耦合。

库 内容 约束
micro_libs ringbuf、crc32、序列化与字节序、定点与浮点数学、FIR/IIR/匹配滤波、内存池、FSM 状态机框架、软定时器、事件分发器、字符串处理 纯 C 实现,不依赖特定 OS 与硬件,可单独编译成静态库
diagnosis 内存监控、backtrace异常回溯、coredump调试手段 只依赖 adapter/common 与 middleware 自身实现,不含任何产品语义
third_party lwIP(UDP/IP 协议栈)、FreeRTOS操作系统 第三方源码原样引入,仅在 third_party 目录,不做任何改动

adapter **—— **适配层

职责:主要负责芯片平台的硬件适配和 RTOS 的适配;相同芯片使用同一分支管理,确保对外提供的 API 一致,屏蔽底层差异。

hal —— 芯片能力封装

HAL 是芯片能力与上层之间的唯一通道。芯片能力由 Broadcom 在 BSP/SDK 中提供接口,MCU1 侧统一封装成平台无关、语义清晰的能力接口,module 层只依赖这些接口。

HAL 封装 覆盖的芯片能力 厂商依赖 备注
hal/hsadc 16 通道 1.25G 高速 ADC、FIR 与抽取、采集内存、FFT 加速器、TXSLZR 激光脉冲发生器、HSREF / HSAFE、NSU 触发网络 hsadc_helper、hsref / hsafe / txslzr / nsu / acqcmn 需要
hal/awg_dac 任意波形发生、DDS 相位累加、波形内存、通道链式、AWG-DAC、幅度斜坡调制器 awg_helper 需要
hal/hkadc Housekeeping ADC、通道分工、ADC 6/7 序列器、触发与数据流 hkadc_helper 暂缓
hal/hkdac 8 个 Housekeeping DAC、触发矩阵、组内同步输出、软件输出与 DMA hkdac 不需要
hal/timer CAPCOM 捕获比较定时器、CCT 输出、输入捕获、计数与定时、外部接口与触发矩阵 ccu_helper 需要
hal/pwm PWM 输出:频率/占空比配置、输出极性与同步 ccu_helper 需要
hal/pvt_mon PVT Monitor 电压温度监控、监控矩阵、转换与标度、数字/模拟比较器、越限信号路由 — 不需要
hal/ethernet 1.0G XGMAC、速率路径、SGMII/HSGMII、描述符环、收发特性、IEEE1588 / 802.1as 时间戳、MACsec xgmac_helper、ethernet 需要
hal/i2c I2C 主/从模式、时钟产生、中断、寄存器映射 i2c 需要
hal/spi SPI 主机 / 从机 — 不需要
hal/uart UART 收发、中断、FIFO — 需要
hal/gpio GPIO 输入输出、电平、方向、外部中断 — 不需要
hal/flash SPI / QSPI Flash 读写擦除 — 需要
hal/wdt 内部看门狗 — 需要
hal/ptp_ts IEEE1588 / 802.1as 时间戳生成与读取 — 不需要
hal/ipc 共享内存缓冲区、中断通知与跨核同步 — 需要

osif/ common/ bsp / sdk

子层 定位 内容
osif 操作系统能力抽象 task、queue、semaphore、mutex、event group、timer、ipc/shm、memory、irq context;对外提供一致 API,屏蔽 OS 差异
common 平台优先适配的基础能力 logger、assert、delay、cli/shell,以及其他与芯片编译配置强相关的组件
bsp 板级支持 引脚与外设实例映射、器件互联拓扑、中断与 DMA 通道分配、板级初始化、GPIO 电平与方向等板级细节
sdk 厂商 SDK 适配 BCM89158 寄存器定义与官方驱动库、启动代码、链接脚本、时钟与电源初始化;仅 HAL 层可访问,上层不得直接使用

五、各层调用关系

运行时调用关系

运行期调用关系遵循”自上而下单向依赖 + 必要回调”:

  • 上层通过下层的公开API接口发起接口调用
  • 下层在完成处理后以callback回调或事件的方式异步通知上层;
  • 下层绝不能直接反向持有上层逻辑。

call relationships

各层间的依赖约束

白名单是强制约束:每层代码只能调用白名单所列层的接口,未列出的层一律禁止调用;

同层模块之间禁止直接耦合。

后期将该规则由 include 依赖检查py脚本,在 build构建中强制约束检查,否则编译失败。

当前层 允许调用 禁止
Application service、module、middleware、adapter 直接访问 hal / sdk 私有 API;跨模块调用其他 module 的内部实现;同层模块之间互相耦合
Service module、middleware、adapter 调用 application;直接访问寄存器;绕过 module 直接调用 hal
Module adapter(hal / osif / common)、middleware 调用 service、application;直接访问 sdk / 厂商 BSP 私有 API;模块之间互相耦合
Middleware adapter(仅必要接口) 依赖特定 OS 或硬件环境;库之间互相耦合;反向依赖上层
Adapter / hal sdk / 厂商 BSP 向上暴露 sdk 私有 API

初始化装配关系 ≠ 运行期调用关系

运行期调用关系和初始化装配关系不是一回事。

初始化应由统一入口编排,而不是让业务层自己拉起底层。

init
├── app_adapter_init() // Adapter:BSP、时钟电源、SDK、OS 启动
├── app_middleware_init() // Middleware:基础库与第三方组件初始化
├── app_module_init() // Module:各模块 pubif 初始化(不含业务语义)
├── app_service_init() // Service:通用服务注册与初始化
└── app_start() // Application:状态机与业务对象初始化,进入主循环与调度

初始化与运行期调用是两条不同的链路:运行期由上层主动调用下层接口;而初始化则由统一入口 init 按 Adapter → Middleware → Module → Service → Application 的固定顺序自下而上装配,每层只初始化自身职责范围内的东西,不反向依赖上层。

高内聚、低耦合

  1. 头文件单向可达:每个模块只暴露 pubif 头文件,middle 与 driver 的头文件不进入 include 搜索路径,杜绝”顺手 include 到了内部实现”。
  2. HAL 是唯一硬件入口:module 层不允许出现厂商 SDK / BSP 的头文件 include 与私有 API 调用,依赖检查脚本对此单独设规则。
  3. 同层零耦合:module 与 service 的模块之间不允许互相 include;需要协作时通过 Service 编排或事件回调。
  4. 依赖检查进 CI:对每个源文件计算其所属层与被包含头文件所属层,与依赖白名单比对,违规即构建失败。
  5. 接口稳定性评审:pubif 头文件变更需架构评审,禁止暴露结构体内存布局以外的实现细节,禁止跨核共享结构体不做版本管理。
  6. 模块可独立测试:pubif 接口必须可在无真实硬件的情况下打桩测试;middle 层算法(ABI 解码、角度标定、峰值判定)必须可离线单元测试。

六、如何判断放置哪一层

问答判断法

新功能进来时,按下表逐条自问,命中即落层;全部不命中说明需求尚未澄清,应回到产品需求层面先厘清。

判断问题 归属层 Viper V2 举例
是不是厂商库、寄存器访问、启动代码、RTOS 本体? adapter / sdk BCM89158 寄存器定义、FreeRTOS 任务创建、时钟树初始化
是不是芯片自带的能力(外设采样、波形发生、捕获比较、电压温度监测、以太网收发)? adapter / hal HSADC 采样配置、AWG 波形写入、CAPCOM 捕获、PVT 读数、XGMAC 收发
是不是在封装操作系统能力? adapter / osif 任务、队列、信号量、事件组
是不是这块板子的资源映射(哪个引脚、哪个实例、哪路通道)? adapter / bsp 看门狗芯片接 GPIO_xx、电机驱动板接 UART0
是不是与业务和硬件都无关、可独立复用的基础能力? middleware CRC32、环形缓冲、点云 Payload 编码
是不是在封装一个产品外设模块能力? module 转镜电机、激光器调制、芯片状态监测、IMU 封装
是不是给多个业务提供公共能力(协议、存储、诊断、调度)? service 参数管理、UDP 上报、状态监测调度、交叉验证、系统保活与看门狗
是不是独立业务流程逻辑? application 工作模式切换、状态机迁移、探测区/盲区判定、命令执行流程

判断优先级与仲裁规则

如果一个模块”好像哪层都能放”,按此顺序判断:先看职责,再看依赖,最后看复用性。

看它本质在解决什么问题、依赖哪些层、未来是否需要复用。

  • 先用上层已有能力解决,就不要新建模块:例如点云时间戳,优先用 module/time,而不是在 module/net 里再加一套时间逻辑。
  • 同一能力只允许有一个归属:若发现同一功能在两层各有一份实现,说明分层已腐化,必须合并到唯一层。
  • 策略与机制分离:机制(怎么算角度、怎么收包、怎么写波形)放 module 与 service,策略(何时算、算完做什么)放 application。
  • 单一模块协议单独****封装:某个器件的特殊协议只允许出现在该器件对应的 module模块 的 middle 层中,不得在 application 中再次进行解析。

七、代码目录结构

viper_v2/
├── platform/ # 平台代码,随芯片与版本演进
│ ├── adapter/
│ │ ├── common/ # logger / assert / delay / cli
│ │ ├── hal/ # 芯片能力封装
│ │ │ ├── hsadc/ # 16ch 高速 ADC · FIR/抽取 · FFT · TXSLZR · NSU
│ │ │ ├── awg_dac/ # 任意波形 · 链式 · 斜坡调制
│ │ │ ├── hkadc/ hkdac/ # Housekeeping ADC / DAC
│ │ │ ├── timer/ pwm/ # CAPCOM 捕获比较 · PWM 输出
│ │ │ ├── pvt_mon/ # PVT 电压温度
│ │ │ ├── ethernet/ # 2.5G XGMAC · 描述符环 · 1588
│ │ │ └── i2c/ spi/ uart/ gpio/ gpadc
│ │ ├── osif/ # OS操作系统封装
│ │ ├── bsp/ # 引脚 / 实例映射 · 器件拓扑 · 中断与 DMA 分配
│ │ └── sdk/ # vendor_sdk / startup / linker
│ ├── middleware/
│ │ ├── micro_libs/ # 纯 C代码实现的轮子接口:fifo, list, time
│ │ ├── diagnosis/ # 内存监控,栈异常回溯
│ │ └── third_party/ # lwip / freertos
│ ├── module/
│ │ ├── acquisition/ # 采集链 → hal/hsadc + hal/dma
│ │ ├── laser/ # 激光器 → hal/awg_dac + hal/hkdac
│ │ ├── motor/ # 转镜电机 → hal/timer + hal/pwm
│ │ ├── chip_monitor/ # 芯片状态监测 → hal/pvt_mon + hal/hkadc
│ │ ├── net/ # 网络通信 → hal/ethernet
│ │ ├── time/ # 时间同步 → hal/ptp_ts
│ │ ├── storage/ # 非易失存储 → hal/flash
│ │ ├── imu/ # IMU单元
│ └── service/ # 可复用业务服务
├── application/ # 具体的业务实现
└── boards/
│ ├── config/ # 每一层级的配置、功能裁剪
│ ├── linker/ # 芯片链接文件
└── └── startup/ # 芯片启动文件

八、强制约束

以下约束对 MCU1 全部代码强制生效,由代码评审与 CI/CD 依赖检查共同保障;

违反任一条即视为架构违规,必须在合入前整改。

编程范式与分层约束

  • 面向接口编程,采用面向对象封装:每个模块、每个对外接口都封装为一个独立对象(结构体实例 + 一组操作函数),状态私有、行为公开;上层只持有句柄与接口指针,不感知内部实现,禁止用全局变量或裸函数跨层暴露数据。
  • 禁止跨层级调用:严格遵守第五章的层间依赖白名单。application 不得直接调用 hal;service 不得直接访问寄存器;module 不得越过 hal 触碰 SDK 私有 API;同层模块之间禁止互相 include 或直接调用。
  • 接口命名清晰、职责单一:接口函数名必须动词开头、语义完整、可自解释(如 md_motor_start、md_motor_get_angle),不得使用含糊缩写;一个函数只做一件事,参数与返回值需有明确的类型与错误码定义。
  • 每层接口函数统一前缀:各层对外函数按层加前缀,从命名上即可看出归属,杜绝同名混淆。

接口命名前缀约定

层级 函数命名前缀 示例
application app_ app_fsm_start、app_scan_ctrl_tick
service svc_ svc_config_get、svc_transport_send_pointcloud
module md_ md_motor_start、md_laser_load_waveform
middleware middle``_ middle``_ringbuf_push、middle``_crc32_calc
adapter / hal adapter_``hal_ adapter_``hal_hsadc_config、adapter_``h``al_awg_dac_write_waveform
adapter / osif adapter_``osif_ adapter_``osif_task_create、adapter_``o``sif_queue_send
adapter / common adapter_``com_ adapter_``com_log_printf、adapter_``c``om_assert

命名与目录约束

  1. 模块命名体现产品语义:module 目录与模块名必须体现产品能力(laser、motor、chip_monitor),禁止以芯片外设命名(禁止出现 hsadc 模块、awg 模块、xgmac 模块)。
  2. 头文件与源文件同名对应:模块按 module/<name>/ 组织,内部固定 pubif / middle / driver 三层目录;公开头文件命名 md_<name>_pubif.h。
  3. 常量、类型与变量命名:宏与常量用大写下划线(MD_MOTOR_MAX_RPM),类型用小写下划线加模块缩写(md_motor_cfg_t),局部变量与参数用短小写下划线(rpm、angle_deg)。
  4. 注释与文档:所有 pubif 接口须有函数级注释,说明功能、参数、返回值与错误码;模块 pubif 头文件须标注所属层与依赖的 HAL 能力,采用doxgen方式,示例:
/**
* @brief adapter适配层初始化
* @param [in]: none
* @details
* @return [类型]: int
* @retval [0]: 成功
* @retval [其他]: 失败
*/
int app_adapter_init(void)
{
int32_t ret = LIGHTIC_OK;

ret = app_adapter_unused_io_config();
if (false == app_adapter_is_init) {
ret |= adapter_init();
app_adapter_is_init = true;
}

return ret;
}