This commit is contained in:
Mitchell Marino 2025-08-22 15:05:11 -05:00
parent 0caf28c86a
commit da781c23f1
4 changed files with 295 additions and 2 deletions

View File

@ -1,3 +1,138 @@
#include "hwdata.h"
#include "esp_err.h"
#include "esp_log.h"
static const char* TAG = "hwdata";
HWData::HWData()
: compat_mode(true)
{}
HWData::HWData(HWData1 data, bool compat_mode)
: compat_mode(compat_mode),
inner(data)
{}
esp_err_t HWData::save(nvs_handle_t handle, bool force) {
if (compat_mode && !force) {
ESP_LOGW(TAG, "Not saving due to being in compatability mode.");
return ESP_OK;
}
return inner.save(handle);
}
HWData HWData::load(nvs_handle_t handle) {
esp_err_t err;
uint16_t stored_version = 0;
err = nvs_get_u16(handle, "version", &stored_version);
if (err == ESP_ERR_NVS_NOT_FOUND) {
ESP_LOGE(TAG, "No NVS data found! using defaults");
return HWData();
} else if (err != ESP_OK) {
ESP_ERROR_CHECK_WITHOUT_ABORT(err);
ESP_LOGE(TAG, "Other esp error! using defaults");
return HWData();
}
HWData1 data;
switch (stored_version) {
case 0:
ESP_LOGE(TAG, "HWData version was 0! using defaults");
return HWData();
case 1:
data.load(handle);
return HWData(data, false);
default:
ESP_LOGW(TAG, "Max currently supported version is %d, but saved version is %d. Loading version %d anyway!", CURRENT_HWDATA_VERSION, stored_version, CURRENT_HWDATA_VERSION);
data.load(handle);
return HWData(data, true);
}
}
HWData1::HWData1() {}
esp_err_t HWData1::save(nvs_handle_t handle) const {
ESP_ERROR_CHECK(nvs_set_u16(handle, "version", 1));
// Serial number
ESP_ERROR_CHECK(nvs_set_str(handle, "serial_num", serial_num.c_str()));
// Revisions
ESP_ERROR_CHECK(nvs_set_u8(handle, "rev_ctrl_maj", rev_ctrl_maj));
ESP_ERROR_CHECK(nvs_set_u8(handle, "rev_ctrl_min", rev_ctrl_min));
ESP_ERROR_CHECK(nvs_set_u8(handle, "rev_exp_maj", rev_exp_maj));
ESP_ERROR_CHECK(nvs_set_u8(handle, "rev_exp_min", rev_exp_min));
ESP_ERROR_CHECK(nvs_set_u8(handle, "rev_ft_maj", rev_ft_maj));
ESP_ERROR_CHECK(nvs_set_u8(handle, "rev_ft_min", rev_ft_min));
ESP_ERROR_CHECK(nvs_set_u8(handle, "rev_fb_maj", rev_fb_maj));
ESP_ERROR_CHECK(nvs_set_u8(handle, "rev_fb_min", rev_fb_min));
// Enums
ESP_ERROR_CHECK(nvs_set_u8(handle, "sseg_color_t", static_cast<uint8_t>(sseg_color_t)));
ESP_ERROR_CHECK(nvs_set_u8(handle, "sseg_color_b", static_cast<uint8_t>(sseg_color_b)));
ESP_ERROR_CHECK(nvs_set_u8(handle, "lcd_color", static_cast<uint8_t>(lcd_color)));
ESP_ERROR_CHECK(nvs_set_u8(handle, "button_type", static_cast<uint8_t>(button_type)));
ESP_ERROR_CHECK(nvs_set_u8(handle, "tft_type", static_cast<uint8_t>(tft_type)));
ESP_ERROR_CHECK(nvs_set_u8(handle, "bat_type", static_cast<uint8_t>(bat_type)));
ESP_ERROR_CHECK(nvs_set_u8(handle, "shape1", static_cast<uint8_t>(shape1)));
ESP_ERROR_CHECK(nvs_set_u8(handle, "shape2", static_cast<uint8_t>(shape2)));
ESP_ERROR_CHECK(nvs_set_u8(handle, "shape3", static_cast<uint8_t>(shape3)));
ESP_ERROR_CHECK(nvs_set_u8(handle, "shape4", static_cast<uint8_t>(shape4)));
// Other fields
ESP_ERROR_CHECK(nvs_set_u8(handle, "switch_pos", switch_pos));
ESP_ERROR_CHECK(nvs_set_u8(handle, "has_speaker", has_speaker));
ESP_ERROR_CHECK(nvs_set_u8(handle, "has_mic", has_mic));
ESP_ERROR_CHECK(nvs_set_u8(handle, "has_ir", has_ir));
ESP_ERROR_CHECK(nvs_set_u8(handle, "has_rfid", has_rfid));
ESP_ERROR_CHECK(nvs_set_u8(handle, "has_fp", has_fp));
ESP_ERROR_CHECK(nvs_set_u8(handle, "has_fp_hall", has_fp_hall));
ESP_ERROR_CHECK(nvs_set_u8(handle, "has_close_hall", has_close_hall));
// Battery capacity
ESP_ERROR_CHECK(nvs_set_u16(handle, "bat_cap", bat_cap));
return nvs_commit(handle);
}
void HWData1::load(nvs_handle_t handle) {
char buf[128];
size_t required_size = sizeof(buf);
esp_err_t err = nvs_get_str(handle, "serial_num", buf, &required_size);
serial_num = (err == ESP_OK) ? std::string(buf) : "";
nvs_get_u8(handle, "rev_ctrl_maj", &rev_ctrl_maj);
nvs_get_u8(handle, "rev_ctrl_min", &rev_ctrl_min);
nvs_get_u8(handle, "rev_exp_maj", &rev_exp_maj);
nvs_get_u8(handle, "rev_exp_min", &rev_exp_min);
nvs_get_u8(handle, "rev_ft_maj", &rev_ft_maj);
nvs_get_u8(handle, "rev_ft_min", &rev_ft_min);
nvs_get_u8(handle, "rev_fb_maj", &rev_fb_maj);
nvs_get_u8(handle, "rev_fb_min", &rev_fb_min);
uint8_t tmp;
if (nvs_get_u8(handle, "sseg_color_t", &tmp) == ESP_OK) sseg_color_t = static_cast<SSegColor>(tmp);
if (nvs_get_u8(handle, "sseg_color_b", &tmp) == ESP_OK) sseg_color_b = static_cast<SSegColor>(tmp);
if (nvs_get_u8(handle, "lcd_color", &tmp) == ESP_OK) lcd_color = static_cast<LCDColor>(tmp);
if (nvs_get_u8(handle, "button_type", &tmp) == ESP_OK) button_type = static_cast<ButtonType>(tmp);
if (nvs_get_u8(handle, "tft_type", &tmp) == ESP_OK) tft_type = static_cast<TFTType>(tmp);
if (nvs_get_u8(handle, "bat_type", &tmp) == ESP_OK) bat_type = static_cast<BatType>(tmp);
nvs_get_u16(handle, "bat_cap", &bat_cap);
if (nvs_get_u8(handle, "shape1", &tmp) == ESP_OK) shape1 = static_cast<Shape>(tmp);
if (nvs_get_u8(handle, "shape2", &tmp) == ESP_OK) shape2 = static_cast<Shape>(tmp);
if (nvs_get_u8(handle, "shape3", &tmp) == ESP_OK) shape3 = static_cast<Shape>(tmp);
if (nvs_get_u8(handle, "shape4", &tmp) == ESP_OK) shape4 = static_cast<Shape>(tmp);
nvs_get_u8(handle, "switch_pos", &switch_pos);
nvs_get_u8(handle, "has_speaker", &tmp); has_speaker = tmp;
nvs_get_u8(handle, "has_mic", &tmp); has_mic = tmp;
nvs_get_u8(handle, "has_ir", &tmp); has_ir = tmp;
nvs_get_u8(handle, "has_rfid", &tmp); has_rfid = tmp;
nvs_get_u8(handle, "has_fp", &tmp); has_fp = tmp;
nvs_get_u8(handle, "has_fp_hall", &tmp); has_fp_hall = tmp;
nvs_get_u8(handle, "has_close_hall", &tmp); has_close_hall = tmp;
}

View File

@ -1,6 +1,133 @@
#ifndef HWDATA_H
#define HWDATA_H
#include <string>
#include <cstdint>
#include <cstring>
#include "esp_err.h"
#include "nvs_flash.h"
#define CURRENT_HWDATA_VERSION 1
#define CURRENT_HWDATA_STRUCT HWData1
enum class SSegColor : uint8_t {
UNKNOWN = 0,
NONE = 1,
OTHER = 2,
RED = 3,
ORANGE = 4,
YELLOW = 5,
GREEN = 6,
BLUE = 7,
PURPLE = 8,
WHITE = 9,
};
enum class LCDColor : uint8_t {
UNKNOWN = 0,
NONE = 1,
OTHER = 2,
BLACK_GREEN = 3,
WHITE_BLUE = 4,
BLACK_SKY = 5,
BLACK_WHITE = 6,
WHITE_BLACK = 7,
};
enum class ButtonType : uint8_t {
UNKNOWN = 0,
NONE = 1,
OTHER = 2,
WHITE = 3,
BROWN = 4,
RED = 5,
};
enum class TFTType : uint8_t {
UNKNOWN = 0,
NONE = 1,
OTHER = 2,
EAST_RISING = 3,
SHENZHEN = 4,
};
enum class BatType : uint8_t {
UNKNOWN = 0,
NONE = 1,
OTHER = 2,
BAT_18650 = 3,
LIPO = 4,
};
enum class Shape : uint8_t {
UNKNOWN = 0,
OTHER = 1,
CIRCLE = 2,
SQUARE = 3,
TRIANGLE = 4,
X = 5,
STAR = 6,
SPADE = 7,
DIAMOND = 8,
CLUB = 9,
HEART = 10,
};
/// @brief Version 1 of HWData, kept constant for migrations
struct HWData1 {
std::string serial_num;
uint8_t rev_ctrl_maj;
uint8_t rev_ctrl_min;
uint8_t rev_exp_maj;
uint8_t rev_exp_min;
uint8_t rev_ft_maj;
uint8_t rev_ft_min;
uint8_t rev_fb_maj;
uint8_t rev_fb_min;
SSegColor sseg_color_t;
SSegColor sseg_color_b;
LCDColor lcd_color;
uint8_t switch_pos;
ButtonType button_type;
TFTType tft_type;
BatType bat_type;
uint16_t bat_cap;
Shape shape1;
Shape shape2;
Shape shape3;
Shape shape4;
bool has_speaker;
bool has_mic;
bool has_ir;
bool has_rfid;
bool has_fp;
bool has_fp_hall;
bool has_close_hall;
HWData1();
esp_err_t save(nvs_handle_t handle) const;
void load(nvs_handle_t handle);
// Add migration method as necessary
};
/// @brief The current version of HWData, to be stored
struct HWData {
/// @brief `true` if there is some issue in loading, and we are doing a "best effort" to be compatible
/// We should make no writes to NVS if this is `true`.
volatile bool compat_mode;
HWData1 inner;
HWData();
HWData(HWData1 data, bool compat_mode);
esp_err_t save(nvs_handle_t handle, bool force = false);
static HWData load(nvs_handle_t handle);
};
#endif /* HWDATA_H */

View File

@ -1,14 +1,15 @@
#include "nvs.h"
#include "nvs_flash.h"
#include "esp_log.h"
#include "bottom_half.h"
#include "char_lcd.h"
static const char* TAG = "nvs";
nvs_handle_t hw_handle;
static const char* HWDATA_NAMESPACE = "hwdata";
static HWData hw_data;
bool init_nvs() {
ESP_LOGI(TAG, "Initializing NVS...");
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
// NVS partition was truncated, erase and retry
@ -32,7 +33,31 @@ bool init_nvs() {
}
}
ESP_ERROR_CHECK(ret);
nvs_handle_t hw_handle;
ret = nvs_open(HWDATA_NAMESPACE, NVS_READONLY, &hw_handle);
if (ret == ESP_ERR_NVS_NOT_FOUND) {
ESP_LOGW(TAG, "Partition \"%s\" has not been initialized. Loading defaults.", HWDATA_NAMESPACE);
hw_data = HWData();
} else {
ESP_ERROR_CHECK(ret);
hw_data = HWData::load(hw_handle);
nvs_close(hw_handle);
}
ESP_LOGI(TAG, "NVS initialized!");
return true;
}
HWData& get_hw_data() {
return hw_data;
}
void save_hw_data(bool force) {
nvs_handle_t hw_handle;
ESP_ERROR_CHECK(nvs_open(HWDATA_NAMESPACE, NVS_READWRITE, &hw_handle));
hw_data.save(hw_handle);
nvs_close(hw_handle);
}

View File

@ -1,7 +1,13 @@
#ifndef NVS_H
#define NVS_H
#include "nvs_flash.h"
#include "hwdata.h"
/// @brief Initializes the NVS.
bool init_nvs();
/// Gets the HWData stored in NVS.
HWData& get_hw_data();
#endif /* NVS_H */