17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-10-17 05:09:20 +02:00

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.
This commit is contained in:
2026-09-05 20:41:59 +00:00
parent 6bfd21d135
commit 40df8e84f6
4 changed files with 20 additions and 166 deletions

View File

@@ -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

View File

@@ -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 ); } );

View File

@@ -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<float>(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<std::string, zmq_input::output_fields> 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);
}

View File

@@ -2,45 +2,10 @@
#include <zmq_addon.hpp>
#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<zmq::socket_t> sock;
@@ -55,7 +20,8 @@ class zmq_input
struct peer_state {
float update_interval;
std::vector<output_fields> sopi_list;
// symbols this peer subscribed to, resolved through the shared TrainState registry
std::vector<hardware::state_descriptor const *> sopi_list;
std::vector<std::tuple<input_type, user_command, user_command, bool>> sipo_list;;
std::chrono::time_point<std::chrono::high_resolution_clock> 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<std::string, user_command> nametocommandmap;
static std::unordered_map<std::string, output_fields> output_fields_map;
command_relay relay;
public: