- 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)
160 lines
5.9 KiB
C++
160 lines
5.9 KiB
C++
#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
|