1 //
2 // Copyright 2020 Ettus Research, a National Instruments Brand
3 //
4 // SPDX-License-Identifier: GPL-3.0-or-later
5 //
6 
7 #pragma once
8 
9 #include <uhd/config.hpp>
10 #include <stddef.h>
11 #include <string>
12 #include <vector>
13 #include <functional>
14 
15 namespace uhd { namespace usrp { namespace cal {
16 
17 //! Identify the source of calibration data, i.e., where was it stored
18 //
19 // This enum lists the sources in reverse order of priority, i.e., user-provided
20 // data has the highest priority, and hard-coded data from the resource compiler
21 // has the lowest priority.
22 enum class source {
23     NONE, //!< No calibration data available
24     ANY, //!< Undefined source
25     RC, //!< Internal Resource Compiler (i.e., hard-coded within UHD)
26     FLASH, //!< Stored on device flash memory, e.g. EEPROM
27     FILESYSTEM, //!< Stored on the local filesystem
28     USER //!< Provided by the user
29 };
30 
31 /*! Calibration Data Storage/Retrieval Class
32  *
33  * UHD can store calibration data on disk or compiled within UHD. This class
34  * provides access to both locations.
35  *
36  * \section cal_db_blob Format of binary data
37  *
38  * This class can read and write binary data, but it does not verify the data
39  * or expect any kind of format. It simply manages BLOBs (binary large objects).
40  * It is up to the consumers and producers of this data to agree on a format.
41  * Typically, since this class stores calibration data, it will be consuming
42  * data that was produced by uhd::usrp::cal::container::serialize().
43  *
44  * \section cal_db_serial Serial number and key
45  *
46  * Calibration data is indexed by two keys: An arbitrary key that describes the
47  * type of calibration data (e.g., "rx_iq") and a serial number. The serial
48  * number has to uniquely identify the device for which the calibration data was
49  * obtained. This can either be the serial number of the daughterboard (if the
50  * calibration data only relates to the daughterboard), the motherboard (for
51  * example, if there is no such thing as a daughterboard, or the data only
52  * relates to the motherboard), it can be combination of both daughterboard and
53  * motherboard serial (if the calibration data is only valid for a combination),
54  * or it can be a combination of a device serial number and a channel index
55  * (if a device with single serial has different channels that have separate
56  * characteristics).
57  *
58  * It is up to the individual device drivers which value they use for the serial
59  * numbers and keys.
60  *
61  * Note that the serial number is irrelevant when the data is pulled out of the
62  * resource compiler. By definition, it is not permitted to store data in the
63  * resource compiler that is specific to a certain serial number, only data that
64  * applies to an entire family of devices is permitted.
65  */
66 class UHD_API database
67 {
68 public:
69     //! Return a calibration data set as a serialized string
70     //
71     // Note: the \p source_type parameter can be used to specify where to read
72     //                          cal data from. However, this class only has
73     //                          access to RC and FILESYSTEM type cal data. ANY
74     //                          will pick FILESYSTEM data if both are available,
75     //                          and RC data if only RC data is available.
76     // \param key The calibration type key (e.g., "rx_iq")
77     // \param serial The serial number of the device this data is for. See also
78     //               \ref cal_db_serial
79     // \param source_type Where to read the calibration data from. See comments
80     //                    above. For anything other than RC, FILESYSTEM, or ANY,
81     //                    this will always throw a uhd::key_error because this
82     //                    class does not have access to user data or EEPROM data.
83     //
84     // \throws uhd::key_error if no calibration data is found matching the source
85     //                        type.
86     static std::vector<uint8_t> read_cal_data(const std::string& key,
87         const std::string& serial,
88         const source source_type = source::ANY);
89 
90     //! Check if calibration data exists for a given source type
91     //
92     // This can be called before calling read_cal_data() to avoid having to
93     // catch an exception. If \p source_type is FILESYSTEM, then it will only
94     // return true if a file is found with the appropriate cal data. The same
95     // is true for RC. If \p is ANY, then having either RC or FILESYSTEM data
96     // will yield true.
97     //
98     // \param key The calibration type key (e.g., "rx_iq")
99     // \param serial The serial number of the device this data is for. See also
100     //               \ref cal_db_serial
101     // \param source_type Where to read the calibration data from. For anything
102     //                    other than RC, FILESYSTEM, or ANY, this will always
103     //                    return false because this class does not have access
104     //                    to user data or EEPROM data.
105     // \return true if calibration data is available that matches this key/serial
106     //              pair.
107     static bool has_cal_data(const std::string& key,
108         const std::string& serial,
109         const source source_type = source::ANY);
110 
111     //! Store calibration data to the local filesystem database
112     //
113     // This implies a source type of FILESYSTEM. Note that writing the data does
114     // not apply it to a currently running UHD session. Devices will typically
115     // load calibration data at initialization time, and thus this call will
116     // take effect only for future UHD sessions.
117     //
118     // If calibration data for this key/serial pair already exists in the
119     // database, the original data will be backed up by renaming the original
120     // file from `filename.cal` to `filename.cal.$TIMESTAMP`. Alternatively, a
121     // custom extension can be chosen instead of `$TIMESTAMP`.
122     //
123     // \param key The calibration type key (e.g., "rx_iq")
124     // \param serial The serial number of the device this data is for. See also
125     //               \ref cal_db_serial
126     // \param cal_data The calibration data to be written
127     // \param backup_ext A custom extension for backing up calibration data. If
128     //                   left empty, a POSIX timestamp is used.
129     static void write_cal_data(const std::string& key,
130         const std::string& serial,
131         const std::vector<uint8_t>& cal_data,
132         const std::string& backup_ext = "");
133 
134     //! Function type to look up if there is cal data given a key and serial
135     using has_data_fn_type = std::function<bool(const std::string&, const std::string&)>;
136 
137     //! Function type to return serialized cal data key and serial
138     //
139     // These functions should throw a uhd::runtime_error if called with invalid
140     // key/serial pairs, although database will internally always call the
141     // corresponding 'has' function before calling this.
142     using get_data_fn_type =
143         std::function<std::vector<uint8_t>(const std::string&, const std::string&)>;
144 
145     //! Register a lookup function for cal data
146     //
147     // \param has_cal_data A function object to a function that returns true if
148     //        cal data is available
149     // \param get_cal_data A function object to a function that returns serialized
150     //        cal data
151     // \param source_type Reserved. Must be source::FLASH.
152     static void register_lookup(has_data_fn_type has_cal_data,
153         get_data_fn_type get_cal_data,
154         const source source_type = source::FLASH);
155 };
156 
157 
158 }}} // namespace uhd::usrp::cal
159