]> git.tdb.fi Git - r2c2.git/blob - source/libmarklin/timetable.cpp
Add timetable-based operation
[r2c2.git] / source / libmarklin / timetable.cpp
1 /* $Id$
2
3 This file is part of the MSP Märklin suite
4 Copyright © 2010  Mikkosoft Productions, Mikko Rasa
5 Distributed under the GPL
6 */
7
8 #include <msp/time/units.h>
9 #include "block.h"
10 #include "catalogue.h"
11 #include "driver.h"
12 #include "layout.h"
13 #include "timetable.h"
14 #include "train.h"
15
16 using namespace std;
17 using namespace Msp;
18
19 namespace Marklin {
20
21 Timetable::Timetable(Train &t):
22         train(t),
23         current_row(0),
24         executing(true),
25         pending_block(0)
26 {
27         train.signal_arrived.connect(sigc::mem_fun(this, &Timetable::train_arrived));
28         train.get_layout().get_driver().signal_sensor.connect(sigc::mem_fun(this, &Timetable::sensor_event));
29 }
30
31 void Timetable::tick(const Time::TimeStamp &t)
32 {
33         if(wait_timeout && t>=wait_timeout)
34         {
35                 wait_timeout = Time::TimeStamp();
36                 current_row = (current_row+1)%rows.size();
37                 executing = true;
38         }
39
40         while(executing)
41         {
42                 Row &row = rows[current_row];
43                 switch(row.type)
44                 {
45                 case GOTO:
46                         train.go_to(**parse_location(row.strparam).get_tracks().begin());
47                         executing = false;
48                         break;
49                 case TRAVEL:
50                         pending_block = &parse_location(row.strparam);
51                         executing = false;
52                         break;
53                 case WAIT:
54                         wait_timeout = t+row.intparam*Time::sec;
55                         executing = false;
56                         break;
57                 case SPEED:
58                         train.set_control("speed", row.intparam/3.6*train.get_layout().get_catalogue().get_scale());
59                         break;
60                 case ROUTE:
61                         train.set_route(&train.get_layout().get_route(row.strparam));
62                         break;
63                 }
64
65                 if(executing)
66                         current_row = (current_row+1)%rows.size();
67         }
68 }
69
70 void Timetable::save(list<DataFile::Statement> &st) const
71 {
72         for(vector<Row>::const_iterator i=rows.begin(); i!=rows.end(); ++i)
73         {
74                 switch(i->type)
75                 {
76                 case GOTO:
77                         st.push_back((DataFile::Statement("goto"), i->strparam));
78                         break;
79                 case TRAVEL:
80                         st.push_back((DataFile::Statement("travel"), i->strparam));
81                         break;
82                 case WAIT:
83                         st.push_back((DataFile::Statement("wait"), i->intparam));
84                         break;
85                 case SPEED:
86                         st.push_back((DataFile::Statement("speed"), i->intparam));
87                         break;
88                 case ROUTE:
89                         st.push_back((DataFile::Statement("route"), i->strparam));
90                         break;
91                 }
92         }
93 }
94
95 Block &Timetable::parse_location(const string &loc)
96 {
97         if(!loc.compare(0, 7, "sensor "))
98                 return train.get_layout().get_block(lexical_cast<unsigned>(loc.substr(7))|0x1000);
99         throw Exception("Named blocks are not supported yet");
100 }
101
102 void Timetable::sensor_event(unsigned addr, bool state)
103 {
104         if(pending_block && pending_block->get_train()==&train && addr==pending_block->get_sensor_id() && state)
105         {
106                 pending_block = 0;
107                 current_row = (current_row+1)%rows.size();
108                 executing = true;
109         }
110 }
111
112 void Timetable::train_arrived()
113 {
114         Row &row = rows[current_row];
115         if(row.type==GOTO)
116         {
117                 current_row = (current_row+1)%rows.size();
118                 executing = true;
119         }
120 }
121
122
123 Timetable::Row::Row(RowType t, int p):
124         type(t),
125         intparam(p)
126 { }
127
128 Timetable::Row::Row(RowType t, const string &p):
129         type(t),
130         intparam(0),
131         strparam(p)
132 { }
133
134
135 Timetable::Loader::Loader(Timetable &tt):
136         DataFile::ObjectLoader<Timetable>(tt)
137 {
138         add("goto",   &Loader::go_to);
139         add("route",  &Loader::route);
140         add("speed",  &Loader::speed);
141         add("travel", &Loader::travel);
142         add("wait",   &Loader::wait);
143 }
144
145 void Timetable::Loader::go_to(const string &t)
146 {
147         obj.rows.push_back(Row(GOTO, t));
148 }
149
150 void Timetable::Loader::route(const string &r)
151 {
152         obj.rows.push_back(Row(ROUTE, r));
153 }
154
155 void Timetable::Loader::speed(int s)
156 {
157         obj.rows.push_back(Row(SPEED, s));
158 }
159
160 void Timetable::Loader::travel(const string &t)
161 {
162         obj.rows.push_back(Row(TRAVEL, t));
163 }
164
165 void Timetable::Loader::wait(unsigned t)
166 {
167         obj.rows.push_back(Row(WAIT, t));
168 }
169
170 } // namespace Marklin