mirror of
https://github.com/saymrwulf/uhd.git
synced 2026-05-16 21:10:10 +00:00
173 lines
6 KiB
C++
173 lines
6 KiB
C++
//
|
|
// Copyright 2012-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 <http://www.gnu.org/licenses/>.
|
|
//
|
|
|
|
#include "ad9361_ctrl.hpp"
|
|
#include "ad9361_transaction.h"
|
|
#include <uhd/exception.hpp>
|
|
#include <uhd/types/ranges.hpp>
|
|
#include <uhd/utils/msg.hpp>
|
|
#include <boost/thread/mutex.hpp>
|
|
#include <boost/format.hpp>
|
|
#include <cstring>
|
|
|
|
//! compat strnlen for platforms that dont have it
|
|
static size_t my_strnlen(const char *str, size_t max)
|
|
{
|
|
const char *end = (const char *)std::memchr((const void *)str, 0, max);
|
|
if (end == NULL) return max;
|
|
return (size_t)(end - str);
|
|
}
|
|
|
|
using namespace uhd;
|
|
|
|
struct ad9361_ctrl_impl : public ad9361_ctrl
|
|
{
|
|
ad9361_ctrl_impl(ad9361_ctrl_iface_sptr iface):
|
|
_iface(iface), _seq(0)
|
|
{
|
|
ad9361_transaction_t request;
|
|
|
|
request.action = AD9361_ACTION_ECHO;
|
|
this->do_transaction(request);
|
|
|
|
request.action = AD9361_ACTION_INIT;
|
|
this->do_transaction(request);
|
|
}
|
|
|
|
double set_gain(const std::string &which, const double value)
|
|
{
|
|
ad9361_transaction_t request;
|
|
|
|
if (which == "RX1") request.action = AD9361_ACTION_SET_RX1_GAIN;
|
|
if (which == "RX2") request.action = AD9361_ACTION_SET_RX2_GAIN;
|
|
if (which == "TX1") request.action = AD9361_ACTION_SET_TX1_GAIN;
|
|
if (which == "TX2") request.action = AD9361_ACTION_SET_TX2_GAIN;
|
|
|
|
ad9361_double_pack(value, request.value.gain);
|
|
const ad9361_transaction_t reply = this->do_transaction(request);
|
|
return ad9361_double_unpack(reply.value.gain);
|
|
}
|
|
|
|
//! set a new clock rate, return the exact value
|
|
double set_clock_rate(const double rate)
|
|
{
|
|
//warning for known trouble rates
|
|
if (rate > 56e6) UHD_MSG(warning) << boost::format(
|
|
"The requested clock rate %f MHz may cause slow configuration.\n"
|
|
"The driver recommends a master clock rate less than %f MHz.\n"
|
|
) % (rate/1e6) % 56.0 << std::endl;
|
|
|
|
//clip to known bounds
|
|
const meta_range_t clock_rate_range = ad9361_ctrl::get_clock_rate_range();
|
|
const double clipped_rate = clock_rate_range.clip(rate);
|
|
|
|
ad9361_transaction_t request;
|
|
request.action = AD9361_ACTION_SET_CLOCK_RATE;
|
|
ad9361_double_pack(clipped_rate, request.value.rate);
|
|
const ad9361_transaction_t reply = this->do_transaction(request);
|
|
return ad9361_double_unpack(reply.value.rate);
|
|
}
|
|
|
|
//! set which RX and TX chains/antennas are active
|
|
void set_active_chains(bool tx1, bool tx2, bool rx1, bool rx2)
|
|
{
|
|
boost::uint32_t mask = 0;
|
|
if (tx1) mask |= (1 << 0);
|
|
if (tx2) mask |= (1 << 1);
|
|
if (rx1) mask |= (1 << 2);
|
|
if (rx2) mask |= (1 << 3);
|
|
|
|
ad9361_transaction_t request;
|
|
request.action = AD9361_ACTION_SET_ACTIVE_CHAINS;
|
|
request.value.enable_mask = mask;
|
|
this->do_transaction(request);
|
|
}
|
|
|
|
//! tune the given frontend, return the exact value
|
|
double tune(const std::string &which, const double freq)
|
|
{
|
|
//clip to known bounds
|
|
const meta_range_t freq_range = ad9361_ctrl::get_rf_freq_range();
|
|
const double clipped_freq = freq_range.clip(freq);
|
|
|
|
ad9361_transaction_t request;
|
|
|
|
if (which[0] == 'R') request.action = AD9361_ACTION_SET_RX_FREQ;
|
|
if (which[0] == 'T') request.action = AD9361_ACTION_SET_TX_FREQ;
|
|
|
|
const double value = ad9361_ctrl::get_rf_freq_range().clip(clipped_freq);
|
|
ad9361_double_pack(value, request.value.freq);
|
|
const ad9361_transaction_t reply = this->do_transaction(request);
|
|
return ad9361_double_unpack(reply.value.freq);
|
|
}
|
|
|
|
//! turn on/off Catalina's data port loopback
|
|
void data_port_loopback(const bool on)
|
|
{
|
|
ad9361_transaction_t request;
|
|
request.action = AD9361_ACTION_SET_CODEC_LOOP;
|
|
request.value.codec_loop = on? 1 : 0;
|
|
this->do_transaction(request);
|
|
}
|
|
|
|
ad9361_transaction_t do_transaction(const ad9361_transaction_t &request)
|
|
{
|
|
boost::mutex::scoped_lock lock(_mutex);
|
|
|
|
//declare in/out buffers
|
|
unsigned char in_buff[64] = {};
|
|
unsigned char out_buff[64] = {};
|
|
|
|
//copy the input transaction
|
|
std::memcpy(in_buff, &request, sizeof(request));
|
|
|
|
//fill in other goodies
|
|
ad9361_transaction_t *in = (ad9361_transaction_t *)in_buff;
|
|
in->version = AD9361_TRANSACTION_VERSION;
|
|
in->sequence = _seq++;
|
|
|
|
//transact
|
|
_iface->ad9361_transact(in_buff, out_buff);
|
|
ad9361_transaction_t *out = (ad9361_transaction_t *)out_buff;
|
|
|
|
//sanity checks
|
|
UHD_ASSERT_THROW(out->version == in->version);
|
|
UHD_ASSERT_THROW(out->sequence == in->sequence);
|
|
|
|
//handle errors
|
|
const size_t len = my_strnlen(out->error_msg, AD9361_TRANSACTION_MAX_ERROR_MSG);
|
|
const std::string error_msg(out->error_msg, len);
|
|
if (not error_msg.empty()) throw uhd::runtime_error("[ad9361_ctrl::do_transaction] firmware reported: \"" + error_msg + "\"");
|
|
|
|
//return result done!
|
|
return *out;
|
|
}
|
|
|
|
ad9361_ctrl_iface_sptr _iface;
|
|
size_t _seq;
|
|
boost::mutex _mutex;
|
|
|
|
};
|
|
|
|
|
|
/***********************************************************************
|
|
* Make an instance of the implementation
|
|
**********************************************************************/
|
|
ad9361_ctrl::sptr ad9361_ctrl::make(ad9361_ctrl_iface_sptr iface)
|
|
{
|
|
return sptr(new ad9361_ctrl_impl(iface));
|
|
}
|