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