<td>Obtiene la planta de nombre [planta].</td>
<td>El mismo archivo que se crea en el Constructor.</td>
</tr>
+ <tr>
+ <td><tt>set/[planta]/[elem]/[prop]/[val]</tt></td>
+ <td>Cambia la propiedad [prop] del elemento [elem], asignándole
+ el valor [val] a planta de nombre [planta].</td>
+ <td>Nada.</td>
+ </tr>
+ <tr>
+ <td><tt>set_frequency/[planta]/[vecesxseg]</tt></td>
+ <td>Cambia la frecuencia de refresco de la simulación de la
+ planta de nombre [planta] a [vecesxseg] veces por
+ segundo. Si [vecesxseg] es cero ("0"), se usa la frecuencia
+ de refresco por omisión del servidor.</td>
+ <td>Nada.</td>
+ </tr>
+ <tr>
+ <td><tt>start/[planta]</tt></td>
+ <td>Reanuda (o comienza) la simulación de la planta de nombre
+ [planta].</td>
+ <td>Nada.</td>
+ </tr>
<tr>
<td><tt>stop/[planta]</tt></td>
- <td>Finaliza la simulación de la planta de nombre <planta>.</td>
+ <td>Pausa la simulación de la planta de nombre
+ [planta].</td>
<td>Nada.</td>
</tr>
<tr>
- <td><tt>set/[planta]/[elem]/[prop]/[val]</tt></td>
- <td>Cambia la propiedad [prop] del elemento [elem], asignándole
- el valor [val] a planta de nombre [planta].</td>
+ <td><tt>remove/[planta]</tt></td>
+ <td>Finaliza la simulación de la planta de nombre
+ [planta] eliminandola del servidor.</td>
<td>Nada.</td>
</tr>
</table>
/// Planta Química.
class Plant: public Runnable {
+ /////////////////////////////////////////////////////////////////////
+ // Constantes.
+
+ private:
+
+ /// Tiempo por defecto a esperar entre iteraciones de la simulación.
+ static const unsigned DEFAULT_WAIT_TIME = 100000u;
+
/////////////////////////////////////////////////////////////////////
// Tipos.
/// Nombre del archivo donde esta el XML de la planta.
std::string filename;
+ /// Tiempo que espera entre cada iteración de la simulación.
+ unsigned wait_time;
+
+ /// Mutex para el tiempo de espera.
+ Glib::Mutex wait_time_mutex;
+
+ /// Indica si la planta está pausada o simulando.
+ bool paused;
+
+ /// Mutex para el indicador de pausa.
+ Glib::Mutex paused_mutex;
+
/////////////////////////////////////////////////////////////////////
// Métodos.
*/
bool set_open(const std::string& element, bool open = true);
+ /**
+ * Setea la frecuencia de refresco de la simulación.
+ * Si se setea a cero, se usa el tiempo por omisión.
+ *
+ * \param hz Cantidad de veces por segundo que debe refrescarse la
+ * simulación.
+ */
+ void set_frequency(unsigned hz = 0u);
+
+ /**
+ * Pausa (o reanuda) la simulación.
+ *
+ * \param paused true si se la quiere pausar, false para reanudar.
+ */
+ void set_paused(bool paused = true);
+
/**
* Obtiene el XML de la planta.
*/
HTTPResponse* cmd_plant_get(const Command& command);
/**
- * Maneja el comando plant/get.
+ * Maneja el comando plant/set.
*/
HTTPResponse* cmd_plant_set(const Command& command);
+ /**
+ * Maneja el comando plant/set_frequency.
+ */
+ HTTPResponse* cmd_plant_set_frequency(const Command& command);
+
+ /**
+ * Maneja el comando plant/start.
+ */
+ HTTPResponse* cmd_plant_start(const Command& command);
+
/**
* Maneja el comando plant/stop.
*/
HTTPResponse* cmd_plant_stop(const Command& command);
+ /**
+ * Maneja el comando plant/remove.
+ */
+ HTTPResponse* cmd_plant_remove(const Command& command);
+
public:
/**
}
}
-Plant::Plant(const string& filename): simulator(filename), filename(filename) {
+Plant::Plant(const string& filename): simulator(filename), filename(filename),
+ wait_time(DEFAULT_WAIT_TIME), paused(true) {
#ifdef DEBUG
cerr << __FILE__ << "(" << __LINE__ << ")"
<< ": constructor. filename = " << filename << endl;
cerr << __FILE__ << "(" << __LINE__ << ")"
<< ": real_run." << endl;
#endif // DEBUG
+ unsigned wait;
while (!stop()) {
- simulator_mutex.lock();
- simulator.simulate();
- string plantstatus = simulator.get_state_as_xml();
- simulator_mutex.unlock();
- transmissions_mutex.lock();
- for (TransmitterList::iterator i = transmissions.begin();
- i != transmissions.end(); i++) {
- (*i)->send(plantstatus);
+ if (paused) { // Si está pausada, espera un tiempo sin simular.
+ Glib::usleep(DEFAULT_WAIT_TIME);
+ } else { // Si está andando, simula y manda estado.
+ simulator_mutex.lock();
+ simulator.simulate();
+ string plantstatus = simulator.get_state_as_xml();
+ simulator_mutex.unlock();
+ transmissions_mutex.lock();
+ for (TransmitterList::iterator i = transmissions.begin();
+ i != transmissions.end(); i++) {
+ (*i)->send(plantstatus);
+ }
+ transmissions_mutex.unlock();
+ wait_time_mutex.lock();
+ wait = wait_time;
+ wait_time_mutex.unlock();
+ Glib::usleep(wait);
}
- transmissions_mutex.unlock();
- Glib::usleep(100000);
}
}
return oss.str();
}
+void Plant::set_frequency(unsigned hz) {
+ Glib::Mutex::Lock lock(wait_time_mutex);
+ wait_time = hz ? (1000000u/hz) : DEFAULT_WAIT_TIME;
+}
+
+void Plant::set_paused(bool paused_) {
+ Glib::Mutex::Lock lock(paused_mutex);
+ paused = paused_;
+}
+
/*
bool Plant::transmission_exists(const string& host,
const Connection::Port& port) {
response = cmd_plant_get(command);
} else if (command.get_command() == "set") {
response = cmd_plant_set(command);
+ } else if (command.get_command() == "set_frequency") {
+ response = cmd_plant_set_frequency(command);
+ } else if (command.get_command() == "start") {
+ response = cmd_plant_start(command);
} else if (command.get_command() == "stop") {
response = cmd_plant_stop(command);
} else {
string("<response desc=\"Se cambió el estado del elemento '") + element + "'.\" />");
}
+HTTPResponse* Server::cmd_plant_set_frequency(const Command& command) {
+ if (command.get_args().size() < 2) {
+ return new HTTPResponse(HTTPMessage::CONFLICT,
+ "<response desc=\"Faltan argumentos.\" />");
+ }
+ Glib::Mutex::Lock lock(plants_mutex);
+ const string name = command.get_args()[0];
+ if (plants.find(name) == plants.end()) {
+ return new HTTPResponse(HTTPMessage::NOT_FOUND,
+ string("<response desc=\"No existe la planta ") + name + "\" />");
+ }
+ unsigned hz;
+ to(command.get_args()[1], hz);
+ plants[name]->set_frequency(hz);
+ return new HTTPResponse(HTTPMessage::OK,
+ string("<response desc=\"La planta '") + name + "' fue pausada.\" />");
+}
+
+HTTPResponse* Server::cmd_plant_start(const Command& command) {
+ if (!command.get_args().size()) {
+ return new HTTPResponse(HTTPMessage::CONFLICT,
+ "<response desc=\"Faltan argumentos.\" />");
+ }
+ Glib::Mutex::Lock lock(plants_mutex);
+ const string name = command.get_args()[0];
+ if (plants.find(name) == plants.end()) {
+ return new HTTPResponse(HTTPMessage::NOT_FOUND,
+ string("<response desc=\"No existe la planta ") + name + "\" />");
+ }
+ plants[name]->set_paused(false);
+ return new HTTPResponse(HTTPMessage::OK,
+ string("<response desc=\"La planta '") + name + "' fue reanudada.\" />");
+}
+
HTTPResponse* Server::cmd_plant_stop(const Command& command) {
if (!command.get_args().size()) {
return new HTTPResponse(HTTPMessage::CONFLICT,
return new HTTPResponse(HTTPMessage::NOT_FOUND,
string("<response desc=\"No existe la planta ") + name + "\" />");
}
- // TODO Ver si al frenar la planta se destruye (no deberia!!!)
+ plants[name]->set_paused(true);
+ return new HTTPResponse(HTTPMessage::OK,
+ string("<response desc=\"La planta '") + name + "' fue pausada.\" />");
+}
+
+HTTPResponse* Server::cmd_plant_remove(const Command& command) {
+ if (!command.get_args().size()) {
+ return new HTTPResponse(HTTPMessage::CONFLICT,
+ "<response desc=\"Faltan argumentos.\" />");
+ }
+ Glib::Mutex::Lock lock(plants_mutex);
+ const string name = command.get_args()[0];
+ if (plants.find(name) == plants.end()) {
+ return new HTTPResponse(HTTPMessage::NOT_FOUND,
+ string("<response desc=\"No existe la planta ") + name + "\" />");
+ }
plants[name]->finish();
return new HTTPResponse(HTTPMessage::OK,
string("<response desc=\"La planta '") + name + "' se cerrará en instantes...\" />");