diff --git a/firmware/application/apps/ui_settings.cpp b/firmware/application/apps/ui_settings.cpp index 88752196b..a583678fa 100644 --- a/firmware/application/apps/ui_settings.cpp +++ b/firmware/application/apps/ui_settings.cpp @@ -774,21 +774,27 @@ void SetConfigModeView::focus() { button_save.focus(); } -/* SetFakeBrightnessView ************************************/ +/* SetDisplayView ************************************/ -SetFakeBrightnessView::SetFakeBrightnessView(NavigationView& nav) { +SetDisplayView::SetDisplayView(NavigationView& nav) { add_children({&labels, &field_fake_brightness, &button_save, &button_cancel, + &checkbox_invert_switch, &checkbox_brightness_switch}); field_fake_brightness.set_by_value(pmem::fake_brightness_level()); checkbox_brightness_switch.set_value(pmem::apply_fake_brightness()); + checkbox_invert_switch.set_value(pmem::config_lcd_inverted_mode()); button_save.on_select = [&nav, this](Button&) { pmem::set_apply_fake_brightness(checkbox_brightness_switch.value()); pmem::set_fake_brightness_level(field_fake_brightness.selected_index_value()); + if (checkbox_invert_switch.value() != pmem::config_lcd_inverted_mode()) { + display.set_inverted(checkbox_invert_switch.value()); + pmem::set_lcd_inverted_mode(checkbox_invert_switch.value()); + } send_system_refresh(); nav.pop(); }; @@ -798,7 +804,7 @@ SetFakeBrightnessView::SetFakeBrightnessView(NavigationView& nav) { }; } -void SetFakeBrightnessView::focus() { +void SetDisplayView::focus() { button_save.focus(); } @@ -999,7 +1005,7 @@ void SettingsMenuView::on_populate() { {"SD Card", ui::Color::dark_cyan(), &bitmap_icon_sdcard, [this]() { nav_.push(); }}, {"User Interface", ui::Color::dark_cyan(), &bitmap_icon_options_ui, [this]() { nav_.push(); }}, //{"QR Code", ui::Color::dark_cyan(), &bitmap_icon_qr_code, [this]() { nav_.push(); }}, - {"Brightness", ui::Color::dark_cyan(), &bitmap_icon_brightness, [this]() { nav_.push(); }}, + {"Display", ui::Color::dark_cyan(), &bitmap_icon_brightness, [this]() { nav_.push(); }}, {"Menu Color", ui::Color::dark_cyan(), &bitmap_icon_brightness, [this]() { nav_.push(); }}, {"Theme", ui::Color::dark_cyan(), &bitmap_icon_setup, [this]() { nav_.push(); }}, {"Autostart", ui::Color::dark_cyan(), &bitmap_icon_setup, [this]() { nav_.push(); }}, diff --git a/firmware/application/apps/ui_settings.hpp b/firmware/application/apps/ui_settings.hpp index 50dc17bb2..048f67e83 100644 --- a/firmware/application/apps/ui_settings.hpp +++ b/firmware/application/apps/ui_settings.hpp @@ -711,13 +711,13 @@ class SetConfigModeView : public View { using portapack::persistent_memory::fake_brightness_level_options; -class SetFakeBrightnessView : public View { +class SetDisplayView : public View { public: - SetFakeBrightnessView(NavigationView& nav); + SetDisplayView(NavigationView& nav); void focus() override; - std::string title() const override { return "Brightness"; }; + std::string title() const override { return "Display"; }; private: Labels labels{ @@ -739,6 +739,11 @@ class SetFakeBrightnessView : public View { 16, "Enable brightness adjust"}; + Checkbox checkbox_invert_switch{ + {1 * 8, 10 * 16}, + 23, + "Invert colors (For IPS)"}; + Button button_save{ {2 * 8, 16 * 16, 12 * 8, 32}, "Save"}; diff --git a/firmware/application/portapack.cpp b/firmware/application/portapack.cpp index ace69ead8..7520a7c71 100644 --- a/firmware/application/portapack.cpp +++ b/firmware/application/portapack.cpp @@ -535,6 +535,8 @@ init_status_t init() { set_cpu_clock_speed(); + if (persistent_memory::config_lcd_inverted_mode()) display.set_inverted(true); + if (lcd_fast_setup) draw_splash_screen_icon(0, ui::bitmap_icon_memory); diff --git a/firmware/common/lcd_ili9341.cpp b/firmware/common/lcd_ili9341.cpp index 7cd0035cd..ba8793dc8 100644 --- a/firmware/common/lcd_ili9341.cpp +++ b/firmware/common/lcd_ili9341.cpp @@ -307,6 +307,14 @@ void ILI9341::wake() { lcd_wake(); } +void ILI9341::set_inverted(bool invert) { + if (invert) { + io.lcd_data_write_command_and_data(0x21, {}); + } else { + io.lcd_data_write_command_and_data(0x20, {}); + } +} + void ILI9341::fill_rectangle(ui::Rect r, const ui::Color c) { const auto r_clipped = r.intersect(screen_rect()); if (!r_clipped.is_empty()) { diff --git a/firmware/common/lcd_ili9341.hpp b/firmware/common/lcd_ili9341.hpp index 20ea625ba..feb87a39a 100644 --- a/firmware/common/lcd_ili9341.hpp +++ b/firmware/common/lcd_ili9341.hpp @@ -50,6 +50,8 @@ class ILI9341 { void sleep(); void wake(); + void set_inverted(bool invert); + void fill_rectangle(ui::Rect r, const ui::Color c); void fill_rectangle_unrolled8(ui::Rect r, const ui::Color c); void draw_line(const ui::Point start, const ui::Point end, const ui::Color color); diff --git a/firmware/common/portapack_io.cpp b/firmware/common/portapack_io.cpp index dbca74d93..f53c6ed58 100644 --- a/firmware/common/portapack_io.cpp +++ b/firmware/common/portapack_io.cpp @@ -81,6 +81,10 @@ bool IO::get_dark_cover() { return portapack::persistent_memory::apply_fake_brightness(); } +bool IO::get_is_inverted() { + return portapack::persistent_memory::config_lcd_inverted_mode(); +} + uint8_t IO::get_brightness() { return portapack::persistent_memory::fake_brightness_level(); } diff --git a/firmware/common/portapack_io.hpp b/firmware/common/portapack_io.hpp index c6ffe2666..2c614a2f6 100644 --- a/firmware/common/portapack_io.hpp +++ b/firmware/common/portapack_io.hpp @@ -163,7 +163,10 @@ class IO { void lcd_write_pixel(ui::Color pixel) { if (get_dark_cover()) { - pixel.v = DARKENED_PIXEL(pixel.v, get_brightness()); + if (!get_is_inverted()) + pixel.v = DARKENED_PIXEL(pixel.v, get_brightness()); + else + pixel.v = UNDARKENED_PIXEL(pixel.v, get_brightness()); } lcd_write_data(pixel.v); } @@ -174,7 +177,10 @@ class IO { void lcd_write_pixels(ui::Color pixel, size_t n) { if (get_dark_cover()) { - pixel.v = DARKENED_PIXEL(pixel.v, get_brightness()); + if (!get_is_inverted()) + pixel.v = DARKENED_PIXEL(pixel.v, get_brightness()); + else + pixel.v = UNDARKENED_PIXEL(pixel.v, get_brightness()); } while (n--) { lcd_write_data(pixel.v); @@ -183,7 +189,10 @@ class IO { void lcd_write_pixels_unrolled8(ui::Color pixel, size_t n) { if (get_dark_cover()) { - pixel.v = DARKENED_PIXEL(pixel.v, get_brightness()); + if (!get_is_inverted()) + pixel.v = DARKENED_PIXEL(pixel.v, get_brightness()); + else + pixel.v = UNDARKENED_PIXEL(pixel.v, get_brightness()); } auto v = pixel.v; n >>= 3; @@ -231,7 +240,7 @@ class IO { return switches_raw; } - + bool get_is_inverted(); bool get_dark_cover(); uint8_t get_brightness(); // TODO: cache the value ^^ & ^ to increaase performance, need a trigger cuz init doesn't work. And since the constructor is constexpr, we can't use with in class var to cache it. maybe cache from outside somewhere and pass it here as argument. @@ -417,7 +426,10 @@ class IO { uint32_t original_value = (value_high << 8) | value_low; if (get_dark_cover()) { - original_value = UNDARKENED_PIXEL(original_value, get_brightness()); + if (!get_is_inverted()) + original_value = DARKENED_PIXEL(original_value, get_brightness()); + else + original_value = UNDARKENED_PIXEL(original_value, get_brightness()); } return original_value; } diff --git a/firmware/common/portapack_persistent_memory.cpp b/firmware/common/portapack_persistent_memory.cpp index 6a24cffe6..52efe710b 100644 --- a/firmware/common/portapack_persistent_memory.cpp +++ b/firmware/common/portapack_persistent_memory.cpp @@ -212,7 +212,7 @@ struct data_t { bool updown_converter; bool updown_frequency_rx_correction; bool updown_frequency_tx_correction; - bool UNUSED_4 : 1; + bool lcd_inverted_mode : 1; bool UNUSED_5 : 1; bool UNUSED_6 : 1; bool UNUSED_7 : 1; @@ -292,7 +292,7 @@ struct data_t { updown_converter(false), updown_frequency_rx_correction(false), updown_frequency_tx_correction(false), - UNUSED_4(false), + lcd_inverted_mode(false), UNUSED_5(false), UNUSED_6(false), UNUSED_7(false), @@ -1062,6 +1062,14 @@ void set_config_freq_rx_correction(uint32_t v) { data->frequency_rx_correction = v; } +// LCD invert +bool config_lcd_inverted_mode() { + return data->lcd_inverted_mode; +} +void set_lcd_inverted_mode(bool v) { + data->lcd_inverted_mode = v; +} + // Rotary encoder dial settings uint8_t encoder_dial_sensitivity() { return data->encoder_dial_sensitivity; @@ -1231,7 +1239,7 @@ bool debug_dump() { pmem_dump_file.write_line("updown_converter: " + to_string_dec_int(data->updown_converter)); pmem_dump_file.write_line("updown_frequency_rx_correction: " + to_string_dec_int(data->updown_frequency_rx_correction)); pmem_dump_file.write_line("updown_frequency_tx_correction: " + to_string_dec_int(data->updown_frequency_tx_correction)); - // pmem_dump_file.write_line("UNUSED_4: " + to_string_dec_int(data->UNUSED_4)); + pmem_dump_file.write_line("lcd_inverted_mode: " + to_string_dec_uint(data->lcd_inverted_mode)); // pmem_dump_file.write_line("UNUSED_5: " + to_string_dec_int(data->UNUSED_5)); // pmem_dump_file.write_line("UNUSED_6: " + to_string_dec_int(data->UNUSED_6)); // pmem_dump_file.write_line("UNUSED_7: " + to_string_dec_int(data->UNUSED_7)); @@ -1278,6 +1286,7 @@ bool debug_dump() { pmem_dump_file.write_line("ui_config2 hide_battery_icon: " + to_string_dec_uint(data->ui_config2.hide_battery_icon)); pmem_dump_file.write_line("ui_config2 hide_numeric_battery: " + to_string_dec_uint(data->ui_config2.hide_numeric_battery)); pmem_dump_file.write_line("ui_config2 theme_id: " + to_string_dec_uint(data->ui_config2.theme_id)); + pmem_dump_file.write_line("ui_config2 override_batt_calc: " + to_string_dec_uint(data->ui_config2.override_batt_calc)); // misc_config bits pmem_dump_file.write_line("misc_config config_audio_mute: " + to_string_dec_int(config_audio_mute())); diff --git a/firmware/common/portapack_persistent_memory.hpp b/firmware/common/portapack_persistent_memory.hpp index 8f512316b..19ea9bf1e 100644 --- a/firmware/common/portapack_persistent_memory.hpp +++ b/firmware/common/portapack_persistent_memory.hpp @@ -251,6 +251,8 @@ void set_config_audio_mute(bool v); void set_config_speaker_disable(bool v); void set_config_backlight_timer(const backlight_config_t& new_value); void set_disable_touchscreen(bool v); +bool config_lcd_inverted_mode(); +void set_lcd_inverted_mode(bool v); uint8_t encoder_dial_sensitivity(); void set_encoder_dial_sensitivity(uint8_t v);