diff --git a/src/mtn_downloader/CMakeLists.txt b/src/mtn_downloader/CMakeLists.txt new file mode 100755 index 0000000000000000000000000000000000000000..0fcb718b0fc6d3253c066f0773257632b6fd533c --- /dev/null +++ b/src/mtn_downloader/CMakeLists.txt @@ -0,0 +1,35 @@ +# locate the necessary dependencies +FIND_PACKAGE(iriutils REQUIRED) +FIND_PACKAGE(comm REQUIRED) +FIND_PACKAGE(robotis_bin_parser REQUIRED) +FIND_PACKAGE(robotis_mtn REQUIRED) +FIND_PACKAGE(robotis_mtn_parser REQUIRED) + +# add the necessary include directories +INCLUDE_DIRECTORIES(.) +INCLUDE_DIRECTORIES(${iriutils_INCLUDE_DIR}) +INCLUDE_DIRECTORIES(${comm_INCLUDE_DIR}) +INCLUDE_DIRECTORIES(${robotis_bin_parser_INCLUDE_DIR}) +INCLUDE_DIRECTORIES(${robotis_mtn_parser_INCLUDE_DIR}) +INCLUDE_DIRECTORIES(${robotis_mtn_INCLUDE_DIR}) + +# application source files +SET(sources mtn_downloader.cpp) +# application header files +SET(headers mtn_downloader.h) + +# create the executable file +ADD_EXECUTABLE(mtn_downloader ${sources}) + +# link necessary libraries +TARGET_LINK_LIBRARIES(mtn_downloader ${iriutils_LIBRARY}) +TARGET_LINK_LIBRARIES(mtn_downloader ${comm_LIBRARY}) +TARGET_LINK_LIBRARIES(mtn_downloader ${robotis_bin_parser_LIBRARY}) +TARGET_LINK_LIBRARIES(mtn_downloader ${robotis_mtn_parser_LIBRARY}) +TARGET_LINK_LIBRARIES(mtn_downloader ${robotis_mtn_LIBRARY}) + +INSTALL(TARGETS mtn_downloader + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib/iridrivers + ARCHIVE DESTINATION lib/iridrivers) + diff --git a/src/mtn_downloader/mtn_downloader.cpp b/src/mtn_downloader/mtn_downloader.cpp new file mode 100755 index 0000000000000000000000000000000000000000..5ec37cc469377d13665c692ea8d8d2e889835c55 --- /dev/null +++ b/src/mtn_downloader/mtn_downloader.cpp @@ -0,0 +1,282 @@ +#include "eventexceptions.h" +#include "eventserver.h" +#include "exceptions.h" +#include "rs232.h" +#include "mtn_file_parser.hpp" +#include "robotis_bin_parser.h" +#include "mtn_exceptions.h" +#include <stdlib.h> +#include <getopt.h> +#include <string.h> +#include <stdio.h> +#include <iostream> +#include <sys/stat.h> + +const unsigned char bootloader_ping='#'; +const unsigned char bootloader_ack='\n'; +const unsigned char bootloader_load[]="l 0x0001E000\0"; +const unsigned char bootloader_go='g'; + +#define MTN_FILE_SIZE (128*1024) + +void show_help(char *name) +{ + std::cout << "Usage: " << name << "-d <serial device> -f <firmware file> -p <protocol> [-h]" << std::endl; + std::cout << " -d serial_device Linux serial device used to communicate" << std::endl; + std::cout << " -m motion_file desired motion file in either .mtn or .bin format" << std::endl; + std::cout << " -h shows this help" << std::endl; +} + +int main(int argc,char *argv[]) +{ + // serial port objects + CEventServer *event_server=CEventServer::instance(); + CRS232 serial_port("mtn_serial_dev"); + std::list<std::string> events; + TRS232_config serial_config; + long int num_data=0,i=0; + bool end=false; + int option; + std::string opt_device,opt_mtn_file,mtn_ext; + // binary file variables + int bin_file_fd; + struct stat st; + unsigned char binary_file[MTN_FILE_SIZE]; + long int downloaded_size=0; + long int start_address=0; + long int binary_size=0; + int block_size=0,count=0; + // bootloader variables + unsigned char bootloader_data[MTN_FILE_SIZE]; + bool bootloader_connected=false; + unsigned char checksum=0x00; + // mtn file parser + MTN::CMtnFileParser mtn_parser; + CRobotisMtn motions; + CBinFileParser bin_parser; + std::string bin_filename; + std::string servo_type("AX-12A"); + + // configuration information for the serial device + serial_config.baud=57600; + serial_config.num_bits=8; + serial_config.parity=none; + serial_config.stop_bits=1; + + memset(binary_file,0xFF,MTN_FILE_SIZE); + + // parse the input arguments + while((option = getopt(argc, argv, "hd:m:")) != -1) + { + switch(option) + { + case 'h':// show help message + show_help(argv[0]); + break; + case 'd':// select serial device + std::cout << "Output device: " << optarg << std::endl; + opt_device=std::string(optarg); + break; + case 'm':// select motion file + std::cout << "Motion file: " << optarg << std::endl; + opt_mtn_file=std::string(optarg); + break; + } + } + + // check that the two arguments have been entered + if(opt_device.size()!=0) + { + if(opt_mtn_file.size()==0) + { + std::cout << "No motion file has been specified" << std::endl; + show_help(argv[0]); + return 0; + } + else + { + try{ + // open the serial port + serial_port.open((void *)&opt_device); + // configure the serial port + serial_port.config(&serial_config); + // get the recevice event + events.push_back(serial_port.get_rx_event_id()); + // convert the hex file to a binary file + if(opt_mtn_file.size()!=0) + { + // check if the motion file is in .mtn format + if(opt_mtn_file.find(".mtn")!=std::string::npos) + { + std::cout << servo_type << std::endl; + try{ + mtn_parser.parse(opt_mtn_file.c_str()); + mtn_parser.get_motions(motions); + for(i=0;i<motions.get_num_servos();i++) + motions.set_motor_type(i,servo_type); + bin_parser.set_motions(motions); + bin_filename=opt_mtn_file; + bin_filename.replace(bin_filename.find(".mtn"),std::string(".mtn").length(),".bin"); + bin_parser.serialize(bin_filename.c_str()); + }catch(CMtnException &e){ + std::cout << e.what() << std::endl; + return 0; + } + // open adn read the generated binary file + if((bin_file_fd=::open(bin_filename.c_str(),O_RDONLY))==-1) + { + std::cout << "Impossible to read the binary file" << std::endl; + return 0; + } + } + else + { + if((bin_file_fd=::open(opt_mtn_file.c_str(),O_RDONLY))==-1) + { + std::cout << "Impossible to read the binary file" << std::endl; + return 0; + } + } + // check the binary file + stat(bin_filename.c_str(), &st); + if(st.st_size!=MTN_FILE_SIZE) + { + ::close(bin_file_fd); + std::cout << "Incorrect motion file size. It should be 128kB long" << std::endl; + return 0; + } + // read the file + if(::read(bin_file_fd,binary_file,MTN_FILE_SIZE)==-1) + { + ::close(bin_file_fd); + std::cout << "Error while reading the motion file" << std::endl; + return 0; + } + // close the file + ::close(bin_file_fd); + binary_size=MTN_FILE_SIZE; + start_address=0; + } + std::cout << "Switch off device power and turn it on" << std::endl; + // ping the device + while(!bootloader_connected) + { + try{ + event_server->wait_all(events,20); + num_data=serial_port.get_num_data(); + serial_port.read((unsigned char *)bootloader_data,num_data); + bootloader_data[num_data]='\0'; + printf("%s",bootloader_data); + fflush(stdout); + for(i=0;i<num_data;i++) + { + if(bootloader_data[i]=='#') + { + count++; + if(count==5) + bootloader_connected=true; + } + } + }catch(CEventTimeoutException &e){ + // do nothing and retry + serial_port.write((unsigned char *)&bootloader_ping, 1); + } + } + /* send acknowledgment to the device*/ + serial_port.write((unsigned char *)&bootloader_ack, 1); + while(!end) + { + try{ + event_server->wait_all(events,300); + num_data=serial_port.get_num_data(); + serial_port.read(bootloader_data,num_data); + bootloader_data[num_data]='\0'; + printf("%s",bootloader_data); + fflush(stdout); + }catch(CEventTimeoutException &e){ + // the flash has been properly erased + end=true; + } + } + end=false; + // start the download + serial_port.write((unsigned char *)&bootloader_load,strlen((char *)bootloader_load)); + serial_port.write((unsigned char *)&bootloader_ack,1); + while(!end) + { + try{ + event_server->wait_all(events,300); + num_data=serial_port.get_num_data(); + serial_port.read(bootloader_data,num_data); + bootloader_data[num_data]='\0'; + printf("%s",bootloader_data); + fflush(stdout); + }catch(CEventTimeoutException &e){ + // the flash has been properly erased + end=true; + } + } + // compute the binary file checksum + for(i=0;i<binary_size;i++) + checksum+=binary_file[start_address+i]; + // send the binary file in 64 byte segments + while(downloaded_size < binary_size) + { + usleep(1000); + block_size=binary_size-downloaded_size; + if(block_size>64) + block_size=64; + serial_port.write(&binary_file[start_address+downloaded_size],block_size); + downloaded_size+=block_size; + printf("\rDownloading Firmware (%ld/%ld byte)", downloaded_size, binary_size); + fflush(stdout); + } + // send the checksum + serial_port.write(&checksum,1); + std::cout << std::endl << "Download complete" << std::endl; + end=false; + while(!end) + { + try{ + event_server->wait_all(events,300); + // there has been an error + num_data=serial_port.get_num_data(); + serial_port.read(bootloader_data,num_data); + bootloader_data[num_data]='\0'; + printf("%s",bootloader_data); + }catch(CEventTimeoutException &e){ + // no error to report + end=true; + } + } + // start the loaded program + serial_port.write((unsigned char *)&bootloader_go,1); + serial_port.write((unsigned char *)&bootloader_ack,1); + end=false; + while(!end) + { + try{ + event_server->wait_all(events,300); + // there has been an error + num_data=serial_port.get_num_data(); + serial_port.read(bootloader_data,num_data); + bootloader_data[num_data]='\0'; + printf("%s",bootloader_data); + }catch(CEventTimeoutException &e){ + // no error to report + end=true; + } + } + serial_port.close(); + }catch(CException &e){ + /* handle exceptions */ + std::cout << e.what() << std::endl; + } + } + } + else + { + std::cout << "No serial device specified" << std::endl; + show_help(argv[0]); + } +}