#include "FcProtocol.h" #include "FieldCodec.h" #include "Frame.h" #include "MessageRegistry.h" namespace ccu { void registerFcMessages(MessageRegistry& reg) { reg.registerMessage(std::unique_ptr(new FcControlMessage())); reg.registerMessage(std::unique_ptr(new FcStatusMessage())); } //============================================================================ // 0x0001 控制指令域编解码 // 数据域 18 字节(字节7~24),偏移 0~17;整包 24 字节 //============================================================================ namespace { // 数据域内偏移(相对数据域起点,offset = 文档字节号 - 7) enum : size_t { CO_MODE = 0, // 模式设定 (字节7) CO_CMD = 1, // 操控指令 (字节8) CO_OUT_POWER = 2, // 输出功率指令 (字节9) CO_PITCH1 = 3, // 纵倾姿态数据1 int16 (字节10,11) CO_RESERVED1 = 5, // 预留 (字节12,13),0827协议由纵倾姿态数据2改为预留 CO_ROLL1 = 7, // 横倾姿态数据1 int16 (字节14,15) CO_RESERVED2 = 9, // 预留 (字节16,17),0827协议由横倾姿态数据2改为预留 CO_EMER_ALLOW = 11, // 应急允许 (字节18) CO_DEPTH = 12, // 潜深深度 u16 (字节19,20) CO_SUPPLY_CMD = 14, // 补给/排放指令 (字节21) CO_RESERVED5 = 15, // 预留指令5 (字节22) CO_RESERVED6 = 16, // 预留指令6 (字节23) CO_HEARTBEAT = 17, // 通信心跳 (字节24) }; } // namespace std::vector FcControlMessage::encode(const void* obj) const { const FcControlValue* v = static_cast(obj); std::vector payload(payloadLength(), 0); FieldCodec::putU8(payload, CO_MODE, v->mode); FieldCodec::putU8(payload, CO_CMD, v->cmd); FieldCodec::putU8(payload, CO_OUT_POWER, v->outputPower); FieldCodec::putU16(payload, CO_PITCH1, static_cast(v->pitch1)); FieldCodec::putU16(payload, CO_RESERVED1, 0); // 预留恒填0 FieldCodec::putU16(payload, CO_ROLL1, static_cast(v->roll1)); FieldCodec::putU16(payload, CO_RESERVED2, 0); // 预留恒填0 FieldCodec::putU8(payload, CO_EMER_ALLOW, v->emergencyAllow); FieldCodec::putU16(payload, CO_DEPTH, v->depth); FieldCodec::putU8(payload, CO_SUPPLY_CMD, v->supplyCmd); FieldCodec::putU8(payload, CO_RESERVED5, v->reservedCmd5); FieldCodec::putU8(payload, CO_RESERVED6, v->reservedCmd6); FieldCodec::putU8(payload, CO_HEARTBEAT, v->heartbeat); return Frame::build(id(), payload, checksum()); } bool FcControlMessage::decode(const std::vector& frame, void* obj) const { if (!validateFrame(frame, id(), checksum(), totalLength())) return false; FcControlValue* v = static_cast(obj); size_t o = FRAME_HEADER_LEN; // 数据域起点 v->mode = FieldCodec::getU8(frame, o + CO_MODE); v->cmd = FieldCodec::getU8(frame, o + CO_CMD); v->outputPower = FieldCodec::getU8(frame, o + CO_OUT_POWER); v->pitch1 = static_cast(FieldCodec::getU16(frame, o + CO_PITCH1)); // 字节12,13 预留,忽略 v->roll1 = static_cast(FieldCodec::getU16(frame, o + CO_ROLL1)); // 字节16,17 预留,忽略 v->emergencyAllow = FieldCodec::getU8(frame, o + CO_EMER_ALLOW); v->depth = FieldCodec::getU16(frame, o + CO_DEPTH); v->supplyCmd = FieldCodec::getU8(frame, o + CO_SUPPLY_CMD); v->reservedCmd5 = FieldCodec::getU8(frame, o + CO_RESERVED5); v->reservedCmd6 = FieldCodec::getU8(frame, o + CO_RESERVED6); v->heartbeat = FieldCodec::getU8(frame, o + CO_HEARTBEAT); return true; } //============================================================================ // 0x0002 状态反馈域编解码 // 数据域 144 字节 //============================================================================ namespace { // 数据域内各字段偏移(相对数据域起点,offset = 文档字节号 - 7) // 注意:文档中"系统故障等级"为字节19(1字节),字节20为隐式保留位, // "系统发电功率"从字节21(offset 14)开始,其后的字段均按此定位。 enum : size_t { OFF_MODE = 0, // 运行模式 (字节7) OFF_STATUS = 1, // 运行状态 (字节8) OFF_FL1 = 2, // 一级故障码 u16 (字节9-10) OFF_FL2 = 4, // 二级故障码 (字节11-12) OFF_FL3 = 6, // 三级故障码 (字节13-14) OFF_FL4 = 8, // 四级故障码 (字节15-16) OFF_GEN_TIME = 10, // 累积发电时间 u16 (字节17-18) OFF_FAULT_LEVEL = 12, // 系统故障等级 (字节19) // 字节20 隐式保留(offset 13) OFF_GEN_POWER = 14, // 系统发电功率 u16 (字节21-22) OFF_H2_CAP = 16, // 储氢剩余容量 (字节23) OFF_LO2_CAP = 17, // 液氧剩余容量 (字节24) OFF_FC1_MIN_V = 18, // I#FC最低单片电压 (字节25) OFF_FC1_MIN_POS = 19, // I#FC最低单片电压位置 (字节26) OFF_FC1_AVG_V = 20, // I#FC平均单片电压 (字节27) OFF_FC2_MIN_V = 21, // 2#FC最低单片电压 (字节28) OFF_FC2_MIN_POS = 22, // 2#FC最低单片电压位置 (字节29) OFF_FC2_AVG_V = 23, // 2#FC平均单片电压 (字节30) OFF_PALLADIUM_TEMP = 24, // 钯膜最高温度 u16 (字节31-32) OFF_BUFFER_PRES = 26, // 缓冲罐压力 (字节33-34) OFF_FLUE_TOTAL = 28, // 烟气累计排放量 (字节35-36) OFF_FLUE_PRES = 30, // 烟气压力 (字节37-38) OFF_REACTOR_PRES = 32, // 反应器压力 (字节39-40) OFF_EVALVE_OPEN = 34, // 电动阀开度 (字节41-42) OFF_DCDC1_IN_V = 36, // DC/DC通道1输入电压 (字节43-44) OFF_DCDC1_IN_I = 38, // DC/DC通道1输入电流 (字节45-46) OFF_DCDC2_IN_V = 40, // DC/DC通道2输入电压 (字节47-48) OFF_DCDC2_IN_I = 42, // DC/DC通道2输入电流 (字节49-50) OFF_DCDC_OUT_V = 44, // DC/DC输出电压 (字节51-52) OFF_DCDC_OUT_I = 46, // DC/DC输出电流 (字节53-54) OFF_DCDC_CTRL_V = 48, // DC/DC控制电源电压 (字节55) OFF_DCDC_AUX_V = 49, // DC/DC辅电输出电压 (字节56) OFF_METHANOL_TOTAL = 50, // 甲醇累计使用量 u16 (字节57-58) OFF_METHANOL_FEED = 52, // 甲醇溶液进料量 (字节59-60) OFF_O2_WATER = 54, // 氧侧生成水箱液位 (字节61-62) OFF_H2_WATER = 56, // 氢侧生成水箱液位 (字节63-64) OFF_BALLAST_WATER = 58, // 配重水箱液位 (字节65-66) OFF_EXH_IN_PRES = 60, // 尾气装置进气压力 (字节67-68) OFF_EXH_OUT_PRES = 62, // 尾气装置排气压力 (字节69-70) OFF_CABIN_P1 = 64, // 舱室压力1 (字节71-72) OFF_CABIN_P2 = 66, // 舱室压力2 (字节73-74) OFF_CABIN_T1 = 68, // 舱室温度1 (字节75-76) OFF_CABIN_T2 = 70, // 舱室温度2 (字节77-78) OFF_CABIN_H1 = 72, // 舱室湿度1 (字节79-80) OFF_CABIN_H2 = 74, // 舱室湿度2 (字节81-82) OFF_H2_C1 = 76, // 舱室H2浓度1 (字节83-84) OFF_H2_C2 = 78, // 舱室H2浓度2 (字节85-86) OFF_H2_C3 = 80, // 舱室H2浓度3 (字节87-88) OFF_O2_C1 = 82, // 舱室O2浓度1 (字节89-90) OFF_O2_C2 = 84, // 舱室O2浓度2 (字节91-92) OFF_CH3OH_C1 = 86, // 舱室甲醇浓度1 (字节93-94) OFF_CH3OH_C2 = 88, // 舱室甲醇浓度2 (字节95-96) OFF_FLAME1 = 90, // 火焰探测器1 (字节97) OFF_FLAME2 = 91, // 火焰探测器2 (字节98) OFF_EMER_DEPTH = 92, // 应急上浮深度 u16 (字节99-100) OFF_EMER_TIME = 94, // 应急上浮时间 (字节101-102) OFF_EXH_FREQ = 96, // 尾气运行频率 (字节103-104) OFF_EXH_IN_TEMP = 98, // 尾气进气温度 (字节105-106) OFF_EXH_OUT_TEMP = 100, // 尾气排气温度 (字节107-108) OFF_EXH_WIN_PRES = 102, // 尾气进水压力 (字节109-110) OFF_EXH_WOUT_PRES = 104, // 尾气排水压力 (字节111-112) OFF_TANK_LO2_PRES = 106, // 液氧罐压力 (字节113-114) OFF_TANK_CO2_PRES = 108, // 二氧化碳压力 (字节115-116) OFF_TANK_LO2_LEVEL = 110, // 液氧罐液位 (字节117-118) OFF_ALLOY_H2_FLOW = 112, // 合金供氢流量 (字节119-120) OFF_FC_H2_FLOW = 114, // FC供氢流量 (字节121-122) OFF_FC_O2_FLOW = 116, // FC供氧流量 (字节123-124) OFF_RESERVED = 118, // 预留1~11 u16*11 -> 118..138 (字节125-146) OFF_REMAIN_GEN = 140, // 剩余发电量 u16 (字节147,148),0827协议由预留12改为 OFF_HEARTBEAT = 142, // 通信心跳 (字节149) OFF_EMERGENCY_CMD = 143, // 应急指令 (字节150) }; inline void getU16Arr(const std::vector& frame, size_t off, uint16_t* dst, size_t n) { for (size_t i = 0; i < n; ++i) dst[i] = FieldCodec::getU16(frame, off + i * 2); } inline void putU16Arr(std::vector& p, size_t off, const uint16_t* src, size_t n) { for (size_t i = 0; i < n; ++i) FieldCodec::putU16(p, off + i * 2, src[i]); } } // namespace std::vector FcStatusMessage::encode(const void* obj) const { const FcStatusValue* v = static_cast(obj); std::vector p(payloadLength(), 0); FieldCodec::putU8(p, OFF_MODE, v->fc_mode); FieldCodec::putU8(p, OFF_STATUS, v->fc_status); FieldCodec::putU16(p, OFF_FL1, v->fault_level_1); FieldCodec::putU16(p, OFF_FL2, v->fault_level_2); FieldCodec::putU16(p, OFF_FL3, v->fault_level_3); FieldCodec::putU16(p, OFF_FL4, v->fault_level_4); FieldCodec::putU16(p, OFF_GEN_TIME, v->total_generation_time); FieldCodec::putU8(p, OFF_FAULT_LEVEL, v->fc_fault_level); FieldCodec::putU16(p, OFF_GEN_POWER, v->generation_power); FieldCodec::putU8(p, OFF_H2_CAP, v->hydrogen_capacity); FieldCodec::putU8(p, OFF_LO2_CAP, v->liquid_oxygen_capacity); FieldCodec::putU8(p, OFF_FC1_MIN_V, v->fc1_min_cell_voltage); FieldCodec::putU8(p, OFF_FC1_MIN_POS, v->fc1_min_cell_pos); FieldCodec::putU8(p, OFF_FC1_AVG_V, v->fc1_avg_cell_voltage); FieldCodec::putU8(p, OFF_FC2_MIN_V, v->fc2_min_cell_voltage); FieldCodec::putU8(p, OFF_FC2_MIN_POS, v->fc2_min_cell_pos); FieldCodec::putU8(p, OFF_FC2_AVG_V, v->fc2_avg_cell_voltage); FieldCodec::putU16(p, OFF_PALLADIUM_TEMP, v->palladium_temp); FieldCodec::putU16(p, OFF_BUFFER_PRES, v->buffer_tank_pressure); FieldCodec::putU16(p, OFF_FLUE_TOTAL, v->flue_total_emission); FieldCodec::putU16(p, OFF_FLUE_PRES, v->flue_pressure); FieldCodec::putU16(p, OFF_REACTOR_PRES, v->reactor_pressure); FieldCodec::putU16(p, OFF_EVALVE_OPEN, v->electric_valve_open); FieldCodec::putU16(p, OFF_DCDC1_IN_V, v->dcdc1_in_voltage); FieldCodec::putU16(p, OFF_DCDC1_IN_I, v->dcdc1_in_current); FieldCodec::putU16(p, OFF_DCDC2_IN_V, v->dcdc2_in_voltage); FieldCodec::putU16(p, OFF_DCDC2_IN_I, v->dcdc2_in_current); FieldCodec::putU16(p, OFF_DCDC_OUT_V, v->dcdc_out_voltage); FieldCodec::putU16(p, OFF_DCDC_OUT_I, v->dcdc_out_current); FieldCodec::putU8(p, OFF_DCDC_CTRL_V, v->dcdc_ctrl_voltage); FieldCodec::putU8(p, OFF_DCDC_AUX_V, v->dcdc_aux_voltage); FieldCodec::putU16(p, OFF_METHANOL_TOTAL, v->methanol_total_use); FieldCodec::putU16(p, OFF_METHANOL_FEED, v->methanol_feed); FieldCodec::putU16(p, OFF_O2_WATER, v->oxygen_side_water_level); FieldCodec::putU16(p, OFF_H2_WATER, v->hydrogen_side_water_level); FieldCodec::putU16(p, OFF_BALLAST_WATER, v->ballast_water_level); FieldCodec::putU16(p, OFF_EXH_IN_PRES, v->exhaust_inlet_pressure); FieldCodec::putU16(p, OFF_EXH_OUT_PRES, v->exhaust_outlet_pressure); FieldCodec::putU16(p, OFF_CABIN_P1, v->cabin_pressure1); FieldCodec::putU16(p, OFF_CABIN_P2, v->cabin_pressure2); FieldCodec::putU16(p, OFF_CABIN_T1, v->cabin_temp1); FieldCodec::putU16(p, OFF_CABIN_T2, v->cabin_temp2); FieldCodec::putU16(p, OFF_CABIN_H1, v->cabin_humidity1); FieldCodec::putU16(p, OFF_CABIN_H2, v->cabin_humidity2); FieldCodec::putU16(p, OFF_H2_C1, v->h2_concentration1); FieldCodec::putU16(p, OFF_H2_C2, v->h2_concentration2); FieldCodec::putU16(p, OFF_H2_C3, v->h2_concentration3); FieldCodec::putU16(p, OFF_O2_C1, v->o2_concentration1); FieldCodec::putU16(p, OFF_O2_C2, v->o2_concentration2); FieldCodec::putU16(p, OFF_CH3OH_C1, v->ch3oh_concentration1); FieldCodec::putU16(p, OFF_CH3OH_C2, v->ch3oh_concentration2); FieldCodec::putU8(p, OFF_FLAME1, v->flame_detector1); FieldCodec::putU8(p, OFF_FLAME2, v->flame_detector2); FieldCodec::putU16(p, OFF_EMER_DEPTH, v->emergency_float_depth); FieldCodec::putU16(p, OFF_EMER_TIME, v->emergency_float_time); FieldCodec::putU16(p, OFF_EXH_FREQ, v->exhaust_run_freq); FieldCodec::putU16(p, OFF_EXH_IN_TEMP, v->exhaust_inlet_temp); FieldCodec::putU16(p, OFF_EXH_OUT_TEMP, v->exhaust_outlet_temp); FieldCodec::putU16(p, OFF_EXH_WIN_PRES, v->exhaust_water_in_pressure); FieldCodec::putU16(p, OFF_EXH_WOUT_PRES, v->exhaust_water_out_pressure); FieldCodec::putU16(p, OFF_TANK_LO2_PRES, v->tank_lo2_pressure); FieldCodec::putU16(p, OFF_TANK_CO2_PRES, v->tank_co2_pressure); FieldCodec::putU16(p, OFF_TANK_LO2_LEVEL, v->tank_lo2_level); FieldCodec::putU16(p, OFF_ALLOY_H2_FLOW, v->alloy_h2_flow); FieldCodec::putU16(p, OFF_FC_H2_FLOW, v->fc_h2_flow); FieldCodec::putU16(p, OFF_FC_O2_FLOW, v->fc_o2_flow); putU16Arr(p, OFF_RESERVED, v->reserved, 11); FieldCodec::putU16(p, OFF_REMAIN_GEN, v->remaining_generation); FieldCodec::putU8(p, OFF_HEARTBEAT, v->heartbeat); FieldCodec::putU8(p, OFF_EMERGENCY_CMD, v->emergency_cmd); return Frame::build(id(), p, checksum()); } bool FcStatusMessage::decode(const std::vector& frame, void* obj) const { if (!validateFrame(frame, id(), checksum(), totalLength())) return false; FcStatusValue* v = static_cast(obj); size_t o = FRAME_HEADER_LEN; v->fc_mode = FieldCodec::getU8(frame, o + OFF_MODE); v->fc_status = FieldCodec::getU8(frame, o + OFF_STATUS); v->fault_level_1 = FieldCodec::getU16(frame, o + OFF_FL1); v->fault_level_2 = FieldCodec::getU16(frame, o + OFF_FL2); v->fault_level_3 = FieldCodec::getU16(frame, o + OFF_FL3); v->fault_level_4 = FieldCodec::getU16(frame, o + OFF_FL4); v->total_generation_time = FieldCodec::getU16(frame, o + OFF_GEN_TIME); v->fc_fault_level = FieldCodec::getU8(frame, o + OFF_FAULT_LEVEL); v->generation_power = FieldCodec::getU16(frame, o + OFF_GEN_POWER); v->hydrogen_capacity = FieldCodec::getU8(frame, o + OFF_H2_CAP); v->liquid_oxygen_capacity = FieldCodec::getU8(frame, o + OFF_LO2_CAP); v->fc1_min_cell_voltage = FieldCodec::getU8(frame, o + OFF_FC1_MIN_V); v->fc1_min_cell_pos = FieldCodec::getU8(frame, o + OFF_FC1_MIN_POS); v->fc1_avg_cell_voltage = FieldCodec::getU8(frame, o + OFF_FC1_AVG_V); v->fc2_min_cell_voltage = FieldCodec::getU8(frame, o + OFF_FC2_MIN_V); v->fc2_min_cell_pos = FieldCodec::getU8(frame, o + OFF_FC2_MIN_POS); v->fc2_avg_cell_voltage = FieldCodec::getU8(frame, o + OFF_FC2_AVG_V); v->palladium_temp = FieldCodec::getU16(frame, o + OFF_PALLADIUM_TEMP); v->buffer_tank_pressure = FieldCodec::getU16(frame, o + OFF_BUFFER_PRES); v->flue_total_emission = FieldCodec::getU16(frame, o + OFF_FLUE_TOTAL); v->flue_pressure = FieldCodec::getU16(frame, o + OFF_FLUE_PRES); v->reactor_pressure = FieldCodec::getU16(frame, o + OFF_REACTOR_PRES); v->electric_valve_open = FieldCodec::getU16(frame, o + OFF_EVALVE_OPEN); v->dcdc1_in_voltage = FieldCodec::getU16(frame, o + OFF_DCDC1_IN_V); v->dcdc1_in_current = FieldCodec::getU16(frame, o + OFF_DCDC1_IN_I); v->dcdc2_in_voltage = FieldCodec::getU16(frame, o + OFF_DCDC2_IN_V); v->dcdc2_in_current = FieldCodec::getU16(frame, o + OFF_DCDC2_IN_I); v->dcdc_out_voltage = FieldCodec::getU16(frame, o + OFF_DCDC_OUT_V); v->dcdc_out_current = FieldCodec::getU16(frame, o + OFF_DCDC_OUT_I); v->dcdc_ctrl_voltage = FieldCodec::getU8(frame, o + OFF_DCDC_CTRL_V); v->dcdc_aux_voltage = FieldCodec::getU8(frame, o + OFF_DCDC_AUX_V); v->methanol_total_use = FieldCodec::getU16(frame, o + OFF_METHANOL_TOTAL); v->methanol_feed = FieldCodec::getU16(frame, o + OFF_METHANOL_FEED); v->oxygen_side_water_level= FieldCodec::getU16(frame, o + OFF_O2_WATER); v->hydrogen_side_water_level = FieldCodec::getU16(frame, o + OFF_H2_WATER); v->ballast_water_level = FieldCodec::getU16(frame, o + OFF_BALLAST_WATER); v->exhaust_inlet_pressure = FieldCodec::getU16(frame, o + OFF_EXH_IN_PRES); v->exhaust_outlet_pressure= FieldCodec::getU16(frame, o + OFF_EXH_OUT_PRES); v->cabin_pressure1 = FieldCodec::getU16(frame, o + OFF_CABIN_P1); v->cabin_pressure2 = FieldCodec::getU16(frame, o + OFF_CABIN_P2); v->cabin_temp1 = FieldCodec::getU16(frame, o + OFF_CABIN_T1); v->cabin_temp2 = FieldCodec::getU16(frame, o + OFF_CABIN_T2); v->cabin_humidity1 = FieldCodec::getU16(frame, o + OFF_CABIN_H1); v->cabin_humidity2 = FieldCodec::getU16(frame, o + OFF_CABIN_H2); v->h2_concentration1 = FieldCodec::getU16(frame, o + OFF_H2_C1); v->h2_concentration2 = FieldCodec::getU16(frame, o + OFF_H2_C2); v->h2_concentration3 = FieldCodec::getU16(frame, o + OFF_H2_C3); v->o2_concentration1 = FieldCodec::getU16(frame, o + OFF_O2_C1); v->o2_concentration2 = FieldCodec::getU16(frame, o + OFF_O2_C2); v->ch3oh_concentration1 = FieldCodec::getU16(frame, o + OFF_CH3OH_C1); v->ch3oh_concentration2 = FieldCodec::getU16(frame, o + OFF_CH3OH_C2); v->flame_detector1 = FieldCodec::getU8(frame, o + OFF_FLAME1); v->flame_detector2 = FieldCodec::getU8(frame, o + OFF_FLAME2); v->emergency_float_depth = FieldCodec::getU16(frame, o + OFF_EMER_DEPTH); v->emergency_float_time = FieldCodec::getU16(frame, o + OFF_EMER_TIME); v->exhaust_run_freq = FieldCodec::getU16(frame, o + OFF_EXH_FREQ); v->exhaust_inlet_temp = FieldCodec::getU16(frame, o + OFF_EXH_IN_TEMP); v->exhaust_outlet_temp = FieldCodec::getU16(frame, o + OFF_EXH_OUT_TEMP); v->exhaust_water_in_pressure = FieldCodec::getU16(frame, o + OFF_EXH_WIN_PRES); v->exhaust_water_out_pressure= FieldCodec::getU16(frame, o + OFF_EXH_WOUT_PRES); v->tank_lo2_pressure = FieldCodec::getU16(frame, o + OFF_TANK_LO2_PRES); v->tank_co2_pressure = FieldCodec::getU16(frame, o + OFF_TANK_CO2_PRES); v->tank_lo2_level = FieldCodec::getU16(frame, o + OFF_TANK_LO2_LEVEL); v->alloy_h2_flow = FieldCodec::getU16(frame, o + OFF_ALLOY_H2_FLOW); v->fc_h2_flow = FieldCodec::getU16(frame, o + OFF_FC_H2_FLOW); v->fc_o2_flow = FieldCodec::getU16(frame, o + OFF_FC_O2_FLOW); getU16Arr(frame, o + OFF_RESERVED, v->reserved, 11); v->remaining_generation = FieldCodec::getU16(frame, o + OFF_REMAIN_GEN); v->heartbeat = FieldCodec::getU8(frame, o + OFF_HEARTBEAT); v->emergency_cmd = FieldCodec::getU8(frame, o + OFF_EMERGENCY_CMD); return true; } } // namespace ccu