summaryrefslogtreecommitdiffstats
path: root/host/lib/simple_device.cpp
diff options
context:
space:
mode:
authorJosh Blum <josh@joshknows.com>2010-03-10 14:47:03 -0800
committerJosh Blum <josh@joshknows.com>2010-03-10 14:47:03 -0800
commit8e9a8464386db03a596e0b88d0714d22723d37d0 (patch)
treede6a35865ba1d54bb4d908d86397aeba459b3e01 /host/lib/simple_device.cpp
parentbb86022d5a5f7055cdeebaeb4a55216e1a056fd4 (diff)
downloaduhd-8e9a8464386db03a596e0b88d0714d22723d37d0.tar.gz
uhd-8e9a8464386db03a596e0b88d0714d22723d37d0.tar.bz2
uhd-8e9a8464386db03a596e0b88d0714d22723d37d0.zip
Added simple device to handle wrapping general properties up into simple api.
Added setting time capability to the usrp2 impl. Messing with props and time specs...
Diffstat (limited to 'host/lib/simple_device.cpp')
-rw-r--r--host/lib/simple_device.cpp303
1 files changed, 303 insertions, 0 deletions
diff --git a/host/lib/simple_device.cpp b/host/lib/simple_device.cpp
new file mode 100644
index 000000000..63a17c52d
--- /dev/null
+++ b/host/lib/simple_device.cpp
@@ -0,0 +1,303 @@
+//
+// 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 <http://www.gnu.org/licenses/>.
+//
+
+#include <uhd/simple_device.hpp>
+#include <uhd/device.hpp>
+#include <uhd/utils.hpp>
+#include <uhd/props.hpp>
+#include <boost/algorithm/string.hpp>
+#include <boost/algorithm/string/trim.hpp>
+#include <boost/foreach.hpp>
+#include <boost/format.hpp>
+#include <stdexcept>
+
+using namespace uhd;
+
+tune_result_t::tune_result_t(void){
+ /* NOP */
+}
+
+/***********************************************************************
+ * Tune Helper Function
+ **********************************************************************/
+static tune_result_t tune(
+ double target_freq,
+ double lo_offset,
+ wax::obj subdev,
+ wax::obj dxc,
+ bool is_tx
+){
+ wax::obj subdev_freq_proxy = subdev[SUBDEV_PROP_FREQ];
+ bool subdev_quadrature = wax::cast<bool>(subdev[SUBDEV_PROP_QUADRATURE]);
+ bool subdev_spectrum_inverted = wax::cast<bool>(subdev[SUBDEV_PROP_SPECTRUM_INVERTED]);
+ wax::obj dxc_freq_proxy = dxc[std::string("freq")];
+ double dxc_sample_rate = wax::cast<double>(dxc[std::string("rate")]);
+
+ // Ask the d'board to tune as closely as it can to target_freq+lo_offset
+ double target_inter_freq = target_freq + lo_offset;
+ subdev_freq_proxy = target_inter_freq;
+ double actual_inter_freq = wax::cast<double>(subdev_freq_proxy);
+
+ // Calculate the DDC setting that will downconvert the baseband from the
+ // daughterboard to our target frequency.
+ double delta_freq = target_freq - actual_inter_freq;
+ double delta_sign = std::signum(delta_freq);
+ delta_freq *= delta_sign;
+ delta_freq = fmod(delta_freq, dxc_sample_rate);
+ bool inverted = delta_freq > dxc_sample_rate/2.0;
+ double target_dxc_freq = inverted? (delta_freq - dxc_sample_rate) : (-delta_freq);
+ target_dxc_freq *= delta_sign;
+
+ // If the spectrum is inverted, and the daughterboard doesn't do
+ // quadrature downconversion, we can fix the inversion by flipping the
+ // sign of the dxc_freq... (This only happens using the basic_rx board)
+ if (subdev_spectrum_inverted){
+ inverted = not inverted;
+ }
+ if (inverted and not subdev_quadrature){
+ target_dxc_freq *= -1.0;
+ inverted = not inverted;
+ }
+ // down conversion versus up conversion, fight!
+ // your mother is ugly and your going down...
+ target_dxc_freq *= (is_tx)? -1.0 : +1.0;
+
+ dxc_freq_proxy = target_dxc_freq;
+ double actual_dxc_freq = wax::cast<double>(dxc_freq_proxy);
+
+ //return some kind of tune result tuple/struct
+ tune_result_t tune_result;
+ tune_result.target_inter_freq = target_inter_freq;
+ tune_result.actual_inter_freq = actual_inter_freq;
+ tune_result.target_dxc_freq = target_dxc_freq;
+ tune_result.actual_dxc_freq = actual_dxc_freq;
+ tune_result.spectrum_inverted = inverted;
+ return tune_result;
+}
+
+/***********************************************************************
+ * Helper Functions
+ **********************************************************************/
+static std::string trim(const std::string &in){
+ return boost::algorithm::trim_copy(in);
+}
+
+device_addr_t args_to_device_addr(const std::string &args){
+ device_addr_t addr;
+
+ //split the args at the semi-colons
+ std::vector<std::string> pairs;
+ boost::split(pairs, args, boost::is_any_of(";"));
+ BOOST_FOREACH(std::string pair, pairs){
+ if (trim(pair) == "") continue;
+
+ //split the key value pairs at the equals
+ std::vector<std::string> key_val;
+ boost::split(key_val, pair, boost::is_any_of("="));
+ if (key_val.size() != 2) throw std::runtime_error("invalid args string: "+args);
+ addr[trim(key_val[0])] = trim(key_val[1]);
+ }
+
+ return addr;
+}
+
+static std::vector<double> get_xx_rates(wax::obj decerps, wax::obj rate){
+ std::vector<double> rates;
+ BOOST_FOREACH(size_t decerp, wax::cast<std::vector<size_t> >(decerps)){
+ rates.push_back(wax::cast<double>(rate)/decerp);
+ }
+ return rates;
+}
+
+/***********************************************************************
+ * Simple Device Implementation
+ **********************************************************************/
+class simple_device_impl : public simple_device{
+public:
+ simple_device_impl(const device_addr_t &addr){
+ _dev = device::make(addr);
+ _mboard = (*_dev)[DEVICE_PROP_MBOARD];
+ _rx_ddc = _mboard[named_prop_t(MBOARD_PROP_RX_DSP, "ddc0")];
+ _tx_duc = _mboard[named_prop_t(MBOARD_PROP_TX_DSP, "duc0")];
+ _rx_subdev = _mboard[MBOARD_PROP_RX_DBOARD][DBOARD_PROP_SUBDEV];
+ _tx_subdev = _mboard[MBOARD_PROP_TX_DBOARD][DBOARD_PROP_SUBDEV];
+ }
+
+ ~simple_device_impl(void){
+ /* NOP */
+ }
+
+ device::sptr get_device(void){
+ return _dev;
+ }
+
+ std::string get_name(void){
+ return wax::cast<std::string>(_mboard[MBOARD_PROP_NAME]);
+ }
+
+ /*******************************************************************
+ * Streaming
+ ******************************************************************/
+ void set_streaming(bool enb){
+ _rx_ddc[std::string("enabled")] = enb;
+ }
+
+ bool get_streaming(void){
+ return wax::cast<bool>(_rx_ddc[std::string("enabled")]);
+ }
+
+ /*******************************************************************
+ * RX methods
+ ******************************************************************/
+ void set_rx_rate(double rate){
+ double samp_rate = wax::cast<double>(_rx_ddc[std::string("rate")]);
+ assert_has(get_rx_rates(), rate, "simple device rx rate");
+ _rx_ddc[std::string("decim")] = size_t(samp_rate/rate);
+ }
+
+ double get_rx_rate(void){
+ double samp_rate = wax::cast<double>(_rx_ddc[std::string("rate")]);
+ size_t decim = wax::cast<size_t>(_rx_ddc[std::string("decim")]);
+ return samp_rate/decim;
+ }
+
+ std::vector<double> get_rx_rates(void){
+ return get_xx_rates(_rx_ddc[std::string("decims")], _rx_ddc[std::string("rate")]);
+ }
+
+ tune_result_t set_rx_freq(double target_freq, double lo_offset){
+ return tune(target_freq, lo_offset, _rx_subdev, _rx_ddc, false/* not tx */);
+ }
+
+ double get_rx_freq_min(void){
+ return wax::cast<double>(_rx_subdev[SUBDEV_PROP_FREQ_MIN]);
+ }
+
+ double get_rx_freq_max(void){
+ return wax::cast<double>(_rx_subdev[SUBDEV_PROP_FREQ_MAX]);
+ }
+
+ void set_rx_gain(float gain){
+ _rx_subdev[SUBDEV_PROP_GAIN] = gain;
+ }
+
+ float get_rx_gain(void){
+ return wax::cast<float>(_rx_subdev[SUBDEV_PROP_GAIN]);
+ }
+
+ float get_rx_gain_min(void){
+ return wax::cast<float>(_rx_subdev[SUBDEV_PROP_GAIN_MIN]);
+ }
+
+ float get_rx_gain_max(void){
+ return wax::cast<float>(_rx_subdev[SUBDEV_PROP_GAIN_MAX]);
+ }
+
+ float get_rx_gain_step(void){
+ return wax::cast<float>(_rx_subdev[SUBDEV_PROP_GAIN_STEP]);
+ }
+
+ void set_rx_antenna(const std::string &ant){
+ _rx_subdev[SUBDEV_PROP_ANTENNA] = ant;
+ }
+
+ std::string get_rx_antenna(void){
+ return wax::cast<std::string>(_rx_subdev[SUBDEV_PROP_ANTENNA]);
+ }
+
+ std::vector<std::string> get_rx_antennas(void){
+ return wax::cast<std::vector<std::string> >(_rx_subdev[SUBDEV_PROP_ANTENNA_NAMES]);
+ }
+
+ /*******************************************************************
+ * TX methods
+ ******************************************************************/
+ void set_tx_rate(double rate){
+ double samp_rate = wax::cast<double>(_tx_duc[std::string("rate")]);
+ assert_has(get_tx_rates(), rate, "simple device tx rate");
+ _tx_duc[std::string("interp")] = size_t(samp_rate/rate);
+ }
+
+ double get_tx_rate(void){
+ double samp_rate = wax::cast<double>(_tx_duc[std::string("rate")]);
+ size_t interp = wax::cast<size_t>(_tx_duc[std::string("interp")]);
+ return samp_rate/interp;
+ }
+
+ std::vector<double> get_tx_rates(void){
+ return get_xx_rates(_tx_duc[std::string("interps")], _tx_duc[std::string("rate")]);
+ }
+
+ tune_result_t set_tx_freq(double target_freq, double lo_offset){
+ return tune(target_freq, lo_offset, _tx_subdev, _tx_duc, true/* is tx */);
+ }
+
+ double get_tx_freq_min(void){
+ return wax::cast<double>(_tx_subdev[SUBDEV_PROP_FREQ_MIN]);
+ }
+
+ double get_tx_freq_max(void){
+ return wax::cast<double>(_tx_subdev[SUBDEV_PROP_FREQ_MAX]);
+ }
+
+ void set_tx_gain(float gain){
+ _tx_subdev[SUBDEV_PROP_GAIN] = gain;
+ }
+
+ float get_tx_gain(void){
+ return wax::cast<float>(_tx_subdev[SUBDEV_PROP_GAIN]);
+ }
+
+ float get_tx_gain_min(void){
+ return wax::cast<float>(_tx_subdev[SUBDEV_PROP_GAIN_MIN]);
+ }
+
+ float get_tx_gain_max(void){
+ return wax::cast<float>(_tx_subdev[SUBDEV_PROP_GAIN_MAX]);
+ }
+
+ float get_tx_gain_step(void){
+ return wax::cast<float>(_tx_subdev[SUBDEV_PROP_GAIN_STEP]);
+ }
+
+ void set_tx_antenna(const std::string &ant){
+ _tx_subdev[SUBDEV_PROP_ANTENNA] = ant;
+ }
+
+ std::string get_tx_antenna(void){
+ return wax::cast<std::string>(_tx_subdev[SUBDEV_PROP_ANTENNA]);
+ }
+
+ std::vector<std::string> get_tx_antennas(void){
+ return wax::cast<std::vector<std::string> >(_tx_subdev[SUBDEV_PROP_ANTENNA_NAMES]);
+ }
+
+private:
+ device::sptr _dev;
+ wax::obj _mboard;
+ wax::obj _rx_ddc;
+ wax::obj _tx_duc;
+ wax::obj _rx_subdev;
+ wax::obj _tx_subdev;
+};
+
+/***********************************************************************
+ * The Make Function
+ **********************************************************************/
+simple_device::sptr simple_device::make(const std::string &args){
+ return sptr(new simple_device_impl(args_to_device_addr(args)));
+}