diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 15f5b02b3f9a37f6fc2b1a4135b500d77ad7dae7..95f8ba91984e0b15d0aab74a43850b534d9bc116 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -10,10 +10,12 @@ INCLUDE_DIRECTORIES(.)
 # edit the following line to find the necessary packages
 FIND_PACKAGE(iriutils REQUIRED)
 FIND_PACKAGE(comm REQUIRED)
+find_package(Boost REQUIRED)
 
 # edit the following line to add the necessary include directories
 INCLUDE_DIRECTORIES(${iriutils_INCLUDE_DIR})
 INCLUDE_DIRECTORIES(${comm_INCLUDE_DIR})
+INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS})
 
 SET_SOURCE_FILES_PROPERTIES(${XSD_SOURCES} PROPERTIES GENERATED 1)
 
@@ -23,6 +25,7 @@ ADD_LIBRARY(dynamixel SHARED ${sources} ${XSD_SOURCES})
 TARGET_LINK_LIBRARIES(dynamixel ${iriutils_LIBRARY})
 TARGET_LINK_LIBRARIES(dynamixel ${comm_LIBRARY})
 TARGET_LINK_LIBRARIES(dynamixel ${XSD_LIBRARY})
+TARGET_LINK_LIBRARIES(dynamixel ${Boost_LIBRARIES})
 
 ADD_DEPENDENCIES(dynamixel xsd_files_gen)
 
diff --git a/src/dynamixel_common.h b/src/dynamixel_common.h
index a28da96a7228f0cdbd08e3b62bbb855143fca973..269105c7101294a99fe8b359046de062f7798e7f 100644
--- a/src/dynamixel_common.h
+++ b/src/dynamixel_common.h
@@ -9,21 +9,21 @@ typedef enum {dyn_ping=0x01,
               dyn_reg_write=0x04,
               dyn_action=0x05,
               dyn_factory_reset=0x06,
-              dyn_reboot=0x08,
+              dyn_reset=0x08,
               dyn_status=0x55,
               dyn_sync_read=0x82,
               dyn_sync_write=0x83,
               dyn_bulk_read=0x92,
               dyn_bulk_write=0x93} dyn_inst_t;
 
-typedef enum{DYN_NO_ERROR=0x00,
-             DYN_INST_ERROR=0x40,
-             DYN_OVERLOAD_ERROR=0x20,
-             DYN_CHECKSUM_ERROR=0x10,
-             DYN_RANGE_ERROR=0x08,
-             DYN_OVERTEMP_ERROR=0x04,
-             DYN_ANGLE_ERROR=0x02,
-             DYN_VOLTAGE_ERROR=0x01} TDynError;
+typedef enum{dyn_no_error=0x00,
+             dyn_inst_error=0x40,
+             dyn_overload_error=0x20,
+             dyn_checksum_error=0x10,
+             dyn_range_error=0x08,
+             dyn_overtemp_error=0x04,
+             dyn_angle_error=0x02,
+             dyn_voltage_error=0x01} dyn_error_t;
 
 typedef enum {dyn_reset_all=0xFF,dyn_reset_keep_id=0x01,dyn_reset_keep_id_baud=0x02} dyn_reset_mode_t;
 
diff --git a/src/dynamixel_slave.cpp b/src/dynamixel_slave.cpp
index d5b12075db9f3d034eb5f44ae9d02f60dab59707..518198e128fa4bdc62de533ab31394262fd01a42 100644
--- a/src/dynamixel_slave.cpp
+++ b/src/dynamixel_slave.cpp
@@ -1,4 +1,6 @@
 #include "dynamixel_slave.h"
+#include "dynamixelserver.h"
+#include "dynamixelexceptions.h"
 #include <iostream>
 
 CDynamixelSlave::CDynamixelSlave(const std::string& cont_id,dyn_version_t dyn_ver)
@@ -10,14 +12,17 @@ CDynamixelSlave::CDynamixelSlave(const std::string& cont_id,dyn_version_t dyn_ve
   this->event_server->create_event(this->finish_thread_event_id);
 
   this->thread_server=CThreadServer::instance();
-  this->process_packets_thread_id=cont_id + "_thread_id";
+  this->process_packets_thread_id=cont_id + "process_packets_thread_id";
   this->thread_server->create_thread(this->process_packets_thread_id);
   this->thread_server->attach_thread(this->process_packets_thread_id,this->process_packets_thread,this);
+  this->dynamixel_loop_thread_id=cont_id + "dynamixel_loop_thread_id";
+  this->thread_server->create_thread(this->dynamixel_loop_thread_id);
+  this->thread_server->attach_thread(this->dynamixel_loop_thread_id,this->dynamixel_loop_thread,this);
 
   this->return_delay=0;
   this->return_level=return_all;
   this->dyn_ver=dyn_ver;
-
+  
   this->comm_dev=NULL;
 }
 
@@ -26,13 +31,13 @@ void *CDynamixelSlave::process_packets_thread(void *params)
   CDynamixelSlave *slave=(CDynamixelSlave *)params;
   std::list<std::string> events;
   int event_index,num,i;
-  unsigned char *data;
+  unsigned char *data,*new_data;
   bool end=false;
 
   static bool data_phase=false;
   static unsigned char packet[256];
   static int num_bytes=0,length=0; 
- 
+
   // wait until the comm device becomes valid 
   while(!end)
   {
@@ -52,16 +57,19 @@ void *CDynamixelSlave::process_packets_thread(void *params)
     else
     {
       // process the incomming data
+      slave->comm_access.enter();
       num=slave->comm_dev->get_num_data();
-      std::cout << "num data: " << num << std::endl;
       data=new unsigned char[num];
       if(slave->comm_dev->read(data,num)!=num)
+      {
+        slave->comm_access.exit();
         std::cout << "Error while reading the communication device" << std::endl;
+      }
       else
       {
+        slave->comm_access.exit();
         for(i=0;i<num;i++)
 	{
-          std::cout << std::hex << (int)data[i] << std::endl;
           if(!data_phase)
           {
             switch(num_bytes)
@@ -117,7 +125,6 @@ void *CDynamixelSlave::process_packets_thread(void *params)
 	      case 6: packet[num_bytes]=data[i];
 		      num_bytes++;
 		      length+=(data[i]<<8);
-		      num_bytes++;
                       /* read packet_data */
                       data_phase=true;
 		      break;
@@ -131,15 +138,46 @@ void *CDynamixelSlave::process_packets_thread(void *params)
             length--;
             if(length==0)
             {
-              num_bytes=0;
               data_phase=false;
-              std::cout << "new packet" << std::endl;
+              new_data=new unsigned char[num_bytes];
+              memcpy(new_data,packet,num_bytes);
+              slave->packets.push_back(new_data);
+              slave->event_server->set_event(slave->new_packet_available_event_id);
+              num_bytes=0;
             }
           }
 	}
       }
     }
     delete[] data;
+    data=NULL;
+  }
+
+  pthread_exit(NULL);
+}
+
+void *CDynamixelSlave::dynamixel_loop_thread(void *params)
+{
+  CDynamixelSlave *slave=(CDynamixelSlave *)params;
+  std::list<std::string> events;
+  int event_index;
+  bool end=false;
+  
+  events.push_back(slave->finish_thread_event_id);
+  events.push_back(slave->new_packet_available_event_id);
+  while(!end)
+  {
+    event_index=slave->event_server->wait_first(events);
+    if(event_index==0)
+      end=true;
+    else
+    {
+      // process the packets
+      if(slave->dyn_ver==dyn_version1)
+        slave->dynamixel_loop_v1();
+      else
+        slave->dynamixel_loop_v2();
+    }
   }
 
   pthread_exit(NULL);
@@ -154,149 +192,682 @@ void CDynamixelSlave::start(void)
 {
   if(this->thread_server->get_thread_state(this->process_packets_thread_id)==attached)
     this->thread_server->start_thread(this->process_packets_thread_id);
+  if(this->thread_server->get_thread_state(this->dynamixel_loop_thread_id)==attached)
+    this->thread_server->start_thread(this->dynamixel_loop_thread_id);
 }
 
 void CDynamixelSlave::stop(void)
 {
+  this->event_server->set_event(this->finish_thread_event_id);
+  this->event_server->set_event(this->finish_thread_event_id);
+  if(this->thread_server->get_thread_state(this->dynamixel_loop_thread_id)==active || this->thread_server->get_thread_state(this->dynamixel_loop_thread_id)==starting)
+    this->thread_server->end_thread(this->dynamixel_loop_thread_id);
   if(this->thread_server->get_thread_state(this->process_packets_thread_id)==active || this->thread_server->get_thread_state(this->process_packets_thread_id)==starting)
-  {
-    this->event_server->set_event(this->finish_thread_event_id);
     this->thread_server->end_thread(this->process_packets_thread_id);
-  }
 }
 
-std::string CDynamixelSlave::get_new_packet_available_event_id(void)
+void CDynamixelSlave::dynamixel_loop_v1(void)
 {
-  return this->new_packet_available_event_id;
+  unsigned short int length,address;
+  unsigned char error,id,prev_id;;
+  unsigned char *data,*write_data,*read_data;
+  unsigned int i=0;
+
+  data=this->packets[0];
+  id=this->get_target_id(data);
+  for(i=0;i<this->slaves.size();i++)
+  {
+    if(id==this->slaves[i].id || id==0xFE)// the packet is addressed to this device or it is a broadcast
+    {  
+      // check the packet checksum
+      if(CDynamixelServer::compute_checksum_v1(data,this->get_packet_length(data))==0x00)// the incomming packet is okay
+      {
+        // process the packet
+        switch(this->get_instruction_type(data))
+        {
+          case dyn_ping: this->slaves[i].on_ping();
+                         if(id!=0xFE)
+                           this->send_status_packet(this->slaves[i].id,dyn_no_error,0,NULL);
+                         break;
+          case dyn_read: read_data=new unsigned char[this->get_read_length(data)];
+                         error=this->slaves[i].on_read(this->get_read_address(data),this->get_read_length(data),read_data);
+                         if(this->return_level!=no_return && id!=0xFE)
+                         {
+                           if(error==dyn_no_error)
+                             this->send_status_packet(this->slaves[i].id,dyn_no_error,this->get_read_length(data),read_data);
+                           else
+                             this->send_status_packet(this->slaves[i].id,dyn_inst_error,0,NULL);
+                         }
+                         delete[] read_data;
+                         break;
+          case dyn_write: length=this->get_write_data(data,&write_data);
+                          error=this->slaves[i].on_write(this->get_write_address(data),length,write_data);
+                          if(this->return_level==return_all && id!=0xFE)
+                          {
+                            if(error==dyn_no_error)
+                              this->send_status_packet(this->slaves[i].id,dyn_no_error,0,NULL);
+                            else
+                              this->send_status_packet(this->slaves[i].id,dyn_inst_error,0,NULL);
+                          }
+                          break;
+          case dyn_reg_write: this->slaves[i].reg_length=this->get_reg_write_data(data,&this->slaves[i].reg_data);
+                              this->slaves[i].reg_address=this->get_reg_write_address(data);
+                              if(this->return_level==return_all && id!=0xFE)
+                                this->send_status_packet(this->slaves[i].id,dyn_no_error,0,NULL);
+                              break;
+          case dyn_action: if(this->slaves[i].reg_address!=-1)
+                           {
+                             error=this->slaves[i].on_write(this->slaves[i].reg_address,this->slaves[i].reg_length,this->slaves[i].reg_data);
+                             this->slaves[i].reg_address=-1;
+                           }
+                           else
+                             if(this->return_level==return_all && id!=0xFE)
+                               this->send_status_packet(this->slaves[i].id,dyn_inst_error,0,NULL);
+                           break;
+          case dyn_reset:
+                          break;
+          case dyn_sync_read: this->send_status_packet(this->slaves[i].id,dyn_inst_error,0,NULL);
+                              break;
+          case dyn_sync_write: if(this->sync_write_id_present(data,this->slaves[i].id,&address,&length,&write_data))// the device is addressed
+                                 error=this->slaves[i].on_write(address,length,write_data);
+                               break;
+          case dyn_bulk_read: prev_id=this->bulk_read_id_present(data,this->slaves[i].id,&address,&length);
+                              if(prev_id!=0xFF)
+                              {
+                                if(prev_id==0x00)// first device to answer
+                                {
+                                  read_data=new unsigned char[length];
+                                  error=this->slaves[i].on_read(address,length,read_data);
+                                  if(error==dyn_no_error)
+                                    this->send_status_packet(this->slaves[i].id,dyn_no_error,length,read_data);
+                                  else
+                                    this->send_status_packet(this->slaves[i].id,dyn_inst_error,0,NULL);
+                                  delete[] read_data;
+                                }
+                                else// wait for the previous device in the sequence to send its data
+                                {
+                                  this->slaves[i].bulk_address=address;
+                                  this->slaves[i].bulk_length=length;
+                                  this->slaves[i].bulk_prev_id=prev_id;
+                                  this->slaves[i].bulk_read_pending=true;
+                                }
+                              }
+                              break;
+          case dyn_bulk_write: this->send_status_packet(this->slaves[i].id,dyn_inst_error,0,NULL);
+                               break;
+          default:
+                   break;
+        }
+      }
+      else
+      {
+        // send a checksum error answer
+        if(this->get_target_id(data)!=0xFE)
+          this->send_status_packet(this->slaves[i].id,dyn_checksum_error,0,NULL);
+      }
+    }
+    else
+    {
+      if(this->slaves[i].bulk_read_pending)
+      {
+        if(id==this->slaves[i].bulk_prev_id)
+        {
+          this->slaves[i].bulk_read_pending=false;
+          read_data=new unsigned char[this->slaves[i].bulk_length];
+          error=this->slaves[i].on_read(this->slaves[i].bulk_address,this->slaves[i].bulk_length,read_data);
+          if(error==dyn_no_error)
+            this->send_status_packet(this->slaves[i].id,dyn_no_error,this->slaves[i].bulk_length,read_data);
+          else
+            this->send_status_packet(this->slaves[i].id,dyn_inst_error,0,NULL);
+          delete[] read_data;
+        }
+      }
+    }
+  }
+  this->packets.erase(this->packets.begin());
 }
 
-void CDynamixelSlave::set_return_delay(unsigned int time_us)
+void CDynamixelSlave::dynamixel_loop_v2(void)
 {
-  if(time_us<1000)
-    this->return_delay=time_us;
-  else
+  unsigned char error,prev_id,id;
+  unsigned short int length,address,checksum,checksum_pkt;
+  unsigned char *data,*write_data,*read_data;
+  unsigned int i=0;
+
+  data=this->packets[0];
+  id=this->get_target_id(data);
+  for(i=0;i<this->slaves.size();i++)
   {
-    /* handle exceptions */
+    if(id==this->slaves[i].id || id==0xFE)// the packet is addressed to this device or it is a broadcast
+    {
+      // check the packet checksum
+      checksum=CDynamixelServer::compute_checksum_v2(data,this->get_packet_length(data)-2);
+      checksum_pkt=this->get_checksum(data);
+      if(checksum==checksum_pkt)
+      {
+        // process the packet
+        switch(this->get_instruction_type(data))
+        {
+          case dyn_ping: this->slaves[i].on_ping();
+                         if(id!=0xFE)
+                           this->send_status_packet(this->slaves[i].id,dyn_no_error,0,NULL);
+                         break;
+          case dyn_read: read_data=new unsigned char[this->get_read_length(data)];
+                         error=this->slaves[i].on_read(this->get_read_address(data),this->get_read_length(data),read_data);
+                         if(this->return_level!=no_return && id!=0xFE)
+                         {
+                           if(error==dyn_no_error)
+                             this->send_status_packet(this->slaves[i].id,dyn_no_error,this->get_read_length(data),read_data);
+                           else
+                             this->send_status_packet(this->slaves[i].id,dyn_inst_error,0,NULL);
+                         }
+                         delete[] read_data;
+                         break;
+          case dyn_write: length=this->get_write_data(data,&write_data);
+                          error=this->slaves[i].on_write(this->get_write_address(data),length,write_data);
+                          if(this->return_level==return_all && id!=0xFE)
+                          {
+                            if(error==dyn_no_error)
+                              this->send_status_packet(this->slaves[i].id,dyn_no_error,0,write_data);
+                            else
+                              this->send_status_packet(this->slaves[i].id,dyn_inst_error,0,NULL);
+                          }
+                          break;
+          case dyn_reg_write: this->slaves[i].reg_length=this->get_reg_write_data(data,&this->slaves[i].reg_data);
+                              this->slaves[i].reg_address=this->get_reg_write_address(data);
+                              if(this->return_level==return_all && id!=0xFE)
+                                this->send_status_packet(this->slaves[i].id,dyn_no_error,0,NULL);
+                              break;
+          case dyn_action: if(this->slaves[i].reg_address!=-1)
+                           {
+                             error=this->slaves[i].on_write(this->slaves[i].reg_address,this->slaves[i].reg_length,this->slaves[i].reg_data);
+                             this->slaves[i].reg_address=-1;
+                           }
+                           else
+                             if(this->return_level==return_all && id!=0xFE)
+                               this->send_status_packet(this->slaves[i].id,dyn_inst_error,0,NULL);
+                           break;
+          case dyn_reset:
+                          break;
+          case dyn_sync_read: prev_id=this->sync_read_id_present(data,this->slaves[i].id,&address,&length);
+                              if(prev_id!=0xFF)
+                              {
+                                if(prev_id==0x00)// first device to answer
+                                {
+                                  read_data=new unsigned char[length];
+                                  error=this->slaves[i].on_read(address,length,read_data);
+                                  if(error==dyn_no_error)
+                                    this->send_status_packet(this->slaves[i].id,dyn_no_error,length,read_data);
+                                  else
+                                    this->send_status_packet(this->slaves[i].id,dyn_inst_error,0,NULL);
+                                  delete[] read_data;
+                                }
+                                else// wait for the previous device in the sequence to send its data
+                                {
+                                  this->slaves[i].sync_address=address;
+                                  this->slaves[i].sync_length=length;
+                                  this->slaves[i].sync_prev_id=prev_id;
+                                  this->slaves[i].sync_read_pending=true;
+                                }
+                              }
+                              break;
+          case dyn_sync_write: if(this->sync_write_id_present(data,this->slaves[i].id,&address,&length,&write_data))// the device is addressed
+                                 error=this->slaves[i].on_write(address,length,write_data);
+                               break;
+          case dyn_bulk_read: prev_id=this->bulk_read_id_present(data,this->slaves[i].id,&address,&length);
+                              if(prev_id!=0xFF)
+                              {
+                                if(prev_id==0x00)// first device to answer
+                                {
+                                  read_data=new unsigned char[length];
+                                  error=this->slaves[i].on_read(address,length,read_data);
+                                  if(error==dyn_no_error)
+                                    this->send_status_packet(this->slaves[i].id,dyn_no_error,length,read_data);
+                                  else
+                                    this->send_status_packet(this->slaves[i].id,dyn_inst_error,0,NULL);
+                                  delete read_data;
+                                }
+                                else// wait for the previous device in the sequence to send its data
+                                {
+                                  this->slaves[i].bulk_address=address;
+                                  this->slaves[i].bulk_length=length;
+                                  this->slaves[i].bulk_prev_id=prev_id;
+                                  this->slaves[i].bulk_read_pending=true;
+                                }
+                              }
+                              break;
+          case dyn_bulk_write: if(this->bulk_write_id_present(data,this->slaves[i].id,&address,&length,&write_data))
+                                 error=this->slaves[i].on_write(address,length,write_data);
+                               break;
+  
+          default:
+                   break;
+        }
+      }
+      else
+      {
+        // send a checksum error answer
+        if(this->get_target_id(data)!=0xFE)
+          this->send_status_packet(this->slaves[i].id,dyn_checksum_error,0,NULL);
+      }
+    }
+    else
+    {
+      if(this->slaves[i].bulk_read_pending)
+      {
+        if(id==this->slaves[i].bulk_prev_id)
+        {
+          this->slaves[i].bulk_read_pending=false;
+          read_data=new unsigned char[this->slaves[i].bulk_length];
+          error=this->slaves[i].on_read(this->slaves[i].bulk_address,this->slaves[i].bulk_length,read_data);
+          if(error==dyn_no_error)
+            this->send_status_packet(this->slaves[i].id,dyn_no_error,this->slaves[i].bulk_length,read_data);
+          else
+            this->send_status_packet(this->slaves[i].id,dyn_inst_error,0,NULL);
+          delete read_data;
+        }
+      }
+      else if(this->slaves[i].sync_read_pending)
+      {
+        if(id==this->slaves[i].sync_prev_id)
+        {
+          this->slaves[i].sync_read_pending=false;
+          read_data=new unsigned char[this->slaves[i].sync_length];
+          error=this->slaves[i].on_read(this->slaves[i].sync_address,this->slaves[i].sync_length,read_data);
+          if(error==dyn_no_error)
+            this->send_status_packet(this->slaves[i].id,dyn_no_error,this->slaves[i].sync_length,read_data);
+          else
+            this->send_status_packet(this->slaves[i].id,dyn_inst_error,0,NULL);
+          delete[] read_data;
+        }
+      }
+    } 
   }
+  this->packets.erase(this->packets.begin());
 }
 
-unsigned int CDynamixelSlave::get_return_delay(void)
+unsigned char CDynamixelSlave::get_target_id(unsigned char *data)
 {
-  return this->return_delay;
+  if(this->dyn_ver==dyn_version1)
+    return data[2];
+  else
+    return data[4];
 }
 
-void CDynamixelSlave::set_return_level(return_level_t level)
+dyn_inst_t CDynamixelSlave::get_instruction_type(unsigned char *data)
 {
-  this->return_level=level;
+  if(this->dyn_ver==dyn_version1)
+    return (dyn_inst_t)data[4];
+  else
+    return (dyn_inst_t)data[7];
 }
 
-return_level_t CDynamixelSlave::get_return_level(void)
+unsigned short int CDynamixelSlave::get_packet_length(unsigned char *data)
 {
-  return this->return_level;
+  if(this->dyn_ver==dyn_version1)
+    return data[3]+4;
+  else
+    return data[5]+data[6]*256+7;
 }
 
-bool CDynamixelSlave::new_packet_available(void)
+unsigned short int CDynamixelSlave::get_checksum(unsigned char *data)
 {
-  if(this->event_server->event_is_set(this->new_packet_available_event_id))
-    return true;
+  unsigned short int length;
+
+  length=this->get_packet_length(data);
+  if(this->dyn_ver==dyn_version1)
+    return data[length-1];
   else
-    return false;
+    return data[length-2]+data[length-1]*256;
 }
 
-unsigned char CDynamixelSlave::get_target_id(void)
+/* read instruction */
+unsigned short int CDynamixelSlave::get_read_length(unsigned char *data)
 {
-
+  if(this->dyn_ver==dyn_version1)
+    return data[6];
+  else
+    return data[10]+data[11]*256;
 }
 
-dyn_inst_t CDynamixelSlave::get_instruction_type(void)
+unsigned short int CDynamixelSlave::get_read_address(unsigned char *data)
 {
-
+  if(this->dyn_ver==dyn_version1)
+    return data[5];
+  else
+    return data[8]+data[9]*256;
 }
 
-// instruction specific functions
-/* read instruction */
-unsigned short int CDynamixelSlave::get_read_length(void)
+/* write instruction */
+unsigned short int CDynamixelSlave::get_write_address(unsigned char *data)
 {
-
+  if(this->dyn_ver==dyn_version1)
+    return data[5];
+  else
+    return data[8]+data[9]*256;
 }
 
-unsigned short int CDynamixelSlave::get_read_address(void)
+unsigned short int CDynamixelSlave::get_write_length(unsigned char *data)
 {
+  if(this->dyn_ver==dyn_version1)
+    return data[3]-3;
+  else
+    return data[5]+data[6]*256-5;
+}
 
+unsigned short int CDynamixelSlave::get_write_data(unsigned char *data, unsigned char **write_data)
+{
+  if(this->dyn_ver==dyn_version1)
+  {
+    (*write_data)=&data[6];
+    return data[3]-3;
+  }
+  else
+  {
+    (*write_data)=&data[10];
+    return data[5]+data[6]*256-5;
+  }
 }
 
-/* write instruction */
-unsigned short int CDynamixelSlave::get_write_address(void)
+/* registered write instruction */
+unsigned short int CDynamixelSlave::get_reg_write_address(unsigned char *data)
 {
+  if(this->dyn_ver==dyn_version1)
+    return data[5];
+  else
+    return data[8]+data[9]*256;
+}
 
+unsigned short int CDynamixelSlave::get_reg_write_length(unsigned char *data)
+{
+  if(this->dyn_ver==dyn_version1)
+    return data[3]-3;
+  else
+    return data[5]+data[6]*256-5;
 }
 
-unsigned short int CDynamixelSlave::get_write_length(void)
+unsigned short int CDynamixelSlave::get_reg_write_data(unsigned char *data,unsigned char **write_data)
 {
+  if(*write_data!=NULL)
+    delete[] *write_data;
 
+  if(this->dyn_ver==dyn_version1)
+  {
+    *write_data=new unsigned char[data[3]-3];
+    memcpy(*write_data,&data[6],data[3]-3);
+    return data[3]-3;
+  }
+  else
+  {
+    *write_data=new unsigned char[data[5]+data[6]*256-5];
+    memcpy(*write_data,&data[10],data[5]+data[6]*256-5);
+    return data[5]+data[6]*256-5;
+  }
 }
 
-void CDynamixelSlave::get_write_data(std::vector<unsigned char> &data)
+/* sync write instruction */
+bool CDynamixelSlave::sync_write_id_present(unsigned char *data,unsigned char id,unsigned short int *address,unsigned short int *length,unsigned char **write_data)
 {
+  unsigned int num_servos=0,i,len;
 
+  if(this->dyn_ver==dyn_version1)
+  {
+    num_servos=(data[3]-4)/(data[6]+1);
+    for(i=0;i<num_servos;i++)
+    {
+      if(data[7+(data[6]+1)*i]==id)
+      {
+        *address=data[5];
+        *length=data[6];
+        (*write_data)=&data[7+(data[6]+1)*i+1];
+        return true;
+      }
+    }
+    return false;
+  }
+  else
+  {
+    len=data[10]+data[11]*256;
+    num_servos=((data[5]+data[6]*256)-7)/(len+1);
+    for(i=0;i<num_servos;i++)
+    {
+      if(data[12+(len+1)*i]==id)
+      {
+        (*address)=data[8]+data[9]*256;
+        (*length)=data[10]+data[11]*256;
+        (*write_data)=&data[12+(len+1)*i+1];
+        return true;
+      }
+    }
+    return false;
+  }
 }
 
-/* registered write instruction */
-unsigned short int CDynamixelSlave::get_reg_write_address(void)
+/* sync read instruction */
+unsigned char CDynamixelSlave::sync_read_id_present(unsigned char *data,unsigned char id,unsigned short int *address,unsigned short int *length)
 {
+  unsigned char num_servos,i;
 
+  if(this->dyn_ver==dyn_version2)
+  {
+    num_servos=(data[5]+data[6]*256)-7;
+    for(i=0;i<num_servos;i++)
+      if(data[12+i]==id)
+      {
+        (*address)=data[8]+data[9]*256;
+        (*length)=data[10]+data[11]*256;
+        if(i==0)
+          return 0x00;
+        else
+          return data[12+i];
+      }
+    return 0xFF;
+  }
+  else
+    return 0xFF;
 }
 
-unsigned short int CDynamixelSlave::get_reg_write_length(void)
+/* bulk read instruction */
+unsigned char CDynamixelSlave::bulk_read_id_present(unsigned char *data,unsigned char id,unsigned short int *address,unsigned short int *length)
 {
+  int num_servos,i;
+  unsigned char prev_id=0xFF;
 
+  if(this->dyn_ver==dyn_version1)
+  {
+    num_servos=(data[3]-3)/3; 
+    for(i=0;i<num_servos;i++)
+    {
+      if(data[6+i*3+1]==id)
+      {
+        (*address)=data[6+i*3+2];
+        (*address)=data[6+i*3+3];
+        if(i==0)
+          return 0x00;
+        else
+          return prev_id;
+      }
+      else
+        prev_id=data[6+i*3+1];
+    }
+    return 0xFF;
+  }
+  else
+  {
+    num_servos=((data[5]+data[6]*256)-3)/5;
+    for(i=0;i<num_servos;i++)
+    {
+      if(data[8+i*5]==id)
+      {
+        (*address)=data[8+i*5+1]+data[9+i*5+1]*256;
+        (*length)=data[10+i*8+1]+data[11+i*5+1]*256;
+        if(i==0)
+          return 0x00;
+        else
+          return prev_id;
+      }
+      else
+        prev_id=data[8+i*5];
+    }
+    return 0xFF;
+  }
 }
 
-void CDynamixelSlave::get_reg_write_data(std::vector<unsigned char> &data)
+/* bulk write instruction */
+bool CDynamixelSlave::bulk_write_id_present(unsigned char *data,unsigned char id,unsigned short int *address,unsigned short int *length,unsigned char **write_data)
 {
+  unsigned short int len,offset=0;
 
+  len=data[5]+data[6]*256-3;
+  while(offset<len)
+  {
+    if(data[8+offset]==id)
+    {
+      (*address)=data[8+offset+1]+data[8+offset+2]*256;
+      (*length)=data[8+offset+3]+data[8+offset+4]*256;
+      (*write_data)=&data[8+offset+5];
+      return true;
+    }
+    else
+      offset+=data[8+offset+3]+data[8+offset+4]*256+5;
+  }
+
+  return false;
 }
 
-/* sync write instruction */
-bool CDynamixelSlave::sync_write_id_present(unsigned char id,unsigned short int *address,unsigned short int *length,std::vector<unsigned char> &data)
+// status return
+void CDynamixelSlave::send_status_packet(unsigned char id,dyn_error_t error,unsigned short int length,unsigned char *data)
 {
+  unsigned char *status_data;
+  unsigned short int checksum;
+
+  if(this->return_delay>0)
+    usleep(this->return_delay*2);
 
+  if(this->dyn_ver==dyn_version1)
+  {
+    this->comm_access.enter();
+    status_data=new unsigned char[6+length];
+    status_data[0]=0xFF;
+    status_data[1]=0xFF;
+    status_data[2]=id;
+    status_data[3]=length+2;
+    status_data[4]=error;
+    memcpy(&status_data[5],data,length);
+    status_data[5+length]=0x00;
+    status_data[5+length]=CDynamixelServer::compute_checksum_v1(status_data,this->get_packet_length(status_data));
+    if(this->comm_dev->write(status_data,this->get_packet_length(status_data))!=this->get_packet_length(status_data))
+      std::cout << "Error while reading the communication device" << std::endl;
+    this->comm_access.exit();
+  }
+  else
+  {
+    this->comm_access.enter();
+    status_data=new unsigned char[11+length];
+    status_data[0]=0xFF;
+    status_data[1]=0xFF;
+    status_data[2]=0xFD;
+    status_data[3]=0x00;
+    status_data[4]=id;
+    status_data[5]=(4+length)%256;
+    status_data[6]=(4+length)/256;
+    status_data[7]=0x55;
+    status_data[8]=error;
+    memcpy(&status_data[9],data,length);
+    status_data[9+length]=0x00;
+    status_data[10+length]=0x00;
+    checksum=CDynamixelServer::compute_checksum_v2(status_data,this->get_packet_length(status_data)-2);
+    status_data[9+length]=checksum%256;
+    status_data[10+length]=checksum/256;
+    if(this->comm_dev->write(status_data,this->get_packet_length(status_data))!=this->get_packet_length(status_data))
+      std::cout << "Error while reading the communication device" << std::endl;
+    this->comm_access.exit();
+  }
 }
 
-/* sync read instruction */
-bool CDynamixelSlave::sync_read_id_present(unsigned char id,unsigned short int *address,unsigned short int *length)
+void CDynamixelSlave::add_slave(unsigned char id, on_ping_fnct on_ping, on_rw_fnct on_read, on_rw_fnct on_write)
 {
+  unsigned int i=0;
+  TSlave new_slave;
 
+  for(i=0;i<this->slaves.size();i++)
+  {
+    if(id==this->slaves[i].id)
+      throw CDynamixelSlaveException(_HERE_,"The desired slave device is already present");
+  }
+  new_slave.id=id;
+  new_slave.on_ping=on_ping;
+  new_slave.on_read=on_read;
+  new_slave.on_write=on_write;
+  new_slave.reg_address=-1;
+  new_slave.reg_length=-1;
+  new_slave.reg_data=NULL;
+  new_slave.bulk_prev_id=-1;
+  new_slave.bulk_address=-1;
+  new_slave.bulk_length=-1;
+  new_slave.bulk_read_pending=-1;
+  new_slave.sync_prev_id=-1;
+  new_slave.sync_address=-1;
+  new_slave.sync_length=-1;
+  new_slave.sync_read_pending=-1;
+  this->slaves.push_back(new_slave);
 }
 
-/* bulk read instruction */
-bool CDynamixelSlave::bulk_read_id_present(unsigned char id,std::vector<unsigned short int> &address,std::vector<unsigned short int> &length)
+void CDynamixelSlave::delete_slave(unsigned char id)
 {
+  unsigned int i=0;
 
+  for(i=0;i<this->slaves.size();i++)
+  {
+    if(id==this->slaves[i].id)
+    {
+      if(this->slaves[i].reg_data!=NULL)
+      {
+        delete[] this->slaves[i].reg_data; 
+        this->slaves[i].reg_data=NULL;
+      }
+      this->slaves.erase(this->slaves.begin()+i);
+      return;
+    }
+  }
+  throw CDynamixelSlaveException(_HERE_,"The desired device is not present to be removed");
 }
 
-/* bulk write instruction */
-bool CDynamixelSlave::bulk_write_id_present(unsigned char id,std::vector<unsigned short int> &address,std::vector<unsigned short int> &length,std::vector<unsigned char> &data)
+unsigned int CDynamixelSlave::get_num_slaves(void)
 {
-
+  return this->slaves.size();
 }
 
-// status return
-void CDynamixelSlave::send_status_packet(unsigned char id,TDynError error,unsigned short int length,std::vector<unsigned char> &data)
+unsigned int CDynamixelSlave::get_return_delay(void)
 {
+  return this->return_delay;
+}
 
+void CDynamixelSlave::set_return_delay(unsigned int delay_us)
+{
+  this->return_delay=delay_us;
 }
 
-void CDynamixelSlave::next_packet(void)
+return_level_t CDynamixelSlave::get_return_level(void)
 {
+  return this->return_level;
+}
 
+void CDynamixelSlave::get_return_level(return_level_t level)
+{
+  this->return_level=level;
 }
+
 CDynamixelSlave::~CDynamixelSlave()
 {
   this->thread_server->detach_thread(this->process_packets_thread_id);
   this->thread_server->delete_thread(this->process_packets_thread_id);
   this->process_packets_thread_id="";
 
+  this->thread_server->detach_thread(this->dynamixel_loop_thread_id);
+  this->thread_server->delete_thread(this->dynamixel_loop_thread_id);
+  this->dynamixel_loop_thread_id="";
+
   this->event_server->delete_event(this->finish_thread_event_id);
   this->finish_thread_event_id="";
   this->event_server->delete_event(this->new_packet_available_event_id);
diff --git a/src/dynamixel_slave.h b/src/dynamixel_slave.h
index 042a28c97b915c0a0068b293879814890f52a235..68c580e645b8e45647717230aea0617e40924635 100644
--- a/src/dynamixel_slave.h
+++ b/src/dynamixel_slave.h
@@ -10,6 +10,29 @@
 #include <stdlib.h>
 #include <string>
 #include <vector>
+#include <boost/function.hpp>
+
+typedef boost::function<void (void)> on_ping_fnct;
+typedef boost::function<unsigned char (unsigned short int,unsigned short int,unsigned char *)> on_rw_fnct;
+
+typedef struct
+{
+  unsigned char id;
+  on_ping_fnct on_ping;
+  on_rw_fnct on_read;
+  on_rw_fnct on_write;
+  unsigned short int reg_address;
+  unsigned short int reg_length;
+  unsigned char *reg_data;
+  unsigned char bulk_prev_id;
+  unsigned short int bulk_address;
+  unsigned short int bulk_length;
+  bool bulk_read_pending;
+  unsigned char sync_prev_id;
+  unsigned short int sync_address;
+  unsigned short int sync_length;
+  bool sync_read_pending;
+}TSlave;
 
 /**
  * \brief 
@@ -43,6 +66,11 @@ class CDynamixelSlave
      * 
      */
     std::string process_packets_thread_id;
+    /**
+     * \brief 
+     * 
+     */
+    std::string dynamixel_loop_thread_id;
     /**
      * \brief
      *
@@ -63,6 +91,16 @@ class CDynamixelSlave
      *
      */
     dyn_version_t dyn_ver;
+    /**
+     * \brief
+     *
+     */
+    std::vector <TSlave> slaves;
+    /**
+     * \brief
+     *
+     */
+    std::vector<unsigned char *> packets;
   protected:
     /**
      * \brief mutual exclusion mechanism to access the usb
@@ -83,152 +121,182 @@ class CDynamixelSlave
      * \brief 
      *
      */
-    void handle_error(unsigned char error); 
+    static void *dynamixel_loop_thread(void *params);
     /**
      * \brief 
      *
      */
-    void start(void);
+    void handle_error(unsigned char error); 
     /**
      * \brief 
      *
      */
-    void stop(void);
-  public:
+    void send_status_packet(unsigned char id,unsigned char error, unsigned short int length, unsigned char *data); 
     /**
-     * \brief
+     * \brief 
      *
-     */ 
-    CDynamixelSlave(const std::string& cont_id,dyn_version_t dyn_ver=dyn_version1);
+     */
+    void start(void);
     /**
      * \brief 
-     *  
-     */ 
-    std::string get_new_packet_available_event_id(void);
+     *
+     */
+    void stop(void);
     /**
      * \brief 
      *
      */
-    virtual void set_baudrate(int baudrate)=0;
+    void dynamixel_loop_v1(void);
     /**
      * \brief 
      *
      */
-    virtual int get_baudrate(void)=0;
+    void dynamixel_loop_v2(void);
     /**
      * \brief 
      *  
      */ 
-    void set_return_delay(unsigned int time_us);
+    unsigned char get_target_id(unsigned char *data);
     /**
      * \brief 
      *  
      */ 
-    unsigned int get_return_delay(void);
+    dyn_inst_t get_instruction_type(unsigned char *data);
     /**
      * \brief 
      *  
      */ 
-    void set_return_level(return_level_t level);
+    unsigned short int get_packet_length(unsigned char *data);
     /**
      * \brief 
      *  
      */ 
-    return_level_t get_return_level(void);
+    unsigned short int get_checksum(unsigned char *data);
+    // instruction specific functions
+    /* read instruction */
     /**
      * \brief 
      *  
      */ 
-    bool new_packet_available(void);
+    unsigned short int get_read_length(unsigned char *data);
     /**
      * \brief 
      *  
      */ 
-    unsigned char get_target_id(void);
+    unsigned short int get_read_address(unsigned char *data);
+    /* write instruction */
     /**
      * \brief 
      *  
      */ 
-    dyn_inst_t get_instruction_type(void);
-    // instruction specific functions
-    /* read instruction */
+    unsigned short int get_write_address(unsigned char *data);
     /**
      * \brief 
      *  
      */ 
-    unsigned short int get_read_length(void);
+    unsigned short int get_write_length(unsigned char *data);
     /**
      * \brief 
      *  
      */ 
-    unsigned short int get_read_address(void);
-    /* write instruction */
+    unsigned short int get_write_data(unsigned char *data, unsigned char **write_data);
+    /* registered write instruction */
     /**
      * \brief 
      *  
      */ 
-    unsigned short int get_write_address(void);
+    unsigned short int get_reg_write_address(unsigned char *data);
     /**
      * \brief 
      *  
      */ 
-    unsigned short int get_write_length(void);
+    unsigned short int get_reg_write_length(unsigned char *data);
     /**
      * \brief 
      *  
      */ 
-    void get_write_data(std::vector<unsigned char> &data);
-    /* registered write instruction */
+    unsigned short int get_reg_write_data(unsigned char *data,unsigned char **write_data);
+    /* sync write instruction */
     /**
      * \brief 
      *  
-     */ 
-    unsigned short int get_reg_write_address(void);
+     */
+    bool sync_write_id_present(unsigned char *data,unsigned char id,unsigned short int *address,unsigned short int *length,unsigned char **write_data);
+    /* sync read instruction */
     /**
      * \brief 
      *  
+     */
+    unsigned char sync_read_id_present(unsigned char *data,unsigned char id,unsigned short int *address,unsigned short int *length);
+    /* bulk read instruction */
+    /**
+     * \brief 
+     *  
+     */
+    unsigned char bulk_read_id_present(unsigned char *data,unsigned char id,unsigned short int *address,unsigned short int *length);
+    /* bulk write instruction */
+    /**
+     * \brief 
+     *  
+     */
+    bool bulk_write_id_present(unsigned char *data,unsigned char id,unsigned short int *address,unsigned short int *length,unsigned char **write_data);
+    // status return
+    /**
+     * \brief 
+     *  
+     */
+    void send_status_packet(unsigned char id,dyn_error_t error,unsigned short int length,unsigned char *data);
+  public:
+    /**
+     * \brief
+     *
      */ 
-    unsigned short int get_reg_write_length(void);
+    CDynamixelSlave(const std::string& cont_id,dyn_version_t dyn_ver=dyn_version1);
+    /**
+     * \brief 
+     *
+     */
+    virtual void set_baudrate(int baudrate)=0;
+    /**
+     * \brief 
+     *
+     */
+    virtual int get_baudrate(void)=0;
     /**
      * \brief 
      *  
      */ 
-    void get_reg_write_data(std::vector<unsigned char> &data);
-    /* sync write instruction */
+    void add_slave(unsigned char id, on_ping_fnct on_ping, on_rw_fnct on_read, on_rw_fnct on_write);
     /**
      * \brief 
      *  
      */ 
-    bool sync_write_id_present(unsigned char id,unsigned short int *address,unsigned short int *length,std::vector<unsigned char> &data);
-    /* sync read instruction */
+    void delete_slave(unsigned char id);
     /**
      * \brief 
      *  
      */ 
-    bool sync_read_id_present(unsigned char id,unsigned short int *address,unsigned short int *length);
-    /* bulk read instruction */
+    unsigned int get_num_slaves(void);
     /**
      * \brief 
      *  
      */ 
-    bool bulk_read_id_present(unsigned char id,std::vector<unsigned short int> &address,std::vector<unsigned short int> &length);
-    /* bulk write instruction */
+    unsigned int get_return_delay(void);
     /**
      * \brief 
      *  
      */ 
-    bool bulk_write_id_present(unsigned char id,std::vector<unsigned short int> &address,std::vector<unsigned short int> &length,std::vector<unsigned char> &data);
-    // status return
+    void set_return_delay(unsigned int delay_us);
     /**
      * \brief 
      *  
      */ 
-    void send_status_packet(unsigned char id,TDynError error,unsigned short int length,std::vector<unsigned char> &data);
+    return_level_t get_return_level(void);
     /**
      * \brief 
      *  
      */ 
-    void next_packet(void);
+    void get_return_level(return_level_t level);
     /**
      * \brief 
      *  
diff --git a/src/dynamixelexceptions.cpp b/src/dynamixelexceptions.cpp
index d7bebd8ccccd3288568e21866973ddbb231dd5a4..a0832e59a1ec884cb5af30aa4be96f4d2fb1a5bf 100644
--- a/src/dynamixelexceptions.cpp
+++ b/src/dynamixelexceptions.cpp
@@ -5,6 +5,7 @@
 
 const std::string dynamixel_error_message="Dynamixel error - ";
 const std::string dynamixel_server_error_message="Dynamixel server error - ";
+const std::string dynamixel_slave_error_message="Dynamixel slave error - ";
 const std::string dynamixel_sync_error="Dynamixel synchronization event";
 
 CDynamixelException::CDynamixelException(const std::string& where,const std::string &error_msg,int dev_id):CException(where,dynamixel_error_message)
@@ -44,3 +45,8 @@ CDynamixelServerException::CDynamixelServerException(const std::string& where,co
   this->error_msg+=error_msg;
 }
 
+CDynamixelSlaveException::CDynamixelSlaveException(const std::string& where,const std::string &error_msg):CException(where,dynamixel_slave_error_message)
+{
+  this->error_msg+=error_msg;
+}
+
diff --git a/src/dynamixelexceptions.h b/src/dynamixelexceptions.h
index 90cb4b5740dec469badb0d8b36a47fa2e8d8a4e1..498c6338a62035d079fbae8877c734c8617a798c 100644
--- a/src/dynamixelexceptions.h
+++ b/src/dynamixelexceptions.h
@@ -132,4 +132,25 @@ class CDynamixelServerException : public CException
     CDynamixelServerException(const std::string& where,const std::string &error_msg);
 };
 
+/**
+ * \brief Dynamixel slave exception
+ * 
+ */
+class CDynamixelSlaveException : public CException
+{
+  public:
+    /**
+     * \brief Class constructor 
+     * 
+     * \param where a null terminated string with the information about the name
+     *              of the function, the source code filename and the line where
+     *              the exception was generated. This string must be generated 
+     *              by the _HERE_ macro.
+     *        
+     * \param error_msg a null terminated string with the details of the error.
+     */
+    CDynamixelSlaveException(const std::string& where,const std::string &error_msg);
+};
+
+
 #endif
diff --git a/src/examples/test_dynamixel_server.cpp b/src/examples/test_dynamixel_server.cpp
index 8e3ed0f5a3e0e65793a7c54e51fc0b3910afcb24..0ca19b63812ad95456ee6e9f8604b518680557cd 100644
--- a/src/examples/test_dynamixel_server.cpp
+++ b/src/examples/test_dynamixel_server.cpp
@@ -2,6 +2,8 @@
 #include "dynamixelserver_ftdi.h"
 #include <iostream>
 
+std::string serial="A400gaIt";
+
 int main(int argc, char *argv[])
 {
   CDynamixelServerFTDI *dyn_server=CDynamixelServerFTDI::instance();
@@ -20,7 +22,7 @@ int main(int argc, char *argv[])
     try{
     events.push_back(dyn_server->get_scan_done_event_id());
     events.push_back(dyn_server->get_scan_error_event_id());
-    dyn_server->config_bus(0,1000000);
+    dyn_server->config_bus(serial,1000000);
     dyn_server->start_scan();
     event_id=event_server->wait_first(events);
     if(event_id==0)
diff --git a/src/examples/test_dynamixel_slave.cpp b/src/examples/test_dynamixel_slave.cpp
index 1f269e340055acf536707fa8cfa4944464b1500a..3360f368be31db2ac1ec1980c95a0f673b2ef0e5 100644
--- a/src/examples/test_dynamixel_slave.cpp
+++ b/src/examples/test_dynamixel_slave.cpp
@@ -1,14 +1,44 @@
 #include "eventexceptions.h"
-#include "dynamixel_slave_serial.h"
+#include "dynamixel_slave_ftdi.h"
 #include <iostream>
+#include <boost/bind.hpp>
+
+std::string serial="A400gavm";
+
+void on_ping(void)
+{
+  std::cout << "device pinged" << std::endl;
+}
+
+unsigned char on_read(unsigned short int address, unsigned short int length, unsigned char *data)
+{
+  std::cout << "read operation at address " << address << " with length " << length << std::endl;
+
+  return 0x00;
+}
+
+unsigned char on_write(unsigned short int address, unsigned short int length, unsigned char *data)
+{
+  std::cout << "wrirte operation at address " << address << " with length " << length << std::endl;
+
+  return 0x00;
+}
 
 int main(int argc, char *argv[])
 {
+  int num_buses=0;
+
   try{
-    CDynamixelSlaveSerial slave("slave","/dev/ttyUSB1");
-    slave.set_baudrate(1000000);
-    sleep(10);
-    std::cout << "exit" << std::endl;
+    CDynamixelSlaveFTDI slave("slave");
+    num_buses=slave.get_num_buses();
+    std::cout << "Num. buses: " << num_buses << std::endl;
+    if(num_buses>0)
+    {
+      slave.config_bus(serial,1000000);
+      slave.add_slave(0x10,boost::bind(&on_ping),boost::bind(&on_read,_1,_2,_3),boost::bind(&on_write,_1,_2,_3));
+      sleep(10000);
+      std::cout << "exit" << std::endl;
+    }
   }catch(CException &e){
     std::cout << e.what() << std::endl;
   }