From bad57d1391f8426a054a4813d126af01ab7f8da3 Mon Sep 17 00:00:00 2001 From: hackrfstuff Date: Thu, 26 Dec 2024 23:23:02 +0100 Subject: [PATCH] Fake brightness reimplementation (#2444) * Fake brightness reimplementation * indentation * added call to the function which is caching the display settings values * use cached values instead of pmem --- firmware/application/apps/ui_settings.cpp | 22 ++++++++- firmware/application/apps/ui_settings.hpp | 28 ++++++++++- firmware/application/ui_navigation.cpp | 13 +++++ firmware/application/ui_navigation.hpp | 6 +++ firmware/common/lcd_ili9341.cpp | 1 + firmware/common/portapack_io.cpp | 14 ++++++ firmware/common/portapack_io.hpp | 22 +++++++++ .../common/portapack_persistent_memory.cpp | 47 +++++++++++++++++-- .../common/portapack_persistent_memory.hpp | 17 +++++++ 9 files changed, 163 insertions(+), 7 deletions(-) diff --git a/firmware/application/apps/ui_settings.cpp b/firmware/application/apps/ui_settings.cpp index 3af587dc..04fbdd50 100644 --- a/firmware/application/apps/ui_settings.cpp +++ b/firmware/application/apps/ui_settings.cpp @@ -324,6 +324,7 @@ SetUIView::SetUIView(NavigationView& nav) { &toggle_bias_tee, &toggle_clock, &toggle_mute, + &toggle_fake_brightness, &toggle_sd_card, &button_save, &button_cancel}); @@ -361,6 +362,7 @@ SetUIView::SetUIView(NavigationView& nav) { toggle_clock.set_value(!pmem::ui_hide_clock()); toggle_speaker.set_value(!pmem::ui_hide_speaker()); toggle_mute.set_value(!pmem::ui_hide_mute()); + toggle_fake_brightness.set_value(!pmem::ui_hide_fake_brightness()); toggle_battery_icon.set_value(!pmem::ui_hide_battery_icon()); toggle_battery_text.set_value(!pmem::ui_hide_numeric_battery()); toggle_sd_card.set_value(!pmem::ui_hide_sd_card()); @@ -389,6 +391,7 @@ SetUIView::SetUIView(NavigationView& nav) { pmem::set_ui_hide_clock(!toggle_clock.value()); pmem::set_ui_hide_speaker(!toggle_speaker.value()); pmem::set_ui_hide_mute(!toggle_mute.value()); + pmem::set_ui_hide_fake_brightness(!toggle_fake_brightness.value()); pmem::set_ui_hide_battery_icon(!toggle_battery_icon.value()); pmem::set_ui_hide_numeric_battery(!toggle_battery_text.value()); pmem::set_ui_hide_sd_card(!toggle_sd_card.value()); @@ -777,13 +780,20 @@ void SetConfigModeView::focus() { /* SetDisplayView ************************************/ SetDisplayView::SetDisplayView(NavigationView& nav) { - add_children({&button_save, + add_children({&labels, + &field_fake_brightness, + &button_save, &button_cancel, - &checkbox_invert_switch}); + &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()); @@ -792,6 +802,14 @@ SetDisplayView::SetDisplayView(NavigationView& nav) { nav.pop(); }; + // only enable invert OR fake brightness + checkbox_invert_switch.on_select = [this](Checkbox&, bool v) { + if (v) checkbox_brightness_switch.set_value(false); + }; + checkbox_brightness_switch.on_select = [this](Checkbox&, bool v) { + if (v) checkbox_invert_switch.set_value(false); + }; + 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 9d31429d..9a587946 100644 --- a/firmware/application/apps/ui_settings.hpp +++ b/firmware/application/apps/ui_settings.hpp @@ -363,8 +363,12 @@ class SetUIView : public View { {19 * 8, 14 * 16 + 2, 16, 16}, &bitmap_icon_batt_text}; - ImageToggle toggle_sd_card{ + ImageToggle toggle_fake_brightness{ {21 * 8, 14 * 16 + 2, 16, 16}, + &bitmap_icon_brightness}; + + ImageToggle toggle_sd_card{ + {23 * 8, 14 * 16 + 2, 16, 16}, &bitmap_sd_card_ok}; Button button_save{ @@ -705,6 +709,7 @@ class SetConfigModeView : public View { "Cancel", }; }; +using portapack::persistent_memory::fake_brightness_level_options; class SetDisplayView : public View { public: @@ -715,8 +720,27 @@ class SetDisplayView : public View { std::string title() const override { return "Display"; }; private: + Labels labels{ + {{1 * 8, 1 * 16}, "Limits screen brightness", Theme::getInstance()->fg_light->foreground}, + {{1 * 8, 2 * 16}, "(has a small performance", Theme::getInstance()->fg_light->foreground}, + {{1 * 8, 3 * 16}, "impact when enabled).", Theme::getInstance()->fg_light->foreground}, + {{2 * 8, 8 * 16}, "Brightness:", Theme::getInstance()->fg_light->foreground}, + }; + + OptionsField field_fake_brightness{ + {20 * 8, 8 * 16}, + 6, + {{"12.5%", fake_brightness_level_options::BRIGHTNESS_12p5}, + {"25%", fake_brightness_level_options::BRIGHTNESS_25}, + {"50%", fake_brightness_level_options::BRIGHTNESS_50}}}; + + Checkbox checkbox_brightness_switch{ + {1 * 8, 5 * 16}, + 16, + "Enable brightness adjust"}; + Checkbox checkbox_invert_switch{ - {1 * 8, 2 * 16}, + {1 * 8, 10 * 16}, 23, "Invert colors (For IPS)"}; diff --git a/firmware/application/ui_navigation.cpp b/firmware/application/ui_navigation.cpp index 8654c204..80bae630 100644 --- a/firmware/application/ui_navigation.cpp +++ b/firmware/application/ui_navigation.cpp @@ -310,6 +310,15 @@ SystemStatusView::SystemStatusView( this->on_bias_tee(); }; + button_fake_brightness.on_select = [this](ImageButton&) { + set_dirty(); + pmem::toggle_fake_brightness_level(); + refresh(); + if (nullptr != parent()) { + parent()->set_dirty(); // The parent of NavigationView shal be the SystemView + } + }; + button_camera.on_select = [this](ImageButton&) { this->on_camera(); }; @@ -373,6 +382,7 @@ void SystemStatusView::refresh() { // Display "Disable speaker" icon only if AK4951 Codec which has separate speaker/headphone control if (audio::speaker_disable_supported() && !pmem::ui_hide_speaker()) status_icons.add(&toggle_speaker); + if (!pmem::ui_hide_fake_brightness() && !pmem::config_lcd_inverted_mode()) status_icons.add(&button_fake_brightness); if (battery::BatteryManagement::isDetected()) { batt_was_inited = true; if (!pmem::ui_hide_battery_icon()) { @@ -405,6 +415,9 @@ void SystemStatusView::refresh() { button_converter.set_bitmap(pmem::config_updown_converter() ? &bitmap_icon_downconvert : &bitmap_icon_upconvert); button_converter.set_foreground(pmem::config_converter() ? Theme::getInstance()->fg_red->foreground : Theme::getInstance()->fg_light->foreground); + // Fake Brightness + button_fake_brightness.set_foreground((pmem::apply_fake_brightness() & (!pmem::config_lcd_inverted_mode())) ? *Theme::getInstance()->status_active : Theme::getInstance()->fg_light->foreground); + set_dirty(); } diff --git a/firmware/application/ui_navigation.hpp b/firmware/application/ui_navigation.hpp index 80187b55..ae49457b 100644 --- a/firmware/application/ui_navigation.hpp +++ b/firmware/application/ui_navigation.hpp @@ -280,6 +280,12 @@ class SystemStatusView : public View { Theme::getInstance()->fg_light->foreground, Theme::getInstance()->bg_dark->background}; + ImageButton button_fake_brightness{ + {0, 0, 2 * 8, 1 * 16}, + &bitmap_icon_brightness, + *Theme::getInstance()->status_active, + Theme::getInstance()->bg_dark->background}; + SDCardStatusView sd_card_status_view{ {0, 0 * 16, 2 * 8, 1 * 16}}; diff --git a/firmware/common/lcd_ili9341.cpp b/firmware/common/lcd_ili9341.cpp index 3c2a0f77..dc02356e 100644 --- a/firmware/common/lcd_ili9341.cpp +++ b/firmware/common/lcd_ili9341.cpp @@ -231,6 +231,7 @@ void lcd_start_ram_write( lcd_caset(p.x(), p.x() + s.width() - 1); lcd_paset(p.y(), p.y() + s.height() - 1); lcd_ramwr_start(); + io.update_cached_values(); } void lcd_start_ram_read( diff --git a/firmware/common/portapack_io.cpp b/firmware/common/portapack_io.cpp index e9eff2f9..22a73617 100644 --- a/firmware/common/portapack_io.cpp +++ b/firmware/common/portapack_io.cpp @@ -77,10 +77,24 @@ void IO::reference_oscillator(const bool enable) { io_write(1, io_reg); } +bool IO::get_dark_cover() { + return portapack::persistent_memory::apply_fake_brightness() & (!portapack::persistent_memory::config_lcd_inverted_mode()); +} + 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(); +} + +void IO::update_cached_values() { + inverted_enabled = get_is_inverted(); + dark_cover_enabled = get_dark_cover(); + brightness = get_brightness(); +} + uint32_t IO::io_update(const TouchPinsConfig write_value) { /* Very touchy code to save context of PortaPack data bus while the * resistive touch pin drive is changed. Order of operations is diff --git a/firmware/common/portapack_io.hpp b/firmware/common/portapack_io.hpp index 96822366..eaeab8b4 100644 --- a/firmware/common/portapack_io.hpp +++ b/firmware/common/portapack_io.hpp @@ -162,6 +162,9 @@ class IO { } void lcd_write_pixel(ui::Color pixel) { + if (dark_cover_enabled) { + pixel.v = DARKENED_PIXEL(pixel.v, brightness); + } lcd_write_data(pixel.v); } @@ -170,12 +173,18 @@ class IO { } void lcd_write_pixels(ui::Color pixel, size_t n) { + if (dark_cover_enabled) { + pixel.v = DARKENED_PIXEL(pixel.v, brightness); + } while (n--) { lcd_write_data(pixel.v); } } void lcd_write_pixels_unrolled8(ui::Color pixel, size_t n) { + if (dark_cover_enabled) { + pixel.v = DARKENED_PIXEL(pixel.v, brightness); + } auto v = pixel.v; n >>= 3; while (n--) { @@ -222,7 +231,13 @@ class IO { return switches_raw; } + bool inverted_enabled = false; + bool dark_cover_enabled = false; + uint8_t brightness = 0; bool get_is_inverted(); + bool get_dark_cover(); + uint8_t get_brightness(); + void update_cached_values(); uint32_t io_update(const TouchPinsConfig write_value); @@ -404,6 +419,13 @@ class IO { const auto value_low = data_read(); uint32_t original_value = (value_high << 8) | value_low; + if (inverted_enabled) return original_value; + + if (dark_cover_enabled) { + // this is read data, so if the fake brightness is enabled AKA get_dark_cover() == true, + // then shift to back side AKA UNDARKENED_PIXEL, to prevent read shifted darkern info + original_value = UNDARKENED_PIXEL(original_value, brightness); + } return original_value; } diff --git a/firmware/common/portapack_persistent_memory.cpp b/firmware/common/portapack_persistent_memory.cpp index 77315955..b2e1bb77 100644 --- a/firmware/common/portapack_persistent_memory.cpp +++ b/firmware/common/portapack_persistent_memory.cpp @@ -109,7 +109,7 @@ struct ui_config_t { bool hide_clock : 1; bool clock_show_date : 1; bool clkout_enabled : 1; - bool unused_FB : 1; // apply_fake_brightness + bool apply_fake_brightness : 1; // Fake brightness level, which eventually could be something along the lines of apply_pwm_brightness bool stealth_mode : 1; bool config_login : 1; bool config_splash : 1; @@ -130,7 +130,7 @@ struct ui_config2_t { bool hide_sd_card : 1; bool hide_mute : 1; - bool UNUSED_3 : 1; + bool hide_fake_brightness : 1; bool hide_numeric_battery : 1; bool hide_battery_icon : 1; bool override_batt_calc : 1; @@ -226,6 +226,9 @@ struct data_t { // Rotary encoder dial sensitivity (encoder.cpp/hpp) uint16_t encoder_dial_sensitivity : 4; + // fake brightness level (not switch, switch is in another place) + uint16_t fake_brightness_level : 4; + // Encoder rotation rate multiplier for larger increments when rotated rapidly uint16_t encoder_rate_multiplier : 4; @@ -297,6 +300,7 @@ struct data_t { frequency_tx_correction(0), encoder_dial_sensitivity(DIAL_SENSITIVITY_NORMAL), + fake_brightness_level(BRIGHTNESS_50), encoder_rate_multiplier(1), UNUSED(0), @@ -465,6 +469,7 @@ void init() { set_config_mode_storage_direct(config_mode_backup); // Firmware upgrade handling - adjust newly defined fields where 0 is an invalid default + if (fake_brightness_level() == 0) set_fake_brightness_level(BRIGHTNESS_50); if (menu_color().v == 0) set_menu_color(Color::grey()); } @@ -645,6 +650,10 @@ bool stealth_mode() { return data->ui_config.stealth_mode; } +bool apply_fake_brightness() { + return data->ui_config.apply_fake_brightness; +} + bool config_login() { return data->ui_config.config_login; } @@ -748,6 +757,10 @@ void set_config_backlight_timer(const backlight_config_t& new_value) { data->ui_config.enable_backlight_timeout = static_cast(new_value.timeout_enabled()); } +void set_apply_fake_brightness(const bool v) { + data->ui_config.apply_fake_brightness = v; +} + uint32_t pocsag_last_address() { return data->pocsag_last_address; } @@ -934,7 +947,9 @@ bool ui_hide_clock() { bool ui_hide_sd_card() { return data->ui_config2.hide_sd_card; } - +bool ui_hide_fake_brightness() { + return data->ui_config2.hide_fake_brightness; +} bool ui_hide_numeric_battery() { return data->ui_config2.hide_numeric_battery; } @@ -977,6 +992,9 @@ void set_ui_hide_clock(bool v) { void set_ui_hide_sd_card(bool v) { data->ui_config2.hide_sd_card = v; } +void set_ui_hide_fake_brightness(bool v) { + data->ui_config2.hide_fake_brightness = v; +} void set_ui_hide_numeric_battery(bool v) { data->ui_config2.hide_numeric_battery = v; } @@ -1094,6 +1112,26 @@ void set_config_dst(dst_config_t v) { rtc_time::dst_init(); } +// Fake brightness level (switch is in another place) +uint8_t fake_brightness_level() { + return data->fake_brightness_level; +} +void set_fake_brightness_level(uint8_t v) { + data->fake_brightness_level = v; +} + +// Cycle through 4 brightness options: disabled -> enabled/50% -> enabled/25% -> enabled/12.5% -> disabled +void toggle_fake_brightness_level() { + bool fbe = apply_fake_brightness(); + if (config_lcd_inverted_mode()) return; // for now only inverted mode OR fake brightness + if ((!fbe) || (data->fake_brightness_level >= BRIGHTNESS_12p5)) { + set_apply_fake_brightness(!fbe); + data->fake_brightness_level = BRIGHTNESS_50; + } else { + data->fake_brightness_level++; + } +} + // Menu Color Scheme Color menu_color() { return data->menu_color; @@ -1211,6 +1249,7 @@ bool debug_dump() { pmem_dump_file.write_line("headphone_volume_cb: " + to_string_dec_int(data->headphone_volume_cb)); pmem_dump_file.write_line("config_mode_storage: 0x" + to_string_hex(data->config_mode_storage, 8)); pmem_dump_file.write_line("dst_config: 0x" + to_string_hex((uint32_t)data->dst_config.v, 8)); + pmem_dump_file.write_line("fake_brightness_level: " + to_string_dec_uint(data->fake_brightness_level)); pmem_dump_file.write_line("menu_color: 0x" + to_string_hex(data->menu_color.v, 4)); pmem_dump_file.write_line("touchscreen_threshold: " + to_string_dec_uint(data->touchscreen_threshold)); @@ -1227,6 +1266,7 @@ bool debug_dump() { pmem_dump_file.write_line("ui_config hide_clock: " + to_string_dec_uint(data->ui_config.hide_clock)); pmem_dump_file.write_line("ui_config clock_with_date: " + to_string_dec_uint(data->ui_config.clock_show_date)); pmem_dump_file.write_line("ui_config clkout_enabled: " + to_string_dec_uint(data->ui_config.clkout_enabled)); + pmem_dump_file.write_line("ui_config apply_fake_brightness: " + to_string_dec_uint(data->ui_config.apply_fake_brightness)); pmem_dump_file.write_line("ui_config stealth_mode: " + to_string_dec_uint(data->ui_config.stealth_mode)); pmem_dump_file.write_line("ui_config config_login: " + to_string_dec_uint(data->ui_config.config_login)); pmem_dump_file.write_line("ui_config config_splash: " + to_string_dec_uint(data->ui_config.config_splash)); @@ -1241,6 +1281,7 @@ bool debug_dump() { pmem_dump_file.write_line("ui_config2 hide_clock: " + to_string_dec_uint(data->ui_config2.hide_clock)); pmem_dump_file.write_line("ui_config2 hide_sd_card: " + to_string_dec_uint(data->ui_config2.hide_sd_card)); pmem_dump_file.write_line("ui_config2 hide_mute: " + to_string_dec_uint(data->ui_config2.hide_mute)); + pmem_dump_file.write_line("ui_config2 hide_fake_brightness: " + to_string_dec_uint(data->ui_config2.hide_fake_brightness)); 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)); diff --git a/firmware/common/portapack_persistent_memory.hpp b/firmware/common/portapack_persistent_memory.hpp index 727a2003..93da33ad 100644 --- a/firmware/common/portapack_persistent_memory.hpp +++ b/firmware/common/portapack_persistent_memory.hpp @@ -135,6 +135,12 @@ typedef union { } dst_config_t; static_assert(sizeof(dst_config_t) == sizeof(uint32_t)); +enum fake_brightness_level_options { + BRIGHTNESS_50 = 1, + BRIGHTNESS_25 = 2, + BRIGHTNESS_12p5 = 3, // 12p5 is 12.5 +}; + namespace cache { /* Set values in cache to sensible defaults. */ @@ -267,6 +273,15 @@ uint16_t clkout_freq(); dst_config_t config_dst(); void set_config_dst(dst_config_t v); +/* Fake brightness */ +// switch (if do color change): +bool apply_fake_brightness(); +void set_apply_fake_brightness(const bool v); +// level (color change level): +uint8_t fake_brightness_level(); +void set_fake_brightness_level(uint8_t v); +void toggle_fake_brightness_level(); + /* Touchscreen threshold */ uint16_t touchscreen_threshold(); void set_touchscreen_threshold(uint16_t v); @@ -319,6 +334,7 @@ bool ui_hide_camera(); bool ui_hide_sleep(); bool ui_hide_bias_tee(); bool ui_hide_clock(); +bool ui_hide_fake_brightness(); bool ui_hide_numeric_battery(); bool ui_hide_battery_icon(); bool ui_hide_sd_card(); @@ -332,6 +348,7 @@ void set_ui_hide_camera(bool v); void set_ui_hide_sleep(bool v); void set_ui_hide_bias_tee(bool v); void set_ui_hide_clock(bool v); +void set_ui_hide_fake_brightness(bool v); void set_ui_hide_numeric_battery(bool v); void set_ui_hide_battery_icon(bool v); void set_ui_hide_sd_card(bool v);