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
00067
00068 BOOST_STATIC_ASSERT(sizeof(EDC_COMMAND) == 4);
00069 }
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: \
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
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
00187
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
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
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
00234
00235
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_,
00241 command_size_,
00242 0x00,
00243 0x07,
00244 ethercat_command_data_address,
00245 0x00,
00246 false,
00247 true,
00248 true);
00249
00250
00251
00252
00253
00254
00255
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
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;
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
00477
00478 bfd_init();
00479
00480
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
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
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
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
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
00530 erase_flash();
00531
00532 sleep(1);
00533
00534
00535
00536 find_address_range(fd, &smallest_start_address, &biggest_end_address);
00537
00538
00539 total_size = biggest_end_address - smallest_start_address;
00540 base_addr = smallest_start_address;
00541
00542
00543
00544
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
00555
00556
00557
00558 memset(binary_content, 0xFF, total_size + 8);
00559
00560
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
00571 bfd_close(fd);
00572
00573
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
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
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
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
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);
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
00801
00802
00803
00804
00805
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
00838
00839
00840
00841
00842
00843
00844
00845
00846 for (s = fd->sections; s; s = s->next)
00847 {
00848
00849 if (bfd_get_section_flags(fd, s) & (SEC_LOAD))
00850 {
00851
00852
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
00877 if (bfd_get_section_flags(fd, s) & (SEC_LOAD))
00878 {
00879
00880
00881 if (bfd_section_lma(fd, s) == bfd_section_vma(fd, s))
00882 {
00883 section_addr = (unsigned int) bfd_section_lma(fd, s);
00884
00885
00886
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
00921
00922
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;
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
01022
01023
01024
01025