sr_edc.cpp
Go to the documentation of this file.
00001 
00033 #include <sr_edc_ethercat_drivers/sr_edc.h>
00034 
00035 #include <realtime_tools/realtime_publisher.h>
00036 
00037 #include <algorithm>
00038 #include <string>
00039 #include <sstream>
00040 #include <iomanip>
00041 #include <boost/foreach.hpp>
00042 #include <std_msgs/Int16.h>
00043 #include <math.h>
00044 #include <fcntl.h>
00045 #include <stdio.h>
00046 #include <pthread.h>
00047 #include <bfd.h>
00048 
00049 #include <sr_utilities/sr_math_utils.hpp>
00050 
00051 using std::string;
00052 using std::stringstream;
00053 using std::vector;
00054 
00055 #include <sr_external_dependencies/types_for_external.h>
00056 
00057 extern "C"
00058 {
00059 #include <sr_external_dependencies/external/simplemotor-bootloader/bootloader.h>
00060 }
00061 
00062 #include <boost/static_assert.hpp>
00063 
00064 namespace is_edc_command_32_bits
00065 {
00066 // check is the EDC_COMMAND is 32bits on the computer
00067 // if not, fails
00068   BOOST_STATIC_ASSERT(sizeof(EDC_COMMAND) == 4);
00069 }  // namespace is_edc_command_32_bits
00070 
00071 const unsigned int SrEdc::max_retry = 20;
00072 
00073 #define ETHERCAT_CAN_BRIDGE_DATA_SIZE sizeof(ETHERCAT_CAN_BRIDGE_DATA)
00074 
00075 
00076 #define check_for_pthread_mutex_init_error(x)  switch (x)               \
00077   {                                                                     \
00078   case EAGAIN:                                                          \
00079     ROS_ERROR("The system temporarily lacks the resources to create another mutex : %s:%d", __FILE__, __LINE__); \
00080     exit(1);                                                            \
00081     break;                                                              \
00082   case EINVAL:                                                          \
00083     ROS_ERROR("The value specified as attribute is invalid for mutex init : %s:%d", __FILE__, __LINE__); \
00084     exit(1);                                                            \
00085     break;                                                              \
00086   case ENOMEM:                                                          \
00087     ROS_ERROR("The process cannot allocate enough memory to create another mutex : %s:%d", __FILE__, __LINE__); \
00088     exit(1);                                                            \
00089     break;                                                              \
00090   case 0: /* SUCCESS */                                                 \
00091     break;                                                              \
00092   default:                                                              \
00093     ROS_ERROR("unknown error value, is this POSIX system ? : %s:%d", __FILE__, __LINE__); \
00094     exit(1);                                                            \
00095   }
00096 
00097 #define unlock(x)  switch ( pthread_mutex_unlock(x) )              \
00098   {                                                                     \
00099   case EINVAL:                                                          \
00100     ROS_ERROR("The value specified as a mutex is invalid : %s:%d", __FILE__, __LINE__); \
00101     exit(1);                                                            \
00102     break;                                                              \
00103   case EPERM:                                                           \
00104     ROS_ERROR("The current thread does not hold a lock on the mutex : %s:%d", __FILE__, __LINE__); \
00105     exit(1);                                                            \
00106     break;                                                              \
00107   }
00108 
00109 #define check_for_trylock_error(x)  if (x == EINVAL)        \
00110   {                                                             \
00111     ROS_ERROR("mutex error %s:%d", __FILE__, __LINE__);         \
00112     exit(1);                                                    \
00113   }
00114 
00121 SrEdc::SrEdc()
00122         : flashing(false),
00123           can_message_sent(true),
00124           can_packet_acked(true),
00125           can_bus_(0),
00126           counter_(0)
00127 {
00128   int res = 0;
00129   check_for_pthread_mutex_init_error(res);
00130 
00131   res = pthread_mutex_init(&producing, NULL);
00132   check_for_pthread_mutex_init_error(res);
00133 }
00134 
00168 void SrEdc::construct(EtherCAT_SlaveHandler *sh, int &start_address, unsigned int ethercat_command_data_size,
00169                       unsigned int ethercat_status_data_size, unsigned int ethercat_can_bridge_data_size,
00170                       unsigned int ethercat_command_data_address, unsigned int ethercat_status_data_address,
00171                       unsigned int ethercat_can_bridge_data_command_address,
00172                       unsigned int ethercat_can_bridge_data_status_address)
00173 {
00174   sh_ = sh;
00175 
00176   // get the alias from the parameter server if it exists
00177   std::string path_to_alias, alias;
00178   path_to_alias = "/hand/mapping/" + boost::lexical_cast<std::string>(sh_->get_serial());
00179   ROS_INFO_STREAM("Trying to read mapping for: " << path_to_alias);
00180   if (ros::param::get(path_to_alias, alias))
00181   {
00182     device_id_ = alias;
00183   }
00184   else
00185   {
00186     // no alias found, using empty device_id_
00187     // Using the serial number as we do in ronex is probably a worse option here.
00188     device_id_ = "";
00189   }
00190   ros::NodeHandle nh_priv = ros::NodeHandle("~");
00191   bool use_ns = true;
00192   if (!nh_priv.getParam("use_ns", use_ns))
00193     ROS_INFO_STREAM("use_ns not set for " << nh_priv.getNamespace());
00194 
00195   if (use_ns)
00196   {
00197     nodehandle_ = ros::NodeHandle(device_id_);
00198     ROS_INFO_STREAM("Using namespace in sr_edc");
00199   }
00200   else
00201   {
00202     ROS_INFO_STREAM("Not using namespace in sr_edc");
00203     nodehandle_ = ros::NodeHandle();
00204   }
00205   nh_tilde_ = ros::NodeHandle(nh_priv, device_id_);
00206 
00207   serviceServer = nodehandle_.advertiseService("SimpleMotorFlasher", &SrEdc::simple_motor_flasher, this);
00208 
00209   // get the alias from the parameter server if it exists
00210   std::string path_to_prefix, prefix;
00211   path_to_prefix = "/hand/joint_prefix/" + boost::lexical_cast<std::string>(sh_->get_serial());
00212   ROS_INFO_STREAM("Trying to read joint_prefix for: " << path_to_prefix);
00213   if (ros::param::get(path_to_prefix, prefix))
00214   {
00215     device_joint_prefix_ = prefix;
00216   }
00217   else
00218   {
00219     // no prefix found, using empty prefix
00220     device_joint_prefix_ = "";
00221   }
00222 
00223   command_base_ = start_address;
00224   command_size_ = ethercat_command_data_size + ethercat_can_bridge_data_size;
00225 
00226   start_address += command_size_;
00227 
00228   status_base_ = start_address;
00229   status_size_ = ethercat_status_data_size + ethercat_can_bridge_data_size;
00230 
00231   start_address += status_size_;
00232 
00233   // ETHERCAT_COMMAND_DATA
00234   //
00235   // This is for data going TO the palm
00236   //
00237   ROS_INFO("First FMMU (command) : start_address : 0x%08X ; size : %3d bytes ; phy addr : 0x%08X", command_base_,
00238            command_size_,
00239            static_cast<int> (ethercat_command_data_address));
00240   EC_FMMU *commandFMMU = new EC_FMMU(command_base_,  // Logical Start Address    (in ROS address space?)
00241                                      command_size_,
00242                                      0x00,  // Logical Start Bit
00243                                      0x07,  // Logical End Bit
00244                                      ethercat_command_data_address,  // Physical Start Address(in ET1200 address space?)
00245                                      0x00,  // Physical Start Bit
00246                                      false,  // Read Enable
00247                                      true,  // Write Enable
00248                                      true);  // Channel Enable
00249 
00250 
00251 
00252 
00253   // ETHERCAT_STATUS_DATA
00254   //
00255   // This is for data coming FROM the palm
00256   //
00257   ROS_INFO("Second FMMU (status) : start_address : 0x%08X ; size : %3d bytes ; phy addr : 0x%08X", status_base_,
00258            status_size_,
00259            static_cast<int> (ethercat_status_data_address));
00260   EC_FMMU *statusFMMU = new EC_FMMU(status_base_,
00261                                     status_size_,
00262                                     0x00,
00263                                     0x07,
00264                                     ethercat_status_data_address,
00265                                     0x00,
00266                                     true,
00267                                     false,
00268                                     true);
00269 
00270 
00271   EtherCAT_FMMU_Config *fmmu = new EtherCAT_FMMU_Config(2);
00272 
00273   (*fmmu)[0] = *commandFMMU;
00274   (*fmmu)[1] = *statusFMMU;
00275 
00276   sh->set_fmmu_config(fmmu);
00277 
00278   EtherCAT_PD_Config *pd = new EtherCAT_PD_Config(4);
00279 
00280   (*pd)[0] = EC_SyncMan(ethercat_command_data_address, ethercat_command_data_size, EC_QUEUED, EC_WRITTEN_FROM_MASTER);
00281   (*pd)[1] = EC_SyncMan(ethercat_can_bridge_data_command_address, ethercat_can_bridge_data_size, EC_QUEUED,
00282                         EC_WRITTEN_FROM_MASTER);
00283   (*pd)[2] = EC_SyncMan(ethercat_status_data_address, ethercat_status_data_size, EC_QUEUED);
00284   (*pd)[3] = EC_SyncMan(ethercat_can_bridge_data_status_address, ethercat_can_bridge_data_size, EC_QUEUED);
00285 
00286   status_size_ = ethercat_status_data_size + ethercat_can_bridge_data_size;
00287 
00288   (*pd)[0].ChannelEnable = true;
00289   (*pd)[0].ALEventEnable = true;
00290   (*pd)[0].WriteEvent = true;
00291 
00292   (*pd)[1].ChannelEnable = true;
00293   (*pd)[1].ALEventEnable = true;
00294   (*pd)[1].WriteEvent = true;
00295 
00296   (*pd)[2].ChannelEnable = true;
00297   (*pd)[3].ChannelEnable = true;
00298 
00299   sh->set_pd_config(pd);
00300 
00301   ROS_INFO("status_size_ : %d ; command_size_ : %d", status_size_, command_size_);
00302 }
00303 
00309 void SrEdc::erase_flash(void)
00310 {
00311   unsigned char cmd_sent;
00312   unsigned int wait_time;
00313   bool timedout = true;
00314   unsigned int timeout;
00315   int err;
00316 
00317   while (timedout)
00318   {
00319     ROS_INFO("Erasing FLASH");
00320     // First we send the erase command
00321     cmd_sent = 0;
00322     while (!cmd_sent)
00323     {
00324       if (!(err = pthread_mutex_trylock(&producing)))
00325       {
00326         can_message_.message_length = 1;
00327         can_message_.can_bus = can_bus_;
00328         can_message_.message_id = 0x0600 | (motor_being_flashed << 5) | ERASE_FLASH_COMMAND;
00329         cmd_sent = 1;
00330         unlock(&producing);
00331       }
00332       else
00333       {
00334         check_for_trylock_error(err);
00335       }
00336     }
00337     wait_time = 0;
00338     timeout = 3000;
00339     can_message_sent = false;
00340     can_packet_acked = false;
00341     timedout = false;
00342     while (!can_packet_acked)
00343     {
00344       usleep(1000);
00345       if (wait_time > timeout)
00346       {
00347         timedout = true;
00348         break;
00349       }
00350       wait_time++;
00351     }
00352 
00353     if (timedout)
00354     {
00355       ROS_ERROR("ERASE command timedout, resending it !");
00356     }
00357   };
00358 }
00359 
00376 bool SrEdc::read_flash(unsigned int offset, unsigned int baddr)
00377 {
00378   unsigned int cmd_sent;
00379   int err;
00380   unsigned int wait_time;
00381   bool timedout;
00382   unsigned int timeout;
00383   cmd_sent = 0;
00384   while (!cmd_sent)
00385   {
00386     if (!(err = pthread_mutex_trylock(&producing)))
00387     {
00388       ROS_DEBUG("Sending READ data ... position : %03x", pos);
00389       can_message_.can_bus = can_bus_;
00390       can_message_.message_length = 3;
00391       can_message_.message_id = 0x0600 | (motor_being_flashed << 5) | READ_FLASH_COMMAND;
00392       can_message_.message_data[2] = (offset + baddr) >> 16;
00393       can_message_.message_data[1] = (offset + baddr) >> 8;  // User application start address is 0x4C0
00394       can_message_.message_data[0] = offset + baddr;
00395       cmd_sent = 1;
00396       unlock(&producing);
00397     }
00398     else
00399     {
00400       check_for_trylock_error(err);
00401     }
00402   }
00403   timedout = false;
00404   wait_time = 0;
00405   timeout = 100;
00406   can_message_sent = false;
00407   can_packet_acked = false;
00408   while (!can_packet_acked)
00409   {
00410     usleep(1000);
00411     if (wait_time > timeout)
00412     {
00413       timedout = true;
00414       break;
00415     }
00416     wait_time++;
00417   }
00418   return timedout;
00419 }
00420 
00459 bool SrEdc::simple_motor_flasher(sr_robot_msgs::SimpleMotorFlasher::Request &req,
00460                                  sr_robot_msgs::SimpleMotorFlasher::Response &res)
00461 {
00462   bfd *fd;
00463   unsigned int base_addr;
00464   unsigned int smallest_start_address = 0x7fff;
00465   unsigned int biggest_end_address = 0;
00466   unsigned int total_size = 0;
00467   bool timedout = true;
00468 
00469   get_board_id_and_can_bus(req.motor_id, &can_bus_, &motor_being_flashed);
00470 
00471   binary_content = NULL;
00472   flashing = true;
00473 
00474   ROS_INFO("Flashing the motor");
00475 
00476   // Initialize the bfd library: "This routine must be called before any other BFD
00477   // function to initialize magical internal data structures."
00478   bfd_init();
00479 
00480   // Open the requested firmware object file
00481   fd = bfd_openr(req.firmware.c_str(), NULL);
00482   if (fd == NULL)
00483   {
00484     ROS_ERROR("error opening the file %s", get_filename(req.firmware).c_str());
00485     res.value = res.FAIL;
00486     flashing = false;
00487     return false;
00488   }
00489 
00490   // Check that bfd recognises the file as a correctly formatted object file
00491   if (!bfd_check_format(fd, bfd_object))
00492   {
00493     if (bfd_get_error() != bfd_error_file_ambiguously_recognized)
00494     {
00495       ROS_ERROR("Incompatible format");
00496       res.value = res.FAIL;
00497       flashing = false;
00498       return false;
00499     }
00500   }
00501 
00502   ROS_INFO("firmware %s's format is : %s.", get_filename(req.firmware).c_str(), fd->xvec->name);
00503 
00504   // @todo Check if it's necessary to send this dummy packet before the magic packet
00505   ROS_DEBUG("Sending dummy packet");
00506   send_CAN_msg(can_bus_, 0, 0, NULL, 1, &timedout);
00507 
00508   ROS_INFO_STREAM("Switching motor " << motor_being_flashed << " on CAN bus " << can_bus_ << " into bootloader mode");
00509   // Send the magic packet that will force the microcontroller to go into bootloader mode
00510   int8u magic_packet[] = {0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA};
00511   send_CAN_msg(can_bus_, 0x0600 | (motor_being_flashed << 5) | 0b1010, 8, magic_packet, 100, &timedout);
00512 
00513   // Send a second magic packet if the first one wasn't acknowledged
00514   if (timedout)
00515   {
00516     ROS_WARN("First magic CAN packet timedout");
00517     ROS_WARN("Sending another magic CAN packet to put the motor in bootloading mode");
00518     send_CAN_msg(can_bus_, 0x0600 | (motor_being_flashed << 5) | 0b1010, 8, magic_packet, 100, &timedout);
00519 
00520     if (timedout)
00521     {
00522       ROS_ERROR("None of the magic packets were ACKed, didn't bootload the motor.");
00523       res.value = res.FAIL;
00524       flashing = false;
00525       return false;
00526     }
00527   }
00528 
00529   // Erase the PIC18 microcontroller flash memory
00530   erase_flash();
00531 
00532   sleep(1);
00533 
00534   // Look for the start and end address of every section in the hex file,
00535   // to detect the lowest and highest address of the data we need to write in the PIC's flash.
00536   find_address_range(fd, &smallest_start_address, &biggest_end_address);
00537 
00538   // Calculate the size of the chunk of data to be flashed
00539   total_size = biggest_end_address - smallest_start_address;
00540   base_addr = smallest_start_address;
00541 
00542   // Allocate the memory space to store the data to be flashed
00543   // This could be done with new bfd_byte[total_size+8] and delete() instead of malloc()
00544   // and free() but will stay this way for the moment
00545   binary_content = reinterpret_cast<bfd_byte *>(malloc(total_size + 8));
00546   if (binary_content == NULL)
00547   {
00548     ROS_ERROR("Error allocating memory for binary_content");
00549     res.value = res.FAIL;
00550     flashing = false;
00551     return false;
00552   }
00553 
00554   // Set all the bytes in the binary_content to 0xFF initially (i.e. before reading the content from the hex file)
00555   // This way we make sure that any byte in the region between smallest_start_address and biggest_end_address
00556   // that is not included in any section of the hex file, will be written with a 0xFF value,
00557   // which is the default in the PIC
00558   memset(binary_content, 0xFF, total_size + 8);
00559 
00560   // The content of the firmware is read from the .hex file pointed by fd, to a memory region pointed by binary_content
00561   if (!read_content_from_object_file(fd, binary_content, base_addr))
00562   {
00563     ROS_ERROR("something went wrong while parsing %s.", get_filename(req.firmware).c_str());
00564     res.value = res.FAIL;
00565     free(binary_content);
00566     flashing = false;
00567     return false;
00568   }
00569 
00570   // We do not need the file anymore
00571   bfd_close(fd);
00572 
00573   // The firmware is actually written to the flash memory of the PIC18
00574   if (!write_flash_data(base_addr, total_size))
00575   {
00576     res.value = res.FAIL;
00577     free(binary_content);
00578     flashing = false;
00579     return false;
00580   }
00581 
00582 
00583   ROS_INFO("Verifying");
00584   // Now we have to read back the flash content
00585   if (!read_back_and_check_flash(base_addr, total_size))
00586   {
00587     res.value = res.FAIL;
00588     free(binary_content);
00589     flashing = false;
00590     return false;
00591   }
00592 
00593 
00594   free(binary_content);
00595 
00596   ROS_INFO("Resetting microcontroller.");
00597   // Then we send the RESET command to PIC18F
00598   timedout = true;
00599   while (timedout)
00600   {
00601     send_CAN_msg(can_bus_, 0x0600 | (motor_being_flashed << 5) | RESET_COMMAND, 0, NULL, 1000, &timedout);
00602   };
00603 
00604   flashing = false;
00605 
00606   ROS_INFO("Flashing done");
00607 
00608   res.value = res.SUCCESS;
00609 
00610   // Reinitialize motor boards or valve controller boards information
00611   reinitialize_boards();
00612 
00613   return true;
00614 }
00615 
00616 void SrEdc::build_CAN_message(ETHERCAT_CAN_BRIDGE_DATA *message)
00617 {
00618   int res;
00619 
00620   if (flashing && !can_packet_acked && !can_message_sent)
00621   {
00622     if (!(res = pthread_mutex_trylock(&producing)))
00623     {
00624       ROS_DEBUG_STREAM("Ethercat bridge data size: " << ETHERCAT_CAN_BRIDGE_DATA_SIZE);
00625 
00626       ROS_DEBUG("We're sending a CAN message for flashing.");
00627       memcpy(message, &can_message_, sizeof(can_message_));
00628       can_message_sent = true;
00629 
00630       ROS_DEBUG(
00631               "Sending : SID : 0x%04X ; bus : 0x%02X ; length : 0x%02X ;"
00632                       " data : 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X",
00633               message->message_id,
00634               message->can_bus,
00635               message->message_length,
00636               message->message_data[0],
00637               message->message_data[1],
00638               message->message_data[2],
00639               message->message_data[3],
00640               message->message_data[4],
00641               message->message_data[5],
00642               message->message_data[6],
00643               message->message_data[7]);
00644 
00645       unlock(&producing);
00646     }
00647     else
00648     {
00649       ROS_ERROR("Mutex is locked, we don't send any CAN message !");
00650       check_for_trylock_error(res);
00651     }
00652   }
00653   else
00654   {
00655     message->can_bus = can_bus_;
00656     message->message_id = 0x00;
00657     message->message_length = 0;
00658   }
00659 }
00660 
00669 bool SrEdc::can_data_is_ack(ETHERCAT_CAN_BRIDGE_DATA *packet)
00670 {
00671   int i;
00672 
00673   if (packet->message_id == 0)
00674   {
00675     ROS_DEBUG("ID is zero");
00676     return false;
00677   }
00678 
00679   ROS_DEBUG("ack sid : %04X", packet->message_id);
00680 
00681   // Is this a reply to a READ request?
00682   if ((packet->message_id & 0b0000011111111111) == (0x0600 | (motor_being_flashed << 5) | 0x10 | READ_FLASH_COMMAND))
00683   {
00684     ROS_DEBUG("READ reply  %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", packet->message_data[0],
00685               packet->message_data[1],
00686               packet->message_data[2],
00687               packet->message_data[3],
00688               packet->message_data[4],
00689               packet->message_data[5],
00690               packet->message_data[6],
00691               packet->message_data[7]);
00692     ROS_DEBUG("Should be   %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", binary_content[pos + 0],
00693               binary_content[pos + 1],
00694               binary_content[pos + 2],
00695               binary_content[pos + 3],
00696               binary_content[pos + 4],
00697               binary_content[pos + 5],
00698               binary_content[pos + 6],
00699               binary_content[pos + 7]);
00700 
00701     if (!memcmp(packet->message_data, binary_content + pos, 8))
00702     {
00703       ROS_DEBUG("data is good");
00704       return true;
00705     }
00706     else
00707     {
00708       ROS_DEBUG("data is bad");
00709       return false;
00710     }
00711   }
00712 
00713   if (packet->message_length != can_message_.message_length)
00714   {
00715     ROS_DEBUG("Length is bad: %d", packet->message_length);
00716     return false;
00717   }
00718 
00719   ROS_DEBUG("Length is OK");
00720 
00721   for (i = 0; i < packet->message_length; ++i)
00722   {
00723     ROS_DEBUG("packet sent, data[%d] : %02X ; ack, data[%d] : %02X", i, can_message_.message_data[i], i,
00724               packet->message_data[i]);
00725     if (packet->message_data[i] != can_message_.message_data[i])
00726     {
00727       return false;
00728     }
00729   }
00730   ROS_DEBUG("Data is OK");
00731 
00732   if (!(0x0010 & packet->message_id))
00733   {
00734     return false;
00735   }
00736 
00737   ROS_DEBUG("This is an ACK");
00738 
00739   if ((packet->message_id & 0b0000000111101111) != (can_message_.message_id & 0b0000000111101111))
00740   {
00741     ROS_WARN_STREAM("Bad packet id: " << packet->message_id);
00742     return false;
00743   }
00744 
00745   ROS_DEBUG("SID is OK");
00746 
00747   ROS_DEBUG("Everything is OK, this is our ACK !");
00748   return true;
00749 }
00750 
00751 void SrEdc::send_CAN_msg(int8u can_bus, int16u msg_id, int8u msg_length, int8u msg_data[], int timeout, bool *timedout)
00752 {
00753   int err;
00754   unsigned char cmd_sent;
00755   int wait_time;
00756 
00757   cmd_sent = 0;
00758   while (!cmd_sent)
00759   {
00760     if (!(err = pthread_mutex_trylock(&producing)))
00761     {
00762       can_message_.message_length = msg_length;
00763       can_message_.can_bus = can_bus;
00764       can_message_.message_id = msg_id;
00765 
00766       if (msg_data != NULL)
00767       {
00768         for (unsigned int i = 0; i < msg_length; i++)
00769         {
00770           can_message_.message_data[i] = msg_data[i];
00771         }
00772       }
00773 
00774       cmd_sent = 1;
00775       unlock(&producing);
00776     }
00777     else
00778     {
00779       check_for_trylock_error(err);
00780     }
00781   }
00782   wait_time = 0;
00783   *timedout = false;
00784   can_message_sent = false;
00785   can_packet_acked = false;
00786   while (!can_packet_acked)
00787   {
00788     usleep(1000);  // 1 ms
00789     wait_time++;
00790     if (wait_time > timeout)
00791     {
00792       *timedout = true;
00793       break;
00794     }
00795   }
00796 }
00797 
00798 bool SrEdc::read_back_and_check_flash(unsigned int baddr, unsigned int total_size)
00799 {
00800   // The actual comparison between the content read from the flash and the content read from
00801   // the hex file is carried out in the can_data_is_ack() function.
00802   // read_flash(...) will return timedout = true if the 8 byte content read from the flash doesn't
00803   // match the 8 bytes from the hex file
00804   // BE CAREFUL with the pos "global" field, because it's being used inside can_data_is_ack()
00805   // function to check if the response of the READ_FLASH_COMMAND is correct
00806   pos = 0;
00807   unsigned int retry;
00808   while (pos < total_size)
00809   {
00810     bool timedout = true;
00811 
00812     retry = 0;
00813     while (timedout)
00814     {
00815       timedout = read_flash(pos, baddr);
00816       if (!timedout)
00817       {
00818         pos += 8;
00819       }
00820       retry++;
00821       if (retry > max_retry)
00822       {
00823         ROS_ERROR("Too much retry for READ back, try flashing again");
00824         return false;
00825       }
00826     };
00827   }
00828   return true;
00829 }
00830 
00831 void SrEdc::find_address_range(bfd *fd, unsigned int *smallest_start_address, unsigned int *biggest_end_address)
00832 {
00833   asection *s;
00834   unsigned int section_size = 0;
00835   unsigned int section_addr = 0;
00836 
00837   // Look for the start and end address of every section in the hex file,
00838   // to detect the lowest and highest address of the data we need to write in the PIC's flash.
00839   // The sections starting at an address higher than 0x7fff will be ignored as they are not proper
00840   // "code memory" firmware
00841   // (they can contain the CONFIG bits of the microcontroller, which we don't want to write here)
00842   // To understand the structure (sections) of the object file containing the firmware (usually a .hex) the following
00843   // commands can be useful:
00844   //  \code objdump -x simplemotor.hex \endcode
00845   //  \code objdump -s simplemotor.hex \endcode
00846   for (s = fd->sections; s; s = s->next)
00847   {
00848     // Only the sections with the LOAD flag on will be considered
00849     if (bfd_get_section_flags(fd, s) & (SEC_LOAD))
00850     {
00851       // Only the sections with the same VMA (virtual memory address) and LMA (load MA) will be considered
00852       // http://www.delorie.com/gnu/docs/binutils/ld_7.html
00853       if (bfd_section_lma(fd, s) == bfd_section_vma(fd, s))
00854       {
00855         section_addr = (unsigned int) bfd_section_lma(fd, s);
00856         if (section_addr >= 0x7fff)
00857         {
00858           continue;
00859         }
00860         section_size = (unsigned int) bfd_section_size(fd, s);
00861         *smallest_start_address = std::min(section_addr, *smallest_start_address);
00862         *biggest_end_address = std::max(*biggest_end_address, section_addr + section_size);
00863       }
00864     }
00865   }
00866 }
00867 
00868 bool SrEdc::read_content_from_object_file(bfd *fd, bfd_byte *content, unsigned int base_addr)
00869 {
00870   asection *s;
00871   unsigned int section_size = 0;
00872   unsigned int section_addr = 0;
00873 
00874   for (s = fd->sections; s; s = s->next)
00875   {
00876     // Only the sections with the LOAD flag on will be considered
00877     if (bfd_get_section_flags(fd, s) & (SEC_LOAD))
00878     {
00879       // Only the sections with the same VMA (virtual memory address) and LMA (load MA) will be considered
00880       // http://www.delorie.com/gnu/docs/binutils/ld_7.html
00881       if (bfd_section_lma(fd, s) == bfd_section_vma(fd, s))
00882       {
00883         section_addr = (unsigned int) bfd_section_lma(fd, s);
00884         // The sections starting at an address higher than 0x7fff will be ignored as they are
00885         // not proper "code memory" firmware
00886         // (they can contain the CONFIG bits of the microcontroller, which we don't want to write here)
00887         if (section_addr >= 0x7fff)
00888         {
00889           continue;
00890         }
00891         section_size = (unsigned int) bfd_section_size(fd, s);
00892         bfd_get_section_contents(fd, s, content + (section_addr - base_addr), 0, section_size);
00893       }
00894       else
00895       {
00896         return false;
00897       }
00898     }
00899     else
00900     {
00901       return false;
00902     }
00903   }
00904   return true;
00905 }
00906 
00907 bool SrEdc::write_flash_data(unsigned int base_addr, unsigned int total_size)
00908 {
00909   int err;
00910   unsigned char cmd_sent;
00911   int wait_time, timeout;
00912 
00913   pos = 0;
00914   unsigned int packet = 0;
00915   ROS_INFO("Sending the firmware data");
00916   while (pos < ((total_size % 32) == 0 ? total_size : (total_size + 32 - (total_size % 32))))
00917   {
00918     bool timedout = true;
00919 
00920     // For every WRITE_FLASH_ADDRESS_COMMAND we write 32 bytes of data to flash
00921     // and this is done by sending 4 WRITE_FLASH_DATA_COMMAND packets, every one containing
00922     // 8 bytes of data to be written
00923     if ((pos % 32) == 0)
00924     {
00925       packet = 0;
00926       while (timedout)
00927       {
00928         cmd_sent = 0;
00929         while (!cmd_sent)
00930         {
00931           if (!(err = pthread_mutex_trylock(&producing)))
00932           {
00933             can_message_.message_length = 3;
00934             can_message_.can_bus = can_bus_;
00935             can_message_.message_id = 0x0600 | (motor_being_flashed << 5) | WRITE_FLASH_ADDRESS_COMMAND;
00936             can_message_.message_data[2] = (base_addr + pos) >> 16;
00937             can_message_.message_data[1] = (base_addr + pos) >> 8;  // User application start address is 0x4C0
00938             can_message_.message_data[0] = base_addr + pos;
00939             ROS_DEBUG("Sending write address to motor %d : 0x%02X%02X%02X", motor_being_flashed,
00940                       can_message_.message_data[2], can_message_.message_data[1], can_message_.message_data[0]);
00941             cmd_sent = 1;
00942             unlock(&producing);
00943           }
00944           else
00945           {
00946             check_for_trylock_error(err);
00947           }
00948         }
00949         wait_time = 0;
00950         timedout = false;
00951         timeout = 100;
00952         can_message_sent = false;
00953         can_packet_acked = false;
00954         while (!can_packet_acked)
00955         {
00956           usleep(1000);
00957           if (wait_time > timeout)
00958           {
00959             timedout = true;
00960             break;
00961           }
00962           wait_time++;
00963         }
00964         if (timedout)
00965         {
00966           ROS_ERROR("WRITE ADDRESS timedout ");
00967         }
00968       };
00969     }
00970     cmd_sent = 0;
00971     while (!cmd_sent)
00972     {
00973       if (!(err = pthread_mutex_trylock(&producing)))
00974       {
00975         ROS_DEBUG("Sending data ... position == %d", pos);
00976         can_message_.message_length = 8;
00977         can_message_.can_bus = can_bus_;
00978         can_message_.message_id = 0x0600 | (motor_being_flashed << 5) | WRITE_FLASH_DATA_COMMAND;
00979         bzero(can_message_.message_data, 8);
00980         for (unsigned char j = 0; j < 8; ++j)
00981         {
00982           can_message_.message_data[j] = (pos > total_size) ? 0xFF : *(binary_content + pos + j);
00983         }
00984 
00985         pos += 8;
00986         cmd_sent = 1;
00987         unlock(&producing);
00988       }
00989       else
00990       {
00991         check_for_trylock_error(err);
00992       }
00993     }
00994     packet++;
00995     timedout = false;
00996     wait_time = 0;
00997     timeout = 100;
00998     can_message_sent = false;
00999     can_packet_acked = false;
01000     while (!can_packet_acked)
01001     {
01002       usleep(1000);
01003       if (wait_time > timeout)
01004       {
01005         timedout = true;
01006         break;
01007       }
01008       wait_time++;
01009     }
01010     if (timedout)
01011     {
01012       ROS_ERROR("A WRITE data packet has been lost at pos=%u, resending the 32 bytes block at pos=%u  !", pos,
01013                 (pos - packet * 8));
01014       pos -= packet * 8;
01015     }
01016   }
01017   return true;
01018 }
01019 
01020 
01021 /* For the emacs weenies in the crowd.
01022    Local Variables:
01023    c-basic-offset: 2
01024    End:
01025  */


sr_edc_ethercat_drivers
Author(s): Ugo Cupcic, Yann Sionneau, Toni Oliver
autogenerated on Mon Jul 1 2019 20:06:31