Index: trunk/lib/CMakeLists.txt
===================================================================
--- trunk/lib/CMakeLists.txt	(revision 388)
+++ trunk/lib/CMakeLists.txt	(revision 397)
@@ -9,4 +9,5 @@
 add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/FlairSimulator)
 add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/FlairVisionFilter)
+add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/FlairIpc)
 
 
Index: trunk/lib/FlairFilter/src/SimulatedAhrs.h
===================================================================
--- trunk/lib/FlairFilter/src/SimulatedAhrs.h	(revision 388)
+++ trunk/lib/FlairFilter/src/SimulatedAhrs.h	(revision 397)
@@ -15,5 +15,4 @@
 
 #include <Ahrs.h>
-#include <stdint.h>
 
 namespace flair {
Index: trunk/lib/FlairIpc/CMakeLists.txt
===================================================================
--- trunk/lib/FlairIpc/CMakeLists.txt	(revision 397)
+++ trunk/lib/FlairIpc/CMakeLists.txt	(revision 397)
@@ -0,0 +1,18 @@
+PROJECT(FlairIpc)
+cmake_minimum_required(VERSION 2.8)
+include($ENV{FLAIR_ROOT}/flair-src/cmake-modules/GlobalCmakeFlair.cmake)
+
+INCLUDE_DIRECTORIES(
+	${CMAKE_CURRENT_SOURCE_DIR}/src
+	${CMAKE_CURRENT_SOURCE_DIR}/src/unexported
+	${CMAKE_CURRENT_SOURCE_DIR}/../FlairCore/src
+	${CMAKE_CURRENT_SOURCE_DIR}/../FlairFilter/src
+	${CMAKE_CURRENT_SOURCE_DIR}/../FlairSensorActuator/src
+    ${CMAKE_CURRENT_SOURCE_DIR}/../FlairMeta/src
+)
+
+FILE(GLOB SRC_FILES "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
+
+FLAIR_LIB(${PROJECT_NAME} "${SRC_FILES}"
+        INCLUDES_DEST_DIR ${PROJECT_NAME}
+)
Index: trunk/lib/FlairIpc/src/IpcAhrs.cpp
===================================================================
--- trunk/lib/FlairIpc/src/IpcAhrs.cpp	(revision 397)
+++ trunk/lib/FlairIpc/src/IpcAhrs.cpp	(revision 397)
@@ -0,0 +1,54 @@
+// %flair:license{
+// This file is part of the Flair framework distributed under the
+// CECILL-C License, Version 1.0.
+// %flair:license}
+//  created:    2021/03/03
+//  filename:   IpcdAhrs.cpp
+//
+//  author:     Sébastien Ambroziak
+//              Copyright Heudiasyc UMR UTC/CNRS 7253
+//
+//  version:    $Id: $
+//
+//  purpose:    Class for an ipc ahrs
+//
+//
+/*********************************************************************/
+
+
+#include "IpcAhrs.h"
+#include "IpcImu.h"
+#include <AhrsData.h>
+
+using std::string;
+using namespace flair::core;
+using namespace flair::sensor;
+
+namespace flair {
+namespace filter {
+
+IpcAhrs::IpcAhrs(string name, uint8_t priority, const char* ipc_name, int ipc_channel)
+    : Ahrs(new IpcImu("imu", priority, ipc_name, ipc_channel, false), name) {
+  SetIsReady(true);
+}
+
+IpcAhrs::~IpcAhrs() {}
+
+// datas from IpcImu are AhrsData!
+void IpcAhrs::UpdateFrom(const io_data *data) {
+  AhrsData *input = (AhrsData *)data;
+  AhrsData *output;
+  GetDatas(&output);
+
+  Quaternion quaternion;
+  Vector3Df filteredAngRates;
+  input->GetQuaternionAndAngularRates(quaternion, filteredAngRates);
+  output->SetQuaternionAndAngularRates(quaternion, filteredAngRates);
+  output->SetDataTime(input->DataTime());
+
+  ProcessUpdate(output);
+}
+
+} // end namespace filter
+} // end namespace flair
+
Index: trunk/lib/FlairIpc/src/IpcAhrs.h
===================================================================
--- trunk/lib/FlairIpc/src/IpcAhrs.h	(revision 397)
+++ trunk/lib/FlairIpc/src/IpcAhrs.h	(revision 397)
@@ -0,0 +1,58 @@
+// %flair:license{
+// This file is part of the Flair framework distributed under the
+// CECILL-C License, Version 1.0.
+// %flair:license}
+/*!
+ * \file IpcAhrs.h
+ * \brief Class for an ipc Ahrs
+ * \author Sébastien Ambroziak, Copyright Heudiasyc UMR UTC/CNRS 7253
+ * \date 2021/03/03
+ * \version 4.0
+ */
+
+#ifndef IPCAHRS_H
+#define IPCAHRS_H
+
+#include <Ahrs.h>
+
+namespace flair {
+namespace filter {
+/*! \class IpcAhrs
+*
+* \brief Class for an ipc Ahrs
+*
+* This class also constructs an IpcImu as Imu of this Ahrs.
+*/
+class IpcAhrs : public filter::Ahrs {
+public:
+  /*!
+  * \brief Constructor
+  *
+  * Construct an ipc Ahrs. It will be child of the FrameworkManager.
+  *
+  * \param name name
+  * \param priority priority of the SimulatedImu Thread
+  * \param ipc_name name of the ipc
+  * \param ipc_channel ipc channel number
+  */
+  IpcAhrs(std::string name, uint8_t priority, const char* ipc_name, int ipc_channel);
+
+  /*!
+  * \brief Destructor
+  *
+  */
+  ~IpcAhrs();
+
+private:
+  /*!
+  * \brief Update using provided datas
+  *
+  * Reimplemented from IODevice.
+  *
+  * \param data data from the parent to process
+  */
+  void UpdateFrom(const core::io_data *data);
+};
+} // end namespace filter
+} // end namespace flair
+#endif // IPCAHRS_H
Index: trunk/lib/FlairIpc/src/IpcAhrsSensor.cpp
===================================================================
--- trunk/lib/FlairIpc/src/IpcAhrsSensor.cpp	(revision 397)
+++ trunk/lib/FlairIpc/src/IpcAhrsSensor.cpp	(revision 397)
@@ -0,0 +1,64 @@
+// %flair:license{
+// This file is part of the Flair framework distributed under the
+// CECILL-C License, Version 1.0.
+// %flair:license}
+//  created:    2021/03/03
+//  filename:   IpcAhrsSensor.cpp
+//
+//  author:     Sébastien Ambroziak
+//              Copyright Heudiasyc UMR UTC/CNRS 7253
+//
+//  version:    $Id: $
+//
+//  purpose:    Class for a simulation ahrs
+//
+//
+/*********************************************************************/
+
+#include "IpcAhrsSensor.h"
+#include "ipc_receive.h"
+#include <FrameworkManager.h>
+#include <AhrsData.h>
+
+using std::string;
+using namespace flair::core;
+using namespace flair::sensor;
+
+namespace flair {
+namespace filter {
+
+IpcAhrsSensor::IpcAhrsSensor(string name, uint8_t priority, const char* ipc_name, int ipc_channel)
+    : Ahrs(nullptr, name), Thread(getFrameworkManager(), name, priority) {
+  receiver = new IpcReceiver<ipc::type::ahrs>(ipc_name,ipc_channel);
+  SetIsReady(true);
+}
+
+IpcAhrsSensor::~IpcAhrsSensor() {} 
+// datas from SimulatedImu are AhrsData!
+void IpcAhrsSensor::Run(void) {
+  AhrsData *output;
+  GetDatas(&output);
+
+  while (!ToBeStopped()) {
+
+  Quaternion quaternion;
+  Vector3Df filteredAngRates;
+
+  receiver->receive();
+  quaternion.q0 = receiver->getValue().quaternion.w;
+  quaternion.q1 = receiver->getValue().quaternion.x;
+  quaternion.q2 = receiver->getValue().quaternion.y;
+  quaternion.q3 = receiver->getValue().quaternion.z;
+  filteredAngRates.x = receiver->getValue().angular_rate.x;
+  filteredAngRates.y = receiver->getValue().angular_rate.y;
+  filteredAngRates.z = receiver->getValue().angular_rate.z;
+
+  output->SetQuaternionAndAngularRates(quaternion, filteredAngRates);
+  output->SetDataTime(receiver->getTimestamp().toNanosec());
+
+  ProcessUpdate(output);
+  }
+}
+
+} // end namespace filter
+} // end namespace flair
Index: trunk/lib/FlairIpc/src/IpcAhrsSensor.h
===================================================================
--- trunk/lib/FlairIpc/src/IpcAhrsSensor.h	(revision 397)
+++ trunk/lib/FlairIpc/src/IpcAhrsSensor.h	(revision 397)
@@ -0,0 +1,77 @@
+// %flair:license{
+// This file is part of the Flair framework distributed under the
+// CECILL-C License, Version 1.0.
+// %flair:license}
+/*!
+ * \file IpcAhrsSensor.h
+ * \brief Class for an ipc Ahrs
+ * \author Sébastien Ambroziak, Copyright Heudiasyc UMR UTC/CNRS 7253
+ * \date 2021/03/03
+ * \version 4.0
+ */
+
+#ifndef IPCAHRSSENSOR_H
+#define IPCAHRSSENSOR_H
+
+#include <Ahrs.h>
+#include <Thread.h>
+
+template <typename T>
+class IpcReceiver;
+
+namespace ipc{
+  namespace type{
+    struct ahrs;
+  }
+}
+
+namespace flair {
+namespace filter {
+/*! \class IpcAhrs
+*
+* \brief Class for an ipc Ahrs
+*
+*/
+class IpcAhrsSensor : public filter::Ahrs, public core::Thread {
+public:
+  /*!
+  * \brief Constructor
+  *
+  * Construct an ipc Ahrs. It will be child of the FrameworkManager.
+  *
+  * \param name name
+  * \param priority priority of the SimulatedImu Thread
+  * \param ipc_name name of the ipc
+  * \param ipc_channel ipc channel number
+  */
+  IpcAhrsSensor(std::string name, uint8_t priority, const char* ipc_name, int ipc_channel);
+
+  /*!
+  * \brief Destructor
+  *
+  */
+  ~IpcAhrsSensor();
+
+private:
+  /*!
+  * \brief Run function
+  *
+  * Reimplemented from Thread.
+  *
+  */
+  void Run(void);
+
+  /*!
+  * \brief Update using provided datas
+  *
+  * Reimplemented from IODevice.
+  *
+  * \param data data from the parent to process
+  */
+  void UpdateFrom(const core::io_data *data){};
+
+  IpcReceiver<ipc::type::ahrs>* receiver;
+};
+} // end namespace filter
+} // end namespace flair
+#endif // IPCAHRSSENSOR_H
Index: trunk/lib/FlairIpc/src/IpcBldc.cpp
===================================================================
--- trunk/lib/FlairIpc/src/IpcBldc.cpp	(revision 397)
+++ trunk/lib/FlairIpc/src/IpcBldc.cpp	(revision 397)
@@ -0,0 +1,57 @@
+// %flair:license{
+// This file is part of the Flair framework distributed under the
+// CECILL-C License, Version 1.0.
+// %flair:license}
+//  created:    2021/03/03
+//  filename:   IpcBldc.cpp
+//
+//  author:     Sébastien Ambroziak
+//              Copyright Heudiasyc UMR UTC/CNRS 7253
+//
+//  version:    $Id: $
+//
+//  purpose:    Class for a simulation bldc
+//
+//
+/*********************************************************************/
+
+#include "IpcBldc.h"
+#include "shm_send.h"
+#include <FrameworkManager.h>
+#include <GridLayout.h>
+#include <Matrix.h>
+
+using namespace flair::core;
+using namespace flair::gui;
+
+namespace flair {
+namespace actuator {
+
+IpcBldc::IpcBldc(const IODevice *parent, Layout *layout, string name,
+                   uint8_t motors_count, const char* ipc_name, int ipc_channel)
+    : Bldc(parent, layout, name, motors_count) {
+
+
+  //sender = new IpcSenderTab<uint16_t>(motors_count,ipc_name,ipc_channel);
+  sender = new ShmSenderTab<float>(motors_count,ipc_name,ipc_channel);
+  SetIsReady(true);
+}
+
+IpcBldc::~IpcBldc() {
+  
+}
+
+void IpcBldc::SetMotors(float *value) {
+
+  sender->send(value);
+  
+  // on prend une fois pour toute le mutex et on fait des accès directs
+  output->GetMutex();
+  for (int i = 0; i < MotorsCount(); i++) {
+    output->SetValueNoMutex(i, 0, value[i]);
+  }
+  output->ReleaseMutex();
+}
+
+} // end namespace sensor
+} // end namespace flair
Index: trunk/lib/FlairIpc/src/IpcBldc.h
===================================================================
--- trunk/lib/FlairIpc/src/IpcBldc.h	(revision 397)
+++ trunk/lib/FlairIpc/src/IpcBldc.h	(revision 397)
@@ -0,0 +1,96 @@
+// %flair:license{
+// This file is part of the Flair framework distributed under the
+// CECILL-C License, Version 1.0.
+// %flair:license}
+/*!
+ * \file IpcBldc.h
+ * \brief Class for a ipc bldc
+ * \author Sébastien Ambroziak, Copyright Heudiasyc UMR UTC/CNRS 7253
+ * \date 2021/03/03
+ * \version 4.0
+ */
+
+#ifndef IPCBLDC_H
+#define IPCBLDC_H
+
+#include <Bldc.h>
+
+namespace flair {
+namespace core {
+class IODevice;
+}
+namespace gui {
+class Layout;
+}
+}
+
+template <typename T>
+class ShmSenderTab;
+
+namespace flair {
+namespace actuator {
+/*! \class IpcBldc
+*
+* \brief Class for an ipc bldc
+*
+*/
+class IpcBldc : public Bldc {
+public:
+  /*!
+  * \brief Constructor
+  *
+  * Construct an IpcBldc
+  *
+  * \param parent parent
+  * \param layout layout
+  * \param name name
+  * \param motors_count number of motors
+  * \param ipc_name name of the ipc
+  * \param ipc_channel ipc channel number
+  */
+  IpcBldc(const core::IODevice *parent, gui::Layout *layout, std::string name,
+           uint8_t motors_count, const char* ipc_name, int ipc_channel);
+
+  /*!
+  * \brief Destructor
+  *
+  */
+  ~IpcBldc();
+
+  /*!
+  * \brief Has speed measurement
+  *
+  * Reimplemented from Bldc. \n
+  *
+  * \return true if it has speed measurement
+  */
+  bool HasSpeedMeasurement(void) const { return false; };
+
+  /*!
+  * \brief Has current measurement
+  *
+  * Reimplemented from Bldc. \n
+  *
+  * \return true if it has current measurement
+  */
+  bool HasCurrentMeasurement(void) const { return false; };
+
+private:
+  /*!
+  * \brief Set motors values
+  *
+  * Reimplemented from Bldc. \n
+  * Values size must be the same as MotorsCount()
+  *
+  * \param values motor values
+  */
+  void SetMotors(float *value);
+  
+  
+  //IpcSenderTab<uint16_t> *sender;
+  ShmSenderTab<float> *sender;
+
+};
+} // end namespace actuator
+} // end namespace flair
+#endif // IPCBLDC_H
Index: trunk/lib/FlairIpc/src/IpcController.cpp
===================================================================
--- trunk/lib/FlairIpc/src/IpcController.cpp	(revision 397)
+++ trunk/lib/FlairIpc/src/IpcController.cpp	(revision 397)
@@ -0,0 +1,372 @@
+// %flair:license{
+// This file is part of the Flair framework distributed under the
+// CECILL-C License, Version 1.0.
+// %flair:license}
+//  created:    2021/03/03
+//  filename:   IpcController.cpp
+//
+//  author:     Sébastien Ambroziak
+//              Copyright Heudiasyc UMR UTC/CNRS 7253
+//
+//  version:    $Id: $
+//
+//  purpose:    class that gets remote controls through an ethernet connection.
+//              Typical use case: a remote control is plugged in a workstation
+//              and sends remote control
+//              data to a distant target (this class) through Wifi//
+//
+/*********************************************************************/
+#include "IpcController.h"
+#include <Controller.h>
+#include <FrameworkManager.h>
+#include <TcpSocket.h>
+#include <UdpSocket.h>
+#include <cstring>
+#include <string>
+#include <Matrix.h>
+#include <stdexcept>
+
+using namespace flair::core;
+using namespace flair::gui;
+using std::string;
+
+namespace flair {
+namespace sensor {
+
+IpcController::IpcController(string name, uint16_t _port,
+                                         uint8_t priority)
+    : TargetController(name, priority), listeningPort(_port),
+      receiveCurrentPosition(0) {
+  
+  Thread::Err("ipc is not yet implemented!\n");
+        
+  const bool blocking = true;
+  listeningSocket =
+      new TcpSocket(getFrameworkManager(), "TEC_listening_socket", blocking, blocking);
+  dataSocket =
+      new UdpSocket(getFrameworkManager(), "TEC_data_socket", _port + 1); // receiving side
+}
+
+IpcController::~IpcController() {
+  // We are (currently) the server side. We must ask the client side to initiate
+  // tcp connexion closing to avoid the server socket
+  // to get stuck in TIME_WAIT state
+  Message msg(32);
+  if (controlSocket) {
+    Message cancelAcquisition(sizeof(ControllerAction));
+    ControllerAction exit = ControllerAction::Exit;
+    memcpy(cancelAcquisition.buffer, &exit, sizeof(ControllerAction));
+    controlSocket->SendMessage(cancelAcquisition.buffer,
+                               cancelAcquisition.bufferSize);
+    // We don't expect any more data from the client, we're just waiting for the
+    // socket to be closed by the client
+    controlSocket->RecvMessage(msg.buffer, msg.bufferSize);
+    delete controlSocket;
+  }
+
+  // TargetController calls IpcController methods in its run
+  // we must stop the thread now
+  SafeStop();
+  Join();
+  delete dataSocket;
+  delete listeningSocket;
+}
+
+bool IpcController::IsConnected() const {
+  // TODO
+}
+
+bool IpcController::IsDataFrameReady() {
+  // read up to the last data
+  ssize_t received;
+  size_t bytesToReceive = dataFrameSize - receiveCurrentPosition;
+  bool fullDatagramReceived = false;
+
+    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;
+}
+
+uint8_t IpcController::getByteOrNull(char *buffer, int byte,
+                                           size_t bufferSize) {
+  if (byte < bufferSize)
+    return buffer[byte];
+  else
+    return 0;
+}
+
+uint32_t IpcController::charBufferToUint32(char *buffer,
+                                                 size_t bufferSize) {
+  union {
+    uint32_t int32;
+    char byte[4];
+  } bitField;
+  if (!IsBigEndian()) {
+    bitField.byte[0] = getByteOrNull(buffer, 3, bufferSize);
+    bitField.byte[1] = getByteOrNull(buffer, 2, bufferSize);
+    bitField.byte[2] = getByteOrNull(buffer, 1, bufferSize);
+    bitField.byte[3] = getByteOrNull(buffer, 0, bufferSize);
+  } else {
+    bitField.byte[0] = getByteOrNull(buffer, 0, bufferSize);
+    bitField.byte[1] = getByteOrNull(buffer, 1, bufferSize);
+    bitField.byte[2] = getByteOrNull(buffer, 2, bufferSize);
+    bitField.byte[3] = getByteOrNull(buffer, 3, bufferSize);
+  }
+  return bitField.int32;
+}
+
+// read _up_to_16_bits_ in a buffer
+uint16_t IpcController::readBits(uint8_t offsetInBits,
+                                       uint8_t valueSizeInBits, char *buffer,
+                                       size_t bufferSize) {
+  // parameters check
+  if (valueSizeInBits > 16)
+    throw std::range_error("bitfield should be at max 16bits wide");
+  size_t minBufferSize = (offsetInBits + valueSizeInBits) / 8;
+  if ((offsetInBits + valueSizeInBits) % 8 != 0)
+    minBufferSize++;
+  if (bufferSize < minBufferSize)
+    throw std::range_error("buffer too small");
+  // skip first bytes
+  size_t bytesToSkip = offsetInBits / 8;
+  buffer += bytesToSkip;
+  bufferSize -= bytesToSkip;
+  offsetInBits -= bytesToSkip * 8;
+  // take care of endianness
+  uint32_t value = charBufferToUint32(buffer, bufferSize);
+  value >>= 32 - offsetInBits - valueSizeInBits;
+  value &= (1 << valueSizeInBits) - 1;
+  return (uint16_t)value;
+}
+
+void IpcController::AcquireAxisData(core::Matrix &axis) {
+  axis.GetMutex();
+  // char testFrameBuffer[3]={(char)0x09,(char)0x59,(char)0xB8};
+  for (unsigned int i = 0; i < axisNumber; i++) {
+    uint16_t rawAxisValue =
+        readBits(i * bitsPerAxis, bitsPerAxis, dataFrameBuffer, dataFrameSize);
+    //        uint16_t
+    //        rawAxisValue=readBits(i*bitsPerAxis,bitsPerAxis,testFrameBuffer);
+    uint16_t scale = 1 << (bitsPerAxis - 1);
+    // Thread::Info("RawAxisValue=%d, scale=%d => scaled rawValue=%d, float
+    // value)%f\n",rawAxisValue,scale,rawAxisValue-scale,(rawAxisValue-scale)/(float)scale);
+    axis.SetValueNoMutex(i, 0, (rawAxisValue - scale) / (float)scale);
+  }
+  axis.ReleaseMutex();
+}
+
+void IpcController::AcquireButtonData(core::Matrix &button) {
+  uint8_t buttonValue;
+  int currentButton = 0;
+  button.GetMutex();
+  /*
+  for (unsigned int i=0;i<buttonNumber;i++) {
+      memcpy(&buttonValue,buttonOffset+i*sizeof(bool),sizeof(bool));
+      dataSocket->NetworkToHost((char*)&buttonValue,sizeof(bool));
+      button.SetValueNoMutex(i,0,buttonValue);
+//        if (buttonValue) Thread::Info("Debug: button '%s' pressed\n",
+GetButtonName(i).c_str());
+  }*/
+  for (unsigned int i = 0; i < buttonNumber / 8; i++) {
+    memcpy(&buttonValue, dataFrameBuffer + buttonOffset + i * sizeof(uint8_t),
+           sizeof(uint8_t));
+    //        dataSocket->NetworkToHost((char*)&buttonValue,sizeof(uint8_t));
+    for (unsigned int j = 0; j < 8; j++) {
+      button.SetValueNoMutex(currentButton, 0, (buttonValue >> j) & 0x01);
+      currentButton++;
+    }
+  }
+  button.ReleaseMutex();
+}
+
+string IpcController::GetAxisName(unsigned int axisId) const {
+  // TODO: should throw an exception if axisName==NULL or axisId>axisNumber
+  return axisName[axisId];
+}
+
+string IpcController::GetButtonName(unsigned int buttonId) const {
+  // TODO: should throw an exception if buttonName==NULL or
+  // buttonId>buttonNumber
+  return buttonName[buttonId];
+}
+
+bool IpcController::ProcessMessage(Message *msg) {
+  return !(controlSocket->SendMessage(msg->buffer, msg->bufferSize, TIME_INFINITE) < 0);
+}
+
+bool IpcController::IsControllerActionSupported(
+    ControllerAction action) const {
+  // TODO: here we should ask the remote side (host). Probably through the
+  // control socket
+  switch (action) {
+  case ControllerAction::SetLedOn:
+    return true;
+  case ControllerAction::SetLedOff:
+    return true;
+  case ControllerAction::Rumble:
+    return true;
+  case ControllerAction::FlashLed:
+    return true;
+  default:
+    return false;
+  }
+}
+
+bool IpcController::ControllerInitialization() {
+  char message[1024];
+  ssize_t received;
+  bool connected = false;
+  bool mustReadMore;
+
+  listeningSocket->Listen(listeningPort);
+  Thread::Info("Debug: Listening to port %d\n", listeningPort);
+  // accept incoming connection
+  while (!controlSocket) {
+    try {
+      controlSocket = listeningSocket->Accept(100000000);
+    } catch (std::logic_error &e) {
+      Thread::Err("%s\n",e.what());
+      if (ToBeStopped())
+        return false;
+    } catch (std::runtime_error e) {
+      // timeout
+      //Thread::Err("%s\n",e.what());
+      if (ToBeStopped())
+        return false;
+    }
+  }
+  Thread::Info("Debug: Connexion accepted\n");
+
+  // get axis stuff
+  bool axisNumberRead = false;
+  while (!axisNumberRead) {
+    try {
+      axisNumber = controlSocket->ReadUInt32(100000000);
+      // Thread::Info("Debug: axisNumber %d\n", axisNumber);
+      axisNumberRead = true;
+    } catch (std::runtime_error e) {
+      // timeout
+      if (ToBeStopped())
+        return false;
+    }
+  }
+  bool bitsPerAxisRead = false;
+  while (!bitsPerAxisRead) {
+    try {
+      bitsPerAxis = controlSocket->ReadUInt32(100000000);
+      // Thread::Info("Debug: bits per axis %d\n", bitsPerAxis);
+      bitsPerAxisRead = true;
+    } catch (std::runtime_error e) {
+      // timeout
+      if (ToBeStopped())
+        return false;
+    }
+  }
+  axisName = new string[axisNumber];
+  for (unsigned int i = 0; i < axisNumber; i++) {
+    // read string size
+    int stringSize;
+    bool stringSizeRead = false;
+    while (!stringSizeRead) {
+      try {
+        stringSize = controlSocket->ReadUInt32(100000000);
+        stringSizeRead = true;
+      } catch (std::runtime_error e) {
+        // timeout
+        if (ToBeStopped())
+          return false;
+      }
+    }
+    // read string
+    bool axisNameRead = false;
+    while (!axisNameRead) {
+      try {
+        axisName[i] = controlSocket->ReadString(stringSize, 100000000);
+        axisNameRead = true;
+      } catch (std::runtime_error e) {
+        // timeout
+        if (ToBeStopped())
+          return false;
+      }
+    }
+    // Thread::Info("Debug: axisName for axis %d %s\n", i, axisName[i].c_str());
+  }
+
+  // get button stuff
+  bool buttonNumberRead = false;
+  while (!buttonNumberRead) {
+    try {
+      buttonNumber = controlSocket->ReadUInt32(100000000);
+      buttonNumberRead = true;
+    } catch (std::runtime_error e) {
+      // timeout
+      if (ToBeStopped())
+        return false;
+    }
+  }
+  // Thread::Info("Debug: buttonNumber %d\n", buttonNumber);
+  buttonName = new string[buttonNumber];
+  for (unsigned int i = 0; i < buttonNumber; i++) {
+    // read string size
+    int stringSize;
+    bool stringSizeRead = false;
+    while (!stringSizeRead) {
+      try {
+        stringSize = controlSocket->ReadUInt32(100000000);
+        stringSizeRead = true;
+      } catch (std::runtime_error e) {
+        // timeout
+        if (ToBeStopped())
+          return false;
+      }
+    }
+    // read string
+    bool buttonNameRead = false;
+    while (!buttonNameRead) {
+      try {
+        buttonName[i] = controlSocket->ReadString(stringSize, 10000000);
+        buttonNameRead = true;
+      } catch (std::runtime_error e) {
+        // timeout
+        if (ToBeStopped())
+          return false;
+      }
+    }
+    // Thread::Info("Debug: buttonName for button %d %s\n", i,
+    // buttonName[i].c_str());
+  }
+
+  //    dataFrameSize=axisNumber*sizeof(float)+buttonNumber/8*sizeof(uint8_t);
+  buttonOffset = (axisNumber * bitsPerAxis) / 8;
+  if ((axisNumber * bitsPerAxis) % 8 != 0)
+    buttonOffset++;
+  dataFrameSize = buttonOffset + (buttonNumber / 8) * sizeof(uint8_t);
+  if ((buttonNumber % 8) != 0)
+    dataFrameSize++;
+  dataFrameBuffer = new char[dataFrameSize];
+  receiveFrameBuffer = new char[dataFrameSize];
+
+  Thread::Info("Controller connected with host side\n");
+  if (buttonNumber % 8 != 0)
+    Thread::Err("Button number is not multiple of 8\n");
+  return true;
+}
+
+} // end namespace sensor
+} // end namespace flair
Index: trunk/lib/FlairIpc/src/IpcController.h
===================================================================
--- trunk/lib/FlairIpc/src/IpcController.h	(revision 397)
+++ trunk/lib/FlairIpc/src/IpcController.h	(revision 397)
@@ -0,0 +1,92 @@
+// %flair:license{
+// This file is part of the Flair framework distributed under the
+// CECILL-C License, Version 1.0.
+// %flair:license}
+//  created:    2021/03/03
+//  filename:   IpcController.h
+//
+//  author:     Sébastien Ambroziak
+//              Copyright Heudiasyc UMR UTC/CNRS 7253
+//
+//  version:    $Id: $
+//
+//  purpose:    class that gets remote controls through an ethernet connection.
+//              Typical use case: a remote control is plugged in a workstation
+//              and sends remote control
+//              data to a distant target (this class) through Wifi
+//
+//
+/*********************************************************************/
+
+#ifndef IPCCONTROLLER_H
+#define IPCCONTROLLER_H
+
+#include "TargetController.h"
+
+namespace flair {
+namespace core {
+class FrameworkManager;
+class Matrix;
+class TcpSocket;
+class UdpSocket;
+}
+namespace gui {
+class Tab;
+class TabWidget;
+class DataPlot1D;
+}
+}
+
+namespace flair {
+namespace sensor {
+/*! \class TargetController
+*
+* \brief Base Class for target side remote controls
+*
+*/
+class IpcController : public TargetController {
+public:
+  IpcController(std::string name,
+                      uint16_t port, uint8_t priority = 0);
+  ~IpcController();
+  // void DrawUserInterface();
+protected:
+  bool IsConnected() const;
+  // axis stuff
+  std::string GetAxisName(unsigned int axisId) const;
+  // button stuff
+  std::string GetButtonName(unsigned int axisId) const;
+  // controller state stuff
+  bool ProcessMessage(core::Message *msg);
+  bool IsControllerActionSupported(ControllerAction action) const;
+
+  bool IsDataFrameReady();
+  void AcquireAxisData(core::Matrix &axis);     // responsible for getting the
+                                                  // axis data from the hardware
+  void AcquireButtonData(core::Matrix &button); // responsible for getting the
+                                                  // button data from the
+                                                  // hardware
+
+  bool ControllerInitialization();
+
+private:
+  uint16_t readBits(uint8_t offsetInBits, uint8_t valueSizeInBits, char *buffer,
+                    size_t bufferSize);
+  uint8_t getByteOrNull(char *buffer, int byte, size_t bufferSize);
+  uint32_t charBufferToUint32(char *buffer, size_t bufferSize);
+  core::TcpSocket *listeningSocket;
+  int listeningPort;
+  core::TcpSocket *controlSocket = nullptr;
+  core::UdpSocket *dataSocket;
+  std::string *axisName = nullptr;
+  std::string *buttonName = nullptr;
+  size_t dataFrameSize;
+  char *dataFrameBuffer;
+  char *receiveFrameBuffer;
+  size_t receiveCurrentPosition;
+  uint8_t buttonOffset;
+};
+}
+}
+
+#endif // IPCCONTROLLER_H
Index: trunk/lib/FlairIpc/src/IpcImu.cpp
===================================================================
--- trunk/lib/FlairIpc/src/IpcImu.cpp	(revision 397)
+++ trunk/lib/FlairIpc/src/IpcImu.cpp	(revision 397)
@@ -0,0 +1,155 @@
+// %flair:license{
+// This file is part of the Flair framework distributed under the
+// CECILL-C License, Version 1.0.
+// %flair:license}
+//  created:    2021/03/03
+//  filename:   IpcImu.cpp
+//
+//  author:     Sébastien Ambroziak
+//              Copyright Heudiasyc UMR UTC/CNRS 7253
+//
+//  version:    $Id: $
+//
+//  purpose:    Class for an ipc imu
+//
+//
+/*********************************************************************/
+
+#include "IpcImu.h"
+#include "ipc_receive.h"
+#include <FrameworkManager.h>
+#include <ImuData.h>
+#include <SpinBox.h>
+#include <GroupBox.h>
+#include <Matrix.h>
+#include <AhrsData.h>
+
+using namespace flair::core;
+using namespace flair::gui;
+
+namespace flair {
+namespace sensor {
+
+IpcImu::IpcImu(std::string name, uint8_t priority, const char* ipc_name, int ipc_channel, bool AhrsOnly)
+    : Imu(name,false), Thread(getFrameworkManager(), name, priority) {
+  dataRate = new SpinBox(GetGroupBox()->NewRow(), "data rate", " Hz", 1, 500, 1, 200);
+  ahrsData = new AhrsData((Imu *)this);
+  _AhrsOnly = AhrsOnly;
+  if (AhrsOnly){
+    //AhrsReceiver = new IpcReceiver<ipc::type::ahrs>(ipc_name,ipc_channel);
+    orientation_quat = new IpcReceiver<ipc::type::vector4D_32>("ipc_quat",65);
+    angular_vel = new IpcReceiver<ipc::type::vector3D_32>("ipc_angl",65);
+  }
+  else{
+    ImuReceiver = new IpcReceiver<ipc::type::imu>(ipc_name,ipc_channel);
+  }
+  
+  SetIsReady(true);
+}
+
+IpcImu::~IpcImu() {
+  SafeStop();
+  Join();
+}
+
+
+void IpcImu::Run(void) {
+  imu_states_t state;
+  ImuData *imuData;
+  ipc::type::imu imu_msg;
+  ipc::type::ahrs ahrs_msg;
+  ipc::type::vector4D_32 quat_msg;
+  ipc::type::vector3D_32 angl_msg;
+  GetDatas(&imuData);
+
+  Quaternion quaternion;
+  Vector3Df angRate;
+  Vector3Df rawAcc;
+  Vector3Df rawMag;
+  Vector3Df rawGyr;
+  SetPeriodUS((uint32_t)(1000000. / dataRate->Value()));
+
+  while (!ToBeStopped()) {
+
+    angRate.x = 0;
+    angRate.y = 0;
+    angRate.z = 0;
+
+    rawAcc.x = 0;
+    rawAcc.y = 0;
+    rawAcc.z = 0;
+
+    rawMag.x = 0;
+    rawMag.y = 0;
+    rawMag.z = 0;
+
+    rawGyr.x = 0;
+    rawGyr.y = 0;
+    rawGyr.z = 0;
+
+    if (_AhrsOnly){
+      //AhrsReceiver->receive();
+      //ahrs_msg = AhrsReceiver->getValue();
+      
+      orientation_quat->receive();
+      angular_vel->receive();
+      quat_msg = orientation_quat->getValue();
+      angl_msg = angular_vel->getValue();
+
+      quaternion.q0 = quat_msg.x;
+      quaternion.q1 = quat_msg.y;
+      quaternion.q2 = quat_msg.z;
+      quaternion.q3 = quat_msg.w;
+
+      angRate.x = angl_msg.x;
+      angRate.y = angl_msg.y;
+      angRate.z = angl_msg.z;
+
+      imuData->SetDataTime(AhrsReceiver->getTimestamp().toNanosec());
+      ahrsData->SetDataTime(ImuReceiver->getTimestamp().toNanosec());
+    }
+    else {
+      ImuReceiver->receive();
+
+      imu_msg = ImuReceiver->getValue();
+
+      quaternion.q0 = imu_msg.orientation.w;
+      quaternion.q1 = imu_msg.orientation.x;
+      quaternion.q2 = imu_msg.orientation.y;
+      quaternion.q3 = imu_msg.orientation.z;
+
+      rawAcc.x = imu_msg.linear_acceleration.x;
+      rawAcc.y = imu_msg.linear_acceleration.y;
+      rawAcc.z = imu_msg.linear_acceleration.z;
+
+      /*rawGyr.x = imu_msg.angular_velocity.x;
+      rawGyr.y = imu_msg.angular_velocity.y;
+      rawGyr.z = imu_msg.angular_velocity.z;*/
+
+      angRate.x = imu_msg.angular_velocity.x;
+      angRate.y = imu_msg.angular_velocity.y;
+      angRate.z = imu_msg.angular_velocity.z;
+
+      imuData->SetDataTime(ImuReceiver->getTimestamp().toNanosec());
+      ahrsData->SetDataTime(ImuReceiver->getTimestamp().toNanosec());
+    }
+
+    
+    
+    //we do not need rotation in simulation
+    /*
+    ApplyRotation(angRate);
+    ApplyRotation(quaternion);
+    ApplyRotation(rawAcc);
+    ApplyRotation(rawMag);
+    ApplyRotation(rawGyr);*/
+    ahrsData->SetQuaternionAndAngularRates(quaternion,angRate);
+    imuData->SetRawAccMagAndGyr(rawAcc,rawMag,rawGyr);
+    
+    //ahrsData->SetDataTime(GetTime());
+    ProcessUpdate(ahrsData);
+  }
+}
+
+} // end namespace sensor
+} // end namespace flair
Index: trunk/lib/FlairIpc/src/IpcImu.h
===================================================================
--- trunk/lib/FlairIpc/src/IpcImu.h	(revision 397)
+++ trunk/lib/FlairIpc/src/IpcImu.h	(revision 397)
@@ -0,0 +1,113 @@
+// %flair:license{
+// This file is part of the Flair framework distributed under the
+// CECILL-C License, Version 1.0.
+// %flair:license}
+/*!
+ * \file IpcImu.h
+ * \brief Class for an ipc Imu
+ * \author Sébastien Ambroziak, Copyright Heudiasyc UMR UTC/CNRS 7253
+ * \date 2021/03/03
+ * \version 4.0
+ */
+
+#ifndef IPCIMU_H
+#define IPCIMU_H
+
+#include <Imu.h>
+#include <Thread.h>
+
+namespace flair {
+  namespace core {
+    class AhrsData;
+  }
+  namespace gui {
+    class SpinBox;
+  }
+}
+
+namespace ipc{
+  namespace type{
+    struct imu;
+    struct ahrs;
+    struct vector3D_32;
+    struct vector4D_32;
+  }
+}
+
+template <typename T>
+class IpcReceiver;
+
+namespace flair {
+namespace sensor {
+/*! \class IpcImu
+*
+* \brief Class for an Ipc Imu
+*/
+class IpcImu : public Imu, public core::Thread {
+public:
+  /*!
+  * \brief Constructor
+  *
+  * Construct an IpcImu.
+	* It will be child of the FrameworkManager.
+  *
+  * \param name name
+  * \param priority priority of the Thread
+  * \param ipc_name name of the ipc
+  * \param ipc_channel ipc channel number
+  * \param AhrsOnly AhrsOnly
+  */
+  IpcImu(std::string name, uint8_t priority,
+           const char* ipc_name, int ipc_channel, bool AhrsOnly=true);
+
+  /*!
+  * \brief Destructor
+  *
+  */
+  ~IpcImu();
+
+private:
+  /*!
+  * \brief Run function
+  *
+  * Reimplemented from Thread.
+  *
+  */
+  void Run(void);
+
+  /*!
+  * \brief Update using provided datas
+  *
+  * Reimplemented from IODevice.
+  *
+  * \param data data from the parent to process
+  */
+  void UpdateFrom(const core::io_data *data){};
+
+  typedef struct {
+    float q0;
+    float q1;
+    float q2;
+    float q3;
+    float wx;
+    float wy;
+    float wz;
+    float ax;
+    float ay;
+    float az;
+    float mx;
+    float my;
+    float mz;
+  } imu_states_t;
+
+  IpcReceiver<ipc::type::imu>* ImuReceiver;
+  IpcReceiver<ipc::type::ahrs>* AhrsReceiver;
+  IpcReceiver<ipc::type::vector4D_32>* orientation_quat;
+  IpcReceiver<ipc::type::vector3D_32>* angular_vel;
+  gui::SpinBox *dataRate;
+  core::AhrsData *ahrsData;
+  bool _AhrsOnly;
+};
+} // end namespace sensor
+} // end namespace flair
+#endif // IPCIMU_H
Index: trunk/lib/FlairIpc/src/IpcPressureSensor.cpp
===================================================================
--- trunk/lib/FlairIpc/src/IpcPressureSensor.cpp	(revision 397)
+++ trunk/lib/FlairIpc/src/IpcPressureSensor.cpp	(revision 397)
@@ -0,0 +1,71 @@
+// %flair:license{
+// This file is part of the Flair framework distributed under the
+// CECILL-C License, Version 1.0.
+// %flair:license}
+//  created:    2021/03/03
+//  filename:   IpcPressureSensor.cpp
+//
+//  author:     Sébastien Ambroziak
+//              Copyright Heudiasyc UMR UTC/CNRS 7253
+//
+//  version:    $Id: $
+//
+//  purpose:    Class for an ipc pressure sensor
+//
+//
+/*********************************************************************/
+
+#include "IpcPressureSensor.h"
+#include "shm_receive.h"
+#include <FrameworkManager.h>
+#include <SpinBox.h>
+#include <GroupBox.h>
+#include <Matrix.h>
+
+
+using namespace flair::core;
+using namespace flair::gui;
+
+namespace flair {
+namespace sensor {
+
+IpcPressureSensor::IpcPressureSensor(string name,
+               uint8_t priority, const char* ipc_name, int ipc_channel)
+    : Thread(getFrameworkManager(), name, priority), PressureSensor( name) {
+  data_rate =
+      new SpinBox(GetGroupBox()->NewRow(), "data rate", " Hz", 1, 500, 1, 50);
+
+  receiver = new ShmReceiver<float>(ipc_name,ipc_channel);
+
+  SetIsReady(true);
+}
+
+
+IpcPressureSensor::~IpcPressureSensor() {
+  SafeStop();
+  Join();
+}
+
+
+void IpcPressureSensor::Run(void) {
+
+  SetPeriodUS((uint32_t)(1000000. / data_rate->Value()));
+
+  while (!ToBeStopped()) {
+    WaitPeriod();
+
+    receiver->receive();
+    //shmem->Read((char *)&p, sizeof(float));
+
+    if (data_rate->ValueChanged() == true) {
+      SetPeriodUS((uint32_t)(1000000. / data_rate->Value()));
+    }
+
+    output->SetValue(0, 0, receiver->getValue());
+    output->SetDataTime(receiver->getTimestamp().toNanosec());
+    ProcessUpdate(output);
+  }
+}
+
+} // end namespace sensor
+} // end namespace flair
Index: trunk/lib/FlairIpc/src/IpcPressureSensor.h
===================================================================
--- trunk/lib/FlairIpc/src/IpcPressureSensor.h	(revision 397)
+++ trunk/lib/FlairIpc/src/IpcPressureSensor.h	(revision 397)
@@ -0,0 +1,88 @@
+// %flair:license{
+// This file is part of the Flair framework distributed under the
+// CECILL-C License, Version 1.0.
+// %flair:license}
+/*!
+ * \file IpcPressureSensor.h
+ * \brief Class for an ipc PressureSensor
+ * \author Sébastien Ambroziak, Copyright Heudiasyc UMR UTC/CNRS 7253
+ * \date 2021/03/03
+ * \version 4.0
+ */
+
+#ifndef IPCPRESSURESENSOR_H
+#define IPCPRESSURESENSOR_H
+
+#include <PressureSensor.h>
+#include <Thread.h>
+
+namespace flair {
+namespace core {
+class SharedMem;
+}
+namespace gui {
+class SpinBox;
+}
+}
+
+template <typename T>
+class ShmReceiver;
+
+namespace flair {
+namespace sensor {
+/*! \class IpcPressureSensor
+*
+* \brief Class for an ipc PressureSensor
+*/
+class IpcPressureSensor : public core::Thread, public PressureSensor {
+public:
+  /*!
+  * \brief Constructor
+  *
+  * Construct an IpcPressureSensor.
+	* It will be child of the FrameworkManager.
+  *
+  * \param name name
+  * \param priority priority of the Thread
+  * \param ipc_name name of the ipc
+  * \param ipc_channel ipc channel number
+  */
+  IpcPressureSensor(std::string name,
+         uint8_t priority, const char* ipc_name, int ipc_channel);
+
+  /*!
+  * \brief Destructor
+  *
+  */
+  ~IpcPressureSensor();
+
+protected:
+  /*!
+  * \brief SharedMem to access datas
+  *
+  */
+
+private:
+  /*!
+  * \brief Update using provided datas
+  *
+  * Reimplemented from IODevice.
+  *
+  * \param data data from the parent to process
+  */
+  void UpdateFrom(const core::io_data *data){};
+
+  /*!
+  * \brief Run function
+  *
+  * Reimplemented from Thread.
+  *
+  */
+  void Run(void);
+
+  gui::SpinBox *data_rate;
+  ShmReceiver<float>* receiver;
+};
+} // end namespace sensor
+} // end namespace flair
+#endif // IPCPRESSURESENSOR_H
Index: trunk/lib/FlairIpc/src/IpcUs.cpp
===================================================================
--- trunk/lib/FlairIpc/src/IpcUs.cpp	(revision 397)
+++ trunk/lib/FlairIpc/src/IpcUs.cpp	(revision 397)
@@ -0,0 +1,104 @@
+// %flair:license{
+// This file is part of the Flair framework distributed under the
+// CECILL-C License, Version 1.0.
+// %flair:license}
+//  created:    2021/03/03
+//  filename:   IpcUs.cpp
+//
+//  author:     Sébastien Ambroziak
+//              Copyright Heudiasyc UMR UTC/CNRS 7253
+//
+//  version:    $Id: $
+//
+//  purpose:    Class for an ipc us
+//
+//
+/*********************************************************************/
+
+#include "IpcUs.h"
+#include "ipc_receive.h"
+#include "shm_receive.h"
+#include <FrameworkManager.h>
+#include <SpinBox.h>
+#include <GroupBox.h>
+#include <Matrix.h>
+
+using namespace flair::core;
+using namespace flair::gui;
+
+namespace flair {
+namespace sensor {
+
+IpcUs::IpcUs(string name, uint8_t priority, const char* ipc_name, int ipc_channel)
+    : Thread(getFrameworkManager(), name, priority), UsRangeFinder( name) {
+  data_rate =
+      new SpinBox(GetGroupBox()->NewRow(), "data rate", " Hz", 1, 500, 1, 50);
+
+  //init non blocking ipc receiver
+  receiver = new ShmReceiver<float>(ipc_name,ipc_channel,true);
+
+  SetIsReady(true);
+}
+
+IpcUs::~IpcUs() {
+  SafeStop();
+  Join();
+}
+
+
+void IpcUs::Run(void) {
+  
+  SetPeriodUS((uint32_t)(1000000. / data_rate->Value()));
+  Time stamp; 
+  Time lastT = GetTime();
+  while (!ToBeStopped()) {
+    WaitPeriod();
+
+    receiver->receive();
+
+    stamp = GetTime();
+
+    //SetPeriodUS((receiver->getTimestamp().toNanosec() - Last)/1000);
+    
+    
+    
+    if (data_rate->ValueChanged() == true) {
+      SetPeriodUS((uint32_t)(1000000. / data_rate->Value()));
+    }
+
+    //output->SetDataTime((Time)receiver->getTimestamp().toNanosec());
+    /*if (lastT < receiver->getTimestamp().toNanosec()){
+      output->SetValue(0, 0, receiver->getValue());
+      output->SetDataTime(receiver->getTimestamp().toNanosec());
+      //cout << "lastT: " << receiver->getTimestamp().toNanosec()  << " ecart: " << receiver->getTimestamp().toNanosec() - lastT << endl;
+      lastT = receiver->getTimestamp().toNanosec();
+    }
+
+    else{
+      output->SetValue(0, 0, receiver->getValue());
+      output->SetDataTime(lastT + GetPeriodUS()*1000);
+      //cout << "stamp: " << lastT + GetPeriodUS() << ' ' << " \tecart: " << stamp - lastT << endl;
+      lastT = lastT + GetPeriodUS()*1000;
+    }*/
+
+    /*if (receiver->getValue() >= 0){
+      output->SetValue(0, 0, (receiver->getValue())/100.0);
+    }
+    else
+    {
+      output->SetValue(0,0,0);
+    }*/
+    
+    output->SetValue(0, 0, (receiver->getValue())/100.0);
+    output->SetDataTime(stamp);
+    //output->SetDataTime(receiver->getTimestamp().toNanosec());
+
+    //cout << receiver->getTimestamp().toNanosec() << ' ' << receiver->getValue() << endl;
+    ProcessUpdate(output);
+    //cout << "GetTime: " <<  stamp << " ipc: " << receiver->getTimestamp().toNanosec() << " écart: " << stamp - receiver->getTimestamp().toNanosec() << endl;
+  }
+}
+
+} // end namespace sensor
+} // end namespace flair
+
Index: trunk/lib/FlairIpc/src/IpcUs.h
===================================================================
--- trunk/lib/FlairIpc/src/IpcUs.h	(revision 397)
+++ trunk/lib/FlairIpc/src/IpcUs.h	(revision 397)
@@ -0,0 +1,83 @@
+// %flair:license{
+// This file is part of the Flair framework distributed under the
+// CECILL-C License, Version 1.0.
+// %flair:license}
+/*!
+ * \file IpcUs.h
+ * \brief Class for an ipc UsRangeFinder
+ * \author Sébastien Ambroziak Copyright Heudiasyc UMR UTC/CNRS 7253
+ * \date 2021/03/03
+ * \version 4.0
+ */
+
+#ifndef IPCUS_H
+#define IPCUS_H
+
+#include <UsRangeFinder.h>
+#include <Thread.h>
+
+namespace flair {
+namespace gui {
+class SpinBox;
+}
+}
+
+template <typename T>
+class ShmReceiver;
+
+template <typename T>
+class IpcReceiver;
+
+namespace flair {
+namespace sensor {
+/*! \class IpcUs
+*
+* \brief Class for a simulation UsRangeFinder
+*/
+class IpcUs : public core::Thread, public UsRangeFinder {
+public:
+  /*!
+  * \brief Constructor
+  *
+  * Construct an IpcUs.
+	* It will be child of the FrameworkManager.
+  *
+  * \param name name
+  * \param modelId Model id
+  * \param ipc_name name of the ipc
+  * \param ipc_channel ipc channel number
+  
+  */
+  IpcUs(std::string name, uint8_t priority, const char* ipc_name, int ipc_channel);
+
+  /*!
+  * \brief Destructor
+  *
+  */
+  ~IpcUs();
+
+
+private:
+  /*!
+  * \brief Update using provided datas
+  *
+  * Reimplemented from IODevice.
+  *
+  * \param data data from the parent to process
+  */
+  void UpdateFrom(const core::io_data *data){};
+
+  /*!
+  * \brief Run function
+  *
+  * Reimplemented from Thread.
+  *
+  */
+  void Run(void);
+  
+  gui::SpinBox *data_rate;
+  ShmReceiver<float>* receiver;
+};
+} // end namespace sensor
+} // end namespace flair
+#endif // IPCUS_H
Index: trunk/lib/FlairIpc/src/IpcX4.cpp
===================================================================
--- trunk/lib/FlairIpc/src/IpcX4.cpp	(revision 397)
+++ trunk/lib/FlairIpc/src/IpcX4.cpp	(revision 397)
@@ -0,0 +1,69 @@
+// %flair:license{
+// This file is part of the Flair framework distributed under the
+// CECILL-C License, Version 1.0.
+// %flair:license}
+//  created:    2021/03/03
+//  filename:   IpcX4.cpp
+//
+//  author:     Sébastien Ambroziak
+//              Copyright Heudiasyc UMR UTC/CNRS 7253
+//
+//  version:    $Id: $
+//
+//  purpose:    Class defining an x4 uav using ipc data
+//
+//
+/*********************************************************************/
+
+#include <IpcX4.h>
+#include <IpcBldc.h>
+#include <IpcUs.h>
+#include <IpcAhrs.h>
+#include <IpcImu.h>
+#include <BatteryMonitor.h>
+#include <FrameworkManager.h>
+#include <X4X8Multiplex.h>
+#include <Tab.h>
+//#include <FindArgument.h>
+
+
+using std::string;
+using namespace flair::core;
+using namespace flair::gui;
+using namespace flair::sensor;
+using namespace flair::filter;
+using namespace flair::actuator;
+
+namespace flair {
+namespace meta {
+
+IpcX4::IpcX4(string name,string options,
+               filter::UavMultiplex *multiplex)
+    : Uav(name, multiplex) {
+
+  if (multiplex == NULL)
+    SetMultiplex(new X4X8Multiplex("motors", X4X8Multiplex::X4));
+
+  SetBldc(new IpcBldc(GetUavMultiplex(), GetUavMultiplex()->GetLayout(),"motors", GetUavMultiplex()->MotorsCount(),"motors",65));
+  
+  SetUsRangeFinder(new IpcUs("us", 70, "altitude", 65));
+ 
+  SetAhrs(new IpcAhrs("ahrs",70,"imu",65));
+
+  Tab *bat_tab = new Tab(getFrameworkManager()->GetTabWidget(), "battery");
+  SetBatteryMonitor(new BatteryMonitor(bat_tab->NewRow(), "battery"));
+  GetBatteryMonitor()->SetBatteryValue(12);
+  
+}
+
+IpcX4::~IpcX4() {}
+
+void IpcX4::StartSensors(void) {
+  ((IpcImu *)(GetAhrs()->GetImu()))->Start();
+  ((IpcUs *)GetUsRangeFinder())->Start();
+  
+}
+
+
+} // end namespace meta
+} // end namespace flair
Index: trunk/lib/FlairIpc/src/IpcX4.h
===================================================================
--- trunk/lib/FlairIpc/src/IpcX4.h	(revision 397)
+++ trunk/lib/FlairIpc/src/IpcX4.h	(revision 397)
@@ -0,0 +1,38 @@
+// %flair:license{
+// This file is part of the Flair framework distributed under the
+// CECILL-C License, Version 1.0.
+// %flair:license}
+/*!
+ * \file IpcX4.h
+ * \brief Class defining an ipc x4 uav
+ * \author Sébastien Ambroziak, Copyright Heudiasyc UMR UTC/CNRS 7253
+ * \date 2021/03/03
+ * \version 4.0
+ */
+
+#ifndef IPCX4_H
+#define IPCX4_H
+
+#include "Uav.h"
+
+namespace flair {
+namespace meta {
+  
+/*! \class IpcX4
+*
+* \brief Class defining an ipc x4 uav
+*/
+class IpcX4 : public Uav {
+  public:
+    IpcX4(std::string name,std::string options="",
+           filter::UavMultiplex *multiplex = NULL);
+    ~IpcX4();
+    void StartSensors(void);
+    virtual std::string GetType(void) const{return "x4_ipc";}
+
+  private:
+  
+};
+} // end namespace meta
+} // end namespace flair
+#endif // IPCX4_H
Index: trunk/lib/FlairIpc/src/constructor.cpp
===================================================================
--- trunk/lib/FlairIpc/src/constructor.cpp	(revision 397)
+++ trunk/lib/FlairIpc/src/constructor.cpp	(revision 397)
@@ -0,0 +1,42 @@
+// %flair:license{
+// This file is part of the Flair framework distributed under the
+// CECILL-C License, Version 1.0.
+// %flair:license}
+//  created:    2021/03/03
+//  filename:   constructor.cpp
+//
+//  author:     Sébastien Ambroziak
+//              Copyright Heudiasyc UMR UTC/CNRS 7253
+//
+//  version:    $Id: $
+//
+//  purpose:    constructor for ipc lib
+//
+//
+/*********************************************************************/
+
+#include <stdio.h>
+#include <UavFactory.h>
+#include "IpcX4.h"
+#include "compile_info.h"
+
+static void constructor() __attribute__((constructor));
+
+using namespace std;
+using namespace flair::core;
+using namespace flair::filter;
+using namespace flair::meta;
+
+Uav *CreateIpcX4(string name, string uav_type,string options,
+               UavMultiplex *multiplex) {
+  if(uav_type=="x4_ipc") {
+    return new IpcX4(name,options,multiplex);
+  } else {
+    return NULL;
+  }
+}
+
+void constructor() {
+  compile_info("x4_ipc");
+  RegisterUavCreator(CreateIpcX4);
+}
Index: trunk/lib/FlairIpc/src/unexported/ipc_base.h
===================================================================
--- trunk/lib/FlairIpc/src/unexported/ipc_base.h	(revision 397)
+++ trunk/lib/FlairIpc/src/unexported/ipc_base.h	(revision 397)
@@ -0,0 +1,247 @@
+/**
+ * \file ipc_base.h
+ * \brief definition de structures
+ * \author {
+ * 			Sébastien Ambroziak
+ * 			Paul Sauvage
+ * 			}
+ * \version 0.1
+ * \date 5 novembre 2020
+ *
+ * Definitions des structures pour la message queue
+ *
+ */
+
+
+#ifndef IPC_BASE
+#define IPC_BASE
+
+#include <string>
+#include <iostream>
+
+#define ROS2 1
+#define FLAIR 2
+#define ARDUPILOT 3
+
+#include <ctime>
+
+//#define MAX_TOPIC_SIZE 25
+//#define MAX_CHAR_ARRAY_SIZE 255
+
+// structures for message queue
+namespace ipc{
+namespace type{
+
+struct vector2D {
+	double x;
+	double y;
+};
+
+struct vector2D_32 {
+	float x;
+	float y;
+	float z;
+};
+
+inline std::ostream &operator<<(std::ostream &out, vector2D vecteur) {
+    out << "\tx : " << vecteur.x << std::endl;
+	out << "\ty : " << vecteur.y << std::endl;
+    return out;
+}
+
+struct vector3D {
+	double x;
+	double y;
+	double z;
+};
+
+struct vector3D_32 {
+	float x;
+	float y;
+	float z;
+};
+
+inline std::ostream &operator<<(std::ostream &out, vector3D vecteur) {
+    out << "\tx : " << vecteur.x << std::endl;
+	out << "\ty : " << vecteur.y << std::endl;
+	out << "\tz : " << vecteur.z << std::endl;
+    return out;
+}
+
+inline std::ostream &operator<<(std::ostream &out, vector3D_32 vecteur) {
+    out << "\tx : " << vecteur.x << std::endl;
+	out << "\ty : " << vecteur.y << std::endl;
+	out << "\tz : " << vecteur.z << std::endl;
+    return out;
+}
+
+struct acceleration {
+	vector3D linear;
+	vector3D angular;
+};
+
+struct vector4D {
+	double x;
+	double y;
+	double z;
+	double w;
+};
+
+struct vector4D_32 {
+	float x;
+	float y;
+	float z;
+	float w;
+};
+
+inline std::ostream &operator<<(std::ostream &out, vector4D vecteur) {
+    out << "\tx : " << vecteur.x << std::endl;
+	out << "\ty : " << vecteur.y << std::endl;
+	out << "\tz : " << vecteur.z << std::endl;
+	out << "\tw : " << vecteur.w << std::endl;
+    return out;
+}
+
+inline std::ostream &operator<<(std::ostream &out, vector4D_32 vecteur) {
+    out << "\tx : " << vecteur.x << std::endl;
+	out << "\ty : " << vecteur.y << std::endl;
+	out << "\tz : " << vecteur.z << std::endl;
+	out << "\tw : " << vecteur.w << std::endl;
+    return out;
+}
+
+struct matrix {
+	int width;
+	int height;
+	float data[5][5];
+};
+
+inline std::ostream &operator<<(std::ostream &out, matrix M) {
+    
+	for(int j = 0;j < M.height;j++){
+		out<<"\t| "<<M.data[0][j];
+		for(int i = 1;i < M.width;i++){
+			out << "\t " << M.data[i][j];
+		}
+		out << " |" << std::endl;
+	}
+    return out;
+}
+
+struct imu{
+	vector4D orientation;
+	double orientation_covariance[9];
+
+	vector3D angular_velocity;
+	double angular_velocity_covariance[9];
+
+	vector3D linear_acceleration;
+	double linear_acceleration_covariance[9];
+};
+
+inline std::ostream &operator<<(std::ostream &out, imu msg) {
+	out << "orientation : \n" << msg.orientation << std::endl;
+	out << "orientation covarience : " ;
+	for (int i=0;i<9;i++){out << msg.orientation_covariance[i] << ' ';} 
+	out << std::endl;
+
+	out << "angular_velocity : \n" << msg.angular_velocity << std::endl;
+	out << "angular_velocity_covariance : " ;
+	for (int i=0;i<9;i++){out << msg.orientation_covariance[i] << ' ';} 
+	out << std::endl;
+
+	out << "linear_acceleration : \n" << msg.linear_acceleration << std::endl;
+	out << "linear_acceleration_covariance : " ;
+	for (int i=0;i<9;i++){out << msg.linear_acceleration_covariance[i] << ' ';} 
+	out << std::endl;
+
+    return out;
+}
+
+struct ahrs{
+	vector4D_32 quaternion;
+	vector3D_32 angular_rate;
+};
+
+inline std::ostream &operator<<(std::ostream &out, ahrs msg) {
+	out << "quaternion : \n" << msg.quaternion << std::endl;
+	out << "angular_rate : \n" << msg.angular_rate << std::endl;
+    return out;
+}
+
+
+/**
+ * \struct ipc_message
+ * \brief Structure classique de message ipc.
+ * 
+ * 	\param T permet de choisir le type de l'élément data
+ *  \param N permet de choisir la taille du tableau d'objet du message 
+ *  Si N = 0 : data est une structure de type T
+ *  Si N > 0 : data est un tableau d'élement de type T et de taille N
+ */
+
+
+
+struct timestamp{
+	uint32_t sec=0;
+  	uint32_t nanosec=0;
+
+	void now(){
+		struct timespec now;
+		timespec_get( &now, TIME_UTC );
+		sec = (int32_t)now.tv_sec;
+		nanosec = (uint32_t)now.tv_nsec;
+	}
+
+	uint64_t toNanosec(){
+		return (uint64_t)((uint64_t)sec*1000000000 + (uint64_t)nanosec) ;
+	}
+};
+
+inline std::ostream &operator<<(std::ostream &out, timestamp stamp) {
+    out << "[" << stamp.sec << '.' << stamp.nanosec << ']';
+    return out;
+}
+
+inline timestamp operator-(timestamp const& a, timestamp const& b)
+{
+    timestamp resultat;
+    resultat.sec = a.sec - b.sec;
+	resultat.nanosec = a.nanosec - b.nanosec;
+    return resultat;
+}
+
+//message ipc
+
+template <typename T>
+struct ipc_message {
+	long msg_type = 1;
+	struct {
+		struct timestamp stamp;
+		T value;
+	} data;
+
+	void time_now(){
+		data.stamp.now();
+	}
+};
+
+template <typename T>
+struct ipc_tab {
+	long msg_type = 1;
+	struct {
+		struct timestamp stamp;
+		T values[1];
+	} data;
+
+	void time_now(){
+		data.stamp.now();
+	}
+};
+
+} // end namespace type
+} // end namespace ipc
+
+
+
+#endif
Index: trunk/lib/FlairIpc/src/unexported/ipc_receive.h
===================================================================
--- trunk/lib/FlairIpc/src/unexported/ipc_receive.h	(revision 397)
+++ trunk/lib/FlairIpc/src/unexported/ipc_receive.h	(revision 397)
@@ -0,0 +1,148 @@
+/**
+ * \file ipc_receive.h
+ * \brief definition de classe
+ * \author {
+ * 			Sébastien Ambroziak
+ * 			Paul Sauvage
+ * 			}
+ * \version 0.1
+ * \date 5 novembre 2020
+ *
+ * Definitions de la classe IpcReceiver ainsi que ses méthodes.
+ * Cette classe permet de recevoir des structures ou des liste de structure par ipc
+ * 
+ * La classe IpcReceiver utilise une template à 2 paramètres, T et N
+ * 	le paramètre T correspond au type de donnée que le receiver doit recevoir
+ * 	le paramètre N correspond au nombre d'élément du tableau d'élément de type T à recevoir
+ * 		si N = 0 la fonction receive() retourne directement un objet de type T
+ * 		si N > 0 la fonction receive() retourne un pointeur de type T et donc un tableau d'élément T de N éléments
+ * 
+ * Le constructeur utilise 2 paramètres:
+ *  Une chaîne de caractère contenant le nom du fichier ipc vers lequel lire les données
+ *  Un entier correspond au numéro de canal Ipc
+ * 
+ */
+
+
+
+#ifndef IPC_RECEIVE
+#define IPC_RECEIVE
+
+#include "ipc_base.h"
+
+#include <functional>
+#include <memory>
+#include <iostream>
+#include <stdio.h>
+#include <type_traits>
+
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#include <sys/time.h>
+#include <string>
+#include <errno.h>
+
+using namespace std;
+using namespace ipc::type;
+
+class IpcReceiverBase {
+	public:
+		IpcReceiverBase(const char* ipc_name, int proj_id=65){
+			cout << "IpcReceiver on " << ipc_name << endl;
+			system("mkdir -p /tmp/ipc");
+			system("chmod 777 /tmp/ipc");
+
+			string pathname = string("/tmp/ipc/") + string(ipc_name);
+			string command = string("> ") + pathname;
+			system(command.c_str());
+			
+			command = string("chmod 666 ") + pathname;
+			system(command.c_str());
+
+			key_t ipc_key = ftok(pathname.c_str(), proj_id); //crete unique key
+			cout << "ipc key " << ipc_key << endl << endl;
+			_queue_id = msgget(ipc_key, 0666 | IPC_CREAT); //create message queue and return id
+		}
+
+		~IpcReceiverBase(){msgctl(_queue_id, IPC_RMID, NULL);} //destroy the message queue.
+
+	protected:
+		int _queue_id;
+};
+
+template <typename T>
+class IpcReceiver : IpcReceiverBase {
+	public:
+		IpcReceiver(const char* ipc_name, int proj_id=65, bool blocking = true): IpcReceiverBase(ipc_name, proj_id), _blocking(blocking) {}
+		~IpcReceiver() = default;
+
+		int receive(){
+			if(_blocking){
+				msgrcv(_queue_id, &_message, sizeof(_message.data), 0, 0);
+			}
+			else if(msgrcv(_queue_id, &_message, sizeof(_message.data), 0, IPC_NOWAIT) == -1){
+				return -1;
+			}
+			return 0;
+		}
+
+		timestamp getTimestamp() const {
+			return _message.data.stamp;
+		}
+
+		T getValue() const {return _message.data.value;}
+
+
+	protected:
+		ipc_message<T> _message;
+		bool _blocking;
+};
+
+template <typename T>
+class IpcReceiverTab : IpcReceiverBase {
+	public:
+		IpcReceiverTab(size_t N, const char* ipc_name, int proj_id=65, bool blocking = true): IpcReceiverBase(ipc_name, proj_id), _N(N), _blocking(blocking) {
+			_message = (ipc_tab<T>*) malloc(sizeof(ipc_tab<T>) + sizeof(T)*N);
+		}
+
+		~IpcReceiverTab() = default;
+
+		int receive(){
+			if(_blocking){
+				msgrcv(_queue_id, _message, sizeof(T)*_N + sizeof(_message->data), 0, 0);
+			}
+			else if(msgrcv(_queue_id, _message, sizeof(T)*_N + sizeof(_message->data), 0, IPC_NOWAIT) == -1){
+				return -1;
+			}
+			return 0;
+		}
+		
+		T getValue(size_t index) const {
+			return _message->data.values[index];
+		}
+
+		const T* getValues() const {
+			return _message->data.values;
+		}
+
+		timestamp getTimestamp() const {
+			return _message->data.stamp;
+		}
+
+		size_t getN() const {return _N;}
+
+		void setAll(T value) {
+			for (size_t i = 0; i < _N; i++)
+			{
+				_message->data.values[i] = value;
+			}
+		}
+
+	protected:
+		size_t _N;
+		bool _blocking;
+		ipc_tab<T> *_message;
+		
+};
+
+#endif
Index: trunk/lib/FlairIpc/src/unexported/ipc_send.h
===================================================================
--- trunk/lib/FlairIpc/src/unexported/ipc_send.h	(revision 397)
+++ trunk/lib/FlairIpc/src/unexported/ipc_send.h	(revision 397)
@@ -0,0 +1,178 @@
+/**
+ * \file ipc_send.h
+ * \brief definition de classe
+ * \author {
+ * 			Sébastien Ambroziak
+ * 			Paul Sauvage
+ * 			}
+ * \version 0.1
+ * \date 5 novembre 2020
+ *
+ * Definitions de la classe IpcSender ainsi que ses méthodes.
+ * Cette classe permet d'envoyer des structures ou des liste de structure par ipc
+ * 
+ * La classe IpcSender utilise une template à 2 paramètres, T et N
+ * 	le paramètre T correspond au type de donnée que le sender doit pouvoir envoyer
+ * 	le paramètre N correspond au nombre d'élément du tableau d'élément de type T à envoyer
+ * 		si N = 0 la fonction send() prend en paramètre et envoi une structure de type T
+ * 		si N > 0 la fonction send() prend en paramètre et envoi un tableau de N éléments de type T
+ *
+* Le constructeur utilise 2 paramètres:
+ *  Une chaîne de caractère contenant le nom du fichier ipc vers lequel écrire les données
+ *  Un entier correspond au numéro de canal Ipc
+ * 
+ */
+
+#ifndef IPC_SEND
+#define IPC_SEND
+
+#include "ipc_base.h"
+
+#include <functional>
+#include <memory>
+#include <stdio.h>
+
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#include <sys/time.h>
+
+#include <string>
+#include <cstring>
+#include <errno.h>
+
+using namespace std;
+using namespace ipc::type;
+
+class IpcSenderBase {
+	public:
+		IpcSenderBase(const char* ipc_name, int proj_id=65) {
+			cout << "IpcReceiver on " << ipc_name << endl;
+			system("mkdir -p /tmp/ipc");
+			system("chmod 777 /tmp/ipc");
+
+			string pathname = string("/tmp/ipc/") + string(ipc_name);
+			string command = string("> ") + pathname;
+			system(command.c_str());
+			
+			command = string("chmod 666 ") + pathname;
+			system(command.c_str());
+
+			key_t ipc_key = ftok(pathname.c_str(), proj_id); //crete unique key
+			cout << "ipc key " << ipc_key << endl << endl;
+			_queue_id = msgget(ipc_key, 0666 | IPC_CREAT); //create message queue and return id
+		}
+		~IpcSenderBase() {
+			msgctl(_queue_id, IPC_RMID, NULL); //destroy the message queue.
+		}
+	
+	protected:
+		int _queue_id;
+
+};
+
+template <typename T>
+class IpcSender : IpcSenderBase {
+	public:
+		IpcSender(const char* ipc_name, int proj_id=65, bool auto_refresh = true): IpcSenderBase(ipc_name, proj_id), _auto_refresh(auto_refresh) {}
+		~IpcSender() = default;
+
+		void send(){
+			if(_auto_refresh) refreshTime();
+			if (msgsnd(_queue_id, &_message, sizeof(_message.data), IPC_NOWAIT) < 0) //send message
+			{
+				//std::cout << "Erreur envoi message" << std::endl;
+			}
+		}
+
+		void send(T value)
+		{
+			_message.data.value = value;
+			send();
+		}
+
+		timestamp getTimestamp(){
+			return _message.data.stamp;
+		}
+
+		timestamp refreshTime(){
+			_message.time_now();
+			return _message.data.stamp;
+		}
+
+		T getValue(){return _message.data.value;}
+
+		void setValue(T value){_message.data.value = value;}
+
+		void setTimestamp(timestamp stamp){_message.data.stamp = stamp;}
+		void setTimestamp(int32_t sec, uint32_t nanosec){
+			_message.data.stamp.sec = sec;
+			_message.data.stamp.nanosec = nanosec;
+		}
+
+	protected:
+		bool _auto_refresh;
+		ipc_message<T> _message;
+};
+
+
+template <typename T>
+class IpcSenderTab : IpcSenderBase {
+	public:
+		IpcSenderTab(size_t N, const char* ipc_name, int proj_id=65, bool auto_refresh = true): IpcSenderBase(ipc_name, proj_id), _N(N), _auto_refresh(auto_refresh){
+			_message = (ipc_tab<T>*) malloc(sizeof(ipc_tab<T>) + sizeof(T)*(N-1));
+			_message->msg_type = 1;
+		}
+		~IpcSenderTab() = default;
+
+		void send(T* values){
+			memcpy(_message->data.values, values, sizeof(T)*_N);
+			send();
+		}
+
+		void send(){
+			if(_auto_refresh) refreshTime();
+			if (msgsnd(_queue_id, _message, sizeof(T)*_N + sizeof(_message->data), IPC_NOWAIT) < 0) //send message
+			{
+				//cout << errno << endl;
+			}
+		}
+
+		void setTimestamp(timestamp stamp){_message->data.stamp = stamp;}
+		void setTimestamp(int32_t sec, uint32_t nanosec){
+			_message->data.stamp.sec = sec;
+			_message->data.stamp.nanosec = nanosec;
+		}
+
+		timestamp getTimestamp(){
+			return _message->data.stamp;
+		}
+
+		timestamp refreshTime(){
+			_message->time_now();
+			return _message->data.stamp;
+		}
+
+		void setValue(T value, size_t index){
+			if(index < _N){
+				_message->data.values[index] = value;
+			}
+		}
+
+		void setAll(T value) {
+			for (size_t i = 0; i < _N; i++)
+			{
+				_message->data.values[i] = value;
+			}
+		}
+
+		size_t getN() const {return _N;}
+
+	protected:
+		size_t _N;
+		bool _auto_refresh;
+		ipc_tab<T>* _message;
+		
+};
+
+
+#endif
Index: trunk/lib/FlairIpc/src/unexported/shm_receive.h
===================================================================
--- trunk/lib/FlairIpc/src/unexported/shm_receive.h	(revision 397)
+++ trunk/lib/FlairIpc/src/unexported/shm_receive.h	(revision 397)
@@ -0,0 +1,212 @@
+/**
+ * \file ipc_receive.h
+ * \brief definition de classe
+ * \author {
+ * 			Sébastien Ambroziak
+ * 			Paul Sauvage
+ * 			}
+ * \version 0.1
+ * \date 5 novembre 2020
+ *
+ * Definitions de la classe IpcReceiver ainsi que ses méthodes.
+ * Cette classe permet de recevoir des structures ou des liste de structure par ipc
+ * 
+ * La classe IpcReceiver utilise une template à 2 paramètres, T et N
+ * 	le paramètre T correspond au type de donnée que le receiver doit recevoir
+ * 	le paramètre N correspond au nombre d'élément du tableau d'élément de type T à recevoir
+ * 		si N = 0 la fonction receive() retourne directement un objet de type T
+ * 		si N > 0 la fonction receive() retourne un pointeur de type T et donc un tableau d'élément T de N éléments
+ * 
+ * Le constructeur utilise 2 paramètres:
+ *  Une chaîne de caractère contenant le nom du fichier ipc vers lequel lire les données
+ *  Un entier correspond au numéro de canal Ipc
+ * 
+ */
+
+
+
+#ifndef SHM_RECEIVE
+#define SHM_RECEIVE
+
+#include "ipc_base.h"
+
+#include <functional>
+#include <memory>
+#include <iostream>
+#include <stdio.h>
+#include <type_traits>
+#include <cstring>
+
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#include <sys/shm.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/sem.h>
+#include <sys/time.h>
+#include <string>
+#include <errno.h>
+
+using namespace std;
+using namespace ipc::type;
+
+class ShmReceiverBase {
+	public:
+		ShmReceiverBase(size_t msg_size, const char* ipc_name, int proj_id=65){
+			cout << "Creating ShmReceiver" << endl;
+			system("mkdir -p /tmp/shmem");
+			system("chmod 777 /tmp/shmem");
+			string pathname = string("/tmp/shmem/") + string(ipc_name);
+			string command = string("> ") + pathname;
+			system(command.c_str());
+			command = string("chmod 666 ") + pathname;
+			system(command.c_str());
+
+			key_t ipc_key = ftok(pathname.c_str(), proj_id); //crete unique key
+			cout << "clé ipc" << ipc_key << endl;
+
+			_shmid = shmget(ipc_key, msg_size, 0666|IPC_CREAT); // shmget returns an identifier in shmid 
+			cout << "Shm Id : " << _shmid << endl;
+
+			_semid=semget(ipc_key,1,IPC_CREAT|0666);
+			cout << "Sem Id : " << _semid << endl;
+
+			/*struct shmid_ds buf;
+			shmctl(_shmid, IPC_STAT,&buf);
+			buf.shm_perm.mode = (S_IRWXU|S_IRWXG|S_IRWXO);
+			shmctl(_shmid, IPC_SET,&buf);*/
+		}
+
+		~ShmReceiverBase(){
+			shmctl(_shmid, IPC_RMID, NULL); // destroy the shared memory 
+			semctl(_semid, 0, IPC_RMID); // destroy semaphore
+		} 
+
+	protected:
+		int _shmid;
+		int _semid;
+		struct sembuf _semaphore; 
+};
+
+template <typename T>
+class ShmReceiver : ShmReceiverBase {
+	public:
+		ShmReceiver(const char* ipc_name, int proj_id=65, bool auto_refresh = false): ShmReceiverBase(sizeof(ipc_message<T>), ipc_name, proj_id), _auto_refresh(auto_refresh) {}
+		~ShmReceiver() = default;
+
+		int receive(){
+			int return_value = 0;
+			_semaphore.sem_num=0;
+			_semaphore.sem_op=-1; //getMutex
+			semop(_semid,&_semaphore,1);
+
+			if ((tmp.sec == _shm_ptr->data.stamp.sec) && (tmp.nanosec == _shm_ptr->data.stamp.nanosec)){
+				return_value = -1; //Donnée obsolète
+				
+				if(_auto_refresh == true){
+					refreshTime();
+				}
+			}
+			else{
+				tmp.sec = _shm_ptr->data.stamp.sec;
+				tmp.nanosec = _shm_ptr->data.stamp.nanosec;
+				memcpy(&_message, _shm_ptr, sizeof(ipc_message<T>)); //write message
+			}
+			
+			_semaphore.sem_num=0;
+			_semaphore.sem_op=1; //release mutex
+			semop(_semid,&_semaphore,1);
+
+			return return_value;
+		}
+
+		timestamp getTimestamp() const {
+			return _message.data.stamp;
+		}
+
+		T getValue() const {return _message.data.value;}
+
+		timestamp refreshTime(){
+			_message.time_now();
+			return _message.data.stamp;
+		}
+
+
+	protected:
+		timestamp tmp;
+		bool _auto_refresh;
+		ipc_message<T> *_shm_ptr = (ipc_message<T>*) shmat(_shmid,(void*)0, SHM_RDONLY); // shmat to attach to shared memory 
+		ipc_message<T> _message;
+		bool _blocking;
+};
+
+template <typename T>
+class ShmReceiverTab : ShmReceiverBase {
+	public:
+		ShmReceiverTab(size_t N, const char* ipc_name, int proj_id=65, bool auto_refresh = false): ShmReceiverBase(sizeof(ipc_tab<T>) + sizeof(T)*(N-1), ipc_name, proj_id), _N(N), _auto_refresh(auto_refresh) {
+			_message = (ipc_tab<T>*) malloc(sizeof(ipc_tab<T>) + sizeof(T)*N);
+		}
+
+		~ShmReceiverTab() = default;
+
+		int receive(){
+			
+			int return_value = 0;
+			_semaphore.sem_num=0;
+			_semaphore.sem_op=-1; //getMutex
+			semop(_semid,&_semaphore,1);
+
+			if ((tmp.sec == _shm_ptr->data.stamp.sec) && (tmp.nanosec == _shm_ptr->data.stamp.nanosec)){
+				return_value = -1; //Donnée obsolète
+				if(_auto_refresh == true)
+					refreshTime();
+			}
+			else{
+				tmp.sec = _shm_ptr->data.stamp.sec;
+				tmp.nanosec = _shm_ptr->data.stamp.nanosec;
+				memcpy(_message, _shm_ptr, sizeof(ipc_tab<T>) + sizeof(T)*_N); //write message
+			}
+			
+			_semaphore.sem_num=0;
+			_semaphore.sem_op=1; //release mutex
+			semop(_semid,&_semaphore,1);
+
+			return return_value;
+		}
+		
+		T getValue(size_t index) const {
+			return _message->data.values[index];
+		}
+
+		const T* getValues() const {
+			return _message->data.values;
+		}
+
+		timestamp getTimestamp() const {
+			return _message->data.stamp;
+		}
+
+		size_t getN() const {return _N;}
+
+		timestamp refreshTime(){
+			_message->time_now();
+			return _message->data.stamp;
+		}
+
+		void setAll(T value) {
+			for (size_t i = 0; i < _N; i++)
+			{
+				_message->data.values[i] = value;
+			}
+		}
+
+	protected:
+		timestamp tmp;
+		size_t _N;
+		bool _auto_refresh;
+		ipc_tab<T> *_message;
+		ipc_tab<T> *_shm_ptr = (ipc_tab<T>*) shmat(_shmid,(void*)0,SHM_RDONLY); // shmat to attach to shared memory 
+		
+};
+
+#endif
Index: trunk/lib/FlairIpc/src/unexported/shm_send.h
===================================================================
--- trunk/lib/FlairIpc/src/unexported/shm_send.h	(revision 397)
+++ trunk/lib/FlairIpc/src/unexported/shm_send.h	(revision 397)
@@ -0,0 +1,214 @@
+/**
+ * \file ipc_send.h
+ * \brief definition de classe
+ * \author {
+ * 			Sébastien Ambroziak
+ * 			Paul Sauvage
+ * 			}
+ * \version 0.1
+ * \date 5 novembre 2020
+ *
+ * Definitions de la classe IpcSender ainsi que ses méthodes.
+ * Cette classe permet d'envoyer des structures ou des liste de structure par ipc
+ * 
+ * La classe IpcSender utilise une template à 2 paramètres, T et N
+ * 	le paramètre T correspond au type de donnée que le sender doit pouvoir envoyer
+ * 	le paramètre N correspond au nombre d'élément du tableau d'élément de type T à envoyer
+ * 		si N = 0 la fonction send() prend en paramètre et envoi une structure de type T
+ * 		si N > 0 la fonction send() prend en paramètre et envoi un tableau de N éléments de type T
+ *
+* Le constructeur utilise 2 paramètres:
+ *  Une chaîne de caractère contenant le nom du fichier ipc vers lequel écrire les données
+ *  Un entier correspond au numéro de canal Ipc
+ * 
+ */
+
+#ifndef SHM_SEND
+#define SHM_SEND
+
+#include "ipc_base.h"
+
+#include <functional>
+#include <memory>
+#include <stdio.h>
+
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/sem.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/msg.h>
+#include <sys/time.h>
+
+#include <string>
+#include <cstring>
+#include <errno.h>
+
+using namespace std;
+using namespace ipc::type;
+
+class ShmSenderBase {
+	public:
+		ShmSenderBase(size_t msg_size, const char* ipc_name, int proj_id=65) {
+			cout << "Creating ShmSender" << endl;
+			system("mkdir -p /tmp/shmem");
+			system("chmod 777 /tmp/shmem");
+			string pathname = string("/tmp/shmem/") + string(ipc_name);
+			string command = string("> ") + pathname;
+			system(command.c_str());
+			command = string("chmod 666 ") + pathname;
+			system(command.c_str());
+
+			key_t ipc_key = ftok(pathname.c_str(), proj_id); //create unique key
+			cout << "clé ipc " << ipc_key << endl;
+
+    		_shmid = shmget(ipc_key, msg_size, 0666|IPC_CREAT); // shmget returns an identifier in shmid 
+			cout << "Shm Id : " << _shmid << endl;
+
+			_semid = semget(ipc_key,1,IPC_CREAT|0666);
+			cout << "Sem Id : " << _semid << endl;
+			
+			_semaphore.sem_num=0; //init semaphore
+			_semaphore.sem_op=1;
+			semop(_semid,&_semaphore,1);
+
+			/*struct shmid_ds buf;
+			shmctl(_shmid, IPC_STAT,&buf);
+			buf.shm_perm.mode = (S_IRWXU|S_IRWXG|S_IRWXO);
+			shmctl(_shmid, IPC_SET,&buf);*/
+		}
+		~ShmSenderBase() {
+    		shmctl(_shmid, IPC_RMID, NULL); // destroy the shared memory 
+			semctl(_semid, 0, IPC_RMID); // destroy semaphore
+		}
+	
+	protected:
+		int _shmid;
+		int _semid;
+		struct sembuf _semaphore; 
+};
+
+template <typename T>
+class ShmSender : ShmSenderBase {
+	public:
+		ShmSender(const char* ipc_name, int proj_id=65, bool auto_refresh = true): ShmSenderBase(sizeof(ipc_message<T>), ipc_name, proj_id), _auto_refresh(auto_refresh) {}
+		~ShmSender() = default;
+
+		void send(){
+			if(_auto_refresh) refreshTime();
+
+			_semaphore.sem_num=0;
+			_semaphore.sem_op=-1; //getMutex
+			semop(_semid,&_semaphore,1); 
+
+			memcpy(_shm_ptr, &_message, sizeof(ipc_message<T>)); //write message
+
+			_semaphore.sem_num=0;
+			_semaphore.sem_op=1; //release mutex
+			semop(_semid,&_semaphore,1);
+		}
+
+		void send(T value)
+		{
+			_message.data.value = value;
+			send();
+		}
+
+		timestamp getTimestamp(){
+			return _message.data.stamp;
+		}
+
+		timestamp refreshTime(){
+			_message.time_now();
+			return _message.data.stamp;
+		}
+
+		T getValue(){return _message.data.value;}
+
+		void setValue(T value){_message.data.value = value;}
+
+		void setTimestamp(timestamp stamp){_message.data.stamp = stamp;}
+		void setTimestamp(int32_t sec, uint32_t nanosec){
+			_message.data.stamp.sec = sec;
+			_message.data.stamp.nanosec = nanosec;
+		}
+
+	protected:
+		bool _auto_refresh;
+		ipc_message<T> _message;
+    	ipc_message<T> *_shm_ptr = (ipc_message<T>*) shmat(_shmid,(void*)0,0); // shmat to attach to shared memory 
+};
+
+
+template <typename T>
+class ShmSenderTab : ShmSenderBase {
+	public:
+		ShmSenderTab(size_t N, const char* ipc_name, int proj_id=65, bool auto_refresh = true): ShmSenderBase(sizeof(ipc_tab<T>) + sizeof(T)*(N-1), ipc_name, proj_id), _N(N), _auto_refresh(auto_refresh){
+			_message = (ipc_tab<T>*) malloc(sizeof(ipc_tab<T>) + sizeof(T)*(N-1));
+			_message->msg_type = 1;
+		}
+		~ShmSenderTab() = default;
+
+		void send(T* values){
+			memcpy(_message->data.values, values, sizeof(T)*_N);
+			send();
+		}
+
+		void send(){
+			if(_auto_refresh) refreshTime();
+
+			_semaphore.sem_num=0;
+			_semaphore.sem_op=-1; //getMutex
+			semop(_semid,&_semaphore,1); 
+
+			memcpy(_shm_ptr, _message, sizeof(ipc_tab<T>) + sizeof(T)*_N); //write message
+
+			_semaphore.sem_num=0;
+			_semaphore.sem_op=1; //release mutex
+			semop(_semid,&_semaphore,1);
+		}
+
+		void setTimestamp(timestamp stamp){_message->data.stamp = stamp;}
+		void setTimestamp(int32_t sec, uint32_t nanosec){
+			_message->data.stamp.sec = sec;
+			_message->data.stamp.nanosec = nanosec;
+		}
+
+		timestamp getTimestamp(){
+			return _message->data.stamp;
+		}
+
+		timestamp refreshTime(){
+			_message->time_now();
+			return _message->data.stamp;
+		}
+
+		void setValue(T value, size_t index){
+			if(index < _N){
+				_message->data.values[index] = value;
+			}
+		}
+
+		void setAll(T value) {
+			for (size_t i = 0; i < _N; i++)
+			{
+				_message->data.values[i] = value;
+			}
+		}
+
+		void setValues(T* values){
+			memcpy(_message->data.values, values, sizeof(T)*_N);
+		}
+
+		size_t getN() const {return _N;}
+
+	protected:
+		size_t _N;
+		bool _auto_refresh;
+		ipc_tab<T>* _message;
+		ipc_tab<T> *_shm_ptr = (ipc_tab<T>*) shmat(_shmid,(void*)0,0); // shmat to attach to shared memory 
+		
+};
+
+
+#endif
