aboutsummaryrefslogtreecommitdiffstats
path: root/host/include/uhd/rfnoc/mb_controller.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'host/include/uhd/rfnoc/mb_controller.hpp')
-rw-r--r--host/include/uhd/rfnoc/mb_controller.hpp352
1 files changed, 352 insertions, 0 deletions
diff --git a/host/include/uhd/rfnoc/mb_controller.hpp b/host/include/uhd/rfnoc/mb_controller.hpp
new file mode 100644
index 000000000..a1c0f21aa
--- /dev/null
+++ b/host/include/uhd/rfnoc/mb_controller.hpp
@@ -0,0 +1,352 @@
+//
+// Copyright 2019 Ettus Research, a National Instruments Brand
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+
+#ifndef INCLUDED_LIBUHD_MB_CONTROLLER_HPP
+#define INCLUDED_LIBUHD_MB_CONTROLLER_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/types/device_addr.hpp>
+#include <uhd/types/sensors.hpp>
+#include <uhd/types/time_spec.hpp>
+#include <uhd/usrp/mboard_eeprom.hpp>
+#include <uhd/utils/noncopyable.hpp>
+#include <unordered_map>
+#include <functional>
+#include <memory>
+#include <vector>
+
+namespace uhd { namespace rfnoc {
+
+/*! A default block controller for blocks that can't be found in the registry
+ */
+class UHD_API mb_controller : public uhd::noncopyable
+{
+public:
+ using sptr = std::shared_ptr<mb_controller>;
+
+ virtual ~mb_controller() {}
+
+ /**************************************************************************
+ * Timebase API
+ *************************************************************************/
+ /*! Interface to interact with timekeepers
+ *
+ * Timekeepers are objects separate from RFNoC blocks. This class is meant
+ * to be subclassed by motherboards implementing it.
+ */
+ class UHD_API timekeeper
+ {
+ public:
+ using sptr = std::shared_ptr<timekeeper>;
+ using write_period_fn_t = std::function<void(uint64_t)>;
+
+ timekeeper();
+
+ virtual ~timekeeper() {}
+
+ /*! Return the current time as a time spec
+ *
+ * Note that there is no control over when this command gets executed,
+ * it will read the time "as soon as possible", and then return that
+ * value. Calling this on two synchronized clocks sequentially will
+ * definitely return two different values.
+ *
+ * \returns the current time
+ */
+ uhd::time_spec_t get_time_now(void);
+
+ /*! Return the current time as a tick count
+ *
+ * See also get_time_now().
+ *
+ * \returns the current time
+ */
+ virtual uint64_t get_ticks_now() = 0;
+
+ /*! Return the time from the last PPS as a time spec
+ *
+ * Note that there is no control over when this command gets executed,
+ * it will read the time "as soon as possible", and then return that
+ * value. Calling this on two synchronized clocks sequentially will
+ * definitely return two different values.
+ */
+ uhd::time_spec_t get_time_last_pps(void);
+
+ /*! Return the time from the last PPS as a tick count
+ *
+ * See also get_time_last_pps()
+ */
+ virtual uint64_t get_ticks_last_pps() = 0;
+
+ /*! Set the time "now" from a time spec
+ */
+ void set_time_now(const uhd::time_spec_t &time);
+
+ /*! Set the ticks "now"
+ */
+ virtual void set_ticks_now(const uint64_t ticks) = 0;
+
+ /*! Set the time at next PPS from a time spec
+ */
+ void set_time_next_pps(const uhd::time_spec_t &time);
+
+ /*! Set the ticks at next PPS
+ */
+ virtual void set_ticks_next_pps(const uint64_t ticks) = 0;
+
+ /*! Return the current tick rate
+ */
+ double get_tick_rate() { return _tick_rate; }
+
+ protected:
+ /*! Set the tick rate
+ *
+ * This doesn't change the input clock to the timekeeper, but does two
+ * things:
+ * - Update the local value of the tick rate, so the time-spec based API
+ * calls work
+ * - Convert the tick rate to a period and call set_period()
+ */
+ void set_tick_rate(const double rate);
+
+ /*! Set the time period as a 64-bit Q32 value
+ *
+ * \param period_ns The period as nanoseconds per tick, in Q32 format
+ */
+ virtual void set_period(const uint64_t period_ns) = 0;
+
+ private:
+ //! Ticks/Second
+ double _tick_rate = 1.0;
+ };
+
+ //! Returns the number of timekeepers, which equals the number of timebases
+ // on this device.
+ size_t get_num_timekeepers() const;
+
+ //! Return a reference to the \p tk_idx-th timekeeper on this motherboard
+ //
+ // \throws uhd::index_error if \p tk_idx is not valid
+ timekeeper::sptr get_timekeeper(const size_t tk_idx) const;
+
+ /**************************************************************************
+ * Motherboard Control
+ *************************************************************************/
+ /*! Get canonical name for this USRP motherboard
+ *
+ * \return a string representing the name
+ */
+ virtual std::string get_mboard_name() const = 0;
+
+ /*! Set the time source for the USRP device
+ *
+ * This sets the method of time synchronization, typically a pulse per
+ * second signal. In order to time-align multiple USRPs, it is necessary to
+ * connect all of them to a common reference and provide them with the same
+ * time source.
+ * Typical values for \p source are 'internal', 'external'. Refer to the
+ * specific device manual for a full list of options.
+ *
+ * If the value for for \p source is not available for this device, it will
+ * throw an exception. Calling get_time_sources() will return a valid list
+ * of options for this method.
+ *
+ * Side effects: Some devices only support certain combinations of time and
+ * clock source. It is possible that the underlying device implementation
+ * will change the clock source when the time source changes and vice versa.
+ * Reading back the current values of clock and time source using
+ * get_clock_source() and get_time_source() is the only certain way of
+ * knowing which clock and time source are currently selected.
+ *
+ * This function does not force a re-initialization of the underlying
+ * hardware when the value does not change. Consider the following snippet:
+ * ~~~{.cpp}
+ * auto usrp = uhd::usrp::multi_usrp::make(device_args);
+ * // This may or may not cause the hardware to reconfigure, depending on
+ * // the default state of the device
+ * usrp->set_time_source("internal");
+ * // Now, the time source is definitely set to "internal"!
+ * // The next call probably won't do anything but will return immediately,
+ * // because the time source was already set to "internal"
+ * usrp->set_time_source("internal");
+ * // The time source is still guaranteed to be "internal" at this point
+ * ~~~
+ *
+ * See also:
+ * - set_clock_source()
+ * - set_sync_source()
+ *
+ * \param source a string representing the time source
+ * \throws uhd::value_error if \p source is an invalid option
+ */
+ virtual void set_time_source(const std::string& source) = 0;
+
+ /*! Get the currently set time source
+ *
+ * \return the string representing the time source
+ */
+ virtual std::string get_time_source() const = 0;
+
+ /*!
+ * Get a list of possible time sources.
+ * \return a vector of strings for possible settings
+ */
+ virtual std::vector<std::string> get_time_sources() const = 0;
+
+ /*! Set the clock source for the USRP device
+ *
+ * This sets the source of the frequency reference, typically a 10 MHz
+ * signal. In order to frequency-align multiple USRPs, it is necessary to
+ * connect all of them to a common reference and provide them with the same
+ * clock source.
+ * Typical values for \p source are 'internal', 'external'. Refer to the
+ * specific device manual for a full list of options.
+ *
+ * If the value for for \p source is not available for this device, it will
+ * throw an exception. Calling get_clock_sources() will return a valid list
+ * of options for this method.
+ *
+ * Side effects: Some devices only support certain combinations of time and
+ * clock source. It is possible that the underlying device implementation
+ * will change the time source when the clock source changes and vice versa.
+ * Reading back the current values of clock and time source using
+ * get_clock_source() and get_time_source() is the only certain way of
+ * knowing which clock and time source are currently selected.
+ *
+ * This function does not force a re-initialization of the underlying
+ * hardware when the value does not change. Consider the following snippet:
+ * ~~~{.cpp}
+ * auto usrp = uhd::usrp::multi_usrp::make(device_args);
+ * // This may or may not cause the hardware to reconfigure, depending on
+ * // the default state of the device
+ * usrp->set_clock_source("internal");
+ * // Now, the clock source is definitely set to "internal"!
+ * // The next call probably won't do anything but will return immediately,
+ * // because the clock source was already set to "internal"
+ * usrp->set_clock_source("internal");
+ * // The clock source is still guaranteed to be "internal" at this point
+ * ~~~
+ *
+ * See also:
+ * - set_time_source()
+ * - set_sync_source()
+ *
+ * \param source a string representing the time source
+ * \throws uhd::value_error if \p source is an invalid option
+ */
+ virtual void set_clock_source(const std::string& source) = 0;
+
+ /*! Get the currently set clock source
+ *
+ * \return the string representing the clock source
+ */
+ virtual std::string get_clock_source() const = 0;
+
+ /*! Get a list of possible clock sources
+ *
+ * \return a vector of strings for possible settings
+ */
+ virtual std::vector<std::string> get_clock_sources() const = 0;
+
+ /*! Set the reference/synchronization sources for the USRP device
+ *
+ * This is a shorthand for calling
+ * `set_sync_source(device_addr_t("clock_source=$CLOCK_SOURCE,time_source=$TIME_SOURCE"))`
+ *
+ * \param clock_source A string representing the clock source
+ * \param time_source A string representing the time source
+ * \throws uhd::value_error if the sources don't actually exist
+ */
+ virtual void set_sync_source(
+ const std::string& clock_source, const std::string& time_source) = 0;
+
+ /*! Set the reference/synchronization sources for the USRP device
+ *
+ * Typically, this will set both clock and time source in a single call. For
+ * some USRPs, this may be significantly faster than calling
+ * set_time_source() and set_clock_source() individually.
+ *
+ * Example:
+ * ~~~{.cpp}
+ * auto usrp = uhd::usrp::multi_usrp::make("");
+ * usrp->set_sync_source(
+ * device_addr_t("clock_source=external,time_source=external"));
+ * ~~~
+ *
+ * This function does not force a re-initialization of the underlying
+ * hardware when the value does not change. See also set_time_source() and
+ * set_clock_source() for more details.
+ *
+ * \param sync_source A dictionary representing the various source settings.
+ * \throws uhd::value_error if the sources don't actually exist or if the
+ * combination of clock and time source is invalid.
+ */
+ virtual void set_sync_source(const uhd::device_addr_t& sync_source) = 0;
+
+ /*! Get the currently set sync source
+ *
+ * \return the dictionary representing the sync source settings
+ */
+ virtual uhd::device_addr_t get_sync_source() const = 0;
+
+ /*! Get a list of available sync sources
+ *
+ * \return the dictionary representing the sync source settings
+ */
+ virtual std::vector<uhd::device_addr_t> get_sync_sources() = 0;
+
+ /*! Send the clock source to an output connector
+ *
+ * This call is only applicable on devices with reference outputs.
+ * By default, the reference output will be enabled for ease of use.
+ * This call may be used to enable or disable the output.
+ * \param enb true to output the clock source.
+ */
+ virtual void set_clock_source_out(const bool enb) = 0;
+
+ /*! Send the time source to an output connector
+ *
+ * This call is only applicable on devices with PPS outputs.
+ * By default, the PPS output will be enabled for ease of use.
+ * This call may be used to enable or disable the output.
+ * \param enb true to output the time source.
+ */
+ virtual void set_time_source_out(const bool enb) = 0;
+
+ /*! Get a motherboard sensor value
+ *
+ * \param name the name of the sensor
+ * \return a sensor value object
+ */
+ virtual uhd::sensor_value_t get_sensor(const std::string& name) = 0;
+
+ /*! Get a list of possible motherboard sensor names
+ *
+ * \return a vector of sensor names
+ */
+ virtual std::vector<std::string> get_sensor_names() = 0;
+
+ /*! Return the motherboard EEPROM data
+ */
+ virtual uhd::usrp::mboard_eeprom_t get_eeprom() = 0;
+
+protected:
+ /*! Stash away a timekeeper. This needs to be called by the implementer of
+ * mb_controller.
+ */
+ void register_timekeeper(const size_t idx, timekeeper::sptr tk);
+
+private:
+ /**************************************************************************
+ * Attributes
+ *************************************************************************/
+ std::unordered_map<size_t, timekeeper::sptr> _timekeepers;
+};
+
+}} // namespace uhd::rfnoc
+
+#endif /* INCLUDED_LIBUHD_MB_CONTROLLER_HPP */
+