]> git.tdb.fi Git - r2c2.git/commitdiff
Foundations of using physics simulation for trains
authorMikko Rasa <tdb@tdb.fi>
Mon, 12 Apr 2010 20:49:54 +0000 (20:49 +0000)
committerMikko Rasa <tdb@tdb.fi>
Mon, 12 Apr 2010 20:49:54 +0000 (20:49 +0000)
30 files changed:
locos.dat
source/engineer/engineer.cpp
source/engineer/trainpanel.cpp
source/engineer/trainpanel.h
source/libmarklin/aicontrol.cpp [new file with mode: 0644]
source/libmarklin/aicontrol.h [new file with mode: 0644]
source/libmarklin/controlmodel.h [new file with mode: 0644]
source/libmarklin/simplephysics.cpp [new file with mode: 0644]
source/libmarklin/simplephysics.h [new file with mode: 0644]
source/libmarklin/track.cpp
source/libmarklin/track.h
source/libmarklin/train.cpp
source/libmarklin/train.h
source/libmarklin/traincontrol.cpp [new file with mode: 0644]
source/libmarklin/traincontrol.h [new file with mode: 0644]
source/libmarklin/vehicle.h
source/network/client.cpp
source/network/client.h
source/network/packets.h
source/network/protocol.cpp
source/network/server.cpp
source/network/server.h
source/network/train.cpp
source/network/train.h
source/remote/remote.cpp
source/remote/remote.h
source/remote/trainpanel.cpp
source/remote/trainpanel.h
source/serial/serial.cpp
source/serial/serial.h

index e2f57565e7218bf0de6b411928a769d201603eea..3c045babdab914f35c51a559139077bca09ef19d 100644 (file)
--- a/locos.dat
+++ b/locos.dat
@@ -1,5 +1,8 @@
 /* $Id$ */
 
+scale 1 87;
+gauge 16.5;
+
 locomotive 37844
 {
        name "BR 50";
index d1a123bb7b5e44282e7045da291309a67a8dc91c..92f0f0f419e451c98676597f9954b216c0717b42 100644 (file)
@@ -114,7 +114,7 @@ Engineer::~Engineer()
 {
        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().set_loco_speed(i->first, 0);
        layout.get_driver().flush();
 
        if(!options.simulate)
@@ -433,7 +433,7 @@ void Engineer::sighandler(int sig)
                IO::print(IO::cerr, "Fatal signal received, terminating\n");
                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().set_loco_speed(i->first, 0);
                layout.get_driver().flush();
                raise(sig);
        }
index dce1387f58540c604e3b8b45c4e661ace7d523a6..1fd4abe527084209f68df5cf19db6c15cabfe868 100644 (file)
@@ -5,6 +5,7 @@ Copyright © 2006-2010  Mikkosoft Productions, Mikko Rasa
 Distributed under the GPL
 */
 
+#include <cmath>
 #include <msp/gltk/button.h>
 #include <msp/strings/formatter.h>
 #include "libmarklin/locotype.h"
@@ -25,6 +26,8 @@ TrainPanel::TrainPanel(Engineer &e, const GLtk::Resources &r, Train &t):
 {
        set_size(200, 170);
 
+       train.signal_control_changed.connect(sigc::mem_fun(this, &TrainPanel::train_control_changed));
+
        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,23 +37,21 @@ 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_speed()))));
+       add(*(lbl_speed=new GLtk::Label(res, "  0")));
        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));
 
        add(*(sld_speed=new GLtk::HSlider(res)));
        sld_speed->set_geometry(GLtk::Geometry(50, geom.h-51, geom.w-80, 10));
-       sld_speed->set_range(0, 14);
-       sld_speed->set_step(1);
+       sld_speed->set_range(0, 200);
+       sld_speed->set_step(5);
        sld_speed->signal_value_changed.connect(sigc::mem_fun(this, &TrainPanel::speed_slider_changed));
 
        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_reverse());
+       tgl_forward->set_value(true);
        tgl_forward->signal_toggled.connect(sigc::mem_fun(this, &TrainPanel::forward_toggled));
-       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"))));
@@ -99,20 +100,24 @@ TrainPanel::TrainPanel(Engineer &e, const GLtk::Resources &r, Train &t):
        btn->signal_clicked.connect(sigc::mem_fun(this, &TrainPanel::route_clicked));
 }
 
-void TrainPanel::speed_slider_changed(double v)
-{
-       train.set_speed(static_cast<unsigned>(v));
-}
-
-void TrainPanel::train_speed_changed(unsigned speed)
+void TrainPanel::speed_slider_changed(double value)
 {
-       lbl_speed->set_text(format("%2d", speed));
-       sld_speed->set_value(speed);
+       float speed = value/3.6*engineer.get_layout().get_catalogue().get_scale();
+       if(!tgl_forward->get_value())
+               speed = -speed;
+       train.set_control("speed", speed);
 }
 
-void TrainPanel::train_reverse_changed(bool reverse)
+void TrainPanel::train_control_changed(const string &control, float value)
 {
-       tgl_forward->set_value(!reverse);
+       if(control=="speed")
+       {
+               float speed = abs(value)/engineer.get_layout().get_catalogue().get_scale()*3.6;
+               sld_speed->set_value(speed);
+               lbl_speed->set_text(format("%03.0f", speed));
+               if(value)
+                       tgl_forward->set_value(value>0);
+       }
 }
 
 void TrainPanel::train_function_changed(unsigned func, bool value)
@@ -163,9 +168,9 @@ void TrainPanel::goto_clicked()
        pick_conn = engineer.signal_pick_done.connect(sigc::mem_fun(this, &TrainPanel::go_to));
 }
 
-void TrainPanel::forward_toggled(bool value)
+void TrainPanel::forward_toggled(bool /*value*/)
 {
-       train.set_reverse(!value);
+       train.set_control("speed", 0);
 }
 
 void TrainPanel::func_toggled(bool value, unsigned func)
index b4bd386896af3aa07c3a467fb7dfe155442e9b8e..12aa8fc835a8e1c5d9d355459e23be5aea0ae8ee 100644 (file)
@@ -37,8 +37,7 @@ public:
        TrainPanel(Engineer &, const Msp::GLtk::Resources &, Marklin::Train &);
 private:
        void speed_slider_changed(double);
-       void train_speed_changed(unsigned);
-       void train_reverse_changed(bool);
+       void train_control_changed(const std::string &, float);
        void train_function_changed(unsigned, bool);
        void train_route_changed(const Marklin::Route *);
        void train_status_changed(const std::string &);
diff --git a/source/libmarklin/aicontrol.cpp b/source/libmarklin/aicontrol.cpp
new file mode 100644 (file)
index 0000000..ae47d41
--- /dev/null
@@ -0,0 +1,94 @@
+/* $Id$
+
+This file is part of the MSP Märklin suite
+Copyright © 2010  Mikkosoft Productions, Mikko Rasa
+Distributed under the GPL
+*/
+
+#include "aicontrol.h"
+#include "catalogue.h"
+#include "layout.h"
+#include "train.h"
+
+using namespace std;
+using namespace Msp;
+
+namespace Marklin {
+
+AIControl::AIControl(Train &t, ControlModel *n):
+       train(t),
+       next_model(n),
+       target_speed(TrainControl::continuous("speed", -1000, 1000)),
+       blocked(false)
+{
+       target_speed.set(0);
+
+       train.signal_arrived.connect(sigc::mem_fun(this, &AIControl::arrived));
+}
+
+AIControl::~AIControl()
+{
+       delete next_model;
+}
+
+void AIControl::set_control(const string &n, float v)
+{
+       if(n=="speed")
+       {
+               if(v && !train.is_active())
+                       train.set_active(true);
+
+               target_speed.set(v);
+               if(!blocked)
+                       next_model->set_control("speed", target_speed.value);
+       }
+       else
+               next_model->set_control(n, v);
+}
+
+const TrainControl &AIControl::get_control(const string &n) const
+{
+       if(n=="speed")
+               return target_speed;
+       else
+               return next_model->get_control(n);
+}
+
+float AIControl::get_speed() const
+{
+       return next_model->get_speed();
+}
+
+float AIControl::get_braking_distance() const
+{
+       return next_model->get_braking_distance();
+}
+
+void AIControl::tick(const Time::TimeDelta &dt)
+{
+       float rsv_dist = train.get_reserved_distance();
+       float brake_dist = next_model->get_braking_distance()*1.15;
+       float margin = 25*train.get_layout().get_catalogue().get_scale();
+       if(!blocked && rsv_dist<brake_dist+margin)
+       {
+               blocked = true;
+               next_model->set_control("speed", 0);
+       }
+       else if(blocked && rsv_dist>brake_dist+margin*3)
+       {
+               blocked = false;
+               next_model->set_control("speed", target_speed.value);
+       }
+
+       next_model->tick(dt);
+
+       if(!target_speed.value && !next_model->get_speed() && train.is_active())
+               train.set_active(false);
+}
+
+void AIControl::arrived()
+{
+       set_control("speed", 0);
+}
+
+} // namespace Marklin
diff --git a/source/libmarklin/aicontrol.h b/source/libmarklin/aicontrol.h
new file mode 100644 (file)
index 0000000..7c5bf5d
--- /dev/null
@@ -0,0 +1,45 @@
+/* $Id$
+
+This file is part of the MSP Märklin suite
+Copyright © 2010  Mikkosoft Productions, Mikko Rasa
+Distributed under the GPL
+*/
+
+#ifndef LIBMARKLIN_AICONTROL_H_
+#define LIBMARKLIN_AICONTROL_H_
+
+#include <sigc++/trackable.h>
+#include "controlmodel.h"
+#include "traincontrol.h"
+
+namespace Marklin {
+
+class Train;
+
+class AIControl: public ControlModel, public sigc::trackable
+{
+private:
+       Train &train;
+       ControlModel *next_model;
+       TrainControl target_speed;
+       bool blocked;
+
+public:
+       AIControl(Train &, ControlModel *);
+       virtual ~AIControl();
+
+       virtual void set_control(const std::string &, float);
+       virtual const TrainControl &get_control(const std::string &) const;
+
+       virtual float get_speed() const;
+       virtual float get_braking_distance() const;
+
+       virtual void tick(const Msp::Time::TimeDelta &);
+
+private:
+       void arrived();
+};
+
+} // namespace Marklin
+
+#endif
diff --git a/source/libmarklin/controlmodel.h b/source/libmarklin/controlmodel.h
new file mode 100644 (file)
index 0000000..d37ef63
--- /dev/null
@@ -0,0 +1,36 @@
+/* $Id$
+
+This file is part of the MSP Märklin suite
+Copyright © 2010  Mikkosoft Productions, Mikko Rasa
+Distributed under the GPL
+*/
+
+#ifndef LIBMARKLIN_CONTROLMODEL_H_
+#define LIBMARKLIN_CONTROLMODEL_H_
+
+#include <string>
+#include <msp/time/timedelta.h>
+
+namespace Marklin {
+
+class TrainControl;
+
+class ControlModel
+{
+protected:
+       ControlModel() { }
+public:
+       virtual ~ControlModel() { }
+
+       virtual void set_control(const std::string &, float) = 0;
+       virtual const TrainControl &get_control(const std::string &) const = 0;
+
+       virtual float get_speed() const = 0;
+       virtual float get_braking_distance() const = 0;
+
+       virtual void tick(const Msp::Time::TimeDelta &) = 0;
+};
+
+} // namespace Marklin
+
+#endif
diff --git a/source/libmarklin/simplephysics.cpp b/source/libmarklin/simplephysics.cpp
new file mode 100644 (file)
index 0000000..3dc8e2e
--- /dev/null
@@ -0,0 +1,61 @@
+/* $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 <msp/time/units.h>
+#include "simplephysics.h"
+
+using namespace std;
+using namespace Msp;
+
+namespace Marklin {
+
+SimplePhysics::SimplePhysics():
+       target_speed(TrainControl::continuous("speed", -1000, 1000)),
+       accel(0.07),
+       speed(0)
+{
+       target_speed.set(0);
+}
+
+void SimplePhysics::set_control(const string &name, float v)
+{
+       if(name=="speed")
+               target_speed.set(v);
+}
+
+const TrainControl &SimplePhysics::get_control(const string &name) const
+{
+       if(name=="speed")
+               return target_speed;
+       else
+               throw KeyError("Unknown control", name);
+}
+
+float SimplePhysics::get_braking_distance() const
+{
+       return speed*speed/(2*accel);
+}
+
+void SimplePhysics::tick(const Time::TimeDelta &dt)
+{
+       float secs = dt/Time::sec;
+       if(speed<target_speed.value)
+       {
+               speed += secs*accel;
+               if(speed>target_speed.value)
+                       speed = target_speed.value;
+       }
+       else if(speed>target_speed.value)
+       {
+               speed -= secs*accel;
+               if(speed<target_speed.value)
+                       speed = target_speed.value;
+       }
+}
+
+} // namespace Marklin
diff --git a/source/libmarklin/simplephysics.h b/source/libmarklin/simplephysics.h
new file mode 100644 (file)
index 0000000..6e33e4e
--- /dev/null
@@ -0,0 +1,38 @@
+/* $Id$
+
+This file is part of the MSP Märklin suite
+Copyright © 2010  Mikkosoft Productions, Mikko Rasa
+Distributed under the GPL
+*/
+
+#ifndef LIBMARKLIN_SIMPLEPHYSICS_H_
+#define LIBMARKLIN_SIMPLEPHYSICS_H_
+
+#include <string>
+#include "controlmodel.h"
+#include "traincontrol.h"
+
+namespace Marklin {
+
+class SimplePhysics: public ControlModel
+{
+private:
+       TrainControl target_speed;
+       float accel;
+       float speed;
+
+public:
+       SimplePhysics();
+
+       virtual void set_control(const std::string &, float);
+       virtual const TrainControl &get_control(const std::string &) const;
+
+       virtual float get_speed() const { return speed; }
+       virtual float get_braking_distance() const;
+
+       virtual void tick(const Msp::Time::TimeDelta &);
+};
+
+} // namespace Marklin
+
+#endif
index 030af70bc85fd1d2e667b4e47a24830a7ac915ea..208d40f10cdbbdfe09e81f6457c1a29a3da1a7c8 100644 (file)
@@ -293,6 +293,11 @@ unsigned Track::traverse(unsigned i, unsigned path) const
        throw Exception("Track endpoint did not have a counterpart");
 }
 
+unsigned Track::traverse(unsigned i) const
+{
+       return traverse(i, active_path);
+}
+
 TrackPoint Track::get_point(unsigned epi, unsigned path, float d) const
 {
        TrackPoint p = type.get_point(epi, path, d);
index 008b81dd4a169c46429e17f4f972f7cb14322eac..34d484c9f67bc487b3fc15b4afcf9778b6dd0be7 100644 (file)
@@ -80,6 +80,7 @@ public:
        const std::vector<Track *> &get_links() const { return links; }
        Track *get_link(unsigned) const;
        unsigned traverse(unsigned, unsigned) const;
+       unsigned traverse(unsigned) const;
        TrackPoint get_point(unsigned, unsigned, float) const;
        TrackPoint get_point(unsigned, float) const;
 
index f05799265ef9e186c3f553ffc28f6a045ec3d6c9..8ddb66bee3c5047a7c287a6925220d3456a1af0b 100644 (file)
@@ -9,10 +9,13 @@ Distributed under the GPL
 #include <msp/strings/formatter.h>
 #include <msp/time/units.h>
 #include <msp/time/utils.h>
+#include "aicontrol.h"
+#include "catalogue.h"
 #include "driver.h"
 #include "layout.h"
 #include "locotype.h"
 #include "route.h"
+#include "simplephysics.h"
 #include "tracktype.h"
 #include "train.h"
 #include "vehicle.h"
@@ -27,8 +30,10 @@ Train::Train(Layout &l, const LocoType &t, unsigned a):
        loco_type(t),
        address(a),
        pending_block(0),
-       target_speed(0),
+       control(new AIControl(*this, new SimplePhysics)),
+       active(false),
        current_speed(0),
+       speed_changing(false),
        reverse(false),
        functions(0),
        route(0),
@@ -36,7 +41,6 @@ Train::Train(Layout &l, const LocoType &t, unsigned a):
        end_of_route(false),
        status("Unplaced"),
        travel_dist(0),
-       travel_speed(0),
        pure_speed(false),
        real_speed(15)
 {
@@ -81,44 +85,30 @@ const Vehicle &Train::get_vehicle(unsigned i) const
        return *vehicles[i];
 }
 
-void Train::set_speed(unsigned speed)
+void Train::set_control(const string &n, float v)
 {
-       if(speed==target_speed)
-               return;
-       travel_speed = static_cast<int>(round(get_real_speed(speed)*87*3.6/5))*5;
-
-       target_speed = speed;
-       if(!target_speed)
-       {
-               pending_block = 0;
-               stop_timeout = Time::now()+(800+current_speed*150)*Time::msec;
-       }
-       else
-               reserve_more();
-
-       signal_target_speed_changed.emit(target_speed);
-
-       update_speed();
-       pure_speed = false;
+       control->set_control(n, v);
+       signal_control_changed.emit(n, control->get_control(n).value);
 }
 
-void Train::set_reverse(bool rev)
+void Train::set_active(bool a)
 {
-       if(rev==reverse)
+       if(a==active)
                return;
+       if(!a && control->get_speed())
+               throw InvalidState("Can't deactivate while moving");
 
-       if(target_speed)
+       active = a;
+       if(active)
        {
-               set_speed(0);
-               return;
+               stop_timeout = Time::TimeStamp();
+               reserve_more();
+       }
+       else
+       {
+               stop_timeout = Time::now()+2*Time::sec;
+               set_status("Stopped");
        }
-       else if(stop_timeout)
-               return;
-
-       layout.get_driver().set_loco_reverse(address, rev);
-
-       release_blocks(rsv_blocks);
-       reverse_blocks(cur_blocks);
 }
 
 void Train::set_function(unsigned func, bool state)
@@ -164,8 +154,8 @@ void Train::set_route(const Route *r)
                }
        }
 
-       if(target_speed && reserve_more()<2)
-               update_speed();
+       if(active)
+               reserve_more();
 
        signal_route_changed.emit(route);
 }
@@ -175,7 +165,7 @@ void Train::go_to(const Track &to)
        for(list<BlockRef>::const_iterator i=cur_blocks.begin(); i!=cur_blocks.end(); ++i)
                if(i->block->get_tracks().count(const_cast<Track *>(&to)))
                {
-                       set_speed(0);
+                       signal_arrived.emit();
                        set_route(0);
                        return;
                }
@@ -198,12 +188,14 @@ void Train::go_to(const Track &to)
 
 void Train::place(Block &block, unsigned entry)
 {
-       if(target_speed)
-               set_speed(0);
+       if(control->get_speed())
+               throw InvalidState("Must be stopped before placing");
 
        release_blocks(rsv_blocks);
        release_blocks(cur_blocks);
 
+       set_active(false);
+
        if(!block.reserve(this))
        {
                set_status("Unplaced");
@@ -224,8 +216,6 @@ void Train::place(Block &block, unsigned entry)
                const Block::Endpoint &bep = block.get_endpoints()[entry];
                vehicles.front()->place(bep.track, bep.track_ep, 0, Vehicle::BACK_BUFFER);
        }
-
-       set_status("Stopped");
 }
 
 bool Train::free_block(Block &block)
@@ -238,7 +228,6 @@ bool Train::free_block(Block &block)
                        if(nsens<1)
                                return false;
                        release_blocks(rsv_blocks, i, rsv_blocks.end());
-                       update_speed();
                        return true;
                }
                else if(i->block->get_sensor_id())
@@ -259,17 +248,89 @@ int Train::get_entry_to_block(Block &block) const
        return -1;
 }
 
+float Train::get_reserved_distance() const
+{
+       Vehicle &veh = *(reverse ? vehicles.back() : vehicles.front());
+       const VehicleType &vtype = veh.get_type();
+
+       Track *track = veh.get_track();
+       unsigned entry = veh.get_entry();
+
+       float result = -vtype.get_length()/2;
+       if(reverse)
+       {
+               entry = track->traverse(entry);
+               result += veh.get_offset();
+       }
+       else
+               result -= veh.get_offset();
+
+       bool first = true;
+       list<BlockRef>::const_iterator block = cur_blocks.begin();
+       while(1)
+       {
+               if(!first || !reverse)
+                       result += track->get_type().get_path_length(track->get_active_path());
+               first = false;
+
+               unsigned exit = track->traverse(entry);
+               Track *next = track->get_link(exit);
+
+               while(!block->block->get_tracks().count(next))
+               {
+                       ++block;
+                       if(block==cur_blocks.end())
+                               block = rsv_blocks.begin();
+                       if(block==rsv_blocks.end())
+                               return result;
+               }
+
+               entry = next->get_endpoint_by_link(*track);
+               track = next;
+       }
+}
+
 void Train::tick(const Time::TimeStamp &t, const Time::TimeDelta &dt)
 {
-       if(stop_timeout && t>=stop_timeout)
+       if(!active && stop_timeout && t>=stop_timeout)
        {
                release_blocks(rsv_blocks);
                end_of_route = false;
                stop_timeout = Time::TimeStamp();
        }
 
-       if(current_speed)
+       control->tick(dt);
+       float speed = control->get_speed();
+       unsigned speed_notch = find_speed(abs(speed));
+
+       if(speed && (speed<0)!=reverse)
+       {
+               layout.get_driver().set_loco_reverse(address, speed<0);
+               reverse = speed<0;
+
+               release_blocks(rsv_blocks);
+               reverse_blocks(cur_blocks);
+
+               reserve_more();
+       }
+       if(speed_notch!=current_speed && !speed_changing)
+       {
+               speed_changing = true;
+               layout.get_driver().set_loco_speed(address, speed_notch);
+
+               pure_speed = false;
+
+               if(speed_notch)
+                       set_status(format("Traveling %d kmh", get_travel_speed()));
+               else
+                       set_status("Waiting");
+       }
+
+       if(speed)
        {
+               if(!active)
+                       set_active(true);
+
                Track *track = vehicles[0]->get_track();
 
                bool ok = false;
@@ -308,15 +369,12 @@ void Train::save(list<DataFile::Statement> &st) const
                st.push_back((DataFile::Statement("route"), route->get_name()));
 }
 
-void Train::loco_speed_event(unsigned addr, unsigned speed, bool rev)
+void Train::loco_speed_event(unsigned addr, unsigned speed, bool)
 {
        if(addr==address)
        {
                current_speed = speed;
-               reverse = rev;
-
-               signal_speed_changed.emit(current_speed);
-               signal_reverse_changed.emit(reverse);
+               speed_changing = false;
        }
 }
 
@@ -349,12 +407,12 @@ void Train::sensor_event(unsigned addr, bool state)
                {
                        // Compute speed and update related state
                        float travel_time_secs = (Time::now()-last_entry_time)/Time::sec;
-                       travel_speed = static_cast<int>(round(travel_dist/travel_time_secs*87*3.6/5))*5;
 
                        if(pure_speed)
                        {
                                RealSpeed &rs = real_speed[current_speed];
                                rs.add(travel_dist/travel_time_secs, travel_time_secs);
+                               set_status(format("Traveling %d kmh", get_travel_speed()));
                        }
 
                        travel_dist = 0;
@@ -399,16 +457,14 @@ void Train::sensor_event(unsigned addr, bool state)
                        cur_blocks.splice(cur_blocks.end(), rsv_blocks, rsv_blocks.begin(), i);
 
                        // Try to get more blocks if we're moving
-                       if(target_speed)
+                       if(active)
                        {
                                unsigned nsens = reserve_more();
                                if(!nsens && end_of_route)
                                {
-                                       set_speed(0);
+                                       signal_arrived.emit();
                                        set_route(0);
                                }
-                               else if(nsens<2)
-                                       update_speed();
                        }
                }
        }
@@ -577,52 +633,9 @@ unsigned Train::reserve_more()
                        last = &rsv_blocks.back();
        }
 
-       if(got_more)
-               update_speed();
-
        return good_sens;
 }
 
-void Train::update_speed()
-{
-       Driver &driver = layout.get_driver();
-
-       unsigned speed;
-       if(!target_speed)
-       {
-               speed = 0;
-               set_status("Stopped");
-       }
-       else
-       {
-               unsigned nsens = 0;
-               for(list<BlockRef>::const_iterator i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
-                       if(i->block->get_sensor_id())
-                               ++nsens;
-
-               unsigned slow_speed = find_speed(0.1);  // 31.3 km/h
-               if(nsens==0)
-               {
-                       speed = 0;
-                       pure_speed = false;
-                       set_status("Blocked");
-               }
-               else if(nsens==1 && target_speed>slow_speed)
-               {
-                       speed = slow_speed;
-                       pure_speed = false;
-                       set_status("Slow");
-               }
-               else
-               {
-                       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
 {
        if(real_speed[i].weight)
@@ -679,6 +692,13 @@ unsigned Train::find_speed(float real) const
        return static_cast<unsigned>(low*(1-f)+high*f+0.5);
 }
 
+float Train::get_travel_speed() const
+{
+       float speed = get_real_speed(current_speed);
+       float scale = layout.get_catalogue().get_scale();
+       return static_cast<int>(round(speed/scale*3.6/5))*5;
+}
+
 void Train::set_status(const string &s)
 {
        status = s;
index 5a20bd01a4855fce7a330606838817b5caba6ba8..4289d3c0dd9b5b77e13224b8c8a01eb616771def 100644 (file)
@@ -15,6 +15,7 @@ Distributed under the GPL
 
 namespace Marklin {
 
+class ControlModel;
 class LocoType;
 class Route;
 class Vehicle;
@@ -38,11 +39,10 @@ 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, const std::string &, float> signal_control_changed;
        sigc::signal<void, unsigned, bool> signal_function_changed;
        sigc::signal<void, const Route *> signal_route_changed;
+       sigc::signal<void> signal_arrived;
        sigc::signal<void, const std::string &> signal_status_changed;
 
 private:
@@ -72,8 +72,10 @@ private:
        std::list<BlockRef> cur_blocks;
        std::list<BlockRef> rsv_blocks;
        Block *pending_block;
-       unsigned target_speed;
+       ControlModel *control;
+       bool active;
        unsigned current_speed;
+       bool speed_changing;
        bool reverse;
        Msp::Time::TimeStamp stop_timeout;
        unsigned functions;
@@ -84,7 +86,6 @@ private:
 
        Msp::Time::TimeStamp last_entry_time;
        float travel_dist;
-       unsigned travel_speed;
        bool pure_speed;
        std::vector<RealSpeed> real_speed;
 
@@ -92,20 +93,21 @@ public:
        Train(Layout &, const LocoType &, unsigned);
        ~Train();
 
+       Layout &get_layout() const { return layout; }
        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; }
+       ControlModel &get_control() const { return *control; }
 
        Vehicle &get_vehicle(unsigned);
        const Vehicle &get_vehicle(unsigned) const;
 
-       void set_speed(unsigned);
-       void set_reverse(bool);
+       void set_control(const std::string &, float);
+       void set_active(bool);
        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; }
+       float get_control(const std::string &) const;
+       bool is_active() const { return active; }
        bool get_function(unsigned) const;
        unsigned get_functions() const { return functions; }
 
@@ -116,6 +118,7 @@ public:
        bool is_placed() const { return !cur_blocks.empty(); }
        bool free_block(Block &);
        int get_entry_to_block(Block &) const;
+       float get_reserved_distance() const;
 
        const std::string &get_status() const { return status; }
 
@@ -129,9 +132,9 @@ private:
        void turnout_event(unsigned, bool);
        void block_reserved(const Block &, const Train *);
        unsigned reserve_more();
-       void update_speed();
        float get_real_speed(unsigned) const;
        unsigned find_speed(float) const;
+       float get_travel_speed() const;
        void set_status(const std::string &);
        void release_blocks(std::list<BlockRef> &);
        void release_blocks(std::list<BlockRef> &, std::list<BlockRef>::iterator, std::list<BlockRef>::iterator);
diff --git a/source/libmarklin/traincontrol.cpp b/source/libmarklin/traincontrol.cpp
new file mode 100644 (file)
index 0000000..a9a5a84
--- /dev/null
@@ -0,0 +1,76 @@
+/* $Id$
+
+This file is part of the MSP Märklin suite
+Copyright © 2010  Mikkosoft Productions, Mikko Rasa
+Distributed under the GPL
+*/
+
+#include <cmath>
+#include <msp/core/except.h>
+#include "traincontrol.h"
+
+using namespace std;
+using namespace Msp;
+
+namespace Marklin {
+
+void TrainControl::set(float v)
+{
+       if(v<min_value)
+               v = min_value;
+       else if(v>max_value)
+               v = max_value;
+       else if(type==BINARY)
+               value = v ? 1 : 0;
+       else if(type==DISCRETE)
+               value = min_value+floor((v-min_value)/step)*step;
+       else if(type==CONTINUOUS)
+               value = v;
+}
+
+TrainControl TrainControl::binary(const string &n)
+{
+       TrainControl tc;
+       tc.name = n;
+       tc.type = BINARY;
+       tc.min_value = 0;
+       tc.max_value = 1;
+       tc.step = 1;
+       tc.value = 0;
+
+       return tc;
+}
+
+TrainControl TrainControl::discrete(const string &n, float m, float x, float s)
+{
+       if(x<m)
+               throw InvalidParameterValue("Max value must be greater than min value");
+
+       TrainControl tc;
+       tc.name = n;
+       tc.type = DISCRETE;
+       tc.min_value = m;
+       tc.max_value = m+floor((x-m)/s)*s;
+       tc.step = s;
+       tc.value = m;
+
+       return tc;
+}
+
+TrainControl TrainControl::continuous(const string &n, float m, float x)
+{
+       if(x<m)
+               throw InvalidParameterValue("Max value must be greater than min value");
+
+       TrainControl tc;
+       tc.name = n;
+       tc.type = CONTINUOUS;
+       tc.min_value = m;
+       tc.max_value = x;
+       tc.step = 0;
+       tc.value = m;
+
+       return tc;
+}
+
+} // namespace Marklin
diff --git a/source/libmarklin/traincontrol.h b/source/libmarklin/traincontrol.h
new file mode 100644 (file)
index 0000000..ac86bc4
--- /dev/null
@@ -0,0 +1,44 @@
+/* $Id$
+
+This file is part of the MSP Märklin suite
+Copyright © 2010  Mikkosoft Productions, Mikko Rasa
+Distributed under the GPL
+*/
+
+#ifndef LIBMARKLIN_TRAINCONTROL_H_
+#define LIBMARKLIN_TRAINCONTROL_H_
+
+#include <string>
+
+namespace Marklin {
+
+struct TrainControl
+{
+       enum Type
+       {
+               BINARY,
+               DISCRETE,
+               CONTINUOUS
+       };
+
+       std::string name;
+       Type type;
+       float min_value;
+       float max_value;
+       float step;
+       float value;
+
+private:
+       TrainControl() { }
+
+public:
+       void set(float);
+
+       static TrainControl binary(const std::string &);
+       static TrainControl discrete(const std::string &, float, float, float);
+       static TrainControl continuous(const std::string &, float, float);
+};
+
+} // namespace Marklin
+
+#endif
index d24bebea60f491568302fead5aff1c3545b58142..149adda5d55e931ab6f92a6a83be383e510c8caf 100644 (file)
@@ -58,6 +58,8 @@ public:
        void place(Track *, unsigned, float, PlaceMode = CENTER);
        void advance(float);
        Track *get_track() const { return track_pos.track; }
+       unsigned get_entry() const { return track_pos.ep; }
+       float get_offset() const { return track_pos.offs; }
        const Point &get_position() const { return position; }
        float get_direction() const { return direction; }
 private:
index 2e003842e9c007e9c75334bd80e4765fb0ba143a..50db7df6d817bdcbb738e4182262de9df2fd275f 100644 (file)
@@ -58,7 +58,7 @@ void Client::receive(const TrainInfoPacket &pkt)
        signal_train_added.emit(*train);
 }
 
-void Client::receive(const TrainSpeedPacket &pkt)
+void Client::receive(const TrainControlPacket &pkt)
 {
        get_train(pkt.address).process_packet(pkt);
 }
index 39c7eb035c16ae82bacab2a12f2f7c803e34276c..2ab8722f1eb8f24dca84c2e223904b30295ee327 100644 (file)
@@ -18,8 +18,8 @@ Distributed under the GPL
 namespace Marklin {
 
 class Client: public Msp::Net::PacketReceiver<TrainInfoPacket>,
-       Msp::Net::PacketReceiver<TrainSpeedPacket>,
        Msp::Net::PacketReceiver<TrainFunctionPacket>,
+       Msp::Net::PacketReceiver<TrainControlPacket>,
        Msp::Net::PacketReceiver<TrainStatusPacket>,
        Msp::Net::PacketReceiver<RouteInfoPacket>,
        Msp::Net::PacketReceiver<TrainRoutePacket>,
@@ -56,7 +56,7 @@ public:
 
 private:
        virtual void receive(const TrainInfoPacket &);
-       virtual void receive(const TrainSpeedPacket &);
+       virtual void receive(const TrainControlPacket &);
        virtual void receive(const TrainFunctionPacket &);
        virtual void receive(const TrainStatusPacket &);
        virtual void receive(const RouteInfoPacket &);
index 31fd56d11350ff8390585cdfa7c97745956b1319..8bbaf8e239d4b8d3dd946f5c3e0817d1098df496 100644 (file)
@@ -19,11 +19,11 @@ struct TrainInfoPacket
        std::string name;
 };
 
-struct TrainSpeedPacket
+struct TrainControlPacket
 {
        unsigned address;
-       unsigned speed;
-       char reverse;
+       std::string control;
+       float value;
 };
 
 struct TrainFunctionPacket
index f8e13beb4ac5f4156780a415d9b24cecfd7be2fb..623eadb334eff2b89666c085333fb63af516be9c 100644 (file)
@@ -14,8 +14,8 @@ Protocol::Protocol()
 {
        add<TrainInfoPacket>() (&TrainInfoPacket::address)
                (&TrainInfoPacket::loco_type) (&TrainInfoPacket::name);
-       add<TrainSpeedPacket>() (&TrainSpeedPacket::address)
-               (&TrainSpeedPacket::speed) (&TrainSpeedPacket::reverse);
+       add<TrainControlPacket>() (&TrainControlPacket::address)
+               (&TrainControlPacket::control) (&TrainControlPacket::value);
        add<TrainFunctionPacket>() (&TrainFunctionPacket::address)
                (&TrainFunctionPacket::functions);
        add<TrainStatusPacket>() (&TrainStatusPacket::address)
index 2e3248f28878bf0a7000d874895c69d2675f3056..dd0dd8b927bde2a43ea9522d30aaef3f99cd912a 100644 (file)
@@ -47,8 +47,7 @@ void Server::incoming_connection()
 
 void Server::train_added(Train &train)
 {
-       train.signal_target_speed_changed.connect(sigc::bind<0>(sigc::mem_fun(this, &Server::train_speed_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_control_changed.connect(sigc::bind<0>(sigc::mem_fun(this, &Server::train_control_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)));
@@ -60,21 +59,12 @@ void Server::train_added(Train &train)
        send(pkt);
 }
 
-void Server::train_speed_changed(const Train &train, unsigned speed)
+void Server::train_control_changed(const Train &train, const string &control, float value)
 {
-       TrainSpeedPacket pkt;
+       TrainControlPacket pkt;
        pkt.address = train.get_address();
-       pkt.speed = speed;
-       pkt.reverse = train.get_reverse();
-       send(pkt);
-}
-
-void Server::train_reverse_changed(const Train &train, bool reverse)
-{
-       TrainSpeedPacket pkt;
-       pkt.address = train.get_address();
-       pkt.speed = train.get_target_speed();
-       pkt.reverse = reverse;
+       pkt.control = control;
+       pkt.value = value;
        send(pkt);
 }
 
@@ -149,13 +139,7 @@ void Server::Connection::handshake_done()
                        pkt.name = train.get_name();
                        comm.send(pkt);
                }
-               {
-                       TrainSpeedPacket pkt;
-                       pkt.address = train.get_address();
-                       pkt.speed = train.get_target_speed();
-                       pkt.reverse = train.get_reverse();
-                       comm.send(pkt);
-               }
+               // XXX Need control enumeration to send control packets
                {
                        TrainFunctionPacket pkt;
                        pkt.address = train.get_address();
@@ -184,15 +168,12 @@ void Server::Connection::end_of_file()
        stale = true;
 }
 
-void Server::Connection::receive(const TrainSpeedPacket &pkt)
+void Server::Connection::receive(const TrainControlPacket &pkt)
 {
        try
        {
                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);
+               train.set_control(pkt.control, pkt.value);
        }
        catch(const Exception &e)
        {
index 41bb8e9b50bc9765767efa7ae5a1c09868e66d13..056b0dd089d0c5b2b285136167834f8f81c0947a 100644 (file)
@@ -21,7 +21,7 @@ namespace Marklin {
 class Server
 {
 private:
-       struct Connection: private Msp::Net::PacketReceiver<TrainSpeedPacket>,
+       struct Connection: private Msp::Net::PacketReceiver<TrainControlPacket>,
                private Msp::Net::PacketReceiver<TrainFunctionPacket>,
                private Msp::Net::PacketReceiver<TrainRoutePacket>
        {
@@ -35,7 +35,7 @@ private:
 
                void handshake_done();
                void end_of_file();
-               virtual void receive(const TrainSpeedPacket &);
+               virtual void receive(const TrainControlPacket &);
                virtual void receive(const TrainFunctionPacket &);
                virtual void receive(const TrainRoutePacket &);
                void error(const std::string &);
@@ -54,8 +54,7 @@ private:
        void incoming_connection();
 
        void train_added(Train &);
-       void train_speed_changed(const Train &, unsigned);
-       void train_reverse_changed(const Train &, bool);
+       void train_control_changed(const Train &, const std::string &, float);
        void train_function_changed(const Train &, unsigned, bool);
        void train_route_changed(const Train &, const Route *);
        void train_status_changed(const Train &, const std::string &);
index 025dcf52a75268b1dcdaa6b40c3cdc41d2a84d9b..5c4b457bad9bb3093edb962887d567798e6d8777 100644 (file)
@@ -17,32 +17,18 @@ NetTrain::NetTrain(Client &c, const TrainInfoPacket &pkt):
        loco_type(client.get_catalogue().get_locomotive(pkt.loco_type)),
        address(pkt.address),
        name(pkt.name),
-       speed(0),
-       reverse(0),
        functions(0)
 { }
 
-void NetTrain::set_speed(unsigned s)
+void NetTrain::set_control(const string &c, float v)
 {
-       if(s==speed)
+       if(v==controls[c])
                return;
 
-       TrainSpeedPacket pkt;
+       TrainControlPacket pkt;
        pkt.address = address;
-       pkt.speed = s;
-       pkt.reverse = reverse;
-       client.send(pkt);
-}
-
-void NetTrain::set_reverse(bool r)
-{
-       if(r==reverse)
-               return;
-
-       TrainSpeedPacket pkt;
-       pkt.address = address;
-       pkt.speed = speed;
-       pkt.reverse = r;
+       pkt.control = c;
+       pkt.value = v;
        client.send(pkt);
 }
 
@@ -69,18 +55,10 @@ void NetTrain::set_route(const string &r)
        client.send(pkt);
 }
 
-void NetTrain::process_packet(const TrainSpeedPacket &pkt)
+void NetTrain::process_packet(const TrainControlPacket &pkt)
 {
-       if(pkt.speed!=speed)
-       {
-               speed = pkt.speed;
-               signal_speed_changed.emit(speed);
-       }
-       if(pkt.reverse!=reverse)
-       {
-               reverse = pkt.reverse;
-               signal_reverse_changed.emit(reverse);
-       }
+       controls[pkt.control] = pkt.value;
+       signal_control_changed.emit(pkt.control, pkt.value);
 }
 
 void NetTrain::process_packet(const TrainFunctionPacket &pkt)
index 0a6a8a8f9063700dadf6bdb1d26c8f6eda835fbf..74c6ccb6cae38d28d3216f0ed6d6dd53cc5dd7b7 100644 (file)
@@ -20,8 +20,7 @@ class NetTrain
 {
 public:
        sigc::signal<void, const std::string &> signal_name_changed;
-       sigc::signal<void, unsigned> signal_speed_changed;
-       sigc::signal<void, bool> signal_reverse_changed;
+       sigc::signal<void, const std::string &, float> signal_control_changed;
        sigc::signal<void, unsigned, bool> signal_function_changed;
        sigc::signal<void, const std::string &> signal_route_changed;
        sigc::signal<void, const std::string &> signal_status_changed;
@@ -31,8 +30,7 @@ private:
        const LocoType &loco_type;
        unsigned address;
        std::string name;
-       unsigned speed;
-       bool reverse;
+       std::map<std::string, float> controls;
        unsigned functions;
        std::string route;
        std::string status;
@@ -43,16 +41,14 @@ public:
        const LocoType &get_loco_type() const { return loco_type; }
        unsigned get_address() const { return address; }
        const std::string &get_name() const { return name; }
-       void set_speed(unsigned);
-       unsigned get_speed() const { return speed; }
-       void set_reverse(bool);
-       bool get_reverse() const { return reverse; }
+       void set_control(const std::string &, float);
+       float get_control(const std::string &) const;
        void set_function(unsigned, bool);
        bool get_function(unsigned i) const { return (functions>>i)&1; }
        void set_route(const std::string &);
        const std::string &get_route() const { return route; }
 
-       void process_packet(const TrainSpeedPacket &);
+       void process_packet(const TrainControlPacket &);
        void process_packet(const TrainFunctionPacket &);
        void process_packet(const TrainRoutePacket &);
        void process_packet(const TrainStatusPacket &);
index c6afc6de537e0ab4fe7d3d4ffb75970fc69af24f..a193b2bf599ef87507fa9aedc037c4572c7a3c10 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
 */
 
@@ -52,7 +52,7 @@ void Remote::tick()
 
 void Remote::train_added(Marklin::NetTrain &t)
 {
-       TrainPanel *panel = new TrainPanel(client, t);
+       TrainPanel *panel = new TrainPanel(*this, client, t);
        if(!train_panels.empty())
        {
                Gtk::HSeparator *sep = new Gtk::HSeparator;
index a4bfc428e7ed467797e90b59414ded97baf2a367..6d6be3377aa1f1cc71ffb2b4407c88335f0ee03e 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
 */
 
@@ -31,6 +31,8 @@ private:
 
 public:
        Remote(int argc, char **argv);
+
+       const Marklin::Catalogue &get_catalogue() const { return catalogue; }
 private:
        void tick();
 
index ce46fa19dffaa86634df6553609c8a28f086878e..37d75afba7273e36c8bb496f5e688cc1bfffb65e 100644 (file)
@@ -1,24 +1,25 @@
 /* $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 <gtkmm/box.h>
 #include <gtkmm/liststore.h>
 #include "libmarklin/locotype.h"
+#include "remote.h"
 #include "trainpanel.h"
 
 using namespace std;
 
-TrainPanel::TrainPanel(Marklin::Client &c, Marklin::NetTrain &t):
+TrainPanel::TrainPanel(Remote &r, Marklin::Client &c, Marklin::NetTrain &t):
+       remote(r),
        client(c),
        train(t)
 {
        train.signal_name_changed.connect(sigc::mem_fun(this, &TrainPanel::name_changed));
-       train.signal_speed_changed.connect(sigc::mem_fun(this, &TrainPanel::speed_changed));
-       train.signal_reverse_changed.connect(sigc::mem_fun(this, &TrainPanel::reverse_changed));
+       train.signal_control_changed.connect(sigc::mem_fun(this, &TrainPanel::control_changed));
        train.signal_function_changed.connect(sigc::mem_fun(this, &TrainPanel::function_changed));
        train.signal_route_changed.connect(sigc::mem_fun(this, &TrainPanel::route_changed));
        train.signal_status_changed.connect(sigc::mem_fun(this, &TrainPanel::status_changed));
@@ -34,8 +35,8 @@ TrainPanel::TrainPanel(Marklin::Client &c, Marklin::NetTrain &t):
 
        hbox->add(*manage(scl_speed = new Gtk::HScale));
        scl_speed->set_digits(0);
-       scl_speed->set_range(0, 14);
-       scl_speed->set_increments(1, 1);
+       scl_speed->set_range(0, 200);
+       scl_speed->set_increments(5, 5);
        scl_speed->set_size_request(210, -1);
        scl_speed->signal_value_changed().connect(sigc::mem_fun(this, &TrainPanel::ui_speed_changed));
 
@@ -80,14 +81,14 @@ void TrainPanel::status_changed(const string &status)
        lbl_status->set_text(status);
 }
 
-void TrainPanel::speed_changed(unsigned speed)
+void TrainPanel::control_changed(const string &control, float value)
 {
-       scl_speed->set_value(speed);
-}
-
-void TrainPanel::reverse_changed(bool rev)
-{
-       chk_reverse->set_active(rev);
+       if(control=="speed")
+       {
+               // XXX It would be better to make the LocoType give us the catalogue
+               scl_speed->set_value(abs(value)*3.6/remote.get_catalogue().get_scale());
+               chk_reverse->set_active(value<0);
+       }
 }
 
 void TrainPanel::function_changed(unsigned func, bool set)
@@ -110,12 +111,15 @@ void TrainPanel::route_changed(const string &route)
 
 void TrainPanel::ui_speed_changed()
 {
-       train.set_speed(static_cast<unsigned>(scl_speed->get_value()));
+       float speed = scl_speed->get_value()/3.6*remote.get_catalogue().get_scale();
+       if(chk_reverse->get_active())
+               speed = -speed;
+       train.set_control("speed", speed);
 }
 
 void TrainPanel::ui_reverse_changed()
 {
-       train.set_reverse(chk_reverse->get_active());
+       train.set_control("speed", 0);
 }
 
 void TrainPanel::ui_function_changed(unsigned func)
index b969af406d2becef314f48b114823882801d4f3d..e1464e36331f4bd8923d141644a146ce3eeb7ea8 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
 */
 
@@ -16,6 +16,8 @@ Distributed under the GPL
 #include "network/client.h"
 #include "network/train.h"
 
+class Remote;
+
 class TrainPanel: public Gtk::Expander
 {
 private:
@@ -26,6 +28,7 @@ private:
                RouteRecord();
        };
 
+       Remote &remote;
        Marklin::Client &client;
        Marklin::NetTrain &train;
        Gtk::Scale *scl_speed;
@@ -36,12 +39,11 @@ private:
        std::map<unsigned, Gtk::CheckButton *> chk_funcs;
 
 public:
-       TrainPanel(Marklin::Client &, Marklin::NetTrain &);
+       TrainPanel(Remote &, Marklin::Client &, Marklin::NetTrain &);
 private:
        void name_changed(const std::string &);
        void status_changed(const std::string &);
-       void speed_changed(unsigned);
-       void reverse_changed(bool);
+       void control_changed(const std::string &, float);
        void function_changed(unsigned, bool);
        void route_changed(const std::string &);
        void ui_speed_changed();
index 27667521e1eb07cba7d3ba81545d6f70c847a72f..4b94034f0354d9c535ff3016b8617bbc7e5c78c3 100644 (file)
@@ -20,6 +20,7 @@ Serial::Serial(int, char **argv):
        client(catalogue),
        serial_port(argv[2]),
        train(0),
+       reverse(false),
        rx_fill(0)
 {
        DataFile::load(catalogue, "locos.dat");
@@ -97,7 +98,8 @@ void Serial::data_available()
                else if(c=='R')
                {
                        IO::print("Reverse\n");
-                       train->set_reverse(!train->get_reverse());
+                       reverse = !reverse;
+                       train->set_control("speed", 0);
                }
                else if(c=='N')
                        next_train();
@@ -121,9 +123,10 @@ void Serial::data_available()
                }
                else if(rx_buf[0]=='S' && rx_fill==3)
                {
-                       unsigned speed = (rx_buf[1]-'0')*10+(rx_buf[2]-'0');
-                       IO::print("Set speed %d\n", speed);
-                       train->set_speed(speed);
+                       // XXX The firmware is still coded for speed step based control
+                       float speed = ((rx_buf[1]-'0')*10+(rx_buf[2]-'0'))*10/3.6*catalogue.get_scale();
+                       IO::print("Set speed %g\n", speed);
+                       train->set_control("speed", speed);
                        rx_fill = 0;
                }
        }
index b5427e44a35fe2d0bc244b52da234729b5f5c0b2..e03bb50d08c5e95bfc132d93957894b72067261c 100644 (file)
@@ -20,6 +20,7 @@ private:
        Marklin::Client client;
        Msp::IO::Serial serial_port;
        Marklin::NetTrain *train;
+       bool reverse;
        char rx_buf[3];
        unsigned rx_fill;