From 57cc9583a914de29f34ebdfd06d78663e4ae4045 Mon Sep 17 00:00:00 2001
From: Sergi Hernandez Juan <shernand@iri.upc.edu>
Date: Fri, 17 Feb 2023 10:54:30 +0100
Subject: [PATCH] Added functions to receive all the answers from bulk and sync
 read commands.

---
 include/dynamixelserver.h |  10 ++
 src/dynamixelserver.cpp   | 347 ++++++++++++++++++++++----------------
 2 files changed, 215 insertions(+), 142 deletions(-)

diff --git a/include/dynamixelserver.h b/include/dynamixelserver.h
index c7266d3..3e9030a 100644
--- a/include/dynamixelserver.h
+++ b/include/dynamixelserver.h
@@ -106,11 +106,21 @@ class CDynamixelServer
      *
      */ 
     virtual unsigned char receive_status_packet_v1(unsigned char **data,unsigned char *len);
+    /**
+     * \brief 
+     *
+     */ 
+    virtual void receive_sync_bulk_status_packets_v1(std::vector<unsigned char>& servo_ids, std::vector< std::vector<unsigned char> >& data);
     /**
      * \brief 
      *
      */ 
     virtual unsigned char receive_status_packet_v2(unsigned char **data,unsigned short int *len);
+    /**
+     * \brief 
+     *
+     */ 
+    virtual void receive_sync_bulk_status_packets_v2(std::vector<unsigned char>& servo_ids, std::vector< std::vector<unsigned char> >& data);
     /**
      * \brief
      *
diff --git a/src/dynamixelserver.cpp b/src/dynamixelserver.cpp
index 37c91fc..a38ae2b 100644
--- a/src/dynamixelserver.cpp
+++ b/src/dynamixelserver.cpp
@@ -2,6 +2,7 @@
 #include "dynamixelserver.h"
 #include "eventexceptions.h"
 #include <sstream>
+#include <iostream>
 
 const unsigned short crc_table[256] = {
         0x0000, 0x8005, 0x800F, 0x000A, 0x801B, 0x001E, 0x0014, 0x8011,
@@ -194,7 +195,7 @@ unsigned char CDynamixelServer::receive_status_packet_v1(unsigned char **data,un
       do{
         if((num=this->comm_dev->get_num_data())==0)
         {
-          this->event_server->wait_all(events,20);
+          this->event_server->wait_all(events,100);
           num=this->comm_dev->get_num_data();
         }
         if((read+num)>1024)
@@ -262,6 +263,92 @@ unsigned char CDynamixelServer::receive_status_packet_v1(unsigned char **data,un
   }
 }
 
+
+void CDynamixelServer::receive_sync_bulk_status_packets_v1(std::vector<unsigned char>& servo_ids, std::vector< std::vector<unsigned char> >& data)
+{
+  std::list<std::string> events;
+  unsigned char data_int[1024];
+  int num=0,read=0,length=-1,new_data,total=0;
+  bool need_data=true;
+
+  if(this->comm_dev!=NULL)
+  {
+    try{
+      data.resize(servo_ids.size());
+      events.push_back(this->comm_dev->get_rx_event_id());
+      // read up to the length field
+      for(unsigned int i=0;i<servo_ids.size();)
+      {
+	if(need_data)
+        {
+          this->event_server->wait_all(events,100);
+          new_data=this->comm_dev->get_num_data();
+          this->comm_dev->read(&data_int[total],new_data);
+	  total+=new_data;
+	  num+=new_data;
+	  need_data=false;
+        }
+	if(length==-1)
+	{
+	  if(num>=4)
+	  {
+	    if(data_int[read+2]!=servo_ids[i])
+              throw CDynamixelServerException(_HERE_,"Invalid status packet order in Sync/Bulk read");
+            length=data_int[read+3]+4;
+	  }
+	  else
+	    need_data=true;
+	}
+	if(length!=-1 && num>=length)
+	{
+          if(this->compute_checksum_v1(&data_int[read],length)!=0x00)
+          {
+            data[i].clear();
+	    read+=length;
+	    num-=length;
+	    length=-1;
+	    i++;
+	    continue;
+          }
+	  try{
+            this->handle_error(data_int[read+4]);
+	  }catch(CException &e){
+            data[i].clear();
+	    read+=length;
+	    num-=length;
+	    length=-1;
+	    i++;
+	    continue;
+	  } 
+          if(length>6)
+          {
+            data[i].resize(length-6);
+	    for(unsigned j=0;j<(unsigned int)(length-6);j++)
+	      data[i][j]=data_int[read+5+j];
+          }
+          else
+            data[i].clear();
+	  read+=length;
+	  num-=length;
+	  length=-1;
+	  i++;
+	}
+	else
+          need_data=true;
+      }
+    }catch(CEventTimeoutException &e){
+      throw e;
+    }catch(CException &e){
+      throw e;
+    }
+  }
+  else
+  {
+    /* handle exceptions */
+    throw CDynamixelServerException(_HERE_,"The communication device is not properly configured");
+  }
+}
+
 unsigned char CDynamixelServer::receive_status_packet_v2(unsigned char **data,unsigned short int *len)
 {
   std::list<std::string> events;
@@ -277,7 +364,7 @@ unsigned char CDynamixelServer::receive_status_packet_v2(unsigned char **data,un
       do{
         if((num=this->comm_dev->get_num_data())==0)
         {
-          this->event_server->wait_all(events,20);
+          this->event_server->wait_all(events,100);
           num=this->comm_dev->get_num_data();
         }
         if((read+num)>1024)
@@ -298,7 +385,7 @@ unsigned char CDynamixelServer::receive_status_packet_v2(unsigned char **data,un
       {
         if((num=this->comm_dev->get_num_data())==0)
         {
-          this->event_server->wait_all(events,20);
+          this->event_server->wait_all(events,100);
           num=this->comm_dev->get_num_data();
         }
         if((read-start+num)>length)
@@ -345,6 +432,95 @@ unsigned char CDynamixelServer::receive_status_packet_v2(unsigned char **data,un
   }
 }
 
+void CDynamixelServer::receive_sync_bulk_status_packets_v2(std::vector<unsigned char> &servo_ids,std::vector< std::vector<unsigned char>  > &data)
+{
+  std::list<std::string> events;
+  unsigned char data_int[1024];
+  unsigned short int crc;
+  int num=0,read=0,length=-1,new_data,total=0;
+  bool need_data=true;
+
+  if(this->comm_dev!=NULL)
+  {
+    try{
+      data.resize(servo_ids.size());
+      events.push_back(this->comm_dev->get_rx_event_id());
+      // read up to the length field
+      for(unsigned int i=0;i<servo_ids.size();)
+      {
+	if(need_data)
+        {
+          this->event_server->wait_all(events,100);
+          new_data=this->comm_dev->get_num_data();
+          this->comm_dev->read(&data_int[total],new_data);
+	  total+=new_data;
+	  num+=new_data;
+	  need_data=false;
+        }
+	if(length==-1)
+	{
+	  if(num>=7)
+	  {
+	    if(data_int[read+2]!=servo_ids[i])
+              throw CDynamixelServerException(_HERE_,"Invalid status packet order in Sync/Bulk read");
+            length=data_int[read+5]+data_int[read+6]*256+7;
+	  }
+	  else
+	    need_data=true;
+	}
+	if(length!=-1 && num>=length)
+	{
+          // check the checksum
+          crc=this->compute_checksum_v2(&data_int[read],length-2);
+          if((crc%256)!=data_int[read+length-2] || (crc/256)!=data_int[read+length-1])
+          {
+            /* handle exceptions */
+            data[i].clear();
+	    read+=length;
+	    num-=length;
+	    length=-1;
+	    i++;
+	    continue;
+          }
+	  try{
+            this->handle_error(data_int[read+8]);
+	  }catch(CException &e){
+            data[i].clear();
+	    read+=length;
+	    num-=length;
+	    length=-1;
+	    i++;
+	    continue;
+	  }
+          if(length>11)
+          {
+            data[i].resize(length-11);
+	    for(unsigned j=0;j<(unsigned int)(length-11);j++)
+	      data[i][j]=data_int[read+9+j];
+          }
+          else
+            data[i].clear();
+	  read+=length;
+	  num-=length;
+	  length=-1;
+	  i++;
+	}
+	else
+          need_data=true;
+      }
+    }catch(CEventTimeoutException &e){
+      throw e;
+    }catch(CException &e){
+      throw e;
+    }
+  }
+  else
+  {
+    /* handle exceptions */
+    throw CDynamixelServerException(_HERE_,"The communication device is not properly configured");
+  }
+}
+
 unsigned char CDynamixelServer::compute_checksum_v1(unsigned char *packet,int len)
 {
   int i=0;
@@ -895,6 +1071,7 @@ void CDynamixelServer::write_sync(std::vector<unsigned char>& servo_ids,unsigned
     throw CDynamixelServerException(_HERE_,"Too much data blocks or some missing servos");
   }
   try{
+    this->dynamixel_access.enter();
     if(version==dyn_version1)
     {
       length=2+(data[0].size()+1)*servo_ids.size();
@@ -909,9 +1086,7 @@ void CDynamixelServer::write_sync(std::vector<unsigned char>& servo_ids,unsigned
       }
       try
       {
-        this->dynamixel_access.enter();
         this->send_instruction_packet_v1(dyn_sync_write,data_int,length);
-        this->dynamixel_access.exit();
       }
       catch(CEventTimeoutException &e)
       {
@@ -941,9 +1116,7 @@ void CDynamixelServer::write_sync(std::vector<unsigned char>& servo_ids,unsigned
       }
       try
       {
-        this->dynamixel_access.enter();
         this->send_instruction_packet_v2(dyn_sync_write,data_int,length);
-        this->dynamixel_access.exit();
       }
       catch(CEventTimeoutException &e)
       {
@@ -957,6 +1130,7 @@ void CDynamixelServer::write_sync(std::vector<unsigned char>& servo_ids,unsigned
       }
       delete[] data_int;
     }
+    this->dynamixel_access.exit();
   }catch(CException &e){
     if(data_int!=NULL)
     {
@@ -969,9 +1143,8 @@ void CDynamixelServer::write_sync(std::vector<unsigned char>& servo_ids,unsigned
 
 void CDynamixelServer::read_sync(std::vector<unsigned char>& servo_ids,unsigned short int start_addr,unsigned short int length, std::vector< std::vector<unsigned char> >& data,dyn_version_t version)
 {
-  unsigned char *data_int=NULL,*data_out=NULL,error,length_v1;
-  unsigned short length_v2;
-  unsigned int i,j=0;
+  unsigned char *data_int=NULL;
+  unsigned int i;
   int length_int=0;
 
   if(servo_ids.size()==0)
@@ -980,6 +1153,7 @@ void CDynamixelServer::read_sync(std::vector<unsigned char>& servo_ids,unsigned
     throw CDynamixelServerException(_HERE_,"No servos specified");
   }
   try{
+    this->dynamixel_access.enter();
     if(version==dyn_version2)
     {
       length_int=4+servo_ids.size();
@@ -992,38 +1166,9 @@ void CDynamixelServer::read_sync(std::vector<unsigned char>& servo_ids,unsigned
         data_int[4+i]=servo_ids[i];
       try
       {
-        this->dynamixel_access.enter();
         this->send_instruction_packet_v2(dyn_sync_read,data_int,length_int);
         /* read all the data from all the servos */
-        if(data_int!=NULL)
-        {
-          delete[] data_int;
-          data_int=NULL;
-        }
-        data.resize(servo_ids.size());
-        for(i=0;i<servo_ids.size();i++)
-        {
-          try{
-            error=this->receive_status_packet_v2(&data_out,&length_v2);
-            this->handle_error(error);
-            if(data_out!=NULL)
-            {
-              data[i].resize(length_v2);
-              for(j=0;j<length_v2;j++)
-                data[i][j]=data_out[j];
-              delete[] data_out;
-              data_out=NULL;
-            }
-          }catch(CException &e){
-            if(data_out!=NULL)
-            {
-              delete[] data_out;
-              data_out=NULL;
-            }
-            throw e;
-          } 
-        }
-        this->dynamixel_access.exit();
+	receive_sync_bulk_status_packets_v2(servo_ids,data);
       }
       catch(CEventTimeoutException &e)
       {
@@ -1035,6 +1180,7 @@ void CDynamixelServer::read_sync(std::vector<unsigned char>& servo_ids,unsigned
         this->dynamixel_access.exit();
         throw e;
       }
+      delete[] data_int;
     }
     else
     {
@@ -1046,38 +1192,9 @@ void CDynamixelServer::read_sync(std::vector<unsigned char>& servo_ids,unsigned
         data_int[2+i]=servo_ids[i];
       try
       {
-        this->dynamixel_access.enter();
         this->send_instruction_packet_v1(dyn_sync_read,data_int,length_int);
         /* read all the data from all the servos */
-        if(data_int!=NULL)
-        {
-          delete[] data_int;
-          data_int=NULL;
-        }
-        data.resize(servo_ids.size());
-        for(i=0;i<servo_ids.size();i++)
-        {
-          try{
-            error=this->receive_status_packet_v1(&data_out,&length_v1);
-            this->handle_error(error);
-            if(data_out!=NULL)
-            {
-              data[i].resize(length_v1);
-              for(j=0;j<length_v1;j++)
-                data[i][j]=data_out[j];
-              delete[] data_out;
-              data_out=NULL;
-            }
-          }catch(CException &e){
-            if(data_out!=NULL)
-            {
-              delete[] data_out;
-              data_out=NULL;
-            }
-            throw e;
-          } 
-        }
-        this->dynamixel_access.exit();
+	receive_sync_bulk_status_packets_v1(servo_ids,data);
       }
       catch(CEventTimeoutException &e)
       {
@@ -1089,12 +1206,14 @@ void CDynamixelServer::read_sync(std::vector<unsigned char>& servo_ids,unsigned
         this->dynamixel_access.exit();
         throw e;
       }
+      delete[] data_int;
     }
+    this->dynamixel_access.exit();
   }catch(CException &e){
     if(data_int!=NULL)
     {
       delete[] data_int;
-      data_out=NULL;
+      data_int=NULL;
     }
     throw e;
   }
@@ -1122,6 +1241,7 @@ void CDynamixelServer::write_bulk(std::vector<unsigned char>& servo_ids,std::vec
     throw CDynamixelServerException(_HERE_,"Too many or not enough data blocks");
   }
   try{
+    this->dynamixel_access.enter();
     if(version==dyn_version2)
     {
       length=0;
@@ -1141,9 +1261,7 @@ void CDynamixelServer::write_bulk(std::vector<unsigned char>& servo_ids,std::vec
       }
       try
       {
-        this->dynamixel_access.enter();
         this->send_instruction_packet_v2(dyn_bulk_write,data_int,length);
-        this->dynamixel_access.exit();
       }
       catch(CEventTimeoutException &e)
       {
@@ -1174,9 +1292,7 @@ void CDynamixelServer::write_bulk(std::vector<unsigned char>& servo_ids,std::vec
       }
       try
       {
-        this->dynamixel_access.enter();
         this->send_instruction_packet_v1(dyn_bulk_write,data_int,length);
-        this->dynamixel_access.exit();
       }
       catch(CEventTimeoutException &e)
       {
@@ -1190,6 +1306,7 @@ void CDynamixelServer::write_bulk(std::vector<unsigned char>& servo_ids,std::vec
       }
       delete[] data_int;
     }
+    this->dynamixel_access.exit();
   }catch(CException &e){
     if(data_int!=NULL)
     {
@@ -1202,9 +1319,8 @@ void CDynamixelServer::write_bulk(std::vector<unsigned char>& servo_ids,std::vec
 
 void CDynamixelServer::read_bulk(std::vector<unsigned char>& servo_ids,std::vector<unsigned short int> &start_addr,std::vector<unsigned short int> &length, std::vector< std::vector<unsigned char> >& data,dyn_version_t version)
 {
-  unsigned char *data_int=NULL,*data_out=NULL,error,length_v1;
-  unsigned short int length_v2;
-  unsigned int i,j=0;
+  unsigned char *data_int=NULL;
+  unsigned int i;
   int length_int=0;
 
   if(servo_ids.size()==0)
@@ -1223,6 +1339,7 @@ void CDynamixelServer::read_bulk(std::vector<unsigned char>& servo_ids,std::vect
     throw CDynamixelServerException(_HERE_,"Too many or not enough read lengths");
   }
   try{
+    this->dynamixel_access.enter();
     if(version==dyn_version2)
     {
       length_int=5*servo_ids.size();
@@ -1237,38 +1354,9 @@ void CDynamixelServer::read_bulk(std::vector<unsigned char>& servo_ids,std::vect
       }
       try
       {
-        this->dynamixel_access.enter();
         this->send_instruction_packet_v2(dyn_bulk_read,data_int,length_int);
         /* read all the data from all the servos */
-        if(data_int!=NULL)
-        {
-          delete[] data_int;
-          data_int=NULL;
-        }
-        data.resize(servo_ids.size());
-        for(i=0;i<servo_ids.size();i++)
-        {
-          error=this->receive_status_packet_v2(&data_out,&length_v2);
-          try{
-            this->handle_error(error);
-            if(data_out!=NULL)
-            {
-              data[i].resize(length_v2);
-              for(j=0;j<length_v2;j++)
-                data[i][j]=data_out[j];
-              delete[] data_out;
-              data_out=NULL;
-            }
-          }catch(CException &e){
-            if(data_out!=NULL)
-            {
-              delete[] data_out;
-              data_out=NULL;
-            }
-            throw e;
-          }
-        }
-        this->dynamixel_access.exit();
+        receive_sync_bulk_status_packets_v2(servo_ids,data);
       }
       catch(CEventTimeoutException &e)
       {
@@ -1280,51 +1368,24 @@ void CDynamixelServer::read_bulk(std::vector<unsigned char>& servo_ids,std::vect
         this->dynamixel_access.exit();
         throw e;
       }
+      delete[] data_int;
     }
     else
     {
-      length_int=3*servo_ids.size();
+      length_int=3*servo_ids.size()+1;
       data_int=new unsigned char[length_int];
+      data_int[0]=0x00;
       for(i=0;i<servo_ids.size();i++)
       {
-        data_int[i*3]=servo_ids[i];
-        data_int[i*3+1]=(unsigned char)start_addr[i];
-        data_int[i*3+2]=(unsigned char)length[i];
+        data_int[i*3+1]=(unsigned char)length[i];
+        data_int[i*3+2]=servo_ids[i];
+        data_int[i*3+3]=(unsigned char)start_addr[i];
       }
       try
       {
-        this->dynamixel_access.enter();
         this->send_instruction_packet_v1(dyn_bulk_read,data_int,length_int);
         /* read all the data from all the servos */
-        if(data_int!=NULL)
-        {
-          delete[] data_int;
-          data_int=NULL;
-        }
-        data.resize(servo_ids.size());
-        for(i=0;i<servo_ids.size();i++)
-        {
-          error=this->receive_status_packet_v1(&data_out,&length_v1);
-          try{
-            this->handle_error(error);
-            if(data_out!=NULL)
-            {
-              data[i].resize(length_v1);
-              for(j=0;j<length_v1;j++)
-                data[i][j]=data_out[j];
-              delete[] data_out;
-              data_out=NULL;
-            }
-          }catch(CException &e){
-            if(data_out!=NULL)
-            {
-              delete[] data_out;
-              data_out=NULL;
-            }
-            throw e;
-          }
-        }
-        this->dynamixel_access.exit();
+        receive_sync_bulk_status_packets_v1(servo_ids,data);
       }
       catch(CEventTimeoutException &e)
       {
@@ -1336,7 +1397,9 @@ void CDynamixelServer::read_bulk(std::vector<unsigned char>& servo_ids,std::vect
         this->dynamixel_access.exit();
         throw e;
       }
+      delete[] data_int;
     }
+    this->dynamixel_access.exit();
   }catch(CException &e){
     if(data_int!=NULL)
     {
-- 
GitLab