From a9180bc4bb7ff4c403e206cc2c785ff32544a0d6 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Fri, 16 Apr 2010 18:26:06 +0000 Subject: [PATCH] Add timetable-based operation --- source/libmarklin/timetable.cpp | 170 ++++++++++++++++++++++++++++++++ source/libmarklin/timetable.h | 76 ++++++++++++++ source/libmarklin/train.cpp | 21 ++++ source/libmarklin/train.h | 3 + 4 files changed, 270 insertions(+) create mode 100644 source/libmarklin/timetable.cpp create mode 100644 source/libmarklin/timetable.h diff --git a/source/libmarklin/timetable.cpp b/source/libmarklin/timetable.cpp new file mode 100644 index 0000000..bd9d4b3 --- /dev/null +++ b/source/libmarklin/timetable.cpp @@ -0,0 +1,170 @@ +/* $Id$ + +This file is part of the MSP Märklin suite +Copyright © 2010 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#include +#include "block.h" +#include "catalogue.h" +#include "driver.h" +#include "layout.h" +#include "timetable.h" +#include "train.h" + +using namespace std; +using namespace Msp; + +namespace Marklin { + +Timetable::Timetable(Train &t): + train(t), + current_row(0), + executing(true), + pending_block(0) +{ + train.signal_arrived.connect(sigc::mem_fun(this, &Timetable::train_arrived)); + train.get_layout().get_driver().signal_sensor.connect(sigc::mem_fun(this, &Timetable::sensor_event)); +} + +void Timetable::tick(const Time::TimeStamp &t) +{ + if(wait_timeout && t>=wait_timeout) + { + wait_timeout = Time::TimeStamp(); + current_row = (current_row+1)%rows.size(); + executing = true; + } + + while(executing) + { + Row &row = rows[current_row]; + switch(row.type) + { + case GOTO: + train.go_to(**parse_location(row.strparam).get_tracks().begin()); + executing = false; + break; + case TRAVEL: + pending_block = &parse_location(row.strparam); + executing = false; + break; + case WAIT: + wait_timeout = t+row.intparam*Time::sec; + executing = false; + break; + case SPEED: + train.set_control("speed", row.intparam/3.6*train.get_layout().get_catalogue().get_scale()); + break; + case ROUTE: + train.set_route(&train.get_layout().get_route(row.strparam)); + break; + } + + if(executing) + current_row = (current_row+1)%rows.size(); + } +} + +void Timetable::save(list &st) const +{ + for(vector::const_iterator i=rows.begin(); i!=rows.end(); ++i) + { + switch(i->type) + { + case GOTO: + st.push_back((DataFile::Statement("goto"), i->strparam)); + break; + case TRAVEL: + st.push_back((DataFile::Statement("travel"), i->strparam)); + break; + case WAIT: + st.push_back((DataFile::Statement("wait"), i->intparam)); + break; + case SPEED: + st.push_back((DataFile::Statement("speed"), i->intparam)); + break; + case ROUTE: + st.push_back((DataFile::Statement("route"), i->strparam)); + break; + } + } +} + +Block &Timetable::parse_location(const string &loc) +{ + if(!loc.compare(0, 7, "sensor ")) + return train.get_layout().get_block(lexical_cast(loc.substr(7))|0x1000); + throw Exception("Named blocks are not supported yet"); +} + +void Timetable::sensor_event(unsigned addr, bool state) +{ + if(pending_block && pending_block->get_train()==&train && addr==pending_block->get_sensor_id() && state) + { + pending_block = 0; + current_row = (current_row+1)%rows.size(); + executing = true; + } +} + +void Timetable::train_arrived() +{ + Row &row = rows[current_row]; + if(row.type==GOTO) + { + current_row = (current_row+1)%rows.size(); + executing = true; + } +} + + +Timetable::Row::Row(RowType t, int p): + type(t), + intparam(p) +{ } + +Timetable::Row::Row(RowType t, const string &p): + type(t), + intparam(0), + strparam(p) +{ } + + +Timetable::Loader::Loader(Timetable &tt): + DataFile::ObjectLoader(tt) +{ + add("goto", &Loader::go_to); + add("route", &Loader::route); + add("speed", &Loader::speed); + add("travel", &Loader::travel); + add("wait", &Loader::wait); +} + +void Timetable::Loader::go_to(const string &t) +{ + obj.rows.push_back(Row(GOTO, t)); +} + +void Timetable::Loader::route(const string &r) +{ + obj.rows.push_back(Row(ROUTE, r)); +} + +void Timetable::Loader::speed(int s) +{ + obj.rows.push_back(Row(SPEED, s)); +} + +void Timetable::Loader::travel(const string &t) +{ + obj.rows.push_back(Row(TRAVEL, t)); +} + +void Timetable::Loader::wait(unsigned t) +{ + obj.rows.push_back(Row(WAIT, t)); +} + +} // namespace Marklin diff --git a/source/libmarklin/timetable.h b/source/libmarklin/timetable.h new file mode 100644 index 0000000..39cff5e --- /dev/null +++ b/source/libmarklin/timetable.h @@ -0,0 +1,76 @@ +/* $Id$ + +This file is part of the MSP Märklin suite +Copyright © 2010 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#ifndef LIBMARKLIN_TIMETABLE_H_ +#define LIBMARKLIN_TIMETABLE_H_ + +#include +#include +#include +#include + +namespace Marklin { + +class Block; +class Train; + +class Timetable +{ +public: + class Loader: public Msp::DataFile::ObjectLoader + { + public: + Loader(Timetable &); + private: + void go_to(const std::string &); + void route(const std::string &); + void speed(int); + void travel(const std::string &); + void wait(unsigned); + }; + + enum RowType + { + GOTO, + TRAVEL, + WAIT, + SPEED, + ROUTE + }; + + struct Row + { + RowType type; + int intparam; + std::string strparam; + + Row(RowType, int); + Row(RowType, const std::string &); + }; + +private: + Train &train; + std::vector rows; + unsigned current_row; + bool executing; + Block *pending_block; + Msp::Time::TimeStamp wait_timeout; + +public: + Timetable(Train &); + + void tick(const Msp::Time::TimeStamp &); + void save(std::list &) const; +private: + Block &parse_location(const std::string &); + void sensor_event(unsigned, bool); + void train_arrived(); +}; + +} // namespace Marklin + +#endif diff --git a/source/libmarklin/train.cpp b/source/libmarklin/train.cpp index d5b2b22..24ccfa2 100644 --- a/source/libmarklin/train.cpp +++ b/source/libmarklin/train.cpp @@ -16,6 +16,7 @@ Distributed under the GPL #include "locotype.h" #include "route.h" #include "simplephysics.h" +#include "timetable.h" #include "tracktype.h" #include "train.h" #include "vehicle.h" @@ -31,6 +32,7 @@ Train::Train(Layout &l, const LocoType &t, unsigned a): address(a), pending_block(0), control(new AIControl(*this, new SimplePhysics)), + timetable(0), active(false), current_speed(0), speed_changing(false), @@ -299,6 +301,8 @@ void Train::tick(const Time::TimeStamp &t, const Time::TimeDelta &dt) stop_timeout = Time::TimeStamp(); } + if(timetable) + timetable->tick(t); control->tick(dt); float speed = control->get_speed(); unsigned speed_notch = find_speed(abs(speed)); @@ -369,6 +373,13 @@ void Train::save(list &st) const if(route) st.push_back((DataFile::Statement("route"), route->get_name())); + + if(timetable) + { + DataFile::Statement ss("timetable"); + timetable->save(ss.sub); + st.push_back(ss); + } } void Train::loco_speed_event(unsigned addr, unsigned speed, bool) @@ -772,6 +783,7 @@ Train::Loader::Loader(Train &t): add("name", &Loader::name); add("real_speed", &Loader::real_speed); add("route", &Loader::route); + add("timetable", &Loader::timetable); } void Train::Loader::block(unsigned id) @@ -816,4 +828,13 @@ void Train::Loader::route(const string &n) obj.set_route(&obj.layout.get_route(n)); } +void Train::Loader::timetable() +{ + if(obj.timetable) + throw InvalidState("A timetable has already been loaded"); + + obj.timetable = new Timetable(obj); + load_sub(*obj.timetable); +} + } // namespace Marklin diff --git a/source/libmarklin/train.h b/source/libmarklin/train.h index 4289d3c..5960c27 100644 --- a/source/libmarklin/train.h +++ b/source/libmarklin/train.h @@ -18,6 +18,7 @@ namespace Marklin { class ControlModel; class LocoType; class Route; +class Timetable; class Vehicle; class Train: public sigc::trackable @@ -36,6 +37,7 @@ public: void name(const std::string &); void real_speed(unsigned, float, float); void route(const std::string &); + void timetable(); }; sigc::signal signal_name_changed; @@ -73,6 +75,7 @@ private: std::list rsv_blocks; Block *pending_block; ControlModel *control; + Timetable *timetable; bool active; unsigned current_speed; bool speed_changing; -- 2.45.2