# HG changeset patch # User sl # Date 1402991720 -7200 # Node ID 0f874d9e4130921795f48c35c4ee9596f9cbcea5 First contrib taken from Qt MiniDisplayManager. diff -r 000000000000 -r 0f874d9e4130 BitArray.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/BitArray.cpp Tue Jun 17 09:55:20 2014 +0200 @@ -0,0 +1,1020 @@ +/*************************************************************************** +* Arrays of Arbitrary Bit Length +* +* File : bitarray.cpp +* Purpose : Provides object with methods for creation and manipulation of +* arbitrary length arrays of bits. +* +* Bit arrays are implemented as vectors of unsigned chars. Bit +* 0 is the MSB of char 0, and the last bit is the least +* significant (non-spare) bit of the last unsigned char. +* +* Example: array of 20 bits (0 through 19) with 8 bit unsigned +* chars requires 3 unsigned chars (0 through 2) to +* store all the bits. +* +* char 0 1 2 +* +--------+--------+--------+ +* | | | | +* +--------+--------+--------+ +* bit 01234567 8911111111111XXXX +* 012345 6789 +* +* Author : Michael Dipperstein +* Date : July 23, 2004 +* +**************************************************************************** +* HISTORY +* +* $Id: bitarray.cpp,v 1.7 2010/02/04 03:31:43 michael Exp $ +* $Log: bitarray.cpp,v $ +* Revision 1.7 2010/02/04 03:31:43 michael +* Replaced vector with an array of unsigned char. +* +* Made updates for GCC 4.4. +* +* Revision 1.5 2007/08/06 05:23:29 michael +* Updated for LGPL Version 3. +* +* All methods that don't modify object have been made +* const to increase functionality of const bit_array_c. +* +* All assignment operators return a reference to the object being assigned a value so that operator chaining will work. +* +* Added >> and << operators. +* +* Revision 1.3 2006/04/30 23:34:07 michael +* Improved performance by incorporating Benjamin Schindler's +* changes to pass arguments as a reference. +* +* Revision 1.2 2004/08/05 22:16:49 michael +* Add overloads for bitwise operators returning values. +* Add a more natural looking way to set bit values. +* +* Revision 1.1.1.1 2004/08/04 13:28:20 michael +* bit_array_c +* +**************************************************************************** +* +* Bitarray: An ANSI C++ class for manipulating arbitrary length bit arrays +* Copyright (C) 2004, 2006-2007, 2010 by +* Michael Dipperstein (mdipper@alumni.engr.ucsb.edu) +* +* This file is part of the bit array library. +* +* The bit array library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public License as +* published by the Free Software Foundation; either version 3 of the +* License, or (at your option) any later version. +* +* The bit array library 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 Lesser +* General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this program. If not, see . +* +***************************************************************************/ + +/*************************************************************************** +* INCLUDED FILES +***************************************************************************/ +#include +#include +#include "bitarray.h" + +using namespace std; + +/*************************************************************************** +* MACROS +***************************************************************************/ + +/* make CHAR_BIT 8 if it's not defined in limits.h */ +#ifndef CHAR_BIT +#warning CHAR_BIT not defined. Assuming 8 bits. +#define CHAR_BIT 8 +#endif + +/* position of bit within character */ +#define BIT_CHAR(bit) ((bit) / CHAR_BIT) + +/* array index for character containing bit */ +//SL: We had to change that macro since bits in our frame buffer are the other way around +//TODO: Find a solution to tackle that problem +//#define BIT_IN_CHAR(bit) (1 << (CHAR_BIT - 1 - ((bit) % CHAR_BIT))) +#define BIT_IN_CHAR(bit) (1 << (((bit) % CHAR_BIT))) + +/* number of characters required to contain number of bits */ +#define BITS_TO_CHARS(bits) ((((bits) - 1) / CHAR_BIT) + 1) + +/* most significant bit in a character */ +#define MS_BIT (1 << (CHAR_BIT - 1)) + +/*************************************************************************** +* METHODS +***************************************************************************/ + +/*************************************************************************** +* Method : bit_array_c - constructor +* Description: This is the bit_array_c constructor. It reserves memory +* for the vector storing the array. +* Parameters : numBits - number of bits in the array +* Effects : Allocates vectory for array bits +* Returned : None +***************************************************************************/ +BitArray::BitArray(const int numBits): + m_NumBits(numBits), + m_Array(NULL), + m_OwnsBuffer(true) +{ + m_SizeInBytes = BITS_TO_CHARS(numBits); + + + /* allocate space for bit array */ + m_Array = new unsigned char[m_SizeInBytes]; + + /* set all bits to 0 */ + fill_n(m_Array, m_SizeInBytes, 0); +} + +/*************************************************************************** +* Method : bit_array_c - constructor +* Description: This is the bit_array_c constructor. It copies the +* for contents of a vector of unsigned char into the +* bitarray. +* Parameters : vect - vector to be copied +* numBits - number of bits in the array +* Effects : Allocates vectory for array bits +* Returned : None +***************************************************************************/ +BitArray::BitArray(unsigned char *array, const int numBits,bool aOwnsBuffer): + m_NumBits(numBits), + m_Array(array), + m_OwnsBuffer(aOwnsBuffer) +{ + +} + +/*************************************************************************** +* Method : ~bit_array_c - destructor +* Description: This is the bit_array_c destructor. At this point it's +* just a place holder. +* Parameters : None +* Effects : None +* Returned : None +***************************************************************************/ +BitArray::~BitArray(void) +{ + if (m_OwnsBuffer) + { + delete[] m_Array; + m_Array = NULL; + } +} + +/*************************************************************************** +* Method : Dump +* Description: This method dumps the conents of a bit array to stdout. +* The format of the dump is a series of bytes represented in +* hexadecimal. +* Parameters : outStream - stream to write to +* Effects : Array contents are dumped to stdout +* Returned : None +***************************************************************************/ +void BitArray::Dump(std::ostream &outStream) +{ + int size; + + size = BITS_TO_CHARS(m_NumBits); + + outStream.width(2); + outStream.fill('0'); + outStream << uppercase << hex << (int)(m_Array[0]); /* first byte */ + + for (int i = 1; i < size; i++) + { + /* remaining bytes with a leading space */ + outStream << " "; + outStream.width(2); + outStream.fill('0'); + outStream << (int)(m_Array[i]); + } + + outStream << dec; +} + +/*************************************************************************** +* Method : SetAll +* Description: This method sets every bit in the bit array to 1. This +* method uses UCHAR_MAX to determine what it means to set +* all bits in an unsigned char, so it is crucial that the +* machine implementation of unsigned char utilizes all of +* the bits in the memory allocated for an unsigned char. +* Parameters : None +* Effects : Each of the bits used in the bit array are set to 1. +* Unused (spare) bits are set to 0. +* Returned : None +***************************************************************************/ +void BitArray::SetAll(void) +{ + int bits, size; + unsigned char mask; + + size = BITS_TO_CHARS(m_NumBits); + + /* set bits in all bytes to 1 */ + fill_n(m_Array, size, UCHAR_MAX); + + /* zero any spare bits so increment and decrement are consistent */ + bits = m_NumBits % CHAR_BIT; + if (bits != 0) + { + mask = UCHAR_MAX << (CHAR_BIT - bits); + m_Array[BIT_CHAR(m_NumBits - 1)] = mask; + } +} + +/*************************************************************************** +* Method : ClearAll +* Description: This method sets every bit in the bit array to 0. +* Parameters : None +* Effects : Each of the bits in the bit array are set to 0. +* Returned : None +***************************************************************************/ +void BitArray::ClearAll(void) +{ + int size; + + size = BITS_TO_CHARS(m_NumBits); + + /* set bits in all bytes to 0 */ + fill_n(m_Array, size, 0); +} + +/*************************************************************************** +* Method : SetBit +* Description: This method sets a bit in the bit array to 1. +* Parameters : bit - the number of the bit to set +* Effects : The specified bit will be set to 1. +* Returned : None +***************************************************************************/ +void BitArray::SetBit(const unsigned int bit) +{ + if (m_NumBits <= bit) + { + return; /* bit out of range */ + } + + m_Array[BIT_CHAR(bit)] |= BIT_IN_CHAR(bit); +} + +/** +*/ +void BitArray::SetBitValue(const unsigned int bit, bool aValue) + { + if (aValue) + { + SetBit(bit); + } + else + { + ClearBit(bit); + } + } + +/*************************************************************************** +* Method : ClearBit +* Description: This method sets a bit in the bit array to 0. +* Parameters : bit - the number of the bit to clear +* Effects : The specified bit will be set to 0. +* Returned : None +***************************************************************************/ +void BitArray::ClearBit(const unsigned int bit) +{ + unsigned char mask; + + if (m_NumBits <= bit) + { + return; /* bit out of range */ + } + + /* create a mask to zero out desired bit */ + mask = BIT_IN_CHAR(bit); + mask = ~mask; + + m_Array[BIT_CHAR(bit)] &= mask; +} + +/*************************************************************************** +* Method : operator() +* Description: Overload of the () operator. This method approximates +* array indices used for assignment. It returns a +* bit_array_index_c which includes an = method used to +* set bit values. +* Parameters : bit - index of array bit +* Effects : None +* Returned : bit_array_index_c (pointer to bit) +***************************************************************************/ +BitArrayIndex BitArray::operator()(const unsigned int bit) +{ + BitArrayIndex result(this, bit); + + return result; +} + +/*************************************************************************** +* Method : operator[] +* Description: Overload of the [] operator. This method returns the +* value of a bit in the bit array. +* Parameters : bit - index of array bit +* Effects : None +* Returned : The value of the specified bit. +***************************************************************************/ +bool BitArray::operator[](const unsigned int bit) const +{ + return((m_Array[BIT_CHAR(bit)] & BIT_IN_CHAR(bit)) != 0); +} + +/*************************************************************************** +* Method : operator== +* Description: overload of the == operator +* Parameters : other - bit array to compare +* Effects : None +* Returned : True if this == other. Otherwise false. +***************************************************************************/ +bool BitArray::operator==(const BitArray &other) const +{ + if (m_NumBits != other.m_NumBits) + { + /* unequal sizes */ + return false; + } + + return (this->m_Array == other.m_Array); +} + +/*************************************************************************** +* Method : operator!= +* Description: overload of the != operator +* Parameters : other - bit array to compare +* Effects : None +* Returned : True if this != other. Otherwise false. +***************************************************************************/ +bool BitArray::operator!=(const BitArray &other) const +{ + if (m_NumBits != other.m_NumBits) + { + /* unequal sizes */ + return true; + } + + return (this->m_Array != other.m_Array); +} + +/*************************************************************************** +* Method : operator< +* Description: overload of the < operator +* Parameters : other - bit array to compare +* Effects : None +* Returned : True if this < other. Otherwise false. +***************************************************************************/ +bool BitArray::operator<(const BitArray &other) const +{ + if (m_NumBits != other.m_NumBits) + { + /* unequal sizes */ + return false; + } + + return (this->m_Array < other.m_Array); +} + +/*************************************************************************** +* Method : operator<= +* Description: overload of the <= operator +* Parameters : other - bit array to compare +* Effects : None +* Returned : True if this <= other. Otherwise false. +***************************************************************************/ +bool BitArray::operator<=(const BitArray &other) const +{ + if (m_NumBits != other.m_NumBits) + { + /* unequal sizes */ + return false; + } + + return (this->m_Array <= other.m_Array); +} + +/*************************************************************************** +* Method : operator> +* Description: overload of the > operator +* Parameters : other - bit array to compare +* Effects : None +* Returned : True if this > other. Otherwise false. +***************************************************************************/ +bool BitArray::operator>(const BitArray &other) const +{ + if (m_NumBits != other.m_NumBits) + { + /* unequal sizes */ + return false; + } + + return (this->m_Array > other.m_Array); +} + +/*************************************************************************** +* Method : operator>= +* Description: overload of the >= operator +* Parameters : other - bit array to compare +* Effects : None +* Returned : True if this >= other. Otherwise false. +***************************************************************************/ +bool BitArray::operator>=(const BitArray &other) const +{ + if (m_NumBits != other.m_NumBits) + { + /* unequal sizes */ + return false; + } + + return (this->m_Array >= other.m_Array); +} + +/*************************************************************************** +* Method : operator~ +* Description: overload of the ~ operator. Negates all non-spare bits in +* bit array +* Parameters : None +* Effects : None +* Returned : value of this after bitwise not +***************************************************************************/ +BitArray BitArray::operator~(void) const +{ + BitArray result(this->m_NumBits); + result = *this; + result.Not(); + + return result; +} + +/*************************************************************************** +* Method : operator& +* Description: overload of the & operator. Performs a bitwise and +* between the source array and this bit array. +* Parameters : other - bit array on righthand side of & +* Effects : None +* Returned : value of bitwise and of this and other. +***************************************************************************/ +BitArray BitArray::operator&(const BitArray &other) const +{ + BitArray result(this->m_NumBits); + result = *this; + result &= other; + + return result; +} + + +/*************************************************************************** +* Method : operator^ +* Description: overload of the ^ operator. Performs a bitwise xor +* between the source array and this bit array. +* Parameters : other - bit array on righthand side of ^ +* Effects : None +* Returned : value of bitwise xor of this and other. +***************************************************************************/ +BitArray BitArray::operator^(const BitArray &other) const +{ + BitArray result(this->m_NumBits); + result = *this; + result ^= other; + + return result; +} + +/*************************************************************************** +* Method : operator| +* Description: overload of the | operator. Performs a bitwise or +* between the source array and this bit array. +* Parameters : other - bit array on righthand side of | +* Effects : None +* Returned : value of bitwise or of this and other. +***************************************************************************/ +BitArray BitArray::operator|(const BitArray &other) const +{ + BitArray result(this->m_NumBits); + result = *this; + result |= other; + + return result; +} + +/*************************************************************************** +* Method : operator<< +* Description: overload of the << operator. Performs a bitwise left +* shift of this bit array. +* Parameters : count - the number of bits to shift left +* Effects : None +* Returned : result of bitwise left shift +***************************************************************************/ +BitArray BitArray::operator<<(const unsigned int count) const +{ + BitArray result(this->m_NumBits); + result = *this; + result <<= count; + + return result; +} + +/*************************************************************************** +* Method : operator>> +* Description: overload of the >> operator. Performs a bitwise right +* shift of this bit array. +* Parameters : count - the number of bits to shift right +* Effects : None +* Returned : result of bitwise right shift +***************************************************************************/ +BitArray BitArray::operator>>(const unsigned int count) const +{ + BitArray result(this->m_NumBits); + result = *this; + result >>= count; + + return result; +} + +/*************************************************************************** +* Method : operator++ (prefix) +* Description: overload of the ++ operator. Increments the contents of +* a bit array. Overflows cause rollover. +* Parameters : None +* Effects : Bit array contents are incremented +* Returned : Reference to this array after increment +***************************************************************************/ +BitArray& BitArray::operator++(void) +{ + int i; + unsigned char maxValue; /* maximum value for current char */ + unsigned char one; /* least significant bit in current char */ + + if (m_NumBits == 0) + { + return *this; /* nothing to increment */ + } + + /* handle arrays that don't use every bit in the last character */ + i = (m_NumBits % CHAR_BIT); + if (i != 0) + { + maxValue = UCHAR_MAX << (CHAR_BIT - i); + one = 1 << (CHAR_BIT - i); + } + else + { + maxValue = UCHAR_MAX; + one = 1; + } + + for (i = BIT_CHAR(m_NumBits - 1); i >= 0; i--) + { + if (m_Array[i] != maxValue) + { + m_Array[i] = m_Array[i] + one; + return *this; + } + else + { + /* need to carry to next byte */ + m_Array[i] = 0; + + /* remaining characters must use all bits */ + maxValue = UCHAR_MAX; + one = 1; + } + } + + return *this; +} + +/*************************************************************************** +* Method : operator++ (postfix) +* Description: overload of the ++ operator. Increments the contents of +* a bit array. Overflows cause rollover. +* Parameters : dumy - needed for postfix increment +* Effects : Bit array contents are incremented +* Returned : Reference to this array after increment +***************************************************************************/ +BitArray& BitArray::operator++(int dummy) +{ + ++(*this); + return *this; +} + +/*************************************************************************** +* Method : operator-- (prefix) +* Description: overload of the -- operator. Decrements the contents of +* a bit array. Underflows cause rollover. +* Parameters : None +* Effects : Bit array contents are decremented +* Returned : None +***************************************************************************/ +BitArray& BitArray::operator--(void) +{ + int i; + unsigned char maxValue; /* maximum value for current char */ + unsigned char one; /* least significant bit in current char */ + + if (m_NumBits == 0) + { + return *this; /* nothing to decrement */ + } + + /* handle arrays that don't use every bit in the last character */ + i = (m_NumBits % CHAR_BIT); + if (i != 0) + { + maxValue = UCHAR_MAX << (CHAR_BIT - i); + one = 1 << (CHAR_BIT - i); + } + else + { + maxValue = UCHAR_MAX; + one = 1; + } + + for (i = BIT_CHAR(m_NumBits - 1); i >= 0; i--) + { + if (m_Array[i] >= one) + { + m_Array[i] = m_Array[i] - one; + return *this; + } + else + { + /* need to borrow from the next byte */ + m_Array[i] = maxValue; + + /* remaining characters must use all bits */ + maxValue = UCHAR_MAX; + one = 1; + } + } + + return *this; +} + +/*************************************************************************** +* Method : operator-- (postfix) +* Description: overload of the -- operator. Decrements the contents of +* a bit array. Underflows cause rollover. +* Parameters : dumy - needed for postfix decrement +* Effects : Bit array contents are decremented +* Returned : None +***************************************************************************/ +BitArray& BitArray::operator--(int dummy) +{ + --(*this); + return *this; +} + +/*************************************************************************** +* Method : operator= +* Description: overload of the = operator. Copies source contents into +* this bit array. +* Parameters : src - Source bit array +* Effects : Source bit array contents are copied into this array +* Returned : Reference to this array after copy +***************************************************************************/ +BitArray& BitArray::operator=(const BitArray &src) +{ + if (*this == src) + { + /* don't do anything for a self assignment */ + return *this; + } + + if (m_NumBits != src.m_NumBits) + { + /* don't do assignment with different array sizes */ + return *this; + } + + if ((m_NumBits == 0) || (src.m_NumBits == 0)) + { + /* don't do assignment with unallocated array */ + return *this; + } + + /* copy bits from source */ + int size; + size = BITS_TO_CHARS(m_NumBits); + + copy(src.m_Array, &src.m_Array[size], this->m_Array); + return *this; +} + +/*************************************************************************** +* Method : operator&= +* Description: overload of the &= operator. Performs a bitwise and +* between the source array and this bit array. This bit +* array will contain the result. +* Parameters : src - Source bit array +* Effects : Results of bitwise and are stored in this array +* Returned : Reference to this array after and +***************************************************************************/ +BitArray& BitArray::operator&=(const BitArray &src) +{ + int size; + + size = BITS_TO_CHARS(m_NumBits); + + if (m_NumBits != src.m_NumBits) + { + /* don't do assignment with different array sizes */ + return *this; + } + + /* AND array one unsigned char at a time */ + for(int i = 0; i < size; i++) + { + m_Array[i] = m_Array[i] & src.m_Array[i]; + } + + return *this; +} + +/*************************************************************************** +* Method : operator^= +* Description: overload of the ^= operator. Performs a bitwise xor +* between the source array and this bit array. This bit +* array will contain the result. +* Parameters : src - Source bit array +* Effects : Results of bitwise xor are stored in this array +* Returned : Reference to this array after xor +***************************************************************************/ +BitArray& BitArray::operator^=(const BitArray &src) +{ + int size; + + size = BITS_TO_CHARS(m_NumBits); + + if (m_NumBits != src.m_NumBits) + { + /* don't do assignment with different array sizes */ + return *this; + } + + /* XOR array one unsigned char at a time */ + for(int i = 0; i < size; i++) + { + m_Array[i] = m_Array[i] ^ src.m_Array[i]; + } + + return *this; +} + +/*************************************************************************** +* Method : operator|= +* Description: overload of the |= operator. Performs a bitwise or +* between the source array and this bit array. This bit +* array will contain the result. +* Parameters : src - Source bit array +* Effects : Results of bitwise or are stored in this array +* Returned : Reference to this array after or +***************************************************************************/ +BitArray& BitArray::operator|=(const BitArray &src) +{ + int size; + + size = BITS_TO_CHARS(m_NumBits); + + if (m_NumBits != src.m_NumBits) + { + /* don't do assignment with different array sizes */ + return *this; + } + + /* OR array one unsigned char at a time */ + for(int i = 0; i < size; i++) + { + m_Array[i] = m_Array[i] | src.m_Array[i]; + } + + return *this; +} + +/*************************************************************************** +* Method : Not +* Description: Negates all non-spare bits in bit array. +* Parameters : None +* Effects : Contents of bit array are negated. Any spare bits are +* left at 0. +* Returned : Reference to this array after not +***************************************************************************/ +BitArray& BitArray::Not(void) +{ + int bits; + unsigned char mask; + int size; + + size = BITS_TO_CHARS(m_NumBits); + + if (m_NumBits == 0) + { + /* don't do not with unallocated array */ + return *this; + } + + /* NOT array one unsigned char at a time */ + for(int i = 0; i < size; i++) + { + m_Array[i] = ~m_Array[i]; + } + + /* zero any spare bits so increment and decrement are consistent */ + bits = m_NumBits % CHAR_BIT; + if (bits != 0) + { + mask = UCHAR_MAX << (CHAR_BIT - bits); + m_Array[BIT_CHAR(m_NumBits - 1)] &= mask; + } + + return *this; +} + +/*************************************************************************** +* Method : operator<<= +* Description: overload of the <<= operator. Performs a left shift on +* this bit array. This bit array will contain the result. +* Parameters : shifts - number of bit positions to shift +* Effects : Results of the shifts are stored in this array +* Returned : Reference to this array after shift +***************************************************************************/ +BitArray& BitArray::operator<<=(const unsigned int shifts) +{ + int i; + int chars = shifts / CHAR_BIT; /* number of whole byte shifts */ + + if (shifts >= m_NumBits) + { + /* all bits have been shifted off */ + this->ClearAll(); + return *this; + } + + /* first handle big jumps of bytes */ + if (chars > 0) + { + int size; + + size = BITS_TO_CHARS(m_NumBits); + + for (i = 0; (i + chars) < size; i++) + { + m_Array[i] = m_Array[i + chars]; + } + + /* now zero out new bytes on the right */ + for (i = size; chars > 0; chars--) + { + m_Array[i - chars] = 0; + } + } + + /* now we have at most CHAR_BIT - 1 bit shifts across the whole array */ + for (i = 0; i < (int)(shifts % CHAR_BIT); i++) + { + for (unsigned int j = 0; j < BIT_CHAR(m_NumBits - 1); j++) + { + m_Array[j] <<= 1; + + /* handle shifts across byte bounds */ + if (m_Array[j + 1] & MS_BIT) + { + m_Array[j] |= 0x01; + } + } + + m_Array[BIT_CHAR(m_NumBits - 1)] <<= 1; + } + + return *this; +} + +/*************************************************************************** +* Method : operator>>= +* Description: overload of the >>= operator. Performs a right shift on +* this bit array. This bit array will contain the result. +* Parameters : shifts - number of bit positions to shift +* Effects : Results of the shifts are stored in this array +* Returned : Reference to this array after shift +***************************************************************************/ +BitArray& BitArray::operator>>=(const unsigned int shifts) +{ + int i; + char mask; + int chars = shifts / CHAR_BIT; /* number of whole byte shifts */ + + if (shifts >= m_NumBits) + { + /* all bits have been shifted off */ + this->ClearAll(); + return *this; + } + + /* first handle big jumps of bytes */ + if (chars > 0) + { + for (i = BIT_CHAR(m_NumBits - 1); (i - chars) >= 0; i--) + { + m_Array[i] = m_Array[i - chars]; + } + + /* now zero out new bytes on the right */ + for (; chars > 0; chars--) + { + m_Array[chars - 1] = 0; + } + } + + /* now we have at most CHAR_BIT - 1 bit shifts across the whole array */ + for (i = 0; i < (int)(shifts % CHAR_BIT); i++) + { + for (unsigned int j = BIT_CHAR(m_NumBits - 1); j > 0; j--) + { + m_Array[j] >>= 1; + + /* handle shifts across byte bounds */ + if (m_Array[j - 1] & 0x01) + { + m_Array[j] |= MS_BIT; + } + } + + m_Array[0] >>= 1; + } + + /*********************************************************************** + * zero any spare bits that are shifted beyond the end of the bit array + * so that increment and decrement are consistent. + ***********************************************************************/ + i = m_NumBits % CHAR_BIT; + if (i != 0) + { + mask = UCHAR_MAX << (CHAR_BIT - i); + m_Array[BIT_CHAR(m_NumBits - 1)] &= mask; + } + + return *this; +} + +/*************************************************************************** +* Method : bit_array_index_c - constructor +* Description: This is the bit_array_index_c constructor. It stores a +* pointer to the bit array and the bit index. +* Parameters : array - pointer to bit array +* index - index of bit in array +* Effects : Pointer to bit array and bit index are stored. +* Returned : None +***************************************************************************/ +BitArrayIndex::BitArrayIndex(BitArray *array, + const unsigned int index) +{ + m_BitArray = array; + m_Index = index; +} + +/*************************************************************************** +* Method : operator= +* Description: overload of the = operator. Sets the bit array bit to +* the value of src. +* Parameters : src - bit value +* Effects : Bit pointed to by this object is set to the value of +* source. +* Returned : None +***************************************************************************/ +void BitArrayIndex::operator=(const bool src) +{ + if (m_BitArray == NULL) + { + return; /* no array */ + } + + if (m_BitArray->SizeInBits() <= m_Index) + { + return; /* index is out of bounds */ + } + + if (src) + { + m_BitArray->SetBit(m_Index); + } + else + { + m_BitArray->ClearBit(m_Index); + } +} diff -r 000000000000 -r 0f874d9e4130 BitArray.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/BitArray.h Tue Jun 17 09:55:20 2014 +0200 @@ -0,0 +1,161 @@ +/*************************************************************************** +* Arrays of Arbitrary Bit Length +* +* File : bitarray.h +* Purpose : Header file for class supporting the creation and +* manipulation of arbitrary length arrays of bits. +* Author : Michael Dipperstein +* Date : July 23, 2004 +* +**************************************************************************** +* HISTORY +* +* $Id: bitarray.h,v 1.5 2010/02/04 03:31:43 michael Exp $ +* $Log: bitarray.h,v $ +* Revision 1.5 2010/02/04 03:31:43 michael +* Replaced vector with an array of unsigned char. +* +* Made updates for GCC 4.4. +* +* Revision 1.4 2007/08/06 05:23:12 michael +* Updated for LGPL Version 3. +* +* All methods that don't modify object have been made +* const to increase functionality of const bit_array_c. +* +* All assignment operators return a reference to the object being assigned a value so that operator chaining will work. +* +* Added >> and << operators. +* +* Revision 1.3 2006/04/30 23:34:07 michael +* Improved performance by incorporating Benjamin Schindler's +* changes to pass arguments as a reference. +* +* Revision 1.2 2004/08/05 22:17:04 michael +* Add overloads for bitwise operators returning values. +* Add a more natural looking way to set bit values. +* +* Revision 1.1.1.1 2004/08/04 13:28:20 michael +* bit_array_c +* +**************************************************************************** +* +* Bitarray: An ANSI C++ class for manipulating arbitrary length bit arrays +* Copyright (C) 2004, 2006-2007, 2010 by +* Michael Dipperstein (mdipper@alumni.engr.ucsb.edu) +* +* This file is part of the bit array library. +* +* The bit array library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public License as +* published by the Free Software Foundation; either version 3 of the +* License, or (at your option) any later version. +* +* The bit array library 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 Lesser +* General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this program. If not, see . +* +***************************************************************************/ +#ifndef BIT_ARRAY_H +#define BIT_ARRAY_H + +/*************************************************************************** +* INCLUDED FILES +***************************************************************************/ +#include + +/*************************************************************************** +* TYPE DEFINITIONS +***************************************************************************/ +class BitArray; + +/** +*/ +class BitArrayIndex +{ + public: + BitArrayIndex(BitArray *array, const unsigned int index); + + /* assignment */ + void operator=(const bool src); + + private: + BitArray *m_BitArray; /* array index applies to */ + unsigned int m_Index; /* index of bit in array */ +}; + +/** +TODO: Derive a Bit Frame class from this one for X Y access to pixels. +*/ +class BitArray +{ + public: + BitArray(const int numBits); + BitArray(unsigned char *array, const int numBits, bool aOwnsBuffer); + + virtual ~BitArray(void); + + void Dump(std::ostream &outStream); + + const unsigned int SizeInBits() { return m_NumBits; } + const unsigned int SizeInBytes() { return m_SizeInBytes; } + + /* set/clear functions */ + void SetAll(void); + void ClearAll(void); + void SetBit(const unsigned int bit); + void SetBitValue(const unsigned int bit, bool aValue); + void ClearBit(const unsigned int bit); + + BitArrayIndex operator()(const unsigned int bit); + + /* boolean operator */ + bool operator[](const unsigned int bit) const; + bool operator==(const BitArray &other) const; + bool operator!=(const BitArray &other) const; + bool operator<(const BitArray &other) const; + bool operator<=(const BitArray &other) const; + bool operator>(const BitArray &other) const; + bool operator>=(const BitArray &other) const; + + /* bitwise operators */ + BitArray operator&(const BitArray &other) const; + BitArray operator^(const BitArray &other) const; + BitArray operator|(const BitArray &other) const; + BitArray operator~(void) const; + + BitArray operator<<(const unsigned int count) const; + BitArray operator>>(const unsigned int count) const; + + /* increment/decrement */ + BitArray& operator++(void); /* prefix */ + BitArray& operator++(int dummy); /* postfix */ + BitArray& operator--(void); /* prefix */ + BitArray& operator--(int dummy); /* postfix */ + + /* assignments */ + BitArray& operator=(const BitArray &src); + + BitArray& operator&=(const BitArray &src); + BitArray& operator^=(const BitArray &src); + BitArray& operator|=(const BitArray &src); + BitArray& Not(void); /* negate (~=) */ + + BitArray& operator<<=(unsigned const int shifts); + BitArray& operator>>=(unsigned const int shifts); + + unsigned char* Ptr(){return m_Array;} + const unsigned char* Ptr() const{return m_Array;} + + protected: + unsigned int m_NumBits; /* number of bits in the array */ + unsigned int m_SizeInBytes; + unsigned char *m_Array; /* vector of characters */ + bool m_OwnsBuffer; +}; + +#endif /* ndef BIT_ARRAY_H */ diff -r 000000000000 -r 0f874d9e4130 FutabaVfd.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/FutabaVfd.cpp Tue Jun 17 09:55:20 2014 +0200 @@ -0,0 +1,699 @@ + +#include "FutabaVfd.h" +//#include +#include + + +#ifdef DEBUG_FRAME_DIFF +#include +#include +#endif + + +const int KNumberOfFrameBeforeDiffAlgo = 3; + +// +// +// + +FutabaVfdCommand::FutabaVfdCommand():/*iBuffer(NULL),*/iSize(0),iMaxSize(0) + { + } + +FutabaVfdCommand::~FutabaVfdCommand() + { + //Delete(); + } + + +/** + +*/ +void FutabaVfdCommand::Reset() + { + memset(iReports,0,sizeof(iReports)); + } + + + +/** + +*/ +/* +void FutabaVfdCommand::Create(int aMaxSize) + { + iBuffer=new unsigned char[aMaxSize]; + if (iBuffer) + { + iMaxSize = aMaxSize; + iSize = 0; + } + } +*/ + +/** + +*/ +/* +void FutabaVfdCommand::Delete() +{ + delete[] iBuffer; + iBuffer = NULL; + iMaxSize = 0; + iSize = 0; +} +*/ + + + + +// +// class GP1212A01A +// + +GP1212A01A::GP1212A01A(): + iDisplayPositionX(0),iDisplayPositionY(0), + iOffScreenMode(true), + iUseFrameDifferencing(true), + iFrameNext(NULL), + iFrameCurrent(NULL), + iFramePrevious(NULL), + iFrameAlpha(NULL), + iFrameBeta(NULL), + iFrameGamma(NULL), + iNeedFullFrameUpdate(0), + iRequest(ERequestNone),iPowerOn(false) + { + //ResetBuffers(); + } + +/** +*/ +GP1212A01A::~GP1212A01A() + { + delete iFrameAlpha; + iFrameAlpha=NULL; + // + delete iFrameBeta; + iFrameBeta=NULL; + // + delete iFrameGamma; + iFrameGamma=NULL; + // + iFrameNext=NULL; + iFrameCurrent=NULL; + iFramePrevious=NULL; + // + iNeedFullFrameUpdate=0; + } + +/** +*/ +int GP1212A01A::Open() + { + int success = HidDevice::Open(KFutabaVendorId,KFutabaProductIdGP1212A01A,NULL); + if (success) + { + //Allocate both frames + delete iFrameAlpha; + iFrameAlpha=NULL; + iFrameAlpha=new BitArray(KGP12xFrameBufferPixelCount); + // + delete iFrameBeta; + iFrameBeta=NULL; + iFrameBeta=new BitArray(KGP12xFrameBufferPixelCount); + // + delete iFrameGamma; + iFrameGamma=NULL; + iFrameGamma=new BitArray(KGP12xFrameBufferPixelCount); + // + iFrameNext=iFrameAlpha; + iFrameCurrent=iFrameBeta; + iFramePrevious=iFrameGamma; + + + //To make sure it is synced properly + iNeedFullFrameUpdate=0; + // + SetNonBlocking(1); + //Since we can't get our display position we force it to our default + //This makes sure frames are in sync from the start + //Clever clients will have taken care of putting back frame (0,0) before closing + SetDisplayPosition(iDisplayPositionX,iDisplayPositionY); + } + return success; + } + +/** +*/ +void GP1212A01A::SetPixel(unsigned char aX, unsigned char aY, bool aOn) + { + // + //int byteOffset=(aX*HeightInPixels()+aY)/8; + //int bitOffset=(aX*HeightInPixels()+aY)%8; + //iNextFrame[byteOffset] |= ( (aOn?0x01:0x00) << bitOffset ); + + if (iOffScreenMode) + { + if (aOn) + { + iFrameNext->SetBit(aX*HeightInPixels()+aY); + } + else + { + iFrameNext->ClearBit(aX*HeightInPixels()+aY); + } + } + else + { + //Just specify a one pixel block + SetPixelBlock(aX,aY,0x00,0x01,aOn); + } + } + +/** +*/ +void GP1212A01A::BitBlit(const BitArray& aBitmap, int aSrcWidth, int aSrcHeight, int aTargetX, int aTargetY) const + { + //TODO: amend loop values so that we don't keep on looping past our frame buffer dimensions. + for (int i=0;iSetBitValue((aTargetX+i)*HeightInPixels()+aTargetY+j,aBitmap[+i*aSrcHeight+j]); + } + } + } + +/** +Clear our client side back buffer. +Call to SwapBuffers must follow to actually clear the display. +*/ +void GP1212A01A::Clear() + { + //memset(iNextFrame->Ptr(),0x00,FrameBufferSizeInBytes()); + if (iOffScreenMode) + { + iFrameNext->ClearAll(); + } + else + { + SendClearCommand(); + } + } + +/** +Set all pixels on our screen to the desired value. +This operation is performed off screen to avoid tearing. +@param 8 pixels pattern +*/ +void GP1212A01A::SetAllPixels(unsigned char aPattern) + { + //With a single buffer + //unsigned char screen[2048]; //One screen worth of pixels + //memset(screen,0xFF,sizeof(screen)); + //SetPixelBlock(0,0,63,sizeof(screen),screen); + + + if (iOffScreenMode) + { + memset(iFrameNext->Ptr(),aPattern,FrameBufferSizeInBytes()); + } + else + { + //Using pattern SetPixelBlock variant. + SetPixelBlock(0,0,63,FrameBufferSizeInBytes(),aPattern); + } + // + } + + +/** +Set the defined pixel block to the given value. +@param X coordinate of our pixel block starting point. +@param Y coordinate of our pixel block starting point. +@param The height of our pixel block. +@param The size of our pixel data. Number of pixels divided by 8. +@param The value set to 8 pixels used as a pattern. +*/ +void GP1212A01A::SetPixelBlock(unsigned char aX, unsigned char aY, int aHeight, int aSize, unsigned char aValue) + { + OffScreenTranslation(aX,aY); + FutabaVfdReport report; + report[0]=0x00; //Report ID + report[1]=(aSize<=report.Size()-10?aSize+0x08:64); //Report length. -10 is for our header first 10 bytes. +8 is for our Futaba header size + report[2]=0x1B; //Command ID + report[3]=0x5B; //Command ID + report[4]=0xF0; //Command ID + report[5]=aX; //X + report[6]=aY; //Y + report[7]=aHeight; //Y length before return. Though outside the specs, setting this to zero apparently allows us to modify a single pixel without touching any other. + report[8]=aSize>>8; //Size of pixel data in bytes (MSB) + report[9]=aSize; //Size of pixel data in bytes (LSB) + int sizeWritten=MIN(aSize,report.Size()-10); + memset(report.Buffer()+10, aValue, sizeWritten); + Write(report); + + int remainingSize=aSize; + //We need to keep on sending our pixel data until we are done + while (report[1]==64) + { + report.Reset(); + remainingSize-=sizeWritten; + report[0]=0x00; //Report ID + report[1]=(remainingSize<=report.Size()-2?remainingSize:64); //Report length, should be 64 or the remaining size + sizeWritten=(report[1]==64?63:report[1]); + memset(report.Buffer()+2, aValue, sizeWritten); + Write(report); + } + } + +/** +Set the defined pixel block to the given value. +@param X coordinate of our pixel block starting point. +@param Y coordinate of our pixel block starting point. +@param The height of our pixel block. +@param The size of our pixel data. Number of pixels divided by 8. +@param Pointer to our pixel data. +*/ +void GP1212A01A::SetPixelBlock(unsigned char aX, unsigned char aY, int aHeight, int aSize, unsigned char* aPixels) + { + OffScreenTranslation(aX,aY); + FutabaVfdReport report; + report[0]=0x00; //Report ID + report[1]=(aSize<=report.Size()-10?aSize+0x08:64); //Report length. -10 is for our header first 10 bytes. +8 is for our Futaba header size + report[2]=0x1B; //Command ID + report[3]=0x5B; //Command ID + report[4]=0xF0; //Command ID + report[5]=aX; //X + report[6]=aY; //Y + report[7]=aHeight; //Y length before return. Though outside the specs, setting this to zero apparently allows us to modify a single pixel without touching any other. + report[8]=aSize>>8; //Size of pixel data in bytes (MSB) + report[9]=aSize; //Size of pixel data in bytes (LSB) + int sizeWritten=MIN(aSize,report.Size()-10); + memcpy(report.Buffer()+10, aPixels, sizeWritten); + Write(report); + + int remainingSize=aSize; + //We need to keep on sending our pixel data until we are done + while (report[1]==64) + { + report.Reset(); + remainingSize-=sizeWritten; + report[0]=0x00; //Report ID + report[1]=(remainingSize<=report.Size()-2?remainingSize:64); //Report length, should be 64 or the remaining size + sizeWritten=(report[1]==64?63:report[1]); + memcpy(report.Buffer()+2, aPixels+(aSize-remainingSize), sizeWritten); + Write(report); + } + } + +/** +Using this function is advised against as is causes tearing. +Use Clear instead. +*/ +void GP1212A01A::SendClearCommand() + { + //1BH,5BH,32H,4AH + //Send Clear Display Command + FutabaVfdReport report; + report[0]=0x00; //Report ID + report[1]=0x04; //Report length + report[2]=0x1B; //Command ID + report[3]=0x5B; //Command ID + report[4]=0x32; //Command ID + report[5]=0x4A; //Command ID + Write(report); + } + +/** +Change our display position within our buffer. +*/ +void GP1212A01A::SetDisplayPosition(DW aDw,unsigned char aX, unsigned char aY) + { + //1BH,5BH,Dw,Px,Py + //Send Display Position Settings Command + FutabaVfdReport report; + report[0]=0x00; //Report ID + report[1]=0x05; //Report length + report[2]=0x1B; //Command ID + report[3]=0x5B; //Command ID + report[4]=aDw; //Specify our DW + report[5]=aX; //X coordinate of our DW top-left corner + report[6]=aY; //Y coordinate of our DW top-left corner + Write(report); + } + +/** +Change our display position within our buffer. +*/ +void GP1212A01A::SetDisplayPosition(unsigned char aX, unsigned char aY) + { + //Specs apparently says both DW should remain the same + //Just don't ask + SetDisplayPosition(GP1212A01A::DW1,aX,aY); + SetDisplayPosition(GP1212A01A::DW2,aX,aY); + iDisplayPositionX=aX; + iDisplayPositionY=aY; + } + +/** +Provide Y coordinate of our off screen buffer. +*/ +unsigned char GP1212A01A::OffScreenY() const + { + //Overflowing is fine this is just what we want + return iDisplayPositionY+HeightInPixels(); + } + +/** +Put our off screen buffer on screen. +On screen buffer goes off screen. +*/ +void GP1212A01A::SwapBuffers() + { + //Only perform buffer swapping if off screen mode is enabled + if (OffScreenMode()) + { + //Send host back buffer to device back buffer + if (!iUseFrameDifferencing || iNeedFullFrameUpdatePtr()); + } + else + { + //Frame diff algo is enabled + //We are going to send to our device only the differences between next frame and previous frame + SendModifiedPixelBlocks(); + } + //Swap device front and back buffer + SetDisplayPosition(iDisplayPositionX,OffScreenY()); + + //Cycle through our frame buffers + //We keep track of previous frame which is in fact our device back buffer. + //We can then compare previous and next frame and send only the differences to our device. + //This mechanism allows us to reduce traffic over our USB bus thus improving our frame rate from 14 FPS to 30 FPS. + //Keep our previous frame pointer + BitArray* previousFrame=iFramePrevious; + //Current frame becomes the previous one + iFramePrevious = iFrameCurrent; + //Next frame becomes the current one + iFrameCurrent = iFrameNext; + //Next frame is now our former previous + iFrameNext = previousFrame; + } + } + + +//Define the edge of our pixel block +//Pixel blocks of 32x32 seems to run almost as fast as full screen update in worse case scenarii. +//Though I wonder if in some situations 16 could be better. Make this an attribute at some point if need be. +const int KPixelBlockEdge = 32; +const int KPixelBlockSizeInBits = KPixelBlockEdge*KPixelBlockEdge; +const int KPixelBlockSizeInBytes = KPixelBlockSizeInBits/8; + + +/** + * @brief GP1212A01A::SendModifiedPixelBlocks + * Compare our back and front buffer and send to the device only the modified pixels. + */ +void GP1212A01A::SendModifiedPixelBlocks() + { + int w=WidthInPixels(); + int h=HeightInPixels(); + + + //TODO: optimize with memcmp and 16 inc + /* + + for (int i=0;iPtr()+offset); + } + } + } + */ + + BitArray nextBlock(KPixelBlockSizeInBits); + BitArray previousBlock(KPixelBlockSizeInBits); + + for (int i=0;iPtr()+offset,iFramePrevious->Ptr()+offset,32 )) //32=(16*16/8) + if (memcmp(nextBlock.Ptr(),previousBlock.Ptr(),KPixelBlockSizeInBytes)!=0) + { + //We need to update that block + SetPixelBlock(i,j,KPixelBlockEdge-1,KPixelBlockSizeInBytes,nextBlock.Ptr()); + //SetPixelBlock(i,j,15,32,0xFF/*nextBlock.Ptr()*/); + //SetDisplayPosition(iDisplayPositionX,OffScreenY()); + //SetDisplayPosition(iDisplayPositionX,OffScreenY()); + + //SetPixelBlock(i,j,15,32,iFrameNext->Ptr()+offset); + } + } + } + + } + +/** +Translate the given pixel coordinate according to our off screen mode. +*/ +void GP1212A01A::OffScreenTranslation(unsigned char& aX, unsigned char& aY) + { + if (OffScreenMode()) + { + aX+=WidthInPixels()-iDisplayPositionX; + aY+=HeightInPixels()-iDisplayPositionY; + } + } + + +/** +*/ +void GP1212A01A::ResetBuffers() + { + //iNextFrame->ClearAll(); + //memset(iFrameAlpha,0x00,sizeof(iFrameAlpha)); + //memset(iFrameBeta,0x00,sizeof(iFrameBeta)); + } + +/** +*/ +void GP1212A01A::RequestDeviceId() + { + if (RequestPending()) + { + //Abort silently for now + return; + } + + //1BH,5BH,63H,49H,44H + //Send Read ID command + FutabaVfdReport report; + report[0]=0x00; //Report ID + report[1]=0x05; //Report length + report[2]=0x1B; //Command ID + report[3]=0x5B; //Command ID + report[4]=0x63; //Command ID + report[5]=0x49; //Command ID + report[6]=0x44; //Command ID + if (Write(report)==report.Size()) + { + iRequest=ERequestDeviceId; + } + } + +/** +*/ +void GP1212A01A::RequestFirmwareRevision() + { + if (RequestPending()) + { + //Abort silently for now + return; + } + + //1BH,5BH,63H,46H,52H + //Send Software Revision Read Command + FutabaVfdReport report; + report[0]=0x00; //Report ID + report[1]=0x05; //Report length + report[2]=0x1B; //Command ID + report[3]=0x5B; //Command ID + report[4]=0x63; //Command ID + report[5]=0x46; //Command ID + report[6]=0x52; //Command ID + if (Write(report)==report.Size()) + { + iRequest=ERequestFirmwareRevision; + } + } + +/** +*/ +void GP1212A01A::RequestPowerSupplyStatus() + { + if (RequestPending()) + { + //Abort silently for now + return; + } + //1BH,5BH,63H,50H,4DH + //Send Power Suppply Monitor Command + FutabaVfdReport report; + report[0]=0x00; //Report ID + report[1]=0x05; //Report length + report[2]=0x1B; //Command ID + report[3]=0x5B; //Command ID + report[4]=0x63; //Command ID + report[5]=0x50; //Command ID + report[6]=0x4D; //Command ID + if (Write(report)==report.Size()) + { + iRequest=ERequestPowerSupplyStatus; + } + } + + +/** +This is for development purposes only. +Production application should stick to off-screen mode to avoid tearing. +*/ +void GP1212A01A::ToggleOffScreenMode() + { + SetOffScreenMode(!iOffScreenMode); + } + +/** + * @brief GP1212A01A::SetOffScreenMode + * @param aOn + * @return + */ +void GP1212A01A::SetOffScreenMode(bool aOn) + { + if (aOn==iOffScreenMode) + { + //Nothing to do here + return; + } + + iOffScreenMode=aOn; + + //Clean up our buffers upon switching modes + SetDisplayPosition(0,0); + Clear(); + SwapBuffers(); + Clear(); + } + +/** + */ +GP1212A01A::Request GP1212A01A::AttemptRequestCompletion() + { + if (!RequestPending()) + { + return ERequestNone; + } + + int res=Read(iInputReport); + + if (!res) + { + return ERequestNone; + } + + //Process our request + if (CurrentRequest()==GP1212A01A::ERequestPowerSupplyStatus) + { + if (iInputReport[1]==0x4F && iInputReport[2]==0x4E) + { + iPowerOn = true; + } + else if (iInputReport[1]==0x4F && iInputReport[2]==0x46 && iInputReport[3]==0x46) + { + iPowerOn = false; + } + } + + Request completed=iRequest; + //Our request was completed + iRequest=ERequestNone; + + return completed; + } + + +/** +Set our screen brightness. +@param The desired brightness level. Must be between MinBrightness and MaxBrightness. +*/ +void GP1212A01A::SetBrightness(int aBrightness) + { + if (aBrightnessMaxBrightness()) + { + //Brightness out of range. + //Just ignore that request. + return; + } + + FutabaVfdReport report; + report[0]=0x00; //Report ID + report[1]=0x06; //Report size + report[2]=0x1B; //Command ID + report[3]=0x5C; //Command ID + report[4]=0x3F; //Command ID + report[5]=0x4C; //Command ID + report[6]=0x44; //Command ID + report[7]=0x30+aBrightness; //Brightness level + Write(report); + } + + diff -r 000000000000 -r 0f874d9e4130 FutabaVfd.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/FutabaVfd.h Tue Jun 17 09:55:20 2014 +0200 @@ -0,0 +1,217 @@ +// +// +// + +#ifndef FUTABA_VFD_H +#define FUTABA_VFD_H + +#include "hidapi.h" +#include "HidDevice.h" +#include "BitArray.h" + +#ifndef MIN +#define MIN(a,b) (((a)<(b))?(a):(b)) +#endif + +#ifndef MAX +#define MAX(a,b) (((a)>(b))?(a):(b)) +#endif + + +//This was computed from our number of pixels as follow 256x64/8/64 = 32 + 1 = 33 +//+1 was added for our header +const int KFutabaMaxCommandOutputReport = 33; +//TODO: Get ride of that constant once we figure out a way to get it from hidapi +const int KFutabaMaxHidReportSize = 65; + +const int KHidReportIdIndex=0; +const int KFutabaHidReportSizeIndex=1; +//Define Futaba vendor ID to filter our list of device +const unsigned short KFutabaVendorId = 0x1008; +const unsigned short KFutabaProductIdGP1212A01A = 0x100C; +const unsigned short KFutabaProductIdGP1212A02A = 0x1013; //Or is it 0x1015 +const int KGP12xWidthInPixels = 256; +const int KGP12xHeightInPixels = 64; +const int KGP12xPixelsPerByte = 8; +const int KGP12xFrameBufferSizeInBytes = KGP12xWidthInPixels*KGP12xHeightInPixels/KGP12xPixelsPerByte; //256*64/8=2048 +const int KGP12xFrameBufferPixelCount = KGP12xWidthInPixels*KGP12xHeightInPixels; + +//typedef struct hid_device_info HidDeviceInfo; + +/** +Define a Futaba HID report. +*/ +class FutabaVfdReport: public HidReport + { + +private: + + }; + + +/** +Define a generic Futaba VFD command. +*/ +class FutabaVfdCommand + { +public: + FutabaVfdCommand(); + ~FutabaVfdCommand(); + // + //void Create(int aMaxSize); + //void Delete(); + + //inline unsigned char& operator[](int aIndex){return iBuffer[aIndex];} + + void Reset(); + +private: + //unsigned char* iBuffer; + FutabaVfdReport iReports[KFutabaMaxCommandOutputReport]; + int iSize; + int iMaxSize; + }; + +/** +*/ +class FutabaVfd : public HidDevice + { +public: + virtual int MinBrightness() const=0; + virtual int MaxBrightness() const=0; + virtual void SetBrightness(int aBrightness)=0; + virtual void Clear()=0; + }; + + +/** +*/ +class FutabaGraphicVfd : public FutabaVfd + { +public: + virtual int WidthInPixels() const=0; + virtual int HeightInPixels() const=0; + virtual void SetPixel(unsigned char aX, unsigned char aY, bool aOn)=0; + virtual void SetAllPixels(unsigned char aOn)=0; + virtual int FrameBufferSizeInBytes() const=0; + //virtual int BitBlit(unsigned char* aSrc, unsigned char aSrcWidth, unsigned char aSrcHeight, unsigned char aTargetX, unsigned char aTargetY) const=0; + + }; + +/** +Common functionality between GP1212A01A and GP1212A02A +*/ +class GP1212XXXX : public FutabaGraphicVfd + { +public: + //From FutabaVfd + virtual int MinBrightness() const {return 0;} + virtual int MaxBrightness() const {return 5;} + }; + +/** +GP1212A01A is a graphic display module using a FUTABA 256x64dots VFD. +The module do not include character ROM, the customer will compile the character +by themselves (from main system). +*/ +class GP1212A01A : public GP1212XXXX + { +public: + enum Request + { + ERequestNone, + ERequestDeviceId, + ERequestFirmwareRevision, + ERequestPowerSupplyStatus + }; + +public: + GP1212A01A(); + ~GP1212A01A(); + + // + int Open(); + //From FutabaGraphicVfd + virtual int WidthInPixels() const {return KGP12xWidthInPixels;} + virtual int HeightInPixels() const {return KGP12xHeightInPixels;} + virtual void SetPixel(unsigned char aX, unsigned char aY, bool aOn); + virtual void SetAllPixels(unsigned char aPattern); + virtual int FrameBufferSizeInBytes() const {return KGP12xFrameBufferSizeInBytes;} + virtual void BitBlit(const BitArray& aBitmap, int aSrcWidth, int aSrcHeight, int aTargetX, int aTargetY) const; + //From FutabaVfd + virtual void SetBrightness(int aBrightness); + virtual void Clear(); + + //Specific to GP1212A01A + void SetPixelBlock(unsigned char aX, unsigned char aY, int aHeight, int aSize, unsigned char aValue); + void SetPixelBlock(unsigned char aX, unsigned char aY, int aHeight, int aSize, unsigned char* aPixels); + //Define display position within our display RAM + void SetDisplayPosition(unsigned char aX, unsigned char aY); + unsigned char DisplayPositionX() const {return iDisplayPositionX;} + unsigned char DisplayPositionY() const {return iDisplayPositionY;} + // + void SwapBuffers(); + // + void RequestDeviceId(); + void RequestFirmwareRevision(); + void RequestPowerSupplyStatus(); + // + void ToggleOffScreenMode(); + void SetOffScreenMode(bool aOn); + bool OffScreenMode() const {return iOffScreenMode;} + // + void SetFrameDifferencing(bool aOn){iUseFrameDifferencing=aOn;} + bool FrameDifferencing() const {return iUseFrameDifferencing;} + // + bool RequestPending(){return iRequest!=ERequestNone;} + Request CurrentRequest(){return iRequest;} + void CancelRequest(){iRequest=ERequestNone;} + Request AttemptRequestCompletion(); + FutabaVfdReport& InputReport() {return iInputReport;} + bool PowerOn(){return iPowerOn;} + +private: + enum DW + { + DW1=0xC0, + DW2=0xD0 + }; + + void SetDisplayPosition(DW aDw,unsigned char aX, unsigned char aY); + unsigned char OffScreenY() const; + void SendClearCommand(); + void OffScreenTranslation(unsigned char& aX, unsigned char& aY); + void ResetBuffers(); + void SendModifiedPixelBlocks(); + +private: + unsigned char iDisplayPositionX; + unsigned char iDisplayPositionY; + ///Off screen mode is the recommended default settings to avoid tearing. + ///Though turning it off can be useful for debugging + bool iOffScreenMode; + ///Frame differences algo is used to reduce USB bus traffic and improve frame rate in typical use case + bool iUseFrameDifferencing; + /// + //FutabaVfdReport iReport; + /// + //unsigned char iFrameBuffer[256*64]; + BitArray* iFrameNext; + BitArray* iFrameCurrent; + BitArray* iFramePrevious; + // + BitArray* iFrameAlpha; + BitArray* iFrameBeta; + BitArray* iFrameGamma; + // + int iNeedFullFrameUpdate; + //unsigned char iFrameBeta[256*64]; + //unsigned char *iFrontBuffer; + //unsigned char *iBackBuffer; + Request iRequest; + FutabaVfdReport iInputReport; + bool iPowerOn; + }; + + +#endif diff -r 000000000000 -r 0f874d9e4130 HidDevice.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/HidDevice.cpp Tue Jun 17 09:55:20 2014 +0200 @@ -0,0 +1,122 @@ +// +// +// + +#include "HidDevice.h" + + + +// +// class HidDevice +// + +HidDevice::HidDevice():iHidDevice(NULL) + { + Close(); + } + +/** +*/ +int HidDevice::Open(const char* aPath) + { + Close(); + + iHidDevice = hid_open_path(aPath); + + if (!iHidDevice) + { + //Fail to connect our device + return 0; + } + + FetchStrings(); + + return 1; + } + +/** +See hidapi documentation. +*/ +int HidDevice::Open(unsigned short aVendorId, unsigned short aProductId, const wchar_t* aSerialNumber) + { + Close(); + + iHidDevice = hid_open(aVendorId, aProductId, aSerialNumber); + + if (!iHidDevice) + { + //Fail to connect our device + return 0; + } + + FetchStrings(); + + return 1; + } + +/** +*/ +void HidDevice::Close() + { + hid_close(iHidDevice); + iHidDevice=NULL; + // + memset(iVendor,0,sizeof(iVendor)); + memset(iProduct,0,sizeof(iProduct)); + memset(iSerialNumber,0,sizeof(iSerialNumber)); + } + +/** +*/ +bool HidDevice::IsOpen() + { + return iHidDevice!=NULL; + } + + +/** +*/ +const wchar_t* HidDevice::Error() + { + return hid_error(iHidDevice); + } + +/** +*/ +int HidDevice::SetNonBlocking(int aNonBlocking) + { + //Success we are now connected to our HID device + //Set read operation as non blocking + return hid_set_nonblocking(iHidDevice, aNonBlocking); + } + +/** +*/ +wchar_t* HidDevice::Vendor() + { + return iVendor; + } + +/** +*/ +wchar_t* HidDevice::Product() + { + return iProduct; + } + +/** +*/ +wchar_t* HidDevice::SerialNumber() + { + return iSerialNumber; + } + +/** + +*/ +void HidDevice::FetchStrings() + { + hid_get_manufacturer_string(iHidDevice,iVendor,sizeof(iVendor)); + hid_get_product_string(iHidDevice,iProduct,sizeof(iProduct)); + hid_get_serial_number_string(iHidDevice,iSerialNumber,sizeof(iSerialNumber)); + } diff -r 000000000000 -r 0f874d9e4130 HidDevice.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/HidDevice.h Tue Jun 17 09:55:20 2014 +0200 @@ -0,0 +1,69 @@ +// +// +// + +#ifndef HID_DEVICE_H +#define HID_DEVICE_H + +#include "HidReport.h" +#include "hidapi.h" + +const int KMaxHidStringChar=256; + +/** +TODO: move to another header +*/ +class HidDevice + { +public: + HidDevice(); + int Open(const char* aPath); + int Open(unsigned short aVendorId, unsigned short aProductId, const wchar_t* aSerialNumber); + void Close(); + bool IsOpen(); + // + int SetNonBlocking(int aNonBlocking); + //Read + template + int Read(HidReport& aInputReport); + //Write + template + int Write(const HidReport& aOutputReport); + // + const wchar_t* Error(); + // + wchar_t* Vendor(); + wchar_t* Product(); + wchar_t* SerialNumber(); + +private: + void FetchStrings(); + +private: + ///Our USB HID device + hid_device* iHidDevice; + // + wchar_t iVendor[KMaxHidStringChar]; + wchar_t iProduct[KMaxHidStringChar]; + wchar_t iSerialNumber[KMaxHidStringChar]; + }; + + +/** +*/ +template +int HidDevice::Write(const HidReport& aOutputReport) + { + return hid_write(iHidDevice,aOutputReport.Buffer(),S); + } + +/** +*/ +template +int HidDevice::Read(HidReport& aInputReport) + { + return hid_read(iHidDevice,aInputReport.Buffer(),S); + } + + +#endif \ No newline at end of file diff -r 000000000000 -r 0f874d9e4130 HidReport.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/HidReport.h Tue Jun 17 09:55:20 2014 +0200 @@ -0,0 +1,31 @@ +#ifndef HID_REPORT_H +#define HID_REPORT_H + +#include + +/** +Define an HID report. +Can be used as input and output. +*/ +template +class HidReport + { +public: + HidReport(){Reset();} + void Reset(); + inline unsigned char& operator[](int aIndex){return iBuffer[aIndex];} + const unsigned char* Buffer() const {return iBuffer;} + unsigned char* Buffer() {return iBuffer;} + int Size() {return S;} +protected: + unsigned char iBuffer[S]; + }; + +template +void HidReport::Reset() + { + memset(iBuffer,0,sizeof(iBuffer)); + } + + +#endif