#include "hwdata.h" #include "esp_err.h" #include "esp_log.h" #include "bottom_half.h" #include "char_lcd.h" #include "../helper.h" #include "nvs.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; } static void handle_uint8(KeypadKey key, uint8_t& val) { char key_c = char_of_keypad_key(key); bool is_digit = std::isdigit(static_cast(key_c)); uint8_t digit = is_digit ? static_cast(key_c - '0') : 0; if (key == KeypadKey::star) { val = 0; } else if (is_digit) { uint16_t new_digit = ((uint16_t) val) * 10 + (uint16_t) digit; if (new_digit < 255) val = new_digit; } } static void handle_uint16(KeypadKey key, uint16_t& val) { char key_c = char_of_keypad_key(key); bool is_digit = std::isdigit(static_cast(key_c)); uint8_t digit = is_digit ? static_cast(key_c - '0') : 0; if (key == KeypadKey::star) { val = 0; } else if (is_digit) { uint32_t new_digit = ((uint32_t) val) * 10 + (uint32_t) digit; if (new_digit < 65535) val = new_digit; } } static void handle_enum(ButtonKey key, uint8_t& val, uint8_t n_items) { if (key == ButtonKey::b1) { // dec val = (val + n_items - 1) % n_items; } else if (key == ButtonKey::b2) { // inc val = (val + 1) % n_items; } } void hardware_config() { clean_bomb(); uint8_t current_item = 0; const uint8_t n_items = 28; HWData1& hwdata = get_hw_data().inner; ButtonKey btn; KeypadKey key; bool dirty = true; while (true) { if (dirty) { // display char name[21]; char value[21]; switch (current_item) { case 0: // serial_num snprintf(name, sizeof(name), "%-20s", "serial_num"); snprintf(value, sizeof(value), "%s", hwdata.serial_num.c_str()); break; case 1: // rev_ctrl_maj snprintf(name, sizeof(name), "%-20s", "rev_ctrl_maj"); snprintf(value, sizeof(value), "%d", hwdata.rev_ctrl_maj); break; case 2: // rev_ctrl_min snprintf(name, sizeof(name), "%-20s", "rev_ctrl_min"); snprintf(value, sizeof(value), "%d", hwdata.rev_ctrl_min); break; case 3: // rev_exp_maj snprintf(name, sizeof(name), "%-20s", "rev_exp_maj"); snprintf(value, sizeof(value), "%d", hwdata.rev_exp_maj); break; case 4: // rev_exp_min snprintf(name, sizeof(name), "%-20s", "rev_exp_min"); snprintf(value, sizeof(value), "%d", hwdata.rev_exp_min); break; case 5: // rev_ft_maj snprintf(name, sizeof(name), "%-20s", "rev_ft_maj"); snprintf(value, sizeof(value), "%d", hwdata.rev_ft_maj); break; case 6: // rev_ft_min snprintf(name, sizeof(name), "%-20s", "rev_ft_min"); snprintf(value, sizeof(value), "%d", hwdata.rev_ft_min); break; case 7: // rev_fb_maj snprintf(name, sizeof(name), "%-20s", "rev_fb_maj"); snprintf(value, sizeof(value), "%d", hwdata.rev_fb_maj); break; case 8: // rev_fb_min snprintf(name, sizeof(name), "%-20s", "rev_fb_min"); snprintf(value, sizeof(value), "%d", hwdata.rev_fb_min); break; case 9: // sseg_color_t snprintf(name, sizeof(name), "%-20s", "sseg_color_t"); snprintf(value, sizeof(value), "%s", SSEG_COLOR_NAMES[static_cast(hwdata.sseg_color_t)]); break; case 10: // sseg_color_b snprintf(name, sizeof(name), "%-20s", "sseg_color_b"); snprintf(value, sizeof(value), "%s", SSEG_COLOR_NAMES[static_cast(hwdata.sseg_color_b)]); break; case 11: // lcd_color snprintf(name, sizeof(name), "%-20s", "lcd_color"); snprintf(value, sizeof(value), "%s", LCD_COLOR_NAMES[static_cast(hwdata.lcd_color)]); break; case 12: // switch_pos snprintf(name, sizeof(name), "%-20s", "switch_pos"); snprintf(value, sizeof(value), "%d", hwdata.switch_pos); break; case 13: // button_type snprintf(name, sizeof(name), "%-20s", "button_type"); snprintf(value, sizeof(value), "%s", BUTTON_TYPE_NAMES[static_cast(hwdata.button_type)]); break; case 14: // tft_type snprintf(name, sizeof(name), "%-20s", "tft_type"); snprintf(value, sizeof(value), "%s", TFT_TYPE_NAMES[static_cast(hwdata.tft_type)]); break; case 15: // bat_type snprintf(name, sizeof(name), "%-20s", "bat_type"); snprintf(value, sizeof(value), "%s", BAT_TYPE_NAMES[static_cast(hwdata.bat_type)]); break; case 16: // bat_cap snprintf(name, sizeof(name), "%-20s", "bat_cap"); snprintf(value, sizeof(value), "%d", hwdata.bat_cap); break; case 17: // shape1 snprintf(name, sizeof(name), "%-20s", "shape1"); snprintf(value, sizeof(value), "%s", SHAPE_TYPE_NAMES[static_cast(hwdata.shape1)]); break; case 18: // shape2 snprintf(name, sizeof(name), "%-20s", "shape2"); snprintf(value, sizeof(value), "%s", SHAPE_TYPE_NAMES[static_cast(hwdata.shape2)]); break; case 19: // shape3 snprintf(name, sizeof(name), "%-20s", "shape3"); snprintf(value, sizeof(value), "%s", SHAPE_TYPE_NAMES[static_cast(hwdata.shape3)]); break; case 20: // shape4 snprintf(name, sizeof(name), "%-20s", "shape4"); snprintf(value, sizeof(value), "%s", SHAPE_TYPE_NAMES[static_cast(hwdata.shape4)]); break; case 21: // has_speaker snprintf(name, sizeof(name), "%-20s", "has_speaker"); snprintf(value, sizeof(value), "%s", hwdata.has_speaker ? "true" : "false"); break; case 22: // has_mic snprintf(name, sizeof(name), "%-20s", "has_mic"); snprintf(value, sizeof(value), "%s", hwdata.has_mic ? "true" : "false"); break; case 23: // has_ir snprintf(name, sizeof(name), "%-20s", "has_ir"); snprintf(value, sizeof(value), "%s", hwdata.has_ir ? "true" : "false"); break; case 24: // has_rfid snprintf(name, sizeof(name), "%-20s", "has_rfid"); snprintf(value, sizeof(value), "%s", hwdata.has_rfid ? "true" : "false"); break; case 25: // has_fp snprintf(name, sizeof(name), "%-20s", "has_fp"); snprintf(value, sizeof(value), "%s", hwdata.has_fp ? "true" : "false"); break; case 26: // has_fp_hall snprintf(name, sizeof(name), "%-20s", "has_fp_hall"); snprintf(value, sizeof(value), "%s", hwdata.has_fp_hall ? "true" : "false"); break; case 27: // has_close_hall snprintf(name, sizeof(name), "%-20s", "has_close_hall"); snprintf(value, sizeof(value), "%s", hwdata.has_close_hall ? "true" : "false"); break; default: break; } lcd_print(1, 0, name); lcd_print(2, 0, value); dirty = false; } if (get_button_pressed(&btn)) { dirty = true; switch (btn) { case ButtonKey::b3: // dec current_item = (current_item + n_items - 1) % n_items; break; case ButtonKey::b4: // inc current_item = (current_item + 1) % n_items; break; default: switch (current_item) { case 9: // sseg_color_t handle_enum(btn, reinterpret_cast(hwdata.sseg_color_t), SSEG_COLOR_COUNT); break; case 10: // sseg_color_b handle_enum(btn, reinterpret_cast(hwdata.sseg_color_b), SSEG_COLOR_COUNT); break; case 11: // lcd_color handle_enum(btn, reinterpret_cast(hwdata.lcd_color), LCD_COLOR_COUNT); break; case 13: // button_type handle_enum(btn, reinterpret_cast(hwdata.button_type), BUTTON_TYPE_COUNT); break; case 14: // tft_type handle_enum(btn, reinterpret_cast(hwdata.tft_type), TFT_TYPE_COUNT); break; case 15: // bat_type handle_enum(btn, reinterpret_cast(hwdata.bat_type), BAT_TYPE_COUNT); break; case 17: // shape1 handle_enum(btn, reinterpret_cast(hwdata.shape1), SHAPE_TYPE_COUNT); break; case 18: // shape2 handle_enum(btn, reinterpret_cast(hwdata.shape2), SHAPE_TYPE_COUNT); break; case 19: // shape3 handle_enum(btn, reinterpret_cast(hwdata.shape3), SHAPE_TYPE_COUNT); break; case 20: // shape4 handle_enum(btn, reinterpret_cast(hwdata.shape4), SHAPE_TYPE_COUNT); break; case 21: // has_speaker hwdata.has_speaker = btn == ButtonKey::button_green; break; case 22: // has_mic hwdata.has_mic = btn == ButtonKey::button_green; break; case 23: // has_ir hwdata.has_ir = btn == ButtonKey::button_green; break; case 24: // has_rfid hwdata.has_rfid = btn == ButtonKey::button_green; break; case 25: // has_fp hwdata.has_fp = btn == ButtonKey::button_green; break; case 26: // has_fp_hall hwdata.has_fp_hall = btn == ButtonKey::button_green; break; case 27: // has_close_hall hwdata.has_close_hall = btn == ButtonKey::button_green; break; default: break; } break; } } if (get_keypad_pressed(&key)) { dirty = true; if (key == KeypadKey::pound) { // TODO: ask the user to save return; // done } char key_c = char_of_keypad_key(key); bool is_digit = std::isdigit(static_cast(key_c)); uint8_t digit = is_digit ? static_cast(key_c - '0') : 0; // update the current value switch (current_item) { case 0: // serial_num if (key == KeypadKey::star) { hwdata.serial_num.clear(); } else { hwdata.serial_num.push_back(char_of_keypad_key(key)); } break; case 1: // rev_ctrl_maj handle_uint8(key, hwdata.rev_ctrl_maj); break; case 2: // rev_ctrl_min handle_uint8(key, hwdata.rev_ctrl_min); break; case 3: // rev_exp_maj handle_uint8(key, hwdata.rev_exp_maj); break; case 4: // rev_exp_min handle_uint8(key, hwdata.rev_exp_min); break; case 5: // rev_ft_maj handle_uint8(key, hwdata.rev_ft_maj); break; case 6: // rev_ft_min handle_uint8(key, hwdata.rev_ft_min); break; case 7: // rev_fb_maj handle_uint8(key, hwdata.rev_fb_maj); break; case 8: // rev_fb_min handle_uint8(key, hwdata.rev_fb_min); break; case 12: // switch_pos if (digit == 2 || digit == 3) hwdata.switch_pos = digit; break; case 16: // bat_cap handle_uint16(key, hwdata.bat_cap); break; default: break; } } vTaskDelay(pdMS_TO_TICKS(10)); } }