From 40df8e84f6ad0a49f55e57aa59c1b21ca44d9c85 Mon Sep 17 00:00:00 2001 From: Hirek193 Date: Sat, 5 Sep 2026 20:41:59 +0000 Subject: [PATCH] zmq: read simulator state from the shared TrainState registry The zmq interface kept its own copy of the state field list, its own name table and its own packer. All three are now the shared registry, which resolves the same channel names and returns the same values, so the wire format is unchanged. New state exposed to external interfaces is added in one place from now on. The registry reports the raw velocity rather than zeroing it while the simulation is paused, and a symbol which doesn't apply to the current vehicle keeps its measurement and says so through its quality flag. --- CMakeLists.txt | 6 +- hardware/registry/state_registry.cpp | 7 +- input/zmq_input.cpp | 131 ++------------------------- input/zmq_input.h | 42 +-------- 4 files changed, 20 insertions(+), 166 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 96441e04..256de9c9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -268,6 +268,11 @@ if (WITH_UART) set(SOURCES ${SOURCES} "utilities/uart.cpp") endif() +if (WITH_HARDWARE_PROTOCOL_V2 OR WITH_ZMQ) + # shared TrainState registry, used both by the hardware protocol and by the zmq interface + set(SOURCES ${SOURCES} "hardware/registry/state_registry.cpp") +endif() + if (WITH_HARDWARE_PROTOCOL_V2) set(DEFINITIONS ${DEFINITIONS} "WITH_HARDWARE_PROTOCOL_V2") set(SOURCES ${SOURCES} @@ -278,7 +283,6 @@ if (WITH_HARDWARE_PROTOCOL_V2) "hardware/protocol/protocol_session.cpp" "hardware/registry/command_registry.cpp" "hardware/registry/hardware_symbol_registry.cpp" - "hardware/registry/state_registry.cpp" "hardware/subscriptions/subscription_manager.cpp") if (WITH_UART) # the serial transport is the only one which needs libserialport diff --git a/hardware/registry/state_registry.cpp b/hardware/registry/state_registry.cpp index 47151f92..916a2af5 100644 --- a/hardware/registry/state_registry.cpp +++ b/hardware/registry/state_registry.cpp @@ -12,7 +12,6 @@ http://mozilla.org/MPL/2.0/. #include "simulation/simulation.h" #include "simulation/simulationtime.h" -#include "utilities/Globals.h" namespace hardware { @@ -29,8 +28,10 @@ state_value make_value( state_snapshot const &Snapshot, value_type const Type, d false == Snapshot.available ? value_quality::unavailable : false == Applicable ? value_quality::not_applicable : value_quality::valid ); - if( result.quality != value_quality::valid ) + if( result.quality == value_quality::unavailable ) { + // there's nothing to report; a value which merely doesn't apply keeps whatever the + // simulator holds, the quality flag is what tells the device not to trust it result.numeric = 0.0; } return result; @@ -115,7 +116,7 @@ state_registry::state_registry() add( "radio_channel", value_type::uint8, "", 0.0, 15.0, []( state_snapshot const &s ) { return make_value( s, value_type::uint8, s.train.radio_channel ); } ); // measurements, in engineering units - add( "velocity", value_type::float32, "km/h", 0.0, 400.0, []( state_snapshot const &s ) { return make_value( s, value_type::float32, Global.iPause ? 0.0 : s.train.velocity ); } ); + add( "velocity", value_type::float32, "km/h", 0.0, 400.0, []( state_snapshot const &s ) { return make_value( s, value_type::float32, s.train.velocity ); } ); add( "reservoir_pressure", value_type::float32, "bar", 0.0, 16.0, []( state_snapshot const &s ) { return make_value( s, value_type::float32, s.train.reservoir_pressure ); } ); add( "pipe_pressure", value_type::float32, "bar", 0.0, 16.0, []( state_snapshot const &s ) { return make_value( s, value_type::float32, s.train.pipe_pressure ); } ); add( "brake_pressure", value_type::float32, "bar", 0.0, 16.0, []( state_snapshot const &s ) { return make_value( s, value_type::float32, s.train.brake_pressure ); } ); diff --git a/input/zmq_input.cpp b/input/zmq_input.cpp index 62fb41ee..d390bede 100644 --- a/input/zmq_input.cpp +++ b/input/zmq_input.cpp @@ -71,9 +71,9 @@ void zmq_input::poll() for (size_t i = 3; i < multipart.size(); i++) { std::string chan_name((char*)multipart[i].data(), multipart[i].size()); - auto chan_it = output_fields_map.find(chan_name); - if (chan_it != output_fields_map.end()) - peer_it->second.sopi_list.push_back(chan_it->second); + auto const *descriptor = hardware::state_registry::instance().find(chan_name); + if (descriptor != nullptr) + peer_it->second.sopi_list.push_back(descriptor); } } if (multipart[1] == zmq::message_t("REG_SIPO", 8)) { @@ -162,6 +162,9 @@ void zmq_input::poll() } } + hardware::state_snapshot snapshot; + hardware::state_registry::capture(snapshot); + auto now = std::chrono::high_resolution_clock::now(); for (auto peer = peers.begin(); peer != peers.end();) { @@ -183,8 +186,8 @@ void zmq_input::poll() msg.addmem(peerbuf, sizeof(peerbuf)); msg.addstr("SOPI_DATA"); - for (output_fields field : peer->second.sopi_list) - msg.add(pack_field(field)); + for (auto const *field : peer->second.sopi_list) + msg.add(pack_float(static_cast(field->getter(snapshot).numeric))); if (!msg.send(*sock, ZMQ_DONTWAIT)) peer = peers.erase(peer); @@ -192,121 +195,3 @@ void zmq_input::poll() ++peer; } } - -std::unordered_map zmq_input::output_fields_map = { - { "shp", output_fields::shp }, - { "alerter", output_fields::alerter }, - { "radio_stop", output_fields::radio_stop }, - { "motor_resistors", output_fields::motor_resistors }, - { "line_breaker", output_fields::line_breaker }, - { "motor_overload", output_fields::motor_overload }, - { "motor_connectors", output_fields::motor_connectors }, - { "wheelslip", output_fields::wheelslip }, - { "converter_overload", output_fields::converter_overload }, - { "converter_off", output_fields::converter_off }, - { "compressor_overload", output_fields::compressor_overload }, - { "ventilator_overload", output_fields::ventilator_overload }, - { "motor_overload_threshold", output_fields::motor_overload_threshold }, - { "train_heating", output_fields::train_heating }, - { "cab", output_fields::cab }, - { "recorder_braking", output_fields::recorder_braking }, - { "recorder_power", output_fields::recorder_power }, - { "alerter_sound",output_fields:: alerter_sound }, - { "coupled_hv_voltage_relays", output_fields::coupled_hv_voltage_relays }, - { "velocity", output_fields::velocity }, - { "reservoir_pressure", output_fields::reservoir_pressure }, - { "pipe_pressure", output_fields::pipe_pressure }, - { "brake_pressure", output_fields::brake_pressure }, - { "hv_voltage", output_fields::hv_voltage }, - { "hv_current_1", output_fields::hv_current_1 }, - { "hv_current_2", output_fields::hv_current_2 }, - { "hv_current_3", output_fields::hv_current_3 }, - { "lv_voltage", output_fields::lv_voltage }, - { "distance", output_fields::distance }, - { "radio_channel", output_fields::radio_channel }, - { "springbrake_active", output_fields::springbrake_active }, - { "time_month_of_era", output_fields::time_month_of_era }, - { "time_minute_of_month", output_fields::time_minute_of_month }, - { "time_millisecond_of_day", output_fields::time_millisecond_of_day } -}; - -zmq::message_t zmq_input::pack_field(zmq_input::output_fields f) { - const SYSTEMTIME time = simulation::Time.data(); - - if (f == output_fields::time_month_of_era) - return pack_float((time.wYear - 1) * 12 + time.wMonth - 1); - if (f == output_fields::time_minute_of_month) - return pack_float((time.wDay - 1) * 1440 + time.wHour * 60 + time.wMinute); - if (f == output_fields::time_millisecond_of_day) - return pack_float(time.wSecond * 1000 + time.wMilliseconds); - - TTrain *train = simulation::Train; - if (!train) - return pack_float(0.0f); - const TTrain::state_t state = train->get_state(); - - if (f == output_fields::shp) - return pack_float(state.shp); - if (f == output_fields::alerter) - return pack_float(state.alerter); - if (f == output_fields::radio_stop) - return pack_float(state.radio_stop); - if (f == output_fields::motor_resistors) - return pack_float(state.motor_resistors); - if (f == output_fields::line_breaker) - return pack_float(state.line_breaker); - if (f == output_fields::motor_overload) - return pack_float(state.motor_overload); - if (f == output_fields::motor_connectors) - return pack_float(state.motor_connectors); - if (f == output_fields::wheelslip) - return pack_float(state.wheelslip); - if (f == output_fields::converter_overload) - return pack_float(state.converter_overload); - if (f == output_fields::converter_off) - return pack_float(state.converter_off); - if (f == output_fields::compressor_overload) - return pack_float(state.compressor_overload); - if (f == output_fields::ventilator_overload) - return pack_float(state.ventilator_overload); - if (f == output_fields::motor_overload_threshold) - return pack_float(state.motor_overload_threshold); - if (f == output_fields::train_heating) - return pack_float(state.train_heating); - if (f == output_fields::cab) - return pack_float(state.cab); - if (f == output_fields::recorder_braking) - return pack_float(state.recorder_braking); - if (f == output_fields::recorder_power) - return pack_float(state.recorder_power); - if (f == output_fields::alerter_sound) - return pack_float(state.alerter_sound); - if (f == output_fields::coupled_hv_voltage_relays) - return pack_float(state.coupled_hv_voltage_relays); - if (f == output_fields::velocity) - return pack_float(state.velocity); - if (f == output_fields::reservoir_pressure) - return pack_float(state.reservoir_pressure); - if (f == output_fields::pipe_pressure) - return pack_float(state.pipe_pressure); - if (f == output_fields::brake_pressure) - return pack_float(state.brake_pressure); - if (f == output_fields::hv_voltage) - return pack_float(state.hv_voltage); - if (f == output_fields::hv_current_1) - return pack_float(state.hv_current[0]); - if (f == output_fields::hv_current_2) - return pack_float(state.hv_current[1]); - if (f == output_fields::hv_current_3) - return pack_float(state.hv_current[2]); - if (f == output_fields::lv_voltage) - return pack_float(state.lv_voltage); - if (f == output_fields::distance) - return pack_float(state.distance); - if (f == output_fields::radio_channel) - return pack_float(state.radio_channel); - if (f == output_fields::springbrake_active) - return pack_float(state.springbrake_active); - - return pack_float(0.0f); -} diff --git a/input/zmq_input.h b/input/zmq_input.h index 503a6a59..8ff0ab89 100644 --- a/input/zmq_input.h +++ b/input/zmq_input.h @@ -2,45 +2,10 @@ #include #include "input/command.h" +#include "hardware/registry/state_registry.h" class zmq_input { - enum class output_fields { - shp, - alerter, - radio_stop, - motor_resistors, - line_breaker, - motor_overload, - motor_connectors, - wheelslip, - converter_overload, - converter_off, - compressor_overload, - ventilator_overload, - motor_overload_threshold, - train_heating, - cab, - recorder_braking, - recorder_power, - alerter_sound, - coupled_hv_voltage_relays, - velocity, - reservoir_pressure, - pipe_pressure, - brake_pressure, - hv_voltage, - hv_current_1, - hv_current_2, - hv_current_3, - lv_voltage, - distance, - radio_channel, - springbrake_active, - time_month_of_era, - time_minute_of_month, - time_millisecond_of_day - }; zmq::context_t ctx; std::optional sock; @@ -55,7 +20,8 @@ class zmq_input struct peer_state { float update_interval; - std::vector sopi_list; + // symbols this peer subscribed to, resolved through the shared TrainState registry + std::vector sopi_list; std::vector> sipo_list;; std::chrono::time_point last_update; }; @@ -64,11 +30,9 @@ class zmq_input float unpack_float(const zmq::message_t &); zmq::message_t pack_float(float f); - zmq::message_t pack_field(output_fields f); std::unordered_map nametocommandmap; - static std::unordered_map output_fields_map; command_relay relay; public: