//
// Copyright 2010-2013 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
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
namespace po = boost::program_options;
namespace fs = boost::filesystem;
//!used with lexical cast to parse a hex string
template struct to_hex{
T value;
operator T() const {return value;}
friend std::istream& operator>>(std::istream& in, to_hex& out){
in >> std::hex >> out.value;
return in;
}
};
//!parse hex-formatted ASCII text into an int
boost::uint16_t atoh(const std::string &string){
if (string.substr(0, 2) == "0x"){
return boost::lexical_cast >(string);
}
return boost::lexical_cast(string);
}
boost::int32_t main(boost::int32_t argc, char *argv[]) {
boost::uint16_t vid, pid;
std::string pid_str, vid_str, fw_file, fpga_file;
po::options_description visible("Allowed options");
visible.add_options()
("help,h", "help message")
("vid,v", po::value(&vid_str),
"Specify VID of device to use.")
("pid,p", po::value(&pid_str),
"Specify PID of device to use.")
("speed,S", "Read back the USB mode currently in use.")
("reset-device,D", "Reset the B2xx Device.")
("reset-fpga,F", "Reset the FPGA (does not require re-programming.")
("reset-usb,U", "Reset the USB subsystem on your host computer.")
("init-device,I", "Initialize a B2xx device.")
("load-fw,W", po::value(&fw_file),
"Load a firmware (hex) file into the FX3.")
("load-fpga,L", po::value(&fpga_file),
"Load a FPGA (bin) file into the FPGA.")
;
// Hidden options provided for testing - use at your own risk!
po::options_description hidden("Hidden options");
hidden.add_options()
("uninit-device,U", "Uninitialize a B2xx device.")
("read-eeprom,R", "Read first 8 bytes of EEPROM")
("erase-eeprom,E", "Erase first 8 bytes of EEPROM");
po::options_description desc;
desc.add(visible);
desc.add(hidden);
po::variables_map vm;
po::store(po::parse_command_line(argc, argv, desc), vm);
po::notify(vm);
if (vm.count("help")){
std::cout << boost::format("B2xx Utilitiy Program %s") % desc << std::endl;
return ~0;
} else if (vm.count("reset-usb")) {
/* Okay, first, we need to discover what the path is to the ehci and
* xhci device files. */
std::set path_list;
path_list.insert("/sys/bus/pci/drivers/xhci-pci/");
path_list.insert("/sys/bus/pci/drivers/ehci-pci/");
path_list.insert("/sys/bus/pci/drivers/xhci_hcd/");
path_list.insert("/sys/bus/pci/drivers/ehci_hcd/");
/* Check each of the possible paths above to find which ones this system
* uses. */
for(std::set::iterator found = path_list.begin();
found != path_list.end(); ++found) {
if(fs::exists(*found)) {
fs::path devpath = *found;
std::set globbed;
/* Now, glob all of the files in the directory. */
fs::directory_iterator end_itr;
for(fs::directory_iterator itr(devpath); itr != end_itr; ++itr) {
globbed.insert((*itr).path());
}
/* Check each file path string to see if it is a device file. */
for(std::set::iterator it = globbed.begin();
it != globbed.end(); ++it) {
std::string file = fs::path((*it).filename()).string();
if(file.compare(0, 5, "0000:") == 0) {
/* Un-bind the device. */
std::fstream unbind((devpath.string() + "unbind").c_str(),
std::fstream::out);
unbind << file;
unbind.close();
/* Re-bind the device. */
std::cout << "Re-binding: " << file << " in "
<< devpath.string() << std::endl;
std::fstream bind((devpath.string() + "bind").c_str(),
std::fstream::out);
bind << file;
bind.close();
}
}
}
}
return 0;
}
std::vector handles;
uhd::transport::usb_device_handle::sptr handle;
uhd::transport::usb_control::sptr usb_ctrl;
b200_iface::sptr b200;
vid = B200_VENDOR_ID; // Default
pid = B200_PRODUCT_ID; // Default
if (vm.count("vid"))
vid = atoh(vid_str);
if (vm.count("pid"))
pid = atoh(pid_str);
// Added for testing purposes - not exposed
if (vm.count("read-eeprom")) {
uhd::byte_vector_t data;
handles = uhd::transport::usb_device_handle::get_device_list(vid, pid);
if (handles.size() == 0) {
std::cerr << "Cannot find device with vid: " << boost::format("0x%X") % vid << " and pid: "
<< boost::format("0x%X") % pid << std::endl;
return -1;
}
usb_ctrl = uhd::transport::usb_control::make(handles[0], 0);
b200 = b200_iface::make(usb_ctrl);
if (!(handles[0]->firmware_loaded()))
{
b200->load_firmware(fw_file);
// Now that the firmware is loaded, we need to re-open the device
handles.clear();
handles = uhd::transport::usb_device_handle::get_device_list(vid, pid);
if (handles.size() == 0) {
std::cerr << "Unable to reopen device with vid: " << boost::format("0x%X") % vid << " and pid: "
<< boost::format("0x%X") % pid << std::endl;
return -1;
}
usb_ctrl = uhd::transport::usb_control::make(handles[0], 0);
b200 = b200_iface::make(usb_ctrl);
}
try {
data = b200->read_eeprom(0x0, 0x0, 8);
} catch (std::exception &e) {
std::cerr << "Exception while reading EEPROM: " << e.what() << std::endl;
return -1;
}
for (int i = 0; i < 8; i++)
std::cout << i << ": " << boost::format("0x%X") % (int)data[i] << std::endl;
return 0;
}
// Added for testing purposes - not exposed
if (vm.count("erase-eeprom")) {
if (vm.count("vid") && vm.count("pid"))
handles = uhd::transport::usb_device_handle::get_device_list(vid, pid); // try user defined VID/PID first
if (handles.size() == 0)
handles = uhd::transport::usb_device_handle::get_device_list(FX3_VID, FX3_DEFAULT_PID); // try default FX3 VID/PID next
if (handles.size() == 0)
handles = uhd::transport::usb_device_handle::get_device_list(FX3_VID, FX3_REENUM_PID); // try reenumerated FX3 VID/PID next
if (handles.size() == 0)
handles = uhd::transport::usb_device_handle::get_device_list(B200_VENDOR_ID, B200_PRODUCT_ID); // try default B200 VID/PID next
if (handles.size() == 0) {
std::cerr << "Cannot find device" << std::endl;
return -1;
}
usb_ctrl = uhd::transport::usb_control::make(handles[0], 0);
b200 = b200_iface::make(usb_ctrl);
if (!(handles[0]->firmware_loaded()))
{
// load FW
b200->load_firmware(fw_file);
// re-open device
handles.clear();
if (vm.count("vid") && vm.count("pid"))
handles = uhd::transport::usb_device_handle::get_device_list(vid, pid); // try user defined VID/PID first
if (handles.size() == 0)
handles = uhd::transport::usb_device_handle::get_device_list(FX3_VID, FX3_DEFAULT_PID); // try default FX3 VID/PID next
if (handles.size() == 0)
handles = uhd::transport::usb_device_handle::get_device_list(FX3_VID, FX3_REENUM_PID); // try reenumerated FX3 VID/PID next
if (handles.size() == 0)
handles = uhd::transport::usb_device_handle::get_device_list(B200_VENDOR_ID, B200_PRODUCT_ID); // try default B200 VID/PID next
if (handles.size() == 0) {
std::cerr << "Cannot find device" << std::endl;
return -1;
}
usb_ctrl = uhd::transport::usb_control::make(handles[0], 0);
b200 = b200_iface::make(usb_ctrl);
}
uhd::byte_vector_t bytes(8);
bytes[0] = 0xFF;
bytes[1] = 0xFF;
bytes[2] = 0xFF;
bytes[3] = 0xFF;
bytes[4] = 0xFF;
bytes[5] = 0xFF;
bytes[6] = 0xFF;
bytes[7] = 0xFF;
try {
b200->write_eeprom(0x0, 0x0, bytes);
} catch (uhd::exception &e) {
std::cerr << "Exception while writing to EEPROM: " << e.what() << std::endl;
return -1;
}
// verify
uhd::byte_vector_t read_bytes(8);
try {
read_bytes = b200->read_eeprom(0x0, 0x0, 8);
} catch (uhd::exception &e) {
std::cerr << "Exception while reading from EEPROM: " << e.what() << std::endl;
return -1;
}
bool verified = true;
for (int i = 0; i < 8; i++) {
if (bytes[i] != read_bytes[i]) {
verified = false;
std::cerr << "Expected: " << bytes[i] << ", Got: " << read_bytes[i] << std::endl;
}
}
if (!verified) {
std::cerr << "Verification failed" << std::endl;
return -1;
}
std::cout << "Erase Successful!" << std::endl;
return 0;
}
// Added for testing purposes - not exposed
if (vm.count("uninit-device")) {
handles = uhd::transport::usb_device_handle::get_device_list(vid, pid);
if (handles.size() == 0) {
std::cerr << "Cannot find device with vid: " << boost::format("0x%X") % vid << " and pid: "
<< boost::format("0x%X") % pid << std::endl;
return -1;
}
std::cout << "Initialized B2xx detected..." << std::flush;
usb_ctrl = uhd::transport::usb_control::make(handles[0], 0);
b200 = b200_iface::make(usb_ctrl);
std::cout << " Control of B2xx granted..." << std::endl << std::endl;
if (!(handles[0]->firmware_loaded()))
{
b200->load_firmware(fw_file);
// Now that the firmware is loaded, we need to re-open the device
handles.clear();
handles = uhd::transport::usb_device_handle::get_device_list(vid, pid);
if (handles.size() == 0) {
std::cerr << "Unable to reopen device with vid: " << boost::format("0x%X") % vid << " and pid: "
<< boost::format("0x%X") % pid << std::endl;
return -1;
}
usb_ctrl = uhd::transport::usb_control::make(handles[0], 0);
b200 = b200_iface::make(usb_ctrl);
}
/* Now, uninitialize the device. */
uhd::byte_vector_t bytes(8);
bytes[0] = 0xFF;
bytes[1] = 0xFF;
bytes[2] = 0xFF;
bytes[3] = 0xFF;
bytes[4] = 0xFF;
bytes[5] = 0xFF;
bytes[6] = 0xFF;
bytes[7] = 0xFF;
try {
b200->write_eeprom(0x0, 0x0, bytes);
} catch (uhd::exception &e) {
std::cerr << "Exception while writing to EEPROM: " << e.what() << std::endl;
return -1;
}
std::cout << "EEPROM uninitialized, resetting device..."
<< std::endl << std::endl;
/* Reset the device! */
try {
b200->reset_fx3();
} catch (uhd::exception &e) {
std::cerr << "Exception while resetting FX3: " << e.what() << std::endl;
return -1;
}
std::cout << "Uninitialization Process Complete."
<< std::endl << std::endl;
return 0;
}
/* If we are initializing the device, the VID/PID should default to the
* Cypress VID/PID for the initial FW load, but we can initialize from any state. */
if (vm.count("init-device")) {
if (vm.count("vid") && vm.count("pid"))
handles = uhd::transport::usb_device_handle::get_device_list(vid, pid); // try user defined VID/PID first
if (handles.size() == 0)
handles = uhd::transport::usb_device_handle::get_device_list(FX3_VID, FX3_DEFAULT_PID); // try default FX3 VID/PID next
if (handles.size() == 0)
handles = uhd::transport::usb_device_handle::get_device_list(FX3_VID, FX3_REENUM_PID); // try reenumerated FX3 VID/PID next
if (handles.size() == 0)
handles = uhd::transport::usb_device_handle::get_device_list(B200_VENDOR_ID, B200_PRODUCT_ID); // try default B200 VID/PID next
if (handles.size() == 0) {
std::cerr << "Cannot find device" << std::endl;
return -1;
}
std::cout << "Uninitialized B2xx detected..." << std::flush;
usb_ctrl = uhd::transport::usb_control::make(handles[0], 0);
b200 = b200_iface::make(usb_ctrl);
std::cout << " Control of B2xx granted..." << std::endl << std::endl;
if (!(handles[0]->firmware_loaded()))
{
// load FW
b200->load_firmware(fw_file);
// re-open device
handles.clear();
if (vm.count("vid") && vm.count("pid"))
handles = uhd::transport::usb_device_handle::get_device_list(vid, pid); // try user defined VID/PID first
if (handles.size() == 0)
handles = uhd::transport::usb_device_handle::get_device_list(FX3_VID, FX3_DEFAULT_PID); // try default FX3 VID/PID next
if (handles.size() == 0)
handles = uhd::transport::usb_device_handle::get_device_list(FX3_VID, FX3_REENUM_PID); // try reenumerated FX3 VID/PID next
if (handles.size() == 0)
handles = uhd::transport::usb_device_handle::get_device_list(B200_VENDOR_ID, B200_PRODUCT_ID); // try default B200 VID/PID next
if (handles.size() == 0) {
std::cerr << "Cannot find device" << std::endl;
return -1;
}
usb_ctrl = uhd::transport::usb_control::make(handles[0], 0);
b200 = b200_iface::make(usb_ctrl);
}
/* Now, initialize the device. */
uhd::byte_vector_t bytes(8);
bytes[0] = 0x43;
bytes[1] = 0x59;
bytes[2] = 0x14;
bytes[3] = 0xB2;
bytes[4] = (B200_PRODUCT_ID & 0xff);
bytes[5] = (B200_PRODUCT_ID >> 8);
bytes[6] = (B200_VENDOR_ID & 0xff);
bytes[7] = (B200_VENDOR_ID >> 8);
try {
b200->write_eeprom(0x0, 0x0, bytes);
} catch (uhd::exception &e) {
std::cerr << "Exception while writing to EEPROM: " << e.what() << std::endl;
return -1;
}
std::cout << "EEPROM initialized, resetting device..."
<< std::endl << std::endl;
/* Reset the device! */
try {
b200->reset_fx3();
} catch (const std::exception &e) {
std::cerr << "Exceptions while resetting device: " << e.what() << std::endl;
return -1;
}
std::cout << "Initialization Process Complete."
<< std::endl << std::endl;
return 0;
}
// open device for all other operations
handles = uhd::transport::usb_device_handle::get_device_list(vid, pid);
if (handles.size() == 0) {
std::cerr << "Cannot find device with vid: " << boost::format("0x%X") % vid << " and pid: "
<< boost::format("0x%X") % pid << std::endl;
return -1;
}
std::cout << "Reactor Core Online..." << std::flush;
usb_ctrl = uhd::transport::usb_control::make(handles[0], 0);
b200 = b200_iface::make(usb_ctrl);
std::cout << " All Systems Nominal..." << std::endl << std::endl;
boost::uint8_t data_buffer[16];
memset(data_buffer, 0x0, sizeof(data_buffer));
if (vm.count("speed")){
boost::uint8_t speed;
try {speed = b200->get_usb_speed();}
catch (uhd::exception &e) {
std::cerr << "Exception while getting USB speed: " << e.what() << std::endl;
return -1;
}
std::cout << "Currently operating at USB " << (int) speed << std::endl;
} else if (vm.count("reset-device")) {
try {b200->reset_fx3();}
catch (uhd::exception &e) {
std::cerr << "Exception while resetting FX3: " << e.what() << std::endl;
return -1;
}
} else if (vm.count("reset-fpga")) {
try {b200->set_fpga_reset_pin(true);}
catch (uhd::exception &e) {
std::cerr << "Exception while resetting FPGA: " << e.what() << std::endl;
return -1;
}
} else if (vm.count("load-fw")) {
std::cout << "Loading firmware" << std::endl;
try {b200->load_firmware(fw_file);}
catch (uhd::exception &e) {
std::cerr << "Exception while loading firmware: " << e.what() << std::endl;
return ~0;
}
std::cout << "Firmware load complete, releasing USB interface..."
<< std::endl;
} else if (vm.count("load-fpga")) {
std::cout << "Loading FPGA image (" << fpga_file << ")" << std::endl;
uint32_t fx3_state;
try {fx3_state = b200->load_fpga(fpga_file);} // returns 0 on success, or FX3 state on error
catch (uhd::exception &e) {
std::cerr << "Exception while resetting FPGA: " << e.what() << std::endl;
return ~0;
}
if (fx3_state != 0) {
std::cerr << std::flush << "Error loading FPGA. FX3 state: "
<< fx3_state << std::endl;
return ~0;
}
std::cout << "FPGA load complete, releasing USB interface..."
<< std::endl;
} else {
std::cout << boost::format("B2xx Utilitiy Program %s") % desc << std::endl;
return ~0;
}
std::cout << std::endl << "Reactor Shutting Down..." << std::endl;
return 0;
}