From f90b62f3871fb701a8d9cb7c91c1a7f3421fced9 Mon Sep 17 00:00:00 2001 From: michael-west Date: Wed, 7 Oct 2015 13:10:01 -0700 Subject: B210: Add VITA time synchronization on internal signal --- host/lib/usrp/b200/b200_impl.cpp | 22 +++++++++++++++------- host/lib/usrp/b200/b200_impl.hpp | 1 + host/lib/usrp/b200/b200_regs.hpp | 2 +- 3 files changed, 17 insertions(+), 8 deletions(-) (limited to 'host/lib/usrp/b200') diff --git a/host/lib/usrp/b200/b200_impl.cpp b/host/lib/usrp/b200/b200_impl.cpp index ffce08567..a18e595a6 100644 --- a/host/lib/usrp/b200/b200_impl.cpp +++ b/host/lib/usrp/b200/b200_impl.cpp @@ -555,7 +555,7 @@ b200_impl::b200_impl(const uhd::device_addr_t& device_addr, usb_device_handle::s client_settings = boost::make_shared(); } _codec_ctrl = ad9361_ctrl::make_spi(client_settings, _spi_iface, AD9361_SLAVENO); - + //////////////////////////////////////////////////////////////////// // create codec control objects //////////////////////////////////////////////////////////////////// @@ -623,15 +623,15 @@ 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(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::sync_times, this, _1)) + .set(0.0); _tree->create(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(mb_path / "time" / "now") - .subscribe(boost::bind(&time_core_3000::set_time_now, _radio_perifs[i].time64, _1)); _tree->access(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 @@ -1074,11 +1074,19 @@ 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::sync_times(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); +} + /*********************************************************************** * GPIO setup **********************************************************************/ diff --git a/host/lib/usrp/b200/b200_impl.hpp b/host/lib/usrp/b200/b200_impl.hpp index 25fef7d4b..f052c55e6 100644 --- a/host/lib/usrp/b200/b200_impl.hpp +++ b/host/lib/usrp/b200/b200_impl.hpp @@ -167,6 +167,7 @@ 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 sync_times(const uhd::time_spec_t&); 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_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; -- cgit v1.2.3 From c1e6da087946b522018996267441b8555791dabd Mon Sep 17 00:00:00 2001 From: michael-west Date: Wed, 14 Oct 2015 14:10:25 -0700 Subject: B210/E300: Re-sync times after master clock rate change. --- host/lib/usrp/b200/b200_impl.cpp | 3 +++ host/lib/usrp/e300/e300_impl.cpp | 3 +++ 2 files changed, 6 insertions(+) (limited to 'host/lib/usrp/b200') diff --git a/host/lib/usrp/b200/b200_impl.cpp b/host/lib/usrp/b200/b200_impl.cpp index a18e595a6..dae90bbfe 100644 --- a/host/lib/usrp/b200/b200_impl.cpp +++ b/host/lib/usrp/b200/b200_impl.cpp @@ -626,6 +626,9 @@ b200_impl::b200_impl(const uhd::device_addr_t& device_addr, usb_device_handle::s .publish(boost::bind(&time_core_3000::get_time_now, _radio_perifs[0].time64)) .subscribe(boost::bind(&b200_impl::sync_times, this, _1)) .set(0.0); + //re-sync the times when the tick rate changes + _tree->access(mb_path / "tick_rate") + .subscribe(boost::bind(&b200_impl::sync_times, this, _radio_perifs[0].time64->get_time_now())); _tree->create(mb_path / "time" / "pps") .publish(boost::bind(&time_core_3000::get_time_last_pps, _radio_perifs[0].time64)); BOOST_FOREACH(radio_perifs_t &perif, _radio_perifs) diff --git a/host/lib/usrp/e300/e300_impl.cpp b/host/lib/usrp/e300/e300_impl.cpp index bf108e171..5cc274bbb 100644 --- a/host/lib/usrp/e300/e300_impl.cpp +++ b/host/lib/usrp/e300/e300_impl.cpp @@ -530,6 +530,9 @@ e300_impl::e300_impl(const uhd::device_addr_t &device_addr) .publish(boost::bind(&time_core_3000::get_time_now, _radio_perifs[0].time64)) .subscribe(boost::bind(&e300_impl::_sync_times, this, _1)) .set(0.0); + //re-sync the times when the tick rate changes + _tree->access(mb_path / "tick_rate") + .subscribe(boost::bind(&e300_impl::_sync_times, this, _radio_perifs[0].time64->get_time_now())); _tree->create(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)) -- cgit v1.2.3 From b9b83502771e5caa60fb336441fb0d5ed3fe9f1a Mon Sep 17 00:00:00 2001 From: michael-west Date: Thu, 15 Oct 2015 13:44:00 -0700 Subject: B200/E300: Set time sync on clock rate change to current time of first radio --- host/lib/usrp/b200/b200_impl.cpp | 11 ++++++++--- host/lib/usrp/b200/b200_impl.hpp | 3 ++- host/lib/usrp/e300/e300_impl.cpp | 11 ++++++++--- host/lib/usrp/e300/e300_impl.hpp | 3 ++- 4 files changed, 20 insertions(+), 8 deletions(-) (limited to 'host/lib/usrp/b200') diff --git a/host/lib/usrp/b200/b200_impl.cpp b/host/lib/usrp/b200/b200_impl.cpp index dae90bbfe..9a2c65680 100644 --- a/host/lib/usrp/b200/b200_impl.cpp +++ b/host/lib/usrp/b200/b200_impl.cpp @@ -624,11 +624,11 @@ 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(mb_path / "time" / "now") .publish(boost::bind(&time_core_3000::get_time_now, _radio_perifs[0].time64)) - .subscribe(boost::bind(&b200_impl::sync_times, this, _1)) + .subscribe(boost::bind(&b200_impl::set_time, this, _1)) .set(0.0); //re-sync the times when the tick rate changes _tree->access(mb_path / "tick_rate") - .subscribe(boost::bind(&b200_impl::sync_times, this, _radio_perifs[0].time64->get_time_now())); + .subscribe(boost::bind(&b200_impl::sync_times, this)); _tree->create(mb_path / "time" / "pps") .publish(boost::bind(&time_core_3000::get_time_last_pps, _radio_perifs[0].time64)); BOOST_FOREACH(radio_perifs_t &perif, _radio_perifs) @@ -1082,7 +1082,7 @@ void b200_impl::update_time_source(const std::string &source) } } -void b200_impl::sync_times(const uhd::time_spec_t& t) +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); @@ -1090,6 +1090,11 @@ void b200_impl::sync_times(const uhd::time_spec_t& t) _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 **********************************************************************/ diff --git a/host/lib/usrp/b200/b200_impl.hpp b/host/lib/usrp/b200/b200_impl.hpp index f052c55e6..4ddb29f0b 100644 --- a/host/lib/usrp/b200/b200_impl.hpp +++ b/host/lib/usrp/b200/b200_impl.hpp @@ -167,7 +167,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 sync_times(const uhd::time_spec_t&); + 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/e300/e300_impl.cpp b/host/lib/usrp/e300/e300_impl.cpp index 5cc274bbb..0003dddb0 100644 --- a/host/lib/usrp/e300/e300_impl.cpp +++ b/host/lib/usrp/e300/e300_impl.cpp @@ -528,11 +528,11 @@ e300_impl::e300_impl(const uhd::device_addr_t &device_addr) //////////////////////////////////////////////////////////////////// _tree->create(mb_path / "time" / "now") .publish(boost::bind(&time_core_3000::get_time_now, _radio_perifs[0].time64)) - .subscribe(boost::bind(&e300_impl::_sync_times, this, _1)) + .subscribe(boost::bind(&e300_impl::_set_time, this, _1)) .set(0.0); //re-sync the times when the tick rate changes _tree->access(mb_path / "tick_rate") - .subscribe(boost::bind(&e300_impl::_sync_times, this, _radio_perifs[0].time64->get_time_now())); + .subscribe(boost::bind(&e300_impl::_sync_times, this)); _tree->create(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)) @@ -829,7 +829,7 @@ void e300_impl::_update_time_source(const std::string &source) _update_gpio_state(); } -void e300_impl::_sync_times(const uhd::time_spec_t& t) +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); @@ -839,6 +839,11 @@ void e300_impl::_sync_times(const uhd::time_spec_t& t) _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) diff --git a/host/lib/usrp/e300/e300_impl.hpp b/host/lib/usrp/e300/e300_impl.hpp index 1f20726ea..764059c1b 100644 --- a/host/lib/usrp/e300/e300_impl.hpp +++ b/host/lib/usrp/e300/e300_impl.hpp @@ -260,7 +260,8 @@ private: // methods void _update_time_source(const std::string &source); void _update_clock_source(const std::string &); - void _sync_times(const uhd::time_spec_t&); + void _set_time(const uhd::time_spec_t&); + void _sync_times(void); void _update_subdev_spec( const std::string &txrx, -- cgit v1.2.3 From 9f9a55e1f59dfd1ff7c6580f4e8c7752ac87775b Mon Sep 17 00:00:00 2001 From: michael-west Date: Mon, 2 Nov 2015 16:05:01 -0800 Subject: Bumped FPGA compat numbers for B200, X300, and E300. --- host/lib/usrp/b200/b200_impl.hpp | 2 +- host/lib/usrp/e300/e300_fpga_defs.hpp | 2 +- host/lib/usrp/x300/x300_fw_common.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'host/lib/usrp/b200') diff --git a/host/lib/usrp/b200/b200_impl.hpp b/host/lib/usrp/b200/b200_impl.hpp index 4ddb29f0b..538ee8cd7 100644 --- a/host/lib/usrp/b200/b200_impl.hpp +++ b/host/lib/usrp/b200/b200_impl.hpp @@ -49,7 +49,7 @@ #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 = 11; +static const boost::uint16_t B200_FPGA_COMPAT_NUM = 12; static const boost::uint16_t B205_FPGA_COMPAT_NUM = 2; static const double B200_BUS_CLOCK_RATE = 100e6; static const boost::uint32_t B200_GPSDO_ST_NONE = 0x83; diff --git a/host/lib/usrp/e300/e300_fpga_defs.hpp b/host/lib/usrp/e300/e300_fpga_defs.hpp index a8fa60d9d..3b21468ba 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 = 11; +static const boost::uint32_t COMPAT_MAJOR = 12; static const boost::uint32_t COMPAT_MINOR = 0; }}}} // namespace diff --git a/host/lib/usrp/x300/x300_fw_common.h b/host/lib/usrp/x300/x300_fw_common.h index 1b88db69a..dc9e6eba1 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 15 +#define X300_FPGA_COMPAT_MAJOR 16 //shared memory sections - in between the stack and the program space #define X300_FW_SHMEM_BASE 0x6000 -- cgit v1.2.3 From bf634e1e902f535ca1ddb4f4a25c84c066018b17 Mon Sep 17 00:00:00 2001 From: Ashish Chaudhari Date: Tue, 24 Nov 2015 12:01:37 -0800 Subject: b2xx,e3xx,x300: Bumped FPGA compat numbers after SW time-sync changes - b200: compat 13 - b200mini: compat 4 - e3xx: compat 14 - x3xx: compat 19 --- host/lib/usrp/b200/b200_impl.hpp | 4 ++-- host/lib/usrp/e300/e300_fpga_defs.hpp | 2 +- host/lib/usrp/x300/x300_fw_common.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'host/lib/usrp/b200') diff --git a/host/lib/usrp/b200/b200_impl.hpp b/host/lib/usrp/b200/b200_impl.hpp index 538ee8cd7..041c8bcb2 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 = 2; +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 diff --git a/host/lib/usrp/e300/e300_fpga_defs.hpp b/host/lib/usrp/e300/e300_fpga_defs.hpp index 3b21468ba..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 = 12; +static const boost::uint32_t COMPAT_MAJOR = 14; static const boost::uint32_t COMPAT_MINOR = 0; }}}} // namespace diff --git a/host/lib/usrp/x300/x300_fw_common.h b/host/lib/usrp/x300/x300_fw_common.h index dc9e6eba1..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 16 +#define X300_FPGA_COMPAT_MAJOR 19 //shared memory sections - in between the stack and the program space #define X300_FW_SHMEM_BASE 0x6000 -- cgit v1.2.3 From ac1db2c4605427fa7e8929422c647004a4333e59 Mon Sep 17 00:00:00 2001 From: michael-west Date: Fri, 20 Nov 2015 12:23:09 -0800 Subject: B2xx: Added B205mini support. - Add support to b200_impl - New INF file - Removed references to old 'B205' name --- host/cmake/msvc/erllc_uhd_b205mini.inf | 175 +++++++++++++++++++++++++++++++++ host/lib/usrp/b200/b200_iface.hpp | 45 +++++---- host/lib/usrp/b200/b200_impl.cpp | 30 +++--- host/lib/usrp/b200/b200_impl.hpp | 3 +- host/lib/usrp/b200/b200_io_impl.cpp | 3 +- host/utils/b2xx_fx3_utils.cpp | 5 +- 6 files changed, 224 insertions(+), 37 deletions(-) create mode 100644 host/cmake/msvc/erllc_uhd_b205mini.inf (limited to 'host/lib/usrp/b200') 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.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 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 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 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 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 9a2c65680..38709bbb3 100644 --- a/host/lib/usrp/b200/b200_impl.cpp +++ b/host/lib/usrp/b200/b200_impl.cpp @@ -74,9 +74,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 @@ -318,7 +318,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)); } @@ -332,7 +333,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)); } @@ -386,7 +388,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 @@ -405,7 +407,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 @@ -512,7 +514,7 @@ b200_impl::b200_impl(const uhd::device_addr_t& device_addr, usb_device_handle::s //////////////////////////////////////////////////////////////////// _tree->create("/name").set("B-Series Device"); _tree->create(mb_path / "name").set(product_name); - _tree->create(mb_path / "codename").set((_product == B205) ? "Pixie" : "Sasquatch"); + _tree->create(mb_path / "codename").set((_product == B200MINI or _product == B205MINI) ? "Pixie" : "Sasquatch"); //////////////////////////////////////////////////////////////////// // Create data transport @@ -540,7 +542,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(_spi_iface); } @@ -549,8 +551,8 @@ 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(); + if (_product == B200MINI or _product == B205MINI) { + client_settings = boost::make_shared(); } else { client_settings = boost::make_shared(); } @@ -949,7 +951,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( @@ -995,7 +997,7 @@ void b200_impl::set_fp_gpio(gpio_core_200::sptr gpio, const gpio_attr_t attr, co 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) { @@ -1057,7 +1059,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"); } @@ -1102,7 +1104,7 @@ void b200_impl::sync_times() 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 041c8bcb2..22dd231ce 100644 --- a/host/lib/usrp/b200/b200_impl.hpp +++ b/host/lib/usrp/b200/b200_impl.hpp @@ -95,7 +95,8 @@ static const unsigned char B200_USB_DATA_SEND_ENDPOINT = 2; static std::vector 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)) ; diff --git a/host/lib/usrp/b200/b200_io_impl.cpp b/host/lib/usrp/b200/b200_io_impl.cpp index 7fcd04823..5b0c4ba13 100644 --- a/host/lib/usrp/b200/b200_io_impl.cpp +++ b/host/lib/usrp/b200/b200_io_impl.cpp @@ -228,7 +228,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/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) -- cgit v1.2.3 From 4cc09da892141fc08c33eec6cc168bccdb6b84ac Mon Sep 17 00:00:00 2001 From: Martin Braun Date: Wed, 25 Nov 2015 10:25:54 -0800 Subject: b200: Factored ihex routines out of b200_iface --- host/lib/usrp/b200/b200_iface.cpp | 183 ++++------------------------- host/lib/utils/CMakeLists.txt | 1 + host/lib/utils/ihex.cpp | 236 ++++++++++++++++++++++++++++++++++++++ host/lib/utils/ihex.hpp | 79 +++++++++++++ 4 files changed, 339 insertions(+), 160 deletions(-) create mode 100644 host/lib/utils/ihex.cpp create mode 100644 host/lib/utils/ihex.hpp (limited to 'host/lib/usrp/b200') 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 #include #include @@ -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/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..bb9b49b32 --- /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 . +// + +#include "ihex.hpp" +#include +#include +#include +#include +#include + +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 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 output_file(boost::make_shared()); + 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 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 ihex_reader::to_vector(const size_t size_estimate) +{ + std::vector buf; + buf.reserve(size_estimate == 0 ? DEFAULT_SIZE_ESTIMATE : size_estimate); + + this->read(boost::bind(&_vector_writer_callback, 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 . +// + +#ifndef INCLUDED_IHEX_READER_HPP +#define INCLUDED_IHEX_READER_HPP + +#include +#include +#include +#include +#include + +namespace uhd { + +class ihex_reader +{ +public: + // Arguments are: lower address bits, upper address bits, buff, length + typedef boost::function 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 to_vector(const size_t size_estimate = 0); + +private: + const std::string _ihex_filename; +}; + +}; /* namespace uhd */ + +#endif /* INCLUDED_IHEX_READER_HPP */ + -- cgit v1.2.3