Fork of the espurna firmware for `mhsw` switches
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

157 lines
4.5 KiB

  1. /*
  2. ENCODER MODULE
  3. Copyright (C) 2018-2019 by Xose Pérez <xose dot perez at gmail dot com>
  4. */
  5. #if ENCODER_SUPPORT && (LIGHT_PROVIDER != LIGHT_PROVIDER_NONE)
  6. #include "libs/Encoder.h"
  7. #include <vector>
  8. struct encoder_t {
  9. Encoder * encoder;
  10. unsigned char button_pin;
  11. unsigned char button_logic;
  12. unsigned char button_mode;
  13. unsigned char mode;
  14. unsigned char channel1; // default
  15. unsigned char channel2; // only if button defined and pressed
  16. };
  17. std::vector<encoder_t> _encoders;
  18. unsigned long _encoder_min_delta = 1;
  19. void _encoderConfigure() {
  20. _encoder_min_delta = getSetting("encMinDelta", ENCODER_MINIMUM_DELTA).toInt();
  21. if (!_encoder_min_delta) _encoder_min_delta = 1;
  22. // no need to reload objects right now
  23. if (_encoders.size()) return;
  24. // Clean previous encoders and re-add them
  25. for (auto& encoder : _encoders) {
  26. delete encoder.encoder;
  27. }
  28. _encoders.clear();
  29. // TODO: encEnable
  30. // TODO: implement reloading without re-allocating objects
  31. #if (ENCODER1_PIN1 != GPIO_NONE) && (ENCODER1_PIN2 != GPIO_NONE)
  32. {
  33. _encoders.push_back({
  34. new Encoder(ENCODER1_PIN1, ENCODER1_PIN2),
  35. ENCODER1_BUTTON_PIN, ENCODER1_BUTTON_LOGIC, ENCODER1_BUTTON_MODE, ENCODER1_MODE,
  36. ENCODER1_CHANNEL1, ENCODER1_CHANNEL2
  37. });
  38. }
  39. #endif
  40. #if (ENCODER2_PIN1 != GPIO_NONE) && (ENCODER2_PIN2 != GPIO_NONE)
  41. {
  42. _encoders.push_back({
  43. new Encoder(ENCODER2_PIN1, ENCODER2_PIN2),
  44. ENCODER2_BUTTON_PIN, ENCODER2_BUTTON_LOGIC, ENCODER2_BUTTON_MODE, ENCODER2_MODE,
  45. ENCODER2_CHANNEL1, ENCODER2_CHANNEL2
  46. });
  47. }
  48. #endif
  49. #if (ENCODER3_PIN1 != GPIO_NONE) && (ENCODER3_PIN2 != GPIO_NONE)
  50. {
  51. _encoders.push_back({
  52. new Encoder(ENCODER3_PIN1, ENCODER3_PIN2),
  53. ENCODER3_BUTTON_PIN, ENCODER3_BUTTON_LOGIC, ENCODER3_BUTTON_MODE, ENCODER3_MODE,
  54. ENCODER3_CHANNEL1, ENCODER3_CHANNEL2
  55. });
  56. }
  57. #endif
  58. #if (ENCODER4_PIN1 != GPIO_NONE) && (ENCODER4_PIN2 != GPIO_NONE)
  59. {
  60. _encoders.push_back({
  61. new Encoder(ENCODER4_PIN1, ENCODER4_PIN2),
  62. ENCODER4_BUTTON_PIN, ENCODER4_BUTTON_LOGIC, ENCODER4_BUTTON_MODE, ENCODER4_MODE,
  63. ENCODER4_CHANNEL1, ENCODER4_CHANNEL2
  64. });
  65. }
  66. #endif
  67. #if (ENCODER5_PIN1 != GPIO_NONE) && (ENCODER5_PIN2 != GPIO_NONE)
  68. {
  69. _encoders.push_back({
  70. new Encoder(ENCODER5_PIN1, ENCODER5_PIN2),
  71. ENCODER5_BUTTON_PIN, ENCODER5_BUTTON_LOGIC, ENCODER5_BUTTON_MODE, ENCODER5_MODE,
  72. ENCODER5_CHANNEL1, ENCODER5_CHANNEL2
  73. });
  74. }
  75. #endif
  76. // TODO: manage buttons through debounceevent?
  77. for (auto& encoder : _encoders) {
  78. if (GPIO_NONE != encoder.button_pin) {
  79. pinMode(encoder.button_pin, encoder.button_mode);
  80. }
  81. }
  82. }
  83. void _encoderLoop() {
  84. // for each encoder, read delta (read()) and map button action
  85. for (auto& encoder : _encoders) {
  86. const auto delta = encoder.encoder->read();
  87. encoder.encoder->write(0);
  88. if ((0 == delta) || (_encoder_min_delta > abs(delta))) continue;
  89. if (encoder.button_pin == GPIO_NONE) {
  90. // if there is no button, the encoder drives CHANNEL1
  91. lightChannelStep(encoder.channel1, delta);
  92. } else {
  93. // otherwise, use button based on encoder mode
  94. bool pressed = (digitalRead(encoder.button_pin) != encoder.button_logic);
  95. if (ENCODER_MODE_CHANNEL == encoder.mode) {
  96. // the button controls what channel we are changing
  97. lightChannelStep(pressed ? encoder.channel2 : encoder.channel1, delta);
  98. } if (ENCODER_MODE_RATIO == encoder.mode) {
  99. // the button controls if we are changing the channel ratio or the overall brightness
  100. if (pressed) {
  101. lightChannelStep(encoder.channel1, delta);
  102. lightChannelStep(encoder.channel2, -delta);
  103. } else {
  104. lightBrightnessStep(delta);
  105. }
  106. }
  107. }
  108. lightUpdate(true, true);
  109. }
  110. }
  111. // -----------------------------------------------------------------------------
  112. void encoderSetup() {
  113. // Configure encoders
  114. _encoderConfigure();
  115. // Main callbacks
  116. espurnaRegisterLoop(_encoderLoop);
  117. espurnaRegisterReload(_encoderConfigure);
  118. DEBUG_MSG_P(PSTR("[ENCODER] Number of encoders: %u\n"), _encoders.size());
  119. }
  120. #endif // ENCODER_SUPPORT && (LIGHT_PROVIDER != LIGHT_PROVIDER_NONE)