]> git.tdb.fi Git - r2c2.git/blob - source/network/server.cpp
Add networking library and a remote control program
[r2c2.git] / source / network / server.cpp
1 /* $Id$
2
3 This file is part of the MSP Märklin suite
4 Copyright © 2009  Mikkosoft Productions, Mikko Rasa
5 Distributed under the GPL
6 */
7
8 #include <msp/net/inet.h>
9 #include "libmarklin/control.h"
10 #include "libmarklin/locomotive.h"
11 #include "libmarklin/locotype.h"
12 #include "server.h"
13
14 using namespace std;
15 using namespace Msp;
16
17 namespace Marklin {
18
19 Server::Server(TrafficManager &tm):
20         trfc_mgr(tm),
21         listen_sock(Net::INET),
22         event_disp(0)
23 {
24         const list<Train *> &trains = trfc_mgr.get_trains();
25         for(list<Train *>::const_iterator i=trains.begin(); i!=trains.end(); ++i)
26         {
27                 Locomotive &loco = (*i)->get_locomotive();
28                 (*i)->signal_target_speed_changed.connect(sigc::bind<0>(sigc::mem_fun(this, &Server::train_speed_changed), sigc::ref(**i)));
29                 loco.signal_function_changed.connect(sigc::bind<0>(sigc::mem_fun(this, &Server::train_function_changed), sigc::ref(**i)));
30                 (*i)->signal_status_changed.connect(sigc::bind<0>(sigc::mem_fun(this, &Server::train_status_changed), sigc::ref(**i)));
31         }
32
33         listen_sock.listen(Net::InetAddr(0, 8315), 4);
34         listen_sock.signal_data_available.connect(sigc::mem_fun(this, &Server::incoming_connection));
35 }
36
37 void Server::use_event_dispatcher(IO::EventDispatcher &ed)
38 {
39         event_disp = &ed;
40         event_disp->add(listen_sock);
41 }
42
43 void Server::incoming_connection()
44 {
45         Net::StreamSocket *sock = listen_sock.accept();
46         if(event_disp)
47                 event_disp->add(*sock);
48         connections.push_back(new Connection(*this, sock));
49 }
50
51 void Server::train_added(Train &train)
52 {
53         Locomotive &loco = train.get_locomotive();
54         train.signal_target_speed_changed.connect(sigc::bind<0>(sigc::mem_fun(this, &Server::train_speed_changed), sigc::ref(train)));
55         loco.signal_function_changed.connect(sigc::bind<0>(sigc::mem_fun(this, &Server::train_function_changed), sigc::ref(train)));
56         train.signal_status_changed.connect(sigc::bind<0>(sigc::mem_fun(this, &Server::train_status_changed), sigc::ref(train)));
57
58         TrainInfoPacket pkt;
59         pkt.address = loco.get_address();
60         pkt.loco_type = loco.get_type().get_article_number();
61         pkt.name = train.get_name();
62         send(pkt);
63 }
64
65 void Server::train_speed_changed(const Train &train, unsigned speed)
66 {
67         TrainSpeedPacket pkt;
68         pkt.address = train.get_locomotive().get_address();
69         pkt.speed = speed;
70         pkt.reverse = train.get_locomotive().get_reverse();
71         send(pkt);
72 }
73
74 void Server::train_function_changed(const Train &train, unsigned, bool)
75 {
76         TrainFunctionPacket pkt;
77         pkt.address = train.get_locomotive().get_address();
78         pkt.functions = train.get_locomotive().get_functions();
79         send(pkt);
80 }
81
82 void Server::train_status_changed(const Train &train, const string &status)
83 {
84         TrainStatusPacket pkt;
85         pkt.address = train.get_locomotive().get_address();
86         pkt.status = status;
87         send(pkt);
88 }
89
90 template<typename P>
91 void Server::send(const P &pkt)
92 {
93         for(vector<Connection *>::const_iterator i=connections.begin(); i!=connections.end(); ++i)
94                 if(!(*i)->stale)
95                         (*i)->comm.send(pkt);
96 }
97
98
99 Server::Connection::Connection(Server &s, Net::StreamSocket *o):
100         server(s),
101         socket(o),
102         comm(*socket, server.proto, *this)
103 {
104         socket->signal_end_of_file.connect(sigc::mem_fun(this, &Connection::end_of_file));
105         comm.signal_handshake_done.connect(sigc::mem_fun(this, &Connection::handshake_done));
106         comm.initiate_handshake();
107 }
108
109 Server::Connection::~Connection()
110 {
111         delete socket;
112 }
113
114 void Server::Connection::handshake_done()
115 {
116         const list<Train *> &trains = server.trfc_mgr.get_trains();
117         for(list<Train *>::const_iterator i=trains.begin(); i!=trains.end(); ++i)
118         {
119                 Locomotive &loco = (*i)->get_locomotive();
120
121                 {
122                         TrainInfoPacket pkt;
123                         pkt.address = loco.get_address();
124                         pkt.loco_type = loco.get_type().get_article_number();
125                         pkt.name = (*i)->get_name();
126                         comm.send(pkt);
127                 }
128                 {
129                         TrainSpeedPacket pkt;
130                         pkt.address = loco.get_address();
131                         pkt.speed = (*i)->get_target_speed();
132                         pkt.reverse = loco.get_reverse();
133                         comm.send(pkt);
134                 }
135                 {
136                         TrainFunctionPacket pkt;
137                         pkt.address = loco.get_address();
138                         pkt.functions = loco.get_functions();
139                         comm.send(pkt);
140                 }
141                 {
142                         TrainStatusPacket pkt;
143                         pkt.address = loco.get_address();
144                         pkt.status = (*i)->get_status();
145                         comm.send(pkt);
146                 }
147         }
148 }
149
150 void Server::Connection::end_of_file()
151 {
152         socket->close();
153         stale = true;
154 }
155
156 void Server::Connection::receive(const TrainSpeedPacket &pkt)
157 {
158         Locomotive &loco = server.trfc_mgr.get_control().get_locomotive(pkt.address);
159         Train &train = server.trfc_mgr.get_train_by_locomotive(loco);
160         if(pkt.reverse!=loco.get_reverse())
161                 train.set_reverse(pkt.reverse);
162         else
163                 train.set_speed(pkt.speed);
164 }
165
166 void Server::Connection::receive(const TrainFunctionPacket &pkt)
167 {
168         Locomotive &loco = server.trfc_mgr.get_control().get_locomotive(pkt.address);
169         for(unsigned i=0; i<9; ++i)
170                 if(((pkt.functions^loco.get_functions())>>i)&1)
171                         loco.set_function(i, (pkt.functions>>i)&1);
172 }
173
174 } // namespace Marklin