From c0dbd3d065897cffbbd93267d940550582d4e518 Mon Sep 17 00:00:00 2001 From: Daniil Kalamin <56044849+dakalamin@users.noreply.github.com> Date: Wed, 9 Jul 2025 04:43:14 +0300 Subject: [PATCH 1/6] Prefer existing 'flags' methods to generic bitwise ops --- src/core/VirtEncoder.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/core/VirtEncoder.h b/src/core/VirtEncoder.h index de12b0a..6a857d3 100644 --- a/src/core/VirtEncoder.h +++ b/src/core/VirtEncoder.h @@ -29,12 +29,13 @@ class VirtEncoder { // ====================== SET ====================== // инвертировать направление энкодера void setEncReverse(const bool rev) { - rev ? ef.set(EB_REV) : ef.clear(EB_REV); + ef.write(EB_REV, rev); } // установить тип энкодера (EB_STEP4_LOW, EB_STEP4_HIGH, EB_STEP2, EB_STEP1) void setEncType(const uint8_t type) { - ef.flags = (ef.flags & 0b11111100) | type; + ef.clear(0b11111100); + ef.set(type); } // использовать обработку энкодера в прерывании From 3bcdc14aa9eda7787e127b7d12e29901410dad42 Mon Sep 17 00:00:00 2001 From: Daniil Kalamin <56044849+dakalamin@users.noreply.github.com> Date: Wed, 9 Jul 2025 06:35:33 +0300 Subject: [PATCH 2/6] Extract special case of 'eq' method - 'all' --- src/core/VirtButton.h | 6 +++--- src/core/flags.h | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/core/VirtButton.h b/src/core/VirtButton.h index ec81141..9b70abd 100644 --- a/src/core/VirtButton.h +++ b/src/core/VirtButton.h @@ -206,7 +206,7 @@ class VirtButton { // кнопка отпущена (в любом случае) [событие] bool release() { - return bf.eq(EB_REL_R | EB_REL, EB_REL_R | EB_REL); + return bf.all(EB_REL_R | EB_REL); } // кнопка отпущена (в любом случае) с предварительными кликами [событие] @@ -246,7 +246,7 @@ class VirtButton { // кнопка удерживается (больше таймаута) [состояние] bool holding() { - return bf.eq(EB_PRS | EB_HLD, EB_PRS | EB_HLD); + return bf.all(EB_PRS | EB_HLD); } // кнопка удерживается (больше таймаута) с предварительными кликами [состояние] @@ -304,7 +304,7 @@ class VirtButton { // кнопка отпущена после импульсного удержания с предварительными кликами [событие] bool releaseStep(const uint8_t num) { - return clicks == num && bf.eq(EB_CLKS_R | EB_STP, EB_CLKS_R | EB_STP); + return clicks == num && bf.all(EB_CLKS_R | EB_STP); } // кнопка отпущена после удержания или импульсного удержания [событие] diff --git a/src/core/flags.h b/src/core/flags.h index 9d8ea57..4e389de 100644 --- a/src/core/flags.h +++ b/src/core/flags.h @@ -25,6 +25,9 @@ struct Flags { inline bool eq(const T x, const T y) __attribute__((always_inline)) { return (flags & x) == y; } + inline bool all(const T x) __attribute__((always_inline)) { + return eq(x, x); + } }; } // namespace encb \ No newline at end of file From 059b0612349d8edc015eb26ed3d485cbf088bee6 Mon Sep 17 00:00:00 2001 From: Daniil Kalamin <56044849+dakalamin@users.noreply.github.com> Date: Wed, 9 Jul 2025 06:37:25 +0300 Subject: [PATCH 3/6] Remove redundant conditions --- src/core/VirtButton.h | 8 +++----- src/core/VirtEncButton.h | 4 ++-- src/core/VirtEncoder.h | 2 +- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/core/VirtButton.h b/src/core/VirtButton.h index 9b70abd..aa693f7 100644 --- a/src/core/VirtButton.h +++ b/src/core/VirtButton.h @@ -165,12 +165,10 @@ class VirtButton { // принудительно сбросить флаги событий void clear(bool resetTout = false) { - if (resetTout && bf.read(EB_TOUT)) bf.clear(EB_TOUT); + if (resetTout) bf.clear(EB_TOUT); if (bf.read(EB_CLKS_R)) clicks = 0; - if (bf.read(EB_CLKS_R | EB_STP_R | EB_PRS_R | EB_HLD_R | EB_REL_R)) { bf.clear(EB_CLKS_R | EB_STP_R | EB_PRS_R | EB_HLD_R | EB_REL_R); } - } // игнорировать все события до отпускания кнопки void skipEvents() { @@ -564,7 +562,7 @@ class VirtButton { } else if (clicks) { // есть клики, ждём EB_CLICK_TIME if (bf.read(EB_HLD | EB_STP) || deb >= EB_GET_CLICK_TIME()) bf.set(EB_CLKS_R); // флаг clicks #ifndef EB_NO_FOR - else if (ftmr) ftmr = 0; + else ftmr = 0; #endif } else if (bf.read(EB_BUSY)) { bf.clear(EB_HLD | EB_STP | EB_BUSY); @@ -574,7 +572,7 @@ class VirtButton { #endif tmr = ms; // test!! } - if (bf.read(EB_DEB)) bf.clear(EB_DEB); // сброс ожидания нажатия (дебаунс) + bf.clear(EB_DEB); // сброс ожидания нажатия (дебаунс) } return bf.read(EB_CLKS_R | EB_PRS_R | EB_HLD_R | EB_STP_R | EB_REL_R); } diff --git a/src/core/VirtEncButton.h b/src/core/VirtEncButton.h index a596e75..474403d 100644 --- a/src/core/VirtEncButton.h +++ b/src/core/VirtEncButton.h @@ -168,8 +168,8 @@ class VirtEncButton : public VirtButton, public VirtEncoder { if (encf) { if (bf.read(EB_PRS)) bf.set(EB_EHLD); // зажать энкодер else clicks = 0; - if (!bf.read(EB_TOUT)) bf.set(EB_TOUT); // таймаут - ef.set(EB_ETRN_R); // флаг поворота + bf.set(EB_TOUT); // таймаут + ef.set(EB_ETRN_R); // флаг поворота } return VirtButton::tickRaw(btn) | encf; } diff --git a/src/core/VirtEncoder.h b/src/core/VirtEncoder.h index 6a857d3..bf60234 100644 --- a/src/core/VirtEncoder.h +++ b/src/core/VirtEncoder.h @@ -50,7 +50,7 @@ class VirtEncoder { // сбросить флаги событий void clear() { - if (ef.read(EB_ETRN_R)) ef.clear(EB_ETRN_R); + ef.clear(EB_ETRN_R); } // ====================== ОПРОС ====================== From 13c4bf7d5d316de50cd5a530a5ef35e784d5cc0e Mon Sep 17 00:00:00 2001 From: Daniil Kalamin <56044849+dakalamin@users.noreply.github.com> Date: Wed, 9 Jul 2025 08:04:31 +0300 Subject: [PATCH 4/6] Optimize and simplify --- src/core/MultiButton.h | 12 ++---------- src/core/VirtButton.h | 2 +- src/core/VirtEncButton.h | 22 ++++++++++------------ src/core/VirtEncoder.h | 7 +------ 4 files changed, 14 insertions(+), 29 deletions(-) diff --git a/src/core/MultiButton.h b/src/core/MultiButton.h index a81778f..f50d33d 100644 --- a/src/core/MultiButton.h +++ b/src/core/MultiButton.h @@ -12,18 +12,10 @@ class MultiButton : public VirtButton { b0.tickRaw(); b1.tickRaw(); - if (bf.read(EB_BOTH)) { - if (!b0.pressing() && !b1.pressing()) bf.clear(EB_BOTH); - if (!b0.pressing()) b0.reset(); - if (!b1.pressing()) b1.reset(); - b0.clear(); - b1.clear(); - return VirtButton::tick(true); - } else { - if (b0.pressing() && b1.pressing()) bf.set(EB_BOTH); + if (!bf.read(EB_BOTH)) { b0.call(); b1.call(); - return VirtButton::tick(false); } + return VirtButton::tick(b0, b1); } }; \ No newline at end of file diff --git a/src/core/VirtButton.h b/src/core/VirtButton.h index aa693f7..cdf9d29 100644 --- a/src/core/VirtButton.h +++ b/src/core/VirtButton.h @@ -317,7 +317,7 @@ class VirtButton { // кнопка ожидает повторных кликов [состояние] bool waiting() { - return clicks && bf.eq(EB_PRS | EB_REL, 0); + return clicks && !bf.read(EB_PRS | EB_REL); } // идёт обработка [состояние] diff --git a/src/core/VirtEncButton.h b/src/core/VirtEncButton.h index 474403d..8387efc 100644 --- a/src/core/VirtEncButton.h +++ b/src/core/VirtEncButton.h @@ -133,7 +133,7 @@ class VirtEncButton : public VirtButton, public VirtEncoder { private: bool _checkFast() { uint16_t ms = EB_uptime(); - bool f = ms - tmr < EB_FAST_T; + bool f = (ms - tmr) < EB_FAST_T; tmr = ms; return f; } @@ -146,31 +146,29 @@ class VirtEncButton : public VirtButton, public VirtEncoder { } bool _tickRaw(bool btn, int8_t estate = 0) { - bool encf = 0; #ifdef EB_NO_BUFFER if (ef.read(EB_ISR_F)) { ef.clear(EB_ISR_F); - encf = 1; } #else if (ebuffer) { ef.write(EB_DIR, ebuffer & 0b10); ef.write(EB_FAST, ebuffer & 0b100); ebuffer >>= 3; - encf = 1; } #endif else if (estate) { ef.write(EB_DIR, estate > 0); ef.write(EB_FAST, _checkFast()); - encf = 1; } - if (encf) { - if (bf.read(EB_PRS)) bf.set(EB_EHLD); // зажать энкодер - else clicks = 0; - bf.set(EB_TOUT); // таймаут - ef.set(EB_ETRN_R); // флаг поворота - } - return VirtButton::tickRaw(btn) | encf; + else return VirtButton::tickRaw(btn); + + if (bf.read(EB_PRS)) bf.set(EB_EHLD); // зажать энкодер + else clicks = 0; + bf.set(EB_TOUT); // таймаут + ef.set(EB_ETRN_R); // флаг поворота + + VirtButton::tickRaw(btn); + return true; } }; \ No newline at end of file diff --git a/src/core/VirtEncoder.h b/src/core/VirtEncoder.h index bf60234..2a306f1 100644 --- a/src/core/VirtEncoder.h +++ b/src/core/VirtEncoder.h @@ -97,12 +97,7 @@ class VirtEncoder { int8_t state = tickRaw(); if (state) return state; - state = pollEnc(e0, e1); - if (state) { - ef.write(EB_DIR, state > 0); - ef.set(EB_ETRN_R); - } - return state; + return tickISR(e0, e1); } // опросить энкодер без сброса события поворота (сам опрос в прерывании) From 4bbbe2b700795188a1234dffb24b954258e26a09 Mon Sep 17 00:00:00 2001 From: Daniil Kalamin <56044849+dakalamin@users.noreply.github.com> Date: Wed, 9 Jul 2025 08:18:53 +0300 Subject: [PATCH 5/6] Refactor defines and magic values --- src/core/VirtButton.h | 9 +++++---- src/core/VirtEncButton.h | 22 ++++++++++++---------- src/core/VirtEncoder.h | 4 ++-- 3 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/core/VirtButton.h b/src/core/VirtButton.h index cdf9d29..2e602de 100644 --- a/src/core/VirtButton.h +++ b/src/core/VirtButton.h @@ -86,6 +86,7 @@ enum class EBAction { #define EB_HLD_R (1 << 2) #define EB_STP_R (1 << 3) #define EB_REL_R (1 << 4) +#define EB_ALL_R (EB_CLKS_R | EB_PRS_R | EB_HLD_R | EB_STP_R | EB_REL_R) #define EB_PRS (1 << 5) #define EB_HLD (1 << 6) @@ -167,8 +168,8 @@ class VirtButton { void clear(bool resetTout = false) { if (resetTout) bf.clear(EB_TOUT); if (bf.read(EB_CLKS_R)) clicks = 0; - bf.clear(EB_CLKS_R | EB_STP_R | EB_PRS_R | EB_HLD_R | EB_REL_R); - } + bf.clear(EB_ALL_R); + } // игнорировать все события до отпускания кнопки void skipEvents() { @@ -327,7 +328,7 @@ class VirtButton { // было действие с кнопки, вернёт код события [событие] uint16_t action() { - switch (bf.mask(0b111111111)) { + switch (bf.mask(EB_ALL_R | EB_PRS | EB_HLD | EB_STP | EB_REL)) { case (EB_PRS | EB_PRS_R): return EB_PRESS; case (EB_PRS | EB_HLD | EB_HLD_R): return EB_HOLD; case (EB_PRS | EB_HLD | EB_STP | EB_STP_R): return EB_STEP; @@ -574,6 +575,6 @@ class VirtButton { } bf.clear(EB_DEB); // сброс ожидания нажатия (дебаунс) } - return bf.read(EB_CLKS_R | EB_PRS_R | EB_HLD_R | EB_STP_R | EB_REL_R); + return bf.read(EB_ALL_R); } }; diff --git a/src/core/VirtEncButton.h b/src/core/VirtEncButton.h index 8387efc..92d44ef 100644 --- a/src/core/VirtEncButton.h +++ b/src/core/VirtEncButton.h @@ -9,6 +9,11 @@ #define EB_FAST_T (EB_FAST_TIME) #endif +#define EB_BUF_TURN (1 << 0) +#define EB_BUF_DIR (1 << 1) +#define EB_BUF_FAST (1 << 2) +#define EB_BUF_LEN 3 + // базовый клас энкодера с кнопкой class VirtEncButton : public VirtButton, public VirtEncoder { public: @@ -83,13 +88,10 @@ class VirtEncButton : public VirtButton, public VirtEncoder { ef.write(EB_DIR, state > 0); ef.write(EB_FAST, _checkFast()); #else - for (uint8_t i = 0; i < 15; i += 3) { - if (!(ebuffer & (1 << i))) { - ebuffer |= (1 << i); // turn - if (state > 0) ebuffer |= (1 << (i + 1)); // dir - if (_checkFast()) ebuffer |= (1 << (i + 2)); // fast - break; - } + for (uint8_t i = 0; i < 15; i += EB_BUF_LEN) { + if (ebuffer & (EB_BUF_TURN << i)) continue; + ebuffer |= (EB_BUF_TURN | ((state > 0) * EB_BUF_DIR) | (_checkFast() * EB_BUF_FAST)) << i; + break; } #endif } @@ -152,9 +154,9 @@ class VirtEncButton : public VirtButton, public VirtEncoder { } #else if (ebuffer) { - ef.write(EB_DIR, ebuffer & 0b10); - ef.write(EB_FAST, ebuffer & 0b100); - ebuffer >>= 3; + ef.write(EB_DIR, ebuffer & EB_BUF_DIR); + ef.write(EB_FAST, ebuffer & EB_BUF_FAST); + ebuffer >>= EB_BUF_LEN; } #endif else if (estate) { diff --git a/src/core/VirtEncoder.h b/src/core/VirtEncoder.h index 2a306f1..7bae175 100644 --- a/src/core/VirtEncoder.h +++ b/src/core/VirtEncoder.h @@ -11,7 +11,7 @@ #define EB_STEP1 3 // ===================== FLAGS ====================== -#define EB_TYPE (1 << 0) +#define EB_TYPE ((1 << 0) | (1 << 1)) #define EB_REV (1 << 2) #define EB_FAST (1 << 3) #define EB_DIR (1 << 4) @@ -34,7 +34,7 @@ class VirtEncoder { // установить тип энкодера (EB_STEP4_LOW, EB_STEP4_HIGH, EB_STEP2, EB_STEP1) void setEncType(const uint8_t type) { - ef.clear(0b11111100); + ef.clear(~EB_TYPE); ef.set(type); } From 91873407f000db30cf0d1bb03fea0827fe9f9e0b Mon Sep 17 00:00:00 2001 From: Daniil Kalamin <56044849+dakalamin@users.noreply.github.com> Date: Wed, 9 Jul 2025 08:22:18 +0300 Subject: [PATCH 6/6] Refactor - early return --- src/core/VirtEncButton.h | 20 +++++++-------- src/core/VirtEncoder.h | 54 +++++++++++++++++++--------------------- 2 files changed, 36 insertions(+), 38 deletions(-) diff --git a/src/core/VirtEncButton.h b/src/core/VirtEncButton.h index 92d44ef..94e75e3 100644 --- a/src/core/VirtEncButton.h +++ b/src/core/VirtEncButton.h @@ -82,19 +82,19 @@ class VirtEncButton : public VirtButton, public VirtEncoder { // обработка в прерывании (только энкодер). Вернёт 0 в покое, 1 или -1 при повороте int8_t tickISR(const bool e0, const bool e1) { int8_t state = VirtEncoder::pollEnc(e0, e1); - if (state) { + if (!state) return state; + #ifdef EB_NO_BUFFER - ef.set(EB_ISR_F); - ef.write(EB_DIR, state > 0); - ef.write(EB_FAST, _checkFast()); + ef.set(EB_ISR_F); + ef.write(EB_DIR, state > 0); + ef.write(EB_FAST, _checkFast()); #else - for (uint8_t i = 0; i < 15; i += EB_BUF_LEN) { - if (ebuffer & (EB_BUF_TURN << i)) continue; - ebuffer |= (EB_BUF_TURN | ((state > 0) * EB_BUF_DIR) | (_checkFast() * EB_BUF_FAST)) << i; - break; - } -#endif + for (uint8_t i = 0; i < 15; i += EB_BUF_LEN) { + if (ebuffer & (EB_BUF_TURN << i)) continue; + ebuffer |= (EB_BUF_TURN | ((state > 0) * EB_BUF_DIR) | (_checkFast() * EB_BUF_FAST)) << i; + break; } +#endif return state; } diff --git a/src/core/VirtEncoder.h b/src/core/VirtEncoder.h index 7bae175..164d861 100644 --- a/src/core/VirtEncoder.h +++ b/src/core/VirtEncoder.h @@ -102,41 +102,39 @@ class VirtEncoder { // опросить энкодер без сброса события поворота (сам опрос в прерывании) int8_t tickRaw() { - if (ef.read(EB_ISR_F)) { - ef.clear(EB_ISR_F); - ef.set(EB_ETRN_R); - return dir(); - } - return 0; + if (!ef.read(EB_ISR_F)) return 0; + + ef.clear(EB_ISR_F); + ef.set(EB_ETRN_R); + return dir(); } // POLL // опросить энкодер без установки события поворота (быстрее). Вернёт 1 или -1 при вращении, 0 при остановке int8_t pollEnc(const bool e0, const bool e1) { - if (p0 ^ p1 ^ e0 ^ e1) { - (p1 ^ e0) ? ++epos : --epos; - p0 = e0, p1 = e1; - if (!epos) return 0; - - switch (ef.mask(0b11)) { - case EB_STEP4_LOW: - if (!(e0 & e1)) return 0; // skip 01, 10, 00 - break; - case EB_STEP4_HIGH: - if (e0 | e1) return 0; // skip 01, 10, 11 - break; - case EB_STEP2: - if (e0 ^ e1) return 0; // skip 10 01 - break; - } - int8_t state = ((epos > 0) ^ ef.read(EB_REV)) ? -1 : 1; - epos = 0; + if (!(p0 ^ p1 ^ e0 ^ e1)) return 0; + + (p1 ^ e0) ? ++epos : --epos; + p0 = e0, p1 = e1; + if (!epos) return 0; + + switch (ef.mask(0b11)) { + case EB_STEP4_LOW: + if (!(e0 & e1)) return 0; // skip 01, 10, 00 + break; + case EB_STEP4_HIGH: + if (e0 | e1) return 0; // skip 01, 10, 11 + break; + case EB_STEP2: + if (e0 ^ e1) return 0; // skip 10 01 + break; + } + int8_t state = ((epos > 0) ^ ef.read(EB_REV)) ? -1 : 1; + epos = 0; #ifndef EB_NO_COUNTER - counter += state; + counter += state; #endif - return state; - } - return 0; + return state; } #ifndef EB_NO_COUNTER