diff options
Diffstat (limited to 'host')
30 files changed, 701 insertions, 911 deletions
diff --git a/host/cmake/msvc/erllc_uhd_b205mini.inf b/host/cmake/msvc/erllc_uhd_b205mini.inf new file mode 100644 index 000000000..1e5852656 --- /dev/null +++ b/host/cmake/msvc/erllc_uhd_b205mini.inf @@ -0,0 +1,175 @@ +; ======== libusb 1.0 (WinUSB) device driver ========== +; +; To customize this inf file for your own device +; +; 1. Change "DeviceName" with the name you want your device to appear with +;    on your system. +; +; 2. Change "VendorID" and "ProductID" according to those of your device. +;    If your device is plugged in, you can retrieve these values through the +;    Device Manager (regardless of whether the driver is installed or not). +; +; 3. Change "DeviceGUID" to a value that is unique on your system. For more +;    information and tools to help you generate your own GUIDs, see +;    http://en.wikipedia.org/wiki/Universally_Unique_Identifier. +; +; 4. Change "DeviceClassGUID" to reflect your USB Device Class. +;    The following Device Classes are listed for reference: +;    {745a17a0-74d3-11d0-b6fe-00a0c90f57da} : HID device +;    {78a1c341-4539-11d3-b88d-00c04fad5171} : Generic WinUSB device +; +; 5. (Optional) Change the "Date" string. +; +; Note 1: if you need to create a matching cat file for this inf, you can use +; the inf2cat utility from the WinDDK, with the the following command: +; inf2cat /driver:"path_to_your inf" /os:7_X86,7_X64,Vista_X86,Vista_X64 +; +; Note 2: The co-installers provided in these files are version 1.9. +; Please refer to: +; http://blogs.msdn.com/iliast/archive/2008/03/10/why-do-we-need-wdf-coinstallers.aspx and +; http://blogs.msdn.com/iliast/archive/2009/08/13/wdf-logo-requirements-regarding-coinstallers.aspx +; for more information about co-installers and their versioning + +; ===================== Strings ======================= + +[Strings] + +; ===================================================== +; ========= START USER CONFIGURABLE SECTION =========== +; ===================================================== + +DeviceName = "Ettus Research B205mini" +; Make sure "VID_" and "PID_" are always part of the strings below +VendorID = "VID_2500" +ProductID = "PID_0022" +DeviceGUID = "{211d89c8-92d7-11e5-be76-3c970eb8a18b}" +DeviceClassGUID = "{78a1c341-4539-11d3-b88d-00c04fad5171}" +; Date MUST be in MM/DD/YYYY format +Date = "11/24/2015" + +; ===================================================== +; ========== END USER CONFIGURABLE SECTION ============ +; ===================================================== + +ProviderName = "libusb 1.0" +WinUSB_SvcDesc = "WinUSB Driver Service" +DiskName = "libusb (WinUSB) Device Install Disk" +ClassName = "libusb (WinUSB) devices" + +; ====================== Version ====================== + +[Version] +DriverVer = %Date% +Signature = "$Windows NT$" +Class = %ClassName% +ClassGuid = %DeviceClassGUID% +Provider = %ProviderName% +CatalogFile = libusb_device.cat + +; =================== Class section =================== + +; Since the device is not a standard USB device, we define a new class for it. +[ClassInstall32] +Addreg = WinUSBDeviceClassReg + +[WinUSBDeviceClassReg] +HKR,,,0,%ClassName% +; -20 is for the USB icon +HKR,,Icon,,-20 + +; =========== Manufacturer/Models sections ============ + +[Manufacturer] +%ProviderName% = libusbDevice_WinUSB,NTx86,NTamd64 + +[libusbDevice_WinUSB.NTx86] +%DeviceName% = USB_Install, USB\%VendorID%&%ProductID% + +[libusbDevice_WinUSB.NTamd64] +%DeviceName% = USB_Install, USB\%VendorID%&%ProductID% + +; ==================== Installation =================== + +; The Include and Needs directives in the USB_Install section are required for +; installing WinUSB on Windows Vista systems. Windows XP systems ignore these +; directives. These directives should not be modified. +[USB_Install] +Include=winusb.inf +Needs=WINUSB.NT + +; The Include directive in the USB_Install.Services section includes the system- +; supplied INF for WinUSB. This INF is installed by the WinUSB co-installer if +; it is not already on the target system. The AddService directive specifies +; WinUsb.sys as the device’s function driver. These directives should not be +; modified. +[USB_Install.Services] +Include=winusb.inf +AddService=WinUSB,0x00000002,WinUSB_ServiceInstall + +; The WinUSB_ServiceInstall section contains the data for installing WinUsb.sys +; as a service. This section should not be modified. +[WinUSB_ServiceInstall] +DisplayName     = %WinUSB_SvcDesc% +ServiceType     = 1 +StartType       = 3 +ErrorControl    = 1 +ServiceBinary   = %12%\WinUSB.sys + +; The KmdfService directive installs WinUsb.sys as a kernel-mode service. The +; referenced WinUSB_Install section specifies the KMDF library version. +; Usually, the version can be derived from the WdfCoInstallerxxyyy.dll with +; xx = major, yyy = minor +[USB_Install.Wdf] +KmdfService=WINUSB, WinUsb_Install + +[WinUSB_Install] +KmdfLibraryVersion=1.9 + +; USB_Install.HW is the key section in the INF. It specifies the device +; interface globally unique identifier (GUID) for your device. The AddReg +; directive puts the interface GUID in a standard registry value. When +; WinUsb.sys is loaded as the device’s function driver, it reads the registry +; value and uses the specified GUID to represent the device interface. You +; should replace the GUID in this example with one that you create specifically +; for your device. If the protocols for the device change, you should create a +; new device interface GUID. +[USB_Install.HW] +AddReg=Dev_AddReg + +[Dev_AddReg] +HKR,,DeviceInterfaceGUIDs,0x10000,%DeviceGUID% + +; The USB_Install.CoInstallers section, including the referenced AddReg and +; CopyFiles sections, contains data and instructions to install the WinUSB and +; KMDF co installers and associate them with the device. Most USB devices can +; use these sections and directives without modification. +[USB_Install.CoInstallers] +AddReg=CoInstallers_AddReg +CopyFiles=CoInstallers_CopyFiles + +[CoInstallers_AddReg] +HKR,,CoInstallers32,0x00010000,"WdfCoInstaller01009.dll,WdfCoInstaller","WinUSBCoInstaller2.dll" + +[CoInstallers_CopyFiles] +WinUSBCoInstaller2.dll +WdfCoInstaller01009.dll + +[DestinationDirs] +CoInstallers_CopyFiles=11 + +; =============== Source Media Section ================ + +; The x86 and x64 versions of Windows have separate co installers. This example +; stores them on the installation disk in folders that are named x86 and amd64 +[SourceDisksNames] +1 = %DiskName%,,,\x86 +2 = %DiskName%,,,\amd64 + +[SourceDisksFiles.x86] +WinUSBCoInstaller2.dll=1 +WdfCoInstaller01009.dll=1 + +[SourceDisksFiles.amd64] +WinUSBCoInstaller2.dll=2 +WdfCoInstaller01009.dll=2 + diff --git a/host/lib/usrp/b200/b200_iface.cpp b/host/lib/usrp/b200/b200_iface.cpp index 4754a6357..207c418fc 100644 --- a/host/lib/usrp/b200/b200_iface.cpp +++ b/host/lib/usrp/b200/b200_iface.cpp @@ -17,6 +17,7 @@  #include "b200_iface.hpp" +#include "../../utils/ihex.hpp"  #include <uhd/config.hpp>  #include <uhd/utils/msg.hpp>  #include <uhd/utils/log.hpp> @@ -87,7 +88,7 @@ typedef boost::uint32_t hash_type;   **********************************************************************/  /*!   * Create a file hash - * The hash will be used to identify the loaded firmware and fpga image + * The hash will be used to identify the loaded fpga image   * \param filename file used to generate hash value   * \return hash value in a uint32_t type   */ @@ -125,66 +126,6 @@ static hash_type generate_hash(const char *filename)  } -/*! - * Verify checksum of a Intel HEX record - * \param record a line from an Intel HEX file - * \return true if record is valid, false otherwise - */ -bool checksum(const std::string& record) { - -    size_t len = record.length(); -    unsigned int i; -    unsigned char sum = 0; -    unsigned int val; - -    for (i = 1; i < len; i += 2) { -        std::istringstream(record.substr(i, 2)) >> std::hex >> val; -        sum += val; -    } - -    if (sum == 0) -       return true; -    else -       return false; -} - - -/*! - * Parse Intel HEX record - * - * \param record a line from an Intel HEX file - * \param len output length of record - * \param addr output address - * \param type output type - * \param data output data - * \return true if record is sucessfully read, false on error - */ -bool parse_record(const std::string& record, boost::uint16_t &len, \ -        boost::uint16_t &addr, boost::uint16_t &type, unsigned char* data) { - -    unsigned int i; -    std::string _data; -    unsigned int val; - -    if (record.substr(0, 1) != ":") -        return false; - -    std::istringstream(record.substr(1, 2)) >> std::hex >> len; -    std::istringstream(record.substr(3, 4)) >> std::hex >> addr; -    std::istringstream(record.substr(7, 2)) >> std::hex >> type; - -    if (len > (2 * (record.length() - 9)))  // sanity check to prevent buffer overrun -        return false; - -    for (i = 0; i < len; i++) { -        std::istringstream(record.substr(9 + 2 * i, 2)) >> std::hex >> val; -        data[i] = (unsigned char) val; -    } - -    return true; -} - -  /***********************************************************************   * The implementation class   **********************************************************************/ @@ -270,109 +211,31 @@ public:      void load_firmware(const std::string filestring, UHD_UNUSED(bool force) = false)      { -        const char *filename = filestring.c_str(); - -        /* Fields used in each USB control transfer. */ -        boost::uint16_t len = 0; -        boost::uint16_t type = 0; -        boost::uint16_t lower_address_bits = 0x0000; -        unsigned char data[512]; - -        /* Can be set by the Intel HEX record 0x04, used for all 0x00 records -         * thereafter. Note this field takes the place of the 'index' parameter in -         * libusb calls, and is necessary for FX3's 32-bit addressing. */ -        boost::uint16_t upper_address_bits = 0x0000; - -        std::ifstream file; -        file.open(filename, std::ifstream::in); - -        if(!file.good()) { -            throw uhd::io_error("fx3_load_firmware: cannot open firmware input file"); +        if (load_img_msg) +            UHD_MSG(status) << "Loading firmware image: " +                            << filestring << "..." << std::flush; + +        ihex_reader file_reader(filestring); +        try { +            file_reader.read( +                boost::bind( +                    &b200_iface_impl::fx3_control_write, this, +                    FX3_FIRMWARE_LOAD, _1, _2, _3, _4, 0 +                ) +            ); +        } catch (const uhd::io_error &e) { +            throw uhd::io_error(str(boost::format("Could not load firmware: \n%s") % e.what()));          } -        if (load_img_msg) UHD_MSG(status) << "Loading firmware image: " \ -            << filestring << "..." << std::flush; - -        while (!file.eof()) { -            boost::int32_t ret = 0; -            std::string record; -            file >> record; - -        if (!(record.length() > 0)) -            continue; - -            /* Check for valid Intel HEX record. */ -            if (!checksum(record) || !parse_record(record, len, \ -                        lower_address_bits, type, data)) { -                throw uhd::io_error("fx3_load_firmware: bad intel hex record checksum"); -            } - -            /* Type 0x00: Data. */ -            if (type == 0x00) { -                ret = fx3_control_write(FX3_FIRMWARE_LOAD, \ -                        lower_address_bits, upper_address_bits, data, len); - -                if (ret < 0) { -                    throw uhd::io_error("usrp_load_firmware: usrp_control_write failed"); -                } -            } - -            /* Type 0x01: EOF. */ -            else if (type == 0x01) { -                if (lower_address_bits != 0x0000 || len != 0 ) { -                    throw uhd::io_error("fx3_load_firmware: For EOF record, address must be 0, length must be 0."); -                } - -                //TODO -                //usrp_set_firmware_hash(hash); //set hash before reset - -                /* Successful termination! */ -                file.close(); +        UHD_MSG(status) << std::endl; -                /* Let the system settle. */ -                boost::this_thread::sleep(boost::posix_time::milliseconds(1000)); -                return; -            } - -            /* Type 0x04: Extended Linear Address Record. */ -            else if (type == 0x04) { -                if (lower_address_bits != 0x0000 || len != 2 ) { -                    throw uhd::io_error("fx3_load_firmware: For ELA record, address must be 0, length must be 2."); -                } - -                upper_address_bits = ((boost::uint16_t)((data[0] & 0x00FF) << 8))\ -                                     + ((boost::uint16_t)(data[1] & 0x00FF)); -            } - -            /* Type 0x05: Start Linear Address Record. */ -            else if (type == 0x05) { -                if (lower_address_bits != 0x0000 || len != 4 ) { -                    throw uhd::io_error("fx3_load_firmware: For SLA record, address must be 0, length must be 4."); -                } - -                /* The firmware load is complete.  We now need to tell the CPU -                 * to jump to an execution address start point, now contained within -                 * the data field.  Parse these address bits out, and then push the -                 * instruction. */ -                upper_address_bits = ((boost::uint16_t)((data[0] & 0x00FF) << 8))\ -                                     + ((boost::uint16_t)(data[1] & 0x00FF)); -                lower_address_bits = ((boost::uint16_t)((data[2] & 0x00FF) << 8))\ -                                     + ((boost::uint16_t)(data[3] & 0x00FF)); - -                fx3_control_write(FX3_FIRMWARE_LOAD, lower_address_bits, \ -                        upper_address_bits, 0, 0); - -                if (load_img_msg) UHD_MSG(status) << " done" << std::endl; -            } - -            /* If we receive an unknown record type, error out. */ -            else { -                throw uhd::io_error("fx3_load_firmware: unsupported record type."); -            } -        } +        //TODO +        //usrp_set_firmware_hash(hash); //set hash before reset -        /* There was no valid EOF. */ -        throw uhd::io_error("fx3_load_firmware: No EOF record found."); +        /* Success! Let the system settle. */ +        // TODO: Replace this with a polling loop in the FX3, or find out +        // what the actual, correct timeout value is. +        boost::this_thread::sleep(boost::posix_time::milliseconds(1000));      }      void reset_fx3(void) { diff --git a/host/lib/usrp/b200/b200_iface.hpp b/host/lib/usrp/b200/b200_iface.hpp index 19ec561fa..e45c78d49 100644 --- a/host/lib/usrp/b200/b200_iface.hpp +++ b/host/lib/usrp/b200/b200_iface.hpp @@ -30,25 +30,28 @@  enum b200_product_t {      B200,      B210, -    B205 +    B200MINI, +    B205MINI  };  // These are actual USB PIDs (not Ettus Product IDs) -const static boost::uint16_t B200_VENDOR_ID     = 0x2500; -const static boost::uint16_t B200_VENDOR_NI_ID  = 0x3923; -const static boost::uint16_t B200_PRODUCT_ID    = 0x0020; -const static boost::uint16_t B205_PRODUCT_ID    = 0x0021; -const static boost::uint16_t B200_PRODUCT_NI_ID = 0x7813; -const static boost::uint16_t B210_PRODUCT_NI_ID = 0x7814; -const static boost::uint16_t FX3_VID            = 0x04b4; -const static boost::uint16_t FX3_DEFAULT_PID    = 0x00f3; -const static boost::uint16_t FX3_REENUM_PID     = 0x00f0; +const static boost::uint16_t B200_VENDOR_ID         = 0x2500; +const static boost::uint16_t B200_VENDOR_NI_ID      = 0x3923; +const static boost::uint16_t B200_PRODUCT_ID        = 0x0020; +const static boost::uint16_t B200MINI_PRODUCT_ID    = 0x0021; +const static boost::uint16_t B205MINI_PRODUCT_ID    = 0x0022; +const static boost::uint16_t B200_PRODUCT_NI_ID     = 0x7813; +const static boost::uint16_t B210_PRODUCT_NI_ID     = 0x7814; +const static boost::uint16_t FX3_VID                = 0x04b4; +const static boost::uint16_t FX3_DEFAULT_PID        = 0x00f3; +const static boost::uint16_t FX3_REENUM_PID         = 0x00f0;  //! Map the USB PID to the product (only for PIDs that map to a single product)  static const uhd::dict<boost::uint16_t, b200_product_t> B2XX_PID_TO_PRODUCT = boost::assign::map_list_of -        (B200_PRODUCT_NI_ID, B200) -        (B210_PRODUCT_NI_ID, B210) -        (B205_PRODUCT_ID,    B205) +        (B200_PRODUCT_NI_ID,    B200) +        (B210_PRODUCT_NI_ID,    B210) +        (B200MINI_PRODUCT_ID,   B200MINI) +        (B205MINI_PRODUCT_ID,   B205MINI)  ;  static const std::string     B200_FW_FILE_NAME = "usrp_b200_fw.hex"; @@ -61,21 +64,25 @@ static const uhd::dict<boost::uint16_t, b200_product_t> B2XX_PRODUCT_ID = boost:          (0x0002,             B210)          (0x7738,             B210)          (B210_PRODUCT_NI_ID, B210) -        (0x0003,             B205) -        (0x7739,             B205) +        (0x0003,             B200MINI) +        (0x7739,             B200MINI) +        (0x0004,             B205MINI) +        (0x773a,             B205MINI)  ;  static const uhd::dict<b200_product_t, std::string> B2XX_STR_NAMES = boost::assign::map_list_of -        (B200, "B200") -        (B210, "B210") -        (B205, "B200mini") +        (B200,      "B200") +        (B210,      "B210") +        (B200MINI,  "B200mini") +        (B205MINI,  "B205mini")  ;  static const uhd::dict<b200_product_t, std::string> B2XX_FPGA_FILE_NAME = boost::assign::map_list_of          (B200, "usrp_b200_fpga.bin")          (B210, "usrp_b210_fpga.bin") -        (B205, "usrp_b200mini_fpga.bin") +        (B200MINI, "usrp_b200mini_fpga.bin") +        (B205MINI, "usrp_b205mini_fpga.bin")  ; diff --git a/host/lib/usrp/b200/b200_impl.cpp b/host/lib/usrp/b200/b200_impl.cpp index 3aaf28ab3..62690f09f 100644 --- a/host/lib/usrp/b200/b200_impl.cpp +++ b/host/lib/usrp/b200/b200_impl.cpp @@ -75,9 +75,9 @@ public:  };  // B205 -class b205_ad9361_client_t : public ad9361_params { +class b2xxmini_ad9361_client_t : public ad9361_params {  public: -    ~b205_ad9361_client_t() {} +    ~b2xxmini_ad9361_client_t() {}      double get_band_edge(frequency_band_t band) {          switch (band) {          case AD9361_RX_BAND0:   return 0; // Set these all to @@ -319,7 +319,8 @@ b200_impl::b200_impl(const uhd::device_addr_t& device_addr, usb_device_handle::s      else if (specified_vid)      {          vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(vid, B200_PRODUCT_ID)); -        vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(vid, B205_PRODUCT_ID)); +        vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(vid, B200MINI_PRODUCT_ID)); +        vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(vid, B205MINI_PRODUCT_ID));          vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(vid, B200_PRODUCT_NI_ID));          vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(vid, B210_PRODUCT_NI_ID));      } @@ -333,7 +334,8 @@ b200_impl::b200_impl(const uhd::device_addr_t& device_addr, usb_device_handle::s      else      {          vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(B200_VENDOR_ID,    B200_PRODUCT_ID)); -        vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(B200_VENDOR_ID,    B205_PRODUCT_ID)); +        vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(B200_VENDOR_ID,    B200MINI_PRODUCT_ID)); +        vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(B200_VENDOR_ID,    B205MINI_PRODUCT_ID));          vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(B200_VENDOR_NI_ID, B200_PRODUCT_NI_ID));          vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(B200_VENDOR_NI_ID, B210_PRODUCT_NI_ID));      } @@ -387,7 +389,7 @@ b200_impl::b200_impl(const uhd::device_addr_t& device_addr, usb_device_handle::s      UHD_MSG(status) << "Detected Device: " << B2XX_STR_NAMES[_product] << std::endl; -    _gpsdo_capable = (_product != B205); +    _gpsdo_capable = (not (_product == B200MINI or _product == B205MINI));      ////////////////////////////////////////////////////////////////////      // Set up frontend mapping @@ -406,7 +408,7 @@ b200_impl::b200_impl(const uhd::device_addr_t& device_addr, usb_device_handle::s      _fe2 = 0;      _gpio_state.swap_atr = 1;      // Unswapped setup: -    if (_product == B205 or (_product == B200 and _revision >= 5)) { +    if (_product == B200MINI or _product == B205MINI or (_product == B200 and _revision >= 5)) {          _fe1 = 0;                   //map radio0 to FE1          _fe2 = 1;                   //map radio1 to FE2          _gpio_state.swap_atr = 0; // ATRs for radio0 are mapped to FE1 @@ -513,7 +515,7 @@ b200_impl::b200_impl(const uhd::device_addr_t& device_addr, usb_device_handle::s      ////////////////////////////////////////////////////////////////////      _tree->create<std::string>("/name").set("B-Series Device");      _tree->create<std::string>(mb_path / "name").set(product_name); -    _tree->create<std::string>(mb_path / "codename").set((_product == B205) ? "Pixie" : "Sasquatch"); +    _tree->create<std::string>(mb_path / "codename").set((_product == B200MINI or _product == B205MINI) ? "Pixie" : "Sasquatch");      ////////////////////////////////////////////////////////////////////      // Create data transport @@ -541,7 +543,7 @@ b200_impl::b200_impl(const uhd::device_addr_t& device_addr, usb_device_handle::s      // create time and clock control objects      ////////////////////////////////////////////////////////////////////      _spi_iface = b200_local_spi_core::make(_local_ctrl); -    if (_product != B205) { +    if (not (_product == B200MINI or _product == B205MINI)) {          _adf4001_iface = boost::make_shared<b200_ref_pll_ctrl>(_spi_iface);      } @@ -550,13 +552,13 @@ b200_impl::b200_impl(const uhd::device_addr_t& device_addr, usb_device_handle::s      ////////////////////////////////////////////////////////////////////      UHD_MSG(status) << "Initialize CODEC control..." << std::endl;      ad9361_params::sptr client_settings; -    if (_product == B205) { -        client_settings = boost::make_shared<b205_ad9361_client_t>(); +    if (_product == B200MINI or _product == B205MINI) { +        client_settings = boost::make_shared<b2xxmini_ad9361_client_t>();      } else {          client_settings = boost::make_shared<b200_ad9361_client_t>();      }      _codec_ctrl = ad9361_ctrl::make_spi(client_settings, _spi_iface, AD9361_SLAVENO); -    +      ////////////////////////////////////////////////////////////////////      // create codec control objects      //////////////////////////////////////////////////////////////////// @@ -624,15 +626,18 @@ b200_impl::b200_impl(const uhd::device_addr_t& device_addr, usb_device_handle::s      //register time now and pps onto available radio cores      _tree->create<time_spec_t>(mb_path / "time" / "now") -        .publish(boost::bind(&time_core_3000::get_time_now, _radio_perifs[0].time64)); +        .publish(boost::bind(&time_core_3000::get_time_now, _radio_perifs[0].time64)) +        .subscribe(boost::bind(&b200_impl::set_time, this, _1)) +        .set(0.0); +    //re-sync the times when the tick rate changes +    _tree->access<double>(mb_path / "tick_rate") +        .subscribe(boost::bind(&b200_impl::sync_times, this));      _tree->create<time_spec_t>(mb_path / "time" / "pps")          .publish(boost::bind(&time_core_3000::get_time_last_pps, _radio_perifs[0].time64)); -    for (size_t i = 0; i < _radio_perifs.size(); i++) +    BOOST_FOREACH(radio_perifs_t &perif, _radio_perifs)      { -        _tree->access<time_spec_t>(mb_path / "time" / "now") -            .subscribe(boost::bind(&time_core_3000::set_time_now, _radio_perifs[i].time64, _1));          _tree->access<time_spec_t>(mb_path / "time" / "pps") -            .subscribe(boost::bind(&time_core_3000::set_time_next_pps, _radio_perifs[i].time64, _1)); +            .subscribe(boost::bind(&time_core_3000::set_time_next_pps, perif.time64, _1));      }      //setup time source props @@ -945,7 +950,7 @@ void b200_impl::check_fpga_compat(void)      if (signature != 0xACE0BA5E) throw uhd::runtime_error(          "b200::check_fpga_compat signature register readback failed"); -    const boost::uint16_t expected = (_product == B205 ? B205_FPGA_COMPAT_NUM : B200_FPGA_COMPAT_NUM); +    const boost::uint16_t expected = ((_product == B200MINI or _product == B205MINI) ? B205_FPGA_COMPAT_NUM : B200_FPGA_COMPAT_NUM);      if (compat_major != expected)      {          throw uhd::runtime_error(str(boost::format( @@ -970,7 +975,7 @@ void b200_impl::set_mb_eeprom(const uhd::usrp::mboard_eeprom_t &mb_eeprom)  void b200_impl::update_clock_source(const std::string &source)  {      // For B205, ref_sel selects whether or not to lock to the external clock source -    if (_product == B205) +    if (_product == B200MINI or _product == B205MINI)      {          if (source == "external" and _time_source == EXTERNAL)          { @@ -1032,7 +1037,7 @@ void b200_impl::update_clock_source(const std::string &source)  void b200_impl::update_time_source(const std::string &source)  { -    if (_product == B205 and source == "external" and _gpio_state.ref_sel == 1) +    if ((_product == B200MINI or _product == B205MINI) and source == "external" and _gpio_state.ref_sel == 1)      {          throw uhd::value_error("external reference cannot be both a time source and a clock source");      } @@ -1052,11 +1057,24 @@ void b200_impl::update_time_source(const std::string &source)          throw uhd::key_error("update_time_source: unknown source: " + source);      if (_time_source != value)      { -        _local_ctrl->poke32(TOREG(SR_CORE_PPS_SEL), value); +        _local_ctrl->poke32(TOREG(SR_CORE_SYNC), value);          _time_source = value;      }  } +void b200_impl::set_time(const uhd::time_spec_t& t) +{ +    BOOST_FOREACH(radio_perifs_t &perif, _radio_perifs) +        perif.time64->set_time_sync(t); +    _local_ctrl->poke32(TOREG(SR_CORE_SYNC), 1 << 2 | boost::uint32_t(_time_source)); +    _local_ctrl->poke32(TOREG(SR_CORE_SYNC), _time_source); +} + +void b200_impl::sync_times() +{ +    set_time(_radio_perifs[0].time64->get_time_now()); +} +  /***********************************************************************   * GPIO setup   **********************************************************************/ @@ -1064,7 +1082,7 @@ void b200_impl::update_time_source(const std::string &source)  void b200_impl::update_bandsel(const std::string& which, double freq)  {      // B205 does not have bandsels -    if (_product == B205) { +    if (_product == B200MINI or _product == B205MINI) {          return;      } diff --git a/host/lib/usrp/b200/b200_impl.hpp b/host/lib/usrp/b200/b200_impl.hpp index b406572fb..08ae68e9a 100644 --- a/host/lib/usrp/b200/b200_impl.hpp +++ b/host/lib/usrp/b200/b200_impl.hpp @@ -49,8 +49,8 @@  #include "recv_packet_demuxer_3000.hpp"  static const boost::uint8_t  B200_FW_COMPAT_NUM_MAJOR = 8;  static const boost::uint8_t  B200_FW_COMPAT_NUM_MINOR = 0; -static const boost::uint16_t B200_FPGA_COMPAT_NUM = 12; -static const boost::uint16_t B205_FPGA_COMPAT_NUM = 3; +static const boost::uint16_t B200_FPGA_COMPAT_NUM = 13; +static const boost::uint16_t B205_FPGA_COMPAT_NUM = 4;  static const double          B200_BUS_CLOCK_RATE = 100e6;  static const boost::uint32_t B200_GPSDO_ST_NONE = 0x83;  static const size_t B200_MAX_RATE_USB2              =  53248000; // bytes/s @@ -95,7 +95,8 @@ static const unsigned char B200_USB_DATA_SEND_ENDPOINT  = 2;  static std::vector<uhd::transport::usb_device_handle::vid_pid_pair_t> b200_vid_pid_pairs =      boost::assign::list_of          (uhd::transport::usb_device_handle::vid_pid_pair_t(B200_VENDOR_ID, B200_PRODUCT_ID)) -        (uhd::transport::usb_device_handle::vid_pid_pair_t(B200_VENDOR_ID, B205_PRODUCT_ID)) +        (uhd::transport::usb_device_handle::vid_pid_pair_t(B200_VENDOR_ID, B200MINI_PRODUCT_ID)) +        (uhd::transport::usb_device_handle::vid_pid_pair_t(B200_VENDOR_ID, B205MINI_PRODUCT_ID))          (uhd::transport::usb_device_handle::vid_pid_pair_t(B200_VENDOR_NI_ID, B200_PRODUCT_NI_ID))          (uhd::transport::usb_device_handle::vid_pid_pair_t(B200_VENDOR_NI_ID, B210_PRODUCT_NI_ID))      ; @@ -167,6 +168,8 @@ private:      uhd::usrp::subdev_spec_t coerce_subdev_spec(const uhd::usrp::subdev_spec_t &);      void update_subdev_spec(const std::string &tx_rx, const uhd::usrp::subdev_spec_t &);      void update_time_source(const std::string &); +    void set_time(const uhd::time_spec_t&); +    void sync_times(void);      void update_clock_source(const std::string &);      void update_bandsel(const std::string& which, double freq);      void update_antenna_sel(const size_t which, const std::string &ant); diff --git a/host/lib/usrp/b200/b200_io_impl.cpp b/host/lib/usrp/b200/b200_io_impl.cpp index 41b4b8a74..279901208 100644 --- a/host/lib/usrp/b200/b200_io_impl.cpp +++ b/host/lib/usrp/b200/b200_io_impl.cpp @@ -227,7 +227,8 @@ uhd::usrp::subdev_spec_t b200_impl::coerce_subdev_spec(const uhd::usrp::subdev_s      //      // Any other spec is probably illegal and will be caught by      // validate_subdev_spec(). -    if (spec.size() and (_product == B200 or _product == B205) and spec[0].sd_name == "B") { +    if (spec.size() and (_product == B200 or _product == B200MINI or _product == B205MINI) and spec[0].sd_name == "B") +    {          spec[0].sd_name = "A";      }      return spec; diff --git a/host/lib/usrp/b200/b200_regs.hpp b/host/lib/usrp/b200/b200_regs.hpp index 8f2dd03f3..e9ab81bae 100644 --- a/host/lib/usrp/b200/b200_regs.hpp +++ b/host/lib/usrp/b200/b200_regs.hpp @@ -28,7 +28,7 @@ localparam SR_CORE_SPI       = 8;  localparam SR_CORE_MISC      = 16;  localparam SR_CORE_COMPAT    = 24;  localparam SR_CORE_GPSDO_ST  = 40; -localparam SR_CORE_PPS_SEL   = 48; +localparam SR_CORE_SYNC      = 48;  localparam RB32_CORE_SPI     = 8;  localparam RB32_CORE_MISC    = 16;  localparam RB32_CORE_STATUS  = 20; diff --git a/host/lib/usrp/common/adf4001_ctrl.cpp b/host/lib/usrp/common/adf4001_ctrl.cpp index a7510c272..001b68b7a 100644 --- a/host/lib/usrp/common/adf4001_ctrl.cpp +++ b/host/lib/usrp/common/adf4001_ctrl.cpp @@ -81,7 +81,7 @@ boost::uint32_t adf4001_regs_t::get_reg(boost::uint8_t addr) {          reg |= (boost::uint32_t(timer_counter_control) & 0x00000F) << 11;          reg |= (boost::uint32_t(charge_pump_current_1) & 0x000007) << 15;          reg |= (boost::uint32_t(charge_pump_current_2) & 0x000007) << 18; -        reg |= (boost::uint32_t(power_down) & 0x000002) << 21; +        reg |= (boost::uint32_t(power_down) & 0x000002) << 20;          break;      default:          break; @@ -128,15 +128,15 @@ void adf4001_ctrl::set_lock_to_ext_ref(bool external) {  void adf4001_ctrl::program_regs(void) {      //no control over CE, only LE, therefore we use the initialization latch method      write_reg(3); -    boost::this_thread::sleep(boost::posix_time::microseconds(1)); + +    //conduct a function latch (2) +    write_reg(2);      //write R counter latch (0)      write_reg(0); -    boost::this_thread::sleep(boost::posix_time::microseconds(1));      //write N counter latch (1)      write_reg(1); -    boost::this_thread::sleep(boost::posix_time::microseconds(1));  } diff --git a/host/lib/usrp/cores/time_core_3000.cpp b/host/lib/usrp/cores/time_core_3000.cpp index ffae5dc0d..694edf31c 100644 --- a/host/lib/usrp/cores/time_core_3000.cpp +++ b/host/lib/usrp/cores/time_core_3000.cpp @@ -24,8 +24,9 @@  #define REG_TIME_LO       _base + 4  #define REG_TIME_CTRL     _base + 8 -#define CTRL_LATCH_TIME_PPS (1 << 1) -#define CTRL_LATCH_TIME_NOW (1 << 0) +#define CTRL_LATCH_TIME_NOW     (1 << 0) +#define CTRL_LATCH_TIME_PPS     (1 << 1) +#define CTRL_LATCH_TIME_SYNC    (1 << 2)  using namespace uhd; @@ -99,6 +100,14 @@ struct time_core_3000_impl : time_core_3000          _iface->poke32(REG_TIME_CTRL, CTRL_LATCH_TIME_NOW);      } +    void set_time_sync(const uhd::time_spec_t &time) +    { +        const boost::uint64_t ticks = time.to_ticks(_tick_rate); +        _iface->poke32(REG_TIME_HI, boost::uint32_t(ticks >> 32)); +        _iface->poke32(REG_TIME_LO, boost::uint32_t(ticks >> 0)); +        _iface->poke32(REG_TIME_CTRL, CTRL_LATCH_TIME_SYNC); +    } +      void set_time_next_pps(const uhd::time_spec_t &time)      {          const boost::uint64_t ticks = time.to_ticks(_tick_rate); diff --git a/host/lib/usrp/cores/time_core_3000.hpp b/host/lib/usrp/cores/time_core_3000.hpp index 7463386ba..7dde4e797 100644 --- a/host/lib/usrp/cores/time_core_3000.hpp +++ b/host/lib/usrp/cores/time_core_3000.hpp @@ -53,6 +53,8 @@ public:      virtual void set_time_now(const uhd::time_spec_t &time) = 0; +    virtual void set_time_sync(const uhd::time_spec_t &time) = 0; +      virtual void set_time_next_pps(const uhd::time_spec_t &time) = 0;  }; diff --git a/host/lib/usrp/e300/e300_fpga_defs.hpp b/host/lib/usrp/e300/e300_fpga_defs.hpp index dcfb05021..594461518 100644 --- a/host/lib/usrp/e300/e300_fpga_defs.hpp +++ b/host/lib/usrp/e300/e300_fpga_defs.hpp @@ -21,7 +21,7 @@ namespace uhd { namespace usrp { namespace e300 { namespace fpga {  static const size_t NUM_RADIOS = 2; -static const boost::uint32_t COMPAT_MAJOR = 13; +static const boost::uint32_t COMPAT_MAJOR = 14;  static const boost::uint32_t COMPAT_MINOR = 0;  }}}} // namespace diff --git a/host/lib/usrp/e300/e300_impl.cpp b/host/lib/usrp/e300/e300_impl.cpp index c82ab3d0e..3242a7fe8 100644 --- a/host/lib/usrp/e300/e300_impl.cpp +++ b/host/lib/usrp/e300/e300_impl.cpp @@ -175,7 +175,7 @@ device_addrs_t e300_find(const device_addr_t &multi_dev_hint)                  device_addr_t new_hint = hint;                  new_hint["addr"] = if_addrs.bcast; -                // call discover with the new hint ad append results +                // call discover with the new hint and append results                  device_addrs_t new_e300_addrs = e300_find(new_hint);                  e300_addrs.insert(e300_addrs.begin(),                      new_e300_addrs.begin(), new_e300_addrs.end()); @@ -529,8 +529,11 @@ e300_impl::e300_impl(const uhd::device_addr_t &device_addr)      ////////////////////////////////////////////////////////////////////      _tree->create<time_spec_t>(mb_path / "time" / "now")          .publish(boost::bind(&time_core_3000::get_time_now, _radio_perifs[0].time64)) -        .subscribe(boost::bind(&time_core_3000::set_time_now, _radio_perifs[0].time64, _1)) -        .subscribe(boost::bind(&time_core_3000::set_time_now, _radio_perifs[1].time64, _1)); +        .subscribe(boost::bind(&e300_impl::_set_time, this, _1)) +        .set(0.0); +    //re-sync the times when the tick rate changes +    _tree->access<double>(mb_path / "tick_rate") +        .subscribe(boost::bind(&e300_impl::_sync_times, this));      _tree->create<time_spec_t>(mb_path / "time" / "pps")          .publish(boost::bind(&time_core_3000::get_time_last_pps, _radio_perifs[0].time64))          .subscribe(boost::bind(&time_core_3000::set_time_next_pps, _radio_perifs[0].time64, _1)) @@ -796,6 +799,21 @@ void e300_impl::_update_time_source(const std::string &source)      _update_gpio_state();  } +void e300_impl::_set_time(const uhd::time_spec_t& t) +{ +    BOOST_FOREACH(radio_perifs_t &perif, _radio_perifs) +        perif.time64->set_time_sync(t); +    _misc.time_sync = 1; +    _update_gpio_state(); +    _misc.time_sync = 0; +    _update_gpio_state(); +} + +void e300_impl::_sync_times() +{ +    _set_time(_radio_perifs[0].time64->get_time_now()); +} +  size_t e300_impl::_get_axi_dma_channel(      boost::uint8_t destination,      boost::uint8_t prefix) @@ -1081,7 +1099,8 @@ void e300_impl::_update_gpio_state(void)          | (_misc.tx_bandsels  << gpio_t::TX_BANDSEL)          | (_misc.rx_bandsel_a << gpio_t::RX_BANDSELA)          | (_misc.rx_bandsel_b << gpio_t::RX_BANDSELB) -        | (_misc.rx_bandsel_c << gpio_t::RX_BANDSELC); +        | (_misc.rx_bandsel_c << gpio_t::RX_BANDSELC) +        | (_misc.time_sync    << gpio_t::TIME_SYNC);      _global_regs->poke32(global_regs::SR_CORE_MISC, misc_reg);  } diff --git a/host/lib/usrp/e300/e300_impl.hpp b/host/lib/usrp/e300/e300_impl.hpp index 9b39c7468..1bf5cb950 100644 --- a/host/lib/usrp/e300/e300_impl.hpp +++ b/host/lib/usrp/e300/e300_impl.hpp @@ -200,6 +200,8 @@ private: // types          boost::uint32_t rx_bandsel_b;          boost::uint32_t rx_bandsel_c; +        boost::uint32_t time_sync; +          static const size_t PPS_SEL     = 0;          static const size_t MIMO        = 2;          static const size_t CODEC_ARST  = 3; @@ -207,6 +209,7 @@ private: // types          static const size_t RX_BANDSELA = 7;          static const size_t RX_BANDSELB = 13;          static const size_t RX_BANDSELC = 17; +        static const size_t TIME_SYNC   = 21;      };  private: // methods @@ -257,6 +260,8 @@ private: // methods      void _update_time_source(const std::string &source);      void _update_clock_source(const std::string &); +    void _set_time(const uhd::time_spec_t&); +    void _sync_times(void);      void _update_subdev_spec(          const std::string &txrx, diff --git a/host/lib/usrp/x300/x300_fw_common.h b/host/lib/usrp/x300/x300_fw_common.h index 4c5051eaa..549fc9dfa 100644 --- a/host/lib/usrp/x300/x300_fw_common.h +++ b/host/lib/usrp/x300/x300_fw_common.h @@ -33,7 +33,7 @@ extern "C" {  #define X300_REVISION_MIN    2  #define X300_FW_COMPAT_MAJOR 4  #define X300_FW_COMPAT_MINOR 0 -#define X300_FPGA_COMPAT_MAJOR 18 +#define X300_FPGA_COMPAT_MAJOR 19  //shared memory sections - in between the stack and the program space  #define X300_FW_SHMEM_BASE 0x6000 diff --git a/host/lib/usrp/x300/x300_impl.cpp b/host/lib/usrp/x300/x300_impl.cpp index 0483ecf11..37461e2e5 100644 --- a/host/lib/usrp/x300/x300_impl.cpp +++ b/host/lib/usrp/x300/x300_impl.cpp @@ -809,8 +809,8 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr)      ////////////////////////////////////////////////////////////////////      _tree->create<time_spec_t>(mb_path / "time" / "now")          .publish(boost::bind(&time_core_3000::get_time_now, mb.radio_perifs[0].time64)) -        .subscribe(boost::bind(&time_core_3000::set_time_now, mb.radio_perifs[0].time64, _1)) -        .subscribe(boost::bind(&time_core_3000::set_time_now, mb.radio_perifs[1].time64, _1)); +        .subscribe(boost::bind(&x300_impl::sync_times, this, mb, _1)) +        .set(0.0);      _tree->create<time_spec_t>(mb_path / "time" / "pps")          .publish(boost::bind(&time_core_3000::get_time_last_pps, mb.radio_perifs[0].time64))          .subscribe(boost::bind(&time_core_3000::set_time_next_pps, mb.radio_perifs[0].time64, _1)) @@ -1505,6 +1505,14 @@ void x300_impl::update_time_source(mboard_members_t &mb, const std::string &sour      */  } +void x300_impl::sync_times(mboard_members_t &mb, const uhd::time_spec_t& t) +{ +    BOOST_FOREACH(radio_perifs_t &perif, mb.radio_perifs) +        perif.time64->set_time_sync(t); +    mb.fw_regmap->clock_ctrl_reg.write(fw_regmap_t::clk_ctrl_reg_t::TIME_SYNC, 1); +    mb.fw_regmap->clock_ctrl_reg.write(fw_regmap_t::clk_ctrl_reg_t::TIME_SYNC, 0); +} +  bool x300_impl::wait_for_clk_locked(mboard_members_t& mb, boost::uint32_t which, double timeout)  {      boost::system_time timeout_time = boost::get_system_time() + boost::posix_time::milliseconds(timeout * 1000.0); diff --git a/host/lib/usrp/x300/x300_impl.hpp b/host/lib/usrp/x300/x300_impl.hpp index 521ce8a0e..4de0344bf 100644 --- a/host/lib/usrp/x300/x300_impl.hpp +++ b/host/lib/usrp/x300/x300_impl.hpp @@ -362,6 +362,7 @@ private:      void set_time_source_out(mboard_members_t&, const bool);      void update_clock_source(mboard_members_t&, const std::string &);      void update_time_source(mboard_members_t&, const std::string &); +    void sync_times(mboard_members_t&, const uhd::time_spec_t&);      uhd::sensor_value_t get_ref_locked(mboard_members_t& mb);      bool wait_for_clk_locked(mboard_members_t& mb, boost::uint32_t which, double timeout); diff --git a/host/lib/usrp/x300/x300_regs.hpp b/host/lib/usrp/x300/x300_regs.hpp index 489d249ba..de3a3161a 100644 --- a/host/lib/usrp/x300/x300_regs.hpp +++ b/host/lib/usrp/x300/x300_regs.hpp @@ -213,6 +213,7 @@ namespace uhd { namespace usrp { namespace x300 {              UHD_DEFINE_SOFT_REG_FIELD(PPS_OUT_EN,   /*width*/ 1, /*shift*/ 4);  //[4]              UHD_DEFINE_SOFT_REG_FIELD(TCXO_EN,      /*width*/ 1, /*shift*/ 5);  //[5]              UHD_DEFINE_SOFT_REG_FIELD(GPSDO_PWR_EN, /*width*/ 1, /*shift*/ 6);  //[6] +            UHD_DEFINE_SOFT_REG_FIELD(TIME_SYNC,    /*width*/ 1, /*shift*/ 7);  //[7]              static const boost::uint32_t SRC_EXTERNAL = 0x0;              static const boost::uint32_t SRC_INTERNAL = 0x2; @@ -225,6 +226,7 @@ namespace uhd { namespace usrp { namespace x300 {                  set(PPS_OUT_EN, 0);                  set(TCXO_EN, 1);                  set(GPSDO_PWR_EN, 1);   //GPSDO power always ON +                set(TIME_SYNC, 0);              }          } clock_ctrl_reg; diff --git a/host/lib/usrp_clock/octoclock/CMakeLists.txt b/host/lib/usrp_clock/octoclock/CMakeLists.txt index d3728344e..d2b70e356 100644 --- a/host/lib/usrp_clock/octoclock/CMakeLists.txt +++ b/host/lib/usrp_clock/octoclock/CMakeLists.txt @@ -19,10 +19,7 @@  # Conditionally configure the OctoClock support  ########################################################################  IF(ENABLE_OCTOCLOCK) -    ADD_DEFINITIONS(-DIHEX_USE_STDBOOL) -      LIBUHD_APPEND_SOURCES( -        ${CMAKE_CURRENT_SOURCE_DIR}/kk_ihex_read.c          ${CMAKE_CURRENT_SOURCE_DIR}/octoclock_eeprom.cpp          ${CMAKE_CURRENT_SOURCE_DIR}/octoclock_image_loader.cpp          ${CMAKE_CURRENT_SOURCE_DIR}/octoclock_impl.cpp diff --git a/host/lib/usrp_clock/octoclock/kk_ihex.h b/host/lib/usrp_clock/octoclock/kk_ihex.h deleted file mode 100644 index 20eba43cc..000000000 --- a/host/lib/usrp_clock/octoclock/kk_ihex.h +++ /dev/null @@ -1,191 +0,0 @@ -/* - * kk_ihex.h: A simple library for reading and writing the Intel HEX  - * or IHEX format. Intended mainly for embedded systems, and thus - * somewhat optimised for size at the expense of error handling and - * generality. - * - *      USAGE - *      ----- - * - * The library has been split into read and write parts, which use a - * common data structure (`struct ihex_state`), but each can be used - * independently. Include the header `kk_ihex_read.h` for reading, and/or - * the header `kk_ihex_write.h` for writing (and link with their respective - * object files). Both can be used simultaneously - this header defines - * the shared data structures and definitions. - * - * - *      READING INTEL HEX DATA - *      ---------------------- - * - * To read data in the Intel HEX format, you must perform the actual reading - * of bytes using other means (e.g., stdio). The bytes read must then be - * passed to `ihex_read_byte` and/or `ihex_read_bytes`. The reading functions - * will then call `ihex_data_read`, at which stage the `struct ihex_state` - * structure will contain the data along with its address. See the header - * `kk_ihex_read.h` for details and example implementation of `ihex_data_read`. - * - * The sequence to read data in IHEX format is: - *      struct ihex_state ihex; - *      ihex_begin_read(&ihex); - *      ihex_read_bytes(&ihex, my_input_bytes, length_of_my_input_bytes); - *      ihex_end_read(&ihex); - * - * - *      WRITING BINARY DATA AS INTEL HEX - *      -------------------------------- - * - * In order to write out data, the `ihex_write_at_address` or - * `ihex_write_at_segment` functions are used to set the data location, - * and then the binary bytes are written with `ihex_write_byte` and/or - * `ihex_write_bytes`. The writing functions will then call the function - * `ihex_flush_buffer` whenever the internal write buffer needs to be - * cleared - it is up to the caller to provide an implementation of - * `ihex_flush_buffer` to do the actual writing. See the header - * `kk_ihex_write.h` for details and an example implementation. - * - * See the declaration further down for an example implementation. - * - * The sequence to write data in IHEX format is: - *      struct ihex_state ihex; - *      ihex_init(&ihex); - *      ihex_write_at_address(&ihex, 0); - *      ihex_write_bytes(&ihex, my_data, length_of_my_data); - *      ihex_end_write(&ihex); - * - * For outputs larger than 64KiB, 32-bit linear addresses are output. Normally - * the initial linear extended address record of zero is NOT written - it can - * be forced by setting `ihex->flags |= IHEX_FLAG_ADDRESS_OVERFLOW` before - * writing the first byte. - * - * Gaps in the data may be created by calling `ihex_write_at_address` with the - * new starting address without calling `ihex_end_write` in between. - * - * - * The same `struct ihex_state` may be used either for reading or writing, - * but NOT both at the same time. Furthermore, a global output buffer is - * used for writing, i.e., multiple threads must not write simultaneously - * (but multiple writes may be interleaved). - * - * - *      CONSERVING MEMORY - *      ----------------- - * - * For memory-critical use, you can save additional memory by defining - * `IHEX_LINE_MAX_LENGTH` as something less than 255. Note, however, that - * this limit affects both reading and writing, so the resulting library - * will be unable to read lines with more than this number of data bytes. - * That said, I haven't encountered any IHEX files with more than 32 - * data bytes per line. For write only there is no reason to define the - * maximum as greater than the line length you'll actually be writing, - * e.g., 32 or 16. - * - * If the write functionality is only occasionally used, you can provide - * your own buffer for the duration by defining `IHEX_EXTERNAL_WRITE_BUFFER` - * and providing a `char *ihex_write_buffer` which points to valid storage - * for at least `IHEX_WRITE_BUFFER_LENGTH` characters from before the first - * call to any IHEX write function to until after the last. - * - * If you are doing both reading and writing, you can define the maximum - * output length separately as `IHEX_MAX_OUTPUT_LINE_LENGTH` - this will - * decrease the write buffer size, but `struct ihex_state` will still - * use the larger `IHEX_LINE_MAX_LENGTH` for its data storage. - * - * You can also save a few additional bytes by disabling support for - * segmented addresses, by defining `IHEX_DISABLE_SEGMENTS`. Both the - * read and write modules need to be build with the same option, as the - * resulting data structures will not be compatible otherwise. To be honest, - * this is a fairly pointless optimisation. - * - * - * Copyright (c) 2013-2015 Kimmo Kulovesi, http://arkku.com/ - * Provided with absolutely no warranty, use at your own risk only. - * Use and distribute freely, mark modified copies as such. - */ - -#ifndef KK_IHEX_H -#define KK_IHEX_H - -#define KK_IHEX_VERSION "2015-08-10" - -#include <stdint.h> - -#ifdef IHEX_USE_STDBOOL -#include <stdbool.h> -typedef bool ihex_bool_t; -#else -typedef uint_fast8_t ihex_bool_t; -#endif - -typedef uint_least32_t ihex_address_t; -typedef uint_least16_t ihex_segment_t; -typedef int ihex_count_t; - -// Maximum number of data bytes per line (applies to both reading and -// writing!); specify 255 to support reading all possible lengths. Less -// can be used to limit memory footprint on embedded systems, e.g., -// most programs with IHEX output use 32. -#ifndef IHEX_LINE_MAX_LENGTH -#define IHEX_LINE_MAX_LENGTH 255 -#endif - -enum ihex_flags { -    IHEX_FLAG_ADDRESS_OVERFLOW = 0x80   // 16-bit address overflow -}; -typedef uint8_t ihex_flags_t; - -typedef struct ihex_state { -    ihex_address_t  address; -#ifndef IHEX_DISABLE_SEGMENTS -    ihex_segment_t  segment; -#endif -    ihex_flags_t    flags; -    uint8_t         line_length; -    uint8_t         length; -    uint8_t         data[IHEX_LINE_MAX_LENGTH + 1]; -} kk_ihex_t; - -enum ihex_record_type { -    IHEX_DATA_RECORD, -    IHEX_END_OF_FILE_RECORD, -    IHEX_EXTENDED_SEGMENT_ADDRESS_RECORD, -    IHEX_START_SEGMENT_ADDRESS_RECORD, -    IHEX_EXTENDED_LINEAR_ADDRESS_RECORD, -    IHEX_START_LINEAR_ADDRESS_RECORD -}; -typedef uint8_t ihex_record_type_t; - -#ifndef IHEX_DISABLE_SEGMENTS - -// Resolve segmented address (if any). It is the author's recommendation that -// segmented addressing not be used (and indeed the write function of this -// library uses linear 32-bit addressing unless manually overridden). -// -#define IHEX_LINEAR_ADDRESS(ihex) ((ihex)->address + (((ihex_address_t)((ihex)->segment)) << 4)) -// -// Note that segmented addressing with the above macro is not strictly adherent -// to the IHEX specification, which mandates that the lowest 16 bits of the -// address and the index of the data byte must be added modulo 64K (i.e., -// at 16 bits precision with wraparound) and the segment address only added -// afterwards. -// -// To implement fully correct segmented addressing, compute the address -// of _each byte_ with its index in `data` as follows: -// -#define IHEX_BYTE_ADDRESS(ihex, byte_index) ((((ihex)->address + (byte_index)) & 0xFFFFU) + (((ihex_address_t)((ihex)->segment)) << 4)) - -#else // IHEX_DISABLE_SEGMENTS: - -#define IHEX_LINEAR_ADDRESS(ihex) ((ihex)->address) -#define IHEX_BYTE_ADDRESS(ihex, byte_index) ((ihex)->address + (byte_index)) - -#endif - -// The newline string (appended to every output line, e.g., "\r\n") -#ifndef IHEX_NEWLINE_STRING -#define IHEX_NEWLINE_STRING "\n" -#endif - -// See kk_ihex_read.h and kk_ihex_write.h for function declarations! - -#endif // !KK_IHEX_H diff --git a/host/lib/usrp_clock/octoclock/kk_ihex_license.txt b/host/lib/usrp_clock/octoclock/kk_ihex_license.txt deleted file mode 100644 index 530f413e3..000000000 --- a/host/lib/usrp_clock/octoclock/kk_ihex_license.txt +++ /dev/null @@ -1,20 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2013-2015 Kimmo Kulovesi - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/host/lib/usrp_clock/octoclock/kk_ihex_read.c b/host/lib/usrp_clock/octoclock/kk_ihex_read.c deleted file mode 100644 index 964cdd165..000000000 --- a/host/lib/usrp_clock/octoclock/kk_ihex_read.c +++ /dev/null @@ -1,261 +0,0 @@ -/* - * kk_ihex_read.c: A simple library for reading the Intel HEX (IHEX) format. - * - * See the header `kk_ihex.h` for instructions. - * - * Copyright (c) 2013-2015 Kimmo Kulovesi, http://arkku.com/ - * Provided with absolutely no warranty, use at your own risk only. - * Use and distribute freely, mark modified copies as such. - * - * Modifications Copyright (c) 2015 National Instruments Corp. - */ - -#include "kk_ihex_read.h" - -#include <stdio.h> -#include <stdlib.h> - -#define IHEX_START ':' - -#define AUTODETECT_ADDRESS (~0UL) - -#define ADDRESS_HIGH_MASK ((ihex_address_t) 0xFFFF0000U) - -enum ihex_read_state { -    READ_WAIT_FOR_START = 0, -    READ_COUNT_HIGH = 1, -    READ_COUNT_LOW, -    READ_ADDRESS_MSB_HIGH, -    READ_ADDRESS_MSB_LOW, -    READ_ADDRESS_LSB_HIGH, -    READ_ADDRESS_LSB_LOW, -    READ_RECORD_TYPE_HIGH, -    READ_RECORD_TYPE_LOW, -    READ_DATA_HIGH, -    READ_DATA_LOW -}; - -#define IHEX_READ_RECORD_TYPE_MASK 0x07 -#define IHEX_READ_STATE_MASK 0x78 -#define IHEX_READ_STATE_OFFSET 3 - -void -ihex_begin_read (struct ihex_state * const ihex) { -    ihex->address = 0; -#ifndef IHEX_DISABLE_SEGMENTS -    ihex->segment = 0; -#endif -    ihex->flags = 0; -    ihex->line_length = 0; -    ihex->length = 0; -} - -void -ihex_read_at_address (struct ihex_state * const ihex, ihex_address_t address) { -    ihex_begin_read(ihex); -    ihex->address = address; -} - -#ifndef IHEX_DISABLE_SEGMENTS -void -ihex_read_at_segment (struct ihex_state * const ihex, ihex_segment_t segment) { -    ihex_begin_read(ihex); -    ihex->segment = segment; -} -#endif - -void -ihex_end_read (struct ihex_state * const ihex, FILE* outfile) { -    uint_fast8_t type = ihex->flags & IHEX_READ_RECORD_TYPE_MASK; -    uint_fast8_t sum; -    if ((sum = ihex->length) == 0 && type == IHEX_DATA_RECORD) { -        return; -    } -    { -        // compute and validate checksum -        const uint8_t * const eptr = ihex->data + sum; -        const uint8_t *r = ihex->data; -        sum += type + (ihex->address & 0xFFU) + ((ihex->address >> 8) & 0xFFU); -        while (r != eptr) { -            sum += *r++; -        } -        sum = (~sum + 1U) ^ *eptr; // *eptr is the received checksum -    } -    if (ihex_data_read(ihex, type, sum, outfile)) { -        if (type == IHEX_EXTENDED_LINEAR_ADDRESS_RECORD) { -            ihex->address &= 0xFFFFU; -            ihex->address |= (((ihex_address_t) ihex->data[0]) << 24) | -                             (((ihex_address_t) ihex->data[1]) << 16); -#ifndef IHEX_DISABLE_SEGMENTS -        } else if (type == IHEX_EXTENDED_SEGMENT_ADDRESS_RECORD) { -            ihex->segment = (ihex_segment_t) ((ihex->data[0] << 8) | ihex->data[1]); -#endif -        } -    } -    ihex->length = 0; -    ihex->flags = 0; -} - -void -ihex_read_byte (struct ihex_state * const ihex, const char byte, FILE* outfile) { -    uint_fast8_t b = (uint_fast8_t) byte; -    uint_fast8_t len = ihex->length; -    uint_fast8_t state = (ihex->flags & IHEX_READ_STATE_MASK); -    ihex->flags ^= state; // turn off the old state -    state >>= IHEX_READ_STATE_OFFSET; - -    if (b >= '0' && b <= '9') { -        b -= '0'; -    } else if (b >= 'A' && b <= 'F') { -        b -= 'A' - 10; -    } else if (b >= 'a' && b <= 'f') { -        b -= 'a' - 10; -    } else if (b == IHEX_START) { -        // sync to a new record at any state -        state = READ_COUNT_HIGH; -        goto end_read; -    } else { -        // ignore unknown characters (e.g., extra whitespace) -        goto save_read_state; -    } - -    if (!(++state & 1)) { -        // high nybble, store temporarily at end of data: -        b <<= 4; -        ihex->data[len] = b; -    } else { -        // low nybble, combine with stored high nybble: -        b = (ihex->data[len] |= b); -        switch (state >> 1) { -        default: -            // remain in initial state while waiting for : -            return; -        case (READ_COUNT_LOW >> 1): -            // data length -            ihex->line_length = b; -#if IHEX_LINE_MAX_LENGTH < 255 -            if (b > IHEX_LINE_MAX_LENGTH) { -                ihex_end_read(ihex); -                return; -            } -#endif -            break; -        case (READ_ADDRESS_MSB_LOW >> 1): -            // high byte of 16-bit address -            ihex->address &= ADDRESS_HIGH_MASK; // clear the 16-bit address -            ihex->address |= ((ihex_address_t) b) << 8U; -            break; -        case (READ_ADDRESS_LSB_LOW >> 1): -            // low byte of 16-bit address -            ihex->address |= (ihex_address_t) b; -            break; -        case (READ_RECORD_TYPE_LOW >> 1): -            // record type -            if (b & ~IHEX_READ_RECORD_TYPE_MASK) { -                // skip unknown record types silently -                return; -            }  -            ihex->flags = (ihex->flags & ~IHEX_READ_RECORD_TYPE_MASK) | b; -            break; -        case (READ_DATA_LOW >> 1): -            if (len < ihex->line_length) { -                // data byte -                ihex->length = len + 1; -                state = READ_DATA_HIGH; -                goto save_read_state; -            } -            // end of line (last "data" byte is checksum) -            state = READ_WAIT_FOR_START; -        end_read: -            ihex_end_read(ihex, outfile); -        } -    } -save_read_state: -    ihex->flags |= state << IHEX_READ_STATE_OFFSET; -} - -void -ihex_read_bytes (struct ihex_state * ihex, -                 const char * data, -                 ihex_count_t count, -		 FILE* outfile) { -    while (count > 0) { -        ihex_read_byte(ihex, *data++, outfile); -        --count; -    } -} - -ihex_bool_t -ihex_data_read (struct ihex_state *ihex, -                ihex_record_type_t type, -                ihex_bool_t error, -		FILE* outfile) { -    unsigned long line_number = 1L; -    unsigned long file_position = 0L; -    unsigned long address_offset = 0L; -    bool debug_enabled = false; - -    if (error) { -        (void) fprintf(stderr, "Checksum error on line %lu\n", line_number); -        return false; -    } -    if ((error = (ihex->length < ihex->line_length))) { -        (void) fprintf(stderr, "Line length error on line %lu\n", line_number); -        return false; -    } -    if (!outfile) { -        (void) fprintf(stderr, "Excess data after end of file record\n"); -        return false; -    } -    if (type == IHEX_DATA_RECORD) { -        unsigned long address = (unsigned long) IHEX_LINEAR_ADDRESS(ihex); -        if (address < address_offset) { -            if (address_offset == AUTODETECT_ADDRESS) { -                // autodetect initial address -                address_offset = address; -                if (debug_enabled) { -                    (void) fprintf(stderr, "Address offset: 0x%lx\n", -                            address_offset); -                } -            } else { -                (void) fprintf(stderr, "Address underflow on line %lu\n", -                        line_number); -                return false; -            } -        } -        address -= address_offset; -        if (address != file_position) { -            if (debug_enabled) { -                (void) fprintf(stderr, -                        "Seeking from 0x%lx to 0x%lx on line %lu\n", -                        file_position, address, line_number); -            } -            if (outfile == stdout || fseek(outfile, (long) address, SEEK_SET)) { -                if (file_position < address) { -                    // "seek" forward in stdout by writing NUL bytes -                    do { -                        (void) fputc('\0', outfile); -                    } while (++file_position < address); -                } else { -                    perror("fseek"); -                    return false; -                } -            } -            file_position = address; -        } -        if (!fwrite(ihex->data, ihex->length, 1, outfile)) { -            perror("fwrite"); -            return false; -        } -        file_position += ihex->length; -    } else if (type == IHEX_END_OF_FILE_RECORD) { -        if (debug_enabled) { -            (void) fprintf(stderr, "%lu bytes written\n", file_position); -        } -        if (outfile != stdout) { -            (void) fclose(outfile); -        } -        outfile = NULL; -    } -    return true; -} diff --git a/host/lib/usrp_clock/octoclock/kk_ihex_read.h b/host/lib/usrp_clock/octoclock/kk_ihex_read.h deleted file mode 100644 index 303622b18..000000000 --- a/host/lib/usrp_clock/octoclock/kk_ihex_read.h +++ /dev/null @@ -1,119 +0,0 @@ -/* - * kk_ihex_read.h: A simple library for reading Intel HEX data. See - * the accompanying kk_ihex_write.h for IHEX write support. - * - * - *      READING INTEL HEX DATA - *      ---------------------- - * - * To read data in the Intel HEX format, you must perform the actual reading - * of bytes using other means (e.g., stdio). The bytes read must then be - * passed to `ihex_read_byte` and/or `ihex_read_bytes`. The reading functions - * will then call `ihex_data_read`, at which stage the `struct ihex_state` - * structure will contain the data along with its address. See below for - * details and example implementation of `ihex_data_read`. - * - * The sequence to read data in IHEX format is: - *      struct ihex_state ihex; - *      ihex_begin_read(&ihex); - *      ihex_read_bytes(&ihex, my_input_bytes, length_of_my_input_bytes); - *      ihex_end_read(&ihex); - * - * - *      CONSERVING MEMORY - *      ----------------- - * - * For memory-critical use, you can save additional memory by defining - * `IHEX_LINE_MAX_LENGTH` as something less than 255. Note, however, that - * this limit affects both reading and writing, so the resulting library - * will be unable to read lines with more than this number of data bytes. - * That said, I haven't encountered any IHEX files with more than 32 - * data bytes per line. - * - * - * Copyright (c) 2013-2015 Kimmo Kulovesi, http://arkku.com/ - * Provided with absolutely no warranty, use at your own risk only. - * Use and distribute freely, mark modified copies as such. - * - * Modifications Copyright (c) 2015 National Instruments Corp. - */ - -#ifndef KK_IHEX_READ_H -#define KK_IHEX_READ_H -#ifdef __cplusplus -extern "C" { -#endif - -#include "kk_ihex.h" - -#include <stdio.h> - -// Begin reading at address 0 -void ihex_begin_read(struct ihex_state * const ihex); - -// Begin reading at `address` (the lowest 16 bits of which will be ignored); -// this is required only if the high bytes of the 32-bit starting address -// are not specified in the input data and they are non-zero -void ihex_read_at_address(struct ihex_state * const ihex, -                          ihex_address_t address); - -// Read a single character -void ihex_read_byte(struct ihex_state * const ihex, const char byte, FILE* outfile); - -// Read `count` bytes from `data` -void ihex_read_bytes(struct ihex_state * ihex, -                     const char * data, -                     ihex_count_t count, -                     FILE* outfile); - -// End reading (may call `ihex_data_read` if there is data waiting) -void ihex_end_read(struct ihex_state * const ihex, FILE* outfile); - -// Called when a complete line has been read, the record type of which is -// passed as `type`. The `ihex` structure will have its fields `data`, -// `line_length`, `address`, and `segment` set appropriately. In case -// of reading an `IHEX_EXTENDED_LINEAR_ADDRESS_RECORD` or an -// `IHEX_EXTENDED_SEGMENT_ADDRESS_RECORD` the record's data is not -// yet parsed - it will be parsed into the `address` or `segment` field -// only if `ihex_data_read` returns `true`. This allows manual handling -// of extended addresses by parsing the `ihex->data` bytes. -// -// Possible error cases include checksum mismatch (which is indicated -// as an argument), and excessive line length (in case this has been -// compiled with `IHEX_LINE_MAX_LENGTH` less than 255) which is indicated -// by `line_length` greater than `length`. Unknown record types and -// other erroneous data is usually silently ignored by this minimalistic -// parser. (It is recommended to compute a hash over the complete data -// once received and verify that against the source.) -// -// Example implementation: -// -//      ihex_bool_t ihex_data_read(struct ihex_state *ihex, -//                                 ihex_record_type_t type, -//                                 ihex_bool_t error) { -//          error = error || (ihex->length < ihex->line_length); -//          if (type == IHEX_DATA_RECORD && !error) { -//              (void) fseek(outfile, IHEX_LINEAR_ADDRESS(ihex), SEEK_SET); -//              (void) fwrite(ihex->data, 1, ihex->length, outfile); -//          } else if (type == IHEX_END_OF_FILE_RECORD) { -//              (void) fclose(outfile); -//          } -//          return !error; -//      } -// -ihex_bool_t ihex_data_read(struct ihex_state *ihex, -                           ihex_record_type_t type, -                           ihex_bool_t checksum_mismatch, -                           FILE* outfile); - -// Begin reading at `segment`; this is required only if the initial segment -// is not specified in the input data and it is non-zero. -// -#ifndef IHEX_DISABLE_SEGMENTS -void ihex_read_at_segment(struct ihex_state *ihex, ihex_segment_t segment); -#endif - -#ifdef __cplusplus -} -#endif -#endif // !KK_IHEX_READ_H diff --git a/host/lib/usrp_clock/octoclock/octoclock_image_loader.cpp b/host/lib/usrp_clock/octoclock/octoclock_image_loader.cpp index 8b47da7e5..fdb254024 100644 --- a/host/lib/usrp_clock/octoclock/octoclock_image_loader.cpp +++ b/host/lib/usrp_clock/octoclock/octoclock_image_loader.cpp @@ -17,8 +17,8 @@  #include "octoclock_impl.hpp"  #include "common.h" -#include "kk_ihex_read.h" +#include "../../utils/ihex.hpp"  #include <uhd/device.hpp>  #include <uhd/image_loader.hpp>  #include <uhd/transport/udp_simple.hpp> @@ -34,6 +34,8 @@  #include <boost/lexical_cast.hpp>  #include <boost/thread.hpp> +#include <algorithm> +#include <iterator>  #include <cstdio>  #include <cstring>  #include <fstream> @@ -54,83 +56,70 @@ using namespace uhd::transport;  typedef struct {      bool                        found;      uhd::device_addr_t          dev_addr; -    std::string                 given_filepath; -    std::string                 actual_filepath; // If using a .hex, this is the converted .bin -    bool                        from_hex; -    boost::uint32_t             size; +    std::string                 image_filepath;      boost::uint16_t             crc;      boost::uint16_t             num_blocks;      udp_simple::sptr            ctrl_xport;      udp_simple::sptr            fw_xport;      boost::uint8_t              data_in[udp_simple::mtu]; +    std::vector<boost::uint8_t> image;  } octoclock_session_t;  static void octoclock_calculate_crc(octoclock_session_t &session){ -    std::ifstream ifile(session.actual_filepath.c_str()); -    boost::uint8_t temp_image[OCTOCLOCK_FIRMWARE_MAX_SIZE_BYTES]; -    ifile.read((char*)temp_image, session.size); -      session.crc = 0xFFFF; -    for(size_t i = 0; i < session.size; i++){ -        session.crc ^= temp_image[i]; +    for(size_t i = 0; i < session.image.size(); i++) +    { +        session.crc ^= session.image[i];          for(boost::uint8_t j = 0; j < 8; ++j){              if(session.crc & 1) session.crc = (session.crc >> 1) ^ 0xA001;              else session.crc = (session.crc >> 1);          }      } - -    ifile.close();  } -static void octoclock_convert_ihex(octoclock_session_t &session){ -    struct ihex_state ihex; -    ihex_count_t count; -    char buf[256]; -    FILE* infile = fopen(session.given_filepath.c_str(), "r"); -    FILE* outfile = fopen(session.actual_filepath.c_str(), "w"); -    uint64_t line_number = 1; - -    ihex_begin_read(&ihex); -    while(fgets(buf, 256, infile)){ -        count = ihex_count_t(strlen(buf)); -        ihex_read_bytes(&ihex, buf, count, outfile); -        line_number += (count && buf[count - 1] == '\n'); +static void octoclock_read_bin(octoclock_session_t &session) +{ +    std::ifstream bin_file(session.image_filepath.c_str(), std::ios::in | std::ios::binary); +    if (not bin_file.is_open()) { +        throw uhd::io_error("Could not read image file.");      } -    ihex_end_read(&ihex, outfile); // Closes outfile -    (void)fclose(infile); +    size_t filesize = fs::file_size(session.image_filepath); +    session.image.clear(); +    session.image.resize(filesize); +    bin_file.read((char*)&session.image[0], filesize); +    if(size_t(bin_file.gcount()) != filesize) { +        throw uhd::io_error("Failed to read firmware image."); +    } + +    bin_file.close();  }  static void octoclock_validate_firmware_image(octoclock_session_t &session){ -    if(not fs::exists(session.given_filepath)){ +    if(not fs::exists(session.image_filepath)){          throw uhd::runtime_error(str(boost::format("Could not find image at path \"%s\"") -                                     % session.given_filepath)); +                                     % session.image_filepath));      } -    std::string extension = fs::extension(session.given_filepath); +    std::string extension = fs::extension(session.image_filepath);      if(extension == ".bin"){ -        session.actual_filepath = session.given_filepath; -        session.from_hex = false; +        octoclock_read_bin(session);      }      else if(extension == ".hex"){ -        session.actual_filepath = fs::path(fs::path(uhd::get_tmp_path()) / -                                           str(boost::format("octoclock_fw_%d.bin") -                                               % time_spec_t::get_system_time().get_full_secs()) -                                          ).string(); - -        octoclock_convert_ihex(session); -        session.from_hex = true; +        ihex_reader hex_reader(session.image_filepath); +        session.image = hex_reader.to_vector(OCTOCLOCK_FIRMWARE_MAX_SIZE_BYTES);      } -    else throw uhd::runtime_error(str(boost::format("Invalid extension \"%s\". Extension must be .hex or .bin."))); +    else throw uhd::runtime_error(str(boost::format("Invalid extension \"%s\". Extension must be .hex or .bin.") +                                      % extension)); -    session.size = fs::file_size(session.actual_filepath); -    if(session.size > OCTOCLOCK_FIRMWARE_MAX_SIZE_BYTES){ +    if(session.image.size() > OCTOCLOCK_FIRMWARE_MAX_SIZE_BYTES){          throw uhd::runtime_error(str(boost::format("The specified firmware image is too large: %d vs. %d") -                                     % session.size % OCTOCLOCK_FIRMWARE_MAX_SIZE_BYTES)); +                                     % session.image.size() % OCTOCLOCK_FIRMWARE_MAX_SIZE_BYTES));      } -    session.num_blocks = (session.size % OCTOCLOCK_BLOCK_SIZE) ? ((session.size / OCTOCLOCK_BLOCK_SIZE) + 1) -                                                               : (session.size / OCTOCLOCK_BLOCK_SIZE); +    session.num_blocks = (session.image.size() % OCTOCLOCK_BLOCK_SIZE) +                            ? ((session.image.size() / OCTOCLOCK_BLOCK_SIZE) + 1) +                            : (session.image.size() / OCTOCLOCK_BLOCK_SIZE);      octoclock_calculate_crc(session);  } @@ -164,14 +153,15 @@ static void octoclock_setup_session(octoclock_session_t &session,      }      session.dev_addr = devs[0]; +    session.found = true;      // If no filepath is given, use the default      if(filepath == ""){ -        session.given_filepath = find_image_path(str(boost::format("octoclock_r%s_fw.hex") +        session.image_filepath = find_image_path(str(boost::format("octoclock_r%s_fw.hex")                                                       % session.dev_addr.get("revision","4")                                                   ));      } -    else session.given_filepath = filepath; +    else session.image_filepath = filepath;      octoclock_validate_firmware_image(session); @@ -231,10 +221,10 @@ static void octoclock_burn(octoclock_session_t &session){      const octoclock_packet_t* pkt_in = reinterpret_cast<const octoclock_packet_t*>(session.data_in);      // Tell OctoClock to prepare for burn -    pkt_out.len = htonx<boost::uint16_t>(session.size); +    pkt_out.len = htonx<boost::uint16_t>(session.image.size());      size_t len = 0;      std::cout << " -- Preparing OctoClock for firmware load..." << std::flush; -    pkt_out.len = session.size; +    pkt_out.len = session.image.size();      pkt_out.crc = session.crc;      UHD_OCTOCLOCK_SEND_AND_RECV(session.fw_xport, PREPARE_FW_BURN_CMD, pkt_out, len, session.data_in);      if(UHD_OCTOCLOCK_PACKET_MATCHES(FW_BURN_READY_ACK, pkt_out, pkt_in, len)){ @@ -242,14 +232,10 @@ static void octoclock_burn(octoclock_session_t &session){      }      else{          std::cout << "failed." << std::endl; -        if(session.from_hex){ -            fs::remove(session.actual_filepath); -        }          throw uhd::runtime_error("Failed to prepare OctoClock for firmware load.");      }      // Start burning -    std::ifstream image(session.actual_filepath.c_str(), std::ios::binary);      for(size_t i = 0; i < session.num_blocks; i++){          pkt_out.sequence++;          pkt_out.addr = i * OCTOCLOCK_BLOCK_SIZE; @@ -260,14 +246,10 @@ static void octoclock_burn(octoclock_session_t &session){                    << std::flush;          memset(pkt_out.data, 0, OCTOCLOCK_BLOCK_SIZE); -        image.read((char*)pkt_out.data, OCTOCLOCK_BLOCK_SIZE); +        memcpy((char*)pkt_out.data, &session.image[pkt_out.addr], OCTOCLOCK_BLOCK_SIZE);          UHD_OCTOCLOCK_SEND_AND_RECV(session.fw_xport, FILE_TRANSFER_CMD, pkt_out, len, session.data_in);          if(not UHD_OCTOCLOCK_PACKET_MATCHES(FILE_TRANSFER_ACK, pkt_out, pkt_in, len)){ -            image.close();              std::cout << std::endl; -            if(session.from_hex){ -                fs::remove(session.actual_filepath); -            }              throw uhd::runtime_error("Failed to load firmware.");          }      } @@ -275,7 +257,6 @@ static void octoclock_burn(octoclock_session_t &session){      std::cout << str(boost::format("\r -- Loading firmware: 100%% (%d/%d blocks)")                       % session.num_blocks % session.num_blocks)                << std::endl; -    image.close();  }  static void octoclock_verify(octoclock_session_t &session){ @@ -285,7 +266,6 @@ static void octoclock_verify(octoclock_session_t &session){      const octoclock_packet_t* pkt_in = reinterpret_cast<const octoclock_packet_t*>(session.data_in);      size_t len = 0; -    std::ifstream image(session.actual_filepath.c_str(), std::ios::binary);      boost::uint8_t image_part[OCTOCLOCK_BLOCK_SIZE];      boost::uint16_t cmp_len = 0;      for(size_t i = 0; i < session.num_blocks; i++){ @@ -298,34 +278,22 @@ static void octoclock_verify(octoclock_session_t &session){                    << std::flush;          memset(image_part, 0, OCTOCLOCK_BLOCK_SIZE); -        image.read((char*)image_part, OCTOCLOCK_BLOCK_SIZE); -        cmp_len = image.gcount(); +        memcpy((char*)image_part, &session.image[pkt_out.addr], OCTOCLOCK_BLOCK_SIZE); +        cmp_len = std::min<size_t>(OCTOCLOCK_BLOCK_SIZE, session.image.size() - size_t(pkt_out.addr));          UHD_OCTOCLOCK_SEND_AND_RECV(session.fw_xport, READ_FW_CMD, pkt_out, len, session.data_in);          if(UHD_OCTOCLOCK_PACKET_MATCHES(READ_FW_ACK, pkt_out, pkt_in, len)){              if(memcmp(pkt_in->data, image_part, cmp_len)){                  std::cout << std::endl; -                image.close(); -                if(session.from_hex){ -                    fs::remove(session.actual_filepath); -                }                  throw uhd::runtime_error("Failed to verify OctoClock firmware.");              }          }          else{              std::cout << std::endl; -            image.close(); -            if(session.from_hex){ -                fs::remove(session.actual_filepath); -            }              throw uhd::runtime_error("Failed to verify OctoClock firmware.");          }      } -    image.close(); -    if(session.from_hex){ -        fs::remove(session.actual_filepath); -    }      std::cout << str(boost::format("\r -- Verifying firmware load: 100%% (%d/%d blocks)")                       % session.num_blocks % session.num_blocks)                << std::endl; @@ -360,7 +328,7 @@ bool octoclock_image_loader(const image_loader::image_loader_args_t &image_loade      std::cout << boost::format("Unit: OctoClock (%s)")                   % session.dev_addr["addr"]                << std::endl; -    std::cout << "Firmware: " << session.given_filepath << std::endl; +    std::cout << "Firmware: " << session.image_filepath << std::endl;      octoclock_burn(session);      octoclock_verify(session); diff --git a/host/lib/utils/CMakeLists.txt b/host/lib/utils/CMakeLists.txt index c5c975dfa..72e2f3f50 100644 --- a/host/lib/utils/CMakeLists.txt +++ b/host/lib/utils/CMakeLists.txt @@ -132,6 +132,7 @@ SET_SOURCE_FILES_PROPERTIES(  LIBUHD_APPEND_SOURCES(      ${CMAKE_CURRENT_SOURCE_DIR}/csv.cpp      ${CMAKE_CURRENT_SOURCE_DIR}/gain_group.cpp +    ${CMAKE_CURRENT_SOURCE_DIR}/ihex.cpp      ${CMAKE_CURRENT_SOURCE_DIR}/load_modules.cpp      ${CMAKE_CURRENT_SOURCE_DIR}/log.cpp      ${CMAKE_CURRENT_SOURCE_DIR}/msg.cpp diff --git a/host/lib/utils/ihex.cpp b/host/lib/utils/ihex.cpp new file mode 100644 index 000000000..a29ac3e72 --- /dev/null +++ b/host/lib/utils/ihex.cpp @@ -0,0 +1,236 @@ +// +// Copyright 2015 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +#include "ihex.hpp" +#include <uhd/exception.hpp> +#include <boost/format.hpp> +#include <boost/make_shared.hpp> +#include <sstream> +#include <fstream> + +using namespace uhd; + +/*! + * Verify checksum of a Intel HEX record + * \param record a line from an Intel HEX file + * \return true if record is valid, false otherwise + */ +static bool checksum(const std::string& record) +{ +    size_t len = record.length(); +    unsigned char sum = 0; +    unsigned int val; + +    for (size_t i = 1; i < len; i += 2) { +        std::istringstream(record.substr(i, 2)) >> std::hex >> val; +        sum += val; +    } + +    if (sum == 0) +       return true; +    else +       return false; +} + + +/*! + * Parse Intel HEX record + * + * \param record a line from an Intel HEX file + * \param len output length of record + * \param addr output address + * \param type output type + * \param data output data + * \return true if record is sucessfully read, false on error + */ +static bool parse_record( +        const std::string& record, +        boost::uint16_t &len, +        boost::uint16_t &addr, +        boost::uint16_t &type, +        unsigned char* data +) { +    unsigned int i; +    unsigned int val; + +    if (record.substr(0, 1) != ":") +        return false; + +    std::istringstream(record.substr(1, 2)) >> std::hex >> len; +    std::istringstream(record.substr(3, 4)) >> std::hex >> addr; +    std::istringstream(record.substr(7, 2)) >> std::hex >> type; + +    if (len > (2 * (record.length() - 9)))  // sanity check to prevent buffer overrun +        return false; + +    for (i = 0; i < len; i++) { +        std::istringstream(record.substr(9 + 2 * i, 2)) >> std::hex >> val; +        data[i] = (unsigned char) val; +    } + +    return true; +} + + +ihex_reader::ihex_reader(const std::string &ihex_filename) +    : _ihex_filename(ihex_filename) +{ +    // nop +} + + +void ihex_reader::read(ihex_reader::record_handle_type record_handler) +{ +    const char *filename = _ihex_filename.c_str(); + +    /* Fields used in every record. */ +    boost::uint16_t len = 0; +    boost::uint16_t type = 0; +    boost::uint16_t lower_address_bits = 0x0000; +    static const int MAX_RECORD_LENGTH = 255; +    unsigned char data[MAX_RECORD_LENGTH]; + +    /* Can be set by the Intel HEX record 0x04, used for all 0x00 records +     * thereafter. Note this field takes the place of the 'index' parameter in +     * libusb calls, and is necessary for FX3's 32-bit addressing. */ +    boost::uint16_t upper_address_bits = 0x0000; + +    std::ifstream file; +    file.open(filename, std::ifstream::in); + +    if(!file.good()) { +        throw uhd::io_error("ihex_reader::read(): cannot open firmware input file"); +    } + +    while (!file.eof()) { +        boost::int32_t ret = 0; +        std::string record; +        file >> record; + +        if (!(record.length() > 0)) +            continue; + +        /* Check for valid Intel HEX record. */ +        if (!checksum(record) +            || !parse_record(record, len, lower_address_bits, type, data)) { +            throw uhd::io_error("ihex_reader::read(): bad intel hex record checksum"); +        } + +        /* Type 0x00: Data. */ +        if (type == 0x00) { +            ret = record_handler(lower_address_bits, upper_address_bits, data, len); + +            if (ret < 0) { +                throw uhd::io_error("ihex_reader::read(): record hander returned failure code"); +            } +        } + +        /* Type 0x01: EOF. */ +        else if (type == 0x01) { +            if (lower_address_bits != 0x0000 || len != 0 ) { +                throw uhd::io_error("ihex_reader::read(): For EOF record, address must be 0, length must be 0."); +            } + +            /* Successful termination! */ +            file.close(); +            return; +        } + +        /* Type 0x04: Extended Linear Address Record. */ +        else if (type == 0x04) { +            if (lower_address_bits != 0x0000 || len != 2 ) { +                throw uhd::io_error("ihex_reader::read(): For ELA record, address must be 0, length must be 2."); +            } + +            upper_address_bits = ((boost::uint16_t)((data[0] & 0x00FF) << 8))\ +                                 + ((boost::uint16_t)(data[1] & 0x00FF)); +        } + +        /* Type 0x05: Start Linear Address Record. */ +        else if (type == 0x05) { +            if (lower_address_bits != 0x0000 || len != 4 ) { +                throw uhd::io_error("ihex_reader::read(): For SLA record, address must be 0, length must be 4."); +            } + +            /* The firmware load is complete.  We now need to tell the CPU +             * to jump to an execution address start point, now contained within +             * the data field.  Parse these address bits out, and then push the +             * instruction. */ +            upper_address_bits = ((boost::uint16_t)((data[0] & 0x00FF) << 8))\ +                                 + ((boost::uint16_t)(data[1] & 0x00FF)); +            lower_address_bits = ((boost::uint16_t)((data[2] & 0x00FF) << 8))\ +                                 + ((boost::uint16_t)(data[3] & 0x00FF)); + +            record_handler(lower_address_bits, upper_address_bits, 0, 0); +        } + +        /* If we receive an unknown record type, error out. */ +        else { +            throw uhd::io_error(str(boost::format("ihex_reader::read(): unsupported record type: %X.") % type)); +        } +    } + +    /* There was no valid EOF. */ +    throw uhd::io_error("ihex_reader::read(): No EOF record found."); +} + +// We need a functor for the cast, a lambda would be perfect... +int _file_writer_callback( +    boost::shared_ptr<std::ofstream> output_file, +    unsigned char *buff, +    boost::uint16_t len +) { +    output_file->write((const char *) buff, len); +    return 0; +} + +void ihex_reader::to_bin_file(const std::string &bin_filename) +{ +    boost::shared_ptr<std::ofstream> output_file(boost::make_shared<std::ofstream>()); +    output_file->open(bin_filename.c_str(), std::ios::out | std::ios::binary); +    if (not output_file->is_open()) { +        throw uhd::io_error(str(boost::format("Could not open file for writing: %s") % bin_filename)); +    } + +    this->read(boost::bind(&_file_writer_callback, output_file, _3, _4)); + +    output_file->close(); +} + +// We need a functor for the cast, a lambda would be perfect... +int _vector_writer_callback( +    std::vector<boost::uint8_t>& vector, +    unsigned char *buff, +    boost::uint16_t len +) { +    for (size_t i = 0; i < len; i++) { +        vector.push_back(buff[i]); +    } +    return 0; +} + +#define DEFAULT_SIZE_ESTIMATE 8000000 +std::vector<boost::uint8_t> ihex_reader::to_vector(const size_t size_estimate) +{ +    std::vector<boost::uint8_t> buf; +    buf.reserve(size_estimate == 0 ? DEFAULT_SIZE_ESTIMATE : size_estimate); + +    this->read(boost::bind(&_vector_writer_callback, boost::ref(buf), _3, _4)); + +    return buf; +} + diff --git a/host/lib/utils/ihex.hpp b/host/lib/utils/ihex.hpp new file mode 100644 index 000000000..9df1fcbc3 --- /dev/null +++ b/host/lib/utils/ihex.hpp @@ -0,0 +1,79 @@ +// +// Copyright 2015 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +#ifndef INCLUDED_IHEX_READER_HPP +#define INCLUDED_IHEX_READER_HPP + +#include <boost/bind.hpp> +#include <boost/function.hpp> +#include <boost/cstdint.hpp> +#include <string> +#include <vector> + +namespace uhd { + +class ihex_reader +{ +public: +    // Arguments are: lower address bits, upper address bits, buff, length +    typedef boost::function<int(boost::uint16_t,boost::uint16_t,unsigned char*,boost::uint16_t)> record_handle_type; + +    /* +     * \param ihex_filename Path to the *.ihx file +     */ +    ihex_reader(const std::string &ihex_filename); + +    /*! Read an Intel HEX file and handle it record by record. +     * +     * Every record is individually passed off to a record handler function. +     * +     * \param record_handler The functor that will handle the records. +     * +     * \throws uhd::io_error if the HEX file is corrupted or unreadable. +     */ +    void read(record_handle_type record_handler); + +    /* Convert the ihex file to a bin file. +     * +     * *Note:* This function makes the assumption that the hex file is +     * contiguous, and starts at address zero. +     * +     * \param bin_filename Output filename. +     * +     * \throws uhd::io_error if the HEX file is corrupted or unreadable. +     */ +    void to_bin_file(const std::string &bin_filename); + +    /*! Copy the ihex file into a buffer. +     * +     * Very similar functionality as to_bin_file(). +     * +     * *Note:* This function makes the assumption that the hex file is +     * contiguous, and starts at address zero. +     * +     * \throws uhd::io_error if the HEX file is corrupted or unreadable. +     */ +    std::vector<boost::uint8_t> to_vector(const size_t size_estimate = 0); + +private: +    const std::string _ihex_filename; +}; + +}; /* namespace uhd */ + +#endif /* INCLUDED_IHEX_READER_HPP */ + diff --git a/host/utils/CMakeLists.txt b/host/utils/CMakeLists.txt index 1ea86f2cc..9ab95596d 100644 --- a/host/utils/CMakeLists.txt +++ b/host/utils/CMakeLists.txt @@ -91,10 +91,9 @@ IF(ENABLE_OCTOCLOCK)      SET(octoclock_burner_sources          octoclock_firmware_burner.cpp -        ${CMAKE_SOURCE_DIR}/lib/usrp_clock/octoclock/kk_ihex_read.c +        ${CMAKE_SOURCE_DIR}/lib/utils/ihex.cpp      ) -    ADD_DEFINITIONS(-DIHEX_USE_STDBOOL)      INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/lib/usrp_clock/octoclock)      ADD_EXECUTABLE(octoclock_firmware_burner ${octoclock_burner_sources})      TARGET_LINK_LIBRARIES(octoclock_firmware_burner uhd ${Boost_LIBRARIES}) diff --git a/host/utils/b2xx_fx3_utils.cpp b/host/utils/b2xx_fx3_utils.cpp index a3eaf862a..a6896c868 100644 --- a/host/utils/b2xx_fx3_utils.cpp +++ b/host/utils/b2xx_fx3_utils.cpp @@ -52,7 +52,8 @@ const static vid_pid_t known_vid_pids[] = {      {FX3_VID, FX3_DEFAULT_PID},      {FX3_VID, FX3_REENUM_PID},      {B200_VENDOR_ID, B200_PRODUCT_ID}, -    {B200_VENDOR_ID, B205_PRODUCT_ID}, +    {B200_VENDOR_ID, B200MINI_PRODUCT_ID}, +    {B200_VENDOR_ID, B205MINI_PRODUCT_ID},      {B200_VENDOR_NI_ID, B200_PRODUCT_NI_ID},      {B200_VENDOR_NI_ID, B210_PRODUCT_NI_ID}  }; @@ -175,7 +176,7 @@ uhd::transport::usb_device_handle::sptr open_device(const boost::uint16_t vid, c                  vp = known_vid_pid_vector[i];                  handles = uhd::transport::usb_device_handle::get_device_list(vp.vid, vp.pid);              } -            +          }          if (handles.size() > 0) diff --git a/host/utils/octoclock_firmware_burner.cpp b/host/utils/octoclock_firmware_burner.cpp index c338cd818..326985df5 100644 --- a/host/utils/octoclock_firmware_burner.cpp +++ b/host/utils/octoclock_firmware_burner.cpp @@ -42,7 +42,7 @@  #include <uhd/utils/safe_main.hpp>  #include "../lib/usrp_clock/octoclock/common.h" -#include "kk_ihex_read.h" +#include "../lib/utils/ihex.hpp"  #define MAX_FIRMWARE_SIZE 1024*120  #define BLOCK_SIZE 256 @@ -142,7 +142,7 @@ device_addrs_t bootloader_find(const std::string &ip_addr){      device_addrs_t addrs;      boost::system_time comm_timeout = boost::get_system_time() + boost::posix_time::milliseconds(3000); -     +      while(boost::get_system_time() < comm_timeout){          UHD_OCTOCLOCK_SEND_AND_RECV(udp_transport, OCTOCLOCK_QUERY_CMD, pkt_out, len, octoclock_data);          if(UHD_OCTOCLOCK_PACKET_MATCHES(OCTOCLOCK_QUERY_ACK, pkt_out, pkt_in, len) and @@ -292,22 +292,8 @@ void finalize(udp_simple::sptr udp_transport){  }  void octoclock_convert_ihex(const std::string &hex_path, const std::string &bin_path){ -    struct ihex_state ihex; -    ihex_count_t count; -    char buf[256]; -    FILE* infile = fopen(hex_path.c_str(), "r"); -    FILE* outfile = fopen(bin_path.c_str(), "w"); -    uint64_t line_number = 1; - -    ihex_begin_read(&ihex); -    while(fgets(buf, 256, infile)){ -        count = ihex_count_t(strlen(buf)); -        ihex_read_bytes(&ihex, buf, count, outfile); -        line_number += (count && buf[count - 1] == '\n'); -    } -    ihex_end_read(&ihex, outfile); // Closes outfile - -    (void)fclose(infile); +    ihex_reader hex_reader(hex_path); +    hex_reader.to_bin_file(bin_path);  }  int UHD_SAFE_MAIN(UHD_UNUSED(int argc), UHD_UNUSED(char *argv[])){ diff --git a/host/utils/uhd-usrp.rules b/host/utils/uhd-usrp.rules index e10c86f13..76bccfefa 100644 --- a/host/utils/uhd-usrp.rules +++ b/host/utils/uhd-usrp.rules @@ -24,5 +24,6 @@ SUBSYSTEMS=="usb", ATTRS{idVendor}=="2500", ATTRS{idProduct}=="0002", MODE:="066  #B200  SUBSYSTEMS=="usb", ATTRS{idVendor}=="2500", ATTRS{idProduct}=="0020", MODE:="0666"  SUBSYSTEMS=="usb", ATTRS{idVendor}=="2500", ATTRS{idProduct}=="0021", MODE:="0666" +SUBSYSTEMS=="usb", ATTRS{idVendor}=="2500", ATTRS{idProduct}=="0022", MODE:="0666"  SUBSYSTEMS=="usb", ATTRS{idVendor}=="3923", ATTRS{idProduct}=="7813", MODE:="0666"  SUBSYSTEMS=="usb", ATTRS{idVendor}=="3923", ATTRS{idProduct}=="7814", MODE:="0666"  | 
