TrainPanel::TrainPanel(Engineer &e, Train &t):
engineer(e),
train(t),
+ status(train),
expanded(false)
{
set_size(200, 65);
lbl_route->set_geometry(GLtk::Geometry(10, 85, geom.w-20, 20));
train.signal_route_changed.connect(sigc::mem_fun(this, &TrainPanel::train_route_changed));
- pnl_extra->add(*(lbl_status = new GLtk::Label(train.get_status())));
+ pnl_extra->add(*(lbl_status = new GLtk::Label(status.get_status())));
lbl_status->set_style("digital");
lbl_status->set_geometry(GLtk::Geometry(10, 60, geom.w-20, 20));
- train.signal_status_changed.connect(sigc::mem_fun(this, &TrainPanel::train_status_changed));
+ status.signal_changed.connect(sigc::mem_fun(this, &TrainPanel::train_status_changed));
const map<unsigned, string> &funcs = train.get_locomotive_type().get_functions();
unsigned x = 10;
lbl_speed->set_text(format("%3.0f", speed));
}
else if(msg.type=="reverse-changed")
- tgl_forward->set_value(msg.value.value<bool>());
+ tgl_forward->set_value(!msg.value.value<bool>());
}
void TrainPanel::train_function_changed(unsigned func, bool value)
#include <msp/gltk/toggle.h>
#include "libr2c2/route.h"
#include "libr2c2/train.h"
+#include "libr2c2/trainstatus.h"
class Engineer;
private:
Engineer &engineer;
R2C2::Train &train;
+ R2C2::TrainStatus status;
Msp::GLtk::Panel *pnl_basic;
Msp::GLtk::Panel *pnl_extra;
Msp::GLtk::Button *btn_expand;
reverse(false),
functions(0),
end_of_route(false),
- status("Unplaced"),
travel_dist(0),
pure_speed(false),
speed_quantizer(0),
reserve_more();
}
else
- {
stop_timeout = Time::now()+2*Time::sec;
- set_status("Stopped");
- }
}
void Train::set_function(unsigned func, bool state)
return controller->get_speed();
}
+float Train::get_quantized_speed() const
+{
+ if(speed_quantizer)
+ return speed_quantizer->quantize_speed(controller->get_speed());
+ else
+ return controller->get_speed();
+}
+
bool Train::get_function(unsigned func) const
{
return (functions>>func)&1;
ais.erase(i);
}
-TrainAI *Train::get_tagged_ai(const string &tag)
+TrainAI *Train::get_tagged_ai(const string &tag) const
{
- for(list<TrainAI *>::iterator i=ais.begin(); i!=ais.end(); ++i)
+ for(list<TrainAI *>::const_iterator i=ais.begin(); i!=ais.end(); ++i)
if((*i)->get_tag()==tag)
return *i;
accurate_position = false;
if(!block.reserve(this))
- {
- set_status("Unplaced");
return;
- }
blocks.push_back(BlockIter(&block, entry));
if(reverse)
for(vector<Vehicle *>::iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
(*i)->unplace();
-
- set_status("Unplaced");
}
bool Train::free_block(Block &block)
driver.set_loco_speed(address, speed_step);
pure_speed = false;
-
- if(speed_step)
- set_status(format("Traveling %d kmh", get_travel_speed()));
- else
- set_status("Waiting");
}
speed = speed_quantizer->get_speed(current_speed_step);
// Compute speed and update related state
float travel_time_secs = (Time::now()-last_entry_time)/Time::sec;
- if(pure_speed)
- {
- if(speed_quantizer && current_speed_step>0)
- speed_quantizer->learn(current_speed_step, travel_dist/travel_time_secs, travel_time_secs);
- set_status(format("Traveling %d kmh", get_travel_speed()));
- }
+ if(pure_speed && speed_quantizer && current_speed_step>0)
+ speed_quantizer->learn(current_speed_step, travel_dist/travel_time_secs, travel_time_secs);
travel_dist = 0;
for(BlockList::iterator j=cur_blocks_end; j!=end; ++j)
return result;
}
-float Train::get_travel_speed() const
-{
- float speed = 0;
- if(speed_quantizer)
- speed = speed_quantizer->get_speed(current_speed_step);
- else
- speed = controller->get_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;
- signal_status_changed.emit(s);
-}
-
void Train::release_blocks()
{
release_blocks(blocks.begin(), blocks.end());
TrackIter track = obj.blocks.front().track_iter();
float offset = 2*obj.layout.get_catalogue().get_scale();
obj.vehicles.back()->place(*track, track.entry(), offset, Vehicle::BACK_BUFFER);
-
- obj.set_status("Stopped");
}
}
unsigned functions;
std::list<RouteRef> routes;
bool end_of_route;
- std::string status;
Msp::Time::TimeStamp last_entry_time;
float travel_dist;
void set_function(unsigned, bool);
float get_control(const std::string &) const;
float get_speed() const;
+ float get_quantized_speed() const;
+ unsigned get_speed_step() const { return current_speed_step; }
bool is_active() const { return active; }
bool get_function(unsigned) const;
unsigned get_functions() const { return functions; }
void add_ai(TrainAI &);
void remove_ai(TrainAI &);
- TrainAI *get_tagged_ai(const std::string &);
+ TrainAI *get_tagged_ai(const std::string &) const;
void ai_message(const TrainAI::Message &);
bool set_route(const Route *);
int get_entry_to_block(Block &) const;
float get_reserved_distance() const;
- const std::string &get_status() const { return status; }
-
void tick(const Msp::Time::TimeStamp &, const Msp::Time::TimeDelta &);
void save(std::list<Msp::DataFile::Statement> &) const;
void reserve_more();
void check_turnout_paths(bool);
float get_reserved_distance_until(const Block *, bool) const;
- float get_real_speed(unsigned) const;
- unsigned find_speed_step(float) const;
- float get_travel_speed() const;
- void set_status(const std::string &);
void release_blocks();
void release_blocks(BlockList::iterator, BlockList::iterator);
void reverse_blocks(BlockList &) const;
--- /dev/null
+/* $Id$
+
+This file is part of R²C²
+Copyright © 2011 Mikkosoft Productions, Mikko Rasa
+Distributed under the GPL
+*/
+
+#include <msp/strings/formatter.h>
+#include "catalogue.h"
+#include "layout.h"
+#include "train.h"
+#include "trainstatus.h"
+#include "vehicle.h"
+
+using namespace Msp;
+
+#include <msp/io/print.h>
+
+namespace R2C2 {
+
+TrainStatus::TrainStatus(Train &t):
+ TrainAI(t),
+ speed(-2)
+{
+ check();
+}
+
+void TrainStatus::tick(const Time::TimeStamp &, const Time::TimeDelta &)
+{
+ check();
+}
+
+void TrainStatus::check()
+{
+ float scale = train.get_layout().get_catalogue().get_scale();
+ int s = static_cast<int>(train.get_quantized_speed()*3.6/scale+0.5);
+ if(s==0 && train.is_active())
+ s = -1;
+
+ if(s!=speed)
+ {
+ if(s>0)
+ {
+ status = format("Traveling %d kmh", s);
+ if(unsigned step = train.get_speed_step())
+ status += format(" (%d)", step);
+ }
+ else if(s==-1)
+ status = "Waiting";
+ else if(!train.get_vehicle(0).get_track())
+ status = "Unplaced";
+ else
+ status = "Stopped";
+
+ speed = s;
+
+ signal_changed.emit(status);
+ signal_event.emit(Message("status-changed", status));
+ }
+}
+
+} // namespace R2C2
--- /dev/null
+/* $Id$
+
+This file is part of R²C²
+Copyright © 2011 Mikkosoft Productions, Mikko Rasa
+Distributed under the GPL
+*/
+
+#ifndef LIBR2C2_TRAINSTATUS_H_
+#define LIBR2C2_TRAINSTATUS_H_
+
+#include <string>
+#include <sigc++/signal.h>
+#include "trainai.h"
+
+namespace R2C2 {
+
+class Train;
+
+/**
+Provides textual description of the status of a train.
+*/
+class TrainStatus: public TrainAI
+{
+public:
+ sigc::signal<void, const std::string &> signal_changed;
+
+private:
+ int speed;
+ std::string status;
+
+public:
+ TrainStatus(Train &);
+
+ const std::string &get_status() const { return status; }
+ void tick(const Msp::Time::TimeStamp &, const Msp::Time::TimeDelta &);
+private:
+ void check();
+};
+
+} // namespace R2C2
+
+#endif
pkt.loco_type = train.get_locomotive_type().get_article_number().str();
pkt.name = train.get_name();
send(pkt);
+
+ TrainStatus *status = new TrainStatus(train);
+ status->set_tag("server:status");
+ status->signal_changed.connect(sigc::bind<0>(sigc::mem_fun(this, &Server::train_status_changed), sigc::ref(train)));
}
void Server::train_control_changed(const Train &train, const string &control, float value)
pkt.functions = train.get_functions();
comm.send(pkt);
}
+ if(TrainStatus *status = dynamic_cast<TrainStatus *>(train.get_tagged_ai("server:status")))
{
TrainStatusPacket pkt;
pkt.address = train.get_address();
- pkt.status = train.get_status();
+ pkt.status = status->get_status();
comm.send(pkt);
}
if(train.get_route())
/* $Id$
This file is part of R²C²
-Copyright © 2009-2010 Mikkosoft Productions, Mikko Rasa
+Copyright © 2009-2011 Mikkosoft Productions, Mikko Rasa
Distributed under the GPL
*/
#include <msp/net/streamsocket.h>
#include <msp/net/streamlistensocket.h>
#include "libr2c2/layout.h"
+#include "libr2c2/trainstatus.h"
#include "packets.h"
#include "protocol.h"