diff options
-rw-r--r-- | host/include/uhd/image_loader.hpp | 3 | ||||
-rw-r--r-- | host/lib/usrp/b200/b200_image_loader.cpp | 33 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/n200_image_loader.cpp | 80 | ||||
-rw-r--r-- | host/lib/usrp/x300/x300_image_loader.cpp | 32 | ||||
-rw-r--r-- | host/lib/usrp_clock/octoclock/octoclock_image_loader.cpp | 48 | ||||
-rw-r--r-- | host/utils/uhd_image_loader.cpp | 5 |
6 files changed, 148 insertions, 53 deletions
diff --git a/host/include/uhd/image_loader.hpp b/host/include/uhd/image_loader.hpp index 8124e7dea..5963c862f 100644 --- a/host/include/uhd/image_loader.hpp +++ b/host/include/uhd/image_loader.hpp @@ -46,8 +46,9 @@ public: * * This function must return true upon the end of a successful image load * or false if no applicable device was found. It may only throw a runtime - * error under one of two conditions: + * error under one of three conditions: * + * * The function finds multiple devices that fit the user's arguments. * * The function has already engaged with a specific device and * something goes wrong. * * The user gives arguments that unambiguously lead to a specific diff --git a/host/lib/usrp/b200/b200_image_loader.cpp b/host/lib/usrp/b200/b200_image_loader.cpp index 87010244c..9eaeeff63 100644 --- a/host/lib/usrp/b200/b200_image_loader.cpp +++ b/host/lib/usrp/b200/b200_image_loader.cpp @@ -40,27 +40,50 @@ static b200_iface::sptr get_b200_iface(const image_loader::image_loader_args_t & bool user_specified){ std::vector<usb_device_handle::sptr> dev_handles = get_b200_device_handles(image_loader_args.args); + std::vector<usb_device_handle::sptr> applicable_dev_handles; b200_iface::sptr iface; + mboard_eeprom_t eeprom; // Internal use if(dev_handles.size() > 0){ BOOST_FOREACH(usb_device_handle::sptr dev_handle, dev_handles){ if(dev_handle->firmware_loaded()){ iface = b200_iface::make(usb_control::make(dev_handle,0)); - mb_eeprom = mboard_eeprom_t(*iface, "B200"); + eeprom = mboard_eeprom_t(*iface, "B200"); if(user_specified){ if(image_loader_args.args.has_key("serial") and - mb_eeprom.get("serial") != image_loader_args.args.get("serial")){ + eeprom.get("serial") != image_loader_args.args.get("serial")){ continue; } if(image_loader_args.args.has_key("name") and - mb_eeprom.get("name") != image_loader_args.args.get("name")){ + eeprom.get("name") != image_loader_args.args.get("name")){ continue; } - return iface; + applicable_dev_handles.push_back(dev_handle); } - else return iface; // Just return first found + else applicable_dev_handles.push_back(dev_handle); } } + + // At this point, we should have a single B2XX + if(applicable_dev_handles.size() == 1){ + mb_eeprom = eeprom; + return iface; + } + else if(applicable_dev_handles.size() > 1){ + std::string err_msg = "Could not resolve given args to a single B2XX device.\n" + "Applicable devices:\n"; + + BOOST_FOREACH(usb_device_handle::sptr dev_handle, applicable_dev_handles){ + eeprom = mboard_eeprom_t(*b200_iface::make(usb_control::make(dev_handle,0)), "B200"); + err_msg += str(boost::format(" * %s (serial=%s)\n") + % B2X0_STR_NAMES.get(get_b200_type(mb_eeprom), "B2XX") + % mb_eeprom.get("serial")); + } + + err_msg += "\nSpecify one of these devices with the given args to load an image onto it."; + + throw uhd::runtime_error(err_msg); + } } // No applicable devices found, return empty sptr so we can exit diff --git a/host/lib/usrp/usrp2/n200_image_loader.cpp b/host/lib/usrp/usrp2/n200_image_loader.cpp index ce956c22c..29bec8b4a 100644 --- a/host/lib/usrp/usrp2/n200_image_loader.cpp +++ b/host/lib/usrp/usrp2/n200_image_loader.cpp @@ -210,36 +210,62 @@ static uhd::device_addr_t n200_find(const image_loader::image_loader_args_t &ima image_loader_args.args.has_key("name"); uhd::device_addrs_t found = usrp2_find(image_loader_args.args); - if(found.size() > 0){ - uhd::device_addr_t ret = found[0]; - - /* - * Make sure the device found is an N-Series and not a USRP2. A USRP2 - * will not respond to this query. If the user supplied specific - * arguments that led to a USRP2, throw an error. - */ - udp_simple::sptr rev_xport = udp_simple::make_connected( - ret["addr"], - BOOST_STRINGIZE(N200_UDP_FW_UPDATE_PORT) - ); + if(found.size() > 0){ + uhd::device_addrs_t n200_found; + udp_simple::sptr rev_xport; n200_fw_update_data_t pkt_out; boost::uint8_t data_in[udp_simple::mtu]; const n200_fw_update_data_t *pkt_in = reinterpret_cast<const n200_fw_update_data_t*>(data_in); + size_t len = 0; - size_t len = n200_send_and_recv(rev_xport, GET_HW_REV_CMD, &pkt_out, data_in); - if(n200_response_matches(pkt_in, GET_HW_REV_ACK, len)){ - boost::uint32_t rev = ntohl(pkt_in->data.hw_rev); - ret["hw_rev"] = n200_filename_map.get(rev, "n2xx"); - return ret; + /* + * Filter out any USRP2 devices by sending a query over the + * UDP update port. Only N-Series devices will respond to + * this query. If the user supplied specific arguments that + * led to a USRP2, throw an error. + */ + BOOST_FOREACH(const uhd::device_addr_t &dev, found){ + rev_xport = udp_simple::make_connected( + dev.get("addr"), + BOOST_STRINGIZE(N200_UDP_FW_UPDATE_PORT) + ); + + len = n200_send_and_recv(rev_xport, GET_HW_REV_CMD, &pkt_out, data_in); + if(n200_response_matches(pkt_in, GET_HW_REV_ACK, len)){ + boost::uint32_t rev = ntohl(pkt_in->data.hw_rev); + std::string hw_rev = n200_filename_map.get(rev, "n2xx"); + + n200_found.push_back(dev); + n200_found[n200_found.size()-1]["hw_rev"] = hw_rev; + } + else if(len > offsetof(n200_fw_update_data_t, data) and ntohl(pkt_in->id) != GET_HW_REV_ACK){ + throw uhd::runtime_error(str(boost::format("Received invalid reply %d from device.") + % ntohl(pkt_in->id))); + } + else if(user_specified){ + // At this point, we haven't received any response, so assume it's a USRP2 + print_usrp2_error(image_loader_args); + } } - else if(len > offsetof(n200_fw_update_data_t, data) and ntohl(pkt_in->id) != GET_HW_REV_ACK){ - throw uhd::runtime_error(str(boost::format("Received invalid reply %d from device.") - % ntohl(pkt_in->id))); + + // At this point, we should have a single N-Series device + if(n200_found.size() == 1){ + return n200_found[0]; } - else if(user_specified){ - // At this point, we haven't received any response, so assume it's a USRP2 - print_usrp2_error(image_loader_args); + else if(n200_found.size() > 1){ + std::string err_msg = "Could not resolve given args to a single N-Series device.\n" + "Applicable devices:\n"; + + BOOST_FOREACH(const uhd::device_addr_t &dev, n200_found){ + err_msg += str(boost::format("* %s (addr=%s)\n") + % dev.get("hw_rev") + % dev.get("addr")); + } + + err_msg += "\nSpecify one of these devices with the given args to load an image onto it."; + + throw uhd::runtime_error(err_msg); } } @@ -259,7 +285,7 @@ static void n200_validate_firmware_image(n200_session_t &session){ session.max_size = N200_FW_MAX_SIZE_BYTES; if(session.size > session.max_size){ - throw uhd::runtime_error(str(boost::format("The specified FPGA image is too large: %d vs. %d") + throw uhd::runtime_error(str(boost::format("The specified firmware image is too large: %d vs. %d") % session.size % session.max_size)); } @@ -559,11 +585,15 @@ static std::string nice_name(const std::string &fw_rev){ } static bool n200_image_loader(const image_loader::image_loader_args_t &image_loader_args){ + if(!image_loader_args.load_firmware and !image_loader_args.load_fpga){ + return false; + } + // See if any N2x0 with the given args is found // This will throw if specific args lead to a USRP2 n200_session_t session; session.dev_addr = n200_find(image_loader_args); - if(session.dev_addr.size() == 0 or (!image_loader_args.load_firmware and !image_loader_args.load_fpga)){ + if(session.dev_addr.size() == 0){ return false; } diff --git a/host/lib/usrp/x300/x300_image_loader.cpp b/host/lib/usrp/x300/x300_image_loader.cpp index 321309868..9ec8a2e13 100644 --- a/host/lib/usrp/x300/x300_image_loader.cpp +++ b/host/lib/usrp/x300/x300_image_loader.cpp @@ -158,17 +158,31 @@ static void x300_validate_image(x300_session_t &session){ static void x300_setup_session(x300_session_t &session, const device_addr_t &args, const std::string &filepath){ - device_addr_t find_args; - find_args["type"] = "x300"; - if(args.has_key("name")) find_args["name"] = args["name"]; - if(args.has_key("serial")) find_args["serial"] = args["serial"]; - if(args.has_key("ip-addr")) find_args["addr"] = args["ip-addr"]; - else if(args.has_key("resource")) find_args["resource"] = args["resource"]; - device_addrs_t devs = x300_find(args); - session.found = (devs.size() > 0); - if(!session.found) return; + if(devs.size() == 0){ + session.found = false; + return; + } + else if(devs.size() > 1){ + std::string err_msg = "Could not resolve given args to a single X-Series device.\n" + "Applicable devices:\n"; + + BOOST_FOREACH(const uhd::device_addr_t &dev, devs){ + std::string identifier = dev.has_key("addr") ? "addr" + : "resource"; + + err_msg += str(boost::format(" * %s (%s=%s)\n") + % dev.get("product", "X3XX") + % identifier + % dev.get(identifier)); + } + + err_msg += "\nSpecify one of these devices with the given args to load an image onto it."; + + throw uhd::runtime_error(err_msg); + } + session.found = true; session.dev_addr = devs[0]; session.ethernet = session.dev_addr.has_key("addr"); if(session.ethernet){ diff --git a/host/lib/usrp_clock/octoclock/octoclock_image_loader.cpp b/host/lib/usrp_clock/octoclock/octoclock_image_loader.cpp index c88177f0f..e8c50e029 100644 --- a/host/lib/usrp_clock/octoclock/octoclock_image_loader.cpp +++ b/host/lib/usrp_clock/octoclock/octoclock_image_loader.cpp @@ -51,7 +51,7 @@ using namespace uhd::transport; * OctoClock burn session */ typedef struct { - bool valid; + bool found; uhd::device_addr_t dev_addr; std::string given_filepath; std::string actual_filepath; // If using a .hex, this is the converted .bin @@ -113,18 +113,43 @@ static void octoclock_validate_firmware_image(octoclock_session_t &session){ : (session.size / OCTOCLOCK_BLOCK_SIZE); octoclock_calculate_crc(session); - session.valid = true; } static void octoclock_setup_session(octoclock_session_t &session, + const uhd::device_addr_t &args, const std::string &filepath){ + // See if we can find an OctoClock with the given args + device_addrs_t devs = octoclock_find(args); + if(devs.size() == 0){ + session.found = false; + return; + } + else if(devs.size() > 1){ + std::string err_msg = "Could not resolve given args to a single OctoClock device.\n" + "Applicable devices:\n"; + + BOOST_FOREACH(const uhd::device_addr_t &dev, devs){ + std::string name = (dev["type"] == "octoclock") ? str(boost::format("OctoClock r%d") + % dev.get("revision","4")) + : "OctoClock Bootloader"; + err_msg += str(boost::format(" * %s (addr=%s)\n") + % name + % dev.get("addr")); + } + + err_msg += "\nSpecify one of these devices with the given args to load an image onto it."; + + throw uhd::runtime_error(err_msg); + } + + session.dev_addr = devs[0]; + // 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") - ))); + session.given_filepath = find_image_path(str(boost::format("octoclock_r%s_fw.hex") + % session.dev_addr.get("revision","4") + )); } else session.given_filepath = filepath; @@ -287,7 +312,7 @@ static void octoclock_verify(octoclock_session_t &session){ } 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); @@ -305,15 +330,12 @@ static void octoclock_finalize(octoclock_session_t &session){ } 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.args, image_loader_args.firmware_path ); + if(!session.found or !image_loader_args.load_firmware) return false; std::cout << boost::format("Unit: OctoClock (%s)") % session.dev_addr["addr"] @@ -329,7 +351,7 @@ bool octoclock_image_loader(const image_loader::image_loader_args_t &image_loade 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." + "is functional, but the device will not have functional clock distribution.\n" "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."; diff --git a/host/utils/uhd_image_loader.cpp b/host/utils/uhd_image_loader.cpp index 39efc8f1e..5ea789ee2 100644 --- a/host/utils/uhd_image_loader.cpp +++ b/host/utils/uhd_image_loader.cpp @@ -91,6 +91,11 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ image_loader_args.firmware_path = vm["fw-path"].as<std::string>(); image_loader_args.fpga_path = vm["fpga-path"].as<std::string>(); + // Force user to specify a device + if(not image_loader_args.args.has_key("type")){ + throw uhd::runtime_error("You must specify a device type."); + } + // Clean up paths, if given if(image_loader_args.firmware_path != ""){ #ifndef UHD_PLATFORM_WIN32 |