//
// Copyright 2010 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 "dboard_ctor_args.hpp"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace uhd;
using namespace uhd::usrp;
/***********************************************************************
* storage and registering for dboards
**********************************************************************/
//dboard registry tuple: dboard constructor, canonical name, subdev names
typedef boost::tuple args_t;
//map a dboard id to a dboard constructor
typedef uhd::dict id_to_args_map_t;
UHD_SINGLETON_FCN(id_to_args_map_t, get_id_to_args_map)
void dboard_manager::register_dboard(
const dboard_id_t &dboard_id,
dboard_ctor_t dboard_ctor,
const std::string &name,
const prop_names_t &subdev_names
){
//std::cout << "registering: " << name << std::endl;
if (get_id_to_args_map().has_key(dboard_id)){
throw std::runtime_error(str(boost::format(
"The dboard id %s is already registered to %s."
) % dboard_id.to_string() % dboard_id.to_pp_string()));
}
get_id_to_args_map()[dboard_id] = args_t(dboard_ctor, name, subdev_names);
}
//map an xcvr dboard id to its partner dboard id
typedef uhd::dict xcvr_id_to_id_map_t;
UHD_SINGLETON_FCN(xcvr_id_to_id_map_t, get_xcvr_id_to_id_map)
void dboard_manager::register_dboard(
const dboard_id_t &rx_dboard_id,
const dboard_id_t &tx_dboard_id,
dboard_ctor_t dboard_ctor,
const std::string &name,
const prop_names_t &subdev_names
){
//regular registration for ids
register_dboard(rx_dboard_id, dboard_ctor, name + " RX", subdev_names);
register_dboard(tx_dboard_id, dboard_ctor, name + " TX", subdev_names);
//register xcvr mapping for ids
get_xcvr_id_to_id_map()[rx_dboard_id] = tx_dboard_id;
get_xcvr_id_to_id_map()[tx_dboard_id] = rx_dboard_id;
}
std::string dboard_id_t::to_pp_string(void) const{
std::string name = "unknown";
if (get_id_to_args_map().has_key(*this)){
name = get_id_to_args_map()[*this].get<1>();
}
return str(boost::format("%s (%s)") % name % this->to_string());
}
/***********************************************************************
* internal helper classe
**********************************************************************/
/*!
* A special wax proxy object that forwards calls to a subdev.
* A sptr to an instance will be used in the properties structure.
*/
class subdev_proxy : boost::noncopyable, public wax::obj{
public:
typedef boost::shared_ptr sptr;
enum type_t{RX_TYPE, TX_TYPE};
//structors
subdev_proxy(dboard_base::sptr subdev, type_t type)
: _subdev(subdev), _type(type){
//initialize gain props struct
gain_handler::props_t gain_props;
gain_props.value = SUBDEV_PROP_GAIN;
gain_props.range = SUBDEV_PROP_GAIN_RANGE;
gain_props.names = SUBDEV_PROP_GAIN_NAMES;
//make a new gain handler
_gain_handler = gain_handler::make(
this->get_link(), gain_props,
boost::bind(&gain_handler::is_equal, _1, _2)
);
}
~subdev_proxy(void){
/* NOP */
}
private:
gain_handler::sptr _gain_handler;
dboard_base::sptr _subdev;
type_t _type;
//forward the get calls to the rx or tx
void get(const wax::obj &key, wax::obj &val){
if (_gain_handler->intercept_get(key, val)) return;
switch(_type){
case RX_TYPE: return _subdev->rx_get(key, val);
case TX_TYPE: return _subdev->tx_get(key, val);
}
}
//forward the set calls to the rx or tx
void set(const wax::obj &key, const wax::obj &val){
if (_gain_handler->intercept_set(key, val)) return;
switch(_type){
case RX_TYPE: return _subdev->rx_set(key, val);
case TX_TYPE: return _subdev->tx_set(key, val);
}
}
};
/***********************************************************************
* dboard manager implementation class
**********************************************************************/
class dboard_manager_impl : public dboard_manager{
public:
dboard_manager_impl(
dboard_id_t rx_dboard_id,
dboard_id_t tx_dboard_id,
dboard_iface::sptr iface
);
~dboard_manager_impl(void);
//dboard_iface
prop_names_t get_rx_subdev_names(void);
prop_names_t get_tx_subdev_names(void);
wax::obj get_rx_subdev(const std::string &subdev_name);
wax::obj get_tx_subdev(const std::string &subdev_name);
private:
//list of rx and tx dboards in this dboard_manager
//each dboard here is actually a subdevice proxy
//the subdevice proxy is internal to the cpp file
uhd::dict _rx_dboards;
uhd::dict _tx_dboards;
dboard_iface::sptr _iface;
void set_nice_dboard_if(void);
};
/***********************************************************************
* make routine for dboard manager
**********************************************************************/
dboard_manager::sptr dboard_manager::make(
dboard_id_t rx_dboard_id,
dboard_id_t tx_dboard_id,
dboard_iface::sptr iface
){
return dboard_manager::sptr(
new dboard_manager_impl(rx_dboard_id, tx_dboard_id, iface)
);
}
/***********************************************************************
* implementation class methods
**********************************************************************/
static args_t get_dboard_args(
dboard_iface::unit_t unit,
dboard_id_t dboard_id,
bool force_to_unknown = false
){
//special case, the none id was provided, use the following ids
if (dboard_id == dboard_id_t::none() or force_to_unknown){
std::cerr << boost::format(
"Warning: unknown dboard-id or dboard-id combination: %s\n"
" -> defaulting to the unknown board type"
) % dboard_id.to_pp_string() << std::endl;
UHD_ASSERT_THROW(get_id_to_args_map().has_key(0xfff1));
UHD_ASSERT_THROW(get_id_to_args_map().has_key(0xfff0));
switch(unit){
case dboard_iface::UNIT_RX: return get_dboard_args(unit, 0xfff1);
case dboard_iface::UNIT_TX: return get_dboard_args(unit, 0xfff0);
default: UHD_THROW_INVALID_CODE_PATH();
}
}
//verify that there is a registered constructor for this id
if (not get_id_to_args_map().has_key(dboard_id)){
return get_dboard_args(unit, dboard_id, true);
}
//return the dboard args for this id
return get_id_to_args_map()[dboard_id];
}
dboard_manager_impl::dboard_manager_impl(
dboard_id_t rx_dboard_id,
dboard_id_t tx_dboard_id,
dboard_iface::sptr iface
){
_iface = iface;
//determine xcvr status
bool rx_dboard_is_xcvr = get_xcvr_id_to_id_map().has_key(rx_dboard_id);
bool tx_dboard_is_xcvr = get_xcvr_id_to_id_map().has_key(tx_dboard_id);
bool this_dboard_is_xcvr = (
rx_dboard_is_xcvr and tx_dboard_is_xcvr and
(get_xcvr_id_to_id_map()[rx_dboard_id] == tx_dboard_id) and
(get_xcvr_id_to_id_map()[tx_dboard_id] == rx_dboard_id)
);
//extract dboard constructor and settings (force to unknown for messed up xcvr status)
dboard_ctor_t rx_dboard_ctor; std::string rx_name; prop_names_t rx_subdevs;
boost::tie(rx_dboard_ctor, rx_name, rx_subdevs) = get_dboard_args(dboard_iface::UNIT_RX, rx_dboard_id, rx_dboard_is_xcvr != this_dboard_is_xcvr);
dboard_ctor_t tx_dboard_ctor; std::string tx_name; prop_names_t tx_subdevs;
boost::tie(tx_dboard_ctor, tx_name, tx_subdevs) = get_dboard_args(dboard_iface::UNIT_TX, tx_dboard_id, tx_dboard_is_xcvr != this_dboard_is_xcvr);
//initialize the gpio pins before creating subdevs
set_nice_dboard_if();
//dboard constructor args
dboard_ctor_args_t db_ctor_args;
db_ctor_args.db_iface = iface;
//make xcvr subdevs (make one subdev for both rx and tx dboards)
if (this_dboard_is_xcvr){
UHD_ASSERT_THROW(rx_dboard_ctor == tx_dboard_ctor);
UHD_ASSERT_THROW(rx_subdevs == tx_subdevs);
BOOST_FOREACH(const std::string &subdev, rx_subdevs){
db_ctor_args.sd_name = subdev;
db_ctor_args.rx_id = rx_dboard_id;
db_ctor_args.tx_id = tx_dboard_id;
dboard_base::sptr xcvr_dboard = rx_dboard_ctor(&db_ctor_args);
//create a rx proxy for this xcvr board
_rx_dboards[subdev] = subdev_proxy::sptr(
new subdev_proxy(xcvr_dboard, subdev_proxy::RX_TYPE)
);
//create a tx proxy for this xcvr board
_tx_dboards[subdev] = subdev_proxy::sptr(
new subdev_proxy(xcvr_dboard, subdev_proxy::TX_TYPE)
);
}
}
//make tx and rx subdevs (separate subdevs for rx and tx dboards)
else{
//make the rx subdevs
BOOST_FOREACH(const std::string &subdev, rx_subdevs){
db_ctor_args.sd_name = subdev;
db_ctor_args.rx_id = rx_dboard_id;
db_ctor_args.tx_id = dboard_id_t::none();
dboard_base::sptr rx_dboard = rx_dboard_ctor(&db_ctor_args);
//create a rx proxy for this rx board
_rx_dboards[subdev] = subdev_proxy::sptr(
new subdev_proxy(rx_dboard, subdev_proxy::RX_TYPE)
);
}
//make the tx subdevs
BOOST_FOREACH(const std::string &subdev, tx_subdevs){
db_ctor_args.sd_name = subdev;
db_ctor_args.rx_id = dboard_id_t::none();
db_ctor_args.tx_id = tx_dboard_id;
dboard_base::sptr tx_dboard = tx_dboard_ctor(&db_ctor_args);
//create a tx proxy for this tx board
_tx_dboards[subdev] = subdev_proxy::sptr(
new subdev_proxy(tx_dboard, subdev_proxy::TX_TYPE)
);
}
}
}
dboard_manager_impl::~dboard_manager_impl(void){
set_nice_dboard_if();
}
prop_names_t dboard_manager_impl::get_rx_subdev_names(void){
return _rx_dboards.keys();
}
prop_names_t dboard_manager_impl::get_tx_subdev_names(void){
return _tx_dboards.keys();
}
wax::obj dboard_manager_impl::get_rx_subdev(const std::string &subdev_name){
if (not _rx_dboards.has_key(subdev_name)) throw std::invalid_argument(
str(boost::format("Unknown rx subdev name %s") % subdev_name)
);
//get a link to the rx subdev proxy
return _rx_dboards[subdev_name]->get_link();
}
wax::obj dboard_manager_impl::get_tx_subdev(const std::string &subdev_name){
if (not _tx_dboards.has_key(subdev_name)) throw std::invalid_argument(
str(boost::format("Unknown tx subdev name %s") % subdev_name)
);
//get a link to the tx subdev proxy
return _tx_dboards[subdev_name]->get_link();
}
void dboard_manager_impl::set_nice_dboard_if(void){
//make a list of possible unit types
std::vector units = boost::assign::list_of
(dboard_iface::UNIT_RX)
(dboard_iface::UNIT_TX)
;
//set nice settings on each unit
BOOST_FOREACH(dboard_iface::unit_t unit, units){
_iface->set_gpio_ddr(unit, 0x0000); //all inputs
_iface->write_gpio(unit, 0x0000); //all low
_iface->set_pin_ctrl(unit, 0x0000); //all gpio
_iface->set_clock_enabled(unit, false); //clock off
}
}