Skip to content

Commit

Permalink
BlockPath: implement delayed release
Browse files Browse the repository at this point in the history
This simulates train still occupying turnouts while it has
already left the entrance ("from") block.
Useful when turnouts do not have dedicate occupancy detectors.

- New World property
- English and Italian translations
  • Loading branch information
gfgit committed Jul 29, 2024
1 parent ad0c2e1 commit cde858f
Show file tree
Hide file tree
Showing 7 changed files with 79 additions and 2 deletions.
48 changes: 48 additions & 0 deletions server/src/board/map/blockpath.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include "../tile/rail/linkrailtile.hpp"
#include "../tile/rail/nxbuttonrailtile.hpp"
#include "../../train/trainblockstatus.hpp"
#include "../../core/eventloop.hpp"
#include "../../core/objectproperty.tpp"
#include "../../enum/bridgepath.hpp"

Expand Down Expand Up @@ -297,10 +298,34 @@ BlockPath::BlockPath(BlockRailTile& block, BlockSide side)
: m_fromBlock{block}
, m_fromSide{side}
, m_toSide{static_cast<BlockSide>(-1)}
, m_delayReleaseTimer{EventLoop::ioContext}
, m_isReserved(false)
, m_delayedReleaseScheduled(false)
{
}

BlockPath::BlockPath(const BlockPath &other)
: Path(other)
, std::enable_shared_from_this<BlockPath>()
, m_fromBlock(other.m_fromBlock)
, m_fromSide(other.m_fromSide)
, m_toBlock(other.m_toBlock)
, m_toSide(other.m_toSide)
, m_tiles(other.m_tiles)
, m_turnouts(other.m_turnouts)
, m_directionControls(other.m_directionControls)
, m_crossings(other.m_crossings)
, m_bridges(other.m_bridges)
, m_signals(other.m_signals)
, m_nxButtonFrom(other.m_nxButtonFrom)
, m_nxButtonTo(other.m_nxButtonTo)
, m_delayReleaseTimer{EventLoop::ioContext}
, m_isReserved(false)
, m_delayedReleaseScheduled(false)
{

}

bool BlockPath::operator ==(const BlockPath& other) const noexcept
{
return
Expand Down Expand Up @@ -504,6 +529,9 @@ bool BlockPath::release(bool dryRun)
return false;
}

if(!dryRun)
m_delayReleaseTimer.cancel();

auto toBlock = m_toBlock.lock();
if(!toBlock) /*[[unlikely]]*/
return false;
Expand Down Expand Up @@ -629,3 +657,23 @@ bool BlockPath::release(bool dryRun)

return true;
}

bool BlockPath::delayedRelease(uint16_t timeoutMillis)
{
if(m_delayedReleaseScheduled)
return false;

m_delayedReleaseScheduled = true;

m_delayReleaseTimer.expires_after(boost::asio::chrono::milliseconds(timeoutMillis));
m_delayReleaseTimer.async_wait([this](const boost::system::error_code& ec)
{
m_delayedReleaseScheduled = false;

if(ec)
return;

release();
});
return true;
}
6 changes: 6 additions & 0 deletions server/src/board/map/blockpath.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include <array>
#include <vector>
#include <utility>
#include <boost/asio/steady_timer.hpp>
#include "../../enum/blockside.hpp"

class RailTile;
Expand Down Expand Up @@ -63,12 +64,16 @@ class BlockPath : public Path, public std::enable_shared_from_this<BlockPath>
std::vector<std::weak_ptr<SignalRailTile>> m_signals; //!< signals in path
std::weak_ptr<NXButtonRailTile> m_nxButtonFrom;
std::weak_ptr<NXButtonRailTile> m_nxButtonTo;

boost::asio::steady_timer m_delayReleaseTimer;
bool m_isReserved;
bool m_delayedReleaseScheduled;

public:
static std::vector<std::shared_ptr<BlockPath>> find(BlockRailTile& block);

BlockPath(BlockRailTile& block, BlockSide side);
BlockPath(const BlockPath& other);

bool operator ==(const BlockPath& other) const noexcept;

Expand Down Expand Up @@ -110,6 +115,7 @@ class BlockPath : public Path, public std::enable_shared_from_this<BlockPath>

bool reserve(const std::shared_ptr<Train>& train, bool dryRun = false);
bool release(bool dryRun = false);
bool delayedRelease(uint16_t timeoutMillis);
};

#endif
4 changes: 2 additions & 2 deletions server/src/board/tile/rail/blockrailtile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -335,11 +335,11 @@ void BlockRailTile::inputItemValueChanged(BlockInputMapItem& item)

if(blockTrainDirection == BlockTrainDirection::TowardsA && exitA)
{
pathA->release();
pathA->delayedRelease(m_world.pathReleaseDelay);
}
else if(blockTrainDirection == BlockTrainDirection::TowardsB && exitB)
{
pathB->release();
pathB->delayedRelease(m_world.pathReleaseDelay);
}
}
}
Expand Down
6 changes: 6 additions & 0 deletions server/src/world/world.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ World::World(Private /*unused*/) :
}},
correctOutputPosWhenLocked{this, "correct_output_pos_when_locked", true, PropertyFlags::ReadWrite | PropertyFlags::Store | PropertyFlags::NoScript},
extOutputChangeAction{this, "ext_output_change_action", ExternalOutputChangeAction::EmergencyStopTrain, PropertyFlags::ReadWrite | PropertyFlags::Store | PropertyFlags::NoScript},
pathReleaseDelay{this, "path_release_delay", 5000, PropertyFlags::ReadWrite | PropertyFlags::Store | PropertyFlags::NoScript},
decoderControllers{this, "input_controllers", nullptr, PropertyFlags::ReadOnly | PropertyFlags::SubObject | PropertyFlags::NoStore},
inputControllers{this, "input_controllers", nullptr, PropertyFlags::ReadOnly | PropertyFlags::SubObject | PropertyFlags::NoStore},
outputControllers{this, "output_controllers", nullptr, PropertyFlags::ReadOnly | PropertyFlags::SubObject | PropertyFlags::NoStore},
Expand Down Expand Up @@ -320,6 +321,11 @@ World::World(Private /*unused*/) :
Attributes::addValues(extOutputChangeAction, extOutputChangeActionValues);
m_interfaceItems.add(extOutputChangeAction);

Attributes::addCategory(pathReleaseDelay, Category::trains);
Attributes::addEnabled(pathReleaseDelay, true);
Attributes::addMinMax(pathReleaseDelay, {0, 15000}); // Up to 15 seconds
m_interfaceItems.add(pathReleaseDelay);

Attributes::addObjectEditor(decoderControllers, false);
m_interfaceItems.add(decoderControllers);
Attributes::addObjectEditor(inputControllers, false);
Expand Down
1 change: 1 addition & 0 deletions server/src/world/world.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ class World : public Object

Property<bool> correctOutputPosWhenLocked;
Property<ExternalOutputChangeAction> extOutputChangeAction;
Property<uint16_t> pathReleaseDelay;

ObjectProperty<ControllerList<DecoderController>> decoderControllers;
ObjectProperty<ControllerList<InputController>> inputControllers;
Expand Down
8 changes: 8 additions & 0 deletions shared/translations/en-us.json
Original file line number Diff line number Diff line change
Expand Up @@ -4502,6 +4502,14 @@
"reference": "",
"comment": ""
},
{
"term": "world:path_release_delay",
"definition": "Block Path release delay",
"context": "",
"term_plural": "",
"reference": "",
"comment": ""
},
{
"term": "world_scale:custom",
"definition": "Custom",
Expand Down
8 changes: 8 additions & 0 deletions shared/translations/it-it.json
Original file line number Diff line number Diff line change
Expand Up @@ -4502,6 +4502,14 @@
"reference": "",
"comment": ""
},
{
"term": "world:path_release_delay",
"definition": "Ritardo nella liberazione dell'itinerario",
"context": "",
"term_plural": "",
"reference": "",
"comment": ""
},
{
"term": "world_scale:custom",
"definition": "Custom",
Expand Down

0 comments on commit cde858f

Please sign in to comment.