aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib/usrp/mpmd/mpmd_prop_tree.cpp
blob: e1b5d43cb7080b26e9ee8889a927b1ec36b7c068 (plain)
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
//
// 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 <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>

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;

    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];
        }
        // 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<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(1e9 / 8);
    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"));

    /*** 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](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<size_t>(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<size_t>(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); });
}