Encoder rotation rate multiplier support (#1876)

This commit is contained in:
Mark Thompson 2024-02-10 02:32:03 -06:00 committed by GitHub
parent 367479d163
commit 46d9e02684
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 73 additions and 18 deletions

View File

@ -3,6 +3,7 @@
* Copyright (C) 2016 Furrtek * Copyright (C) 2016 Furrtek
* Copyright (C) 2023 gullradriel, Nilorea Studio Inc. * Copyright (C) 2023 gullradriel, Nilorea Studio Inc.
* Copyright (C) 2023 Kyle Reed * Copyright (C) 2023 Kyle Reed
* Copyright (C) 2024 Mark Thompson
* Copyleft (ɔ) 2024 zxkmm under GPL license * Copyleft (ɔ) 2024 zxkmm under GPL license
* *
* This file is part of PortaPack. * This file is part of PortaPack.
@ -680,13 +681,16 @@ void SetQRCodeView::focus() {
SetEncoderDialView::SetEncoderDialView(NavigationView& nav) { SetEncoderDialView::SetEncoderDialView(NavigationView& nav) {
add_children({&labels, add_children({&labels,
&field_encoder_dial_sensitivity, &field_encoder_dial_sensitivity,
&field_encoder_rate_multiplier,
&button_save, &button_save,
&button_cancel}); &button_cancel});
field_encoder_dial_sensitivity.set_by_value(pmem::config_encoder_dial_sensitivity()); field_encoder_dial_sensitivity.set_by_value(pmem::encoder_dial_sensitivity());
field_encoder_rate_multiplier.set_value(pmem::encoder_rate_multiplier());
button_save.on_select = [&nav, this](Button&) { button_save.on_select = [&nav, this](Button&) {
pmem::set_encoder_dial_sensitivity(field_encoder_dial_sensitivity.selected_index_value()); pmem::set_encoder_dial_sensitivity(field_encoder_dial_sensitivity.selected_index_value());
pmem::set_encoder_rate_multiplier(field_encoder_rate_multiplier.value());
nav.pop(); nav.pop();
}; };

View File

@ -3,6 +3,7 @@
* Copyright (C) 2016 Furrtek * Copyright (C) 2016 Furrtek
* Copyright (C) 2023 gullradriel, Nilorea Studio Inc. * Copyright (C) 2023 gullradriel, Nilorea Studio Inc.
* Copyright (C) 2023 Kyle Reed * Copyright (C) 2023 Kyle Reed
* Copyright (C) 2024 Mark Thompson
* Copyleft (ɔ) 2024 zxkmm under GPL license * Copyleft (ɔ) 2024 zxkmm under GPL license
* *
* This file is part of PortaPack. * This file is part of PortaPack.
@ -555,6 +556,7 @@ class SetQRCodeView : public View {
}; };
using portapack::persistent_memory::encoder_dial_sensitivity; using portapack::persistent_memory::encoder_dial_sensitivity;
using portapack::persistent_memory::encoder_rate_multiplier;
class SetEncoderDialView : public View { class SetEncoderDialView : public View {
public: public:
@ -566,18 +568,30 @@ class SetEncoderDialView : public View {
private: private:
Labels labels{ Labels labels{
{{1 * 8, 1 * 16}, "Adjusts how many steps to", Color::light_grey()}, {{1 * 8, 1 * 16}, "Adjusts sensitivity to dial", Color::light_grey()},
{{1 * 8, 2 * 16}, "change the encoder value.", Color::light_grey()}, {{1 * 8, 2 * 16}, "rotation position (number of", Color::light_grey()},
{{2 * 8, 4 * 16}, "Dial sensitivity:", Color::light_grey()}, {{1 * 8, 3 * 16}, "steps per full rotation):", Color::light_grey()},
{{2 * 8, 5 * 16}, "Dial sensitivity:", Color::light_grey()},
{{1 * 8, 8 * 16}, "Adjusts sensitivity to dial", Color::light_grey()},
{{1 * 8, 9 * 16}, "rotation rate (default 1", Color::light_grey()},
{{1 * 8, 10 * 16}, "means no rate dependency):", Color::light_grey()},
{{3 * 8, 12 * 16}, "Rate multiplier:", Color::light_grey()},
}; };
OptionsField field_encoder_dial_sensitivity{ OptionsField field_encoder_dial_sensitivity{
{20 * 8, 4 * 16}, {20 * 8, 5 * 16},
6, 6,
{{"LOW", encoder_dial_sensitivity::DIAL_SENSITIVITY_LOW}, {{"LOW", encoder_dial_sensitivity::DIAL_SENSITIVITY_LOW},
{"NORMAL", encoder_dial_sensitivity::DIAL_SENSITIVITY_NORMAL}, {"NORMAL", encoder_dial_sensitivity::DIAL_SENSITIVITY_NORMAL},
{"HIGH", encoder_dial_sensitivity::DIAL_SENSITIVITY_HIGH}}}; {"HIGH", encoder_dial_sensitivity::DIAL_SENSITIVITY_HIGH}}};
NumberField field_encoder_rate_multiplier{
{20 * 8, 12 * 16},
2,
{1, 10},
1,
' '};
Button button_save{ Button button_save{
{2 * 8, 16 * 16, 12 * 8, 32}, {2 * 8, 16 * 16, 12 * 8, 32},
"Save"}; "Save"};

View File

@ -24,6 +24,9 @@
#include "utility.hpp" #include "utility.hpp"
#include "portapack.hpp"
#include "portapack_persistent_memory.hpp"
uint8_t Debounce::state() { uint8_t Debounce::state() {
uint8_t v = state_to_report_; uint8_t v = state_to_report_;
simulated_pulse_ = false; simulated_pulse_ = false;
@ -154,6 +157,10 @@ uint8_t EncoderDebounce::state() {
return state_; return state_;
} }
uint8_t EncoderDebounce::rotation_rate() {
return last_rotation_rate_;
}
// Returns TRUE if encoder position phase bits changed (after debouncing) // Returns TRUE if encoder position phase bits changed (after debouncing)
bool EncoderDebounce::feed(const uint8_t phase_bits) { bool EncoderDebounce::feed(const uint8_t phase_bits) {
history_ = (history_ << 2) | phase_bits; history_ = (history_ << 2) | phase_bits;
@ -164,14 +171,21 @@ bool EncoderDebounce::feed(const uint8_t phase_bits) {
// But, checking for equal seems to cause issues with at least 1 user's encoder, so we're treating the input // But, checking for equal seems to cause issues with at least 1 user's encoder, so we're treating the input
// as "stable" if at least ONE input bit is consistent for 4 ticks... // as "stable" if at least ONE input bit is consistent for 4 ticks...
uint8_t diff = (history_ ^ expected_stable_history); uint8_t diff = (history_ ^ expected_stable_history);
if ((diff == 0) || ((diff & 0b01010101) == 0) || ((diff & 0b10101010) == 0)) { if (((diff & 0b01010101) == 0) || ((diff & 0b10101010) == 0)) {
// Has the debounced input value changed? // Has the debounced input value changed?
if (state_ != phase_bits) { if (state_ != phase_bits) {
state_ = phase_bits; state_ = phase_bits;
// Rate multiplier is for larger delta increments when dial is rotated rapidly.
last_rotation_rate_ = rotation_rate_downcounter_;
rotation_rate_downcounter_ = portapack::persistent_memory::encoder_rate_multiplier();
return true; return true;
} }
} }
// Unstable input, or no change // Unstable input, or no change.
// Decrement rotation rate detector once per timer tick.
if (rotation_rate_downcounter_ > 1)
rotation_rate_downcounter_--;
return false; return false;
} }

View File

@ -1,5 +1,6 @@
/* /*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc. * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2024 Mark Thompson
* *
* This file is part of PortaPack. * This file is part of PortaPack.
* *
@ -70,10 +71,15 @@ class EncoderDebounce {
uint8_t state(); // returns debounced phase bits from encoder uint8_t state(); // returns debounced phase bits from encoder
uint8_t rotation_rate(); // returns last rotation rate
private: private:
uint8_t history_{0}; // shift register of previous reads from encoder uint8_t history_{0}; // shift register of previous reads from encoder
uint8_t state_{0}; // actual encoder output state (after debounce logic) uint8_t state_{0}; // actual encoder output state (after debounce logic)
uint8_t last_rotation_rate_{1};
uint8_t rotation_rate_downcounter_{1}; // down-counter to estimate rotation speed
}; };
#endif /*__DEBOUNCE_H__*/ #endif /*__DEBOUNCE_H__*/

View File

@ -1,5 +1,6 @@
/* /*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc. * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2024 Mark Thompson
* *
* This file is part of PortaPack. * This file is part of PortaPack.
* *
@ -63,7 +64,7 @@ int_fast8_t Encoder::update(const uint_fast8_t phase_bits) {
// Require 2 state changes in same direction to register movement -- for additional level of contact switch debouncing // Require 2 state changes in same direction to register movement -- for additional level of contact switch debouncing
if (direction == prev_direction) { if (direction == prev_direction) {
if ((sensitivity_map[portapack::persistent_memory::config_encoder_dial_sensitivity()] & (1 << state)) == 0) if ((sensitivity_map[portapack::persistent_memory::encoder_dial_sensitivity()] & (1 << state)) == 0)
return 0; return 0;
return direction; return direction;
} }

View File

@ -1,5 +1,6 @@
/* /*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc. * Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2024 Mark Thompson
* *
* This file is part of PortaPack. * This file is part of PortaPack.
* *

View File

@ -1,5 +1,6 @@
/* /*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2024 Mark Thompson
* *
* This file is part of PortaPack. * This file is part of PortaPack.
* *
@ -166,7 +167,7 @@ static bool encoder_update(const uint8_t raw) {
} }
static bool encoder_read() { static bool encoder_read() {
auto delta = encoder.update(encoder_debounce.state()); auto delta = encoder.update(encoder_debounce.state()) * encoder_debounce.rotation_rate();
if (injected_encoder > 0) { if (injected_encoder > 0) {
if (injected_encoder == 1) delta = -1; if (injected_encoder == 1) delta = -1;

View File

@ -1,5 +1,6 @@
/* /*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2024 Mark Thompson
* *
* This file is part of PortaPack. * This file is part of PortaPack.
* *

View File

@ -1,6 +1,7 @@
/* /*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2016 Furrtek * Copyright (C) 2016 Furrtek
* Copyright (C) 2024 Mark Thompson
* *
* This file is part of PortaPack. * This file is part of PortaPack.
* *
@ -226,7 +227,9 @@ struct data_t {
// fake brightness level (not switch, switch is in another place) // fake brightness level (not switch, switch is in another place)
uint16_t fake_brightness_level : 4; uint16_t fake_brightness_level : 4;
uint16_t UNUSED_8 : 8;
// Encoder rotation rate multiplier for larger increments when rotated rapidly
uint16_t encoder_rate_multiplier : 8;
// Headphone volume in centibels. // Headphone volume in centibels.
int16_t headphone_volume_cb; int16_t headphone_volume_cb;
@ -292,7 +295,7 @@ struct data_t {
encoder_dial_sensitivity(DIAL_SENSITIVITY_NORMAL), encoder_dial_sensitivity(DIAL_SENSITIVITY_NORMAL),
fake_brightness_level(BRIGHTNESS_50), fake_brightness_level(BRIGHTNESS_50),
UNUSED_8(0), encoder_rate_multiplier(1),
headphone_volume_cb(-600), headphone_volume_cb(-600),
misc_config(), misc_config(),
ui_config2(), ui_config2(),
@ -399,6 +402,7 @@ void defaults() {
cached_backup_ram = backup_ram_t(); cached_backup_ram = backup_ram_t();
// If the desired default is 0/false, then no need to set it here (buffer is initialized to 0) // If the desired default is 0/false, then no need to set it here (buffer is initialized to 0)
// NB: This function is only called when pmem is reset; also see firmware upgrade handling below.
set_config_backlight_timer(backlight_config_t{}); set_config_backlight_timer(backlight_config_t{});
set_config_splash(true); set_config_splash(true);
set_config_disable_external_tcxo(false); set_config_disable_external_tcxo(false);
@ -449,9 +453,9 @@ void init() {
} }
set_config_mode_storage_direct(config_mode_backup); set_config_mode_storage_direct(config_mode_backup);
// Firmware upgrade handling - adjust newly defined fields where 0 is an unwanted default // Firmware upgrade handling - adjust newly defined fields where 0 is an invalid default
if (fake_brightness_level() == 0) if (fake_brightness_level() == 0) set_fake_brightness_level(BRIGHTNESS_50);
set_fake_brightness_level(BRIGHTNESS_50); if (encoder_rate_multiplier() == 0) set_encoder_rate_multiplier(1);
} }
void persist() { void persist() {
@ -976,13 +980,18 @@ void set_config_freq_rx_correction(uint32_t v) {
} }
// Rotary encoder dial settings // Rotary encoder dial settings
uint8_t encoder_dial_sensitivity() {
uint8_t config_encoder_dial_sensitivity() {
return data->encoder_dial_sensitivity; return data->encoder_dial_sensitivity;
} }
void set_encoder_dial_sensitivity(uint8_t v) { void set_encoder_dial_sensitivity(uint8_t v) {
data->encoder_dial_sensitivity = v; data->encoder_dial_sensitivity = v;
} }
uint8_t encoder_rate_multiplier() {
return data->encoder_rate_multiplier;
}
void set_encoder_rate_multiplier(uint8_t v) {
data->encoder_rate_multiplier = v;
}
// Recovery mode magic value storage // Recovery mode magic value storage
static data_t* data_direct_access = reinterpret_cast<data_t*>(memory::map::backup_ram.base()); static data_t* data_direct_access = reinterpret_cast<data_t*>(memory::map::backup_ram.base());
@ -1137,7 +1146,7 @@ bool debug_dump() {
pmem_dump_file.write_line("frequency_rx_correction: " + to_string_dec_uint(data->frequency_rx_correction)); pmem_dump_file.write_line("frequency_rx_correction: " + to_string_dec_uint(data->frequency_rx_correction));
pmem_dump_file.write_line("frequency_tx_correction: " + to_string_dec_uint(data->frequency_tx_correction)); pmem_dump_file.write_line("frequency_tx_correction: " + to_string_dec_uint(data->frequency_tx_correction));
pmem_dump_file.write_line("encoder_dial_sensitivity: " + to_string_dec_uint(data->encoder_dial_sensitivity)); pmem_dump_file.write_line("encoder_dial_sensitivity: " + to_string_dec_uint(data->encoder_dial_sensitivity));
// pmem_dump_file.write_line("UNUSED_8: " + to_string_dec_uint(data->UNUSED_8)); pmem_dump_file.write_line("encoder_rate_multiplier: " + to_string_dec_uint(data->encoder_rate_multiplier));
pmem_dump_file.write_line("headphone_volume_cb: " + to_string_dec_int(data->headphone_volume_cb)); 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("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("dst_config: 0x" + to_string_hex((uint32_t)data->dst_config.v, 8));

View File

@ -1,6 +1,7 @@
/* /*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2016 Furrtek * Copyright (C) 2016 Furrtek
* Copyright (C) 2024 Mark Thompson
* *
* This file is part of PortaPack. * This file is part of PortaPack.
* *
@ -246,8 +247,11 @@ void set_config_audio_mute(bool v);
void set_config_speaker_disable(bool v); void set_config_speaker_disable(bool v);
void set_config_backlight_timer(const backlight_config_t& new_value); void set_config_backlight_timer(const backlight_config_t& new_value);
void set_disable_touchscreen(bool v); void set_disable_touchscreen(bool v);
uint8_t config_encoder_dial_sensitivity();
uint8_t encoder_dial_sensitivity();
void set_encoder_dial_sensitivity(uint8_t v); void set_encoder_dial_sensitivity(uint8_t v);
uint8_t encoder_rate_multiplier();
void set_encoder_rate_multiplier(uint8_t v);
uint32_t config_mode_storage_direct(); uint32_t config_mode_storage_direct();
void set_config_mode_storage_direct(uint32_t v); void set_config_mode_storage_direct(uint32_t v);