logo

qmk_firmware

custom branch of QMK firmware git clone https://anongit.hacktivis.me/git/qmk_firmware.git

opt_encoder_tiny.c (4001B)


  1. /* Copyright 2023 Leorize <leorize+oss@disroot.org>
  2. * Copyright 2011 Ben Buxton <bb@cactii.net>
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 3 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. #include "opt_encoder.h"
  18. #include <stdbool.h>
  19. #include <stdint.h>
  20. /* An extremely simple implementation of the encoder:
  21. *
  22. * For read out, the mechanism mimics that of a Schmitt trigger, with
  23. * statically defined high/low thresholds used instead of computing
  24. * one at runtime.
  25. *
  26. * The advantage of this approach is computing less in the decoder
  27. * implementation and allow the state to be measured before the wheel
  28. * moved.
  29. *
  30. * Compared to opt_encoder_simple.c, the use of an intermediary state
  31. * reduces sensitivity and de-sensitize against tiny movements caused
  32. * when lifting finger off the wheel.
  33. *
  34. * For turning decoded values into rotation, an algorithm inspired by
  35. * http://www.buxtronix.net/2011/10/rotary-encoders-done-properly.html
  36. * is employed.
  37. */
  38. #if !defined(ENCODER_LOW_THRES_A) || !defined(ENCODER_HIGH_THRES_A)
  39. # error "The thresholds for phototransistors A is not defined in config.h"
  40. #endif
  41. #if !defined(ENCODER_LOW_THRES_B) || !defined(ENCODER_HIGH_THRES_B)
  42. # error "The thresholds for phototransistors B is not defined in config.h"
  43. #endif
  44. /*
  45. * Sample values, captured for a Ploopy Mini Trackball
  46. *
  47. * The following min-max values was captured by aggregating data recorded
  48. * when debug_encoder is enabled:
  49. *
  50. * A: min: 0, max: 214
  51. * B: min: 0, max: 204
  52. *
  53. * The threshold specified is then defined at the 1/4 and the 3/4 points.
  54. *
  55. * As these values might vary between units, you're encouraged to
  56. * measure your own.
  57. */
  58. #if 0
  59. # define ENCODER_LOW_THRES_A 53
  60. # define ENCODER_HIGH_THRES_A 161
  61. # define ENCODER_LOW_THRES_B 52
  62. # define ENCODER_HIGH_THRES_B 153
  63. #endif
  64. /* Utilities for composing the encoder state */
  65. #define MAKE_STATE(HI_A, HI_B) (((uint8_t)((HI_A) & 0x1) << 1) | ((uint8_t)((HI_B) & 0x1)))
  66. #define STATE_A(st) ((st & 0x2) >> 1)
  67. #define STATE_B(st) (st & 0x1)
  68. typedef enum {
  69. START,
  70. DOWN_BEGIN,
  71. UP_BEGIN,
  72. START_MID,
  73. DOWN_BEGIN_MID,
  74. UP_BEGIN_MID,
  75. STATE_MASK = 0xf, /* 0b1111 */
  76. EMIT_UP = 0x10,
  77. EMIT_UP_MID = EMIT_UP & START_MID,
  78. EMIT_DOWN = 0x80,
  79. EMIT_DOWN_MID = EMIT_DOWN & START_MID,
  80. EMIT_MASK = 0xf0
  81. } encoder_state_t;
  82. static encoder_state_t state;
  83. static uint8_t encState;
  84. static const uint8_t transitions[] = {
  85. // clang-format off
  86. // START -> 00, 01, 10, 11
  87. START, DOWN_BEGIN, UP_BEGIN, START_MID,
  88. // DOWN_BEGIN -> 00, 01, 10, 11
  89. START, DOWN_BEGIN, START, EMIT_DOWN_MID,
  90. // UP_BEGIN -> 00, 01, 10, 11
  91. START, START, UP_BEGIN, EMIT_UP_MID,
  92. // START_MID -> 00, 01, 10, 11
  93. START, UP_BEGIN_MID, DOWN_BEGIN_MID, START_MID,
  94. // DOWN_BEGIN_MID -> 00, 01, 10, 11
  95. EMIT_DOWN, START_MID, DOWN_BEGIN_MID, START_MID,
  96. // UP_BEGIN_MID -> 00, 01, 10, 11
  97. EMIT_UP, UP_BEGIN_MID, START_MID, START_MID,
  98. // clang-format on
  99. };
  100. void opt_encoder_init(void) {
  101. state = START;
  102. encState = 0;
  103. }
  104. int8_t opt_encoder_handler(uint16_t encA, uint16_t encB) {
  105. encState = MAKE_STATE((STATE_A(encState) & (encA > ENCODER_LOW_THRES_A)) | (encA > ENCODER_HIGH_THRES_A), (STATE_B(encState) & (encB > ENCODER_LOW_THRES_B)) | (encB > ENCODER_HIGH_THRES_B));
  106. state = transitions[((state & STATE_MASK) << 2) + encState];
  107. return state & EMIT_MASK;
  108. }