From 6b44a77ef6f968cfda6713b0e324f9f63c9f3865 Mon Sep 17 00:00:00 2001 From: Mark Thompson <129641948+NotherNgineer@users.noreply.github.com> Date: Wed, 24 May 2023 21:32:12 -0500 Subject: [PATCH] Support for Rotary Encoder Dial sensitivity levels, issue #965 (#1057) * Support for 3 levels of rotary encoder sensitivity #965 Backend support; UI will still need to call set function to configure. * Support for 3 levels of rotary encoder sensitivity #965 Backend support only. UI will still need to be changed to call the set_sensitivity() function to configure. * Removed trailing space * Deleted blank lines to see if format checker will be happier * Simpler support for multiple levels of encoder sensitivity, for issue #965 Removed the convoluted code :-) and instead just using a 2-dimensional array to choose which transition map to use. For now I only have 2 (vs 3) levels enabled as well, to save code space and because high-sensitivity is very touchy. * Simpler version of configurable encoder sensitivity, issue #965 * Formatting * Formatting test for Clang * Formatting test * Formatting (removed helpful comment) * Formatting test (remove commented-out code) * Formatting & swapping medium/low so default mode=0 * Swapped medium/low so default mode=0 * Adding UI & PMEM support to make encoder dial sensitivity configurable, issue #965 * Adding UI & PMEM support to make encoder dial sensitivity configurable, issue #965 * Adding UI & PMEM support to make encoder dial sensitivity configurable, issue #965 * Adding UI & PMEM support to make encoder dial sensitivity configurable, issue #965 * Adding UI & PMEM support to make encoder dial sensitivity configurable, issue #965 * Adding UI & PMEM support to make encoder dial sensitivity configurable, issue #965 * Removed unneeded range check (trusting in pmem checksum) --- firmware/application/apps/ui_settings.cpp | 35 +++++++- firmware/application/apps/ui_settings.hpp | 32 +++++++ firmware/application/hw/encoder.cpp | 89 +++++++++++++++---- .../common/portapack_persistent_memory.cpp | 14 ++- .../common/portapack_persistent_memory.hpp | 9 ++ 5 files changed, 157 insertions(+), 22 deletions(-) diff --git a/firmware/application/apps/ui_settings.cpp b/firmware/application/apps/ui_settings.cpp index 38fe1696..b699c5d9 100644 --- a/firmware/application/apps/ui_settings.cpp +++ b/firmware/application/apps/ui_settings.cpp @@ -529,9 +529,9 @@ void SetPersistentMemoryView::focus() { button_return.focus(); } -// -// Audio settings -// +// --------------------------------------------------------- +// Audio Settings +// --------------------------------------------------------- SetAudioView::SetAudioView(NavigationView& nav) { add_children({&labels, &field_tone_mix, @@ -554,6 +554,9 @@ void SetAudioView::focus() { button_save.focus(); } +// --------------------------------------------------------- +// QR Code Settings +// ------------------------------------------------------ SetQRCodeView::SetQRCodeView(NavigationView& nav) { add_children({&checkbox_bigger_qr, &button_save, @@ -575,6 +578,31 @@ void SetQRCodeView::focus() { button_save.focus(); } +// --------------------------------------------------------- +// Rotary Encoder Dial Settings +// --------------------------------------------------------- +SetEncoderDialView::SetEncoderDialView(NavigationView& nav) { + add_children({&labels, + &field_encoder_dial_sensitivity, + &button_save, + &button_cancel}); + + field_encoder_dial_sensitivity.set_by_value(persistent_memory::config_encoder_dial_sensitivity()); + + button_save.on_select = [&nav, this](Button&) { + persistent_memory::set_encoder_dial_sensitivity(field_encoder_dial_sensitivity.selected_index_value()); + nav.pop(); + }; + + button_cancel.on_select = [&nav, this](Button&) { + nav.pop(); + }; +} + +void SetEncoderDialView::focus() { + button_save.focus(); +} + // --------------------------------------------------------- // Settings main menu // --------------------------------------------------------- @@ -593,6 +621,7 @@ SettingsMenuView::SettingsMenuView(NavigationView& nav) { {"FreqCorrection", ui::Color::dark_cyan(), &bitmap_icon_options_radio, [&nav]() { nav.push(); }}, {"QR Code", ui::Color::dark_cyan(), &bitmap_icon_qr_code, [&nav]() { nav.push(); }}, {"P.Memory Mgmt", ui::Color::dark_cyan(), &bitmap_icon_memory, [&nav]() { nav.push(); }}, + {"Encoder Dial", ui::Color::dark_cyan(), &bitmap_icon_setup, [&nav]() { nav.push(); }}, }); set_max_rows(2); // allow wider buttons } diff --git a/firmware/application/apps/ui_settings.hpp b/firmware/application/apps/ui_settings.hpp index 04fe1c46..f4fb79e1 100644 --- a/firmware/application/apps/ui_settings.hpp +++ b/firmware/application/apps/ui_settings.hpp @@ -432,6 +432,38 @@ class SetQRCodeView : public View { }; }; +using portapack::persistent_memory::encoder_dial_sensitivity; + +class SetEncoderDialView : public View { + public: + SetEncoderDialView(NavigationView& nav); + + void focus() override; + + std::string title() const override { return "Encoder Dial"; }; + + private: + Labels labels{ + {{2 * 8, 3 * 16}, "Dial sensitivity:", Color::light_grey()}, + }; + + OptionsField field_encoder_dial_sensitivity{ + {20 * 8, 3 * 16}, + 6, + {{"LOW", encoder_dial_sensitivity::DIAL_SENSITIVITY_LOW}, + {"NORMAL", encoder_dial_sensitivity::DIAL_SENSITIVITY_MEDIUM}, + {"HIGH", encoder_dial_sensitivity::DIAL_SENSITIVITY_HIGH}}}; + + Button button_save{ + {2 * 8, 16 * 16, 12 * 8, 32}, + "Save"}; + + Button button_cancel{ + {16 * 8, 16 * 16, 12 * 8, 32}, + "Cancel", + }; +}; + class SetPersistentMemoryView : public View { public: SetPersistentMemoryView(NavigationView& nav); diff --git a/firmware/application/hw/encoder.cpp b/firmware/application/hw/encoder.cpp index 4a38953b..0bb427c9 100644 --- a/firmware/application/hw/encoder.cpp +++ b/firmware/application/hw/encoder.cpp @@ -23,23 +23,75 @@ #include "utility.hpp" -static const int8_t transition_map[] = { - 0, // 0000: noop - 0, // 0001: start - 0, // 0010: start - 0, // 0011: rate - 1, // 0100: end - 0, // 0101: noop - 0, // 0110: rate - -1, // 0111: end - -1, // 1000: end - 0, // 1001: rate - 0, // 1010: noop - 1, // 1011: end - 0, // 1100: rate - 0, // 1101: start - 0, // 1110: start - 0, // 1111: noop +#include "portapack.hpp" +#include "portapack_persistent_memory.hpp" + +// Now supporting multiple levels of rotary encoder dial sensitivity +// +// Portapack H2 normally has a 30-step encoder, meaning one step (pulse) every +// 12 degrees of rotation. +// +// For each encoder "pulse" there are 4 state transitions, and we can choose +// between looking at all of them (high sensitivity), half of them (medium/default), +// or one quarter of them (low sensitivity). +static const int8_t transition_map[][16] = { + // Normal (Medium) Sensitivity -- default + { + 0, // 0000: noop + 0, // 0001: ccw start + 0, // 0010: cw start + 0, // 0011: rate + 1, // 0100: cw end + 0, // 0101: noop + 0, // 0110: rate + -1, // 0111: ccw end + -1, // 1000: ccw end + 0, // 1001: rate + 0, // 1010: noop + 1, // 1011: cw end + 0, // 1100: rate + 0, // 1101: cw start + 0, // 1110: ccw start + 0, // 1111: noop + }, + // Low Sensitivity + { + 0, // 0000: noop + 0, // 0001: ccw start + 0, // 0010: cw start + 0, // 0011: rate + 1, // 0100: cw end + 0, // 0101: noop + 0, // 0110: rate + 0, // 0111: ccw end + -1, // 1000: ccw end + 0, // 1001: rate + 0, // 1010: noop + 0, // 1011: cw end + 0, // 1100: rate + 0, // 1101: cw start + 0, // 1110: ccw start + 0, // 1111: noop + }, + // High Sensitivity + { + 0, // 0000: noop + -1, // 0001: ccw start + 1, // 0010: cw start + 0, // 0011: rate + 1, // 0100: cw end + 0, // 0101: noop + 0, // 0110: rate + -1, // 0111: ccw end + -1, // 1000: ccw end + 0, // 1001: rate + 0, // 1010: noop + 1, // 1011: cw end + 0, // 1100: rate + 1, // 1101: cw start + -1, // 1110: ccw start + 0, // 1111: noop + }, }; int_fast8_t Encoder::update( @@ -50,5 +102,6 @@ int_fast8_t Encoder::update( state <<= 1; state |= phase_1; - return transition_map[state & 0xf]; + // dial sensitivity setting is stored in pmem + return transition_map[portapack::persistent_memory::config_encoder_dial_sensitivity()][state & 0xf]; } diff --git a/firmware/common/portapack_persistent_memory.cpp b/firmware/common/portapack_persistent_memory.cpp index a7cfd9f3..af8bcfcd 100644 --- a/firmware/common/portapack_persistent_memory.cpp +++ b/firmware/common/portapack_persistent_memory.cpp @@ -302,6 +302,9 @@ struct data_t { uint32_t frequency_tx_correction; bool updown_frequency_tx_correction; + // Rotary encoder dial sensitivity (encoder.cpp/hpp) + uint8_t encoder_dial_sensitivity; + constexpr data_t() : structure_version(data_structure_version_enum::VERSION_CURRENT), tuned_frequency(tuned_frequency_reset_value), @@ -337,7 +340,8 @@ struct data_t { frequency_rx_correction(0), updown_frequency_rx_correction(0), frequency_tx_correction(0), - updown_frequency_tx_correction(0) { + updown_frequency_tx_correction(0), + encoder_dial_sensitivity(0) { } }; @@ -808,6 +812,14 @@ void set_config_freq_rx_correction(uint32_t v) { data->frequency_rx_correction = v; } +// rotary encoder dial settings +uint8_t config_encoder_dial_sensitivity() { + return data->encoder_dial_sensitivity; +} +void set_encoder_dial_sensitivity(uint8_t v) { + data->encoder_dial_sensitivity = v; +} + // sd persisting settings int save_persistent_settings_to_file(std::string filename) { delete_file(filename); diff --git a/firmware/common/portapack_persistent_memory.hpp b/firmware/common/portapack_persistent_memory.hpp index c16181db..101512b4 100644 --- a/firmware/common/portapack_persistent_memory.hpp +++ b/firmware/common/portapack_persistent_memory.hpp @@ -99,6 +99,13 @@ struct backlight_config_t { bool _timeout_enabled; }; +enum encoder_dial_sensitivity { + DIAL_SENSITIVITY_MEDIUM = 0, + DIAL_SENSITIVITY_LOW = 1, + DIAL_SENSITIVITY_HIGH = 2, + NUM_DIAL_SENSITIVITY +}; + namespace cache { /* Set values in cache to sensible defaults. */ @@ -199,6 +206,8 @@ void set_config_login(bool v); void set_config_speaker(bool v); void set_config_backlight_timer(const backlight_config_t& new_value); void set_disable_touchscreen(bool v); +uint8_t config_encoder_dial_sensitivity(); +void set_encoder_dial_sensitivity(uint8_t v); // uint8_t ui_config_textentry(); // void set_config_textentry(uint8_t new_value);