aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--host/LICENSE4
-rw-r--r--host/docs/gpsdo.rst87
-rw-r--r--host/docs/identification.rst130
-rw-r--r--host/docs/usrp1.rst111
-rw-r--r--host/docs/usrp2.rst474
-rw-r--r--host/docs/usrp_x3x0.dox2
-rw-r--r--host/examples/benchmark_rate.cpp2
-rw-r--r--host/examples/rx_multi_samples.cpp4
-rw-r--r--host/examples/rx_samples_to_file.cpp19
-rw-r--r--host/examples/rx_timed_samples.cpp4
-rw-r--r--host/examples/test_timed_commands.cpp4
-rw-r--r--host/examples/transport_hammer.cpp2
-rw-r--r--host/examples/txrx_loopback_to_file.cpp4
-rw-r--r--host/include/uhd/transport/nirio/nirio_fifo.h6
-rw-r--r--host/include/uhd/transport/nirio/nirio_fifo.ipp234
-rw-r--r--host/include/uhd/transport/nirio/nirio_quirks.h4
-rw-r--r--host/include/uhd/types/metadata.hpp16
-rw-r--r--host/include/uhd/usrp/multi_usrp.hpp8
-rw-r--r--host/include/uhd/utils/CMakeLists.txt1
-rw-r--r--host/include/uhd/utils/cast.hpp43
-rw-r--r--host/lib/convert/convert_impl.cpp1
-rw-r--r--host/lib/types/CMakeLists.txt1
-rw-r--r--host/lib/types/metadata.cpp92
-rw-r--r--host/lib/usrp/b100/b100_impl.cpp8
-rw-r--r--host/lib/usrp/b100/b100_impl.hpp1
-rw-r--r--host/lib/usrp/b200/b200_impl.cpp12
-rw-r--r--host/lib/usrp/b200/b200_impl.hpp4
-rw-r--r--host/lib/usrp/dboard/db_tvrx2.cpp6
-rw-r--r--host/lib/usrp/multi_usrp.cpp41
-rw-r--r--host/lib/usrp/usrp1/usrp1_impl.cpp9
-rw-r--r--host/lib/usrp/usrp1/usrp1_impl.hpp1
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.cpp7
-rw-r--r--host/lib/usrp/x300/x300_impl.cpp9
-rw-r--r--host/lib/usrp/x300/x300_impl.hpp4
-rw-r--r--host/lib/usrp/x300/x300_io_impl.cpp35
-rw-r--r--host/tests/CMakeLists.txt1
-rw-r--r--host/tests/cast_test.cpp33
-rw-r--r--host/utils/uhd_cal_rx_iq_balance.cpp31
-rw-r--r--host/utils/uhd_cal_tx_dc_offset.cpp31
-rw-r--r--host/utils/uhd_cal_tx_iq_balance.cpp36
-rw-r--r--host/utils/usrp_burn_mb_eeprom.cpp51
-rw-r--r--host/utils/usrp_cal_utils.hpp64
-rw-r--r--host/utils/usrp_n2xx_simple_net_burner.cpp495
-rw-r--r--host/utils/usrp_simple_burner_utils.hpp99
44 files changed, 1643 insertions, 588 deletions
diff --git a/host/LICENSE b/host/LICENSE
index 9aa03b39b..b91233b22 100644
--- a/host/LICENSE
+++ b/host/LICENSE
@@ -1,3 +1,7 @@
+This LICENSE file applies only to this directory and all subdirectories. Other
+top-level directories in the UHD(tm) Software distribution are not necessarily
+covered by this license.
+
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
diff --git a/host/docs/gpsdo.rst b/host/docs/gpsdo.rst
new file mode 100644
index 000000000..5afd9d78d
--- /dev/null
+++ b/host/docs/gpsdo.rst
@@ -0,0 +1,87 @@
+========================================================================
+UHD - Internal GPSDO Application Notes (USRP-N2x0/E1X0 Models)
+========================================================================
+
+.. contents:: Table of Contents
+
+This application note describes the use of integrated GPS-disciplined oscillators (GPSDOs) for
+the USRP N-Series and E1xx. For information regarding the GPSDO that is compatible with
+the USRP X-Series, please see:
+
+`USRP-X3x0 Internal GPSDO Device Manual <./gpsdo_x3x0.html>`_
+
+=======
+
+------------------------------------------------------------------------
+Specifications
+------------------------------------------------------------------------
+* **Receiver type**: 50 channel with WAAS, EGNOS, MSAS
+* **10MHz ADEV**: 1e-11 over >24h
+* **1PPS RMS jitter**: <50ns 1-sigma
+* **Holdover**: <11us over 3h
+* **Phase noise**:
+
+ * **1Hz:** -80 dBc/Hz
+ * **10Hz:** -110 dBc/Hz
+ * **100Hz:** -135 dBc/Hz
+ * **1kHz:** -145 dBc/Hz
+ * **10kHz:** <-145 dBc/Hz
+
+**Antenna Types:**
+
+The GPSDO is capable of supplying a 3V for active GPS antennas or supporting passive antennas.
+
+------------------------------------------------------------------------
+Installation Instructions
+------------------------------------------------------------------------
+Instructions for mounting the GPSDO kit onto your USRP device can be found here:
+`http://www.ettus.com/content/files/gpsdo-kit_2.pdf <http://www.ettus.com/content/files/gpsdo-kit_2.pdf>`_
+
+********************************************
+Post-installation Task (N-Series only)
+********************************************
+
+**Note:** The following instructions are only necessary for UHD 3.4.* and below.
+
+This is necessary if you require absolute GPS time in your application
+or need to communicate with the GPSDO to obtain location, satellite info, etc.
+If you only require 10 MHz and PPS signals for reference or MIMO use
+(see the `Synchronization Application Notes <./sync.html>`_),
+it is not necessary to perform this step.
+
+To configure the USRP to communicate with the GPSDO, use the
+**usrp_burn_mb_eeprom** utility:
+
+::
+
+ cd <install-path>/lib/uhd/utils
+ ./usrp_burn_mb_eeprom --args=<optional device args> --values="gpsdo=internal"
+
+ -- restore original setting --
+ ./usrp_burn_mb_eeprom --args=<optional device args> --values="gpsdo=none"
+
+------------------------------------------------------------------------
+Using the GPSDO in Your Application
+------------------------------------------------------------------------
+By default, if a GPSDO is detected at startup, the USRP will be configured
+to use it as a frequency and time reference. The internal VITA timestamp
+will be initialized to the GPS time, and the internal oscillator will be
+phase-locked to the 10 MHz GPSDO reference. If the GPSDO is not locked to
+satellites, the VITA time will not be initialized.
+
+GPS data is obtained through the **mboard_sensors** interface. To retrieve
+the current GPS time, use the **gps_time** sensor:
+
+::
+
+ usrp->get_mboard_sensor("gps_time");
+
+The returned value will be the current epoch time, in seconds since
+January 1, 1970. This value is readily converted into human-readable
+format using the **time.h** library in C, **boost::posix_time** in C++, etc.
+
+Other information can be fetched as well. You can query the lock status
+with the **gps_locked** sensor, as well as obtain raw NMEA sentences using
+the **gps_gprmc**, and **gps_gpgga** sensors. Location
+information can be parsed out of the **gps_gpgga** sensor by using **gpsd** or
+another NMEA parser.
diff --git a/host/docs/identification.rst b/host/docs/identification.rst
new file mode 100644
index 000000000..65b4e5e99
--- /dev/null
+++ b/host/docs/identification.rst
@@ -0,0 +1,130 @@
+=================================
+UHD - Device Identification Notes
+=================================
+
+.. contents:: Table of Contents
+
+------------------------
+Identifying USRP Devices
+------------------------
+Devices are addressed through key/value string pairs.
+These string pairs can be used to narrow down the search for a specific device or group of devices.
+Most UHD utility applications and examples have an **--args** parameter that takes a device address, which is expressed as a delimited string.
+
+See the documentation in **types/device_addr.hpp** for reference.
+
+^^^^^^^^^^^^^^^^^^^^^^^^^
+Common device identifiers
+^^^^^^^^^^^^^^^^^^^^^^^^^
+Every device has several ways of identifying it on the host system:
+
++------------+----------+-----------------------------------------------------------+-------------------------------
+| Identifier | Key | Notes | Example
++============+==========+===========================================================+===============================
+| Serial | serial | globally unique identifier | 12345678
++------------+----------+-----------------------------------------------------------+----------------------------
+| Address | addr | unique identifier on a network | 192.168.10.2
++------------+----------+-----------------------------------------------------------+-------------------------------
+| Resource | resource | unique identifier for USRP RIO devices (over PCI Express) | RIO0
++------------+----------+-----------------------------------------------------------+-------------------------------
+| Name | name | optional user-set identifier | my_usrp1 (User-defined value)
++------------+----------+-----------------------------------------------------------+----------------------------
+| Type | type | hardware series identifier | usrp1, usrp2,
++------------+----------+-----------------------------------------------------------+----------------------------
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Device discovery via command line
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Devices attached to your system can be discovered using the **uhd_find_devices** program.
+This program scans your system for supported devices and prints
+out an enumerated list of discovered devices and their addresses.
+The list of discovered devices can be narrowed down by specifying device address args.
+
+::
+
+ uhd_find_devices
+
+Device address arguments can be supplied to narrow the scope of the search.
+
+::
+
+ uhd_find_devices --args="type=usrp1"
+
+ -- OR --
+
+ uhd_find_devices --args="serial=12345678"
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Device discovery through the API
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+The **device::find()** API call searches for devices and returns a list of discovered devices.
+
+::
+
+ uhd::device_addr_t hint; //an empty hint discovers all devices
+ uhd::device_addrs_t dev_addrs = uhd::device::find(hint);
+
+The **hint** argument can be populated to narrow the scope of the search.
+
+::
+
+ uhd::device_addr_t hint;
+ hint["type"] = "usrp1";
+ uhd::device_addrs_t dev_addrs = uhd::device::find(hint);
+
+ -- OR --
+
+ uhd::device_addr_t hint;
+ hint["serial"] = "12345678";
+ uhd::device_addrs_t dev_addrs = uhd::device::find(hint);
+
+^^^^^^^^^^^^^^^^^
+Device properties
+^^^^^^^^^^^^^^^^^
+Properties of devices attached to your system can be probed with the **uhd_usrp_probe** program.
+This program constructs an instance of the device and prints out its properties,
+such as detected daughterboards, frequency range, gain ranges, etc...
+
+**Usage:**
+
+::
+
+ uhd_usrp_probe --args <device-specific-address-args>
+
+--------------------
+Naming a USRP Device
+--------------------
+For convenience purposes, users may assign a custom name to their USRP device.
+The USRP device can then be identified via name, rather than a difficult to remember serial or address.
+
+A name has the following properties:
+
+* is composed of ASCII characters
+* is 0-20 characters
+* is not required to be unique
+
+^^^^^^^^^^^^^^^^^
+Set a custom name
+^^^^^^^^^^^^^^^^^
+
+Run the following commands:
+
+::
+
+ cd <install-path>/lib/uhd/utils
+ ./usrp_burn_mb_eeprom --args=<optional device args> --values="name=lab1_xcvr"
+
+^^^^^^^^^^^^^^^^^^
+Discovery via name
+^^^^^^^^^^^^^^^^^^
+
+The keyword **name** can be used to narrow the scope of the search.
+Example with the find devices utility:
+
+::
+
+ uhd_find_devices --args="name=lab1_xcvr"
+
+ -- OR --
+
+ uhd_find_devices --args="type=usrp1, name=lab1_xcvr"
diff --git a/host/docs/usrp1.rst b/host/docs/usrp1.rst
new file mode 100644
index 000000000..ecf90502b
--- /dev/null
+++ b/host/docs/usrp1.rst
@@ -0,0 +1,111 @@
+========================================================================
+UHD - USRP1 Device Manual
+========================================================================
+
+.. contents:: Table of Contents
+
+------------------------------------------------------------------------
+Comparative features list
+------------------------------------------------------------------------
+
+**Hardware Capabilities:**
+ * 2 transceiver card slots
+ * 64 MHz fixed clock rate
+
+**FPGA Capabilities:**
+ * 2 RX DDC chains in FPGA
+ * 2 TX DUC chains in FPGA (no TX CORDIC -> uses DAC)
+ * sc16 sample modes - RX & TX
+
+ - Up to 8 MHz of RF BW with 16-bit samples
+
+ * sc8 sample mode - RX only
+
+ - Up to 16 MHz of RF BW with 8-bit samples
+
+------------------------------------------------------------------------
+Specify a Non-standard Image
+------------------------------------------------------------------------
+The standard USRP1 images installer comes with two FPGA images:
+ * **usrp1_fpga.rbf:** 2 DDCs + 2 DUCs
+ * **usrp1_fpga_4rx.rbf:** 4 DDCs + 0 DUCs
+
+By default, the USRP1 uses the FPGA image with 2 DDCs and 2 DUCs.
+However, a device address parameter can be used to override
+the FPGA image selection to use an alternate or a custom FPGA image.
+See the images application notes for installing custom images.
+
+Example device address string representations to specify non-standard firmware and/or FPGA images:
+
+::
+
+ fpga=usrp1_fpga_4rx.rbf
+
+ -- OR --
+
+ fw=usrp1_fw_custom.ihx
+
+ -- OR --
+
+ fpga=usrp1_fpga_4rx.rbf, fw=usrp1_fw_custom.ihx
+
+------------------------------------------------------------------------
+Missing and Emulated Features
+------------------------------------------------------------------------
+The USRP1 FPGA does not have the necessary space to support the advanced
+streaming capabilities that are possible with the newer USRP devices.
+Some of these features are emulated in software to support the API.
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+List of emulated features
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+* Setting the current device time
+* Getting the current device time
+* Transmitting at a specific time
+* Transmitting a specific number of samples
+* Receiving at a specific time
+* Receiving a specific number of samples
+* End of burst flags for transmit/receive
+* Notification on late stream command
+* Notification on late transmit packet
+* Notification on underflow or overflow
+* Notification on broken chain error
+
+**Note:**
+These emulated features rely on the host system's clock for timed operations
+and therefore may not have sufficient precision for the application.
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+List of missing features
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+* Start of burst flags for transmit/receive
+
+------------------------------------------------------------------------
+Hardware Setup Notes
+------------------------------------------------------------------------
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+External clock modification
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+The USRP device can be modified to accept an external clock reference instead of the 64MHz onboard reference.
+ * Solder SMA (**LTI-SASF54GT**) connector to **J2001**.
+ * Move 0 ohm 0603 resistor **R2029** to **R2030**.
+ * Move 0.01uF 0603 capacitor **C925** to **C926**.
+ * Remove 0.01uF 0603 capacitor **C924**.
+
+The new external clock needs to be a square wave between +7dBm and +15dBm
+
+After the hardware modification,
+the user should burn the setting into the EEPROM,
+so UHD software can initialize with the correct clock rate.
+Run the following commands to record the setting into the EEPROM:
+::
+
+ cd <install-path>/lib/uhd/utils
+ ./usrp_burn_mb_eeprom --args=<optional device args> --values="mcr=<rate>"
+
+The user may override the clock rate specified in the EEPROM by using a device address:
+Example:
+::
+
+ uhd_usrp_probe --args="mcr=52e6"
diff --git a/host/docs/usrp2.rst b/host/docs/usrp2.rst
new file mode 100644
index 000000000..1070a23fc
--- /dev/null
+++ b/host/docs/usrp2.rst
@@ -0,0 +1,474 @@
+========================================================================
+UHD - USRP2 and N2x0 Series Device Manual
+========================================================================
+
+.. contents:: Table of Contents
+
+------------------------------------------------------------------------
+Comparative features list
+------------------------------------------------------------------------
+
+**Hardware Capabilities:**
+ * 1 transceiver card slot
+ * External PPS reference input
+ * External 10 MHz reference input
+ * MIMO cable shared reference
+ * Fixed 100 MHz clock rate
+ * Internal GPSDO option (N2x0 only)
+
+**FPGA Capabilities:**
+ * 2 RX DDC chains in FPGA
+ * 1 TX DUC chain in FPGA
+ * Timed commands in FPGA (N2x0 only)
+ * Timed sampling in FPGA
+ * 16-bit and 8-bit sample modes (sc8 and sc16)
+
+ * Up to 25 MHz of RF BW with 16-bit samples
+ * Up to 50 MHz of RF BW with 8-bit samples
+
+------------------------------------------------------------------------
+Load the Images onto the SD card (USRP2 only)
+------------------------------------------------------------------------
+**Warning!**
+Use **usrp2_card_burner** with caution. If you specify the wrong device node,
+you could overwrite your hard drive. Make sure that **--dev=** specifies the SD card.
+
+**Warning!**
+It is possible to use 3rd party SD cards with the USRP2.
+However, certain types of SD cards will not interface with the CPLD:
+
+* Cards can be SDHC, which is not a supported interface.
+* Cards can have unexpected timing characteristics.
+
+For these reasons, we recommend that you use the SD card that was supplied with the USRP2.
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Use the card burner tool (UNIX)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+::
+
+ sudo <install-path>/lib/uhd/utils/usrp2_card_burner_gui.py
+
+ -- OR --
+
+ cd <install-path>/lib/uhd/utils
+ sudo ./usrp2_card_burner.py --dev=/dev/sd<XXX> --fpga=<path_to_fpga_image>
+ sudo ./usrp2_card_burner.py --dev=/dev/sd<XXX> --fw=<path_to_firmware_image>
+
+Use the **--list** option to get a list of possible raw devices.
+The list result will filter out disk partitions and devices too large to be the sd card.
+The list option has been implemented on Linux, Mac OS X, and Windows.
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Use the card burner tool (Windows)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+::
+
+ <path_to_python.exe> <install-path>/lib/uhd/utils/usrp2_card_burner_gui.py
+
+------------------------------------------------------------------------
+Load the Images onto the On-board Flash (USRP-N Series only)
+------------------------------------------------------------------------
+The USRP-N Series can be reprogrammed over the network to update or change the firmware and FPGA images.
+When updating images, always burn both the FPGA and firmware images before power cycling.
+This ensures that when the device reboots, it has a compatible set of images to boot into.
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Use the net burner tool
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+::
+
+ Use default images:
+ usrp_n2xx_simple_net_burner --addr=<IP address>
+
+ Use custom-built images:
+ usrp_n2xx_simple_net_burner --addr=<IP address> --fw=<firmware path> --fpga=<FPGA path>
+
+**Note:**
+Different hardware revisions require different FPGA images.
+Determine the revision number from the sticker on the rear of the chassis.
+Use this number to select the correct FPGA image for your device.
+
+For users who would prefer a graphical utility, a Python-based alternative exists.
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Use the graphical net burner tool (Linux)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+::
+
+ <install-path>/lib/uhd/utils/usrp_n2xx_net_burner_gui.py
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Use the graphical net burner tool (Windows)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+::
+
+ <path_to_python.exe> <install-path>/lib/uhd/utils/usrp_n2xx_net_burner_gui.py
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Device recovery and bricking
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Its possible to put the device into an unusable state by loading bad images.
+Fortunately, the USRP-N Series can be booted into a safe (read-only) image.
+Once booted into the safe image, the user can once again load images onto the device.
+
+The safe-mode button is a pushbutton switch (S2) located inside the enclosure.
+To boot into the safe image, hold-down the safe-mode button while power-cycling the device.
+Continue to hold-down the button until the front-panel LEDs blink and remain solid.
+
+When in safe-mode, the USRP-N device will always have the IP address **192.168.10.2**.
+
+------------------------------------------------------------------------
+Setup Networking
+------------------------------------------------------------------------
+The USRP2 only supports Gigabit Ethernet
+and will not work with a 10/100 Mbps interface.
+However, a 10/100 Mbps interface can be connected indirectly
+to a USRP2 through a Gigabit Ethernet switch.
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Setup the host interface
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+The USRP2 communicates at the IP/UDP layer over the gigabit ethernet.
+The default IP address of the USRP2 is **192.168.10.2**.
+You will need to configure the host's Ethernet interface with a static IP
+address to enable communication. An address of **192.168.10.1** and a subnet
+mask of **255.255.255.0** is recommended.
+
+On a Linux system, you can set a static IP address very easily by using the
+'ifconfig' command:
+::
+
+ sudo ifconfig <interface> 192.168.10.1
+
+Note that **<interface>** is usually something like **eth0**. You can discover the
+names of the network interfaces in your computer by running **ifconfig** without
+any parameters:
+::
+
+ ifconfig -a
+
+**Note:**
+When using UHD software, if an IP address for the USRP2 is not specified,
+the software will use UDP broadcast packets to locate the USRP2.
+On some systems, the firewall will block UDP broadcast packets.
+It is recommended that you change or disable your firewall settings.
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Multiple devices per host
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+For maximum throughput, one Ethernet interface per USRP2 is recommended,
+although multiple devices may be connected via a Gigabit Ethernet switch.
+In any case, each Ethernet interface should have its own subnet,
+and the corresponding USRP2 device should be assigned an address in that subnet.
+Example:
+
+**Configuration for USRP2 device 0:**
+
+* Ethernet interface IPv4 address: **192.168.10.1**
+* Ethernet interface subnet mask: **255.255.255.0**
+* USRP2 device IPv4 address: **192.168.10.2**
+
+**Configuration for USRP2 device 1:**
+
+* Ethernet interface IPv4 address: **192.168.20.1**
+* Ethernet interface subnet mask: **255.255.255.0**
+* USRP2 device IPv4 address: **192.168.20.2**
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Change the USRP2's IP address
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+You may need to change the USRP2's IP address for several reasons:
+
+* to satisfy your particular network configuration
+* to use multiple USRP2s on the same host computer
+* to set a known IP address into USRP2 (in case you forgot)
+
+**Method 1:**
+To change the USRP2's IP address,
+you must know the current address of the USRP2,
+and the network must be setup properly as described above.
+Run the following commands:
+::
+
+ cd <install-path>/lib/uhd/utils
+ ./usrp_burn_mb_eeprom --args=<optional device args> --values="ip-addr=192.168.10.3"
+
+**Method 2 (Linux Only):**
+This method assumes that you do not know the IP address of your USRP2.
+It uses raw Ethernet packets to bypass the IP/UDP layer to communicate with the USRP2.
+Run the following commands:
+::
+
+ cd <install-path>/lib/uhd/utils
+ sudo ./usrp2_recovery.py --ifc=eth0 --new-ip=192.168.10.3
+
+------------------------------------------------------------------------
+Communication Problems
+------------------------------------------------------------------------
+When setting up a development machine for the first time,
+you may have various difficulties communicating with the USRP device.
+The following tips are designed to help narrow down and diagnose the problem.
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+RuntimeError: no control response
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+This is a common error that occurs when you have set the subnet of your network
+interface to a different subnet than the network interface of the USRP device. For
+example, if your network interface is set to **192.168.20.1**, and the USRP device is
+**192.168.10.2** (note the difference in the third numbers of the IP addresses), you
+will likely see a 'no control response' error message.
+
+Fixing this is simple - just set the your host PC's IP address to the same
+subnet as that of your USRP device. Instructions for setting your IP address are in the
+previous section of this documentation.
+
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Firewall issues
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+When the IP address is not specified,
+the device discovery broadcasts UDP packets from each ethernet interface.
+Many firewalls will block the replies to these broadcast packets.
+If disabling your system's firewall
+or specifying the IP address yields a discovered device,
+then your firewall may be blocking replies to UDP broadcast packets.
+If this is the case, we recommend that you disable the firewall
+or create a rule to allow all incoming packets with UDP source port **49152**.
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Ping the device
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+The USRP device will reply to ICMP echo requests.
+A successful ping response means that the device has booted properly
+and that it is using the expected IP address.
+
+::
+
+ ping 192.168.10.2
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Monitor the serial output
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Read the serial port to get debug verbose output from the embedded microcontroller.
+The microcontroller prints useful information about IP addresses,
+MAC addresses, control packets, fast-path settings, and bootloading.
+Use a standard USB to 3.3v-level serial converter at 230400 baud.
+Connect **GND** to the converter ground, and connect **TXD** to the converter receive.
+The **RXD** pin can be left unconnected as this is only a one-way communication.
+
+* **USRP2:** Serial port located on the rear edge
+* **N210:** Serial port located on the left side
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Monitor the host network traffic
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Use Wireshark to monitor packets sent to and received from the device.
+
+------------------------------------------------------------------------
+Addressing the Device
+------------------------------------------------------------------------
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Single device configuration
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+In a single-device configuration, the USRP device must have a unique IPv4
+address on the host computer. The USRP can be identified through its IPv4
+address, resolvable hostname, or by other means. See the application notes on
+`device identification <./identification.html>`_. Please note that this
+addressing scheme should also be used with the **multi_usrp** interface.
+
+Example device address string representation for a USRP2 with IPv4 address **192.168.10.2**:
+
+::
+
+ addr=192.168.10.2
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Multiple device configuration
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+In a multi-device configuration,
+each USRP device must have a unique IPv4 address on the host computer.
+The device address parameter keys must be suffixed with the device index.
+Each parameter key should be of the format <key><index>.
+Use this addressing scheme with the **multi_usrp** interface.
+
+* The order in which devices are indexed corresponds to the indexing of the transmit and receive channels.
+* The key indexing provides the same granularity of device identification as in the single device case.
+
+Example device address string representation for 2 USRP2s with IPv4 addresses **192.168.10.2** and **192.168.20.2**:
+::
+
+ addr0=192.168.10.2, addr1=192.168.20.2
+
+------------------------------------------------------------------------
+Using the MIMO Cable
+------------------------------------------------------------------------
+The MIMO cable allows two USRP devices to share reference clocks,
+time synchronization, and the Ethernet interface.
+One of the devices will sync its clock and time references to the MIMO cable.
+This device will be referred to as the slave, and the other device, the master.
+
+* The slave device acquires the clock and time references from the master device.
+* The master and slave may be used individually or in a multi-device configuration.
+* External clocking is optional and should only be supplied to the master device.
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Shared Ethernet mode
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+In shared Ethernet mode,
+only one device in the configuration can be attached to the Ethernet.
+
+* Clock reference, time reference, and data are communicated over the MIMO cable.
+* Master and slave must have different IPv4 addresses in the same subnet.
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Dual Ethernet mode
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+In dual Ethernet mode,
+both devices in the configuration must be attached to the Ethernet.
+
+* Only clock reference and time reference are communicated over the MIMO cable.
+* The master and slave must have different IPv4 addresses in different subnets.
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Configuring the slave
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+In order for the slave to synchronize to the master over MIMO cable,
+the following clock configuration must be set on the slave device:
+::
+
+ usrp->set_time_source("mimo", slave_index);
+ usrp->set_clock_source("mimo", slave_index);
+
+
+------------------------------------------------------------------------
+Alternative stream destination
+------------------------------------------------------------------------
+It is possible to program the USRP device to send RX packets to an alternative IP/UDP destination.
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Set the subnet and gateway
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+To use an alternative streaming destination,
+the device needs to be able to determine if the destination address
+is within its subnet, and ARP appropriately.
+Therefore, the user should ensure that subnet and gateway addresses
+have been programmed into the device's EEPROM.
+
+Run the following commands:
+::
+
+ cd <install-path>/lib/uhd/utils
+ ./usrp_burn_mb_eeprom --args=<optional device args> --values="subnet=255.255.255.0,gateway=192.168.10.1"
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Create a receive streamer
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Set the stream args "addr" and "port" values to the alternative destination.
+Packets will be sent to this destination when the user issues a stream command.
+
+::
+
+ //create a receive streamer, host type does not matter
+ uhd::stream_args_t stream_args("fc32");
+
+ //resolvable address and port for a remote udp socket
+ stream_args.args["addr"] = "192.168.10.42";
+ stream_args.args["port"] = "12345";
+
+ //create the streamer
+ uhd::rx_streamer::sptr rx_stream = usrp->get_rx_stream(stream_args);
+
+ //issue stream command
+ uhd::stream_cmd_t stream_cmd(uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE);
+ stream_cmd.num_samps = total_num_samps;
+ stream_cmd.stream_now = true;
+ usrp->issue_stream_cmd(stream_cmd);
+
+**Note:**
+Calling recv() on this streamer object should yield a timeout.
+
+------------------------------------------------------------------------
+Hardware Setup Notes
+------------------------------------------------------------------------
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Front panel LEDs
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+The LEDs on the front panel can be useful in debugging hardware and software issues.
+The LEDs reveal the following about the state of the device:
+
+* **LED A:** transmitting
+* **LED B:** MIMO cable link
+* **LED C:** receiving
+* **LED D:** firmware loaded
+* **LED E:** reference lock
+* **LED F:** CPLD loaded
+
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Ref Clock - 10 MHz
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Using an external 10 MHz reference clock, a square wave will offer the best phase
+noise performance, but a sinusoid is acceptable. The reference clock requires the following power level:
+
+* **USRP2** 5 to 15 dBm
+* **N2XX** 0 to 15 dBm
+
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+PPS - Pulse Per Second
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Using a PPS signal for timestamp synchronization requires a square wave signal with the following amplitude:
+
+* **USRP2** 5Vpp
+* **N2XX** 3.3 to 5Vpp
+
+Test the PPS input with the following app:
+
+* **<args>** are device address arguments (optional if only one USRP device is on your machine)
+
+::
+
+ cd <install-path>/lib/uhd/examples
+ ./test_pps_input --args=<args>
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Internal GPSDO
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Please see the `Internal GPSDO Application Notes <./gpsdo.html>`_
+for information on configuring and using the internal GPSDO.
+
+------------------------------------------------------------------------
+Miscellaneous
+------------------------------------------------------------------------
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Available Sensors
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+The following sensors are available for the USRP2/N-Series motherboards;
+they can be queried through the API.
+
+* **mimo_locked** - clock reference locked over the MIMO cable
+* **ref_locked** - clock reference locked (internal/external)
+* other sensors are added when the GPSDO is enabled
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Multiple RX channels
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+There are two complete DDC chains in the FPGA.
+In the single channel case, only one chain is ever used.
+To receive from both channels,
+the user must set the **RX** subdevice specification.
+This hardware has only one daughterboard slot,
+which has been aptly named slot **A**.
+
+In the following example, a TVRX2 is installed.
+Channel 0 is sourced from subdevice **RX1**,
+and channel 1 is sourced from subdevice **RX2** (**RX1** and **RX2**
+are the antenna ports on the TVRX2 daughterboard):
+
+::
+
+ usrp->set_rx_subdev_spec("A:RX1 A:RX2");
diff --git a/host/docs/usrp_x3x0.dox b/host/docs/usrp_x3x0.dox
index 7996bc7e1..42574334b 100644
--- a/host/docs/usrp_x3x0.dox
+++ b/host/docs/usrp_x3x0.dox
@@ -91,7 +91,7 @@ number, you will have to update the FPGA image before you can start using your U
usrp_x3xx_fpga_burner --addr=192.168.10.2 --fpga-path <path_to_images>/usrp_x310_fpga_HGS.bit
- The process of updating the FPGA will take several minutes. Make sure the process of flashing the image does not get interrupted.
+ The process of updating the FPGA image will take several minutes. Make sure the process of flashing the image does not get interrupted.
See \ref x3x0_flash for more details.
diff --git a/host/examples/benchmark_rate.cpp b/host/examples/benchmark_rate.cpp
index ea49d48d9..9e9aa67e9 100644
--- a/host/examples/benchmark_rate.cpp
+++ b/host/examples/benchmark_rate.cpp
@@ -98,7 +98,7 @@ void benchmark_rx_rate(uhd::usrp::multi_usrp::sptr usrp, const std::string &rx_c
break;
default:
- std::cerr << "Error code: " << md.error_code << std::endl;
+ std::cerr << "Receiver error: " << md.strerror() << std::endl;
std::cerr << "Unexpected error on recv, continuing..." << std::endl;
break;
}
diff --git a/host/examples/rx_multi_samples.cpp b/host/examples/rx_multi_samples.cpp
index 9e5970978..a50b5f0e0 100644
--- a/host/examples/rx_multi_samples.cpp
+++ b/host/examples/rx_multi_samples.cpp
@@ -172,8 +172,8 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
if (md.error_code == uhd::rx_metadata_t::ERROR_CODE_TIMEOUT) break;
if (md.error_code != uhd::rx_metadata_t::ERROR_CODE_NONE){
throw std::runtime_error(str(boost::format(
- "Unexpected error code 0x%x"
- ) % md.error_code));
+ "Receiver error %s"
+ ) % md.strerror()));
}
if(verbose) std::cout << boost::format(
diff --git a/host/examples/rx_samples_to_file.cpp b/host/examples/rx_samples_to_file.cpp
index 0d42404d3..de3640794 100644
--- a/host/examples/rx_samples_to_file.cpp
+++ b/host/examples/rx_samples_to_file.cpp
@@ -101,18 +101,15 @@ template<typename samp_type> void recv_to_file(
continue;
}
if (md.error_code != uhd::rx_metadata_t::ERROR_CODE_NONE){
- std::string error = str(boost::format(
- "Unexpected error code 0x%x"
- ) % md.error_code);
-
- if (continue_on_bad_packet){
- std::cerr << error << std::endl;
- continue;
- }
- else
- throw std::runtime_error(error);
+ std::string error = str(boost::format("Receiver error: %s") % md.strerror());
+ if (continue_on_bad_packet){
+ std::cerr << error << std::endl;
+ continue;
+ }
+ else
+ throw std::runtime_error(error);
}
-
+
if (enable_size_map){
SizeMap::iterator it = mapSizes.find(num_rx_samps);
if (it == mapSizes.end())
diff --git a/host/examples/rx_timed_samples.cpp b/host/examples/rx_timed_samples.cpp
index cc9216cb7..30535907f 100644
--- a/host/examples/rx_timed_samples.cpp
+++ b/host/examples/rx_timed_samples.cpp
@@ -130,8 +130,8 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
if (md.error_code == uhd::rx_metadata_t::ERROR_CODE_TIMEOUT) break;
if (md.error_code != uhd::rx_metadata_t::ERROR_CODE_NONE){
throw std::runtime_error(str(boost::format(
- "Unexpected error code 0x%x"
- ) % md.error_code));
+ "Receiver error %s"
+ ) % md.strerror()));
}
if(verbose) std::cout << boost::format(
diff --git a/host/examples/test_timed_commands.cpp b/host/examples/test_timed_commands.cpp
index 8c6011c68..3da4bc707 100644
--- a/host/examples/test_timed_commands.cpp
+++ b/host/examples/test_timed_commands.cpp
@@ -139,8 +139,8 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
const size_t num_rx_samps = rx_stream->recv(&buff.front(), buff.size(), md, 1.0);
if (md.error_code != uhd::rx_metadata_t::ERROR_CODE_NONE){
throw std::runtime_error(str(boost::format(
- "Unexpected error code 0x%x"
- ) % md.error_code));
+ "Receiver error %s"
+ ) % md.strerror()));
}
std::cout << boost::format(
" Received packet: %u samples, %u full secs, %f frac secs"
diff --git a/host/examples/transport_hammer.cpp b/host/examples/transport_hammer.cpp
index 4b949e5bd..3f233b2a5 100644
--- a/host/examples/transport_hammer.cpp
+++ b/host/examples/transport_hammer.cpp
@@ -88,7 +88,7 @@ void rx_hammer(uhd::usrp::multi_usrp::sptr usrp, const std::string &rx_cpu, uhd:
break;
default:
- std::cerr << "Error code: " << md.error_code << std::endl;
+ std::cerr << "Receiver error: " << md.strerror() << std::endl;
std::cerr << "Unexpected error on recv, continuing..." << std::endl;
break;
}
diff --git a/host/examples/txrx_loopback_to_file.cpp b/host/examples/txrx_loopback_to_file.cpp
index 3d3cf1dfc..a62ccd7b2 100644
--- a/host/examples/txrx_loopback_to_file.cpp
+++ b/host/examples/txrx_loopback_to_file.cpp
@@ -181,8 +181,8 @@ template<typename samp_type> void recv_to_file(
}
if (md.error_code != uhd::rx_metadata_t::ERROR_CODE_NONE){
throw std::runtime_error(str(boost::format(
- "Unexpected error code 0x%x"
- ) % md.error_code));
+ "Receiver error %s"
+ ) % md.strerror()));
}
num_total_samps += num_rx_samps;
diff --git a/host/include/uhd/transport/nirio/nirio_fifo.h b/host/include/uhd/transport/nirio/nirio_fifo.h
index f7abb396f..fc1de245d 100644
--- a/host/include/uhd/transport/nirio/nirio_fifo.h
+++ b/host/include/uhd/transport/nirio/nirio_fifo.h
@@ -104,16 +104,20 @@ public:
uint32_t& num_remaining);
private: //Methods
- bool _is_initialized();
datatype_info_t _get_datatype_info();
nirio_status _get_transfer_count(uint64_t& transfer_count);
nirio_status _ensure_transfer_completed(uint32_t timeout_ms);
private: //Members
+ enum fifo_state_t {
+ UNMAPPED, MAPPED, STARTED
+ };
+
std::string _name;
fifo_direction_t _fifo_direction;
uint32_t _fifo_channel;
datatype_info_t _datatype_info;
+ fifo_state_t _state;
size_t _acquired_pending;
nirio_driver_iface::rio_mmap_t _mem_map;
boost::recursive_mutex _mutex;
diff --git a/host/include/uhd/transport/nirio/nirio_fifo.ipp b/host/include/uhd/transport/nirio/nirio_fifo.ipp
index 80a0c2a89..437e3a1fc 100644
--- a/host/include/uhd/transport/nirio/nirio_fifo.ipp
+++ b/host/include/uhd/transport/nirio/nirio_fifo.ipp
@@ -31,6 +31,7 @@ nirio_fifo<data_t>::nirio_fifo(
_fifo_direction(direction),
_fifo_channel(fifo_instance),
_datatype_info(_get_datatype_info()),
+ _state(UNMAPPED),
_acquired_pending(0),
_mem_map(),
_riok_proxy_ptr(&riok_proxy),
@@ -61,28 +62,37 @@ nirio_status nirio_fifo<data_t>::initialize(
if (!_riok_proxy_ptr) return NiRio_Status_ResourceNotInitialized;
boost::unique_lock<boost::recursive_mutex> lock(_mutex);
- nirio_driver_iface::nirio_syncop_in_params_t in = {};
- nirio_driver_iface::nirio_syncop_out_params_t out = {};
+ if (_state == UNMAPPED) {
+ nirio_driver_iface::nirio_syncop_in_params_t in = {};
+ nirio_driver_iface::nirio_syncop_out_params_t out = {};
- //Forcefully stop the fifo if it is running
- in.function = nirio_driver_iface::NIRIO_FUNC::FIFO;
- in.subfunction = nirio_driver_iface::NIRIO_FIFO::STOP;
- status = _riok_proxy_ptr->sync_operation(&in, sizeof(in), &out, sizeof(out));
+ //Forcefully stop the fifo if it is running
+ in.function = nirio_driver_iface::NIRIO_FUNC::FIFO;
+ in.subfunction = nirio_driver_iface::NIRIO_FIFO::STOP;
+ in.params.fifo.channel = _fifo_channel;
+ _riok_proxy_ptr->sync_operation(&in, sizeof(in), &out, sizeof(out)); //Cleanup operation. Ignore status.
- in.function = nirio_driver_iface::NIRIO_FUNC::FIFO;
- in.subfunction = nirio_driver_iface::NIRIO_FIFO::CONFIGURE;
+ //Configure the FIFO now that we know it is stopped
+ in.function = nirio_driver_iface::NIRIO_FUNC::FIFO;
+ in.subfunction = nirio_driver_iface::NIRIO_FIFO::CONFIGURE;
+ in.params.fifo.channel = _fifo_channel;
+ in.params.fifo.op.config.requestedDepth = static_cast<uint32_t>(requested_depth);
+ in.params.fifo.op.config.requiresActuals = 1;
+ status = _riok_proxy_ptr->sync_operation(&in, sizeof(in), &out, sizeof(out));
- in.params.fifo.channel = _fifo_channel;
- in.params.fifo.op.config.requestedDepth = static_cast<uint32_t>(requested_depth);
- in.params.fifo.op.config.requiresActuals = 1;
+ if (nirio_status_fatal(status)) return status;
- status = _riok_proxy_ptr->sync_operation(&in, sizeof(in), &out, sizeof(out));
- if (nirio_status_fatal(status)) return status;
+ actual_depth = out.params.fifo.op.config.actualDepth;
+ actual_size = out.params.fifo.op.config.actualSize;
- actual_depth = out.params.fifo.op.config.actualDepth;
- actual_size = out.params.fifo.op.config.actualSize;
+ status = _riok_proxy_ptr->map_fifo_memory(_fifo_channel, actual_size, _mem_map);
- status = _riok_proxy_ptr->map_fifo_memory(_fifo_channel, actual_size, _mem_map);
+ if (nirio_status_not_fatal(status)) {
+ _state = MAPPED;
+ }
+ } else {
+ status = NiRio_Status_SoftwareFault;
+ }
return status;
}
@@ -90,9 +100,13 @@ template <typename data_t>
void nirio_fifo<data_t>::finalize()
{
boost::unique_lock<boost::recursive_mutex> lock(_mutex);
- if (!_mem_map.is_null()) {
- stop();
+
+ //If the FIFO is started, the stop will change the state to MAPPED.
+ stop();
+
+ if (_state == MAPPED) {
_riok_proxy_ptr->unmap_fifo_memory(_mem_map);
+ _state = UNMAPPED; //Assume teardown succeeded
}
}
@@ -104,16 +118,25 @@ nirio_status nirio_fifo<data_t>::start()
boost::unique_lock<boost::recursive_mutex> lock(_mutex);
- nirio_driver_iface::nirio_syncop_in_params_t in = {};
- nirio_driver_iface::nirio_syncop_out_params_t out = {};
+ if (_state == STARTED) {
+ //Do nothing. Already started.
+ } else if (_state == MAPPED) {
+ nirio_driver_iface::nirio_syncop_in_params_t in = {};
+ nirio_driver_iface::nirio_syncop_out_params_t out = {};
- in.function = nirio_driver_iface::NIRIO_FUNC::FIFO;
- in.subfunction = nirio_driver_iface::NIRIO_FIFO::START;
+ in.function = nirio_driver_iface::NIRIO_FUNC::FIFO;
+ in.subfunction = nirio_driver_iface::NIRIO_FIFO::START;
- status = _riok_proxy_ptr->sync_operation(&in, sizeof(in), &out, sizeof(out));
- if (nirio_status_not_fatal(status)) {
- _acquired_pending = 0;
- _expected_xfer_count = 0;
+ in.params.fifo.channel = _fifo_channel;
+
+ status = _riok_proxy_ptr->sync_operation(&in, sizeof(in), &out, sizeof(out));
+ if (nirio_status_not_fatal(status)) {
+ _state = STARTED;
+ _acquired_pending = 0;
+ _expected_xfer_count = 0;
+ }
+ } else {
+ status = NiRio_Status_ResourceNotInitialized;
}
return status;
}
@@ -125,15 +148,22 @@ nirio_status nirio_fifo<data_t>::stop()
if (!_riok_proxy_ptr) return NiRio_Status_ResourceNotInitialized;
boost::unique_lock<boost::recursive_mutex> lock(_mutex);
- if (_acquired_pending > 0) release(_acquired_pending);
- nirio_driver_iface::nirio_syncop_in_params_t in = {};
- nirio_driver_iface::nirio_syncop_out_params_t out = {};
+ if (_state == STARTED) {
+ if (_acquired_pending > 0) release(_acquired_pending);
+
+ nirio_driver_iface::nirio_syncop_in_params_t in = {};
+ nirio_driver_iface::nirio_syncop_out_params_t out = {};
- in.function = nirio_driver_iface::NIRIO_FUNC::FIFO;
- in.subfunction = nirio_driver_iface::NIRIO_FIFO::STOP;
+ in.function = nirio_driver_iface::NIRIO_FUNC::FIFO;
+ in.subfunction = nirio_driver_iface::NIRIO_FIFO::STOP;
- status = _riok_proxy_ptr->sync_operation(&in, sizeof(in), &out, sizeof(out));
+ in.params.fifo.channel = _fifo_channel;
+
+ status = _riok_proxy_ptr->sync_operation(&in, sizeof(in), &out, sizeof(out));
+
+ _state = MAPPED; //Assume teardown succeeded
+ }
return status;
}
@@ -151,36 +181,40 @@ nirio_status nirio_fifo<data_t>::acquire(
boost::unique_lock<boost::recursive_mutex> lock(_mutex);
- nirio_driver_iface::nirio_syncop_in_params_t in = {};
- uint32_t stuffed[2];
- nirio_driver_iface::nirio_syncop_out_params_t out = {};
- init_syncop_out_params(out, stuffed, sizeof(stuffed));
-
- in.function = nirio_driver_iface::NIRIO_FUNC::FIFO;
- in.subfunction = nirio_driver_iface::NIRIO_FIFO::WAIT;
-
- in.params.fifo.channel = _fifo_channel;
- in.params.fifo.op.wait.elementsRequested = static_cast<uint32_t>(elements_requested);
- in.params.fifo.op.wait.scalarType = static_cast<uint32_t>(_datatype_info.scalar_type);
- in.params.fifo.op.wait.bitWidth = _datatype_info.width * 8;
- in.params.fifo.op.wait.output = _fifo_direction == OUTPUT_FIFO;
- in.params.fifo.op.wait.timeout = timeout;
-
- status = _riok_proxy_ptr->sync_operation(&in, sizeof(in), &out, sizeof(out));
-
- if (nirio_status_not_fatal(status)) {
- elements = static_cast<data_t*>(out.params.fifo.op.wait.elements.pointer);
- elements_acquired = stuffed[0];
- elements_remaining = stuffed[1];
- _acquired_pending = elements_acquired;
-
- if (UHD_NIRIO_RX_FIFO_XFER_CHECK_EN &&
- _riok_proxy_ptr->get_rio_quirks().rx_fifo_xfer_check_en() &&
- get_direction() == INPUT_FIFO
- ) {
- _expected_xfer_count += static_cast<uint64_t>(elements_requested * sizeof(data_t));
- status = _ensure_transfer_completed(timeout);
+ if (_state == STARTED) {
+ nirio_driver_iface::nirio_syncop_in_params_t in = {};
+ uint32_t stuffed[2];
+ nirio_driver_iface::nirio_syncop_out_params_t out = {};
+ init_syncop_out_params(out, stuffed, sizeof(stuffed));
+
+ in.function = nirio_driver_iface::NIRIO_FUNC::FIFO;
+ in.subfunction = nirio_driver_iface::NIRIO_FIFO::WAIT;
+
+ in.params.fifo.channel = _fifo_channel;
+ in.params.fifo.op.wait.elementsRequested = static_cast<uint32_t>(elements_requested);
+ in.params.fifo.op.wait.scalarType = static_cast<uint32_t>(_datatype_info.scalar_type);
+ in.params.fifo.op.wait.bitWidth = _datatype_info.width * 8;
+ in.params.fifo.op.wait.output = _fifo_direction == OUTPUT_FIFO;
+ in.params.fifo.op.wait.timeout = timeout;
+
+ status = _riok_proxy_ptr->sync_operation(&in, sizeof(in), &out, sizeof(out));
+
+ if (nirio_status_not_fatal(status)) {
+ elements = static_cast<data_t*>(out.params.fifo.op.wait.elements.pointer);
+ elements_acquired = stuffed[0];
+ elements_remaining = stuffed[1];
+ _acquired_pending = elements_acquired;
+
+ if (UHD_NIRIO_RX_FIFO_XFER_CHECK_EN &&
+ _riok_proxy_ptr->get_rio_quirks().rx_fifo_xfer_check_en() &&
+ get_direction() == INPUT_FIFO
+ ) {
+ _expected_xfer_count += static_cast<uint64_t>(elements_requested * sizeof(data_t));
+ status = _ensure_transfer_completed(timeout);
+ }
}
+ } else {
+ status = NiRio_Status_ResourceNotInitialized;
}
return status;
@@ -194,17 +228,21 @@ nirio_status nirio_fifo<data_t>::release(const size_t elements)
boost::unique_lock<boost::recursive_mutex> lock(_mutex);
- nirio_driver_iface::nirio_syncop_in_params_t in = {};
- nirio_driver_iface::nirio_syncop_out_params_t out = {};
+ if (_state == STARTED) {
+ nirio_driver_iface::nirio_syncop_in_params_t in = {};
+ nirio_driver_iface::nirio_syncop_out_params_t out = {};
- in.function = nirio_driver_iface::NIRIO_FUNC::FIFO;
- in.subfunction = nirio_driver_iface::NIRIO_FIFO::GRANT;
+ in.function = nirio_driver_iface::NIRIO_FUNC::FIFO;
+ in.subfunction = nirio_driver_iface::NIRIO_FIFO::GRANT;
- in.params.fifo.channel = _fifo_channel;
- in.params.fifo.op.grant.elements = static_cast<uint32_t>(elements);
+ in.params.fifo.channel = _fifo_channel;
+ in.params.fifo.op.grant.elements = static_cast<uint32_t>(elements);
- status = _riok_proxy_ptr->sync_operation(&in, sizeof(in), &out, sizeof(out));
- _acquired_pending = 0;
+ status = _riok_proxy_ptr->sync_operation(&in, sizeof(in), &out, sizeof(out));
+ _acquired_pending = 0;
+ } else {
+ status = NiRio_Status_ResourceNotInitialized;
+ }
return status;
}
@@ -222,23 +260,27 @@ nirio_status nirio_fifo<data_t>::read(
boost::unique_lock<boost::recursive_mutex> lock(_mutex);
- nirio_driver_iface::nirio_syncop_in_params_t in = {};
- nirio_driver_iface::nirio_syncop_out_params_t out = {};
- init_syncop_out_params(out, buf, num_elements * _datatype_info.width);
+ if (_state == STARTED) {
+ nirio_driver_iface::nirio_syncop_in_params_t in = {};
+ nirio_driver_iface::nirio_syncop_out_params_t out = {};
+ init_syncop_out_params(out, buf, num_elements * _datatype_info.width);
- in.function = nirio_driver_iface::NIRIO_FUNC::FIFO;
- in.subfunction = nirio_driver_iface::NIRIO_FIFO::READ;
+ in.function = nirio_driver_iface::NIRIO_FUNC::FIFO;
+ in.subfunction = nirio_driver_iface::NIRIO_FIFO::READ;
- in.params.fifo.channel = _fifo_channel;
- in.params.fifo.op.readWithDataType.timeout = timeout;
- in.params.fifo.op.readWithDataType.scalarType = static_cast<uint32_t>(_datatype_info.scalar_type);
- in.params.fifo.op.readWithDataType.bitWidth = _datatype_info.width * 8;
+ in.params.fifo.channel = _fifo_channel;
+ in.params.fifo.op.readWithDataType.timeout = timeout;
+ in.params.fifo.op.readWithDataType.scalarType = static_cast<uint32_t>(_datatype_info.scalar_type);
+ in.params.fifo.op.readWithDataType.bitWidth = _datatype_info.width * 8;
- status = _riok_proxy_ptr->sync_operation(&in, sizeof(in), &out, sizeof(out));
+ status = _riok_proxy_ptr->sync_operation(&in, sizeof(in), &out, sizeof(out));
- if (nirio_status_not_fatal(status) || status == NiRio_Status_FifoTimeout) {
- num_read = out.params.fifo.op.read.numberRead;
- num_remaining = out.params.fifo.op.read.numberRemaining;
+ if (nirio_status_not_fatal(status) || status == NiRio_Status_FifoTimeout) {
+ num_read = out.params.fifo.op.read.numberRead;
+ num_remaining = out.params.fifo.op.read.numberRemaining;
+ }
+ } else {
+ status = NiRio_Status_ResourceNotInitialized;
}
return status;
@@ -256,22 +298,26 @@ nirio_status nirio_fifo<data_t>::write(
boost::unique_lock<boost::recursive_mutex> lock(_mutex);
- nirio_driver_iface::nirio_syncop_in_params_t in = {};
- init_syncop_in_params(in, buf, num_elements * _datatype_info.width);
- nirio_driver_iface::nirio_syncop_out_params_t out = {};
+ if (_state == STARTED) {
+ nirio_driver_iface::nirio_syncop_in_params_t in = {};
+ init_syncop_in_params(in, buf, num_elements * _datatype_info.width);
+ nirio_driver_iface::nirio_syncop_out_params_t out = {};
- in.function = nirio_driver_iface::NIRIO_FUNC::FIFO;
- in.subfunction = nirio_driver_iface::NIRIO_FIFO::WRITE;
+ in.function = nirio_driver_iface::NIRIO_FUNC::FIFO;
+ in.subfunction = nirio_driver_iface::NIRIO_FIFO::WRITE;
- in.params.fifo.channel = _fifo_channel;
- in.params.fifo.op.writeWithDataType.timeout = timeout;
- in.params.fifo.op.readWithDataType.scalarType = static_cast<uint32_t>(_datatype_info.scalar_type);
- in.params.fifo.op.readWithDataType.bitWidth = _datatype_info.width * 8;
+ in.params.fifo.channel = _fifo_channel;
+ in.params.fifo.op.writeWithDataType.timeout = timeout;
+ in.params.fifo.op.readWithDataType.scalarType = static_cast<uint32_t>(_datatype_info.scalar_type);
+ in.params.fifo.op.readWithDataType.bitWidth = _datatype_info.width * 8;
- status = _riok_proxy_ptr->sync_operation(&in, sizeof(in), &out, sizeof(out));
+ status = _riok_proxy_ptr->sync_operation(&in, sizeof(in), &out, sizeof(out));
- if (nirio_status_not_fatal(status) || status == NiRio_Status_FifoTimeout) {
- num_remaining = out.params.fifo.op.write.numberRemaining;
+ if (nirio_status_not_fatal(status) || status == NiRio_Status_FifoTimeout) {
+ num_remaining = out.params.fifo.op.write.numberRemaining;
+ }
+ } else {
+ status = NiRio_Status_ResourceNotInitialized;
}
return status;
diff --git a/host/include/uhd/transport/nirio/nirio_quirks.h b/host/include/uhd/transport/nirio/nirio_quirks.h
index 326eeeb8c..ed4f72e7f 100644
--- a/host/include/uhd/transport/nirio/nirio_quirks.h
+++ b/host/include/uhd/transport/nirio/nirio_quirks.h
@@ -24,8 +24,8 @@
//Quirk#1: We need to verify RX zero-copy data transfers from the RIO
// driver if we are in full duplex mode.
-// This option allows disabling this quirk by compiling it out.
-#define UHD_NIRIO_RX_FIFO_XFER_CHECK_EN 1
+// This option allows enabling this quirk.
+#define UHD_NIRIO_RX_FIFO_XFER_CHECK_EN 0
namespace uhd { namespace niusrprio {
diff --git a/host/include/uhd/types/metadata.hpp b/host/include/uhd/types/metadata.hpp
index 6a79720d0..51a2b7c43 100644
--- a/host/include/uhd/types/metadata.hpp
+++ b/host/include/uhd/types/metadata.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010-2012 Ettus Research LLC
+// Copyright 2010-2012,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
@@ -117,6 +117,20 @@ namespace uhd{
//! Out of sequence. The transport has either dropped a packet or received data out of order.
bool out_of_sequence;
+
+ /*!
+ * Convert a rx_metadata_t into a pretty print string.
+ *
+ * \param compact Set to false for a more verbose output.
+ * \return a printable string representing the metadata.
+ */
+ std::string to_pp_string(bool compact=true) const;
+
+ /*!
+ * Similar to C's strerror() function, creates a std::string describing the error code.
+ * \return a printable string representing the error.
+ */
+ std::string strerror(void) const;
};
/*!
diff --git a/host/include/uhd/usrp/multi_usrp.hpp b/host/include/uhd/usrp/multi_usrp.hpp
index aac40efe5..883e4da3d 100644
--- a/host/include/uhd/usrp/multi_usrp.hpp
+++ b/host/include/uhd/usrp/multi_usrp.hpp
@@ -119,14 +119,10 @@ public:
virtual device::sptr get_device(void) = 0;
//! Convenience method to get a RX streamer. See also uhd::device::get_rx_stream().
- rx_streamer::sptr get_rx_stream(const stream_args_t &args){
- return this->get_device()->get_rx_stream(args);
- }
+ virtual rx_streamer::sptr get_rx_stream(const stream_args_t &args) = 0;
//! Convenience method to get a TX streamer. See also uhd::device::get_rx_stream().
- tx_streamer::sptr get_tx_stream(const stream_args_t &args){
- return this->get_device()->get_tx_stream(args);
- }
+ virtual tx_streamer::sptr get_tx_stream(const stream_args_t &args) = 0;
/*!
* Returns identifying information about this USRP's configuration.
diff --git a/host/include/uhd/utils/CMakeLists.txt b/host/include/uhd/utils/CMakeLists.txt
index c0991b3ce..e9633286f 100644
--- a/host/include/uhd/utils/CMakeLists.txt
+++ b/host/include/uhd/utils/CMakeLists.txt
@@ -22,6 +22,7 @@ UHD_INSTALL(FILES
atomic.hpp
byteswap.hpp
byteswap.ipp
+ cast.hpp
csv.hpp
gain_group.hpp
images.hpp
diff --git a/host/include/uhd/utils/cast.hpp b/host/include/uhd/utils/cast.hpp
new file mode 100644
index 000000000..9db92c526
--- /dev/null
+++ b/host/include/uhd/utils/cast.hpp
@@ -0,0 +1,43 @@
+//
+// 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 INCLUDED_UHD_UTILS_CAST_HPP
+#define INCLUDED_UHD_UTILS_CAST_HPP
+
+#include <uhd/config.hpp>
+#include <string>
+#include <sstream>
+
+namespace uhd{ namespace cast{
+ //! Convert a hexadecimal string into a value.
+ //
+ // Example:
+ // boost::uint16_t x = hexstr_cast<boost::uint16_t>("0xDEADBEEF");
+ // Uses stringstream.
+ template<typename T> inline T hexstr_cast(const std::string &in)
+ {
+ T x;
+ std::stringstream ss;
+ ss << std::hex << in;
+ ss >> x;
+ return x;
+ }
+
+}} //namespace uhd::cast
+
+#endif /* INCLUDED_UHD_UTILS_CAST_HPP */
+
diff --git a/host/lib/convert/convert_impl.cpp b/host/lib/convert/convert_impl.cpp
index dc7f8f9dc..c7907ed83 100644
--- a/host/lib/convert/convert_impl.cpp
+++ b/host/lib/convert/convert_impl.cpp
@@ -134,6 +134,7 @@ UHD_STATIC_BLOCK(convert_register_item_sizes){
convert::register_bytes_per_item("sc64", sizeof(std::complex<boost::int64_t>));
convert::register_bytes_per_item("sc32", sizeof(std::complex<boost::int32_t>));
convert::register_bytes_per_item("sc16", sizeof(std::complex<boost::int16_t>));
+ convert::register_bytes_per_item("sc12", 3 * sizeof(std::complex<boost::int8_t>));
convert::register_bytes_per_item("sc8", sizeof(std::complex<boost::int8_t>));
//register standard real types
diff --git a/host/lib/types/CMakeLists.txt b/host/lib/types/CMakeLists.txt
index b69c8e487..7fc6bdd94 100644
--- a/host/lib/types/CMakeLists.txt
+++ b/host/lib/types/CMakeLists.txt
@@ -82,6 +82,7 @@ SET_SOURCE_FILES_PROPERTIES(
LIBUHD_APPEND_SOURCES(
${CMAKE_CURRENT_SOURCE_DIR}/device_addr.cpp
${CMAKE_CURRENT_SOURCE_DIR}/mac_addr.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/metadata.cpp
${CMAKE_CURRENT_SOURCE_DIR}/ranges.cpp
${CMAKE_CURRENT_SOURCE_DIR}/sensors.cpp
${CMAKE_CURRENT_SOURCE_DIR}/serial.cpp
diff --git a/host/lib/types/metadata.cpp b/host/lib/types/metadata.cpp
new file mode 100644
index 000000000..fec2ac564
--- /dev/null
+++ b/host/lib/types/metadata.cpp
@@ -0,0 +1,92 @@
+//
+// 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 <string>
+#include <sstream>
+#include <boost/format.hpp>
+#include <uhd/exception.hpp>
+#include <uhd/types/metadata.hpp>
+#include <uhd/types/time_spec.hpp>
+
+using namespace uhd;
+
+std::string rx_metadata_t::to_pp_string(bool compact) const
+{
+ std::stringstream ss;
+
+ if (compact) {
+ if (has_time_spec) {
+ ss << "Time: " << time_spec.get_real_secs() << " s\n";
+ }
+ if (more_fragments) {
+ ss << "Fragmentation offset: " << fragment_offset << "\n";
+ }
+ if (start_of_burst) {
+ ss << "Start of burst.\n" << fragment_offset;
+ }
+ if (end_of_burst) {
+ ss << "End of burst.\n" << fragment_offset;
+ }
+ if (error_code != ERROR_CODE_NONE) {
+ ss << strerror() << "\n";
+ }
+ } else {
+ ss << "Has timespec: " << (has_time_spec ? "Yes" : "No")
+ << "\tTime of first sample: " << time_spec.get_real_secs()
+ << "\nFragmented: " << (more_fragments ? "Yes" : "No")
+ << " Fragmentation offset: " << fragment_offset
+ << "\nStart of burst: " << (start_of_burst ? "Yes" : "No")
+ << "\tEnd of burst: " << (end_of_burst ? "Yes" : "No")
+ << "\nError Code: " << strerror()
+ << "\tOut of sequence: " << (out_of_sequence ? "Yes" : "No");
+ }
+
+ return ss.str();
+}
+
+std::string rx_metadata_t::strerror() const
+{
+ std::string errstr = "";
+ switch(this->error_code) {
+ case ERROR_CODE_NONE:
+ errstr = "ERROR_CODE_NONE";
+ break;
+ case ERROR_CODE_TIMEOUT:
+ errstr = "ERROR_CODE_TIMEOUT";
+ break;
+ case ERROR_CODE_LATE_COMMAND:
+ errstr = "ERROR_CODE_LATE_COMMAND";
+ break;
+ case ERROR_CODE_BROKEN_CHAIN:
+ errstr = "ERROR_CODE_BROKEN_CHAIN (Expected another stream command)";
+ break;
+ case ERROR_CODE_OVERFLOW:
+ errstr = "ERROR_CODE_OVERFLOW ";
+ errstr += (this->out_of_sequence ? "(Out of sequence error)" : "(Overflow)");
+ break;
+ case ERROR_CODE_ALIGNMENT:
+ errstr = "ERROR_CODE_ALIGNMENT (Multi-channel alignment failed)";
+ break;
+ case ERROR_CODE_BAD_PACKET:
+ errstr = "ERROR_CODE_BAD_PACKET";
+ break;
+ default:
+ errstr = std::string(str(boost::format("Unknown error code: 0x%x") % error_code));
+ }
+
+ return errstr;
+}
diff --git a/host/lib/usrp/b100/b100_impl.cpp b/host/lib/usrp/b100/b100_impl.cpp
index a47856b07..baf2b6ae3 100644
--- a/host/lib/usrp/b100/b100_impl.cpp
+++ b/host/lib/usrp/b100/b100_impl.cpp
@@ -20,6 +20,7 @@
#include "b100_regs.hpp"
#include <uhd/transport/usb_control.hpp>
#include <uhd/utils/msg.hpp>
+#include <uhd/utils/cast.hpp>
#include <uhd/exception.hpp>
#include <uhd/utils/static.hpp>
#include <uhd/utils/images.hpp>
@@ -56,11 +57,11 @@ static device_addrs_t b100_find(const device_addr_t &hint)
//since an address and resource is intended for a different, non-USB, device.
if (hint.has_key("addr") || hint.has_key("resource")) return b100_addrs;
- unsigned int vid, pid;
+ boost::uint16_t vid, pid;
if(hint.has_key("vid") && hint.has_key("pid") && hint.has_key("type") && hint["type"] == "b100") {
- sscanf(hint.get("vid").c_str(), "%x", &vid);
- sscanf(hint.get("pid").c_str(), "%x", &pid);
+ vid = uhd::cast::hexstr_cast<boost::uint16_t>(hint.get("vid"));
+ pid = uhd::cast::hexstr_cast<boost::uint16_t>(hint.get("pid"));
} else {
vid = B100_VENDOR_ID;
pid = B100_PRODUCT_ID;
@@ -515,6 +516,7 @@ b100_impl::b100_impl(const device_addr_t &device_addr){
_tree->access<subdev_spec_t>(mb_path / "tx_subdev_spec").set(subdev_spec_t("A:" + _tree->list(mb_path / "dboards/A/tx_frontends").at(0)));
_tree->access<std::string>(mb_path / "clock_source/value").set("internal");
_tree->access<std::string>(mb_path / "time_source/value").set("none");
+ _tree->create<double>(mb_path / "link_max_rate").set(B100_MAX_RATE_USB2);
}
b100_impl::~b100_impl(void){
diff --git a/host/lib/usrp/b100/b100_impl.hpp b/host/lib/usrp/b100/b100_impl.hpp
index 7d71d5ec3..b6752681e 100644
--- a/host/lib/usrp/b100/b100_impl.hpp
+++ b/host/lib/usrp/b100/b100_impl.hpp
@@ -54,6 +54,7 @@ static const boost::uint32_t B100_CTRL_MSG_SID = 20;
static const double B100_DEFAULT_TICK_RATE = 64e6;
static const size_t B100_MAX_PKT_BYTE_LIMIT = 2048;
static const std::string B100_EEPROM_MAP_KEY = "B100";
+static const size_t B100_MAX_RATE_USB2 = 32000000; // bytes/s
#define I2C_ADDR_TX_A (I2C_DEV_EEPROM | 0x4)
#define I2C_ADDR_RX_A (I2C_DEV_EEPROM | 0x5)
diff --git a/host/lib/usrp/b200/b200_impl.cpp b/host/lib/usrp/b200/b200_impl.cpp
index 9dd3a424d..98141dbaa 100644
--- a/host/lib/usrp/b200/b200_impl.cpp
+++ b/host/lib/usrp/b200/b200_impl.cpp
@@ -19,6 +19,7 @@
#include "b200_regs.hpp"
#include <uhd/transport/usb_control.hpp>
#include <uhd/utils/msg.hpp>
+#include <uhd/utils/cast.hpp>
#include <uhd/exception.hpp>
#include <uhd/utils/static.hpp>
#include <uhd/utils/images.hpp>
@@ -58,11 +59,11 @@ static device_addrs_t b200_find(const device_addr_t &hint)
//since an address and resource is intended for a different, non-USB, device.
if (hint.has_key("addr") || hint.has_key("resource")) return b200_addrs;
- unsigned int vid, pid;
+ boost::uint16_t vid, pid;
if(hint.has_key("vid") && hint.has_key("pid") && hint.has_key("type") && hint["type"] == "b200") {
- sscanf(hint.get("vid").c_str(), "%x", &vid);
- sscanf(hint.get("pid").c_str(), "%x", &pid);
+ vid = uhd::cast::hexstr_cast<boost::uint16_t>(hint.get("vid"));
+ pid = uhd::cast::hexstr_cast<boost::uint16_t>(hint.get("pid"));
} else {
vid = B200_VENDOR_ID;
pid = B200_PRODUCT_ID;
@@ -160,9 +161,9 @@ b200_impl::b200_impl(const device_addr_t &device_addr)
boost::uint16_t vid = B200_VENDOR_ID;
boost::uint16_t pid = B200_PRODUCT_ID;
if (device_addr.has_key("vid"))
- sscanf(device_addr.get("vid").c_str(), "%hx", &vid);
+ vid = uhd::cast::hexstr_cast<boost::uint16_t>(device_addr.get("vid"));
if (device_addr.has_key("pid"))
- sscanf(device_addr.get("pid").c_str(), "%hx", &pid);
+ pid = uhd::cast::hexstr_cast<boost::uint16_t>(device_addr.get("pid"));
std::vector<usb_device_handle::sptr> device_list =
usb_device_handle::get_device_list(vid, pid);
@@ -250,6 +251,7 @@ b200_impl::b200_impl(const device_addr_t &device_addr)
ctrl_xport_args
);
while (_ctrl_transport->get_recv_buff(0.0)){} //flush ctrl xport
+ _tree->create<double>(mb_path / "link_max_rate").set((usb_speed == 3) ? B200_MAX_RATE_USB3 : B200_MAX_RATE_USB2);
////////////////////////////////////////////////////////////////////
// Async task structure
diff --git a/host/lib/usrp/b200/b200_impl.hpp b/host/lib/usrp/b200/b200_impl.hpp
index 7d98a8f8d..c3508c550 100644
--- a/host/lib/usrp/b200/b200_impl.hpp
+++ b/host/lib/usrp/b200/b200_impl.hpp
@@ -47,11 +47,13 @@
static const boost::uint8_t B200_FW_COMPAT_NUM_MAJOR = 0x04;
static const boost::uint8_t B200_FW_COMPAT_NUM_MINOR = 0x00;
static const boost::uint16_t B200_FPGA_COMPAT_NUM = 0x03;
-static const double B200_LINK_RATE_BPS = (5e9)/8; //practical link rate (5 Gbps)
static const double B200_BUS_CLOCK_RATE = 100e6;
static const double B200_DEFAULT_TICK_RATE = 32e6;
static const boost::uint32_t B200_GPSDO_ST_NONE = 0x83;
+static const size_t B200_MAX_RATE_USB2 = 32000000; // bytes/s
+static const size_t B200_MAX_RATE_USB3 = 500000000; // bytes/s
+
#define FLIP_SID(sid) (((sid)<<16)|((sid)>>16))
static const boost::uint32_t B200_CTRL0_MSG_SID = 0x00000010;
diff --git a/host/lib/usrp/dboard/db_tvrx2.cpp b/host/lib/usrp/dboard/db_tvrx2.cpp
index c593c5437..c74c64471 100644
--- a/host/lib/usrp/dboard/db_tvrx2.cpp
+++ b/host/lib/usrp/dboard/db_tvrx2.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010,2012-2013 Ettus Research LLC
+// Copyright 2010,2012-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
@@ -1005,8 +1005,8 @@ tvrx2::tvrx2(ctor_args_t args) : rx_dboard_base(args){
_freq_scalar = (4*16.0e6)/(this->get_iface()->get_clock_rate(dboard_iface::UNIT_RX));
} else if (ref_clock == 100e6) {
-
- this->get_iface()->set_gpio_out(dboard_iface::UNIT_RX, REFCLOCK_DIV8);
+
+ this->get_iface()->set_gpio_out(dboard_iface::UNIT_RX, REFCLOCK_DIV6);
UHD_LOGV(often) << boost::format(
"TVRX2 (%s): Dividing Refclock by 6"
diff --git a/host/lib/usrp/multi_usrp.cpp b/host/lib/usrp/multi_usrp.cpp
index f08709669..4883b2410 100644
--- a/host/lib/usrp/multi_usrp.cpp
+++ b/host/lib/usrp/multi_usrp.cpp
@@ -24,6 +24,7 @@
#include <uhd/usrp/dboard_id.hpp>
#include <uhd/usrp/mboard_eeprom.hpp>
#include <uhd/usrp/dboard_eeprom.hpp>
+#include <uhd/convert.hpp>
#include <boost/assign/list_of.hpp>
#include <boost/thread.hpp>
#include <boost/foreach.hpp>
@@ -103,6 +104,8 @@ static meta_range_t make_overall_tune_range(
return range;
}
+
+
/***********************************************************************
* Gain helper functions
**********************************************************************/
@@ -589,6 +592,11 @@ public:
/*******************************************************************
* RX methods
******************************************************************/
+ rx_streamer::sptr get_rx_stream(const stream_args_t &args) {
+ _check_link_rate(args, false);
+ return this->get_device()->get_rx_stream(args);
+ }
+
void set_rx_subdev_spec(const subdev_spec_t &spec, size_t mboard){
if (mboard != ALL_MBOARDS){
_tree->access<subdev_spec_t>(mb_root(mboard) / "rx_subdev_spec").set(spec);
@@ -770,6 +778,11 @@ public:
/*******************************************************************
* TX methods
******************************************************************/
+ tx_streamer::sptr get_tx_stream(const stream_args_t &args) {
+ _check_link_rate(args, true);
+ return this->get_device()->get_tx_stream(args);
+ }
+
void set_tx_subdev_spec(const subdev_spec_t &spec, size_t mboard){
if (mboard != ALL_MBOARDS){
_tree->access<subdev_spec_t>(mb_root(mboard) / "tx_subdev_spec").set(spec);
@@ -1178,6 +1191,34 @@ private:
}
return gg;
}
+
+ //! \param is_tx True for tx
+ // Assumption is that all mboards use the same link
+ bool _check_link_rate(const stream_args_t &args, bool is_tx) {
+ bool link_rate_is_ok = true;
+ size_t bytes_per_sample = convert::get_bytes_per_item(args.otw_format);
+ double max_link_rate = 0;
+ double sum_rate = 0;
+ BOOST_FOREACH(const size_t chan, args.channels) {
+ mboard_chan_pair mcp = is_tx ? tx_chan_to_mcp(chan) : rx_chan_to_mcp(chan);
+ if (_tree->exists(mb_root(mcp.mboard) / "link_max_rate")) {
+ max_link_rate = std::max(
+ max_link_rate,
+ _tree->access<double>(mb_root(mcp.mboard) / "link_max_rate").get()
+ );
+ }
+ sum_rate += is_tx ? get_tx_rate(chan) : get_rx_rate(chan);
+ }
+ if (max_link_rate > 0 and (max_link_rate / bytes_per_sample) < sum_rate) {
+ UHD_MSG(warning) << boost::format(
+ "The total sum of rates (%f MSps on %u channels) exceeds the maximum capacity of the connection.\n"
+ "This can cause %s."
+ ) % (sum_rate/1e6) % args.channels.size() % (is_tx ? "underruns (U)" : "overflows (O)") << std::endl;
+ link_rate_is_ok = false;
+ }
+
+ return link_rate_is_ok;
+ }
};
/***********************************************************************
diff --git a/host/lib/usrp/usrp1/usrp1_impl.cpp b/host/lib/usrp/usrp1/usrp1_impl.cpp
index 3b902b343..0ba2e1e4a 100644
--- a/host/lib/usrp/usrp1/usrp1_impl.cpp
+++ b/host/lib/usrp/usrp1/usrp1_impl.cpp
@@ -20,6 +20,7 @@
#include <uhd/utils/safe_call.hpp>
#include <uhd/transport/usb_control.hpp>
#include <uhd/utils/msg.hpp>
+#include <uhd/utils/cast.hpp>
#include <uhd/exception.hpp>
#include <uhd/utils/static.hpp>
#include <uhd/utils/images.hpp>
@@ -59,11 +60,11 @@ static device_addrs_t usrp1_find(const device_addr_t &hint)
//since an address and resource is intended for a different, non-USB, device.
if (hint.has_key("addr") || hint.has_key("resource")) return usrp1_addrs;
- unsigned int vid, pid;
+ boost::uint16_t vid, pid;
if(hint.has_key("vid") && hint.has_key("pid") && hint.has_key("type") && hint["type"] == "usrp1") {
- sscanf(hint.get("vid").c_str(), "%x", &vid);
- sscanf(hint.get("pid").c_str(), "%x", &pid);
+ vid = uhd::cast::hexstr_cast<boost::uint16_t>(hint.get("vid"));
+ pid = uhd::cast::hexstr_cast<boost::uint16_t>(hint.get("pid"));
} else {
vid = USRP1_VENDOR_ID;
pid = USRP1_PRODUCT_ID;
@@ -409,7 +410,7 @@ usrp1_impl::usrp1_impl(const device_addr_t &device_addr){
_tree->access<subdev_spec_t>(mb_path / "rx_subdev_spec").set(_rx_subdev_spec);
if (_tree->list(mb_path / "tx_dsps").size() > 0)
_tree->access<subdev_spec_t>(mb_path / "tx_subdev_spec").set(_tx_subdev_spec);
-
+ _tree->create<double>(mb_path / "link_max_rate").set(USRP1_MAX_RATE_USB2);
}
usrp1_impl::~usrp1_impl(void){
diff --git a/host/lib/usrp/usrp1/usrp1_impl.hpp b/host/lib/usrp/usrp1/usrp1_impl.hpp
index da9fe8b16..012bc0794 100644
--- a/host/lib/usrp/usrp1/usrp1_impl.hpp
+++ b/host/lib/usrp/usrp1/usrp1_impl.hpp
@@ -39,6 +39,7 @@
#define INCLUDED_USRP1_IMPL_HPP
static const std::string USRP1_EEPROM_MAP_KEY = "B000";
+static const size_t USRP1_MAX_RATE_USB2 = 32000000; // bytes/s
#define FR_RB_CAPS 3
#define FR_MODE 13
diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp
index 16d9b9a54..918f3e892 100644
--- a/host/lib/usrp/usrp2/usrp2_impl.cpp
+++ b/host/lib/usrp/usrp2/usrp2_impl.cpp
@@ -442,6 +442,7 @@ usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){
_mbc[mb].spiface = _mbc[mb].iface;
break;
}
+ _tree->create<double>(mb_path / "link_max_rate").set(USRP2_LINK_RATE_BPS);
////////////////////////////////////////////////////////////////
// setup the mboard eeprom
@@ -655,12 +656,14 @@ usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){
.subscribe(boost::bind(&time64_core_200::set_time_next_pps, _mbc[mb].time64, _1));
//setup time source props
_tree->create<std::string>(mb_path / "time_source/value")
- .subscribe(boost::bind(&time64_core_200::set_time_source, _mbc[mb].time64, _1));
+ .subscribe(boost::bind(&time64_core_200::set_time_source, _mbc[mb].time64, _1))
+ .set("none");
_tree->create<std::vector<std::string> >(mb_path / "time_source/options")
.publish(boost::bind(&time64_core_200::get_time_sources, _mbc[mb].time64));
//setup reference source props
_tree->create<std::string>(mb_path / "clock_source/value")
- .subscribe(boost::bind(&usrp2_impl::update_clock_source, this, mb, _1));
+ .subscribe(boost::bind(&usrp2_impl::update_clock_source, this, mb, _1))
+ .set("internal");
std::vector<std::string> clock_sources = boost::assign::list_of("internal")("external")("mimo");
if (_mbc[mb].gps and _mbc[mb].gps->gps_detected()) clock_sources.push_back("gpsdo");
_tree->create<std::vector<std::string> >(mb_path / "clock_source/options").set(clock_sources);
diff --git a/host/lib/usrp/x300/x300_impl.cpp b/host/lib/usrp/x300/x300_impl.cpp
index e492b2238..f5e53678c 100644
--- a/host/lib/usrp/x300/x300_impl.cpp
+++ b/host/lib/usrp/x300/x300_impl.cpp
@@ -392,6 +392,8 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr)
//Tell the quirks object which FIFOs carry TX stream data
const uint32_t tx_data_fifos[2] = {X300_RADIO_DEST_PREFIX_TX, X300_RADIO_DEST_PREFIX_TX + 3};
mb.rio_fpga_interface->get_kernel_proxy().get_rio_quirks().register_tx_streams(tx_data_fifos);
+
+ _tree->create<double>(mb_path / "link_max_rate").set(X300_MAX_RATE_PCIE);
}
BOOST_FOREACH(const std::string &key, dev_addr.keys())
@@ -456,6 +458,8 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr)
<< "UHD will use the auto-detected max frame size for this connection."
<< std::endl;
}
+
+ _tree->create<double>(mb_path / "link_max_rate").set(X300_MAX_RATE_10GIGE);
}
//create basic communication
@@ -1133,11 +1137,14 @@ x300_impl::both_xports_t x300_impl::make_transport(
if (mb.loaded_fpga_image == "HGS") {
if (mb.router_dst_here == X300_XB_DST_E0) {
eth_data_rec_frame_size = X300_1GE_DATA_FRAME_MAX_SIZE;
+ _tree->access<double>("/mboards/"+boost::lexical_cast<std::string>(mb_index) / "link_max_rate").set(X300_MAX_RATE_1GIGE);
} else if (mb.router_dst_here == X300_XB_DST_E1) {
eth_data_rec_frame_size = X300_10GE_DATA_FRAME_MAX_SIZE;
+ _tree->access<double>("/mboards/"+boost::lexical_cast<std::string>(mb_index) / "link_max_rate").set(X300_MAX_RATE_10GIGE);
}
} else if (mb.loaded_fpga_image == "XGS") {
- eth_data_rec_frame_size = X300_10GE_DATA_FRAME_MAX_SIZE;
+ eth_data_rec_frame_size = X300_10GE_DATA_FRAME_MAX_SIZE;
+ _tree->access<double>("/mboards/"+boost::lexical_cast<std::string>(mb_index) / "link_max_rate").set(X300_MAX_RATE_10GIGE);
}
if (eth_data_rec_frame_size == 0) {
diff --git a/host/lib/usrp/x300/x300_impl.hpp b/host/lib/usrp/x300/x300_impl.hpp
index 692427f31..4b3efc845 100644
--- a/host/lib/usrp/x300/x300_impl.hpp
+++ b/host/lib/usrp/x300/x300_impl.hpp
@@ -85,6 +85,10 @@ static const size_t X300_RX_MAX_HDR_LEN = // bytes
+ sizeof(uhd::transport::vrt::if_packet_info_t().sid) // SID
+ sizeof(uhd::transport::vrt::if_packet_info_t().tsf); // Timestamp
+static const size_t X300_MAX_RATE_PCIE = 800000000; // bytes/s
+static const size_t X300_MAX_RATE_10GIGE = 800000000; // bytes/s
+static const size_t X300_MAX_RATE_1GIGE = 100000000; // bytes/s
+
#define X300_RADIO_DEST_PREFIX_TX 0
#define X300_RADIO_DEST_PREFIX_CTRL 1
#define X300_RADIO_DEST_PREFIX_RX 2
diff --git a/host/lib/usrp/x300/x300_io_impl.cpp b/host/lib/usrp/x300/x300_io_impl.cpp
index 09ed1d705..9263c9b44 100644
--- a/host/lib/usrp/x300/x300_io_impl.cpp
+++ b/host/lib/usrp/x300/x300_io_impl.cpp
@@ -242,6 +242,8 @@ struct x300_tx_fc_guts_t
boost::shared_ptr<x300_impl::async_md_type> old_async_queue;
};
+#define X300_ASYNC_EVENT_CODE_FLOW_CTRL 0
+
static size_t get_tx_flow_control_window(size_t frame_size, const device_addr_t& tx_args)
{
double hw_buff_size = tx_args.cast<double>("send_buff_size", X300_TX_HW_BUFF_SIZE);
@@ -283,23 +285,28 @@ static void handle_tx_async_msgs(boost::shared_ptr<x300_tx_fc_guts_t> guts, zero
return;
}
- //catch the flow control packets and react
- if (endian_conv(packet_buff[if_packet_info.num_header_words32+0]) == 0)
- {
- const size_t seq = endian_conv(packet_buff[if_packet_info.num_header_words32+1]);
- guts->seq_queue.push_with_haste(seq);
- return;
- }
-
//fill in the async metadata
async_metadata_t metadata;
load_metadata_from_buff(
endian_conv, metadata, if_packet_info, packet_buff,
clock->get_master_clock_rate(), guts->stream_channel);
- guts->async_queue->push_with_pop_on_full(metadata);
- metadata.channel = guts->device_channel;
- guts->old_async_queue->push_with_pop_on_full(metadata);
- standard_async_msg_prints(metadata);
+
+ //The FC response and the burst ack are two indicators that the radio
+ //consumed packets. Use them to update the FC metadata
+ if (metadata.event_code == X300_ASYNC_EVENT_CODE_FLOW_CTRL or
+ metadata.event_code == async_metadata_t::EVENT_CODE_BURST_ACK
+ ) {
+ const size_t seq = metadata.user_payload[0];
+ guts->seq_queue.push_with_pop_on_full(seq);
+ }
+
+ //FC responses don't propagate up to the user so filter them here
+ if (metadata.event_code != X300_ASYNC_EVENT_CODE_FLOW_CTRL) {
+ guts->async_queue->push_with_pop_on_full(metadata);
+ metadata.channel = guts->device_channel;
+ guts->old_async_queue->push_with_pop_on_full(metadata);
+ standard_async_msg_prints(metadata);
+ }
}
static managed_send_buffer::sptr get_tx_buff_with_flowctrl(
@@ -319,7 +326,9 @@ static managed_send_buffer::sptr get_tx_buff_with_flowctrl(
}
managed_send_buffer::sptr buff = xport->get_send_buff(timeout);
- if (buff) guts->last_seq_out++; //update seq, this will actually be a send
+ if (buff) {
+ guts->last_seq_out++; //update seq, this will actually be a send
+ }
return buff;
}
diff --git a/host/tests/CMakeLists.txt b/host/tests/CMakeLists.txt
index 2a40d0050..7c4815004 100644
--- a/host/tests/CMakeLists.txt
+++ b/host/tests/CMakeLists.txt
@@ -28,6 +28,7 @@ SET(test_sources
buffer_test.cpp
byteswap_test.cpp
convert_test.cpp
+ cast_test.cpp
dict_test.cpp
error_test.cpp
gain_group_test.cpp
diff --git a/host/tests/cast_test.cpp b/host/tests/cast_test.cpp
new file mode 100644
index 000000000..6b8a4c527
--- /dev/null
+++ b/host/tests/cast_test.cpp
@@ -0,0 +1,33 @@
+//
+// 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 <iostream>
+#include <boost/test/unit_test.hpp>
+#include <boost/cstdint.hpp>
+#include <uhd/utils/cast.hpp>
+
+BOOST_AUTO_TEST_CASE(test_mac_addr){
+ std::string in = "0x0100";
+ boost::uint16_t correct_result = 256;
+ boost::uint16_t x = uhd::cast::hexstr_cast<boost::uint16_t>(in);
+ //boost::uint16_t x = uhd::cast::hexstr_cast(in);
+ std::cout
+ << "Testing hex -> uint16_t conversion. "
+ << in << " == " << std::hex << x << "?" << std::endl;
+ BOOST_CHECK_EQUAL(x, correct_result);
+}
+
diff --git a/host/utils/uhd_cal_rx_iq_balance.cpp b/host/utils/uhd_cal_rx_iq_balance.cpp
index 551da7544..3188e02a0 100644
--- a/host/utils/uhd_cal_rx_iq_balance.cpp
+++ b/host/utils/uhd_cal_rx_iq_balance.cpp
@@ -121,37 +121,14 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
if (vm.count("help")){
std::cout << boost::format("USRP Generate RX IQ Balance Calibration Table %s") % desc << std::endl;
std::cout <<
- "This application measures leakage between RX and TX on an XCVR daughterboard to self-calibrate.\n"
+ "This application measures leakage between RX and TX on a transceiver daughterboard to self-calibrate.\n"
+ "Note: Not all daughterboards support this feature. Refer to the UHD manual for details.\n"
<< std::endl;
return EXIT_FAILURE;
}
- //create a usrp device
- std::cout << std::endl;
- std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl;
- uhd::usrp::multi_usrp::sptr usrp = uhd::usrp::multi_usrp::make(args);
-
- // Configure subdev
- if (vm.count("subdev")) {
- usrp->set_tx_subdev_spec(subdev);
- usrp->set_rx_subdev_spec(subdev);
- }
- UHD_MSG(status) << "Running calibration for " << usrp->get_tx_subdev_name(0) << std::endl;
- serial = get_serial(usrp, "tx");
- UHD_MSG(status) << "Daughterboard serial: " << serial << std::endl;
-
- //set the antennas to cal
- if (not uhd::has(usrp->get_rx_antennas(), "CAL") or not uhd::has(usrp->get_tx_antennas(), "CAL")){
- throw std::runtime_error("This board does not have the CAL antenna option, cannot self-calibrate.");
- }
- usrp->set_rx_antenna("CAL");
- usrp->set_tx_antenna("CAL");
-
- //fail if daughterboard has no serial
- check_for_empty_serial(usrp, "RX", "rx", args);
-
- //set optimum defaults
- set_optimum_defaults(usrp);
+ // Create a USRP device
+ uhd::usrp::multi_usrp::sptr usrp = setup_usrp_for_cal(args, subdev, serial);
//create a receive streamer
uhd::stream_args_t stream_args("fc32"); //complex floats
diff --git a/host/utils/uhd_cal_tx_dc_offset.cpp b/host/utils/uhd_cal_tx_dc_offset.cpp
index eb82db826..b5c5293f0 100644
--- a/host/utils/uhd_cal_tx_dc_offset.cpp
+++ b/host/utils/uhd_cal_tx_dc_offset.cpp
@@ -123,37 +123,14 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
if (vm.count("help")){
std::cout << boost::format("USRP Generate TX DC Offset Calibration Table %s") % desc << std::endl;
std::cout <<
- "This application measures leakage between RX and TX on an XCVR daughterboard to self-calibrate.\n"
+ "This application measures leakage between RX and TX on a transceiver daughterboard to self-calibrate.\n"
+ "Note: Not all daughterboards support this feature. Refer to the UHD manual for details.\n"
<< std::endl;
return EXIT_FAILURE;
}
- //create a usrp device
- std::cout << std::endl;
- std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl;
- uhd::usrp::multi_usrp::sptr usrp = uhd::usrp::multi_usrp::make(args);
-
- // Configure subdev
- if (vm.count("subdev")) {
- usrp->set_tx_subdev_spec(subdev);
- usrp->set_rx_subdev_spec(subdev);
- }
- UHD_MSG(status) << "Running calibration for " << usrp->get_tx_subdev_name(0) << std::endl;
- serial = get_serial(usrp, "tx");
- UHD_MSG(status) << "Daughterboard serial: " << serial << std::endl;
-
- //set the antennas to cal
- if (not uhd::has(usrp->get_rx_antennas(), "CAL") or not uhd::has(usrp->get_tx_antennas(), "CAL")){
- throw std::runtime_error("This board does not have the CAL antenna option, cannot self-calibrate.");
- }
- usrp->set_rx_antenna("CAL");
- usrp->set_tx_antenna("CAL");
-
- //fail if daughterboard has no serial
- check_for_empty_serial(usrp, "TX", "tx", args);
-
- //set optimum defaults
- set_optimum_defaults(usrp);
+ // Create a USRP device
+ uhd::usrp::multi_usrp::sptr usrp = setup_usrp_for_cal(args, subdev, serial);
//create a receive streamer
uhd::stream_args_t stream_args("fc32"); //complex floats
diff --git a/host/utils/uhd_cal_tx_iq_balance.cpp b/host/utils/uhd_cal_tx_iq_balance.cpp
index 786aac061..6461b3d71 100644
--- a/host/utils/uhd_cal_tx_iq_balance.cpp
+++ b/host/utils/uhd_cal_tx_iq_balance.cpp
@@ -18,12 +18,7 @@
#include "usrp_cal_utils.hpp"
#include <uhd/utils/thread_priority.hpp>
#include <uhd/utils/safe_main.hpp>
-#include <uhd/utils/paths.hpp>
-#include <uhd/utils/algorithm.hpp>
-#include <uhd/utils/msg.hpp>
-#include <uhd/usrp/multi_usrp.hpp>
#include <boost/program_options.hpp>
-#include <boost/format.hpp>
#include <boost/thread/thread.hpp>
#include <boost/math/special_functions/round.hpp>
#include <iostream>
@@ -124,37 +119,14 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
if (vm.count("help")){
std::cout << boost::format("USRP Generate TX IQ Balance Calibration Table %s") % desc << std::endl;
std::cout <<
- "This application measures leakage between RX and TX on a daughterboard to self-calibrate.\n"
+ "This application measures leakage between RX and TX on a transceiver daughterboard to self-calibrate.\n"
+ "Note: Not all daughterboards support this feature. Refer to the UHD manual for details.\n"
<< std::endl;
return EXIT_FAILURE;
}
- //create a usrp device
- std::cout << std::endl;
- std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl;
- uhd::usrp::multi_usrp::sptr usrp = uhd::usrp::multi_usrp::make(args);
-
- // Configure subdev
- if (vm.count("subdev")) {
- usrp->set_tx_subdev_spec(subdev);
- usrp->set_rx_subdev_spec(subdev);
- }
- UHD_MSG(status) << "Running calibration for " << usrp->get_tx_subdev_name(0) << std::endl;
- serial = get_serial(usrp, "tx");
- UHD_MSG(status) << "Daughterboard serial: " << serial << std::endl;
-
- //set the antennas to cal
- if (not uhd::has(usrp->get_rx_antennas(), "CAL") or not uhd::has(usrp->get_tx_antennas(), "CAL")){
- throw std::runtime_error("This board does not have the CAL antenna option, cannot self-calibrate.");
- }
- usrp->set_rx_antenna("CAL");
- usrp->set_tx_antenna("CAL");
-
- //fail if daughterboard has no serial
- check_for_empty_serial(usrp, "TX", "tx", args);
-
- //set optimum defaults
- set_optimum_defaults(usrp);
+ // Create a USRP device
+ uhd::usrp::multi_usrp::sptr usrp = setup_usrp_for_cal(args, subdev, serial);
//create a receive streamer
uhd::stream_args_t stream_args("fc32"); //complex floats
diff --git a/host/utils/usrp_burn_mb_eeprom.cpp b/host/utils/usrp_burn_mb_eeprom.cpp
index ce0879c8e..c631c9c09 100644
--- a/host/utils/usrp_burn_mb_eeprom.cpp
+++ b/host/utils/usrp_burn_mb_eeprom.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010,2013 Ettus Research LLC
+// Copyright 2010,2013-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
@@ -19,6 +19,7 @@
#include <uhd/device.hpp>
#include <uhd/property_tree.hpp>
#include <uhd/usrp/mboard_eeprom.hpp>
+#include <uhd/types/device_addr.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/program_options.hpp>
#include <boost/format.hpp>
@@ -28,14 +29,16 @@
namespace po = boost::program_options;
int UHD_SAFE_MAIN(int argc, char *argv[]){
- std::string args, key, val;
+ 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 = \"\"]")
- ("key", po::value<std::string>(&key), "identifiers for new values in EEPROM, separate multiple by \",\"")
- ("val", po::value<std::string>(&val), "the new values to set, omit for readback, separate multiple by \",\"")
+ ("values", po::value<std::string>(&input_str), "keys+values to read/write, separate multiple by \",\"")
+ ("key", po::value<std::string>(&key), "identifiers for new values in EEPROM, separate multiple by \",\" (DEPRECATED)")
+ ("val", po::value<std::string>(&val), "the new values to set, omit for readback, separate multiple by \",\" (DEPRECATED)")
+ ("read-all", "Read all motherboard EEPROM values without writing")
;
po::variables_map vm;
@@ -43,7 +46,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
po::notify(vm);
//print the help message
- if (vm.count("help") or not vm.count("key")){
+ if (vm.count("help") or (not vm.count("key") and not vm.count("values") and not vm.count("read-all"))){
std::cout << boost::format("USRP Burn Motherboard EEPROM %s") % desc << std::endl;
std::cout << boost::format(
"Omit the value argument to perform a readback,\n"
@@ -55,23 +58,33 @@ 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::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;
- //remove whitespace, split arguments and values
- boost::algorithm::erase_all(key, " ");
- boost::algorithm::erase_all(val, " ");
-
std::vector<std::string> keys_vec, vals_vec;
- boost::split(keys_vec, key, boost::is_any_of("\"',"));
- boost::split(vals_vec, val, boost::is_any_of("\"',"));
+ if(vm.count("read-all")) keys_vec = mb_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
+ uhd::device_addr_t vals(input_str);
+ keys_vec = vals.keys();
+ vals_vec = vals.vals();
+ }
+ else{
+ std::cout << "WARNING: Use of --key and --val is deprecated!" << std::endl;
+ //remove whitespace, split arguments and values
+ boost::algorithm::erase_all(key, " ");
+ boost::algorithm::erase_all(val, " ");
+
+ boost::split(keys_vec, key, boost::is_any_of("\"',"));
+ boost::split(vals_vec, val, boost::is_any_of("\"',"));
- if((keys_vec.size() != vals_vec.size()) and val != "") {
- //If zero values are given, then user just wants values read to them
- throw std::runtime_error("Number of keys must match number of values!");
+ if((keys_vec.size() != vals_vec.size()) and val != "") {
+ //If zero values are given, then user just wants values read to them
+ throw std::runtime_error("Number of keys must match number of values!");
+ }
}
std::cout << "Fetching current settings from EEPROM..." << std::endl;
- uhd::usrp::mboard_eeprom_t mb_eeprom = tree->access<uhd::usrp::mboard_eeprom_t>("/mboards/0/eeprom").get();
for(size_t i = 0; i < keys_vec.size(); i++){
if (not mb_eeprom.has_key(keys_vec[i])){
std::cerr << boost::format("Cannot find value for EEPROM[%s]") % keys_vec[i] << std::endl;
@@ -80,15 +93,15 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
std::cout << boost::format(" EEPROM [\"%s\"] is \"%s\"") % keys_vec[i] % mb_eeprom[keys_vec[i]] << std::endl;
}
std::cout << std::endl;
- if (vm.count("val")){
- for(size_t i = 0; i < vals_vec.size(); i++){
+ for(size_t i = 0; i < vals_vec.size(); i++){
+ if(vals_vec[i] != ""){
uhd::usrp::mboard_eeprom_t mb_eeprom; mb_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<uhd::usrp::mboard_eeprom_t>("/mboards/0/eeprom").set(mb_eeprom);
}
- std::cout << "Power-cycle the USRP device for the changes to take effect." << std::endl;
- std::cout << std::endl;
}
+ std::cout << "Power-cycle the USRP device for the changes to take effect." << std::endl;
+ std::cout << std::endl;
std::cout << "Done" << std::endl;
return EXIT_SUCCESS;
diff --git a/host/utils/usrp_cal_utils.hpp b/host/utils/usrp_cal_utils.hpp
index 5aff5e22f..9e7f4c469 100644
--- a/host/utils/usrp_cal_utils.hpp
+++ b/host/utils/usrp_cal_utils.hpp
@@ -20,6 +20,8 @@
#include <uhd/usrp/multi_usrp.hpp>
#include <uhd/usrp/dboard_eeprom.hpp>
#include <uhd/utils/paths.hpp>
+#include <uhd/utils/algorithm.hpp>
+#include <uhd/utils/msg.hpp>
#include <boost/filesystem.hpp>
#include <boost/format.hpp>
#include <iostream>
@@ -50,6 +52,8 @@ static const size_t default_num_samps = 10000;
**********************************************************************/
static inline void set_optimum_defaults(uhd::usrp::multi_usrp::sptr usrp){
uhd::property_tree::sptr tree = usrp->get_device()->get_tree();
+ // Will work on 1st subdev, top-level must make sure it's the right one
+ uhd::usrp::subdev_spec_t subdev_spec = usrp->get_rx_subdev_spec();
const uhd::fs_path mb_path = "/mboards/0";
const std::string mb_name = tree->access<std::string>(mb_path / "name").get();
@@ -69,7 +73,7 @@ static inline void set_optimum_defaults(uhd::usrp::multi_usrp::sptr usrp){
throw std::runtime_error("self-calibration is not supported for this hardware");
}
- const uhd::fs_path tx_fe_path = "/mboards/0/dboards/A/tx_frontends/0";
+ const uhd::fs_path tx_fe_path = "/mboards/0/dboards/" + subdev_spec[0].db_name + "/tx_frontends/0";
const std::string tx_name = tree->access<std::string>(tx_fe_path / "name").get();
if (tx_name.find("WBX") != std::string::npos){
usrp->set_tx_gain(0);
@@ -87,7 +91,7 @@ static inline void set_optimum_defaults(uhd::usrp::multi_usrp::sptr usrp){
throw std::runtime_error("self-calibration is not supported for this hardware");
}
- const uhd::fs_path rx_fe_path = "/mboards/0/dboards/A/rx_frontends/0";
+ const uhd::fs_path rx_fe_path = "/mboards/0/dboards/" + subdev_spec[0].db_name + "/rx_frontends/0";
const std::string rx_name = tree->access<std::string>(rx_fe_path / "name").get();
if (rx_name.find("WBX") != std::string::npos){
usrp->set_rx_gain(25);
@@ -110,24 +114,19 @@ static inline void set_optimum_defaults(uhd::usrp::multi_usrp::sptr usrp){
/***********************************************************************
* Check for empty serial
**********************************************************************/
-
void check_for_empty_serial(
- uhd::usrp::multi_usrp::sptr usrp,
- std::string XX,
- std::string xx,
- std::string uhd_args
+ uhd::usrp::multi_usrp::sptr usrp
){
+ // Will work on 1st subdev, top-level must make sure it's the right one
+ uhd::usrp::subdev_spec_t subdev_spec = usrp->get_rx_subdev_spec();
//extract eeprom
uhd::property_tree::sptr tree = usrp->get_device()->get_tree();
- const uhd::fs_path db_path = "/mboards/0/dboards/A/" + xx + "_eeprom";
+ // This only works with transceiver boards, so we can always check rx side
+ const uhd::fs_path db_path = "/mboards/0/dboards/" + subdev_spec[0].db_name + "/rx_eeprom";
const uhd::usrp::dboard_eeprom_t db_eeprom = tree->access<uhd::usrp::dboard_eeprom_t>(db_path).get();
- std::string args_str = "";
- if(uhd_args != "") args_str = str(boost::format(" --args=%s") % uhd_args);
-
- std::string error_string = str(boost::format("This %s dboard has no serial!\n\nPlease see the Calibration documentation for details on how to fix this.") % XX);
-
+ std::string error_string = "This dboard has no serial!\n\nPlease see the Calibration documentation for details on how to fix this.";
if (db_eeprom.serial.empty()) throw std::runtime_error(error_string);
}
@@ -188,6 +187,7 @@ static std::string get_serial(
const std::string &tx_rx
){
uhd::property_tree::sptr tree = usrp->get_device()->get_tree();
+ // Will work on 1st subdev, top-level must make sure it's the right one
uhd::usrp::subdev_spec_t subdev_spec = usrp->get_rx_subdev_spec();
const uhd::fs_path db_path = "/mboards/0/dboards/" + subdev_spec[0].db_name + "/" + tx_rx + "_eeprom";
const uhd::usrp::dboard_eeprom_t db_eeprom = tree->access<uhd::usrp::dboard_eeprom_t>(db_path).get();
@@ -257,8 +257,8 @@ static void capture_samples(
//validate the received data
if (md.error_code != uhd::rx_metadata_t::ERROR_CODE_NONE){
throw std::runtime_error(str(boost::format(
- "Unexpected error code 0x%x"
- ) % md.error_code));
+ "Receiver error: %s"
+ ) % md.strerror()));
}
//we can live if all the data didnt come in
if (num_rx_samps > buff.size()/2){
@@ -270,3 +270,37 @@ static void capture_samples(
}
}
+/***********************************************************************
+ * Setup function
+ **********************************************************************/
+static uhd::usrp::multi_usrp::sptr setup_usrp_for_cal(std::string &args, std::string &subdev, std::string &serial)
+{
+ std::cout << std::endl;
+ std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl;
+ uhd::usrp::multi_usrp::sptr usrp = uhd::usrp::multi_usrp::make(args);
+
+ // Configure subdev
+ if (!subdev.empty()) {
+ usrp->set_tx_subdev_spec(subdev);
+ usrp->set_rx_subdev_spec(subdev);
+ }
+ UHD_MSG(status) << "Running calibration for " << usrp->get_tx_subdev_name(0) << std::endl;
+ serial = get_serial(usrp, "tx");
+ UHD_MSG(status) << "Daughterboard serial: " << serial << std::endl;
+
+ //set the antennas to cal
+ if (not uhd::has(usrp->get_rx_antennas(), "CAL") or not uhd::has(usrp->get_tx_antennas(), "CAL")){
+ throw std::runtime_error("This board does not have the CAL antenna option, cannot self-calibrate.");
+ }
+ usrp->set_rx_antenna("CAL");
+ usrp->set_tx_antenna("CAL");
+
+ //fail if daughterboard has no serial
+ check_for_empty_serial(usrp);
+
+ //set optimum defaults
+ set_optimum_defaults(usrp);
+
+ return usrp;
+}
+
diff --git a/host/utils/usrp_n2xx_simple_net_burner.cpp b/host/utils/usrp_n2xx_simple_net_burner.cpp
index 277e807d9..cecac5588 100644
--- a/host/utils/usrp_n2xx_simple_net_burner.cpp
+++ b/host/utils/usrp_n2xx_simple_net_burner.cpp
@@ -17,13 +17,13 @@
#include <csignal>
#include <iostream>
-#include <map>
#include <fstream>
#include <time.h>
#include <vector>
#include <boost/foreach.hpp>
#include <boost/asio.hpp>
+#include <boost/filesystem.hpp>
#include <boost/program_options.hpp>
#include <boost/assign.hpp>
#include <boost/assign/list_of.hpp>
@@ -32,21 +32,97 @@
#include <boost/filesystem.hpp>
#include <boost/thread/thread.hpp>
-#include "usrp_simple_burner_utils.hpp"
#include <uhd/exception.hpp>
#include <uhd/property_tree.hpp>
#include <uhd/transport/if_addrs.hpp>
#include <uhd/transport/udp_simple.hpp>
+#include <uhd/types/dict.hpp>
#include <uhd/utils/byteswap.hpp>
#include <uhd/utils/images.hpp>
#include <uhd/utils/safe_main.hpp>
#include <uhd/utils/safe_call.hpp>
+namespace fs = boost::filesystem;
namespace po = boost::program_options;
using namespace boost::algorithm;
using namespace uhd;
using namespace uhd::transport;
+#define UDP_FW_UPDATE_PORT 49154
+#define UDP_MAX_XFER_BYTES 1024
+#define UDP_TIMEOUT 3
+#define UDP_POLL_INTERVAL 0.10 //in seconds
+#define USRP2_FW_PROTO_VERSION 7 //should be unused after r6
+#define USRP2_UDP_UPDATE_PORT 49154
+#define FLASH_DATA_PACKET_SIZE 256
+#define FPGA_IMAGE_SIZE_BYTES 1572864
+#define FW_IMAGE_SIZE_BYTES 31744
+#define PROD_FPGA_IMAGE_LOCATION_ADDR 0x00180000
+#define PROD_FW_IMAGE_LOCATION_ADDR 0x00300000
+#define SAFE_FPGA_IMAGE_LOCATION_ADDR 0x00000000
+#define SAFE_FW_IMAGE_LOCATION_ADDR 0x003F0000
+
+typedef enum {
+ UNKNOWN = ' ',
+
+ USRP2_QUERY = 'a',
+ USRP2_ACK = 'A',
+
+ GET_FLASH_INFO_CMD = 'f',
+ GET_FLASH_INFO_ACK = 'F',
+
+ ERASE_FLASH_CMD = 'e',
+ ERASE_FLASH_ACK = 'E',
+
+ CHECK_ERASING_DONE_CMD = 'd',
+ DONE_ERASING_ACK = 'D',
+ NOT_DONE_ERASING_ACK = 'B',
+
+ WRITE_FLASH_CMD = 'w',
+ WRITE_FLASH_ACK = 'W',
+
+ READ_FLASH_CMD = 'r',
+ READ_FLASH_ACK = 'R',
+
+ RESET_USRP_CMD = 's',
+ RESET_USRP_ACK = 'S',
+
+ GET_HW_REV_CMD = 'v',
+ GET_HW_REV_ACK = 'V',
+
+} usrp2_fw_update_id_t;
+
+typedef struct {
+ uint32_t proto_ver;
+ uint32_t id;
+ uint32_t seq;
+ union {
+ uint32_t ip_addr;
+ uint32_t hw_rev;
+ struct {
+ uint32_t flash_addr;
+ uint32_t length;
+ uint8_t data[256];
+ } flash_args;
+ struct {
+ uint32_t sector_size_bytes;
+ uint32_t memory_size_bytes;
+ } flash_info_args;
+ } data;
+} usrp2_fw_update_data_t;
+
+//Mapping revision numbers to filenames
+uhd::dict<boost::uint32_t, std::string> filename_map = boost::assign::map_list_of
+ (0xa, "n200_r3")
+ (0x100a, "n200_r4")
+ (0x10a, "n210_r3")
+ (0x110a, "n210_r4")
+;
+
+boost::uint8_t usrp2_update_data_in_mem[udp_simple::mtu];
+boost::uint8_t fpga_image[FPGA_IMAGE_SIZE_BYTES];
+boost::uint8_t fw_image[FW_IMAGE_SIZE_BYTES];
+
/***********************************************************************
* Signal handlers
**********************************************************************/
@@ -66,59 +142,94 @@ void sig_int_handler(int){
}
}
-//Mapping revision numbers to filenames
-std::map<boost::uint32_t, std::string> filename_map = boost::assign::map_list_of
- (0xa, "n200_r3")
- (0x100a, "n200_r4")
- (0x10a, "n210_r3")
- (0x110a, "n210_r4")
-;
+/***********************************************************************
+ * List all connected USRP N2XX devices
+ **********************************************************************/
+void list_usrps(){
+ udp_simple::sptr udp_bc_transport;
+ const usrp2_fw_update_data_t *update_data_in = reinterpret_cast<const usrp2_fw_update_data_t *>(usrp2_update_data_in_mem);
+ boost::uint32_t hw_rev;
-//Images and image sizes, to be populated as necessary
-boost::uint8_t fpga_image[FPGA_IMAGE_SIZE_BYTES];
-boost::uint8_t fw_image[FW_IMAGE_SIZE_BYTES];
-int fpga_image_size = 0;
-int fw_image_size = 0;
+ usrp2_fw_update_data_t usrp2_ack_pkt = usrp2_fw_update_data_t();
+ usrp2_ack_pkt.proto_ver = htonx<boost::uint32_t>(USRP2_FW_PROTO_VERSION);
+ usrp2_ack_pkt.id = htonx<boost::uint32_t>(USRP2_QUERY);
+
+ std::cout << "Available USRP N2XX devices:" << std::endl;
-//For non-standard images not covered by uhd::find_image_path()
-bool does_image_exist(std::string image_filepath){
+ //Send UDP packets to all broadcast addresses
+ BOOST_FOREACH(const if_addrs_t &if_addrs, get_if_addrs()){
+ //Avoid the loopback device
+ if(if_addrs.inet == boost::asio::ip::address_v4::loopback().to_string()) continue;
+ udp_bc_transport = udp_simple::make_broadcast(if_addrs.bcast, BOOST_STRINGIZE(USRP2_UDP_UPDATE_PORT));
+ udp_bc_transport->send(boost::asio::buffer(&usrp2_ack_pkt, sizeof(usrp2_ack_pkt)));
- std::ifstream ifile((char*)image_filepath.c_str());
- return ifile;
+ size_t len = udp_bc_transport->recv(boost::asio::buffer(usrp2_update_data_in_mem), UDP_TIMEOUT);
+ if(len > offsetof(usrp2_fw_update_data_t, data) and ntohl(update_data_in->id) == USRP2_ACK){
+ usrp2_ack_pkt.id = htonx<boost::uint32_t>(GET_HW_REV_CMD);
+ udp_bc_transport->send(boost::asio::buffer(&usrp2_ack_pkt, sizeof(usrp2_ack_pkt)));
+
+ size_t len = udp_bc_transport->recv(boost::asio::buffer(usrp2_update_data_in_mem), UDP_TIMEOUT);
+ if(len > offsetof(usrp2_fw_update_data_t, data) and ntohl(update_data_in->id) == GET_HW_REV_ACK){
+ hw_rev = ntohl(update_data_in->data.hw_rev);
+ }
+
+ std::cout << boost::format(" * %s (%s)\n") % udp_bc_transport->get_recv_addr() % filename_map[hw_rev];
+ }
+ }
+}
+
+/***********************************************************************
+ * Find USRP N2XX with specified IP address and return type
+ **********************************************************************/
+boost::uint32_t find_usrp(udp_simple::sptr udp_transport){
+ boost::uint32_t hw_rev;
+ bool found_it = false;
+
+ const usrp2_fw_update_data_t *update_data_in = reinterpret_cast<const usrp2_fw_update_data_t *>(usrp2_update_data_in_mem);
+ usrp2_fw_update_data_t hw_info_pkt = usrp2_fw_update_data_t();
+ hw_info_pkt.proto_ver = htonx<boost::uint32_t>(USRP2_FW_PROTO_VERSION);
+ hw_info_pkt.id = htonx<boost::uint32_t>(GET_HW_REV_CMD);
+ udp_transport->send(boost::asio::buffer(&hw_info_pkt, sizeof(hw_info_pkt)));
+
+ //Loop and receive until the timeout
+ size_t len = udp_transport->recv(boost::asio::buffer(usrp2_update_data_in_mem), UDP_TIMEOUT);
+ if(len > offsetof(usrp2_fw_update_data_t, data) and ntohl(update_data_in->id) == GET_HW_REV_ACK){
+ hw_rev = ntohl(update_data_in->data.hw_rev);
+ if(filename_map.has_key(hw_rev)){
+ std::cout << boost::format("Found %s.\n\n") % filename_map[hw_rev];
+ found_it = true;
+ }
+ else throw std::runtime_error("Invalid revision found.");
+ }
+ if(not found_it) throw std::runtime_error("No USRP N2XX found.");
+
+ return hw_rev;
}
/***********************************************************************
* Custom filename validation functions
**********************************************************************/
-void validate_custom_fpga_file(std::string rev_str, std::string fpga_path){
+void validate_custom_fpga_file(std::string rev_str, std::string& fpga_path){
//Check for existence of file
- if(!does_image_exist(fpga_path)) throw std::runtime_error(str(boost::format("No file at specified FPGA path: %s") % fpga_path));
+ if(not fs::exists(fpga_path)) throw std::runtime_error(str(boost::format("No file at specified FPGA path: %s") % fpga_path));
//Check to find rev_str in filename
uhd::fs_path custom_fpga_path(fpga_path);
- if(custom_fpga_path.leaf().find("fw") != std::string::npos){
- throw std::runtime_error(str(boost::format("Invalid FPGA image filename at path: %s\nFilename indicates that this is a firmware image.")
- % fpga_path));
- }
if(custom_fpga_path.leaf().find(rev_str) == std::string::npos){
throw std::runtime_error(str(boost::format("Invalid FPGA image filename at path: %s\nFilename must contain '%s' to be considered valid for this model.")
% fpga_path % rev_str));
}
}
-void validate_custom_fw_file(std::string rev_str, std::string fw_path){
+void validate_custom_fw_file(std::string rev_str, std::string& fw_path){
//Check for existence of file
- if(!does_image_exist(fw_path)) throw std::runtime_error(str(boost::format("No file at specified firmware path: %s") % fw_path));
+ if(not fs::exists(fw_path)) throw std::runtime_error(str(boost::format("No file at specified firmware path: %s") % fw_path));
//Check to find truncated rev_str in filename
uhd::fs_path custom_fw_path(fw_path);
- if(custom_fw_path.leaf().find("fpga") != std::string::npos){
- throw std::runtime_error(str(boost::format("Invalid firmware image filename at path: %s\nFilename indicates that this is an FPGA image.")
- % fw_path));
- }
if(custom_fw_path.leaf().find(erase_tail_copy(rev_str,3)) == std::string::npos){
throw std::runtime_error(str(boost::format("Invalid firmware image filename at path: %s\nFilename must contain '%s' to be considered valid for this model.")
% fw_path % erase_tail_copy(rev_str,3)));
@@ -126,89 +237,91 @@ void validate_custom_fw_file(std::string rev_str, std::string fw_path){
}
/***********************************************************************
- * Grabbing and validating image binaries
+ * Reading and validating image binaries
**********************************************************************/
-int grab_fpga_image(std::string fpga_path){
+int read_fpga_image(std::string& fpga_path){
- //Reading FPGA image from file
- std::ifstream to_read_fpga((char*)fpga_path.c_str(), std::ios::binary);
- to_read_fpga.seekg(0, std::ios::end);
- fpga_image_size = to_read_fpga.tellg();
- to_read_fpga.seekg(0, std::ios::beg);
- char fpga_read[FPGA_IMAGE_SIZE_BYTES];
- to_read_fpga.read(fpga_read,fpga_image_size);
- to_read_fpga.close();
- for(int i = 0; i < fpga_image_size; i++) fpga_image[i] = (boost::uint8_t)fpga_read[i];
-
- //Checking validity of image
+ //Check size of given image
+ std::ifstream fpga_file(fpga_path.c_str(), std::ios::binary);
+ fpga_file.seekg(0, std::ios::end);
+ int fpga_image_size = fpga_file.tellg();
if(fpga_image_size > FPGA_IMAGE_SIZE_BYTES){
- throw std::runtime_error(str(boost::format("FPGA image is too large. %d > %d") % fpga_image_size % FPGA_IMAGE_SIZE_BYTES));
+ throw std::runtime_error(str(boost::format("FPGA image is too large. %d > %d")
+ % fpga_image_size % FPGA_IMAGE_SIZE_BYTES));
}
- //Check sequence of bytes in image
+ //Check sequence of bytes in image before reading
+ boost::uint8_t fpga_test_bytes[63];
+ fpga_file.seekg(0, std::ios::beg);
+ fpga_file.read((char*)fpga_test_bytes,63);
bool is_good = false;
for(int i = 0; i < 63; i++){
- if((boost::uint8_t)fpga_image[i] == 255) continue;
- else if((boost::uint8_t)fpga_image[i] == 170 and
- (boost::uint8_t)fpga_image[i+1] == 153){
+ if(fpga_test_bytes[i] == 255) continue;
+ else if(fpga_test_bytes[i] == 170 and
+ fpga_test_bytes[i+1] == 153){
is_good = true;
break;
}
}
+ if(not is_good) throw std::runtime_error("Not a valid FPGA image.");
- if(!is_good) throw std::runtime_error("Not a valid FPGA image.");
+ //With image validated, read into utility
+ fpga_file.seekg(0, std::ios::beg);
+ fpga_file.read((char*)fpga_image,fpga_image_size);
+ fpga_file.close();
//Return image size
return fpga_image_size;
}
-int grab_fw_image(std::string fw_path){
-
- //Reading firmware image from file
- std::ifstream to_read_fw((char*)fw_path.c_str(), std::ios::binary);
- to_read_fw.seekg(0, std::ios::end);
- fw_image_size = to_read_fw.tellg();
- to_read_fw.seekg(0, std::ios::beg);
- char fw_read[FW_IMAGE_SIZE_BYTES];
- to_read_fw.read(fw_read,fw_image_size);
- to_read_fw.close();
- for(int i = 0; i < fw_image_size; i++) fw_image[i] = (boost::uint8_t)fw_read[i];
+int read_fw_image(std::string& fw_path){
- //Checking validity of image
+ //Check size of given image
+ std::ifstream fw_file(fw_path.c_str(), std::ios::binary);
+ fw_file.seekg(0, std::ios::end);
+ int fw_image_size = fw_file.tellg();
if(fw_image_size > FW_IMAGE_SIZE_BYTES){
- throw std::runtime_error(str(boost::format("Firmware image is too large. %d > %d") % fw_image_size % FW_IMAGE_SIZE_BYTES));
+ throw std::runtime_error(str(boost::format("Firmware image is too large. %d > %d")
+ % fw_image_size % FW_IMAGE_SIZE_BYTES));
}
- //Check first four bytes of image
- for(int i = 0; i < 4; i++) if((boost::uint8_t)fw_image[i] != 11) throw std::runtime_error("Not a valid firmware image.");
+ //Check sequence of bytes in image before reading
+ boost::uint8_t fw_test_bytes[4];
+ fw_file.seekg(0, std::ios::beg);
+ fw_file.read((char*)fw_test_bytes,4);
+ for(int i = 0; i < 4; i++) if(fw_test_bytes[i] != 11) throw std::runtime_error("Not a valid firmware image.");
+
+ //With image validated, read into utility
+ fw_file.seekg(0, std::ios::beg);
+ fw_file.read((char*)fw_image,fw_image_size);
+ fw_file.close();
- //Return image size
return fw_image_size;
}
-boost::uint32_t* get_flash_info(std::string ip_addr){
+boost::uint32_t* get_flash_info(std::string& ip_addr){
boost::uint32_t *flash_info = new boost::uint32_t[2];
- boost::uint8_t usrp2_update_data_in_mem[udp_simple::mtu];
const usrp2_fw_update_data_t *update_data_in = reinterpret_cast<const usrp2_fw_update_data_t *>(usrp2_update_data_in_mem);
udp_simple::sptr udp_transport = udp_simple::make_connected(ip_addr, BOOST_STRINGIZE(USRP2_UDP_UPDATE_PORT));
usrp2_fw_update_data_t get_flash_info_pkt = usrp2_fw_update_data_t();
get_flash_info_pkt.proto_ver = htonx<boost::uint32_t>(USRP2_FW_PROTO_VERSION);
- get_flash_info_pkt.id = htonx<boost::uint32_t>(USRP2_FW_UPDATE_ID_WATS_TEH_FLASH_INFO_LOL);
+ get_flash_info_pkt.id = htonx<boost::uint32_t>(GET_FLASH_INFO_CMD);
udp_transport->send(boost::asio::buffer(&get_flash_info_pkt, sizeof(get_flash_info_pkt)));
//Loop and receive until the timeout
size_t len = udp_transport->recv(boost::asio::buffer(usrp2_update_data_in_mem), UDP_TIMEOUT);
- if(len > offsetof(usrp2_fw_update_data_t, data) and ntohl(update_data_in->id) == USRP2_FW_UPDATE_ID_HERES_TEH_FLASH_INFO_OMG){
+ if(len > offsetof(usrp2_fw_update_data_t, data) and ntohl(update_data_in->id) == GET_FLASH_INFO_ACK){
flash_info[0] = ntohl(update_data_in->data.flash_info_args.sector_size_bytes);
flash_info[1] = ntohl(update_data_in->data.flash_info_args.memory_size_bytes);
}
- else if(ntohl(update_data_in->id) != USRP2_FW_UPDATE_ID_HERES_TEH_FLASH_INFO_OMG){
- throw std::runtime_error(str(boost::format("Received invalid reply %d from device.\n") % ntohl(update_data_in->id)));
+ else if(ntohl(update_data_in->id) != GET_FLASH_INFO_ACK){
+ throw std::runtime_error(str(boost::format("Received invalid reply %d from device.\n")
+ % ntohl(update_data_in->id)));
}
-
+
return flash_info;
}
@@ -218,102 +331,100 @@ boost::uint32_t* get_flash_info(std::string ip_addr){
void erase_image(udp_simple::sptr udp_transport, bool is_fw, boost::uint32_t memory_size){
+ boost::uint32_t image_location_addr = is_fw ? PROD_FW_IMAGE_LOCATION_ADDR
+ : PROD_FPGA_IMAGE_LOCATION_ADDR;
+ boost::uint32_t image_size = is_fw ? FW_IMAGE_SIZE_BYTES
+ : FPGA_IMAGE_SIZE_BYTES;
+
//Making sure this won't attempt to erase past end of device
- if(is_fw){
- if(PROD_FW_IMAGE_LOCATION_ADDR+FW_IMAGE_SIZE_BYTES > memory_size) throw std::runtime_error("Cannot erase past end of device.");
- }
- else{
- if(PROD_FPGA_IMAGE_LOCATION_ADDR+FPGA_IMAGE_SIZE_BYTES > memory_size) throw std::runtime_error("Cannot erase past end of device.");
- }
+ if((image_location_addr+image_size) > memory_size) throw std::runtime_error("Cannot erase past end of device.");
- //Setting up UDP transport
- boost::uint8_t usrp2_update_data_in_mem[udp_simple::mtu];
+ //UDP receive buffer
const usrp2_fw_update_data_t *update_data_in = reinterpret_cast<const usrp2_fw_update_data_t *>(usrp2_update_data_in_mem);
//Setting up UDP packet
usrp2_fw_update_data_t erase_pkt = usrp2_fw_update_data_t();
- erase_pkt.id = htonx<boost::uint32_t>(USRP2_FW_UPDATE_ID_ERASE_TEH_FLASHES_LOL);
+ erase_pkt.id = htonx<boost::uint32_t>(ERASE_FLASH_CMD);
erase_pkt.proto_ver = htonx<boost::uint32_t>(USRP2_FW_PROTO_VERSION);
- if(is_fw){
- erase_pkt.data.flash_args.flash_addr = htonx<boost::uint32_t>(PROD_FW_IMAGE_LOCATION_ADDR);
- erase_pkt.data.flash_args.length = htonx<boost::uint32_t>(FW_IMAGE_SIZE_BYTES);
- }
- else{
- erase_pkt.data.flash_args.flash_addr = htonx<boost::uint32_t>(PROD_FPGA_IMAGE_LOCATION_ADDR);
- erase_pkt.data.flash_args.length = htonx<boost::uint32_t>(FPGA_IMAGE_SIZE_BYTES);
- }
+ erase_pkt.data.flash_args.flash_addr = htonx<boost::uint32_t>(image_location_addr);
+ erase_pkt.data.flash_args.length = htonx<boost::uint32_t>(image_size);
//Begin erasing
udp_transport->send(boost::asio::buffer(&erase_pkt, sizeof(erase_pkt)));
size_t len = udp_transport->recv(boost::asio::buffer(usrp2_update_data_in_mem), UDP_TIMEOUT);
- if(len > offsetof(usrp2_fw_update_data_t, data) and ntohl(update_data_in->id) == USRP2_FW_UPDATE_ID_ERASING_TEH_FLASHES_OMG){
+ if(len > offsetof(usrp2_fw_update_data_t, data) and ntohl(update_data_in->id) == ERASE_FLASH_ACK){
if(is_fw) std::cout << "Erasing firmware image." << std::endl;
else std::cout << "Erasing FPGA image." << std::endl;
}
- else if(ntohl(update_data_in->id) != USRP2_FW_UPDATE_ID_ERASING_TEH_FLASHES_OMG){
- throw std::runtime_error(str(boost::format("Received invalid reply %d from device.\n") % ntohl(update_data_in->id)));
+ else if(ntohl(update_data_in->id) != ERASE_FLASH_ACK){
+ throw std::runtime_error(str(boost::format("Received invalid reply %d from device.\n")
+ % ntohl(update_data_in->id)));
}
//Check for erase completion
- erase_pkt.id = htonx<boost::uint32_t>(USRP2_FW_UPDATE_ID_R_U_DONE_ERASING_LOL);
+ erase_pkt.id = htonx<boost::uint32_t>(CHECK_ERASING_DONE_CMD);
while(true){
udp_transport->send(boost::asio::buffer(&erase_pkt, sizeof(erase_pkt)));
size_t len = udp_transport->recv(boost::asio::buffer(usrp2_update_data_in_mem), UDP_TIMEOUT);
- if(len > offsetof(usrp2_fw_update_data_t, data) and ntohl(update_data_in->id) == USRP2_FW_UPDATE_ID_IM_DONE_ERASING_OMG){
- if(is_fw) std::cout << boost::format(" * Successfully erased %d bytes at %d.\n") % FW_IMAGE_SIZE_BYTES % PROD_FW_IMAGE_LOCATION_ADDR;
- else std::cout << boost::format(" * Successfully erased %d bytes at %d.\n") % FPGA_IMAGE_SIZE_BYTES % PROD_FPGA_IMAGE_LOCATION_ADDR;
+ if(len > offsetof(usrp2_fw_update_data_t, data) and ntohl(update_data_in->id) == DONE_ERASING_ACK){
+ std::cout << boost::format(" * Successfully erased %d bytes at %d.\n")
+ % image_size % image_location_addr;
break;
}
- else if(ntohl(update_data_in->id) != USRP2_FW_UPDATE_ID_NOPE_NOT_DONE_ERASING_OMG){
- throw std::runtime_error(str(boost::format("Received invalid reply %d from device.\n") % ntohl(update_data_in->id)));
+ else if(ntohl(update_data_in->id) != NOT_DONE_ERASING_ACK){
+ throw std::runtime_error(str(boost::format("Received invalid reply %d from device.\n")
+ % ntohl(update_data_in->id)));
}
}
}
void write_image(udp_simple::sptr udp_transport, bool is_fw, boost::uint8_t* image, boost::uint32_t memory_size, int image_size){
- boost::uint32_t current_addr;
- if(is_fw) current_addr = PROD_FW_IMAGE_LOCATION_ADDR;
- else current_addr = PROD_FPGA_IMAGE_LOCATION_ADDR;
+ boost::uint32_t begin_addr = is_fw ? PROD_FW_IMAGE_LOCATION_ADDR
+ : PROD_FPGA_IMAGE_LOCATION_ADDR;
+ boost::uint32_t current_addr = begin_addr;
+ std::string type = is_fw ? "firmware" : "FPGA";
//Making sure this won't attempt to write past end of device
if(current_addr+image_size > memory_size) throw std::runtime_error("Cannot write past end of device.");
- //Setting up UDP transport
- boost::uint8_t usrp2_update_data_in_mem[udp_simple::mtu];
+ //UDP receive buffer
const usrp2_fw_update_data_t *update_data_in = reinterpret_cast<const usrp2_fw_update_data_t *>(usrp2_update_data_in_mem);
//Setting up UDP packet
usrp2_fw_update_data_t write_pkt = usrp2_fw_update_data_t();
- write_pkt.id = htonx<boost::uint32_t>(USRP2_FW_UPDATE_ID_WRITE_TEH_FLASHES_LOL);
+ write_pkt.id = htonx<boost::uint32_t>(WRITE_FLASH_CMD);
write_pkt.proto_ver = htonx<boost::uint32_t>(USRP2_FW_PROTO_VERSION);
write_pkt.data.flash_args.length = htonx<boost::uint32_t>(FLASH_DATA_PACKET_SIZE);
- //Write image
- if(is_fw) std::cout << "Writing firmware image." << std::endl;
- else std::cout << "Writing FPGA image." << std::endl;
-
for(int i = 0; i < ((image_size/FLASH_DATA_PACKET_SIZE)+1); i++){
+ //Print progress
+ std::cout << "\rWriting " << type << " image ("
+ << int((double(current_addr-begin_addr)/double(image_size))*100) << "%)." << std::flush;
+
write_pkt.data.flash_args.flash_addr = htonx<boost::uint32_t>(current_addr);
std::copy(image+(i*FLASH_DATA_PACKET_SIZE), image+((i+1)*FLASH_DATA_PACKET_SIZE), write_pkt.data.flash_args.data);
udp_transport->send(boost::asio::buffer(&write_pkt, sizeof(write_pkt)));
size_t len = udp_transport->recv(boost::asio::buffer(usrp2_update_data_in_mem), UDP_TIMEOUT);
- if(len > offsetof(usrp2_fw_update_data_t, data) and ntohl(update_data_in->id) != USRP2_FW_UPDATE_ID_WROTE_TEH_FLASHES_OMG){
- throw std::runtime_error(str(boost::format("Invalid reply %d from device.") % ntohl(update_data_in->id)));
+ if(len > offsetof(usrp2_fw_update_data_t, data) and ntohl(update_data_in->id) != WRITE_FLASH_ACK){
+ throw std::runtime_error(str(boost::format("Invalid reply %d from device.")
+ % ntohl(update_data_in->id)));
}
current_addr += FLASH_DATA_PACKET_SIZE;
}
+ std::cout << std::flush << "\rWriting " << type << " image (100%)." << std::endl;
std::cout << boost::format(" * Successfully wrote %d bytes.\n") % image_size;
}
void verify_image(udp_simple::sptr udp_transport, bool is_fw, boost::uint8_t* image, boost::uint32_t memory_size, int image_size){
int current_index = 0;
- boost::uint32_t current_addr;
- if(is_fw) current_addr = PROD_FW_IMAGE_LOCATION_ADDR;
- else current_addr = PROD_FPGA_IMAGE_LOCATION_ADDR;
+ boost::uint32_t begin_addr = is_fw ? PROD_FW_IMAGE_LOCATION_ADDR
+ : PROD_FPGA_IMAGE_LOCATION_ADDR;
+ boost::uint32_t current_addr = begin_addr;
+ std::string type = is_fw ? "firmware" : "FPGA";
//Array size needs to be known at runtime, this constant is guaranteed to be larger than any firmware or FPGA image
boost::uint8_t from_usrp[FPGA_IMAGE_SIZE_BYTES];
@@ -321,27 +432,27 @@ void verify_image(udp_simple::sptr udp_transport, bool is_fw, boost::uint8_t* im
//Making sure this won't attempt to read past end of device
if(current_addr+image_size > memory_size) throw std::runtime_error("Cannot read past end of device.");
- //Setting up UDP transport
- boost::uint8_t usrp2_update_data_in_mem[udp_simple::mtu];
+ //UDP receive buffer
const usrp2_fw_update_data_t *update_data_in = reinterpret_cast<const usrp2_fw_update_data_t *>(usrp2_update_data_in_mem);
//Setting up UDP packet
usrp2_fw_update_data_t verify_pkt = usrp2_fw_update_data_t();
- verify_pkt.id = htonx<boost::uint32_t>(USRP2_FW_UPDATE_ID_READ_TEH_FLASHES_LOL);
+ verify_pkt.id = htonx<boost::uint32_t>(READ_FLASH_CMD);
verify_pkt.proto_ver = htonx<boost::uint32_t>(USRP2_FW_PROTO_VERSION);
verify_pkt.data.flash_args.length = htonx<boost::uint32_t>(FLASH_DATA_PACKET_SIZE);
- //Verify image
- if(is_fw) std::cout << "Verifying firmware image." << std::endl;
- else std::cout << "Verifying FPGA image." << std::endl;
-
for(int i = 0; i < ((image_size/FLASH_DATA_PACKET_SIZE)+1); i++){
+ //Print progress
+ std::cout << "\rVerifying " << type << " image ("
+ << int((double(current_addr-begin_addr)/double(image_size))*100) << "%)." << std::flush;
+
verify_pkt.data.flash_args.flash_addr = htonx<boost::uint32_t>(current_addr);
udp_transport->send(boost::asio::buffer(&verify_pkt, sizeof(verify_pkt)));
size_t len = udp_transport->recv(boost::asio::buffer(usrp2_update_data_in_mem), UDP_TIMEOUT);
- if(len > offsetof(usrp2_fw_update_data_t, data) and ntohl(update_data_in->id) != USRP2_FW_UPDATE_ID_KK_READ_TEH_FLASHES_OMG){
- throw std::runtime_error(str(boost::format("Invalid reply %d from device.") % ntohl(update_data_in->id)));
+ if(len > offsetof(usrp2_fw_update_data_t, data) and ntohl(update_data_in->id) != READ_FLASH_ACK){
+ throw std::runtime_error(str(boost::format("Invalid reply %d from device.")
+ % ntohl(update_data_in->id)));
}
for(int j = 0; j < FLASH_DATA_PACKET_SIZE; j++) from_usrp[current_index+j] = update_data_in->data.flash_args.data[j];
@@ -350,27 +461,27 @@ void verify_image(udp_simple::sptr udp_transport, bool is_fw, boost::uint8_t* im
}
for(int i = 0; i < image_size; i++) if(from_usrp[i] != image[i]) throw std::runtime_error("Image write failed.");
+ std::cout << std::flush << "\rVerifying " << type << " image (100%)." << std::endl;
std::cout << " * Successful." << std::endl;
}
void reset_usrp(udp_simple::sptr udp_transport){
//Set up UDP transport
- boost::uint8_t usrp2_update_data_in_mem[udp_simple::mtu];
const usrp2_fw_update_data_t *update_data_in = reinterpret_cast<const usrp2_fw_update_data_t *>(usrp2_update_data_in_mem);
//Set up UDP packet
usrp2_fw_update_data_t reset_pkt = usrp2_fw_update_data_t();
- reset_pkt.id = htonx<boost::uint32_t>(USRP2_FW_UPDATE_ID_RESET_MAH_COMPUTORZ_LOL);
+ reset_pkt.id = htonx<boost::uint32_t>(RESET_USRP_CMD);
reset_pkt.proto_ver = htonx<boost::uint32_t>(USRP2_FW_PROTO_VERSION);
//Reset USRP
udp_transport->send(boost::asio::buffer(&reset_pkt, sizeof(reset_pkt)));
size_t len = udp_transport->recv(boost::asio::buffer(usrp2_update_data_in_mem), UDP_TIMEOUT);
- if(len > offsetof(usrp2_fw_update_data_t, data) and ntohl(update_data_in->id) == USRP2_FW_UPDATE_ID_RESETTIN_TEH_COMPUTORZ_OMG){
+ if(len > offsetof(usrp2_fw_update_data_t, data) and ntohl(update_data_in->id) == RESET_USRP_ACK){
throw std::runtime_error("USRP reset failed."); //There should be no response to this UDP packet
}
- else std::cout << "Resetting USRP." << std::endl;
+ else std::cout << std::endl << "Resetting USRP." << std::endl;
}
int UHD_SAFE_MAIN(int argc, char *argv[]){
@@ -386,125 +497,88 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
("addr", po::value<std::string>(&ip_addr)->default_value("192.168.10.2"), "Specify an IP address.")
("fw", po::value<std::string>(&fw_path), "Specify a filepath for a custom firmware image.")
("fpga", po::value<std::string>(&fpga_path), "Specify a filepath for a custom FPGA image.")
- ("no_fw", "Do not burn a firmware image.")
- ("no_fpga", "Do not burn an FPGA image.")
- ("auto_reboot", "Automatically reboot N2XX without prompting.")
+ ("no-fw", "Do not burn a firmware image.")
+ ("no_fw", "Do not burn a firmware image (DEPRECATED).")
+ ("no-fpga", "Do not burn an FPGA image.")
+ ("no_fpga", "Do not burn an FPGA image (DEPRECATED).")
+ ("auto-reboot", "Automatically reboot N2XX without prompting.")
+ ("auto_reboot", "Automatically reboot N2XX without prompting (DEPRECATED).")
("list", "List available N2XX USRP devices.")
;
po::variables_map vm;
po::store(po::parse_command_line(argc, argv, desc), vm);
po::notify(vm);
- //Apply options
+ //Print help message
if(vm.count("help") > 0){
std::cout << boost::format("N2XX Simple Net Burner\n");
std::cout << boost::format("Automatically detects and burns standard firmware and FPGA images onto USRP N2XX devices.\n");
std::cout << boost::format("Can optionally take user input for custom images.\n\n");
std::cout << desc << std::endl;
- return EXIT_FAILURE;
+ return EXIT_SUCCESS;
}
- bool burn_fpga = (vm.count("no_fpga") == 0);
- bool burn_fw = (vm.count("no_fw") == 0);
+ //List option
+ if(vm.count("list")){
+ list_usrps();
+ return EXIT_SUCCESS;
+ }
+
+ //Process user options
+ bool burn_fpga = (vm.count("no-fpga") == 0) and (vm.count("no_fpga") == 0);
+ bool burn_fw = (vm.count("no-fw") == 0) and (vm.count("no_fw") == 0);
bool use_custom_fpga = (vm.count("fpga") > 0);
bool use_custom_fw = (vm.count("fw") > 0);
- bool list_usrps = (vm.count("list") > 0);
- bool auto_reboot = (vm.count("auto_reboot") > 0);
+ bool auto_reboot = (vm.count("auto-reboot") > 0) or (vm.count("auto_reboot") > 0);
+ int fpga_image_size = 0;
+ int fw_image_size = 0;
- if(!burn_fpga && !burn_fw){
+ if(not burn_fpga && not burn_fw){
std::cout << "No images will be burned." << std::endl;
return EXIT_FAILURE;
}
- if(!burn_fw && use_custom_fw) std::cout << boost::format("Conflicting firmware options presented. Will not burn a firmware image.\n\n");
- if(!burn_fpga && use_custom_fpga) std::cout << boost::format("Conflicting FPGA options presented. Will not burn an FPGA image.\n\n");
-
- //Variables not from options
- boost::uint32_t hw_rev;
- bool found_it = false;
- boost::uint8_t usrp2_update_data_in_mem[udp_simple::mtu];
- const usrp2_fw_update_data_t *update_data_in = reinterpret_cast<const usrp2_fw_update_data_t *>(usrp2_update_data_in_mem);
-
- //List option
- if(list_usrps){
- udp_simple::sptr udp_bc_transport;
- usrp2_fw_update_data_t usrp2_ack_pkt = usrp2_fw_update_data_t();
- usrp2_ack_pkt.proto_ver = htonx<boost::uint32_t>(USRP2_FW_PROTO_VERSION);
- usrp2_ack_pkt.id = htonx<boost::uint32_t>(USRP2_FW_UPDATE_ID_OHAI_LOL);
-
- std::cout << "Available USRP N2XX devices:" << std::endl;
-
- //Send UDP packets to all broadcast addresses
- BOOST_FOREACH(const if_addrs_t &if_addrs, get_if_addrs()){
- //Avoid the loopback device
- if(if_addrs.inet == boost::asio::ip::address_v4::loopback().to_string()) continue;
- udp_bc_transport = udp_simple::make_broadcast(if_addrs.bcast, BOOST_STRINGIZE(USRP2_UDP_UPDATE_PORT));
- udp_bc_transport->send(boost::asio::buffer(&usrp2_ack_pkt, sizeof(usrp2_ack_pkt)));
-
- size_t len = udp_bc_transport->recv(boost::asio::buffer(usrp2_update_data_in_mem), UDP_TIMEOUT);
- if(len > offsetof(usrp2_fw_update_data_t, data) and ntohl(update_data_in->id) == USRP2_FW_UPDATE_ID_OHAI_OMG){
- usrp2_ack_pkt.id = htonx<boost::uint32_t>(USRP2_FW_UPDATE_ID_I_CAN_HAS_HW_REV_LOL);
- udp_bc_transport->send(boost::asio::buffer(&usrp2_ack_pkt, sizeof(usrp2_ack_pkt)));
-
- size_t len = udp_bc_transport->recv(boost::asio::buffer(usrp2_update_data_in_mem), UDP_TIMEOUT);
- if(len > offsetof(usrp2_fw_update_data_t, data) and ntohl(update_data_in->id) == USRP2_FW_UPDATE_ID_HERES_TEH_HW_REV_OMG){
- hw_rev = ntohl(update_data_in->data.hw_rev);
- }
+ //Print deprecation messages if necessary
+ if(vm.count("no_fpga") > 0) std::cout << "WARNING: --no_fpga option is deprecated! Use --no-fpga instead." << std::endl << std::endl;
+ if(vm.count("no_fw") > 0) std::cout << "WARNING: --no_fw option is deprecated! Use --no-fw instead." << std::endl << std::endl;
+ if(vm.count("auto_reboot") > 0) std::cout << "WARNING: --auto_reboot option is deprecated! Use --auto-reboot instead." << std::endl << std::endl;
- std::cout << boost::format(" * %s (%s)\n") % udp_bc_transport->get_recv_addr() % filename_map[hw_rev];
- }
-
- }
- return EXIT_FAILURE;
- }
+ //Find USRP and establish connection
std::cout << boost::format("Searching for USRP N2XX with IP address %s.\n") % ip_addr;
-
- //Address specified
udp_simple::sptr udp_transport = udp_simple::make_connected(ip_addr, BOOST_STRINGIZE(USRP2_UDP_UPDATE_PORT));
- usrp2_fw_update_data_t hw_info_pkt = usrp2_fw_update_data_t();
- hw_info_pkt.proto_ver = htonx<boost::uint32_t>(USRP2_FW_PROTO_VERSION);
- hw_info_pkt.id = htonx<boost::uint32_t>(USRP2_FW_UPDATE_ID_I_CAN_HAS_HW_REV_LOL);
- udp_transport->send(boost::asio::buffer(&hw_info_pkt, sizeof(hw_info_pkt)));
-
- //Loop and receive until the timeout
- size_t len = udp_transport->recv(boost::asio::buffer(usrp2_update_data_in_mem), UDP_TIMEOUT);
- if(len > offsetof(usrp2_fw_update_data_t, data) and ntohl(update_data_in->id) == USRP2_FW_UPDATE_ID_HERES_TEH_HW_REV_OMG){
- hw_rev = ntohl(update_data_in->data.hw_rev);
- if(filename_map.find(hw_rev) != filename_map.end()){
- std::cout << boost::format("Found %s.\n\n") % filename_map[hw_rev];
- found_it = true;
- }
- else throw std::runtime_error("Invalid revision found.");
- }
- if(!found_it) throw std::runtime_error("No USRP N2XX found.");
-
- //Determining default image filenames for validation
- std::string default_fw_filename = str(boost::format("usrp_%s_fw.bin") % erase_tail_copy(filename_map[hw_rev],3));
- std::string default_fpga_filename = str(boost::format("usrp_%s_fpga.bin") % filename_map[hw_rev]);
- std::string default_fw_filepath = "";
- std::string default_fpga_filepath = "";
+ boost::uint32_t hw_rev = find_usrp(udp_transport);
//Check validity of file locations and binaries before attempting burn
std::cout << "Searching for specified images." << std::endl << std::endl;
if(burn_fpga){
- if(!use_custom_fpga) fpga_path = find_image_path(default_fpga_filename);
- else{
- //Replace ~ with home directory
- if(fpga_path.find("~/") == 0) fpga_path.replace(0,1,getenv("HOME"));
+ if(use_custom_fpga){
+ //Expand tilde usage if applicable
+ #ifndef UHD_PLATFORM_WIN32
+ if(fpga_path.find("~/") == 0) fpga_path.replace(0,1,getenv("HOME"));
+ #endif
validate_custom_fpga_file(filename_map[hw_rev], fpga_path);
}
+ else{
+ std::string default_fpga_filename = str(boost::format("usrp_%s_fpga.bin") % filename_map[hw_rev]);
+ fpga_path = find_image_path(default_fpga_filename);
+ }
- grab_fpga_image(fpga_path);
+ fpga_image_size = read_fpga_image(fpga_path);
}
if(burn_fw){
- if(!use_custom_fw) fw_path = find_image_path(default_fw_filename);
- else{
- //Replace ~ with home directory
- if(fw_path.find("~/") == 0) fw_path.replace(0,1,getenv("HOME"));
+ if(use_custom_fw){
+ //Expand tilde usage if applicable
+ #ifndef UHD_PLATFORM_WIN32
+ if(fw_path.find("~/") == 0) fw_path.replace(0,1,getenv("HOME"));
+ #endif
validate_custom_fw_file(filename_map[hw_rev], fw_path);
}
+ else{
+ std::string default_fw_filename = str(boost::format("usrp_%s_fw.bin") % erase_tail_copy(filename_map[hw_rev],3));
+ fw_path = find_image_path(default_fw_filename);
+ }
- grab_fw_image(fw_path);
+ fw_image_size = read_fw_image(fw_path);
}
std::cout << "Will burn the following images:" << std::endl;
@@ -547,7 +621,6 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
std::cout << std::endl; //Formatting
}
if(reset) reset_usrp(udp_transport);
- else return EXIT_SUCCESS;
return EXIT_SUCCESS;
}
diff --git a/host/utils/usrp_simple_burner_utils.hpp b/host/utils/usrp_simple_burner_utils.hpp
deleted file mode 100644
index f386c3620..000000000
--- a/host/utils/usrp_simple_burner_utils.hpp
+++ /dev/null
@@ -1,99 +0,0 @@
-//
-// Copyright 2012 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 <iostream>
-#include <math.h>
-#include <stdint.h>
-
-#include <boost/foreach.hpp>
-#include <boost/asio.hpp>
-#include <boost/filesystem.hpp>
-
-#include <uhd/exception.hpp>
-#include <uhd/transport/if_addrs.hpp>
-#include <uhd/transport/udp_simple.hpp>
-#include <uhd/types/device_addr.hpp>
-#include <uhd/utils/msg.hpp>
-
-#define UDP_FW_UPDATE_PORT 49154
-#define UDP_MAX_XFER_BYTES 1024
-#define UDP_TIMEOUT 3
-#define UDP_POLL_INTERVAL 0.10 //in seconds
-#define USRP2_FW_PROTO_VERSION 7 //should be unused after r6
-#define USRP2_UDP_UPDATE_PORT 49154
-#define FLASH_DATA_PACKET_SIZE 256
-#define FPGA_IMAGE_SIZE_BYTES 1572864
-#define FW_IMAGE_SIZE_BYTES 31744
-#define PROD_FPGA_IMAGE_LOCATION_ADDR 0x00180000
-#define PROD_FW_IMAGE_LOCATION_ADDR 0x00300000
-#define SAFE_FPGA_IMAGE_LOCATION_ADDR 0x00000000
-#define SAFE_FW_IMAGE_LOCATION_ADDR 0x003F0000
-
-using namespace uhd;
-using namespace uhd::transport;
-namespace asio = boost::asio;
-
-typedef enum {
- USRP2_FW_UPDATE_ID_WAT = ' ',
-
- USRP2_FW_UPDATE_ID_OHAI_LOL = 'a',
- USRP2_FW_UPDATE_ID_OHAI_OMG = 'A',
-
- USRP2_FW_UPDATE_ID_WATS_TEH_FLASH_INFO_LOL = 'f',
- USRP2_FW_UPDATE_ID_HERES_TEH_FLASH_INFO_OMG = 'F',
-
- USRP2_FW_UPDATE_ID_ERASE_TEH_FLASHES_LOL = 'e',
- USRP2_FW_UPDATE_ID_ERASING_TEH_FLASHES_OMG = 'E',
-
- USRP2_FW_UPDATE_ID_R_U_DONE_ERASING_LOL = 'd',
- USRP2_FW_UPDATE_ID_IM_DONE_ERASING_OMG = 'D',
- USRP2_FW_UPDATE_ID_NOPE_NOT_DONE_ERASING_OMG = 'B',
-
- USRP2_FW_UPDATE_ID_WRITE_TEH_FLASHES_LOL = 'w',
- USRP2_FW_UPDATE_ID_WROTE_TEH_FLASHES_OMG = 'W',
-
- USRP2_FW_UPDATE_ID_READ_TEH_FLASHES_LOL = 'r',
- USRP2_FW_UPDATE_ID_KK_READ_TEH_FLASHES_OMG = 'R',
-
- USRP2_FW_UPDATE_ID_RESET_MAH_COMPUTORZ_LOL = 's',
- USRP2_FW_UPDATE_ID_RESETTIN_TEH_COMPUTORZ_OMG = 'S',
-
- USRP2_FW_UPDATE_ID_I_CAN_HAS_HW_REV_LOL = 'v',
- USRP2_FW_UPDATE_ID_HERES_TEH_HW_REV_OMG = 'V',
-
- USRP2_FW_UPDATE_ID_KTHXBAI = '~'
-
-} usrp2_fw_update_id_t;
-
-typedef struct {
- uint32_t proto_ver;
- uint32_t id;
- uint32_t seq;
- union {
- uint32_t ip_addr;
- uint32_t hw_rev;
- struct {
- uint32_t flash_addr;
- uint32_t length;
- uint8_t data[256];
- } flash_args;
- struct {
- uint32_t sector_size_bytes;
- uint32_t memory_size_bytes;
- } flash_info_args;
- } data;
-} usrp2_fw_update_data_t;