sr06.cpp
Go to the documentation of this file.
00001 
00028 #include <sr_edc_ethercat_drivers/sr06.h>
00029 
00030 #include <dll/ethercat_dll.h>
00031 #include <al/ethercat_AL.h>
00032 #include <dll/ethercat_device_addressed_telegram.h>
00033 #include <dll/ethercat_frame.h>
00034 #include <realtime_tools/realtime_publisher.h>
00035 
00036 #include <math.h>
00037 #include <sstream>
00038 #include <iomanip>
00039 #include <boost/foreach.hpp>
00040 #include <std_msgs/Int16.h>
00041 #include <math.h>
00042 #include <fcntl.h>
00043 #include <stdio.h>
00044 #include <pthread.h>
00045 #include <bfd.h>
00046 
00047 #include <sr_utilities/sr_math_utils.hpp>
00048 
00049 using namespace std;
00050 
00051 #include <sr_external_dependencies/types_for_external.h>
00052 extern "C"
00053 {
00054   #include <sr_external_dependencies/external/simplemotor-bootloader/bootloader.h>
00055 }
00056 
00057 #include <boost/static_assert.hpp>
00058 namespace is_edc_command_32_bits
00059 {
00060   //check is the EDC_COMMAND is 32bits on the computer
00061   //if not, fails
00062   BOOST_STATIC_ASSERT(sizeof(EDC_COMMAND) == 4);
00063 } // namespace is_edc_command_32_bits
00064 
00065 #define ETHERCAT_STATUS_DATA_SIZE sizeof(ETHERCAT_DATA_STRUCTURE_0200_PALM_EDC_STATUS)
00066 #define ETHERCAT_COMMAND_DATA_SIZE sizeof(ETHERCAT_DATA_STRUCTURE_0200_PALM_EDC_COMMAND)
00067 
00068 const unsigned short int SR06::device_pub_freq_const      = 1000;
00069 const unsigned short int SR06::ros_pub_freq_const         = 1000;
00070 const unsigned short int SR06::max_iter_const             = device_pub_freq_const / ros_pub_freq_const;
00071 const unsigned int       SR06::nb_sensors_const           = ETHERCAT_STATUS_DATA_SIZE/2; //36;
00072 const unsigned char      SR06::nb_publish_by_unpack_const = (nb_sensors_const % max_iter_const) ? (nb_sensors_const / max_iter_const) + 1 : (nb_sensors_const / max_iter_const);
00073 const unsigned int       SR06::max_retry                  = 20;
00074 
00075 #define ETHERCAT_CAN_BRIDGE_DATA_SIZE sizeof(ETHERCAT_CAN_BRIDGE_DATA)
00076 
00077 
00078 PLUGINLIB_REGISTER_CLASS(6, SR06, EthercatDevice);
00079 
00080 #define check_for_pthread_mutex_init_error(x)   switch(x)               \
00081   {                                                                     \
00082   case EAGAIN:                                                          \
00083     ROS_ERROR("The system temporarily lacks the resources to create another mutex : %s:%d", __FILE__, __LINE__); \
00084     exit(1);                                                            \
00085     break;                                                              \
00086   case EINVAL:                                                          \
00087     ROS_ERROR("The value specified as attribute is invalid for mutex init : %s:%d", __FILE__, __LINE__); \
00088     exit(1);                                                            \
00089     break;                                                              \
00090   case ENOMEM:                                                          \
00091     ROS_ERROR("The process cannot allocate enough memory to create another mutex : %s:%d", __FILE__, __LINE__); \
00092     exit(1);                                                            \
00093     break;                                                              \
00094   case 0: /* SUCCESS */                                                 \
00095     break;                                                              \
00096   default:                                                              \
00097     ROS_ERROR("unknown error value, is this POSIX system ? : %s:%d", __FILE__, __LINE__); \
00098     exit(1);                                                            \
00099   }
00100 
00101 #define unlock(x)       switch ( pthread_mutex_unlock(x) )              \
00102   {                                                                     \
00103   case EINVAL:                                                          \
00104     ROS_ERROR("The value specified as a mutex is invalid : %s:%d", __FILE__, __LINE__); \
00105     exit(1);                                                            \
00106     break;                                                              \
00107   case EPERM:                                                           \
00108     ROS_ERROR("The current thread does not hold a lock on the mutex : %s:%d", __FILE__, __LINE__); \
00109     exit(1);                                                            \
00110     break;                                                              \
00111   }
00112 
00113 #define check_for_trylock_error(x)      if (x == EINVAL)        \
00114   {                                                             \
00115     ROS_ERROR("mutex error %s:%d", __FILE__, __LINE__);         \
00116     exit(1);                                                    \
00117   }
00118 
00119 
00126 SR06::SR06()
00127   : SR0X(),
00128     flashing(false),
00129     can_message_sent(true),
00130     can_packet_acked(true),
00131     zero_buffer_read(0),
00132     cycle_count(0),
00133     can_bus_(0)
00134 {
00135   int res = 0;
00136   check_for_pthread_mutex_init_error(res);
00137   counter_ = 0;
00138 
00139   ROS_INFO("There are %d sensors", nb_sensors_const);
00140   ROS_INFO(     "device_pub_freq_const = %d", device_pub_freq_const      );
00141   ROS_INFO(        "ros_pub_freq_const = %d", ros_pub_freq_const         );
00142   ROS_INFO(            "max_iter_const = %d", max_iter_const             );
00143   ROS_INFO(          "nb_sensors_const = %d", nb_sensors_const           );
00144   ROS_INFO("nb_publish_by_unpack_const = %d", nb_publish_by_unpack_const );
00145 
00146   res = pthread_mutex_init(&producing, NULL);
00147   check_for_pthread_mutex_init_error(res);
00148 
00149   serviceServer = nodehandle_.advertiseService("SimpleMotorFlasher", &SR06::simple_motor_flasher, this);
00150 }
00151 
00156 SR06::~SR06()
00157 {
00158   delete sh_->get_fmmu_config();
00159   delete sh_->get_pd_config();
00160 }
00161 
00195 void SR06::construct(EtherCAT_SlaveHandler *sh, int &start_address)
00196 {
00197     SR0X::construct(sh, start_address);
00198 
00199     command_base_ = start_address;
00200     command_size_ = ETHERCAT_COMMAND_DATA_SIZE + ETHERCAT_CAN_BRIDGE_DATA_SIZE;
00201 
00202     start_address += ETHERCAT_COMMAND_DATA_SIZE;
00203     start_address += ETHERCAT_CAN_BRIDGE_DATA_SIZE;
00204 
00205     status_base_ = start_address;
00206     status_size_ = ETHERCAT_STATUS_DATA_SIZE + ETHERCAT_CAN_BRIDGE_DATA_SIZE;
00207 
00208 
00209     // ETHERCAT_COMMAND_DATA
00210     //
00211     // This is for data going TO the palm
00212     //
00213     ROS_INFO("First FMMU (command) : start_address : 0x%08X ; size : %3d bytes ; phy addr : 0x%08X", command_base_, command_size_,
00214              static_cast<int>(ETHERCAT_COMMAND_DATA_ADDRESS) );
00215     EC_FMMU *commandFMMU = new EC_FMMU( command_base_,                                                  // Logical Start Address    (in ROS address space?)
00216                                         command_size_,
00217                                         0x00,                                                           // Logical Start Bit
00218                                         0x07,                                                           // Logical End Bit
00219                                         ETHERCAT_COMMAND_DATA_ADDRESS,                                  // Physical Start Address   (in ET1200 address space?)
00220                                         0x00,                                                           // Physical Start Bit
00221                                         false,                                                          // Read Enable
00222                                         true,                                                           // Write Enable
00223                                         true                                                            // Channel Enable
00224                                        );
00225 
00226 
00227 
00228 
00229     // ETHERCAT_STATUS_DATA
00230     //
00231     // This is for data coming FROM the palm
00232     //
00233     ROS_INFO("Second FMMU (status) : start_address : 0x%08X ; size : %3d bytes ; phy addr : 0x%08X", status_base_, status_size_,
00234              static_cast<int>(ETHERCAT_STATUS_DATA_ADDRESS) );
00235     EC_FMMU *statusFMMU = new EC_FMMU(  status_base_,
00236                                         status_size_,
00237                                         0x00,
00238                                         0x07,
00239                                         ETHERCAT_STATUS_DATA_ADDRESS,
00240                                         0x00,
00241                                         true,
00242                                         false,
00243                                         true);
00244 
00245 
00246 
00247     EtherCAT_FMMU_Config *fmmu = new EtherCAT_FMMU_Config(2);
00248 
00249     (*fmmu)[0] = *commandFMMU;
00250     (*fmmu)[1] = *statusFMMU;
00251 
00252     sh->set_fmmu_config(fmmu);
00253 
00254     EtherCAT_PD_Config *pd = new EtherCAT_PD_Config(4);
00255 
00256     (*pd)[0] = EC_SyncMan(ETHERCAT_COMMAND_DATA_ADDRESS,             ETHERCAT_COMMAND_DATA_SIZE,    EC_QUEUED, EC_WRITTEN_FROM_MASTER);
00257     (*pd)[1] = EC_SyncMan(ETHERCAT_CAN_BRIDGE_DATA_COMMAND_ADDRESS,  ETHERCAT_CAN_BRIDGE_DATA_SIZE, EC_QUEUED, EC_WRITTEN_FROM_MASTER);
00258     (*pd)[2] = EC_SyncMan(ETHERCAT_STATUS_DATA_ADDRESS,              ETHERCAT_STATUS_DATA_SIZE,     EC_QUEUED);
00259     (*pd)[3] = EC_SyncMan(ETHERCAT_CAN_BRIDGE_DATA_STATUS_ADDRESS,   ETHERCAT_CAN_BRIDGE_DATA_SIZE, EC_QUEUED);
00260 
00261     status_size_ = ETHERCAT_STATUS_DATA_SIZE + ETHERCAT_CAN_BRIDGE_DATA_SIZE;
00262 
00263     (*pd)[0].ChannelEnable = true;
00264     (*pd)[0].ALEventEnable = true;
00265     (*pd)[0].WriteEvent    = true;
00266 
00267     (*pd)[1].ChannelEnable = true;
00268     (*pd)[1].ALEventEnable = true;
00269     (*pd)[1].WriteEvent    = true;
00270 
00271     (*pd)[2].ChannelEnable = true;
00272     (*pd)[3].ChannelEnable = true;
00273 
00274     sh->set_pd_config(pd);
00275 
00276     ROS_INFO("status_size_ : %d ; command_size_ : %d", status_size_, command_size_);
00277 
00278     ROS_INFO("Finished constructing the SR06 driver");
00279 }
00280 
00284 int SR06::initialize(pr2_hardware_interface::HardwareInterface *hw, bool allow_unprogrammed)
00285 {
00286 
00287   int retval = SR0X::initialize(hw, allow_unprogrammed);
00288 
00289   if(retval != 0)
00290     return retval;
00291 
00292   sr_hand_lib = boost::shared_ptr<shadow_robot::SrHandLib>( new shadow_robot::SrHandLib(hw) );
00293 
00294   ROS_INFO("ETHERCAT_STATUS_DATA_SIZE      = %4d bytes", static_cast<int>(ETHERCAT_STATUS_DATA_SIZE) );
00295   ROS_INFO("ETHERCAT_COMMAND_DATA_SIZE     = %4d bytes", static_cast<int>(ETHERCAT_COMMAND_DATA_SIZE) );
00296   ROS_INFO("ETHERCAT_CAN_BRIDGE_DATA_SIZE  = %4d bytes", static_cast<int>(ETHERCAT_CAN_BRIDGE_DATA_SIZE) );
00297 
00298   //initialise the publisher for the extra analog inputs, gyroscope and accelerometer on the palm
00299   extra_analog_inputs_publisher.reset(new realtime_tools::RealtimePublisher<std_msgs::Float64MultiArray>(nodehandle_ , "palm_extras", 10));
00300 
00301 
00302   // Debug real time publisher: publishes the raw ethercat data
00303   debug_publisher = boost::shared_ptr<realtime_tools::RealtimePublisher<sr_robot_msgs::EthercatDebug> >( new realtime_tools::RealtimePublisher<sr_robot_msgs::EthercatDebug>(nodehandle_ , "debug_etherCAT_data", 4));
00304   return retval;
00305 }
00306 
00312 void SR06::erase_flash(void)
00313 {
00314   unsigned char cmd_sent;
00315   unsigned int wait_time;
00316   bool timedout;
00317   unsigned int timeout;
00318   int err;
00319 
00320   do {
00321     ROS_INFO("Erasing FLASH");
00322     // First we send the erase command
00323     cmd_sent = 0;
00324     while (! cmd_sent )
00325     {
00326       if ( !(err = pthread_mutex_trylock(&producing)) )
00327       {
00328         can_message_.message_length = 1;
00329         can_message_.can_bus = can_bus_;
00330         can_message_.message_id = 0x0600 | (motor_being_flashed << 5) | ERASE_FLASH_COMMAND;
00331         cmd_sent = 1;
00332         unlock(&producing);
00333       }
00334       else
00335       {
00336         check_for_trylock_error(err);
00337       }
00338     }
00339     wait_time = 0;
00340     timeout = 3000;
00341     can_message_sent = false;
00342     can_packet_acked = false;
00343     timedout = false;
00344     while ( !can_packet_acked )
00345     {
00346       usleep(1000);
00347       if (wait_time > timeout)
00348       {
00349         timedout = true;
00350         break;
00351       }
00352       wait_time++;
00353     }
00354 
00355     if (timedout)
00356     {
00357       ROS_ERROR("ERASE command timedout, resending it !");
00358     }
00359   } while (timedout);
00360 }
00361 
00378 bool SR06::read_flash(unsigned int offset, unsigned int baddr)
00379 {
00380   unsigned int cmd_sent;
00381   int err;
00382   unsigned int wait_time;
00383   bool timedout;
00384   unsigned int timeout;
00385   cmd_sent = 0;
00386   while ( !cmd_sent )
00387   {
00388     if ( !(err = pthread_mutex_trylock(&producing)) )
00389     {
00390       ROS_DEBUG("Sending READ data ... position : %03x", pos);
00391       can_message_.can_bus = can_bus_;
00392       can_message_.message_length = 3;
00393       can_message_.message_id = 0x0600 | (motor_being_flashed << 5) | READ_FLASH_COMMAND;
00394       can_message_.message_data[2] = (offset + baddr) >> 16;
00395       can_message_.message_data[1] = (offset + baddr) >> 8; // User application start address is 0x4C0
00396       can_message_.message_data[0] = offset + baddr;
00397       cmd_sent = 1;
00398       unlock(&producing);
00399     }
00400     else
00401     {
00402       check_for_trylock_error(err);
00403     }
00404 
00405   }
00406   timedout = false;
00407   wait_time = 0;
00408   timeout = 100;
00409   can_message_sent = false;
00410   can_packet_acked = false;
00411   while ( !can_packet_acked )
00412   {
00413     usleep(1000);
00414     if (wait_time > timeout)
00415     {
00416       timedout = true;
00417       break;
00418     }
00419     wait_time++;
00420   }
00421   return timedout;
00422 }
00423 
00462 bool SR06::simple_motor_flasher(sr_robot_msgs::SimpleMotorFlasher::Request &req, sr_robot_msgs::SimpleMotorFlasher::Response &res)
00463 {
00464   bfd *fd;
00465   unsigned int base_addr;
00466   unsigned int smallest_start_address = 0x7fff;
00467   unsigned int biggest_end_address = 0;
00468   unsigned int total_size = 0;
00469   bool timedout;
00470 
00471   // We're using 2 can busses,
00472   // if motor id is between 0 and 9, then we're using the can_bus 1
00473   // else, we're using the can bus 2.
00474   int motor_id_tmp = req.motor_id;
00475   if( motor_id_tmp > 9 )
00476   {
00477     motor_id_tmp -= 10;
00478     can_bus_ = 2;
00479   }
00480   else
00481   {
00482     can_bus_ = 1;
00483   }
00484 
00485   motor_being_flashed = motor_id_tmp;
00486   binary_content = NULL;
00487   flashing = true;
00488 
00489   ROS_INFO("Flashing the motor");
00490 
00491   //Initialize the bfd library: "This routine must be called before any other BFD function to initialize magical internal data structures."
00492   bfd_init();
00493 
00494   //Open the requested firmware object file
00495   fd = bfd_openr(req.firmware.c_str(), NULL);
00496   if (fd == NULL)
00497   {
00498     ROS_ERROR("error opening the file %s", get_filename(req.firmware).c_str());
00499     res.value = res.FAIL;
00500     flashing = false;
00501     return false;
00502   }
00503 
00504   //Check that bfd recognises the file as a correctly formatted object file
00505   if (!bfd_check_format (fd, bfd_object))
00506   {
00507     if (bfd_get_error () != bfd_error_file_ambiguously_recognized)
00508     {
00509       ROS_ERROR("Incompatible format");
00510       res.value = res.FAIL;
00511       flashing = false;
00512       return false;
00513     }
00514   }
00515 
00516   ROS_INFO("firmware %s's format is : %s.", get_filename(req.firmware).c_str(), fd->xvec->name);
00517 
00518   //TODO Check if it's necessary to send this dummy packet before the magic packet
00519   ROS_DEBUG("Sending dummy packet");
00520   send_CAN_msg(can_bus_, 0, 0, NULL, 1, &timedout);
00521 
00522   ROS_INFO_STREAM("Switching motor "<< motor_being_flashed << " on CAN bus " << can_bus_ << " into bootloader mode");
00523   //Send the magic packet that will force the microcontroller to go into bootloader mode
00524   int8u magic_packet[] = {0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA};
00525   send_CAN_msg(can_bus_, 0x0600 | (motor_being_flashed << 5) | 0b1010, 8, magic_packet, 100, &timedout);
00526 
00527   //Send a second magic packet if the first one wasn't acknowledged
00528   if ( timedout )
00529   {
00530     ROS_WARN("First magic CAN packet timedout");
00531     ROS_WARN("Sending another magic CAN packet to put the motor in bootloading mode");
00532     send_CAN_msg(can_bus_, 0x0600 | (motor_being_flashed << 5) | 0b1010, 8, magic_packet, 100, &timedout);
00533 
00534     if (timedout)
00535     {
00536       ROS_ERROR("None of the magic packets were ACKed, didn't bootload the motor.");
00537       res.value = res.FAIL;
00538       flashing = false;
00539       return false;
00540     }
00541   }
00542 
00543   //Erase the PIC18 microcontroller flash memory
00544   erase_flash();
00545 
00546   sleep(1);
00547 
00548   //Look for the start and end address of every section in the hex file,
00549   //to detect the lowest and highest address of the data we need to write in the PIC's flash.
00550   find_address_range(fd, &smallest_start_address, &biggest_end_address);
00551 
00552   //Calculate the size of the chunk of data to be flashed
00553   total_size = biggest_end_address - smallest_start_address;
00554   base_addr = smallest_start_address;
00555 
00556   //Allocate the memory space to store the data to be flashed
00557   //This could be done with new bfd_byte[total_size+8] and delete() instead of malloc() and free() but will stay this way for the moment
00558   binary_content = (bfd_byte *)malloc(total_size+8);
00559   if (binary_content == NULL)
00560   {
00561     ROS_ERROR("Error allocating memory for binary_content");
00562     res.value = res.FAIL;
00563     flashing = false;
00564     return false;
00565   }
00566 
00567   //Set all the bytes in the binary_content to 0xFF initially (i.e. before reading the content from the hex file)
00568   //This way we make sure that any byte in the region between smallest_start_address and biggest_end_address
00569   //that is not included in any section of the hex file, will be written with a 0xFF value, which is the default in the PIC
00570   memset(binary_content, 0xFF, total_size+8);
00571 
00572   //The content of the firmware is read from the .hex file pointed by fd, to a memory region pointed by binary_content
00573   if(!read_content_from_object_file(fd, binary_content, base_addr))
00574   {
00575     ROS_ERROR("something went wrong while parsing %s.", get_filename(req.firmware).c_str());
00576     res.value = res.FAIL;
00577     free(binary_content);
00578     flashing = false;
00579     return false;
00580   }
00581 
00582   // We do not need the file anymore
00583   bfd_close(fd);
00584 
00585   //The firmware is actually written to the flash memory of the PIC18
00586   if(!write_flash_data(base_addr, total_size))
00587   {
00588     res.value = res.FAIL;
00589     free(binary_content);
00590     flashing = false;
00591     return false;
00592   }
00593 
00594 
00595   ROS_INFO("Verifying");
00596   // Now we have to read back the flash content
00597   if( !read_back_and_check_flash(base_addr, total_size))
00598   {
00599     res.value = res.FAIL;
00600     free(binary_content);
00601     flashing = false;
00602     return false;
00603   }
00604 
00605 
00606   free(binary_content);
00607 
00608   ROS_INFO("Resetting microcontroller.");
00609   // Then we send the RESET command to PIC18F
00610   do {
00611     send_CAN_msg(can_bus_, 0x0600 | (motor_being_flashed << 5) | RESET_COMMAND, 0, NULL, 1000, &timedout);
00612   } while ( timedout );
00613 
00614 
00615   flashing = false;
00616 
00617   ROS_INFO("Flashing done");
00618 
00619   res.value = res.SUCCESS;
00620 
00621   //Reinitialize motors information
00622   sr_hand_lib->reinitialize_motors();
00623 
00624   return true;
00625 }
00626 
00633 void SR06::multiDiagnostics(vector<diagnostic_msgs::DiagnosticStatus> &vec, unsigned char *buffer)
00634 {
00635   diagnostic_updater::DiagnosticStatusWrapper &d(diagnostic_status_);
00636 
00637   stringstream name;
00638   d.name = "EtherCAT Dual CAN Palm";
00639   d.summary(d.OK, "OK");
00640   stringstream hwid;
00641   hwid << sh_->get_product_code() << "-" << sh_->get_serial();
00642   d.hardware_id = hwid.str();
00643 
00644   d.clear();
00645   d.addf("Position", "%02d", sh_->get_ring_position());
00646   d.addf("Product Code", "%d", sh_->get_product_code());
00647   d.addf("Serial Number", "%d", sh_->get_serial());
00648   d.addf("Revision", "%d", sh_->get_revision());
00649   d.addf("Counter", "%d", ++counter_);
00650 
00651   d.addf("PIC idle time (in microsecs)", "%d", sr_hand_lib->main_pic_idle_time);
00652   d.addf("Min PIC idle time (since last diagnostics)", "%d", sr_hand_lib->main_pic_idle_time_min);
00653   //reset the idle time min to a big number, to get a fresh number on next diagnostic
00654   sr_hand_lib->main_pic_idle_time_min = 1000;
00655 
00656   this->ethercatDiagnostics(d,2);
00657   vec.push_back(d);
00658 
00659   //Add the diagnostics from the hand
00660   sr_hand_lib->add_diagnostics(vec, d);
00661 
00662   //Add the diagnostics from the tactiles
00663   if( sr_hand_lib->tactiles != NULL )
00664     sr_hand_lib->tactiles->add_diagnostics(vec, d);
00665 }
00666 
00667 
00668 
00684 void SR06::packCommand(unsigned char *buffer, bool halt, bool reset)
00685 {
00686   int res;
00687 
00688   SR0X::packCommand(buffer, halt, reset);
00689 
00690   ETHERCAT_DATA_STRUCTURE_0200_PALM_EDC_COMMAND   *command = (ETHERCAT_DATA_STRUCTURE_0200_PALM_EDC_COMMAND *)(buffer                             );
00691   ETHERCAT_CAN_BRIDGE_DATA                        *message = (ETHERCAT_CAN_BRIDGE_DATA                      *)(buffer + ETHERCAT_COMMAND_DATA_SIZE);
00692 
00693   if ( !flashing )
00694   {
00695     command->EDC_command = EDC_COMMAND_SENSOR_DATA;
00696   }
00697   else
00698   {
00699     command->EDC_command = EDC_COMMAND_CAN_DIRECT_MODE;
00700   }
00701 
00702   //alternate between even and uneven motors
00703   // and ask for the different informations.
00704   sr_hand_lib->build_motor_command(command);
00705 
00706   ROS_DEBUG("Sending command : Type : 0x%02X ; data : 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X 0x%04X",
00707                 command->to_motor_data_type,
00708                 command->motor_data[0],
00709                 command->motor_data[1],
00710                 command->motor_data[2],
00711                 command->motor_data[3],
00712                 command->motor_data[4],
00713                 command->motor_data[5],
00714                 command->motor_data[6],
00715                 command->motor_data[7],
00716                 command->motor_data[8],
00717                 command->motor_data[9],
00718                 command->motor_data[10],
00719                 command->motor_data[11],
00720                 command->motor_data[12],
00721                 command->motor_data[13],
00722                 command->motor_data[14],
00723                 command->motor_data[15],
00724                 command->motor_data[16],
00725                 command->motor_data[17],
00726                 command->motor_data[18],
00727                 command->motor_data[19]);
00728 
00729   if (flashing && !can_packet_acked && !can_message_sent)
00730   {
00731     if ( !(res = pthread_mutex_trylock(&producing)) )
00732     {
00733       ROS_DEBUG_STREAM("Ethercat Command data size: "<< ETHERCAT_COMMAND_DATA_SIZE);
00734       ROS_DEBUG_STREAM("Ethercat bridge data size: "<< ETHERCAT_CAN_BRIDGE_DATA_SIZE);
00735 
00736       ROS_DEBUG("We're sending a CAN message for flashing.");
00737       memcpy(message, &can_message_, sizeof(can_message_));
00738       can_message_sent = true;
00739 
00740       ROS_DEBUG("Sending : SID : 0x%04X ; bus : 0x%02X ; length : 0x%02X ; data : 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X",
00741                 message->message_id,
00742                 message->can_bus,
00743                 message->message_length,
00744                 message->message_data[0],
00745                 message->message_data[1],
00746                 message->message_data[2],
00747                 message->message_data[3],
00748                 message->message_data[4],
00749                 message->message_data[5],
00750                 message->message_data[6],
00751                 message->message_data[7]);
00752 
00753       unlock(&producing);
00754     }
00755     else
00756     {
00757       ROS_ERROR("Mutex is locked, we don't send any CAN message !");
00758       check_for_trylock_error(res);
00759     }
00760   }
00761   else
00762   {
00763     message->can_bus        = can_bus_;
00764     message->message_id     = 0x00;
00765     message->message_length = 0;
00766   }
00767 
00768 }
00769 
00778 bool SR06::can_data_is_ack(ETHERCAT_CAN_BRIDGE_DATA * packet)
00779 {
00780   int i;
00781 
00782   if (packet->message_id == 0)
00783   {
00784     ROS_DEBUG("ID is zero");
00785     return false;
00786   }
00787 
00788   ROS_DEBUG("ack sid : %04X", packet->message_id);
00789 
00790   // Is this a reply to a READ request?
00791   if ( (packet->message_id & 0b0000011111111111) == (0x0600 | (motor_being_flashed << 5) | 0x10 | READ_FLASH_COMMAND))
00792   {
00793     ROS_DEBUG("READ reply  %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", packet->message_data[0],
00794               packet->message_data[1],
00795               packet->message_data[2],
00796               packet->message_data[3],
00797               packet->message_data[4],
00798               packet->message_data[5],
00799               packet->message_data[6],
00800               packet->message_data[7]  );
00801     ROS_DEBUG("Should be   %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", binary_content[pos+0],
00802               binary_content[pos+1],
00803               binary_content[pos+2],
00804               binary_content[pos+3],
00805               binary_content[pos+4],
00806               binary_content[pos+5],
00807               binary_content[pos+6],
00808               binary_content[pos+7]  );
00809 
00810       if ( !memcmp(packet->message_data, binary_content + pos, 8) )
00811       {
00812         ROS_DEBUG("data is good");
00813         return true;
00814       }
00815       else
00816       {
00817         ROS_DEBUG("data is bad");
00818         return false;
00819       }
00820   }
00821 
00822   if (packet->message_length != can_message_.message_length)
00823   {
00824     ROS_DEBUG("Length is bad: %d", packet->message_length);
00825     return false;
00826   }
00827 
00828   ROS_DEBUG("Length is OK");
00829 
00830   for (i = 0 ; i < packet->message_length ; ++i)
00831   {
00832     ROS_DEBUG("packet sent, data[%d] : %02X ; ack, data[%d] : %02X", i, can_message_.message_data[i], i, packet->message_data[i]);
00833     if (packet->message_data[i] != can_message_.message_data[i])
00834       return false;
00835   }
00836   ROS_DEBUG("Data is OK");
00837 
00838   if ( !(0x0010 & packet->message_id))
00839     return false;
00840 
00841   ROS_DEBUG("This is an ACK");
00842 
00843   if ( (packet->message_id & 0b0000000111101111) != (can_message_.message_id & 0b0000000111101111) )
00844   {
00845     ROS_WARN_STREAM("Bad packet id: " << packet->message_id);
00846     return false;
00847   }
00848 
00849   ROS_DEBUG("SID is OK");
00850 
00851   ROS_DEBUG("Everything is OK, this is our ACK !");
00852   return true;
00853 }
00854 
00873 bool SR06::unpackState(unsigned char *this_buffer, unsigned char *prev_buffer)
00874 {
00875   ETHERCAT_DATA_STRUCTURE_0200_PALM_EDC_STATUS  *status_data = (ETHERCAT_DATA_STRUCTURE_0200_PALM_EDC_STATUS *)(this_buffer + command_size_                             );
00876   ETHERCAT_CAN_BRIDGE_DATA                      *can_data    = (ETHERCAT_CAN_BRIDGE_DATA                     *)(this_buffer + command_size_ + ETHERCAT_STATUS_DATA_SIZE );
00877   //  int16u                                        *status_buffer = (int16u*)status_data;
00878   static unsigned int num_rxed_packets = 0;
00879 
00880   ++num_rxed_packets;
00881 
00882 
00883   // publishes the debug information (a slightly formatted version of the incoming ethercat packet):
00884   if(debug_publisher->trylock())
00885   {
00886     debug_publisher->msg_.header.stamp = ros::Time::now();
00887 
00888     debug_publisher->msg_.sensors.clear();
00889     for(unsigned int i=0; i<SENSORS_NUM_0220 + 1; ++i)
00890       debug_publisher->msg_.sensors.push_back( status_data->sensors[i] );
00891 
00892     debug_publisher->msg_.motor_data_type.data = static_cast<int>(status_data->motor_data_type);
00893     debug_publisher->msg_.which_motors = status_data->which_motors;
00894     debug_publisher->msg_.which_motor_data_arrived = status_data->which_motor_data_arrived;
00895     debug_publisher->msg_.which_motor_data_had_errors = status_data->which_motor_data_had_errors;
00896 
00897     debug_publisher->msg_.motor_data_packet_torque.clear();
00898     debug_publisher->msg_.motor_data_packet_misc.clear();
00899     for(unsigned int i=0; i < 10; ++i)
00900     {
00901       debug_publisher->msg_.motor_data_packet_torque.push_back( status_data->motor_data_packet[i].torque );
00902       debug_publisher->msg_.motor_data_packet_misc.push_back( status_data->motor_data_packet[i].misc );
00903     }
00904 
00905     debug_publisher->msg_.tactile_data_type = static_cast<unsigned int>(static_cast<int32u>(status_data->tactile_data_type));
00906     debug_publisher->msg_.tactile_data_valid = static_cast<unsigned int>(static_cast<int16u>(status_data->tactile_data_valid));
00907     debug_publisher->msg_.tactile.clear();
00908     for(unsigned int i=0; i < 5; ++i)
00909       debug_publisher->msg_.tactile.push_back( static_cast<unsigned int>(static_cast<int16u>(status_data->tactile[i].word[0])) );
00910 
00911     debug_publisher->msg_.idle_time_us = status_data->idle_time_us;
00912 
00913     debug_publisher->unlockAndPublish();
00914   }
00915 
00916   if (status_data->EDC_command == EDC_COMMAND_INVALID)
00917   {
00918     //received empty message: the pic is not writing to its mailbox.
00919     ++zero_buffer_read;
00920     float percentage_packet_loss = 100.f * ((float)zero_buffer_read / (float)num_rxed_packets);
00921 
00922     ROS_DEBUG("Reception error detected : %d errors out of %d rxed packets (%2.3f%%) ; idle time %dus", zero_buffer_read, num_rxed_packets, percentage_packet_loss, status_data->idle_time_us);
00923     return true;
00924   }
00925 
00926   //We received a coherent message.
00927   //Update the library (positions, diagnostics values, actuators, etc...)
00928   //with the received information
00929   sr_hand_lib->update(status_data);
00930 
00931   //Now publish the additional data at 100Hz (every 10 cycles)
00932   if( cycle_count >= 9)
00933   {
00934     //publish tactiles if we have them
00935     if( sr_hand_lib->tactiles != NULL )
00936       sr_hand_lib->tactiles->publish();
00937 
00938     //And we also publish the additional data (accelerometer / gyroscope / analog inputs)
00939     std_msgs::Float64MultiArray extra_analog_msg;
00940     extra_analog_msg.layout.dim.resize(3);
00941     extra_analog_msg.data.resize(3+3+4);
00942     std::vector<double> data;
00943 
00944     extra_analog_msg.layout.dim[0].label = "accelerometer";
00945     extra_analog_msg.layout.dim[0].size = 3;
00946     extra_analog_msg.data[0] = status_data->sensors[ACCX];
00947     extra_analog_msg.data[1] = status_data->sensors[ACCY];
00948     extra_analog_msg.data[2] = status_data->sensors[ACCZ];
00949 
00950     extra_analog_msg.layout.dim[1].label = "gyrometer";
00951     extra_analog_msg.layout.dim[1].size = 3;
00952     extra_analog_msg.data[3] = status_data->sensors[GYRX];
00953     extra_analog_msg.data[4] = status_data->sensors[GYRY];
00954     extra_analog_msg.data[5] = status_data->sensors[GYRZ];
00955 
00956     extra_analog_msg.layout.dim[2].label = "analog_inputs";
00957     extra_analog_msg.layout.dim[2].size = 4;
00958     extra_analog_msg.data[6] = status_data->sensors[AN0];
00959     extra_analog_msg.data[7] = status_data->sensors[AN1];
00960     extra_analog_msg.data[8] = status_data->sensors[AN2];
00961     extra_analog_msg.data[9] = status_data->sensors[AN3];
00962 
00963     if( extra_analog_inputs_publisher->trylock() )
00964     {
00965       extra_analog_inputs_publisher->msg_ = extra_analog_msg;
00966       extra_analog_inputs_publisher->unlockAndPublish();
00967     }
00968 
00969     cycle_count = 0;
00970   }
00971   ++cycle_count;
00972 
00973 
00974   //If we're flashing, check is the packet has been acked
00975   if (flashing & !can_packet_acked)
00976   {
00977     if (can_data_is_ack(can_data))
00978     {
00979       can_packet_acked = true;
00980     }
00981   }
00982 
00983   return true;
00984 }
00985 
00986 void SR06::send_CAN_msg(int8u can_bus, int16u msg_id, int8u msg_length, int8u msg_data[], int timeout, bool *timedout)
00987 {
00988   int err;
00989   unsigned char cmd_sent;
00990   int wait_time;
00991 
00992   cmd_sent = 0;
00993   while ( !cmd_sent )
00994   {
00995     if ( !(err = pthread_mutex_trylock(&producing)) )
00996     {
00997       can_message_.message_length = msg_length;
00998       can_message_.can_bus = can_bus;
00999       can_message_.message_id = msg_id;
01000 
01001       if (msg_data != NULL)
01002       {
01003         for(unsigned int i = 0; i<msg_length; i++)
01004         {
01005           can_message_.message_data[i] = msg_data[i];
01006         }
01007       }
01008 
01009       cmd_sent = 1;
01010       unlock(&producing);
01011     }
01012     else
01013     {
01014       check_for_trylock_error(err);
01015     }
01016   }
01017   wait_time = 0;
01018   *timedout = false;
01019   can_message_sent = false;
01020   can_packet_acked = false;
01021   while ( !can_packet_acked )
01022   {
01023     usleep(1000); // 1 ms
01024     wait_time++;
01025     if (wait_time > timeout) {
01026       *timedout = true;
01027       break;
01028     }
01029   }
01030 }
01031 
01032 bool SR06::read_back_and_check_flash(unsigned int baddr, unsigned int total_size)
01033 {
01034   bool timedout;
01035   // The actual comparison between the content read from the flash and the content read from the hex file is carried out
01036   // in the can_data_is_ack() function.
01037   // read_flash(...) will return timedout = true if the 8 byte content read from the flash doesn't match the 8 bytes from the hex file
01038   //BE CAREFUL with the pos "global" field, because it's being used inside can_data_is_ack() function to check if the response
01039   //of the READ_FLASH_COMMAND is correct
01040   pos = 0;
01041   unsigned int retry;
01042   while (pos < total_size)
01043   {
01044     retry = 0;
01045     do {
01046       timedout = read_flash(pos, baddr);
01047       if ( ! timedout )
01048         pos += 8;
01049       retry++;
01050       if (retry > max_retry)
01051       {
01052         ROS_ERROR("Too much retry for READ back, try flashing again");
01053         return false;
01054       }
01055     } while ( timedout );
01056   }
01057   return true;
01058 }
01059 
01060 void SR06::find_address_range(bfd *fd, unsigned int *smallest_start_address, unsigned int *biggest_end_address)
01061 {
01062   asection *s;
01063   unsigned int section_size = 0;
01064   unsigned int section_addr = 0;
01065 
01066   //Look for the start and end address of every section in the hex file,
01067   //to detect the lowest and highest address of the data we need to write in the PIC's flash.
01068   //The sections starting at an address higher than 0x7fff will be ignored as they are not proper "code memory" firmware
01069   //(they can contain the CONFIG bits of the microcontroller, which we don't want to write here)
01070   //To understand the structure (sections) of the object file containing the firmware (usually a .hex) the following commands can be useful:
01071   //  \code objdump -x simplemotor.hex \endcode
01072   //  \code objdump -s simplemotor.hex \endcode
01073   for (s = fd->sections ; s ; s = s->next)
01074   {
01075     //Only the sections with the LOAD flag on will be considered
01076     if (bfd_get_section_flags (fd, s) & (SEC_LOAD))
01077     {
01078       //Only the sections with the same VMA (virtual memory address) and LMA (load MA) will be considered
01079       //http://www.delorie.com/gnu/docs/binutils/ld_7.html
01080       if (bfd_section_lma (fd, s) == bfd_section_vma (fd, s))
01081       {
01082         section_addr = (unsigned int) bfd_section_lma (fd, s);
01083         if (section_addr >= 0x7fff)
01084           continue;
01085         section_size = (unsigned int) bfd_section_size (fd, s);
01086         *smallest_start_address = min(section_addr, *smallest_start_address);
01087         *biggest_end_address = max(*biggest_end_address, section_addr + section_size);
01088       }
01089     }
01090   }
01091 }
01092 
01093 bool SR06::read_content_from_object_file(bfd *fd, bfd_byte *content, unsigned int base_addr)
01094 {
01095   asection *s;
01096   unsigned int section_size = 0;
01097   unsigned int section_addr = 0;
01098 
01099   for (s = fd->sections ; s ; s = s->next)
01100   {
01101     //Only the sections with the LOAD flag on will be considered
01102     if (bfd_get_section_flags (fd, s) & (SEC_LOAD))
01103     {
01104       //Only the sections with the same VMA (virtual memory address) and LMA (load MA) will be considered
01105       //http://www.delorie.com/gnu/docs/binutils/ld_7.html
01106       if (bfd_section_lma (fd, s) == bfd_section_vma (fd, s))
01107       {
01108         section_addr = (unsigned int) bfd_section_lma (fd, s);
01109         //The sections starting at an address higher than 0x7fff will be ignored as they are not proper "code memory" firmware
01110         //(they can contain the CONFIG bits of the microcontroller, which we don't want to write here)
01111         if (section_addr >= 0x7fff)
01112           continue;
01113         section_size = (unsigned int) bfd_section_size (fd, s);
01114         bfd_get_section_contents(fd, s, content + (section_addr - base_addr), 0, section_size);
01115       }
01116       else
01117       {
01118         return false;
01119       }
01120     }
01121     else
01122     {
01123       return false;
01124     }
01125   }
01126   return true;
01127 }
01128 
01129 bool SR06::write_flash_data(unsigned int base_addr, unsigned int total_size)
01130 {
01131   int err;
01132   unsigned char cmd_sent;
01133   int wait_time, timeout;
01134   bool timedout;
01135 
01136   pos = 0;
01137   unsigned int packet = 0;
01138   ROS_INFO("Sending the firmware data");
01139   while ( pos < ((total_size % 32) == 0 ? total_size : (total_size + 32 - (total_size % 32))) )
01140   {
01141     //For every WRITE_FLASH_ADDRESS_COMMAND we write 32 bytes of data to flash
01142     //and this is done by sending 4 WRITE_FLASH_DATA_COMMAND packets, every one containing 8 bytes of data to be written
01143     if ((pos % 32) == 0)
01144     {
01145       packet = 0;
01146       do {
01147         cmd_sent = 0;
01148         while (! cmd_sent )
01149         {
01150           if ( !(err = pthread_mutex_trylock(&producing)) )
01151           {
01152             can_message_.message_length = 3;
01153             can_message_.can_bus = can_bus_;
01154             can_message_.message_id = 0x0600 | (motor_being_flashed << 5) | WRITE_FLASH_ADDRESS_COMMAND;
01155             can_message_.message_data[2] = (base_addr + pos) >> 16;
01156             can_message_.message_data[1] = (base_addr + pos) >> 8; // User application start address is 0x4C0
01157             can_message_.message_data[0] = base_addr + pos;
01158             ROS_DEBUG("Sending write address to motor %d : 0x%02X%02X%02X", motor_being_flashed, can_message_.message_data[2], can_message_.message_data[1], can_message_.message_data[0]);
01159             cmd_sent = 1;
01160             unlock(&producing);
01161           }
01162           else
01163           {
01164             check_for_trylock_error(err);
01165           }
01166         }
01167         wait_time = 0;
01168         timedout = false;
01169         timeout = 100;
01170         can_message_sent = false;
01171         can_packet_acked = false;
01172         while ( !can_packet_acked )
01173         {
01174           usleep(1000);
01175           if (wait_time > timeout)
01176           {
01177             timedout = true;
01178             break;
01179           }
01180           wait_time++;
01181         }
01182         if (timedout)
01183         {
01184           ROS_ERROR("WRITE ADDRESS timedout ");
01185           return false;
01186         }
01187       } while ( timedout );
01188     }
01189     cmd_sent = 0;
01190     while (! cmd_sent )
01191     {
01192       if ( !(err = pthread_mutex_trylock(&producing)) )
01193       {
01194         ROS_DEBUG("Sending data ... position == %d", pos);
01195         can_message_.message_length = 8;
01196         can_message_.can_bus = can_bus_;
01197         can_message_.message_id = 0x0600 | (motor_being_flashed << 5) | WRITE_FLASH_DATA_COMMAND;
01198         bzero(can_message_.message_data, 8);
01199         for (unsigned char j = 0 ; j < 8 ; ++j)
01200           can_message_.message_data[j] = (pos > total_size) ? 0xFF : *(binary_content + pos + j);
01201 
01202         pos += 8;
01203         cmd_sent = 1;
01204         unlock(&producing);
01205       }
01206       else
01207       {
01208         check_for_trylock_error(err);
01209       }
01210     }
01211     packet++;
01212     timedout = false;
01213     wait_time = 0;
01214     timeout = 100;
01215     can_message_sent = false;
01216     can_packet_acked = false;
01217     while ( !can_packet_acked )
01218     {
01219       usleep(1000);
01220       if (wait_time > timeout)
01221       {
01222         timedout = true;
01223         break;
01224       }
01225       wait_time++;
01226     }
01227     if ( timedout )
01228     {
01229       ROS_ERROR("A WRITE data packet has been lost, resending the 32 bytes block !");
01230       pos -= packet*8;
01231     }
01232   }
01233   return true;
01234 }
01235 
01236 
01237 /* For the emacs weenies in the crowd.
01238    Local Variables:
01239    c-basic-offset: 2
01240    End:
01241 */


sr_edc_ethercat_drivers
Author(s): Yann Sionneau, Ugo Cupcic / ugo@shadowrobot.com, software@shadowrobot.com
autogenerated on Thu Jan 2 2014 12:03:32