// // Copyright 2018 Ettus Research, a National Instruments Company // // SPDX-License-Identifier: GPL-3.0-or-later // // property tree initialization code #include "mpmd_impl.hpp" #include #include #include #include #include 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> all_data; std::vector> all_metadata; // Also construct a copy of just the metadata to store in the property tree uhd::usrp::component_files_t all_comps_copy; for (const auto& comp : comps) { // Make a map for update components args std::map 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]; } // 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); } // 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>( "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("/name").set( mb->device_info.get("description", "Unknown MPM device")); } tree->create(mb_path / "name") .set(mb->device_info.get("name", "UNKNOWN")); tree->create(mb_path / "serial") .set(mb->device_info.get("serial", "n/a")); tree->create(mb_path / "connection") .set(mb->device_info.get("connection", "UNKNOWN")); tree->create(mb_path / "link_max_rate").set(1e9 / 8); tree->create(mb_path / "mpm_version") .set(mb->device_info.get("mpm_version", "UNKNOWN")); tree->create(mb_path / "fpga_version") .set(mb->device_info.get("fpga_version", "UNKNOWN")); tree->create(mb_path / "fpga_version_hash") .set(mb->device_info.get("fpga_version_hash", "UNKNOWN")); /*** Clocking *******************************************************/ tree->create(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("get_clock_source"); }); tree->create>(mb_path / "clock_source/options") .set_publisher([mb]() { return mb->rpc->request_with_token>( "get_clock_sources"); }); tree->create(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("get_time_source"); }); tree->create>(mb_path / "time_source/options") .set_publisher([mb]() { return mb->rpc->request_with_token>( "get_time_sources"); }); /*** Sensors ********************************************************/ auto sensor_list = mb->rpc->request_with_token>("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(mb_path / "sensors" / sensor_name) .set_publisher([mb, sensor_name]() { auto sensor_val = sensor_value_t( mb->rpc->request_with_token( 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(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(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>( "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 updateable_components = mb->rpc->request>("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(mb_path / "components" / comp_name) .set_coercer([mb](const uhd::usrp::component_files_t& comp_files) { return _update_component(comp_files, mb); }) .set_publisher([mb, comp_name]() { return _get_component_info(comp_name, mb); }); // Done adding component to property tree } /*** MTUs ***********************************************************/ tree->create(mb_path / "mtu/recv") .add_coerced_subscriber([](const size_t) { throw uhd::runtime_error("Attempting to write read-only value (MTU)!"); }) .set_publisher([mb]() { return mb->get_mtu(uhd::RX_DIRECTION); }); tree->create(mb_path / "mtu/send") .add_coerced_subscriber([](const size_t) { throw uhd::runtime_error("Attempting to write read-only value (MTU)!"); }) .set_publisher([mb]() { return mb->get_mtu(uhd::TX_DIRECTION); }); }