// 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 digital outputs behind a shift register. This // class maintains an internal array reflecting the status of each output. A // call to Output() writes the content of the array to a shift register, if the // content of the array has changed. // // The num_intensity_level template parameter allows basic PWM on the output // of the array. More specifically, each call to Output() will write a 0 or 1 // depending on the "analog" level. This can be used for example to adjust // the brightness of a LED. More precisely, this is achieved in a PWM-like way // (we cycle N times through the array and at time i, we power only the outputs // with level above i/N). #ifndef AVRLIB_DEVICES_OUTPUT_ARRAY_H_ #define AVRLIB_DEVICES_OUTPUT_ARRAY_H_ #include #include "avrlib/devices/shift_register.h" #include "avrlib/size_to_type.h" namespace avrlib { // A generic, not very efficient implementation, especially for small bit // depths. template class OutputArray { public: OutputArray() { } typedef ShiftRegisterOutput Register; typedef typename DataTypeForSize::Type Value; typedef typename DataTypeForSize::Type Index; static inline void Init() { if (safe) { memset(values_, 0, sizeof(values_)); cycle_ = 0; } Register::Init(); } static inline void set_value(Index output_index, Value intensity) { values_[output_index] = intensity; } static inline Value value(Index output_index) { return values_[output_index]; } static inline void ShiftOutByte(uint8_t v) { Register::ShiftOut(v); } static inline void Begin() { Register::Begin(); } static inline void End() { Register::End(); } static inline void Clear() { memset(values_, 0, sizeof(values_)); } static inline void ShiftOut() { Index c = 0; Index bit = 1; for (Index i = 0; i < size; ++i) { if (values_[i] > cycle_ || values_[i] == ((1 << bit_depth) - 1)) { c |= bit; } bit <<= 1; } cycle_ = (cycle_ + 1) & ((1 << bit_depth) - 1); Register::ShiftOut(c); } static inline void Write() { Begin(); ShiftOut(); End(); } private: static Value values_[size]; static Value cycle_; DISALLOW_COPY_AND_ASSIGN(OutputArray); }; template typename OutputArray::Value OutputArray::values_[size]; template typename OutputArray::Value OutputArray::cycle_; // A specialization with only two states. In this case, we can write data to the // shift register only when a bit has changed in the array - there's no pseudo // PWM brightness modulation. template class OutputArray { typedef ShiftRegisterOutput Register; public: typedef typename DataTypeForSize::Type T; OutputArray() { } static inline void Init() { if (safe) { last_bits_ = 1; bits_ = 0; } Register::Init(); } static inline void set_value(uint8_t output_index, uint8_t intensity) { T mask = T(1) << output_index; if (intensity) { bits_ |= mask; } else { bits_ &= ~mask; } } static inline void Clear() { bits_ = 0; } static inline uint8_t value(uint8_t output_index) { T mask = T(1) << output_index; return T(bits_ & mask) ? 1 : 0; } static inline void ShiftOutByte(uint8_t v) { Register::ShiftOut(v); } static inline void Begin() { Register::Begin(); } static inline void End() { Register::End(); } static inline void ShiftOut() { if (bits_ == last_bits_) { return; } Register::ShiftOut(bits_); last_bits_ = bits_; } static inline void Write() { Begin(); ShiftOut(); End(); } private: static T bits_; static T last_bits_; DISALLOW_COPY_AND_ASSIGN(OutputArray); }; template typename OutputArray::T OutputArray::bits_; template typename OutputArray::T OutputArray::last_bits_; } // namespace avrlib #endif // AVRLIB_DEVICES_OUTPUT_ARRAY_H_