mirror of
https://github.com/EttusResearch/uhd.git
synced 2026-10-25 17:36:10 +00:00
mg: General fixes
- Make DB probe-able - Add RPC client
This commit is contained in:
parent
8ee3da3ef9
commit
309a2f04e3
@ -5,7 +5,7 @@
|
||||
<key>MagnesiumRadio</key>
|
||||
<!--There can be several of these:-->
|
||||
<ids>
|
||||
<id revision="0">12AD100000000003</id>
|
||||
<id revision="0">12AD100000000310</id>
|
||||
</ids>
|
||||
<!-- Registers -->
|
||||
<registers>
|
||||
|
||||
@ -23,90 +23,246 @@
|
||||
#include <uhd/utils/math.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/make_shared.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time_io.hpp>
|
||||
#include <boost/format.hpp>
|
||||
#include <sstream>
|
||||
|
||||
using namespace uhd;
|
||||
using namespace uhd::usrp;
|
||||
using namespace uhd::rfnoc;
|
||||
|
||||
static const size_t IO_MASTER_RADIO = 0;
|
||||
static const double MAGNESIUM_TICK_RATE = 125e6; // Hz
|
||||
static const double MAGNESIUM_RADIO_RATE = 125e6; // Hz
|
||||
static const double MAGNESIUM_CENTER_FREQ = 2.5e9; // Hz
|
||||
static const double MAGNESIUM_DEFAULT_GAIN = 0.0; // dB
|
||||
static const double MAGNESIUM_DEFAULT_BANDWIDTH = 40e6; // Hz TODO: fix
|
||||
static const size_t MAGNESIUM_NUM_TX_CHANS = 2;
|
||||
static const size_t MAGNESIUM_NUM_RX_CHANS = 2;
|
||||
|
||||
std::string _get_which(direction_t dir, size_t chan)
|
||||
{
|
||||
std::stringstream ss;
|
||||
switch (dir)
|
||||
{
|
||||
case RX_DIRECTION:
|
||||
ss << "RX";
|
||||
break;
|
||||
case TX_DIRECTION:
|
||||
ss << "TX";
|
||||
break;
|
||||
default:
|
||||
UHD_THROW_INVALID_CODE_PATH();
|
||||
}
|
||||
|
||||
switch (chan)
|
||||
{
|
||||
case 0:
|
||||
ss << "1";
|
||||
break;
|
||||
case 1:
|
||||
ss << "2";
|
||||
break;
|
||||
default:
|
||||
throw uhd::runtime_error("invalid channel number");
|
||||
}
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
UHD_RFNOC_RADIO_BLOCK_CONSTRUCTOR(magnesium_radio_ctrl)
|
||||
{
|
||||
std::cout << "magnesium_radio_ctrl_impl::ctor() " << std::endl;
|
||||
UHD_LOG_TRACE("MAGNESIUM", "magnesium_radio_ctrl_impl::ctor() ");
|
||||
_radio_slot = (get_block_id().get_block_count() == IO_MASTER_RADIO) ? "A" : "B";
|
||||
_slot_prefix = (get_block_id().get_block_count() == IO_MASTER_RADIO) ? "db_0_" : "db_1_";
|
||||
UHD_LOG_TRACE("MAGNESIUM", "Radio slot: " << _radio_slot);
|
||||
|
||||
|
||||
const size_t num_rx_chans = get_output_ports().size();
|
||||
UHD_ASSERT_THROW(num_rx_chans == MAGNESIUM_NUM_RX_CHANS);
|
||||
const size_t num_tx_chans = get_input_ports().size();
|
||||
UHD_ASSERT_THROW(num_tx_chans == MAGNESIUM_NUM_TX_CHANS);
|
||||
|
||||
UHD_LOG_TRACE("MAGNESIUM", "Setting tick rate to " << MAGNESIUM_TICK_RATE / 1e6 << " MHz");
|
||||
radio_ctrl_impl::set_rate(MAGNESIUM_TICK_RATE);
|
||||
|
||||
for (size_t chan = 0; chan < num_rx_chans; chan++) {
|
||||
radio_ctrl_impl::set_rx_frequency(MAGNESIUM_CENTER_FREQ, chan);
|
||||
radio_ctrl_impl::set_rx_gain(MAGNESIUM_DEFAULT_GAIN, chan);
|
||||
// TODO: fix antenna name
|
||||
radio_ctrl_impl::set_rx_antenna(str(boost::format("RX%d") % (chan+1)), chan);
|
||||
radio_ctrl_impl::set_rx_bandwidth(MAGNESIUM_DEFAULT_BANDWIDTH, chan);
|
||||
}
|
||||
|
||||
for (size_t chan = 0; chan < num_tx_chans; chan++) {
|
||||
radio_ctrl_impl::set_tx_frequency(MAGNESIUM_CENTER_FREQ, chan);
|
||||
radio_ctrl_impl::set_tx_gain(MAGNESIUM_DEFAULT_GAIN, chan);
|
||||
// TODO: fix antenna name
|
||||
radio_ctrl_impl::set_tx_antenna(str(boost::format("TX%d") % (chan + 1)), chan);
|
||||
}
|
||||
|
||||
/**** Set up legacy compatible properties ******************************/
|
||||
// For use with multi_usrp APIs etc.
|
||||
// For legacy prop tree init:
|
||||
// TODO: determine DB number
|
||||
fs_path fe_base = fs_path("dboards") / _radio_slot;
|
||||
std::vector<std::string> fe({ "rx_frontends" , "tx_frontends" });
|
||||
std::vector<std::string> ant({ "RX" , "TX" });
|
||||
|
||||
UHD_ASSERT_THROW(MAGNESIUM_NUM_RX_CHANS == MAGNESIUM_NUM_TX_CHANS);
|
||||
for (size_t fe_idx = 0; fe_idx < fe.size(); ++fe_idx)
|
||||
{
|
||||
fs_path fe_direction_path = fe_base / fe[fe_idx];
|
||||
for (size_t chan = 0; chan < MAGNESIUM_NUM_RX_CHANS; ++chan) {
|
||||
fs_path fe_path = fe_direction_path / chan;
|
||||
UHD_LOG_TRACE("MAGNESIUM", "Adding FE at " << fe_path);
|
||||
_tree->create<std::string>(fe_path / "name")
|
||||
.set(str(boost::format("Magnesium %s %d") % ant[fe_idx] % chan))
|
||||
;
|
||||
_tree->create<std::string>(fe_path / "connection")
|
||||
.set("IQ")
|
||||
;
|
||||
// TODO: fix antenna name
|
||||
_tree->create<std::string>(fe_path / "antenna" / "value")
|
||||
.set(str(boost::format("%s%d") % ant[fe_idx] % (chan+1)))
|
||||
.add_coerced_subscriber(boost::bind(&magnesium_radio_ctrl_impl::set_rx_antenna, this, _1, chan))
|
||||
.set_publisher(boost::bind(&radio_ctrl_impl::get_rx_antenna, this, chan))
|
||||
;
|
||||
_tree->create<std::vector<std::string>>(fe_path / "antenna" / "options")
|
||||
.set(std::vector<std::string>(1, str(boost::format("%s%d") % ant[fe_idx] % (chan + 1))))
|
||||
;
|
||||
_tree->create<double>(fe_path / "freq" / "value")
|
||||
.set(MAGNESIUM_CENTER_FREQ)
|
||||
.set_coercer(boost::bind(&magnesium_radio_ctrl_impl::set_rx_frequency, this, _1, chan))
|
||||
.set_publisher(boost::bind(&radio_ctrl_impl::get_rx_frequency, this, chan))
|
||||
;
|
||||
_tree->create<meta_range_t>(fe_path / "freq" / "range")
|
||||
.set(meta_range_t(MAGNESIUM_CENTER_FREQ, MAGNESIUM_CENTER_FREQ))
|
||||
;
|
||||
_tree->create<double>(fe_path / "gains" / "null" / "value")
|
||||
.set(MAGNESIUM_DEFAULT_GAIN)
|
||||
.set_coercer(boost::bind(&magnesium_radio_ctrl_impl::set_rx_gain, this, _1, chan))
|
||||
.set_publisher(boost::bind(&radio_ctrl_impl::get_rx_gain, this, chan))
|
||||
;
|
||||
_tree->create<meta_range_t>(fe_path / "gains" / "null" / "range")
|
||||
.set(meta_range_t(MAGNESIUM_DEFAULT_GAIN, MAGNESIUM_DEFAULT_GAIN))
|
||||
;
|
||||
_tree->create<double>(fe_path / "bandwidth" / "value")
|
||||
.set(MAGNESIUM_DEFAULT_BANDWIDTH)
|
||||
.set_coercer(boost::bind(&magnesium_radio_ctrl_impl::set_rx_bandwidth, this, _1, chan))
|
||||
.set_publisher(boost::bind(&radio_ctrl_impl::get_rx_bandwidth, this, chan))
|
||||
;
|
||||
_tree->create<meta_range_t>(fe_path / "bandwidth" / "range")
|
||||
.set(meta_range_t(MAGNESIUM_DEFAULT_BANDWIDTH, MAGNESIUM_DEFAULT_BANDWIDTH))
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO change codec names
|
||||
_tree->create<int>("rx_codecs" / _radio_slot / "gains");
|
||||
_tree->create<int>("tx_codecs" / _radio_slot / "gains");
|
||||
_tree->create<std::string>("rx_codecs" / _radio_slot / "name").set("AD9361 Dual ADC");
|
||||
_tree->create<std::string>("tx_codecs" / _radio_slot / "name").set("AD9361 Dual DAC");
|
||||
|
||||
// TODO remove this dirty hack
|
||||
if (not _tree->exists("tick_rate"))
|
||||
{
|
||||
_tree->create<double>("tick_rate").set(MAGNESIUM_TICK_RATE);
|
||||
}
|
||||
}
|
||||
|
||||
magnesium_radio_ctrl_impl::~magnesium_radio_ctrl_impl()
|
||||
{
|
||||
UHD_LOG_TRACE("MAGNESIUM", "magnesium_radio_ctrl_impl::dtor() ");
|
||||
}
|
||||
|
||||
|
||||
double magnesium_radio_ctrl_impl::set_rate(double rate)
|
||||
{
|
||||
return 0;
|
||||
// TODO: implement
|
||||
if (rate != get_rate()) {
|
||||
UHD_LOG_WARNING("MAGNESIUM", "Attempting to set sampling rate to invalid value " << rate);
|
||||
}
|
||||
return get_rate();
|
||||
}
|
||||
|
||||
void magnesium_radio_ctrl_impl::set_tx_antenna(const std::string &ant, const size_t chan)
|
||||
{
|
||||
// TODO: implement
|
||||
UHD_LOG_WARNING("MAGNESIUM", "Ignoring attempt to set Tx antenna");
|
||||
// CPLD control?
|
||||
}
|
||||
|
||||
void magnesium_radio_ctrl_impl::set_rx_antenna(const std::string &ant, const size_t chan)
|
||||
{
|
||||
// TODO: implement
|
||||
UHD_LOG_WARNING("MAGNESIUM", "Ignoring attempt to set Rx antenna");
|
||||
// CPLD control?
|
||||
}
|
||||
|
||||
double magnesium_radio_ctrl_impl::set_tx_frequency(const double freq, const size_t chan)
|
||||
{
|
||||
return 0;
|
||||
return _set_freq(freq, chan, TX_DIRECTION);
|
||||
}
|
||||
|
||||
double magnesium_radio_ctrl_impl::set_rx_frequency(const double freq, const size_t chan)
|
||||
{
|
||||
return 0;
|
||||
return _set_freq(freq, chan, RX_DIRECTION);
|
||||
}
|
||||
|
||||
double magnesium_radio_ctrl_impl::set_rx_bandwidth(const double bandwidth, const size_t chan)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
double magnesium_radio_ctrl_impl::get_tx_frequency(const size_t chan)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
double magnesium_radio_ctrl_impl::get_rx_frequency(const size_t chan)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
double magnesium_radio_ctrl_impl::get_rx_bandwidth(const size_t chan)
|
||||
{
|
||||
return 0;
|
||||
// TODO: implement
|
||||
return get_rx_bandwidth(chan);
|
||||
}
|
||||
|
||||
double magnesium_radio_ctrl_impl::set_tx_gain(const double gain, const size_t chan)
|
||||
{
|
||||
return 0;
|
||||
return _set_gain(gain, chan, TX_DIRECTION);
|
||||
}
|
||||
|
||||
double magnesium_radio_ctrl_impl::set_rx_gain(const double gain, const size_t chan)
|
||||
{
|
||||
return 0;
|
||||
return _set_gain(gain, chan, RX_DIRECTION);
|
||||
}
|
||||
|
||||
size_t magnesium_radio_ctrl_impl::get_chan_from_dboard_fe(const std::string &fe, const direction_t dir)
|
||||
{
|
||||
return 0;
|
||||
UHD_LOG_TRACE("MAGNESIUM", "get_chan_from_dboard_fe " << fe << " returns " << boost::lexical_cast<size_t>(fe));
|
||||
return boost::lexical_cast<size_t>(fe);
|
||||
}
|
||||
|
||||
std::string magnesium_radio_ctrl_impl::get_dboard_fe_from_chan(const size_t chan, const direction_t dir)
|
||||
{
|
||||
return "";
|
||||
UHD_LOG_TRACE("MAGNESIUM", "get_dboard_fe_from_chan " << chan << " returns " << std::to_string(chan));
|
||||
return std::to_string(chan);
|
||||
}
|
||||
|
||||
double magnesium_radio_ctrl_impl::get_output_samp_rate(size_t port)
|
||||
{
|
||||
return 0;
|
||||
return 125e6;
|
||||
}
|
||||
|
||||
void magnesium_radio_ctrl_impl::set_rpc_client(
|
||||
uhd::rpc_client::sptr rpcc,
|
||||
const uhd::device_addr_t &block_args
|
||||
)
|
||||
{
|
||||
_rpcc = rpcc;
|
||||
_block_args = block_args;
|
||||
}
|
||||
|
||||
double magnesium_radio_ctrl_impl::_set_freq(const double freq, const size_t chan, const direction_t dir)
|
||||
{
|
||||
auto which = _get_which(dir, chan);
|
||||
UHD_LOG_TRACE("MAGNESIUM", "calling " << _slot_prefix << "set_freq on " << which << " with " << freq);
|
||||
return _rpcc->request_with_token<double>(_slot_prefix + "set_freq", which, freq, false);
|
||||
}
|
||||
|
||||
double magnesium_radio_ctrl_impl::_set_gain(const double gain, const size_t chan, const direction_t dir)
|
||||
{
|
||||
auto which = _get_which(dir, chan);
|
||||
UHD_LOG_TRACE("MAGNESIUM", "calling " << _slot_prefix << "set_gain on " << which << " with " << gain);
|
||||
return _rpcc->request_with_token<double>(_slot_prefix + "set_gain", which, gain);
|
||||
}
|
||||
|
||||
UHD_RFNOC_BLOCK_REGISTER(magnesium_radio_ctrl, "MagnesiumRadio");
|
||||
|
||||
@ -19,6 +19,7 @@
|
||||
#define INCLUDED_LIBUHD_RFNOC_MAGNESIUM_RADIO_CTRL_IMPL_HPP
|
||||
|
||||
#include "radio_ctrl_impl.hpp"
|
||||
#include "rpc_block_ctrl.hpp"
|
||||
#include <uhd/usrp/dboard_manager.hpp>
|
||||
#include <uhd/usrp/gpio_defs.hpp>
|
||||
|
||||
@ -27,7 +28,7 @@ namespace uhd {
|
||||
|
||||
/*! \brief Provide access to an Magnesium radio.
|
||||
*/
|
||||
class magnesium_radio_ctrl_impl : public radio_ctrl_impl
|
||||
class magnesium_radio_ctrl_impl : public radio_ctrl_impl, public rpc_block_ctrl
|
||||
{
|
||||
public:
|
||||
typedef boost::shared_ptr<magnesium_radio_ctrl_impl> sptr;
|
||||
@ -49,9 +50,6 @@ public:
|
||||
double set_tx_frequency(const double freq, const size_t chan);
|
||||
double set_rx_frequency(const double freq, const size_t chan);
|
||||
double set_rx_bandwidth(const double bandwidth, const size_t chan);
|
||||
double get_tx_frequency(const size_t chan);
|
||||
double get_rx_frequency(const size_t chan);
|
||||
double get_rx_bandwidth(const size_t chan);
|
||||
|
||||
double set_tx_gain(const double gain, const size_t chan);
|
||||
double set_rx_gain(const double gain, const size_t chan);
|
||||
@ -61,7 +59,22 @@ public:
|
||||
|
||||
double get_output_samp_rate(size_t port);
|
||||
|
||||
void set_rpc_client(
|
||||
uhd::rpc_client::sptr rpcc,
|
||||
const uhd::device_addr_t &block_args
|
||||
);
|
||||
|
||||
private:
|
||||
double _set_freq(const double freq, const size_t chan, const direction_t dir);
|
||||
double _set_gain(const double gain, const size_t chan, const direction_t dir);
|
||||
|
||||
std::string _radio_slot;
|
||||
std::string _slot_prefix;
|
||||
//! Additional block args; gets set during set_rpc_client()
|
||||
uhd::device_addr_t _block_args;
|
||||
|
||||
//! Reference to the RPC client
|
||||
uhd::rpc_client::sptr _rpcc;
|
||||
|
||||
}; /* class radio_ctrl_impl */
|
||||
|
||||
|
||||
@ -106,13 +106,6 @@ namespace {
|
||||
);
|
||||
})
|
||||
;
|
||||
tree->create<int>(
|
||||
mb_path / "rx_codecs" / "A" / "gains")
|
||||
.set_publisher([](){
|
||||
return 1 // FIXME: Remove hardcoding
|
||||
;
|
||||
})
|
||||
;
|
||||
}
|
||||
|
||||
void reset_time_synchronized(uhd::property_tree::sptr tree)
|
||||
|
||||
@ -74,7 +74,6 @@ public:
|
||||
virtual uint8_t get_framer_status() = 0;
|
||||
virtual uint8_t get_deframer_status() = 0;
|
||||
|
||||
virtual uint8_t get_deframer_irq() = 0;
|
||||
virtual uint16_t get_ilas_config_match() = 0;
|
||||
virtual void enable_jesd_loopback(uint8_t enable) = 0;
|
||||
|
||||
@ -140,9 +139,10 @@ public:
|
||||
* Sets the RF frequency. This is a per direction setting.
|
||||
* \param which frontend string to specify direction to tune
|
||||
* \param value target frequency
|
||||
* \param wait_for_lock wait after tuning for the PLL to lock
|
||||
* \return actual frequency
|
||||
*/
|
||||
virtual double set_freq(const std::string &which, double value) = 0;
|
||||
virtual double set_freq(const std::string &which, double value, bool wait_for_lock) = 0;
|
||||
|
||||
/*! \brief get the RF frequency for the direction specified in which
|
||||
*
|
||||
@ -189,7 +189,6 @@ void export_mykonos(){
|
||||
.def("get_multichip_sync_status", &ad937x_ctrl::get_multichip_sync_status)
|
||||
.def("get_framer_status", &ad937x_ctrl::get_framer_status)
|
||||
.def("get_deframer_status", &ad937x_ctrl::get_deframer_status)
|
||||
//.def("get_deframer_irq", &ad937x_ctrl::get_deframer_irq)
|
||||
.def("get_ilas_config_match", &ad937x_ctrl::get_ilas_config_match)
|
||||
.def("enable_jesd_loopback", &ad937x_ctrl::enable_jesd_loopback)
|
||||
.def("get_rf_freq_range", &ad937x_ctrl::get_rf_freq_range)
|
||||
|
||||
@ -157,41 +157,30 @@ public:
|
||||
device.start_jesd_tx();
|
||||
}
|
||||
|
||||
// TODO: interpret the status byte
|
||||
// or provide means to do so
|
||||
virtual uint8_t get_multichip_sync_status()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(*spi_mutex);
|
||||
return device.get_multichip_sync_status();
|
||||
}
|
||||
|
||||
// TODO: interpret the status byte
|
||||
// or provide means to do so
|
||||
virtual uint8_t get_framer_status()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(*spi_mutex);
|
||||
return device.get_framer_status();
|
||||
}
|
||||
|
||||
// TODO: interpret the status byte
|
||||
// or provide means to do so
|
||||
virtual uint8_t get_deframer_status()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(*spi_mutex);
|
||||
return device.get_deframer_status();
|
||||
}
|
||||
|
||||
virtual uint8_t get_deframer_irq()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(*spi_mutex);
|
||||
return device.get_deframer_irq();
|
||||
}
|
||||
|
||||
virtual uint16_t get_ilas_config_match()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(*spi_mutex);
|
||||
return device.get_ilas_config_match();
|
||||
}
|
||||
|
||||
virtual void enable_jesd_loopback(uint8_t enable)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(*spi_mutex);
|
||||
@ -297,13 +286,13 @@ public:
|
||||
return device.enable_channel(dir, chain, enable);
|
||||
}
|
||||
|
||||
virtual double set_freq(const std::string &which, double value)
|
||||
virtual double set_freq(const std::string &which, double value, bool wait_for_lock)
|
||||
{
|
||||
auto dir = _get_direction_from_antenna(which);
|
||||
auto clipped_value = get_rf_freq_range().clip(value);
|
||||
|
||||
std::lock_guard<std::mutex> lock(*spi_mutex);
|
||||
return device.tune(dir, clipped_value);
|
||||
return device.tune(dir, clipped_value, wait_for_lock);
|
||||
}
|
||||
|
||||
virtual double get_freq(const std::string &which)
|
||||
|
||||
@ -25,6 +25,7 @@
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
#include <fstream>
|
||||
|
||||
using namespace mpm::ad937x::device;
|
||||
using namespace mpm::ad937x::gpio;
|
||||
@ -39,8 +40,10 @@ const double ad937x_device::MIN_TX_GAIN = 0.0;
|
||||
const double ad937x_device::MAX_TX_GAIN = 41.95;
|
||||
const double ad937x_device::TX_GAIN_STEP = 0.05;
|
||||
|
||||
static const double RX_DEFAULT_FREQ = 1e9;
|
||||
static const double TX_DEFAULT_FREQ = 1e9;
|
||||
static const double RX_DEFAULT_FREQ = 2.5e9;
|
||||
static const double TX_DEFAULT_FREQ = 2.5e9;
|
||||
static const double RX_DEFAULT_GAIN = 0;
|
||||
static const double TX_DEFAULT_GAIN = 0;
|
||||
|
||||
// TODO: get the actual device ID
|
||||
static const uint32_t AD9371_PRODUCT_ID = 0x1;
|
||||
@ -112,89 +115,59 @@ void ad937x_device::_call_gpio_api_function(std::function<mykonosGpioErr_t()> fu
|
||||
}
|
||||
}
|
||||
|
||||
//void ad937x_device::_call_debug_api_function(std::function<mykonosDbgErr_t()> func)
|
||||
//{
|
||||
//auto error = func();
|
||||
//if (error != MYKONOS_ERR_DBG_OK)
|
||||
//{
|
||||
//std::cout << getDbgJesdMykonosErrorMessage(error);
|
||||
//// TODO: make UHD exception
|
||||
////throw std::exception(getMykonosErrorMessage(error));
|
||||
//}
|
||||
//}
|
||||
|
||||
// TODO: delete this comment closer to release
|
||||
/*
|
||||
EX 1 Preconditions
|
||||
EX 1. Check revision register
|
||||
EX 2. Initialize Clocking
|
||||
EX 3. Initialize FPGA JESD
|
||||
|
||||
begin_initialize()
|
||||
IN 2 Start
|
||||
IN 1. Reset Myk
|
||||
IN 2. Init Myk
|
||||
IN 3. Check base PLL
|
||||
IN 4. Start Multichip Sync
|
||||
|
||||
EX 3 Multichip Pulses
|
||||
EX 1. Send 2 SYSREF pulses
|
||||
|
||||
finish_initialize()
|
||||
IN 4 Verify Multichip
|
||||
IN 1. Verify Multichip
|
||||
IN 2. Complete Init
|
||||
|
||||
--skipping this for now using special hack from jepson
|
||||
--IN 3. Load ARM
|
||||
--IN 4. RF Start
|
||||
--IN Set RF Freq
|
||||
--IN Check RF PLLs
|
||||
--IN Set GPIO controls
|
||||
--IN Set gain
|
||||
--IN Init TX attenuations
|
||||
--IN Initialization Calibrations
|
||||
--IN External LOL Calibration (do we need this ???)
|
||||
|
||||
--separate functions here for reusability--
|
||||
|
||||
start_jesd_rx()
|
||||
IN 5 Start Myk JESD RX
|
||||
IN 1. Reset Myk JESD RX (???)
|
||||
IN 2. Enable Myk JESD RX Transmitter
|
||||
|
||||
EX 6 Start FPGA CGS
|
||||
EX 1. Reset and Ready RX JESD for CGS
|
||||
EX 2. Reset and Ready TX JESD for CGS
|
||||
|
||||
start_jesd_tx()
|
||||
IN 7 Start Myk JESD TX
|
||||
IN 1. Disable Myk JESD Receiver
|
||||
IN 2. Reset Myk JESD Receiver
|
||||
IN 3. Enable Myk JESD Receiver
|
||||
|
||||
EX 8 Finish CGS
|
||||
EX 1. Enable FPGA LMFC Generator
|
||||
EX 2. Send SYSREF Pulse
|
||||
EX 3. Wait (200 ms ???)
|
||||
EX 4. Check TX Core is Synced
|
||||
EX 5. Check RX Core is Synced
|
||||
|
||||
OTHER FUNCTIONS THAT SHOULD BE WRITTEN
|
||||
get_framer_status() get_deframer_status() Read framer/deframer status
|
||||
get_deframer_irq() Read Deframer IRQ
|
||||
get_ilas_config_match() Check ILAS Config Match
|
||||
set_jesd_loopback() Enable Loopback
|
||||
stop_jesd() Stop Link
|
||||
|
||||
*/
|
||||
|
||||
void ad937x_device::begin_initialization()
|
||||
std::string ad937x_device::_get_arm_binary_path()
|
||||
{
|
||||
// TODO: make this reset actually do something (implement CMB_HardReset or replace)
|
||||
_call_api_function(std::bind(MYKONOS_resetDevice, mykonos_config.device));
|
||||
_call_api_function(std::bind(MYKONOS_initialize, mykonos_config.device));
|
||||
// TODO: possibly add more options here, for now it's always in /lib/firmware or we explode
|
||||
return "/lib/firmware/Mykonos_M3.bin";
|
||||
}
|
||||
|
||||
std::vector<uint8_t> ad937x_device::_get_arm_binary()
|
||||
{
|
||||
auto path = _get_arm_binary_path();
|
||||
std::ifstream file(path, std::ios::binary);
|
||||
if (!file.is_open())
|
||||
{
|
||||
throw mpm::runtime_error("Could not open AD9371 ARM binary at path " + path);
|
||||
return{};
|
||||
}
|
||||
|
||||
std::vector<uint8_t> binary(ARM_BINARY_SIZE);
|
||||
file.read(reinterpret_cast<char*>(binary.data()), ARM_BINARY_SIZE);
|
||||
if (file.bad())
|
||||
{
|
||||
throw mpm::runtime_error("Error reading AD9371 ARM binary at path " + path);
|
||||
}
|
||||
return binary;
|
||||
}
|
||||
|
||||
void ad937x_device::_initialize_rf()
|
||||
{
|
||||
// Set frequencies
|
||||
tune(uhd::RX_DIRECTION, RX_DEFAULT_FREQ, true);
|
||||
tune(uhd::TX_DIRECTION, TX_DEFAULT_FREQ, true);
|
||||
|
||||
if (!get_pll_lock_status(pll_t::CLK_SYNTH))
|
||||
{
|
||||
throw mpm::runtime_error("CLK SYNTH PLL became unlocked!");
|
||||
}
|
||||
|
||||
// Set gain control GPIO pins
|
||||
_apply_gain_pins(uhd::RX_DIRECTION, chain_t::ONE);
|
||||
_apply_gain_pins(uhd::RX_DIRECTION, chain_t::TWO);
|
||||
_apply_gain_pins(uhd::TX_DIRECTION, chain_t::ONE);
|
||||
_apply_gain_pins(uhd::TX_DIRECTION, chain_t::TWO);
|
||||
|
||||
// Set manual gain values
|
||||
set_gain(uhd::RX_DIRECTION, chain_t::ONE, RX_DEFAULT_GAIN);
|
||||
set_gain(uhd::RX_DIRECTION, chain_t::TWO, RX_DEFAULT_GAIN);
|
||||
set_gain(uhd::TX_DIRECTION, chain_t::ONE, TX_DEFAULT_GAIN);
|
||||
set_gain(uhd::TX_DIRECTION, chain_t::TWO, TX_DEFAULT_GAIN);
|
||||
|
||||
// TODO: add calibration stuff
|
||||
}
|
||||
|
||||
void ad937x_device::_verify_product_id()
|
||||
{
|
||||
uint8_t product_id = get_product_id();
|
||||
if (product_id != AD9371_PRODUCT_ID)
|
||||
{
|
||||
@ -203,10 +176,30 @@ void ad937x_device::begin_initialization()
|
||||
% int(product_id) % int(AD9371_PRODUCT_ID)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
void ad937x_device::_verify_multichip_sync_status(multichip_sync_t mcs)
|
||||
{
|
||||
uint8_t status_expected = (mcs == multichip_sync_t::FULL) ? 0x0B : 0x0A;
|
||||
uint8_t status_mask = status_expected; // all 1s expected, mask is the same
|
||||
|
||||
uint8_t mcs_status = get_multichip_sync_status();
|
||||
if ((mcs_status & status_mask) != status_expected)
|
||||
{
|
||||
throw mpm::runtime_error(str(boost::format("Multichip sync failed! Read: %X Expected: %X")
|
||||
% int(mcs_status) % int(status_expected)));
|
||||
}
|
||||
}
|
||||
|
||||
void ad937x_device::begin_initialization()
|
||||
{
|
||||
_call_api_function(std::bind(MYKONOS_initialize, mykonos_config.device));
|
||||
|
||||
_verify_product_id();
|
||||
|
||||
if (!get_pll_lock_status(pll_t::CLK_SYNTH))
|
||||
{
|
||||
throw mpm::runtime_error("AD937x CLK_SYNTH PLL failed to lock in initialize()");
|
||||
throw mpm::runtime_error("AD937x CLK_SYNTH PLL failed to lock");
|
||||
}
|
||||
|
||||
uint8_t mcs_status = 0;
|
||||
@ -215,33 +208,24 @@ void ad937x_device::begin_initialization()
|
||||
|
||||
void ad937x_device::finish_initialization()
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||
// to check status, just call the same function with a 0 instead of a 1, seems good
|
||||
uint8_t mcs_status = 0;
|
||||
_call_api_function(std::bind(MYKONOS_enableMultichipSync, mykonos_config.device, 0, &mcs_status));
|
||||
_verify_multichip_sync_status(multichip_sync_t::PARTIAL);
|
||||
|
||||
if ((mcs_status & 0x0A) != 0x0A)
|
||||
{
|
||||
throw mpm::runtime_error(str(boost::format("Multichip sync failed! Read: %X Expected: %X")
|
||||
% int(mcs_status) % int(0x0A)));
|
||||
}
|
||||
_call_api_function(std::bind(MYKONOS_initArm, mykonos_config.device));
|
||||
auto binary = _get_arm_binary();
|
||||
_call_api_function(std::bind(MYKONOS_loadArmFromBinary,
|
||||
mykonos_config.device,
|
||||
binary.data(),
|
||||
binary.size()));
|
||||
|
||||
_call_api_function(std::bind(MYKONOS_initSubRegisterTables, mykonos_config.device));
|
||||
// according to djepson, we can call only this function and avoid loading the ARM or
|
||||
// doing an RF stuff
|
||||
// TODO: fix all this once we want to more than just loopback
|
||||
|
||||
// load ARM
|
||||
// ARM init
|
||||
// RF setup
|
||||
_initialize_rf();
|
||||
}
|
||||
|
||||
void ad937x_device::start_jesd_rx()
|
||||
void ad937x_device::start_jesd_tx()
|
||||
{
|
||||
_call_api_function(std::bind(MYKONOS_enableSysrefToRxFramer, mykonos_config.device, 1));
|
||||
}
|
||||
|
||||
void ad937x_device::start_jesd_tx()
|
||||
void ad937x_device::start_jesd_rx()
|
||||
{
|
||||
_call_api_function(std::bind(MYKONOS_enableSysrefToDeframer, mykonos_config.device, 0));
|
||||
_call_api_function(std::bind(MYKONOS_resetDeframer, mykonos_config.device));
|
||||
@ -251,6 +235,7 @@ void ad937x_device::start_jesd_tx()
|
||||
uint8_t ad937x_device::get_multichip_sync_status()
|
||||
{
|
||||
uint8_t mcs_status = 0;
|
||||
// to check status, just call the enable function with a 0 instead of a 1, seems good
|
||||
_call_api_function(std::bind(MYKONOS_enableMultichipSync, mykonos_config.device, 0, &mcs_status));
|
||||
return mcs_status;
|
||||
}
|
||||
@ -269,19 +254,11 @@ uint8_t ad937x_device::get_deframer_status()
|
||||
return status;
|
||||
}
|
||||
|
||||
uint8_t ad937x_device::get_deframer_irq()
|
||||
{
|
||||
uint8_t irq_status = 0;
|
||||
//_call_debug_api_function(std::bind(MYKONOS_deframerGetIrq, mykonos_config.device, &irq_status));
|
||||
return irq_status;
|
||||
}
|
||||
|
||||
uint16_t ad937x_device::get_ilas_config_match()
|
||||
{
|
||||
uint16_t ilas_status = 0;
|
||||
_call_api_function(std::bind(MYKONOS_jesd204bIlasCheck, mykonos_config.device, &ilas_status));
|
||||
return ilas_status;
|
||||
|
||||
}
|
||||
|
||||
void ad937x_device::enable_jesd_loopback(uint8_t enable)
|
||||
@ -351,21 +328,24 @@ void ad937x_device::enable_channel(direction_t direction, chain_t chain, bool en
|
||||
// is _initialize(). Need to figure out how to deal with this.
|
||||
}
|
||||
|
||||
double ad937x_device::tune(direction_t direction, double value)
|
||||
double ad937x_device::tune(direction_t direction, double value, bool wait_for_lock = false)
|
||||
{
|
||||
// I'm not sure why we set the PLL value in the config AND as a function parameter
|
||||
// but here it is
|
||||
|
||||
mykonosRfPllName_t pll;
|
||||
pll_t locked_pll;
|
||||
uint64_t integer_value = static_cast<uint64_t>(value);
|
||||
switch (direction)
|
||||
{
|
||||
case TX_DIRECTION:
|
||||
pll = TX_PLL;
|
||||
locked_pll = pll_t::TX_SYNTH;
|
||||
mykonos_config.device->tx->txPllLoFrequency_Hz = integer_value;
|
||||
break;
|
||||
case RX_DIRECTION:
|
||||
pll = RX_PLL;
|
||||
locked_pll = pll_t::RX_SYNTH;
|
||||
mykonos_config.device->rx->rxPllLoFrequency_Hz = integer_value;
|
||||
break;
|
||||
default:
|
||||
@ -373,11 +353,30 @@ double ad937x_device::tune(direction_t direction, double value)
|
||||
}
|
||||
|
||||
_call_api_function(std::bind(MYKONOS_setRfPllFrequency, mykonos_config.device, pll, integer_value));
|
||||
auto lock_time = std::chrono::steady_clock::now() + std::chrono::milliseconds(200);
|
||||
|
||||
// TODO: coercion here causes extra device accesses, when the formula is provided on pg 119 of the user guide
|
||||
// Furthermore, because coerced is returned as an integer, it's not even accurate
|
||||
uint64_t coerced_pll;
|
||||
_call_api_function(std::bind(MYKONOS_getRfPllFrequency, mykonos_config.device, pll, &coerced_pll));
|
||||
|
||||
if (wait_for_lock)
|
||||
{
|
||||
bool locked = false;
|
||||
while (not locked and lock_time > std::chrono::steady_clock::now())
|
||||
{
|
||||
locked = get_pll_lock_status(locked_pll);
|
||||
}
|
||||
|
||||
if (!locked)
|
||||
{
|
||||
if (!get_pll_lock_status(locked_pll)) // last chance
|
||||
{
|
||||
throw mpm::runtime_error("RF PLL did not lock");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return static_cast<double>(coerced_pll);
|
||||
}
|
||||
|
||||
@ -403,6 +402,7 @@ bool ad937x_device::get_pll_lock_status(pll_t pll)
|
||||
{
|
||||
uint8_t pll_status;
|
||||
_call_api_function(std::bind(MYKONOS_checkPllsLockStatus, mykonos_config.device, &pll_status));
|
||||
|
||||
switch (pll)
|
||||
{
|
||||
case pll_t::CLK_SYNTH:
|
||||
|
||||
@ -30,6 +30,7 @@
|
||||
#include <mpm/spi/spi_iface.hpp>
|
||||
#include <mpm/exception.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
|
||||
@ -37,7 +38,7 @@ class ad937x_device : public boost::noncopyable
|
||||
{
|
||||
public:
|
||||
enum class gain_mode_t { MANUAL, AUTOMATIC, HYBRID };
|
||||
enum class pll_t {CLK_SYNTH, RX_SYNTH, TX_SYNTH, SNIFF_SYNTH, CALPLL_SDM};
|
||||
enum class pll_t { CLK_SYNTH, RX_SYNTH, TX_SYNTH, SNIFF_SYNTH, CALPLL_SDM };
|
||||
|
||||
ad937x_device(
|
||||
mpm::types::regs_iface* iface,
|
||||
@ -48,13 +49,10 @@ public:
|
||||
void finish_initialization();
|
||||
void start_jesd_rx();
|
||||
void start_jesd_tx();
|
||||
|
||||
uint8_t get_multichip_sync_status();
|
||||
uint8_t get_framer_status();
|
||||
uint8_t get_deframer_status();
|
||||
|
||||
// debug functions for JESD
|
||||
// TODO: make these returns useful
|
||||
uint8_t get_deframer_irq();
|
||||
uint16_t get_ilas_config_match();
|
||||
void enable_jesd_loopback(uint8_t enable);
|
||||
|
||||
@ -68,7 +66,7 @@ public:
|
||||
void set_agc_mode(uhd::direction_t direction, gain_mode_t mode);
|
||||
double set_clock_rate(double value);
|
||||
void enable_channel(uhd::direction_t direction, mpm::ad937x::device::chain_t chain, bool enable);
|
||||
double tune(uhd::direction_t direction, double value);
|
||||
double tune(uhd::direction_t direction, double value, bool wait_for_lock);
|
||||
double get_freq(uhd::direction_t direction);
|
||||
|
||||
bool get_pll_lock_status(pll_t pll);
|
||||
@ -91,6 +89,8 @@ public:
|
||||
const static double TX_GAIN_STEP;
|
||||
|
||||
private:
|
||||
enum class multichip_sync_t { PARTIAL, FULL };
|
||||
|
||||
ad9371_spiSettings_t full_spi_settings;
|
||||
ad937x_config_t mykonos_config;
|
||||
ad937x_gain_ctrl_config_t gain_ctrl;
|
||||
@ -99,7 +99,13 @@ private:
|
||||
|
||||
void _call_api_function(std::function<mykonosErr_t()> func);
|
||||
void _call_gpio_api_function(std::function<mykonosGpioErr_t()> func);
|
||||
//void _call_debug_api_function(std::function<mykonosDbgErr_t()> func);
|
||||
|
||||
std::string _get_arm_binary_path();
|
||||
std::vector<uint8_t> _get_arm_binary();
|
||||
|
||||
void _initialize_rf();
|
||||
void _verify_product_id();
|
||||
void _verify_multichip_sync_status(multichip_sync_t mcs);
|
||||
|
||||
static uint8_t _convert_rx_gain(double gain);
|
||||
static uint16_t _convert_tx_gain(double gain);
|
||||
|
||||
@ -199,7 +199,7 @@ static const mykonosObsRxSettings_t DEFAULT_ORX_SETTINGS =
|
||||
nullptr, // Sniffer datapath profile, 3dB corner frequencies, and digital filter enables
|
||||
nullptr, // SnRx gain control settings structure
|
||||
nullptr, // ObsRx JESD204b framer configuration structure
|
||||
MYK_OBS_RXOFF, // obsRxChannel
|
||||
MYK_ORX1, // obsRxChannel TODO: fix this garbage please
|
||||
OBSLO_TX_PLL, // (obsRxLoSource) The Obs Rx mixer can use the Tx Synth(TX_PLL) or Sniffer Synth (SNIFFER_PLL)
|
||||
2600000000U, // SnRx PLL LO frequency in Hz
|
||||
0, // Flag to choose if complex baseband or real IF data are selected for Rx and ObsRx paths. Where if > 0 = real IF data, '0' = complex data
|
||||
|
||||
@ -64,8 +64,9 @@ class Magnesium(DboardManagerBase):
|
||||
spi_chipselect = {"lmk": 0, "mykonos": 1}
|
||||
|
||||
def __init__(self, slot_idx, **kwargs):
|
||||
super(Magnesium, self).__init__(*args, **kwargs)
|
||||
self.log = get_logger("Magnesium")
|
||||
super(Magnesium, self).__init__(slot_idx, **kwargs)
|
||||
self.log = get_logger("Magnesium-{}".format(slot_idx))
|
||||
self.log.trace("Initializing Magnesium daughterboard, slot index {}".format(self.slot_idx))
|
||||
|
||||
def init(self, args):
|
||||
"""
|
||||
@ -88,6 +89,7 @@ class Magnesium(DboardManagerBase):
|
||||
self.radio_regs = UIO(label="jesd204b-regs", read_only=False)
|
||||
self.log.info("Radio-register UIO object successfully generated!")
|
||||
self.init_jesd(self.radio_regs)
|
||||
return True
|
||||
|
||||
def init_jesd(self, uio):
|
||||
"""
|
||||
@ -117,14 +119,14 @@ class Magnesium(DboardManagerBase):
|
||||
self.mykonos.finish_initialization()
|
||||
|
||||
self.log.trace("Starting Mykonos framer...")
|
||||
self.mykonos.start_jesd_rx()
|
||||
self.mykonos.start_jesd_tx()
|
||||
self.jesdcore.send_sysref_pulse()
|
||||
self.log.trace("Resetting FPGA deframer...")
|
||||
self.jesdcore.init_deframer()
|
||||
self.log.trace("Resetting FPGA framer...")
|
||||
self.jesdcore.init_framer()
|
||||
self.log.trace("Starting Mykonos deframer...")
|
||||
self.mykonos.start_jesd_tx()
|
||||
self.mykonos.start_jesd_rx()
|
||||
|
||||
self.log.trace("Enable LMFC and send")
|
||||
self.jesdcore.enable_lmfc()
|
||||
|
||||
Loading…
Reference in New Issue
Block a user