baseexperiment.h
1 /********************************************************************************
2  * FARSA *
3  * Copyright (C) 2007-2012 *
4  * Gianluca Massera <emmegian@yahoo.it> *
5  * Stefano Nolfi <stefano.nolfi@istc.cnr.it> *
6  * Tomassino Ferrauto <tomassino.ferrauto@istc.cnr.it> *
7  * *
8  * This program is free software; you can redistribute it and/or modify *
9  * it under the terms of the GNU General Public License as published by *
10  * the Free Software Foundation; either version 2 of the License, or *
11  * (at your option) any later version. *
12  * *
13  * This program is distributed in the hope that it will be useful, *
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16  * GNU General Public License for more details. *
17  * *
18  * You should have received a copy of the GNU General Public License *
19  * along with this program; if not, write to the Free Software *
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA *
21  ********************************************************************************/
22 
23 #ifndef BASEEXPERIMENT_H
24 #define BASEEXPERIMENT_H
25 
26 #include "experimentsconfig.h"
27 #include "dataexchange.h"
28 #include "component.h"
29 #include "workerthread.h"
30 #include "parametersettable.h"
31 #include "parametersettableui.h"
32 #include "baseexception.h"
33 #include "configurationhelper.h"
34 #include "logger.h"
35 #include "flowcontrol.h"
36 #include <QMutex>
37 #include <QMutexLocker>
38 #include <QWaitCondition>
39 #include <QSignalMapper>
40 #include <QList>
41 #include <QVector>
42 #include <QAction>
43 #include <QMenu>
44 #include <QMenuBar>
45 #include <memory>
46 #include <QtGlobal>
47 
48 namespace farsa {
49 
50 class BaseExperimentGUI;
51 
57 namespace __BaseExperiment_internal {
58  class BaseExperimentUIManager;
59 
64  struct FARSA_EXPERIMENTS_TEMPLATE OperationStatus {
68  enum Status {
73  OperationResumed,
75  OperationStepDelayChanged
77  };
78 
83 
90  unsigned int operationID;
91 
98  unsigned long delay;
99  };
100 
105  struct FARSA_EXPERIMENTS_TEMPLATE OperationControl {
109  enum Action {
111  StartOperationPaused,
118  StepOperation,
120  ResumeOperation,
122  ChangeInterval
124  };
125 
130 
136  unsigned int operationID;
137 
143  unsigned long interval;
144  };
145 }
146 
265 class FARSA_EXPERIMENTS_API BaseExperiment : public Component, public ParameterSettableUI, public ThreadOperation, private FlowControlled
266 {
267  Q_OBJECT
268 
269 private:
279  class Notifee : public NewDatumNotifiable<__BaseExperiment_internal::OperationControl>
280  {
281  public:
287  Notifee(BaseExperiment& experiment);
288 
292  virtual ~Notifee();
293 
300  virtual void newDatumAvailable(DataDownloader<__BaseExperiment_internal::OperationControl>* downloader);
301 
302  private:
306  BaseExperiment& m_experiment;
307  };
308 
313  friend class Notifee;
314 
322  class BaseExperimentFlowController : public FlowController
323  {
324  public:
331  BaseExperimentFlowController(BaseExperiment* baseExperiment);
332 
341  virtual bool stop();
342 
348  virtual void pause();
349 
350  private:
354  BaseExperiment* m_baseExperiment;
355  };
356 
361  friend class BaseExperimentFlowController;
362 
363 public:
371  {
372  public:
376  QString getName() const
377  {
378  return name;
379  }
380 
385  bool getUseSeparateThread() const
386  {
387  return useSeparateThread;
388  }
389 
393  bool getSteppable() const
394  {
395  return steppable;
396  }
397 
398  private:
405  virtual ~AbstractOperationWrapper()
406  {
407  }
408 
415  virtual void executeOperation() = 0;
416 
420  QString name;
421 
426  bool useSeparateThread;
427 
431  bool steppable;
432 
437  friend class BaseExperiment;
438 
442  template <class T>
443  friend class std::auto_ptr;
444  };
445 
452  template <class T>
454  {
455  public:
463  OperationWrapper(T* experiment, void (T::*operation)())
465  , m_experiment(experiment)
466  , m_operation(operation)
467  {
468  }
469 
470  private:
474  virtual ~OperationWrapper()
475  {
476  }
477 
481  virtual void executeOperation()
482  {
483  (m_experiment->*m_operation)();
484  }
485 
489  T* const m_experiment;
490 
495  void (T::*m_operation)();
496  };
497 
504  template <class T, class P0>
506  {
507  public:
516  OperationWrapperOneParameter(T* experiment, void (T::*operation)(P0), P0 p0)
518  , m_experiment(experiment)
519  , m_operation(operation)
520  , m_p0(p0)
521  {
522  }
523 
529  const P0& p0() const
530  {
531  return m_p0;
532  }
533 
534  private:
539  {
540  }
541 
545  virtual void executeOperation()
546  {
547  (m_experiment->*m_operation)(m_p0);
548  }
549 
553  T* const m_experiment;
554 
559  void (T::*m_operation)(P0);
560 
564  const P0 m_p0;
565  };
566 
573  template <class T, class P0, class P1>
575  {
576  public:
586  OperationWrapperTwoParameters(T* experiment, void (T::*operation)(P0, P1), P0 p0, P1 p1)
588  , m_experiment(experiment)
589  , m_operation(operation)
590  , m_p0(p0)
591  , m_p1(p1)
592  {
593  }
594 
601  const P0& p0() const
602  {
603  return m_p0;
604  }
605 
612  const P1& p1() const
613  {
614  return m_p1;
615  }
616 
617  private:
622  {
623  }
624 
628  virtual void executeOperation()
629  {
630  (m_experiment->*m_operation)(m_p0, m_p1);
631  }
632 
636  T* const m_experiment;
637 
642  void (T::*m_operation)(P0, P1);
643 
647  const P0 m_p0;
648 
652  const P1 m_p1;
653  };
654 
661  template <class T, class P0, class P1, class P2>
663  {
664  public:
675  OperationWrapperThreeParameters(T* experiment, void (T::*operation)(P0, P1, P2), P0 p0, P1 p1, P2 p2)
677  , m_experiment(experiment)
678  , m_operation(operation)
679  , m_p0(p0)
680  , m_p1(p1)
681  , m_p2(p2)
682  {
683  }
684 
691  const P0& p0() const
692  {
693  return m_p0;
694  }
695 
702  const P1& p1() const
703  {
704  return m_p1;
705  }
706 
713  const P2& p2() const
714  {
715  return m_p2;
716  }
717 
718  private:
723  {
724  }
725 
729  virtual void executeOperation()
730  {
731  (m_experiment->*m_operation)(m_p0, m_p1, m_p2);
732  }
733 
737  T* const m_experiment;
738 
743  void (T::*m_operation)(P0, P1, P2);
744 
748  const P0 m_p0;
749 
753  const P1 m_p1;
754 
758  const P1 m_p2;
759  };
760 
761 public:
765  BaseExperiment();
766 
774  virtual ~BaseExperiment();
775 
786  virtual void configure(ConfigurationParameters& params, QString prefix);
787 
797  virtual void save(ConfigurationParameters& params, QString prefix);
798 
814  static void describe(QString type);
815 
823  virtual void postConfigureInitialization();
824 
833  virtual ParameterSettableUI* getUIManager();
834 
844  virtual void fillActionsMenu(QMenu* actionsMenu);
845 
858  virtual QList<ParameterSettableUIViewer> getViewers(QWidget* parent, Qt::WindowFlags flags);
859 
865  virtual void addAdditionalMenus(QMenuBar* menuBar);
866 
873  virtual void run();
874 
882  virtual void stop();
883 
890  void pause();
891 
899  void step();
900 
907  void resume();
908 
918  void changeInterval(unsigned long interval);
919 
925  unsigned long currentInterval() const;
926 
932  const QVector<AbstractOperationWrapper*>& getOperations() const;
933 
942  DataUploaderDownloader<__BaseExperiment_internal::OperationStatus, __BaseExperiment_internal::OperationControl>* getUploaderDownloader();
943 
953  {
954  return &m_flowController;
955  }
956 
957 public slots:
965  virtual void stopCurrentOperation(bool wait);
966 
972  virtual void stopCurrentOperation();
973 
974 private slots:
982  void exceptionDuringOperation(farsa::BaseException *e);
983 
992  void runOperation(int operationID);
993 
994 protected:
1006  QList<QAction*> getActionsForOperations(QObject* actionsParent) const;
1007 
1034  template <class T>
1035  void addOperation(QString name, void (T::*func)(), bool useSeparateThread, bool steppable)
1036  {
1037  std::auto_ptr<AbstractOperationWrapper> newOp(new OperationWrapper<T>(static_cast<T*>(this), func));
1038  newOp->name = name;
1039  newOp->useSeparateThread = useSeparateThread;
1040  newOp->steppable = steppable;
1041 
1042  m_operationsVector.push_back(newOp.release());
1043 
1044  // Signalling a new operation has been added
1045  uploadNewOperationStatus(__BaseExperiment_internal::OperationStatus::NewOperation, m_operationsVector.size() - 1);
1046  }
1047 
1067  template <class T, class P0>
1068  void addOperation(QString name, void (T::*func)(P0), P0 p0, bool useSeparateThread, bool steppable)
1069  {
1070  std::auto_ptr<AbstractOperationWrapper> newOp(new OperationWrapperOneParameter<T, P0>(static_cast<T*>(this), func, p0));
1071  newOp->name = name;
1072  newOp->useSeparateThread = useSeparateThread;
1073  newOp->steppable = steppable;
1074 
1075  m_operationsVector.push_back(newOp.release());
1076 
1077  // Signalling a new operation has been added
1078  uploadNewOperationStatus(__BaseExperiment_internal::OperationStatus::NewOperation, m_operationsVector.size() - 1);
1079  }
1080 
1101  template <class T, class P0, class P1>
1102  void addOperation(QString name, void (T::*func)(P0, P1), P0 p0, P1 p1, bool useSeparateThread, bool steppable)
1103  {
1104  std::auto_ptr<AbstractOperationWrapper> newOp(new OperationWrapperTwoParameters<T, P0, P1>(static_cast<T*>(this), func, p0, p1));
1105  newOp->name = name;
1106  newOp->useSeparateThread = useSeparateThread;
1107  newOp->steppable = steppable;
1108 
1109  m_operationsVector.push_back(newOp.release());
1110 
1111  // Signalling a new operation has been added
1112  uploadNewOperationStatus(__BaseExperiment_internal::OperationStatus::NewOperation, m_operationsVector.size() - 1);
1113  }
1114 
1136  template <class T, class P0, class P1, class P2>
1137  void addOperation(QString name, void (T::*func)(P0, P1, P2), P0 p0, P1 p1, P2 p2, bool useSeparateThread, bool steppable)
1138  {
1139  std::auto_ptr<AbstractOperationWrapper> newOp(new OperationWrapperThreeParameters<T, P0, P1, P2>(static_cast<T*>(this), func, p0, p1, p2));
1140  newOp->name = name;
1141  newOp->useSeparateThread = useSeparateThread;
1142  newOp->steppable = steppable;
1143 
1144  m_operationsVector.push_back(newOp.release());
1145 
1146  // Signalling a new operation has been added
1147  uploadNewOperationStatus(__BaseExperiment_internal::OperationStatus::NewOperation, m_operationsVector.size() - 1);
1148  }
1149 
1155  bool batchRunning() const;
1156 
1161 
1166 
1167 private:
1175  bool stopSimulation();
1176 
1186  void checkPause();
1187 
1191  void resetStop();
1192 
1202  void uploadNewOperationStatus(__BaseExperiment_internal::OperationStatus::Status status, unsigned int operationID, unsigned long newDelay = 0);
1203 
1215  void changeInterval(unsigned long interval, bool sendNotificationToGUI);
1216 
1220  QVector<AbstractOperationWrapper*> m_operationsVector;
1221 
1228  std::auto_ptr<QSignalMapper> m_actionSignalsMapper;
1229 
1233  std::auto_ptr<WorkerThread> const m_workerThread;
1234 
1241  int m_runningOperationID;
1242 
1246  bool m_batchRunning;
1247 
1251  bool m_stop;
1252 
1257  QMutex m_mutex;
1258 
1263  QWaitCondition m_waitCondition;
1264 
1268  bool m_pause;
1269 
1275  bool m_previousPauseStatus;
1276 
1280  unsigned long m_delay;
1281 
1285  Notifee m_notifee;
1286 
1299 
1303  BaseExperimentFlowController m_flowController;
1304 };
1305 
1306 } // End namespace farsa
1307 
1316 #define DECLARE_THREAD_OPERATION(classname, op) addOperation(#op, &classname::op, true, false);
1317 
1326 #define DECLARE_STEPPABLE_THREAD_OPERATION(classname, op) addOperation(#op, &classname::op, true, true);
1327 
1336 #define DECLARE_IMMEDIATE_OPERATION(classname, op) addOperation(#op, &classname::op, false, false);
1337 
1338 #endif
bool getUseSeparateThread() const
Returns true if the operation is run in a separate thread.
The class for operation wrappers.
OperationWrapperTwoParameters(T *experiment, void(T::*operation)(P0, P1), P0 p0, P1 p1)
Constructor.
const P0 & p0() const
Returns the first parameter that is passed to the function.
The base for classes that have a controllable flow of execution.
Definition: flowcontrol.h:170
unsigned int operationID
The id of the operation that was added/started/ended...
The class for operation wrappers taking two parameters.
unsigned long delay
The new delay for steps of the current operation.
OperationWrapper(T *experiment, void(T::*operation)())
Constructor.
QString getName() const
Returns the name of the operation.
The class for operation wrappers taking one parameter.
void addOperation(QString name, void(T::*func)(), bool useSeparateThread, bool steppable)
The function that adds the given operation to the list of all operations declared by the experiment...
const P0 & p0() const
Returns the first parameter that is passed to the function.
OperationWrapperOneParameter(T *experiment, void(T::*operation)(P0), P0 p0)
Constructor.
The base abstract class for operation wrappers.
This file contains the common type defitions used on the whole framework.
Action
The list of possible actions to perform.
void addOperation(QString name, void(T::*func)(P0, P1, P2), P0 p0, P1 p1, P2 p2, bool useSeparateThread, bool steppable)
The function that adds the given operation that takes three parameters to the list of all operations ...
const P1 & p1() const
Returns the second parameter that is passed to the function.
const P1 & p1() const
Returns the second parameter that is passed to the function.
FlowController * flowController()
Returns the flow controller.
unsigned long interval
The new interval in milliseconds.
const P2 & p2() const
Returns the third parameter that is passed to the function.
const P0 & p0() const
Returns the parameter that is passed to the function.
The Component is the base (abstract) class for any specific project implementation.
Definition: component.h:45
The interface for classes controlling the flow of execution.
Definition: flowcontrol.h:36
void addOperation(QString name, void(T::*func)(P0), P0 p0, bool useSeparateThread, bool steppable)
The function that adds the given operation that takes one parameter to the list of all operations dec...
void addOperation(QString name, void(T::*func)(P0, P1), P0 p0, P1 p1, bool useSeparateThread, bool steppable)
The function that adds the given operation that takes two parameters to the list of all operations de...
void pauseFlow()
Performs a pause in the if needed.
Definition: flowcontrol.h:236
bool getSteppable() const
Returns true if the operation can be run step-by-step.
bool stopFlow()
Checks if execution should stop as soon as possible.
Definition: flowcontrol.h:225
The class for operation wrappers taking three parameters.
The base class for experiments.
The data sent by a BaseExperimentGUI instance to the corresponding experiment.
unsigned int operationID
The id of the operation to start.
The data sent by a BaseExperiment instance to the corresponding GUI.
OperationWrapperThreeParameters(T *experiment, void(T::*operation)(P0, P1, P2), P0 p0, P1 p1, P2 p2)
Constructor.