]> git.tdb.fi Git - r2c2.git/commitdiff
Add timetable-based operation
authorMikko Rasa <tdb@tdb.fi>
Fri, 16 Apr 2010 18:26:06 +0000 (18:26 +0000)
committerMikko Rasa <tdb@tdb.fi>
Fri, 16 Apr 2010 18:26:06 +0000 (18:26 +0000)
source/libmarklin/timetable.cpp [new file with mode: 0644]
source/libmarklin/timetable.h [new file with mode: 0644]
source/libmarklin/train.cpp
source/libmarklin/train.h

diff --git a/source/libmarklin/timetable.cpp b/source/libmarklin/timetable.cpp
new file mode 100644 (file)
index 0000000..bd9d4b3
--- /dev/null
@@ -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 <msp/time/units.h>
+#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<DataFile::Statement> &st) const
+{
+       for(vector<Row>::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<unsigned>(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<Timetable>(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 (file)
index 0000000..39cff5e
--- /dev/null
@@ -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 <string>
+#include <vector>
+#include <msp/datafile/objectloader.h>
+#include <msp/time/timestamp.h>
+
+namespace Marklin {
+
+class Block;
+class Train;
+
+class Timetable
+{
+public:
+       class Loader: public Msp::DataFile::ObjectLoader<Timetable>
+       {
+       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<Row> 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<Msp::DataFile::Statement> &) const;
+private:
+       Block &parse_location(const std::string &);
+       void sensor_event(unsigned, bool);
+       void train_arrived();
+};
+
+} // namespace Marklin
+
+#endif
index d5b2b226721c961fb88b96753434d665f1f0180d..24ccfa2448bf1abf814afc4d728da7c935a9908b 100644 (file)
@@ -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<DataFile::Statement> &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
index 4289d3c0dd9b5b77e13224b8c8a01eb616771def..5960c27d16b78164da022a40e0c79e7529647244 100644 (file)
@@ -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<void, const std::string &> signal_name_changed;
@@ -73,6 +75,7 @@ private:
        std::list<BlockRef> rsv_blocks;
        Block *pending_block;
        ControlModel *control;
+       Timetable *timetable;
        bool active;
        unsigned current_speed;
        bool speed_changing;