//======================================================================= // full_feeder.cpp: 集成测试用 — 仿真真实 CCU + 配电系统,向 pPowerManger // 发送全部 5 类状态反馈 UDP 消息(CCU 状态 + 4 路配电反馈)。 // 直接使用真实 C++ 结构体构造消息(字节级与协议一致,无打包漂移)。 // 用法: fullFeeder [host] [port] [rounds] [interval_ms] // rounds=0 表示持续发送直到被 kill。 //======================================================================= #include #include #include #include #include #include #include #include #include #include "udpcomm/ccuUdpMsg.h" static int g_fd = -1; static sockaddr_in g_addr{}; static bool sendBuf(const void* buf, size_t len) { ssize_t n = sendto(g_fd, buf, len, 0, reinterpret_cast(&g_addr), sizeof(g_addr)); return n == (ssize_t)len; } // CCU 消息校验和:4 字节全宽(sum 覆盖 sizeof-4 字节) static unsigned int ccuChecksum(const unsigned char* d, int size) { unsigned int s = 0; for (int i = 0; i < size - (int)sizeof(Checksum); ++i) s += d[i]; return s; } // 配电消息校验和:1 字节(sum 覆盖 sizeof-1 字节,&0xFF) static unsigned char disChecksum(const unsigned char* d, int size) { unsigned int s = 0; for (int i = 0; i < size - (int)sizeof(cChecksum); ++i) s += d[i]; return (unsigned char)(s & 0xFF); } static void fillCcuState(msg_CcuStateFbMsg& m, unsigned int beat) { memset(&m, 0, sizeof(m)); m.header.start1 = CCU_UDPMSG_START1; m.header.start2 = CCU_UDPMSG_START2; m.header.id = CCU_STATE_FB_ID; m.header.length = sizeof(msg_CcuStateFbMsg); // 域字节数为整个协议包长度 m.data.fc_mode = 0x02; // 自动 m.data.fc_status = 0x06; // 运行 m.data.fc_fault_level = 0x00; // 无故障 m.data.output_power_limit = 30000; m.data.total_generation_time = 1234; m.data.total_generation_power = 8000; m.data.hydrogen_capacity = 70; m.data.liquid_oxygen_capacity = 65; m.data.fc1_min_cell_voltage = 85; // 850mV m.data.fc1_min_cell_pos = 12; m.data.fc1_avg_cell_voltage = 90; // 900mV m.data.fc2_min_cell_voltage = 84; m.data.fc2_min_cell_pos = 8; m.data.fc2_avg_cell_voltage = 89; m.data.palladium_temp = 600; // 60.0℃ m.data.buffer_tank_pressure = 200; // 20.0kPa m.data.flue_total_emission = 500; // 50.0kg m.data.flue_pressure = 20000; // 20.000MPa m.data.reactor_pressure = 30000; // 30.000MPa m.data.electric_valve_open = 500; // 50.0% m.data.main_pipe_pressure = 2000; // 20.00kPa m.data.aux_pipe_pressure = 1800; m.data.dcdc1_in_voltage = 700; // 70.0V m.data.dcdc1_in_current = 120; // 12.0A m.data.dcdc2_in_voltage = 700; m.data.dcdc2_in_current = 120; m.data.dcdc_out_voltage = 4800; // 480.0V m.data.dcdc_out_current = 160; // 16.0A m.data.dcdc_control_voltage = 100; // 25.0V m.data.dcdc_aux_out_voltage = 100; // 12.5V m.data.methanol_total_usage = 1000; // 100.0kg m.data.methanol_solution_feed = 100; // 100mL/min m.data.oxygen_water_tank_level = 50000; // 500.00mm m.data.hydrogen_water_tank_level = 45000; m.data.ballast_water_tank_level = 40000; m.data.exhaust_in_pressure = 2000; // 20.00MPa m.data.exhaust_out_pressure = 1800; m.data.exhaust_run_freq = 5000; // 50.00Hz m.data.exhaust_in_temp = 6000; // 60.00℃ m.data.exhaust_out_temp = 5500; m.data.exhaust_in_water_pressure = 3000; // 30.00kPa m.data.exhaust_out_water_pressure = 2800; m.data.tank_lo2_pressure = 1000; // 10.00MPa m.data.tank_co2_pressure = 800; m.data.tank_lo2_level = 20000; // 200.00mm m.data.alloy_h2_flow = 500; // 5.00L/min m.data.fc_h2_flow = 450; m.data.fc_o2_flow = 300; m.data.emergency_float_depth = 50; // 50m m.data.emergency_float_time = 20; // 20min m.data.cabin_pressure1 = 10100; // 101.00kPa m.data.cabin_pressure2 = 10100; m.data.cabin_temp1 = 2500; // 25.00℃ m.data.cabin_temp2 = 2600; m.data.cabin_humidity1 = 5000; // 50.00%RH m.data.cabin_humidity2 = 5200; m.data.flame_detector1 = 0x00; m.data.flame_detector2 = 0x00; m.data.h2_concentration1 = 500; // 5.00%LEL m.data.o2_concentration1 = 200000; // 2000.00%Vol m.data.ch3oh_concentration1 = 300; m.data.emergency_battery1_voltage = 240; m.data.emergency_battery1_current = 10; m.data.emergency_battery1_max_temp = 30; m.data.emergency_battery2_voltage = 240; m.data.emergency_battery2_current = 10; m.data.emergency_battery2_max_temp = 31; m.data.cabin_ox_concentration = 2000; m.data.cabin_temperature = 250; m.data.cabin_humidity = 500; m.data.cabin_pressure = 1010; m.data.power_cabin_ox_concentration = 2000; m.data.power_cabin_temperature = 280; m.data.power_cabin_humidity = 480; m.data.power_cabin_pressure = 1010; m.data.ins_relay_status1 = 0x11; m.data.ins_relay_status2 = 0x12; m.data.dyn_relay_status1 = 0x11; m.data.dyn_relay_status2 = 0x12; m.data.ins_max_discharge_power = 200; m.data.dyn_max_discharge_power = 400; m.data.ins_soc = 85; m.data.dyn_soc = 80; m.data.ins_total_energy = 100; m.data.dyn_total_energy = 500; m.data.ins_power_input = 10; m.data.dyn_power_input = 30; m.data.ins_charge_status = 0x20; // 放电 m.data.dyn_charge_status = 0x20; m.data.ins_voltage_link = 2400; // 24.00V m.data.ins_voltage_pack = 2350; m.data.ins_current = 400; // 20.0A m.data.ins_resistance_pos = 999; m.data.ins_resistance_neg = 999; m.data.dyn_voltage_link = 5200; // 52.00V m.data.dyn_voltage_pack = 5150; m.data.dyn_current = 600; // 30.0A m.data.dyn_resistance_pos = 999; m.data.dyn_resistance_neg = 999; m.data.ins_emergency_status = 0x00; m.data.dyn_emergency_status = 0x00; m.data.ins_soc_threshold1 = 90; m.data.ins_soc_threshold2 = 80; m.data.ins_soc_threshold3 = 70; m.data.dyn_soc_threshold1 = 90; m.data.dyn_soc_threshold2 = 80; m.data.dyn_soc_threshold3 = 70; m.data.ins_power_limit1 = 8; m.data.ins_power_limit2 = 4; m.data.dyn_power_limit1 = 8; m.data.dyn_power_limit2 = 4; m.data.device_online_flag1 = 0x000000FF; m.data.device_online_flag2 = 0x0000001F; m.data.heartbeat = static_cast(beat); m.data.emergency_command = 0x03; m.checkCode = ccuChecksum(reinterpret_cast(&m), sizeof(m)); } static void fillDisHighVolBus(msg_disHighVolBusFbMsg& m) { memset(&m, 0, sizeof(m)); m.header.start1 = DIS_MSG_HEAD1; m.header.start2 = DIS_MSG_HEAD2; m.header.id = DIS_HVBUS_FB_ID; m.header.length = sizeof(disHighVolBusState); m.data.fuelCellCircuitBreaker = BREAK_ON; m.data.powerLithiumBatteryCircuitBreaker = BREAK_ON; m.data.propulsionMotorCircuitBreaker = BREAK_OFF; m.data.lithiumBatteryGroupInstrumentCircuitBreaker = BREAK_ON; m.data.dcDc5ModuleCircuitBreaker = BREAK_ON; m.data.bowHighVoltageDistributionBoxCircuitBreaker = BREAK_ON; m.data.sternFTDevice45CircuitBreaker = BREAK_OFF; m.data.sternRudderSwitch1CircuitBreaker = BREAK_OFF; m.data.sternRudderSwitch2CircuitBreaker = BREAK_OFF; m.data.fbReservedCircuitBreaker = BREAK_OFF; m.data.tyzReservedCircuitBreaker = BREAK_OFF; m.data.reservedCircuitBreaker = BREAK_OFF; m.data.dcDcFaultWord1 = 0x00; m.data.dcDcFaultWord2 = 0x62; // 工作状态启动 + 冷却泵运行 m.data.powerBusInsulationStatus = BREAK_ON; // 正常 m.data.aBusInsulationStatus = BREAK_ON; m.data.meterPowerLossSignal = BREAK_ON; m.data.emergencyPowerLossSignal = BREAK_ON; m.data.dcDcTemperature = 60; m.data.powerBusVoltage = 5000; // 500.0V m.data.dcDc5ModuleCurrent = 200; m.data.powerBusCurrent = 400; m.data.busbarAVoltage = 5000; m.data.propulsionMotorControlBoxCurrent = 10; m.data.busbarACurrent = 300; m.data.lithiumBatteryGroupMeterCurrent = 50; m.data.bowHighVoltageDistributionBoxCurrent = 100; m.data.sternFTDevice45Current = 0; m.data.tyzReservedSwitchCurrent = 0; m.data.sternRudderSwitch1Current = 0; m.data.sternRudderSwitch2Current = 0; m.data.coolWaterPressure = 150; m.checkCode = disChecksum(reinterpret_cast(&m), sizeof(m)); } static void fillDisHighAVolBus(msg_disHighAVolBusFbMsg& m) { memset(&m, 0, sizeof(m)); m.header.start1 = DIS_MSG_HEAD1; m.header.start2 = DIS_MSG_HEAD2; m.header.id = DIS_HVBUSA_FB_ID; m.header.length = sizeof(disHighAVolBusState); m.data.bowFTDevice123CircuitBreaker = BREAK_ON; m.data.actuatorCircuitBreaker = BREAK_OFF; m.data.mastSteeringGearControlBoxCircuitBreaker = BREAK_OFF; m.data.xczCircuitBreaker = BREAK_ON; m.data.bowRudderControlBoxCircuitBreaker = BREAK_OFF; m.data.openWaterCoverStartCylinderCircuitBreaker = BREAK_OFF; m.data.instrumentPowerFailureSignal = BREAK_ON; m.data.emergencyPowerFailureSignal = BREAK_ON; m.data.waterIngressionAlarm = BREAK_ON; // 正常 m.data.busbarBVoltage = 5000; m.data.busbarBCurrent = 300; m.data.bowFTDevice123Current = 80; m.data.actuatorCurrent = 0; m.data.mastSteeringGearControlBoxCurrent = 0; m.data.xczCurrent = 40; m.data.bowRudderControlBoxCurrent = 0; m.data.openWaterCoverStartCylinderCurrent = 0; m.checkCode = disChecksum(reinterpret_cast(&m), sizeof(m)); } static void fillDisLowMainBus(msg_disLowMainBusFbMsg& m) { memset(&m, 0, sizeof(m)); m.header.start1 = DIS_MSG_HEAD1; m.header.start2 = DIS_MSG_HEAD2; m.header.id = DIS_HVBUSB_FB_ID; m.header.length = sizeof(disLowMainBusState); m.data.lithiumBatteryGroupInstrumentCircuitBreaker = BREAK_ON; m.data.bowLowVoltageDistributionBoxCircuitBreaker = BREAK_ON; m.data.unit4InstrumentDC48VCircuitBreaker = BREAK_ON; m.data.dcC1DCDistributionPanelCircuitBreaker = BREAK_ON; m.data.reservedCircuitBreaker1 = BREAK_OFF; m.data.reservedCircuitBreaker2 = BREAK_OFF; m.data.emergencyLithiumBatteryGroup2CircuitBreaker = BREAK_ON; m.data.instrumentPowerFailureSignal = BREAK_ON; m.data.emergencyPowerFailureSignal = BREAK_ON; m.data.instrumentBusbarInsulationLow = BREAK_ON; // 正常 m.data.instrumentBusbarVoltage = 480; // 48.0V m.data.bowLowVoltageDistributionBoxCurrent = 50; m.data.dcC1InstrumentDC48VCurrent = 30; m.data.emergencyLithiumBatteryGroup2Current = 10; m.data.lithiumBatteryGroupInstrumentCurrent = 20; m.data.unit4InstrumentDC48VCurrent = 15; m.data.emergency2BusbarVoltage = 480; m.data.compositeEnergyManagementSystemEmergencyDC48VCurrent = 5; m.data.fuelCellSecuritySystemEmergencyDC48VCurrent = 5; m.data.plcControlPowerCurrent = 8; m.checkCode = disChecksum(reinterpret_cast(&m), sizeof(m)); } static void fillDisLowBus(msg_disLowBusFbMsg& m) { memset(&m, 0, sizeof(m)); m.header.start1 = DIS_MSG_HEAD1; m.header.start2 = DIS_MSG_HEAD2; m.header.id = DIS_LVBUS_FB_ID; m.header.length = sizeof(disLowBusState); m.data.unit1CircuitBreaker = BREAK_ON; m.data.unit2CircuitBreaker = BREAK_ON; m.data.unit3CircuitBreaker = BREAK_ON; m.data.unit5CircuitBreaker = BREAK_OFF; m.data.bowPZDeviceCircuitBreaker = BREAK_ON; m.data.reservedCircuitBreaker1 = BREAK_OFF; m.data.reservedCircuitBreaker2 = BREAK_OFF; m.data.emergencyLithiumBatteryGroup1CircuitBreaker = BREAK_ON; m.data.powerFailureSignal = BREAK_ON; m.data.emergencyPowerFailureSignal = BREAK_ON; m.data.waterIngressionAlarm = BREAK_ON; // 正常 m.data.instrumentBusbarVoltage = 240; // 24.0V m.data.instrumentBusbarCurrent = 60; m.data.unit1Current = 15; m.data.unit2Current = 15; m.data.unit3Current = 15; m.data.unit5Current = 0; m.data.bowPZDeviceCurrent = 10; m.data.emergencyLithiumBatteryGroup1Current = 8; m.data.emergency1BusbarVoltage = 240; m.checkCode = disChecksum(reinterpret_cast(&m), sizeof(m)); } int main(int argc, char* argv[]) { const char* host = (argc > 1) ? argv[1] : "127.0.0.1"; int port = (argc > 2) ? atoi(argv[2]) : 5001; int rounds = (argc > 3) ? atoi(argv[3]) : 0; // 0 = 持续 int intervalMs = (argc > 4) ? atoi(argv[4]) : 200; g_fd = socket(AF_INET, SOCK_DGRAM, 0); if (g_fd < 0) { perror("socket"); return 1; } g_addr.sin_family = AF_INET; g_addr.sin_port = htons(static_cast(port)); if (inet_pton(AF_INET, host, &g_addr.sin_addr) != 1) { perror("inet_pton"); close(g_fd); return 1; } unsigned int beat = 1; int sent = 0; while (rounds == 0 || sent < rounds) { msg_CcuStateFbMsg ccu; msg_disHighVolBusFbMsg hv; msg_disHighAVolBusFbMsg hva; msg_disLowMainBusFbMsg lvmain; msg_disLowBusFbMsg lv; fillCcuState(ccu, beat); fillDisHighVolBus(hv); fillDisHighAVolBus(hva); fillDisLowMainBus(lvmain); fillDisLowBus(lv); if (!sendBuf(&ccu, sizeof(ccu)) || !sendBuf(&hv, sizeof(hv)) || !sendBuf(&hva, sizeof(hva)) || !sendBuf(&lvmain, sizeof(lvmain)) || !sendBuf(&lv, sizeof(lv))) { perror("sendto"); break; } ++beat; ++sent; std::this_thread::sleep_for(std::chrono::milliseconds(intervalMs)); } close(g_fd); printf("sent %d round(s) of 5 message types to %s:%d\n", sent, host, port); return 0; }