aboutsummaryrefslogtreecommitdiffstats
path: root/host
diff options
context:
space:
mode:
Diffstat (limited to 'host')
-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);
+}