namespace R2C2 {
+class TrackType;
+class VehicleType;
+
class Driver
{
public:
sigc::signal<void, bool> signal_halt;
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, unsigned> signal_turnout;
sigc::signal<void, unsigned, bool> signal_sensor;
protected:
virtual const char *enumerate_protocols(unsigned) const = 0;
virtual unsigned get_protocol_speed_steps(const std::string &) const = 0;
- virtual void add_loco(unsigned, const std::string &) = 0;
+ virtual void add_loco(unsigned, const std::string &, const VehicleType &) = 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_turnout(unsigned, const TrackType &) = 0;
+ virtual void set_turnout(unsigned, unsigned) = 0;
+ virtual unsigned get_turnout(unsigned) const = 0;
virtual void add_sensor(unsigned) = 0;
virtual void set_sensor(unsigned, bool) = 0;
return 0;
}
-void Dummy::add_turnout(unsigned addr)
+void Dummy::add_turnout(unsigned addr, const TrackType &)
{
turnouts[addr];
}
-void Dummy::set_turnout(unsigned addr, bool state)
+void Dummy::set_turnout(unsigned addr, unsigned state)
{
if(turnouts[addr]!=state)
{
}
}
-bool Dummy::get_turnout(unsigned addr) const
+unsigned Dummy::get_turnout(unsigned addr) const
{
- map<unsigned, bool>::const_iterator i = turnouts.find(addr);
+ map<unsigned, unsigned>::const_iterator i = turnouts.find(addr);
if(i!=turnouts.end())
return i->second;
return false;
};
bool power;
- std::map<unsigned, bool> turnouts;
+ std::map<unsigned, unsigned> turnouts;
std::map<unsigned, LocoState> locos;
std::map<unsigned, bool> sensors;
virtual const char *enumerate_protocols(unsigned) const;
virtual unsigned get_protocol_speed_steps(const std::string &) const;
- virtual void add_loco(unsigned, const std::string &) { }
+ virtual void add_loco(unsigned, const std::string &, const VehicleType &) { }
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_turnout(unsigned, const TrackType &);
+ virtual void set_turnout(unsigned, unsigned);
+ virtual unsigned get_turnout(unsigned) const;
virtual void add_sensor(unsigned) { }
virtual void set_sensor(unsigned, bool);
#include <msp/time/units.h>
#include <msp/time/utils.h>
#include "intellibox.h"
+#include "tracktype.h"
+#include "vehicletype.h"
using namespace std;
using namespace Msp;
const char *Intellibox::enumerate_protocols(unsigned i) const
{
+ ++i;
if(i==MM)
return "MM";
else if(i==MM_27)
return 0;
}
-void Intellibox::add_loco(unsigned addr, const string &proto_name)
+void Intellibox::add_loco(unsigned addr, const string &proto_name, const VehicleType &type)
{
Protocol proto = map_protocol(proto_name);
if(!locos.count(addr))
{
- locos[addr].protocol = proto;
+ Locomotive &loco = locos[addr];
+ loco.protocol = proto;
+ if(type.get_max_function()>4)
+ {
+ loco.ext_func = true;
+ locos[addr+1].protocol = NONE;
+ }
unsigned char data[2];
data[0] = addr&0xFF;
void Intellibox::set_loco_speed(unsigned addr, unsigned speed)
{
Locomotive &loco = locos[addr];
+ if(loco.protocol==NONE)
+ return;
+
if(speed==loco.speed)
{
if(loco.pending_half_step)
loco.pending_half_step = 0;
loco.half_step_delay = Time::TimeStamp();
- loco_command(addr, (speed+1)/2, loco.reverse, loco.funcs|0x100);
+ loco_command(addr, (speed+1)/2, loco.reverse, loco.funcs, false);
}
- else
+ else if(loco.protocol==MM)
{
if(speed>14)
speed = 14;
- loco_command(addr, speed, loco.reverse, loco.funcs|0x100);
+ loco_command(addr, speed, loco.reverse, loco.funcs, false);
}
loco.speed = speed;
}
void Intellibox::set_loco_reverse(unsigned addr, bool rev)
{
Locomotive &loco = locos[addr];
- if(rev==loco.reverse)
+ if(loco.protocol==NONE || rev==loco.reverse)
return;
+ loco.speed = 0;
loco.reverse = rev;
- loco_command(addr, loco.speed, rev, loco.funcs|0x100);
+ loco_command(addr, 0, rev, loco.funcs, false);
}
void Intellibox::set_loco_function(unsigned addr, unsigned func, bool state)
{
Locomotive &loco = locos[addr];
+ if(loco.protocol==NONE)
+ return;
+
if(state)
loco.funcs |= 1<<func;
else
loco.funcs &= ~(1<<func);
- loco_command(addr, loco.speed, loco.reverse, loco.funcs);
+ if(func<=4)
+ loco_command(addr, loco.speed, loco.reverse, loco.funcs, true);
+ else if(loco.ext_func && func<=8)
+ loco_command(addr+1, 0, false, (loco.funcs>>4)&0x1E, true);
signal_loco_function.emit(addr, func, state);
}
-void Intellibox::add_turnout(unsigned addr)
+void Intellibox::add_turnout(unsigned addr, const TrackType &type)
{
if(!turnouts.count(addr))
{
- turnouts[addr];
+ Turnout &turnout = turnouts[addr];
+ turnout.bits = type.get_state_bits();
unsigned char data[2];
data[0] = addr&0xFF;
data[1] = (addr>>8)&0xFF;
command(CMD_TURNOUT_STATUS, addr, data, 2);
+ for(unsigned i=1; i<turnout.bits; ++i)
+ {
+ turnouts[addr+i].bits = 0;
+
+ ++data[0];
+ if(!data[0])
+ ++data[1];
+ command(CMD_TURNOUT_STATUS, addr+i, data, 2);
+ }
}
}
-void Intellibox::set_turnout(unsigned addr, bool state)
+void Intellibox::set_turnout(unsigned addr, unsigned state)
{
Turnout &turnout = turnouts[addr];
- if(state==turnout.state || state==turnout.pending)
+ unsigned mask = (1<<turnout.bits)-1;
+ if(((state^turnout.state)&mask)==0 || ((state^turnout.pending)&mask)==0)
+ {
+ turnout.state = state;
+ turnout.pending = state;
+ signal_turnout.emit(addr, state);
return;
+ }
+ turnout.state = (turnout.state&mask) | (state&~mask);
turnout.pending = state;
turnout.active = true;
turnout.off_timeout = Time::TimeStamp();
- turnout_command(addr, state, true);
+ for(unsigned i=0; i<turnout.bits; ++i)
+ if((state^turnout.state)&(1<<i))
+ turnout_command(addr+i, state&(1<<i), true);
}
-bool Intellibox::get_turnout(unsigned addr) const
+unsigned 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;
+ return 0;
}
void Intellibox::add_sensor(unsigned addr)
i->second.speed += i->second.pending_half_step;
i->second.pending_half_step = 0;
i->second.half_step_delay = Time::TimeStamp();
- loco_command(i->first, (i->second.speed+1)/2, i->second.reverse, i->second.funcs|0x100);
+ loco_command(i->first, (i->second.speed+1)/2, i->second.reverse, i->second.funcs, false);
}
for(map<unsigned, Turnout>::iterator i=turnouts.begin(); i!=turnouts.end(); ++i)
queue.push_back(slot);
}
-void Intellibox::loco_command(unsigned addr, unsigned speed, bool rev, unsigned funcs)
+void Intellibox::loco_command(unsigned addr, unsigned speed, bool rev, unsigned funcs, bool setf)
{
unsigned char data[4];
data[0] = addr&0xFF;
data[3] = (rev ? 0 : 0x20) | ((funcs&1) ? 0x10 : 0);
- if(!(funcs&0x100))
+ if(setf)
data[3] |= 0x80 | ((funcs>>1)&0xF);
command(CMD_LOK, addr, data, 4);
{
unsigned addr = queue.front().addr;
Locomotive &loco = locos[addr];
- signal_loco_speed.emit(addr, loco.speed+loco.pending_half_step, loco.reverse);
- if(loco.pending_half_step)
- loco.half_step_delay = Time::now()+500*Time::msec;
+ if(loco.protocol)
+ {
+ signal_loco_speed.emit(addr, loco.speed+loco.pending_half_step, loco.reverse);
+ if(loco.pending_half_step)
+ loco.half_step_delay = Time::now()+500*Time::msec;
+ }
}
else
error(cmd, err);
read_status(&err);
unsigned addr = queue.front().addr;
+ unsigned mask = 1;
+ while(!turnouts[addr].bits)
+ {
+ --addr;
+ mask <<= 1;
+ }
Turnout &turnout = turnouts[addr];
if(err==ERR_NO_ERROR)
{
- turnout.state = turnout.pending;
+ turnout.state = (turnout.state&~mask) | (turnout.pending&mask);
if(turnout.active)
{
- signal_turnout.emit(addr, turnout.state);
+ if(turnout.state==turnout.pending)
+ signal_turnout.emit(addr, turnout.state);
turnout.off_timeout = t+500*Time::msec;
}
}
queue.push_back(queue.front());
else
{
- turnout.pending = turnout.state;
+ turnout.pending = (turnout.pending&~mask) | (turnout.state&mask);
error(cmd, err);
}
}
read_all(&data, 1);
unsigned addr = queue.front().addr;
- bool state = data&0x04;
-
+ unsigned mask = 1;
+ while(!turnouts[addr].bits)
+ {
+ --addr;
+ mask <<= 1;
+ }
Turnout &turnout = turnouts[addr];
- if(state!=turnout.state)
+
+ bool state = data&0x04;
+ if(state!=((turnout.state&mask)!=0))
{
- turnout.state = state;
- turnout.pending = state;
+ turnout.state = (turnout.state&~mask) | (state ? mask : 0);
+ turnout.pending = turnout.state;
signal_turnout.emit(addr, turnout.state);
}
}
Intellibox::Locomotive::Locomotive():
+ ext_func(false),
speed(0),
reverse(false),
funcs(0)
Intellibox::Turnout::Turnout():
- state(false),
+ bits(1),
+ state(0),
active(false),
pending(false)
{ }
enum Protocol
{
+ NONE,
MM,
MM_27
};
struct Locomotive
{
Protocol protocol;
+ bool ext_func;
unsigned speed;
bool reverse;
unsigned funcs;
struct Turnout
{
- bool state;
+ unsigned bits;
+ unsigned state;
bool active;
- bool pending;
+ unsigned pending;
Msp::Time::TimeStamp off_timeout;
Turnout();
virtual const char *enumerate_protocols(unsigned) const;
virtual unsigned get_protocol_speed_steps(const std::string &) const;
- virtual void add_loco(unsigned, const std::string &);
+ virtual void add_loco(unsigned, const std::string &, const VehicleType &);
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_turnout(unsigned, const TrackType &);
+ virtual void set_turnout(unsigned, unsigned);
+ virtual unsigned get_turnout(unsigned) const;
virtual void add_sensor(unsigned);
virtual void set_sensor(unsigned, bool) { }
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 loco_command(unsigned, unsigned, bool, unsigned, bool);
void turnout_command(unsigned, bool, bool);
void process_reply(const Msp::Time::TimeStamp &);
unsigned read_all(unsigned char *, unsigned);
}
}
-unsigned Layout::allocate_turnout_id(bool dbl)
+unsigned Layout::allocate_turnout_id()
{
set<unsigned> used_ids;
for(set<Track *>::const_iterator i=tracks.begin(); i!=tracks.end(); ++i)
used_ids.insert((*i)->get_turnout_id());
unsigned result = next_turnout_id;
- while(used_ids.count(result) || (dbl && used_ids.count(result+1)))
+ while(used_ids.count(result))
++result;
- next_turnout_id = result+1+dbl;
+ next_turnout_id = result+1;
return result;
}
void add_track(Track &);
const std::set<Track *> &get_tracks() const { return tracks; }
void remove_track(Track &);
- unsigned allocate_turnout_id(bool);
+ unsigned allocate_turnout_id();
void add_block(Block &);
Block &get_block(unsigned) const;
rot(0),
slope(0),
flex(false),
- turnout_id(type.is_turnout() ? layout.allocate_turnout_id(type.is_double_address()) : 0),
+ turnout_id(0),
sensor_id(0),
links(type.get_endpoints().size()),
active_path(0)
{
+ if(type.is_turnout())
+ turnout_id = layout.allocate_turnout_id();
+
layout.add_track(*this);
if(layout.has_driver())
layout.create_blocks(*this);
layout.update_routes();
if(layout.has_driver() && turnout_id)
- {
- layout.get_driver().add_turnout(turnout_id);
- if(type.is_double_address())
- layout.get_driver().add_turnout(turnout_id+1);
- }
+ layout.get_driver().add_turnout(turnout_id, type);
}
void Track::set_sensor_id(unsigned i)
if(!(type.get_paths()&(1<<p)))
throw InvalidParameterValue("Invalid path");
- layout.get_driver().set_turnout(turnout_id, p&1);
- if(type.is_double_address())
- layout.get_driver().set_turnout(turnout_id+1, p&2);
- else if(type.get_n_paths()>2)
- active_path = (active_path&1) | (p&2);
+ layout.get_driver().set_turnout(turnout_id, p);
}
int Track::get_endpoint_by_link(Track &other) const
st.push_back((DataFile::Statement("flex"), true));
}
-void Track::turnout_event(unsigned addr, bool state)
+void Track::turnout_event(unsigned addr, unsigned 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);
- else
- return;
-
- signal_path_changed.emit(active_path);
+ {
+ active_path = state;
+ signal_path_changed.emit(active_path);
+ }
}
void save(std::list<Msp::DataFile::Statement> &) const;
private:
- void turnout_event(unsigned, bool);
+ void turnout_event(unsigned, unsigned);
};
} // namespace R2C2
TrackType::TrackType(const ArticleNumber &an):
art_nr(an),
- double_address(false),
+ state_bits(0),
autofit_preference(1)
{ }
TrackType::Loader::Loader(TrackType &t):
- Msp::DataFile::BasicLoader<TrackType>(t)
+ Msp::DataFile::BasicLoader<TrackType>(t),
+ state_bits_set(false)
{
add("autofit_preference", &TrackType::autofit_preference);
add("description", &TrackType::description);
- add("double_address", &TrackType::double_address);
+ add("state_bits", &Loader::state_bits);
add("part", &Loader::part);
}
TrackPart p;
load_sub(p);
obj.parts.push_back(p);
+ if(!state_bits_set && p.get_path())
+ while(p.get_path()>=(1U<<obj.state_bits))
+ ++obj.state_bits;
+}
+
+void TrackType::Loader::state_bits(unsigned b)
+{
+ obj.state_bits = b;
+ state_bits_set = true;
}
} // namespace R2C2
class Loader: public Msp::DataFile::BasicLoader<TrackType>
{
+ private:
+ bool state_bits_set;
+
public:
Loader(TrackType &);
private:
virtual void finish();
void part();
void position(float, float, float);
+ void state_bits(unsigned);
};
private:
std::string description;
std::vector<TrackPart> parts;
std::vector<Endpoint> endpoints;
- bool double_address;
+ unsigned state_bits;
unsigned autofit_preference;
public:
float get_path_length(int) const;
unsigned get_paths() const;
unsigned get_n_paths() const;
+ unsigned get_state_bits() const { return state_bits; }
bool is_turnout() const;
bool is_dead_end() const;
- bool is_double_address() const { return double_address; }
unsigned get_autofit_preference() const { return autofit_preference; }
const std::vector<TrackPart> &get_parts() const { return parts; }
const std::vector<Endpoint> &get_endpoints() const { return endpoints; }
layout.add_train(*this);
- layout.get_driver().add_loco(address, protocol);
+ layout.get_driver().add_loco(address, protocol, loco_type);
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));
{
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);
+ layout.get_driver().set_loco_function(address, func, state);
}
float Train::get_control(const string &ctrl) const
void Train::loco_func_event(unsigned addr, unsigned func, bool state)
{
- if(addr==address || (addr==address+1 && loco_type.get_max_function()>4))
+ if(addr==address)
{
- if(addr==address+1)
- func += 4;
if(state)
functions |= 1<<func;
else
track 24630
{
description "Turnout, 3-way";
- double_address true;
part
{
length 188.3;
track 24624
{
description "Turnout, double slip";
+ state_bits 1;
part
{
length 188.3;