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.

152 lines
4.5KB

  1. // Copyright 2009 Olivier Gillet.
  2. //
  3. // Author: Olivier Gillet (ol.gillet@gmail.com)
  4. //
  5. // This program is free software: you can redistribute it and/or modify
  6. // it under the terms of the GNU General Public License as published by
  7. // the Free Software Foundation, either version 3 of the License, or
  8. // (at your option) any later version.
  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. // You should have received a copy of the GNU General Public License
  14. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. //
  16. // -----------------------------------------------------------------------------
  17. //
  18. // Controller for an array of switches read through a parallel-in > serial out
  19. // shift register. Includes debouncing.
  20. #ifndef AVRLIB_DEVICES_SWITCH_ARRAY_H_
  21. #define AVRLIB_DEVICES_SWITCH_ARRAY_H_
  22. #include "avrlib/devices/shift_register.h"
  23. #include "avrlib/size_to_type.h"
  24. #include "avrlib/time.h"
  25. namespace avrlib {
  26. struct SwitchState {
  27. uint8_t changed;
  28. uint8_t state;
  29. uint8_t debounced_state;
  30. uint32_t time;
  31. };
  32. struct KeyEvent {
  33. uint8_t id;
  34. uint8_t shifted;
  35. uint8_t hold_time;
  36. };
  37. template<typename Load, typename Clock, typename Data,
  38. uint8_t num_inputs, uint8_t shift = 0>
  39. class SwitchArray {
  40. typedef typename DataTypeForSize<num_inputs>::Type T;
  41. typedef ShiftRegisterInput<
  42. Load, Clock, Data,
  43. 8 * sizeof(T), LSB_FIRST> Register;
  44. public:
  45. SwitchArray() { }
  46. static void Init() {
  47. for (uint8_t i = 0; i < num_inputs; ++i) {
  48. switch_state_[i].state = 0xff;
  49. switch_state_[i].debounced_state = HIGH;
  50. switch_state_[i].time = 0;
  51. }
  52. last_event_time_ = 0;
  53. Register::Init();
  54. }
  55. static uint32_t last_event_time() { return last_event_time_; }
  56. static uint32_t idle_time() { return milliseconds() - last_event_time_; }
  57. static uint8_t shifted() { return switch_state_[shift].state == 0x00; }
  58. static void InhibitShiftRelease() { inhibit_shift_release_ = 1; }
  59. static const SwitchState& switch_state(uint8_t i) { return switch_state_[i]; }
  60. static uint8_t released() {
  61. for (uint8_t i = 0; i < num_inputs; ++i) {
  62. if (switch_state_[i].state == 0x7f &&
  63. (i != shift || !inhibit_shift_release_)) {
  64. return 1;
  65. }
  66. }
  67. return 0;
  68. }
  69. static void Touch() {
  70. last_event_time_ = milliseconds();
  71. }
  72. static inline KeyEvent key_event() {
  73. KeyEvent e;
  74. e.id = num_inputs;
  75. for (uint8_t i = 0; i < num_inputs; ++i) {
  76. if (switch_state_[i].state == 0x7f) {
  77. if (i == shift && inhibit_shift_release_) {
  78. inhibit_shift_release_ = 0;
  79. } else {
  80. e.id = i;
  81. e.shifted = shifted();
  82. e.hold_time = static_cast<uint16_t>(
  83. last_event_time_ - switch_state_[i].time) >> 8;
  84. if (e.shifted) {
  85. inhibit_shift_release_ = 1;
  86. }
  87. }
  88. }
  89. }
  90. return e;
  91. }
  92. static uint8_t Read() {
  93. T value = Register::Read();
  94. uint32_t now = milliseconds();
  95. T mask = 1 << (num_inputs - 1);
  96. for (uint8_t i = 0; i < num_inputs; ++i) {
  97. switch_state_[i].state <<= 1;
  98. if (value & mask) {
  99. switch_state_[i].state |= 1;
  100. }
  101. if (switch_state_[i].state == 0x80) {
  102. last_event_time_ = now;
  103. switch_state_[i].debounced_state = LOW;
  104. switch_state_[i].time = now;
  105. inhibit_shift_release_ = 0;
  106. } else if (switch_state_[i].state == 0x7f) {
  107. last_event_time_ = now;
  108. switch_state_[i].debounced_state = HIGH;
  109. }
  110. mask >>= 1;
  111. }
  112. }
  113. private:
  114. static uint32_t last_event_time_;
  115. static SwitchState switch_state_[num_inputs];
  116. static uint8_t inhibit_shift_release_;
  117. DISALLOW_COPY_AND_ASSIGN(SwitchArray);
  118. };
  119. template<typename Load, typename Clock, typename Data, uint8_t num_inputs,
  120. uint8_t shift>
  121. SwitchState SwitchArray<Load, Clock, Data, num_inputs,
  122. shift>::switch_state_[num_inputs];
  123. template<typename Load, typename Clock, typename Data, uint8_t num_inputs,
  124. uint8_t shift>
  125. uint32_t SwitchArray<Load, Clock, Data, num_inputs, shift>::last_event_time_;
  126. template<typename Load, typename Clock, typename Data, uint8_t num_inputs,
  127. uint8_t shift>
  128. uint8_t SwitchArray<Load, Clock, Data, num_inputs,
  129. shift>::inhibit_shift_release_;
  130. } // namespace avrlib
  131. #endif // AVRLIB_DEVICES_SWITCH_ARRAY_H_