diff options
| author | Lane Kolbly <lane.kolbly@ni.com> | 2021-01-06 11:34:05 -0600 | 
|---|---|---|
| committer | Aaron Rossetto <aaron.rossetto@ni.com> | 2021-01-11 12:23:24 -0600 | 
| commit | c9b35e3b7107ab82c0e3978b7cbfd76ba98e2407 (patch) | |
| tree | 3e161a882f8005baf04b3a802dc7636a579643e2 /host/lib/include/uhdlib/usrp | |
| parent | 7f765f4f2be719473ee329c00f7125a785057deb (diff) | |
| download | uhd-c9b35e3b7107ab82c0e3978b7cbfd76ba98e2407.tar.gz uhd-c9b35e3b7107ab82c0e3978b7cbfd76ba98e2407.tar.bz2 uhd-c9b35e3b7107ab82c0e3978b7cbfd76ba98e2407.zip | |
Create C++ wrappers for MPM RPC calls
This gives us type-safety, as well as allowing us to create unit tests for
RFNoC radio_controls without having to create actual RPC servers and clients
in the unit tests.
This change also fixes a bug in mpmd_mb_controller::set_sync_source, where
it was calling the wrong MPM function.
Diffstat (limited to 'host/lib/include/uhdlib/usrp')
| -rw-r--r-- | host/lib/include/uhdlib/usrp/common/mpmd_mb_controller.hpp | 17 | ||||
| -rw-r--r-- | host/lib/include/uhdlib/usrp/common/rpc.py | 152 | 
2 files changed, 164 insertions, 5 deletions
| diff --git a/host/lib/include/uhdlib/usrp/common/mpmd_mb_controller.hpp b/host/lib/include/uhdlib/usrp/common/mpmd_mb_controller.hpp index 7285eb254..acdd361e4 100644 --- a/host/lib/include/uhdlib/usrp/common/mpmd_mb_controller.hpp +++ b/host/lib/include/uhdlib/usrp/common/mpmd_mb_controller.hpp @@ -7,6 +7,7 @@  #pragma once  #include <uhd/rfnoc/mb_controller.hpp> +#include <uhdlib/usrp/common/rpc.hpp>  #include <uhdlib/utils/rpc.hpp>  #include <memory> @@ -23,12 +24,18 @@ class mpmd_mb_controller : public mb_controller  public:      using sptr = std::shared_ptr<mpmd_mb_controller>; -    mpmd_mb_controller(uhd::rpc_client::sptr rpcc, uhd::device_addr_t device_info); +    mpmd_mb_controller(uhd::usrp::mpmd_rpc_iface::sptr rpcc, uhd::device_addr_t device_info);      //! Return reference to the RPC client      uhd::rpc_client::sptr get_rpc_client()      { -        return _rpc; +        return _rpc->get_raw_rpc_client(); +    } + +    template<typename T> +    std::shared_ptr<T> dynamic_cast_rpc_as() +    { +        return std::dynamic_pointer_cast<T>(_rpc);      }      /************************************************************************** @@ -42,7 +49,7 @@ public:      public:          using sptr = std::shared_ptr<mpmd_timekeeper>; -        mpmd_timekeeper(const size_t tk_idx, uhd::rpc_client::sptr rpc_client) +        mpmd_timekeeper(const size_t tk_idx, uhd::usrp::mpmd_rpc_iface::sptr rpc_client)              : _tk_idx(tk_idx), _rpc(rpc_client)          {              // nop @@ -62,7 +69,7 @@ public:      private:          const size_t _tk_idx; -        uhd::rpc_client::sptr _rpc; +        uhd::usrp::mpmd_rpc_iface::sptr _rpc;      };      /************************************************************************** @@ -94,7 +101,7 @@ private:       * Attributes       *************************************************************************/      //! Reference to RPC interface -    mutable uhd::rpc_client::sptr _rpc; +    mutable uhd::usrp::mpmd_rpc_iface::sptr _rpc;      uhd::device_addr_t _device_info; diff --git a/host/lib/include/uhdlib/usrp/common/rpc.py b/host/lib/include/uhdlib/usrp/common/rpc.py new file mode 100644 index 000000000..c484991a6 --- /dev/null +++ b/host/lib/include/uhdlib/usrp/common/rpc.py @@ -0,0 +1,152 @@ +# +# Copyright 2021 Ettus Research, a National Instruments Company +# +# SPDX-License-Identifier: GPL-3.0-or-later +# + +import re +import sys +from mako.template import Template + +class Function: +    def __init__(self, return_type, function_name, args): +        self.name = function_name +        self.does_return = return_type != "void" +        self.return_type = return_type +        self.arg_names = [arg[1] for arg in args] +        self.rpcname = f"\"{function_name}\"" +        self.args = [" ".join(arg) for arg in args] +        self.has_rpcprefix = False + +    def enable_rpcprefix(self): +        self.rpcname = f"_rpc_prefix + \"{self.name}\"" +        self.has_rpcprefix = True + +class Interface: +    def __init__(self, basename, functions, has_rpcprefix=False): +        self.basename = basename +        self.functions = functions +        self.has_rpcprefix = has_rpcprefix +        if has_rpcprefix: +            for fn in self.functions: +                fn.enable_rpcprefix() + +def fn_from_string(function_string): +    m = re.match(r"^([a-zA-Z:<>,_0-9 ]+)\s+([a-zA-Z0-9_]+)\(([a-zA-Z0-9,_:&<> ]*)\)$", function_string) +    return_type = m.group(1) +    function_name = m.group(2) +    args = m.group(3) +    args = [arg.strip() for arg in args.split(",")] +    args = [arg.split(" ") for arg in args if len(arg) > 0] +    args = [(" ".join(arg[:-1]), arg[-1]) for arg in args] +    return Function(return_type, function_name, args) + +IFACES = [ +    Interface("mpmd_rpc", [ +        fn_from_string("size_t get_num_timekeepers()"), +        fn_from_string("std::vector<std::string> get_mb_sensors()"), +        fn_from_string("sensor_value_t::sensor_map_t get_mb_sensor(const std::string& sensor)"), +        fn_from_string("std::vector<std::string> get_gpio_banks()"), +        fn_from_string("std::vector<std::string> get_gpio_srcs(const std::string& bank)"), +        fn_from_string("bool supports_feature(const std::string& feature)"), +        fn_from_string("void set_tick_period(size_t tick_index, uint64_t period_ns)"), +        fn_from_string("uint64_t get_timekeeper_time(size_t timekeeper_idx, bool last_pps)"), +        fn_from_string("void set_timekeeper_time(size_t timekeeper_idx, uint64_t ticks, bool last_pps)"), +        fn_from_string("void set_time_source(const std::string& source)"), +        fn_from_string("std::string get_time_source()"), +        fn_from_string("std::vector<std::string> get_time_sources()"), +        fn_from_string("void set_clock_source(const std::string& source)"), +        fn_from_string("std::string get_clock_source()"), +        fn_from_string("std::vector<std::string> get_clock_sources()"), +        Function("void", "set_sync_source", [("const std::map<std::string, std::string>&", "source")]), +        fn_from_string("std::map<std::string, std::string> get_sync_source()"), +        fn_from_string("std::vector<std::map<std::string, std::string>> get_sync_sources()"), +        fn_from_string("void set_clock_source_out(bool enb)"), +        fn_from_string("void set_trigger_io(const std::string& direction)"), +        fn_from_string("std::map<std::string, std::string> get_mb_eeprom()"), +        fn_from_string("std::vector<std::string> get_gpio_src(const std::string& bank)"), +        fn_from_string("void set_gpio_src(const std::string& bank, const std::vector<std::string>& src)"), +    ]), +] + +COMMON_TMPL = """<% import time %>\ +/*********************************************************************** + * This file was generated by ${file} on ${time.strftime("%c")} + **********************************************************************/ + +// +// Copyright 2021 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: GPL-3.0-or-later +// + +#pragma once + +#include <uhd/types/sensors.hpp> +#include <uhdlib/utils/rpc.hpp> +#include <stddef.h> +#include <memory> +#include <string> +#include <vector> + +namespace uhd { namespace usrp { + +%for iface in ifaces: +    class ${iface.basename}_iface { +    public: +        using sptr = std::shared_ptr<${iface.basename}_iface>; + +        %for function in iface.functions: +            virtual ${function.return_type} ${function.name}(${",".join(function.args)}) = 0; +        %endfor + +        // Deprecated +        virtual uhd::rpc_client::sptr get_raw_rpc_client() = 0; +    }; + +    class ${iface.basename} : public ${iface.basename}_iface { +    public: +        %if iface.has_rpcprefix: +            ${iface.basename}(uhd::rpc_client::sptr rpc, const std::string& rpc_prefix) : _rpcc(rpc), _rpc_prefix(rpc_prefix) {} +        %else: +            ${iface.basename}(uhd::rpc_client::sptr rpc) : _rpcc(rpc) {} +        %endif + +        %for function in iface.functions: +            ${function.return_type} ${function.name}(${",".join(function.args)}) override +            { +                %if function.does_return: +                return _rpcc->request_with_token<${function.return_type}>(${",".join([function.rpcname] + function.arg_names)}); +                %else: +                _rpcc->notify_with_token(${",".join([function.rpcname] + function.arg_names)}); +                %endif +            } +        %endfor + +        // Deprecated +        uhd::rpc_client::sptr get_raw_rpc_client() { return _rpcc; } + +    private: +        uhd::rpc_client::sptr _rpcc; +        %if iface.has_rpcprefix: +            const std::string _rpc_prefix; +        %endif +    }; +%endfor + +}} +""" + +def parse_tmpl(_tmpl_text, **kwargs): +    return Template(_tmpl_text).render(**kwargs) + +if __name__ == '__main__': +    out_file = sys.argv[1] + +    code = parse_tmpl(COMMON_TMPL, +        ifaces=IFACES, +        file=__file__, +    ) + +    with open(out_file, 'w') as f: +        f.write(code) | 
