aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib/usrp
diff options
context:
space:
mode:
Diffstat (limited to 'host/lib/usrp')
-rw-r--r--host/lib/usrp/dboard/eiscat/eiscat_radio_ctrl_impl.cpp244
-rw-r--r--host/lib/usrp/dboard/eiscat/eiscat_radio_ctrl_impl.hpp3
2 files changed, 219 insertions, 28 deletions
diff --git a/host/lib/usrp/dboard/eiscat/eiscat_radio_ctrl_impl.cpp b/host/lib/usrp/dboard/eiscat/eiscat_radio_ctrl_impl.cpp
index 3912e4f32..73851656b 100644
--- a/host/lib/usrp/dboard/eiscat/eiscat_radio_ctrl_impl.cpp
+++ b/host/lib/usrp/dboard/eiscat/eiscat_radio_ctrl_impl.cpp
@@ -22,7 +22,7 @@ using namespace uhd::rfnoc;
namespace {
const size_t SR_ANTENNA_GAIN_BASE = 204;
const size_t SR_ANTENNA_SELECT_BASE = 192; // Note: On other dboards, 192 is DB_GPIO address space
- const size_t RB_CHOOSE_BEAMS = 10;
+ const size_t RB_CHOOSE_BEAMS = 11;
const double EISCAT_TICK_RATE = 208e6; // Hz
const double EISCAT_RADIO_RATE = 104e6; // Hz
@@ -33,9 +33,11 @@ namespace {
const size_t EISCAT_NUM_ANTENNAS = 16;
const size_t EISCAT_NUM_BEAMS = 10;
const size_t EISCAT_NUM_PORTS = 5;
- const size_t EISCAT_GAIN_RANGE = 18; // Bits, *signed*.
- const int32_t EISCAT_MAX_GAIN = (1<<(EISCAT_GAIN_RANGE-1))-1;
- const int32_t EISCAT_MIN_GAIN = -(1<<(EISCAT_GAIN_RANGE-1));
+ const size_t EISCAT_MAX_GAIN_RANGE = 18; // Bits, *signed*.
+ const size_t EISCAT_UNIT_GAIN_RANGE = 14; // Bits, *signed*.
+ const int32_t EISCAT_MAX_GAIN = (1<<(EISCAT_MAX_GAIN_RANGE-1))-1;
+ const int32_t EISCAT_UNIT_GAIN = (1<<(EISCAT_UNIT_GAIN_RANGE-1))-1;
+ const int32_t EISCAT_MIN_GAIN = -(1<<(EISCAT_MAX_GAIN_RANGE-1));
const double EISCAT_DEFAULT_NORM_GAIN = 1.0; // Normalized. This is the actual digital gain value.
const size_t EISCAT_BITS_PER_TAP = 18;
const eiscat_radio_ctrl_impl::fir_tap_t EISCAT_MAX_TAP_VALUE = (1<<(EISCAT_BITS_PER_TAP-1))-1;
@@ -70,6 +72,10 @@ UHD_RFNOC_RADIO_BLOCK_CONSTRUCTOR(eiscat_radio_ctrl)
radio_ctrl_impl::set_rx_gain(EISCAT_DEFAULT_NULL_GAIN, chan);
radio_ctrl_impl::set_rx_antenna(EISCAT_DEFAULT_ANTENNA, chan);
radio_ctrl_impl::set_rx_bandwidth(EISCAT_DEFAULT_BANDWIDTH, chan);
+ // We might get tx async messages from upstream radios, we send them to the
+ // nevernever by default or they interfere with our streamers or ctrl_iface
+ // objects. The assumption is that FF:FF is never a valid SID.
+ this->sr_write(uhd::rfnoc::SR_RESP_IN_DST_SID, 0xFFFF, chan);
}
/**** Set up arg-based control API **************************************/
@@ -169,7 +175,7 @@ UHD_RFNOC_RADIO_BLOCK_CONSTRUCTOR(eiscat_radio_ctrl)
for (size_t i = 0; i < EISCAT_NUM_ANTENNAS; i++) {
_tree->access<double>(get_arg_path("gain", i) / "value")
.set_coercer([](double gain){
- return std::max(-1.0, std::min(1.0, gain));
+ return std::max(-16.0, std::min(16.0, gain));
})
.add_coerced_subscriber([this, i](double gain){
this->set_antenna_gain(i, gain);
@@ -268,6 +274,28 @@ UHD_RFNOC_RADIO_BLOCK_CONSTRUCTOR(eiscat_radio_ctrl)
;
}
+ for (size_t i = 0; i < EISCAT_NUM_PORTS; i++) {
+ _tree->create<uhd::time_spec_t>(get_arg_path("pseudo_stream_cmd", i) / "value")
+ .add_coerced_subscriber([this, i](uhd::time_spec_t stream_time){
+ if (stream_time != uhd::time_spec_t(0.0)) {
+ uhd::stream_cmd_t cmd(uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS);
+ cmd.stream_now = false;
+ cmd.time_spec = stream_time;
+ this->issue_stream_cmd(cmd, i);
+ } else {
+ this->issue_stream_cmd(
+ uhd::stream_cmd_t(uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS),
+ i
+ );
+ }
+ })
+ ;
+ }
+ //FIXME elaborate this more, but for now it works.
+ _tree->create<int>("rx_codecs/A/gains");
+ _tree->create<std::string>("rx_codecs/A/name").set("ADS54J66");
+
+
// There is only ever one EISCAT radio per mboard, so this should be unset
// when we reach this line:
UHD_ASSERT_THROW(not _tree->exists("tick_rate"));
@@ -295,7 +323,7 @@ void eiscat_radio_ctrl_impl::set_rx_antenna(
const std::string &ant,
const size_t port
) {
- UHD_ASSERT_THROW(port < EISCAT_NUM_PORTS);
+ UHD_ASSERT_THROW(port < EISCAT_NUM_BEAMS);
if (ant == "BF") {
UHD_LOG_TRACE("EISCAT", "Setting antenna to 'BF' (which is a no-op)");
return;
@@ -357,16 +385,13 @@ void eiscat_radio_ctrl_impl::set_rx_antenna(
sr_write(SR_ANTENNA_SELECT_BASE + port, antenna_idx);
enable_firs(false);
} else if (ant_mode == "FI") {
- size_t beam_select_offset =
- (get_arg<int>("choose_beams") & EISCAT_CONTRIB_UPPER) ?
- EISCAT_NUM_PORTS : 0;
- const size_t beam_index = port + beam_select_offset;
+ size_t beam_index = port % EISCAT_NUM_PORTS;
UHD_LOG_TRACE("EISCAT", str(
boost::format("Setting port %d to filter index %d on all antennas "
- "using beam index %d.")
+ "using beam indices %d and %d.")
% port
% antenna_idx
- % beam_index
+ % beam_index % (beam_index + EISCAT_NUM_PORTS)
));
// Note: antenna_idx is not indexing a physical antenna in this scenario.
uhd::time_spec_t send_now(0.0);
@@ -377,6 +402,50 @@ void eiscat_radio_ctrl_impl::set_rx_antenna(
antenna_idx,
send_now
);
+ select_filter(
+ beam_index + EISCAT_NUM_PORTS,
+ i,
+ antenna_idx,
+ send_now
+ );
+ }
+ enable_firs(true);
+ } else if (ant_mode == "CN") {
+ const size_t beam_index = port % EISCAT_NUM_PORTS;
+ UHD_LOG_TRACE("EISCAT", str(
+ boost::format("Setting port %d to filter index %d on all antennas "
+ "using beam indices %d and %d.")
+ % port
+ % antenna_idx
+ % beam_index % (beam_index + EISCAT_NUM_PORTS)
+ ));
+ // Note: antenna_idx is not indexing a physical antenna in this scenario.
+ uhd::time_spec_t send_now(0.0);
+ for (size_t i = 0; i < EISCAT_NUM_ANTENNAS; i+=2) {
+ select_filter(
+ beam_index,
+ i,
+ 0,
+ send_now
+ );
+ select_filter(
+ beam_index + EISCAT_NUM_PORTS,
+ i,
+ 0,
+ send_now
+ );
+ select_filter(
+ beam_index,
+ i+1,
+ antenna_idx,
+ send_now
+ );
+ select_filter(
+ beam_index + EISCAT_NUM_PORTS,
+ i+1,
+ antenna_idx,
+ send_now
+ );
}
enable_firs(true);
} else {
@@ -456,9 +525,111 @@ double eiscat_radio_ctrl_impl::get_output_samp_rate(size_t /* port */)
return EISCAT_RADIO_RATE;
}
+void eiscat_radio_ctrl_impl::set_rx_streamer(bool active, const size_t port)
+{
+ UHD_RFNOC_BLOCK_TRACE() << "radio_ctrl_impl::set_rx_streamer() " << port << " -> " << active ;
+ if (port > EISCAT_NUM_PORTS) {
+ throw uhd::value_error(str(
+ boost::format("[%s] Can't (un)register RX streamer on port %d (invalid port)")
+ % unique_id() % port
+ ));
+ }
+ _rx_streamer_active[port] = active;
+ if (not check_radio_config()) {
+ throw std::runtime_error(str(
+ boost::format("[%s]: Invalid radio configuration.")
+ % unique_id()
+ ));
+ }
+
+ if (list_upstream_nodes().empty() or not bool(get_arg<int>("use_prev"))) {
+ UHD_LOG_DEBUG(unique_id(), "No prevs found, or prevs disabled, not passing on set_rx_streamer");
+ } else {
+ UHD_LOG_DEBUG(unique_id(), "set_rx_streamer(): We have prevs, so passing on set_rx_streamer");
+ source_node_ctrl::sptr this_upstream_block_ctrl =
+ boost::dynamic_pointer_cast<source_node_ctrl>(list_upstream_nodes().at(0).lock());
+ if (this_upstream_block_ctrl) {
+ this_upstream_block_ctrl->set_rx_streamer(active, port);
+ } else {
+ UHD_LOG_WARNING(unique_id(), "Oh noes, couldn't lock sptr!");
+ }
+ }
+}
+
+void eiscat_radio_ctrl_impl::issue_stream_cmd(const uhd::stream_cmd_t &stream_cmd, const size_t chan)
+{
+ std::lock_guard<std::mutex> lock(_mutex);
+
+ // Turn on/off top ones
+ if (list_upstream_nodes().empty() or not bool(get_arg<int>("use_prev"))) {
+ UHD_LOG_DEBUG(unique_id(), "No prevs found, or prevs disabled, not passing on stream cmd");
+ } else {
+ UHD_LOG_DEBUG(unique_id(), "issue_stream_cmd(): We have prevs, so passing on stream command");
+ source_node_ctrl::sptr this_upstream_block_ctrl =
+ boost::dynamic_pointer_cast<source_node_ctrl>(list_upstream_nodes().at(0).lock());
+ if (this_upstream_block_ctrl) {
+ this_upstream_block_ctrl->issue_stream_cmd(
+ stream_cmd,
+ chan
+ );
+ } else {
+ UHD_LOG_WARNING(unique_id(), "Oh noes, couldn't lock sptr!");
+ }
+ }
+
+ // Turn on/off this one
+ UHD_LOGGER_DEBUG(unique_id()) << "eiscat_radio_ctrl_impl::issue_stream_cmd() " << chan << " " << char(stream_cmd.stream_mode);
+ if (not _is_streamer_active(uhd::RX_DIRECTION, chan)) {
+ UHD_RFNOC_BLOCK_TRACE() << "radio_ctrl_impl::issue_stream_cmd() called on inactive channel. Skipping." ;
+ return;
+ }
+ UHD_ASSERT_THROW(stream_cmd.num_samps <= 0x0fffffff);
+ _continuous_streaming[chan] = (stream_cmd.stream_mode == stream_cmd_t::STREAM_MODE_START_CONTINUOUS);
+
+ if (stream_cmd.stream_mode == stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS &&
+ stream_cmd.stream_now == false) {
+ UHD_LOG_TRACE("EISCAT", "Stop cmd timed, setting cmd time!");
+ set_command_time(stream_cmd.time_spec, chan);
+ }
+
+ //setup the mode to instruction flags
+ typedef boost::tuple<bool, bool, bool, bool> inst_t;
+ static const uhd::dict<stream_cmd_t::stream_mode_t, inst_t> mode_to_inst = boost::assign::map_list_of
+ //reload, chain, samps, stop
+ (stream_cmd_t::STREAM_MODE_START_CONTINUOUS, inst_t(true, true, false, false))
+ (stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS, inst_t(false, false, false, true))
+ (stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE, inst_t(false, false, true, false))
+ (stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_MORE, inst_t(false, true, true, false))
+ ;
+
+ //setup the instruction flag values
+ bool inst_reload, inst_chain, inst_samps, inst_stop;
+ boost::tie(inst_reload, inst_chain, inst_samps, inst_stop) = mode_to_inst[stream_cmd.stream_mode];
+
+ //calculate the word from flags and length
+ uint32_t cmd_word = 0;
+ cmd_word |= uint32_t((stream_cmd.stream_now)? 1 : 0) << 31;
+ cmd_word |= uint32_t((inst_chain)? 1 : 0) << 30;
+ cmd_word |= uint32_t((inst_reload)? 1 : 0) << 29;
+ cmd_word |= uint32_t((inst_stop)? 1 : 0) << 28;
+ cmd_word |= (inst_samps)? stream_cmd.num_samps : ((inst_stop)? 0 : 1);
+
+ //issue the stream command
+ const uint64_t ticks = (stream_cmd.stream_now)? 0 : stream_cmd.time_spec.to_ticks(get_rate());
+ sr_write(regs::RX_CTRL_CMD, cmd_word, chan);
+ sr_write(regs::RX_CTRL_TIME_HI, uint32_t(ticks >> 32), chan);
+ sr_write(regs::RX_CTRL_TIME_LO, uint32_t(ticks >> 0), chan); //latches the command
+ UHD_LOG_INFO(unique_id(), "issued stream command.");
+ if (stream_cmd.stream_mode == stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS &&
+ stream_cmd.stream_now == false) {
+ UHD_LOG_TRACE("EISCAT", "Stop cmd timed, setting cmd time!");
+ set_command_time(uhd::time_spec_t(0.0), chan);
+ }
+
+}
+
bool eiscat_radio_ctrl_impl::check_radio_config()
{
- UHD_RFNOC_BLOCK_TRACE() << "x300_radio_ctrl_impl::check_radio_config() " ;
const uint32_t config_beams = get_arg<int>("configure_beams");
bool skipping_neighbours = config_beams & EISCAT_SKIP_NEIGHBOURS;
bool upper_contrib = config_beams & EISCAT_CONTRIB_UPPER;
@@ -511,18 +682,35 @@ void eiscat_radio_ctrl_impl::set_rpc_client(
"EISCAT",
"Finalizing dboard initialization; initializing JESD cores and ADCs."
);
- if (not assert_jesd_cores_initialized()) {
- throw uhd::runtime_error("Failed to initialize JESD cores and reset ADCs!");
- }
- send_sysref();
- if (not assert_adcs_deframers()) {
- throw uhd::runtime_error("Failed to initialize ADCs and JESD deframers!");
- }
- send_sysref();
- std::this_thread::sleep_for(std::chrono::milliseconds(500));
- if (not assert_deframer_status()) {
- throw uhd::runtime_error("Failed to finalize JESD core setup!");
+
+ /* Start of the ADC synchronization operation.
+ * These steps must be repeated if any ADC fails its deframer check
+ * Changing the sync line from SyncbAB to SyncnCD usually resolves the error
+ */
+ const size_t possible_sync_combinations = 16; // 2 sync lines ^ (2 ADCs * 2 Daughtercards)
+ for (size_t iteration = 0; iteration < possible_sync_combinations; iteration++) {
+ UHD_LOG_INFO(
+ "EISCAT",
+ "looping to initialize JESD cores and ADCs."
+ );
+ if (not assert_jesd_cores_initialized()) {
+ throw uhd::runtime_error("Failed to initialize JESD cores and reset ADCs!");
+ }
+ send_sysref();
+
+ if (not assert_adcs_deframers()) {
+ throw uhd::runtime_error("Failed to initialize ADCs and JESD deframers!");
+ }
+ send_sysref();
+ std::this_thread::sleep_for(std::chrono::milliseconds(500));
+
+ if (assert_deframer_status()) {
+ return;
+ }
}
+
+ // Unable to find a sync line combination which works
+ throw uhd::runtime_error("Failed to finalize JESD core setup!");
}
/****************************************************************************
@@ -597,13 +785,13 @@ void eiscat_radio_ctrl_impl::select_filter(
| (beam_index & 0xF) << 18
| send_now << 22
;
-
if (not send_now) {
UHD_LOG_TRACE("EISCAT", str(
boost::format("Filter selection will be applied at "
"time %f (0x%016X == %u). %s")
% time_spec.get_full_secs()
% time_spec.to_ticks(EISCAT_TICK_RATE)
+ % time_spec.to_ticks(EISCAT_TICK_RATE)
% (write_time ? "Writing time regs now."
: "Assuming time regs already up-to-date.")
));
@@ -632,9 +820,9 @@ void eiscat_radio_ctrl_impl::set_antenna_gain(
const size_t antenna_idx,
const double normalized_gain
) {
- if (normalized_gain < -1.0 or normalized_gain > 1.0) {
+ if (normalized_gain < -16.0 or normalized_gain > 16.0) {
throw uhd::value_error(str(
- boost::format("Invalid gain value for antenna %d: %f")
+ boost::format("Invalid digital gain value for antenna %d: %f")
% antenna_idx % normalized_gain
));
}
@@ -643,7 +831,7 @@ void eiscat_radio_ctrl_impl::set_antenna_gain(
EISCAT_MIN_GAIN,
std::min(
EISCAT_MAX_GAIN,
- int32_t(normalized_gain * EISCAT_MAX_GAIN)
+ int32_t(normalized_gain * EISCAT_UNIT_GAIN)
)
);
diff --git a/host/lib/usrp/dboard/eiscat/eiscat_radio_ctrl_impl.hpp b/host/lib/usrp/dboard/eiscat/eiscat_radio_ctrl_impl.hpp
index 959e5aa74..99d35c4a0 100644
--- a/host/lib/usrp/dboard/eiscat/eiscat_radio_ctrl_impl.hpp
+++ b/host/lib/usrp/dboard/eiscat/eiscat_radio_ctrl_impl.hpp
@@ -151,6 +151,9 @@ public:
//! \returns The EISCAT sampling rate
double get_output_samp_rate(size_t port);
+ void set_rx_streamer(bool active, const size_t port);
+ void issue_stream_cmd(const uhd::stream_cmd_t &stream_cmd, const size_t port);
+
protected:
virtual bool check_radio_config();