diff --git a/main/drivers/hwdata.cpp b/main/drivers/hwdata.cpp index f8c1e30..673f3a1 100644 --- a/main/drivers/hwdata.cpp +++ b/main/drivers/hwdata.cpp @@ -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(sseg_color_t))); + ESP_ERROR_CHECK(nvs_set_u8(handle, "sseg_color_b", static_cast(sseg_color_b))); + ESP_ERROR_CHECK(nvs_set_u8(handle, "lcd_color", static_cast(lcd_color))); + ESP_ERROR_CHECK(nvs_set_u8(handle, "button_type", static_cast(button_type))); + ESP_ERROR_CHECK(nvs_set_u8(handle, "tft_type", static_cast(tft_type))); + ESP_ERROR_CHECK(nvs_set_u8(handle, "bat_type", static_cast(bat_type))); + ESP_ERROR_CHECK(nvs_set_u8(handle, "shape1", static_cast(shape1))); + ESP_ERROR_CHECK(nvs_set_u8(handle, "shape2", static_cast(shape2))); + ESP_ERROR_CHECK(nvs_set_u8(handle, "shape3", static_cast(shape3))); + ESP_ERROR_CHECK(nvs_set_u8(handle, "shape4", static_cast(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(tmp); + if (nvs_get_u8(handle, "sseg_color_b", &tmp) == ESP_OK) sseg_color_b = static_cast(tmp); + if (nvs_get_u8(handle, "lcd_color", &tmp) == ESP_OK) lcd_color = static_cast(tmp); + if (nvs_get_u8(handle, "button_type", &tmp) == ESP_OK) button_type = static_cast(tmp); + if (nvs_get_u8(handle, "tft_type", &tmp) == ESP_OK) tft_type = static_cast(tmp); + if (nvs_get_u8(handle, "bat_type", &tmp) == ESP_OK) bat_type = static_cast(tmp); + nvs_get_u16(handle, "bat_cap", &bat_cap); + + if (nvs_get_u8(handle, "shape1", &tmp) == ESP_OK) shape1 = static_cast(tmp); + if (nvs_get_u8(handle, "shape2", &tmp) == ESP_OK) shape2 = static_cast(tmp); + if (nvs_get_u8(handle, "shape3", &tmp) == ESP_OK) shape3 = static_cast(tmp); + if (nvs_get_u8(handle, "shape4", &tmp) == ESP_OK) shape4 = static_cast(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; +} diff --git a/main/drivers/hwdata.h b/main/drivers/hwdata.h index 597e243..569ac5d 100644 --- a/main/drivers/hwdata.h +++ b/main/drivers/hwdata.h @@ -1,6 +1,133 @@ #ifndef HWDATA_H #define HWDATA_H +#include +#include +#include +#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 */ diff --git a/main/drivers/nvs.cpp b/main/drivers/nvs.cpp index 09d81ea..20c67bc 100644 --- a/main/drivers/nvs.cpp +++ b/main/drivers/nvs.cpp @@ -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); +} diff --git a/main/drivers/nvs.h b/main/drivers/nvs.h index 7523fab..42e03d9 100644 --- a/main/drivers/nvs.h +++ b/main/drivers/nvs.h @@ -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 */ \ No newline at end of file