mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-11-15 22:14:10 +01:00
Merge pull request #291 from MaSzyna-EU07/fix/sod-lamp-whole-consist
SOD lamp: doors of the whole consist, three states (eu07/maszyna#288)
This commit is contained in:
@@ -261,6 +261,22 @@ enum class range_t
|
||||
/// <summary>Affects the entire consist.</summary>
|
||||
consist
|
||||
};
|
||||
/// <summary>State of the door closure signalling (SOD) of a vehicle or a consist, ordered from the least to the most
|
||||
/// severe: the state of a consist is the most severe state of its vehicles.</summary>
|
||||
enum class door_closure_t
|
||||
{
|
||||
/// <summary>No doors worked by the crew: the vehicle doesn't take part in the signalling.</summary>
|
||||
none,
|
||||
/// <summary>All doors closed and locked: they can't be opened.</summary>
|
||||
locked,
|
||||
/// <summary>All doors closed, but released: a permit is given, or no lock holds them shut.</summary>
|
||||
released,
|
||||
/// <summary>A door is open, or not fully closed yet.</summary>
|
||||
open
|
||||
};
|
||||
/// <summary>Whether the door closure signalling lamp is lit: steadily for locked doors, in the lit phase of the
|
||||
/// blinking for released ones, never with a door open or with no doors signalled.</summary>
|
||||
bool door_closure_lamp(door_closure_t const State, bool const BlinkLit);
|
||||
/// <summary>Possible settings for an enable/disable input pair (mutually exclusive).</summary>
|
||||
enum class operation_t
|
||||
{
|
||||
@@ -1439,6 +1455,7 @@ class TMoverParameters
|
||||
float auto_velocity{-1.f}; // automatic door closure velocity threshold
|
||||
bool auto_include_remote{false}; // automatic door closure applies also to remote control
|
||||
bool permit_needed{false};
|
||||
bool closure_signal{false}; // the door closure lamp (SOD) of the cab signals the doors of the whole consist in three states
|
||||
std::vector<int> permit_presets; // permit presets selectable with preset switch
|
||||
float voltage{0.f}; // power type required for door movement
|
||||
// ld inputs
|
||||
@@ -2593,6 +2610,10 @@ class TMoverParameters
|
||||
bool LockDoors(bool const State, range_t const Notify = range_t::consist);
|
||||
bool signal_departure(bool const State, range_t const Notify = range_t::consist); // toggles departure warning
|
||||
void update_doors(double const Deltatime); // door controller update
|
||||
door_closure_t door_closure() const; // state of the door closure signalling of this vehicle
|
||||
// whether the door closure lamp in the cab of this vehicle is lit: with DoorClosureSignal, for the given state of the
|
||||
// consist; without it, for the lock of the vehicle's own doors, as the lamp always worked
|
||||
bool door_closure_lamp_lit(door_closure_t const Consist, bool const BlinkLit) const;
|
||||
|
||||
/* funkcje dla samochodow*/
|
||||
bool ChangeOffsetH(double DeltaOffset);
|
||||
|
||||
@@ -8699,6 +8699,48 @@ bool TMoverParameters::signal_departure(bool const State, range_t const Notify)
|
||||
return true;
|
||||
}
|
||||
|
||||
// state of the door closure signalling (SOD) of this vehicle: open while a door isn't fully closed, released while
|
||||
// the closed doors can be opened (a permit given, or, for doors that need none, no lock engaged), locked otherwise.
|
||||
// doors the crew doesn't close (autonomous) aren't signalled, the same as for the door lights of the consist
|
||||
door_closure_t TMoverParameters::door_closure() const
|
||||
{
|
||||
if (Doors.range == 0.f || Doors.close_control == control_t::autonomous)
|
||||
{
|
||||
return door_closure_t::none;
|
||||
}
|
||||
if (std::ranges::any_of(Doors.instances, [](basic_door const &Door) { return false == Door.is_closed; }))
|
||||
{
|
||||
return door_closure_t::open;
|
||||
}
|
||||
if (Doors.is_locked)
|
||||
{
|
||||
return door_closure_t::locked;
|
||||
}
|
||||
if (Doors.permit_needed && std::ranges::none_of(Doors.instances, [](basic_door const &Door) { return Door.open_permit; }))
|
||||
{
|
||||
return door_closure_t::locked;
|
||||
}
|
||||
return door_closure_t::released;
|
||||
}
|
||||
|
||||
bool TMoverParameters::door_closure_lamp_lit(door_closure_t const Consist, bool const BlinkLit) const
|
||||
{
|
||||
return Doors.closure_signal ? door_closure_lamp(Consist, BlinkLit) : Doors.is_locked;
|
||||
}
|
||||
|
||||
bool door_closure_lamp(door_closure_t const State, bool const BlinkLit)
|
||||
{
|
||||
switch (State)
|
||||
{
|
||||
case door_closure_t::locked:
|
||||
return true;
|
||||
case door_closure_t::released:
|
||||
return BlinkLit;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// automatic door controller update
|
||||
void TMoverParameters::update_doors(double const Deltatime)
|
||||
{
|
||||
@@ -10576,6 +10618,8 @@ void TMoverParameters::LoadFIZ_Doors(std::string const &line)
|
||||
extract_value(Doors.auto_include_remote, "DoorAutoCloseRemote", line, "");
|
||||
// operation permit
|
||||
extract_value(Doors.permit_needed, "DoorNeedPermit", line, "");
|
||||
// the door closure lamp (SOD) of the cab signals the doors of the whole consist
|
||||
extract_value(Doors.closure_signal, "DoorClosureSignal", line, "");
|
||||
{
|
||||
auto permitpresets = Split(extract_value("DoorPermitList", line), '|');
|
||||
for (auto const &permit : permitpresets)
|
||||
|
||||
158
tests/unit/test_door_closure.cpp
Normal file
158
tests/unit/test_door_closure.cpp
Normal file
@@ -0,0 +1,158 @@
|
||||
#include "stdafx.h"
|
||||
#include "doctest.h"
|
||||
#include "scenario.h"
|
||||
#include "vehicle.h"
|
||||
|
||||
// the door closure signalling (SOD, the i-door_blocked lamp of a cab): the state of each vehicle's doors and of the
|
||||
// whole train, the most severe of its vehicles, as the driver gathers it for the lamp (eu07/maszyna#288)
|
||||
|
||||
using test::scenario;
|
||||
using test::definition;
|
||||
using test::vehicle;
|
||||
using namespace test::channels;
|
||||
|
||||
namespace {
|
||||
|
||||
// the state of the whole train, the way TController::determine_consist_state() gathers it
|
||||
door_closure_t consist_closure(scenario &Scenario) {
|
||||
auto closure{door_closure_t::none};
|
||||
for (std::size_t i = 0; i < Scenario.train().size(); ++i) {
|
||||
closure = std::max(closure, Scenario.vehicle(i).door_closure());
|
||||
}
|
||||
return closure;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("door closure: the lamp is lit for locked doors, blinks for released ones and is dark for open ones") {
|
||||
for (auto const lit : {true, false}) {
|
||||
CAPTURE(lit);
|
||||
CHECK(door_closure_lamp(door_closure_t::locked, lit));
|
||||
CHECK(door_closure_lamp(door_closure_t::released, lit) == lit);
|
||||
CHECK_FALSE(door_closure_lamp(door_closure_t::open, lit));
|
||||
CHECK_FALSE(door_closure_lamp(door_closure_t::none, lit));
|
||||
}
|
||||
// a consist takes the most severe state of its vehicles
|
||||
CHECK(std::max(door_closure_t::none, door_closure_t::locked) == door_closure_t::locked);
|
||||
CHECK(std::max(door_closure_t::locked, door_closure_t::released) == door_closure_t::released);
|
||||
CHECK(std::max(door_closure_t::released, door_closure_t::open) == door_closure_t::open);
|
||||
}
|
||||
|
||||
TEST_CASE("door closure: a unit with permits, locked, released by the permit and open, in any of its cars") {
|
||||
scenario scenario{"door closure/elf", motion() + doors()};
|
||||
scenario.add("elf_v1/21we-a", 1).add("elf_v1/21we-b").add("elf_v1/21we-c");
|
||||
scenario.start_up();
|
||||
auto &cab{scenario.cab()};
|
||||
auto &last{scenario.vehicle(scenario.train().size() - 1)};
|
||||
// closed with no permit: no door can be opened
|
||||
CHECK(cab.door_closure() == door_closure_t::locked);
|
||||
CHECK(last.door_closure() == door_closure_t::locked);
|
||||
CHECK(consist_closure(scenario) == door_closure_t::locked);
|
||||
|
||||
scenario.act("permit left");
|
||||
cab.PermitDoors(side::left, true);
|
||||
scenario.wait(2.0);
|
||||
CHECK(last.door_closure() == door_closure_t::released);
|
||||
CHECK(consist_closure(scenario) == door_closure_t::released);
|
||||
|
||||
scenario.act("the last car opens its own door");
|
||||
last.OperateDoors(side::left, true, range_t::local);
|
||||
scenario.wait(5.0);
|
||||
// the cab's own doors stay closed, the train is open all the same
|
||||
CHECK(cab.door_closure() == door_closure_t::released);
|
||||
CHECK(last.door_closure() == door_closure_t::open);
|
||||
CHECK(consist_closure(scenario) == door_closure_t::open);
|
||||
|
||||
scenario.act("close, the steps stay out under the permit");
|
||||
last.OperateDoors(side::left, false, range_t::local);
|
||||
cab.OperateDoors(side::left, false);
|
||||
scenario.wait(10.0);
|
||||
CHECK(last.Doors.instances[side::left].position <= 0.f);
|
||||
// a step out isn't a closed door
|
||||
CHECK(consist_closure(scenario) == door_closure_t::open);
|
||||
|
||||
scenario.act("revoke the permit");
|
||||
cab.PermitDoors(side::left, false);
|
||||
scenario.wait(10.0);
|
||||
CHECK(consist_closure(scenario) == door_closure_t::locked);
|
||||
}
|
||||
|
||||
TEST_CASE("door closure: the doors of a unit without permits are released at a standstill") {
|
||||
scenario scenario{"door closure/en57", motion() + doors()};
|
||||
scenario.add("en57_v1/5bgaiii_led_spot", 1).add("en57_v1/6ba_840").add("en57_v1/5bgb");
|
||||
scenario.start_up();
|
||||
auto &cab{scenario.cab()};
|
||||
auto &middle{scenario.vehicle(1)};
|
||||
REQUIRE_FALSE(cab.Doors.permit_needed);
|
||||
REQUIRE(middle.Doors.permit_needed);
|
||||
// the door lock engages only once the train runs (DoorLockSpeed), till then the end cars' doors can be opened
|
||||
CHECK(cab.door_closure() == door_closure_t::released);
|
||||
CHECK(middle.door_closure() == door_closure_t::locked);
|
||||
CHECK(consist_closure(scenario) == door_closure_t::released);
|
||||
scenario.act("open right");
|
||||
cab.OperateDoors(side::right, true);
|
||||
scenario.wait(10.0);
|
||||
CHECK(consist_closure(scenario) == door_closure_t::open);
|
||||
scenario.act("close right");
|
||||
cab.OperateDoors(side::right, false);
|
||||
scenario.wait(10.0);
|
||||
CHECK(consist_closure(scenario) == door_closure_t::released);
|
||||
}
|
||||
|
||||
TEST_CASE("door closure: a locomotive has no doors to signal, its coach does") {
|
||||
scenario scenario{"door closure/eu07 with a coach", motion() + doors()};
|
||||
scenario.add("4e_v1/4e", 1).add("bdhpumn_v3/bdhpumn");
|
||||
scenario.start_up();
|
||||
CHECK(scenario.cab().door_closure() == door_closure_t::none);
|
||||
scenario.act("open right");
|
||||
scenario.cab().PermitDoors(side::right, true);
|
||||
scenario.cab().OperateDoors(side::right, true);
|
||||
scenario.wait(10.0);
|
||||
CHECK(scenario.vehicle(1).door_closure() == door_closure_t::open);
|
||||
CHECK(consist_closure(scenario) == door_closure_t::open);
|
||||
}
|
||||
|
||||
TEST_CASE("door closure: the signalling is switched on by DoorClosureSignal in the Doors section, off without it") {
|
||||
SUBCASE("without the key") {
|
||||
vehicle wagon{definition::load("wagon")};
|
||||
CHECK_FALSE(wagon->Doors.closure_signal);
|
||||
}
|
||||
SUBCASE("with the key") {
|
||||
vehicle wagon{definition::load("wagon").set("Doors", "DoorClosureSignal", "Yes")};
|
||||
CHECK(wagon->Doors.closure_signal);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("door closure: without DoorClosureSignal the lamp shows the lock of the vehicle's own doors, as before") {
|
||||
vehicle wagon{definition::load("wagon")};
|
||||
REQUIRE_FALSE(wagon->Doors.closure_signal);
|
||||
for (auto const locked : {true, false}) {
|
||||
wagon->Doors.is_locked = locked;
|
||||
for (auto const consist : {door_closure_t::none, door_closure_t::locked, door_closure_t::released, door_closure_t::open}) {
|
||||
for (auto const lit : {true, false}) {
|
||||
CAPTURE(locked);
|
||||
CAPTURE(static_cast<int>(consist));
|
||||
CAPTURE(lit);
|
||||
// no blinking at a standstill with the doors closed, whatever the consist does
|
||||
CHECK(wagon->door_closure_lamp_lit(consist, lit) == locked);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("door closure: with DoorClosureSignal the lamp shows the consist in three states") {
|
||||
vehicle wagon{definition::load("wagon").set("Doors", "DoorClosureSignal", "Yes")};
|
||||
REQUIRE(wagon->Doors.closure_signal);
|
||||
for (auto const locked : {true, false}) {
|
||||
// the vehicle's own lock doesn't matter, the consist does
|
||||
wagon->Doors.is_locked = locked;
|
||||
for (auto const lit : {true, false}) {
|
||||
CAPTURE(locked);
|
||||
CAPTURE(lit);
|
||||
CHECK(wagon->door_closure_lamp_lit(door_closure_t::locked, lit));
|
||||
CHECK(wagon->door_closure_lamp_lit(door_closure_t::released, lit) == lit);
|
||||
CHECK_FALSE(wagon->door_closure_lamp_lit(door_closure_t::open, lit));
|
||||
CHECK_FALSE(wagon->door_closure_lamp_lit(door_closure_t::none, lit));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6019,6 +6019,7 @@ TController::determine_consist_state() {
|
||||
IsAnyDoorOnlyOpen[ side::right ] = IsAnyDoorOnlyOpen[ side::left ] = false;
|
||||
IsAnyDoorOpen[ side::right ] = IsAnyDoorOpen[ side::left ] = false;
|
||||
IsAnyDoorPermitActive[ side::right ] = IsAnyDoorPermitActive[ side::left ] = false;
|
||||
auto doorclosure { door_closure_t::none };
|
||||
ConsistShade = 0.0;
|
||||
auto *p { pVehicles[ end::front ] }; // pojazd na czole składu
|
||||
double dy; // składowa styczna grawitacji, w przedziale <0,1>
|
||||
@@ -6080,12 +6081,14 @@ TController::determine_consist_state() {
|
||||
IsAnyDoorPermitActive[ side::right ] |= rightdoor.open_permit;
|
||||
IsAnyDoorPermitActive[ side::left ] |= leftdoor.open_permit;
|
||||
}
|
||||
doorclosure = std::max( doorclosure, vehicle->door_closure() );
|
||||
}
|
||||
// measure lighting level
|
||||
// TBD: apply weight (multiplier) to partially lit vehicles?
|
||||
ConsistShade += p->fShade > 0.0 ? p->fShade : 1.0;
|
||||
p = p->Next(); // pojazd podłączony z tyłu (patrząc od czoła)
|
||||
}
|
||||
DoorClosure = doorclosure;
|
||||
// calculate average amount of received sunlight
|
||||
ConsistShade /= iVehicles;
|
||||
|
||||
|
||||
@@ -637,6 +637,7 @@ private:
|
||||
bool IsAnyDoorOpen[ 2 ]; // state of door in the consist
|
||||
bool IsAnyDoorOnlyOpen[ 2 ]; // state of door in the consist regardless of step
|
||||
bool IsAnyDoorPermitActive[ 2 ]; // state of door permit in the consist
|
||||
door_closure_t DoorClosure{ door_closure_t::none }; // state of the door closure signalling (SOD) of the consist
|
||||
bool IsAnyLineBreakerOpen{ false }; // state of line breaker in all powered vehicles under control
|
||||
bool IsAnyConverterOverloadRelayOpen{ false }; // state of converter overload relays in all vehicles under control
|
||||
bool IsAnyMotorOverloadRelayOpen{ false }; // state of motor overload relays in all vehicles under control
|
||||
|
||||
@@ -9116,7 +9116,17 @@ bool TTrain::Update(double const Deltatime)
|
||||
btLampkaDoorLeft.Turn(DynamicObject->Mechanik->IsAnyDoorOpen[cab_to_end() == end::front ? side::left : side::right]);
|
||||
btLampkaDoorRight.Turn(DynamicObject->Mechanik->IsAnyDoorOpen[cab_to_end() == end::front ? side::right : side::left]);
|
||||
}
|
||||
btLampkaBlokadaDrzwi.Turn(mvOccupied->Doors.is_locked);
|
||||
if (DynamicObject->Mechanik != nullptr)
|
||||
{
|
||||
// with DoorClosureSignal in the definition of the cab's vehicle, the door closure signalling (SOD) of the whole
|
||||
// consist: lit with all doors closed and locked, blinking with them closed but released, dark with a door open.
|
||||
// without it, the lock of the vehicle's own doors, as before
|
||||
btLampkaBlokadaDrzwi.Turn(mvOccupied->door_closure_lamp_lit(DynamicObject->Mechanik->DoorClosure, simulation::Time.data().wSecond % 2 < 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
btLampkaBlokadaDrzwi.Turn(mvOccupied->Doors.is_locked);
|
||||
}
|
||||
btLampkaDoorLockOff.Turn(false == mvOccupied->Doors.lock_enabled);
|
||||
btLampkaDepartureSignal.Turn(mvControlled->DepartureSignal);
|
||||
btLampkaNapNastHam.Turn(mvControlled->DirActive != 0 && mvOccupied->EpFuse); // napiecie na nastawniku hamulcowym
|
||||
|
||||
Reference in New Issue
Block a user