// Copyright 2009 Olivier Gillet. // // Author: Olivier Gillet (ol.gillet@gmail.com) // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see . // // ----------------------------------------------------------------------------- // // Controller for an array of switches read through a parallel-in > serial out // shift register. Includes debouncing. #ifndef AVRLIB_DEVICES_SWITCH_ARRAY_H_ #define AVRLIB_DEVICES_SWITCH_ARRAY_H_ #include "avrlib/devices/shift_register.h" #include "avrlib/size_to_type.h" #include "avrlib/time.h" namespace avrlib { struct SwitchState { uint8_t changed; uint8_t state; uint8_t debounced_state; uint32_t time; }; struct KeyEvent { uint8_t id; uint8_t shifted; uint8_t hold_time; }; template class SwitchArray { typedef typename DataTypeForSize::Type T; typedef ShiftRegisterInput< Load, Clock, Data, 8 * sizeof(T), LSB_FIRST> Register; public: SwitchArray() { } static void Init() { for (uint8_t i = 0; i < num_inputs; ++i) { switch_state_[i].state = 0xff; switch_state_[i].debounced_state = HIGH; switch_state_[i].time = 0; } last_event_time_ = 0; Register::Init(); } static uint32_t last_event_time() { return last_event_time_; } static uint32_t idle_time() { return milliseconds() - last_event_time_; } static uint8_t shifted() { return switch_state_[shift].state == 0x00; } static void InhibitShiftRelease() { inhibit_shift_release_ = 1; } static const SwitchState& switch_state(uint8_t i) { return switch_state_[i]; } static uint8_t released() { for (uint8_t i = 0; i < num_inputs; ++i) { if (switch_state_[i].state == 0x7f && (i != shift || !inhibit_shift_release_)) { return 1; } } return 0; } static void Touch() { last_event_time_ = milliseconds(); } static inline KeyEvent key_event() { KeyEvent e; e.id = num_inputs; for (uint8_t i = 0; i < num_inputs; ++i) { if (switch_state_[i].state == 0x7f) { if (i == shift && inhibit_shift_release_) { inhibit_shift_release_ = 0; } else { e.id = i; e.shifted = shifted(); e.hold_time = static_cast( last_event_time_ - switch_state_[i].time) >> 8; if (e.shifted) { inhibit_shift_release_ = 1; } } } } return e; } static uint8_t Read() { T value = Register::Read(); uint32_t now = milliseconds(); T mask = 1 << (num_inputs - 1); for (uint8_t i = 0; i < num_inputs; ++i) { switch_state_[i].state <<= 1; if (value & mask) { switch_state_[i].state |= 1; } if (switch_state_[i].state == 0x80) { last_event_time_ = now; switch_state_[i].debounced_state = LOW; switch_state_[i].time = now; inhibit_shift_release_ = 0; } else if (switch_state_[i].state == 0x7f) { last_event_time_ = now; switch_state_[i].debounced_state = HIGH; } mask >>= 1; } } private: static uint32_t last_event_time_; static SwitchState switch_state_[num_inputs]; static uint8_t inhibit_shift_release_; DISALLOW_COPY_AND_ASSIGN(SwitchArray); }; template SwitchState SwitchArray::switch_state_[num_inputs]; template uint32_t SwitchArray::last_event_time_; template uint8_t SwitchArray::inhibit_shift_release_; } // namespace avrlib #endif // AVRLIB_DEVICES_SWITCH_ARRAY_H_