From 651698847d5293cfb15b6fb23a394701388c0151 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Mon, 8 Mar 2010 21:53:29 +0000 Subject: [PATCH] Major architecture rework Create a Driver abstraction to hide the code that talks to the physical equipment Remove TrafficManager and put Blocks and Trains in Layout Dynamically update Blocks as the layout changes Remove Locomotive, Turnout and Sensor classes Tracks now have an active_path property Trains now allows setting functions Move option parsing in Engineer to a separate class Many minor changes --- source/3d/layout.cpp | 7 +- source/3d/layout.h | 4 +- source/designer/designer.cpp | 8 +- source/designer/manipulator.cpp | 7 +- source/designer/toolbar.cpp | 3 +- source/engineer/engineer.cpp | 184 ++++------ source/engineer/engineer.h | 20 +- source/engineer/mainpanel.cpp | 16 +- source/engineer/options.cpp | 51 +++ source/engineer/options.h | 27 ++ source/engineer/trainpanel.cpp | 22 +- source/engineer/trainpanel.h | 4 +- source/engineer/trainproperties.cpp | 12 +- source/libmarklin/block.cpp | 78 +++-- source/libmarklin/block.h | 21 +- source/libmarklin/command.cpp | 45 --- source/libmarklin/command.h | 43 --- source/libmarklin/constants.cpp | 71 ---- source/libmarklin/constants.h | 66 ---- source/libmarklin/control.cpp | 284 --------------- source/libmarklin/control.h | 79 ----- source/libmarklin/driver.cpp | 34 ++ source/libmarklin/driver.h | 53 +++ source/libmarklin/dummy.cpp | 43 +++ source/libmarklin/dummy.h | 46 +++ source/libmarklin/except.h | 31 -- source/libmarklin/intellibox.cpp | 502 +++++++++++++++++++++++++++ source/libmarklin/intellibox.h | 142 ++++++++ source/libmarklin/layout.cpp | 189 +++++++++- source/libmarklin/layout.h | 47 ++- source/libmarklin/locomotive.cpp | 152 -------- source/libmarklin/locomotive.h | 59 ---- source/libmarklin/reply.cpp | 159 --------- source/libmarklin/reply.h | 37 -- source/libmarklin/route.cpp | 11 +- source/libmarklin/route.h | 8 +- source/libmarklin/sensor.cpp | 61 ---- source/libmarklin/sensor.h | 43 --- source/libmarklin/track.cpp | 81 ++++- source/libmarklin/track.h | 23 +- source/libmarklin/tracktype.cpp | 27 +- source/libmarklin/tracktype.h | 5 +- source/libmarklin/trafficmanager.cpp | 145 -------- source/libmarklin/trafficmanager.h | 61 ---- source/libmarklin/train.cpp | 199 ++++++----- source/libmarklin/train.h | 51 ++- source/libmarklin/turnout.cpp | 121 ------- source/libmarklin/turnout.h | 52 --- source/network/server.cpp | 91 +++-- source/network/server.h | 8 +- tracks.dat | 42 +-- 51 files changed, 1616 insertions(+), 1959 deletions(-) create mode 100644 source/engineer/options.cpp create mode 100644 source/engineer/options.h delete mode 100644 source/libmarklin/command.cpp delete mode 100644 source/libmarklin/command.h delete mode 100644 source/libmarklin/constants.cpp delete mode 100644 source/libmarklin/constants.h delete mode 100644 source/libmarklin/control.cpp delete mode 100644 source/libmarklin/control.h create mode 100644 source/libmarklin/driver.cpp create mode 100644 source/libmarklin/driver.h create mode 100644 source/libmarklin/dummy.cpp create mode 100644 source/libmarklin/dummy.h delete mode 100644 source/libmarklin/except.h create mode 100644 source/libmarklin/intellibox.cpp create mode 100644 source/libmarklin/intellibox.h delete mode 100644 source/libmarklin/locomotive.cpp delete mode 100644 source/libmarklin/locomotive.h delete mode 100644 source/libmarklin/reply.cpp delete mode 100644 source/libmarklin/reply.h delete mode 100644 source/libmarklin/sensor.cpp delete mode 100644 source/libmarklin/sensor.h delete mode 100644 source/libmarklin/trafficmanager.cpp delete mode 100644 source/libmarklin/trafficmanager.h delete mode 100644 source/libmarklin/turnout.cpp delete mode 100644 source/libmarklin/turnout.h diff --git a/source/3d/layout.cpp b/source/3d/layout.cpp index 8ea58bf..1a55715 100644 --- a/source/3d/layout.cpp +++ b/source/3d/layout.cpp @@ -13,7 +13,6 @@ Distributed under the GPL #include #include #include -#include "libmarklin/trafficmanager.h" #include "layout.h" using namespace std; @@ -27,6 +26,7 @@ Layout3D::Layout3D(Layout &l): { layout.signal_track_added.connect(sigc::mem_fun(this, &Layout3D::track_added)); layout.signal_track_removed.connect(sigc::mem_fun(this, &Layout3D::track_removed)); + layout.signal_train_added.connect(sigc::mem_fun(this, &Layout3D::train_added)); const set <racks = layout.get_tracks(); for(set::iterator i=ltracks.begin(); i!=ltracks.end(); ++i) @@ -98,11 +98,6 @@ Track3D *Layout3D::pick_track(float x, float y, float size) const return track; } -void Layout3D::set_traffic_manager(TrafficManager &tm) -{ - tm.signal_train_added.connect(sigc::mem_fun(this, &Layout3D::train_added)); -} - void Layout3D::add_train(Train3D &t) { trains.push_back(&t); diff --git a/source/3d/layout.h b/source/3d/layout.h index 2e56ea6..ba590dd 100644 --- a/source/3d/layout.h +++ b/source/3d/layout.h @@ -8,6 +8,7 @@ Distributed under the GPL #ifndef MARKLIN3D_LAYOUT_H_ #define MARKLIN3D_LAYOUT_H_ +#include #include #include "libmarklin/layout.h" #include "catalogue.h" @@ -16,7 +17,7 @@ Distributed under the GPL namespace Marklin { -class Layout3D +class Layout3D: public sigc::trackable { private: Layout &layout; @@ -38,7 +39,6 @@ public: Track3D &get_track(const Track &) const; Track3D *pick_track(float, float, float) const; - void set_traffic_manager(TrafficManager &); void add_train(Train3D &); void remove_train(Train3D &); Train3D &get_train(const Train &) const; diff --git a/source/designer/designer.cpp b/source/designer/designer.cpp index 9e99a1d..b0971c2 100644 --- a/source/designer/designer.cpp +++ b/source/designer/designer.cpp @@ -25,6 +25,7 @@ Distributed under the GPL #include #include #include +#include "libmarklin/route.h" #include "libmarklin/tracktype.h" #include "designer.h" #include "input.h" @@ -165,7 +166,7 @@ void Designer::new_track() void Designer::set_turnout_id() { Track *track = selection.get_track(); - if(selection.size()==1 && track->get_type().get_n_paths()>1) + if(selection.size()==1 && track->get_type().is_turnout()) { InputDialog *input = new InputDialog(*this, "Turnout ID", lexical_cast(track->get_turnout_id())); input->signal_accept.connect(sigc::mem_fun(this, &Designer::turnout_id_accept)); @@ -179,7 +180,7 @@ void Designer::set_sensor_id() int id = -1; for(set::const_iterator i=tracks.begin(); i!=tracks.end(); ++i) { - if((*i)->get_type().get_n_paths()==1) + if(!(*i)->get_type().is_turnout()) ok = true; if(static_cast((*i)->get_sensor_id())!=id) { @@ -354,9 +355,8 @@ void Designer::button_press(int x, int y, unsigned btn, unsigned mod) Track3D *ctrack = pick_track(x, y); if(ctrack) { - Track *track = ctrack->get_track().copy(); + Track *track = new Track(*layout, ctrack->get_track().get_type()); track->set_position(ground); - layout->add_track(*track); selection.clear(); selection.add_track(track); diff --git a/source/designer/manipulator.cpp b/source/designer/manipulator.cpp index e690c1d..dfcdd2c 100644 --- a/source/designer/manipulator.cpp +++ b/source/designer/manipulator.cpp @@ -1,7 +1,7 @@ /* $Id$ This file is part of the MSP Märklin suite -Copyright © 2006-2008 Mikkosoft Productions, Mikko Rasa +Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ @@ -67,8 +67,7 @@ void Manipulator::duplicate() list new_tracks; for(vector::iterator i=tracks.begin(); i!=tracks.end(); ++i) { - Track *track = i->track->copy(); - designer.get_layout()->add_track(*track); + Track *track = new Track(*designer.get_layout(), i->track->get_type()); new_tracks.push_back(track); } @@ -355,8 +354,6 @@ void Manipulator::render() glPopMatrix(); } -/*** private ***/ - void Manipulator::selection_changed() { if(mode) diff --git a/source/designer/toolbar.cpp b/source/designer/toolbar.cpp index c4a674d..36b4882 100644 --- a/source/designer/toolbar.cpp +++ b/source/designer/toolbar.cpp @@ -1,12 +1,13 @@ /* $Id$ This file is part of the MSP Märklin suite -Copyright © 2009 Mikkosoft Productions, Mikko Rasa +Copyright © 2009-2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ #include #include +#include "libmarklin/route.h" #include "designer.h" #include "toolbar.h" diff --git a/source/engineer/engineer.cpp b/source/engineer/engineer.cpp index 87a4d6d..e62cd2b 100644 --- a/source/engineer/engineer.cpp +++ b/source/engineer/engineer.cpp @@ -9,24 +9,19 @@ Distributed under the GPL #include #include #include -#include #include #include #include #include #include -#include #include #include -#include #include #include #include #include -#include -#include #include -#include "libmarklin/except.h" +#include "libmarklin/driver.h" #include "libmarklin/tracktype.h" #include "engineer.h" #include "mainpanel.h" @@ -38,103 +33,61 @@ using namespace Marklin; using namespace Msp; Engineer::Engineer(int argc, char **argv): - layout(catalogue), + options(argc, argv), + window(options.screen_w, options.screen_h, options.fullscreen), + layout(catalogue, (options.driver.empty() ? 0 : Driver::create(options.driver))), layout_3d(layout), server(0), + pipeline(window.get_width(), window.get_height(), false), placing_train(0), placing_block(0), - placing_entry(0), - simulate(false) + placing_entry(0) { - // Parse options - unsigned screen_w = 1280; - unsigned screen_h = 960; - bool fullscreen = false; - string res; - bool debug = false; - string device = "/dev/ttyS0"; - bool network = false; - - GetOpt getopt; - getopt.add_option('r', "resolution", res, GetOpt::REQUIRED_ARG); - getopt.add_option('f', "fullscreen", fullscreen, GetOpt::NO_ARG); - getopt.add_option('g', "debug", debug, GetOpt::NO_ARG); - getopt.add_option('d', "device", device, GetOpt::REQUIRED_ARG); - getopt.add_option('s', "simulate", simulate, GetOpt::NO_ARG); - getopt.add_option('n', "network", network, GetOpt::NO_ARG); - getopt(argc, argv); - - const vector &args = getopt.get_args(); - if(args.empty()) - throw UsageError("No layout given"); - - if(!res.empty()) - { - if(RegMatch m=Regex("([1-9][0-9]*)x([1-9][0-9]*)").match(res)) - { - screen_w = lexical_cast(m[1].str); - screen_h = lexical_cast(m[2].str); - } - else - throw UsageError("Invalid resolution"); - } - // Setup GUI - window = new Graphics::SimpleGLWindow(screen_w, screen_h, fullscreen); - window->set_title("Railroad Engineer"); - window->signal_close.connect(sigc::bind(sigc::mem_fun(this, &Engineer::exit), 0)); + window.set_title("Railroad Engineer"); + window.signal_close.connect(sigc::bind(sigc::mem_fun(this, &Engineer::exit), 0)); DataFile::load(ui_res, "marklin.res"); - root = new GLtk::Root(ui_res, *window); + root = new GLtk::Root(ui_res, window); root->signal_button_press.connect(sigc::mem_fun(this, &Engineer::button_press)); root->signal_pointer_motion.connect(sigc::mem_fun(this, &Engineer::pointer_motion)); root->set_visible(true); main_panel = new MainPanel(*this, ui_res); root->add(*main_panel); - main_panel->set_position(0, window->get_height()-main_panel->get_geometry().h); + main_panel->set_position(0, window.get_height()-main_panel->get_geometry().h); main_panel->set_visible(true); // Setup railroad control DataFile::load(catalogue, "tracks.dat"); DataFile::load(catalogue, "locos.dat"); - DataFile::load(layout, args.front()); - - if(device!="none") - control.open(device); + DataFile::load(layout, options.layout_fn); - control.set_debug(debug); - - trfc_mgr = new TrafficManager(control, layout); - layout_3d.set_traffic_manager(*trfc_mgr); - trfc_mgr->signal_train_added.connect(sigc::mem_fun(this, &Engineer::train_added)); - trfc_mgr->signal_block_reserved.connect(sigc::mem_fun(this, &Engineer::block_reserved)); + layout.signal_train_added.connect(sigc::mem_fun(this, &Engineer::train_added)); + layout.signal_block_reserved.connect(sigc::mem_fun(this, &Engineer::block_reserved)); if(FS::exists("engineer.state")) - DataFile::load(*trfc_mgr, "engineer.state"); + DataFile::load(layout, "engineer.state"); - if(network) + if(options.network) { - server = new Server(*trfc_mgr); + server = new Server(layout); 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)); + layout.get_driver().signal_sensor.connect(sigc::mem_fun(this, &Engineer::sensor_event)); // Setup 3D view DataFile::load(arrow_mesh, "arrow.mesh"); - overlay = new Overlay3D(*window, camera, ui_res.get_default_font()); + overlay = new Overlay3D(window, camera, ui_res.get_default_font()); - pipeline = new GL::Pipeline(window->get_width(), window->get_height(), false); - pipeline->set_camera(&camera); - pipeline->add_renderable(layout_3d.get_scene()); + pipeline.set_camera(&camera); + pipeline.add_renderable(layout_3d.get_scene()); light.set_position(0, -0.259, 0.966, 0); lighting.attach(0, light); - GL::PipelinePass &pass = pipeline->add_pass(0); + GL::PipelinePass &pass = pipeline.add_pass(0); pass.depth_test = &GL::DepthTest::lequal(); pass.lighting = &lighting; @@ -151,22 +104,17 @@ Engineer::Engineer(int argc, char **argv): Engineer::~Engineer() { - const list &trains = trfc_mgr->get_trains(); - for(list::const_iterator i=trains.begin(); i!=trains.end(); ++i) - (*i)->set_speed(0); - - while(control.get_queue_length()) - control.tick(); + const map &trains = layout.get_trains(); + for(map::const_iterator i=trains.begin(); i!=trains.end(); ++i) + i->second->set_speed(0); + layout.get_driver().flush(); - if(!simulate) - trfc_mgr->save("engineer.state"); + if(!options.simulate) + layout.save_trains("engineer.state"); - delete pipeline; delete overlay; delete root; - delete window; - delete trfc_mgr; delete server; } @@ -179,17 +127,16 @@ void Engineer::place_train(Train &train) int Engineer::main() { - window->show(); + window.show(); return Application::main(); } void Engineer::tick() { - window->get_display().tick(); + window.get_display().tick(); - control.tick(); - trfc_mgr->tick(); + layout.tick(); event_disp.tick(Time::zero); for(list::iterator i=new_trains.begin(); i!=new_trains.end(); ++i) @@ -198,7 +145,7 @@ void Engineer::tick() GL::clear(GL::COLOR_BUFFER_BIT|GL::DEPTH_BUFFER_BIT); - pipeline->render_all(); + pipeline.render_all(); { GL::Bind blend(GL::Blend::alpha()); overlay->render(0); @@ -231,7 +178,7 @@ void Engineer::tick() GL::Texture::unbind(); } - window->swap_buffers(); + window.swap_buffers(); } void Engineer::button_press(int x, int y, unsigned btn, unsigned) @@ -254,30 +201,37 @@ void Engineer::button_press(int x, int y, unsigned btn, unsigned) } else { - Track3D *track = pick_track(x, window->get_height()-y-1); - if(track) + Track3D *t3d = pick_track(x, window.get_height()-y-1); + if(t3d) { - if(unsigned tid=track->get_track().get_turnout_id()) + Track &track = t3d->get_track(); + if(track.get_turnout_id()) { - Turnout &turnout = control.get_turnout(tid); - try + Block &block = layout.get_block_by_track(track); + if(block.get_train() && !block.get_train()->free_block(block)) + main_panel->set_status_text("Turnout busy"); + else { - turnout.set_path((turnout.get_path()+1)%track->get_track().get_type().get_n_paths()); - main_panel->set_status_text(format("Turnout %d switched", turnout.get_address())); - } - catch(const TurnoutBusy &e) - { - main_panel->set_status_text(e.what()); + unsigned paths = track.get_type().get_paths(); + unsigned i = track.get_active_path()+1; + while(!(paths&(1<>i)) + i = 0; + else + ++i; + } + track.set_active_path(i); } } - else if(simulate) + /*else if(simulate) { if(unsigned sid=track->get_track().get_sensor_id()) { Sensor &sensor = control.get_sensor(sid); control.signal_sensor_event.emit(sid, !sensor.get_state()); } - } + }*/ } } } @@ -286,10 +240,10 @@ void Engineer::pointer_motion(int x, int y) { if(placing_train) { - Track3D *track = pick_track(x, window->get_height()-y-1); + Track3D *track = pick_track(x, window.get_height()-y-1); if(track) { - Block &block = trfc_mgr->get_block_by_track(track->get_track()); + Block &block = layout.get_block_by_track(track->get_track()); if(&block!=placing_block) { if(placing_block) @@ -306,7 +260,7 @@ void Engineer::view_all() { const list &tracks = layout_3d.get_tracks(); - float view_aspect = float(window->get_width()-200)/window->get_height(); + float view_aspect = float(window.get_width()-200)/window.get_height(); float view_height = tan(camera.get_field_of_view()/2)*2; float best_score = 0; GL::Vector3 pos; @@ -339,7 +293,7 @@ void Engineer::view_all() float size = max(width/view_aspect, height); float c = cos(angle); float s = sin(angle); - float x = (min_x+max_x)/2-size*105/window->get_height(); + float x = (min_x+max_x)/2-size*105/window.get_height(); float y = (min_y+max_y)/2; float z = max(size*1.05/view_height, 0.15); @@ -355,16 +309,14 @@ void Engineer::view_all() void Engineer::set_block_color(const Block &block, const GL::Color &color) { - (void)block; - (void)color; + (void)block; (void)color; } void Engineer::reset_block_color(const Block &block) { if(unsigned sid=block.get_sensor_id()) { - Sensor &sensor = control.get_sensor(sid); - if(sensor.get_state()) + if(layout.get_driver().get_sensor(sid)) { set_block_color(block, GL::Color(1, 0.5, 0.3)); return; @@ -377,11 +329,11 @@ void Engineer::reset_block_color(const Block &block) set_block_color(block, GL::Color(1, 1, 1)); } -void Engineer::sensor_event(bool, Sensor *sensor) +void Engineer::sensor_event(unsigned addr, bool) { - const list &blocks = trfc_mgr->get_blocks(); - for(list::const_iterator i=blocks.begin(); i!=blocks.end(); ++i) - if((*i)->get_sensor_id()==sensor->get_address()) + const set &blocks = layout.get_blocks(); + for(set::const_iterator i=blocks.begin(); i!=blocks.end(); ++i) + if((*i)->get_sensor_id()==addr) reset_block_color(**i); } @@ -393,9 +345,9 @@ void Engineer::block_reserved(const Block &block, const Train *) Track3D *Engineer::pick_track(int x, int y) { float view_height = tan(camera.get_field_of_view()/2)*2; - float xx = ((float(x)-window->get_width()/2)/window->get_height())*view_height; - float yy = (float(y)/window->get_height()-0.5)*view_height; - float size = 4.0/window->get_height()*view_height; + float xx = ((float(x)-window.get_width()/2)/window.get_height())*view_height; + float yy = (float(y)/window.get_height()-0.5)*view_height; + float size = 4.0/window.get_height()*view_height; camera.apply(); @@ -422,10 +374,10 @@ void Engineer::sighandler(int sig) { signal(sig, SIG_DFL); IO::print(IO::cerr, "Fatal signal received, terminating\n"); - const map &locos = control.get_locomotives(); - for(map::const_iterator i=locos.begin(); i!=locos.end(); ++i) + const map &trains = layout.get_trains(); + for(map::const_iterator i=trains.begin(); i!=trains.end(); ++i) i->second->set_speed(0); - control.flush(); + layout.get_driver().flush(); raise(sig); } else if(sig==SIGTERM || sig==SIGINT) diff --git a/source/engineer/engineer.h b/source/engineer/engineer.h index 3e7a910..5fa0587 100644 --- a/source/engineer/engineer.h +++ b/source/engineer/engineer.h @@ -17,13 +17,11 @@ Distributed under the GPL #include #include #include "libmarklin/catalogue.h" -#include "libmarklin/control.h" -#include "libmarklin/locotype.h" -#include "libmarklin/trafficmanager.h" #include "libmarklin/train.h" #include "3d/layout.h" #include "3d/overlay.h" #include "network/server.h" +#include "options.h" class MainPanel; class TrainPanel; @@ -32,15 +30,15 @@ class TrainProperties; class Engineer: public Msp::Application { private: - Msp::Graphics::SimpleGLWindow *window; + Options options; + + Msp::Graphics::SimpleGLWindow window; Msp::GLtk::Resources ui_res; Msp::GLtk::Root *root; Marklin::Catalogue catalogue; Marklin::Layout layout; Marklin::Layout3D layout_3d; - Marklin::Control control; - Marklin::TrafficManager *trfc_mgr; Marklin::Server *server; Msp::IO::EventDispatcher event_disp; Marklin::Overlay3D *overlay; @@ -49,7 +47,7 @@ private: Msp::GL::Camera camera; Msp::GL::Lighting lighting; Msp::GL::Light light; - Msp::GL::Pipeline *pipeline; + Msp::GL::Pipeline pipeline; Msp::GL::Mesh arrow_mesh; MainPanel *main_panel; @@ -58,8 +56,6 @@ private: Marklin::Block *placing_block; unsigned placing_entry; - bool simulate; - public: Engineer(int argc, char **argv); ~Engineer(); @@ -67,9 +63,7 @@ public: const Msp::GLtk::Resources &get_ui_resources() const { return ui_res; } Msp::GLtk::Root &get_root() const { return *root; } const Marklin::Catalogue &get_catalogue() const { return catalogue; } - const Marklin::Layout &get_layout() const { return layout; } - Marklin::Control &get_control() { return control; } - Marklin::TrafficManager &get_traffic_manager() { return *trfc_mgr; } + Marklin::Layout &get_layout() { return layout; } void place_train(Marklin::Train &); int main(); void quit() { exit(0); } @@ -80,7 +74,7 @@ private: void view_all(); void set_block_color(const Marklin::Block &, const Msp::GL::Color &); void reset_block_color(const Marklin::Block &); - void sensor_event(bool, Marklin::Sensor *); + void sensor_event(unsigned, bool); void block_reserved(const Marklin::Block &, const Marklin::Train *); Marklin::Track3D *pick_track(int, int); void train_added(Marklin::Train &); diff --git a/source/engineer/mainpanel.cpp b/source/engineer/mainpanel.cpp index 8c3718b..197c1a4 100644 --- a/source/engineer/mainpanel.cpp +++ b/source/engineer/mainpanel.cpp @@ -1,11 +1,12 @@ /* $Id$ This file is part of the MSP Märklin suite -Copyright © 2006-2009 Mikkosoft Productions, Mikko Rasa +Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ #include +#include "libmarklin/driver.h" #include "engineer.h" #include "mainpanel.h" #include "trainproperties.h" @@ -53,12 +54,13 @@ MainPanel::MainPanel(Engineer &e, GLtk::Resources &r): lbl_status->set_geometry(GLtk::Geometry(10, 10, 180, 24)); lbl_status->set_style("digital"); - if(engineer.get_control().get_power()) + Marklin::Driver &driver = engineer.get_layout().get_driver(); + if(driver.get_power()) ind_on->set_active(true); else ind_off->set_active(true); - engineer.get_control().signal_power_event.connect(sigc::mem_fun(this, &MainPanel::power_event)); + driver.signal_power.connect(sigc::mem_fun(this, &MainPanel::power_event)); } void MainPanel::set_status_text(const string &txt) @@ -68,16 +70,12 @@ void MainPanel::set_status_text(const string &txt) void MainPanel::power_on() { - engineer.get_control().set_power(true); - ind_on->set_active(true); - ind_off->set_active(false); + engineer.get_layout().get_driver().set_power(true); } void MainPanel::power_off() { - engineer.get_control().set_power(false); - ind_on->set_active(false); - ind_off->set_active(true); + engineer.get_layout().get_driver().set_power(false); } void MainPanel::new_loc() diff --git a/source/engineer/options.cpp b/source/engineer/options.cpp new file mode 100644 index 0000000..9861c10 --- /dev/null +++ b/source/engineer/options.cpp @@ -0,0 +1,51 @@ +/* $Id$ + +This file is part of the MSP Märklin suite +Copyright © 2010 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#include +#include +#include +#include "options.h" + +using namespace std; +using namespace Msp; + +Options::Options(int argc, char **argv): + screen_w(1280), + screen_h(960), + fullscreen(false), + debug(false), + network(false), + simulate(false) +{ + string res; + + GetOpt getopt; + getopt.add_option('r', "resolution", res, GetOpt::REQUIRED_ARG); + getopt.add_option('f', "fullscreen", fullscreen, GetOpt::NO_ARG); + getopt.add_option('g', "debug", debug, GetOpt::NO_ARG); + getopt.add_option('d', "driver", driver, GetOpt::REQUIRED_ARG); + getopt.add_option('s', "simulate", simulate, GetOpt::NO_ARG); + getopt.add_option('n', "network", network, GetOpt::NO_ARG); + getopt(argc, argv); + + if(!res.empty()) + { + if(RegMatch m=Regex("([1-9][0-9]*)x([1-9][0-9]*)").match(res)) + { + screen_w = lexical_cast(m[1].str); + screen_h = lexical_cast(m[2].str); + } + else + throw UsageError("Invalid resolution"); + } + + const vector &args = getopt.get_args(); + if(args.empty()) + throw UsageError("No layout given"); + + layout_fn = args[0]; +} diff --git a/source/engineer/options.h b/source/engineer/options.h new file mode 100644 index 0000000..e842c25 --- /dev/null +++ b/source/engineer/options.h @@ -0,0 +1,27 @@ +/* $Id$ + +This file is part of the MSP Märklin suite +Copyright © 2010 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#ifndef OPTIONS_H_ +#define OPTIONS_H_ + +#include + +struct Options +{ + unsigned screen_w; + unsigned screen_h; + bool fullscreen; + bool debug; + std::string driver; + bool network; + bool simulate; + std::string layout_fn; + + Options(int, char **); +}; + +#endif diff --git a/source/engineer/trainpanel.cpp b/source/engineer/trainpanel.cpp index 339f4ec..24a182b 100644 --- a/source/engineer/trainpanel.cpp +++ b/source/engineer/trainpanel.cpp @@ -1,13 +1,13 @@ /* $Id$ This file is part of the MSP Märklin suite -Copyright © 2006-2009 Mikkosoft Productions, Mikko Rasa +Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ #include #include -#include "libmarklin/locomotive.h" +#include "libmarklin/locotype.h" #include "engineer.h" #include "routeselect.h" #include "trainpanel.h" @@ -25,7 +25,7 @@ TrainPanel::TrainPanel(Engineer &e, const GLtk::Resources &r, Train &t): { set_size(200, 170); - add(*(lbl_addr=new GLtk::Label(res, format("%2d", train.get_locomotive().get_address())))); + add(*(lbl_addr=new GLtk::Label(res, format("%2d", train.get_address())))); lbl_addr->set_style("digital"); lbl_addr->set_geometry(GLtk::Geometry(10, geom.h-34, 35, 24)); @@ -34,7 +34,7 @@ TrainPanel::TrainPanel(Engineer &e, const GLtk::Resources &r, Train &t): lbl_name->set_geometry(GLtk::Geometry(45, geom.h-34, geom.w-55, 24)); train.signal_name_changed.connect(sigc::mem_fun(lbl_name, &GLtk::Label::set_text)); - add(*(lbl_speed=new GLtk::Label(res, format("%2d", train.get_locomotive().get_speed())))); + add(*(lbl_speed=new GLtk::Label(res, format("%2d", train.get_speed())))); lbl_speed->set_style("digital"); lbl_speed->set_geometry(GLtk::Geometry(10, geom.h-58, 35, 24)); train.signal_target_speed_changed.connect(sigc::mem_fun(this, &TrainPanel::train_speed_changed)); @@ -48,9 +48,9 @@ TrainPanel::TrainPanel(Engineer &e, const GLtk::Resources &r, Train &t): add(*(tgl_forward=new GLtk::Toggle(res))); tgl_forward->set_text("Fwd"); tgl_forward->set_geometry(GLtk::Geometry(geom.w-30, geom.h-59, 20, 27)); - tgl_forward->set_value(!train.get_locomotive().get_reverse()); + tgl_forward->set_value(!train.get_reverse()); tgl_forward->signal_toggled.connect(sigc::mem_fun(this, &TrainPanel::forward_toggled)); - train.get_locomotive().signal_reverse_changed.connect(sigc::mem_fun(this, &TrainPanel::train_reverse_changed)); + train.signal_reverse_changed.connect(sigc::mem_fun(this, &TrainPanel::train_reverse_changed)); const Route *route = train.get_route(); add(*(lbl_route=new GLtk::Label(res, (route ? route->get_name() : "Free run")))); @@ -63,7 +63,7 @@ TrainPanel::TrainPanel(Engineer &e, const GLtk::Resources &r, Train &t): lbl_status->set_geometry(GLtk::Geometry(10, 34, geom.w-20, 24)); train.signal_status_changed.connect(sigc::mem_fun(this, &TrainPanel::train_status_changed)); - const map &funcs = train.get_locomotive().get_type().get_functions(); + const map &funcs = train.get_locomotive_type().get_functions(); unsigned x = 10; for(map::const_iterator i=funcs.begin(); i!=funcs.end(); ++i, x+=36) { @@ -73,12 +73,12 @@ TrainPanel::TrainPanel(Engineer &e, const GLtk::Resources &r, Train &t): add(*(tgl=new GLtk::Toggle(res))); tgl->set_text(fname); tgl->set_geometry(GLtk::Geometry(x, geom.h-85, 36, 27)); - tgl->set_value(train.get_locomotive().get_function(i->first)); + tgl->set_value(train.get_function(i->first)); tgl->signal_toggled.connect(sigc::bind(sigc::mem_fun(this, &TrainPanel::func_toggled), i->first)); tgl_funcs[i->first] = tgl; } - train.get_locomotive().signal_function_changed.connect(sigc::mem_fun(this, &TrainPanel::loco_function_changed)); + train.signal_function_changed.connect(sigc::mem_fun(this, &TrainPanel::train_function_changed)); GLtk::Button *btn; @@ -114,7 +114,7 @@ void TrainPanel::train_reverse_changed(bool reverse) tgl_forward->set_value(!reverse); } -void TrainPanel::loco_function_changed(unsigned func, bool value) +void TrainPanel::train_function_changed(unsigned func, bool value) { map::iterator i = tgl_funcs.find(func); if(i!=tgl_funcs.end()) @@ -162,5 +162,5 @@ void TrainPanel::forward_toggled(bool value) void TrainPanel::func_toggled(bool value, unsigned func) { - train.get_locomotive().set_function(func, value); + train.set_function(func, value); } diff --git a/source/engineer/trainpanel.h b/source/engineer/trainpanel.h index 7b92985..c8825af 100644 --- a/source/engineer/trainpanel.h +++ b/source/engineer/trainpanel.h @@ -1,7 +1,7 @@ /* $Id$ This file is part of the MSP Märklin suite -Copyright © 2006-2009 Mikkosoft Productions, Mikko Rasa +Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ @@ -38,7 +38,7 @@ private: void speed_slider_changed(double); void train_speed_changed(unsigned); void train_reverse_changed(bool); - void loco_function_changed(unsigned, bool); + void train_function_changed(unsigned, bool); void train_route_changed(const Marklin::Route *); void train_status_changed(const std::string &); void place_clicked(); diff --git a/source/engineer/trainproperties.cpp b/source/engineer/trainproperties.cpp index 004747c..8780dc4 100644 --- a/source/engineer/trainproperties.cpp +++ b/source/engineer/trainproperties.cpp @@ -1,7 +1,7 @@ /* $Id$ This file is part of the MSP Märklin suite -Copyright © 2006-2009 Mikkosoft Productions, Mikko Rasa +Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ @@ -9,6 +9,7 @@ Distributed under the GPL #include #include #include +#include "libmarklin/locotype.h" #include "engineer.h" #include "trainproperties.h" @@ -39,7 +40,7 @@ TrainProperties::TrainProperties(Engineer &e, const GLtk::Resources &r, Train *t for(map::const_iterator i=locos.begin(); i!=locos.end(); ++i, ++n) { drp_type->append(format("%d %s", i->second->get_article_number(), i->second->get_name())); - if(train && i->second==&train->get_locomotive().get_type()) + if(train && i->second==&train->get_locomotive_type()) drp_type->set_selected_index(n); } @@ -48,11 +49,11 @@ TrainProperties::TrainProperties(Engineer &e, const GLtk::Resources &r, Train *t if(train) { - ent_addr->set_text(lexical_cast(train->get_locomotive().get_address())); + ent_addr->set_text(lexical_cast(train->get_address())); ent_name->set_text(train->get_name()); } else - ent_name->set_text(format("Train %d", engineer.get_traffic_manager().get_trains().size()+1)); + ent_name->set_text(format("Train %d", engineer.get_layout().get_trains().size()+1)); } void TrainProperties::on_ok_clicked() @@ -64,8 +65,7 @@ void TrainProperties::on_ok_clicked() advance(i, drp_type->get_selected_index()); unsigned addr = lexical_cast(ent_addr->get_text()); - Locomotive *loco = new Locomotive(*i->second, engineer.get_control(), addr); - train = new Train(engineer.get_traffic_manager(), *loco); + train = new Train(engineer.get_layout(), *i->second, addr); engineer.place_train(*train); } diff --git a/source/libmarklin/block.cpp b/source/libmarklin/block.cpp index a29469c..51f8ddb 100644 --- a/source/libmarklin/block.cpp +++ b/source/libmarklin/block.cpp @@ -1,24 +1,22 @@ /* $Id$ This file is part of the MSP Märklin suite -Copyright © 2006-2009 Mikkosoft Productions, Mikko Rasa +Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ #include -#include "control.h" #include "block.h" +#include "layout.h" #include "tracktype.h" -#include "trafficmanager.h" -#include "turnout.h" using namespace std; using namespace Msp; namespace Marklin { -Block::Block(TrafficManager &tm, Track &start): - trfc_mgr(tm), +Block::Block(Layout &l, Track &start): + layout(l), id(0), sensor_id(start.get_sensor_id()), turnout_id(start.get_turnout_id()), @@ -48,10 +46,7 @@ Block::Block(TrafficManager &tm, Track &start): } } - if(sensor_id) - id = 0x1000|sensor_id; - else if(turnout_id) - id = 0x2000|turnout_id; + determine_id(); for(unsigned i=0; i visited; find_paths(*endpoints[i].track, endpoints[i].track_ep, path, visited); } + + layout.add_block(*this); +} + +Block::~Block() +{ + for(vector::iterator i=endpoints.begin(); i!=endpoints.end(); ++i) + if(Block *blk = i->link) + { + i->link = 0; + blk->break_link(*this); + } + + layout.remove_block(*this); } int Block::get_endpoint_by_link(const Block &other) const @@ -85,13 +94,7 @@ unsigned Block::traverse(unsigned epi, float *len) const while(1) { - unsigned cur_path = 0; - unsigned tid = track->get_turnout_id(); - if(tid) - { - Turnout &turnout = trfc_mgr.get_control().get_turnout(tid); - cur_path = turnout.get_path(); - } + unsigned cur_path = track->get_active_path(); if(len) *len += track->get_type().get_path_length(cur_path); @@ -121,17 +124,22 @@ void Block::check_link(Block &other) { i->link = &other; j->link = this; + + determine_id(); + other.determine_id(); } } +} - if(!sensor_id && !turnout_id && endpoints.size()==2) - { - unsigned id1 = endpoints[0].link ? endpoints[0].link->get_id() : 1; - unsigned id2 = endpoints[1].link ? endpoints[1].link->get_id() : 1; - if(id2::iterator i=endpoints.begin(); i!=endpoints.end(); ++i) + if(i->link==&other) + { + i->link = 0; + other.break_link(*this); + determine_id(); + } } Block *Block::get_link(unsigned epi) const @@ -141,12 +149,12 @@ Block *Block::get_link(unsigned epi) const return endpoints[epi].link; } -bool Block::reserve(const Train *t) +bool Block::reserve(Train *t) { if(!t || !train) { train = t; - trfc_mgr.signal_block_reserved.emit(*this, train); + layout.signal_block_reserved.emit(*this, train); return true; } else @@ -177,6 +185,22 @@ void Block::find_paths(Track &track, unsigned track_ep, unsigned path, setget_id() : 1; + unsigned id2 = endpoints[1].link ? endpoints[1].link->get_id() : 1; + if(id2 #include @@ -14,8 +14,8 @@ Distributed under the GPL namespace Marklin { +class Layout; class Train; -class TrafficManager; class Block { @@ -31,16 +31,17 @@ public: }; private: - TrafficManager &trfc_mgr; + Layout &layout; unsigned id; unsigned sensor_id; unsigned turnout_id; std::set tracks; std::vector endpoints; - const Train *train; + Train *train; public: - Block(TrafficManager &, Track &); + Block(Layout &, Track &); + ~Block(); unsigned get_id() const { return id; } unsigned get_sensor_id() const { return sensor_id; } @@ -50,12 +51,14 @@ public: int get_endpoint_by_link(const Block &) const; unsigned traverse(unsigned, float * =0) const; void check_link(Block &); + void break_link(Block &); Block *get_link(unsigned) const; - bool reserve(const Train *); - const Train *get_train() const { return train; } + bool reserve(Train *); + Train *get_train() const { return train; } void print_debug(); private: void find_paths(Track &, unsigned, unsigned, std::set &); + void determine_id(); }; } // namespace Marklin diff --git a/source/libmarklin/command.cpp b/source/libmarklin/command.cpp deleted file mode 100644 index dd1cdbc..0000000 --- a/source/libmarklin/command.cpp +++ /dev/null @@ -1,45 +0,0 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2006-2008 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - -#include -#include -#include "command.h" - -using namespace std; -using namespace Msp; - -namespace Marklin { - -Command::Command(Cmd c, const unsigned char *d, unsigned l): - cmd(c), - len(1), - sent(false) -{ - data[0]=cmd; - if(d) - { - memcpy(data+1, d, min(l, 127U)); - len+=min(l, 127U); - } -} - -void Command::send(int fd) -{ - write(fd, data, len); - sent=true; -} - -ostream &operator<<(ostream &out, const Command &cmd) -{ - out<(cmd.data[i])); - - return out; -} - -} // namespace Marklin diff --git a/source/libmarklin/command.h b/source/libmarklin/command.h deleted file mode 100644 index e6123c3..0000000 --- a/source/libmarklin/command.h +++ /dev/null @@ -1,43 +0,0 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2007-2008 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - -#ifndef COMMAND_H_ -#define COMMAND_H_ - -#include -#include -#include -#include "constants.h" - -namespace Marklin { - -class Reply; - -class Command -{ -public: - sigc::signal signal_done; - -private: - Cmd cmd; - unsigned char data[128]; - unsigned len; - bool sent; - -public: - Command(Cmd, const unsigned char *, unsigned); - - void send(int); - bool is_sent() const { return sent; } - Cmd get_command() const { return cmd; } - - friend std::ostream &operator<<(std::ostream &, const Command &); -}; - -} // namespace Marklin - -#endif diff --git a/source/libmarklin/constants.cpp b/source/libmarklin/constants.cpp deleted file mode 100644 index e6f5946..0000000 --- a/source/libmarklin/constants.cpp +++ /dev/null @@ -1,71 +0,0 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2008-2009 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - -#include "constants.h" - -using namespace std; - -namespace Marklin { - -ostream &operator<<(ostream &out, const Error &err) -{ - switch(err) - { - case ERR_NO_ERROR: out<<"ERR_NO_ERROR"; break; - case ERR_SYS_ERROR: out<<"ERR_SYS_ERROR"; break; - case ERR_BAD_PARAM: out<<"ERR_BAD_PARAM"; break; - case ERR_POWER_OFF: out<<"ERR_POWER_OFF"; break; - case ERR_NO_LOK_SPACE: out<<"ERR_NO_LOK_SPACE"; break; - case ERR_NO_TURNOUT_SPACE: out<<"ERR_NO_TURNOUT_SPACE"; break; - case ERR_NO_DATA: out<<"ERR_NO_DATA"; break; - case ERR_NO_SLOT: out<<"ERR_NO_SLOT"; break; - case ERR_BAD_LOK_ADDR: out<<"ERR_BAD_LOK_ADDR"; break; - case ERR_LOK_BUSY: out<<"ERR_LOK_BUSY"; break; - case ERR_BAD_TURNOUT_ADDR: out<<"ERR_BAD_TURNOUT_ADDR"; break; - case ERR_BAD_SO_VALUE: out<<"ERR_BAD_SO_VALUE"; break; - case ERR_NO_I2C_SPACE: out<<"ERR_NO_I2C_SPACE"; break; - case ERR_LOW_TURNOUT_SPACE: out<<"ERR_LOW_TURNOUT_SPACE"; break; - case ERR_LOK_HALTED: out<<"ERR_LOK_HALTED"; break; - case ERR_LOK_POWER_OFF: out<<"ERR_LOK_POWER_OFF"; break; - case ERR_UNKNOWN_ERROR: out<<"ERR_UNKNOWN_ERROR"; break; - default: out<<"Err("<(err)<<')'; break; - } - - return out; -} - -ostream &operator<<(ostream &out, const Cmd &cmd) -{ - switch(cmd) - { - case CMD_LOK: out<<"CMD_LOK"; break; - case CMD_LOK_STATUS: out<<"CMD_LOK_STATUS"; break; - case CMD_LOK_CONFIG: out<<"CMD_LOK_CONFIG"; break; - case CMD_FUNC: out<<"CMD_FUNC"; break; - case CMD_FUNC_STATUS: out<<"CMD_FUNC_STATUS"; break; - case CMD_TURNOUT: out<<"CMD_TURNOUT"; break; - case CMD_TURNOUT_FREE: out<<"CMD_TURNOUT_FREE"; break; - case CMD_TURNOUT_STATUS: out<<"CMD_TURNOUT_STATUS"; break; - case CMD_TURNOUT_GROUP_STATUS: out<<"CMD_TURNOUT_GROUP_STATUS"; break; - case CMD_SENSOR_STATUS: out<<"CMD_SENSOR_STATUS"; break; - case CMD_SENSOR_REPORT: out<<"CMD_SENSOR_REPORT"; break; - case CMD_SENSOR_PARAM_SET: out<<"CMD_SENSOR_PARAM_SET"; break; - case CMD_STATUS: out<<"CMD_STATUS"; break; - case CMD_POWER_OFF: out<<"CMD_POWER_OFF"; break; - case CMD_POWER_ON: out<<"CMD_POWER_ON"; break; - case CMD_NOP: out<<"CMD_NOP"; break; - case CMD_EVENT: out<<"CMD_EVENT"; break; - case CMD_EVENT_LOK: out<<"CMD_EVENT_LOK"; break; - case CMD_EVENT_TURNOUT: out<<"CMD_EVENT_TURNOUT"; break; - case CMD_EVENT_SENSOR: out<<"CMD_EVENT_SENSOR"; break; - default: out<<"Cmd("<(cmd)<<')'; break; - } - - return out; -} - -} // namespace Marklin diff --git a/source/libmarklin/constants.h b/source/libmarklin/constants.h deleted file mode 100644 index f68737d..0000000 --- a/source/libmarklin/constants.h +++ /dev/null @@ -1,66 +0,0 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2006-2008 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - -#ifndef ERROR_H_ -#define ERROR_H_ - -#include - -namespace Marklin { - -enum Error -{ - ERR_NO_ERROR=0, - ERR_SYS_ERROR, - ERR_BAD_PARAM, - ERR_POWER_OFF=0x6, - ERR_NO_LOK_SPACE=0x8, // No space in lok command buffer - ERR_NO_TURNOUT_SPACE, // No space in turnout command buffer - ERR_NO_DATA, // "no Lok status available (Lok is not in a slot)" - ERR_NO_SLOT, // "there is no slot available" - ERR_BAD_LOK_ADDR, - ERR_LOK_BUSY, - ERR_BAD_TURNOUT_ADDR, - ERR_BAD_SO_VALUE, - ERR_NO_I2C_SPACE, - ERR_LOW_TURNOUT_SPACE=0x40, - ERR_LOK_HALTED, - ERR_LOK_POWER_OFF, - ERR_UNKNOWN_ERROR=0xFF -}; - -std::ostream &operator<<(std::ostream &, const Error &); - -enum Cmd -{ - CMD_LOK=0x80, - CMD_LOK_STATUS=0x84, - CMD_LOK_CONFIG=0x85, - CMD_FUNC=0x88, - CMD_FUNC_STATUS=0x8C, - CMD_TURNOUT=0x90, - CMD_TURNOUT_FREE=0x93, - CMD_TURNOUT_STATUS=0x94, - CMD_TURNOUT_GROUP_STATUS=0x95, - CMD_SENSOR_STATUS=0x98, - CMD_SENSOR_REPORT=0x99, - CMD_SENSOR_PARAM_SET=0x9D, - CMD_STATUS=0xA2, - CMD_POWER_OFF=0xA6, - CMD_POWER_ON=0xA7, - CMD_NOP=0xC4, - CMD_EVENT=0xC8, - CMD_EVENT_LOK=0xC9, - CMD_EVENT_TURNOUT=0xCA, - CMD_EVENT_SENSOR=0xCB -}; - -std::ostream &operator<<(std::ostream &, const Cmd &); - -} // namespace Marklin - -#endif diff --git a/source/libmarklin/control.cpp b/source/libmarklin/control.cpp deleted file mode 100644 index ae26a17..0000000 --- a/source/libmarklin/control.cpp +++ /dev/null @@ -1,284 +0,0 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2007-2009 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - -#include -#include -#include -#include -#include -#include -#include -#include "command.h" -#include "control.h" -#include "reply.h" - -using namespace std; -using namespace Msp; - -namespace Marklin { - -Control::Control(): - serial_fd(-1), - power(true), - poll_sensors(false), - debug(false) -{ } - -Control::~Control() -{ - for(map::iterator i=sensors.begin(); i!=sensors.end(); ++i) - delete i->second; - for(map::iterator i=turnouts.begin(); i!=turnouts.end(); ++i) - delete i->second; - for(map::iterator i=locomotives.begin(); i!=locomotives.end(); ++i) - delete i->second; - if(serial_fd>=0) - close(serial_fd); -} - -void Control::open(const string &dev) -{ - serial_fd = ::open(dev.c_str(), O_RDWR); - if(serial_fd<0) - throw Exception("Couldn't open serial port\n"); - - static unsigned baud[]= - { - 2400, B2400, - 4800, B4800, - 9600, B9600, - 19200, B19200, - 0 - }; - - termios attr; - tcgetattr(serial_fd, &attr); - cfmakeraw(&attr); - attr.c_cflag |= CSTOPB; - - bool ok = false; - bool p50 = false; - for(unsigned i=0; baud[i]; i+=2) - { - cfsetospeed(&attr, baud[i+1]); - tcsetattr(serial_fd, TCSADRAIN, &attr); - - write(serial_fd, "\xC4", 1); - - pollfd pfd = { serial_fd, POLLIN, 0 }; - if(poll(&pfd, 1, 500)>0) - { - IO::print("IB detected at %d bits/s\n", baud[i]); - char buf[2]; - p50 = (read(serial_fd, buf, 2)==2); - ok = true; - break; - } - } - - if(!ok) - throw Exception("IB not detected"); - - if(p50) - write(serial_fd, "xZzA1\r", 6); - - command(CMD_STATUS).signal_done.connect(sigc::mem_fun(this, &Control::status_done)); -} - -void Control::set_debug(bool d) -{ - debug = d; -} - -void Control::set_power(bool p) -{ - power = p; - if(power) - command(CMD_POWER_ON); - else - command(CMD_POWER_OFF); - - signal_power_event.emit(power); -} - -Command &Control::command(Cmd cmd) -{ - queue.push_back(Command(cmd, 0, 0)); - return queue.back(); -} - -Command &Control::command(Cmd cmd, unsigned char data) -{ - queue.push_back(Command(cmd, &data, 1)); - return queue.back(); -} - -Command &Control::command(Cmd cmd, const unsigned char *data, unsigned len) -{ - queue.push_back(Command(cmd, data, len)); - return queue.back(); -} - -void Control::flush() -{ - for(list::iterator i=queue.begin(); i!=queue.end(); ++i) - i->send(serial_fd); -} - -void Control::add_turnout(Turnout &t) -{ - turnouts[t.get_address()] = &t; -} - -Turnout &Control::get_turnout(unsigned id) const -{ - map::const_iterator i = turnouts.find(id); - if(i==turnouts.end()) - throw KeyError("Unknown turnout"); - - return *i->second; -} - -void Control::add_locomotive(Locomotive &l) -{ - locomotives[l.get_address()] = &l; -} - -Locomotive &Control::get_locomotive(unsigned id) const -{ - map::const_iterator i = locomotives.find(id); - if(i==locomotives.end()) - throw KeyError("Unknown locomotive"); - - return *i->second; -} - -void Control::add_sensor(Sensor &s) -{ - sensors[s.get_address()] = &s; - poll_sensors = true; -} - -Sensor &Control::get_sensor(unsigned id) const -{ - map::const_iterator i = sensors.find(id); - if(i==sensors.end()) - throw KeyError("Unknown sensor"); - - return *i->second; -} - -void Control::tick() -{ - const Time::TimeStamp t = Time::now(); - - for(map::const_iterator i=sensors.begin(); i!=sensors.end(); ++i) - i->second->tick(); - - timer.tick(false); - - if(t>next_event_query) - { - next_event_query = t+200*Time::msec; - command(CMD_EVENT).signal_done.connect(sigc::mem_fun(this, &Control::event_query_done)); - } - - if(poll_sensors) - { - unsigned max_addr = (--sensors.end())->first; - unsigned char data[2]; - data[0] = 0; - data[1] = (max_addr+7)/8; - command(CMD_SENSOR_PARAM_SET, data, 2); - command(CMD_SENSOR_REPORT); - poll_sensors = false; - } - - if(!queue.empty() && queue.front().is_sent()) - { - pollfd pfd = { serial_fd, POLLIN, 0 }; - if(poll(&pfd, 1, 0)>0) - { - Reply reply = Reply::read(serial_fd, queue.front().get_command()); - if(debug) - IO::print("R: %s\n", reply); - - queue.front().signal_done.emit(reply); - queue.erase(queue.begin()); - } - else - return; - } - - if(!queue.empty()) - { - if(debug) - IO::print("W: %s\n", queue.front()); - - if(serial_fd>=0) - queue.front().send(serial_fd); - else - { - Reply reply = Reply::simulate(queue.front().get_command()); - queue.front().signal_done.emit(reply); - queue.erase(queue.begin()); - } - } -} - -Time::Timer::Slot &Control::set_timer(const Time::TimeDelta &dt) -{ - return timer.add(dt); -} - -void Control::status_done(const Reply &reply) -{ - power = ((reply.get_data()[0]&0x08)!=0); - signal_power_event.emit(power); -} - -void Control::event_query_done(const Reply &reply) -{ - const unsigned char *data = reply.get_data(); - if(data[0]&0x01) - command(CMD_EVENT_LOK); - if(data[0]&0x20) - command(CMD_EVENT_TURNOUT).signal_done.connect(sigc::mem_fun(this, &Control::turnout_event_done)); - if(data[0]&0x04) - command(CMD_EVENT_SENSOR).signal_done.connect(sigc::mem_fun(this, &Control::sensor_event_done)); - if((data[0]&0x80) && (data[1]&0x40)) - command(CMD_STATUS).signal_done.connect(sigc::mem_fun(this, &Control::status_done)); -} - -void Control::turnout_event_done(const Reply &reply) -{ - const unsigned char *data = reply.get_data(); - unsigned count = data[0]; - for(unsigned i=0; i>(7-j%8))&1); - } -} - -} // namespace Marklin diff --git a/source/libmarklin/control.h b/source/libmarklin/control.h deleted file mode 100644 index a041e95..0000000 --- a/source/libmarklin/control.h +++ /dev/null @@ -1,79 +0,0 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2006-2009 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - -#ifndef LIBMARKLIN_CONTROL_H_ -#define LIBMARKLIN_CONTROL_H_ - -#include -#include -#include -#include -#include "constants.h" -#include "sensor.h" -#include "locomotive.h" -#include "turnout.h" - -namespace Marklin { - -class Command; -class Reply; - -class Control -{ -public: - sigc::signal signal_power_event; - sigc::signal signal_turnout_event; - sigc::signal signal_sensor_event; - -private: - int serial_fd; - bool power; - std::list queue; - std::map turnouts; - std::map locomotives; - std::map sensors; - Msp::Time::TimeStamp next_event_query; - bool poll_sensors; - bool debug; - Msp::Time::Timer timer; - -public: - Control(); - ~Control(); - - void open(const std::string &); - void set_debug(bool); - void set_power(bool); - bool get_power() const { return power; } - Command &command(Cmd); - Command &command(Cmd, unsigned char); - Command &command(Cmd, const unsigned char *, unsigned); - unsigned get_queue_length() const { return queue.size(); } - void flush(); - - void add_turnout(Turnout &); - Turnout &get_turnout(unsigned) const; - const std::map &get_turnouts() const { return turnouts; } - void add_locomotive(Locomotive &); - Locomotive &get_locomotive(unsigned) const; - const std::map &get_locomotives() const { return locomotives; } - void add_sensor(Sensor &); - Sensor &get_sensor(unsigned) const; - const std::map &get_sensors() const { return sensors; } - - void tick(); - Msp::Time::Timer::Slot &set_timer(const Msp::Time::TimeDelta &); -private: - void status_done(const Reply &); - void event_query_done(const Reply &); - void turnout_event_done(const Reply &); - void sensor_event_done(const Reply &); -}; - -} // namespace Marklin - -#endif diff --git a/source/libmarklin/driver.cpp b/source/libmarklin/driver.cpp new file mode 100644 index 0000000..3bec54e --- /dev/null +++ b/source/libmarklin/driver.cpp @@ -0,0 +1,34 @@ +/* $Id$ + +This file is part of the MSP Märklin suite +Copyright © 2010 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#include +#include "driver.h" +#include "dummy.h" +#include "intellibox.h" + +using namespace std; + +namespace Marklin { + +Driver *Driver::create(const string &str) +{ + string::size_type colon = str.find(':'); + string type = str.substr(0, colon); + string params; + + if(colon!=string::npos) + params = str.substr(colon+1); + + if(type=="ib" || type=="intellibox") + return new Intellibox(params); + else if(type=="dummy") + return new Dummy; + + throw Msp::InvalidParameterValue("Unknown driver"); +} + +} // namespace Marklin diff --git a/source/libmarklin/driver.h b/source/libmarklin/driver.h new file mode 100644 index 0000000..1a5084d --- /dev/null +++ b/source/libmarklin/driver.h @@ -0,0 +1,53 @@ +/* $Id$ + +This file is part of the MSP Märklin suite +Copyright © 2010 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#ifndef LIBMARKLIN_DRIVER_H_ +#define LIBMARKLIN_DRIVER_H_ + +#include +#include + +namespace Marklin { + +class Driver +{ +public: + sigc::signal signal_power; + sigc::signal signal_loco_speed; + sigc::signal signal_loco_function; + sigc::signal signal_turnout; + sigc::signal signal_sensor; + +protected: + Driver() { } +public: + virtual ~Driver() { } + + virtual void set_power(bool) = 0; + virtual bool get_power() const = 0; + + virtual void add_loco(unsigned) = 0; + virtual void set_loco_speed(unsigned, unsigned) = 0; + virtual void set_loco_reverse(unsigned, bool) = 0; + virtual void set_loco_function(unsigned, unsigned, bool) = 0; + + virtual void add_turnout(unsigned) = 0; + virtual void set_turnout(unsigned, bool) = 0; + virtual bool get_turnout(unsigned) const = 0; + + virtual void add_sensor(unsigned) = 0; + virtual bool get_sensor(unsigned) const = 0; + + virtual void tick() = 0; + virtual void flush() = 0; + + static Driver *create(const std::string &); +}; + +} // namespace Marklin + +#endif diff --git a/source/libmarklin/dummy.cpp b/source/libmarklin/dummy.cpp new file mode 100644 index 0000000..1a7dd36 --- /dev/null +++ b/source/libmarklin/dummy.cpp @@ -0,0 +1,43 @@ +/* $Id$ + +This file is part of the MSP Märklin suite +Copyright © 2010 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#include "dummy.h" + +using namespace std; + +namespace Marklin { + +Dummy::Dummy(): + power(true) +{ } + +void Dummy::set_power(bool p) +{ + power = p; + signal_power.emit(power); +} + +void Dummy::add_turnout(unsigned addr) +{ + turnouts[addr]; +} + +void Dummy::set_turnout(unsigned addr, bool state) +{ + turnouts[addr] = state; + signal_turnout.emit(addr, state); +} + +bool Dummy::get_turnout(unsigned addr) const +{ + map::const_iterator i = turnouts.find(addr); + if(i!=turnouts.end()) + return i->second; + return false; +} + +} // namespace Marklin diff --git a/source/libmarklin/dummy.h b/source/libmarklin/dummy.h new file mode 100644 index 0000000..96b62a8 --- /dev/null +++ b/source/libmarklin/dummy.h @@ -0,0 +1,46 @@ +/* $Id$ + +This file is part of the MSP Märklin suite +Copyright © 2010 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#ifndef LIBMARKLIN_DUMMY_H_ +#define LIBMARKLIN_DUMMY_H_ + +#include +#include "driver.h" + +namespace Marklin { + +class Dummy: public Driver +{ +private: + bool power; + std::map turnouts; + +public: + Dummy(); + + virtual void set_power(bool); + virtual bool get_power() const { return power; } + + virtual void add_loco(unsigned) { } + virtual void set_loco_speed(unsigned, unsigned) { } + virtual void set_loco_reverse(unsigned, bool) { } + virtual void set_loco_function(unsigned, unsigned, bool) { } + + virtual void add_turnout(unsigned); + virtual void set_turnout(unsigned, bool); + virtual bool get_turnout(unsigned) const; + + virtual void add_sensor(unsigned) { } + virtual bool get_sensor(unsigned) const { return false; } + + virtual void tick() { } + virtual void flush() { } +}; + +} // namespace Marklin + +#endif diff --git a/source/libmarklin/except.h b/source/libmarklin/except.h deleted file mode 100644 index 85fe431..0000000 --- a/source/libmarklin/except.h +++ /dev/null @@ -1,31 +0,0 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2009 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - -#ifndef LIBMARKLIN_EXCEPT_H_ -#define LIBMARKLIN_EXCEPT_H_ - -#include - -namespace Marklin { - -class Train; - -class TurnoutBusy: public Msp::Exception -{ -private: - Train *train; - -public: - TurnoutBusy(Train *t): Exception("Turnout is busy"), train(t) { } - virtual ~TurnoutBusy() throw() { } - - Train *get_train() const throw() { return train; } -}; - -} - -#endif diff --git a/source/libmarklin/intellibox.cpp b/source/libmarklin/intellibox.cpp new file mode 100644 index 0000000..3588061 --- /dev/null +++ b/source/libmarklin/intellibox.cpp @@ -0,0 +1,502 @@ +/* $Id$ + +This file is part of the MSP Märklin suite +Copyright © 2010 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#include +#include +#include +#include +#include +#include +#include "intellibox.h" + +using namespace std; +using namespace Msp; + +namespace Marklin { + +Intellibox::Intellibox(const string &dev): + power(false), + update_sensors(false), + command_sent(false) +{ + serial_fd = ::open(dev.c_str(), O_RDWR); + if(serial_fd<0) + throw Exception("Couldn't open serial port\n"); + + static unsigned baud[]= + { + 2400, B2400, + 4800, B4800, + 9600, B9600, + 19200, B19200, + 0 + }; + + termios attr; + tcgetattr(serial_fd, &attr); + cfmakeraw(&attr); + attr.c_cflag |= CSTOPB; + + bool ok = false; + bool p50 = false; + for(unsigned i=0; baud[i]; i+=2) + { + cfsetospeed(&attr, baud[i+1]); + tcsetattr(serial_fd, TCSADRAIN, &attr); + + write(serial_fd, "\xC4", 1); + + pollfd pfd = { serial_fd, POLLIN, 0 }; + if(poll(&pfd, 1, 500)>0) + { + IO::print("IB detected at %d bits/s\n", baud[i]); + char buf[2]; + p50 = (read(serial_fd, buf, 2)==2); + ok = true; + break; + } + } + + if(!ok) + throw Exception("IB not detected"); + + if(p50) + write(serial_fd, "xZzA1\r", 6); + + command(CMD_STATUS); +} + +void Intellibox::set_power(bool p) +{ + power = p; + if(power) + command(CMD_POWER_ON); + else + command(CMD_POWER_OFF); + signal_power.emit(power); +} + +void Intellibox::add_loco(unsigned addr) +{ + if(!locos.count(addr)) + { + locos[addr]; + + unsigned char data[2]; + data[0] = addr&0xFF; + data[1] = (addr>>8)&0xFF; + command(CMD_LOK_STATUS, addr, data, 2); + } +} + +void Intellibox::set_loco_speed(unsigned addr, unsigned speed) +{ + Locomotive &loco = locos[addr]; + loco.speed = speed; + loco_command(addr, speed, loco.reverse, loco.funcs|0x100); + signal_loco_speed.emit(addr, speed, loco.reverse); +} + +void Intellibox::set_loco_reverse(unsigned addr, bool rev) +{ + Locomotive &loco = locos[addr]; + loco.reverse = rev; + loco_command(addr, loco.speed, rev, loco.funcs|0x100); + signal_loco_speed.emit(addr, loco.speed, rev); +} + +void Intellibox::set_loco_function(unsigned addr, unsigned func, bool state) +{ + Locomotive &loco = locos[addr]; + if(state) + loco.funcs |= 1<>8)&0xFF; + command(CMD_TURNOUT_STATUS, addr, data, 2); + } +} + +void Intellibox::set_turnout(unsigned addr, bool state) +{ + Turnout &turnout = turnouts[addr]; + if(state==turnout.state || state==turnout.pending) + return; + + turnout.pending = state; + turnout.active = true; + + turnout_command(addr, state, true); +} + +bool Intellibox::get_turnout(unsigned addr) const +{ + map::const_iterator i = turnouts.find(addr); + if(i!=turnouts.end()) + return i->second.state; + return false; +} + +void Intellibox::add_sensor(unsigned addr) +{ + if(!sensors.count(addr)) + { + sensors[addr]; + update_sensors = true; + } +} + +bool Intellibox::get_sensor(unsigned addr) const +{ + map::const_iterator i = sensors.find(addr); + if(i!=sensors.end()) + return i->second.state; + return false; +} + +void Intellibox::tick() +{ + const Time::TimeStamp t = Time::now(); + + if(t>next_event_query) + { + next_event_query = t+200*Time::msec; + command(CMD_EVENT); + } + + for(map::iterator i=turnouts.begin(); i!=turnouts.end(); ++i) + if(i->second.active && i->second.off_timeout && t>i->second.off_timeout) + { + i->second.active = false; + i->second.off_timeout = Time::TimeStamp(); + turnout_command(i->first, i->second.state, false); + } + + for(map::iterator i=sensors.begin(); i!=sensors.end(); ++i) + if(i->second.off_timeout && t>i->second.off_timeout) + { + i->second.state = false; + i->second.off_timeout = Time::TimeStamp(); + signal_sensor.emit(i->first, false); + } + + if(update_sensors) + { + unsigned max_addr = (--sensors.end())->first; + unsigned char data[2]; + data[0] = 0; + data[1] = (max_addr+7)/8; + command(CMD_SENSOR_PARAM_SET, data, 2); + command(CMD_SENSOR_REPORT); + update_sensors = false; + } + + if(!queue.empty() && command_sent) + { + pollfd pfd = { serial_fd, POLLIN, 0 }; + if(poll(&pfd, 1, 0)>0) + { + process_reply(t); + queue.erase(queue.begin()); + command_sent = false; + } + else + return; + } + + if(!queue.empty()) + { + const CommandSlot &slot = queue.front(); + write(serial_fd, slot.data, slot.length); + command_sent = true; + } +} + +void Intellibox::flush() +{ + for(list::iterator i=queue.begin(); i!=queue.end(); ++i) + write(serial_fd, i->data, i->length); +} + +void Intellibox::command(Command cmd) +{ + command(cmd, 0, 0); +} + +void Intellibox::command(Command cmd, const unsigned char *data, unsigned len) +{ + command(cmd, 0, data, len); +} + +void Intellibox::command(Command cmd, unsigned addr, const unsigned char *data, unsigned len) +{ + CommandSlot slot; + slot.cmd = cmd; + slot.addr = addr; + slot.data[0] = cmd; + copy(data, data+len, slot.data+1); + slot.length = 1+len; + queue.push_back(slot); +} + +void Intellibox::loco_command(unsigned addr, unsigned speed, bool rev, unsigned funcs) +{ + unsigned char data[4]; + data[0] = addr&0xFF; + data[1] = (addr>>8)&0xFF; + + if(speed==0) + data[2] = 0; + else if(speed==1) + data[2] = 2; + else + data[2] = (speed*19-18)/2; + + data[3] = (rev ? 0 : 0x20) | ((funcs&1) ? 0x10 : 0); + + if(!(funcs&0x100)) + data[3] |= 0x80 | ((funcs>>1)&0xF); + + command(CMD_LOK, addr, data, 4); +} + +void Intellibox::turnout_command(unsigned addr, bool state, bool active) +{ + unsigned char data[2]; + data[0] = addr&0xFF; + data[1] = ((addr>>8)&0x7) | (active ? 0x40 : 0) | (state ? 0x80 : 0); + command(CMD_TURNOUT, addr, data, 2); +} + +void Intellibox::process_reply(const Time::TimeStamp &t) +{ + Command cmd = queue.front().cmd; + + if(cmd==CMD_STATUS) + { + unsigned char status; + read_all(&status, 1); + power = status&0x08; + signal_power.emit(power); + } + else if(cmd==CMD_EVENT) + { + for(unsigned i=0;; ++i) + { + unsigned char byte; + read_all(&byte, 1); + + if(i==0) + { + if(byte&0x01) + command(CMD_EVENT_LOK); + if(byte&0x20) + command(CMD_EVENT_TURNOUT); + if(byte&0x04) + command(CMD_EVENT_SENSOR); + } + else if(i==1) + { + if(byte&0x40) + command(CMD_STATUS); + } + + if(!(byte&0x80)) + break; + } + } + else if(cmd==CMD_EVENT_LOK) + { + while(1) + { + unsigned char data[5]; + read_all(data, 1); + if(data[0]==0x80) + break; + read_all(data+1, 4); + } + } + else if(cmd==CMD_EVENT_TURNOUT) + { + unsigned char count; + read_all(&count, 1); + for(unsigned i=0; i>(7-i%8))&1; + + Sensor &sensor = sensors[addr]; + if(state) + { + sensor.off_timeout = Time::TimeStamp(); + if(!sensor.state) + { + sensor.state = state; + signal_sensor(addr, state); + } + } + else if(sensor.state) + sensor.off_timeout = t+700*Time::msec; + } + } + } + else if(cmd==CMD_TURNOUT) + { + unsigned char err; + read_all(&err, 1); + + if(err==ERR_NO_ERROR) + { + unsigned addr = queue.front().addr; + Turnout &turnout = turnouts[addr]; + turnout.state = turnout.pending; + if(turnout.active) + { + signal_turnout.emit(addr, turnout.state); + turnout.off_timeout = t+500*Time::msec; + } + } + else if(err==ERR_NO_I2C_SPACE) + queue.push_back(queue.front()); + } + else if(cmd==CMD_TURNOUT_STATUS) + { + unsigned char err; + read_all(&err, 1); + + if(err==ERR_NO_ERROR) + { + unsigned char data; + read_all(&data, 1); + + unsigned addr = queue.front().addr; + bool state = data&0x04; + + Turnout &turnout = turnouts[addr]; + if(state!=turnout.state) + { + turnout.state = state; + signal_turnout.emit(addr, turnout.state); + } + } + } + else if(cmd==CMD_LOK_STATUS) + { + unsigned char err; + read_all(&err, 1); + + if(err==ERR_NO_ERROR) + { + unsigned char data[3]; + read_all(data, 3); + + unsigned addr = queue.front().addr; + Locomotive &loco = locos[addr]; + + unsigned speed = (data[0]<=1 ? 0 : data[0]*2/19+1); + bool reverse = !(data[1]&0x20); + if(speed!=loco.speed || reverse!=loco.reverse) + { + loco.speed = speed; + loco.reverse = reverse; + signal_loco_speed.emit(addr, loco.speed, loco.reverse); + } + + unsigned funcs = (data[1]&0xF)<<1; + if(data[1]&0x10) + funcs |= 1; + if(funcs!=loco.funcs) + { + unsigned changed = loco.funcs^funcs; + loco.funcs = funcs; + for(unsigned i=0; i<5; ++i) + if(changed&(1< +#include +#include "driver.h" + +namespace Marklin { + +class Intellibox: public Driver +{ +private: + enum Command + { + CMD_LOK=0x80, + CMD_LOK_STATUS=0x84, + CMD_LOK_CONFIG=0x85, + CMD_FUNC=0x88, + CMD_FUNC_STATUS=0x8C, + CMD_TURNOUT=0x90, + CMD_TURNOUT_FREE=0x93, + CMD_TURNOUT_STATUS=0x94, + CMD_TURNOUT_GROUP_STATUS=0x95, + CMD_SENSOR_STATUS=0x98, + CMD_SENSOR_REPORT=0x99, + CMD_SENSOR_PARAM_SET=0x9D, + CMD_STATUS=0xA2, + CMD_POWER_OFF=0xA6, + CMD_POWER_ON=0xA7, + CMD_NOP=0xC4, + CMD_EVENT=0xC8, + CMD_EVENT_LOK=0xC9, + CMD_EVENT_TURNOUT=0xCA, + CMD_EVENT_SENSOR=0xCB + }; + + enum Error + { + ERR_NO_ERROR=0, + ERR_SYS_ERROR, + ERR_BAD_PARAM, + ERR_POWER_OFF=0x6, + ERR_NO_LOK_SPACE=0x8, // No space in lok command buffer + ERR_NO_TURNOUT_SPACE, // No space in turnout command buffer + ERR_NO_DATA, // "no Lok status available (Lok is not in a slot)" + ERR_NO_SLOT, // "there is no slot available" + ERR_BAD_LOK_ADDR, + ERR_LOK_BUSY, + ERR_BAD_TURNOUT_ADDR, + ERR_BAD_SO_VALUE, + ERR_NO_I2C_SPACE, + ERR_LOW_TURNOUT_SPACE=0x40, + ERR_LOK_HALTED, + ERR_LOK_POWER_OFF, + }; + + struct Locomotive + { + unsigned speed; + bool reverse; + unsigned funcs; + + Locomotive(); + }; + + struct Turnout + { + bool state; + bool active; + bool pending; + Msp::Time::TimeStamp off_timeout; + + Turnout(); + }; + + struct Sensor + { + bool state; + Msp::Time::TimeStamp off_timeout; + + Sensor(); + }; + + struct CommandSlot + { + Command cmd; + unsigned addr; + unsigned char data[8]; + unsigned length; + }; + + int serial_fd; + bool power; + std::map locos; + std::map turnouts; + std::map sensors; + bool update_sensors; + std::list queue; + bool command_sent; + Msp::Time::TimeStamp next_event_query; + +public: + Intellibox(const std::string &); + + virtual void set_power(bool); + virtual bool get_power() const { return power; } + + virtual void add_loco(unsigned); + virtual void set_loco_speed(unsigned, unsigned); + virtual void set_loco_reverse(unsigned, bool); + virtual void set_loco_function(unsigned, unsigned, bool); + + virtual void add_turnout(unsigned); + virtual void set_turnout(unsigned, bool); + virtual bool get_turnout(unsigned) const; + + virtual void add_sensor(unsigned); + virtual bool get_sensor(unsigned) const; + + virtual void tick(); + virtual void flush(); + +private: + void command(Command); + void command(Command, const unsigned char *, unsigned); + void command(Command, unsigned, const unsigned char *, unsigned); + void loco_command(unsigned, unsigned, bool, unsigned); + void turnout_command(unsigned, bool, bool); + void process_reply(const Msp::Time::TimeStamp &); + unsigned read_all(unsigned char *, unsigned); +}; + +} // namespace Marklin + +#endif diff --git a/source/libmarklin/layout.cpp b/source/libmarklin/layout.cpp index b61522b..c093035 100644 --- a/source/libmarklin/layout.cpp +++ b/source/libmarklin/layout.cpp @@ -1,50 +1,146 @@ /* $Id$ This file is part of the MSP Märklin suite -Copyright © 2006-2009 Mikkosoft Productions, Mikko Rasa +Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ +#include #include #include #include +#include +#include "block.h" #include "catalogue.h" +#include "driver.h" #include "layout.h" +#include "locotype.h" +#include "route.h" +#include "track.h" #include "tracktype.h" +#include "train.h" using namespace std; using namespace Msp; namespace Marklin { -Layout::Layout(Catalogue &c): - catalogue(c) +Layout::Layout(Catalogue &c, Driver *d): + catalogue(c), + driver(d) { } Layout::~Layout() { - for(set::iterator i=tracks.begin(); i!=tracks.end(); ++i) - delete *i; - for(map::iterator i=routes.begin(); i!=routes.end(); ++i) - delete i->second; + delete driver; + while(!trains.empty()) + delete trains.begin()->second; + while(!routes.empty()) + delete routes.begin()->second; + while(!tracks.empty()) + delete *tracks.begin(); + while(!blocks.empty()) + delete *blocks.begin(); +} + +Driver &Layout::get_driver() const +{ + if(!driver) + throw InvalidState("No driver"); + return *driver; } void Layout::add_track(Track &t) { if(tracks.insert(&t).second) + { + create_blocks(); signal_track_added.emit(t); + } } void Layout::remove_track(Track &t) { if(tracks.erase(&t)) + { + create_blocks(t); signal_track_removed.emit(t); + } +} + +void Layout::add_block(Block &b) +{ + blocks.insert(&b); +} + +Block &Layout::get_block(unsigned id) const +{ + for(set::const_iterator i=blocks.begin(); i!=blocks.end(); ++i) + if((*i)->get_id()==id) + return **i; + + throw KeyError("Unknown block", lexical_cast(id)); +} + +Block &Layout::get_block_by_track(const Track &t) const +{ + for(set::const_iterator i=blocks.begin(); i!=blocks.end(); ++i) + if((*i)->get_tracks().count(const_cast(&t))) + return **i; + + throw InvalidParameterValue("No block found for track"); +} + +void Layout::create_blocks() +{ + set used_tracks; + for(set::const_iterator i=blocks.begin(); i!=blocks.end(); ++i) + { + const set &btracks = (*i)->get_tracks(); + used_tracks.insert(btracks.begin(), btracks.end()); + } + + for(set::const_iterator i=tracks.begin(); i!=tracks.end(); ++i) + if(used_tracks.count(*i)==0) + { + Block *block = new Block(*this, **i); + used_tracks.insert(block->get_tracks().begin(), block->get_tracks().end()); + } + + for(set::iterator i=blocks.begin(); i!=blocks.end(); ++i) + for(set::iterator j=i; j!=blocks.end(); ++j) + if(j!=i) + (*i)->check_link(**j); +} + +void Layout::create_blocks(const Track &track) +{ + const vector &links = track.get_links(); + for(set::iterator i=blocks.begin(); i!=blocks.end();) + { + bool del = (*i)->get_tracks().count(const_cast(&track)); + for(vector::const_iterator j=links.begin(); (!del && j!=links.end()); ++j) + del = (*i)->get_tracks().count(*j); + + if(del) + delete *i++; + else + ++i; + } + + create_blocks(); +} + +void Layout::remove_block(Block &b) +{ + blocks.erase(&b); } void Layout::add_route(Route &r) { if(routes.count(r.get_name())) - throw KeyError("Duplicate route name"); + throw KeyError("Duplicate route name", r.get_name()); + routes[r.get_name()] = &r; signal_route_added.emit(r); } @@ -63,6 +159,44 @@ void Layout::remove_route(Route &r) signal_route_removed.emit(r); } +void Layout::add_train(Train &t) +{ + if(trains.count(t.get_address())) + throw KeyError("Duplicate train address", lexical_cast(t.get_address())); + + trains[t.get_address()] = &t; + signal_train_added.emit(t); +} + +Train &Layout::get_train(unsigned addr) const +{ + map::const_iterator i = trains.find(addr); + if(i==trains.end()) + throw KeyError("Unknown train", lexical_cast(addr)); + return *i->second; +} + +void Layout::remove_train(Train &t) +{ + if(trains.erase(t.get_address())) + signal_train_removed.emit(t); +} + +void Layout::tick() +{ + if(driver) + driver->tick(); + + Time::TimeStamp t = Time::now(); + Time::TimeDelta dt; + if(last_tick) + dt = t-last_tick; + last_tick = t; + + for(map::iterator i=trains.begin(); i!=trains.end(); ++i) + i->second->tick(t, dt); +} + void Layout::save(const string &fn) { IO::BufferedFile out(fn, IO::M_WRITE); @@ -88,6 +222,21 @@ void Layout::save(const string &fn) } } +void Layout::save_trains(const string &fn) +{ + IO::BufferedFile out(fn, IO::M_WRITE); + DataFile::Writer writer(out); + + for(map::const_iterator i=trains.begin(); i!=trains.end(); ++i) + { + DataFile::Statement st("train"); + st.append(i->second->get_locomotive_type().get_article_number()); + st.append(i->second->get_address()); + i->second->save(st.sub); + writer.write(st); + } +} + void Layout::check_links() { for(set::iterator i=tracks.begin(); i!=tracks.end(); ++i) @@ -157,7 +306,7 @@ void Layout::check_routes() break; ep = next->get_endpoint_by_link(*track); - if(next->get_type().get_n_paths()>1) + if(next->get_type().is_turnout()) { // Select correct path across the turnout, or break if we hit an unknown turnout map::const_iterator j = turnouts.find(next->get_turnout_id()); @@ -185,16 +334,19 @@ void Layout::check_routes() Layout::Loader::Loader(Layout &l): - DataFile::BasicLoader(l) + DataFile::BasicLoader(l), + new_tracks(false) { add("base", &Layout::base); add("route", &Loader::route); add("track", &Loader::track); + add("train", &Loader::train); } void Layout::Loader::finish() { - obj.check_links(); + if(new_tracks) + obj.check_links(); obj.check_routes(); for(set::iterator i=obj.tracks.begin(); i!=obj.tracks.end(); ++i) @@ -203,18 +355,21 @@ void Layout::Loader::finish() void Layout::Loader::route(const string &n) { - RefPtr rte = new Route(obj, n); + Route *rte = new Route(obj, n); load_sub(*rte); - obj.add_route(*rte.release()); } void Layout::Loader::track(unsigned art_nr) { - const TrackType &type = obj.catalogue.get_track(art_nr); - - RefPtr trk = new Track(type); + Track *trk = new Track(obj, obj.catalogue.get_track(art_nr)); load_sub(*trk); - obj.add_track(*trk.release()); + new_tracks = true; +} + +void Layout::Loader::train(unsigned art_nr, unsigned addr) +{ + Train *trn = new Train(obj, obj.catalogue.get_locomotive(art_nr), addr); + load_sub(*trn); } } // namespace Marklin diff --git a/source/libmarklin/layout.h b/source/libmarklin/layout.h index 86836b8..608ddec 100644 --- a/source/libmarklin/layout.h +++ b/source/libmarklin/layout.h @@ -1,33 +1,42 @@ /* $Id$ This file is part of the MSP Märklin suite -Copyright © 2006-2009 Mikkosoft Productions, Mikko Rasa +Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ #ifndef LIBMARKLIN_LAYOUT_H_ #define LIBMARKLIN_LAYOUT_H_ +#include #include #include -#include "route.h" -#include "track.h" +#include namespace Marklin { +class Block; class Catalogue; +class Driver; +class Route; +class Track; +class Train; class Layout { public: class Loader: public Msp::DataFile::BasicLoader { + private: + bool new_tracks; + public: Loader(Layout &); private: virtual void finish(); void route(const std::string &); void track(unsigned); + void train(unsigned, unsigned); }; public: @@ -35,27 +44,55 @@ public: sigc::signal signal_track_removed; sigc::signal signal_route_added; sigc::signal signal_route_removed; + sigc::signal signal_train_added; + sigc::signal signal_train_removed; + sigc::signal signal_block_reserved; private: Catalogue &catalogue; + Driver *driver; std::string base; std::set tracks; std::map routes; + std::set blocks; + std::map trains; + Msp::Time::TimeStamp last_tick; public: - Layout(Catalogue &); + Layout(Catalogue &, Driver * = 0); ~Layout(); Catalogue &get_catalogue() const { return catalogue; } + bool has_driver() const { return driver; } + Driver &get_driver() const; const std::string &get_base() const { return base; } - const std::set &get_tracks() const { return tracks; } + void add_track(Track &); + const std::set &get_tracks() const { return tracks; } void remove_track(Track &); + + void add_block(Block &); + Block &get_block(unsigned) const; + Block &get_block_by_track(const Track &) const; + const std::set &get_blocks() const { return blocks; } + void create_blocks(); + void create_blocks(const Track &); + void remove_block(Block &); + void add_route(Route &); const std::map &get_routes() const { return routes; } Route &get_route(const std::string &) const; void remove_route(Route &); + + void add_train(Train &); + Train &get_train(unsigned) const; + const std::map &get_trains() const { return trains; } + void remove_train(Train &); + + void tick(); + void save(const std::string &); + void save_trains(const std::string &); private: void check_links(); void check_routes(); diff --git a/source/libmarklin/locomotive.cpp b/source/libmarklin/locomotive.cpp deleted file mode 100644 index 5fe5ca5..0000000 --- a/source/libmarklin/locomotive.cpp +++ /dev/null @@ -1,152 +0,0 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2006-2009 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - -#include -#include -#include "command.h" -#include "constants.h" -#include "control.h" -#include "locomotive.h" -#include "locotype.h" -#include "reply.h" - -using namespace std; -using namespace Msp; - -namespace Marklin { - -Locomotive::Locomotive(const LocoType &t, Control &c, unsigned a): - type(t), - control(c), - addr(a), - speed(0), - reverse(false), - funcs(0) -{ - control.add_locomotive(*this); - - refresh_status(); -} - -void Locomotive::set_speed(unsigned spd) -{ - spd = min(spd, 14U); - if(spd==speed) - return; - signal_speed_changing.emit(spd); - - speed = spd; - send_command(false); - - signal_speed_changed.emit(speed); -} - -void Locomotive::set_reverse(bool rev) -{ - if(rev==reverse) - return; - - if(speed) - { - control.set_timer((500+speed*150)*Time::msec).signal_timeout.connect(sigc::mem_fun(this, &Locomotive::reverse_timeout)); - set_speed(0); - } - else - { - reverse = rev; - send_command(false); - signal_reverse_changed.emit(reverse); - } -} - -void Locomotive::set_function(unsigned func, bool state) -{ - if(state) - funcs |= 1<>8)&0xFF; - control.command(CMD_LOK_STATUS, data, 2).signal_done.connect(sigc::mem_fun(this, &Locomotive::status_reply)); -} - -void Locomotive::send_command(bool setf) -{ - unsigned char data[4]; - data[0] = addr&0xFF; - data[1] = (addr>>8)&0xFF; - - if(speed==0) - data[2] = 0; - else if(speed==1) - data[2] = 2; - else - data[2] = (speed*19-18)/2; - - data[3] = (reverse ? 0 : 0x20) | ((funcs&1) ? 0x10 : 0); - - if(setf) - { - data[3] |= 0x80; - for(unsigned i=0; i<4; ++i) - if((funcs>>i)&2) - data[3] |= (1<4) - { - if(!++data[0]) - ++data[1]; - data[2] = 0; - data[3] = 0xA0; - for(unsigned i=0; i<4; ++i) - if((funcs>>i)&32) - data[3] |= (1<>i)&1); - } -} - -bool Locomotive::reverse_timeout() -{ - reverse = !reverse; - send_command(true); - signal_reverse_changed.emit(reverse); - return false; -} - -} // namespace Marklin diff --git a/source/libmarklin/locomotive.h b/source/libmarklin/locomotive.h deleted file mode 100644 index 4a6770e..0000000 --- a/source/libmarklin/locomotive.h +++ /dev/null @@ -1,59 +0,0 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2006-2009 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - -#ifndef LIBMARKLIN_LOCOMOTIVE_H_ -#define LIBMARKLIN_LOCOMOTIVE_H_ - -#include -#include -#include -#include "constants.h" - -namespace Marklin { - -class Control; -class LocoType; -class Reply; - -class Locomotive -{ -public: - sigc::signal signal_speed_changing; - sigc::signal signal_speed_changed; - sigc::signal signal_reverse_changed; - sigc::signal signal_function_changed; - -private: - const LocoType &type; - Control &control; - unsigned addr; - unsigned speed; - bool reverse; - unsigned funcs; - -public: - Locomotive(const LocoType &, Control &, unsigned); - - const LocoType &get_type() const { return type; } - unsigned get_address() const { return addr; } - void set_speed(unsigned); - void set_reverse(bool); - void set_function(unsigned, bool); - 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); - void status_reply(const Reply &); - bool reverse_timeout(); -}; - -} // namespace Marklin - -#endif diff --git a/source/libmarklin/reply.cpp b/source/libmarklin/reply.cpp deleted file mode 100644 index 1d7d536..0000000 --- a/source/libmarklin/reply.cpp +++ /dev/null @@ -1,159 +0,0 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2006-2009 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - -#include -#include -#include -#include "constants.h" -#include "reply.h" - -using namespace std; -using namespace Msp; - -namespace { - -unsigned read_all(int fd, char *buf, unsigned size) -{ - unsigned pos = 0; - while(pos(result.data); - - if(cmd==CMD_EVENT) - { - for(unsigned i=0; i<3; ++i) - { - result.len += read_all(fd, data+i, 1); - if(!(result.data[i]&0x80)) - break; - } - } - else if(cmd==CMD_EVENT_LOK) - { - for(unsigned i=0;; i+=5) - { - result.len += read_all(fd, data+i, 1); - - if(result.data[i]&0x80) - break; - - result.len += read_all(fd, data+i+1, 4); - } - } - else if(cmd==CMD_EVENT_TURNOUT) - { - result.len += read_all(fd, data, 1); - result.len += read_all(fd, data+1, result.data[0]*2); - } - else if(cmd==CMD_EVENT_SENSOR) - { - for(unsigned i=0;; i+=3) - { - result.len += read_all(fd, data+i, 1); - - if(result.data[i]==0) - break; - - result.len += read_all(fd, data+i+1, 2); - } - } - else - { - bool expect_errcode = (cmd!=CMD_STATUS); - - unsigned expected_bytes = 0; - if(cmd==CMD_STATUS || cmd==CMD_FUNC_STATUS || cmd==CMD_TURNOUT_STATUS) - expected_bytes = 1; - if(cmd==CMD_SENSOR_STATUS || cmd==CMD_TURNOUT_GROUP_STATUS) - expected_bytes = 2; - if(cmd==CMD_LOK_STATUS) - expected_bytes = 3; - if(cmd==CMD_LOK_CONFIG) - expected_bytes = 4; - - if(expect_errcode) - { - char c; - read_all(fd, &c, 1); - result.err = static_cast(c); - } - - if(result.err==ERR_NO_ERROR) - result.len += read_all(fd, data, expected_bytes); - } - - return result; -} - -Reply Reply::simulate(Cmd cmd) -{ - Reply result; - - if(cmd==CMD_STATUS) - { - result.data[0] = 0x80; - result.len = 1; - } - if(cmd==CMD_EVENT) - result.len = 1; - else if(cmd==CMD_TURNOUT) - ; - else if(cmd==CMD_TURNOUT_STATUS) - { - result.data[0] = 0x04; - result.len = 1; - } - else if(cmd==CMD_LOK) - ; - else if(cmd==CMD_LOK_STATUS) - { - result.data[1] = 0x20; - result.len = 3; - } - else if(cmd==CMD_SENSOR_PARAM_SET) - ; - else if(cmd==CMD_SENSOR_REPORT) - ; - else if(cmd==CMD_POWER_ON) - ; - else if(cmd==CMD_POWER_OFF) - ; - else - result.err = ERR_SYS_ERROR; - - return result; -} - -ostream &operator<<(ostream &out, const Reply &reply) -{ - out<(reply.data[i])); - - return out; -} - -} // namespace Marklin diff --git a/source/libmarklin/reply.h b/source/libmarklin/reply.h deleted file mode 100644 index 1666490..0000000 --- a/source/libmarklin/reply.h +++ /dev/null @@ -1,37 +0,0 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2006-2009 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - -#ifndef LIBMARKLIN_REPLY_H_ -#define LIBMARKLIN_REPLY_H_ - -#include - -namespace Marklin { - -class Reply -{ -private: - Error err; - unsigned char data[128]; - unsigned len; - - Reply(); -public: - Error get_error() const { return err; } - const unsigned char *get_data() const { return data; } - - static Reply read(int, Cmd); - static Reply simulate(Cmd); - - friend std::ostream &operator<<(std::ostream &, const Reply &); -}; - - - -} // namespace Marklin - -#endif diff --git a/source/libmarklin/route.cpp b/source/libmarklin/route.cpp index 20017d2..7db3f32 100644 --- a/source/libmarklin/route.cpp +++ b/source/libmarklin/route.cpp @@ -1,7 +1,7 @@ /* $Id$ This file is part of the MSP Märklin suite -Copyright © 2007-2009 Mikkosoft Productions, Mikko Rasa +Copyright © 2007-2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ @@ -15,12 +15,19 @@ using namespace Msp; namespace Marklin { -Route::Route(Layout &layout, const string &n): +Route::Route(Layout &l, const string &n): + layout(l), name(n) { + layout.add_route(*this); layout.signal_track_removed.connect(sigc::mem_fun(this, &Route::track_removed)); } +Route::~Route() +{ + layout.remove_route(*this); +} + int Route::get_turnout(unsigned id) const { map::const_iterator i = turnouts.find(id); diff --git a/source/libmarklin/route.h b/source/libmarklin/route.h index bcb76e1..98b64f5 100644 --- a/source/libmarklin/route.h +++ b/source/libmarklin/route.h @@ -1,7 +1,7 @@ /* $Id$ This file is part of the MSP Märklin suite -Copyright © 2007-2009 Mikkosoft Productions, Mikko Rasa +Copyright © 2007-2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ @@ -11,15 +11,15 @@ Distributed under the GPL #include #include #include +#include #include namespace Marklin { class Layout; class Track; -class Turnout; -class Route +class Route: public sigc::trackable { public: class Loader: public Msp::DataFile::BasicLoader @@ -31,12 +31,14 @@ public: }; private: + Layout &layout; std::string name; std::set tracks; std::map turnouts; public: Route(Layout &, const std::string &); + ~Route(); const std::string &get_name() const { return name; } int get_turnout(unsigned) const; diff --git a/source/libmarklin/sensor.cpp b/source/libmarklin/sensor.cpp deleted file mode 100644 index 28f9548..0000000 --- a/source/libmarklin/sensor.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2007-2008 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - -#include -#include -#include "control.h" -#include "sensor.h" - -using namespace Msp; - -namespace Marklin { - -Sensor::Sensor(Control &c, unsigned a): - control(c), - addr(a), - state(false) -{ - control.add_sensor(*this); - control.signal_sensor_event.connect(sigc::mem_fun(this, &Sensor::sensor_event)); -} - -void Sensor::sensor_event(unsigned a, bool s) -{ - if(a==addr) - { - if(s) - { - off_timeout = Time::TimeStamp(); - if(s!=state) - { - state = s; - signal_state_changed.emit(state); - } - } - else - off_timeout = Time::now()+0.5*Time::sec; - } -} - -void Sensor::tick() -{ - if(off_timeout) - { - const Time::TimeStamp t = Time::now(); - if(t>off_timeout) - { - off_timeout = Time::TimeStamp(); - if(state) - { - state = false; - signal_state_changed.emit(state); - } - } - } -} - -} // namespace Marklin diff --git a/source/libmarklin/sensor.h b/source/libmarklin/sensor.h deleted file mode 100644 index 45749ea..0000000 --- a/source/libmarklin/sensor.h +++ /dev/null @@ -1,43 +0,0 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2007-2008 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - -#ifndef LIBMARKLIN_SENSOR_H_ -#define LIBMARKLIN_SENSOR_H_ - -#include -#include -#include -#include - -namespace Marklin { - -class Control; - -class Sensor -{ -public: - sigc::signal signal_state_changed; - -private: - Control &control; - unsigned addr; - bool state; - Msp::Time::TimeStamp off_timeout; - -public: - Sensor(Control &, unsigned); - - unsigned get_address() const { return addr; } - bool get_state() const { return state; } - void tick(); -private: - void sensor_event(unsigned, bool); -}; - -} // namespace Marklin - -#endif diff --git a/source/libmarklin/track.cpp b/source/libmarklin/track.cpp index 3c2a410..5843e22 100644 --- a/source/libmarklin/track.cpp +++ b/source/libmarklin/track.cpp @@ -1,11 +1,13 @@ /* $Id$ This file is part of the MSP Märklin suite -Copyright © 2006-2009 Mikkosoft Productions, Mikko Rasa +Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ #include +#include "driver.h" +#include "layout.h" #include "track.h" #include "tracktype.h" @@ -14,19 +16,27 @@ using namespace Msp; namespace Marklin { -Track::Track(const TrackType &t): +Track::Track(Layout &l, const TrackType &t): + layout(l), type(t), rot(0), slope(0), flex(false), turnout_id(0), sensor_id(0), - links(t.get_endpoints().size()) -{ } + links(t.get_endpoints().size()), + active_path(0) +{ + layout.add_track(*this); + + if(layout.has_driver()) + layout.get_driver().signal_turnout.connect(sigc::mem_fun(this, &Track::turnout_event)); +} Track::~Track() { break_links(); + layout.remove_track(*this); } void Track::set_position(const Point &p) @@ -85,12 +95,36 @@ void Track::check_slope() void Track::set_turnout_id(unsigned i) { + if(!type.is_turnout()) + throw InvalidState("Not a turnout"); + turnout_id = i; + layout.create_blocks(*this); + if(layout.has_driver() && turnout_id) + layout.get_driver().add_turnout(turnout_id); } void Track::set_sensor_id(unsigned i) { + if(type.is_turnout()) + throw InvalidState("Can't set sensor on a turnout"); + sensor_id = i; + layout.create_blocks(*this); + if(layout.has_driver() && sensor_id) + layout.get_driver().add_sensor(sensor_id); +} + +void Track::set_active_path(unsigned p) +{ + if(!turnout_id) + throw InvalidState("Not a turnout"); + if(!(type.get_paths()&(1<2) + layout.get_driver().set_turnout(turnout_id+1, p&2); } int Track::get_endpoint_by_link(const Track &other) const @@ -164,6 +198,7 @@ bool Track::snap_to(Track &other, bool link) break_link(*links[i]); links[i] = &other; other.links[j] = this; + layout.create_blocks(*this); } return true; @@ -201,6 +236,8 @@ void Track::break_link(Track &trk) { *i = 0; trk.break_link(*this); + // XXX Creates the blocks twice + layout.create_blocks(*this); return; } } @@ -324,17 +361,6 @@ Point Track::get_point(unsigned epi, unsigned path, float d) const } } -Track *Track::copy() const -{ - Track *trk = new Track(type); - trk->set_position(pos); - trk->set_rotation(rot); - trk->set_slope(slope); - trk->set_flex(flex); - - return trk; -} - void Track::save(list &st) const { st.push_back((DataFile::Statement("position"), pos.x, pos.y, pos.z)); @@ -348,6 +374,17 @@ void Track::save(list &st) const st.push_back((DataFile::Statement("flex"), true)); } +void Track::turnout_event(unsigned addr, bool state) +{ + if(!turnout_id) + return; + + if(addr==turnout_id) + active_path = (active_path&2) | (state ? 1 : 0); + else if(type.is_double_address() && addr==turnout_id+1) + active_path = (active_path&1) | (state ? 2 : 0); +} + Track::Loader::Loader(Track &t): DataFile::BasicLoader(t) @@ -355,8 +392,8 @@ Track::Loader::Loader(Track &t): add("position", &Loader::position); add("rotation", &Track::rot); add("slope", &Track::slope); - add("turnout_id", &Track::turnout_id); - add("sensor_id", &Track::sensor_id); + add("turnout_id", &Loader::turnout_id); + add("sensor_id", &Loader::sensor_id); add("flex", &Track::flex); } @@ -365,4 +402,14 @@ void Track::Loader::position(float x, float y, float z) obj.pos = Point(x, y, z); } +void Track::Loader::sensor_id(unsigned id) +{ + obj.set_sensor_id(id); +} + +void Track::Loader::turnout_id(unsigned id) +{ + obj.set_turnout_id(id); +} + } // namespace Marklin diff --git a/source/libmarklin/track.h b/source/libmarklin/track.h index 21c505f..7ef5119 100644 --- a/source/libmarklin/track.h +++ b/source/libmarklin/track.h @@ -1,7 +1,7 @@ /* $Id$ This file is part of the MSP Märklin suite -Copyright © 2006-2009 Mikkosoft Productions, Mikko Rasa +Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ @@ -10,14 +10,16 @@ Distributed under the GPL #include #include +#include #include #include "geometry.h" namespace Marklin { +class Layout; class TrackType; -class Track +class Track: public sigc::trackable { public: class Loader: public Msp::DataFile::BasicLoader @@ -26,9 +28,12 @@ public: Loader(Track &); private: void position(float, float, float); + void sensor_id(unsigned); + void turnout_id(unsigned); }; private: + Layout &layout; const TrackType &type; Point pos; float rot; @@ -37,12 +42,12 @@ private: unsigned turnout_id; unsigned sensor_id; std::vector links; + unsigned active_path; - // Direct copying not allowed due to links. See the copy() function. Track(const Track &); Track &operator=(const Track &); public: - Track(const TrackType &); + Track(Layout &, const TrackType &); ~Track(); const TrackType &get_type() const { return type; } @@ -61,6 +66,8 @@ public: void set_sensor_id(unsigned); unsigned get_turnout_id() const { return turnout_id; } unsigned get_sensor_id() const { return sensor_id; } + void set_active_path(unsigned); + unsigned get_active_path() const { return active_path; } int get_endpoint_by_link(const Track &) const; Point get_endpoint_position(unsigned) const; @@ -74,13 +81,9 @@ public: unsigned traverse(unsigned, unsigned) const; Point get_point(unsigned, unsigned, float) const; - /** - Creates a copy of the track. The new track will be almost identical, but - won't have any links to other tracks, nor a turnout or sensor id. - */ - Track *copy() const; - void save(std::list &) const; +private: + void turnout_event(unsigned, bool); }; } // namespace Marklin diff --git a/source/libmarklin/tracktype.cpp b/source/libmarklin/tracktype.cpp index c6757cb..5bbd40a 100644 --- a/source/libmarklin/tracktype.cpp +++ b/source/libmarklin/tracktype.cpp @@ -1,7 +1,7 @@ /* $Id$ This file is part of the MSP Märklin suite -Copyright © 2006-2009 Mikkosoft Productions, Mikko Rasa +Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ @@ -35,15 +35,32 @@ float TrackType::get_path_length(int p) const return len; } -unsigned TrackType::get_n_paths() const +unsigned TrackType::get_paths() const { - unsigned n = 1; + unsigned mask = 0; for(vector::const_iterator i=parts.begin(); i!=parts.end(); ++i) - if(i->path>=n) - n = i->path+1; + mask |= 1<path; + return mask; +} + +unsigned TrackType::get_n_paths() const +{ + unsigned n = 0; + for(unsigned mask = get_paths(); mask; ++n) + mask &= mask-1; return n; } +bool TrackType::is_turnout() const +{ + return endpoints.size()>2; +} + +bool TrackType::is_double_address() const +{ + return get_n_paths()>2; +} + void TrackType::collect_endpoints() { endpoints.clear(); diff --git a/source/libmarklin/tracktype.h b/source/libmarklin/tracktype.h index 45d8720..6f636e0 100644 --- a/source/libmarklin/tracktype.h +++ b/source/libmarklin/tracktype.h @@ -1,7 +1,7 @@ /* $Id$ This file is part of the MSP Märklin suite -Copyright © 2006-2009 Mikkosoft Productions, Mikko Rasa +Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ @@ -40,7 +40,10 @@ public: const std::string &get_description() const { return description; } float get_total_length() const; float get_path_length(int) const; + unsigned get_paths() const; unsigned get_n_paths() const; + bool is_turnout() const; + bool is_double_address() const; const std::vector &get_parts() const { return parts; } const std::vector &get_endpoints() const { return endpoints; } diff --git a/source/libmarklin/trafficmanager.cpp b/source/libmarklin/trafficmanager.cpp deleted file mode 100644 index 49dda42..0000000 --- a/source/libmarklin/trafficmanager.cpp +++ /dev/null @@ -1,145 +0,0 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2006-2009 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - -#include -#include -#include -#include "catalogue.h" -#include "control.h" -#include "layout.h" -#include "locotype.h" -#include "tracktype.h" -#include "trafficmanager.h" -#include "turnout.h" - -using namespace std; -using namespace Msp; - -namespace Marklin { - -TrafficManager::TrafficManager(Control &c, Layout &l): - control(c), - layout(l) -{ - const set &tracks = layout.get_tracks(); - - set used_tracks; - for(set::const_iterator i=tracks.begin(); i!=tracks.end(); ++i) - { - if(unsigned tid=(*i)->get_turnout_id()) - new Turnout(control, tid, (*i)->get_type().get_n_paths()>=3); - if(unsigned sid=(*i)->get_sensor_id()) - if(!control.get_sensors().count(sid)) - new Sensor(control, sid); - - if(used_tracks.count(*i)==0) - { - Block *block = new Block(*this, **i); - blocks.push_back(block); - used_tracks.insert(block->get_tracks().begin(), block->get_tracks().end()); - } - } - - for(list::iterator i=blocks.begin(); i!=blocks.end(); ++i) - for(list::iterator j=i; j!=blocks.end(); ++j) - if(j!=i) - (*i)->check_link(**j); -} - -TrafficManager::~TrafficManager() -{ - for(list::iterator i=blocks.begin(); i!=blocks.end(); ++i) - delete *i; - for(list::iterator i=trains.begin(); i!=trains.end(); ++i) - delete *i; -} - -Block &TrafficManager::get_block(unsigned id) const -{ - for(list::const_iterator i=blocks.begin(); i!=blocks.end(); ++i) - if((*i)->get_id()==id) - return **i; - - throw KeyError("Unknown block", lexical_cast(id)); -} - -Block &TrafficManager::get_block_by_track(const Track &t) const -{ - for(list::const_iterator i=blocks.begin(); i!=blocks.end(); ++i) - { - const set &tracks = (*i)->get_tracks(); - if(tracks.count(const_cast(&t))) - return **i; - } - - 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() -{ - Time::TimeStamp t = Time::now(); - Time::TimeDelta dt; - if(last_tick) - dt = t-last_tick; - last_tick = t; - - for(list::iterator i=trains.begin(); i!=trains.end(); ++i) - (*i)->tick(t, dt); -} - -void TrafficManager::save(const string &fn) const -{ - IO::BufferedFile out(fn, IO::M_WRITE); - DataFile::Writer writer(out); - for(list::const_iterator i=trains.begin(); i!=trains.end(); ++i) - { - const Locomotive &loco = (*i)->get_locomotive(); - DataFile::Statement st("train"); - st.append(loco.get_type().get_article_number()); - st.append(loco.get_address()); - (*i)->save(st.sub); - writer.write(st); - } -} - -void TrafficManager::turnout_path_changed(unsigned, Turnout *) -{ -} - - -TrafficManager::Loader::Loader(TrafficManager &tm): - DataFile::BasicLoader(tm) -{ - add("train", &Loader::train); -} - -void TrafficManager::Loader::train(unsigned art_nr, unsigned addr) -{ - Locomotive *loco = new Locomotive(obj.layout.get_catalogue().get_locomotive(art_nr), obj.control, addr); - Train *trn = new Train(obj, *loco); - load_sub(*trn); -} - -} // namespace Marklin diff --git a/source/libmarklin/trafficmanager.h b/source/libmarklin/trafficmanager.h deleted file mode 100644 index 266d2ff..0000000 --- a/source/libmarklin/trafficmanager.h +++ /dev/null @@ -1,61 +0,0 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2006-2009 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - -#ifndef LIBMARKLIN_TRAFFICMANAGER_H_ -#define LIBMARKLIN_TRAFFICMANAGER_H_ - -#include "block.h" -#include "train.h" - -namespace Marklin { - -class Control; -class Layout; -class Turnout; - -class TrafficManager -{ -public: - class Loader: public Msp::DataFile::BasicLoader - { - public: - Loader(TrafficManager &); - private: - void train(unsigned, unsigned); - }; - - sigc::signal signal_train_added; - sigc::signal signal_block_reserved; - -private: - Control &control; - Layout &layout; - std::list blocks; - std::list trains; - Msp::Time::TimeStamp last_tick; - -public: - TrafficManager(Control &, Layout &); - ~TrafficManager(); - - Control &get_control() const { return control; } - Layout &get_layout() const { return layout; } - const std::list &get_blocks() const { return blocks; } - Block &get_block(unsigned) const; - 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; -private: - void turnout_path_changed(unsigned, Turnout *); -}; - -} // namespace Marklin - -#endif diff --git a/source/libmarklin/train.cpp b/source/libmarklin/train.cpp index 56832c8..63a14e9 100644 --- a/source/libmarklin/train.cpp +++ b/source/libmarklin/train.cpp @@ -1,7 +1,7 @@ /* $Id$ This file is part of the MSP Märklin suite -Copyright © 2006-2009 Mikkosoft Productions, Mikko Rasa +Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ @@ -9,12 +9,11 @@ Distributed under the GPL #include #include #include -#include "control.h" -#include "except.h" +#include "driver.h" #include "layout.h" +#include "locotype.h" #include "route.h" #include "tracktype.h" -#include "trafficmanager.h" #include "train.h" using namespace std; @@ -22,11 +21,14 @@ using namespace Msp; namespace Marklin { -Train::Train(TrafficManager &tm, Locomotive &l): - trfc_mgr(tm), - loco(l), +Train::Train(Layout &l, const LocoType &t, unsigned a): + layout(l), + loco_type(t), + address(a), pending_block(0), target_speed(0), + current_speed(0), + reverse(false), route(0), status("Unplaced"), travel_dist(0), @@ -35,22 +37,20 @@ Train::Train(TrafficManager &tm, Locomotive &l): real_speed(15), cur_track(0) { - trfc_mgr.add_train(this); + layout.add_train(*this); - loco.signal_reverse_changed.connect(sigc::mem_fun(this, &Train::locomotive_reverse_changed)); + layout.get_driver().add_loco(address); + layout.get_driver().signal_loco_speed.connect(sigc::mem_fun(this, &Train::loco_speed_event)); + layout.get_driver().signal_loco_function.connect(sigc::mem_fun(this, &Train::loco_func_event)); - const map &sensors = trfc_mgr.get_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, &Train::sensor_event), i->second)); - - const map &turnouts = trfc_mgr.get_control().get_turnouts(); - for(map::const_iterator i=turnouts.begin(); i!=turnouts.end(); ++i) - { - i->second->signal_path_changing.connect(sigc::bind(sigc::mem_fun(this, &Train::turnout_path_changing), i->second)); - i->second->signal_path_changed.connect(sigc::bind(sigc::mem_fun(this, &Train::turnout_path_changed), i->second)); - } + layout.signal_block_reserved.connect(sigc::mem_fun(this, &Train::block_reserved)); + layout.get_driver().signal_sensor.connect(sigc::mem_fun(this, &Train::sensor_event)); + layout.get_driver().signal_turnout.connect(sigc::mem_fun(this, &Train::turnout_event)); +} - trfc_mgr.signal_block_reserved.connect(sigc::mem_fun(this, &Train::block_reserved)); +Train::~Train() +{ + layout.remove_train(*this); } void Train::set_name(const string &n) @@ -70,10 +70,7 @@ void Train::set_speed(unsigned speed) if(!target_speed) { pending_block = 0; - trfc_mgr.get_control().set_timer(3*Time::sec).signal_timeout.connect( - sigc::bind_return(sigc::bind( - sigc::mem_fun(this, static_cast &)>(&Train::release_blocks)), - sigc::ref(rsv_blocks)), false)); + stop_timeout = Time::now()+(800+current_speed*150)*Time::msec; } else reserve_more(); @@ -86,7 +83,43 @@ void Train::set_speed(unsigned speed) void Train::set_reverse(bool rev) { - loco.set_reverse(rev); + if(rev==reverse) + return; + + if(target_speed) + { + set_speed(0); + return; + } + else if(stop_timeout) + return; + + layout.get_driver().set_loco_reverse(address, rev); + + release_blocks(rsv_blocks); + reverse_blocks(cur_blocks); + + if(cur_track) + { + unsigned path = cur_track->get_active_path(); + cur_track_ep = cur_track->traverse(cur_track_ep, path); + offset = cur_track->get_type().get_path_length(path)-offset; + } +} + +void Train::set_function(unsigned func, bool state) +{ + if(!loco_type.get_functions().count(func)) + throw InvalidParameterValue("Invalid function"); + if(func<5) + layout.get_driver().set_loco_function(address, func, state); + else + layout.get_driver().set_loco_function(address+1, func-4, state); +} + +bool Train::get_function(unsigned func) const +{ + return (functions>>func)&1; } void Train::set_route(const Route *r) @@ -146,15 +179,19 @@ int Train::get_entry_to_block(Block &block) const return -1; } -void Train::tick(const Time::TimeStamp &, const Time::TimeDelta &dt) +void Train::tick(const Time::TimeStamp &t, const Time::TimeDelta &dt) { + if(stop_timeout && t>=stop_timeout) + { + release_blocks(rsv_blocks); + stop_timeout = Time::TimeStamp(); + } + if(cur_track) { - unsigned path = 0; - if(cur_track->get_turnout_id()) - path = trfc_mgr.get_control().get_turnout(cur_track->get_turnout_id()).get_path(); + unsigned path = cur_track->get_active_path(); - offset += get_real_speed(loco.get_speed())*(dt/Time::sec); + offset += get_real_speed(current_speed)*(dt/Time::sec); float path_len = cur_track->get_type().get_path_length(path); if(offset>path_len) { @@ -193,7 +230,7 @@ void Train::save(list &st) const if(!cur_blocks.empty()) { list blocks = cur_blocks; - if(loco.get_reverse()) + if(reverse) reverse_blocks(blocks); Block *prev = blocks.front().block->get_endpoints()[blocks.front().entry].link; @@ -204,26 +241,35 @@ void Train::save(list &st) const } } -void Train::locomotive_reverse_changed(bool) +void Train::loco_speed_event(unsigned addr, unsigned speed, bool rev) { - release_blocks(rsv_blocks); - reverse_blocks(cur_blocks); - reserve_more(); - - if(cur_track) + if(addr==address) { - unsigned path = 0; - if(unsigned turnout = cur_track->get_turnout_id()) - path = trfc_mgr.get_control().get_turnout(turnout).get_path(); - cur_track_ep = cur_track->traverse(cur_track_ep, path); - offset = cur_track->get_type().get_path_length(path)-offset; + current_speed = speed; + reverse = rev; + + signal_speed_changed.emit(current_speed); + signal_reverse_changed.emit(reverse); } } -void Train::sensor_event(bool state, Sensor *sensor) +void Train::loco_func_event(unsigned addr, unsigned func, bool state) { - unsigned addr = sensor->get_address(); + if(addr==address || (addr==address+1 && loco_type.get_max_function()>4)) + { + if(addr==address+1) + func += 4; + if(state) + functions |= 1<::iterator i=cur_blocks.begin(); i!=cur_blocks.end(); ++i) if(i->block->get_sensor_id()) { - if(trfc_mgr.get_control().get_sensor(i->block->get_sensor_id()).get_state()) + if(layout.get_driver().get_sensor(i->block->get_sensor_id())) break; else end = i; @@ -287,39 +333,9 @@ void Train::sensor_event(bool state, Sensor *sensor) } } -void Train::turnout_path_changing(unsigned, Turnout *turnout) -{ - unsigned tid = turnout->get_address(); - for(list::const_iterator i=cur_blocks.begin(); i!=cur_blocks.end(); ++i) - if(i->block->get_turnout_id()==tid) - throw TurnoutBusy(this); - - unsigned nsens = 0; - for(list::const_iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i) - { - if(i->block->get_turnout_id()==tid) - { - if(nsens<1) - throw TurnoutBusy(this); - break; - } - else if(i->block->get_sensor_id()) - ++nsens; - } -} - -void Train::turnout_path_changed(unsigned, Turnout *turnout) +void Train::turnout_event(unsigned addr, bool) { - unsigned tid = turnout->get_address(); - for(list::iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i) - if(i->block->get_turnout_id()==tid) - { - release_blocks(rsv_blocks, i, rsv_blocks.end()); - reserve_more(); - return; - } - - if(pending_block && tid==pending_block->get_turnout_id()) + if(pending_block && addr==pending_block->get_turnout_id()) reserve_more(); } @@ -385,14 +401,12 @@ unsigned Train::reserve_more() good = last; good_sens = nsens; - Turnout &turnout = trfc_mgr.get_control().get_turnout(link->get_turnout_id()); - // Figure out what path we'd like to take on the turnout int path = -1; if(route) path = route->get_turnout(link->get_turnout_id()); if(path<0) - path = turnout.get_path(); + path = ep.track->get_active_path(); if(!((track_ep.paths>>path)&1)) { for(unsigned i=0; track_ep.paths>>i; ++i) @@ -400,12 +414,12 @@ unsigned Train::reserve_more() path = i; } - if(path!=turnout.get_path()) + if(path!=static_cast(ep.track->get_active_path())) { // The turnout is set to wrong path - switch and wait for it link->reserve(0); pending_block = link; - turnout.set_path(path); + ep.track->set_active_path(path); break; } } @@ -436,9 +450,12 @@ unsigned Train::reserve_more() void Train::update_speed() { + Driver &driver = layout.get_driver(); + + unsigned speed; if(!target_speed) { - loco.set_speed(0); + speed = 0; set_status("Stopped"); } else @@ -451,22 +468,24 @@ void Train::update_speed() unsigned slow_speed = find_speed(0.1); // 31.3 km/h if(nsens==0) { - loco.set_speed(0); + speed = 0; pure_speed = false; set_status("Blocked"); } else if(nsens==1 && target_speed>slow_speed) { - loco.set_speed(slow_speed); + speed = slow_speed; pure_speed = false; set_status("Slow"); } else { - loco.set_speed(target_speed); + speed = target_speed; set_status(format("Traveling %d kmh", travel_speed)); } } + + driver.set_loco_speed(address, speed); } float Train::get_real_speed(unsigned i) const @@ -587,7 +606,7 @@ Train::Loader::Loader(Train &t): void Train::Loader::block(unsigned id) { - Block &blk = obj.trfc_mgr.get_block(id); + Block &blk = obj.layout.get_block(id); int entry = -1; if(prev_block) entry = blk.get_endpoint_by_link(*prev_block); @@ -604,7 +623,7 @@ void Train::Loader::block(unsigned id) void Train::Loader::block_hint(unsigned id) { - prev_block = &obj.trfc_mgr.get_block(id); + prev_block = &obj.layout.get_block(id); } void Train::Loader::name(const string &n) @@ -620,7 +639,7 @@ void Train::Loader::real_speed(unsigned i, float speed, float weight) void Train::Loader::route(const string &n) { - obj.set_route(&obj.trfc_mgr.get_layout().get_route(n)); + obj.set_route(&obj.layout.get_route(n)); } } // namespace Marklin diff --git a/source/libmarklin/train.h b/source/libmarklin/train.h index 530d020..60a0c08 100644 --- a/source/libmarklin/train.h +++ b/source/libmarklin/train.h @@ -1,7 +1,7 @@ /* $Id$ This file is part of the MSP Märklin suite -Copyright © 2006-2009 Mikkosoft Productions, Mikko Rasa +Copyright © 2006-2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ @@ -15,11 +15,8 @@ Distributed under the GPL namespace Marklin { -class Locomotive; +class LocoType; class Route; -class Sensor; -class TrafficManager; -class Turnout; class Train: public sigc::trackable { @@ -41,6 +38,9 @@ public: sigc::signal signal_name_changed; sigc::signal signal_target_speed_changed; + sigc::signal signal_speed_changed; + sigc::signal signal_reverse_changed; + sigc::signal signal_function_changed; sigc::signal signal_route_changed; sigc::signal signal_status_changed; @@ -62,13 +62,18 @@ private: void add(float, float); }; - TrafficManager &trfc_mgr; + Layout &layout; + const LocoType &loco_type; + unsigned address; std::string name; - Locomotive &loco; std::list cur_blocks; std::list rsv_blocks; Block *pending_block; unsigned target_speed; + unsigned current_speed; + bool reverse; + Msp::Time::TimeStamp stop_timeout; + unsigned functions; const Route *route; std::string status; @@ -84,29 +89,41 @@ private: Point pos; public: - Train(TrafficManager &, Locomotive &); + Train(Layout &, const LocoType &, unsigned); + ~Train(); + const LocoType &get_locomotive_type() const { return loco_type; } + unsigned get_address() const { return address; } void set_name(const std::string &); + const std::string &get_name() const { return name; } + void set_speed(unsigned); void set_reverse(bool); - void set_route(const Route *); - const std::string &get_name() const { return name; } - Locomotive &get_locomotive() const { return loco; } + void set_function(unsigned, bool); unsigned get_target_speed() const { return target_speed; } + unsigned get_speed() const { return current_speed; } + bool get_reverse() const { return reverse; } + bool get_function(unsigned) const; + unsigned get_functions() const { return functions; } + + void set_route(const Route *); const Route *get_route() const { return route; } - const std::string &get_status() const { return status; } - const Point &get_position() const { return pos; } void place(Block &, unsigned); bool is_placed() const { return !cur_blocks.empty(); } bool free_block(Block &); int get_entry_to_block(Block &) const; + + const std::string &get_status() const { return status; } + const Point &get_position() const { return pos; } + void tick(const Msp::Time::TimeStamp &, const Msp::Time::TimeDelta &); + void save(std::list &) const; private: - void locomotive_reverse_changed(bool); - void sensor_event(bool, Sensor *); - void turnout_path_changing(unsigned, Turnout *); - void turnout_path_changed(unsigned, Turnout *); + void loco_speed_event(unsigned, unsigned, bool); + void loco_func_event(unsigned, unsigned, bool); + void sensor_event(unsigned, bool); + void turnout_event(unsigned, bool); void block_reserved(const Block &, const Train *); unsigned reserve_more(); void update_speed(); diff --git a/source/libmarklin/turnout.cpp b/source/libmarklin/turnout.cpp deleted file mode 100644 index c022e05..0000000 --- a/source/libmarklin/turnout.cpp +++ /dev/null @@ -1,121 +0,0 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2006-2009 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - -#include -#include -#include "command.h" -#include "control.h" -#include "reply.h" -#include "turnout.h" - -using namespace std; -using namespace Msp; - -namespace Marklin { - -Turnout::Turnout(Control &c, unsigned a, bool d): - control(c), - addr(a), - path(0), - pending_path(0), - pending_cmds(0), - dual(d), - on(false) -{ - control.add_turnout(*this); - - control.signal_turnout_event.connect(sigc::mem_fun(this, &Turnout::turnout_event)); - - unsigned char data[2]; - data[0] = addr&0xFF; - data[1] = (addr>>8)&0xFF; - control.command(CMD_TURNOUT_STATUS, data, 2).signal_done.connect(sigc::bind(sigc::mem_fun(this, &Turnout::status_reply), 1)); - if(dual) - { - data[0] = (addr+1)&0xFF; - data[1] = ((addr+1)>>8)&0xFF; - control.command(CMD_TURNOUT_STATUS, data, 2).signal_done.connect(sigc::bind(sigc::mem_fun(this, &Turnout::status_reply), 2)); - } -} - -void Turnout::set_path(unsigned char p) -{ - if(path==p || pending_cmds) - return; - - signal_path_changing.emit(p); - - pending_path = p; - on = true; - command(3); -} - -void Turnout::command(unsigned char mask) -{ - unsigned char data[2]; - if(mask&1) - { - data[0] = addr&0xFF; - data[1] = ((addr>>8)&0x7) | (on ? 0x40 : 0) | (pending_path&1 ? 0 : 0x80); - control.command(CMD_TURNOUT, data, 2).signal_done.connect(sigc::bind(sigc::mem_fun(this, &Turnout::command_reply), 1)); - pending_cmds |= 1; - } - if(dual && (mask&2)) - { - data[0] = (addr+1)&0xFF; - data[1] = (((addr+1)>>8)&0x7) | (on ? 0x40 : 0) | (pending_path&2 ? 0 : 0x80); - control.command(CMD_TURNOUT, data, 2).signal_done.connect(sigc::bind(sigc::mem_fun(this, &Turnout::command_reply), 2)); - pending_cmds |= 2; - } -} - -void Turnout::command_reply(const Reply &reply, unsigned char bit) -{ - pending_cmds &= ~bit; - if(reply.get_error()==ERR_NO_ERROR) - { - if(on && !pending_cmds) - { - path = pending_path; - on = false; - control.set_timer(500*Time::msec).signal_timeout.connect( - sigc::bind_return(sigc::bind(sigc::mem_fun(this, &Turnout::command), 3), false)); - signal_path_changed.emit(path); - } - } - else if(reply.get_error()==ERR_NO_I2C_SPACE) - { - control.set_timer(100*Time::msec).signal_timeout.connect( - sigc::bind_return(sigc::bind(sigc::mem_fun(this, &Turnout::command), bit), false)); - } -} - -void Turnout::status_reply(const Reply &reply, unsigned char bit) -{ - if(reply.get_error()==ERR_NO_ERROR) - { - bool v = !(reply.get_data()[0]&0x04); - path = (path&~bit)|(v?bit:0); - signal_path_changed.emit(path); - } -} - -void Turnout::turnout_event(unsigned a, bool p) -{ - if(a==addr && p!=(path&1)) - { - path = (path&2)|(p?1:0); - signal_path_changed.emit(path); - } - else if(dual && a==addr+1 && p!=((path>>1)&1)) - { - path = (path&1)|(p?2:0); - signal_path_changed.emit(path); - } -} - -} // namespace Marklin diff --git a/source/libmarklin/turnout.h b/source/libmarklin/turnout.h deleted file mode 100644 index c7a603c..0000000 --- a/source/libmarklin/turnout.h +++ /dev/null @@ -1,52 +0,0 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2006-2009 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - -#ifndef LIBMARKLIN_TURNOUT_H_ -#define LIBMARKLIN_TURNOUT_H_ - -#include -#include -#include -#include -#include "constants.h" - -namespace Marklin { - -class Control; -class Reply; - -class Turnout -{ -public: - sigc::signal signal_path_changing; - sigc::signal signal_path_changed; - -private: - Control &control; - unsigned addr; - unsigned char path; - unsigned char pending_path; - unsigned char pending_cmds; - bool dual; - bool on; - -public: - Turnout(Control &, unsigned, bool =false); - - void set_path(unsigned char); - unsigned get_address() const { return addr; } - unsigned char get_path() const { return path; } -private: - void command(unsigned char); - void command_reply(const Reply &, unsigned char); - void status_reply(const Reply &, unsigned char); - void turnout_event(unsigned, bool); -}; - -} // namespace Marklin - -#endif diff --git a/source/network/server.cpp b/source/network/server.cpp index 044b310..2e3248f 100644 --- a/source/network/server.cpp +++ b/source/network/server.cpp @@ -1,16 +1,14 @@ /* $Id$ This file is part of the MSP Märklin suite -Copyright © 2009 Mikkosoft Productions, Mikko Rasa +Copyright © 2009-2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ #include -#include "libmarklin/control.h" -#include "libmarklin/layout.h" -#include "libmarklin/locomotive.h" #include "libmarklin/locotype.h" #include "libmarklin/route.h" +#include "libmarklin/train.h" #include "server.h" using namespace std; @@ -18,14 +16,16 @@ using namespace Msp; namespace Marklin { -Server::Server(TrafficManager &tm): - trfc_mgr(tm), +Server::Server(Layout &l): + layout(l), 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) - train_added(**i); + layout.signal_train_added.connect(sigc::mem_fun(this, &Server::train_added)); + + const map &trains = layout.get_trains(); + for(map::const_iterator i=trains.begin(); i!=trains.end(); ++i) + train_added(*i->second); listen_sock.listen(Net::InetAddr(0, 8315), 4); listen_sock.signal_data_available.connect(sigc::mem_fun(this, &Server::incoming_connection)); @@ -47,16 +47,15 @@ void Server::incoming_connection() 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_reverse_changed.connect(sigc::bind<0>(sigc::mem_fun(this, &Server::train_reverse_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_reverse_changed.connect(sigc::bind<0>(sigc::mem_fun(this, &Server::train_reverse_changed), sigc::ref(train))); + train.signal_function_changed.connect(sigc::bind<0>(sigc::mem_fun(this, &Server::train_function_changed), sigc::ref(train))); train.signal_route_changed.connect(sigc::bind<0>(sigc::mem_fun(this, &Server::train_route_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.address = train.get_address(); + pkt.loco_type = train.get_locomotive_type().get_article_number(); pkt.name = train.get_name(); send(pkt); } @@ -64,16 +63,16 @@ void Server::train_added(Train &train) void Server::train_speed_changed(const Train &train, unsigned speed) { TrainSpeedPacket pkt; - pkt.address = train.get_locomotive().get_address(); + pkt.address = train.get_address(); pkt.speed = speed; - pkt.reverse = train.get_locomotive().get_reverse(); + pkt.reverse = train.get_reverse(); send(pkt); } void Server::train_reverse_changed(const Train &train, bool reverse) { TrainSpeedPacket pkt; - pkt.address = train.get_locomotive().get_address(); + pkt.address = train.get_address(); pkt.speed = train.get_target_speed(); pkt.reverse = reverse; send(pkt); @@ -82,15 +81,15 @@ void Server::train_reverse_changed(const Train &train, bool reverse) 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(); + pkt.address = train.get_address(); + pkt.functions = train.get_functions(); send(pkt); } void Server::train_route_changed(const Train &train, const Route *route) { TrainRoutePacket pkt; - pkt.address = train.get_locomotive().get_address(); + pkt.address = train.get_address(); if(route) pkt.route = route->get_name(); send(pkt); @@ -99,7 +98,7 @@ void Server::train_route_changed(const Train &train, const Route *route) void Server::train_status_changed(const Train &train, const string &status) { TrainStatusPacket pkt; - pkt.address = train.get_locomotive().get_address(); + pkt.address = train.get_address(); pkt.status = status; send(pkt); } @@ -130,7 +129,7 @@ Server::Connection::~Connection() void Server::Connection::handshake_done() { - const map &routes = server.trfc_mgr.get_layout().get_routes(); + const map &routes = server.layout.get_routes(); for(map::const_iterator i=routes.begin(); i!=routes.end(); ++i) { RouteInfoPacket pkt; @@ -138,42 +137,42 @@ void Server::Connection::handshake_done() comm.send(pkt); } - const list &trains = server.trfc_mgr.get_trains(); - for(list::const_iterator i=trains.begin(); i!=trains.end(); ++i) + const map &trains = server.layout.get_trains(); + for(map::const_iterator i=trains.begin(); i!=trains.end(); ++i) { - Locomotive &loco = (*i)->get_locomotive(); + const Train &train = *i->second; { TrainInfoPacket pkt; - pkt.address = loco.get_address(); - pkt.loco_type = loco.get_type().get_article_number(); - pkt.name = (*i)->get_name(); + pkt.address = train.get_address(); + pkt.loco_type = train.get_locomotive_type().get_article_number(); + pkt.name = train.get_name(); comm.send(pkt); } { TrainSpeedPacket pkt; - pkt.address = loco.get_address(); - pkt.speed = (*i)->get_target_speed(); - pkt.reverse = loco.get_reverse(); + pkt.address = train.get_address(); + pkt.speed = train.get_target_speed(); + pkt.reverse = train.get_reverse(); comm.send(pkt); } { TrainFunctionPacket pkt; - pkt.address = loco.get_address(); - pkt.functions = loco.get_functions(); + pkt.address = train.get_address(); + pkt.functions = train.get_functions(); comm.send(pkt); } { TrainStatusPacket pkt; - pkt.address = loco.get_address(); - pkt.status = (*i)->get_status(); + pkt.address = train.get_address(); + pkt.status = train.get_status(); comm.send(pkt); } - if((*i)->get_route()) + if(train.get_route()) { TrainRoutePacket pkt; - pkt.address = loco.get_address(); - pkt.route = (*i)->get_route()->get_name(); + pkt.address = train.get_address(); + pkt.route = train.get_route()->get_name(); comm.send(pkt); } } @@ -189,9 +188,8 @@ void Server::Connection::receive(const TrainSpeedPacket &pkt) { try { - 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 &train = server.layout.get_train(pkt.address); + if(pkt.reverse!=train.get_reverse()) train.set_reverse(pkt.reverse); else train.set_speed(pkt.speed); @@ -206,10 +204,10 @@ void Server::Connection::receive(const TrainFunctionPacket &pkt) { try { - Locomotive &loco = server.trfc_mgr.get_control().get_locomotive(pkt.address); + Train &train = server.layout.get_train(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); + if(((pkt.functions^train.get_functions())>>i)&1) + train.set_function(i, (pkt.functions>>i)&1); } catch(const Exception &e) { @@ -221,13 +219,12 @@ void Server::Connection::receive(const TrainRoutePacket &pkt) { try { - Locomotive &loco = server.trfc_mgr.get_control().get_locomotive(pkt.address); - Train &train = server.trfc_mgr.get_train_by_locomotive(loco); + Train &train = server.layout.get_train(pkt.address); if(pkt.route.empty()) train.set_route(0); else { - Route &route = server.trfc_mgr.get_layout().get_route(pkt.route); + Route &route = server.layout.get_route(pkt.route); train.set_route(&route); } } diff --git a/source/network/server.h b/source/network/server.h index 7c3dce9..41bb8e9 100644 --- a/source/network/server.h +++ b/source/network/server.h @@ -1,7 +1,7 @@ /* $Id$ This file is part of the MSP Märklin suite -Copyright © 2009 Mikkosoft Productions, Mikko Rasa +Copyright © 2009-2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ @@ -12,7 +12,7 @@ Distributed under the GPL #include #include #include -#include "libmarklin/trafficmanager.h" +#include "libmarklin/layout.h" #include "packets.h" #include "protocol.h" @@ -42,13 +42,13 @@ private: }; Protocol proto; - TrafficManager &trfc_mgr; + Layout &layout; Msp::Net::StreamListenSocket listen_sock; Msp::IO::EventDispatcher *event_disp; std::vector connections; public: - Server(TrafficManager &); + Server(Layout &); void use_event_dispatcher(Msp::IO::EventDispatcher &); private: void incoming_connection(); diff --git a/tracks.dat b/tracks.dat index 7c800f1..dafc85b 100644 --- a/tracks.dat +++ b/tracks.dat @@ -231,20 +231,20 @@ track 24671 part { length 77.5; - path 0; + path 1; }; part { start 77.5 0 0; length 30; radius 360; - path 0; + path 1; }; part { length 30; radius 360; - path 1; + path 0; }; }; @@ -254,20 +254,20 @@ track 24672 part { length 77.5; - path 0; + path 1; }; part { start 77.5 0 0; length 30; radius -360; - path 0; + path 1; }; part { length 30; radius -360; - path 1; + path 0; }; }; @@ -279,13 +279,13 @@ track 24611 part { length 188.3; - path 0; + path 1; }; part { length 24.3; radius 437.5; - path 1; + path 0; }; }; @@ -295,13 +295,13 @@ track 24612 part { length 188.3; - path 0; + path 1; }; part { length 24.3; radius -437.5; - path 1; + path 0; }; }; @@ -311,19 +311,19 @@ track 24630 part { length 188.3; - path 0; + path 3; }; part { length 24.3; radius 437.5; - path 1; + path 2; }; part { length 24.3; radius -437.5; - path 2; + path 1; }; }; @@ -333,26 +333,26 @@ track 24624 part { length 188.3; - path 0; + path 3; }; part { length 24.3; radius -437.5; - path 1; + path 2; }; part { start 8.34 38.74 -24.3; length 188.3; - path 2; + path 1; }; part { start 8.34 38.74 -24.3; length 24.3; radius 437.5; - path 3; + path 0; }; }; @@ -364,13 +364,13 @@ track 24711 part { length 236.1; - path 0; + path 1; }; part { length 12.1; radius 1114.6; - path 1; + path 0; }; }; @@ -380,13 +380,13 @@ track 24712 part { length 236.1; - path 0; + path 1; }; part { length 12.1; radius -1114.6; - path 1; + path 0; }; }; -- 2.45.2