Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve Rotary Encoder #631

Merged
merged 2 commits into from
May 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions components/encoder/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,15 @@ menu "Rotary encoders"
int "Long press timeout, us"
default 500000

config RE_ACCELERATION_MIN_CUTOFF
int "Minimum Acceleration cutoff time (ms)"
default 200
help
At this time in milliseconds between rotary ticks we want to be at the minimum acceleration

config RE_ACCELERATION_MAX_CUTOFF
int "Maximum Acceleration cutoff time (ms)"
default 4
help
At this time in milliseconds between rotary ticks we want to be at the maximum acceleration
endmenu
41 changes: 38 additions & 3 deletions components/encoder/encoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -128,13 +128,33 @@ inline static void read_encoder(rotary_encoder_t *re)

re->store = (re->store << 4) | re->code;

if (re->store == 0xe817) inc = 1;
if (re->store == 0xd42b) inc = -1;
if ((re->store == 0xe817)||(re->store == 0x17e8)) inc = 1;
if ((re->store == 0xd42b)||(re->store == 0x2bd4)) inc = -1;

if (inc)
{
ev.type = RE_ET_CHANGED;
ev.diff = inc;
if (re->acceleration.coeff > 1)
{
int64_t nowMicros = esp_timer_get_time();
// at 200 ms, we want to have minimum acceleration
uint32_t accelerationMinCutoffMillis = CONFIG_RE_ACCELERATION_MIN_CUTOFF;
// at 4 ms, we want to have maximum acceleration
uint32_t accelerationMaxCutoffMillis = CONFIG_RE_ACCELERATION_MAX_CUTOFF;
uint32_t millisAfterLastMotion = (nowMicros - re->acceleration.last_time) / 1000u;
re->acceleration.last_time = nowMicros;

if (millisAfterLastMotion < accelerationMinCutoffMillis)
{
if (millisAfterLastMotion < accelerationMaxCutoffMillis)
{
millisAfterLastMotion = accelerationMaxCutoffMillis; // limit to maximum acceleration
}
ev.diff = inc * ((int32_t)(re->acceleration.coeff / millisAfterLastMotion) == 0 ? 1 : (int32_t)(re->acceleration.coeff / millisAfterLastMotion));
}
}

ev.type = RE_ET_CHANGED;
xQueueSendToBack(_queue, &ev, 0);
}
}
Expand Down Expand Up @@ -252,3 +272,18 @@ esp_err_t rotary_encoder_remove(rotary_encoder_t *re)
xSemaphoreGive(mutex);
return ESP_ERR_NOT_FOUND;
}

esp_err_t rotary_encoder_enable_acceleration(rotary_encoder_t *re, uint16_t coeff)
{
CHECK_ARG(re);
re->acceleration.coeff = coeff;
re->acceleration.last_time = esp_timer_get_time();
return ESP_OK;
}

esp_err_t rotary_encoder_disable_acceleration(rotary_encoder_t *re)
{
CHECK_ARG(re);
re->acceleration.coeff = 0;
return ESP_OK;
}
23 changes: 23 additions & 0 deletions components/encoder/encoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ typedef enum {
RE_BTN_LONG_PRESSED = 2 //!< Button currently long pressed
} rotary_encoder_btn_state_t;

//Rotary encoder acceleration variables
typedef struct {
int64_t last_time;
uint16_t coeff;
} rotary_encoder_acceleration_t;
/**
* Rotary encoder descriptor
*/
Expand All @@ -68,6 +73,7 @@ typedef struct
size_t index;
uint64_t btn_pressed_time_us;
rotary_encoder_btn_state_t btn_state;
rotary_encoder_acceleration_t acceleration;
} rotary_encoder_t;

/**
Expand Down Expand Up @@ -115,6 +121,23 @@ esp_err_t rotary_encoder_add(rotary_encoder_t *re);
*/
esp_err_t rotary_encoder_remove(rotary_encoder_t *re);

/**
* @brief Enable acceleration on the rotary encoder
*
* @param re Encoder descriptor
* @param coeff Acceleration coefficient. Higher value means faster acceleration
* @return esp_err_t
*/
esp_err_t rotary_encoder_enable_acceleration(rotary_encoder_t *re, uint16_t coeff);

/**
* @brief Disable acceleration on the rotary encoder
*
* @param re Encoder descriptor
* @return `ESP_OK` on success
*/
esp_err_t rotary_encoder_disable_acceleration(rotary_encoder_t *re);

#ifdef __cplusplus
}
#endif
Expand Down
4 changes: 4 additions & 0 deletions examples/encoder/default/main/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,13 @@ void test(void *arg)
break;
case RE_ET_BTN_CLICKED:
ESP_LOGI(TAG, "Button clicked");
rotary_encoder_enable_acceleration(&re, 100);
ESP_LOGI(TAG, "Acceleration enabled");
break;
case RE_ET_BTN_LONG_PRESSED:
ESP_LOGI(TAG, "Looooong pressed button");
rotary_encoder_disable_acceleration(&re);
ESP_LOGI(TAG, "Acceleration disabled");
break;
case RE_ET_CHANGED:
val += e.diff;
Expand Down
Loading