Index: trunk/lib/FlairCore/src/IODevice.cpp
===================================================================
--- trunk/lib/FlairCore/src/IODevice.cpp	(revision 24)
+++ trunk/lib/FlairCore/src/IODevice.cpp	(revision 38)
@@ -27,7 +27,7 @@
 namespace core {
 
-IODevice::IODevice(const Object *parent, string name)
-    : Object(parent, name, "IODevice") {
-  pimpl_ = new IODevice_impl(this);
+IODevice::IODevice(const Object* parent,string name): Object(parent,name,"IODevice") {
+    pimpl_=new IODevice_impl(this);
+    lastUpdate=GetTime();
 }
 
@@ -48,7 +48,7 @@
   }
 
-  if (data != NULL) {
-    if (getFrameworkManager()->IsLogging() == true)
-      pimpl_->WriteLog(data->DataTime());
+    if(data!=NULL) {
+        lastUpdate=data->DataTime();
+        if(getFrameworkManager()->IsLogging()==true) pimpl_->WriteLog(data->DataTime());
 
     data->pimpl_->Circle();
Index: trunk/lib/FlairCore/src/IODevice.h
===================================================================
--- trunk/lib/FlairCore/src/IODevice.h	(revision 24)
+++ trunk/lib/FlairCore/src/IODevice.h	(revision 38)
@@ -114,21 +114,20 @@
   virtual DataType const &GetOutputDataType() const;
 
-protected:
-  /*!
-  * \brief Process the childs of type IODevice, and log if needed
-  *
-  * This method must be called after computing datas;
-  * generally at the end of the reimplemented UpdateFrom or after acquiring
-  *datas in case of a sensor. \n
-  * It will call UpdateFrom methods of each child of type IODevice,
-  * and log all datas (this IODevice and its childs)
-  * if logging is enabled (see SetDataToLog(), AddDeviceToLog(),
-  * FrameworkManager::StartLog and FrameworkManager::AddDeviceToLog). \n
-  * If a thread is waiting on this IODevice (see Thread::WaitUpdate), it will be
-  *resumed.
-  *
-  * \param data data to process
-  */
-  void ProcessUpdate(io_data *data);
+            Time lastUpdate;
+        protected:
+            /*!
+            * \brief Process the childs of type IODevice, and log if needed
+            *
+            * This method must be called after computing datas;
+            * generally at the end of the reimplemented UpdateFrom or after acquiring datas in case of a sensor. \n
+            * It will call UpdateFrom methods of each child of type IODevice,
+            * and log all datas (this IODevice and its childs)
+            * if logging is enabled (see SetDataToLog(), AddDeviceToLog(),
+            * FrameworkManager::StartLog and FrameworkManager::AddDeviceToLog). \n
+            * If a thread is waiting on this IODevice (see Thread::WaitUpdate), it will be resumed.
+            *
+            * \param data data to process
+            */
+            void ProcessUpdate(io_data* data);
 
 private:
Index: trunk/lib/FlairCore/src/Thread_impl.cpp
===================================================================
--- trunk/lib/FlairCore/src/Thread_impl.cpp	(revision 24)
+++ trunk/lib/FlairCore/src/Thread_impl.cpp	(revision 38)
@@ -28,4 +28,6 @@
 #else
 #include <sys/resource.h>
+#include <unistd.h>
+#include <sys/syscall.h>
 #endif
 
@@ -153,6 +155,9 @@
 }
 #else
-void *Thread_impl::main_nrt(void *arg) {
-  Thread_impl *caller = (Thread_impl *)arg;
+void* Thread_impl::main_nrt(void * arg)
+{
+    Thread_impl *caller = (Thread_impl*)arg;
+/*string th_name=getFrameworkManager()->ObjectName()+ "-" + caller->self->ObjectName();
+caller->self->Info("pthread '%s' created with TID %x\n",th_name.c_str(),(pid_t)syscall(SYS_gettid));*/
 
   caller->self->Run();
Index: trunk/lib/FlairMeta/src/MetaDualShock3.cpp
===================================================================
--- trunk/lib/FlairMeta/src/MetaDualShock3.cpp	(revision 24)
+++ trunk/lib/FlairMeta/src/MetaDualShock3.cpp	(revision 38)
@@ -18,4 +18,5 @@
 #include "MetaDualShock3.h"
 #include "MetaDualShock3_impl.h"
+#include "TargetController.h"
 #include "JoyReference.h"
 #include <Tab.h>
@@ -30,4 +31,5 @@
 using namespace flair::filter;
 using namespace flair::gui;
+using namespace flair::sensor;
 
 namespace flair {
@@ -35,9 +37,9 @@
 
 MetaDualShock3::MetaDualShock3(FrameworkManager *parent, string name,
-                               uint16_t port, uint8_t priority)
-    : TargetEthController(parent, name, port, priority) {
+                               TargetController *controller)
+    : controller(controller),IODevice((IODevice*)controller, name) {
   pimpl_ = new MetaDualShock3_impl(this, name);
   parent->AddDeviceToLog(pimpl_->joy_ref);
-  Start();
+  controller->Start();
 }
 
@@ -49,25 +51,22 @@
 
 void MetaDualShock3::ErrorNotify(void) {
-  TargetEthController::FlashLed(4, 10, 0);
-  TargetEthController::Rumble(0xff, 20, 0, 0);
+    controller->FlashLed(4,10,0);
+    controller->Rumble(0xff,20,0,0);
 }
 
-void MetaDualShock3::Rumble(uint8_t left_force, uint8_t left_timeout,
-                            uint8_t right_force, uint8_t right_timeout) {
-  TargetEthController::Rumble(left_force, left_timeout, right_force,
-                              right_timeout);
+void MetaDualShock3::Rumble(uint8_t left_force,uint8_t left_timeout,uint8_t right_force,uint8_t right_timeout) {
+    controller->Rumble(left_force,left_timeout,right_force,right_timeout);
 }
 
 void MetaDualShock3::SetLedON(unsigned int ledId) {
-  TargetEthController::SetLedOn(ledId);
+    controller->SetLedOn(ledId);
 }
 
 void MetaDualShock3::SetLedOFF(unsigned int ledId) {
-  TargetEthController::SetLedOff(ledId);
+    controller->SetLedOff(ledId);
 }
 
-void MetaDualShock3::FlashLed(unsigned int ledId, uint8_t on_timeout,
-                              uint8_t off_timeout) {
-  TargetEthController::FlashLed(ledId, on_timeout, off_timeout);
+void MetaDualShock3::FlashLed(unsigned int ledId,uint8_t on_timeout,uint8_t off_timeout) {
+    controller->FlashLed(ledId,on_timeout,off_timeout);
 }
 
@@ -91,5 +90,9 @@
 
 float MetaDualShock3::PitchTrim(void) const {
-  return pimpl_->joy_ref->PitchTrim();
+    return pimpl_->joy_ref->PitchTrim();
+}
+
+void MetaDualShock3::UpdateFrom(const flair::core::io_data *data) {
+    pimpl_->UpdateFrom(data);
 }
 
Index: trunk/lib/FlairMeta/src/MetaDualShock3.h
===================================================================
--- trunk/lib/FlairMeta/src/MetaDualShock3.h	(revision 24)
+++ trunk/lib/FlairMeta/src/MetaDualShock3.h	(revision 38)
@@ -14,5 +14,6 @@
 #define METADUALSHOCK3_H
 
-#include <TargetEthController.h>
+#include <TargetController.h>
+#include <IODevice.h>
 
 namespace flair {
@@ -35,10 +36,10 @@
 * \brief Classe intégrant la manette MetaDualShock3
 */
-class MetaDualShock3 : public sensor::TargetEthController {
+class MetaDualShock3 : public core::IODevice {
   friend class ::MetaDualShock3_impl;
 
 public:
   MetaDualShock3(core::FrameworkManager *parent, std::string name,
-                 uint16_t port, uint8_t priority);
+                 sensor::TargetController *controller);
   ~MetaDualShock3();
   core::AhrsData *GetReferenceOrientation(void) const;
@@ -66,7 +67,9 @@
   void FlashLed(unsigned int ledId, uint8_t on_timeout, uint8_t off_timeout);
 
-private:
-  class MetaDualShock3_impl *pimpl_;
-};
+        private:
+            class MetaDualShock3_impl* pimpl_;
+            void UpdateFrom(const flair::core::io_data *data);
+            sensor::TargetController *controller;
+    };
 } // end namespace meta
 } // end namespace flair
Index: trunk/lib/FlairMeta/src/MetaDualShock3_impl.cpp
===================================================================
--- trunk/lib/FlairMeta/src/MetaDualShock3_impl.cpp	(revision 24)
+++ trunk/lib/FlairMeta/src/MetaDualShock3_impl.cpp	(revision 38)
@@ -29,7 +29,6 @@
 using namespace flair::meta;
 
-MetaDualShock3_impl::MetaDualShock3_impl(MetaDualShock3 *self, string name)
-    : IODevice((IODevice *)self, name) {
-  joy_ref = new JoyReference(self->GetTab()->NewRow(), "consignes joy");
+MetaDualShock3_impl::MetaDualShock3_impl(MetaDualShock3 *self, string name) {
+  joy_ref=new JoyReference(self->controller->GetTab()->NewRow(),"consignes joy");
   this->self = self;
   joy_init = false;
@@ -50,5 +49,5 @@
 
   // up
-  if (self->IsButtonPressed(12)) {
+  if (self->controller->IsButtonPressed(12)) {
     if (!wasPitchTrimDownButtonPressed) {
       joy_ref->PitchTrimDown();
@@ -60,5 +59,5 @@
 
   // down
-  if (self->IsButtonPressed(13)) {
+  if (self->controller->IsButtonPressed(13)) {
     if (!wasPitchTrimUpButtonPressed) {
       joy_ref->PitchTrimUp();
@@ -70,5 +69,5 @@
 
   // right
-  if (self->IsButtonPressed(15)) {
+  if (self->controller->IsButtonPressed(15)) {
     if (!wasRollTrimUpButtonPressed) {
       joy_ref->RollTrimUp();
@@ -80,5 +79,5 @@
 
   // left
-  if (self->IsButtonPressed(14)) {
+  if (self->controller->IsButtonPressed(14)) {
     if (!wasRollTrimDownButtonPressed) {
       joy_ref->RollTrimDown();
@@ -107,5 +106,5 @@
 
   if (!joy_init) {
-    self->TargetEthController::FlashLed(1, 10, 10);
+    self->controller->FlashLed(1, 10, 10);
     joy_init = true;
   }
Index: trunk/lib/FlairMeta/src/UavStateMachine.cpp
===================================================================
--- trunk/lib/FlairMeta/src/UavStateMachine.cpp	(revision 24)
+++ trunk/lib/FlairMeta/src/UavStateMachine.cpp	(revision 38)
@@ -51,10 +51,9 @@
 using namespace flair::meta;
 
-UavStateMachine::UavStateMachine(Uav *inUav, uint16_t ds3Port)
-    : Thread(getFrameworkManager(), "UavStateMachine", 50), uav(inUav),
-      failSafeMode(true), flagConnectionLost(false), flagBatteryLow(false),
-      flagZTrajectoryFinished(false) {
-  altitudeState = AltitudeState_t::Stopped;
-  uav->UseDefaultPlot();
+UavStateMachine::UavStateMachine(Uav* inUav,TargetController *controller):
+        Thread(getFrameworkManager(),"UavStateMachine",50),
+        uav(inUav),controller(controller),failSafeMode(true),flagConnectionLost(false),flagBatteryLow(false),flagCriticalSensorLost(false),flagZTrajectoryFinished(false),safeToFly(true){
+    altitudeState=AltitudeState_t::Stopped;
+    uav->UseDefaultPlot();
 
   Tab *uavTab = new Tab(getFrameworkManager()->GetTabWidget(), "uav", 0);
@@ -90,6 +89,6 @@
   uZ->AddDeviceToLog(uYaw);
 
-  joy = new MetaDualShock3(getFrameworkManager(), "dualshock3", ds3Port, 30);
-  uav->GetAhrs()->AddPlot(joy->GetReferenceOrientation(), DataPlot::Blue);
+    joy=new MetaDualShock3(getFrameworkManager(),"uav high level controller",controller);
+    uav->GetAhrs()->AddPlot(joy->GetReferenceOrientation(),DataPlot::Blue);
 
   altitudeMode = AltitudeMode_t::Manual;
@@ -124,5 +123,7 @@
 }
 
-const TargetController *UavStateMachine::GetJoystick(void) const { return joy; }
+const TargetController *UavStateMachine::GetJoystick(void) const {
+    return controller;
+}
 
 const Quaternion &UavStateMachine::GetCurrentQuaternion(void) const {
@@ -253,7 +254,6 @@
       // The Uav target altitude has reached its landing value (typically 0)
       // but the real Uav altitude may not have reach this value yet because of
-      // command delay. Moreover, it
-      // may never exactly reach this value if the ground is not perfectly
-      // leveled (critical case: there's a
+      // command delay. Moreover, it may never exactly reach this value if the 
+      // ground is not perfectly leveled (critical case: there's a
       // deep and narrow hole right in the sensor line of sight). That's why we
       // have a 2 phases landing strategy.
@@ -424,12 +424,11 @@
   flagZTrajectoryFinished = false;
 
-  if (altitudeState == AltitudeState_t::Stopped) { // &&
-    // GetBatteryMonitor()->IsBatteryLow()==false)
-    // The uav always takes off in fail safe mode
-    EnterFailSafeMode();
-    joy->SetLedOFF(4); // DualShock3::led4
-    joy->SetLedOFF(1); // DualShock3::led1
-    joy->Rumble(0x70);
-    joy->SetZRef(0);
+    if((altitudeState==AltitudeState_t::Stopped) && safeToFly) {// && GetBatteryMonitor()->IsBatteryLow()==false)
+        //The uav always takes off in fail safe mode
+        EnterFailSafeMode();
+        joy->SetLedOFF(4);//DualShock3::led4
+        joy->SetLedOFF(1);//DualShock3::led1
+        joy->Rumble(0x70);
+        joy->SetZRef(0);
 
     uZ->SetOffset(); // positionne l'offset de compensation de la gravité à sa
@@ -458,14 +457,22 @@
     joy->Rumble(0x70);
 
-    altitudeTrajectory->StopTraj();
-    joy->SetZRef(0);
-    altitudeTrajectory->StartTraj(
-        currentAltitude,
-        desiredLandingAltitude->Value()); // shouldn't it be groundAltitude?
-    SignalEvent(Event_t::StartLanding);
-    altitudeState = AltitudeState_t::StartLanding;
-  } else {
-    joy->ErrorNotify();
-  }
+        altitudeTrajectory->StopTraj();
+        joy->SetZRef(0);
+        altitudeTrajectory->StartTraj(currentAltitude,desiredLandingAltitude->Value()); //shouldn't it be groundAltitude?
+        SignalEvent(Event_t::StartLanding);
+        altitudeState=AltitudeState_t::StartLanding;
+    } else if (altitudeState==AltitudeState_t::TakingOff) {
+        EmergencyLand();
+    } else {
+        joy->ErrorNotify();
+    }
+}
+
+void UavStateMachine::EmergencyLand(void) {
+    //Gradually decrease motor speed
+    //Called if landing is required during take off (motors are accelerating but Uav did not actually left the ground yet), or if critical sensors have been lost (attitude is lost)
+    altitudeState=AltitudeState_t::FinishLanding;
+    safeToFly=false;
+Printf("Emergency landing!\n");
 }
 
@@ -494,10 +501,11 @@
 
 void UavStateMachine::EmergencyStop(void) {
-  if (altitudeState != AltitudeState_t::Stopped) {
-    StopMotors();
-    EnterFailSafeMode();
-    joy->Rumble(0x70);
-    SignalEvent(Event_t::EmergencyStop);
-  }
+    if(altitudeState!=AltitudeState_t::Stopped) {
+        StopMotors();
+        EnterFailSafeMode();
+        joy->Rumble(0x70);
+        SignalEvent(Event_t::EmergencyStop);
+    }
+    safeToFly=false;
 }
 
@@ -534,12 +542,17 @@
     }
   }
-  if ((altitudeState == AltitudeState_t::TakingOff ||
-       altitudeState == AltitudeState_t::Stabilized) &&
-      uav->GetBatteryMonitor()->IsBatteryLow() && !flagBatteryLow) {
-    flagBatteryLow = true;
-    Printf("Battery Low\n");
-    EnterFailSafeMode();
-    Land();
-  }
+    if((altitudeState==AltitudeState_t::TakingOff || altitudeState==AltitudeState_t::Stabilized) && uav->GetBatteryMonitor()->IsBatteryLow() && !flagBatteryLow) {
+        flagBatteryLow=true;
+        Thread::Err("Low Battery\n");
+        EnterFailSafeMode();
+        Land();
+    }
+    Time now=GetTime();
+    if ((altitudeState==AltitudeState_t::Stopped) && (now-uav->GetAhrs()->lastUpdate>(Time)100*1000*1000)) { //100ms
+        flagCriticalSensorLost=true;
+        Thread::Err("Critical sensor lost\n");
+        EnterFailSafeMode();
+        EmergencyLand(); 
+    }
 }
 
@@ -554,5 +567,5 @@
   static bool isSafeModeButtonPressed = false;
 
-  if (joy->IsButtonPressed(1)) { // select
+  if (controller->IsButtonPressed(1)) { // select
     if (!isEmergencyStopButtonPressed) {
       isEmergencyStopButtonPressed = true;
@@ -563,5 +576,5 @@
     isEmergencyStopButtonPressed = false;
 
-  if (joy->IsButtonPressed(0)) { // start
+  if (controller->IsButtonPressed(0)) { // start
     if (!isTakeOffButtonPressed) {
       isTakeOffButtonPressed = true;
@@ -585,7 +598,7 @@
   // check if l1,l2,r1 and r2 are not pressed
   // to allow a combination in user program
-  if (joy->IsButtonPressed(5) && !joy->IsButtonPressed(6) &&
-      !joy->IsButtonPressed(7) && !joy->IsButtonPressed(9) &&
-      !joy->IsButtonPressed(10)) {
+  if (controller->IsButtonPressed(5) && !controller->IsButtonPressed(6) &&
+      !controller->IsButtonPressed(7) && !controller->IsButtonPressed(9) &&
+      !controller->IsButtonPressed(10)) {
     if (!isSafeModeButtonPressed) {
       isSafeModeButtonPressed = true;
Index: trunk/lib/FlairMeta/src/UavStateMachine.h
===================================================================
--- trunk/lib/FlairMeta/src/UavStateMachine.h	(revision 24)
+++ trunk/lib/FlairMeta/src/UavStateMachine.h	(revision 38)
@@ -101,6 +101,6 @@
   };
 
-  UavStateMachine(meta::Uav *uav, uint16_t ds3Port = 20000);
-  ~UavStateMachine();
+        UavStateMachine(meta::Uav* uav, sensor::TargetController* controller);
+        ~UavStateMachine();
 
   const core::Quaternion &GetCurrentQuaternion(void) const;
@@ -110,12 +110,13 @@
   const meta::Uav *GetUav(void) const;
 
-  void Land(void);
-  void TakeOff(void);
-  void EmergencyStop(void);
-  //! Used to signal an event
-  /*!
-      \param event the event which occured
-  */
-  virtual void SignalEvent(Event_t event);
+        void Land(void);
+        void EmergencyLand(void);
+        void TakeOff(void);
+        void EmergencyStop(void);
+        //! Used to signal an event
+        /*!
+            \param event the event which occured
+        */
+        virtual void SignalEvent(Event_t event);
 
   virtual const core::AhrsData *GetOrientation(void) const;
@@ -262,4 +263,5 @@
 
   meta::Uav *uav;
+  sensor::TargetController *controller;
 
   core::Quaternion currentQuaternion;
@@ -289,5 +291,7 @@
   bool flagBatteryLow;
   bool flagConnectionLost;
+  bool flagCriticalSensorLost;
   bool flagZTrajectoryFinished;
+  bool safeToFly;
   filter::NestedSat *uRoll, *uPitch;
   filter::Pid *uYaw;
Index: trunk/lib/FlairMeta/src/unexported/MetaDualShock3_impl.h
===================================================================
--- trunk/lib/FlairMeta/src/unexported/MetaDualShock3_impl.h	(revision 24)
+++ trunk/lib/FlairMeta/src/unexported/MetaDualShock3_impl.h	(revision 38)
@@ -14,5 +14,5 @@
 #define METADUALSHOCK3_IMPL_H
 
-#include <IODevice.h>
+#include <MetaDualShock3.h>
 
 namespace flair {
@@ -29,12 +29,12 @@
 * \brief Classe intégrant la manette DualShock3 et les consignes joystick
 */
-class MetaDualShock3_impl : public flair::core::IODevice {
+class MetaDualShock3_impl {
 public:
   MetaDualShock3_impl(flair::meta::MetaDualShock3 *self, std::string name);
   ~MetaDualShock3_impl();
   flair::filter::JoyReference *joy_ref;
+  void UpdateFrom(const flair::core::io_data *data);
 
 private:
-  void UpdateFrom(const flair::core::io_data *data);
   flair::meta::MetaDualShock3 *self;
   bool joy_init;
Index: trunk/lib/FlairSensorActuator/src/EmulatedController.cpp
===================================================================
--- trunk/lib/FlairSensorActuator/src/EmulatedController.cpp	(revision 38)
+++ trunk/lib/FlairSensorActuator/src/EmulatedController.cpp	(revision 38)
@@ -0,0 +1,153 @@
+//  created:    2015/03/30
+//  filename:   EmulatedController.cpp
+//
+//  author:     Gildas Bayard
+//              Copyright Heudiasyc UMR UTC/CNRS 7253
+//
+//  version:    $Id: $
+//
+//  purpose:    class that emulate a remote control.
+//              Typical use case: run a demo without any reliable communication channel
+//
+/*********************************************************************/
+#include "EmulatedController.h"
+#include <Controller.h>
+#include <FrameworkManager.h>
+#include <TcpSocket.h>
+#include <Socket.h>
+#include <cstring>
+#include <string>
+#include <cvmatrix.h>
+#include <stdexcept>
+
+#include <unistd.h> // for sleep (debug)
+
+using namespace flair::core;
+using namespace flair::gui;
+using std::string;
+
+namespace flair { namespace sensor {
+
+EmulatedController::EmulatedController(const FrameworkManager* parent,string name,uint8_t priority) :
+    TargetController(parent,name,priority) {
+}
+
+EmulatedController::~EmulatedController() {
+    //TargetController calls TargetEthController methods in its run
+    //we must stop the thread now
+    SafeStop();
+    Join();
+}
+
+bool EmulatedController::IsConnected() const {
+    return true;
+}
+
+bool EmulatedController::IsDataFrameReady(){
+    return true;
+}
+
+template<typename T> void EmulatedController::fillVectorNoMutex(cvmatrix &vector,T data[],unsigned int size) {
+    for (unsigned int i=0; i<size; i++) {
+        vector.SetValueNoMutex(i,0,data[i]);
+    }
+}
+
+void EmulatedController::fillVectorNoMutex(cvmatrix &destination,cvmatrix &source,unsigned int size) {
+    for (unsigned int i=0; i<size; i++) {
+        destination.SetValueNoMutex(i,0,source.Value(i,0));
+    }
+}
+
+void EmulatedController::StepData::Print() {
+    Printf("<StepData %s, duration=%d, axisData={%f,%f,%f,%f}, buttonData={%c,%c,%c,%c,%c,%c,%c,%c,%c,%c,%c,%c,%c,%c,%c,%c} />\n",description.c_str(),durationMs,
+      axisData->Value(0,0),axisData->Value(1,0),axisData->Value(2,0),axisData->Value(3,0),
+      buttonData->Value(0,0)?'X':'-',buttonData->Value(1,0)?'X':'-',buttonData->Value(2,0)?'X':'-',buttonData->Value(3,0)?'X':'-',
+      buttonData->Value(4,0)?'X':'-',buttonData->Value(5,0)?'X':'-',buttonData->Value(6,0)?'X':'-',buttonData->Value(7,0)?'X':'-',
+      buttonData->Value(8,0)?'X':'-',buttonData->Value(9,0)?'X':'-',buttonData->Value(10,0)?'X':'-',buttonData->Value(11,0)?'X':'-',
+      buttonData->Value(12,0)?'X':'-',buttonData->Value(13,0)?'X':'-',buttonData->Value(14,0)?'X':'-',buttonData->Value(15,0)?'X':'-'
+    );
+}
+
+void EmulatedController::AddStep(unsigned int durationMs,string description,uint16_t buttonPressed, float leftAxisX, float leftAxisY, float rightAxisX, float rightAxisY) {
+    cvmatrix *axisMatrix=new cvmatrix((IODevice *)this,4,1,floatType);
+    axisMatrix->SetValueNoMutex(0,0,leftAxisX);
+    axisMatrix->SetValueNoMutex(1,0,leftAxisY);
+    axisMatrix->SetValueNoMutex(2,0,rightAxisX);
+    axisMatrix->SetValueNoMutex(3,0,rightAxisY);
+
+    cvmatrix *buttonMatrix=new cvmatrix((IODevice *)this,16,1,SignedIntegerType(8));
+    if (buttonPressed&(uint16_t)ButtonType::start) buttonMatrix->SetValueNoMutex(0,0,1);
+    if (buttonPressed&(uint16_t)ButtonType::select) buttonMatrix->SetValueNoMutex(1,0,1);
+    if (buttonPressed&(uint16_t)ButtonType::square) buttonMatrix->SetValueNoMutex(2,0,1);
+    if (buttonPressed&(uint16_t)ButtonType::triangle) buttonMatrix->SetValueNoMutex(3,0,1);
+    if (buttonPressed&(uint16_t)ButtonType::circle) buttonMatrix->SetValueNoMutex(4,0,1);
+    if (buttonPressed&(uint16_t)ButtonType::cross) buttonMatrix->SetValueNoMutex(5,0,1);
+    if (buttonPressed&(uint16_t)ButtonType::left1) buttonMatrix->SetValueNoMutex(6,0,1);
+    if (buttonPressed&(uint16_t)ButtonType::left2) buttonMatrix->SetValueNoMutex(7,0,1);
+    if (buttonPressed&(uint16_t)ButtonType::left3) buttonMatrix->SetValueNoMutex(8,0,1);
+    if (buttonPressed&(uint16_t)ButtonType::right1) buttonMatrix->SetValueNoMutex(9,0,1);
+    if (buttonPressed&(uint16_t)ButtonType::right2) buttonMatrix->SetValueNoMutex(10,0,1);
+    if (buttonPressed&(uint16_t)ButtonType::right3) buttonMatrix->SetValueNoMutex(11,0,1);
+    if (buttonPressed&(uint16_t)ButtonType::up) buttonMatrix->SetValueNoMutex(12,0,1);
+    if (buttonPressed&(uint16_t)ButtonType::down) buttonMatrix->SetValueNoMutex(13,0,1);
+    if (buttonPressed&(uint16_t)ButtonType::left) buttonMatrix->SetValueNoMutex(14,0,1);
+    if (buttonPressed&(uint16_t)ButtonType::right) buttonMatrix->SetValueNoMutex(15,0,1);
+
+    StepData step={durationMs,axisMatrix,buttonMatrix,description};
+    //step.Print();
+    steps.push_back(step);
+}
+
+void EmulatedController::ComputeControllerData(DataType dataType, cvmatrix &data) {
+    static Time startStepTime=GetTime();
+
+    Time now=GetTime();
+
+    axis->GetMutex();
+    button->GetMutex();
+
+    if (steps.empty()) {
+        if (dataType==DataType::axis) {
+            float values[]={0.,0.,0.,0.};
+            fillVectorNoMutex(data,values,4);
+        }
+        if (dataType==DataType::button) {
+            int values[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+            fillVectorNoMutex(data,values,16);
+        }
+    } else {
+        StepData currentStep=steps.front();
+        if (dataType==DataType::axis) fillVectorNoMutex(data,*(currentStep.axisData),4);
+        if (dataType==DataType::button) fillVectorNoMutex(data,*(currentStep.buttonData),16);
+        if (now-startStepTime>(Time)currentStep.durationMs*1000*1000) {
+            Thread::Info("Step '%s' done\n",currentStep.description.c_str());
+            startStepTime=now;
+            steps.pop_front();
+        }
+    }
+
+    button->ReleaseMutex();
+    axis->ReleaseMutex();
+}
+
+void EmulatedController::AcquireAxisData(core::cvmatrix &axis) {
+    ComputeControllerData(DataType::axis,axis);
+}
+
+void EmulatedController::AcquireButtonData(core::cvmatrix &button) {
+    ComputeControllerData(DataType::button,button);
+}
+
+bool EmulatedController::ProcessMessage(Message *msg) {
+    return false;
+}
+
+bool EmulatedController::ControllerInitialization() {
+    axisNumber=4;
+    buttonNumber=16;
+    return true;
+}
+
+} // end namespace sensor
+} // end namespace flair
Index: trunk/lib/FlairSensorActuator/src/EmulatedController.h
===================================================================
--- trunk/lib/FlairSensorActuator/src/EmulatedController.h	(revision 38)
+++ trunk/lib/FlairSensorActuator/src/EmulatedController.h	(revision 38)
@@ -0,0 +1,76 @@
+//  created:    2015/04/14
+//  filename:   EmulatedController.h
+//
+//  author:     Gildas Bayard
+//              Copyright Heudiasyc UMR UTC/CNRS 7253
+//
+//  version:    $Id: $
+//
+//  purpose:    class that emulate a remote control.
+//              Typical use case: run a demo without any reliable communication channel
+//
+//
+/*********************************************************************/
+
+#ifndef EMULATEDCONTROLLER_H
+#define EMULATEDCONTROLLER_H
+
+#include <TargetController.h>
+#include <list>
+
+namespace flair {
+    namespace core {
+        class FrameworkManager;
+        class cvmatrix;
+    }
+    namespace gui {
+        class Tab;
+        class TabWidget;
+        class DataPlot1D;
+    }
+}
+
+namespace flair { namespace sensor {
+    /*! \class EmulatedController
+    *
+    * \brief Emulated remote control
+    *
+    */
+    class EmulatedController : public TargetController {
+    public:
+        EmulatedController(const core::FrameworkManager* parent,std::string name,uint8_t priority=0);
+        ~EmulatedController();
+        enum class ButtonType : uint16_t {
+            start=0x0001,select=0x0002,square=0x0004,triangle=0x0008,
+            circle=0x0010,cross=0x0020,left1=0x0040,left2=0x0080,
+            left3=0x0100,right1=0x0200,right2=0x0400,right3=0x0800,
+            up=0x1000,down=0x2000,left=0x4000,right=0x8000
+        };
+        void AddStep(unsigned int durationMs,std::string description,uint16_t buttonPressed, float leftAxisX, float leftAxisY, float rightAxisX, float rightAxisY);
+    protected :
+        bool IsConnected() const;
+        //controller state stuff
+        bool ProcessMessage(core::Message *msg);
+        bool IsDataFrameReady();
+        void AcquireAxisData(core::cvmatrix &axis); //responsible for getting the axis data from the hardware
+        void AcquireButtonData(core::cvmatrix &button); //responsible for getting the button data from the hardware
+        bool ControllerInitialization();
+
+    private:
+        enum class DataType { axis,button };
+        void ComputeControllerData(DataType dataType, core::cvmatrix &data);
+        template<typename T> void fillVectorNoMutex(core::cvmatrix &vector,T data[],unsigned int size);
+        void fillVectorNoMutex(core::cvmatrix &destination,core::cvmatrix &source,unsigned int size);
+        struct StepData {
+            unsigned int durationMs; //milliseconds
+            core::cvmatrix *axisData;
+            core::cvmatrix *buttonData;
+            std::string description;
+            void Print();
+        };
+        std::list<StepData> steps;
+    };
+
+}}
+
+#endif // EMULATEDCONTROLLER_H
Index: trunk/lib/FlairSensorActuator/src/TargetController.cpp
===================================================================
--- trunk/lib/FlairSensorActuator/src/TargetController.cpp	(revision 24)
+++ trunk/lib/FlairSensorActuator/src/TargetController.cpp	(revision 38)
@@ -34,10 +34,10 @@
 namespace sensor {
 
-TargetController::TargetController(const FrameworkManager *parent, string name,
-                                   uint8_t priority)
-    : Thread(parent, name, priority), IODevice(parent, name) {
-  main_tab = new Tab(getFrameworkManager()->GetTabWidget(), name);
-  TabWidget *tab = new TabWidget(main_tab->NewRow(), name);
-  setup_tab = new Tab(tab, "Reglages");
+TargetController::TargetController(const FrameworkManager* parent,string name,uint8_t priority) :
+    Thread(parent,name,priority),IODevice(parent,name) {
+    main_tab=new Tab(getFrameworkManager()->GetTabWidget(),name);
+    TabWidget* tab=new TabWidget(main_tab->NewRow(),name);
+    setup_tab=new Tab(tab,"Reglages");
+    SetPeriodMS(20);; //50Hz
 }
 
@@ -150,8 +150,6 @@
           }
         }
-      } else {
-        // Thread::Info("Debug: relax...\n");
-        usleep(20000); // 20ms
       }
+      WaitPeriod();
     }
   }
Index: trunk/lib/FlairSensorActuator/src/TargetEthController.cpp
===================================================================
--- trunk/lib/FlairSensorActuator/src/TargetEthController.cpp	(revision 24)
+++ trunk/lib/FlairSensorActuator/src/TargetEthController.cpp	(revision 38)
@@ -80,21 +80,21 @@
   bool fullDatagramReceived = false;
 
-  do {
-    received =
-        dataSocket->RecvMessage(receiveFrameBuffer + receiveCurrentPosition,
-                                bytesToReceive, TIME_NONBLOCK);
-    if (received > 0) {
-      bytesToReceive -= received;
-      if (bytesToReceive == 0) {
-        // a full datagram has been read in receiveFrameBuffer
-        fullDatagramReceived = true;
-        receiveCurrentPosition = 0;
-        // we swap the data and reception buffers to avoid copy
-        char *swapFrameBuffer = dataFrameBuffer;
-        dataFrameBuffer = receiveFrameBuffer;
-        receiveFrameBuffer = swapFrameBuffer;
-      }
-    }
-  } while (!received < 0);
+    do {
+        received=dataSocket->RecvMessage(receiveFrameBuffer+receiveCurrentPosition,bytesToReceive,TIME_NONBLOCK);
+        if (received>0) {
+            receiveCurrentPosition+=received;
+            bytesToReceive-=received;
+            if (bytesToReceive==0) {
+                //a full datagram has been read in receiveFrameBuffer
+                fullDatagramReceived=true;
+                //we swap the data and reception buffers to avoid copy
+                char *swapFrameBuffer=dataFrameBuffer;
+                dataFrameBuffer=receiveFrameBuffer;
+                receiveFrameBuffer=swapFrameBuffer;
+                receiveCurrentPosition=0;
+                bytesToReceive=dataFrameSize;
+            }
+        }
+    } while (!(received<0));
 
   return fullDatagramReceived;
