mirror of
https://github.com/saymrwulf/uhd.git
synced 2026-05-16 21:10:10 +00:00
Pragma once is the more modern version of include guards, eliminating any potential problems with mistyping include guards. Let's use those.
328 lines
9.6 KiB
C++
328 lines
9.6 KiB
C++
//
|
|
// Copyright 2014 Ettus Research LLC
|
|
// Copyright 2018 Ettus Research, a National Instruments Company
|
|
//
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
//
|
|
|
|
#pragma once
|
|
|
|
#include <uhd/exception.hpp>
|
|
#include <uhd/types/device_addr.hpp>
|
|
#include <uhd/utils/cast.hpp>
|
|
#include <unordered_map>
|
|
#include <boost/algorithm/string.hpp>
|
|
#include <boost/assign/list_of.hpp>
|
|
#include <boost/format.hpp>
|
|
#include <sstream>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
namespace uhd { namespace usrp {
|
|
|
|
/*!
|
|
* constrained_device_args_t provides a base and utilities to
|
|
* map key=value pairs passed in through the device creation
|
|
* args interface (device_addr_t).
|
|
*
|
|
* Inherit from this class to create typed device specific
|
|
* arguments and use the base class methods to handle parsing
|
|
* the device_addr or any key=value string to populate the args
|
|
*
|
|
* This file contains a library of different types of args the
|
|
* the user can pass in. The library can be extended to support
|
|
* non-intrinsic types by the client.
|
|
*
|
|
*/
|
|
class constrained_device_args_t
|
|
{
|
|
public: // Types
|
|
/*!
|
|
* Base argument type. All other arguments inherit from this.
|
|
*/
|
|
class generic_arg
|
|
{
|
|
public:
|
|
generic_arg(const std::string& key) : _key(key) {}
|
|
inline const std::string& key() const
|
|
{
|
|
return _key;
|
|
}
|
|
inline virtual std::string to_string() const = 0;
|
|
|
|
private:
|
|
std::string _key;
|
|
};
|
|
|
|
/*!
|
|
* String argument type. Can be case sensitive or insensitive
|
|
*/
|
|
template <bool case_sensitive>
|
|
class str_arg : public generic_arg
|
|
{
|
|
public:
|
|
str_arg(const std::string& name, const std::string& default_value)
|
|
: generic_arg(name)
|
|
{
|
|
set(default_value);
|
|
}
|
|
|
|
inline void set(const std::string& value)
|
|
{
|
|
_value = case_sensitive ? value : boost::algorithm::to_lower_copy(value);
|
|
}
|
|
inline const std::string& get() const
|
|
{
|
|
return _value;
|
|
}
|
|
inline void parse(const std::string& str_rep)
|
|
{
|
|
set(str_rep);
|
|
}
|
|
inline virtual std::string to_string() const
|
|
{
|
|
return key() + "=" + get();
|
|
}
|
|
inline bool operator==(const std::string& rhs) const
|
|
{
|
|
return get() == boost::algorithm::to_lower_copy(rhs);
|
|
}
|
|
|
|
private:
|
|
std::string _value;
|
|
};
|
|
typedef str_arg<false> str_ci_arg;
|
|
typedef str_arg<true> str_cs_arg;
|
|
|
|
/*!
|
|
* Numeric argument type. The template type data_t allows the
|
|
* client to constrain the type of the number.
|
|
*/
|
|
template <typename data_t>
|
|
class num_arg : public generic_arg
|
|
{
|
|
public:
|
|
num_arg(const std::string& name, const data_t default_value) : generic_arg(name)
|
|
{
|
|
set(default_value);
|
|
}
|
|
|
|
inline void set(const data_t value)
|
|
{
|
|
_value = value;
|
|
}
|
|
inline const data_t get() const
|
|
{
|
|
return _value;
|
|
}
|
|
inline void parse(const std::string& str_rep)
|
|
{
|
|
try {
|
|
_value = boost::lexical_cast<data_t>(str_rep);
|
|
} catch (std::exception& ex) {
|
|
throw uhd::value_error(
|
|
str(boost::format("Error parsing numeric parameter %s: %s.") % key()
|
|
% ex.what()));
|
|
}
|
|
}
|
|
inline virtual std::string to_string() const
|
|
{
|
|
return key() + "=" + std::to_string(get());
|
|
}
|
|
|
|
private:
|
|
data_t _value;
|
|
};
|
|
|
|
/*!
|
|
* Enumeration argument type. The template type enum_t allows the
|
|
* client to use their own enum and specify a string mapping for
|
|
* the values of the enum
|
|
*/
|
|
template <typename enum_t>
|
|
class enum_arg : public generic_arg
|
|
{
|
|
public:
|
|
enum_arg(const std::string& name,
|
|
const enum_t default_value,
|
|
const std::unordered_map<std::string, enum_t>& values)
|
|
: generic_arg(name), _str_values(_enum_map_to_lowercase<enum_t>(values))
|
|
{
|
|
set(default_value);
|
|
}
|
|
inline void set(const enum_t value)
|
|
{
|
|
_value = value;
|
|
}
|
|
inline const enum_t get() const
|
|
{
|
|
return _value;
|
|
}
|
|
inline void parse(const std::string& str_rep, const bool assert_invalid = true)
|
|
{
|
|
const std::string str_rep_lowercase =
|
|
boost::algorithm::to_lower_copy(str_rep);
|
|
if (_str_values.count(str_rep_lowercase) == 0) {
|
|
if (assert_invalid) {
|
|
std::string valid_values_str = "";
|
|
for (const auto& value : _str_values) {
|
|
valid_values_str +=
|
|
(valid_values_str.empty() ? "" : ", ") + value.first;
|
|
}
|
|
throw uhd::value_error(
|
|
str(boost::format("Invalid device arg value: %s=%s (Valid: {%s})")
|
|
% key() % str_rep % valid_values_str));
|
|
} else {
|
|
return;
|
|
}
|
|
}
|
|
|
|
set(_str_values.at(str_rep_lowercase));
|
|
}
|
|
inline virtual std::string to_string() const
|
|
{
|
|
std::string repr;
|
|
for (const auto& value : _str_values) {
|
|
if (value.second == _value) {
|
|
repr = value.first;
|
|
break;
|
|
}
|
|
}
|
|
|
|
UHD_ASSERT_THROW(!repr.empty());
|
|
return key() + "=" + repr;
|
|
}
|
|
|
|
private:
|
|
enum_t _value;
|
|
const std::unordered_map<std::string, enum_t> _str_values;
|
|
};
|
|
|
|
/*!
|
|
* Boolean argument type.
|
|
*/
|
|
class bool_arg : public generic_arg
|
|
{
|
|
public:
|
|
bool_arg(const std::string& name, const bool default_value) : generic_arg(name)
|
|
{
|
|
set(default_value);
|
|
}
|
|
|
|
inline void set(const bool value)
|
|
{
|
|
_value = value;
|
|
}
|
|
inline bool get() const
|
|
{
|
|
return _value;
|
|
}
|
|
inline void parse(const std::string& str_rep)
|
|
{
|
|
try {
|
|
if (str_rep.empty()) {
|
|
// If str_rep is empty, the flag is interpreted as set
|
|
_value = true;
|
|
} else {
|
|
_value = uhd::cast::from_str<bool>(str_rep);
|
|
}
|
|
} catch (std::exception& ex) {
|
|
throw uhd::value_error(
|
|
str(boost::format("Error parsing boolean parameter %s: %s.")
|
|
% key() % ex.what()));
|
|
}
|
|
}
|
|
inline virtual std::string to_string() const
|
|
{
|
|
return key() + "=" + (get() ? "true" : "false");
|
|
}
|
|
|
|
private:
|
|
bool _value;
|
|
};
|
|
|
|
public: // Methods
|
|
constrained_device_args_t() {}
|
|
virtual ~constrained_device_args_t() {}
|
|
|
|
void parse(const std::string& str_args)
|
|
{
|
|
device_addr_t dev_args(str_args);
|
|
_parse(dev_args);
|
|
}
|
|
|
|
void parse(const device_addr_t& dev_args)
|
|
{
|
|
_parse(dev_args);
|
|
}
|
|
|
|
inline virtual std::string to_string() const = 0;
|
|
|
|
template <typename arg_type>
|
|
void parse_arg_default(const device_addr_t& dev_args, arg_type& constrained_arg)
|
|
{
|
|
if (dev_args.has_key(constrained_arg.key())) {
|
|
constrained_arg.parse(dev_args[constrained_arg.key()]);
|
|
}
|
|
}
|
|
|
|
protected: // Methods
|
|
// Override _parse to provide an implementation to parse all
|
|
// client specific device args
|
|
virtual void _parse(const device_addr_t& dev_args) = 0;
|
|
|
|
/*!
|
|
* Utility: Ensure that the value of the device arg is between min and max
|
|
*/
|
|
template <typename num_data_t>
|
|
static inline void _enforce_range(
|
|
const num_arg<num_data_t>& arg, const num_data_t& min, const num_data_t& max)
|
|
{
|
|
if (arg.get() > max || arg.get() < min) {
|
|
throw uhd::value_error(str(
|
|
boost::format("Invalid device arg value: %s (Minimum: %s, Maximum: %s)")
|
|
% arg.to_string() % std::to_string(min) % std::to_string(max)));
|
|
}
|
|
}
|
|
|
|
/*!
|
|
* Utility: Ensure that the value of the device arg is is contained in valid_values
|
|
*/
|
|
template <typename arg_t, typename data_t>
|
|
static inline void _enforce_discrete(
|
|
const arg_t& arg, const std::vector<data_t>& valid_values)
|
|
{
|
|
bool match = false;
|
|
for (const data_t& val : valid_values) {
|
|
if (val == arg.get()) {
|
|
match = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!match) {
|
|
std::string valid_values_str;
|
|
for (size_t i = 0; i < valid_values.size(); i++) {
|
|
std::stringstream valid_values_ss;
|
|
valid_values_ss << ((i == 0) ? "" : ", ") << valid_values[i];
|
|
throw uhd::value_error(
|
|
str(boost::format("Invalid device arg value: %s (Valid: {%s})")
|
|
% arg.to_string() % valid_values_ss.str()));
|
|
}
|
|
}
|
|
}
|
|
|
|
//! Helper for enum_arg: Create a new map where keys are converted to
|
|
// lowercase.
|
|
template <typename enum_t>
|
|
static std::unordered_map<std::string, enum_t> _enum_map_to_lowercase(
|
|
const std::unordered_map<std::string, enum_t>& in_map)
|
|
{
|
|
std::unordered_map<std::string, enum_t> new_map;
|
|
for (const auto& str_to_enum : in_map) {
|
|
new_map.insert(std::pair<std::string, enum_t>(
|
|
boost::algorithm::to_lower_copy(str_to_enum.first), str_to_enum.second));
|
|
}
|
|
return new_map;
|
|
}
|
|
};
|
|
}} // namespace uhd::usrp
|