aboutsummaryrefslogtreecommitdiffstats
path: root/host
diff options
context:
space:
mode:
authorNicholas Corgan <nick.corgan@ettus.com>2015-06-30 13:36:15 -0700
committerMartin Braun <martin.braun@ettus.com>2015-07-09 09:13:41 -0700
commitd9656de88f7af77b39bfe9985f0ac7c623932d71 (patch)
treeed83e5b72fa8c2afd25410ce6e1bece5621896cd /host
parent1449687bb41e9cd39cc3d94413c993a1ec553251 (diff)
downloaduhd-d9656de88f7af77b39bfe9985f0ac7c623932d71.tar.gz
uhd-d9656de88f7af77b39bfe9985f0ac7c623932d71.tar.bz2
uhd-d9656de88f7af77b39bfe9985f0ac7c623932d71.zip
OctoClock bugfixes
* Bumped compatibility version to 3 * firmware: Ethernet, clkdist bugfixes * lib: fixed invalid rev detection
Diffstat (limited to 'host')
-rw-r--r--host/docs/octoclock.dox31
-rw-r--r--host/lib/usrp_clock/octoclock/common.h35
-rw-r--r--host/lib/usrp_clock/octoclock/octoclock_impl.cpp8
-rw-r--r--host/utils/octoclock_firmware_burner.cpp57
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;
}