diff options
Diffstat (limited to 'host')
| -rw-r--r-- | host/docs/octoclock.dox | 31 | ||||
| -rw-r--r-- | host/lib/usrp_clock/octoclock/common.h | 35 | ||||
| -rw-r--r-- | host/lib/usrp_clock/octoclock/octoclock_impl.cpp | 8 | ||||
| -rw-r--r-- | host/utils/octoclock_firmware_burner.cpp | 57 | 
4 files changed, 77 insertions, 54 deletions
diff --git a/host/docs/octoclock.dox b/host/docs/octoclock.dox index 45a12e93a..58d2b1f99 100644 --- a/host/docs/octoclock.dox +++ b/host/docs/octoclock.dox @@ -7,41 +7,24 @@  - Hardware Capabilities:      -   Fully integrated timing source with 8-Way distribution (10 MHz and 1 PPS)      -   User selection between internal GPSDO (when present) or external 10 MHz/1 PPS source +    -   Ethernet bootloader for easy firmware upgrade      -   Source detection with automatic switch over in case of failure or disconnect      -   Streaming GPS time and NMEA strings over Ethernet (OctoClock-G only)  \section octoclock_load Loading Firmware onto the Octoclock -\subsection bootloader OctoClock bootloader - -If you purchased your OctoClock device before Ethernet functionality was introduced, or if your unit's -bootloader has somehow become corrupted, you must burn the bootloader onto the device before you can load -the primary firmware. - -To load the bootloader onto the OctoClock, two things are needed: - -- AVR programmer -- AVRdude software - -Connect the AVR programmer to J108, as specified on the <a href="http://files.ettus.com/schematics/octoclock/octoclock.pdf"> -schematics</a>. Once you verify that the programmer is properly connected, run the following commands to burn the firmware: +First, the OctoClock's bootloader needs to be loaded onto the device. Connect the AVR programmer to J108, as +specified on the <a href="http://files.ettus.com/schematics/octoclock/octoclock.pdf">schematics</a>. Once you +verify that the programmer is properly connected, run the following commands to load the bootloader:      cd <install path>/share/uhd/images -    avrdude -p atmega128 -c <programmer name> -P usb -U efuse:w:0xFF:m -U hfuse:w:0x80:m -U lfuse:w:0xFF:m -U flash:w:octoclock_bootloader.hex:i +    avrdude -p atmega128 -c <programmer name> -P usb -U efuse:w:0xFF:m -U hfuse:w:0x80:m -U lfuse:w:0xEF:m -U flash:w:octoclock_r4_fw.hex:i + +When the bootloader is loaded, it will have a default IP address of `192.168.10.3`.  \b Note:  On Linux, `sudo avrdude ...` might be necessary to gain access to the programmer. -Once the bootloader has been burned, power-cycle your OctoClock device and refer to the below instructions on burning the OctoClock's -primary firmware. - -\subsection application Primary Octoclock firmware - -To load firmware onto the OctoClock, you must use the `octoclock_firmware_burner` utility, specifying the IP -address of the OctoClock device, as follows: - -    octoclock_firmware_burner --addr=192.168.10.3 -  \section octoclock_network Setting Up Networking  \subsection host_interface Setting up the host interface diff --git a/host/lib/usrp_clock/octoclock/common.h b/host/lib/usrp_clock/octoclock/common.h index 96acbb30f..5861bc4b1 100644 --- a/host/lib/usrp_clock/octoclock/common.h +++ b/host/lib/usrp_clock/octoclock/common.h @@ -1,5 +1,5 @@  /* - * Copyright 2014 Ettus Research LLC + * Copyright 2014-2015 Ettus Research LLC   *   * This program is free software: you can redistribute it and/or modify   * it under the terms of the GNU General Public License as published by @@ -42,11 +42,11 @@ extern "C" {   * only valid C code should go in this section.   */ -//These values are placed in the octoclock_packet_t.proto_ver field +// These values are placed in the octoclock_packet_t.proto_ver field  #define OCTOCLOCK_BOOTLOADER_PROTO_VER 1234 -#define OCTOCLOCK_FW_COMPAT_NUM 2 +#define OCTOCLOCK_FW_COMPAT_NUM           3 -//UDP ports assigned for different tasks +// UDP ports assigned for different tasks  #define OCTOCLOCK_UDP_CTRL_PORT   50000  #define OCTOCLOCK_UDP_GPSDO_PORT  50001  #define OCTOCLOCK_UDP_FW_PORT     50002 @@ -98,11 +98,21 @@ typedef enum {  } ref_t;  typedef enum { -    UP, -    DOWN +    PREFER_INTERNAL, +    PREFER_EXTERNAL  } switch_pos_t; +/* + * Some versions of AVR-GCC ignore #pragma pack, so + * if AVR-GCC is being used, use __attribute__ + * instead. + */ +#ifdef AVR +#define __AVR_ALIGNED__ __attribute__((aligned(1))) +#else +#define __AVR_ALIGNED__  #pragma pack(push,1) +#endif  // Structure of values in EEPROM, starting in location 0  typedef struct { @@ -113,34 +123,37 @@ typedef struct {      uint8_t serial[10];      uint8_t name[10];      uint8_t revision; -} octoclock_fw_eeprom_t; +} octoclock_fw_eeprom_t __AVR_ALIGNED__;  typedef struct {      uint8_t external_detected;      uint8_t gps_detected;      uint8_t which_ref;      uint8_t switch_pos; -} octoclock_state_t; +} octoclock_state_t __AVR_ALIGNED__;  typedef struct {      uint8_t num_wraps;      uint8_t pos; -} gpsdo_cache_state_t; +} gpsdo_cache_state_t __AVR_ALIGNED__;  typedef struct {      uint32_t proto_ver;      uint32_t sequence;      uint8_t code;      union { -        uint16_t len; +        uint16_t crc;          gpsdo_cache_state_t state;          uint16_t poolsize;          uint16_t addr;      };      uint8_t data[256]; -} octoclock_packet_t; +    uint16_t len; +} octoclock_packet_t __AVR_ALIGNED__; +#ifndef AVR  #pragma pack(pop) +#endif  #ifdef __cplusplus  } diff --git a/host/lib/usrp_clock/octoclock/octoclock_impl.cpp b/host/lib/usrp_clock/octoclock/octoclock_impl.cpp index b98d95725..ef1bc8ca0 100644 --- a/host/lib/usrp_clock/octoclock/octoclock_impl.cpp +++ b/host/lib/usrp_clock/octoclock/octoclock_impl.cpp @@ -357,14 +357,14 @@ void octoclock_impl::_get_state(const std::string &oc){  }  uhd::dict<ref_t, std::string> _ref_strings = boost::assign::map_list_of -    (NO_REF, "none") +    (NO_REF,   "none")      (INTERNAL, "internal")      (EXTERNAL, "external")  ;  uhd::dict<switch_pos_t, std::string> _switch_pos_strings = boost::assign::map_list_of -    (UP, "Prefer internal") -    (DOWN, "Prefer external") +    (PREFER_INTERNAL, "Prefer internal") +    (PREFER_EXTERNAL, "Prefer external")  ;  sensor_value_t octoclock_impl::_ext_ref_detected(const std::string &oc){ @@ -410,7 +410,7 @@ boost::uint32_t octoclock_impl::_get_time(const std::string &oc){  }  std::string octoclock_impl::_get_images_help_message(const std::string &addr){ -    const std::string image_name = "octoclock_r4_fw.bin"; +    const std::string image_name = "octoclock_r4_fw.hex";      //Check to see if image is in default location      std::string image_location; diff --git a/host/utils/octoclock_firmware_burner.cpp b/host/utils/octoclock_firmware_burner.cpp index d624095e6..eb8198a2b 100644 --- a/host/utils/octoclock_firmware_burner.cpp +++ b/host/utils/octoclock_firmware_burner.cpp @@ -1,5 +1,5 @@  // -// Copyright 2014 Ettus Research LLC +// Copyright 2014-2015 Ettus Research LLC  //  // This program is free software: you can redistribute it and/or modify  // it under the terms of the GNU General Public License as published by @@ -74,8 +74,23 @@ boost::uint8_t firmware_image[MAX_FIRMWARE_SIZE];  size_t firmware_size = 0;  boost::uint8_t octoclock_data[udp_simple::mtu];  octoclock_packet_t *pkt_in = reinterpret_cast<octoclock_packet_t *>(octoclock_data); -std::string firmware_path; +std::string firmware_path, actual_firmware_path;  size_t num_blocks = 0; +bool hex = true; + +static uint16_t calculate_crc(boost::uint8_t* buffer, boost::uint16_t len){ +    boost::uint16_t crc = 0xFFFF; + +    for(size_t i = 0; i < len; i++){ +        crc ^= buffer[i]; +        for(boost::uint8_t j = 0; j < 8; ++j){ +            if(crc & 1) crc = (crc >> 1) ^ 0xA001; +            else crc = (crc >> 1); +        } +    } + +    return crc; +}  /*   * Functions @@ -121,26 +136,25 @@ device_addrs_t bootloader_find(const std::string &ip_addr){  }  void read_firmware(){ -    std::ifstream firmware_file(firmware_path.c_str(), std::ios::binary); -    firmware_file.seekg(0, std::ios::end); -    firmware_size = size_t(firmware_file.tellg()); +    std::ifstream firmware_file(actual_firmware_path.c_str(), std::ios::binary); +    firmware_size = size_t(fs::file_size(actual_firmware_path));      if(firmware_size > MAX_FIRMWARE_SIZE){          firmware_file.close();          throw uhd::runtime_error(str(boost::format("Firmware file too large: %d > %d")                                       % firmware_size % (MAX_FIRMWARE_SIZE)));      } -    firmware_file.seekg(0, std::ios::beg);      firmware_file.read((char*)firmware_image, firmware_size);      firmware_file.close(); -    num_blocks = (firmware_size % BLOCK_SIZE) ? (firmware_size / BLOCK_SIZE) -                                              : ((firmware_size / BLOCK_SIZE) + 1); +    num_blocks = (firmware_size % BLOCK_SIZE) ? ((firmware_size / BLOCK_SIZE) + 1) +                                              : (firmware_size / BLOCK_SIZE);  }  void burn_firmware(udp_simple::sptr udp_transport){      octoclock_packet_t pkt_out;      pkt_out.sequence = uhd::htonx<boost::uint32_t>(std::rand()); -    pkt_out.len = uhd::htonx<boost::uint16_t>((boost::uint16_t)firmware_size); +    pkt_out.len = (boost::uint16_t)firmware_size; +    pkt_out.crc = calculate_crc(firmware_image, firmware_size);      size_t len = 0, current_pos = 0;      //Tell OctoClock not to jump to application, wait for us instead @@ -149,6 +163,7 @@ void burn_firmware(udp_simple::sptr udp_transport){      if(UHD_OCTOCLOCK_PACKET_MATCHES(FW_BURN_READY_ACK, pkt_out, pkt_in, len)) std::cout << "ready." << std::endl;      else{          std::cout << std::endl; +        if(hex) fs::remove(actual_firmware_path);          throw uhd::runtime_error("Could not get OctoClock in valid state for firmware download.");      } @@ -165,7 +180,7 @@ void burn_firmware(udp_simple::sptr udp_transport){                    << "% (" << (i+1) << "/" << num_blocks << " blocks)" << std::flush;          memset(pkt_out.data, 0, BLOCK_SIZE); -        memcpy((void*)(pkt_out.data), &firmware_image[i*BLOCK_SIZE], std::min(int(firmware_size-current_pos), BLOCK_SIZE)); +        memcpy((void*)(pkt_out.data), &firmware_image[i*BLOCK_SIZE], BLOCK_SIZE);          bool success = false;          while(num_tries <= 5){ @@ -181,6 +196,7 @@ void burn_firmware(udp_simple::sptr udp_transport){          }          if(not success){              std::cout << std::endl; +            if(hex) fs::remove(actual_firmware_path);              throw uhd::runtime_error("Failed to burn firmware to OctoClock!");          } @@ -196,7 +212,6 @@ void verify_firmware(udp_simple::sptr udp_transport){      pkt_out.sequence = uhd::htonx<boost::uint32_t>(std::rand());      size_t len = 0, current_pos = 0; -      for(size_t i = 0; i < num_blocks; i++){          pkt_out.sequence++;          pkt_out.addr = i*BLOCK_SIZE; @@ -208,11 +223,13 @@ void verify_firmware(udp_simple::sptr udp_transport){              if(memcmp((void*)(pkt_in->data), &firmware_image[i*BLOCK_SIZE],                        std::min(int(firmware_size-current_pos), BLOCK_SIZE))){                  std::cout << std::endl; +                if(hex) fs::remove(actual_firmware_path);                  throw uhd::runtime_error("Failed to verify OctoClock firmware!");              }          }          else{              std::cout << std::endl; +            if(hex) fs::remove(actual_firmware_path);              throw uhd::runtime_error("Failed to verify OctoClock firmware!");          }      } @@ -230,6 +247,7 @@ bool reset_octoclock(const std::string &ip_addr){      UHD_OCTOCLOCK_SEND_AND_RECV(udp_transport, RESET_CMD, pkt_out, len, octoclock_data);      if(not UHD_OCTOCLOCK_PACKET_MATCHES(RESET_ACK, pkt_out, pkt_in, len)){          std::cout << std::endl; +        if(hex) fs::remove(actual_firmware_path);          throw uhd::runtime_error("Failed to place device in state to receive firmware.");      } @@ -246,11 +264,13 @@ void finalize(udp_simple::sptr udp_transport){      UHD_OCTOCLOCK_SEND_AND_RECV(udp_transport, FINALIZE_BURNING_CMD, pkt_out, len, octoclock_data);      if(not UHD_OCTOCLOCK_PACKET_MATCHES(FINALIZE_BURNING_ACK, pkt_out, pkt_in, len)){          std::cout << std::endl; +        if(hex) fs::remove(actual_firmware_path);          std::cout << "no ACK. Bootloader may not have loaded application." << std::endl;      }  } -int UHD_SAFE_MAIN(int argc, char *argv[]){ +int UHD_SAFE_MAIN(UHD_UNUSED(int argc), UHD_UNUSED(char *argv[])){ +      std::string ip_addr;      po::options_description desc("Allowed options");      desc.add_options() @@ -300,7 +320,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){              throw uhd::runtime_error(str(boost::format("This filepath does not exist: %s") % firmware_path));          }      } -    else firmware_path = find_image_path("octoclock_r4_fw.bin"); +    else firmware_path = find_image_path("octoclock_r4_fw.hex");      //If Intel hex file detected, convert to binary      std::string ext = fs::extension(firmware_path); @@ -312,9 +332,11 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){                                                            % time_spec_t::get_system_time().get_full_secs()));          Hex2Bin(firmware_path.c_str(), temp_bin.string().c_str(), false); -        firmware_path = temp_bin.string(); +        actual_firmware_path = temp_bin.string();      }      else if(ext == ".bin"){ +        hex = false; +        actual_firmware_path = firmware_path;          std::cout << "Found firmware at path: " << firmware_path << std::endl;      }      else throw uhd::runtime_error("The firmware file has in improper extension (must be .hex or .bin)."); @@ -327,6 +349,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){              if(reset_octoclock(ip_addr)) std::cout << "successful." << std::endl;              else{                  std::cout << "failed." << std::endl; +                if(hex) fs::remove(actual_firmware_path);                  throw uhd::runtime_error("Failed to reset OctoClock device into its bootloader.");              }          } @@ -334,6 +357,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){      }      else{          std::cout << "failed." << std::endl; +        if(hex) fs::remove(actual_firmware_path);          throw uhd::runtime_error("Could not find OctoClock with given IP address!");      } @@ -354,7 +378,8 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){      if(octoclocks.size() == 1){          if(octoclocks[0]["type"] == "octoclock-bootloader"){              std::cout << std::endl; -            throw uhd::runtime_error("OctoClock failed to leave bootloader state."); +            if(hex) fs::remove(actual_firmware_path); +            throw uhd::runtime_error("Firmware did not load properly.");          }          else{              std::cout << "found." << std::endl << std::endl @@ -363,8 +388,10 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){      }      else{          std::cout << std::endl; +        if(hex) fs::remove(actual_firmware_path);          throw uhd::runtime_error("Failed to reinitialize OctoClock.");      } +    if(hex) fs::remove(actual_firmware_path);      return EXIT_SUCCESS;  }  | 
