1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
|
//
// Copyright 2018 Ettus Research, a National Instruments Company
// Copyright 2019 Ettus Research, a National Instruments Brand
//
// SPDX-License-Identifier: GPL-3.0-or-later
//
// property tree initialization code
#include "mpmd_impl.hpp"
#include <uhd/property_tree.hpp>
#include <uhd/types/component_file.hpp>
#include <uhd/types/eeprom.hpp>
#include <uhd/types/sensors.hpp>
#include <uhd/usrp/mboard_eeprom.hpp>
#include <uhd/utils/cast.hpp>
#include <boost/algorithm/string/case_conv.hpp>
using namespace uhd;
using namespace uhd::mpmd;
namespace {
/*! Update a component using all required files. For example, when updating the FPGA image
* (.bit or .bin), users can provide a new overlay image (DTS) to apply in addition.
*
* \param comps Vector of component files to be updated
* \param mb Reference to the actual device
*/
uhd::usrp::component_files_t _update_component(
const uhd::usrp::component_files_t& comps, mpmd_mboard_impl* mb)
{
// Construct the arguments to update component
std::vector<std::vector<uint8_t>> all_data;
std::vector<std::map<std::string, std::string>> all_metadata;
// Also construct a copy of just the metadata to store in the property tree
uhd::usrp::component_files_t all_comps_copy;
bool just_reload = false;
for (const auto& comp : comps) {
// Make a map for update components args
std::map<std::string, std::string> metadata;
// Make a component copy to add to the property tree
uhd::usrp::component_file_t comp_copy;
// Copy the metadata
for (const auto& key : comp.metadata.keys()) {
metadata[key] = comp.metadata[key];
comp_copy.metadata[key] = comp.metadata[key];
if (key == "just_reload") {
just_reload =
just_reload
| uhd::cast::from_str<bool>(metadata.at("just_reload"));
//| (boost::to_lower_copy(metadata.at("just_reload")) == "true");
}
}
// Copy to the update component args
all_data.push_back(comp.data);
all_metadata.push_back(metadata);
// Copy to the property tree
all_comps_copy.push_back(comp_copy);
}
// If reset is specified we presume that the fpga/dts
// components were updated in the last uhd::image_loader::load()
// call and just reload the fpga/dts by resetting the peripheral
// manager.
if (just_reload) {
mb->rpc->notify_with_token(MPMD_DEFAULT_INIT_TIMEOUT, "reset_timer_and_mgr");
return all_comps_copy;
}
// Now call update component
mb->rpc->notify_with_token(
MPMD_DEFAULT_INIT_TIMEOUT, "update_component", all_metadata, all_data);
return all_comps_copy;
}
/*
* Query the device to get the metadata for desired component
*
* \param comp_name String component name
* \param mb Reference to the actual device
* \return component files containing the component metadata
*/
uhd::usrp::component_files_t _get_component_info(
const std::string& comp_name, mpmd_mboard_impl* mb)
{
UHD_LOG_TRACE("MPMD", "Getting component info for " << comp_name);
const auto component_metadata = mb->rpc->request<std::map<std::string, std::string>>(
"get_component_info", comp_name);
// Copy the contents of the component metadata into a object we can return
uhd::usrp::component_file_t return_component;
auto& return_metadata = return_component.metadata;
for (auto item : component_metadata) {
return_metadata[item.first] = item.second;
}
return uhd::usrp::component_files_t{return_component};
}
} // namespace
void mpmd_impl::init_property_tree(
uhd::property_tree::sptr tree, fs_path mb_path, mpmd_mboard_impl* mb)
{
/*** Device info ****************************************************/
if (not tree->exists("/name")) {
tree->create<std::string>("/name").set(
mb->device_info.get("description", "Unknown MPM device"));
}
tree->create<std::string>(mb_path / "name")
.set(mb->device_info.get("name", "UNKNOWN"));
tree->create<std::string>(mb_path / "serial")
.set(mb->device_info.get("serial", "n/a"));
tree->create<std::string>(mb_path / "connection")
.set(mb->device_info.get("connection", "UNKNOWN"));
tree->create<size_t>(mb_path / "link_max_rate").set(125000000);
tree->create<std::string>(mb_path / "mpm_version")
.set(mb->device_info.get("mpm_version", "UNKNOWN"));
tree->create<std::string>(mb_path / "fpga_version")
.set(mb->device_info.get("fpga_version", "UNKNOWN"));
tree->create<std::string>(mb_path / "fpga_version_hash")
.set(mb->device_info.get("fpga_version_hash", "UNKNOWN"));
tree->create<std::string>(mb_path / "token").set(mb->get_token());
tree->create<uhd::device_addr_t>(mb_path / "args").set(mb->mb_args);
tree->create<std::string>(mb_path / "mender_artifact")
.set(mb->device_info.get("mender_artifact", "UNKNOWN"));
tree->create<std::string>(mb_path / "mpm_sw_version")
.set(mb->device_info.get("mpm_sw_version", "UNKNOWN"));
tree->create<std::string>(mb_path / "fs_version")
.set(mb->device_info.get("fs_version", "UNKNOWN"));
/*** Clocking *******************************************************/
tree->create<std::string>(mb_path / "clock_source/value")
.add_coerced_subscriber([mb](const std::string& clock_source) {
mb->rpc->notify_with_token(
MPMD_DEFAULT_INIT_TIMEOUT, "set_clock_source", clock_source);
})
.set_publisher([mb]() {
return mb->rpc->request_with_token<std::string>("get_clock_source");
});
tree->create<std::vector<std::string>>(mb_path / "clock_source/options")
.set_publisher([mb]() {
return mb->rpc->request_with_token<std::vector<std::string>>(
"get_clock_sources");
});
tree->create<std::string>(mb_path / "time_source/value")
.add_coerced_subscriber([mb](const std::string& time_source) {
mb->rpc->notify_with_token(
MPMD_DEFAULT_INIT_TIMEOUT, "set_time_source", time_source);
})
.set_publisher([mb]() {
return mb->rpc->request_with_token<std::string>("get_time_source");
});
tree->create<std::vector<std::string>>(mb_path / "time_source/options")
.set_publisher([mb]() {
return mb->rpc->request_with_token<std::vector<std::string>>(
"get_time_sources");
});
/*** Sensors ********************************************************/
auto sensor_list =
mb->rpc->request_with_token<std::vector<std::string>>("get_mb_sensors");
UHD_LOG_DEBUG("MPMD", "Found " << sensor_list.size() << " motherboard sensors.");
for (const auto& sensor_name : sensor_list) {
UHD_LOG_TRACE("MPMD", "Adding motherboard sensor `" << sensor_name << "'");
tree->create<sensor_value_t>(mb_path / "sensors" / sensor_name)
.set_publisher([mb, sensor_name]() {
auto sensor_val = sensor_value_t(
mb->rpc->request_with_token<sensor_value_t::sensor_map_t>(
MPMD_DEFAULT_INIT_TIMEOUT, "get_mb_sensor", sensor_name));
return sensor_val;
})
.set_coercer([](const sensor_value_t&) {
throw uhd::runtime_error("Trying to write read-only sensor value!");
return sensor_value_t("", "", "");
});
}
/*** EEPROM *********************************************************/
tree->create<uhd::usrp::mboard_eeprom_t>(mb_path / "eeprom")
.add_coerced_subscriber([mb](const uhd::usrp::mboard_eeprom_t& mb_eeprom) {
eeprom_map_t eeprom_map;
for (const auto& key : mb_eeprom.keys()) {
eeprom_map[key] =
std::vector<uint8_t>(mb_eeprom[key].cbegin(), mb_eeprom[key].cend());
}
mb->rpc->notify_with_token(
MPMD_DEFAULT_INIT_TIMEOUT, "set_mb_eeprom", eeprom_map);
})
.set_publisher([mb]() {
auto mb_eeprom =
mb->rpc->request_with_token<std::map<std::string, std::string>>(
"get_mb_eeprom");
uhd::usrp::mboard_eeprom_t mb_eeprom_dict(
mb_eeprom.cbegin(), mb_eeprom.cend());
return mb_eeprom_dict;
});
/*** Updateable Components ******************************************/
std::vector<std::string> updateable_components =
mb->rpc->request<std::vector<std::string>>("list_updateable_components");
// TODO: Check the 'id' against the registered property
UHD_LOG_DEBUG("MPMD",
"Found " << updateable_components.size()
<< " updateable motherboard components.");
for (const auto& comp_name : updateable_components) {
UHD_LOG_TRACE("MPMD", "Adding motherboard component: " << comp_name);
tree->create<uhd::usrp::component_files_t>(mb_path / "components" / comp_name)
.set_coercer([mb, comp_name](const uhd::usrp::component_files_t& comp_files) {
auto comp_info = _get_component_info(comp_name, mb)[0];
if (comp_info.metadata.get("reset", "") == "True") {
UHD_LOG_DEBUG(
"MPMD", "Bracing for potential loss of RPC server connection.");
mb->allow_claim_failure(true);
}
auto result = _update_component(comp_files, mb);
mb->allow_claim_failure(false);
return result;
})
.set_publisher([mb, comp_name]() {
return _get_component_info(comp_name, mb);
}); // Done adding component to property tree
}
}
|