signaling: improved 3 aspect signal

signal is now aware of next signal aspect
Dieser Commit ist enthalten in:
Reinder Feenstra 2023-11-26 23:51:55 +01:00
Ursprung 12e23c90a9
Commit 5c69cb107d
9 geänderte Dateien mit 180 neuen und 27 gelöschten Zeilen

Datei anzeigen

@ -84,6 +84,36 @@ bool AbstractSignalPath::requireReservation() const
return (m_signal.requireReservation == AutoYesNo::Yes || (m_signal.requireReservation == AutoYesNo::Auto && m_requireReservation));
}
const AbstractSignalPath::BlockItem* AbstractSignalPath::nextBlock(const Item* item) const
{
while(item)
{
if(const auto* blockItem = dynamic_cast<const BlockItem*>(item))
{
return blockItem;
}
item = item->next().get();
}
return nullptr;
}
std::tuple<const AbstractSignalPath::BlockItem*, const AbstractSignalPath::SignalItem*> AbstractSignalPath::nextBlockOrSignal(const Item* item) const
{
while(item)
{
if(const auto* blockItem = dynamic_cast<const BlockItem*>(item))
{
return {blockItem, nullptr};
}
if(const auto* signalItem = dynamic_cast<const SignalItem*>(item))
{
return {nullptr, signalItem};
}
item = item->next().get();
}
return {nullptr, nullptr};
}
void AbstractSignalPath::getBlockStates(tcb::span<BlockState> blockStates) const
{
size_t i = 0;
@ -135,13 +165,30 @@ std::unique_ptr<const AbstractSignalPath::Item> AbstractSignalPath::findBlocks(c
evaluate();
}));
const auto enterSide = (nextNode.getLink(0).get() == &link) ? BlockSide::A : BlockSide::B;
std::unique_ptr<const Item> next;
if(blocksAhead > 1)
if(const auto& nextLink = otherLink(nextNode, link))
next = findBlocks(nextNode, *nextLink, blocksAhead - 1);
return std::unique_ptr<const AbstractSignalPath::Item>{new BlockItem(block, std::move(next))};
return std::unique_ptr<const AbstractSignalPath::Item>{new BlockItem(block, enterSide, std::move(next))};
}
if(auto turnout = std::dynamic_pointer_cast<TurnoutRailTile>(tile))
if(auto signal = std::dynamic_pointer_cast<SignalRailTile>(tile))
{
if(const auto& nextLink = otherLink(nextNode, link))
{
m_connections.emplace_back(signal->aspectChanged.connect(
[this](const SignalRailTile& /*tile*/, SignalAspect /*aspect*/)
{
evaluate();
}));
return std::unique_ptr<const AbstractSignalPath::Item>{
new SignalItem(
signal,
findBlocks(nextNode, *nextLink, blocksAhead))};
}
}
else if(auto turnout = std::dynamic_pointer_cast<TurnoutRailTile>(tile))
{
m_connections.emplace_back(turnout->positionChanged.connect(
[this](const TurnoutRailTile& /*tile*/, TurnoutPosition /*position*/)

Datei anzeigen

@ -20,8 +20,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef TRAINTASTIC_SERVER_BOARD_MAP_SIGNALPATH_HPP
#define TRAINTASTIC_SERVER_BOARD_MAP_SIGNALPATH_HPP
#ifndef TRAINTASTIC_SERVER_BOARD_MAP_ABSTRACTSIGNALPATH_HPP
#define TRAINTASTIC_SERVER_BOARD_MAP_ABSTRACTSIGNALPATH_HPP
#include "path.hpp"
#include "link.hpp"
@ -30,6 +30,7 @@
#include <traintastic/enum/blockstate.hpp>
class BlockRailTile;
enum class BlockSide : uint8_t;
class TurnoutRailTile;
enum class TurnoutPosition : uint8_t;
class DirectionControlRailTile;
@ -47,7 +48,7 @@ class AbstractSignalPath : public Path
void setAspect(SignalAspect value) const;
private:
protected:
class Item
{
private:
@ -69,11 +70,13 @@ class AbstractSignalPath : public Path
{
private:
std::weak_ptr<BlockRailTile> m_block;
BlockSide m_enterSide;
std::unique_ptr<const Item> m_next;
public:
BlockItem(std::weak_ptr<BlockRailTile> block, std::unique_ptr<const Item> next_)
BlockItem(std::weak_ptr<BlockRailTile> block, BlockSide enterSide_, std::unique_ptr<const Item> next_)
: m_block{std::move(block)}
, m_enterSide{enterSide_}
, m_next{std::move(next_)}
{
}
@ -85,6 +88,34 @@ class AbstractSignalPath : public Path
std::shared_ptr<BlockRailTile> block() const noexcept;
BlockState blockState() const;
BlockSide enterSide() const
{
return m_enterSide;
}
};
class SignalItem : public Item
{
private:
std::weak_ptr<SignalRailTile> m_signal;
std::unique_ptr<const Item> m_next;
public:
SignalItem(std::weak_ptr<SignalRailTile> signal, std::unique_ptr<const Item> next_)
: m_signal{std::move(signal)}
, m_next{std::move(next_)}
{
}
const std::unique_ptr<const Item>& next() const final
{
return m_next;
}
std::shared_ptr<SignalRailTile> signal() const
{
return m_signal.lock();
}
};
class TurnoutItem : public Item
@ -121,6 +152,7 @@ class AbstractSignalPath : public Path
const std::unique_ptr<const Item>& next() const final;
};
private:
std::unique_ptr<const Item> m_root;
bool m_requireReservation = false;
std::vector<boost::signals2::connection> m_connections;
@ -144,6 +176,23 @@ class AbstractSignalPath : public Path
virtual SignalAspect determineAspect() const = 0;
const Item* root() const
{
return m_root.get();
}
const BlockItem* nextBlock(const Item* item) const;
inline const BlockItem* nextBlock() const
{
return nextBlock(root());
}
std::tuple<const BlockItem*, const SignalItem*> nextBlockOrSignal(const Item* item) const;
inline std::tuple<const BlockItem*, const SignalItem*> nextBlockOrSignal() const
{
return nextBlockOrSignal(root());
}
void getBlockStates(tcb::span<BlockState> blockStates) const;
std::shared_ptr<BlockRailTile> getBlock(size_t index) const;

Datei anzeigen

@ -310,7 +310,7 @@ bool BlockPath::reserve(const std::shared_ptr<Train>& train, bool dryRun)
return false;
}
if(!m_fromBlock.reserve(train, m_fromSide, dryRun))
if(!m_fromBlock.reserve(shared_from_this(), train, m_fromSide, dryRun))
{
assert(dryRun);
return false;
@ -318,7 +318,7 @@ bool BlockPath::reserve(const std::shared_ptr<Train>& train, bool dryRun)
if(auto toBlock = m_toBlock.lock()) /*[[likely]]*/
{
if(!toBlock->reserve(train, m_toSide, dryRun))
if(!toBlock->reserve(shared_from_this(), train, m_toSide, dryRun))
{
assert(dryRun);
return false;

Datei anzeigen

@ -271,7 +271,13 @@ void BlockRailTile::identificationEvent(BlockInputMapItem& /*item*/, Identificat
}
}
bool BlockRailTile::reserve(const std::shared_ptr<Train>& train, BlockSide side, bool dryRun)
const std::shared_ptr<BlockPath> BlockRailTile::getReservedPath(BlockSide side) const
{
assert(side == BlockSide::A || side == BlockSide::B);
return m_reservedPaths[static_cast<uint8_t>(side)].lock();
}
bool BlockRailTile::reserve(const std::shared_ptr<BlockPath>& blockPath, const std::shared_ptr<Train>& train, BlockSide side, bool dryRun)
{
const uint8_t mask = 1 << static_cast<uint8_t>(side);
@ -308,6 +314,7 @@ bool BlockRailTile::reserve(const std::shared_ptr<Train>& train, BlockSide side,
if(!dryRun)
{
m_reservedPaths[static_cast<uint8_t>(side)] = blockPath;
RailTile::reserve(reservedState() | mask);
if(state == BlockState::Free)
{

Datei anzeigen

@ -24,6 +24,7 @@
#define TRAINTASTIC_SERVER_BOARD_TILE_RAIL_BLOCKRAILTILE_HPP
#include "railtile.hpp"
#include <array>
#include <traintastic/enum/blocktraindirection.hpp>
#include "../../map/node.hpp"
#include "../../../core/method.hpp"
@ -47,6 +48,7 @@ class BlockRailTile : public RailTile
private:
Node m_node;
std::vector<std::shared_ptr<BlockPath>> m_paths;
std::array<std::weak_ptr<BlockPath>, 2> m_reservedPaths; // index is BlockSide
void updateHeightWidthMax();
@ -90,7 +92,8 @@ class BlockRailTile : public RailTile
void inputItemValueChanged(BlockInputMapItem& item);
void identificationEvent(BlockInputMapItem& item, IdentificationEventType eventType, uint16_t identifier, Direction direction, uint8_t category);
bool reserve(const std::shared_ptr<Train>& train, BlockSide side, bool dryRun = false);
const std::shared_ptr<BlockPath> getReservedPath(BlockSide side) const;
bool reserve(const std::shared_ptr<BlockPath>& blockPath, const std::shared_ptr<Train>& train, BlockSide side, bool dryRun = false);
};
#endif

Datei anzeigen

@ -21,6 +21,7 @@
*/
#include "signal3aspectrailtile.hpp"
#include "../blockrailtile.hpp"
#include "../../../map/abstractsignalpath.hpp"
#include "../../../map/blockpath.hpp"
#include "../../../../core/attributes.hpp"
@ -34,30 +35,65 @@ namespace
{
class SignalPath : public AbstractSignalPath
{
private:
static bool hasSignalReservedPathToBlock(const SignalRailTile& signalTile, const BlockRailTile& blockTile)
{
const auto path = signalTile.reservedPath();
return path && path->toBlock().get() == &blockTile;
}
static bool isPathReserved(const BlockRailTile& from, BlockSide fromSide, const BlockRailTile& to)
{
if(const auto path = from.getReservedPath(fromSide))
{
return (&to == path->toBlock().get());
}
return false;
}
protected:
SignalAspect determineAspect() const final
{
std::array<BlockState, 2> states;
getBlockStates(states);
if(!requireReservation() && states[0] == BlockState::Free)
const auto* blockItem = nextBlock();
if(!blockItem)
{
if(states[1] == BlockState::Free)
return SignalAspect::Stop;
}
const auto blockState = blockItem->blockState();
if((!requireReservation() && blockState == BlockState::Free) ||
(blockState == BlockState::Reserved && hasSignalReservedPathToBlock(signal(), *blockItem->block())))
{
auto [blockItem2, signalItem2] = nextBlockOrSignal(blockItem->next().get());
if(blockItem2)
{
return SignalAspect::Proceed;
const auto blockState2 = blockItem2->blockState();
if(blockState2 == BlockState::Free ||
(blockState2 == BlockState::Reserved && isPathReserved(*blockItem->block(), ~blockItem->enterSide(), *blockItem2->block())))
{
return SignalAspect::Proceed;
}
}
else if(signalItem2)
{
auto signalTile = signalItem2->signal();
if(signalTile && signalTile->aspect != SignalAspect::Unknown && signalTile->aspect != SignalAspect::Stop)
{
switch(signalTile->aspect.value())
{
case SignalAspect::ProceedReducedSpeed:
case SignalAspect::Proceed:
return SignalAspect::Proceed;
case SignalAspect::Stop:
case SignalAspect::Unknown:
break;
}
}
}
return SignalAspect::ProceedReducedSpeed;
}
if(states[0] == BlockState::Reserved)
{
const auto path = signal().reservedPath();
if(path && path->toBlock() == getBlock(0))
{
//! \todo check next block reserved and signal state
return SignalAspect::ProceedReducedSpeed;
}
}
return SignalAspect::Stop;
}

Datei anzeigen

@ -114,7 +114,11 @@ bool SignalRailTile::doSetAspect(SignalAspect value)
if(!values->contains(static_cast<int64_t>(value)))
return false;
(*outputMap)[value]->execute();
aspect.setValueInternal(value);
if(aspect != value)
{
aspect.setValueInternal(value);
aspectChanged(*this, value);
}
return true;
}

Datei anzeigen

@ -54,6 +54,8 @@ class SignalRailTile : public StraightRailTile
void evaluate();
public:
boost::signals2::signal<void (const SignalRailTile&, SignalAspect)> aspectChanged;
Property<std::string> name;
Property<AutoYesNo> requireReservation;
Property<SignalAspect> aspect;

Datei anzeigen

@ -31,4 +31,9 @@ enum class BlockSide : uint8_t
B = 1,
};
constexpr BlockSide operator ~(const BlockSide value)
{
return (value == BlockSide::B) ? BlockSide::A : BlockSide::B;
}
#endif