1 #include <msp/core/refptr.h>
2 #include <msp/net/inet.h>
3 #include <msp/net/resolve.h>
4 #include "libr2c2/driver.h"
5 #include "libr2c2/route.h"
6 #include "libr2c2/train.h"
7 #include "libr2c2/trainrouter.h"
8 #include "libr2c2/trainstatus.h"
9 #include "libr2c2/vehicletype.h"
17 Server::Server(Layout &l):
19 listen_sock(Net::INET),
22 layout.get_driver().signal_power.connect(sigc::hide(sigc::mem_fun(this, &Server::driver_state_changed)));
23 layout.get_driver().signal_halt.connect(sigc::hide(sigc::mem_fun(this, &Server::driver_state_changed)));
24 layout.signal_emergency.connect(sigc::mem_fun(this, &Server::emergency));
26 layout.signal_train_added.connect(sigc::mem_fun(this, &Server::train_added));
28 const map<unsigned, Train *> &trains = layout.get_trains();
29 for(map<unsigned, Train *>::const_iterator i=trains.begin(); i!=trains.end(); ++i)
30 train_added(*i->second);
32 RefPtr<Net::SockAddr> addr = Net::resolve("*", "8315", Net::INET);
33 listen_sock.listen(*addr, 4);
34 listen_sock.signal_data_available.connect(sigc::mem_fun(this, &Server::incoming_connection));
40 void Server::use_event_dispatcher(IO::EventDispatcher &ed)
43 event_disp->add(listen_sock);
46 void Server::incoming_connection()
48 Net::StreamSocket *sock = listen_sock.accept();
50 event_disp->add(*sock);
51 connections.push_back(new Connection(*this, sock));
54 void Server::driver_state_changed()
56 DriverStatePacket pkt;
57 pkt.power = layout.get_driver().get_power();
58 pkt.halt = layout.get_driver().is_halted();
62 void Server::emergency(const string &msg)
69 void Server::train_added(Train &train)
71 train.signal_control_changed.connect(sigc::bind<0>(sigc::mem_fun(this, &Server::train_control_changed), sigc::ref(train)));
72 train.signal_function_changed.connect(sigc::bind<0>(sigc::mem_fun(this, &Server::train_function_changed), sigc::ref(train)));
73 train.signal_ai_event.connect(sigc::bind<0>(sigc::mem_fun(this, &Server::train_ai_event), sigc::ref(train)));
76 pkt.address = train.get_address();
77 pkt.loco_type = train.get_locomotive_type().get_article_number().str();
78 pkt.name = train.get_name();
81 if(!train.get_ai_of_type<TrainStatus>())
82 new TrainStatus(train);
85 void Server::train_control_changed(const Train &train, const string &control, float value)
87 TrainControlPacket pkt;
88 pkt.address = train.get_address();
89 pkt.control = control;
94 void Server::train_function_changed(const Train &train, unsigned, bool)
96 TrainFunctionPacket pkt;
97 pkt.address = train.get_address();
98 pkt.functions = train.get_functions();
102 void Server::train_ai_event(const Train &train, TrainAI &, const TrainAI::Message &ev)
104 if(ev.type=="route-changed")
106 TrainRoutePacket pkt;
107 pkt.address = train.get_address();
108 if(const Route *route = ev.value.value<const Route *>())
109 pkt.route = route->get_name();
112 else if(ev.type=="status-changed")
114 TrainStatusPacket pkt;
115 pkt.address = train.get_address();
116 pkt.status = ev.value.value<std::string>();
122 void Server::send(const P &pkt)
124 for(vector<Connection *>::const_iterator i=connections.begin(); i!=connections.end(); ++i)
125 if(!(*i)->stale && (*i)->comm.is_handshake_done())
129 (*i)->comm.send(pkt);
139 Server::Connection::Connection(Server &s, Net::StreamSocket *o):
142 comm(*socket, server.proto, *this)
144 socket->signal_end_of_file.connect(sigc::mem_fun(this, &Connection::end_of_file));
145 comm.signal_handshake_done.connect(sigc::mem_fun(this, &Connection::handshake_done));
146 comm.initiate_handshake();
149 Server::Connection::~Connection()
154 void Server::Connection::handshake_done()
157 DriverStatePacket pkt;
158 pkt.power = server.layout.get_driver().get_power();
159 pkt.halt = server.layout.get_driver().is_halted();
163 const set<Route *> &routes = server.layout.get_all<Route>();
164 for(set<Route *>::const_iterator i=routes.begin(); i!=routes.end(); ++i)
165 if(!(*i)->is_temporary())
168 pkt.name = (*i)->get_name();
172 const map<unsigned, Train *> &trains = server.layout.get_trains();
173 for(map<unsigned, Train *>::const_iterator i=trains.begin(); i!=trains.end(); ++i)
175 const Train &train = *i->second;
179 pkt.address = train.get_address();
180 pkt.loco_type = train.get_locomotive_type().get_article_number().str();
181 pkt.name = train.get_name();
184 for(unsigned j=0;; ++j)
186 const char *name = train.get_controller().enumerate_controls(j);
190 TrainControlPacket pkt;
191 pkt.address = train.get_address();
193 pkt.value = train.get_control(name);
197 TrainFunctionPacket pkt;
198 pkt.address = train.get_address();
199 pkt.functions = train.get_functions();
202 if(TrainStatus *status = train.get_ai_of_type<TrainStatus>())
204 TrainStatusPacket pkt;
205 pkt.address = train.get_address();
206 pkt.status = status->get_status();
209 if(TrainRouter *router = train.get_ai_of_type<TrainRouter>())
211 TrainRoutePacket pkt;
212 pkt.address = train.get_address();
213 pkt.route = router->get_route()->get_name();
219 void Server::Connection::end_of_file()
224 void Server::Connection::receive(const DriverStatePacket &pkt)
226 Driver &driver = server.layout.get_driver();
227 if(pkt.power!=driver.get_power())
228 driver.set_power(pkt.power);
229 if(pkt.halt!=driver.is_halted())
230 driver.halt(pkt.halt);
233 void Server::Connection::receive(const TrainControlPacket &pkt)
237 Train &train = server.layout.get_train(pkt.address);
238 train.set_control(pkt.control, pkt.value);
240 catch(const exception &e)
246 void Server::Connection::receive(const TrainFunctionPacket &pkt)
250 Train &train = server.layout.get_train(pkt.address);
251 for(unsigned i=0; i<9; ++i)
252 if(((pkt.functions^train.get_functions())>>i)&1)
253 train.set_function(i, (pkt.functions>>i)&1);
255 catch(const exception &e)
261 void Server::Connection::receive(const TrainRoutePacket &pkt)
265 Train &train = server.layout.get_train(pkt.address);
266 if(pkt.route.empty())
267 train.ai_message(TrainAI::Message("clear-route"));
270 Route &route = server.layout.get_route(pkt.route);
271 train.ai_message(TrainAI::Message("set-route", &route));
274 catch(const exception &e)
280 void Server::Connection::error(const string &msg)