]> git.tdb.fi Git - r2c2.git/commitdiff
Major architecture rework
authorMikko Rasa <tdb@tdb.fi>
Mon, 8 Mar 2010 21:53:29 +0000 (21:53 +0000)
committerMikko Rasa <tdb@tdb.fi>
Mon, 8 Mar 2010 21:53:29 +0000 (21:53 +0000)
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

51 files changed:
source/3d/layout.cpp
source/3d/layout.h
source/designer/designer.cpp
source/designer/manipulator.cpp
source/designer/toolbar.cpp
source/engineer/engineer.cpp
source/engineer/engineer.h
source/engineer/mainpanel.cpp
source/engineer/options.cpp [new file with mode: 0644]
source/engineer/options.h [new file with mode: 0644]
source/engineer/trainpanel.cpp
source/engineer/trainpanel.h
source/engineer/trainproperties.cpp
source/libmarklin/block.cpp
source/libmarklin/block.h
source/libmarklin/command.cpp [deleted file]
source/libmarklin/command.h [deleted file]
source/libmarklin/constants.cpp [deleted file]
source/libmarklin/constants.h [deleted file]
source/libmarklin/control.cpp [deleted file]
source/libmarklin/control.h [deleted file]
source/libmarklin/driver.cpp [new file with mode: 0644]
source/libmarklin/driver.h [new file with mode: 0644]
source/libmarklin/dummy.cpp [new file with mode: 0644]
source/libmarklin/dummy.h [new file with mode: 0644]
source/libmarklin/except.h [deleted file]
source/libmarklin/intellibox.cpp [new file with mode: 0644]
source/libmarklin/intellibox.h [new file with mode: 0644]
source/libmarklin/layout.cpp
source/libmarklin/layout.h
source/libmarklin/locomotive.cpp [deleted file]
source/libmarklin/locomotive.h [deleted file]
source/libmarklin/reply.cpp [deleted file]
source/libmarklin/reply.h [deleted file]
source/libmarklin/route.cpp
source/libmarklin/route.h
source/libmarklin/sensor.cpp [deleted file]
source/libmarklin/sensor.h [deleted file]
source/libmarklin/track.cpp
source/libmarklin/track.h
source/libmarklin/tracktype.cpp
source/libmarklin/tracktype.h
source/libmarklin/trafficmanager.cpp [deleted file]
source/libmarklin/trafficmanager.h [deleted file]
source/libmarklin/train.cpp
source/libmarklin/train.h
source/libmarklin/turnout.cpp [deleted file]
source/libmarklin/turnout.h [deleted file]
source/network/server.cpp
source/network/server.h
tracks.dat

index 8ea58bf8454661be87d7e731903411c8d35b3986..1a557153fda308ce56a18066e281ca2e3e1b8830 100644 (file)
@@ -13,7 +13,6 @@ Distributed under the GPL
 #include <msp/gl/select.h>
 #include <msp/gl/texture.h>
 #include <msp/datafile/parser.h>
-#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<Track *> &ltracks = layout.get_tracks();
        for(set<Track *>::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);
index 2e56ea63bd0195ea8ede83b3219f6f8dde1392f3..ba590dd37e2d8482d5180138f2ab6f663a7a6554 100644 (file)
@@ -8,6 +8,7 @@ Distributed under the GPL
 #ifndef MARKLIN3D_LAYOUT_H_
 #define MARKLIN3D_LAYOUT_H_
 
+#include <sigc++/trackable.h>
 #include <msp/gl/scene.h>
 #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;
index 9e99a1d99d4b20c7e91ebf9e6db49bb5d4232db4..b0971c25271be9d65390ff08ca5841614e7c84b6 100644 (file)
@@ -25,6 +25,7 @@ Distributed under the GPL
 #include <msp/strings/utils.h>
 #include <msp/time/units.h>
 #include <msp/time/utils.h>
+#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<Track *>::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<int>((*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);
index e690c1d43aa34bf242361a0e485d49117a4b4574..dfcdd2cccbdc859a08c4cf6326aba090bf2e1696 100644 (file)
@@ -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<Track *> new_tracks;
        for(vector<MTrack>::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)
index c4a674d1031e740e6563a19816666f33badf18e5..36b4882a00a7878730ff850589b2e695333d0683 100644 (file)
@@ -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 <msp/gltk/button.h>
 #include <msp/strings/formatter.h>
+#include "libmarklin/route.h"
 #include "designer.h"
 #include "toolbar.h"
 
index 87a4d6d3afa6c4a75f424ce804e4c3b49491e3e4..e62cd2bab7cd7c1b27d3bc745413b8c2637d17d9 100644 (file)
@@ -9,24 +9,19 @@ Distributed under the GPL
 #include <limits>
 #include <signal.h>
 #include <msp/core/except.h>
-#include <msp/core/getopt.h>
 #include <msp/fs/stat.h>
 #include <msp/gbase/display.h>
 #include <msp/gbase/window.h>
 #include <msp/gl/blend.h>
 #include <msp/gl/framebuffer.h>
-#include <msp/gl/immediate.h>
 #include <msp/gl/matrix.h>
 #include <msp/gl/misc.h>
-#include <msp/gl/projection.h>
 #include <msp/gl/tests.h>
 #include <msp/gl/transform.h>
 #include <msp/io/print.h>
 #include <msp/strings/formatter.h>
-#include <msp/strings/lexicalcast.h>
-#include <msp/strings/regex.h>
 #include <msp/time/units.h>
-#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<string> &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<unsigned>(m[1].str);
-                       screen_h = lexical_cast<unsigned>(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<unsigned, Sensor *> &sensors = control.get_sensors();
-       for(map<unsigned, Sensor *>::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<Train *> &trains = trfc_mgr->get_trains();
-       for(list<Train *>::const_iterator i=trains.begin(); i!=trains.end(); ++i)
-               (*i)->set_speed(0);
-
-       while(control.get_queue_length())
-               control.tick();
+       const map<unsigned, Train *> &trains = layout.get_trains();
+       for(map<unsigned, Train *>::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<Train *>::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)))
+                                       {
+                                               if(!(paths>>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<Track3D *> &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<Block *> &blocks = trfc_mgr->get_blocks();
-       for(list<Block *>::const_iterator i=blocks.begin(); i!=blocks.end(); ++i)
-               if((*i)->get_sensor_id()==sensor->get_address())
+       const set<Block *> &blocks = layout.get_blocks();
+       for(set<Block *>::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<unsigned, Locomotive *> &locos = control.get_locomotives();
-               for(map<unsigned, Locomotive *>::const_iterator i=locos.begin(); i!=locos.end(); ++i)
+               const map<unsigned, Train *> &trains = layout.get_trains();
+               for(map<unsigned, Train *>::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)
index 3e7a9109b7523ea6cba7b6dfb5a0d546048ef34e..5fa05871973e302872b589589df060b3c29680d3 100644 (file)
@@ -17,13 +17,11 @@ Distributed under the GPL
 #include <msp/gltk/resources.h>
 #include <msp/gltk/root.h>
 #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 &);
index 8c3718b9176fa025bcda7087633cf8357a10522e..197c1a4bc9cbbe970605fb988800b7159eb78cf8 100644 (file)
@@ -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 <msp/gltk/button.h>
+#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 (file)
index 0000000..9861c10
--- /dev/null
@@ -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 <msp/core/getopt.h>
+#include <msp/strings/lexicalcast.h>
+#include <msp/strings/regex.h>
+#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<unsigned>(m[1].str);
+                       screen_h = lexical_cast<unsigned>(m[2].str);
+               }
+               else
+                       throw UsageError("Invalid resolution");
+       }
+
+       const vector<string> &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 (file)
index 0000000..e842c25
--- /dev/null
@@ -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 <string>
+
+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
index 339f4eca669f7e9d4337dd25ab674c4937a260c7..24a182b05c9328caca4efc318c14b7d309831ebc 100644 (file)
@@ -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 <msp/gltk/button.h>
 #include <msp/strings/formatter.h>
-#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<unsigned, string> &funcs = train.get_locomotive().get_type().get_functions();
+       const map<unsigned, string> &funcs = train.get_locomotive_type().get_functions();
        unsigned x = 10;
        for(map<unsigned, string>::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<unsigned, GLtk::Toggle *>::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);
 }
index 7b929856b840e6ff04e6eede5d338986f91f0332..c8825af0120a5d8a98865c41fff7292ea1ba7259 100644 (file)
@@ -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();
index 004747cdd1224456ecf0493e1d175e64823160ed..8780dc4ab1cd66c8ead2a755d0cdd307ba29243e 100644 (file)
@@ -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 <msp/gltk/label.h>
 #include <msp/strings/formatter.h>
 #include <msp/strings/lexicalcast.h>
+#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<unsigned, LocoType *>::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<unsigned>(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);
        }
 
index a29469c4fd9b97e32751987e3c42ac6f903b078e..51f8ddb0dfe45dbd954f994ba75b1c82f759e290 100644 (file)
@@ -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 <algorithm>
-#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<endpoints.size(); ++i)
        {
@@ -60,6 +55,20 @@ Block::Block(TrafficManager &tm, Track &start):
                set<Track *> visited;
                find_paths(*endpoints[i].track, endpoints[i].track_ep, path, visited);
        }
+
+       layout.add_block(*this);
+}
+
+Block::~Block()
+{
+       for(vector<Endpoint>::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<id1)
-                       swap(id1, id2);
-               id = (id1<<16)|id2;
-       }
+void Block::break_link(Block &other)
+{
+       for(vector<Endpoint>::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, set<Track
        }
 }
 
+void Block::determine_id()
+{
+       if(sensor_id)
+               id = 0x1000|sensor_id;
+       else if(turnout_id)
+               id = 0x2000|turnout_id;
+       else if(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<id1)
+                       swap(id1, id2);
+               id = (id1<<16)|id2;
+       }
+}
+
 
 Block::Endpoint::Endpoint(Track *t, unsigned e):
        track(t),
index b72215ae03d1608092fd0c41943fdea7b7abeb54..abcd87cd9b02221edba66d33955eca56abe8c7ad 100644 (file)
@@ -1,12 +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
 */
 
-#ifndef MARKLIN_3D_BLOCK_H_
-#define MARKLIN_3D_BLOCK_H_
+#ifndef LIBMARKLIN_BLOCK_H_
+#define LIBMARKLIN_BLOCK_H_
 
 #include <list>
 #include <set>
@@ -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<Track *> tracks;
        std::vector<Endpoint> 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<Track *> &);
+       void determine_id();
 };
 
 } // namespace Marklin
diff --git a/source/libmarklin/command.cpp b/source/libmarklin/command.cpp
deleted file mode 100644 (file)
index dd1cdbc..0000000
+++ /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 <cstring>
-#include <msp/strings/formatter.h>
-#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.cmd;
-       for(unsigned i=1; i<cmd.len; ++i)
-               out<<format(" %02X", static_cast<int>(cmd.data[i]));
-
-       return out;
-}
-
-} // namespace Marklin
diff --git a/source/libmarklin/command.h b/source/libmarklin/command.h
deleted file mode 100644 (file)
index e6123c3..0000000
+++ /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 <ostream>
-#include <string>
-#include <sigc++/sigc++.h>
-#include "constants.h"
-
-namespace Marklin {
-
-class Reply;
-
-class Command
-{
-public:
-       sigc::signal<void, const Reply &> 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 (file)
index e6f5946..0000000
+++ /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("<<static_cast<int>(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("<<static_cast<int>(cmd)<<')'; break;
-       }
-
-       return out;
-}
-
-} // namespace Marklin
diff --git a/source/libmarklin/constants.h b/source/libmarklin/constants.h
deleted file mode 100644 (file)
index f68737d..0000000
+++ /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 <ostream>
-
-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 (file)
index ae26a17..0000000
+++ /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 <fcntl.h>
-#include <termios.h>
-#include <sys/poll.h>
-#include <msp/core/except.h>
-#include <msp/io/print.h>
-#include <msp/time/units.h>
-#include <msp/time/utils.h>
-#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<unsigned, Sensor *>::iterator i=sensors.begin(); i!=sensors.end(); ++i)
-               delete i->second;
-       for(map<unsigned, Turnout *>::iterator i=turnouts.begin(); i!=turnouts.end(); ++i)
-               delete i->second;
-       for(map<unsigned, Locomotive *>::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<Command>::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<unsigned, Turnout *>::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<unsigned, Locomotive *>::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<unsigned, Sensor *>::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<unsigned, Sensor *>::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<count; ++i)
-       {
-               unsigned addr = (data[i*2+1])+((data[i*2+2]&7)<<8);
-               bool status = !(data[i*2+2]&0x80);
-               IO::print("Turnout %d, status %d\n", addr, status);
-               signal_turnout_event.emit(addr, status);
-       }
-}
-
-void Control::sensor_event_done(const Reply &reply)
-{
-       const unsigned char *data = reply.get_data();
-       for(unsigned i=0; data[i]; i+=3)
-       {
-               unsigned module = data[i];
-
-               IO::print("S88 module %d, status %08b%08b\n", module, data[1], data[2]);
-
-               for(unsigned j=0; j<16; ++j)
-                       signal_sensor_event.emit(module*16+j-15, (data[i+1+j/8]>>(7-j%8))&1);
-       }
-}
-
-} // namespace Marklin
diff --git a/source/libmarklin/control.h b/source/libmarklin/control.h
deleted file mode 100644 (file)
index a041e95..0000000
+++ /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 <list>
-#include <string>
-#include <msp/time/timer.h>
-#include <msp/time/timestamp.h>
-#include "constants.h"
-#include "sensor.h"
-#include "locomotive.h"
-#include "turnout.h"
-
-namespace Marklin {
-
-class Command;
-class Reply;
-
-class Control
-{
-public:
-       sigc::signal<void, bool> signal_power_event;
-       sigc::signal<void, unsigned, bool> signal_turnout_event;
-       sigc::signal<void, unsigned, bool> signal_sensor_event;
-
-private:
-       int serial_fd;
-       bool power;
-       std::list<Command> queue;
-       std::map<unsigned, Turnout *> turnouts;
-       std::map<unsigned, Locomotive *> locomotives;
-       std::map<unsigned, Sensor *> 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<unsigned, Turnout *> &get_turnouts() const { return turnouts; }
-       void add_locomotive(Locomotive &);
-       Locomotive &get_locomotive(unsigned) const;
-       const std::map<unsigned, Locomotive *> &get_locomotives() const { return locomotives; }
-       void add_sensor(Sensor &);
-       Sensor &get_sensor(unsigned) const;
-       const std::map<unsigned, Sensor *> &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 (file)
index 0000000..3bec54e
--- /dev/null
@@ -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 <msp/core/except.h>
+#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 (file)
index 0000000..1a5084d
--- /dev/null
@@ -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 <string>
+#include <sigc++/signal.h>
+
+namespace Marklin {
+
+class Driver
+{
+public:
+       sigc::signal<void, bool> signal_power;
+       sigc::signal<void, unsigned, unsigned, bool> signal_loco_speed;
+       sigc::signal<void, unsigned, unsigned, bool> signal_loco_function;
+       sigc::signal<void, unsigned, bool> signal_turnout;
+       sigc::signal<void, unsigned, bool> 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 (file)
index 0000000..1a7dd36
--- /dev/null
@@ -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<unsigned, bool>::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 (file)
index 0000000..96b62a8
--- /dev/null
@@ -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 <map>
+#include "driver.h"
+
+namespace Marklin {
+
+class Dummy: public Driver
+{
+private:
+       bool power;
+       std::map<unsigned, bool> 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 (file)
index 85fe431..0000000
+++ /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 <msp/core/except.h>
-
-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 (file)
index 0000000..3588061
--- /dev/null
@@ -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 <fcntl.h>
+#include <termios.h>
+#include <sys/poll.h>
+#include <msp/io/print.h>
+#include <msp/time/units.h>
+#include <msp/time/utils.h>
+#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<<func;
+       else
+               loco.funcs &= ~(1<<func);
+       loco_command(addr, loco.speed, loco.reverse, loco.funcs);
+       signal_loco_function.emit(addr, func, state);
+}
+
+void Intellibox::add_turnout(unsigned addr)
+{
+       if(!turnouts.count(addr))
+       {
+               turnouts[addr];
+
+               unsigned char data[2];
+               data[0] = addr&0xFF;
+               data[1] = (addr>>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<unsigned, Turnout>::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<unsigned, Sensor>::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<unsigned, Turnout>::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<unsigned, Sensor>::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<CommandSlot>::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<count; ++i)
+               {
+                       unsigned char data[2];
+                       read_all(data, 2);
+
+                       unsigned addr = data[0]+((data[1]&7)<<8);
+                       signal_turnout.emit(addr, (data[1]&0x80)!=0);
+               }
+       }
+       else if(cmd==CMD_EVENT_SENSOR)
+       {
+               while(1)
+               {
+                       unsigned char mod;
+                       read_all(&mod, 1);
+                       if(!mod)
+                               break;
+
+                       unsigned char data[2];
+                       read_all(data, 2);
+                       for(unsigned i=0; i<16; ++i)
+                       {
+                               unsigned addr = mod*16+i-15;
+                               bool state = (data[i/8]>>(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<<i))
+                                               signal_loco_function.emit(addr, i, loco.funcs&(1<<i));
+                       }
+               }
+       }
+       else
+       {
+               unsigned expected_bytes = 0;
+               if(cmd==CMD_FUNC_STATUS)
+                       expected_bytes = 1;
+               if(cmd==CMD_TURNOUT_GROUP_STATUS)
+                       expected_bytes = 2;
+               if(cmd==CMD_LOK_CONFIG)
+                       expected_bytes = 4;
+
+               unsigned char err;
+               read_all(&err, 1);
+
+               if(err==ERR_NO_ERROR)
+               {
+                       unsigned char data[8];
+                       read_all(data, expected_bytes);
+               }
+       }
+}
+
+unsigned Intellibox::read_all(unsigned char *buf, unsigned len)
+{
+       unsigned pos = 0;
+       while(pos<len)
+               pos += read(serial_fd, buf+pos, len-pos);
+
+       return pos;
+}
+
+
+Intellibox::Locomotive::Locomotive():
+       speed(0),
+       reverse(false),
+       funcs(0)
+{ }
+
+
+Intellibox::Turnout::Turnout():
+       state(false),
+       active(false)
+{ }
+
+
+Intellibox::Sensor::Sensor():
+       state(false)
+{ }
+
+} // namespace Marklin
diff --git a/source/libmarklin/intellibox.h b/source/libmarklin/intellibox.h
new file mode 100644 (file)
index 0000000..9f42aa2
--- /dev/null
@@ -0,0 +1,142 @@
+/* $Id$
+
+This file is part of the MSP Märklin suite
+Copyright © 2010  Mikkosoft Productions, Mikko Rasa
+Distributed under the GPL
+*/
+
+#ifndef LIBMARKLIN_INTELLIBOX_H_
+#define LIBMARKLIN_INTELLIBOX_H_
+
+#include <map>
+#include <msp/time/timestamp.h>
+#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<unsigned, Locomotive> locos;
+       std::map<unsigned, Turnout> turnouts;
+       std::map<unsigned, Sensor> sensors;
+       bool update_sensors;
+       std::list<CommandSlot> 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
index b61522ba4d59bfdc2d45344f3487aa912d7d694b..c0930352fb7d2b171f7279a55c0dd1fddffc454b 100644 (file)
 /* $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 <algorithm>
 #include <msp/core/refptr.h>
 #include <msp/datafile/parser.h>
 #include <msp/datafile/writer.h>
+#include <msp/time/utils.h>
+#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<Track *>::iterator i=tracks.begin(); i!=tracks.end(); ++i)
-               delete *i;
-       for(map<string, Route *>::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<Block *>::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<Block *>::const_iterator i=blocks.begin(); i!=blocks.end(); ++i)
+               if((*i)->get_tracks().count(const_cast<Track *>(&t)))
+                       return **i;
+
+       throw InvalidParameterValue("No block found for track");
+}
+
+void Layout::create_blocks()
+{
+       set<Track *> used_tracks;
+       for(set<Block *>::const_iterator i=blocks.begin(); i!=blocks.end(); ++i)
+       {
+               const set<Track *> &btracks = (*i)->get_tracks();
+               used_tracks.insert(btracks.begin(), btracks.end());
+       }
+
+       for(set<Track *>::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<Block *>::iterator i=blocks.begin(); i!=blocks.end(); ++i)
+               for(set<Block *>::iterator j=i; j!=blocks.end(); ++j)
+                       if(j!=i)
+                               (*i)->check_link(**j);
+}
+
+void Layout::create_blocks(const Track &track)
+{
+       const vector<Track *> &links = track.get_links();
+       for(set<Block *>::iterator i=blocks.begin(); i!=blocks.end();)
+       {
+               bool del = (*i)->get_tracks().count(const_cast<Track *>(&track));
+               for(vector<Track *>::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<unsigned, Train *>::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<unsigned, Train *>::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<unsigned, Train *>::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<Track *>::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<unsigned, int>::const_iterator j = turnouts.find(next->get_turnout_id());
@@ -185,16 +334,19 @@ void Layout::check_routes()
 
 
 Layout::Loader::Loader(Layout &l):
-       DataFile::BasicLoader<Layout>(l)
+       DataFile::BasicLoader<Layout>(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<Track *>::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<Route> 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<Track> 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
index 86836b87f16e01fe7cbcba495fd08ab514ae553d..608ddece1eed1c2398fc36b101d2b0d6fb0c5063 100644 (file)
@@ -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 <set>
 #include <sigc++/sigc++.h>
 #include <msp/datafile/loader.h>
-#include "route.h"
-#include "track.h"
+#include <msp/time/timestamp.h>
 
 namespace Marklin {
 
+class Block;
 class Catalogue;
+class Driver;
+class Route;
+class Track;
+class Train;
 
 class Layout
 {
 public:
        class Loader: public Msp::DataFile::BasicLoader<Layout>
        {
+       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<void, Track &> signal_track_removed;
        sigc::signal<void, Route &> signal_route_added;
        sigc::signal<void, Route &> signal_route_removed;
+       sigc::signal<void, Train &> signal_train_added;
+       sigc::signal<void, Train &> signal_train_removed;
+       sigc::signal<void, Block &, Train *> signal_block_reserved;
 
 private:
        Catalogue &catalogue;
+       Driver *driver;
        std::string base;
        std::set<Track *> tracks;
        std::map<std::string, Route *> routes;
+       std::set<Block *> blocks;
+       std::map<unsigned, Train *> 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<Track *> &get_tracks() const { return tracks; }
+
        void add_track(Track &);
+       const std::set<Track *> &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<Block *> &get_blocks() const { return blocks; }
+       void create_blocks();
+       void create_blocks(const Track &);
+       void remove_block(Block &);
+
        void add_route(Route &);
        const std::map<std::string, Route *> &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<unsigned, Train *> &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 (file)
index 5fe5ca5..0000000
+++ /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 <msp/time/timer.h>
-#include <msp/time/units.h>
-#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<<func;
-       else
-               funcs &= ~(1<<func);
-
-       send_command(true);
-
-       signal_function_changed.emit(func, state);
-}
-
-void Locomotive::refresh_status()
-{
-       unsigned char data[2];
-       data[0] = addr&0xFF;
-       data[1] = (addr>>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<<i);
-       }
-       control.command(CMD_LOK, data, 4);
-
-       if(setf && type.get_max_function()>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);
-               control.command(CMD_LOK, data, 4);
-       }
-}
-
-void Locomotive::status_reply(const Reply &reply)
-{
-       if(reply.get_error()==ERR_NO_ERROR)
-       {
-               const unsigned char *data = reply.get_data();
-
-               if(data[0]<=1)
-                       speed = 0;
-               else
-                       speed = data[0]*2/19+1;
-
-               reverse = (data[1]&0x20) ? false : true;
-               funcs = (data[1]&0xF)<<1;
-               if(data[1]&0x10)
-                       funcs |= 1;
-
-               for(unsigned i=0; i<5; ++i)
-                       signal_function_changed.emit(i, (funcs>>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 (file)
index 4a6770e..0000000
+++ /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 <list>
-#include <string>
-#include <sigc++/signal.h>
-#include "constants.h"
-
-namespace Marklin {
-
-class Control;
-class LocoType;
-class Reply;
-
-class Locomotive
-{
-public:
-       sigc::signal<void, unsigned> signal_speed_changing;
-       sigc::signal<void, unsigned> signal_speed_changed;
-       sigc::signal<void, bool> signal_reverse_changed;
-       sigc::signal<void, unsigned, bool> 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 (file)
index 1d7d536..0000000
+++ /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 <cstring>
-#include <unistd.h>
-#include <msp/strings/formatter.h>
-#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<size)
-               pos += read(fd, buf+pos, size-pos);
-
-       return pos;
-}
-
-}
-
-namespace Marklin {
-
-Reply::Reply():
-       err(ERR_NO_ERROR),
-       len(0)
-{
-       memset(data, 0, 128);
-}
-
-Reply Reply::read(int fd, Cmd cmd)
-{
-       Reply result;
-
-       char *data = reinterpret_cast<char *>(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<Error>(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.err;
-       for(unsigned i=0; i<reply.len; ++i)
-               out<<format(" %02X", static_cast<int>(reply.data[i]));
-
-       return out;
-}
-
-} // namespace Marklin
diff --git a/source/libmarklin/reply.h b/source/libmarklin/reply.h
deleted file mode 100644 (file)
index 1666490..0000000
+++ /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 <ostream>
-
-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
index 20017d240a429562a1e7e3907999eb40c2a2ebb6..7db3f324b61e9ce5d753786aac251982cff6ec90 100644 (file)
@@ -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<unsigned, int>::const_iterator i = turnouts.find(id);
index bcb76e143635fa4b0180f24e698dfee292509bef..98b64f5c9ff11e9411bb987f8ad4d5877ab8bd3c 100644 (file)
@@ -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 <map>
 #include <set>
 #include <string>
+#include <sigc++/trackable.h>
 #include <msp/datafile/loader.h>
 
 namespace Marklin {
 
 class Layout;
 class Track;
-class Turnout;
 
-class Route
+class Route: public sigc::trackable
 {
 public:
        class Loader: public Msp::DataFile::BasicLoader<Route>
@@ -31,12 +31,14 @@ public:
        };
 
 private:
+       Layout &layout;
        std::string name;
        std::set<const Track *> tracks;
        std::map<unsigned, int> 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 (file)
index 28f9548..0000000
+++ /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 <msp/time/utils.h>
-#include <msp/time/units.h>
-#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 (file)
index 45749ea..0000000
+++ /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 <list>
-#include <map>
-#include <sigc++/signal.h>
-#include <msp/time/timestamp.h>
-
-namespace Marklin {
-
-class Control;
-
-class Sensor
-{
-public:
-       sigc::signal<void, bool> 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
index 3c2a410fa9d55bf2ab131985a76f7ea4266d4f1c..5843e22f017953474588c956ca73798fcbf4b4be 100644 (file)
@@ -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 <cmath>
+#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<<p)))
+               throw InvalidParameterValue("Invalid path");
+
+       layout.get_driver().set_turnout(turnout_id, p&1);
+       if(type.get_n_paths()>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<DataFile::Statement> &st) const
 {
        st.push_back((DataFile::Statement("position"), pos.x, pos.y, pos.z));
@@ -348,6 +374,17 @@ void Track::save(list<DataFile::Statement> &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<Track>(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
index 21c505fb9ae12c180ed955e632aab989d0684b03..7ef511919986adefcff8fd4eec5627e16db5dad6 100644 (file)
@@ -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 <list>
 #include <set>
+#include <sigc++/trackable.h>
 #include <msp/datafile/loader.h>
 #include "geometry.h"
 
 namespace Marklin {
 
+class Layout;
 class TrackType;
 
-class Track
+class Track: public sigc::trackable
 {
 public:
        class Loader: public Msp::DataFile::BasicLoader<Track>
@@ -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<Track *> 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<Msp::DataFile::Statement> &) const;
+private:
+       void turnout_event(unsigned, bool);
 };
 
 } // namespace Marklin
index c6757cb221b12b9a206bdf6b0295f13fb835c789..5bbd40a411e07632e161dbb9d1a44a099dfeb41e 100644 (file)
@@ -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<TrackPart>::const_iterator i=parts.begin(); i!=parts.end(); ++i)
-               if(i->path>=n)
-                       n = i->path+1;
+               mask |= 1<<i->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();
index 45d8720bd4ae02da8d72f5fc299063017e8302ff..6f636e0c7cfea62e4c13aa50236810745246229e 100644 (file)
@@ -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<TrackPart> &get_parts() const { return parts; }
        const std::vector<Endpoint> &get_endpoints() const { return endpoints; }
 
diff --git a/source/libmarklin/trafficmanager.cpp b/source/libmarklin/trafficmanager.cpp
deleted file mode 100644 (file)
index 49dda42..0000000
+++ /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 <algorithm>
-#include <msp/datafile/writer.h>
-#include <msp/time/utils.h>
-#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<Track *> &tracks = layout.get_tracks();
-
-       set<Track *> used_tracks;
-       for(set<Track *>::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<Block *>::iterator i=blocks.begin(); i!=blocks.end(); ++i)
-               for(list<Block *>::iterator j=i; j!=blocks.end(); ++j)
-                       if(j!=i)
-                               (*i)->check_link(**j);
-}
-
-TrafficManager::~TrafficManager()
-{
-       for(list<Block *>::iterator i=blocks.begin(); i!=blocks.end(); ++i)
-               delete *i;
-       for(list<Train *>::iterator i=trains.begin(); i!=trains.end(); ++i)
-               delete *i;
-}
-
-Block &TrafficManager::get_block(unsigned id) const
-{
-       for(list<Block *>::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<Block *>::const_iterator i=blocks.begin(); i!=blocks.end(); ++i)
-       {
-               const set<Track *> &tracks = (*i)->get_tracks();
-               if(tracks.count(const_cast<Track *>(&t)))
-                       return **i;
-       }
-
-       throw InvalidParameterValue("Unknown track");
-}
-
-Train &TrafficManager::get_train_by_locomotive(const Locomotive &loco) const
-{
-       for(list<Train *>::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<Train *>::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<Train *>::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<TrafficManager>(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 (file)
index 266d2ff..0000000
+++ /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<TrafficManager>
-       {
-       public:
-               Loader(TrafficManager &);
-       private:
-               void train(unsigned, unsigned);
-       };
-
-       sigc::signal<void, Train &> signal_train_added;
-       sigc::signal<void, const Block &, const Train *> signal_block_reserved;
-
-private:
-       Control &control;
-       Layout &layout;
-       std::list<Block *> blocks;
-       std::list<Train *> 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<Block *> &get_blocks() const { return blocks; }
-       Block &get_block(unsigned) const;
-       Block &get_block_by_track(const Track &) const;
-       const std::list<Train *> &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
index 56832c837542d9447acb3022a8d655e1a8786939..63a14e991c9e814a525ce43139ccc9366d42ea64 100644 (file)
@@ -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 <msp/strings/formatter.h>
 #include <msp/time/units.h>
 #include <msp/time/utils.h>
-#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<unsigned, Sensor *> &sensors = trfc_mgr.get_control().get_sensors();
-       for(map<unsigned, Sensor *>::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<unsigned, Turnout *> &turnouts = trfc_mgr.get_control().get_turnouts();
-       for(map<unsigned, Turnout *>::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<void (Train::*)(list<BlockRef> &)>(&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<DataFile::Statement> &st) const
        if(!cur_blocks.empty())
        {
                list<BlockRef> 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<DataFile::Statement> &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<<func;
+               else
+                       functions &= ~(1<<func);
 
+               signal_function_changed.emit(func, state);
+       }
+}
+
+void Train::sensor_event(unsigned addr, bool state)
+{
        if(state)
        {
                // Find the first sensor block from our reserved blocks that isn't this sensor
@@ -240,7 +286,7 @@ void Train::sensor_event(bool state, Sensor *sensor)
 
                        if(pure_speed)
                        {
-                               RealSpeed &rs = real_speed[loco.get_speed()];
+                               RealSpeed &rs = real_speed[current_speed];
                                rs.add(travel_dist/travel_time_secs, travel_time_secs);
                        }
 
@@ -272,7 +318,7 @@ void Train::sensor_event(bool state, Sensor *sensor)
                for(list<BlockRef>::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<BlockRef>::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<BlockRef>::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<BlockRef>::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<int>(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
index 530d0209015a6217165d5fe4217637a239aae024..60a0c0824ade3030e52497ee0ec6a19b4f79f679 100644 (file)
@@ -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<void, const std::string &> signal_name_changed;
        sigc::signal<void, unsigned> signal_target_speed_changed;
+       sigc::signal<void, unsigned> signal_speed_changed;
+       sigc::signal<void, bool> signal_reverse_changed;
+       sigc::signal<void, unsigned, bool> signal_function_changed;
        sigc::signal<void, const Route *> signal_route_changed;
        sigc::signal<void, const std::string &> 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<BlockRef> cur_blocks;
        std::list<BlockRef> 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<Msp::DataFile::Statement> &) 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 (file)
index c022e05..0000000
+++ /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 <msp/time/timer.h>
-#include <msp/time/units.h>
-#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 (file)
index c7a603c..0000000
+++ /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 <list>
-#include <map>
-#include <string>
-#include <sigc++/sigc++.h>
-#include "constants.h"
-
-namespace Marklin {
-
-class Control;
-class Reply;
-
-class Turnout
-{
-public:
-       sigc::signal<void, unsigned> signal_path_changing;
-       sigc::signal<void, unsigned> 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
index 044b310bda43cb77948a8d17cd8149f219b1983e..2e3248f28878bf0a7000d874895c69d2675f3056 100644 (file)
@@ -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 <msp/net/inet.h>
-#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<Train *> &trains = trfc_mgr.get_trains();
-       for(list<Train *>::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<unsigned, Train *> &trains = layout.get_trains();
+       for(map<unsigned, Train *>::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<string, Route *> &routes = server.trfc_mgr.get_layout().get_routes();
+       const map<string, Route *> &routes = server.layout.get_routes();
        for(map<string, Route *>::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<Train *> &trains = server.trfc_mgr.get_trains();
-       for(list<Train *>::const_iterator i=trains.begin(); i!=trains.end(); ++i)
+       const map<unsigned, Train *> &trains = server.layout.get_trains();
+       for(map<unsigned, Train *>::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);
                }
        }
index 7c3dce959c300e9fbb1226e3797b0bd02b60cdd2..41bb8e9b50bc9765767efa7ae5a1c09868e66d13 100644 (file)
@@ -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 <msp/net/communicator.h>
 #include <msp/net/streamsocket.h>
 #include <msp/net/streamlistensocket.h>
-#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<Connection *> connections;
 
 public:
-       Server(TrafficManager &);
+       Server(Layout &);
        void use_event_dispatcher(Msp::IO::EventDispatcher &);
 private:
        void incoming_connection();
index 7c800f11310f07a39817b2587b946aefc759df31..dafc85ba0dae18a7ddf22e42107b7c9d6a8bf8dd 100644 (file)
@@ -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;
        };
 };