diff options
Diffstat (limited to 'host/lib/usrp_clock')
| -rw-r--r-- | host/lib/usrp_clock/octoclock/CMakeLists.txt | 8 | ||||
| -rw-r--r-- | host/lib/usrp_clock/octoclock/common.h | 35 | ||||
| -rw-r--r-- | host/lib/usrp_clock/octoclock/ihexcvt.cpp | 250 | ||||
| -rw-r--r-- | host/lib/usrp_clock/octoclock/ihexcvt.hpp | 22 | ||||
| -rw-r--r-- | host/lib/usrp_clock/octoclock/octoclock_eeprom.cpp | 23 | ||||
| -rw-r--r-- | host/lib/usrp_clock/octoclock/octoclock_image_loader.cpp | 340 | ||||
| -rw-r--r-- | host/lib/usrp_clock/octoclock/octoclock_impl.cpp | 8 | ||||
| -rw-r--r-- | host/lib/usrp_clock/octoclock/octoclock_impl.hpp | 2 | 
8 files changed, 647 insertions, 41 deletions
| diff --git a/host/lib/usrp_clock/octoclock/CMakeLists.txt b/host/lib/usrp_clock/octoclock/CMakeLists.txt index e363bb9da..c489657e2 100644 --- a/host/lib/usrp_clock/octoclock/CMakeLists.txt +++ b/host/lib/usrp_clock/octoclock/CMakeLists.txt @@ -1,5 +1,5 @@  # -# Copyright 2011-2014 Ettus Research LLC +# Copyright 2013-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 @@ -16,17 +16,15 @@  #  ######################################################################## -# This file included, use CMake directory variables -######################################################################## - -########################################################################  # Conditionally configure the OctoClock support  ########################################################################  LIBUHD_REGISTER_COMPONENT("OctoClock" ENABLE_OCTOCLOCK ON "ENABLE_LIBUHD" OFF)  IF(ENABLE_OCTOCLOCK)      LIBUHD_APPEND_SOURCES( +        ${CMAKE_CURRENT_SOURCE_DIR}/ihexcvt.cpp          ${CMAKE_CURRENT_SOURCE_DIR}/octoclock_eeprom.cpp +        ${CMAKE_CURRENT_SOURCE_DIR}/octoclock_image_loader.cpp          ${CMAKE_CURRENT_SOURCE_DIR}/octoclock_impl.cpp          ${CMAKE_CURRENT_SOURCE_DIR}/octoclock_uart.cpp      ) 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/ihexcvt.cpp b/host/lib/usrp_clock/octoclock/ihexcvt.cpp new file mode 100644 index 000000000..0605ee61c --- /dev/null +++ b/host/lib/usrp_clock/octoclock/ihexcvt.cpp @@ -0,0 +1,250 @@ +/*  IHexCvt - Intel HEX File <=> Binary Converter (C++) +    Copyright (C) 2014  Ali Nakisaee + +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 +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +GNU General Public License for more details. + + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.*/ + +//Include needed stuff from C++ +#include <iostream> +#include <fstream> +#include <string> + +//... and also from C +#include <stdio.h> + +#include <boost/filesystem.hpp> + +#include <uhd/exception.hpp> +#include "ihexcvt.hpp" + +//Avoid repeating 'std::': +using namespace std; + +//The following function reads a hexadecimal number from a text file. +template <class T> +static bool ReadValueFromHex(ifstream& InputFile, T& outCh, unsigned char* ApplyChecksum) +{ +	char V, L; +	T X = 0; +	outCh = 0; + +	//Get the characters one by one. +	//Remember: These values are big-endian. +	//Remember: Every two hex characters (0-9/A-F) indicate ONE byte. +	for (size_t i = 0; i < 2 * sizeof(T); i++) +	{ +		InputFile.get( V ); +		if (InputFile.fail()) +			return false; + +		X <<= 4; +		if (V >= '0' && V <= '9') +			L = (V - '0'); +		else if (V >= 'a' && V <= 'f') +			L = (V - 'a' + 10); +		else if (V >= 'A' && V <= 'F') +			L = (V - 'A' + 10); +		else +			return false; +		X |= L; + +		//Apply this character to the checksum +		if (ApplyChecksum && i % 2 == 1) *ApplyChecksum += X & 0xFF; +	} + +	//Return... +	outCh = X; +	return true; +} + +//The following function writes a hexadecimal number from a text file. +template <class T> +static bool WriteHexValue(ofstream& OutFile, T Value, unsigned char* CalcChecksum) +{ +	unsigned char V0 = 0; +	char C; + +	//Remember: These values are big-endian. +	for (size_t i = 0; i < sizeof(T); i++) +	{ +		//Get byte #i from the value. +		V0 = (Value >> ((sizeof(T) - i - 1) * 8)) & 0xFF; + +		//Extract the high nibble (4-bits) +		if ((V0 & 0xF0) <= 0x90) +			C = (V0 >> 4) + '0'; +		else +			C = (V0 >> 4) + ('A' - 10); +		OutFile.put( C ); + +		//Extract the low nibble (4-bits) +		if ((V0 & 0xF) <= 0x9) +			C = (V0 & 0xF) + '0'; +		else +			C = (V0 & 0xF) + ('A' - 10); +		OutFile.put( C ); + +		//Calculate the checksum +		if (CalcChecksum) *CalcChecksum += V0; +	} +	return true; +} + +//Skip any incoming whitespaces +static void SkipWhitespace(ifstream& InputFile) +{ +	for (;;) +	{ +		char C; +		InputFile.get(C); +		if (InputFile.eof() || InputFile.fail()) break; +		if (!(C == '\n' || C == '\r' || C == ' ' || C == '\t' || C == '\v')) +		{ +			InputFile.putback(C); +			break; +		} +	} +} + +//The function responsible for conversion from HEX files to BINary. +void Hex2Bin(const char* SrcName, const char* DstName, bool IgnoreChecksum) +{ +	ifstream Src(SrcName); +	if (Src.bad()) +	{ +        throw uhd::runtime_error("Could not convert Intel .hex file to binary."); +	} + +	ofstream Dst(DstName, ios_base::binary); +	if (Dst.bad()) +	{ +        throw uhd::runtime_error("Could not convert Intel .hex file to binary."); +	} + +	char Ch; +	int LineIdx = 1; + +	unsigned char ByteCount; +	unsigned short AddressLow; +	unsigned short Extra; +	unsigned long ExtraL; +	unsigned long AddressOffset = 0; +	unsigned char RecordType; +	unsigned char Data[255]; +	unsigned char CurChecksum; +	unsigned char FileChecksum; +	bool EOFMarker = false; +	bool EOFWarn = false; +	 +	for ( ;; ) +	{ +		Src.get(Ch); +		if (Src.eof()) +			break; +		if (EOFMarker && !EOFWarn) +		{ +            throw uhd::runtime_error("Could not convert Intel .hex file to binary."); +		} +		if (Ch != ':') goto genericErr; + +		CurChecksum = 0; +		if (!ReadValueFromHex( Src, ByteCount, &CurChecksum )) goto genericErr; +		if (!ReadValueFromHex( Src, AddressLow, &CurChecksum )) goto genericErr; +		if (!ReadValueFromHex( Src, RecordType, &CurChecksum )) goto genericErr; + +		switch (RecordType) +		{ +		case 0x00: //Data record +			for (int i = 0; i < ByteCount; i++) +				if (!ReadValueFromHex( Src, Data[i], &CurChecksum )) goto genericErr; +			break; +		case 0x01: //End Marker +			if ( ByteCount != 0 ) +			{ +				goto onErrExit; +			} +			EOFMarker = true; +			break; +		case 0x02: //Extended Segment Address +			if ( ByteCount != 2 || AddressLow != 0 ) +			{ +				goto onErrExit; +			} +			if (!ReadValueFromHex( Src, Extra, &CurChecksum )) goto genericErr; +			AddressOffset = (unsigned long)Extra << 4; +			break; +		case 0x03: //Start Segment Address +			if ( ByteCount != 4 || AddressLow != 0 ) +			{ +				goto onErrExit; +			} +			if (!ReadValueFromHex( Src, ExtraL, &CurChecksum )) goto genericErr; +			break; +		case 0x04: //Extended Linear Address +			if ( ByteCount != 2 || AddressLow != 0 ) +			{ +				goto onErrExit; +			} +			if (!ReadValueFromHex( Src, Extra, &CurChecksum )) goto genericErr; +			AddressOffset = (unsigned long)Extra << 16; +			break; +		case 0x05: //Start Linear Address +			if ( ByteCount != 4 || AddressLow != 0 ) +			{ +				goto onErrExit; +			} +			if (!ReadValueFromHex( Src, ExtraL, &CurChecksum )) goto genericErr; +			break; +		} +		 +		//Verify checksum +		CurChecksum = (~(CurChecksum & 0xFF) + 1) & 0xFF; +		if (!ReadValueFromHex( Src, FileChecksum, NULL )) goto genericErr; +		if (CurChecksum != FileChecksum) +		{ +			if (!IgnoreChecksum) goto onErrExit; +		} + +		//Put Data +		if (RecordType == 0x00) +		{ +			Dst.seekp( AddressLow + AddressOffset ); +			for (int i = 0; i < ByteCount; i++) +			{ +				Dst.put( Data[i] ); +			} +		} + +		//Skip any white space +		SkipWhitespace( Src ); + +		LineIdx++; +	} + +	Dst << flush; +	Dst.close(); + +	return; + +genericErr: +    throw uhd::runtime_error("Invalid Intel .hex file detected."); + +onErrExit: +	Dst.close(); +	Src.close(); +    boost::filesystem::remove(DstName); +    throw uhd::runtime_error("Could not convert Intel .hex file to binary."); +} diff --git a/host/lib/usrp_clock/octoclock/ihexcvt.hpp b/host/lib/usrp_clock/octoclock/ihexcvt.hpp new file mode 100644 index 000000000..d577ece1f --- /dev/null +++ b/host/lib/usrp_clock/octoclock/ihexcvt.hpp @@ -0,0 +1,22 @@ +// +// Copyright 2014 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 +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// +#ifndef _IHEXCVT_HPP_ +#define _IHEXCVT_HPP_ + +void Hex2Bin(const char* SrcName, const char* DstName, bool IgnoreChecksum); + +#endif /* _IHEXCVT_HPP_ */ diff --git a/host/lib/usrp_clock/octoclock/octoclock_eeprom.cpp b/host/lib/usrp_clock/octoclock/octoclock_eeprom.cpp index 93c317191..49d1a0442 100644 --- a/host/lib/usrp_clock/octoclock/octoclock_eeprom.cpp +++ b/host/lib/usrp_clock/octoclock/octoclock_eeprom.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 @@ -19,6 +19,7 @@  #include <uhd/usrp_clock/octoclock_eeprom.hpp>  #include <uhd/transport/udp_simple.hpp>  #include <uhd/usrp/mboard_eeprom.hpp> +#include <uhd/types/byte_vector.hpp>  #include <uhd/types/mac_addr.hpp>  #include <uhd/utils/byteswap.hpp>  #include <boost/assign/list_of.hpp> @@ -37,26 +38,6 @@ using namespace uhd::usrp_clock;  using namespace uhd::transport;  /*********************************************************************** - * Utility functions - **********************************************************************/ - -//! A wrapper around std::copy that takes ranges instead of iterators. -template<typename RangeSrc, typename RangeDst> inline -void byte_copy(const RangeSrc &src, RangeDst &dst){ -    std::copy(boost::begin(src), boost::end(src), boost::begin(dst)); -} - -//! create a string from a byte vector, return empty if invalid ascii -static const std::string bytes_to_string(const byte_vector_t &bytes){ -    std::string out; -    BOOST_FOREACH(boost::uint8_t byte, bytes){ -        if (byte < 32 or byte > 127) return out; -        out += byte; -    } -    return out; -} - -/***********************************************************************   * Implementation   **********************************************************************/  void octoclock_eeprom_t::_load(){ diff --git a/host/lib/usrp_clock/octoclock/octoclock_image_loader.cpp b/host/lib/usrp_clock/octoclock/octoclock_image_loader.cpp new file mode 100644 index 000000000..c88177f0f --- /dev/null +++ b/host/lib/usrp_clock/octoclock/octoclock_image_loader.cpp @@ -0,0 +1,340 @@ +// +// Copyright 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 +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +#include <cstring> +#include <fstream> +#include <iostream> +#include <string> + +#include <boost/cstdint.hpp> +#include <boost/filesystem.hpp> +#include <boost/format.hpp> +#include <boost/lexical_cast.hpp> +#include <boost/thread.hpp> + +#include <uhd/device.hpp> +#include <uhd/image_loader.hpp> +#include <uhd/transport/udp_simple.hpp> +#include <uhd/types/device_addr.hpp> +#include <uhd/types/time_spec.hpp> +#include <uhd/utils/byteswap.hpp> +#include <uhd/utils/paths.hpp> +#include <uhd/utils/static.hpp> + +#include "octoclock_impl.hpp" +#include "common.h" +#include "ihexcvt.hpp" + +namespace fs = boost::filesystem; +using namespace uhd; +using namespace uhd::usrp_clock; +using namespace uhd::transport; + +#define OCTOCLOCK_FIRMWARE_MAX_SIZE_BYTES (1024*120) // Last 8 MB are for bootloader +#define OCTOCLOCK_BLOCK_SIZE              256 + +/* + * OctoClock burn session + */ +typedef struct { +    bool                        valid; +    uhd::device_addr_t          dev_addr; +    std::string                 given_filepath; +    std::string                 actual_filepath; // If using a .hex, this is the converted .bin +    bool                        from_hex; +    boost::uint32_t             size; +    boost::uint16_t             crc; +    boost::uint16_t             num_blocks; +    udp_simple::sptr            ctrl_xport; +    udp_simple::sptr            fw_xport; +    boost::uint8_t              data_in[udp_simple::mtu]; +} octoclock_session_t; + +static void octoclock_calculate_crc(octoclock_session_t &session){ +    std::ifstream ifile(session.actual_filepath.c_str()); +    boost::uint8_t temp_image[OCTOCLOCK_FIRMWARE_MAX_SIZE_BYTES]; +    ifile.read((char*)temp_image, session.size); + +    session.crc = 0xFFFF; +    for(size_t i = 0; i < session.size; i++){ +        session.crc ^= temp_image[i]; +        for(boost::uint8_t j = 0; j < 8; ++j){ +            if(session.crc & 1) session.crc = (session.crc >> 1) ^ 0xA001; +            else session.crc = (session.crc >> 1);  +        }    +    }    + +    ifile.close(); +} + +static void octoclock_validate_firmware_image(octoclock_session_t &session){ +    if(not fs::exists(session.given_filepath)){ +        throw uhd::runtime_error(str(boost::format("Could not find image at path \"%s\"") +                                     % session.given_filepath)); +    } + +    std::string extension = fs::extension(session.given_filepath); +    if(extension == ".bin"){ +        session.actual_filepath = session.given_filepath; +        session.from_hex = false; +    } +    else if(extension == ".hex"){ +        session.actual_filepath = fs::path(fs::path(uhd::get_tmp_path()) / +                                           str(boost::format("octoclock_fw_%d.bin") +                                               % time_spec_t::get_system_time().get_full_secs()) +                                          ).string(); + +        Hex2Bin(session.given_filepath.c_str(), session.actual_filepath.c_str(), false); +        session.from_hex = true; +    } +    else throw uhd::runtime_error(str(boost::format("Invalid extension \"%s\". Extension must be .hex or .bin."))); + +    session.size = fs::file_size(session.actual_filepath); +    if(session.size > OCTOCLOCK_FIRMWARE_MAX_SIZE_BYTES){ +        throw uhd::runtime_error(str(boost::format("The specified firmware image is too large: %d vs. %d") +                                     % session.size % OCTOCLOCK_FIRMWARE_MAX_SIZE_BYTES)); +    } + +    session.num_blocks = (session.size % OCTOCLOCK_BLOCK_SIZE) ? ((session.size / OCTOCLOCK_BLOCK_SIZE) + 1) +                                                               : (session.size / OCTOCLOCK_BLOCK_SIZE); + +    octoclock_calculate_crc(session); +    session.valid = true; +} + +static void octoclock_setup_session(octoclock_session_t &session, +                                    const std::string &filepath){ + +    // If no filepath is given, use the default +    if(filepath == ""){ +        session.given_filepath = find_image_path(str(boost::format("octoclock_r%d_fw.hex") +                                                     % boost::lexical_cast<std::string>( +                                                     session.dev_addr.get("revision","4") +                                                 ))); +    } +    else session.given_filepath = filepath; + +    octoclock_validate_firmware_image(session); + +    session.ctrl_xport = udp_simple::make_connected(session.dev_addr["addr"], +                                                    BOOST_STRINGIZE(OCTOCLOCK_UDP_CTRL_PORT)); +    session.fw_xport   = udp_simple::make_connected(session.dev_addr["addr"], +                                                    BOOST_STRINGIZE(OCTOCLOCK_UDP_FW_PORT)); +} + +static void octoclock_reset_into_bootloader(octoclock_session_t &session){ + +    // Already in bootloader +    if(session.dev_addr["type"] == "octoclock-bootloader") +        return; + +    octoclock_packet_t pkt_out; +    pkt_out.sequence = uhd::htonx<boost::uint32_t>(std::rand()); +    const octoclock_packet_t* pkt_in = reinterpret_cast<const octoclock_packet_t*>(session.data_in); +    size_t len; + +    std::cout << " -- Resetting into bootloader..." << std::flush; +    UHD_OCTOCLOCK_SEND_AND_RECV(session.ctrl_xport, RESET_CMD, pkt_out, len, session.data_in); +    if(UHD_OCTOCLOCK_PACKET_MATCHES(RESET_ACK, pkt_out, pkt_in, len)){ + +        // Make sure this device is now in its bootloader +        boost::this_thread::sleep(boost::posix_time::milliseconds(500)); +        uhd::device_addrs_t octoclocks = uhd::device::find( +                                             uhd::device_addr_t(str(boost::format("addr=%s") +                                                                    % session.dev_addr["addr"] +                                                               ))); +        if(octoclocks.size() == 0){ +            std::cout << "failed." << std::endl; +            throw uhd::runtime_error("Failed to reset OctoClock."); +        } +        else if(octoclocks[0]["type"] != "octoclock-bootloader"){ +            std::cout << "failed." << std::endl; +            throw uhd::runtime_error("Failed to reset OctoClock."); +        } +        else{ +            std::cout << "successful." << std::endl; +            session.dev_addr = octoclocks[0]; +        } +    } +    else{ +        std::cout << "failed." << std::endl; +        throw uhd::runtime_error("Failed to reset OctoClock."); +    } +} + +static void octoclock_burn(octoclock_session_t &session){ + +    // Make sure we're in the bootloader for this +    octoclock_reset_into_bootloader(session); + +    octoclock_packet_t pkt_out; +    pkt_out.sequence = htonx<boost::uint32_t>(std::rand()); +    const octoclock_packet_t* pkt_in = reinterpret_cast<const octoclock_packet_t*>(session.data_in); + +    // Tell OctoClock to prepare for burn +    pkt_out.len = htonx<boost::uint16_t>(session.size); +    size_t len = 0; +    std::cout << " -- Preparing OctoClock for firmware load..." << std::flush; +    pkt_out.len = session.size; +    pkt_out.crc = session.crc; +    UHD_OCTOCLOCK_SEND_AND_RECV(session.fw_xport, PREPARE_FW_BURN_CMD, pkt_out, len, session.data_in); +    if(UHD_OCTOCLOCK_PACKET_MATCHES(FW_BURN_READY_ACK, pkt_out, pkt_in, len)){ +        std::cout << "successful." << std::endl; +    } +    else{ +        std::cout << "failed." << std::endl; +        if(session.from_hex){ +            fs::remove(session.actual_filepath); +        } +        throw uhd::runtime_error("Failed to prepare OctoClock for firmware load."); +    } + +    // Start burning +    std::ifstream image(session.actual_filepath.c_str(), std::ios::binary); +    for(size_t i = 0; i < session.num_blocks; i++){ +        pkt_out.sequence++; +        pkt_out.addr = i * OCTOCLOCK_BLOCK_SIZE; + +        std::cout << str(boost::format("\r -- Loading firmware: %d%% (%d/%d blocks)") +                         % int((double(i)/double(session.num_blocks))*100) +                         % i % session.num_blocks) +                  << std::flush; + +        memset(pkt_out.data, 0, OCTOCLOCK_BLOCK_SIZE); +        image.read((char*)pkt_out.data, OCTOCLOCK_BLOCK_SIZE); +        UHD_OCTOCLOCK_SEND_AND_RECV(session.fw_xport, FILE_TRANSFER_CMD, pkt_out, len, session.data_in); +        if(not UHD_OCTOCLOCK_PACKET_MATCHES(FILE_TRANSFER_ACK, pkt_out, pkt_in, len)){ +            image.close(); +            std::cout << std::endl; +            if(session.from_hex){ +                fs::remove(session.actual_filepath); +            } +            throw uhd::runtime_error("Failed to load firmware."); +        } +    } + +    std::cout << str(boost::format("\r -- Loading firmware: 100%% (%d/%d blocks)") +                     % session.num_blocks % session.num_blocks) +              << std::endl; +    image.close(); +} + +static void octoclock_verify(octoclock_session_t &session){ +     +    octoclock_packet_t pkt_out; +    pkt_out.sequence = htonx<boost::uint32_t>(std::rand()); +    const octoclock_packet_t* pkt_in = reinterpret_cast<const octoclock_packet_t*>(session.data_in); +    size_t len = 0; + +    std::ifstream image(session.actual_filepath.c_str(), std::ios::binary); +    boost::uint8_t image_part[OCTOCLOCK_BLOCK_SIZE]; +    boost::uint16_t cmp_len = 0; +    for(size_t i = 0; i < session.num_blocks; i++){ +        pkt_out.sequence++; +        pkt_out.addr = i * OCTOCLOCK_BLOCK_SIZE; + +        std::cout << str(boost::format("\r -- Verifying firmware load: %d%% (%d/%d blocks)") +                         % int((double(i)/double(session.num_blocks))*100) +                         % i % session.num_blocks) +                  << std::flush; + +        memset(image_part, 0, OCTOCLOCK_BLOCK_SIZE); +        image.read((char*)image_part, OCTOCLOCK_BLOCK_SIZE); +        cmp_len = image.gcount(); + +        UHD_OCTOCLOCK_SEND_AND_RECV(session.fw_xport, READ_FW_CMD, pkt_out, len, session.data_in); +        if(UHD_OCTOCLOCK_PACKET_MATCHES(READ_FW_ACK, pkt_out, pkt_in, len)){ +            if(memcmp(pkt_in->data, image_part, cmp_len)){ +                std::cout << std::endl; +                image.close(); +                if(session.from_hex){ +                    fs::remove(session.actual_filepath); +                } +                throw uhd::runtime_error("Failed to verify OctoClock firmware."); +            } +        } +        else{ +            std::cout << std::endl; +            image.close(); +            if(session.from_hex){ +                fs::remove(session.actual_filepath); +            } +            throw uhd::runtime_error("Failed to verify OctoClock firmware."); +        } +    } + +    image.close(); +    if(session.from_hex){ +        fs::remove(session.actual_filepath); +    } +    std::cout << str(boost::format("\r -- Verifying firmware load: 100%% (%d/%d blocks)") +                     % session.num_blocks % session.num_blocks) +              << std::endl; +} + +static void octoclock_finalize(octoclock_session_t &session){ +     +    octoclock_packet_t pkt_out; +    pkt_out.sequence = htonx<boost::uint32_t>(std::rand()); +    const octoclock_packet_t* pkt_in = reinterpret_cast<const octoclock_packet_t*>(session.data_in); +    size_t len = 0; + +    std::cout << " -- Finalizing firmware load..." << std::flush; +    UHD_OCTOCLOCK_SEND_AND_RECV(session.fw_xport, FINALIZE_BURNING_CMD, pkt_out, len, session.data_in); +    if(UHD_OCTOCLOCK_PACKET_MATCHES(FINALIZE_BURNING_ACK, pkt_out, pkt_in, len)){ +        std::cout << "successful." << std::endl; +    } +    else{ +        std::cout << "failed." << std::endl; +        throw uhd::runtime_error("Failed to finalize OctoClock firmware load."); +    } +} + +bool octoclock_image_loader(const image_loader::image_loader_args_t &image_loader_args){ +    // See if we can find an OctoClock with the given args +    device_addrs_t devs = octoclock_find(image_loader_args.args); +    if(devs.size() == 0 or !image_loader_args.load_firmware) return false; + +    octoclock_session_t session; +    session.dev_addr = devs[0]; +    octoclock_setup_session(session, +                            image_loader_args.firmware_path +                           ); + +    std::cout << boost::format("Unit: OctoClock (%s)") +                 % session.dev_addr["addr"] +              << std::endl; +    std::cout << "Firmware: " << session.given_filepath << std::endl; + +    octoclock_burn(session); +    octoclock_verify(session); +    octoclock_finalize(session); + +    return true; +} + +UHD_STATIC_BLOCK(register_octoclock_image_loader){ +    std::string recovery_instructions = "Aborting. Your OctoClock firmware is now corrupt. The bootloader\n" +                                        "is functional, but the device will not have functional clock distribution." +                                        "Run this utility again to restore functionality or refer to:\n\n" +                                        "http://files.ettus.com/manual/page_octoclock.html\n\n" +                                        "for alternative setups."; + +    image_loader::register_image_loader("octoclock", +                                        octoclock_image_loader, +                                        recovery_instructions); +} 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/lib/usrp_clock/octoclock/octoclock_impl.hpp b/host/lib/usrp_clock/octoclock/octoclock_impl.hpp index ab45cd5f0..453e75ec5 100644 --- a/host/lib/usrp_clock/octoclock/octoclock_impl.hpp +++ b/host/lib/usrp_clock/octoclock/octoclock_impl.hpp @@ -31,6 +31,8 @@  #include "common.h" +uhd::device_addrs_t octoclock_find(const uhd::device_addr_t &hint); +  /*!   * OctoClock implementation guts   */ | 
