Files
H100PowerManger/src/pCCU/protocol/PmProtocol.cpp
T
zjk 2590282aed
build-test-deploy / ci (push) Successful in 1h13m13s
0827协议修订:姿态数据2改预留 + 状态帧新增剩余发电量 + CCU地址可配置
FC协议(0827 docx):
- 控制指令域:字节12,13/16,17由纵倾/横倾姿态数据2改为预留(编码恒0、解码忽略)
- 状态反馈域:字节147,148由预留12改为剩余发电量(MWh),贯通JSON/网页显示
- PM→CCU链路:姿态字段4xuchar改为2xshort(数据1),结构体大小与线上布局不变
- 同步更新:CCU转发映射、SnapshotBuilder、pCCU网页、fuelcell网页、SQLite列描述、单测/模拟器
- 修正集成测试遗留断言(20B→24B、心跳d[19]→d[23])并增强预留字节校验

CCU地址可配置:
- pPowerManger 支持 moos 配置项 ccuhost/ccuport(默认127.0.0.1:7000)
- build-board.sh 增加 --ccu-host/--ccu-port 参数

文档:FC协议文档更新为0827版,清理过期协议docx
2026-08-28 00:09:17 +08:00

662 lines
32 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 "PmProtocol.h"
#include "FieldCodec.h"
#include "Frame.h"
#include "MessageRegistry.h"
namespace ccu {
void registerPmMessages(MessageRegistry& reg) {
reg.registerMessage(std::unique_ptr<Message>(new PmControlMessage()));
reg.registerMessage(std::unique_ptr<Message>(new PmParamSetMessage()));
reg.registerMessage(std::unique_ptr<Message>(new PmParamSetFbMessage()));
reg.registerMessage(std::unique_ptr<Message>(new PmStatusMessage()));
}
//============================================================================
// 0x0001 操控指令域编解码
// 数据域 35 字节,偏移 0~34(对应文档字节 7~41)
//============================================================================
namespace {
enum : size_t {
PO_YEAR = 0, // u16
PO_MONTH = 2,
PO_DAY = 3,
PO_HOUR = 4,
PO_MINUTE = 5,
PO_SECOND = 6,
PO_MS10 = 7,
PO_MODE = 8,
PO_CMD = 9,
PO_OUTPOWER = 10,
PO_PITCH = 11, // 纵倾姿态数据1 int16 (字节18-19)
PO_ROLL = 13, // 横倾姿态数据1 int16 (字节20-21)
PO_EMER_ALLOW = 15,
PO_DEPTH = 16, // u16
PO_SUPPLY_CMD = 18,
PO_RESV_CMD5 = 19,
PO_RESV_CMD6 = 20,
PO_INS_BAT_CMD = 21,
PO_DYN_BAT_CMD = 22,
PO_DYN_BAT_PWR = 23, // u16
PO_HEARTBEAT = 25,
PO_HOST_STATE = 26,
PO_RESV1 = 27, // u32
PO_RESV2 = 31, // u32
};
}
std::vector<uint8_t> PmControlMessage::encode(const void* obj) const {
const PmControlValue* v = static_cast<const PmControlValue*>(obj);
std::vector<uint8_t> p(payloadLength(), 0);
FieldCodec::putU16(p, PO_YEAR, v->year);
FieldCodec::putU8(p, PO_MONTH, v->month);
FieldCodec::putU8(p, PO_DAY, v->day);
FieldCodec::putU8(p, PO_HOUR, v->hour);
FieldCodec::putU8(p, PO_MINUTE, v->minute);
FieldCodec::putU8(p, PO_SECOND, v->second);
FieldCodec::putU8(p, PO_MS10, v->millisecond10);
FieldCodec::putU8(p, PO_MODE, v->mode);
FieldCodec::putU8(p, PO_CMD, v->cmd);
FieldCodec::putU8(p, PO_OUTPOWER, v->outputPower);
FieldCodec::putU16(p, PO_PITCH, static_cast<uint16_t>(v->pitch)); // 姿态数据1,数据2字节预留
FieldCodec::putU16(p, PO_ROLL, static_cast<uint16_t>(v->roll));
FieldCodec::putU8(p, PO_EMER_ALLOW, v->emergencyAllow);
FieldCodec::putU16(p, PO_DEPTH, v->depth);
FieldCodec::putU8(p, PO_SUPPLY_CMD, v->supplyCmd);
FieldCodec::putU8(p, PO_RESV_CMD5, v->reservedCmd5);
FieldCodec::putU8(p, PO_RESV_CMD6, v->reservedCmd6);
FieldCodec::putU8(p, PO_INS_BAT_CMD, v->insBatCmd);
FieldCodec::putU8(p, PO_DYN_BAT_CMD, v->dynBatCmd);
FieldCodec::putU16(p, PO_DYN_BAT_PWR, v->dynBatPower);
FieldCodec::putU8(p, PO_HEARTBEAT, v->heartbeat);
FieldCodec::putU8(p, PO_HOST_STATE, v->hostState);
FieldCodec::putU32(p, PO_RESV1, v->reserved1);
FieldCodec::putU32(p, PO_RESV2, v->reserved2);
return Frame::build(id(), p, checksum());
}
bool PmControlMessage::decode(const std::vector<uint8_t>& frame, void* obj) const {
if (!validateFrame(frame, id(), checksum(), totalLength())) return false;
PmControlValue* v = static_cast<PmControlValue*>(obj);
size_t o = FRAME_HEADER_LEN;
v->year = FieldCodec::getU16(frame, o + PO_YEAR);
v->month = FieldCodec::getU8(frame, o + PO_MONTH);
v->day = FieldCodec::getU8(frame, o + PO_DAY);
v->hour = FieldCodec::getU8(frame, o + PO_HOUR);
v->minute = FieldCodec::getU8(frame, o + PO_MINUTE);
v->second = FieldCodec::getU8(frame, o + PO_SECOND);
v->millisecond10 = FieldCodec::getU8(frame, o + PO_MS10);
v->mode = FieldCodec::getU8(frame, o + PO_MODE);
v->cmd = FieldCodec::getU8(frame, o + PO_CMD);
v->outputPower = FieldCodec::getU8(frame, o + PO_OUTPOWER);
v->pitch = static_cast<int16_t>(FieldCodec::getU16(frame, o + PO_PITCH));
v->roll = static_cast<int16_t>(FieldCodec::getU16(frame, o + PO_ROLL));
v->emergencyAllow= FieldCodec::getU8(frame, o + PO_EMER_ALLOW);
v->depth = FieldCodec::getU16(frame, o + PO_DEPTH);
v->supplyCmd = FieldCodec::getU8(frame, o + PO_SUPPLY_CMD);
v->reservedCmd5 = FieldCodec::getU8(frame, o + PO_RESV_CMD5);
v->reservedCmd6 = FieldCodec::getU8(frame, o + PO_RESV_CMD6);
v->insBatCmd = FieldCodec::getU8(frame, o + PO_INS_BAT_CMD);
v->dynBatCmd = FieldCodec::getU8(frame, o + PO_DYN_BAT_CMD);
v->dynBatPower = FieldCodec::getU16(frame, o + PO_DYN_BAT_PWR);
v->heartbeat = FieldCodec::getU8(frame, o + PO_HEARTBEAT);
v->hostState = FieldCodec::getU8(frame, o + PO_HOST_STATE);
v->reserved1 = FieldCodec::getU32(frame, o + PO_RESV1);
v->reserved2 = FieldCodec::getU32(frame, o + PO_RESV2);
return true;
}
//============================================================================
// 0x0002 参数设定指令域
// 数据域 18 字节,偏移 0~17
//============================================================================
namespace {
enum : size_t {
PP_INS_H1 = 0,
PP_INS_H2 = 1,
PP_INS_H3 = 2,
PP_INS_PWR = 3,
PP_INS_RESV = 4,
PP_DYN_H1 = 5,
PP_DYN_H2 = 6,
PP_DYN_H3 = 7,
PP_DYN_PWR = 8,
PP_DYN_RESV = 9,
PP_RESV1 = 10, // u32
PP_RESV2 = 14, // u32
};
}
std::vector<uint8_t> PmParamSetMessage::encode(const void* obj) const {
const PmParamSetValue* v = static_cast<const PmParamSetValue*>(obj);
std::vector<uint8_t> p(payloadLength(), 0);
FieldCodec::putU8(p, PP_INS_H1, v->insSocHold1);
FieldCodec::putU8(p, PP_INS_H2, v->insSocHold2);
FieldCodec::putU8(p, PP_INS_H3, v->insSocHold3);
FieldCodec::putU8(p, PP_INS_PWR, v->insOutputPower);
FieldCodec::putU8(p, PP_INS_RESV, v->insReserved);
FieldCodec::putU8(p, PP_DYN_H1, v->dynSocHold1);
FieldCodec::putU8(p, PP_DYN_H2, v->dynSocHold2);
FieldCodec::putU8(p, PP_DYN_H3, v->dynSocHold3);
FieldCodec::putU8(p, PP_DYN_PWR, v->dynOutputPower);
FieldCodec::putU8(p, PP_DYN_RESV, v->dynReserved);
FieldCodec::putU32(p, PP_RESV1, v->reserved1);
FieldCodec::putU32(p, PP_RESV2, v->reserved2);
return Frame::build(id(), p, checksum());
}
bool PmParamSetMessage::decode(const std::vector<uint8_t>& frame, void* obj) const {
if (!validateFrame(frame, id(), checksum(), totalLength())) return false;
PmParamSetValue* v = static_cast<PmParamSetValue*>(obj);
size_t o = FRAME_HEADER_LEN;
v->insSocHold1 = FieldCodec::getU8(frame, o + PP_INS_H1);
v->insSocHold2 = FieldCodec::getU8(frame, o + PP_INS_H2);
v->insSocHold3 = FieldCodec::getU8(frame, o + PP_INS_H3);
v->insOutputPower = FieldCodec::getU8(frame, o + PP_INS_PWR);
v->insReserved = FieldCodec::getU8(frame, o + PP_INS_RESV);
v->dynSocHold1 = FieldCodec::getU8(frame, o + PP_DYN_H1);
v->dynSocHold2 = FieldCodec::getU8(frame, o + PP_DYN_H2);
v->dynSocHold3 = FieldCodec::getU8(frame, o + PP_DYN_H3);
v->dynOutputPower = FieldCodec::getU8(frame, o + PP_DYN_PWR);
v->dynReserved = FieldCodec::getU8(frame, o + PP_DYN_RESV);
v->reserved1 = FieldCodec::getU32(frame, o + PP_RESV1);
v->reserved2 = FieldCodec::getU32(frame, o + PP_RESV2);
return true;
}
//============================================================================
// 0x0003 参数设定反馈域
// 数据域 2 字节
//============================================================================
std::vector<uint8_t> PmParamSetFbMessage::encode(const void* obj) const {
const PmParamSetFbValue* v = static_cast<const PmParamSetFbValue*>(obj);
std::vector<uint8_t> p(payloadLength(), 0);
FieldCodec::putU8(p, 0, v->flag);
FieldCodec::putU8(p, 1, v->failCode);
return Frame::build(id(), p, checksum());
}
bool PmParamSetFbMessage::decode(const std::vector<uint8_t>& frame, void* obj) const {
if (!validateFrame(frame, id(), checksum(), totalLength())) return false;
PmParamSetFbValue* v = static_cast<PmParamSetFbValue*>(obj);
size_t o = FRAME_HEADER_LEN;
v->flag = FieldCodec::getU8(frame, o + 0);
v->failCode = FieldCodec::getU8(frame, o + 1);
return true;
}
//============================================================================
// 0x0004 状态报文域
// 数据域 238 字节,偏移 0~237(对应文档字节 7~244)
//============================================================================
namespace {
enum : size_t {
PS_MODE = 0,
PS_STATUS = 1,
PS_FL1 = 2, // u16
PS_FL2 = 4,
PS_FL3 = 6,
PS_FL4 = 8,
PS_GEN_TIME = 10, // u16
PS_FAULT_LEVEL = 12,
PS_OUT_POWER_LIMIT = 13, // u16
PS_GEN_POWER = 15, // u16
PS_H2_CAP = 17,
PS_LO2_CAP = 18,
PS_FC1_MIN_V = 19,
PS_FC1_MIN_POS = 20,
PS_FC1_AVG_V = 21,
PS_FC2_MIN_V = 22,
PS_FC2_MIN_POS = 23,
PS_FC2_AVG_V = 24,
PS_PALLADIUM = 25, // u16
PS_BUFFER_PRES = 27,
PS_FLUE_TOTAL = 29,
PS_FLUE_PRES = 31,
PS_REACTOR_PRES = 33,
PS_EVALVE_OPEN = 35,
PS_MAIN_PIPE_PRES = 37,
PS_AUX_PIPE_PRES = 39,
PS_DCDC1_IN_V = 41,
PS_DCDC1_IN_I = 43,
PS_DCDC2_IN_V = 45,
PS_DCDC2_IN_I = 47,
PS_DCDC_OUT_V = 49,
PS_DCDC_OUT_I = 51,
PS_DCDC_CTRL_V = 53,
PS_DCDC_AUX_V = 54,
PS_METHANOL_TOTAL = 55, // u16
PS_METHANOL_FEED = 57,
PS_O2_WATER = 59,
PS_H2_WATER = 61,
PS_BALLAST_WATER = 63,
PS_EXH_IN_PRES = 65,
PS_EXH_OUT_PRES = 67,
PS_EXH_FREQ = 69,
PS_EXH_IN_TEMP = 71,
PS_EXH_OUT_TEMP = 73,
PS_EXH_WIN_PRES = 75,
PS_EXH_WOUT_PRES = 77,
PS_TANK_LO2_PRES = 79,
PS_TANK_CO2_PRES = 81,
PS_TANK_LO2_LEVEL = 83,
PS_ALLOY_H2_FLOW = 85,
PS_FC_H2_FLOW = 87,
PS_FC_O2_FLOW = 89,
PS_EMER_DEPTH = 91, // u16
PS_EMER_TIME = 93,
PS_CABIN_P1 = 95,
PS_CABIN_P2 = 97,
PS_CABIN_T1 = 99,
PS_CABIN_T2 = 101,
PS_CABIN_H1 = 103,
PS_CABIN_H2 = 105,
PS_H2_C1 = 107,
PS_H2_C2 = 109,
PS_H2_C3 = 111,
PS_O2_C1 = 113,
PS_O2_C2 = 115,
PS_CH3OH_C1 = 117,
PS_CH3OH_C2 = 119,
PS_FLAME1 = 121,
PS_FLAME2 = 122,
PS_RESV1 = 123, // u16
PS_RESV2 = 125, // u16
PS_EB1_VOLTAGE = 127, // u16
PS_EB1_CURRENT = 129,
PS_EB1_MAX_TEMP = 131,
PS_EB1_FAULT = 133,
PS_EB2_VOLTAGE = 135,
PS_EB2_CURRENT = 137,
PS_EB2_MAX_TEMP = 139,
PS_EB2_FAULT = 141,
PS_INS_CABIN_OX = 143, // u16
PS_INS_CABIN_TEMP = 145,
PS_INS_CABIN_HUM = 147,
PS_INS_CABIN_PRES = 149,
PS_DYN_CABIN_OX = 151,
PS_DYN_CABIN_TEMP = 153,
PS_DYN_CABIN_HUM = 155,
PS_DYN_CABIN_PRES = 157,
PS_RESV3 = 159, // u8
PS_DYN_ALARM = 160, // u8 * 6
PS_INS_ALARM = 166, // u8 * 6
PS_INS_RELAY1 = 172,
PS_INS_RELAY2 = 173,
PS_DYN_RELAY1 = 174,
PS_DYN_RELAY2 = 175,
PS_INS_MAX_PWR = 176, // u16
PS_DYN_MAX_PWR = 178, // u16
PS_INS_SOC = 180,
PS_DYN_SOC = 181,
PS_INS_TOTAL_ENERGY= 182, // u16
PS_DYN_TOTAL_ENERGY= 184, // u16
PS_INS_PWR_IN = 186, // u16
PS_DYN_PWR_IN = 188, // u16
PS_INS_CHARGE_ST = 190,
PS_DYN_CHARGE_ST = 191,
PS_INS_V_LINK = 192, // u16
PS_INS_V_PACK = 194, // u16
PS_INS_CURRENT = 196, // u16
PS_INS_RES_POS = 198, // u16
PS_INS_RES_NEG = 200, // u16
PS_DYN_V_LINK = 202, // u16
PS_DYN_V_PACK = 204, // u16
PS_DYN_CURRENT = 206, // u16
PS_DYN_RES_POS = 208, // u16
PS_DYN_RES_NEG = 210, // u16
PS_INS_EMERGENCY = 212,
PS_DYN_EMERGENCY = 213,
PS_INS_SOC_H1 = 214,
PS_INS_SOC_H2 = 215,
PS_INS_SOC_H3 = 216,
PS_INS_PWR_L1 = 217,
PS_INS_PWR_L2 = 218,
PS_DYN_SOC_H1 = 219,
PS_DYN_SOC_H2 = 220,
PS_DYN_SOC_H3 = 221,
PS_DYN_PWR_L1 = 222,
PS_DYN_PWR_L2 = 223,
PS_ONLINE_FLAG1 = 224, // u32
PS_ONLINE_FLAG2 = 228, // u32
PS_RESV4 = 232, // u32
PS_HEARTBEAT = 236,
PS_EMERGENCY_CMD = 237,
};
inline void getU8Arr(const std::vector<uint8_t>& f, size_t off, uint8_t* dst, size_t n) {
for (size_t i = 0; i < n; ++i) dst[i] = f[off + i];
}
inline void putU8Arr(std::vector<uint8_t>& p, size_t off, const uint8_t* src, size_t n) {
for (size_t i = 0; i < n; ++i) p[off + i] = src[i];
}
}
std::vector<uint8_t> PmStatusMessage::encode(const void* obj) const {
const PmStatusValue* v = static_cast<const PmStatusValue*>(obj);
std::vector<uint8_t> p(payloadLength(), 0);
FieldCodec::putU8(p, PS_MODE, v->fc_mode);
FieldCodec::putU8(p, PS_STATUS, v->fc_status);
FieldCodec::putU16(p, PS_FL1, v->fault_level_1);
FieldCodec::putU16(p, PS_FL2, v->fault_level_2);
FieldCodec::putU16(p, PS_FL3, v->fault_level_3);
FieldCodec::putU16(p, PS_FL4, v->fault_level_4);
FieldCodec::putU16(p, PS_GEN_TIME, v->total_generation_time);
FieldCodec::putU8(p, PS_FAULT_LEVEL, v->fc_fault_level);
FieldCodec::putU16(p, PS_OUT_POWER_LIMIT, v->output_power_limit);
FieldCodec::putU16(p, PS_GEN_POWER, v->generation_power);
FieldCodec::putU8(p, PS_H2_CAP, v->hydrogen_capacity);
FieldCodec::putU8(p, PS_LO2_CAP, v->liquid_oxygen_capacity);
FieldCodec::putU8(p, PS_FC1_MIN_V, v->fc1_min_cell_voltage);
FieldCodec::putU8(p, PS_FC1_MIN_POS, v->fc1_min_cell_pos);
FieldCodec::putU8(p, PS_FC1_AVG_V, v->fc1_avg_cell_voltage);
FieldCodec::putU8(p, PS_FC2_MIN_V, v->fc2_min_cell_voltage);
FieldCodec::putU8(p, PS_FC2_MIN_POS, v->fc2_min_cell_pos);
FieldCodec::putU8(p, PS_FC2_AVG_V, v->fc2_avg_cell_voltage);
FieldCodec::putU16(p, PS_PALLADIUM, v->palladium_temp);
FieldCodec::putU16(p, PS_BUFFER_PRES, v->buffer_tank_pressure);
FieldCodec::putU16(p, PS_FLUE_TOTAL, v->flue_total_emission);
FieldCodec::putU16(p, PS_FLUE_PRES, v->flue_pressure);
FieldCodec::putU16(p, PS_REACTOR_PRES, v->reactor_pressure);
FieldCodec::putU16(p, PS_EVALVE_OPEN, v->electric_valve_open);
FieldCodec::putU16(p, PS_MAIN_PIPE_PRES, v->main_pipe_pressure);
FieldCodec::putU16(p, PS_AUX_PIPE_PRES, v->aux_pipe_pressure);
FieldCodec::putU16(p, PS_DCDC1_IN_V, v->dcdc1_in_voltage);
FieldCodec::putU16(p, PS_DCDC1_IN_I, v->dcdc1_in_current);
FieldCodec::putU16(p, PS_DCDC2_IN_V, v->dcdc2_in_voltage);
FieldCodec::putU16(p, PS_DCDC2_IN_I, v->dcdc2_in_current);
FieldCodec::putU16(p, PS_DCDC_OUT_V, v->dcdc_out_voltage);
FieldCodec::putU16(p, PS_DCDC_OUT_I, v->dcdc_out_current);
FieldCodec::putU8(p, PS_DCDC_CTRL_V, v->dcdc_ctrl_voltage);
FieldCodec::putU8(p, PS_DCDC_AUX_V, v->dcdc_aux_voltage);
FieldCodec::putU16(p, PS_METHANOL_TOTAL, v->methanol_total_use);
FieldCodec::putU16(p, PS_METHANOL_FEED, v->methanol_feed);
FieldCodec::putU16(p, PS_O2_WATER, v->oxygen_side_water_level);
FieldCodec::putU16(p, PS_H2_WATER, v->hydrogen_side_water_level);
FieldCodec::putU16(p, PS_BALLAST_WATER, v->ballast_water_level);
FieldCodec::putU16(p, PS_EXH_IN_PRES, v->exhaust_inlet_pressure);
FieldCodec::putU16(p, PS_EXH_OUT_PRES, v->exhaust_outlet_pressure);
FieldCodec::putU16(p, PS_EXH_FREQ, v->exhaust_run_freq);
FieldCodec::putU16(p, PS_EXH_IN_TEMP, v->exhaust_inlet_temp);
FieldCodec::putU16(p, PS_EXH_OUT_TEMP, v->exhaust_outlet_temp);
FieldCodec::putU16(p, PS_EXH_WIN_PRES, v->exhaust_water_in_pressure);
FieldCodec::putU16(p, PS_EXH_WOUT_PRES, v->exhaust_water_out_pressure);
FieldCodec::putU16(p, PS_TANK_LO2_PRES, v->tank_lo2_pressure);
FieldCodec::putU16(p, PS_TANK_CO2_PRES, v->tank_co2_pressure);
FieldCodec::putU16(p, PS_TANK_LO2_LEVEL, v->tank_lo2_level);
FieldCodec::putU16(p, PS_ALLOY_H2_FLOW, v->alloy_h2_flow);
FieldCodec::putU16(p, PS_FC_H2_FLOW, v->fc_h2_flow);
FieldCodec::putU16(p, PS_FC_O2_FLOW, v->fc_o2_flow);
FieldCodec::putU16(p, PS_EMER_DEPTH, v->emergency_float_depth);
FieldCodec::putU16(p, PS_EMER_TIME, v->emergency_float_time);
FieldCodec::putU16(p, PS_CABIN_P1, v->cabin_pressure1);
FieldCodec::putU16(p, PS_CABIN_P2, v->cabin_pressure2);
FieldCodec::putU16(p, PS_CABIN_T1, v->cabin_temp1);
FieldCodec::putU16(p, PS_CABIN_T2, v->cabin_temp2);
FieldCodec::putU16(p, PS_CABIN_H1, v->cabin_humidity1);
FieldCodec::putU16(p, PS_CABIN_H2, v->cabin_humidity2);
FieldCodec::putU16(p, PS_H2_C1, v->h2_concentration1);
FieldCodec::putU16(p, PS_H2_C2, v->h2_concentration2);
FieldCodec::putU16(p, PS_H2_C3, v->h2_concentration3);
FieldCodec::putU16(p, PS_O2_C1, v->o2_concentration1);
FieldCodec::putU16(p, PS_O2_C2, v->o2_concentration2);
FieldCodec::putU16(p, PS_CH3OH_C1, v->ch3oh_concentration1);
FieldCodec::putU16(p, PS_CH3OH_C2, v->ch3oh_concentration2);
FieldCodec::putU8(p, PS_FLAME1, v->flame_detector1);
FieldCodec::putU8(p, PS_FLAME2, v->flame_detector2);
FieldCodec::putU16(p, PS_RESV1, v->pmReserved1);
FieldCodec::putU16(p, PS_RESV2, v->pmReserved2);
FieldCodec::putU16(p, PS_EB1_VOLTAGE, v->emergency_battery1_voltage);
FieldCodec::putU16(p, PS_EB1_CURRENT, v->emergency_battery1_current);
FieldCodec::putU16(p, PS_EB1_MAX_TEMP, v->emergency_battery1_max_temp);
FieldCodec::putU16(p, PS_EB1_FAULT, v->emergency_battery1_fault_word);
FieldCodec::putU16(p, PS_EB2_VOLTAGE, v->emergency_battery2_voltage);
FieldCodec::putU16(p, PS_EB2_CURRENT, v->emergency_battery2_current);
FieldCodec::putU16(p, PS_EB2_MAX_TEMP, v->emergency_battery2_max_temp);
FieldCodec::putU16(p, PS_EB2_FAULT, v->emergency_battery2_fault_word);
FieldCodec::putU16(p, PS_INS_CABIN_OX, v->ins_cabin_ox_concentration);
FieldCodec::putU16(p, PS_INS_CABIN_TEMP, v->ins_cabin_temperature);
FieldCodec::putU16(p, PS_INS_CABIN_HUM, v->ins_cabin_humidity);
FieldCodec::putU16(p, PS_INS_CABIN_PRES, v->ins_cabin_pressure);
FieldCodec::putU16(p, PS_DYN_CABIN_OX, v->dyn_cabin_ox_concentration);
FieldCodec::putU16(p, PS_DYN_CABIN_TEMP, v->dyn_cabin_temperature);
FieldCodec::putU16(p, PS_DYN_CABIN_HUM, v->dyn_cabin_humidity);
FieldCodec::putU16(p, PS_DYN_CABIN_PRES, v->dyn_cabin_pressure);
FieldCodec::putU8(p, PS_RESV3, v->pmReserved3);
putU8Arr(p, PS_DYN_ALARM, v->dyn_alarm_flag, 6);
putU8Arr(p, PS_INS_ALARM, v->ins_alarm_flag, 6);
FieldCodec::putU8(p, PS_INS_RELAY1, v->ins_relay_status1);
FieldCodec::putU8(p, PS_INS_RELAY2, v->ins_relay_status2);
FieldCodec::putU8(p, PS_DYN_RELAY1, v->dyn_relay_status1);
FieldCodec::putU8(p, PS_DYN_RELAY2, v->dyn_relay_status2);
FieldCodec::putU16(p, PS_INS_MAX_PWR, v->ins_max_discharge_power);
FieldCodec::putU16(p, PS_DYN_MAX_PWR, v->dyn_max_discharge_power);
FieldCodec::putU8(p, PS_INS_SOC, v->ins_soc);
FieldCodec::putU8(p, PS_DYN_SOC, v->dyn_soc);
FieldCodec::putU16(p, PS_INS_TOTAL_ENERGY, v->ins_total_energy);
FieldCodec::putU16(p, PS_DYN_TOTAL_ENERGY, v->dyn_total_energy);
FieldCodec::putU16(p, PS_INS_PWR_IN, v->ins_power_input);
FieldCodec::putU16(p, PS_DYN_PWR_IN, v->dyn_power_input);
FieldCodec::putU8(p, PS_INS_CHARGE_ST, v->ins_charge_status);
FieldCodec::putU8(p, PS_DYN_CHARGE_ST, v->dyn_charge_status);
FieldCodec::putU16(p, PS_INS_V_LINK, v->ins_voltage_link);
FieldCodec::putU16(p, PS_INS_V_PACK, v->ins_voltage_pack);
FieldCodec::putU16(p, PS_INS_CURRENT, v->ins_current);
FieldCodec::putU16(p, PS_INS_RES_POS, v->ins_resistance_pos);
FieldCodec::putU16(p, PS_INS_RES_NEG, v->ins_resistance_neg);
FieldCodec::putU16(p, PS_DYN_V_LINK, v->dyn_voltage_link);
FieldCodec::putU16(p, PS_DYN_V_PACK, v->dyn_voltage_pack);
FieldCodec::putU16(p, PS_DYN_CURRENT, v->dyn_current);
FieldCodec::putU16(p, PS_DYN_RES_POS, v->dyn_resistance_pos);
FieldCodec::putU16(p, PS_DYN_RES_NEG, v->dyn_resistance_neg);
FieldCodec::putU8(p, PS_INS_EMERGENCY, v->ins_emergency_status);
FieldCodec::putU8(p, PS_DYN_EMERGENCY, v->dyn_emergency_status);
FieldCodec::putU8(p, PS_INS_SOC_H1, v->ins_soc_threshold1);
FieldCodec::putU8(p, PS_INS_SOC_H2, v->ins_soc_threshold2);
FieldCodec::putU8(p, PS_INS_SOC_H3, v->ins_soc_threshold3);
FieldCodec::putU8(p, PS_INS_PWR_L1, v->ins_power_limit1);
FieldCodec::putU8(p, PS_INS_PWR_L2, v->ins_power_limit2);
FieldCodec::putU8(p, PS_DYN_SOC_H1, v->dyn_soc_threshold1);
FieldCodec::putU8(p, PS_DYN_SOC_H2, v->dyn_soc_threshold2);
FieldCodec::putU8(p, PS_DYN_SOC_H3, v->dyn_soc_threshold3);
FieldCodec::putU8(p, PS_DYN_PWR_L1, v->dyn_power_limit1);
FieldCodec::putU8(p, PS_DYN_PWR_L2, v->dyn_power_limit2);
FieldCodec::putU32(p, PS_ONLINE_FLAG1, v->device_online_flag1);
FieldCodec::putU32(p, PS_ONLINE_FLAG2, v->device_online_flag2);
FieldCodec::putU32(p, PS_RESV4, v->pmReserved4);
FieldCodec::putU8(p, PS_HEARTBEAT, v->heartbeat);
FieldCodec::putU8(p, PS_EMERGENCY_CMD, v->emergency_cmd);
return Frame::build(id(), p, checksum());
}
bool PmStatusMessage::decode(const std::vector<uint8_t>& frame, void* obj) const {
if (!validateFrame(frame, id(), checksum(), totalLength())) return false;
PmStatusValue* v = static_cast<PmStatusValue*>(obj);
size_t o = FRAME_HEADER_LEN;
v->fc_mode = FieldCodec::getU8(frame, o + PS_MODE);
v->fc_status = FieldCodec::getU8(frame, o + PS_STATUS);
v->fault_level_1 = FieldCodec::getU16(frame, o + PS_FL1);
v->fault_level_2 = FieldCodec::getU16(frame, o + PS_FL2);
v->fault_level_3 = FieldCodec::getU16(frame, o + PS_FL3);
v->fault_level_4 = FieldCodec::getU16(frame, o + PS_FL4);
v->total_generation_time = FieldCodec::getU16(frame, o + PS_GEN_TIME);
v->fc_fault_level = FieldCodec::getU8(frame, o + PS_FAULT_LEVEL);
v->output_power_limit = FieldCodec::getU16(frame, o + PS_OUT_POWER_LIMIT);
v->generation_power = FieldCodec::getU16(frame, o + PS_GEN_POWER);
v->hydrogen_capacity = FieldCodec::getU8(frame, o + PS_H2_CAP);
v->liquid_oxygen_capacity = FieldCodec::getU8(frame, o + PS_LO2_CAP);
v->fc1_min_cell_voltage = FieldCodec::getU8(frame, o + PS_FC1_MIN_V);
v->fc1_min_cell_pos = FieldCodec::getU8(frame, o + PS_FC1_MIN_POS);
v->fc1_avg_cell_voltage = FieldCodec::getU8(frame, o + PS_FC1_AVG_V);
v->fc2_min_cell_voltage = FieldCodec::getU8(frame, o + PS_FC2_MIN_V);
v->fc2_min_cell_pos = FieldCodec::getU8(frame, o + PS_FC2_MIN_POS);
v->fc2_avg_cell_voltage = FieldCodec::getU8(frame, o + PS_FC2_AVG_V);
v->palladium_temp = FieldCodec::getU16(frame, o + PS_PALLADIUM);
v->buffer_tank_pressure = FieldCodec::getU16(frame, o + PS_BUFFER_PRES);
v->flue_total_emission = FieldCodec::getU16(frame, o + PS_FLUE_TOTAL);
v->flue_pressure = FieldCodec::getU16(frame, o + PS_FLUE_PRES);
v->reactor_pressure = FieldCodec::getU16(frame, o + PS_REACTOR_PRES);
v->electric_valve_open = FieldCodec::getU16(frame, o + PS_EVALVE_OPEN);
v->main_pipe_pressure = FieldCodec::getU16(frame, o + PS_MAIN_PIPE_PRES);
v->aux_pipe_pressure = FieldCodec::getU16(frame, o + PS_AUX_PIPE_PRES);
v->dcdc1_in_voltage = FieldCodec::getU16(frame, o + PS_DCDC1_IN_V);
v->dcdc1_in_current = FieldCodec::getU16(frame, o + PS_DCDC1_IN_I);
v->dcdc2_in_voltage = FieldCodec::getU16(frame, o + PS_DCDC2_IN_V);
v->dcdc2_in_current = FieldCodec::getU16(frame, o + PS_DCDC2_IN_I);
v->dcdc_out_voltage = FieldCodec::getU16(frame, o + PS_DCDC_OUT_V);
v->dcdc_out_current = FieldCodec::getU16(frame, o + PS_DCDC_OUT_I);
v->dcdc_ctrl_voltage = FieldCodec::getU8(frame, o + PS_DCDC_CTRL_V);
v->dcdc_aux_voltage = FieldCodec::getU8(frame, o + PS_DCDC_AUX_V);
v->methanol_total_use = FieldCodec::getU16(frame, o + PS_METHANOL_TOTAL);
v->methanol_feed = FieldCodec::getU16(frame, o + PS_METHANOL_FEED);
v->oxygen_side_water_level = FieldCodec::getU16(frame, o + PS_O2_WATER);
v->hydrogen_side_water_level = FieldCodec::getU16(frame, o + PS_H2_WATER);
v->ballast_water_level = FieldCodec::getU16(frame, o + PS_BALLAST_WATER);
v->exhaust_inlet_pressure = FieldCodec::getU16(frame, o + PS_EXH_IN_PRES);
v->exhaust_outlet_pressure = FieldCodec::getU16(frame, o + PS_EXH_OUT_PRES);
v->exhaust_run_freq = FieldCodec::getU16(frame, o + PS_EXH_FREQ);
v->exhaust_inlet_temp = FieldCodec::getU16(frame, o + PS_EXH_IN_TEMP);
v->exhaust_outlet_temp = FieldCodec::getU16(frame, o + PS_EXH_OUT_TEMP);
v->exhaust_water_in_pressure = FieldCodec::getU16(frame, o + PS_EXH_WIN_PRES);
v->exhaust_water_out_pressure = FieldCodec::getU16(frame, o + PS_EXH_WOUT_PRES);
v->tank_lo2_pressure = FieldCodec::getU16(frame, o + PS_TANK_LO2_PRES);
v->tank_co2_pressure = FieldCodec::getU16(frame, o + PS_TANK_CO2_PRES);
v->tank_lo2_level = FieldCodec::getU16(frame, o + PS_TANK_LO2_LEVEL);
v->alloy_h2_flow = FieldCodec::getU16(frame, o + PS_ALLOY_H2_FLOW);
v->fc_h2_flow = FieldCodec::getU16(frame, o + PS_FC_H2_FLOW);
v->fc_o2_flow = FieldCodec::getU16(frame, o + PS_FC_O2_FLOW);
v->emergency_float_depth = FieldCodec::getU16(frame, o + PS_EMER_DEPTH);
v->emergency_float_time = FieldCodec::getU16(frame, o + PS_EMER_TIME);
v->cabin_pressure1 = FieldCodec::getU16(frame, o + PS_CABIN_P1);
v->cabin_pressure2 = FieldCodec::getU16(frame, o + PS_CABIN_P2);
v->cabin_temp1 = FieldCodec::getU16(frame, o + PS_CABIN_T1);
v->cabin_temp2 = FieldCodec::getU16(frame, o + PS_CABIN_T2);
v->cabin_humidity1 = FieldCodec::getU16(frame, o + PS_CABIN_H1);
v->cabin_humidity2 = FieldCodec::getU16(frame, o + PS_CABIN_H2);
v->h2_concentration1 = FieldCodec::getU16(frame, o + PS_H2_C1);
v->h2_concentration2 = FieldCodec::getU16(frame, o + PS_H2_C2);
v->h2_concentration3 = FieldCodec::getU16(frame, o + PS_H2_C3);
v->o2_concentration1 = FieldCodec::getU16(frame, o + PS_O2_C1);
v->o2_concentration2 = FieldCodec::getU16(frame, o + PS_O2_C2);
v->ch3oh_concentration1 = FieldCodec::getU16(frame, o + PS_CH3OH_C1);
v->ch3oh_concentration2 = FieldCodec::getU16(frame, o + PS_CH3OH_C2);
v->flame_detector1 = FieldCodec::getU8(frame, o + PS_FLAME1);
v->flame_detector2 = FieldCodec::getU8(frame, o + PS_FLAME2);
v->pmReserved1 = FieldCodec::getU16(frame, o + PS_RESV1);
v->pmReserved2 = FieldCodec::getU16(frame, o + PS_RESV2);
v->emergency_battery1_voltage = FieldCodec::getU16(frame, o + PS_EB1_VOLTAGE);
v->emergency_battery1_current = FieldCodec::getU16(frame, o + PS_EB1_CURRENT);
v->emergency_battery1_max_temp = FieldCodec::getU16(frame, o + PS_EB1_MAX_TEMP);
v->emergency_battery1_fault_word = FieldCodec::getU16(frame, o + PS_EB1_FAULT);
v->emergency_battery2_voltage = FieldCodec::getU16(frame, o + PS_EB2_VOLTAGE);
v->emergency_battery2_current = FieldCodec::getU16(frame, o + PS_EB2_CURRENT);
v->emergency_battery2_max_temp = FieldCodec::getU16(frame, o + PS_EB2_MAX_TEMP);
v->emergency_battery2_fault_word = FieldCodec::getU16(frame, o + PS_EB2_FAULT);
v->ins_cabin_ox_concentration = FieldCodec::getU16(frame, o + PS_INS_CABIN_OX);
v->ins_cabin_temperature = FieldCodec::getU16(frame, o + PS_INS_CABIN_TEMP);
v->ins_cabin_humidity = FieldCodec::getU16(frame, o + PS_INS_CABIN_HUM);
v->ins_cabin_pressure = FieldCodec::getU16(frame, o + PS_INS_CABIN_PRES);
v->dyn_cabin_ox_concentration = FieldCodec::getU16(frame, o + PS_DYN_CABIN_OX);
v->dyn_cabin_temperature = FieldCodec::getU16(frame, o + PS_DYN_CABIN_TEMP);
v->dyn_cabin_humidity = FieldCodec::getU16(frame, o + PS_DYN_CABIN_HUM);
v->dyn_cabin_pressure = FieldCodec::getU16(frame, o + PS_DYN_CABIN_PRES);
v->pmReserved3 = FieldCodec::getU8(frame, o + PS_RESV3);
getU8Arr(frame, o + PS_DYN_ALARM, v->dyn_alarm_flag, 6);
getU8Arr(frame, o + PS_INS_ALARM, v->ins_alarm_flag, 6);
v->ins_relay_status1 = FieldCodec::getU8(frame, o + PS_INS_RELAY1);
v->ins_relay_status2 = FieldCodec::getU8(frame, o + PS_INS_RELAY2);
v->dyn_relay_status1 = FieldCodec::getU8(frame, o + PS_DYN_RELAY1);
v->dyn_relay_status2 = FieldCodec::getU8(frame, o + PS_DYN_RELAY2);
v->ins_max_discharge_power = FieldCodec::getU16(frame, o + PS_INS_MAX_PWR);
v->dyn_max_discharge_power = FieldCodec::getU16(frame, o + PS_DYN_MAX_PWR);
v->ins_soc = FieldCodec::getU8(frame, o + PS_INS_SOC);
v->dyn_soc = FieldCodec::getU8(frame, o + PS_DYN_SOC);
v->ins_total_energy = FieldCodec::getU16(frame, o + PS_INS_TOTAL_ENERGY);
v->dyn_total_energy = FieldCodec::getU16(frame, o + PS_DYN_TOTAL_ENERGY);
v->ins_power_input = FieldCodec::getU16(frame, o + PS_INS_PWR_IN);
v->dyn_power_input = FieldCodec::getU16(frame, o + PS_DYN_PWR_IN);
v->ins_charge_status = FieldCodec::getU8(frame, o + PS_INS_CHARGE_ST);
v->dyn_charge_status = FieldCodec::getU8(frame, o + PS_DYN_CHARGE_ST);
v->ins_voltage_link = FieldCodec::getU16(frame, o + PS_INS_V_LINK);
v->ins_voltage_pack = FieldCodec::getU16(frame, o + PS_INS_V_PACK);
v->ins_current = FieldCodec::getU16(frame, o + PS_INS_CURRENT);
v->ins_resistance_pos = FieldCodec::getU16(frame, o + PS_INS_RES_POS);
v->ins_resistance_neg = FieldCodec::getU16(frame, o + PS_INS_RES_NEG);
v->dyn_voltage_link = FieldCodec::getU16(frame, o + PS_DYN_V_LINK);
v->dyn_voltage_pack = FieldCodec::getU16(frame, o + PS_DYN_V_PACK);
v->dyn_current = FieldCodec::getU16(frame, o + PS_DYN_CURRENT);
v->dyn_resistance_pos = FieldCodec::getU16(frame, o + PS_DYN_RES_POS);
v->dyn_resistance_neg = FieldCodec::getU16(frame, o + PS_DYN_RES_NEG);
v->ins_emergency_status = FieldCodec::getU8(frame, o + PS_INS_EMERGENCY);
v->dyn_emergency_status = FieldCodec::getU8(frame, o + PS_DYN_EMERGENCY);
v->ins_soc_threshold1 = FieldCodec::getU8(frame, o + PS_INS_SOC_H1);
v->ins_soc_threshold2 = FieldCodec::getU8(frame, o + PS_INS_SOC_H2);
v->ins_soc_threshold3 = FieldCodec::getU8(frame, o + PS_INS_SOC_H3);
v->ins_power_limit1 = FieldCodec::getU8(frame, o + PS_INS_PWR_L1);
v->ins_power_limit2 = FieldCodec::getU8(frame, o + PS_INS_PWR_L2);
v->dyn_soc_threshold1 = FieldCodec::getU8(frame, o + PS_DYN_SOC_H1);
v->dyn_soc_threshold2 = FieldCodec::getU8(frame, o + PS_DYN_SOC_H2);
v->dyn_soc_threshold3 = FieldCodec::getU8(frame, o + PS_DYN_SOC_H3);
v->dyn_power_limit1 = FieldCodec::getU8(frame, o + PS_DYN_PWR_L1);
v->dyn_power_limit2 = FieldCodec::getU8(frame, o + PS_DYN_PWR_L2);
v->device_online_flag1 = FieldCodec::getU32(frame, o + PS_ONLINE_FLAG1);
v->device_online_flag2 = FieldCodec::getU32(frame, o + PS_ONLINE_FLAG2);
v->pmReserved4 = FieldCodec::getU32(frame, o + PS_RESV4);
v->heartbeat = FieldCodec::getU8(frame, o + PS_HEARTBEAT);
v->emergency_cmd = FieldCodec::getU8(frame, o + PS_EMERGENCY_CMD);
return true;
}
} // namespace ccu