1 //
2 // Copyright 2019 Ettus Research, a National Instruments Brand
3 //
4 // SPDX-License-Identifier: GPL-3.0-or-later
5 //
6 
7 #include <uhdlib/usrp/common/mpmd_mb_controller.hpp>
8 
9 using namespace uhd::rfnoc;
10 using namespace uhd;
11 
12 namespace {
13 //! Default timeout value for RPC calls that we know can take long (ms)
14 constexpr size_t MPMD_DEFAULT_LONG_TIMEOUT = 30000; // ms
15 } // namespace
16 
mpmd_mb_controller(uhd::rpc_client::sptr rpcc,uhd::device_addr_t device_info)17 mpmd_mb_controller::mpmd_mb_controller(
18     uhd::rpc_client::sptr rpcc, uhd::device_addr_t device_info)
19     : _rpc(rpcc), _device_info(device_info)
20 {
21     const size_t num_tks = _rpc->request_with_token<size_t>("get_num_timekeepers");
22     for (size_t tk_idx = 0; tk_idx < num_tks; tk_idx++) {
23         register_timekeeper(tk_idx, std::make_shared<mpmd_timekeeper>(tk_idx, _rpc));
24     }
25 
26     // Enumerate sensors
27     auto sensor_list =
28         _rpc->request_with_token<std::vector<std::string>>("get_mb_sensors");
29     UHD_LOG_DEBUG("MPMD", "Found " << sensor_list.size() << " motherboard sensors.");
30     _sensor_names.insert(sensor_list.cbegin(), sensor_list.cend());
31 
32     // Enumerate GPIO banks that are under mb_controller control
33     _gpio_banks = _rpc->request_with_token<std::vector<std::string>>("get_gpio_banks");
34     for (const auto& bank : _gpio_banks) {
35         _gpio_srcs.insert({bank,
36             _rpc->request_with_token<std::vector<std::string>>("get_gpio_srcs", bank)});
37     }
38 }
39 
40 /******************************************************************************
41  * Timekeeper API
42  *****************************************************************************/
get_ticks_now()43 uint64_t mpmd_mb_controller::mpmd_timekeeper::get_ticks_now()
44 {
45     return _rpc->request_with_token<uint64_t>("get_timekeeper_time", _tk_idx, false);
46 }
47 
get_ticks_last_pps()48 uint64_t mpmd_mb_controller::mpmd_timekeeper::get_ticks_last_pps()
49 {
50     return _rpc->request_with_token<uint64_t>("get_timekeeper_time", _tk_idx, true);
51 }
52 
set_ticks_now(const uint64_t ticks)53 void mpmd_mb_controller::mpmd_timekeeper::set_ticks_now(const uint64_t ticks)
54 {
55     _rpc->notify_with_token("set_timekeeper_time", _tk_idx, ticks, false);
56 }
57 
set_ticks_next_pps(const uint64_t ticks)58 void mpmd_mb_controller::mpmd_timekeeper::set_ticks_next_pps(const uint64_t ticks)
59 {
60     _rpc->notify_with_token("set_timekeeper_time", _tk_idx, ticks, true);
61 }
62 
set_period(const uint64_t period_ns)63 void mpmd_mb_controller::mpmd_timekeeper::set_period(const uint64_t period_ns)
64 {
65     _rpc->notify_with_token("set_tick_period", _tk_idx, period_ns);
66 }
67 
update_tick_rate(const double tick_rate)68 void mpmd_mb_controller::mpmd_timekeeper::update_tick_rate(const double tick_rate)
69 {
70     set_tick_rate(tick_rate);
71 }
72 
73 /******************************************************************************
74  * Motherboard Control API (see mb_controller.hpp)
75  *****************************************************************************/
get_mboard_name() const76 std::string mpmd_mb_controller::get_mboard_name() const
77 {
78     return _device_info.get("product", "UNKNOWN");
79 }
80 
set_time_source(const std::string & source)81 void mpmd_mb_controller::set_time_source(const std::string& source)
82 {
83     _rpc->notify_with_token(MPMD_DEFAULT_LONG_TIMEOUT, "set_time_source", source);
84 }
85 
get_time_source() const86 std::string mpmd_mb_controller::get_time_source() const
87 {
88     return _rpc->request_with_token<std::string>("get_time_source");
89 }
90 
get_time_sources() const91 std::vector<std::string> mpmd_mb_controller::get_time_sources() const
92 {
93     return _rpc->request_with_token<std::vector<std::string>>("get_time_sources");
94 }
95 
set_clock_source(const std::string & source)96 void mpmd_mb_controller::set_clock_source(const std::string& source)
97 {
98     _rpc->notify_with_token(MPMD_DEFAULT_LONG_TIMEOUT, "set_clock_source", source);
99 }
100 
get_clock_source() const101 std::string mpmd_mb_controller::get_clock_source() const
102 {
103     return _rpc->request_with_token<std::string>("get_clock_source");
104 }
105 
get_clock_sources() const106 std::vector<std::string> mpmd_mb_controller::get_clock_sources() const
107 {
108     return _rpc->request_with_token<std::vector<std::string>>("get_clock_sources");
109 }
110 
set_sync_source(const std::string & clock_source,const std::string & time_source)111 void mpmd_mb_controller::set_sync_source(
112     const std::string& clock_source, const std::string& time_source)
113 {
114     uhd::device_addr_t sync_source;
115     sync_source["clock_source"] = clock_source;
116     sync_source["time_source"]  = time_source;
117     set_sync_source(sync_source);
118 }
119 
set_sync_source(const device_addr_t & sync_source)120 void mpmd_mb_controller::set_sync_source(const device_addr_t& sync_source)
121 {
122     std::map<std::string, std::string> sync_source_map;
123     for (const auto& key : sync_source.keys()) {
124         sync_source_map[key] = sync_source.get(key);
125     }
126     _rpc->notify_with_token(
127         MPMD_DEFAULT_LONG_TIMEOUT, "set_clock_source", sync_source_map);
128 }
129 
get_sync_source() const130 device_addr_t mpmd_mb_controller::get_sync_source() const
131 {
132     const auto sync_source_map =
133         _rpc->request_with_token<std::map<std::string, std::string>>("get_sync_source");
134     return device_addr_t(sync_source_map);
135 }
136 
get_sync_sources()137 std::vector<device_addr_t> mpmd_mb_controller::get_sync_sources()
138 {
139     std::vector<device_addr_t> result;
140     const auto sync_sources =
141         _rpc->request_with_token<std::vector<std::map<std::string, std::string>>>(
142             "get_sync_sources");
143     for (auto& sync_source : sync_sources) {
144         result.push_back(device_addr_t(sync_source));
145     }
146 
147     return result;
148 }
149 
set_clock_source_out(const bool)150 void mpmd_mb_controller::set_clock_source_out(const bool /*enb*/)
151 {
152     throw uhd::not_implemented_error(
153         "set_clock_source_out() not implemented on this device!");
154 }
155 
set_time_source_out(const bool)156 void mpmd_mb_controller::set_time_source_out(const bool /*enb*/)
157 {
158     throw uhd::not_implemented_error(
159         "set_time_source_out() not implemented on this device!");
160 }
161 
get_sensor(const std::string & name)162 sensor_value_t mpmd_mb_controller::get_sensor(const std::string& name)
163 {
164     if (!_sensor_names.count(name)) {
165         throw uhd::key_error(std::string("Invalid motherboard sensor name: ") + name);
166     }
167     return sensor_value_t(
168         _rpc->request_with_token<sensor_value_t::sensor_map_t>("get_mb_sensor", name));
169 }
170 
get_sensor_names()171 std::vector<std::string> mpmd_mb_controller::get_sensor_names()
172 {
173     std::vector<std::string> sensor_names(_sensor_names.cbegin(), _sensor_names.cend());
174     return sensor_names;
175 }
176 
get_eeprom()177 uhd::usrp::mboard_eeprom_t mpmd_mb_controller::get_eeprom()
178 {
179     auto mb_eeprom =
180         _rpc->request_with_token<std::map<std::string, std::string>>("get_mb_eeprom");
181     uhd::usrp::mboard_eeprom_t mb_eeprom_dict(mb_eeprom.cbegin(), mb_eeprom.cend());
182     return mb_eeprom_dict;
183 }
184 
get_gpio_banks() const185 std::vector<std::string> mpmd_mb_controller::get_gpio_banks() const
186 {
187     return _gpio_banks;
188 }
189 
get_gpio_srcs(const std::string & bank) const190 std::vector<std::string> mpmd_mb_controller::get_gpio_srcs(const std::string& bank) const
191 {
192     if (!_gpio_srcs.count(bank)) {
193         UHD_LOG_ERROR("MPMD", "Invalid GPIO bank: `" << bank << "'");
194         throw uhd::key_error(std::string("Invalid GPIO bank: ") + bank);
195     }
196     return _gpio_srcs.at(bank);
197 }
198 
get_gpio_src(const std::string & bank)199 std::vector<std::string> mpmd_mb_controller::get_gpio_src(const std::string& bank)
200 {
201     if (!_gpio_srcs.count(bank)) {
202         UHD_LOG_ERROR("MPMD", "Invalid GPIO bank: `" << bank << "'");
203         throw uhd::key_error(std::string("Invalid GPIO bank: ") + bank);
204     }
205     return _rpc->request_with_token<std::vector<std::string>>("get_gpio_src", bank);
206 }
207 
set_gpio_src(const std::string & bank,const std::vector<std::string> & src)208 void mpmd_mb_controller::set_gpio_src(
209     const std::string& bank, const std::vector<std::string>& src)
210 {
211     if (!_gpio_srcs.count(bank)) {
212         UHD_LOG_ERROR("MPMD", "Invalid GPIO bank: `" << bank << "'");
213         throw uhd::key_error(std::string("Invalid GPIO bank: ") + bank);
214     }
215     _rpc->notify_with_token("set_gpio_src", bank, src);
216 }
217