aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Braun <martin.braun@ettus.com>2020-05-19 11:12:34 -0700
committerAaron Rossetto <aaron.rossetto@ni.com>2020-05-20 07:30:15 -0500
commitd7287678358b59993d5cace77ffbd0564ebe7593 (patch)
treec3729ae04412178a5b6cf004cec8f220f959f05d
parent746f9c7f0e3fb8c2f9e480ba2bad4527ce9eb34a (diff)
downloaduhd-d7287678358b59993d5cace77ffbd0564ebe7593.tar.gz
uhd-d7287678358b59993d5cace77ffbd0564ebe7593.tar.bz2
uhd-d7287678358b59993d5cace77ffbd0564ebe7593.zip
cal: database: Add option to register flash cal callbacks
This adds the possibility to read cal data from flash/EEPROM by adding callbacks to the database. Unlike the RC and FILESYSTEM data, this is very device-specific, but we can let devices register callbacks in the database so that reading cal data from flash can use the same APIs as from RC or filesystem. Note that this also gives a convenient way to inject call data during unit tests, if desired.
-rw-r--r--host/include/uhd/cal/database.hpp24
-rw-r--r--host/lib/cal/database.cpp54
-rw-r--r--host/tests/cal_database_test.cpp36
3 files changed, 110 insertions, 4 deletions
diff --git a/host/include/uhd/cal/database.hpp b/host/include/uhd/cal/database.hpp
index a4c233030..b6abbb6df 100644
--- a/host/include/uhd/cal/database.hpp
+++ b/host/include/uhd/cal/database.hpp
@@ -10,6 +10,7 @@
#include <stddef.h>
#include <string>
#include <vector>
+#include <functional>
namespace uhd { namespace usrp { namespace cal {
@@ -65,7 +66,6 @@ enum class source {
class UHD_API database
{
public:
-
//! Return a calibration data set as a serialized string
//
// Note: the \p source_type parameter can be used to specify where to read
@@ -130,6 +130,28 @@ public:
const std::string& serial,
const std::vector<uint8_t>& cal_data,
const std::string& backup_ext = "");
+
+ //! Function type to look up if there is cal data given a key and serial
+ using has_data_fn_type = std::function<bool(const std::string&, const std::string&)>;
+
+ //! Function type to return serialized cal data key and serial
+ //
+ // These functions should throw a uhd::runtime_error if called with invalid
+ // key/serial pairs, although database will internally always call the
+ // corresponding 'has' function before calling this.
+ using get_data_fn_type =
+ std::function<std::vector<uint8_t>(const std::string&, const std::string&)>;
+
+ //! Register a lookup function for cal data
+ //
+ // \param has_cal_data A function object to a function that returns true if
+ // cal data is available
+ // \param get_cal_data A function object to a function that returns serialized
+ // cal data
+ // \param source_type Reserved. Must be source::FLASH.
+ static void register_lookup(has_data_fn_type has_cal_data,
+ get_data_fn_type get_cal_data,
+ const source source_type = source::FLASH);
};
diff --git a/host/lib/cal/database.cpp b/host/lib/cal/database.cpp
index fde55e8ba..87f74bc8d 100644
--- a/host/lib/cal/database.cpp
+++ b/host/lib/cal/database.cpp
@@ -8,6 +8,7 @@
#include <uhd/exception.hpp>
#include <uhd/utils/log.hpp>
#include <uhd/utils/paths.hpp>
+#include <uhd/utils/static.hpp>
#include <cmrc/cmrc.hpp>
#include <boost/filesystem.hpp>
#include <ctime>
@@ -42,6 +43,9 @@ std::string get_cal_path_rc(const std::string& key)
}
//! Return true if a cal data resource with given key exists
+//
+// The serial parameter is ignored, as serial numbers should, by definition, not
+// matter for RC data
bool has_cal_data_rc(const std::string& key, const std::string&)
{
auto fs = rc::get_filesystem();
@@ -149,6 +153,38 @@ std::vector<uint8_t> get_cal_data_fs(const std::string& key, const std::string&
} // namespace
+/******************************************************************************
+ * Flash/EEPROM implementation
+ *****************************************************************************/
+// Access to non-volatile memory is device-specific. Instead of implementing
+// anything here, we allow devices to register callbacks to look up cal data
+// from their EEPROMs / flash memories.
+using lookup_registry_type =
+ std::vector<std::pair<database::has_data_fn_type, database::get_data_fn_type>>;
+UHD_SINGLETON_FCN(lookup_registry_type, get_flash_lookup_registry);
+
+bool has_cal_data_flash(const std::string& key, const std::string& serial)
+{
+ for (auto& data_fn_pair : get_flash_lookup_registry()) {
+ if (data_fn_pair.first(key, serial)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+std::vector<uint8_t> get_cal_data_flash(const std::string& key, const std::string& serial)
+{
+ for (auto& data_fn_pair : get_flash_lookup_registry()) {
+ if (data_fn_pair.first(key, serial)) {
+ return data_fn_pair.second(key, serial);
+ }
+ }
+ // No data? Then throw:
+ throw uhd::key_error(
+ std::string("Cannot find flash cal data for key=") + key + ", serial=" + serial);
+}
+
/******************************************************************************
* Function lookup
@@ -156,9 +192,13 @@ std::vector<uint8_t> get_cal_data_fs(const std::string& key, const std::string&
typedef bool (*has_cal_data_fn)(const std::string&, const std::string&);
typedef std::vector<uint8_t> (*get_cal_data_fn)(const std::string&, const std::string&);
// These are in order of priority!
-constexpr std::array<std::tuple<source, has_cal_data_fn, get_cal_data_fn>, 2> data_fns{
- {{source::FILESYSTEM, &has_cal_data_fs, &get_cal_data_fs},
- {source::RC, &has_cal_data_rc, &get_cal_data_rc}}};
+// clang-format off
+constexpr std::array<std::tuple<source, has_cal_data_fn, get_cal_data_fn>, 3> data_fns{{
+ {source::FILESYSTEM, &has_cal_data_fs, &get_cal_data_fs },
+ {source::FLASH, &has_cal_data_flash, &get_cal_data_flash},
+ {source::RC, &has_cal_data_rc, &get_cal_data_rc }
+}};
+// clang-format on
/******************************************************************************
@@ -220,3 +260,11 @@ void database::write_cal_data(const std::string& key,
UHD_LOG_DEBUG(LOG_ID, "Writing to " << cal_file_path);
file.write(reinterpret_cast<const char*>(cal_data.data()), cal_data.size());
}
+
+void database::register_lookup(has_data_fn_type has_cal_data,
+ get_data_fn_type get_cal_data,
+ const source source_type)
+{
+ UHD_ASSERT_THROW(source_type == source::FLASH);
+ get_flash_lookup_registry().push_back({has_cal_data, get_cal_data});
+}
diff --git a/host/tests/cal_database_test.cpp b/host/tests/cal_database_test.cpp
index cd189138b..d53ca4576 100644
--- a/host/tests/cal_database_test.cpp
+++ b/host/tests/cal_database_test.cpp
@@ -6,10 +6,12 @@
#include <uhd/cal/database.hpp>
#include <uhd/utils/paths.hpp>
+#include <uhd/exception.hpp>
#include <stdlib.h> // putenv or _putenv
#include <boost/filesystem.hpp>
#include <boost/test/unit_test.hpp>
#include <iostream>
+#include <numeric>
using namespace uhd::usrp::cal;
namespace fs = boost::filesystem;
@@ -86,3 +88,37 @@ BOOST_AUTO_TEST_CASE(test_fs)
std::cout << "WARNING: Could not remove temp cal path." << std::endl;
}
}
+
+BOOST_AUTO_TEST_CASE(test_flash)
+{
+ // 4 bytes of cal data
+ std::vector<uint8_t> mock_cal_data{42, 23, 1, 2};
+
+ database::register_lookup(
+ [&](const std::string& key, const std::string&) {
+ // Note: We're deliberately not checking the key here, but below, so
+ // we can check all code paths in database.cpp, even the ones we're
+ // not supposed to reach
+ return key == "MOCK_KEY";
+ },
+ [&](const std::string& key, const std::string& serial) {
+ if (key == "MOCK_KEY" && serial == "MOCK_SERIAL") {
+ return mock_cal_data;
+ }
+ throw uhd::runtime_error("no such mock data!");
+ });
+ BOOST_CHECK(database::has_cal_data("MOCK_KEY", "MOCK_SERIAL", source::FLASH));
+ BOOST_CHECK(!database::has_cal_data("FOO_KEY", "FOO_SERIAL", source::FLASH));
+ auto cal_data1 = database::read_cal_data("MOCK_KEY", "MOCK_SERIAL", source::FLASH);
+ BOOST_CHECK_EQUAL_COLLECTIONS(mock_cal_data.cbegin(),
+ mock_cal_data.cend(),
+ cal_data1.cbegin(),
+ cal_data1.cend());
+ auto cal_data2 = database::read_cal_data("MOCK_KEY", "MOCK_SERIAL", source::ANY);
+ BOOST_CHECK_EQUAL_COLLECTIONS(mock_cal_data.cbegin(),
+ mock_cal_data.cend(),
+ cal_data2.cbegin(),
+ cal_data2.cend());
+ BOOST_REQUIRE_THROW(database::read_cal_data("MOCK_KEY", "FOO_SERIAL", source::FLASH),
+ uhd::runtime_error);
+}