Skip to content

Commit

Permalink
SavedConfig: changed CachedCards memory layout
Browse files Browse the repository at this point in the history
  • Loading branch information
PBrunot committed May 12, 2024
1 parent 89fa4f0 commit 76298c5
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 99 deletions.
7 changes: 4 additions & 3 deletions include/AuthProvider.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,19 @@
#include "FabUser.hpp"
#include "secrets.hpp"
#include "WhiteList.hpp"
#include "CachedCards.hpp"

namespace fabomatic
{
class AuthProvider
{
private:
WhiteList whitelist;
mutable CachedList cache;
mutable CachedCards cache;
mutable size_t cache_idx = 0;
[[nodiscard]] auto uidInWhitelist(card::uid_t uid) const -> std::optional<WhiteListEntry>;
[[nodiscard]] auto uidInCache(card::uid_t uid) const -> std::optional<CachedFabUser>;
[[nodiscard]] auto searchCache(card::uid_t candidate_uid) const -> std::optional<CachedFabUser>;
[[nodiscard]] auto uidInCache(card::uid_t uid) const -> std::optional<CachedCard>;
[[nodiscard]] auto searchCache(card::uid_t candidate_uid) const -> std::optional<CachedCard>;
auto updateCache(card::uid_t candidate_uid, FabUser::UserLevel level) const -> void;

public:
Expand Down
46 changes: 46 additions & 0 deletions include/CachedCards.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#ifndef CACHEDCARDS_HPP
#define CACHEDCARDS_HPP

#include <array>

#include "FabUser.hpp"
#include "conf.hpp"
#include "card.hpp"

namespace fabomatic
{
struct CachedCard
{
card::uid_t uid;
FabUser::UserLevel level;
constexpr CachedCard() : uid(card::INVALID), level(FabUser::UserLevel::Unknown){};
constexpr CachedCard(card::uid_t uid, FabUser::UserLevel level) : uid(uid), level(level){};
};

struct CachedCards
{
std::array<card::uid_t, conf::rfid_tags::CACHE_LEN> cards;
std::array<FabUser::UserLevel, conf::rfid_tags::CACHE_LEN> levels;

constexpr CachedCards() : cards{card::INVALID}, levels{FabUser::UserLevel::Unknown} {};

constexpr const CachedCard operator[](int i) const
{
return {cards[i], levels[i]};
}

constexpr void set_at(int idx, const card::uid_t &uid, const FabUser::UserLevel &level)
{
cards[idx] = uid;
levels[idx] = level;
}

constexpr size_t size() const
{
return conf::rfid_tags::CACHE_LEN;
}
};

} // namespace fabomatic

#endif // CACHEDCARDS_HPP
16 changes: 8 additions & 8 deletions include/SavedConfig.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@

#include "MachineConfig.hpp"
#include "conf.hpp"
#include "WhiteList.hpp"
#include "CachedCards.hpp"

namespace fabomatic
{
class SavedConfig
{
private:
static constexpr auto JSON_DOC_SIZE = 1024;
static_assert(JSON_DOC_SIZE > (conf::common::STR_MAX_LENGTH * 7 + sizeof(bool) + sizeof(size_t) + sizeof(CachedList)) * 2, "JSON_DOC_SIZE must be larger than SavedConfig size in JSON");
static_assert(JSON_DOC_SIZE > (conf::common::STR_MAX_LENGTH * 7 + sizeof(bool) + sizeof(size_t) + sizeof(CachedCards)) * 2, "JSON_DOC_SIZE must be larger than SavedConfig size in JSON");
static std::string json_buffer;
static std::mutex buffer_mutex;

Expand All @@ -33,11 +33,14 @@ namespace fabomatic
[[nodiscard]] static auto fromJsonDocument(const std::string &json_text) -> std::optional<SavedConfig>;

public:
static constexpr auto MAGIC_NUMBER = 0x49; // Increment when changing the struct
static constexpr auto MAGIC_NUMBER = 0x50; // Increment when changing the struct

// Magic number to check if the EEPROM is initialized
mutable uint8_t magic_number{0};

/// @brief list of cached RFID cards
CachedCards cachedRfid;

/// @brief WiFi SSID
std::string ssid{""};

Expand All @@ -60,15 +63,12 @@ namespace fabomatic
/// @details This is a string to allow for easier integration with WiFiManager parameter
std::string machine_id{""};

/// @brief list of cached RFID cards
CachedList cachedRfid;
/// @brief number of boot cycles
size_t bootCount{0};

/// @brief if true, the FORCE_OPEN_PORTAL flag will be ignored
bool disablePortal{false};

/// @brief number of boot cycles
size_t bootCount{0};

/// @brief Allow compiler-time construction
constexpr SavedConfig() = default;

Expand Down
28 changes: 0 additions & 28 deletions include/WhiteList.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,34 +19,6 @@ namespace fabomatic
using WhiteListEntry = std::tuple<card::uid_t, FabUser::UserLevel, std::string_view>;
using WhiteList = std::array<WhiteListEntry, conf::cards::LEN>;

struct CachedFabUser
{
card::uid_t uid;
FabUser::UserLevel level;
constexpr CachedFabUser() : uid(card::INVALID), level(FabUser::UserLevel::Unknown){};
constexpr CachedFabUser(card::uid_t uid, FabUser::UserLevel level) : uid(uid), level(level){};
constexpr auto operator<(const CachedFabUser &rhs) const -> bool
{
return uid < rhs.uid;
}
constexpr auto operator==(const CachedFabUser &rhs) const -> bool
{
return uid == rhs.uid;
}
};

using CachedList = std::array<CachedFabUser, conf::rfid_tags::CACHE_LEN>;

template <typename T, size_t N>
[[nodiscard]] bool ScrambledEquals(const std::array<T, N> &arr1, const std::array<T, N> &arr2)
{
std::array<T, N> sorted1 = arr1;
std::array<T, N> sorted2 = arr2;
std::sort(sorted1.begin(), sorted1.end());
std::sort(sorted2.begin(), sorted2.end());

return sorted1 == sorted2;
}
} // namespace fabomatic

#endif // WHITELIST_HPP
83 changes: 30 additions & 53 deletions src/AuthProvider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <cstdint>
#include <string>
#include <algorithm>

#include "FabBackend.hpp"
#include "Logging.hpp"
Expand All @@ -23,13 +24,13 @@ namespace fabomatic
void AuthProvider::updateCache(card::uid_t uid, FabUser::UserLevel level) const
{
// Search for the card in the cache
for (auto &cached : cache)
auto pos = std::find(cache.cards.cbegin(), cache.cards.cend(), uid);
if (pos != cache.cards.cend())
{
if (cached.uid == uid)
{
cached.level = level;
return;
}
// Update the level at same index
auto idx = std::distance(cache.cards.cbegin(), pos);
cache.levels[idx] = level;
return;
}

// No need to add in cache invalid cards
Expand All @@ -41,8 +42,8 @@ namespace fabomatic
cache_idx = 0;

// Add into list
cache.at(cache_idx).uid = uid;
cache.at(cache_idx).level = level;
cache.cards.at(cache_idx) = uid;
cache.levels.at(cache_idx) = level;

cache_idx = (cache_idx + 1) % conf::rfid_tags::CACHE_LEN;
}
Expand Down Expand Up @@ -135,14 +136,14 @@ namespace fabomatic
return std::nullopt;
}

const auto elem = std::find_if(whitelist.begin(), whitelist.end(),
[candidate_uid](const auto &input)
{
const auto [w_uid, w_level, w_name] = input;
return w_uid == candidate_uid;
});
const auto &elem = std::find_if(whitelist.cbegin(), whitelist.cend(),
[candidate_uid](const auto &input)
{
const auto &[w_uid, w_level, w_name] = input;
return w_uid == candidate_uid;
});

if (elem == end(whitelist))
if (elem == whitelist.cend())
{
ESP_LOGD(TAG, "%s not found in whitelist", card::uid_str(candidate_uid).c_str());
return std::nullopt;
Expand All @@ -154,55 +155,35 @@ namespace fabomatic
/// @brief Checks if the card ID is whitelisted
/// @param uid card ID
/// @return a whitelistentry object if the card is found in whitelist
auto AuthProvider::uidInCache(card::uid_t candidate_uid) const -> std::optional<CachedFabUser>
auto AuthProvider::uidInCache(card::uid_t candidate_uid) const -> std::optional<CachedCard>
{
if (candidate_uid == card::INVALID)
{
return std::nullopt;
}

const auto elem = std::find_if(cache.begin(), cache.end(),
[candidate_uid](const auto &input)
{
return input.uid == candidate_uid;
});
const auto elem = std::find(cache.cards.cbegin(), cache.cards.cend(), candidate_uid);

if (elem == end(cache))
if (elem == cache.cards.cend())
{
ESP_LOGD(TAG, "%s not found in cache", card::uid_str(candidate_uid).c_str());
return std::nullopt;
}

return {*elem};
return cache[std::distance(cache.cards.cbegin(), elem)];
}

/// @brief Loads the cache from EEPROM
auto AuthProvider::loadCache() -> void
{
auto config = SavedConfig::LoadFromEEPROM();
const auto &config = SavedConfig::LoadFromEEPROM();
if (!config.has_value())
return;

size_t idx = 0;
for (const auto &user : config.value().cachedRfid)
{
cache.at(idx).uid = user.uid;
cache.at(idx).level = user.level;
if (user.uid != 0)
{
ESP_LOGD(TAG, "Loaded cached RFID tag %s (%d)", card::uid_str(user.uid).c_str(), user.level);
}
idx++;
if (idx >= cache.size())
{
idx = 0;
break;
}
if (user.uid != 0)
{
cache_idx = idx;
}
}
const auto &loaded = config.value().cachedRfid;

std::copy(loaded.cards.cbegin(), loaded.cards.cend(), cache.cards.begin());
std::copy(loaded.levels.cbegin(), loaded.levels.cend(), cache.levels.begin());
}

/// @brief Sets the whitelist
Expand All @@ -216,21 +197,17 @@ namespace fabomatic
auto AuthProvider::saveCache() const -> bool
{
SavedConfig config = SavedConfig::LoadFromEEPROM().value_or(SavedConfig::DefaultConfig());
SavedConfig original{config};

for (auto idx = 0; idx < cache.size(); idx++)
{
config.cachedRfid.at(idx).uid = cache.at(idx).uid;
config.cachedRfid.at(idx).level = cache.at(idx).level;
}

// Check if current config is different from updated cachedRfid ignoring order of elements
if (ScrambledEquals<CachedFabUser, conf::rfid_tags::CACHE_LEN>(original.cachedRfid, config.cachedRfid))
if (std::equal(config.cachedRfid.cards.cbegin(), config.cachedRfid.cards.cend(), cache.cards.cbegin()) &&
std::equal(config.cachedRfid.levels.cbegin(), config.cachedRfid.levels.cend(), cache.levels.cbegin()))
{
ESP_LOGD(TAG, "Cache is the same, not saving");
return true;
}

std::copy(cache.cards.cbegin(), cache.cards.cend(), config.cachedRfid.cards.begin());
std::copy(cache.levels.cbegin(), cache.levels.cend(), config.cachedRfid.levels.begin());

return config.SaveToEEPROM();
}
} // namespace fabomatic
15 changes: 8 additions & 7 deletions src/SavedConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,12 +99,13 @@ namespace fabomatic
doc["mqtt_switch_topic"] = mqtt_switch_topic;
doc["machine_id"] = machine_id;
doc["magic_number"] = magic_number;
auto cache = doc.createNestedArray("cachedRfid");
for (const auto &entry : cachedRfid)
auto json_elem = doc.createNestedArray("cached_cards");
for (auto idx = 0; idx < cachedRfid.size(); idx++)
{
auto &entry = cachedRfid[idx];
if (entry.uid != 0) // Skip empty entries
{
auto obj = cache.createNestedObject();
auto obj = json_elem.createNestedObject();
obj["uid"] = entry.uid;
obj["level"] = static_cast<uint8_t>(entry.level);
}
Expand Down Expand Up @@ -138,16 +139,16 @@ namespace fabomatic
config.magic_number = doc["magic_number"];

auto idx = 0;
for (const auto &elem : doc["cachedRfid"].as<JsonArray>())
for (const auto &elem : doc["cached_cards"].as<JsonArray>())
{
auto uid = elem["uid"];
auto level = static_cast<FabUser::UserLevel>(elem["level"].as<uint8_t>());
config.cachedRfid.at(idx++) = {uid, level};
config.cachedRfid.set_at(idx, elem["uid"], level);
idx++;
}

while (idx < conf::rfid_tags::CACHE_LEN)
{
config.cachedRfid.at(idx) = {0, FabUser::UserLevel::Unknown};
config.cachedRfid.set_at(idx, card::INVALID, FabUser::UserLevel::Unknown);
idx++;
}

Expand Down

0 comments on commit 76298c5

Please sign in to comment.