3 This file is part of the MSP Märklin suite
4 Copyright © 2006-2008 Mikkosoft Productions, Mikko Rasa
5 Distributed under the GPL
12 #include <msp/core/except.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)
42 void Control::set_power(bool p)
46 command(CMD_POWER_ON);
48 command(CMD_POWER_OFF);
50 signal_power_event.emit(power);
53 void Control::set_debug(bool d)
58 void Control::open(const string &dev)
60 serial_fd=::open(dev.c_str(), O_RDWR);
62 throw Exception("Couldn't open serial port\n");
64 static unsigned baud[]=
74 tcgetattr(serial_fd, &attr);
80 for(unsigned i=0; baud[i]; i+=2)
82 cfsetospeed(&attr, baud[i+1]);
83 tcsetattr(serial_fd, TCSADRAIN, &attr);
85 write(serial_fd, "\xC4", 1);
87 pollfd pfd={serial_fd, POLLIN, 0};
88 if(poll(&pfd, 1, 500)>0)
90 cout<<"IB detected at "<<baud[i]<<" bits/s\n";
92 p50=(read(serial_fd, buf, 2)==2);
99 throw Exception("IB not detected");
102 write(serial_fd, "xZzA1\r", 6);
104 command(CMD_STATUS).signal_done.connect(sigc::mem_fun(this, &Control::status_done));
107 Command &Control::command(Cmd cmd)
109 queue.push_back(Command(cmd, 0, 0));
113 Command &Control::command(Cmd cmd, unsigned char data)
115 queue.push_back(Command(cmd, &data, 1));
119 Command &Control::command(Cmd cmd, const unsigned char *data, unsigned len)
121 queue.push_back(Command(cmd, data, len));
125 void Control::add_turnout(Turnout &t)
127 turnouts[t.get_address()]=&t;
130 Turnout &Control::get_turnout(unsigned id) const
132 map<unsigned, Turnout *>::const_iterator i=turnouts.find(id);
133 if(i==turnouts.end())
134 throw KeyError("Unknown turnout");
139 void Control::add_locomotive(Locomotive &l)
141 locomotives[l.get_address()]=&l;
144 Locomotive &Control::get_locomotive(unsigned id) const
146 map<unsigned, Locomotive *>::const_iterator i=locomotives.find(id);
147 if(i==locomotives.end())
148 throw KeyError("Unknown locomotive");
153 void Control::add_sensor(Sensor &s)
155 sensors[s.get_address()]=&s;
159 Sensor &Control::get_sensor(unsigned id) const
161 map<unsigned, Sensor *>::const_iterator i=sensors.find(id);
163 throw KeyError("Unknown sensor");
170 const Time::TimeStamp t=Time::now();
172 for(map<unsigned, Sensor *>::const_iterator i=sensors.begin(); i!=sensors.end(); ++i)
177 if(t>next_event_query)
179 next_event_query=t+200*Time::msec;
180 command(CMD_EVENT).signal_done.connect(sigc::mem_fun(this, &Control::event_query_done));
185 unsigned max_addr=(--sensors.end())->first;
186 unsigned char data[2];
188 data[1]=(max_addr+7)/8;
189 command(CMD_SENSOR_PARAM_SET, data, 2);
190 command(CMD_SENSOR_REPORT);
194 if(!queue.empty() && queue.front().get_sent())
196 pollfd pfd={serial_fd, POLLIN, 0};
197 if(poll(&pfd, 1, 0)>0)
199 Reply reply=Reply::read(serial_fd, queue.front().get_command());
201 cout<<"R: "<<reply<<'\n';
203 queue.front().signal_done.emit(reply);
204 queue.erase(queue.begin());
213 cout<<"W: "<<queue.front()<<'\n';
215 queue.front().send(serial_fd);
219 Time::Timer::Slot &Control::set_timer(const Time::TimeDelta &dt)
221 return timer.add(dt);
224 void Control::read_all(int fd, char *buf, int size)
229 int len=read(fd, buf+pos, size-pos);
234 void Control::status_done(const Reply &reply)
236 power=((reply.get_data()[0]&0x08)!=0);
237 signal_power_event.emit(power);
240 void Control::event_query_done(const Reply &reply)
242 const unsigned char *data=reply.get_data();
244 command(CMD_EVENT_LOK);
246 command(CMD_EVENT_TURNOUT).signal_done.connect(sigc::mem_fun(this, &Control::turnout_event_done));
248 command(CMD_EVENT_SENSOR).signal_done.connect(sigc::mem_fun(this, &Control::sensor_event_done));
250 command(CMD_STATUS).signal_done.connect(sigc::mem_fun(this, &Control::status_done));
253 void Control::turnout_event_done(const Reply &reply)
255 const unsigned char *data=reply.get_data();
256 unsigned count=data[0];
257 for(unsigned i=0; i<count; ++i)
259 unsigned addr=(data[i*2+1])+((data[i*2+2]&7)<<8);
260 bool status=!(data[i*2+2]&0x80);
261 cout<<"Turnout "<<addr<<", status "<<status<<'\n';
262 signal_turnout_event.emit(addr, status);
266 void Control::sensor_event_done(const Reply &reply)
268 const unsigned char *data=reply.get_data();
269 for(unsigned i=0; data[i]; i+=3)
271 unsigned module=data[i];
273 cout<<"S88 module "<<module<<", status ";
274 for(unsigned j=0; j<16; ++j)
275 cout<<((data[i+1+j/8]>>(7-j%8))&1);
278 for(unsigned j=0; j<16; ++j)
279 signal_sensor_event.emit(module*16+j-15, (data[i+1+j/8]>>(7-j%8))&1);
283 } // namespace Marklin