diff options
Diffstat (limited to 'host/utils')
| -rw-r--r-- | host/utils/CMakeLists.txt | 16 | ||||
| -rw-r--r-- | host/utils/fx2_init_eeprom.cpp | 6 | ||||
| -rw-r--r-- | host/utils/ihexcvt.cpp | 250 | ||||
| -rw-r--r-- | host/utils/ihexcvt.hpp | 22 | ||||
| -rw-r--r-- | host/utils/octoclock_burn_eeprom.cpp | 95 | ||||
| -rw-r--r-- | host/utils/octoclock_firmware_burner.cpp | 351 | ||||
| -rw-r--r-- | host/utils/uhd_usrp_probe.cpp | 2 | ||||
| -rw-r--r-- | host/utils/usrp_burn_db_eeprom.cpp | 2 | ||||
| -rw-r--r-- | host/utils/usrp_burn_mb_eeprom.cpp | 2 | ||||
| -rw-r--r-- | host/utils/usrp_x3xx_fpga_burner.cpp | 6 | 
10 files changed, 742 insertions, 10 deletions
| diff --git a/host/utils/CMakeLists.txt b/host/utils/CMakeLists.txt index 7604a7d37..0d9f306b9 100644 --- a/host/utils/CMakeLists.txt +++ b/host/utils/CMakeLists.txt @@ -1,5 +1,5 @@  # -# Copyright 2010-2013 Ettus Research LLC +# Copyright 2010-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 @@ -64,6 +64,20 @@ IF(ENABLE_USB)      # Additional include directories for b2xx_fx3_utils      INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../lib/usrp/b200 ${CMAKE_CURRENT_SOURCE_DIR}/../lib/usrp/common)  ENDIF(ENABLE_USB) +IF(ENABLE_OCTOCLOCK) +    LIST(APPEND util_share_sources +        octoclock_burn_eeprom.cpp +    ) + +    SET(octoclock_burner_sources +        octoclock_firmware_burner.cpp +        ihexcvt.cpp +    ) + +    ADD_EXECUTABLE(octoclock_firmware_burner ${octoclock_burner_sources}) +    TARGET_LINK_LIBRARIES(octoclock_firmware_burner uhd ${Boost_LIBRARIES}) +    UHD_INSTALL(TARGETS octoclock_firmware_burner RUNTIME DESTINATION ${RUNTIME_DIR} COMPONENT utilities) +ENDIF(ENABLE_OCTOCLOCK)  IF(LINUX AND ENABLE_USB)      UHD_INSTALL(FILES diff --git a/host/utils/fx2_init_eeprom.cpp b/host/utils/fx2_init_eeprom.cpp index 701092a5d..5711b73e0 100644 --- a/host/utils/fx2_init_eeprom.cpp +++ b/host/utils/fx2_init_eeprom.cpp @@ -1,5 +1,5 @@  // -// Copyright 2010 Ettus Research LLC +// Copyright 2010,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 @@ -72,7 +72,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){      //find and create a control transport to do the writing. -    uhd::device_addrs_t found_addrs = uhd::device::find(device_addr); +    uhd::device_addrs_t found_addrs = uhd::device::find(device_addr, uhd::device::USRP);      if (found_addrs.size() == 0){          std::cerr << "No USRP devices found" << std::endl; @@ -82,7 +82,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){      for (size_t i = 0; i < found_addrs.size(); i++){          std::cout << "Writing EEPROM data..." << std::endl;          //uhd::device_addrs_t devs = uhd::device::find(found_addrs[i]); -        uhd::device::sptr dev = uhd::device::make(found_addrs[i]); +        uhd::device::sptr dev = uhd::device::make(found_addrs[i], uhd::device::USRP);          uhd::property_tree::sptr tree = dev->get_tree();          tree->access<std::string>("/mboards/0/load_eeprom").set(vm["image"].as<std::string>());      } diff --git a/host/utils/ihexcvt.cpp b/host/utils/ihexcvt.cpp new file mode 100644 index 000000000..0605ee61c --- /dev/null +++ b/host/utils/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/utils/ihexcvt.hpp b/host/utils/ihexcvt.hpp new file mode 100644 index 000000000..d577ece1f --- /dev/null +++ b/host/utils/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/utils/octoclock_burn_eeprom.cpp b/host/utils/octoclock_burn_eeprom.cpp new file mode 100644 index 000000000..033a8f499 --- /dev/null +++ b/host/utils/octoclock_burn_eeprom.cpp @@ -0,0 +1,95 @@ +// +// 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/>. +// + +#include <uhd/device.hpp> +#include <uhd/utils/safe_main.hpp> +#include <uhd/usrp_clock/octoclock_eeprom.hpp> +#include <uhd/property_tree.hpp> +#include <uhd/types/device_addr.hpp> +#include <boost/algorithm/string.hpp> +#include <boost/program_options.hpp> +#include <boost/format.hpp> +#include <iostream> +#include <vector> + +namespace po = boost::program_options; + +using namespace uhd; +using namespace uhd::usrp_clock; + +int UHD_SAFE_MAIN(int argc, char *argv[]){ +    std::string args, input_str, key, val; + +    po::options_description desc("Allowed options"); +    desc.add_options() +        ("help", "help message") +        ("args", po::value<std::string>(&args)->default_value(""), "device address args [default = \"\"]") +        ("values", po::value<std::string>(&input_str), "keys+values to read/write, separate multiple by \",\"") +        ("read-all", "Read all motherboard EEPROM values without writing") +    ; + +    po::variables_map vm; +    po::store(po::parse_command_line(argc, argv, desc), vm); +    po::notify(vm); + +    //print the help message +    if (vm.count("help") or (not vm.count("values") and not vm.count("read-all"))){ +        std::cout << boost::format("OctoClock Burn EEPROM %s") % desc << std::endl; +        std::cout << boost::format( +            "Omit the value argument to perform a readback,\n" +            "Or specify a new value to burn into the EEPROM.\n" +        ) << std::endl; +        return EXIT_FAILURE; +    } + +    std::cout << "Creating OctoClock device from args: " + args << std::endl; +    device::sptr oc = device::make(args, device::CLOCK); +    property_tree::sptr tree = oc->get_tree(); +    octoclock_eeprom_t oc_eeprom = tree->access<octoclock_eeprom_t>("/mboards/0/eeprom").get(); +    std::cout << std::endl; + +    std::vector<std::string> keys_vec, vals_vec; +    if(vm.count("read-all")) keys_vec = oc_eeprom.keys(); //Leaving vals_vec empty will force utility to only read +    else if(vm.count("values")){ +        //uhd::device_addr_t properly parses input values +        device_addr_t vals(input_str); +        keys_vec = vals.keys(); +        vals_vec = vals.vals(); +    } +    else throw std::runtime_error("Must specify --values or --read-all option!"); + +    std::cout << "Fetching current settings from EEPROM..." << std::endl; +    for(size_t i = 0; i < keys_vec.size(); i++){ +        if (not oc_eeprom.has_key(keys_vec[i])){ +            std::cerr << boost::format("Cannot find value for EEPROM[\"%s\"]") % keys_vec[i] << std::endl; +            return EXIT_FAILURE; +        } +        std::cout << boost::format("    EEPROM [\"%s\"] is \"%s\"") % keys_vec[i] % oc_eeprom[keys_vec[i]] << std::endl; +    } +    if(!vm.count("read-all")){ +        std::cout << std::endl; +        for(size_t i = 0; i < vals_vec.size(); i++){ +            if(vals_vec[i] != ""){ +                oc_eeprom[keys_vec[i]] = vals_vec[i]; +                std::cout << boost::format("Setting EEPROM [\"%s\"] to \"%s\"...") % keys_vec[i] % vals_vec[i] << std::endl; +            } +        } +        tree->access<octoclock_eeprom_t>("/mboards/0/eeprom").set(oc_eeprom); +    } +    std::cout << std::endl << "Power-cycle your device to allow any changes to take effect." << std::endl; +    return EXIT_SUCCESS; +} diff --git a/host/utils/octoclock_firmware_burner.cpp b/host/utils/octoclock_firmware_burner.cpp new file mode 100644 index 000000000..b8b8a3c1d --- /dev/null +++ b/host/utils/octoclock_firmware_burner.cpp @@ -0,0 +1,351 @@ +// +// 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/>. +// + +#include <algorithm> +#include <csignal> +#include <iostream> +#include <fstream> +#include <stdexcept> +#include <vector> + +#include <boost/foreach.hpp> +#include <boost/asio.hpp> +#include <boost/program_options.hpp> +#include <boost/assign.hpp> +#include <boost/cstdint.hpp> +#include <boost/assign/list_of.hpp> +#include <boost/format.hpp> +#include <boost/filesystem.hpp> +#include <boost/thread.hpp> + +#include <uhd/device.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/images.hpp> +#include <uhd/utils/paths.hpp> +#include <uhd/utils/safe_main.hpp> + +#include "../lib/usrp_clock/octoclock/common.h" +#include "ihexcvt.hpp" + +#define MAX_FIRMWARE_SIZE 1024*120 +#define BLOCK_SIZE 256 +#define UDP_TIMEOUT 5 + +namespace fs = boost::filesystem; +namespace po = boost::program_options; + +using namespace uhd; +using namespace uhd::transport; + +static int num_ctrl_c = 0; +void sig_int_handler(int){ +    num_ctrl_c++; +    if(num_ctrl_c == 1){ +        std::cout << std::endl << "Are you sure you want to abort the image burning? If you do, your " +                                  "OctoClock device will be bricked!" << std::endl +                               << "Press Ctrl+C again to abort the image burning procedure." << std::endl << std::endl; +    } +    else{ +        std::cout << std::endl << "Aborting. Your OctoClock device will be bricked." << std::endl +                               << "Refer to http://files.ettus.com/uhd_docs/doxymanual/html/octoclock.html" << std::endl +                               << "for details on restoring your device." << std::endl; +        exit(EXIT_FAILURE); +    } +} + +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; +size_t num_blocks = 0; + +/* + * Functions + */ +void list_octoclocks(){ +    device_addrs_t found_octoclocks = device::find(uhd::device_addr_t(), device::CLOCK); + +    std::cout << "Available OctoClock devices:" << std::endl; +    BOOST_FOREACH(const device_addr_t &oc, found_octoclocks){ +        std::cout << " * " << oc["addr"] << std::endl; +    } +} + +/* + * Manually find bootloader. This sends multiple packets in order to increase chances of getting + * bootloader before it switches to the application. + */ +device_addrs_t bootloader_find(std::string ip_addr){ +    udp_simple::sptr udp_transport = udp_simple::make_connected(ip_addr, BOOST_STRINGIZE(OCTOCLOCK_UDP_CTRL_PORT)); + +    octoclock_packet_t pkt_out; +    pkt_out.sequence = uhd::htonx<boost::uint32_t>(std::rand()); +    pkt_out.code = OCTOCLOCK_QUERY_CMD; +    pkt_out.len = 0; +    size_t len = 0; + +    device_addrs_t addrs; + +    boost::system_time comm_timeout = boost::get_system_time() + boost::posix_time::milliseconds(3000); +     +    while(boost::get_system_time() < comm_timeout){ +        UHD_OCTOCLOCK_SEND_AND_RECV(udp_transport, OCTOCLOCK_QUERY_CMD, pkt_out, len, octoclock_data); +        if(UHD_OCTOCLOCK_PACKET_MATCHES(OCTOCLOCK_QUERY_ACK, pkt_out, pkt_in, len) and +           pkt_in->proto_ver == OCTOCLOCK_BOOTLOADER_PROTO_VER){ +            addrs.push_back(device_addr_t()); +            addrs[0]["type"] = "octoclock-bootloader"; +            addrs[0]["addr"] = udp_transport->get_recv_addr(); +            break; +        } +    } + +    return addrs; +} + +void read_firmware(){ +    std::ifstream firmware_file(firmware_path.c_str(), std::ios::binary); +    firmware_file.seekg(0, std::ios::end); +    firmware_size = firmware_file.tellg(); +    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); +} + +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); +    size_t len = 0, current_pos = 0; + +    //Tell OctoClock not to jump to application, wait for us instead +    std::cout << "Telling OctoClock to prepare for firmware download..." << std::flush; +    UHD_OCTOCLOCK_SEND_AND_RECV(udp_transport, PREPARE_FW_BURN_CMD, pkt_out, len, octoclock_data); +    if(UHD_OCTOCLOCK_PACKET_MATCHES(FW_BURN_READY_ACK, pkt_out, pkt_in, len)) std::cout << "ready." << std::endl; +    else{ +        std::cout << std::endl; +        throw uhd::runtime_error("Could not get OctoClock in valid state for firmware download."); +    } + +    std::cout << std::endl << "Burning firmware." << std::endl; +    pkt_out.code = FILE_TRANSFER_CMD; + +    //Actual burning below +    for(size_t i = 0; i < num_blocks; i++){ +        pkt_out.sequence++; +        pkt_out.addr = i*BLOCK_SIZE; +        std::cout << "\r * Progress: " << int(double(i)/double(num_blocks)*100) +                  << "% (" << (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)); +        UHD_OCTOCLOCK_SEND_AND_RECV(udp_transport, FILE_TRANSFER_CMD, pkt_out, len, octoclock_data); +        if(not (UHD_OCTOCLOCK_PACKET_MATCHES(FILE_TRANSFER_ACK, pkt_out, pkt_in, len))){ +            std::cout << std::endl; +            throw uhd::runtime_error("Failed to burn firmware to OctoClock!"); +        } + +        current_pos += BLOCK_SIZE; +    } + +    std::cout << "\r * Progress: 100% (" << num_blocks << "/" << num_blocks << " blocks)" << std::endl; +} + +void verify_firmware(udp_simple::sptr udp_transport){ +    octoclock_packet_t pkt_out; +    pkt_out.proto_ver = OCTOCLOCK_FW_COMPAT_NUM; +    pkt_out.sequence = uhd::htonx<boost::uint32_t>(std::rand()); +    size_t len = 0, current_pos = 0; + +    std::cout << "Verifying firmware." << std::endl; + +    for(size_t i = 0; i < num_blocks; i++){ +        pkt_out.sequence++; +        pkt_out.addr = i*BLOCK_SIZE; +        std::cout << "\r * Progress: " << int(double(i)/double(num_blocks)*100) +                  << "% (" << (i+1) << "/" << num_blocks << " blocks)" << std::flush; + +        UHD_OCTOCLOCK_SEND_AND_RECV(udp_transport, READ_FW_CMD, pkt_out, len, octoclock_data); +        if(UHD_OCTOCLOCK_PACKET_MATCHES(READ_FW_ACK, pkt_out, pkt_in, len)){ +            if(memcmp((void*)(pkt_in->data), &firmware_image[i*BLOCK_SIZE], +                      std::min(int(firmware_size-current_pos), BLOCK_SIZE))){ +                std::cout << std::endl; +                throw uhd::runtime_error("Failed to verify OctoClock firmware!"); +            } +        } +        else{ +            std::cout << std::endl; +            throw uhd::runtime_error("Failed to verify OctoClock firmware!"); +        } +    } + +    std::cout << "\r * Progress: 100% (" << num_blocks << "/" << num_blocks << " blocks)" << std::endl; +} + +void reset_octoclock(const std::string &ip_addr){ +    udp_simple::sptr udp_transport = udp_simple::make_connected(ip_addr, BOOST_STRINGIZE(OCTOCLOCK_UDP_CTRL_PORT)); + +    octoclock_packet_t pkt_out; +    pkt_out.sequence = uhd::htonx<boost::uint32_t>(std::rand()); +    size_t len; + +    UHD_OCTOCLOCK_SEND_AND_RECV(udp_transport, RESET_CMD, pkt_out, len, octoclock_data); +    if(UHD_OCTOCLOCK_PACKET_MATCHES(RESET_ACK, pkt_out, pkt_in, len)) std::cout << "done." << std::endl; +    else throw uhd::runtime_error("Failed to place device in state to receive firmware."); +} + +void finalize(udp_simple::sptr udp_transport){ +    octoclock_packet_t pkt_out; +    pkt_out.len = 0; +    pkt_out.sequence = uhd::htonx<boost::uint32_t>(std::rand()); +    size_t len = 0; + +    std::cout << std::endl << "Telling OctoClock to load application..." << std::flush; +    UHD_OCTOCLOCK_SEND_AND_RECV(udp_transport, FINALIZE_BURNING_CMD, pkt_out, len, octoclock_data); +    if(UHD_OCTOCLOCK_PACKET_MATCHES(FINALIZE_BURNING_ACK, pkt_out, pkt_in, len)) std::cout << "done." << std::endl; +    else std::cout << "no ACK. Device may not have loaded application." << std::endl; +} + +int UHD_SAFE_MAIN(int argc, char *argv[]){ +    std::string ip_addr; +    po::options_description desc("Allowed options"); +    desc.add_options() +        ("help", "Display this help message.") +        ("addr", po::value<std::string>(&ip_addr), "Specify an IP address.") +        ("fw-path", po::value<std::string>(&firmware_path), "Specify a custom firmware path.") +        ("list", "List all available OctoClock devices.") +    ; +    po::variables_map vm; +    po::store(po::parse_command_line(argc, argv, desc), vm); +    po::notify(vm); + +    //Print help message +    if(vm.count("help")){ +        std::cout << "OctoClock Firmware Burner" << std::endl << std::endl; + +        std::cout << "Burns a firmware image file onto an OctoClock device. Specify" << std::endl +                  << "the address of the OctoClock with the --addr option. To burn" << std::endl +                  << "a custom firmware image, use the --fw-path option. Otherwise, the" << std::endl +                  << "utility will use the default image. To list all available" << std::endl +                  << "OctoClock devices without burning firmware, use the --list" << std::endl +                  << "option." << std::endl << std::endl; + +        std::cout << desc << std::endl; +        return EXIT_SUCCESS; +    } + +    //List all available devices +    if(vm.count("list")){ +        list_octoclocks(); +        return EXIT_SUCCESS; +    } + +    if(not (vm.count("addr"))){ +        throw uhd::runtime_error("You must specify an address with the --addr option!"); +    } +    udp_simple::sptr udp_transport = udp_simple::make_connected(ip_addr, BOOST_STRINGIZE(OCTOCLOCK_UDP_FW_PORT)); + +    //If custom path given, make sure it exists +    if(vm.count("fw-path")){ +        //Expand tilde usage if applicable +        #ifndef UHD_PLATFORM_WIN32 +        if(firmware_path.find("~/") == 0) firmware_path.replace(0,1,getenv("HOME")); +        #endif + +        if(not fs::exists(firmware_path)){ +            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"); + +    //If Intel hex file detected, convert to binary +    std::string ext = fs::extension(firmware_path); +    if(ext == ".hex"){ +        std::cout << "Found firmware at path: " << firmware_path << std::endl; + +        //Write firmware .bin file to temporary directory +        fs::path temp_bin = fs::path(fs::path(get_tmp_path()) / str(boost::format("octoclock_fw_%d.bin") +                                                          % 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(); +    } +    else if(ext == ".bin"){ +        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)."); + +    std::cout << std::endl << boost::format("Searching for OctoClock with IP address %s...") % ip_addr << std::flush; +    device_addrs_t octoclocks = device::find(str(boost::format("addr=%s") % ip_addr), device::CLOCK); +    if(octoclocks.size() == 1){ +        //If in application, quietly reset into bootloader and try to find again +        if(octoclocks[0]["type"] == "octoclock"){ +            reset_octoclock(ip_addr); +            boost::this_thread::sleep(boost::posix_time::milliseconds(2000)); +            octoclocks = bootloader_find(ip_addr); +            if(octoclocks.size() == 1) std::cout << "found." << std::endl; +            else{ +                std::cout << std::endl; +                throw uhd::runtime_error("Could not find OctoClock with given IP address!"); +            } +        } +        else std::cout << "found." << std::endl; +    } +    else{ +        std::cout << std::endl; +        throw uhd::runtime_error("Could not find OctoClock with given IP address!"); +    } + +    read_firmware(); + +    std::signal(SIGINT, &sig_int_handler); + +    burn_firmware(udp_transport); +    verify_firmware(udp_transport); +    finalize(udp_transport); + +    std::cout << "Waiting for OctoClock to reinitialize..." << std::flush; +    boost::this_thread::sleep(boost::posix_time::milliseconds(2000)); +    octoclocks = device::find(str(boost::format("addr=%s") % ip_addr), device::CLOCK); +    if(octoclocks.size() == 1){ +        if(octoclocks[0]["type"] == "octoclock-bootloader"){ +            std::cout << std::endl; +            throw uhd::runtime_error("OctoClock failed to leave bootloader state."); +        } +        else{ +            std::cout << "found." << std::endl << std::endl +                      << "Successfully burned firmware." << std::endl << std::endl; +        } +    } +    else{ +        std::cout << std::endl; +        throw uhd::runtime_error("Failed to reinitialize OctoClock."); +    } + +    return EXIT_SUCCESS; +} diff --git a/host/utils/uhd_usrp_probe.cpp b/host/utils/uhd_usrp_probe.cpp index 04ccc1e5a..cfbfe5f20 100644 --- a/host/utils/uhd_usrp_probe.cpp +++ b/host/utils/uhd_usrp_probe.cpp @@ -210,7 +210,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){          return EXIT_SUCCESS;      } -    device::sptr dev = device::make(vm["args"].as<std::string>()); +    device::sptr dev = device::make(vm["args"].as<std::string>(), device::USRP);      property_tree::sptr tree = dev->get_tree();      if (vm.count("string")){ diff --git a/host/utils/usrp_burn_db_eeprom.cpp b/host/utils/usrp_burn_db_eeprom.cpp index 3ca953115..7b483d2e7 100644 --- a/host/utils/usrp_burn_db_eeprom.cpp +++ b/host/utils/usrp_burn_db_eeprom.cpp @@ -62,7 +62,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){      }      //make the device and extract the dboard w/ property -    device::sptr dev = device::make(args); +    device::sptr dev = device::make(args, device::USRP);      uhd::property_tree::sptr tree = dev->get_tree();      const uhd::fs_path db_root = "/mboards/0/dboards";      std::vector<std::string> dboard_names = tree->list(db_root); diff --git a/host/utils/usrp_burn_mb_eeprom.cpp b/host/utils/usrp_burn_mb_eeprom.cpp index c631c9c09..de74d6807 100644 --- a/host/utils/usrp_burn_mb_eeprom.cpp +++ b/host/utils/usrp_burn_mb_eeprom.cpp @@ -56,7 +56,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){      }      std::cout << "Creating USRP device from address: " + args << std::endl; -    uhd::device::sptr dev = uhd::device::make(args); +    uhd::device::sptr dev = uhd::device::make(args, uhd::device::USRP);      uhd::property_tree::sptr tree = dev->get_tree();      uhd::usrp::mboard_eeprom_t mb_eeprom = tree->access<uhd::usrp::mboard_eeprom_t>("/mboards/0/eeprom").get();      std::cout << std::endl; diff --git a/host/utils/usrp_x3xx_fpga_burner.cpp b/host/utils/usrp_x3xx_fpga_burner.cpp index 2f0202e84..0c8ea7465 100644 --- a/host/utils/usrp_x3xx_fpga_burner.cpp +++ b/host/utils/usrp_x3xx_fpga_burner.cpp @@ -118,7 +118,7 @@ boost::uint8_t bitswap(uint8_t b){  }  void list_usrps(){ -    device_addrs_t found_devices = device::find(device_addr_t("type=x300")); +    device_addrs_t found_devices = device::find(device_addr_t("type=x300"), device::USRP);      std::cout << "Available X3x0 devices:" << std::endl;      BOOST_FOREACH(const device_addr_t &dev, found_devices){ @@ -142,7 +142,7 @@ void list_usrps(){  device_addr_t find_usrp_with_ethernet(std::string ip_addr, bool output){      if(output) std::cout << "Attempting to find X3x0 with IP address: " << ip_addr << std::endl;      const device_addr_t dev = device_addr_t(str(boost::format("addr=%s") % ip_addr)); -    device_addrs_t found_devices = device::find(dev); +    device_addrs_t found_devices = device::find(dev, device::USRP);      if(found_devices.size() < 1) {          throw std::runtime_error("Could not find X3x0 with the specified address!"); @@ -161,7 +161,7 @@ device_addr_t find_usrp_with_ethernet(std::string ip_addr, bool output){  device_addr_t find_usrp_with_pcie(std::string resource, bool output){      if(output) std::cout << "Attempting to find X3x0 with resource: " << resource << std::endl;      const device_addr_t dev = device_addr_t(str(boost::format("resource=%s") % resource)); -    device_addrs_t found_devices = device::find(dev); +    device_addrs_t found_devices = device::find(dev, device::USRP);      if(found_devices.size() < 1) {          throw std::runtime_error("Could not find X3x0 with the specified resource!"); | 
