aboutsummaryrefslogtreecommitdiffstats
path: root/mpm/lib/mykonos/ad937x_device.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'mpm/lib/mykonos/ad937x_device.cpp')
-rw-r--r--mpm/lib/mykonos/ad937x_device.cpp610
1 files changed, 385 insertions, 225 deletions
diff --git a/mpm/lib/mykonos/ad937x_device.cpp b/mpm/lib/mykonos/ad937x_device.cpp
index e9815112e..511a0a0a1 100644
--- a/mpm/lib/mykonos/ad937x_device.cpp
+++ b/mpm/lib/mykonos/ad937x_device.cpp
@@ -45,56 +45,61 @@ 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;
-
-// TODO: move this to whereever we declare the ARM binary
+static const uint32_t AD9371_PRODUCT_ID = 0x3;
static const size_t ARM_BINARY_SIZE = 98304;
+static const size_t PLL_LOCK_TIMEOUT_MS = 200;
static const uint32_t INIT_CAL_TIMEOUT_MS = 10000;
// TODO: actually figure out what cals we want to run
+// minimum required cals are 0x4F
static const uint32_t INIT_CALS =
TX_BB_FILTER |
ADC_TUNER |
TIA_3DB_CORNER |
DC_OFFSET |
- TX_ATTENUATION_DELAY |
- RX_GAIN_DELAY |
+// TX_ATTENUATION_DELAY |
+// RX_GAIN_DELAY |
FLASH_CAL |
- PATH_DELAY |
- TX_LO_LEAKAGE_INTERNAL |
-// TX_LO_LEAKAGE_EXTERNAL |
- TX_QEC_INIT |
- LOOPBACK_RX_LO_DELAY |
- LOOPBACK_RX_RX_QEC_INIT |
- RX_LO_DELAY |
- RX_QEC_INIT |
-// DPD_INIT |
-// CLGC_INIT |
-// VSWR_INIT |
+// PATH_DELAY |
+// TX_LO_LEAKAGE_INTERNAL |
+//// TX_LO_LEAKAGE_EXTERNAL |
+// TX_QEC_INIT |
+// LOOPBACK_RX_LO_DELAY |
+// LOOPBACK_RX_RX_QEC_INIT |
+// RX_LO_DELAY |
+// RX_QEC_INIT |
+//// DPD_INIT |
+//// CLGC_INIT |
+//// VSWR_INIT |
0;
static const uint32_t TRACKING_CALS =
- TRACK_RX1_QEC |
- TRACK_RX2_QEC |
- TRACK_ORX1_QEC |
- TRACK_ORX2_QEC |
-// TRACK_TX1_LOL |
-// TRACK_TX2_LOL |
- TRACK_TX1_QEC |
- TRACK_TX2_QEC |
-// TRACK_TX1_DPD |
-// TRACK_TX2_DPD |
-// TRACK_TX1_CLGC |
-// TRACK_TX2_CLGC |
-// TRACK_TX1_VSWR |
-// TRACK_TX2_VSWR |
-// TRACK_ORX1_QEC_SNLO |
-// TRACK_ORX2_QEC_SNLO |
-// TRACK_SRX_QEC |
+// TRACK_RX1_QEC |
+// TRACK_RX2_QEC |
+// TRACK_ORX1_QEC |
+// TRACK_ORX2_QEC |
+//// TRACK_TX1_LOL |
+//// TRACK_TX2_LOL |
+// TRACK_TX1_QEC |
+// TRACK_TX2_QEC |
+//// TRACK_TX1_DPD |
+//// TRACK_TX2_DPD |
+//// TRACK_TX1_CLGC |
+//// TRACK_TX2_CLGC |
+//// TRACK_TX1_VSWR |
+//// TRACK_TX2_VSWR |
+//// TRACK_ORX1_QEC_SNLO |
+//// TRACK_ORX2_QEC_SNLO |
+//// TRACK_SRX_QEC |
0;
+
+
+/******************************************************
+Helper functions
+******************************************************/
+
// helper function to unify error handling
void ad937x_device::_call_api_function(std::function<mykonosErr_t()> func)
{
@@ -115,6 +120,37 @@ void ad937x_device::_call_gpio_api_function(std::function<mykonosGpioErr_t()> fu
}
}
+// _move_to_config_state() and _restore_from_config_state() are a pair of functions
+// that should be called at the beginning and end (respectively) of any configuration
+// function that requires the AD9371 to be in the radioOff state. _restore should be
+// called with the return value of _move.
+
+// read the current state of the AD9371 and change it to radioOff (READY)
+// returns the current state, to later be consumed by _restore_from_config_state()
+ad937x_device::radio_state_t ad937x_device::_move_to_config_state()
+{
+ uint32_t status;
+ _call_api_function(std::bind(MYKONOS_getRadioState, mykonos_config.device, &status));
+ if ((status & 0x3) == 0x3)
+ {
+ stop_radio();
+ return radio_state_t::ON;
+ }
+ else {
+ return radio_state_t::OFF;
+ }
+}
+
+// restores the state from before a call to _move_to_config_state
+// if ON, move to radioOn, otherwise this function is a no-op
+void ad937x_device::_restore_from_config_state(ad937x_device::radio_state_t state)
+{
+ if (state == radio_state_t::ON)
+ {
+ start_radio();
+ }
+}
+
std::string ad937x_device::_get_arm_binary_path()
{
// TODO: possibly add more options here, for now it's always in /lib/firmware or we explode
@@ -128,44 +164,20 @@ std::vector<uint8_t> ad937x_device::_get_arm_binary()
if (!file.is_open())
{
throw mpm::runtime_error("Could not open AD9371 ARM binary at path " + path);
- return{};
+ return {};
}
+ // TODO: add check that opened file size is equal to ARM_BINARY_SIZE
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 {};
}
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();
@@ -191,13 +203,166 @@ void ad937x_device::_verify_multichip_sync_status(multichip_sync_t mcs)
}
}
+// RX Gain values are table entries given in mykonos_user.h
+// An array of gain values is programmed at initialization, which the API will then use for its gain values
+// In general, Gain Value = (255 - Gain Table Index)
+uint8_t ad937x_device::_convert_rx_gain_to_mykonos(double gain)
+{
+ // TODO: derive 195 constant from gain table
+ // gain should be a value 0-60, add 195 to make 195-255
+ return static_cast<uint8_t>((gain * 2) + 195);
+}
+
+double ad937x_device::_convert_rx_gain_from_mykonos(uint8_t gain)
+{
+ return (static_cast<double>(gain) - 195) / 2.0;
+}
+
+// TX gain is completely different from RX gain for no good reason so deal with it
+// TX is set as attenuation using a value from 0-41950 mdB
+// Only increments of 50 mdB are valid
+uint16_t ad937x_device::_convert_tx_gain_to_mykonos(double gain)
+{
+ // attenuation is inverted and in mdB not dB
+ return static_cast<uint16_t>((MAX_TX_GAIN - (gain)) * 1e3);
+}
+
+double ad937x_device::_convert_tx_gain_from_mykonos(uint16_t gain)
+{
+ return (MAX_TX_GAIN - (static_cast<double>(gain) / 1e3));
+}
+
+void ad937x_device::_apply_gain_pins(direction_t direction, chain_t chain)
+{
+ using namespace std::placeholders;
+
+ // get this channels configuration
+ auto chan = gain_ctrl.config.at(direction).at(chain);
+
+ // TX direction does not support different steps per direction
+ if (direction == TX_DIRECTION)
+ {
+ MPM_ASSERT_THROW(chan.inc_step == chan.dec_step);
+ }
+
+ auto state = _move_to_config_state();
+
+ switch (direction)
+ {
+ case RX_DIRECTION:
+ {
+ std::function<decltype(MYKONOS_setRx1GainCtrlPin)> func;
+ switch (chain)
+ {
+ case chain_t::ONE:
+ func = MYKONOS_setRx1GainCtrlPin;
+ break;
+ case chain_t::TWO:
+ func = MYKONOS_setRx2GainCtrlPin;
+ break;
+ }
+ _call_gpio_api_function(
+ std::bind(func,
+ mykonos_config.device,
+ chan.inc_step,
+ chan.dec_step,
+ chan.inc_pin,
+ chan.dec_pin,
+ chan.enable));
+ break;
+ }
+ case TX_DIRECTION:
+ {
+ // TX sets attenuation, but the configuration should be stored correctly
+ std::function<decltype(MYKONOS_setTx2AttenCtrlPin)> func;
+ switch (chain)
+ {
+ case chain_t::ONE:
+ // TX1 has an extra parameter "useTx1ForTx2" that we do not support
+ func = std::bind(MYKONOS_setTx1AttenCtrlPin, _1, _2, _3, _4, _5, 0);
+ break;
+ case chain_t::TWO:
+ func = MYKONOS_setTx2AttenCtrlPin;
+ break;
+ }
+ _call_gpio_api_function(
+ std::bind(func,
+ mykonos_config.device,
+ chan.inc_step,
+ chan.inc_pin,
+ chan.dec_pin,
+ chan.enable));
+ break;
+ }
+ }
+ _restore_from_config_state(state);
+}
+
+
+
+/******************************************************
+Initialization functions
+******************************************************/
+
+ad937x_device::ad937x_device(
+ mpm::types::regs_iface* iface,
+ gain_pins_t gain_pins) :
+ full_spi_settings(iface),
+ mykonos_config(&full_spi_settings.spi_settings),
+ gain_ctrl(gain_pins)
+{
+}
+
+void ad937x_device::_initialize_rf()
+{
+ // TODO: add setRfPllLoopFilter here when we upgrade the API to >3546
+
+ // Set frequencies
+ tune(uhd::RX_DIRECTION, RX_DEFAULT_FREQ, false);
+ tune(uhd::TX_DIRECTION, TX_DEFAULT_FREQ, false);
+
+ if (!get_pll_lock_status(CLK_SYNTH | RX_SYNTH | TX_SYNTH | SNIFF_SYNTH, true))
+ {
+ throw mpm::runtime_error("PLLs did not lock after initial tuning!");
+ }
+
+ // 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);
+
+ _call_gpio_api_function(std::bind(MYKONOS_setupGpio, mykonos_config.device));
+
+ // 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);
+
+ // Run and wait for init cals
+ _call_api_function(std::bind(MYKONOS_runInitCals, mykonos_config.device, INIT_CALS));
+
+ uint8_t errorFlag = 0, errorCode = 0;
+ _call_api_function(std::bind(MYKONOS_waitInitCals, mykonos_config.device, INIT_CAL_TIMEOUT_MS, &errorFlag, &errorCode));
+
+ if ((errorFlag != 0) || (errorCode != 0))
+ {
+ throw mpm::runtime_error("Init cals failed!");
+ // TODO: add more debugging information here
+ }
+
+ _call_api_function(std::bind(MYKONOS_enableTrackingCals, mykonos_config.device, TRACKING_CALS));
+ // ready for radioOn
+}
+
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))
+ if (!get_pll_lock_status(CLK_SYNTH))
{
throw mpm::runtime_error("AD937x CLK_SYNTH PLL failed to lock");
}
@@ -232,6 +397,22 @@ void ad937x_device::start_jesd_rx()
_call_api_function(std::bind(MYKONOS_enableSysrefToDeframer, mykonos_config.device, 1));
}
+void ad937x_device::start_radio()
+{
+ _call_api_function(std::bind(MYKONOS_radioOn, mykonos_config.device));
+}
+
+void ad937x_device::stop_radio()
+{
+ _call_api_function(std::bind(MYKONOS_radioOff, mykonos_config.device));
+}
+
+
+
+/******************************************************
+Get status functions
+******************************************************/
+
uint8_t ad937x_device::get_multichip_sync_status()
{
uint8_t mcs_status = 0;
@@ -261,21 +442,6 @@ uint16_t ad937x_device::get_ilas_config_match()
return ilas_status;
}
-void ad937x_device::enable_jesd_loopback(uint8_t enable)
-{
- _call_api_function(std::bind(MYKONOS_setRxFramerDataSource, mykonos_config.device, enable));
-}
-
-ad937x_device::ad937x_device(
- mpm::types::regs_iface* iface,
- gain_pins_t gain_pins
-) :
- full_spi_settings(iface),
- mykonos_config(&full_spi_settings.spi_settings),
- gain_ctrl(gain_pins)
-{
-}
-
uint8_t ad937x_device::get_product_id()
{
uint8_t id;
@@ -313,11 +479,28 @@ arm_version_t ad937x_device::get_arm_version()
return arm;
}
+
+
+/******************************************************
+Set configuration functions
+******************************************************/
+
+void ad937x_device::enable_jesd_loopback(uint8_t enable)
+{
+ auto state = _move_to_config_state();
+ _call_api_function(std::bind(MYKONOS_setRxFramerDataSource, mykonos_config.device, enable));
+ _restore_from_config_state(state);
+}
+
double ad937x_device::set_clock_rate(double req_rate)
{
auto rate = static_cast<uint32_t>(req_rate / 1000.0);
+
+ auto state = _move_to_config_state();
mykonos_config.device->clocks->deviceClock_kHz = rate;
_call_api_function(std::bind(MYKONOS_initDigitalClocks, mykonos_config.device));
+ _restore_from_config_state(state);
+
return static_cast<double>(rate);
}
@@ -326,6 +509,9 @@ void ad937x_device::enable_channel(direction_t direction, chain_t chain, bool en
// TODO:
// Turns out the only code in the API that actually sets the channel enable settings
// is _initialize(). Need to figure out how to deal with this.
+ // mmeserve 8/24/2017
+ // While it is possible to change the enable state after disabling the radio, we'll probably
+ // always use the GPIO pins to do so. Delete this function at a later time.
}
double ad937x_device::tune(direction_t direction, double value, bool wait_for_lock = false)
@@ -334,91 +520,39 @@ double ad937x_device::tune(direction_t direction, double value, bool wait_for_lo
// but here it is
mykonosRfPllName_t pll;
- pll_t locked_pll;
+ uint8_t locked_pll;
+ uint64_t* config_value;
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;
+ locked_pll = TX_SYNTH;
+ config_value = &(mykonos_config.device->tx->txPllLoFrequency_Hz);
break;
case RX_DIRECTION:
pll = RX_PLL;
- locked_pll = pll_t::RX_SYNTH;
- mykonos_config.device->rx->rxPllLoFrequency_Hz = integer_value;
+ locked_pll = RX_SYNTH;
+ config_value = &(mykonos_config.device->rx->rxPllLoFrequency_Hz);
break;
default:
MPM_THROW_INVALID_CODE_PATH();
}
+ auto state = _move_to_config_state();
+ *config_value = integer_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, true))
{
- if (!get_pll_lock_status(locked_pll)) // last chance
- {
- throw mpm::runtime_error("RF PLL did not lock");
- }
+ throw mpm::runtime_error("PLL did not lock");
}
}
+ _restore_from_config_state(state);
- return static_cast<double>(coerced_pll);
-}
-
-double ad937x_device::get_freq(direction_t direction)
-{
- mykonosRfPllName_t pll;
- switch (direction)
- {
- case TX_DIRECTION: pll = TX_PLL; break;
- case RX_DIRECTION: pll = RX_PLL; break;
- default:
- MPM_THROW_INVALID_CODE_PATH();
- }
-
- // 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));
- return static_cast<double>(coerced_pll);
-}
-
-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:
- return (pll_status & 0x01) > 0;
- case pll_t::RX_SYNTH:
- return (pll_status & 0x02) > 0;
- case pll_t::TX_SYNTH:
- return (pll_status & 0x04) > 0;
- case pll_t::SNIFF_SYNTH:
- return (pll_status & 0x08) > 0;
- case pll_t::CALPLL_SDM:
- return (pll_status & 0x10) > 0;
- default:
- MPM_THROW_INVALID_CODE_PATH();
- return false;
- }
+ return get_freq(direction);
}
double ad937x_device::set_bw_filter(direction_t direction, chain_t chain, double value)
@@ -427,33 +561,16 @@ double ad937x_device::set_bw_filter(direction_t direction, chain_t chain, double
return double();
}
-// RX Gain values are table entries given in mykonos_user.h
-// An array of gain values is programmed at initialization, which the API will then use for its gain values
-// In general, Gain Value = (255 - Gain Table Index)
-uint8_t ad937x_device::_convert_rx_gain(double gain)
-{
- // gain should be a value 0-60, add 195 to make 195-255
- return static_cast<uint8_t>((gain * 2) + 195);
-}
-
-// TX gain is completely different from RX gain for no good reason so deal with it
-// TX is set as attenuation using a value from 0-41950 mdB
-// Only increments of 50 mdB are valid
-uint16_t ad937x_device::_convert_tx_gain(double gain)
-{
- // attenuation is inverted and in mdB not dB
- return static_cast<uint16_t>((MAX_TX_GAIN - (gain)) * 1e3);
-}
-
double ad937x_device::set_gain(direction_t direction, chain_t chain, double value)
{
double coerced_value;
+ auto state = _move_to_config_state();
switch (direction)
{
case TX_DIRECTION:
{
- uint16_t attenuation = _convert_tx_gain(value);
+ uint16_t attenuation = _convert_tx_gain_to_mykonos(value);
coerced_value = static_cast<double>(attenuation);
std::function<mykonosErr_t(mykonosDevice_t*, uint16_t)> func;
@@ -473,7 +590,7 @@ double ad937x_device::set_gain(direction_t direction, chain_t chain, double valu
}
case RX_DIRECTION:
{
- uint8_t gain = _convert_rx_gain(value);
+ uint8_t gain = _convert_rx_gain_to_mykonos(value);
coerced_value = static_cast<double>(gain);
std::function<mykonosErr_t(mykonosDevice_t*, uint8_t)> func;
@@ -494,31 +611,40 @@ double ad937x_device::set_gain(direction_t direction, chain_t chain, double valu
default:
MPM_THROW_INVALID_CODE_PATH();
}
+
+ _restore_from_config_state(state);
+ // TODO: coerced_value here is wrong, should just call get_gain
return coerced_value;
}
void ad937x_device::set_agc_mode(direction_t direction, gain_mode_t mode)
{
+ mykonosGainMode_t mykonos_mode;
switch (direction)
{
case RX_DIRECTION:
switch (mode)
{
case gain_mode_t::MANUAL:
- _call_api_function(std::bind(MYKONOS_setRxGainControlMode, mykonos_config.device, MGC));
+ mykonos_mode = MGC;
break;
case gain_mode_t::AUTOMATIC:
- _call_api_function(std::bind(MYKONOS_setRxGainControlMode, mykonos_config.device, AGC));
+ mykonos_mode = AGC;
break;
case gain_mode_t::HYBRID:
- _call_api_function(std::bind(MYKONOS_setRxGainControlMode, mykonos_config.device, HYBRID));
+ mykonos_mode = HYBRID;
break;
default:
MPM_THROW_INVALID_CODE_PATH();
}
+ break;
default:
MPM_THROW_INVALID_CODE_PATH();
}
+
+ auto state = _move_to_config_state();
+ _call_api_function(std::bind(MYKONOS_setRxGainControlMode, mykonos_config.device, mykonos_mode));
+ _restore_from_config_state(state);
}
void ad937x_device::set_fir(
@@ -538,30 +664,26 @@ void ad937x_device::set_fir(
default:
MPM_THROW_INVALID_CODE_PATH();
}
+
+ // TODO: reload this on device
}
-std::vector<int16_t> ad937x_device::get_fir(
- const direction_t direction,
- const chain_t chain,
- int8_t &gain)
+void ad937x_device::set_gain_pin_step_sizes(direction_t direction, chain_t chain, double inc_step, double dec_step)
{
- switch (direction)
+ if (direction == RX_DIRECTION)
{
- case TX_DIRECTION:
- return mykonos_config.tx_fir_config.get_fir(gain);
- case RX_DIRECTION:
- return mykonos_config.rx_fir_config.get_fir(gain);
- default:
+ gain_ctrl.config.at(direction).at(chain).inc_step = static_cast<uint8_t>(inc_step / 0.5);
+ gain_ctrl.config.at(direction).at(chain).dec_step = static_cast<uint8_t>(dec_step / 0.5);
+ }
+ else if (direction == TX_DIRECTION) {
+ // !!! TX is attenuation direction, so the pins are flipped !!!
+ gain_ctrl.config.at(direction).at(chain).dec_step = static_cast<uint8_t>(inc_step / 0.05);
+ gain_ctrl.config.at(direction).at(chain).inc_step = static_cast<uint8_t>(dec_step / 0.05);
+ }
+ else {
MPM_THROW_INVALID_CODE_PATH();
}
-}
-
-int16_t ad937x_device::get_temperature()
-{
- // TODO: deal with the status.tempValid flag
- mykonosTempSensorStatus_t status;
- _call_gpio_api_function(std::bind(MYKONOS_readTempSensor, mykonos_config.device, &status));
- return status.tempCode;
+ _apply_gain_pins(direction, chain);
}
void ad937x_device::set_enable_gain_pins(direction_t direction, chain_t chain, bool enable)
@@ -570,80 +692,118 @@ void ad937x_device::set_enable_gain_pins(direction_t direction, chain_t chain, b
_apply_gain_pins(direction, chain);
}
-void ad937x_device::set_gain_pin_step_sizes(direction_t direction, chain_t chain, double inc_step, double dec_step)
+
+
+/******************************************************
+Get configuration functions
+******************************************************/
+
+double ad937x_device::get_freq(direction_t direction)
{
- if (direction == RX_DIRECTION)
+ mykonosRfPllName_t pll;
+ switch (direction)
{
- gain_ctrl.config.at(direction).at(chain).inc_step = static_cast<uint8_t>(inc_step / 0.5);
- gain_ctrl.config.at(direction).at(chain).dec_step = static_cast<uint8_t>(dec_step / 0.5);
- } else if (direction == TX_DIRECTION) {
- // !!! TX is attenuation direction, so the pins are flipped !!!
- gain_ctrl.config.at(direction).at(chain).dec_step = static_cast<uint8_t>(inc_step / 0.05);
- gain_ctrl.config.at(direction).at(chain).inc_step = static_cast<uint8_t>(dec_step / 0.05);
- } else {
+ case TX_DIRECTION: pll = TX_PLL; break;
+ case RX_DIRECTION: pll = RX_PLL; break;
+ default:
MPM_THROW_INVALID_CODE_PATH();
}
- _apply_gain_pins(direction, chain);
+
+ // 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));
+ return static_cast<double>(coerced_pll);
}
-void ad937x_device::_apply_gain_pins(direction_t direction, chain_t chain)
+bool ad937x_device::get_pll_lock_status(uint8_t pll, bool wait_for_lock)
{
- using namespace std::placeholders;
-
- // get this channels configuration
- auto chan = gain_ctrl.config.at(direction).at(chain);
+ uint8_t pll_status;
+ _call_api_function(std::bind(MYKONOS_checkPllsLockStatus, mykonos_config.device, &pll_status));
- // TX direction does not support different steps per direction
- if (direction == TX_DIRECTION)
+ if (not wait_for_lock)
{
- MPM_ASSERT_THROW(chan.inc_step == chan.dec_step);
+ return (pll_status & pll) == pll;
}
+ else {
+ auto lock_time = std::chrono::steady_clock::now() + std::chrono::milliseconds(PLL_LOCK_TIMEOUT_MS);
+ bool locked = false;
+ while (not locked and lock_time > std::chrono::steady_clock::now())
+ {
+ locked = get_pll_lock_status(pll);
+ }
+ if (!locked)
+ {
+ // last chance
+ locked = get_pll_lock_status(pll);
+ }
+ return locked;
+ }
+}
+
+double ad937x_device::get_gain(direction_t direction, chain_t chain)
+{
switch (direction)
{
- case RX_DIRECTION:
+ case TX_DIRECTION:
{
- std::function<decltype(MYKONOS_setRx1GainCtrlPin)> func;
+ std::function<mykonosErr_t(mykonosDevice_t*, uint16_t*)> func;
switch (chain)
{
case chain_t::ONE:
- func = MYKONOS_setRx1GainCtrlPin;
+ func = MYKONOS_getTx1Attenuation;
break;
case chain_t::TWO:
- func = MYKONOS_setRx2GainCtrlPin;
+ func = MYKONOS_getTx2Attenuation;
break;
}
- _call_gpio_api_function(
- std::bind(func,
- mykonos_config.device,
- chan.inc_step,
- chan.dec_step,
- chan.inc_pin,
- chan.dec_pin,
- chan.enable));
+ uint16_t atten;
+ _call_api_function(std::bind(func, mykonos_config.device, &atten));
+ return _convert_tx_gain_from_mykonos(atten);
}
- case TX_DIRECTION:
+ case RX_DIRECTION:
{
- // TX sets attenuation, but the configuration should be stored correctly
- std::function<decltype(MYKONOS_setTx2AttenCtrlPin)> func;
+ std::function<mykonosErr_t(mykonosDevice_t*, uint8_t*)> func;
switch (chain)
{
case chain_t::ONE:
- // TX1 has an extra parameter "useTx1ForTx2" that we do not support
- func = std::bind(MYKONOS_setTx1AttenCtrlPin, _1, _2, _3, _4, _5, 0);
+ func = MYKONOS_getRx1Gain;
break;
case chain_t::TWO:
- func = MYKONOS_setTx2AttenCtrlPin;
+ func = MYKONOS_getRx2Gain;
break;
}
- _call_gpio_api_function(
- std::bind(func,
- mykonos_config.device,
- chan.inc_step,
- chan.inc_pin,
- chan.dec_pin,
- chan.enable));
+ uint8_t gain;
+ _call_api_function(std::bind(func, mykonos_config.device, &gain));
+ return _convert_rx_gain_from_mykonos(gain);
}
+ default:
+ MPM_THROW_INVALID_CODE_PATH();
}
}
+std::vector<int16_t> ad937x_device::get_fir(
+ const direction_t direction,
+ const chain_t chain,
+ int8_t &gain)
+{
+ switch (direction)
+ {
+ case TX_DIRECTION:
+ return mykonos_config.tx_fir_config.get_fir(gain);
+ case RX_DIRECTION:
+ return mykonos_config.rx_fir_config.get_fir(gain);
+ default:
+ MPM_THROW_INVALID_CODE_PATH();
+ }
+}
+
+int16_t ad937x_device::get_temperature()
+{
+ // TODO: deal with the status.tempValid flag
+ mykonosTempSensorStatus_t status;
+ _call_gpio_api_function(std::bind(MYKONOS_readTempSensor, mykonos_config.device, &status));
+ return status.tempCode;
+}
+