From: Mikko Rasa Date: Thu, 10 Dec 2009 20:05:34 +0000 (+0000) Subject: Add networking library and a remote control program X-Git-Url: http://git.tdb.fi/?p=r2c2.git;a=commitdiff_plain;h=010d8321e982d1684fcbff5bf6fc2bdec7cb7bae Add networking library and a remote control program --- diff --git a/Build b/Build index 817d757..a69a03d 100644 --- a/Build +++ b/Build @@ -13,6 +13,7 @@ package "märklin" { source "source/libmarklin"; require "mspdatafile"; + install true; }; library "marklin3d" @@ -23,20 +24,21 @@ package "märklin" { incpath "source"; library "marklin"; - libpath "."; }; + install true; }; - /*program "newconsole" + library "marklinnet" { - source "source/newconsole"; + source "source/network"; + require "mspnet"; build_info { - library "marklincontrol"; incpath "source"; - libpath "."; + library "marklin"; }; - };*/ + install true; + }; program "designer" { @@ -48,7 +50,6 @@ package "märklin" { incpath "source"; library "marklin3d"; - libpath "."; }; }; @@ -62,7 +63,18 @@ package "märklin" { incpath "source"; library "marklin3d"; - libpath "."; + library "marklinnet"; + }; + }; + + program "remote" + { + source "source/remote"; + require "gtkmm-2.4"; + build_info + { + incpath "source"; + library "marklinnet"; }; }; }; diff --git a/source/engineer/engineer.cpp b/source/engineer/engineer.cpp index 14e98c6..e0d45b0 100644 --- a/source/engineer/engineer.cpp +++ b/source/engineer/engineer.cpp @@ -20,6 +20,7 @@ Distributed under the GPL #include #include #include +#include #include "libmarklin/except.h" #include "libmarklin/tracktype.h" #include "engineer.h" @@ -37,6 +38,7 @@ Engineer::Engineer(int argc, char **argv): fullscreen(false), layout(catalogue), layout_3d(layout), + server(0), train_prop(0), train_prop_stale(false), placing_train(0), @@ -49,6 +51,7 @@ Engineer::Engineer(int argc, char **argv): bool debug = false; string device = "/dev/ttyS0"; unsigned quality = 4; + bool network = false; GetOpt getopt; getopt.add_option('r', "resolution", res, GetOpt::REQUIRED_ARG); @@ -57,6 +60,7 @@ Engineer::Engineer(int argc, char **argv): getopt.add_option('d', "device", device, GetOpt::REQUIRED_ARG); getopt.add_option('q', "quality", quality, GetOpt::REQUIRED_ARG); getopt.add_option('s', "simulate", simulate, GetOpt::NO_ARG); + getopt.add_option('n', "network", network, GetOpt::NO_ARG); getopt.add_option( "no-lighting", no_lighting, GetOpt::NO_ARG); getopt(argc, argv); @@ -91,6 +95,12 @@ Engineer::Engineer(int argc, char **argv): if(FS::exists("engineer.state")) DataFile::load(*trfc_mgr, "engineer.state"); + if(network) + { + server = new Server(*trfc_mgr); + server->use_event_dispatcher(event_disp); + } + const map &sensors = control.get_sensors(); for(map::const_iterator i=sensors.begin(); i!=sensors.end(); ++i) i->second->signal_state_changed.connect(sigc::bind(sigc::mem_fun(this, &Engineer::sensor_event), i->second)); @@ -213,6 +223,7 @@ void Engineer::tick() control.tick(); trfc_mgr->tick(); + event_disp.tick(Time::zero); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); diff --git a/source/engineer/engineer.h b/source/engineer/engineer.h index ad4bbcc..c7c062f 100644 --- a/source/engineer/engineer.h +++ b/source/engineer/engineer.h @@ -19,6 +19,7 @@ Distributed under the GPL #include "libmarklin/trafficmanager.h" #include "libmarklin/train.h" #include "3d/layout.h" +#include "network/server.h" class MainPanel; class TrainPanel; @@ -41,6 +42,8 @@ private: Marklin::Layout3D layout_3d; Marklin::Control control; Marklin::TrafficManager *trfc_mgr; + Marklin::Server *server; + Msp::IO::EventDispatcher event_disp; Marklin::Point cam_pos; float cam_rot; diff --git a/source/engineer/trainpanel.cpp b/source/engineer/trainpanel.cpp index a01df55..a8c0e90 100644 --- a/source/engineer/trainpanel.cpp +++ b/source/engineer/trainpanel.cpp @@ -35,7 +35,7 @@ TrainPanel::TrainPanel(Engineer &e, const GLtk::Resources &r, Train &t): add(*(lbl_speed=new GLtk::Label(res, format("%2d", train.get_locomotive().get_speed())))); lbl_speed->set_style("digital"); lbl_speed->set_geometry(GLtk::Geometry(10, geom.h-58, 35, 24)); - train.get_locomotive().signal_speed_changed.connect(sigc::mem_fun(this, &TrainPanel::loco_speed_changed)); + train.signal_target_speed_changed.connect(sigc::mem_fun(this, &TrainPanel::train_speed_changed)); add(*(sld_speed=new GLtk::HSlider(res))); sld_speed->set_geometry(GLtk::Geometry(50, geom.h-51, geom.w-80, 10)); @@ -89,9 +89,10 @@ void TrainPanel::speed_slider_changed(double v) train.set_speed(static_cast(v)); } -void TrainPanel::loco_speed_changed(unsigned speed) +void TrainPanel::train_speed_changed(unsigned speed) { lbl_speed->set_text(format("%2d", speed)); + sld_speed->set_value(speed); } void TrainPanel::loco_function_changed(unsigned func, bool value) diff --git a/source/engineer/trainpanel.h b/source/engineer/trainpanel.h index 2597d04..d8b1ab0 100644 --- a/source/engineer/trainpanel.h +++ b/source/engineer/trainpanel.h @@ -33,7 +33,7 @@ public: TrainPanel(Engineer &, const Msp::GLtk::Resources &, Marklin::Train &); private: void speed_slider_changed(double); - void loco_speed_changed(unsigned); + void train_speed_changed(unsigned); void loco_function_changed(unsigned, bool); void train_status_changed(const std::string &); void place_clicked(); diff --git a/source/libmarklin/locomotive.cpp b/source/libmarklin/locomotive.cpp index 3088d46..2df46a0 100644 --- a/source/libmarklin/locomotive.cpp +++ b/source/libmarklin/locomotive.cpp @@ -34,6 +34,8 @@ Locomotive::Locomotive(const LocoType &t, Control &c, unsigned a): void Locomotive::set_speed(unsigned spd) { spd = min(spd, 14U); + if(spd==speed) + return; signal_speed_changing.emit(spd); speed = spd; diff --git a/source/libmarklin/locomotive.h b/source/libmarklin/locomotive.h index 4c1f056..4a6770e 100644 --- a/source/libmarklin/locomotive.h +++ b/source/libmarklin/locomotive.h @@ -46,6 +46,7 @@ public: unsigned get_speed() const { return speed; } bool get_reverse() const { return reverse; } bool get_function(unsigned f) const { return (funcs>>f)&1; } + unsigned get_functions() const { return funcs; } void refresh_status(); private: void send_command(bool); diff --git a/source/libmarklin/trafficmanager.cpp b/source/libmarklin/trafficmanager.cpp index 069731e..b7301d3 100644 --- a/source/libmarklin/trafficmanager.cpp +++ b/source/libmarklin/trafficmanager.cpp @@ -69,10 +69,22 @@ Block &TrafficManager::get_block_by_track(const Track &t) const throw InvalidParameterValue("Unknown track"); } +Train &TrafficManager::get_train_by_locomotive(const Locomotive &loco) const +{ + for(list::const_iterator i=trains.begin(); i!=trains.end(); ++i) + if(&(*i)->get_locomotive()==&loco) + return **i; + + throw InvalidParameterValue("Unknown locomotive"); +} + void TrafficManager::add_train(Train *t) { if(find(trains.begin(), trains.end(), t)==trains.end()) + { trains.push_back(t); + signal_train_added.emit(*t); + } } void TrafficManager::tick() diff --git a/source/libmarklin/trafficmanager.h b/source/libmarklin/trafficmanager.h index d75bf3a..85381e0 100644 --- a/source/libmarklin/trafficmanager.h +++ b/source/libmarklin/trafficmanager.h @@ -28,6 +28,7 @@ public: void train(unsigned, unsigned); }; + sigc::signal signal_train_added; sigc::signal signal_block_reserved; private: @@ -45,6 +46,7 @@ public: const std::list &get_blocks() const { return blocks; } Block &get_block_by_track(const Track &) const; const std::list &get_trains() const { return trains; } + Train &get_train_by_locomotive(const Locomotive &) const; void add_train(Train *); void tick(); void save(const std::string &) const; diff --git a/source/libmarklin/train.cpp b/source/libmarklin/train.cpp index 09f5870..42d3e01 100644 --- a/source/libmarklin/train.cpp +++ b/source/libmarklin/train.cpp @@ -59,6 +59,8 @@ void Train::set_name(const string &n) void Train::set_speed(unsigned speed) { + if(speed==target_speed) + return; if(!target_speed && speed) travel_speed = static_cast(round(speed*speed_scale*87*3.6/5))*5; @@ -73,6 +75,8 @@ void Train::set_speed(unsigned speed) else reserve_more(); + signal_target_speed_changed.emit(target_speed); + update_speed(); pure_speed = false; } diff --git a/source/libmarklin/train.h b/source/libmarklin/train.h index 4c19caf..9b6344c 100644 --- a/source/libmarklin/train.h +++ b/source/libmarklin/train.h @@ -29,6 +29,7 @@ public: }; sigc::signal signal_name_changed; + sigc::signal signal_target_speed_changed; sigc::signal signal_status_changed; private: @@ -69,6 +70,7 @@ public: void set_reverse(bool); const std::string &get_name() const { return name; } Locomotive &get_locomotive() const { return loco; } + unsigned get_target_speed() const { return target_speed; } const std::string &get_status() const { return status; } const Point &get_position() const { return pos; } void place(Block *, unsigned); diff --git a/source/network/client.cpp b/source/network/client.cpp new file mode 100644 index 0000000..4eb4b25 --- /dev/null +++ b/source/network/client.cpp @@ -0,0 +1,76 @@ +/* $Id$ + +This file is part of the MSP Märklin suite +Copyright © 2009 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#include "client.h" + +using namespace std; +using namespace Msp; + +namespace Marklin { + +Client::Client(const Catalogue &c): + catalogue(c), + socket(0), + comm(0), + event_disp(0) +{ } + +Client::~Client() +{ + delete comm; + delete socket; + for(map::iterator i=trains.begin(); i!=trains.end(); ++i) + delete i->second; +} + +void Client::use_event_dispatcher(Msp::IO::EventDispatcher &ed) +{ + event_disp = &ed; + if(socket) + event_disp->add(*socket); +} + +void Client::connect(const Net::SockAddr &addr) +{ + socket = new Net::StreamSocket(addr.get_family()); + socket->connect(addr); + if(event_disp) + event_disp->add(*socket); + comm = new Net::Communicator(*socket, proto, *this); +} + +NetTrain &Client::get_train(unsigned addr) +{ + map::iterator i = trains.find(addr); + if(i==trains.end()) + throw KeyError("Unknown train"); + return *i->second; +} + +void Client::receive(const TrainInfoPacket &pkt) +{ + NetTrain *train = new NetTrain(*this, pkt); + trains[pkt.address] = train; + signal_train_added.emit(*train); +} + +void Client::receive(const TrainSpeedPacket &pkt) +{ + get_train(pkt.address).process_packet(pkt); +} + +void Client::receive(const TrainFunctionPacket &pkt) +{ + get_train(pkt.address).process_packet(pkt); +} + +void Client::receive(const TrainStatusPacket &pkt) +{ + get_train(pkt.address).process_packet(pkt); +} + +} // namespace Marklin diff --git a/source/network/client.h b/source/network/client.h new file mode 100644 index 0000000..ce8dcb6 --- /dev/null +++ b/source/network/client.h @@ -0,0 +1,59 @@ +/* $Id$ + +This file is part of the MSP Märklin suite +Copyright © 2009 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#ifndef MARKLINNET_CLIENT_H_ +#define MARKLINNET_CLIENT_H_ + +#include +#include +#include "libmarklin/catalogue.h" +#include "packets.h" +#include "protocol.h" +#include "train.h" + +namespace Marklin { + +class Client: public Msp::Net::PacketReceiver, + Msp::Net::PacketReceiver, + Msp::Net::PacketReceiver, + Msp::Net::PacketReceiver +{ +public: + sigc::signal signal_train_added; + +private: + const Catalogue &catalogue; + Protocol proto; + Msp::Net::StreamSocket *socket; + Msp::Net::Communicator *comm; + Msp::IO::EventDispatcher *event_disp; + std::map trains; + +public: + Client(const Catalogue &); + ~Client(); + + void use_event_dispatcher(Msp::IO::EventDispatcher &); + void connect(const Msp::Net::SockAddr &); + + template + void send(const P &pkt) + { if(comm) comm->send(pkt); } + + const Catalogue &get_catalogue() const { return catalogue; } + NetTrain &get_train(unsigned); + +private: + virtual void receive(const TrainInfoPacket &); + virtual void receive(const TrainSpeedPacket &); + virtual void receive(const TrainFunctionPacket &); + virtual void receive(const TrainStatusPacket &); +}; + +} // namespace Marklin + +#endif diff --git a/source/network/packets.h b/source/network/packets.h new file mode 100644 index 0000000..d6efafc --- /dev/null +++ b/source/network/packets.h @@ -0,0 +1,43 @@ +/* $Id$ + +This file is part of the MSP Märklin suite +Copyright © 2009 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#ifndef MARKLINNET_PACKETS_H_ +#define MARKLINNET_PACKETS_H_ + +#include + +namespace Marklin { + +struct TrainInfoPacket +{ + unsigned address; + unsigned loco_type; + std::string name; +}; + +struct TrainSpeedPacket +{ + unsigned address; + unsigned speed; + char reverse; +}; + +struct TrainFunctionPacket +{ + unsigned address; + unsigned functions; +}; + +struct TrainStatusPacket +{ + unsigned address; + std::string status; +}; + +} // namespace Marklin + +#endif diff --git a/source/network/protocol.cpp b/source/network/protocol.cpp new file mode 100644 index 0000000..5801d37 --- /dev/null +++ b/source/network/protocol.cpp @@ -0,0 +1,25 @@ +/* $Id$ + +This file is part of the MSP Märklin suite +Copyright © 2009 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#include "packets.h" +#include "protocol.h" + +namespace Marklin { + +Protocol::Protocol() +{ + add() (&TrainInfoPacket::address) + (&TrainInfoPacket::loco_type) (&TrainInfoPacket::name); + add() (&TrainSpeedPacket::address) + (&TrainSpeedPacket::speed) (&TrainSpeedPacket::reverse); + add() (&TrainFunctionPacket::address) + (&TrainFunctionPacket::functions); + add() (&TrainStatusPacket::address) + (&TrainStatusPacket::status); +} + +} // namespace Marklin diff --git a/source/network/protocol.h b/source/network/protocol.h new file mode 100644 index 0000000..176fdad --- /dev/null +++ b/source/network/protocol.h @@ -0,0 +1,23 @@ +/* $Id$ + +This file is part of the MSP Märklin suite +Copyright © 2009 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#ifndef MARKLINNET_PROTOCOL_H_ +#define MARKLINNET_PROTOCOL_H_ + +#include + +namespace Marklin { + +class Protocol: public Msp::Net::Protocol +{ +public: + Protocol(); +}; + +} // namespace Marklin + +#endif diff --git a/source/network/server.cpp b/source/network/server.cpp new file mode 100644 index 0000000..17142f8 --- /dev/null +++ b/source/network/server.cpp @@ -0,0 +1,174 @@ +/* $Id$ + +This file is part of the MSP Märklin suite +Copyright © 2009 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#include +#include "libmarklin/control.h" +#include "libmarklin/locomotive.h" +#include "libmarklin/locotype.h" +#include "server.h" + +using namespace std; +using namespace Msp; + +namespace Marklin { + +Server::Server(TrafficManager &tm): + trfc_mgr(tm), + listen_sock(Net::INET), + event_disp(0) +{ + const list &trains = trfc_mgr.get_trains(); + for(list::const_iterator i=trains.begin(); i!=trains.end(); ++i) + { + Locomotive &loco = (*i)->get_locomotive(); + (*i)->signal_target_speed_changed.connect(sigc::bind<0>(sigc::mem_fun(this, &Server::train_speed_changed), sigc::ref(**i))); + loco.signal_function_changed.connect(sigc::bind<0>(sigc::mem_fun(this, &Server::train_function_changed), sigc::ref(**i))); + (*i)->signal_status_changed.connect(sigc::bind<0>(sigc::mem_fun(this, &Server::train_status_changed), sigc::ref(**i))); + } + + listen_sock.listen(Net::InetAddr(0, 8315), 4); + listen_sock.signal_data_available.connect(sigc::mem_fun(this, &Server::incoming_connection)); +} + +void Server::use_event_dispatcher(IO::EventDispatcher &ed) +{ + event_disp = &ed; + event_disp->add(listen_sock); +} + +void Server::incoming_connection() +{ + Net::StreamSocket *sock = listen_sock.accept(); + if(event_disp) + event_disp->add(*sock); + connections.push_back(new Connection(*this, sock)); +} + +void Server::train_added(Train &train) +{ + Locomotive &loco = train.get_locomotive(); + train.signal_target_speed_changed.connect(sigc::bind<0>(sigc::mem_fun(this, &Server::train_speed_changed), sigc::ref(train))); + loco.signal_function_changed.connect(sigc::bind<0>(sigc::mem_fun(this, &Server::train_function_changed), sigc::ref(train))); + train.signal_status_changed.connect(sigc::bind<0>(sigc::mem_fun(this, &Server::train_status_changed), sigc::ref(train))); + + TrainInfoPacket pkt; + pkt.address = loco.get_address(); + pkt.loco_type = loco.get_type().get_article_number(); + pkt.name = train.get_name(); + send(pkt); +} + +void Server::train_speed_changed(const Train &train, unsigned speed) +{ + TrainSpeedPacket pkt; + pkt.address = train.get_locomotive().get_address(); + pkt.speed = speed; + pkt.reverse = train.get_locomotive().get_reverse(); + send(pkt); +} + +void Server::train_function_changed(const Train &train, unsigned, bool) +{ + TrainFunctionPacket pkt; + pkt.address = train.get_locomotive().get_address(); + pkt.functions = train.get_locomotive().get_functions(); + send(pkt); +} + +void Server::train_status_changed(const Train &train, const string &status) +{ + TrainStatusPacket pkt; + pkt.address = train.get_locomotive().get_address(); + pkt.status = status; + send(pkt); +} + +template +void Server::send(const P &pkt) +{ + for(vector::const_iterator i=connections.begin(); i!=connections.end(); ++i) + if(!(*i)->stale) + (*i)->comm.send(pkt); +} + + +Server::Connection::Connection(Server &s, Net::StreamSocket *o): + server(s), + socket(o), + comm(*socket, server.proto, *this) +{ + socket->signal_end_of_file.connect(sigc::mem_fun(this, &Connection::end_of_file)); + comm.signal_handshake_done.connect(sigc::mem_fun(this, &Connection::handshake_done)); + comm.initiate_handshake(); +} + +Server::Connection::~Connection() +{ + delete socket; +} + +void Server::Connection::handshake_done() +{ + const list &trains = server.trfc_mgr.get_trains(); + for(list::const_iterator i=trains.begin(); i!=trains.end(); ++i) + { + Locomotive &loco = (*i)->get_locomotive(); + + { + TrainInfoPacket pkt; + pkt.address = loco.get_address(); + pkt.loco_type = loco.get_type().get_article_number(); + pkt.name = (*i)->get_name(); + comm.send(pkt); + } + { + TrainSpeedPacket pkt; + pkt.address = loco.get_address(); + pkt.speed = (*i)->get_target_speed(); + pkt.reverse = loco.get_reverse(); + comm.send(pkt); + } + { + TrainFunctionPacket pkt; + pkt.address = loco.get_address(); + pkt.functions = loco.get_functions(); + comm.send(pkt); + } + { + TrainStatusPacket pkt; + pkt.address = loco.get_address(); + pkt.status = (*i)->get_status(); + comm.send(pkt); + } + } +} + +void Server::Connection::end_of_file() +{ + socket->close(); + stale = true; +} + +void Server::Connection::receive(const TrainSpeedPacket &pkt) +{ + Locomotive &loco = server.trfc_mgr.get_control().get_locomotive(pkt.address); + Train &train = server.trfc_mgr.get_train_by_locomotive(loco); + if(pkt.reverse!=loco.get_reverse()) + train.set_reverse(pkt.reverse); + else + train.set_speed(pkt.speed); +} + +void Server::Connection::receive(const TrainFunctionPacket &pkt) +{ + Locomotive &loco = server.trfc_mgr.get_control().get_locomotive(pkt.address); + for(unsigned i=0; i<9; ++i) + if(((pkt.functions^loco.get_functions())>>i)&1) + loco.set_function(i, (pkt.functions>>i)&1); +} + +} // namespace Marklin diff --git a/source/network/server.h b/source/network/server.h new file mode 100644 index 0000000..6ce965e --- /dev/null +++ b/source/network/server.h @@ -0,0 +1,64 @@ +/* $Id$ + +This file is part of the MSP Märklin suite +Copyright © 2009 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#ifndef MARKLINNET_SERVER_H_ +#define MARKLINNET_SERVER_H_ + +#include +#include +#include +#include +#include "libmarklin/trafficmanager.h" +#include "packets.h" +#include "protocol.h" + +namespace Marklin { + +class Server +{ +private: + struct Connection: private Msp::Net::PacketReceiver, + private Msp::Net::PacketReceiver + { + Server &server; + Msp::Net::StreamSocket *socket; + Msp::Net::Communicator comm; + bool stale; + + Connection(Server &, Msp::Net::StreamSocket *); + ~Connection(); + + void handshake_done(); + void end_of_file(); + virtual void receive(const TrainSpeedPacket &); + virtual void receive(const TrainFunctionPacket &); + }; + + Protocol proto; + TrafficManager &trfc_mgr; + Msp::Net::StreamListenSocket listen_sock; + Msp::IO::EventDispatcher *event_disp; + std::vector connections; + +public: + Server(TrafficManager &); + void use_event_dispatcher(Msp::IO::EventDispatcher &); +private: + void incoming_connection(); + + void train_added(Train &); + void train_speed_changed(const Train &, unsigned); + void train_function_changed(const Train &, unsigned, bool); + void train_status_changed(const Train &, const std::string &); + + template + void send(const P &); +}; + +} // namespace Marklin + +#endif diff --git a/source/network/train.cpp b/source/network/train.cpp new file mode 100644 index 0000000..468b220 --- /dev/null +++ b/source/network/train.cpp @@ -0,0 +1,90 @@ +/* $Id$ + +This file is part of the MSP Märklin suite +Copyright © 2009 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#include "client.h" +#include "train.h" + +using namespace std; + +namespace Marklin { + +NetTrain::NetTrain(Client &c, const TrainInfoPacket &pkt): + client(c), + loco_type(client.get_catalogue().get_locomotive(pkt.loco_type)), + address(pkt.address), + name(pkt.name), + speed(0), + reverse(0), + functions(0) +{ } + +void NetTrain::set_speed(unsigned s) +{ + if(s==speed) + return; + + TrainSpeedPacket pkt; + pkt.address = address; + pkt.speed = s; + pkt.reverse = reverse; + client.send(pkt); +} + +void NetTrain::set_reverse(bool r) +{ + if(r==reverse) + return; + + TrainSpeedPacket pkt; + pkt.address = address; + pkt.speed = speed; + pkt.reverse = r; + client.send(pkt); +} + +void NetTrain::set_function(unsigned i, bool set) +{ + TrainFunctionPacket pkt; + pkt.address = address; + pkt.functions = functions; + if(set) + pkt.functions |= 1<>i)&1) + signal_function_changed.emit(i, (functions>>i)&1); +} + +void NetTrain::process_packet(const TrainStatusPacket &pkt) +{ + status = pkt.status; + signal_status_changed.emit(status); +} + +} // namespace Marklin diff --git a/source/network/train.h b/source/network/train.h new file mode 100644 index 0000000..57154a0 --- /dev/null +++ b/source/network/train.h @@ -0,0 +1,58 @@ +/* $Id$ + +This file is part of the MSP Märklin suite +Copyright © 2009 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#ifndef MARKLINNET_TRAIN_H_ +#define MARKLINNET_TRAIN_H_ + +#include +#include "libmarklin/locotype.h" +#include "packets.h" + +namespace Marklin { + +class Client; + +class NetTrain +{ +public: + sigc::signal signal_name_changed; + sigc::signal signal_speed_changed; + sigc::signal signal_reverse_changed; + sigc::signal signal_function_changed; + sigc::signal signal_status_changed; + +private: + Client &client; + const LocoType &loco_type; + unsigned address; + std::string name; + unsigned speed; + bool reverse; + unsigned functions; + std::string status; + +public: + NetTrain(Client &, const TrainInfoPacket &); + + const LocoType &get_loco_type() const { return loco_type; } + unsigned get_address() const { return address; } + const std::string &get_name() const { return name; } + void set_speed(unsigned); + unsigned get_speed() const { return speed; } + void set_reverse(bool); + bool get_reverse() const { return reverse; } + void set_function(unsigned, bool); + bool get_function(unsigned i) const { return (functions>>i)&1; } + + void process_packet(const TrainSpeedPacket &); + void process_packet(const TrainFunctionPacket &); + void process_packet(const TrainStatusPacket &); +}; + +} // namespace Marklin + +#endif diff --git a/source/remote/remote.cpp b/source/remote/remote.cpp new file mode 100644 index 0000000..57080c1 --- /dev/null +++ b/source/remote/remote.cpp @@ -0,0 +1,53 @@ +/* $Id$ + +This file is part of the MSP Märklin suite +Copyright © 2009 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#include +#include +#include "remote.h" +#include "trainpanel.h" + +using namespace std; +using namespace Msp; + +Application::RegApp Remote::reg; + +Remote::Remote(int argc, char **argv): + client(catalogue), + gtk(argc, argv) +{ + if(argc<2) + throw UsageError("No address given"); + + DataFile::load(catalogue, "locos.dat"); + + client.use_event_dispatcher(event_disp); + client.signal_train_added.connect(sigc::mem_fun(this, &Remote::train_added)); + string addr_str = argv[1]; + if(addr_str.find(':')==string::npos) + addr_str += ":8315"; + Net::SockAddr *addr = Net::resolve(addr_str); + client.connect(*addr); + delete addr; + + window.signal_hide().connect(sigc::bind(sigc::mem_fun(this, &Remote::exit), 0)); + window.set_border_width(5); + train_box = new Gtk::VBox(false, 5); + window.add(*manage(train_box)); + window.show_all(); +} + +void Remote::tick() +{ + event_disp.tick(Time::zero); + gtk.iteration(false); +} + +void Remote::train_added(Marklin::NetTrain &t) +{ + TrainPanel *panel = new TrainPanel(t); + train_box->add(*manage(panel)); +} diff --git a/source/remote/remote.h b/source/remote/remote.h new file mode 100644 index 0000000..4599a13 --- /dev/null +++ b/source/remote/remote.h @@ -0,0 +1,37 @@ +/* $Id$ + +This file is part of the MSP Märklin suite +Copyright © 2009 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#ifndef REMOTE_H_ +#define REMOTE_H_ + +#include +#include +#include +#include +#include "network/client.h" + +class Remote: public Msp::Application +{ +private: + Msp::IO::EventDispatcher event_disp; + Marklin::Catalogue catalogue; + Marklin::Client client; + Gtk::Main gtk; + Gtk::Window window; + Gtk::Box *train_box; + + static Msp::Application::RegApp reg; + +public: + Remote(int argc, char **argv); +private: + void tick(); + + void train_added(Marklin::NetTrain &); +}; + +#endif diff --git a/source/remote/trainpanel.cpp b/source/remote/trainpanel.cpp new file mode 100644 index 0000000..e3db1ba --- /dev/null +++ b/source/remote/trainpanel.cpp @@ -0,0 +1,83 @@ +/* $Id$ + +This file is part of the MSP Märklin suite +Copyright © 2009 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#include +#include "libmarklin/locotype.h" +#include "trainpanel.h" + +using namespace std; + +TrainPanel::TrainPanel(Marklin::NetTrain &t): + train(t) +{ + train.signal_name_changed.connect(sigc::mem_fun(this, &TrainPanel::name_changed)); + train.signal_speed_changed.connect(sigc::mem_fun(this, &TrainPanel::speed_changed)); + train.signal_function_changed.connect(sigc::mem_fun(this, &TrainPanel::function_changed)); + train.signal_status_changed.connect(sigc::mem_fun(this, &TrainPanel::status_changed)); + + set_label(train.get_name()); + + Gtk::VBox *vbox = new Gtk::VBox(false, 5); + add(*manage(vbox)); + vbox->set_border_width(5); + + vbox->add(*manage(scl_speed = new Gtk::HScale)); + scl_speed->set_digits(0); + scl_speed->set_range(0, 14); + scl_speed->set_increments(1, 1); + scl_speed->set_size_request(280, -1); + scl_speed->signal_value_changed().connect(sigc::mem_fun(this, &TrainPanel::ui_speed_changed)); + + Gtk::HBox *func_box = new Gtk::HBox(false, 5); + vbox->add(*manage(func_box)); + const std::map &funcs = train.get_loco_type().get_functions(); + for(std::map::const_iterator i=funcs.begin(); i!=funcs.end(); ++i) + { + Gtk::CheckButton *&chk = chk_funcs[i->first]; + chk = new Gtk::CheckButton(i->second); + func_box->pack_start(*manage(chk), false, true); + chk->signal_toggled().connect(sigc::bind(sigc::mem_fun(this, &TrainPanel::ui_function_changed), i->first)); + } + + vbox->add(*manage(lbl_status = new Gtk::Label)); + + show_all(); +} + +void TrainPanel::name_changed(const string &name) +{ + set_label(name); +} + +void TrainPanel::status_changed(const string &status) +{ + lbl_status->set_text(status); +} + +void TrainPanel::speed_changed(unsigned speed) +{ + scl_speed->set_value(speed); +} + +void TrainPanel::function_changed(unsigned func, bool set) +{ + std::map::iterator i = chk_funcs.find(func); + if(i!=chk_funcs.end()) + i->second->set_active(set); +} + +void TrainPanel::ui_speed_changed() +{ + train.set_speed(static_cast(scl_speed->get_value())); +} + +void TrainPanel::ui_function_changed(unsigned func) +{ + std::map::iterator i = chk_funcs.find(func); + if(i!=chk_funcs.end()) + train.set_function(func, i->second->get_active()); +} diff --git a/source/remote/trainpanel.h b/source/remote/trainpanel.h new file mode 100644 index 0000000..2dcd095 --- /dev/null +++ b/source/remote/trainpanel.h @@ -0,0 +1,36 @@ +/* $Id$ + +This file is part of the MSP Märklin suite +Copyright © 2009 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#ifndef TRAINPANEL_H_ +#define TRAINPANEL_H_ + +#include +#include +#include +#include +#include "network/train.h" + +class TrainPanel: public Gtk::Frame +{ +private: + Marklin::NetTrain &train; + Gtk::Scale *scl_speed; + Gtk::Label *lbl_status; + std::map chk_funcs; + +public: + TrainPanel(Marklin::NetTrain &); +private: + void name_changed(const std::string &); + void status_changed(const std::string &); + void speed_changed(unsigned); + void function_changed(unsigned, bool); + void ui_speed_changed(); + void ui_function_changed(unsigned); +}; + +#endif