Files
H100PowerManger/src/pCCU/protocol/CanBms.cpp
T
zjk 5b8f0b1421 锂电池改用 BCU-MBMS CAN 协议按节点解析 + bcu_node 解析数据落库 + 板卡对时脚本
- pCCU/CanBms:按《04KT38电池BCU-MBMS通信(CAN)定义》重写解码,
  BmsStatus 单状态模型改为 BcuNodeStatus 多节点模型(0x10XX00YY,
  节点地址 01~36h),支持 0x0000 电压/电流/SOC/告警码、0x0001 单体
  电压、0x0002 单体温度、0x0003 继电器、0x0006 绝缘/端口电压、
  0x0010 告警位(附录1 中文码表)六类报文
- 平均单体温度偏移修正:协议文档 BYTE5 写"偏移0"有误,实测固件与
  最高/最低一致均带 -40℃ 偏移(实车 0x10020002 原始 68/69 减 40 后
  为 28/29℃,落在最低28~最高30区间内,按文档直读则超出物理范围)
- pCCU/DbStore:新增 bcu_node 解析数据表,锂电池 BMS 报文每帧落一行
  节点合成状态(原 comm_log 仅原始帧,BMS/CAN 帧此前不落 pCCU 库),
  buildReport 增加 BMS 记录数
- 快照/网页:BCU 按节点分组展示(告警位解析中文含义、数据 age),
  PM 状态报文锂电池/应急电池卡片
- pPowerManger:新增 iport 本地输入端口配置(UDP bind 延迟到
  OnStartUp 读取配置后执行,保证 iport/ccuhost/ccuport 生效),
  各 mission 文件补充注释
- test:CAN BCU 解码用例按新协议/新偏移更新(实车抓包 + 文档示例值),
  133 项全部通过
- docs:删除旧 BMS 协议(xlsx/20230324docx),归档 04KT38 BCU-MBMS
  CAN 定义、配电控制器通信协议 20260824、配电系统 CAN 通讯协议
- scripts:新增 sync-board-time.sh,223 板卡(RK3588)时间校正
  (本机为基准 + RTT 折半补偿对时,尽力写 RTC,支持 status/--time)
2026-09-01 12:58:33 +08:00

160 lines
5.9 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "CanBms.h"
namespace ccu {
namespace {
// 大端 u16
inline uint16_t rdU16BE(const uint8_t* p) {
return static_cast<uint16_t>((static_cast<uint16_t>(p[0]) << 8) | p[1]);
}
// 大端 16 位有符号整数(补码)
inline int16_t rdS16BE(const uint8_t* p) {
return static_cast<int16_t>(rdU16BE(p));
}
// 有符号 8 位(温度)
inline int8_t rdS8(uint8_t b) { return static_cast<int8_t>(b); }
// 设置功能码已收位
inline void markRx(BcuNodeStatus& n, uint8_t func) {
n.rxMask |= (1u << (func & 31));
}
} // namespace
//============================================================================
// 附录1:0x10XX0010 告警位定义(04KT38电池BCU-MBMS通信(CAN)定义.docx)
//============================================================================
const BcuAlarmDesc kBcuAlarmTable[] = {
// byte0:2 级告警
{0, 0, "BCU绝缘2级"},
{0, 1, "BCU最高温度过高2级"},
{0, 2, "BCU最低温度过低2级"},
{0, 3, "BCU单体电压不均衡2级"},
{0, 4, "BCU单体温度不均衡2级"},
{0, 5, "BCU放电过流2级"},
{0, 6, "BCU单体电压过高2级"},
{0, 7, "BCU单体电压过低2级"},
// byte1
{1, 0, "BCU总电压过高2级"},
{1, 1, "BCU总电压过低2级"},
{1, 2, "BCU烟雾报警1级"},
{1, 3, "烟雾报警器不在线"},
{1, 4, "烟雾报警器上报自身故障"},
{1, 5, "BCU单包绝缘3级"},
{1, 6, "BCU最高温度过高3级"},
{1, 7, "BCU最低温度过低3级"},
// byte2
{2, 0, "单体电压不均衡3级"},
{2, 1, "单体温度不均衡3级"},
{2, 2, "单包放电过流3级"},
{2, 3, "BCU单体电压过高3级"},
{2, 4, "BCU单体电压过低3级"},
{2, 5, "BCU总电压过高3级"},
{2, 6, "BCU总电压过低3级"},
{2, 7, "BCU单体温度传感器检测故障"},
// byte3
{3, 0, "BCU正极继电器失效"},
{3, 1, "BCU负极继电器失效"},
{3, 3, "单包BMS内部通讯故障"},
{3, 4, "BCU电流传感器故障"},
{3, 5, "BCU电压传感器故障"},
{3, 7, "BCU高压回路连接异常"},
// byte4
{4, 1, "烟雾报警2级"},
{4, 4, "烟雾报警3级"},
{4, 6, "烟雾报警4级"},
{4, 7, "回馈电流过大2级"},
// byte5
{5, 0, "回馈电流过大3级"},
{5, 1, "充电电流过大3级"},
{0xFF, 0, nullptr}, // 表尾
};
int bcuAlarmTexts(const BcuNodeStatus& node, const char* texts[], int cap) {
if (!texts || cap <= 0) return 0;
int count = 0;
for (int i = 0; kBcuAlarmTable[i].text; ++i) {
const BcuAlarmDesc& d = kBcuAlarmTable[i];
if (d.byteIdx < sizeof(node.alarmBits) &&
(node.alarmBits[d.byteIdx] >> d.bitIdx) & 0x01) {
if (count >= cap) break;
texts[count++] = d.text;
}
}
return count;
}
bool decodeCanBcuFrame(uint32_t canId, const uint8_t* data, int dlc,
uint8_t& nodeAddr, BcuNodeStatus& node) {
if (!data || dlc <= 0) return false;
uint8_t addr = bcuAddrOf(canId);
if (!addr || !isCanBcuId(canId)) return false;
nodeAddr = addr;
// 缩放用除法(而非乘 0.1/0.001),保证结果与十进制字面量严格一致。
switch (bcuFuncOf(canId)) {
case BCU_FUNC_BASE: // 0x10XX0000:电压 / 电流 / SOC / 告警码 / 自检
if (dlc >= 8) {
node.totalVoltage = rdU16BE(data + 0) / 10.0; // 0.1V
node.current = rdS16BE(data + 2) / 10.0 - 600.0; // 0.1A,偏移-600A
node.soc = rdU16BE(data + 4) / 10.0; // 0.1%
node.alarmCode = data[6];
node.selfCheck = data[7];
markRx(node, BCU_FUNC_BASE);
}
break;
case BCU_FUNC_CELL_V: // 0x10XX0001:最高/最低/平均单体电压
if (dlc >= 2) node.maxCellVoltage = rdU16BE(data + 0) / 1000.0; // 1mV
if (dlc >= 3) node.maxCellVoltageNo = data[2];
if (dlc >= 5) node.minCellVoltage = rdU16BE(data + 3) / 1000.0; // 1mV
if (dlc >= 6) node.minCellVoltageNo = data[5];
if (dlc >= 8) node.avgCellVoltage = rdU16BE(data + 6) / 1000.0; // 1mV
markRx(node, BCU_FUNC_CELL_V);
break;
case BCU_FUNC_CELL_T: // 0x10XX0002:最高/最低/平均单体温度
if (dlc >= 1) node.maxCellTemp = rdS8(data[0]) - 40.0; // 偏移-40℃
if (dlc >= 2) node.maxCellTempNo = data[1];
if (dlc >= 3) node.minCellTemp = rdS8(data[2]) - 40.0; // 偏移-40℃
if (dlc >= 4) node.minCellTempNo = data[3];
if (dlc >= 5) node.avgCellTemp = rdS8(data[4]) - 40.0; // 偏移-40℃(文档写偏移0,
// 但实测固件与最高/最低一致均带-40偏移,见0x10020002:
// 原始68/69减40后为28/29℃,落在最低28~最高30区间内)
markRx(node, BCU_FUNC_CELL_T);
break;
case BCU_FUNC_RELAY: // 0x10XX0003:正/负极继电器状态
if (dlc >= 1) node.posRelay = data[0];
if (dlc >= 2) node.negRelay = data[1];
markRx(node, BCU_FUNC_RELAY);
break;
case BCU_FUNC_ISU: // 0x10XX0006:绝缘阻值 / 端口电压
if (dlc >= 2) node.posInsulationKohm = rdU16BE(data + 0); // 1kΩ
if (dlc >= 4) node.negInsulationKohm = rdU16BE(data + 2); // 1kΩ
if (dlc >= 6) node.portVoltage = rdU16BE(data + 4) / 10.0; // 0.1V
if (dlc >= 8) node.posRelayOuterVoltage = rdU16BE(data + 6) / 10.0; // 0.1V
markRx(node, BCU_FUNC_ISU);
break;
case BCU_FUNC_ALARM: // 0x10XX0010:告警位(附录1)
for (int i = 0; i < 6 && i < dlc; ++i) node.alarmBits[i] = data[i];
if (dlc >= 7) node.alarmExtraByte6 = data[6];
if (dlc >= 8) node.alarmExtraByte7 = data[7];
markRx(node, BCU_FUNC_ALARM);
break;
default: // Reserve(0x10XX0004/0005 等)不解析
return false;
}
return true;
}
} // namespace ccu