diff --git a/firmware/application/apps/ui_battinfo.cpp b/firmware/application/apps/ui_battinfo.cpp index bb35fc226..013bb4e7d 100644 --- a/firmware/application/apps/ui_battinfo.cpp +++ b/firmware/application/apps/ui_battinfo.cpp @@ -27,6 +27,8 @@ #include "portapack.hpp" #include "battery.hpp" #include +#include "ui_settings.hpp" +#include "portapack_persistent_memory.hpp" using namespace portapack; @@ -138,10 +140,8 @@ void BattinfoView::update_result() { } if ((valid_mask & battery::BatteryManagement::BATT_VALID_PERCENT) == battery::BatteryManagement::BATT_VALID_PERCENT) { text_method.set("IC"); - button_mode.set_text("Volt"); } else { text_method.set("Voltage"); - button_mode.set_text("IC"); } if (uichg) set_dirty(); // to update status bar too, send message in behalf of batt manager @@ -158,8 +158,9 @@ BattinfoView::BattinfoView(NavigationView& nav) &text_current, &text_charge, &text_method, - &button_mode, + &button_settings, &button_exit, + &text_capacity, // &text_cycles, // &text_warn, &text_ttef}); @@ -167,17 +168,11 @@ BattinfoView::BattinfoView(NavigationView& nav) button_exit.on_select = [this, &nav](Button&) { nav.pop(); }; - button_mode.on_select = [this, &nav](Button&) { - if (button_mode.text() == "IC") { - battery::BatteryManagement::set_calc_override(false); - persistent_memory::set_ui_override_batt_calc(false); - button_mode.set_text("Volt"); - } else { - battery::BatteryManagement::set_calc_override(true); - persistent_memory::set_ui_override_batt_calc(true); - button_mode.set_text("IC"); - } + button_settings.on_select = [this, &nav](Button&) { + nav.replace(); }; + text_capacity.set(to_string_dec_uint(persistent_memory::battery_cap_mah()) + " mAh"); + if (!persistent_memory::battery_cap_valid()) text_capacity.set_style(Theme::getInstance()->fg_red); update_result(); if (thread == nullptr) thread = chThdCreateFromHeap(NULL, 1024, NORMALPRIO + 10, BattinfoView::static_fn, this); } diff --git a/firmware/application/apps/ui_battinfo.hpp b/firmware/application/apps/ui_battinfo.hpp index 5357f2578..68cf62453 100644 --- a/firmware/application/apps/ui_battinfo.hpp +++ b/firmware/application/apps/ui_battinfo.hpp @@ -54,48 +54,53 @@ class BattinfoView : public View { int32_t current = 0; Labels labels{ - {{2 * 8, 1 * 16}, "Percent:", Theme::getInstance()->fg_light->foreground}, - {{2 * 8, 2 * 16}, "Voltage:", Theme::getInstance()->fg_light->foreground}, - {{2 * 8, 3 * 16}, "Method:", Theme::getInstance()->fg_light->foreground}, + {{UI_POS_X(2), UI_POS_Y(1)}, "Percent:", Theme::getInstance()->fg_light->foreground}, + {{UI_POS_X(2), UI_POS_Y(2)}, "Voltage:", Theme::getInstance()->fg_light->foreground}, + {{UI_POS_X(2), UI_POS_Y(3)}, "Method:", Theme::getInstance()->fg_light->foreground}, + {{UI_POS_X(2), UI_POS_Y(4)}, "Capacity:", Theme::getInstance()->fg_light->foreground}, }; Labels labels_opt{ - {{2 * 8, 4 * 16}, "Current:", Theme::getInstance()->fg_light->foreground}, - {{2 * 8, 5 * 16}, "Charge:", Theme::getInstance()->fg_light->foreground}, - {{2 * 8, 6 * 16}, "TTF/E:", Theme::getInstance()->fg_light->foreground}, - // {{2 * 8, 7 * 16}, "Cycles:", Theme::getInstance()->fg_light->foreground}, - {{2 * 8, 10 * 16}, "Change method:", Theme::getInstance()->fg_light->foreground}, + {{UI_POS_X(2), UI_POS_Y(5)}, "Current:", Theme::getInstance()->fg_light->foreground}, + {{UI_POS_X(2), UI_POS_Y(6)}, "Charge:", Theme::getInstance()->fg_light->foreground}, + {{UI_POS_X(2), UI_POS_Y(7)}, "TTF/E:", Theme::getInstance()->fg_light->foreground}, + // {{UI_POS_X(2), UI_POS_Y(8)}, "Cycles:", Theme::getInstance()->fg_light->foreground}, + {{UI_POS_X(2), UI_POS_Y(10)}, "Change settings:", Theme::getInstance()->fg_light->foreground}, }; Text text_percent{ - {13 * 8, 1 * 16, 10 * 16, 16}, + {UI_POS_X(13), UI_POS_Y(1), UI_POS_WIDTH(10), UI_POS_HEIGHT(1)}, "-"}; Text text_voltage{ - {13 * 8, 2 * 16, 10 * 16, 16}, + {UI_POS_X(13), UI_POS_Y(2), UI_POS_WIDTH(10), UI_POS_HEIGHT(1)}, "-"}; Text text_method{ - {13 * 8, 3 * 16, 10 * 16, 16}, + {UI_POS_X(13), UI_POS_Y(3), UI_POS_WIDTH(10), UI_POS_HEIGHT(1)}, + "-"}; + Text text_capacity{ + {UI_POS_X(13), UI_POS_Y(4), UI_POS_WIDTH(10), UI_POS_HEIGHT(1)}, "-"}; Text text_current{ - {13 * 8, 4 * 16, 10 * 16, 16}, + {UI_POS_X(13), UI_POS_Y(5), UI_POS_WIDTH(10), UI_POS_HEIGHT(1)}, "-"}; Text text_charge{ - {13 * 8, 5 * 16, 10 * 16, 16}, + {UI_POS_X(13), UI_POS_Y(6), UI_POS_WIDTH(10), UI_POS_HEIGHT(1)}, "-"}; Text text_ttef{ - {13 * 8, 6 * 16, 10 * 16, 16}, + {UI_POS_X(13), UI_POS_Y(7), UI_POS_WIDTH(10), UI_POS_HEIGHT(1)}, "-"}; + /* Text text_cycles{ - {13 * 8, 7 * 16, 10 * 16, 16}, + {UI_POS_X(13), UI_POS_Y(8), UI_POS_WIDTH(10), UI_POS_HEIGHT(1)}, "-"}; Text text_warn{ - {1 * 8, 8 * 16, screen_width, 2 * 16}, + {UI_POS_X(1), UI_POS_Y(9), screen_width, UI_POS_HEIGHT(2)}, ""}; */ - Button button_mode{ - {2 * 8, 11 * 16 + 5, 5 * 16, 32}, - "Volt"}; + Button button_settings{ + {UI_POS_X(2), UI_POS_Y(11) + 5, UI_POS_WIDTH(10), UI_POS_HEIGHT(2)}, + "Settings"}; Button button_exit{ {UI_POS_X_CENTER(12), UI_POS_Y_BOTTOM(4), UI_POS_WIDTH(12), UI_POS_HEIGHT(2)}, diff --git a/firmware/application/apps/ui_settings.cpp b/firmware/application/apps/ui_settings.cpp index 1e9d83375..3f81df4a6 100644 --- a/firmware/application/apps/ui_settings.cpp +++ b/firmware/application/apps/ui_settings.cpp @@ -1160,6 +1160,8 @@ SetBatteryView::SetBatteryView(NavigationView& nav) { add_children({&labels, &button_save, &button_cancel, + &field_battcap, + &button_help_cap, &checkbox_overridebatt, &checkbox_battery_charge_hint}); @@ -1169,21 +1171,44 @@ SetBatteryView::SetBatteryView(NavigationView& nav) { pmem::set_ui_override_batt_calc(checkbox_overridebatt.value()); pmem::set_ui_battery_charge_hint(checkbox_battery_charge_hint.value()); battery::BatteryManagement::set_calc_override(checkbox_overridebatt.value()); + if (((uint32_t)field_battcap.value() != pmem::battery_cap_mah()) || (!pmem::battery_cap_valid())) { + pmem::set_battery_cap_mah(field_battcap.value()); + i2cdev::I2cDev_MAX17055* dev = (i2cdev::I2cDev_MAX17055*)i2cdev::I2CDevManager::get_dev_by_model(I2C_DEVMDL::I2CDEVMDL_MAX17055); + if (dev && !dev->reInit()) { + nav.display_modal("Error", "Battery gauge re-init failed"); + return; + } + } send_system_refresh(); nav.pop(); }; button_reset.on_select = [&nav, this](Button&) { auto dev = (i2cdev::I2cDev_MAX17055*)i2cdev::I2CDevManager::get_dev_by_model(I2C_DEVMDL::I2CDEVMDL_MAX17055); - if (dev->reset_learned()) + if (dev && dev->reset_learned()) nav.display_modal("Reset", "Battery parameters reset"); else nav.display_modal("Error", "Error parameter reset"); }; + button_help_cap.on_select = [&nav, this](Button&) { + nav.display_modal("Battery Capacity", + "Only change default, if you\n" + " changed the battery!\n" + "Defaults:\n" + "H4 + Hackrf One: 2500\n" + "H4 + Hackrf Pro: 2000\n" + "H4Pro + Hackrf Pro: custom\n" + "PortaRf: 3000\n" + + ); + }; + checkbox_overridebatt.set_value(pmem::ui_override_batt_calc()); checkbox_battery_charge_hint.set_value(pmem::ui_battery_charge_hint()); + field_battcap.set_value(pmem::battery_cap_mah()); + button_cancel.on_select = [&nav, this](Button&) { nav.pop(); }; diff --git a/firmware/application/apps/ui_settings.hpp b/firmware/application/apps/ui_settings.hpp index 0a8898a03..45dc033dc 100644 --- a/firmware/application/apps/ui_settings.hpp +++ b/firmware/application/apps/ui_settings.hpp @@ -1045,21 +1045,36 @@ class SetBatteryView : public View { private: int32_t selected = 0; Labels labels{ - {{1 * 8, 1 * 16}, "Override batt calculation", Theme::getInstance()->fg_light->foreground}, - {{1 * 8, 2 * 16}, "method to voltage based", Theme::getInstance()->fg_light->foreground}, + {{UI_POS_X_CENTER(26), UI_POS_Y(0)}, "Override batt calculation", Theme::getInstance()->fg_light->foreground}, + {{UI_POS_X_CENTER(24), UI_POS_Y(1)}, "method to voltage based", Theme::getInstance()->fg_light->foreground}, /**/ - {{1 * 8, 6 * 16}, "Display a hint to remind you", Theme::getInstance()->fg_light->foreground}, - {{1 * 8, 7 * 16}, "when you charge", Theme::getInstance()->fg_light->foreground}}; + {{UI_POS_X_CENTER(29), UI_POS_Y(4)}, "Display a hint to remind you", Theme::getInstance()->fg_light->foreground}, + {{UI_POS_X_CENTER(16), UI_POS_Y(5)}, "when you charge", Theme::getInstance()->fg_light->foreground}, + {{UI_POS_X_CENTER(17), UI_POS_Y(8)}, "Battery capacity", Theme::getInstance()->fg_light->foreground}, + {{UI_POS_X(7), UI_POS_Y(9)}, "mAh", Theme::getInstance()->fg_light->foreground}}; - Labels labels2{{{1 * 8, 11 * 16}, "Reset IC's learned params.", Theme::getInstance()->fg_light->foreground}}; + Labels labels2{{{UI_POS_X(1), UI_POS_Y(11)}, "Reset IC's learned params.", Theme::getInstance()->fg_light->foreground}}; + + NumberField field_battcap{ + {UI_POS_X(1), UI_POS_Y(9)}, + 5, + {BATT_18650_MIN_MAH, BATT_18650_MAX_MAH}, + 100, + ' ', + }; + + Button button_help_cap{ + {UI_POS_X(12), UI_POS_Y(9), UI_POS_WIDTH(5), UI_POS_HEIGHT(1)}, + "Help", + }; Checkbox checkbox_overridebatt{ - {2 * 8, 4 * 16}, + {UI_POS_X(2), UI_POS_Y(2)}, 23, "Override"}; Checkbox checkbox_battery_charge_hint{ - {2 * 8, 9 * 16}, + {UI_POS_X(2), UI_POS_Y(6)}, 23, "Charge hint"}; diff --git a/firmware/common/i2cdev_max17055.cpp b/firmware/common/i2cdev_max17055.cpp index 2e1c93aeb..60f607203 100644 --- a/firmware/common/i2cdev_max17055.cpp +++ b/firmware/common/i2cdev_max17055.cpp @@ -214,6 +214,14 @@ bool I2cDev_MAX17055::init(uint8_t addr_) { return false; } +bool I2cDev_MAX17055::reInit() { + if (!full_reset_and_init()) { + return false; + } + partialInit(); + return true; +} + bool I2cDev_MAX17055::full_reset_and_init() { if (!soft_reset()) { return false; @@ -235,12 +243,12 @@ bool I2cDev_MAX17055::soft_reset() { } bool I2cDev_MAX17055::initialize_custom_parameters() { - if (!write_register(0xD0, 0x03E8)) return false; // Unknown register, possibly related to battery profile - if (!write_register(0xDB, 0x0000)) return false; // ModelCfg - if (!write_register(0x05, 0x0000)) return false; // RepCap - uint32_t designcap = portapack::device_type == portapack::DEV_PORTARF ? __MAX17055_Design_Capacity_PRF__ * 2 : __MAX17055_Design_Capacity__ * 2; // the original design has a 2x multiplier here, so i keep it - if (!write_register(0x18, designcap)) return false; // DesignCap - if (!write_register(0x45, designcap / 32)) return false; // dQAcc = DesignCap / 32 + if (!write_register(0xD0, 0x03E8)) return false; // Unknown register, possibly related to battery profile + if (!write_register(0xDB, 0x0000)) return false; // ModelCfg + if (!write_register(0x05, 0x0000)) return false; // RepCap + uint32_t designcap = portapack::persistent_memory::battery_cap_mah() * 2; // the original design has a 2x multiplier here, so i keep it + if (!write_register(0x18, designcap)) return false; // DesignCap + if (!write_register(0x45, designcap / 32)) return false; // dQAcc = DesignCap / 32 if (!write_register(0x1E, 0x03C0)) return false; // IChgTerm if (!write_register(0x3A, 0x9661)) return false; // VEmpty diff --git a/firmware/common/i2cdev_max17055.hpp b/firmware/common/i2cdev_max17055.hpp index 538a4244a..255b76ad6 100644 --- a/firmware/common/i2cdev_max17055.hpp +++ b/firmware/common/i2cdev_max17055.hpp @@ -290,7 +290,7 @@ class I2cDev_MAX17055 : public I2cDev { uint16_t averageMVoltage(void); int32_t instantCurrent(void); uint16_t stateOfCharge(void); - + bool reInit(); // call when battery parameters changed from ui. don't call if not needed, or the battery is not changed!!! private: const RegisterEntry* findEntry(const char* name) const; diff --git a/firmware/common/portapack_persistent_memory.cpp b/firmware/common/portapack_persistent_memory.cpp index 103ee6d7a..53571c8ca 100644 --- a/firmware/common/portapack_persistent_memory.cpp +++ b/firmware/common/portapack_persistent_memory.cpp @@ -156,8 +156,7 @@ struct misc_config_t { bool tx_amp_disabled : 1; uint8_t tx_gain_max_db; - uint8_t PLACEHOLDER_1; - uint8_t PLACEHOLDER_2; + uint16_t batt_cap_mah; }; static_assert(sizeof(misc_config_t) == sizeof(uint32_t)); @@ -445,6 +444,8 @@ void defaults() { set_config_tx_disabled(false); set_config_tx_amp_disabled(false); set_config_tx_gain_max_db(47); + + set_battery_cap_mah(0); } void init() { @@ -1243,6 +1244,32 @@ int load_persistent_settings_from_file() { return true; } +bool battery_cap_valid() { + return (data->misc_config.batt_cap_mah >= BATT_18650_MIN_MAH && data->misc_config.batt_cap_mah <= BATT_18650_MAX_MAH); +} + +void set_battery_cap_mah(uint16_t mah) { + if ((mah < BATT_18650_MIN_MAH || mah > BATT_18650_MAX_MAH) && mah != 0) { + // Invalid value, ignore it. + return; + } + if (data->misc_config.batt_cap_mah != mah) { + data->misc_config.batt_cap_mah = mah; + } +} + +uint32_t battery_cap_mah() { + if (battery_cap_valid()) { + return data->misc_config.batt_cap_mah; + } + // we don't know, need to assume. + if (portapack::device_type == portapack::DEV_PORTARF) return 3000; +#ifdef PRALINE + return 2000; // with h4 + pro and h4pro + pro it is ~safe +#endif + return 2500; // h4 + one +} + // Pmem size helper size_t data_size() { diff --git a/firmware/common/portapack_persistent_memory.hpp b/firmware/common/portapack_persistent_memory.hpp index cdac91a15..240190588 100644 --- a/firmware/common/portapack_persistent_memory.hpp +++ b/firmware/common/portapack_persistent_memory.hpp @@ -45,6 +45,10 @@ #define PMEM_SIZE_BYTES 256 // total amount of pmem space in bytes, including checksum #define PMEM_SIZE_WORDS (PMEM_SIZE_BYTES / 4) +// to check battery mins and maxes in pmem, and validity +#define BATT_18650_MIN_MAH 1000 +#define BATT_18650_MAX_MAH 5000 + using namespace modems; using namespace serializer; using namespace ui; @@ -387,6 +391,11 @@ uint32_t pmem_data_word(uint32_t index); uint32_t pmem_stored_checksum(void); uint32_t pmem_calculated_checksum(void); +// battery capacity settings +void set_battery_cap_mah(uint16_t mah); // 0 is not known; use assumed default based on device type/build config +uint32_t battery_cap_mah(); +bool battery_cap_valid(); + size_t data_size(); } /* namespace persistent_memory */