Files
H100PowerManger/src/pCCU/protocol/CanBms.h
T
zjk 90caacf9a2 pCCU 锂电池页新增 BCU 断路器控制(0x10XX81FF 经 pCanBridge 下行 CAN 总线)
- CanBms: bcuCtrlCanId(0x10XX81FF) + buildBcuRelayCtrlData(02 00 总正 总负 FF*4)
- SystemData: BcuCtrlCmd 下行队列(Web线程入队->Iterate/MOOS线程出队Notify) + 下发统计
- CCU: /api/bcu_ctrl(addr/action 或 pos/neg, 校验地址01h~36h) + Iterate 经 MOOS CAN_TX_0x* 下发
- pCanBridge 变双向透传: 订阅 CAN_TX_0x*,CanEndpoint::sendFrame(13字节CANET帧,TCP写,互斥保护)
- 网页: 每BCU节点断路器闭合/断开按钮(confirm确认) + 下发统计卡片
- 测试: pccuTest 控制帧编码用例(183项);集成测试新增假CANET服务器验证完整下行链路(闭合/断开/非法地址)
2026-09-01 15:23:30 +08:00

176 lines
7.8 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.
#ifndef PCCU_CAN_BMS_H
#define PCCU_CAN_BMS_H
#include <cstdint>
namespace ccu {
//============================================================================
// 锂电池 BCU-MBMS CAN 协议(docs/04KT38电池BCU-MBMS通信(CAN)定义.docx)
//
// 数据来源:pCanBridge 透传的 MOOS 消息
// 变量名 CAN_0x%08X = CAN ID(扩展帧),m_sVal = 二进制数据域,
// m_dfVal2 = 原始帧信息字节。本模块只负责按报文 ID 解析数据域字段。
//
// 【节点地址】一个 MBMS 下最多挂 54 个 BCU,CAN ID 中间的 XX(01h~36h)
// 为 BCU 节点地址编号,其余位固定:
// 0x10XX00YY BCU 主动上报消息(YY=功能码 00/01/02/03/06/10)
// 0x10XX81FF MBMS 下发指令(继电器控制,经 MOOS CAN_TX_0x* 下行)
//
// 【下发指令 0x10XX81FF】数据域 8 字节(BYTE1~8 = byte0~7):
// byte0 = 0x02(索引号) byte1 = 0x00(索引号)
// byte2 = 总正继电器控制(1 闭合 / 0 断开)
// byte3 = 总负继电器控制(1 闭合 / 0 断开)
// byte4~7 = Reserve(填充 0xFF)
//
// 【上报报文】均为扩展帧,字段大端,BYTE1~8 对应数据域 byte0~7:
// 0x10XX0000 (200ms) 累加电压 u16@0 ÷10 V
// 回路电流 s16@2 ÷10-600 A(偏移 -600A,放电为正)
// SOC u16@4 ÷10 %
// 告警码 u8 @6(循环上报,协议未附码表,原样显示)
// 自检状态 u8 @7
// 0x10XX0001 (200ms) 最高单体电压 u16@0 mV,编号 u8@2
// 最低单体电压 u16@3 mV,编号 u8@5
// 单体平均电压 u16@6 mV
// 0x10XX0002 (1000ms) 最高单体温度 s8@0(偏移 -40℃),编号 u8@1
// 最低单体温度 s8@2(偏移 -40℃),编号 u8@3
// 单体平均温度 s8@4(偏移 -40℃,协议文档写"偏移0"
// 有误:实测原始值减 40 后才落在最低~最高区间内)
// 0x10XX0003 (200ms) 正极继电器状态 u8@0(1 闭合 / 0 断开)
// 负极继电器状态 u8@1(1 闭合 / 0 断开)
// 0x10XX0006 (200ms) 正极绝缘阻抗 u16@0 kΩ
// 负极绝缘阻抗 u16@2 kΩ
// 正负极端口电压 u16@4 ÷10 V
// 正极继电器外侧电压 u16@6 ÷10 V
// 0x10XX0010 (200ms) byte0~5 告警位(bit 定义见附录1,
// kBcuAlarmTable,可经 bcuAlarmTexts() 取告警描述)
// 0x10XX0004/0005 Reserve(调试预留,不解析)
//============================================================================
// BCU 节点地址范围:01h~36h(1~54)
static const int kBcuAddrMin = 0x01;
static const int kBcuAddrMax = 0x36;
static const int kBcuNodeCount = kBcuAddrMax - kBcuAddrMin + 1;
// BCU 上报报文功能码(CAN ID 低字节 YY)
enum BcuFunc : uint8_t {
BCU_FUNC_BASE = 0x00, // 0x10XX0000 电压 / 电流 / SOC / 告警码 / 自检
BCU_FUNC_CELL_V = 0x01, // 0x10XX0001 单体电压
BCU_FUNC_CELL_T = 0x02, // 0x10XX0002 单体温度
BCU_FUNC_RELAY = 0x03, // 0x10XX0003 继电器状态
BCU_FUNC_ISU = 0x06, // 0x10XX0006 绝缘阻值 / 端口电压
BCU_FUNC_ALARM = 0x10, // 0x10XX0010 告警位(附录1)
};
// 从 CAN ID 提取 BCU 节点地址(0x10XX00YY -> XX);非 BCU 报文格式返回 0
inline uint8_t bcuAddrOf(uint32_t canId) {
if ((canId & 0xFF00FF00u) != 0x10000000u) return 0;
uint8_t addr = static_cast<uint8_t>((canId >> 16) & 0xFF);
return (addr >= kBcuAddrMin && addr <= kBcuAddrMax) ? addr : 0;
}
// 从 CAN ID 提取功能码(0x10XX00YY -> YY)
inline uint8_t bcuFuncOf(uint32_t canId) {
return static_cast<uint8_t>(canId & 0xFF);
}
//--------------------------------------------------------------------------
// BCU 断路器(总正/总负继电器)下行控制
//--------------------------------------------------------------------------
// BCU 节点继电器控制指令 CAN ID(0x10XX81FF,XX=节点地址 01h~36h)
inline uint32_t bcuCtrlCanId(uint8_t addr) {
return 0x10000000u | (static_cast<uint32_t>(addr) << 16) | 0x81FFu;
}
// 编码继电器控制数据域(8 字节,经 MOOS CAN_TX_0x%08X 下发,pCanBridge 发送):
// [0]=0x02 [1]=0x00 [2]=总正(1闭合/0断开) [3]=总负 [4..7]=0xFF
// pos/neg 非 0 值均视为闭合(1)。
inline void buildBcuRelayCtrlData(int pos, int neg, uint8_t out[8]) {
out[0] = 0x02;
out[1] = 0x00;
out[2] = pos ? 0x01 : 0x00;
out[3] = neg ? 0x01 : 0x00;
out[4] = 0xFF;
out[5] = 0xFF;
out[6] = 0xFF;
out[7] = 0xFF;
}
// 是否为 BCU 主动上报报文 ID(0x10XX00YY,YY 为已定义功能码)
inline bool isCanBcuId(uint32_t canId) {
uint8_t addr = bcuAddrOf(canId);
if (!addr) return false;
switch (bcuFuncOf(canId)) {
case BCU_FUNC_BASE:
case BCU_FUNC_CELL_V:
case BCU_FUNC_CELL_T:
case BCU_FUNC_RELAY:
case BCU_FUNC_ISU:
case BCU_FUNC_ALARM:
return true;
default:
return false;
}
}
// 单个 BCU 节点最新状态(各报文字段按功能码部分更新,最终合成完整快照)
struct BcuNodeStatus {
// 0x10XX0000 基本信息
double totalVoltage = 0; // 累加电压 V
double current = 0; // 回路电流 A(放电为正,偏移 -600A 已折算)
double soc = 0; // SOC %
int alarmCode = 0; // 告警码(原始值,协议未附码表)
int selfCheck = 0; // 自检状态(原始值)
// 0x10XX0001 单体电压
double maxCellVoltage = 0; // 最高单体电压 V
int maxCellVoltageNo = 0; // 最高单体电压编号
double minCellVoltage = 0; // 最低单体电压 V
int minCellVoltageNo = 0; // 最低单体电压编号
double avgCellVoltage = 0; // 单体平均电压 V
// 0x10XX0002 单体温度
double maxCellTemp = 0; // 最高单体温度 ℃
int maxCellTempNo = 0; // 最高单体温度编号
double minCellTemp = 0; // 最低单体温度 ℃
int minCellTempNo = 0; // 最低单体温度编号
double avgCellTemp = 0; // 单体平均温度 ℃
// 0x10XX0003 继电器(1 闭合 / 0 断开)
int posRelay = 0;
int negRelay = 0;
// 0x10XX0006 绝缘 / 端口电压
double posInsulationKohm = 0; // 正极绝缘阻抗 kΩ
double negInsulationKohm = 0; // 负极绝缘阻抗 kΩ
double portVoltage = 0; // 正负极端口电压 V
double posRelayOuterVoltage = 0; // 正极继电器外侧电压 V
// 0x10XX0010 告警位(附录1,byte0~5)
uint8_t alarmBits[6] = {0, 0, 0, 0, 0, 0};
// 0x10XX0010 附加字节(协议未详列,原样保留)
int alarmExtraByte6 = 0;
int alarmExtraByte7 = 0;
// 元数据
uint32_t rxMask = 0; // 收到过的功能码位图(bit = BcuFunc)
double lastRxTime = 0; // 最近收到该节点任一报文的时刻(MOOSTime)
bool valid = false; // 是否收到过该节点报文
};
// 解析一帧 CAN 数据域;命中 BCU 上报报文返回 true,nodeAddr 为节点地址(1~54),
// 字段按功能码部分更新合并进 node。data/dlc 非法或非 BCU 报文返回 false。
bool decodeCanBcuFrame(uint32_t canId, const uint8_t* data, int dlc,
uint8_t& nodeAddr, BcuNodeStatus& node);
// 附录1:0x10XX0010 告警位定义表(byteIdx/bitIdx -> 告警描述),表尾以 byteIdx=0xFF 结束
struct BcuAlarmDesc {
uint8_t byteIdx;
uint8_t bitIdx;
const char* text;
};
extern const BcuAlarmDesc kBcuAlarmTable[];
// 收集节点当前置位的告警描述;返回条数(不超过 cap,texts 填描述指针)
int bcuAlarmTexts(const BcuNodeStatus& node, const char* texts[], int cap);
} // namespace ccu
#endif // PCCU_CAN_BMS_H