diff --git a/dynamixel_base/include/dynamixel.h b/dynamixel_base/include/dynamixel.h index f2f6182616cf27c824d68305421dc9a9310477a0..8b73f9c5db022f826b4715432de4ab606dd7923e 100755 --- a/dynamixel_base/include/dynamixel.h +++ b/dynamixel_base/include/dynamixel.h @@ -3,6 +3,13 @@ #include "dynamixel_common.h" +#define DYN_HEADER_OFF 0 +#define DYN_ID_OFF 2 +#define DYN_LENGTH_OFF 3 +#define DYN_INST_OFF 4 +#define DYN_ERROR_OFF 4 +#define DYN_DATA_OFF 5 + void dyn_copy_packet(unsigned char *source, unsigned char *destination); inline unsigned char dyn_get_id(unsigned char *packet); inline unsigned char dyn_get_length(unsigned char *packet); @@ -20,6 +27,7 @@ typedef struct{ unsigned char checksum; }TDynInst; */ +unsigned char dyn_convert_v2_inst_packet(unsigned char *source, unsigned char *destination); /* ping instruction */ void dyn_init_ping_packet(unsigned char *packet,unsigned char id); /* read instruction */ @@ -59,6 +67,7 @@ typedef struct{ }TDynStatus; */ +unsigned char dyn_convert_v2_status_packet(unsigned char *source, unsigned char *destination); void dyn_init_status_packet(unsigned char *packet,unsigned char id,TDynError error,unsigned char length,unsigned char *data); inline TDynError dyn_get_status_error(unsigned char *packet); /* read instruction status packet */ diff --git a/dynamixel_base/include/dynamixel2.h b/dynamixel_base/include/dynamixel2.h index f34c6ee81e3a0cfe7d66d7a66863612a443a0c75..f51473c7c62e342bd9f12875f184f165e9944f5b 100644 --- a/dynamixel_base/include/dynamixel2.h +++ b/dynamixel_base/include/dynamixel2.h @@ -3,6 +3,15 @@ #include "dynamixel_common.h" +#define DYN2_HEADER_OFF 0 +#define DYN2_RESERVED 3 +#define DYN2_ID_OFF 4 +#define DYN2_LENGTH_OFF 5 +#define DYN2_INST_OFF 7 +#define DYN2_ERROR_OFF 8 +#define DYN2_DATA_OFF 8 + + void dyn2_copy_packet(unsigned char *source, unsigned char *destination); inline unsigned char dyn2_get_id(unsigned char *packet); inline unsigned short int dyn2_get_length(unsigned char *packet); @@ -20,6 +29,7 @@ typedef struct{ unsigned char checksum; }TDynInst; */ +unsigned char dyn2_convert_v1_inst_packet(unsigned char *source, unsigned char *destination); /* ping instruction */ void dyn2_init_ping_packet(unsigned char *packet,unsigned char id); /* read instruction */ @@ -65,6 +75,7 @@ typedef struct{ }TDynStatus; */ +unsigned char dyn2_convert_v1_status_packet(TDynInstruction inst,unsigned char *source, unsigned char *destination); void dyn2_init_status_packet(unsigned char *packet,unsigned char id,TDynError error,unsigned short int length,unsigned char *data); inline TDynError dyn2_get_status_error(unsigned char *packet); /* read instruction status packet */ diff --git a/dynamixel_base/include/dynamixel_common.h b/dynamixel_base/include/dynamixel_common.h index d8310e95182a860d7fb9ac461faa832717e9887d..ea125c550f3593b27a54b4f6469a947ac5f14446 100644 --- a/dynamixel_base/include/dynamixel_common.h +++ b/dynamixel_base/include/dynamixel_common.h @@ -3,6 +3,8 @@ #define MAX_DATA_LENGTH 255 +#define MAX_HEADER_LENGTH 6 + // errors #define DYN_SUCCESS 0 #define DYN_BAD_FORMAT 1 diff --git a/dynamixel_base/include/dynamixel_master.h b/dynamixel_base/include/dynamixel_master.h index 87eb846ad79a3cea7040373196e75542711feda8..52887cc38689835f8916032d8c0018ad1b96d2e7 100644 --- a/dynamixel_base/include/dynamixel_master.h +++ b/dynamixel_base/include/dynamixel_master.h @@ -10,6 +10,7 @@ typedef struct { TComm *comm_dev; + TDynVersion version; unsigned char tx_buffer[MAX_TX_BUFFER_LEN]; unsigned char rx_buffer[MAX_RX_BUFFER_LEN]; return_level_t return_level; @@ -23,7 +24,7 @@ typedef struct }TDynamixelMaster; /* public functions */ -void dyn_master_init(TDynamixelMaster *master,TComm *dev); +void dyn_master_init(TDynamixelMaster *master,TComm *dev,TDynVersion version); void dyn_master_set_rx_timeout(TDynamixelMaster *master,unsigned short int timeout_ms); inline void dyn_master_set_return_level(TDynamixelMaster *master,return_level_t level); inline return_level_t dyn_master_get_return_level(TDynamixelMaster *master); diff --git a/dynamixel_base/include/dynamixel_slave.h b/dynamixel_base/include/dynamixel_slave.h index 34ddc8e38a795d033e12dd26f6dbbb53f08d9612..5e028f8523984638c36c727f64c0d2d57330a233 100644 --- a/dynamixel_base/include/dynamixel_slave.h +++ b/dynamixel_base/include/dynamixel_slave.h @@ -3,6 +3,7 @@ #include "comm.h" #include "dynamixel.h" +#include "dynamixel2.h" #ifndef MAX_DYN_SLAVE_TX_BUFFER_LEN #define MAX_DYN_SLAVE_TX_BUFFER_LEN 1024 @@ -19,11 +20,13 @@ typedef struct { TComm *comm_dev; + TDynVersion version; unsigned char address; unsigned char return_delay; return_level_t return_level; unsigned char packet_ready; unsigned char received_bytes; + unsigned short int op_length; unsigned char tx_buffer[MAX_DYN_SLAVE_TX_BUFFER_LEN]; unsigned char rx_buffer[MAX_DYN_SLAVE_RX_BUFFER_LEN]; unsigned short int reg_address; @@ -40,16 +43,18 @@ typedef struct unsigned char (*on_read)(unsigned short int address,unsigned short int length,unsigned char *data); unsigned char (*on_write)(unsigned short int address,unsigned short int length,unsigned char *data); unsigned char (*on_reset)(void); + unsigned char (*on_relay)(TDynVersion version,unsigned char *inst_pkt,unsigned char *status_pkt); }TDynamixelSlave; /* public functions */ -void dyn_slave_init(TDynamixelSlave *slave,TComm *dev,unsigned char address); +void dyn_slave_init(TDynamixelSlave *slave,TComm *dev,unsigned char address,TDynVersion version); inline void dyn_slave_set_address(TDynamixelSlave *slave,unsigned char address); inline unsigned char dyn_slave_get_address(TDynamixelSlave *slave); inline void dyn_slave_set_return_delay(TDynamixelSlave *slave,unsigned char delay); inline unsigned char dyn_slave_get_return_delay(TDynamixelSlave *slave); inline void dyn_slave_set_return_level(TDynamixelSlave *slave,return_level_t level); inline return_level_t dyn_slave_get_return_level(TDynamixelSlave *slave); +inline TDynVersion dyn_slave_get_version(TDynamixelSlave *slave); void dyn_slave_loop(TDynamixelSlave *slave); diff --git a/dynamixel_base/src/dynamixel.c b/dynamixel_base/src/dynamixel.c index 5ab4ec6a69ea220a83cad562f7c1c7496ace1362..8a72020d537468250434b8229995895bd09335ef 100755 --- a/dynamixel_base/src/dynamixel.c +++ b/dynamixel_base/src/dynamixel.c @@ -1,13 +1,5 @@ #include "dynamixel.h" - -#define MAX_HEADER_LENGTH 6 - -#define DYN_HEADER_OFF 0 -#define DYN_ID_OFF 2 -#define DYN_LENGTH_OFF 3 -#define DYN_INST_OFF 4 -#define DYN_ERROR_OFF 4 -#define DYN_DATA_OFF 5 +#include "dynamixel2.h" // provate functions void dyn_set_checksum(unsigned char *packet) @@ -63,6 +55,26 @@ inline TDynInstruction dyn_get_instruction(unsigned char *packet) return packet[DYN_INST_OFF]; } +unsigned char dyn_convert_v2_inst_packet(unsigned char *source, unsigned char *destination) +{ + unsigned char i; + + if(dyn2_get_length(source)>255) + return 0x00; + else + { + destination[DYN_HEADER_OFF]=0xFF; + destination[DYN_HEADER_OFF+1]=0xFF; + destination[DYN_ID_OFF]=source[DYN2_ID_OFF]; + destination[DYN_LENGTH_OFF]=source[DYN2_LENGTH_OFF]; + destination[DYN_INST_OFF]=source[DYN2_INST_OFF]; + for(i=0;i<destination[DYN_LENGTH_OFF];i++) + destination[DYN_DATA_OFF+i]=source[DYN2_DATA_OFF+i]; + dyn_set_checksum(destination); + return 0x01; + } +} + /* ping instruction*/ void dyn_init_ping_packet(unsigned char *packet,unsigned char id) { @@ -269,6 +281,26 @@ unsigned char dyn_bulk_read_id_present(unsigned char *packet,unsigned char id,un return 0xFF; } +unsigned char dyn_convert_v2_status_packet(unsigned char *source, unsigned char *destination) +{ + unsigned char i; + + if(dyn2_get_length(source)>255) + return 0x00; + else + { + destination[DYN_HEADER_OFF]=0xFF; + destination[DYN_HEADER_OFF+1]=0xFF; + destination[DYN_ID_OFF]=source[DYN2_ID_OFF]; + destination[DYN_LENGTH_OFF]=source[DYN2_LENGTH_OFF]; + destination[DYN_ERROR_OFF]=source[DYN2_ERROR_OFF]; + for(i=0;i<destination[DYN_LENGTH_OFF];i++) + destination[DYN_DATA_OFF+i]=source[DYN2_DATA_OFF+i]; + dyn_set_checksum(destination); + return 0x01; + } +} + void dyn_init_status_packet(unsigned char *packet,unsigned char id,TDynError error,unsigned char length,unsigned char *data) { unsigned char i; diff --git a/dynamixel_base/src/dynamixel2.c b/dynamixel_base/src/dynamixel2.c index 7731e5e933ebd545578e07627dbeafbf06bd80fe..b85db07a219a7e99d4a6e17114b40f7b73c6f865 100644 --- a/dynamixel_base/src/dynamixel2.c +++ b/dynamixel_base/src/dynamixel2.c @@ -1,15 +1,6 @@ +#include "dynamixel.h" #include "dynamixel2.h" -#define MAX_HEADER_LENGTH 6 - -#define DYN2_HEADER_OFF 0 -#define DYN2_RESERVED 3 -#define DYN2_ID_OFF 4 -#define DYN2_LENGTH_OFF 5 -#define DYN2_INST_OFF 7 -#define DYN2_ERROR_OFF 8 -#define DYN2_DATA_OFF 8 - const unsigned short crc_table[256] = { 0x0000, 0x8005, 0x800F, 0x000A, 0x801B, 0x001E, 0x0014, 0x8011, 0x8033, 0x0036, 0x003C, 0x8039, 0x0028, 0x802D, 0x8027, 0x0022, @@ -45,7 +36,7 @@ const unsigned short crc_table[256] = { 0x8213, 0x0216, 0x021C, 0x8219, 0x0208, 0x820D, 0x8207, 0x0202 }; -// provate functions +// private functions void dyn2_set_checksum(unsigned char *packet) { unsigned short int crc_accum=0x0000,i,j,length; @@ -101,6 +92,25 @@ inline TDynInstruction dyn2_get_instruction(unsigned char *packet) return packet[DYN2_INST_OFF]; } +unsigned char dyn2_convert_v1_inst_packet(unsigned char *source, unsigned char *destination) +{ + unsigned char i; + + destination[DYN2_HEADER_OFF]=0xFF; + destination[DYN2_HEADER_OFF+1]=0xFF; + destination[DYN2_HEADER_OFF+2]=0xFD; + destination[DYN2_RESERVED]=0x00; + destination[DYN2_ID_OFF]=source[DYN_ID_OFF]; + destination[DYN2_LENGTH_OFF]=source[DYN_LENGTH_OFF]; + destination[DYN2_LENGTH_OFF+1]=0x00; + destination[DYN2_INST_OFF]=source[DYN_INST_OFF]; + for(i=0;i<source[DYN_LENGTH_OFF];i++) + destination[DYN2_DATA_OFF+i]=source[DYN_DATA_OFF+i]; + dyn2_set_checksum(destination); + + return 0x01; +} + /* ping instruction*/ void dyn2_init_ping_packet(unsigned char *packet,unsigned char id) { @@ -420,6 +430,26 @@ unsigned char dyn2_bulk_write_id_present(unsigned char *packet,unsigned char id, } /* status packet */ +unsigned char dyn2_convert_v1_status_packet(TDynInstruction inst,unsigned char *source, unsigned char *destination) +{ + unsigned char i; + + destination[DYN2_HEADER_OFF]=0xFF; + destination[DYN2_HEADER_OFF+1]=0xFF; + destination[DYN2_HEADER_OFF+2]=0xFD; + destination[DYN2_RESERVED]=0x00; + destination[DYN2_ID_OFF]=source[DYN_ID_OFF]; + destination[DYN2_LENGTH_OFF]=source[DYN_LENGTH_OFF]; + destination[DYN2_LENGTH_OFF+1]=0x00; + destination[DYN2_INST_OFF]=inst; + destination[DYN2_ERROR_OFF]=source[DYN_ERROR_OFF]; + for(i=0;i<source[DYN_LENGTH_OFF];i++) + destination[DYN2_DATA_OFF+i]=source[DYN_DATA_OFF+i]; + dyn2_set_checksum(destination); + + return 0x01; +} + void dyn2_init_status_packet(unsigned char *packet,unsigned char id,TDynError error,unsigned short int length,unsigned char *data) { unsigned char i; diff --git a/dynamixel_base/src/dynamixel_master.c b/dynamixel_base/src/dynamixel_master.c index 0d38df5832a5ca9dc93e747e31ba1d8d710a2ca9..ad3a4431364737d1c05bfc36c2d37b6369152791 100644 --- a/dynamixel_base/src/dynamixel_master.c +++ b/dynamixel_base/src/dynamixel_master.c @@ -108,8 +108,16 @@ unsigned char dyn_master_send(TDynamixelMaster *master) if((error=dyn_master_wait_transmission(master))!=DYN_SUCCESS) return error; // set the DMA transfer - comm_send_dma(master->comm_dev,master->tx_buffer,dyn_get_length(master->tx_buffer)+4); - return DYN_SUCCESS; + if(master->version==DYN_VER1) + { + comm_send_dma(master->comm_dev,master->tx_buffer,dyn_get_length(master->tx_buffer)+4); + return DYN_SUCCESS; + } + else + { + comm_send_dma(master->comm_dev,master->tx_buffer,dyn2_get_length(master->tx_buffer)+7); + return DYN_SUCCESS; + } } unsigned char dyn_master_wait_reception(TDynamixelMaster *master) @@ -142,13 +150,14 @@ unsigned char dyn_master_wait_reception(TDynamixelMaster *master) } /* public functions */ -void dyn_master_init(TDynamixelMaster *master,TComm *dev) +void dyn_master_init(TDynamixelMaster *master,TComm *dev,TDynVersion version) { /* assign communication functions */ dev->irq_receive_cb=dyn_master_irq_receive_cb; dev->dma_send_cb=dyn_master_dma_send_cb; dev->dma_receive_cb=dyn_master_dma_receive_cb; master->comm_dev=dev; + master->version=version; dev->data=master; /* initialize the internal callbacks */ master->set_tx_mode=dummy_dyn_master_set_tx_mode; diff --git a/dynamixel_base/src/dynamixel_slave.c b/dynamixel_base/src/dynamixel_slave.c index 99a3f2f756c77f5d41782988f43561234e29bfbe..0dc791c52a28029911f0ed276dabb26472e92796 100644 --- a/dynamixel_base/src/dynamixel_slave.c +++ b/dynamixel_base/src/dynamixel_slave.c @@ -23,19 +23,51 @@ unsigned char dyn_slave_irq_receive_cb(void *dyn_slave,unsigned char byte) else dyn->received_bytes--; break; - case 2: if(byte!=0xFF) + case 2: if(byte==0xFD)// version 2 header + { + if(dyn->version==DYN_VER2)// the module is configured for version 2 + { + dyn->rx_buffer[dyn->received_bytes]=byte; + dyn->received_bytes++; + } + else + dyn->received_bytes=0;// ignore packet and restart synchronization + } + else if(byte!=0xFF) { dyn->rx_buffer[dyn->received_bytes]=byte; dyn->received_bytes++; } break; case 3: dyn->rx_buffer[dyn->received_bytes]=byte; + if(dyn->version==DYN_VER1) + { + dyn->op_length=byte; + dyn->received_bytes=0; + /* finish reception by IRQ */ + comm_cancel_irq_receive(dyn->comm_dev); + /* enable dma RX */ + comm_receive_dma(dyn->comm_dev,&dyn->rx_buffer[4],dyn->op_length); + } + else + dyn->received_bytes++; + break; + case 4: dyn->rx_buffer[dyn->received_bytes]=byte; + dyn->received_bytes++; + break; + case 5: dyn->rx_buffer[dyn->received_bytes]=byte; + dyn->received_bytes++; + dyn->op_length=byte; + break; + case 6: dyn->rx_buffer[dyn->received_bytes]=byte; + dyn->received_bytes++; + dyn->op_length+=(byte<<8); dyn->received_bytes=0; /* finish reception by IRQ */ comm_cancel_irq_receive(dyn->comm_dev); /* enable dma RX */ - comm_receive_dma(dyn->comm_dev,&dyn->rx_buffer[4],byte); - break; + comm_receive_dma(dyn->comm_dev,&dyn->rx_buffer[7],dyn->op_length); + break; default: break; } @@ -94,29 +126,314 @@ unsigned char dummy_dyn_slave_on_reset(void) return 0x00; } -void dyn_slave_send_status_packet(TDynamixelSlave *slave,unsigned char error,unsigned char length, unsigned char *data) +unsigned char dummy_dyn_slave_on_relay(TDynVersion version,unsigned char *inst_pkt,unsigned char *status_pkt) +{ + return 0x00; +} + + +void dyn_slave_send_status_packet(TDynamixelSlave *slave,unsigned char error,unsigned short int length, unsigned char *data) { // wait until the previous transmission has ended (if any) while(comm_is_send_done(slave->comm_dev)==COMM_BUSY); if(slave->return_delay>0) if(slave->comm_dev->time!=0x00000000) time_delay_us(slave->comm_dev->time,slave->return_delay<<1); - // create the status packet - dyn_init_status_packet(slave->tx_buffer,slave->address,error,length,data); - // set the tx mode, if necessary - slave->set_tx_mode(); - // start transmission by DMA - comm_send_dma(slave->comm_dev,slave->tx_buffer,dyn_get_length(slave->tx_buffer)+4); + if(slave->version==DYN_VER1) + { + // create the status packet + dyn_init_status_packet(slave->tx_buffer,slave->address,error,length,data); + // set the tx mode, if necessary + slave->set_tx_mode(); + // start transmission by DMA + comm_send_dma(slave->comm_dev,slave->tx_buffer,dyn_get_length(slave->tx_buffer)+4); + } + else + { + // create the status packet + dyn2_init_status_packet(slave->tx_buffer,slave->address,error,length,data); + // set the tx mode, if necessary + slave->set_tx_mode(); + // start transmission by DMA + comm_send_dma(slave->comm_dev,slave->tx_buffer,dyn2_get_length(slave->tx_buffer)+7); + } +} + +void dyn_v1_slave_loop(TDynamixelSlave *slave) +{ + static unsigned char data[MAX_DYN_SLAVE_TX_BUFFER_LEN],error,length,address,prev_id,id; + + id=dyn_get_id(slave->rx_buffer); + if(id==slave->address || id==DYN_BROADCAST_ID)// the packet is addressed to this device or it is a broadcast + { + // check the packet checksum + if(dyn_check_checksum(slave->rx_buffer)==0xFF)// the incomming packet is okay + { + // process the packet + switch(dyn_get_instruction(slave->rx_buffer)) + { + case DYN_PING: slave->on_ping(); + if(id!=DYN_BROADCAST_ID) + dyn_slave_send_status_packet(slave,DYN_NO_ERROR,0,data); + break; + case DYN_READ: error=slave->on_read(dyn_get_read_address(slave->rx_buffer),dyn_get_read_length(slave->rx_buffer),data); + if(slave->return_level!=no_return && id!=DYN_BROADCAST_ID) + { + if(error==DYN_NO_ERROR) + dyn_slave_send_status_packet(slave,DYN_NO_ERROR,dyn_get_read_length(slave->rx_buffer),data); + else + dyn_slave_send_status_packet(slave,DYN_INST_ERROR,0,data); + } + break; + case DYN_WRITE: length=dyn_get_write_data(slave->rx_buffer,data); + error=slave->on_write(dyn_get_write_address(slave->rx_buffer),length,data); + if(slave->return_level==return_all && id!=DYN_BROADCAST_ID) + { + if(error==DYN_NO_ERROR) + dyn_slave_send_status_packet(slave,DYN_NO_ERROR,0,data); + else + dyn_slave_send_status_packet(slave,DYN_INST_ERROR,0,data); + } + break; + case DYN_REG_WRITE: slave->reg_length=dyn_get_reg_write_data(slave->rx_buffer,slave->reg_buffer); + slave->reg_address=dyn_get_reg_write_address(slave->rx_buffer); + if(slave->return_level==return_all && id!=DYN_BROADCAST_ID) + dyn_slave_send_status_packet(slave,DYN_NO_ERROR,0,data); + break; + case DYN_ACTION: if(slave->reg_address!=0xFFFF) + { + error=slave->on_write(slave->reg_address,slave->reg_length,slave->reg_buffer); + slave->reg_address=0xFFFF; + } + else + if(slave->return_level==return_all && id!=DYN_BROADCAST_ID) + dyn_slave_send_status_packet(slave,DYN_INST_ERROR,0,data); + break; + case DYN_RESET: + break; + case DYN_SYNC_READ: dyn_slave_send_status_packet(slave,DYN_INST_ERROR,0,data); + break; + case DYN_SYNC_WRITE: if(dyn_sync_write_id_present(slave->rx_buffer,slave->address,&address,&length,data))// the device is addressed + error=slave->on_write(address,length,data); + break; + case DYN_BULK_READ: prev_id=dyn_bulk_read_id_present(slave->rx_buffer,slave->address,&address,&length); + if(prev_id!=0xFF) + { + if(prev_id==0x00)// first device to answer + { + error=slave->on_read(address,length,data); + if(error==DYN_NO_ERROR) + dyn_slave_send_status_packet(slave,DYN_NO_ERROR,length,data); + else + dyn_slave_send_status_packet(slave,DYN_INST_ERROR,0,data); + } + else// wait for the previous device in the sequence to send its data + { + slave->sync_bulk_address=address; + slave->sync_bulk_length=length; + slave->sync_bulk_prev_id=prev_id; + slave->bulk_read_pending=0x01; + } + } + break; + case DYN_BULK_WRITE: dyn_slave_send_status_packet(slave,DYN_INST_ERROR,0,data); + break; + default: + break; + } + } + else + { + // send a checksum error answer + if(dyn_get_id(slave->rx_buffer)!=DYN_BROADCAST_ID) + dyn_slave_send_status_packet(slave,DYN_CHECKSUM_ERROR,0,0x00); + } + } + else + { + if(slave->bulk_read_pending) + { + if(id==slave->sync_bulk_prev_id) + { + slave->bulk_read_pending=0x00; + error=slave->on_read(slave->sync_bulk_address,slave->sync_bulk_length,data); + if(error==DYN_NO_ERROR) + dyn_slave_send_status_packet(slave,DYN_NO_ERROR,slave->sync_bulk_length,data); + else + dyn_slave_send_status_packet(slave,DYN_INST_ERROR,0,data); + } + } + else// the packet is addressed to another device, so relay it + { + if(slave->on_relay(slave->version,slave->rx_buffer,slave->tx_buffer)) + { + // set the tx mode, if necessary + slave->set_tx_mode(); + // start transmission by DMA + comm_send_dma(slave->comm_dev,slave->tx_buffer,dyn_get_length(slave->tx_buffer)+4); + } + } + } +} + +void dyn_v2_slave_loop(TDynamixelSlave *slave) +{ + static unsigned char data[MAX_DYN_SLAVE_TX_BUFFER_LEN],error,prev_id,id; + static unsigned short int length,address; + + id=dyn2_get_id(slave->rx_buffer); + if(id==slave->address || id==DYN_BROADCAST_ID)// the packet is addressed to this device or it is a broadcast + { + // check the packet checksum + if(dyn2_check_checksum(slave->rx_buffer)==0xFF)// the incomming packet is okay + { + // process the packet + switch(dyn2_get_instruction(slave->rx_buffer)) + { + case DYN_PING: slave->on_ping(); + if(id!=DYN_BROADCAST_ID) + dyn_slave_send_status_packet(slave,DYN_NO_ERROR,0,data); + break; + case DYN_READ: error=slave->on_read(dyn2_get_read_address(slave->rx_buffer),dyn2_get_read_length(slave->rx_buffer),data); + if(slave->return_level!=no_return && id!=DYN_BROADCAST_ID) + { + if(error==DYN_NO_ERROR) + dyn_slave_send_status_packet(slave,DYN_NO_ERROR,dyn2_get_read_length(slave->rx_buffer),data); + else + dyn_slave_send_status_packet(slave,DYN_INST_ERROR,0,data); + } + break; + case DYN_WRITE: length=dyn2_get_write_data(slave->rx_buffer,data); + error=slave->on_write(dyn2_get_write_address(slave->rx_buffer),length,data); + if(slave->return_level==return_all && id!=DYN_BROADCAST_ID) + { + if(error==DYN_NO_ERROR) + dyn_slave_send_status_packet(slave,DYN_NO_ERROR,0,data); + else + dyn_slave_send_status_packet(slave,DYN_INST_ERROR,0,data); + } + break; + case DYN_REG_WRITE: slave->reg_length=dyn2_get_reg_write_data(slave->rx_buffer,slave->reg_buffer); + slave->reg_address=dyn2_get_reg_write_address(slave->rx_buffer); + if(slave->return_level==return_all && id!=DYN_BROADCAST_ID) + dyn_slave_send_status_packet(slave,DYN_NO_ERROR,0,data); + break; + case DYN_ACTION: if(slave->reg_address!=0xFFFF) + { + error=slave->on_write(slave->reg_address,slave->reg_length,slave->reg_buffer); + slave->reg_address=0xFFFF; + } + else + if(slave->return_level==return_all && id!=DYN_BROADCAST_ID) + dyn_slave_send_status_packet(slave,DYN_INST_ERROR,0,data); + break; + case DYN_RESET: + break; + case DYN_SYNC_READ: prev_id=dyn2_sync_read_id_present(slave->rx_buffer,slave->address,&address,&length); + if(prev_id!=0xFF) + { + if(prev_id==0x00)// first device to answer + { + error=slave->on_read(address,length,data); + if(error==DYN_NO_ERROR) + dyn_slave_send_status_packet(slave,DYN_NO_ERROR,length,data); + else + dyn_slave_send_status_packet(slave,DYN_INST_ERROR,0,data); + } + else// wait for the previous device in the sequence to send its data + { + slave->sync_bulk_address=address; + slave->sync_bulk_length=length; + slave->sync_bulk_prev_id=prev_id; + slave->sync_read_pending=0x01; + } + } + break; + case DYN_SYNC_WRITE: if(dyn2_sync_write_id_present(slave->rx_buffer,slave->address,&address,&length,data))// the device is addressed + error=slave->on_write(address,length,data); + break; + case DYN_BULK_READ: prev_id=dyn2_bulk_read_id_present(slave->rx_buffer,slave->address,&address,&length); + if(prev_id!=0xFF) + { + if(prev_id==0x00)// first device to answer + { + error=slave->on_read(address,length,data); + if(error==DYN_NO_ERROR) + dyn_slave_send_status_packet(slave,DYN_NO_ERROR,length,data); + else + dyn_slave_send_status_packet(slave,DYN_INST_ERROR,0,data); + } + else// wait for the previous device in the sequence to send its data + { + slave->sync_bulk_address=address; + slave->sync_bulk_length=length; + slave->sync_bulk_prev_id=prev_id; + slave->bulk_read_pending=0x01; + } + } + break; + case DYN_BULK_WRITE: if(dyn2_bulk_write_id_present(slave->rx_buffer,slave->address,&address,&length,data)) + error=slave->on_write(address,length,data); + break; + default: + break; + } + } + else + { + // send a checksum error answer + if(dyn_get_id(slave->rx_buffer)!=DYN_BROADCAST_ID) + dyn_slave_send_status_packet(slave,DYN_CHECKSUM_ERROR,0,0x00); + } + } + else + { + if(slave->bulk_read_pending) + { + if(id==slave->sync_bulk_prev_id) + { + slave->bulk_read_pending=0x00; + error=slave->on_read(slave->sync_bulk_address,slave->sync_bulk_length,data); + if(error==DYN_NO_ERROR) + dyn_slave_send_status_packet(slave,DYN_NO_ERROR,slave->sync_bulk_length,data); + else + dyn_slave_send_status_packet(slave,DYN_INST_ERROR,0,data); + } + } + else if(slave->sync_read_pending) + { + if(id==slave->sync_bulk_prev_id) + { + slave->sync_read_pending=0x00; + error=slave->on_read(slave->sync_bulk_address,slave->sync_bulk_length,data); + if(error==DYN_NO_ERROR) + dyn_slave_send_status_packet(slave,DYN_NO_ERROR,slave->sync_bulk_length,data); + else + dyn_slave_send_status_packet(slave,DYN_INST_ERROR,0,data); + } + } + else// the packet is addressed to another device, so relay it + { + if(slave->on_relay(slave->version,slave->rx_buffer,slave->tx_buffer)) + { + // set the tx mode, if necessary + slave->set_tx_mode(); + // start transmission by DMA + comm_send_dma(slave->comm_dev,slave->tx_buffer,dyn_get_length(slave->tx_buffer)+8); + } + } + } } /* public functions */ -void dyn_slave_init(TDynamixelSlave *slave,TComm *dev,unsigned char address) +void dyn_slave_init(TDynamixelSlave *slave,TComm *dev,unsigned char address,TDynVersion version) { /* assign communication functions */ dev->irq_receive_cb=dyn_slave_irq_receive_cb; dev->dma_send_cb=dyn_slave_dma_send_cb; dev->dma_receive_cb=dyn_slave_dma_receive_cb; slave->comm_dev=dev; + slave->version=version; dev->data=slave; /* initialize the internal callbacks */ slave->set_tx_mode=dummy_dyn_slave_set_tx_mode; @@ -125,6 +442,7 @@ void dyn_slave_init(TDynamixelSlave *slave,TComm *dev,unsigned char address) slave->on_read=dummy_dyn_slave_on_read; slave->on_write=dummy_dyn_slave_on_write; slave->on_reset=dummy_dyn_slave_on_reset; + slave->on_relay=dummy_dyn_slave_on_relay; /* initialize internal variables */ slave->address=address; slave->return_delay=0x00; @@ -174,115 +492,21 @@ inline return_level_t dyn_slave_get_return_level(TDynamixelSlave *slave) return slave->return_level; } -void dyn_slave_loop(TDynamixelSlave *slave) +inline TDynVersion dyn_slave_get_version(TDynamixelSlave *slave) { - unsigned char data[MAX_DYN_SLAVE_TX_BUFFER_LEN],error,length,address,prev_id,id; + return slave->version; +} +void dyn_slave_loop(TDynamixelSlave *slave) +{ if(slave->packet_ready)// check if a new instruction packet has been received { slave->packet_ready=0x00; // check address - id=dyn_get_id(slave->rx_buffer); - if(id==slave->address || id==DYN_BROADCAST_ID)// the packet is addressed to this device or it is a broadcast - { - // check the packet checksum - if(dyn_check_checksum(slave->rx_buffer)==0xFF)// the incomming packet is okay - { - // process the packet - switch(dyn_get_instruction(slave->rx_buffer)) - { - case DYN_PING: slave->on_ping(); - if(id!=DYN_BROADCAST_ID) - dyn_slave_send_status_packet(slave,DYN_NO_ERROR,0,data); - break; - case DYN_READ: error=slave->on_read(dyn_get_read_address(slave->rx_buffer),dyn_get_read_length(slave->rx_buffer),data); - if(slave->return_level!=no_return && id!=DYN_BROADCAST_ID) - { - if(error==DYN_NO_ERROR) - dyn_slave_send_status_packet(slave,DYN_NO_ERROR,dyn_get_read_length(slave->rx_buffer),data); - else - dyn_slave_send_status_packet(slave,DYN_INST_ERROR,0,data); - } - break; - case DYN_WRITE: length=dyn_get_write_data(slave->rx_buffer,data); - error=slave->on_write(dyn_get_write_address(slave->rx_buffer),length,data); - if(slave->return_level==return_all && id!=DYN_BROADCAST_ID) - { - if(error==DYN_NO_ERROR) - dyn_slave_send_status_packet(slave,DYN_NO_ERROR,0,data); - else - dyn_slave_send_status_packet(slave,DYN_INST_ERROR,0,data); - } - break; - case DYN_REG_WRITE: slave->reg_length=dyn_get_reg_write_data(slave->rx_buffer,slave->reg_buffer); - slave->reg_address=dyn_get_reg_write_address(slave->rx_buffer); - if(slave->return_level==return_all && id!=DYN_BROADCAST_ID) - dyn_slave_send_status_packet(slave,DYN_NO_ERROR,0,data); - break; - case DYN_ACTION: if(slave->reg_address!=0xFFFF) - { - error=slave->on_write(slave->reg_address,slave->reg_length,slave->reg_buffer); - slave->reg_address=0xFFFF; - } - else - if(slave->return_level==return_all && id!=DYN_BROADCAST_ID) - dyn_slave_send_status_packet(slave,DYN_INST_ERROR,0,data); - break; - case DYN_RESET: - break; - case DYN_SYNC_READ: dyn_slave_send_status_packet(slave,DYN_INST_ERROR,0,data); - break; - case DYN_SYNC_WRITE: if(dyn_sync_write_id_present(slave->rx_buffer,slave->address,&address,&length,data))// the device is addressed - error=slave->on_write(address,length,data); - break; - case DYN_BULK_READ: prev_id=dyn_bulk_read_id_present(slave->rx_buffer,slave->address,&address,&length); - if(prev_id!=0xFF) - { - if(prev_id==0x00)// first device to answer - { - error=slave->on_read(address,length,data); - if(error==DYN_NO_ERROR) - dyn_slave_send_status_packet(slave,DYN_NO_ERROR,length,data); - else - dyn_slave_send_status_packet(slave,DYN_INST_ERROR,0,data); - } - else// wait for the previous device in the sequence to send its data - { - slave->sync_bulk_address=address; - slave->sync_bulk_length=length; - slave->sync_bulk_prev_id=prev_id; - slave->bulk_read_pending=0x01; - } - } - break; - case DYN_BULK_WRITE: dyn_slave_send_status_packet(slave,DYN_INST_ERROR,0,data); - break; - default: - break; - } - } - else - { - // send a checksum error answer - if(dyn_get_id(slave->rx_buffer)!=DYN_BROADCAST_ID) - dyn_slave_send_status_packet(slave,DYN_CHECKSUM_ERROR,0,0x00); - } - } + if(slave->version==DYN_VER1) + dyn_v1_slave_loop(slave); else - { - if(slave->bulk_read_pending) - { - if(id==slave->sync_bulk_prev_id) - { - slave->bulk_read_pending=0x00; - error=slave->on_read(slave->sync_bulk_address,slave->sync_bulk_length,data); - if(error==DYN_NO_ERROR) - dyn_slave_send_status_packet(slave,DYN_NO_ERROR,slave->sync_bulk_length,data); - else - dyn_slave_send_status_packet(slave,DYN_INST_ERROR,0,data); - } - } - } + dyn_v2_slave_loop(slave); } else {