init
This commit is contained in:
@@ -0,0 +1,282 @@
|
||||
#include "rfid.hpp"
|
||||
#include <logger.hpp>
|
||||
RfidDB rfidDB;
|
||||
|
||||
RfidDB::RfidDB(const String& filename)
|
||||
: filename_(filename), tmpFilename_(filename + ".tmp"), initialized_(false) {}
|
||||
|
||||
RfidDB::~RfidDB() {}
|
||||
void printDatabaseContents() {
|
||||
LOG_DEBUG("--- RFID Database Contents (Stored Values) ---");
|
||||
rfidDB.iterate([](uint32_t stored_id) {
|
||||
// 'stored_id' ist der Wert, wie er in der Datei steht (Byte-geswappt)
|
||||
Serial.printf("Stored HEX: 0x%08X\n", stored_id);
|
||||
});
|
||||
LOG_DEBUG("-------------------------------------------");
|
||||
}
|
||||
|
||||
bool RfidDB::begin() {
|
||||
if (initialized_) {
|
||||
return true;
|
||||
}
|
||||
if (!LittleFS.begin()) {
|
||||
LOG_ERROR("RfidDB: LittleFS mount failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ensure the file exists, creating it if necessary.
|
||||
if (!LittleFS.exists(filename_)) {
|
||||
File f = LittleFS.open(filename_, "w");
|
||||
if (!f) {
|
||||
return false; // Could not create the file
|
||||
}
|
||||
f.close();
|
||||
}
|
||||
initialized_ = true;
|
||||
printDatabaseContents();
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t RfidDB::count() {
|
||||
if (!initialized_) return 0;
|
||||
|
||||
File f = LittleFS.open(filename_, "r");
|
||||
if (!f) return 0;
|
||||
|
||||
uint32_t n = fileEntryCount(f);
|
||||
f.close();
|
||||
return n;
|
||||
}
|
||||
|
||||
bool RfidDB::contains(uint32_t raw_id) {
|
||||
if (!initialized_) {
|
||||
LOG_DEBUG("RfidDB: contains not initialized");
|
||||
return false;
|
||||
}
|
||||
|
||||
File f = LittleFS.open(filename_, "r");
|
||||
if (!f) {
|
||||
LOG_DEBUG("RfidDB: contains failed to open file");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t id = byteSwap(raw_id);
|
||||
uint32_t idx;
|
||||
bool found = false;
|
||||
bool ok = binarySearch(f, idx, id, found);
|
||||
|
||||
f.close();
|
||||
LOG_DEBUG("RfidDB: contains id=%08X, ok=%d, found=%d", raw_id, ok, found);
|
||||
return ok && found;
|
||||
}
|
||||
|
||||
void RfidDB::iterate(std::function<void(uint32_t)> callback) {
|
||||
if (!initialized_ || !callback) return;
|
||||
|
||||
File f = LittleFS.open(filename_, "r");
|
||||
if (!f) return;
|
||||
|
||||
uint32_t n = fileEntryCount(f);
|
||||
for (uint32_t i = 0; i < n; ++i) {
|
||||
uint32_t v;
|
||||
if (readEntryAt(f, i, v)) {
|
||||
callback(v);
|
||||
}
|
||||
}
|
||||
f.close();
|
||||
}
|
||||
|
||||
uint32_t RfidDB::fileEntryCount(File &f) {
|
||||
return f.size() / ENTRY_SIZE;
|
||||
}
|
||||
|
||||
// 🚀 More efficient read/write methods
|
||||
bool RfidDB::readEntryAt(File &f, uint32_t index, uint32_t &out) {
|
||||
if (!f.seek(index * ENTRY_SIZE, SeekSet)) return false;
|
||||
return f.read(reinterpret_cast<uint8_t*>(&out), ENTRY_SIZE) == ENTRY_SIZE;
|
||||
}
|
||||
|
||||
bool RfidDB::writeEntryAt(File &f, uint32_t index, uint32_t value) {
|
||||
if (!f.seek(index * ENTRY_SIZE, SeekSet)) return false;
|
||||
return f.write(reinterpret_cast<const uint8_t*>(&value), ENTRY_SIZE) == ENTRY_SIZE;
|
||||
}
|
||||
|
||||
|
||||
bool RfidDB::binarySearch(File &f, uint32_t &outIndex, uint32_t key, bool &found) {
|
||||
// Get the number of entries in the file (each entry is 4 bytes)
|
||||
uint32_t n = fileEntryCount(f);
|
||||
|
||||
// If the file is empty, return with outIndex = 0 and found = false
|
||||
if (n == 0) {
|
||||
outIndex = 0;
|
||||
found = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Initialize search boundaries for binary search
|
||||
uint32_t left = 0;
|
||||
uint32_t right = n - 1;
|
||||
|
||||
// Perform binary search on the sorted database
|
||||
// Note: The database must contain values in ascending order of their *swapped* (Little-Endian) representation
|
||||
// to ensure correct search results. The 'key' parameter is the byte-swapped (Little-Endian) value of the
|
||||
// raw RFID ID (e.g., raw ID 0x635C426D is swapped to 0x6D425C63 for comparison).
|
||||
while (left <= right) {
|
||||
// Calculate the middle index
|
||||
uint32_t mid = left + (right - left) / 2;
|
||||
uint32_t v;
|
||||
|
||||
// Read the entry at index 'mid' from the file
|
||||
// The file stores IDs as Big-Endian (e.g., bytes 63 5C 42 6D for original ID 0x635C426D).
|
||||
// On this Little-Endian platform (e.g., ESP32), reading 4 bytes into 'v' interprets them as
|
||||
// Little-Endian, so bytes 63 5C 42 6D become v = 0x6D425C63 (swapped).
|
||||
if (!readEntryAt(f, mid, v)) {
|
||||
return false; // Failed to read entry
|
||||
}
|
||||
|
||||
// Compare the read value 'v' (Little-Endian, swapped) with the search key (also Little-Endian, swapped)
|
||||
if (v == key) {
|
||||
outIndex = mid;
|
||||
found = true;
|
||||
return true; // Found the ID at index 'mid'
|
||||
}
|
||||
|
||||
// Since the database is sorted by the swapped (Little-Endian) values,
|
||||
// adjust the search boundaries based on the comparison
|
||||
if (v < key) {
|
||||
left = mid + 1; // Search in the right half
|
||||
} else {
|
||||
if (mid == 0) break; // Prevent underflow when right = mid - 1
|
||||
right = mid - 1; // Search in the left half
|
||||
}
|
||||
}
|
||||
|
||||
// If not found, set outIndex to the insertion point where the key would be added
|
||||
// to maintain the sorted order of swapped (Little-Endian) values
|
||||
outIndex = left;
|
||||
found = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t RfidDB::byteSwap(uint32_t x) const
|
||||
{
|
||||
return ((x & 0xFF000000) >> 24) |
|
||||
((x & 0x00FF0000) >> 8) |
|
||||
((x & 0x0000FF00) << 8) |
|
||||
((x & 0x000000FF) << 24);
|
||||
}
|
||||
|
||||
bool RfidDB::add(uint32_t raw_id) {
|
||||
if (!initialized_) return false;
|
||||
|
||||
File src = LittleFS.open(filename_, "r");
|
||||
if (!src) return false;
|
||||
uint32_t id = byteSwap(raw_id);
|
||||
uint32_t idx;
|
||||
bool found;
|
||||
if (!binarySearch(src, idx, id, found)) {
|
||||
src.close();
|
||||
return false;
|
||||
}
|
||||
if (found) {
|
||||
src.close();
|
||||
return true; // Already present, we consider this a success
|
||||
}
|
||||
|
||||
File dst = LittleFS.open(tmpFilename_, "w");
|
||||
if (!dst) {
|
||||
src.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool success = true;
|
||||
uint32_t n = fileEntryCount(src);
|
||||
uint32_t v;
|
||||
|
||||
// Copy entries before the insertion point
|
||||
for (uint32_t i = 0; i < idx; ++i) {
|
||||
if (!readEntryAt(src, i, v) || !writeEntryAt(dst, i, v)) {
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Insert the new entry
|
||||
if (success && !writeEntryAt(dst, idx, id)) {
|
||||
success = false;
|
||||
}
|
||||
// Copy the remaining entries
|
||||
if (success) {
|
||||
for (uint32_t i = idx; i < n; ++i) {
|
||||
if (!readEntryAt(src, i, v) || !writeEntryAt(dst, i + 1, v)) {
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
src.close();
|
||||
dst.close();
|
||||
|
||||
if (!success) {
|
||||
LittleFS.remove(tmpFilename_);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Atomic replace
|
||||
if (!LittleFS.rename(tmpFilename_, filename_)) {
|
||||
// Fallback in case rename fails
|
||||
LittleFS.remove(tmpFilename_);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RfidDB::remove(uint32_t raw_id) {
|
||||
if (!initialized_) return false;
|
||||
|
||||
File src = LittleFS.open(filename_, "r");
|
||||
if (!src) return false;
|
||||
uint32_t id = byteSwap(raw_id);
|
||||
uint32_t idx;
|
||||
bool found;
|
||||
if (!binarySearch(src, idx, id, found) || !found) {
|
||||
src.close();
|
||||
return false; // Not found, so nothing to remove
|
||||
}
|
||||
|
||||
File dst = LittleFS.open(tmpFilename_, "w");
|
||||
if (!dst) {
|
||||
src.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool success = true;
|
||||
uint32_t n = fileEntryCount(src);
|
||||
uint32_t written = 0;
|
||||
uint32_t v;
|
||||
|
||||
for (uint32_t i = 0; i < n; ++i) {
|
||||
if (i == idx) continue; // Skip the entry to be deleted
|
||||
if (!readEntryAt(src, i, v) || !writeEntryAt(dst, written, v)) {
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
written++;
|
||||
}
|
||||
|
||||
src.close();
|
||||
dst.close();
|
||||
|
||||
if (!success) {
|
||||
LittleFS.remove(tmpFilename_);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!LittleFS.rename(tmpFilename_, filename_)) {
|
||||
LittleFS.remove(tmpFilename_);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
Reference in New Issue
Block a user