diff --git a/include/dynamixel.h b/include/dynamixel.h index 96c545cae70ec860f23f7876bdacc7ae4d4242c9..e842d55b38d8a5b233a707590aa791fc2263b2e6 100644 --- a/include/dynamixel.h +++ b/include/dynamixel.h @@ -1,7 +1,7 @@ #ifndef _DYNAMIXEL_H #define _DYNAMIXEL_H -//#include "dynamixelserver.h" +#include "dynamixelserver.h" #include "dynamixel_common.h" #include "eventserver.h" #include "comm.h" @@ -24,93 +24,93 @@ class CDynamixel private: friend class CDynamixelServer; /** - * \brief - * + * \brief + * */ - CDynamixelServer *dyn_server; + unsigned char id_register; /** - * \brief Handle to the communications device + * \brief * - */ - CComm *comm_dev; - /** - * \brief - * */ - unsigned char node_address; + unsigned char baudrate_register; /** - * \brief mutual exclusion mechanism to access the usb + * \brief * */ - CMutex *usb_access; + void set_baudrate(int baudrate); + + protected: /** - * \brief Handle to the unique event server + * \brief * */ - CEventServer *event_server; + virtual void send_instruction_packet_v1(dyn_inst_t inst,unsigned char *data=NULL,unsigned char len=0); /** - * \brief data reception event - * + * \brief + * */ - std::string usb_rx_event_id; + virtual void send_instruction_packet_v2(dyn_inst_t inst,unsigned char *data=NULL,unsigned short int len=0); /** * \brief * */ - unsigned char id_register; + virtual unsigned char receive_status_packet_v1(unsigned char **data,unsigned char *len); /** * \brief * */ - unsigned char baudrate_register; + virtual unsigned char receive_status_packet_v2(unsigned char **data,unsigned short int *len); /** * \brief * */ - void set_baudrate(int baudrate); + void handle_error(unsigned char error); + public: /** * \brief * */ - void sync_packet_v1(unsigned char *data,unsigned int length,int *start); + void sync_packet_v2(unsigned char *data,unsigned int length,int *start); /** * \brief * */ - void sync_packet_v2(unsigned char *data,unsigned int length,int *start); + void sync_packet_v1(unsigned char *data,unsigned int length,int *start); + /** + * \brief data reception event + * + */ + std::string usb_rx_event_id; /** * \brief * */ dyn_version_t version; - - protected: /** - * \brief - * + * \brief + * */ - void send_instruction_packet_v1(dyn_inst_t inst,unsigned char *data=NULL,unsigned char len=0); + unsigned char node_address; /** - * \brief + * \brief mutual exclusion mechanism to access the usb * */ - void send_instruction_packet_v2(dyn_inst_t inst,unsigned char *data=NULL,unsigned short int len=0); + CMutex *usb_access; /** - * \brief - * + * \brief + * */ - unsigned char receive_status_packet_v1(unsigned char **data,unsigned char *len); + CDynamixelServer *dyn_server; /** - * \brief + * \brief Handle to the communications device * - */ - unsigned char receive_status_packet_v2(unsigned char **data,unsigned short int *len); + */ + CComm *comm_dev; /** - * \brief + * \brief Handle to the unique event server * */ - void handle_error(unsigned char error); - public: + CEventServer *event_server; /** * \brief * diff --git a/include/dynamixel_can.h b/include/dynamixel_can.h new file mode 100644 index 0000000000000000000000000000000000000000..7ccc7311a7166c0666f764d9c904aa693acbee79 --- /dev/null +++ b/include/dynamixel_can.h @@ -0,0 +1,41 @@ +#ifndef _DYNAMIXEL_CAN_H +#define _DYNAMIXEL_CAN_H + +#include "dynamixel.h" +#include "dynamixelserver_can.h" + +class CDynamixelCAN : public CDynamixel +{ + private: + friend class CDynamixelServerCAN; + unsigned int tx_frame_id; + unsigned int rx_frame_id; + dyn_inst_t current_inst; + unsigned int current_len; + protected: + /** + * \brief + * + */ + virtual void send_instruction_packet_v1(dyn_inst_t inst,unsigned char *data=NULL,unsigned char len=0); + /** + * \brief + * + */ + virtual void send_instruction_packet_v2(dyn_inst_t inst,unsigned char *data=NULL,unsigned short int len=0); + /** + * \brief + * + */ + virtual unsigned char receive_status_packet_v1(unsigned char **data,unsigned char *len); + /** + * \brief + * + */ + virtual unsigned char receive_status_packet_v2(unsigned char **data,unsigned short int *len); + public: + CDynamixelCAN(std::string &cont_id,unsigned int tx_frame_id,unsigned int rx_frame_id); + virtual ~CDynamixelCAN(); +}; + +#endif diff --git a/include/dynamixelserver.h b/include/dynamixelserver.h index 9c5559abda51b86b4510f97ca63b7f6ab4f28657..c7266d36644bde1f495e0d2c386b2a4b48af8a5a 100644 --- a/include/dynamixelserver.h +++ b/include/dynamixelserver.h @@ -7,6 +7,7 @@ #include "comm.h" #include "eventserver.h" #include "threadserver.h" +#include "dynamixel_common.h" // forward declaration of the CDynamixel class class CDynamixel; @@ -50,11 +51,6 @@ const int frequencies[9]={1000000,500000,400000,250000,200000,115200,57600,19200 class CDynamixelServer { private: - /** - * \brief - * - */ - CEventServer *event_server; /** * \brief * @@ -99,22 +95,22 @@ class CDynamixelServer * \brief * */ - void send_instruction_packet_v1(dyn_inst_t inst,unsigned char *data=NULL,unsigned char len=0,unsigned char id=0xFE); + virtual void send_instruction_packet_v1(dyn_inst_t inst,unsigned char *data=NULL,unsigned char len=0,unsigned char id=0xFE); /** * \brief * */ - void send_instruction_packet_v2(dyn_inst_t inst,unsigned char *data=NULL,unsigned short int len=0,unsigned char id=0xFE); + virtual void send_instruction_packet_v2(dyn_inst_t inst,unsigned char *data=NULL,unsigned short int len=0,unsigned char id=0xFE); /** * \brief * */ - unsigned char receive_status_packet_v1(unsigned char **data,unsigned char *len); + virtual unsigned char receive_status_packet_v1(unsigned char **data,unsigned char *len); /** * \brief * */ - unsigned char receive_status_packet_v2(unsigned char **data,unsigned short int *len); + virtual unsigned char receive_status_packet_v2(unsigned char **data,unsigned short int *len); /** * \brief * @@ -172,6 +168,11 @@ class CDynamixelServer */ void handle_error(unsigned char error); public: + /** + * \brief + * + */ + CEventServer *event_server; /** * \brief * @@ -243,7 +244,7 @@ class CDynamixelServer * \brief * */ - CDynamixel *get_device(int dev_id,dyn_version_t version=dyn_version1); + virtual CDynamixel *get_device(int dev_id,dyn_version_t version=dyn_version1); /** * \brief * diff --git a/include/dynamixelserver_can.h b/include/dynamixelserver_can.h new file mode 100644 index 0000000000000000000000000000000000000000..26ea0b87f0e60e5b653678e2f19e21523b039084 --- /dev/null +++ b/include/dynamixelserver_can.h @@ -0,0 +1,126 @@ +#ifndef _DYNAMIXEL_SERVER_CAN_H +#define _DYNAMIXEL_SERVER_CAN_H + +#include "dynamixelserver.h" + +/** + * \brief Basic Dynamixel bus information + * + * This structure holds the identifier of the current bus used (in case there + * exist multiple buses) and also the baudrate of the bus. + */ +typedef struct +{ + std::string device; + unsigned int tx_frame_id; + unsigned int rx_frame_id; +}TBus_info_can; + +/** + * \brief + * + */ +class CDynamixelServerCAN : public CDynamixelServer +{ + private: + std::string rx_event; + dyn_inst_t current_inst; + unsigned int current_len; + /** + * \brief + * + */ + static CDynamixelServerCAN *pinstance; + /** + * \brief + * + */ + TBus_info_can bus_info; + /** + * \brief + * + */ + virtual void send_instruction_packet_v1(dyn_inst_t inst,unsigned char *data=NULL,unsigned char len=0,unsigned char id=0xFE); + /** + * \brief + * + */ + virtual void send_instruction_packet_v2(dyn_inst_t inst,unsigned char *data=NULL,unsigned short int len=0,unsigned char id=0xFE); + /** + * \brief + * + */ + virtual unsigned char receive_status_packet_v1(unsigned char **data,unsigned char *len); + /** + * \brief + * + */ + virtual unsigned char receive_status_packet_v2(unsigned char **data,unsigned short int *len); + /** + * \brief + * + */ + virtual void sync_packet_v1(unsigned char *data,unsigned int length,int *start); + /** + * \brief + * + */ + virtual void sync_packet_v2(unsigned char *data,unsigned int length,int *start); + protected: + /** + * \brief + * + */ + CDynamixelServerCAN(); + /** + * \brief + * + */ + CDynamixelServerCAN(const CDynamixelServerCAN &object); + /** + * \brief + * + */ + CDynamixelServerCAN& operator = (const CDynamixelServerCAN &object); + public: + /** + * \brief + * + */ + static CDynamixelServerCAN* instance(); + /** + * \brief + * + */ + void config_bus(const std::string &device,int baudrate,unsigned int tx_frame_id,unsigned int rx_frame_id); + /** + * \brief + * + */ + std::string &get_bus_device(void); + /** + * \brief + * + */ + void set_baudrate(int baudrate); + /** + * \brief + * + */ + int get_baudrate(void); +#ifdef _HAVE_XSD + /** + * \brief + * + */ + virtual void config(std::string &filename); +#endif + /** + * \brief + * + */ + virtual CDynamixel *get_device(int dev_id,dyn_version_t version=dyn_version1); + virtual ~CDynamixelServerCAN(); +}; + +#endif diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f325bc8eac42cee920082fa172e8a914a8831e58..363fbd0caa79c40479a36ff53c8d8814237d80bf 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,9 +1,9 @@ ADD_SUBDIRECTORY(xml) # edit the following line to add all the source code files of the library -SET(sources dynamixel.cpp dynamixelserver.cpp dynamixelserver_ftdi.cpp dynamixelserver_serial.cpp dynamixelexceptions.cpp dynamixel_slave.cpp dynamixel_slave_ftdi.cpp dynamixel_slave_serial.cpp) +SET(sources dynamixel.cpp dynamixelserver.cpp dynamixelserver_ftdi.cpp dynamixelserver_serial.cpp dynamixelserver_can.cpp dynamixel_can.cpp dynamixelexceptions.cpp dynamixel_slave.cpp dynamixel_slave_ftdi.cpp dynamixel_slave_serial.cpp) # edit the following line to add all the header files of the library -SET(headers ../include/dynamixel.h ../include/dynamixelserver.h ../include/dynamixelserver_ftdi.h ../include/dynamixelserver_serial.h ../include/dynamixelexceptions.h ../include/dynamixel_common.h ../include/dynamixel_slave.h ../include/dynamixel_slave_ftdi.h ../include/dynamixel_slave_serial.h) +SET(headers ../include/dynamixel.h ../include/dynamixelserver.h ../include/dynamixelserver_ftdi.h ../include/dynamixelserver_can.h ../include/dynamixel_can.h ../include/dynamixelserver_serial.h ../include/dynamixelexceptions.h ../include/dynamixel_common.h ../include/dynamixel_slave.h ../include/dynamixel_slave_ftdi.h ../include/dynamixel_slave_serial.h) INCLUDE_DIRECTORIES(. ../include) diff --git a/src/dynamixel.cpp b/src/dynamixel.cpp index 31f8ea8e1200b61d0b77d1b4c0239c79ae3d4ee3..029b0ed755714683aa979eb8cc269bf153286f11 100644 --- a/src/dynamixel.cpp +++ b/src/dynamixel.cpp @@ -1,7 +1,6 @@ +#include "dynamixel.h" #include "eventexceptions.h" -#include "dynamixelserver.h" #include "dynamixelexceptions.h" -#include "dynamixel.h" #include "ftdiserver.h" #include <iostream> #include <sstream> diff --git a/src/dynamixel_can.cpp b/src/dynamixel_can.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d29ca29c260d49002c779b607a82b7acdf4df3d6 --- /dev/null +++ b/src/dynamixel_can.cpp @@ -0,0 +1,286 @@ +#include "dynamixel_can.h" +#include "eventexceptions.h" +#include "dynamixelexceptions.h" +#include "can.h" +#include "dynamixelserver_can.h" +#include <iostream> + +CDynamixelCAN::CDynamixelCAN(std::string &cont_id,unsigned int tx_frame_id,unsigned int rx_frame_id) : CDynamixel(cont_id) +{ + this->tx_frame_id=tx_frame_id; + this->rx_frame_id=rx_frame_id; +} + +void CDynamixelCAN::send_instruction_packet_v1(dyn_inst_t inst,unsigned char *data,unsigned char len) +{ + unsigned char *packet=NULL; + int i,length; + + switch(inst) + { + case dyn_reg_write: + case dyn_write: + case dyn_read: length=6+len; + packet=new unsigned char[length]; + break; + default: throw CDynamixelException(_HERE_,"Instruction not supported",this->get_id()); + break; + } + packet[0]=0xFF; + packet[1]=0xFF; + packet[2]=this->get_id(); + packet[3]=len+2; + packet[4]=inst; + for(i=0;i<len;i++) + packet[5+i]=data[i]; + // byte stuffing + packet[length-1]=0x00; + packet[length-1] = CDynamixelServer::compute_checksum_v1(packet,length); + if(this->comm_dev!=NULL) + { + try{ + ((CCAN *)this->comm_dev)->write(this->tx_frame_id,packet,length); + if(packet!=NULL) + delete[] packet; + }catch(CException &e){ + throw e; + } + } + else + { + if(packet!=NULL) + delete[] packet; + /* handle exceptions */ + throw CDynamixelException(_HERE_,"The communication device is not properly configured",this->get_id()); + } +} + +void CDynamixelCAN::send_instruction_packet_v2(dyn_inst_t inst,unsigned char *data,unsigned short int len) +{ + unsigned char *packet=NULL; + int i,length,crc; + + switch(inst) + { + case dyn_reg_write: + case dyn_write: + case dyn_read: length=10+len; + packet=new unsigned char[length]; + break; + default: throw CDynamixelException(_HERE_,"Instruction not supported",this->get_id()); + break; + } + packet[0]=0xFF; + packet[1]=0xFF; + packet[2]=0xFD; + packet[3]=0x00; + packet[4]=this->node_address; + packet[5]=(len+3)%256; + packet[6]=(len+3)/256; + packet[7]=inst; + for(i=0;i<len;i++) + packet[8+i]=data[i]; + packet[length-2]=0x00; + packet[length-1]=0x00; + crc=CDynamixelServer::compute_checksum_v2(packet,length-2); + packet[length-2]=crc%256; + packet[length-1]=crc/256; + if(this->comm_dev!=NULL) + { + try{ + ((CCAN *)this->comm_dev)->write(this->tx_frame_id,packet,length); + if(packet!=NULL) + delete[] packet; + }catch(CException &e){ + throw e; + } + } + else + { + /* handle exceptions */ + throw CDynamixelException(_HERE_,"The communication device is not properly configured",this->get_id()); + } +} + +unsigned char CDynamixelCAN::receive_status_packet_v1(unsigned char **data,unsigned char *len) +{ + std::list<std::string> events; + unsigned char data_int[1024]; + int num=0,read=0,length,start=0; + + if(this->current_inst==dyn_write) + { + *data=NULL; + *len=0; + return 0; + } + if(this->comm_dev!=NULL) + { + try{ + events.push_back(((CCAN *)this->comm_dev)->get_new_frame_event_id(this->rx_frame_id)); + // read up to the length field + do{ + if((num=((CCAN *)this->comm_dev)->get_num_data(this->rx_frame_id))==0) + { + this->event_server->wait_all(events,500); + num=((CCAN *)this->comm_dev)->get_num_data(this->rx_frame_id); + } + if((read+num)>1024) + { + ((CCAN *)this->comm_dev)->read(this->rx_frame_id,&data_int[read],1024-read); + read=1024; + } + else + { + if(num != 0) + ((CCAN *)this->comm_dev)->read(this->rx_frame_id,&data_int[read],num); + read+=num; + } + this->sync_packet_v1(data_int,read,&start); + }while((read-start)<4); + length=data_int[start+3]+4; + // read the remaining of the packet + while((read-start)<length) + { + if((num=((CCAN *)this->comm_dev)->get_num_data(this->rx_frame_id))==0) + { + this->event_server->wait_all(events,500); + num=((CCAN *)this->comm_dev)->get_num_data(this->rx_frame_id); + } + if((read-start+num)>length) + { + ((CCAN *)this->comm_dev)->read(this->rx_frame_id,&data_int[read],length-read); + read=length; + } + else + { + if(num != 0) + ((CCAN *)this->comm_dev)->read(this->rx_frame_id,&data_int[read],num); + read+=num; + } + } + // check the checksum + if(CDynamixelServer::compute_checksum_v1(&data_int[start],length)!=0x00) + { + /* handle exceptions */ + throw CDynamixelException(_HERE_,"Invalid Checksum",this->node_address); + } + // byte destuffing + // return the error + if(length>6) + { + *data=new unsigned char[length-6]; + memcpy(*data,&data_int[start+5],length-6); + *len=length-6; + } + else + { + *data=NULL; + *len=0; + } + return data_int[start+4]; + }catch(CEventTimeoutException &e){ + throw e; + }catch(CException &e){ + throw e; + } + } + else + { + /* handle exceptions */ + throw CDynamixelException(_HERE_,"The communication device is not properly configured",this->get_id()); + } +} + +unsigned char CDynamixelCAN::receive_status_packet_v2(unsigned char **data,unsigned short int *len) +{ + std::list<std::string> events; + unsigned char data_int[1024]; + int num=0,read=0,length=0,start=0; + unsigned short int crc; + + if(this->comm_dev!=NULL) + { + try{ + events.push_back(((CCAN *)this->comm_dev)->get_new_frame_event_id(this->rx_frame_id)); + // read up to the length field + do{ + if((num=((CCAN *)this->comm_dev)->get_num_data(this->rx_frame_id))==0) + { + this->event_server->wait_all(events,300); + num=((CCAN *)this->comm_dev)->get_num_data(this->rx_frame_id); + } + if((read+num)>1024) + { + ((CCAN *)this->comm_dev)->read(this->rx_frame_id,&data_int[read],1024-read); + read=1024; + } + else + { + + if(num!=0) + ((CCAN *)this->comm_dev)->read(this->rx_frame_id,&data_int[read],num); + read+=num; + } + this->sync_packet_v2(data_int,read,&start); + }while((read-start)<7); + length=data_int[start+5]+data_int[start+6]*256+7; + // read the remaining of the packet + while((read-start)<length) + { + if((num=((CCAN *)this->comm_dev)->get_num_data(this->rx_frame_id))==0) + { + this->event_server->wait_all(events,100); + num=this->comm_dev->get_num_data(); + } + if((read-start+num)>1024) + { + ((CCAN *)this->comm_dev)->read(this->rx_frame_id,&data_int[read],1024-read); + read=1024; + } + else + { + if(num != 0) + ((CCAN *)this->comm_dev)->read(this->rx_frame_id,&data_int[read],num); + read+=num; + } + } + // check the checksum + crc=CDynamixelServer::compute_checksum_v2(&data_int[start],length-2); + if((crc%256)!=data_int[start+length-2] || (crc/256)!=data_int[start+length-1]) + { + /* handle exceptions */ + throw CDynamixelException(_HERE_,"Invalid Checksum",this->node_address); + } + // return the error + if(length>10) + { + *data=new unsigned char[length-11]; + memcpy(*data,&data_int[start+9],length-11); + *len=length-11; + } + else + { + *data=NULL; + *len=0; + } + return data_int[start+8]; + }catch(CEventTimeoutException &e){ + throw e; + }catch(CException &e){ + throw e; + } + } + else + { + /* handle exceptions */ + throw CDynamixelException(_HERE_,"The communication device is not properly configured",this->node_address); + } +} + +CDynamixelCAN::~CDynamixelCAN() +{ + +} + + diff --git a/src/dynamixelserver_can.cpp b/src/dynamixelserver_can.cpp new file mode 100644 index 0000000000000000000000000000000000000000..be8a152036ba76bb0e42ad649c83f4b755bc7c4c --- /dev/null +++ b/src/dynamixelserver_can.cpp @@ -0,0 +1,430 @@ +#include "dynamixelserver_can.h" +#include "dynamixel_can.h" +#include "dynamixelexceptions.h" +#include "eventexceptions.h" +//#include "pal_can.h" +#include "can.h" +#include <sstream> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <iostream> + +CDynamixelServerCAN *CDynamixelServerCAN::pinstance=NULL; + +CDynamixelServerCAN::CDynamixelServerCAN() +{ + this->bus_info.device=""; + this->bus_info.tx_frame_id=-1; + this->bus_info.rx_frame_id=-1; + this->current_len=0; + this->current_inst=(dyn_inst_t)0x00; +} + +CDynamixelServerCAN::CDynamixelServerCAN(const CDynamixelServerCAN& object) +{ + +} + +CDynamixelServerCAN& CDynamixelServerCAN::operator = (const CDynamixelServerCAN& object) +{ + return *this->pinstance; +} + +void CDynamixelServerCAN::send_instruction_packet_v1(dyn_inst_t inst,unsigned char *data,unsigned char len,unsigned char id) +{ + unsigned char *packet=NULL; + int i,length; + + switch(inst) + { + case dyn_action: id=0xFE;// set the broadcast address + case dyn_ping: length=6; + packet=new unsigned char[length]; + if(len!=0) + throw CDynamixelServerException(_HERE_,"Invalid data length"); + break; + case dyn_bulk_read: + case dyn_bulk_write: + case dyn_sync_read: + case dyn_sync_write: id=0xFE; + length=6+len; + packet=new unsigned char[length]; + break; + default: throw CDynamixelServerException(_HERE_,"Instruction not supported"); + break; + } + packet[0]=0xFF; + packet[1]=0xFF; + packet[2]=id; + packet[3]=len+2; + packet[4]=inst; + for(i=0;i<len;i++) + packet[5+i]=data[i]; + // byte stuffing + packet[length-1]=0x00; + packet[length-1]=this->compute_checksum_v1(packet,length); + if(this->comm_dev!=NULL) + { + try{ + ((CCAN *)this->comm_dev)->write(this->bus_info.tx_frame_id,packet,length); + if(packet!=NULL) + delete[] packet; + }catch(CException &e){ + throw e; + } + } + else + { + if(packet!=NULL) + delete[] packet; + /* handle exceptions */ + throw CDynamixelServerException(_HERE_,"The communication device is not properly configured"); + } +} + +void CDynamixelServerCAN::send_instruction_packet_v2(dyn_inst_t inst,unsigned char *data,unsigned short int len,unsigned char id) +{ + unsigned char *packet=NULL; + int i,length,crc; + + switch(inst) + { + case dyn_action: id=0xFE;// set the broadcast address + case dyn_ping: length=10; + packet=new unsigned char[length]; + if(len!=0) + throw CDynamixelServerException(_HERE_,"Invalid data length"); + break; + case dyn_bulk_read: + case dyn_bulk_write: + case dyn_sync_read: + case dyn_sync_write: id=0xFE; + length=10+len; + packet=new unsigned char[length]; + break; + default: throw CDynamixelServerException(_HERE_,"Instruction not supported"); + break; + } + packet[0]=0xFF; + packet[1]=0xFF; + packet[2]=0xFD; + packet[3]=0x00; + packet[4]=id; + packet[5]=(len+3)%256; + packet[6]=(len+3)/256; + packet[7]=inst; + for(i=0;i<len;i++) + packet[8+i]=data[i]; + packet[length-2]=0x00; + packet[length-1]=0x00; + crc=this->compute_checksum_v2(packet,length-2); + packet[length-2]=crc%256; + packet[length-1]=crc/256; + if(this->comm_dev!=NULL) + { + try{ + ((CCAN *)this->comm_dev)->write(this->bus_info.tx_frame_id,packet,length); + if(packet!=NULL) + delete[] packet; + }catch(CException &e){ + throw e; + } + } + else + { + if(packet!=NULL) + delete[] packet; + /* handle exceptions */ + throw CDynamixelServerException(_HERE_,"The communication device is not properly configured"); + } +} + +unsigned char CDynamixelServerCAN::receive_status_packet_v1(unsigned char **data,unsigned char *len) +{ + std::list<std::string> events; + unsigned char data_int[1024]; + int num=0,read=0,length,start=0; + + if(this->current_inst==dyn_write) + { + *data=NULL; + *len=0; + return 0; + } + if(this->comm_dev!=NULL) + { + try{ + events.push_back(((CCAN *)this->comm_dev)->get_new_frame_event_id(this->bus_info.rx_frame_id)); + // read up to the length field + do{ + if((num=((CCAN *)this->comm_dev)->get_num_data(this->bus_info.rx_frame_id))==0) + { + this->event_server->wait_all(events,200); + num=((CCAN *)this->comm_dev)->get_num_data(this->bus_info.rx_frame_id); + } + if((read+num)>1024) + { + ((CCAN *)this->comm_dev)->read(this->bus_info.rx_frame_id,&data_int[read],1024-read); + read=1024; + } + else + { + ((CCAN *)this->comm_dev)->read(this->bus_info.rx_frame_id,&data_int[read],num); + read+=num; + } + this->sync_packet_v1(data_int,read,&start); + }while((read-start)<4); + length=data_int[start+3]+4; + // read the remaining of the packet + while((read-start)<length) + { + if((num=((CCAN *)this->comm_dev)->get_num_data(this->bus_info.rx_frame_id))==0) + { + this->event_server->wait_all(events,200); + num=((CCAN *)this->comm_dev)->get_num_data(this->bus_info.rx_frame_id); + } + if((read-start+num)>length) + { + ((CCAN *)this->comm_dev)->read(this->bus_info.rx_frame_id,&data_int[read],length-read); + read=length; + } + else + { + ((CCAN *)this->comm_dev)->read(this->bus_info.rx_frame_id,&data_int[read],num); + read+=num; + } + } + // check the checksum + if(CDynamixelServer::compute_checksum_v1(&data_int[start],length)!=0x00) + { + /* handle exceptions */ + throw CDynamixelServerException(_HERE_,"Invalid Checksum"); + } + // byte destuffing + // return the error + if(length>6) + { + *data=new unsigned char[length-6]; + memcpy(*data,&data_int[start+5],length-6); + *len=length-6; + } + else + { + *data=NULL; + *len=0; + } + return data_int[start+4]; + }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 CDynamixelServerCAN::receive_status_packet_v2(unsigned char **data,unsigned short int *len) +{ + std::list<std::string> events; + unsigned char data_int[1024]; + int num=0,read=0,length,start=0; + unsigned short int crc; + + if(this->comm_dev!=NULL) + { + try{ + events.push_back(((CCAN *)this->comm_dev)->get_new_frame_event_id(this->bus_info.rx_frame_id)); + // read up to the length field + do{ + if((num=((CCAN *)this->comm_dev)->get_num_data(this->bus_info.rx_frame_id))==0) + { + this->event_server->wait_all(events,200); + num=((CCAN *)this->comm_dev)->get_num_data(this->bus_info.rx_frame_id); + } + if((read+num)>1024) + { + ((CCAN *)this->comm_dev)->read(this->bus_info.rx_frame_id,&data_int[read],1024-read); + read=1024; + } + else + { + if(num != 0) + ((CCAN *)this->comm_dev)->read(this->bus_info.rx_frame_id,&data_int[read],num); + read+=num; + } + this->sync_packet_v2(data_int,read,&start); + }while((read-start)<7); + length=data_int[start+5]+data_int[start+6]*256+7; + // read the remaining of the packet + while((read-start)<length) + { + if((num=((CCAN *)this->comm_dev)->get_num_data(this->bus_info.rx_frame_id))==0) + { + this->event_server->wait_all(events,200); + num=((CCAN *)this->comm_dev)->get_num_data(this->bus_info.rx_frame_id); + } + if((read-start+num)>length) + { + ((CCAN *)this->comm_dev)->read(this->bus_info.rx_frame_id,&data_int[read],length-read); + read=length; + } + else + { + ((CCAN *)this->comm_dev)->read(this->bus_info.rx_frame_id,&data_int[read],num); + read+=num; + } + } + // check the checksum + crc=this->compute_checksum_v2(&data_int[start],length-2); + if((crc%256)!=data_int[start+length-2] || (crc/256)!=data_int[start+length-1]) + { + /* handle exceptions */ + throw CDynamixelServerException(_HERE_,"Invalid Checksum"); + } + // return the error + if(length>11) + { + *data=new unsigned char[length-11]; + memcpy(*data,&data_int[start+9],length-11); + *len=length-11; + } + else + { + *data=NULL; + *len=0; + } + return data_int[start+8]; + }catch(CEventTimeoutException &e){ + throw e; + }catch(CException &e){ + throw e; + } + } + else + { + /* handle exceptions */ + throw CDynamixelServerException(_HERE_,"The communication device is not properly configured"); + } +} + +void CDynamixelServerCAN::sync_packet_v1(unsigned char *data,unsigned int length,int *start) +{ + +} + +void CDynamixelServerCAN::sync_packet_v2(unsigned char *data,unsigned int length,int *start) +{ + +} + +CDynamixelServerCAN *CDynamixelServerCAN::instance(void) +{ + if (CDynamixelServerCAN::pinstance == NULL) + { + CDynamixelServerCAN::pinstance = new CDynamixelServerCAN(); // Creamos la instancia + } + return CDynamixelServerCAN::pinstance; // Retornamos la dirección de la instancia +} + +void CDynamixelServerCAN::config_bus(const std::string &device, int baudrate,unsigned int tx_frame_id,unsigned int rx_frame_id) +{ + std::size_t pos; + std::string can_name; + + if((pos=device.find_last_of("/"))==std::string::npos) + can_name="dynamixel_can_"+device; + else + can_name="dynamixel_can_"+device.substr(pos+1); + this->comm_dev=(CComm *)new CCAN(can_name); + ((CCAN *)this->comm_dev)->open(device); + ((CCAN *)this->comm_dev)->add_id_filter(rx_frame_id,0xFFF); + this->bus_info.device=device; + this->bus_info.tx_frame_id=tx_frame_id; + this->bus_info.rx_frame_id=rx_frame_id; +} + +#ifdef _HAVE_XSD +void CDynamixelServerCAN::config(std::string &filename) +{ +} +#endif + +std::string &CDynamixelServerCAN::get_bus_device(void) +{ + return this->bus_info.device; +} + +void CDynamixelServerCAN::set_baudrate(int baudrate) +{ + +} + +int CDynamixelServerCAN::get_baudrate(void) +{ + return 0; +} + +CDynamixel *CDynamixelServerCAN::get_device(int dev_id,dyn_version_t version) +{ + std::stringstream device_name; + CDynamixelCAN *dynamixel=NULL; + std::string name,serial; + bool updated=false; + unsigned int i=0; + + this->dynamixel_access.enter(); + if(this->comm_dev==NULL) + { + this->dynamixel_access.exit(); + /* handle exceptions */ + throw CDynamixelServerException(_HERE_,"No communication device has been initialized."); + } + this->dynamixel_access.exit(); + if(dynamixel==NULL) + { + this->dynamixel_access.enter(); + device_name.str(""); + device_name << "dynamixel_bus_" << this->comm_dev->get_id() << "_dev_" << dev_id << "_v" << version; + name=device_name.str(); + dynamixel=new CDynamixelCAN(name,this->bus_info.tx_frame_id,this->bus_info.rx_frame_id); + dynamixel->dyn_server=this; + dynamixel->comm_dev=this->comm_dev; + dynamixel->usb_access=&this->dynamixel_access; + dynamixel->node_address=dev_id; + dynamixel->version=version; + dynamixel->usb_rx_event_id=this->comm_dev->get_rx_event_id(); + if(version==dyn_version1) + { + for(i=0;i<devices_v1.size();i++) + { + if(this->devices_v1[i]==dev_id) + updated=true; + } + if(!updated) + this->devices_v1.push_back(dev_id); + } + else + { + for(i=0;i<devices_v2.size();i++) + { + if(this->devices_v2[i]==dev_id) + updated=true; + } + if(!updated) + this->devices_v2.push_back(dev_id); + } + } + this->dynamixel_access.exit(); + + return dynamixel; +} + +CDynamixelServerCAN::~CDynamixelServerCAN() +{ + +} diff --git a/src/examples/CMakeLists.txt b/src/examples/CMakeLists.txt index 666109205992fd850d7d764034bc95c210c91cd9..babdeeb17794cd780a11fdd0b9438af92aaf7920 100644 --- a/src/examples/CMakeLists.txt +++ b/src/examples/CMakeLists.txt @@ -4,6 +4,12 @@ ADD_EXECUTABLE(test_dynamixel_server test_dynamixel_server.cpp) # edit the following line to add the necessary libraries TARGET_LINK_LIBRARIES(test_dynamixel_server dynamixel) +# edit the following line to add the source code for the example and the name of the executable +ADD_EXECUTABLE(test_dynamixel_server_CAN test_dynamixel_server_CAN.cpp) + +# edit the following line to add the necessary libraries +TARGET_LINK_LIBRARIES(test_dynamixel_server_CAN dynamixel) + # edit the following line to add the source code for the example and the name of the executable ADD_EXECUTABLE(test_dynamixel_server_no_scan test_dynamixel_server_no_scan.cpp) diff --git a/src/examples/test_dynamixel_server_CAN.cpp b/src/examples/test_dynamixel_server_CAN.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6693cba0aef84e5552f7d2322b35c129c2a43397 --- /dev/null +++ b/src/examples/test_dynamixel_server_CAN.cpp @@ -0,0 +1,78 @@ +#include "eventexceptions.h" +#include "dynamixelserver_ftdi.h" +#include <iostream> +#include "dynamixelserver_can.h" +#include "dynamixel_can.h" + +std::string serial="slcan0"; + +int main(int argc, char *argv[]) +{ + CDynamixelServerCAN *dyn_server= CDynamixelServerCAN::instance(); + CEventServer *event_server=CEventServer::instance(); + int num_buses=0,baudrate=0,event_id; + std::list<std::string> events; + std::vector<int> devices; + unsigned short int model; + CDynamixelCAN *dyn_device; + unsigned int i,num_dev; + + 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(serial,1000000,0x33C,0x5BC); + dyn_server->start_scan(); + event_id=event_server->wait_first(events); + if(event_id==0) + { + num_dev=dyn_server->get_num_devices(); + std::cout << "Num. devices: " << num_dev << std::endl; + baudrate=dyn_server->get_baudrate(); + std::cout << "Baudrate: " << baudrate << " bps" << std::endl; + devices=dyn_server->get_device_ids(); + for(i=1;i<num_dev;i++) + { + std::cout << "servo " << devices[i] << std::endl; + dyn_device=(CDynamixelCAN*)dyn_server->get_device(devices[i]); + dyn_device->read_word_register(0x00,&model); + std::cout << "servo " << devices[i] << " model " << (int)model << std::endl; + dyn_server->free_device(devices[i]); + delete dyn_device; + } + } + else + std::cout << "Error while scanning the bus: " << dyn_server->get_scan_error() << std::endl; +// try{ +// dyn_server->config_bus(0,1000000); +// dyn_server->start_scan(); +// event_server->wait_first(events,2000); +// }catch(CException &e){ +// dyn_server->stop_scan(); +// std::cout << "Scanning canceled !!!" << std::endl; +// } +// /* scan for version 2 devices */ +// dyn_server->config_bus(0,1000000); +// dyn_server->start_scan(dyn_version2); +// event_id=event_server->wait_first(events); +// if(event_id==0) +// { +// num_dev=dyn_server->get_num_devices(dyn_version2); +// std::cout << "Num. devices: " << num_dev << std::endl; +// baudrate=dyn_server->get_baudrate(); +// std::cout << "Baudrate: " << baudrate << " bps" << std::endl; +// devices=dyn_server->get_device_ids(dyn_version2); +// for(i=0;i<num_dev;i++) +// { +// dyn_device=dyn_server->get_device(devices[i],dyn_version2); +// dyn_device->read_word_register(0x00,&model); +// dyn_server->free_device(devices[i],dyn_version2); +// delete dyn_device; +// } +// } +// else +// std::cout << "Error while scanning the bus: " << dyn_server->get_scan_error() << std::endl; + }catch(CException &e){ + std::cout << e.what() << std::endl; + } +// } +}