#include <msp/time/units.h>
#include <msp/time/utils.h>
#include "libr2c2/driver.h"
+#include "libr2c2/trackcircuit.h"
#include "libr2c2/tracktype.h"
#include "3d/path.h"
#include "3d/track.h"
layout.signal_train_added.connect(sigc::mem_fun(this, &Engineer::train_added));
layout.signal_block_reserved.connect(sigc::hide<1>(sigc::mem_fun(this, &Engineer::reset_block_color)));
- layout.signal_block_state_changed.connect(sigc::hide<1>(sigc::mem_fun(this, &Engineer::reset_block_color)));
layout.signal_emergency.connect(sigc::mem_fun(this, &Engineer::set_status));
+ const set<Block *> &blocks = layout.get_blocks();
+ for(set<Block *>::const_iterator i=blocks.begin(); i!=blocks.end(); ++i)
+ (*i)->get_sensor().signal_state_changed.connect(sigc::hide(sigc::bind(sigc::mem_fun(this, &Engineer::reset_block_color), sigc::ref(**i))));
if(FS::exists(options.state_fn))
DataFile::load(layout, options.state_fn);
void Engineer::reset_block_color(const Block &block)
{
- bool active = block.get_state()>Block::INACTIVE;
+ bool active = block.get_sensor().get_state()>Sensor::INACTIVE;
if(block.get_train())
{
#include "driver.h"
#include "layout.h"
#include "route.h"
+#include "trackcircuit.h"
#include "trackiter.h"
#include "tracktype.h"
id(0),
sensor_id(start.get_sensor_id()),
turnout_id(start.get_turnout_id()),
- state(INACTIVE),
train(0)
{
tracks.insert(&start);
find_paths(endpoints[i].track_iter(), path);
}
- if(sensor_id && layout.has_driver())
- layout.get_driver().signal_sensor.connect(sigc::mem_fun(this, &Block::sensor_event));
+ sensor = new TrackCircuit(layout, *this);
layout.add_block(*this);
}
}
layout.remove_block(*this);
+
+ delete sensor;
}
bool Block::has_track(Track &t) const
return false;
}
-void Block::tick(const Time::TimeDelta &dt)
-{
- if(state_confirm_timeout)
- {
- state_confirm_timeout -= dt;
- if(state_confirm_timeout<=Time::zero)
- {
- if(state==MAYBE_INACTIVE)
- state = INACTIVE;
- else if(state==MAYBE_ACTIVE)
- state = ACTIVE;
- state_confirm_timeout = Time::zero;
- signal_state_changed.emit(state);
- }
- }
-}
-
void Block::find_paths(const TrackIter &track, unsigned path)
{
unsigned mask = track.endpoint().paths;
}
}
-void Block::sensor_event(unsigned addr, bool s)
-{
- if(addr==sensor_id)
- {
- if(s && state<MAYBE_ACTIVE)
- {
- state = MAYBE_ACTIVE;
- state_confirm_timeout = 300*Time::msec;
- signal_state_changed.emit(state);
- }
- else if(!s && state>MAYBE_INACTIVE)
- {
- state = MAYBE_INACTIVE;
- state_confirm_timeout = 700*Time::msec;
- signal_state_changed.emit(state);
- }
- }
-}
-
Block::Endpoint::Endpoint(Track *t, unsigned e):
track(t),
class Layout;
class Route;
+class TrackCircuit;
class TrackIter;
class Train;
-class Block: public sigc::trackable
+class Block
{
public:
- enum State
- {
- INACTIVE,
- MAYBE_INACTIVE,
- MAYBE_ACTIVE,
- ACTIVE
- };
-
struct Endpoint
{
Track *track;
};
sigc::signal<void, Train *> signal_reserved;
- sigc::signal<void, State> signal_state_changed;
private:
Layout &layout;
unsigned id;
unsigned sensor_id;
unsigned turnout_id;
- State state;
- Msp::Time::TimeDelta state_confirm_timeout;
+ TrackCircuit *sensor;
std::set<Track *> tracks;
std::vector<Endpoint> endpoints;
Train *train;
unsigned get_id() const { return id; }
unsigned get_sensor_id() const { return sensor_id; }
unsigned get_turnout_id() const { return turnout_id; }
- State get_state() const { return state; }
+ TrackCircuit &get_sensor() const { return *sensor; }
const std::set<Track *> &get_tracks() const { return tracks; }
bool has_track(Track &) const;
const std::vector<Endpoint> &get_endpoints() const { return endpoints; }
Block *get_link(unsigned) const;
bool reserve(Train *);
Train *get_train() const { return train; }
- void tick(const Msp::Time::TimeDelta &);
private:
void find_paths(const TrackIter &, unsigned);
void determine_id();
- void sensor_event(unsigned, bool);
};
} // namespace R2C2
#include <msp/core/maputils.h>
#include <msp/core/raii.h>
#include "blockallocator.h"
+#include "block.h"
#include "catalogue.h"
#include "driver.h"
#include "layout.h"
+#include "trackcircuit.h"
#include "trackiter.h"
#include "train.h"
#include "vehicle.h"
{
Layout &layout = train.get_layout();
layout.signal_block_reserved.connect(sigc::mem_fun(this, &BlockAllocator::block_reserved));
- layout.signal_block_state_changed.connect(sigc::mem_fun(this, &BlockAllocator::block_state_changed));
+ layout.signal_sensor_state_changed.connect(sigc::mem_fun(this, &BlockAllocator::sensor_state_changed));
const set<Track *> &tracks = layout.get_tracks();
for(set<Track *>::const_iterator i=tracks.begin(); i!=tracks.end(); ++i)
reserve_more();
}
-void BlockAllocator::block_state_changed(Block &block, Block::State state)
+void BlockAllocator::sensor_state_changed(Sensor &sensor, Sensor::State state)
{
- if(block.get_train()!=&train)
+ Block *block = 0;
+ if(TrackCircuit *tc = dynamic_cast<TrackCircuit *>(&sensor))
+ block = &tc->get_block();
+ else
return;
- if(state==Block::MAYBE_ACTIVE)
+ if(block->get_train()!=&train)
+ return;
+
+ if(state==Sensor::MAYBE_ACTIVE)
{
// Find the first sensor block from our reserved blocks that isn't this sensor
BlockList::iterator end;
for(end=cur_blocks_end; end!=blocks.end(); ++end)
if((*end)->get_sensor_id())
{
- if(&**end!=&block)
+ if(&**end!=block)
{
if(result==0)
result = 2;
else if(result==3)
train.get_layout().emergency("Sensor for "+train.get_name()+" triggered out of order");
}
- else if(state==Block::INACTIVE)
+ else if(state==Sensor::INACTIVE)
{
const Vehicle &veh = train.get_vehicle(train.get_controller().get_reverse() ? 0 : train.get_n_vehicles()-1);
const Block &veh_block = veh.get_track()->get_block();
#include <list>
#include <msp/datafile/objectloader.h>
-#include "block.h"
#include "blockiter.h"
+#include "sensor.h"
namespace R2C2 {
private:
void turnout_path_changed(Track &);
void block_reserved(Block &, const Train *);
- void block_state_changed(Block &, Block::State);
+ void sensor_state_changed(Sensor &, Sensor::State);
public:
void save(std::list<Msp::DataFile::Statement> &) const;
#include "signal.h"
#include "signaltype.h"
#include "track.h"
+#include "trackcircuit.h"
#include "tracktype.h"
#include "train.h"
#include "vehicletype.h"
{
blocks.insert(&b);
b.signal_reserved.connect(sigc::bind<0>(signal_block_reserved, sigc::ref(b)));
- if(b.get_sensor_id())
- {
- b.signal_state_changed.connect(sigc::bind<0>(sigc::mem_fun(this, &Layout::block_state_changed), sigc::ref(b)));
- b.signal_state_changed.connect(sigc::bind<0>(signal_block_state_changed, sigc::ref(b)));
- }
}
Block &Layout::get_block(unsigned id) const
signal_vehicle_removed.emit(v);
}
+void Layout::add_sensor(Sensor &s)
+{
+ if(sensors.insert(&s).second)
+ {
+ s.signal_state_changed.connect(sigc::bind<0>(sigc::mem_fun(this, &Layout::sensor_state_changed), sigc::ref(s)));
+ s.signal_state_changed.connect(sigc::bind<0>(signal_sensor_state_changed, sigc::ref(s)));
+ }
+}
+
+void Layout::remove_sensor(Sensor &s)
+{
+ sensors.erase(&s);
+}
+
void Layout::tick()
{
if(driver)
dt = t-last_tick;
last_tick = t;
- for(set<Block *>::iterator i=blocks.begin(); i!=blocks.end(); ++i)
+ for(set<Sensor *>::iterator i=sensors.begin(); i!=sensors.end(); ++i)
(*i)->tick(dt);
for(set<Signal *>::iterator i=signals.begin(); i!=signals.end(); ++i)
(*i)->tick(dt);
}
}
-void Layout::block_state_changed(Block &block, Block::State state)
+void Layout::sensor_state_changed(Sensor &sensor, Sensor::State state)
{
- if(state==Block::ACTIVE && !block.get_train())
- emergency(format("Unreserved sensor %d triggered", block.get_sensor_id()));
+ if(state==Sensor::ACTIVE)
+ {
+ Block *block = 0;
+ if(TrackCircuit *tc = dynamic_cast<TrackCircuit *>(&sensor))
+ block = &tc->get_block();
+
+ if(block && !block->get_train())
+ emergency(format("Unreserved sensor %d triggered", sensor.get_address()));
+ }
}
#include <sigc++/sigc++.h>
#include <msp/datafile/objectloader.h>
#include <msp/time/timestamp.h>
-#include "block.h"
#include "geometry.h"
+#include "sensor.h"
namespace R2C2 {
class ArticleNumber;
+class Block;
class Catalogue;
class Driver;
+class Object;
class Route;
class Signal;
class Track;
sigc::signal<void, Vehicle &> signal_vehicle_added;
sigc::signal<void, Vehicle &> signal_vehicle_removed;
sigc::signal<void, Block &, Train *> signal_block_reserved;
- sigc::signal<void, Block &, Block::State> signal_block_state_changed;
+ sigc::signal<void, Sensor &, Sensor::State> signal_sensor_state_changed;
sigc::signal<void, const std::string &> signal_emergency;
private:
std::set<Route *> routes;
ZoneSet zones;
std::set<Block *> blocks;
+ std::set<Sensor *> sensors;
std::map<unsigned, Train *> trains;
std::set<Vehicle *> vehicles;
Msp::Time::TimeStamp last_tick;
void add_vehicle(Vehicle &);
void remove_vehicle(Vehicle &);
+ void add_sensor(Sensor &);
+ void remove_sensor(Sensor &);
+
void tick();
void emergency(const std::string &);
void save(const std::string &) const;
void save_dynamic(const std::string &) const;
private:
- void block_state_changed(Block &, Block::State);
+ void sensor_state_changed(Sensor &, Sensor::State);
};
} // namespace R2C2
--- /dev/null
+#include "driver.h"
+#include "layout.h"
+#include "sensor.h"
+
+using namespace Msp;
+
+namespace R2C2 {
+
+Sensor::Sensor(Layout &l):
+ layout(l),
+ address(0),
+ state(INACTIVE)
+{
+ if(layout.has_driver())
+ layout.get_driver().signal_sensor.connect(sigc::mem_fun(this, &Sensor::event));
+
+ layout.add_sensor(*this);
+}
+
+Sensor::~Sensor()
+{
+ layout.remove_sensor(*this);
+}
+
+void Sensor::tick(const Time::TimeDelta &dt)
+{
+ if(state_confirm_timeout)
+ {
+ state_confirm_timeout -= dt;
+ if(state_confirm_timeout<=Time::zero)
+ {
+ if(state==MAYBE_INACTIVE)
+ state = INACTIVE;
+ else if(state==MAYBE_ACTIVE)
+ state = ACTIVE;
+ state_confirm_timeout = Time::zero;
+ signal_state_changed.emit(state);
+ }
+ }
+}
+
+void Sensor::event(unsigned a, bool s)
+{
+ if(a==address)
+ {
+ if(s && state<MAYBE_ACTIVE)
+ {
+ state = MAYBE_ACTIVE;
+ state_confirm_timeout = 300*Time::msec;
+ signal_state_changed.emit(state);
+ }
+ else if(!s && state>MAYBE_INACTIVE)
+ {
+ state = MAYBE_INACTIVE;
+ state_confirm_timeout = 700*Time::msec;
+ signal_state_changed.emit(state);
+ }
+ }
+}
+
+} // namespace R2C2
--- /dev/null
+#ifndef LIBR2C2_SENSOR_H_
+#define LIBR2C2_SENSOR_H_
+
+#include <sigc++/signal.h>
+#include <msp/time/timedelta.h>
+
+namespace R2C2 {
+
+class Layout;
+
+class Sensor: public sigc::trackable
+{
+public:
+ enum State
+ {
+ INACTIVE,
+ MAYBE_INACTIVE,
+ MAYBE_ACTIVE,
+ ACTIVE
+ };
+
+ sigc::signal<void, State> signal_state_changed;
+
+protected:
+ Layout &layout;
+ unsigned address;
+ State state;
+ Msp::Time::TimeDelta state_confirm_timeout;
+
+ Sensor(Layout &);
+public:
+ virtual ~Sensor();
+
+ unsigned get_address() const { return address; }
+ State get_state() const { return state; }
+
+ void tick(const Msp::Time::TimeDelta &);
+
+private:
+ void event(unsigned, bool);
+};
+
+} // namespace R2C2
+
+#endif
#include "driver.h"
#include "layout.h"
#include "timetable.h"
+#include "trackcircuit.h"
#include "train.h"
using namespace std;
train.signal_advanced.connect(sigc::mem_fun(this, &Timetable::train_advanced));
train.signal_ai_event.connect(sigc::mem_fun(this, &Timetable::event));
Layout &layout = train.get_layout();
- layout.signal_block_state_changed.connect(sigc::mem_fun(this, &Timetable::block_state_changed));
+ layout.signal_sensor_state_changed.connect(sigc::mem_fun(this, &Timetable::sensor_state_changed));
layout.signal_block_reserved.connect(sigc::mem_fun(this, &Timetable::block_reserved));
}
case TRAVEL_TO:
{
Block *block = &get_sensor(row.get_param<unsigned>(0));
- if(block->get_train()!=&train || block->get_state()<Block::MAYBE_ACTIVE)
+ if(block->get_train()!=&train || block->get_sensor().get_state()<Sensor::MAYBE_ACTIVE)
{
pending_block = block;
pending_train = &train;
{
Train *other_train = &train.get_layout().get_train(row.get_param<unsigned>(0));
Block *block = &get_sensor(row.get_param<unsigned>(1));
- if(block->get_train()!=other_train || block->get_state()<Block::MAYBE_ACTIVE)
+ if(block->get_train()!=other_train || block->get_sensor().get_state()<Sensor::MAYBE_ACTIVE)
{
pending_train = other_train;
pending_block = block;
return train.get_layout().get_zone(name.substr(0, space), number);
}
-void Timetable::block_state_changed(Block &block, Block::State state)
+void Timetable::sensor_state_changed(Sensor &sensor, Sensor::State state)
{
if(rows.empty() || !enabled)
return;
- if(&block==pending_block && block.get_train()==pending_train && state>=Block::MAYBE_ACTIVE)
+ Block *block = 0;
+ if(TrackCircuit *tc = dynamic_cast<TrackCircuit *>(&sensor))
+ block = &tc->get_block();
+ else
+ return;
+
+ if(block==pending_block && block->get_train()==pending_train && state>=Sensor::MAYBE_ACTIVE)
{
pending_block = 0;
current_row = (current_row+1)%rows.size();
#include <vector>
#include <sigc++/trackable.h>
#include <msp/datafile/objectloader.h>
-#include "block.h"
+#include "sensor.h"
#include "trainai.h"
namespace R2C2 {
+class Block;
class Track;
class Train;
class Zone;
Block &get_sensor(unsigned);
Track &get_turnout(unsigned);
Zone &get_zone(const std::string &);
- void block_state_changed(Block &, Block::State);
+ void sensor_state_changed(Sensor &, Sensor::State);
void block_reserved(Block &, Train *);
void train_advanced(Block &);
void event(TrainAI &, const Message &);
--- /dev/null
+#include "block.h"
+#include "trackcircuit.h"
+
+namespace R2C2 {
+
+TrackCircuit::TrackCircuit(Layout &l, Block &b):
+ Sensor(l),
+ block(b)
+{
+ address = block.get_sensor_id();
+}
+
+} // namespace R2C2
--- /dev/null
+#ifndef LIBR2C2_TRACKCIRCUIT_H_
+#define LIBR2C2_TRACKCIRCUIT_H_
+
+#include "sensor.h"
+
+namespace R2C2 {
+
+class Block;
+
+class TrackCircuit: public Sensor
+{
+private:
+ Block █
+
+public:
+ TrackCircuit(Layout &, Block &);
+
+ Block &get_block() const { return block; }
+};
+
+} // namespace R2C2
+
+#endif
#include <msp/time/units.h>
#include <msp/time/utils.h>
#include "aicontrol.h"
+#include "block.h"
#include "catalogue.h"
#include "driver.h"
#include "layout.h"
#include "simplecontroller.h"
#include "speedquantizer.h"
#include "timetable.h"
+#include "trackcircuit.h"
#include "trackiter.h"
#include "tracktype.h"
#include "train.h"
layout.get_driver().signal_loco_speed.connect(sigc::mem_fun(this, &Train::loco_speed_event));
layout.get_driver().signal_loco_function.connect(sigc::mem_fun(this, &Train::loco_func_event));
- layout.signal_block_state_changed.connect(sigc::mem_fun(this, &Train::block_state_changed));
+ layout.signal_sensor_state_changed.connect(sigc::mem_fun(this, &Train::sensor_state_changed));
layout.get_driver().signal_halt.connect(sigc::mem_fun(this, &Train::halt_event));
}
}
-void Train::block_state_changed(Block &block, Block::State state)
+void Train::sensor_state_changed(Sensor &sensor, Sensor::State state)
{
- if(block.get_train()==this && state==Block::MAYBE_ACTIVE)
+ Block *block = 0;
+ if(TrackCircuit *tc = dynamic_cast<TrackCircuit *>(&sensor))
+ block = &tc->get_block();
+ else
+ return;
+
+ if(block->get_train()==this && state==Sensor::MAYBE_ACTIVE)
{
if(last_entry_block)
{
if(pure_speed && speed_quantizer && current_speed_step>0)
travel_distance = 0;
- for(BlockIter i=last_entry_block; &*i!=█ i=i.next())
+ for(BlockIter i=last_entry_block; &*i!=block; i=i.next())
{
if(i->get_sensor_id())
return;
}
}
- last_entry_block = allocator.iter_for(block);
+ last_entry_block = allocator.iter_for(*block);
last_entry_time = Time::now();
pure_speed = true;
accurate_position = true;
#include <sigc++/trackable.h>
#include <msp/datafile/objectloader.h>
#include <msp/time/timestamp.h>
-#include "block.h"
#include "blockallocator.h"
#include "controller.h"
+#include "sensor.h"
#include "trainai.h"
namespace R2C2 {
class ArticleNumber;
+class Block;
class SpeedQuantizer;
class Vehicle;
class VehicleType;
void control_changed(const Controller::Control &);
void loco_speed_event(unsigned, unsigned, bool);
void loco_func_event(unsigned, unsigned, bool);
- void block_state_changed(Block &, Block::State);
+ void sensor_state_changed(Sensor &, Sensor::State);
void halt_event(bool);
void block_reserved(const Block &, const Train *);
float get_reserved_distance_until(const Block *) const;