]> git.tdb.fi Git - r2c2.git/blob - source/network/server.cpp
Foundations of using physics simulation for trains
[r2c2.git] / source / network / server.cpp
1 /* $Id$
2
3 This file is part of the MSP Märklin suite
4 Copyright © 2009-2010  Mikkosoft Productions, Mikko Rasa
5 Distributed under the GPL
6 */
7
8 #include <msp/net/inet.h>
9 #include "libmarklin/locotype.h"
10 #include "libmarklin/route.h"
11 #include "libmarklin/train.h"
12 #include "server.h"
13
14 using namespace std;
15 using namespace Msp;
16
17 namespace Marklin {
18
19 Server::Server(Layout &l):
20         layout(l),
21         listen_sock(Net::INET),
22         event_disp(0)
23 {
24         layout.signal_train_added.connect(sigc::mem_fun(this, &Server::train_added));
25
26         const map<unsigned, Train *> &trains = layout.get_trains();
27         for(map<unsigned, Train *>::const_iterator i=trains.begin(); i!=trains.end(); ++i)
28                 train_added(*i->second);
29
30         listen_sock.listen(Net::InetAddr(0, 8315), 4);
31         listen_sock.signal_data_available.connect(sigc::mem_fun(this, &Server::incoming_connection));
32 }
33
34 void Server::use_event_dispatcher(IO::EventDispatcher &ed)
35 {
36         event_disp = &ed;
37         event_disp->add(listen_sock);
38 }
39
40 void Server::incoming_connection()
41 {
42         Net::StreamSocket *sock = listen_sock.accept();
43         if(event_disp)
44                 event_disp->add(*sock);
45         connections.push_back(new Connection(*this, sock));
46 }
47
48 void Server::train_added(Train &train)
49 {
50         train.signal_control_changed.connect(sigc::bind<0>(sigc::mem_fun(this, &Server::train_control_changed), sigc::ref(train)));
51         train.signal_function_changed.connect(sigc::bind<0>(sigc::mem_fun(this, &Server::train_function_changed), sigc::ref(train)));
52         train.signal_route_changed.connect(sigc::bind<0>(sigc::mem_fun(this, &Server::train_route_changed), sigc::ref(train)));
53         train.signal_status_changed.connect(sigc::bind<0>(sigc::mem_fun(this, &Server::train_status_changed), sigc::ref(train)));
54
55         TrainInfoPacket pkt;
56         pkt.address = train.get_address();
57         pkt.loco_type = train.get_locomotive_type().get_article_number();
58         pkt.name = train.get_name();
59         send(pkt);
60 }
61
62 void Server::train_control_changed(const Train &train, const string &control, float value)
63 {
64         TrainControlPacket pkt;
65         pkt.address = train.get_address();
66         pkt.control = control;
67         pkt.value = value;
68         send(pkt);
69 }
70
71 void Server::train_function_changed(const Train &train, unsigned, bool)
72 {
73         TrainFunctionPacket pkt;
74         pkt.address = train.get_address();
75         pkt.functions = train.get_functions();
76         send(pkt);
77 }
78
79 void Server::train_route_changed(const Train &train, const Route *route)
80 {
81         TrainRoutePacket pkt;
82         pkt.address = train.get_address();
83         if(route)
84                 pkt.route = route->get_name();
85         send(pkt);
86 }
87
88 void Server::train_status_changed(const Train &train, const string &status)
89 {
90         TrainStatusPacket pkt;
91         pkt.address = train.get_address();
92         pkt.status = status;
93         send(pkt);
94 }
95
96 template<typename P>
97 void Server::send(const P &pkt)
98 {
99         for(vector<Connection *>::const_iterator i=connections.begin(); i!=connections.end(); ++i)
100                 if(!(*i)->stale)
101                         (*i)->comm.send(pkt);
102 }
103
104
105 Server::Connection::Connection(Server &s, Net::StreamSocket *o):
106         server(s),
107         socket(o),
108         comm(*socket, server.proto, *this)
109 {
110         socket->signal_end_of_file.connect(sigc::mem_fun(this, &Connection::end_of_file));
111         comm.signal_handshake_done.connect(sigc::mem_fun(this, &Connection::handshake_done));
112         comm.initiate_handshake();
113 }
114
115 Server::Connection::~Connection()
116 {
117         delete socket;
118 }
119
120 void Server::Connection::handshake_done()
121 {
122         const map<string, Route *> &routes = server.layout.get_routes();
123         for(map<string, Route *>::const_iterator i=routes.begin(); i!=routes.end(); ++i)
124         {
125                 RouteInfoPacket pkt;
126                 pkt.name = i->first;
127                 comm.send(pkt);
128         }
129
130         const map<unsigned, Train *> &trains = server.layout.get_trains();
131         for(map<unsigned, Train *>::const_iterator i=trains.begin(); i!=trains.end(); ++i)
132         {
133                 const Train &train = *i->second;
134
135                 {
136                         TrainInfoPacket pkt;
137                         pkt.address = train.get_address();
138                         pkt.loco_type = train.get_locomotive_type().get_article_number();
139                         pkt.name = train.get_name();
140                         comm.send(pkt);
141                 }
142                 // XXX Need control enumeration to send control packets
143                 {
144                         TrainFunctionPacket pkt;
145                         pkt.address = train.get_address();
146                         pkt.functions = train.get_functions();
147                         comm.send(pkt);
148                 }
149                 {
150                         TrainStatusPacket pkt;
151                         pkt.address = train.get_address();
152                         pkt.status = train.get_status();
153                         comm.send(pkt);
154                 }
155                 if(train.get_route())
156                 {
157                         TrainRoutePacket pkt;
158                         pkt.address = train.get_address();
159                         pkt.route = train.get_route()->get_name();
160                         comm.send(pkt);
161                 }
162         }
163 }
164
165 void Server::Connection::end_of_file()
166 {
167         socket->close();
168         stale = true;
169 }
170
171 void Server::Connection::receive(const TrainControlPacket &pkt)
172 {
173         try
174         {
175                 Train &train = server.layout.get_train(pkt.address);
176                 train.set_control(pkt.control, pkt.value);
177         }
178         catch(const Exception &e)
179         {
180                 error(e.what());
181         }
182 }
183
184 void Server::Connection::receive(const TrainFunctionPacket &pkt)
185 {
186         try
187         {
188                 Train &train = server.layout.get_train(pkt.address);
189                 for(unsigned i=0; i<9; ++i)
190                         if(((pkt.functions^train.get_functions())>>i)&1)
191                                 train.set_function(i, (pkt.functions>>i)&1);
192         }
193         catch(const Exception &e)
194         {
195                 error(e.what());
196         }
197 }
198
199 void Server::Connection::receive(const TrainRoutePacket &pkt)
200 {
201         try
202         {
203                 Train &train = server.layout.get_train(pkt.address);
204                 if(pkt.route.empty())
205                         train.set_route(0);
206                 else
207                 {
208                         Route &route = server.layout.get_route(pkt.route);
209                         train.set_route(&route);
210                 }
211         }
212         catch(const Exception &e)
213         {
214                 error(e.what());
215         }
216 }
217
218 void Server::Connection::error(const string &msg)
219 {
220         ErrorPacket pkt;
221         pkt.message = msg;
222         comm.send(pkt);
223 }
224
225 } // namespace Marklin