// 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 analog or digital inputs behind a multiplexer // controlled by a shift register. Stores an array reflecting the current value // of each input. A readout returns an "Event" object with the latest value of // the controller, a flag indicating how it changed with respect to the // previous value, and a timestamp. // // When event = EVENT_NONE, the time is the idle time (how many ms since an // event occurred). // When event != EVENT_NONE, the time is the time spent in the previous state. #ifndef AVRLIB_DEVICES_INPUT_ARRAY_H_ #define AVRLIB_DEVICES_INPUT_ARRAY_H_ #include "avrlib/size_to_type.h" #include "avrlib/time.h" namespace avrlib { enum InputEvent { EVENT_NONE = 0, EVENT_CHANGED = 1, }; template class InputArray { public: InputArray() { } typedef typename DataTypeForSize::Type T; typedef struct { uint8_t id; uint8_t event; // Could have been InputEvent but I want the extra byte. T value; uint32_t time; } Event; static void Init() { // No need to initialize anything - the first cycle of readouts will take // care of this. active_input_ = 0; starting_up_ = num_inputs * 2; Input::Init(); } static void Lock(uint16_t threshold) { for (uint8_t i = 0; i < num_inputs; ++i) { thresholds_[i] = threshold; } } static void Touch() { last_event_time_ = milliseconds(); } static Event Read() { Event e; e.id = active_input_; // Read a value from the ADC and check if something occurred. e.value = Input::Read(active_input_); uint8_t same; int16_t delta = static_cast(values_[active_input_]) - static_cast(e.value); if (delta < 0) { delta = -delta; } same = delta < thresholds_[active_input_]; uint32_t now = milliseconds(); e.time = now - last_event_time_; if (same) { e.event = EVENT_NONE; } else { // Since the input has been touched and the event has been recorded, // lower the threshold. thresholds_[active_input_] = low_threshold; values_[active_input_] = e.value; last_event_time_ = now; e.event = EVENT_CHANGED; } // The next call to Read() will read the next input. ++active_input_; if (active_input_ == num_inputs) { active_input_ = 0; } // During the first cycle, do not raise any event - just record the values. if (starting_up_) { --starting_up_; e.event = EVENT_NONE; e.time = 0; } return e; } static uint8_t active_input() { return active_input_; } private: static T values_[num_inputs]; static T thresholds_[num_inputs]; static uint8_t active_input_; static uint8_t starting_up_; static uint32_t last_event_time_; DISALLOW_COPY_AND_ASSIGN(InputArray); }; template typename InputArray::T InputArray::values_[num_inputs]; template typename InputArray::T InputArray::thresholds_[num_inputs]; template uint8_t InputArray::active_input_; template uint32_t InputArray::last_event_time_; template uint8_t InputArray::starting_up_; } // namespace avrlib #endif // AVRLIB_DEVICES_INPUT_ARRAY_H_