]> git.tdb.fi Git - r2c2.git/blob - source/libmarklin/control.cpp
30e99e6e4f5266cfa1878735bf3a4a21ded55920
[r2c2.git] / source / libmarklin / control.cpp
1 /* $Id$
2
3 This file is part of the MSP Märklin suite
4 Copyright © 2007-2009  Mikkosoft Productions, Mikko Rasa
5 Distributed under the GPL
6 */
7
8 #include <fcntl.h>
9 #include <termios.h>
10 #include <sys/poll.h>
11 #include <iostream>
12 #include <msp/core/except.h>
13 #include <msp/time/units.h>
14 #include <msp/time/utils.h>
15 #include "command.h"
16 #include "control.h"
17 #include "reply.h"
18
19 using namespace std;
20 using namespace Msp;
21
22 namespace Marklin {
23
24 Control::Control():
25         serial_fd(-1),
26         power(true),
27         poll_sensors(false),
28         debug(false)
29 { }
30
31 Control::~Control()
32 {
33         for(map<unsigned, Sensor *>::iterator i=sensors.begin(); i!=sensors.end(); ++i)
34                 delete i->second;
35         for(map<unsigned, Turnout *>::iterator i=turnouts.begin(); i!=turnouts.end(); ++i)
36                 delete i->second;
37         for(map<unsigned, Locomotive *>::iterator i=locomotives.begin(); i!=locomotives.end(); ++i)
38                 delete i->second;
39         if(serial_fd>=0)
40                 close(serial_fd);
41 }
42
43 void Control::open(const string &dev)
44 {
45         serial_fd = ::open(dev.c_str(), O_RDWR);
46         if(serial_fd<0)
47                 throw Exception("Couldn't open serial port\n");
48
49         static unsigned baud[]=
50         {
51                  2400, B2400,
52                  4800, B4800,
53                  9600, B9600,
54                 19200, B19200,
55                 0
56         };
57
58         termios attr;
59         tcgetattr(serial_fd, &attr);
60         cfmakeraw(&attr);
61         attr.c_cflag |= CSTOPB;
62
63         bool ok = false;
64         bool p50 = false;
65         for(unsigned i=0; baud[i]; i+=2)
66         {
67                 cfsetospeed(&attr, baud[i+1]);
68                 tcsetattr(serial_fd, TCSADRAIN, &attr);
69
70                 write(serial_fd, "\xC4", 1);
71
72                 pollfd pfd = { serial_fd, POLLIN, 0 };
73                 if(poll(&pfd, 1, 500)>0)
74                 {
75                         cout<<"IB detected at "<<baud[i]<<" bits/s\n";
76                         char buf[2];
77                         p50 = (read(serial_fd, buf, 2)==2);
78                         ok = true;
79                         break;
80                 }
81         }
82
83         if(!ok)
84                 throw Exception("IB not detected");
85         
86         if(p50)
87                 write(serial_fd, "xZzA1\r", 6);
88
89         command(CMD_STATUS).signal_done.connect(sigc::mem_fun(this, &Control::status_done));
90 }
91
92 void Control::set_debug(bool d)
93 {
94         debug = d;
95 }
96
97 void Control::set_power(bool p)
98 {
99         power = p;
100         if(power)
101                 command(CMD_POWER_ON);
102         else
103                 command(CMD_POWER_OFF);
104
105         signal_power_event.emit(power);
106 }
107
108 Command &Control::command(Cmd cmd)
109 {
110         queue.push_back(Command(cmd, 0, 0));
111         return queue.back();
112 }
113
114 Command &Control::command(Cmd cmd, unsigned char data)
115 {
116         queue.push_back(Command(cmd, &data, 1));
117         return queue.back();
118 }
119
120 Command &Control::command(Cmd cmd, const unsigned char *data, unsigned len)
121 {
122         queue.push_back(Command(cmd, data, len));
123         return queue.back();
124 }
125
126 void Control::add_turnout(Turnout &t)
127 {
128         turnouts[t.get_address()] = &t;
129 }
130
131 Turnout &Control::get_turnout(unsigned id) const
132 {
133         map<unsigned, Turnout *>::const_iterator i = turnouts.find(id);
134         if(i==turnouts.end())
135                 throw KeyError("Unknown turnout");
136
137         return *i->second;
138 }
139
140 void Control::add_locomotive(Locomotive &l)
141 {
142         locomotives[l.get_address()] = &l;
143 }
144
145 Locomotive &Control::get_locomotive(unsigned id) const
146 {
147         map<unsigned, Locomotive *>::const_iterator i = locomotives.find(id);
148         if(i==locomotives.end())
149                 throw KeyError("Unknown locomotive");
150
151         return *i->second;
152 }
153
154 void Control::add_sensor(Sensor &s)
155 {
156         sensors[s.get_address()] = &s;
157         poll_sensors = true;
158 }
159
160 Sensor &Control::get_sensor(unsigned id) const
161 {
162         map<unsigned, Sensor *>::const_iterator i = sensors.find(id);
163         if(i==sensors.end())
164                 throw KeyError("Unknown sensor");
165
166         return *i->second;
167 }
168
169 void Control::tick()
170 {
171         const Time::TimeStamp t = Time::now();
172
173         for(map<unsigned, Sensor *>::const_iterator i=sensors.begin(); i!=sensors.end(); ++i)
174                 i->second->tick();
175
176         timer.tick(false);
177
178         if(t>next_event_query)
179         {
180                 next_event_query = t+200*Time::msec;
181                 command(CMD_EVENT).signal_done.connect(sigc::mem_fun(this, &Control::event_query_done));
182         }
183
184         if(poll_sensors)
185         {
186                 unsigned max_addr = (--sensors.end())->first;
187                 unsigned char data[2];
188                 data[0] = 0;
189                 data[1] = (max_addr+7)/8;
190                 command(CMD_SENSOR_PARAM_SET, data, 2);
191                 command(CMD_SENSOR_REPORT);
192                 poll_sensors = false;
193         }
194
195         if(!queue.empty() && queue.front().is_sent())
196         {
197                 pollfd pfd = { serial_fd, POLLIN, 0 };
198                 if(poll(&pfd, 1, 0)>0)
199                 {
200                         Reply reply = Reply::read(serial_fd, queue.front().get_command());
201                         if(debug)
202                                 cout<<"R: "<<reply<<'\n';
203
204                         queue.front().signal_done.emit(reply);
205                         queue.erase(queue.begin());
206                 }
207                 else
208                         return;
209         }
210
211         if(!queue.empty())
212         {
213                 if(debug)
214                         cout<<"W: "<<queue.front()<<'\n';
215
216                 if(serial_fd>=0)
217                         queue.front().send(serial_fd);
218                 else
219                 {
220                         Reply reply = Reply::simulate(queue.front().get_command());
221                         queue.front().signal_done.emit(reply);
222                         queue.erase(queue.begin());
223                 }
224         }
225 }
226
227 Time::Timer::Slot &Control::set_timer(const Time::TimeDelta &dt)
228 {
229         return timer.add(dt);
230 }
231
232 void Control::status_done(const Reply &reply)
233 {
234         power = ((reply.get_data()[0]&0x08)!=0);
235         signal_power_event.emit(power);
236 }
237
238 void Control::event_query_done(const Reply &reply)
239 {
240         const unsigned char *data = reply.get_data();
241         if(data[0]&0x01)
242                 command(CMD_EVENT_LOK);
243         if(data[0]&0x20)
244                 command(CMD_EVENT_TURNOUT).signal_done.connect(sigc::mem_fun(this, &Control::turnout_event_done));
245         if(data[0]&0x04)
246                 command(CMD_EVENT_SENSOR).signal_done.connect(sigc::mem_fun(this, &Control::sensor_event_done));
247         if((data[0]&0x80) && (data[1]&0x40))
248                 command(CMD_STATUS).signal_done.connect(sigc::mem_fun(this, &Control::status_done));
249 }
250
251 void Control::turnout_event_done(const Reply &reply)
252 {
253         const unsigned char *data = reply.get_data();
254         unsigned count = data[0];
255         for(unsigned i=0; i<count; ++i)
256         {
257                 unsigned addr = (data[i*2+1])+((data[i*2+2]&7)<<8);
258                 bool status = !(data[i*2+2]&0x80);
259                 cout<<"Turnout "<<addr<<", status "<<status<<'\n';
260                 signal_turnout_event.emit(addr, status);
261         }
262 }
263
264 void Control::sensor_event_done(const Reply &reply)
265 {
266         const unsigned char *data = reply.get_data();
267         for(unsigned i=0; data[i]; i+=3)
268         {
269                 unsigned module = data[i];
270
271                 cout<<"S88 module "<<module<<", status ";
272                 for(unsigned j=0; j<16; ++j)
273                         cout<<((data[i+1+j/8]>>(7-j%8))&1);
274                 cout<<'\n';
275
276                 for(unsigned j=0; j<16; ++j)
277                         signal_sensor_event.emit(module*16+j-15, (data[i+1+j/8]>>(7-j%8))&1);
278         }
279 }
280
281 } // namespace Marklin