3 This file is part of the MSP Märklin suite
4 Copyright © 2007-2009 Mikkosoft Productions, Mikko Rasa
5 Distributed under the GPL
11 #include <msp/core/except.h>
12 #include <msp/io/print.h>
13 #include <msp/time/units.h>
14 #include <msp/time/utils.h>
33 for(map<unsigned, Sensor *>::iterator i=sensors.begin(); i!=sensors.end(); ++i)
35 for(map<unsigned, Turnout *>::iterator i=turnouts.begin(); i!=turnouts.end(); ++i)
37 for(map<unsigned, Locomotive *>::iterator i=locomotives.begin(); i!=locomotives.end(); ++i)
43 void Control::open(const string &dev)
45 serial_fd = ::open(dev.c_str(), O_RDWR);
47 throw Exception("Couldn't open serial port\n");
49 static unsigned baud[]=
59 tcgetattr(serial_fd, &attr);
61 attr.c_cflag |= CSTOPB;
65 for(unsigned i=0; baud[i]; i+=2)
67 cfsetospeed(&attr, baud[i+1]);
68 tcsetattr(serial_fd, TCSADRAIN, &attr);
70 write(serial_fd, "\xC4", 1);
72 pollfd pfd = { serial_fd, POLLIN, 0 };
73 if(poll(&pfd, 1, 500)>0)
75 IO::print("IB detected at %d bits/s\n", baud[i]);
77 p50 = (read(serial_fd, buf, 2)==2);
84 throw Exception("IB not detected");
87 write(serial_fd, "xZzA1\r", 6);
89 command(CMD_STATUS).signal_done.connect(sigc::mem_fun(this, &Control::status_done));
92 void Control::set_debug(bool d)
97 void Control::set_power(bool p)
101 command(CMD_POWER_ON);
103 command(CMD_POWER_OFF);
105 signal_power_event.emit(power);
108 Command &Control::command(Cmd cmd)
110 queue.push_back(Command(cmd, 0, 0));
114 Command &Control::command(Cmd cmd, unsigned char data)
116 queue.push_back(Command(cmd, &data, 1));
120 Command &Control::command(Cmd cmd, const unsigned char *data, unsigned len)
122 queue.push_back(Command(cmd, data, len));
126 void Control::flush()
128 for(list<Command>::iterator i=queue.begin(); i!=queue.end(); ++i)
132 void Control::add_turnout(Turnout &t)
134 turnouts[t.get_address()] = &t;
137 Turnout &Control::get_turnout(unsigned id) const
139 map<unsigned, Turnout *>::const_iterator i = turnouts.find(id);
140 if(i==turnouts.end())
141 throw KeyError("Unknown turnout");
146 void Control::add_locomotive(Locomotive &l)
148 locomotives[l.get_address()] = &l;
151 Locomotive &Control::get_locomotive(unsigned id) const
153 map<unsigned, Locomotive *>::const_iterator i = locomotives.find(id);
154 if(i==locomotives.end())
155 throw KeyError("Unknown locomotive");
160 void Control::add_sensor(Sensor &s)
162 sensors[s.get_address()] = &s;
166 Sensor &Control::get_sensor(unsigned id) const
168 map<unsigned, Sensor *>::const_iterator i = sensors.find(id);
170 throw KeyError("Unknown sensor");
177 const Time::TimeStamp t = Time::now();
179 for(map<unsigned, Sensor *>::const_iterator i=sensors.begin(); i!=sensors.end(); ++i)
184 if(t>next_event_query)
186 next_event_query = t+200*Time::msec;
187 command(CMD_EVENT).signal_done.connect(sigc::mem_fun(this, &Control::event_query_done));
192 unsigned max_addr = (--sensors.end())->first;
193 unsigned char data[2];
195 data[1] = (max_addr+7)/8;
196 command(CMD_SENSOR_PARAM_SET, data, 2);
197 command(CMD_SENSOR_REPORT);
198 poll_sensors = false;
201 if(!queue.empty() && queue.front().is_sent())
203 pollfd pfd = { serial_fd, POLLIN, 0 };
204 if(poll(&pfd, 1, 0)>0)
206 Reply reply = Reply::read(serial_fd, queue.front().get_command());
208 IO::print("R: %s\n", reply);
210 queue.front().signal_done.emit(reply);
211 queue.erase(queue.begin());
220 IO::print("W: %s\n", queue.front());
223 queue.front().send(serial_fd);
226 Reply reply = Reply::simulate(queue.front().get_command());
227 queue.front().signal_done.emit(reply);
228 queue.erase(queue.begin());
233 Time::Timer::Slot &Control::set_timer(const Time::TimeDelta &dt)
235 return timer.add(dt);
238 void Control::status_done(const Reply &reply)
240 power = ((reply.get_data()[0]&0x08)!=0);
241 signal_power_event.emit(power);
244 void Control::event_query_done(const Reply &reply)
246 const unsigned char *data = reply.get_data();
248 command(CMD_EVENT_LOK);
250 command(CMD_EVENT_TURNOUT).signal_done.connect(sigc::mem_fun(this, &Control::turnout_event_done));
252 command(CMD_EVENT_SENSOR).signal_done.connect(sigc::mem_fun(this, &Control::sensor_event_done));
253 if((data[0]&0x80) && (data[1]&0x40))
254 command(CMD_STATUS).signal_done.connect(sigc::mem_fun(this, &Control::status_done));
257 void Control::turnout_event_done(const Reply &reply)
259 const unsigned char *data = reply.get_data();
260 unsigned count = data[0];
261 for(unsigned i=0; i<count; ++i)
263 unsigned addr = (data[i*2+1])+((data[i*2+2]&7)<<8);
264 bool status = !(data[i*2+2]&0x80);
265 IO::print("Turnout %d, status %d\n", addr, status);
266 signal_turnout_event.emit(addr, status);
270 void Control::sensor_event_done(const Reply &reply)
272 const unsigned char *data = reply.get_data();
273 for(unsigned i=0; data[i]; i+=3)
275 unsigned module = data[i];
277 IO::print("S88 module %d, status %08b%08b\n", module, data[1], data[2]);
279 for(unsigned j=0; j<16; ++j)
280 signal_sensor_event.emit(module*16+j-15, (data[i+1+j/8]>>(7-j%8))&1);
284 } // namespace Marklin