PMBus 与 CANBus 电源协议开发指南
更新时间: 2026/04/28
在Gitcode上查看源码

本文描述 power_mgmt 中与 PMBusCANBus 相关的软件结构:协议注册、PsuSlot / OnePower 与 Monitor 的职责,以及两套协议在实现上的事务布局与扩展方式。


1. 总体架构

1.1 三类构件

构件作用
协议实现模块继承或封装具体命令,实现 get_<属性名>set_<操作> 等,供槽位对象按属性名反射调用。
协议注册(init)physical_interface 映射到 { 对外协议名字符串, require(协议模块), monitor 路径或缺省 };亦可配置可选的 protocol[制造商][型号] 同名三元素表。
Monitor在通用 PsuSlot 之上封装周期巡检、DBus 订阅、健康位解析、黑匣子等上层逻辑;不同协议可选用不同 read_interval 与初始化流程。

电源槽位对象通过 get_dynamic_data(prop) 调用 self.protocol['get_' .. prop](self.protocol);新增对外属性时,协议类需实现同名 get_<prop>,并与 DAL / 设备树属性名一致。

1.2 核心入口文件

  • 协议注册:include/device_tree/adapters/power_mgmt/protocol/init.lua
  • 通用槽位逻辑:include/device_tree/adapters/PsuSlot.luaget_protocolfetch_power_supply_infoget_dynamic_dataget_black_box_data 等)
  • 通用 OnePower:include/device_tree/adapters/OnePower.lua
  • 单板覆写:include/device_tree/adapters/<与 CSR 同名目录>/PsuSlot.lua(及可选 OnePower.lua;可能替换 Monitor 加载方式或增加去抖)

1.3 协议解析规则

include/device_tree/adapters/power_mgmt/protocol/init.lua 导出 function(physical_interface, manufacturer, model)。解析顺序与源码一致:

  1. manufacturermodel 均非空,且 protocol[manufacturer] 存在、protocol[manufacturer][model] 存在时,使用该嵌套表项(三元素:protocol_namerequire 得到的模块、monitor 模块路径字符串)。
  2. 否则使用 protocol[physical_interface]。若该键不存在,table.unpack 会得到 nil,随后 req_protocol.new 会失败,因此 PhysicalInterface 必须在 protocol 表中注册

PsuSlot:fetch_power_supply_infoPsuSlot.lua)先执行 get_protocol(physical_interface);在 monitor:fetch_power_supply_info 刷新出 manufacturer / model 后,若二者齐全则再次 get_protocol(physical_interface, manufacturer, model),以便在已配置嵌套表时切换实现。

1.4 协议标准与物理层

1.4.1 PMBus

规范关系

  • PMBus(Power Management Bus)面向电源与配电器件的 管理、配置与遥测,电气与帧规则基于 SMBus(常用 SMBus 2.0 子集),并定义电源域 Command、数据格式、典型行为
  • SMBus 建立在 I²C(Inter-Integrated Circuit)电气约定之上:SCL / SDA 双线、多为主从结构,按 从机地址与读写方向 完成寄存器风格访问。

术语

术语含义
Command Code事务中的 命令字节,对应实现中 pmbus.cmd.*,表达读写字的语义(如输入电压、厂商标识)。
PAGE通过 PAGE 寄存器 切换逻辑页后再读 Command,多见于多路输出电源。
Byte / Word / BlockSMBus 读写字节 / 字 / 块(块首字节常为长度)。实现中对应 chip_bytereadchip_wordreadchip_blkreadget_dynamic_block
PEC(Packet Error Code)SMBus 包错误码(CRC-8),覆盖地址与数据域。实现使用 mc.crc8,嵌入 chip_read / chip_write
Linear11 / Linear16PMBus 线性数据格式(尾数与指数)。实现中 get_linear_11get_linear_16
Direct依赖 Coefficients(m、b、R 等) 换算工程量。实现中 get_directtwos_complement_to_original
STATUS_*状态类寄存器,如 INPUT、TEMPERATURE、VOUT、IOUT、CML,用于告警与健康位。

1.4.2 CANBus

规范关系

  • ISO 11898 规定 CANBus 物理与数据链路特性:介质上 广播 帧,靠 仲裁域(Identifier) 区分优先级与过滤;物理层常用 CAN_H / CAN_L 差分对,以差分电压表示显性/隐性位;MAC 子层为 帧格式、15 位 CRC、ACK;规范帧 payload 至多 8 字节(CAN 2.0 A/B)。
  • 标识符长度标准帧 11 bit扩展帧 29 bit(实现中扩展帧常量见 CAN_EXTENDED_FRAME,驱动侧常称 EFF)。
  • 应用层:在 CANBus 帧数据域(≤8 B) 之上定义 私有命令布局(命令字、节点地址、protocolsigid_and_errorSigid 等),实现见 canbus.luacan_data_info 与各 CMD_*;字段语义以 项目规格书 为准。

术语

术语含义
Frame / Data FieldMAC 帧及其 数据段(0–8 B)。实现中常以 8 B 为步长(FRAME_DATA_LENCANBUS_FRAME_DATA_SIZE)。
Arbitration ID仲裁与接收过滤依据;扩展帧下为 29 位。语义字段通过 bitstring 写入 cmdaddrprotocolframe_typesigid_and_error 等;与 Identifier 比特级映射由 驱动 / BMC 插件 完成。
Bit rate同一条 CAN 链路上各节点须用相同比特率(常见 250 kbps / 500 kbps)。波特率在 内核 CAN 驱动 / 设备配置侧设定,不在 power_mgmt 的 Lua 中修改。Lua 仅将应用字段 can_data_info:pack 成缓冲区,经 PsuChip:WriteRead 下发。
Sigid信号编号;与 sigid_and_error 低 12 位 对应,用于 CMD_QUERY(0x82) 等定点读。
批量命令(如 0x40 / 0x50)周期 多帧 payload 拼接;解析顺序由 get_batch_query_datacanbus_get_property_info 与规格书一致锁定。

1.4.3 PMBus 与 CANBus 实现对照

维度PMBus 实现路径CANBus 实现路径
介质I²C / SMBus(SCL/SDA)差分对 CAN_H / CAN_L(ISO 11898)
差错PEC(CRC-8) 与逻辑内校验控制器 CRC-15、ACK、错误帧;应用侧 sigid_and_error
寻址7-bit 从机地址 + Command节点地址、protocol、命令字 等与仲裁 / 数据布局协同
大块数据Block 与多块读多帧 8 B 拼接(电子标签、升级、黑匣子等)
源码入口pmbus.luachip_*get_linear_*canbus.luachip_write_readget_signal_dataget_batch_query_data

规格书维护上,PMBus 以 SMBus 事务与 Command 语义 为主;CANBus 以 波特率、扩展帧约定、命令表、Sigid、批量字段顺序 为主,分别落表到 pmbus.cmd / canbus.cmd


2. 设备树适配(power_mgmt 侧:选协议 + 读硬件)

本章说明 protocol/init.lua 注册OnePower.PhysicalInterfacePsuSlot / OnePower 适配之间的关系,以及协议对象与 Monitor 的典型分工。

2.1 Protocol 与 Monitor 注册

编辑 include/device_tree/adapters/power_mgmt/protocol/init.lua,在 protocol 表中增加一项:键名 = OnePower 的 PhysicalInterface 字符串(与 CSR/设备树约定一致); 为三元素表:

text
{ 对外 Protocol 名字符串, require(协议模块), monitor 模块路径字符串 }

第三项 monitor 可省略(部分条目仅有协议模块);若省略,通用 PsuSlot:get_protocol 会在无 monitor 时打告警日志,需确认机型是否允许。

映射关系示意:

表中已有示例(节选):

lua
-- Lines 18-21: include/device_tree/adapters/power_mgmt/protocol/init.lua
-- 通用电源pmbus协议
pmbus = { 'pmbus', require (base_content .. 'pmbus'), base_content .. 'monitor.pmbus' },
-- 通用电源canbus协议
canbus = { 'canbus', require (base_content .. 'canbus'), base_content .. 'monitor.canbus' },

厂商 + 型号映射(可选):按 init.lua 注释增加与顶表同形的三元组 protocol[制造商][型号] = { 协议名字符串, require(…), '…monitor…' }。当前仓库中 protocol 仅含 physical_interface 顶键;嵌套表需按机型手工添加。fetch_power_supply_info 第二轮 get_protocol 仅当首轮已用 physical_interface 拉取到 manufacturer、model 且嵌套表存在时才会切换实现。

2.2 PsuSlot / OnePower Adapter

类别路径
默认槽位逻辑include/device_tree/adapters/PsuSlot.lua
默认 OnePower 适配include/device_tree/adapters/OnePower.lua
单板差异include/device_tree/adapters/<与 CSR 同名目录>/ 下放置 PsuSlot.lua(必要时 OnePower.lua);框架 优先 使用该目录下的实现

单板解析优先级示意:

PsuSlot 适配中常需关注的方法(通用实现已部分串联 monitor,覆写时需保持行为一致或明确替代策略):

函数作用
fetch_power_supply_info注册协议并刷新 FRU / 动态信息(通用实现中会调用 monitor:fetch_power_supply_info
power_monitor_start启动周期轮询(经 monitor:power_monitor_start
psm_monitor_stop / stop_monitor_tasks停止监控(升级、黑匣子等场景需停轮询)

2.3 Protocol 模块职责

协议类(如 protocol/pmbus.luaprotocol/canbus.lua 及其变体)与 Monitor 分工可概括为:

能力典型实现位置
功率 / 状态 / FRU 查询protocol/pmbus.lua 等协议模块中的 get_*
黑匣子monitor:get_event_log 或协议 get_event_logPsuSlot:get_black_box_data 会优先 monitor)
主备、深度休眠set_power_modeset_sleep_mode 等(依机型在协议或槽位中暴露)
风扇转速set_psu_fan_speed_rpm
固件升级protocol/upgrade/pmbus_upgrade.lua / canbus_upgrade.lua 与协议对象上的 upgrade 相关入口

3. PMBus 相关代码结构

3.1 模块位置与变体

文件说明
protocol/pmbus.lua基类mc.class(),PMBus 命令字表 pmbus.cmd、CRC8、按字/块读写、Linear11/16、Direct、状态与健康、固件版本与升级入口等。
protocol/pmbus_qb900.lua电源砖等变体(如天工 AI 节点),常配合 monitor/pmbus_qb900.lua,功率是否计入总量等策略不同。
protocol/pmbus_eb1000_1.luaEB1000 等刀片/砖块差异(巡检等可能与通用不同)。
protocol/pmbus_PDC3KD5412_LC.luapmbus_PDC4000D12_LC.luapmbus_FP1420.lua特定型号:轮询间隔、命令支持、监控模块等。
protocol/powerconverter_pmbus.lua电源砖通用变体 + monitor/powerconverter_pmbus.lua
protocol/smc.lua经 SMC 取电信息,对外仍挂名 pmbus 类协议名。
protocol/upgrade/pmbus_upgrade.luaPMBus 在线升级状态机(DCDC/PFC/QB 等软体、与 FRU/软体信息结构配合)。

3.2 协议事务与字节布局

PMBus 在链路上按 SMBus / I²C 字节事务 组织,并无与 CAN 类似的固定 MAC 帧;一条事务由 Start / 从机地址与方向 / Command(PMBus 命令码)/ 数据字节 / PEC(CRC-8)/ Stop 等构成,具体比特时序由 PsuChip BlockIO 与控制器完成。实现侧关注的是 命令码 cmdSlotI2cAddr载荷以及 PEC 参与校验的字节序列

3.2.1 写路径与 PEC(chip_write

写操作将 cmddata 经由 Write 下发;PEC 按 SMBus 规则对 [写地址][Command][数据…] 计算 CRC-8,附加在待发数据末尾:

lua
-- Lines 211-216: include/device_tree/adapters/power_mgmt/protocol/pmbus.lua
function pmbus:chip_write(cmd, data)
    local check_buf = string.format('%s%s%s', string.char(self.slot_i2c_addr), string.char(cmd), data)
    local crc = crc8(check_buf)
    self.psu_chip:Write(ctx.new(), cmd, data .. string.pack('B', crc))
end

chip_bytewrite / chip_wordwrite / chip_blkwrite 仅改变 data 的字宽或 Block 首字节长度域,PEC 生成规则不变。

3.2.2 读路径与 PEC(chip_read

读操作请求长度为 lenRead;返回缓冲区 最后一字节为 PEC,其校验范围为 [写地址][Command][读地址][数据…(不含 PEC)]

lua
-- Lines 233-251: include/device_tree/adapters/power_mgmt/protocol/pmbus.lua
-- chip_read 读取指定长的数据
function pmbus:chip_read(cmd, len)
    local err_str = ''
    local value
    local check_buf
    for _ = 1, RETRY_TIMES, 1 do
        value = self.psu_chip:Read(ctx.get_context_or_default(), cmd, len)
        check_buf = string.format('%s%s%s%s',
            string.char(self.slot_i2c_addr),
            string.char(cmd),
            string.char(self.slot_i2c_addr | 0x01),
            value:sub(1, #value - 1))
        if value and check_data(value:sub(#value, #value):byte(), check_buf) == E_OK then
            return value
        end
        err_str = string.format('[power_mgmt][pmbus]read command(0x%02x) failed', cmd)
    end
    error(err_str)
end

读地址参与 check_buf 时为 slot_i2c_addr | 1。失败重试 RETRY_TIMES 次后 error

3.2.3 Word / Byte / Block 映射

API典型 len / 载荷有效数据
chip_wordreadRead(cmd, 3),返回 2 数据字节 + PEC低字节在前解析为 16 位字
chip_bytereadRead(cmd, 2),返回 1 数据字节 + PEC单字节
chip_blkreadRead(cmd, len + 2)去掉 首字节与末尾 PEC,返回中间 len 字节(见源码 sub(2, #value - 1)
block_read / get_dynamic_block先读 BYTE_CNT,再按 计数 + BYTE_CNT + CS 读满缓冲Block 首字节为 长度,末尾 PECget_dynamic_block 在校验通过后去掉 长度字节与 PEC,仅返回 数据块

3.2.4 Block Read 动态长度(get_dynamic_block

lua
-- Lines 287-299: include/device_tree/adapters/power_mgmt/protocol/pmbus.lua
function pmbus:get_dynamic_block(cmd)
    local value = self:block_read(cmd)
    local check_buf = string.format('%s%s%s%s', string.char(get_addr_wr(self.slot_i2c_addr)),
        string.char(cmd),
        string.char(get_addr_rd(self.slot_i2c_addr)),
        value:sub(1, #value - 1))
    -- value 返回布局由 pmbus.block_read 保证
    if check_data(value:sub(-1, -1):byte(), check_buf) == E_OK then
        return value:sub(2, #value - 1)
    end
    error(string.format('[power_mgmt][pmbus]read command(0x%02x) failed, data:[%s]', cmd, utils.to_hex(value)))
end

PEC 覆盖 写地址、命令、读地址及除 PEC 外的全部返回字节;成功时返回 value 的中间段(厂商字符串、序列号等 Block 应用场景)。

3.2.5 寄存器语义与数值解码

  • 命令集合pmbus.cmd 与各电源规格书中的 Command Code 一一对应;扩展时同步维护 pmbus.read_cmd(若用于巡检列表)。
  • Linear11 / Linear16 / Direct:见 get_linear_11get_linear_16get_direct;与 PEC 布局无关,属于 寄存器返回值语义层Linear-11VOUT / LINEAR-16 的位布局与换算见下文 §3.2.6、§3.2.7(写法与 §4.2 CANBus 数据帧格式 类似:先说明层级与字段,再给出布局与实现入口)。

3.2.6 Linear-11 数据格式

§4.2 将 CAN 帧分为 链路层 MAC应用层 PDU 类似,PMBus 在 字节事务(§3.2.1~3.2.4) 之上,还有 数据字(Data Word) 的语义编码:Linear-11一个 16 位字 表示带数量级的模拟量,典型由 chip_wordread 读回(低字节在前,与 PMBus Word 事务一致)。

位域布局(16 位无符号机器字 raw_word 中的划分;解码时按有符号补码解释 YN):

位域宽度含义
高 5 位(bit15–11)5 bit指数 N:二进制 有符号整数,补码表示
低 11 位(bit10–0)11 bit尾数 Y:二进制 有符号整数,补码表示

与真实物理量之间的关系(规格书常用写法):

X = Y · 2^N

  • X:换算后的物理量真值(量纲依 Command Code 而定,如电压、电流)。
  • Y:低 11 位按补码解释的整数尾数。
  • N:高 5 位按补码解释的整数指数。

本仓库在 pmbus:get_linear_11 中对 raw_word 拆出尾数与指数并完成移位运算;对部分 读电流 命令另有 10 mA 量级精度处理,详见 pmbus.lua 实现与注释。

lua
-- Lines 301-312: include/device_tree/adapters/power_mgmt/protocol/pmbus.lua
function pmbus:get_linear_11(cmd)
    local raw_word = self:chip_wordread(cmd)
    local value = raw_word & 0x7FF
    local bit = ((raw_word >> 11) & 0x1f)
    if raw_word & 0x8000 > 0 then
        bit = (255 - (bit | 0xE0)) + 1
        -- 电流较小(0~1 A)时,以 A 为单位传值会导致精度丢失;
        -- 计算电流时,将读数先放大,以 10 mA 为单位传值以保留精度;
        return self:is_pmbus_cmd_read_i(cmd) and ((value * PS_I_SCALING_FACTOR) >> bit) or (value >> bit)
    end
    return value << bit
end

3.2.7 VOUT(LINEAR-16)数据格式

输出电压相关命令(如 READ_VOUT 等)在规格书中常采用 LINEAR-16:由 16 位无符号整数 V指数 N 共同决定电压,与 Linear-11 的「Y+N 同字」布局不同,V 为无符号N 通常由 VOUT_MODE 等寄存器给出

前提:电源需支持 VOUT_MODE 命令(本仓库命令常量见 pmbus.cmd.VOUT_MODE),输出电压数据格式须与 VOUT_MODE 所配置的编码方式一致。

换算关系(输出电压,单位:伏特 V):

Voltage = V · 2^N

  • Voltage:输出电压数值。
  • V16 位无符号整数(对 READ_VOUT 返回的 Data Word 按无符号解析)。
  • N5 位二进制有符号整数(补码);具体取值由 VOUT_MODEModeVID 等字段解码得到。文档或机型说明中常见 N = -12 作为某一 VID 模式下的典型指数;若与具体电源数据手册或寄存器定义不一致,以手册及现场 VOUT_MODE 读值为准

解码入口:pmbus:get_linear_16(cmd, vout_mode),其中 vout_mode 一般为读 VOUT_MODE 得到的字节经解析后的模式量(见 pmbus.lua 中与 VOUT_EXPONENT 相关的指数计算)。

lua
-- Lines 314-322: include/device_tree/adapters/power_mgmt/protocol/pmbus.lua
function pmbus:get_linear_16(cmd, vout_mode)
    local exponent = (1 << VOUT_EXPONENT) - vout_mode
    -- bit0-4 为 exponent,需要判断正负数
    if (vout_mode & 0x10) ~= 0 then
        return self:chip_wordread(cmd) / (2 ^ exponent)
    end

    return self:chip_wordread(cmd) << exponent
end

3.3 Monitor(monitor/pmbus.lua 等)

  • PsuSlotclass 包装,增加 fetch_power_supply_infopower_monitor_start、远程功率上报(PluginRequest / DBus)、时间同步、健康事件合并等。
  • 读周期 等参数可与通用 CANBus Monitor 不同;定制机型使用独立 monitor 模块并在 init.lua 第三元指定路径。

3.4 升级

  • 业务侧 src/lualib/power_upgrade.luaCOMPONENT_IDEXProtocol 字段 pmbus → 0canbus → 2,与 component_idexUpgradeSupported 共同用于升级对象筛选(参见该文件中的升级入口逻辑)。
  • 具体打包、擦写、重启时序在 upgrade/pmbus_upgrade.lua,并与 upgrade/fw_def.lua、FRU 中软体描述结构配合。

4. CANBus 相关代码结构

4.1 模块位置与变体

文件说明
protocol/canbus.lua基类:CANBus 协议栈;canbus.cmdcanbus.protocol(帧长、批量长度、黑匣子参数);chip_write_readget_signal_data(按 sigid);get_batch_query_data(0x40);电子标签与升级帧等。
protocol/canbus_tpsu.lua继承 canbus:双路 CANBus 物理接口(PsuChip + PsuBackupChip)、主备通道切换、canbus.tpsu_cmd、黑匣子/批量长度等对 protocol 表的覆盖。
protocol/canbus_pah.lua继承 canbus:PAH 机型差异(通道、命令选择等)。
protocol/upgrade/canbus_upgrade.luaCANBus 在线升级:读 bin、CRC16、start_canbus_download、分帧与滑窗确认(与 canbus.cmd 中 D3–D6 类命令配合)。

4.2 数据帧格式

4.2.1 CAN 2.0 MAC 帧(链路层)

电源侧 CANBus 物理与 MAC 遵循 ISO 11898CAN 2.0 A/B。主机与电源之间交换的是标准 数据帧(不含远程帧场景时):含 仲裁域(Identifier)控制域数据长度码 DLC数据域 Data Field(0~8 B)CRC(15 bit)ACK帧结束 等。有效载荷至多 8 字节;波特率、采样点、扩展帧 29 bit Identifier 等在驱动与收发器配置,Lua 栈不解析比特时序。

4.2.2 应用层 PDU:can_data_info

与电源通信的 语义字段mc.bitstring 打包为二进制缓冲区,经 PsuChip:WriteRead 下发;驱动将该缓冲区映射到 CAN 帧 Identifier / Data Field 的具体拆分方式以实现为准。定义见 canbus.lua

lua
-- Lines 122-132: include/device_tree/adapters/power_mgmt/protocol/canbus.lua
local can_data_info = bs.new([[<<
    cnt:1,
    reserve:6,
    ms:1,
    cmd:8,
    addr:7,
    protocol:6,
    frame_type:3,
    sigid_and_error:16/big,
    data/string
>>]])

字段按 bitstring 声明顺序 串行打包;sigid_and_error16 bit、大端(/bigget_signal_data 中取 (sigid_and_error & 0xf000) >> 12 为应答错误码,sigid_and_error & 0x0fff 为 Sigid。

字段宽度说明
cnt1 bit计数位
reserve6 bit单播时常为槽位相关保留(如 slot_addr);canbus_broadcast_cmd 中为 0
ms1 bitBIT_M_CNT = 1(主发)、BIT_S_CNT = 0(从侧)
cmd8 bit命令字节,对应 canbus.cmd(如 0x400x500x82
addr7 bit节点地址;广播时为 0
protocol6 bitCAN_POWER_PROTOCOL = 0x3f
frame_type3 bitCAN_EXTENDED_FRAME = 4(扩展帧路径)
sigid_and_error16 bit应答错误码(bit12–15)与 Sigid(bit0–11)
data变长can_data_info 尾部字节串;如 CMD_QUERY 路径使用 6 B 填充(见 can_send_get_data_info)。FRAME_DATA_LEN = 8 在同文件用于 升级分包、批量切片步长 等,与单次 pack 总长无固定相等关系

同源常量:CAN_POWER_PROTOCOLCAN_EXTENDED_FRAMEFRAME_DATA_LEN

4.2.3 批量应答拆解:can_frame_info / can_frame_data

0x40 等批量命令返回的是 较长的 canbus_data;外层用 can_frame_info 解出 canbus_data,再按 CANBUS_FRAME_DATA_SIZE(8) 切成多段,每段用 can_frame_data 解析:

lua
-- Lines 134-148: include/device_tree/adapters/power_mgmt/protocol/canbus.lua
local can_frame_info = bs.new([[<<
    cnt:1,
    reserve:6,
    ms:1,
    cmd:8,
    addr:7,
    protocol:6,
    frame_type:3,
    canbus_data/string
>>]])

local can_frame_data = bs.new([[<<
    sigid_and_error:16/big,
    data/string
>>]])

即:批量路径下,每 8 B 对应一段 sigid_and_error + data 的电源侧约定布局,与 4.2.2单帧 Sigid 语义 一致。

4.2.4 典型用法(与入口函数对应)

  • 单点查询CMD_QUERY0x82),get_signal_data 中校验 (sigid_and_error & 0xf000) >> 12 == 0 后使用 data
  • 周期批量CMD_BATCH_QUERY_PERIOD_DATA0x40),get_batch_query_data 使用 can_frame_info / can_frame_data 按 8 B 切片。
  • 广播canbus_broadcast_cmdaddr = 0reserve = 0,其余字段按广播命令约定填充。

4.3 数值与属性映射

  • 功率/电流等常通过 uint32 + 系数 1024CANBUS_POWER_COFFICIENT)或 canbus:get_batch_query_data 解析链路映射到 DAL 属性;扩展 0x40 批量顺序 时,应修改 canbus:canbus_get_property_infosigid → 属性名、类型、缩放 的表,并保持与电源规格书中顺序一致(注释中已说明追加建议)。

4.4 Monitor(monitor/canbus.luamonitor/canbus_tpsu.luamonitor/canbus_pah.lua

  • 初始化时往往先 update_elabel_info / refresh_basic_info(CANBus 侧电子标签与版本路径与 PMBus 不同)。
  • 健康与告警:例如将 AlarmStatus 位域映射到统一 health_event(见 update_health_event)。
  • TPSU:read_interval、通道切换与升级通道逻辑与基类不同,开发时勿混用 PsuChip 句柄。

5. 开发指导:新增或修改协议时怎么做

5.1 通用步骤(PMBus / CANBus 共用)

  1. protocol/init.lua 中为 OnePower.PhysicalInterface 增加表项,保证 protocol[physical_interface] 存在(否则首轮 get_protocol 即失败)。
  2. 确定键名与模块映射
    • { 'pmbus' 或 'canbus', require('…协议模块'), 'device_tree.adapters.power_mgmt.monitor.xxx' }
    • Monitor 路径可省略;省略时 PsuSlot:get_protocol 仍会建立 protocol 对象,但 log:warn 提示无 monitor。
  3. 实现协议模块
    • 使用 mc.class();构造函数签名与基类一致:function ctor(self, psu_slot, protocol_name),并从 psu_slotPsuChipSlotI2cAddr/SlotNumber 等。
    • 为每个对外属性实现 get_<属性名>,命名与 DAL/上游一致。
  4. 必要时新增 Monitorreturn function(obj) local psu_slot = class(obj) … end,在 ctor(self, protocol) 中保存 self.protocol
  5. 单元测试test/unit/test_pmbus.luaprotocol/test_canbus_**_monitor.lua 等;新增命令或属性时补充 Chip mock 与断言。

5.2 仅 PMBus

  • 优先 继承或复制 pmbus.lua 的结构,避免重复实现 CRC 与 Linear 解码。
  • 新增命令字:在子模块或基类 pmbus.cmd 中增加常量,并在 read_cmd 或业务路径中引用。
  • Block 读长度:注意 BUFFER_MAX_LENblock_read 长度校验,避免 OOB。
  • 电流极小场景:基类已对部分 READ_I 命令做 10 mA 精度 相关处理,修改时勿破坏该分支。

5.3 仅 CANBus

  • 优先 class(canbus_base) 继承 canbus.lua,在子类 ctor 中覆盖 canbus.protocol 各长度常量与黑匣子参数(参考 canbus_tpsu.lua)。
  • 新增 sigid:在 canbus.cmd 或子模块 tpsu_cmd 增加常量;实现 get_xxx 时复用 get_signal_data(sigid)
  • 扩展 0x40 批量:同时更新 canbus_get_property_info 与解析循环,避免属性错位。
  • 双路 CANBus 机型:处理 主备芯片chip_write_read 使用的 psu_chip(TPSU 经 canbus_chip 切换)。

5.4 升级与制造

  • PMBus:upgrade/pmbus_upgrade.luapower_upgrade.lua、制造侧 manufacture/manufacture_app.lua 可能对协议名敏感,新增变体时需确认 组件 ID / 协议名字符串 与既有流程兼容。
  • CANBus:canbus_upgrade.lua 中帧长 8 字节crc16 与文件读取路径需与固件打包约定一致。

5.5 调试建议

  • 日志:调高 mc.logging 级别;PMBus chip_read 在重试耗尽后 error;CANBus chip_write_read 失败返回 nil 并写日志。
  • 集成:test/integration/test_power_mgmt.luatest_power_mgmt_rpc.lua
  • 行为变更以 CHANGELOG.md 为准(延时、防抖、版本读取时机等)。

6. 关键路径索引

类别路径
协议注册include/device_tree/adapters/power_mgmt/protocol/init.lua
PMBus 基类include/device_tree/adapters/power_mgmt/protocol/pmbus.lua
CANBus 基类include/device_tree/adapters/power_mgmt/protocol/canbus.lua
CAN TPSUinclude/device_tree/adapters/power_mgmt/protocol/canbus_tpsu.lua
CAN PAHinclude/device_tree/adapters/power_mgmt/protocol/canbus_pah.lua
Monitor 目录include/device_tree/adapters/power_mgmt/protocol/monitor/
PMBus 升级include/device_tree/adapters/power_mgmt/protocol/upgrade/pmbus_upgrade.lua
CANBus 升级include/device_tree/adapters/power_mgmt/protocol/upgrade/canbus_upgrade.lua
槽位(默认)include/device_tree/adapters/PsuSlot.lua
OnePower(默认)include/device_tree/adapters/OnePower.lua
升级回调src/lualib/power_upgrade.lua

7. 补充

  • 新机型在 init.lua 注册后,优先通过 子类 扩展 pmbus_* / canbus_*,减少重复实现。
  • 设备树Adapter类成员变量应在ctor中初始化,否则运行期可能为nil。