Seven segment (#293)

This commit is contained in:
Michael Miller authored and GitHub committed 2019-09-25 00:49:24 -07:00
1 parent 0177b8d519
commit 7c9ac59ddd
10 files changed
+760 -13

No files matched your search

-1
View File
@@ -153,7 +153,6 @@ private:
_duration = duration;
_remaining = duration;
_fnCallback = animUpdate;
}
void StopAnimation()
+2
View File
@@ -43,10 +43,12 @@ License along with NeoPixel. If not, see
#include "internal/HsbColor.h"
#include "internal/HtmlColor.h"
#include "internal/RgbwColor.h"
#include "internal/SegmentDigit.h"
#include "internal/NeoColorFeatures.h"
#include "internal/DotStarColorFeatures.h"
#include "internal/Lpd8806ColorFeatures.h"
#include "internal/NeoSegmentFeatures.h"
#include "internal/Layouts.h"
#include "internal/NeoTopology.h"
+67
View File
@@ -0,0 +1,67 @@
/*-------------------------------------------------------------------------
NeoPixelBus library wrapper template class that provides enhanced methods
for writing to segment based strips
Written by Michael C. Miller.
I invest time and resources providing this open source code,
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
-------------------------------------------------------------------------
This file is part of the Makuna/NeoPixelBus library.
NeoPixelBus 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.
NeoPixelBus 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 NeoPixel. If not, see
<http://www.gnu.org/licenses/>.
-------------------------------------------------------------------------*/
#pragma once
#include "NeoPixelBus.h"
template<typename T_COLOR_FEATURE, typename T_METHOD> class NeoPixelSegmentBus :
public NeoPixelBus<T_COLOR_FEATURE, T_METHOD>
{
public:
NeoPixelSegmentBus(uint16_t countPixels, uint8_t pin) :
NeoPixelBus<T_COLOR_FEATURE, T_METHOD>(countPixels, pin)
{
}
NeoPixelSegmentBus(uint16_t countPixels) :
NeoPixelBus<T_COLOR_FEATURE, T_METHOD>(countPixels)
{
}
void SetString(uint16_t indexDigit,
const char* str,
uint8_t brightness,
uint8_t defaultBrightness = 0)
{
T_COLOR_FEATURE::ColorObject::SetString(*this,
indexDigit,
str,
brightness,
defaultBrightness);
}
void SetString(uint16_t indexDigit,
const String& str,
uint8_t brightness,
uint8_t defaultBrightness = 0)
{
SetString(indexDigit, str.c_str(), brightness, defaultBrightness);
}
};
+4 -9
View File
@@ -45,9 +45,10 @@ public:
uint8_t* pEnd = pPixelDest + (count * PixelSize);
while (pPixelDest < pEnd)
{
*pPixelDest++ = pPixelSrc[0];
*pPixelDest++ = pPixelSrc[1];
*pPixelDest++ = pPixelSrc[2];
for (uint8_t iElement = 0; iElement < PixelSize; iElement++)
{
*pPixelDest++ = pPixelSrc[iElement];
}
}
}
@@ -57,8 +58,6 @@ public:
while (pPixelDest < pEnd)
{
*pPixelDest++ = *pPixelSrc++;
*pPixelDest++ = *pPixelSrc++;
*pPixelDest++ = *pPixelSrc++;
}
}
@@ -69,8 +68,6 @@ public:
while (pPixelDest < pEnd)
{
*pPixelDest++ = pgm_read_byte(pSrc++);
*pPixelDest++ = pgm_read_byte(pSrc++);
*pPixelDest++ = pgm_read_byte(pSrc++);
}
}
@@ -81,8 +78,6 @@ public:
while (pDestBack > pPixelDest)
{
*--pDestBack = *--pSrcBack;
*--pDestBack = *--pSrcBack;
*--pDestBack = *--pSrcBack;
}
}
+22 -3
View File
@@ -94,6 +94,25 @@ public:
free((uint8_t*)_pixels);
}
NeoDib& operator=(const NeoDib& other)
{
// check for self-assignment
if (&other == this)
{
return *this;
}
uint16_t copyCount = other.PixelCount() < PixelCount() ? other.PixelCount() : PixelCount();
for (uint16_t pixel = 0; pixel < copyCount; pixel++)
{
_pixels[pixel] = other.Pixels()[pixel];
}
Dirty();
return *this;
}
T_COLOR_OBJECT* Pixels() const
{
return _pixels;
@@ -144,8 +163,8 @@ public:
Dirty();
};
template <typename T_COLOR_FEATURE, typename T_SHADER> void Render(NeoBufferContext<T_COLOR_FEATURE> destBuffer,
T_SHADER& shader)
template <typename T_COLOR_FEATURE, typename T_SHADER>
void Render(NeoBufferContext<T_COLOR_FEATURE> destBuffer, T_SHADER& shader, uint16_t destIndexPixel = 0)
{
if (IsDirty() || shader.IsDirty())
{
@@ -159,7 +178,7 @@ public:
for (uint16_t indexPixel = 0; indexPixel < countPixels; indexPixel++)
{
T_COLOR_OBJECT color = shader.Apply(indexPixel, _pixels[indexPixel]);
T_COLOR_FEATURE::applyPixelColor(destBuffer.Pixels, indexPixel, color);
T_COLOR_FEATURE::applyPixelColor(destBuffer.Pixels, destIndexPixel + indexPixel, color);
}
shader.ResetDirty();
+130
View File
@@ -0,0 +1,130 @@
/*-------------------------------------------------------------------------
NeoSegmentFeatures provides feature classes to describe seven segment display
elements for NeoPixelBus template class
Written by Michael C. Miller.
I invest time and resources providing this open source code,
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
-------------------------------------------------------------------------
This file is part of the Makuna/NeoPixelBus library.
NeoPixelBus 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.
NeoPixelBus 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 NeoPixel. If not, see
<http://www.gnu.org/licenses/>.
-------------------------------------------------------------------------*/
#pragma once
class Neo9Elements
{
public:
static const size_t PixelSize = 9; // three 3 element
static uint8_t* getPixelAddress(uint8_t* pPixels, uint16_t indexPixel)
{
return pPixels + indexPixel * PixelSize;
}
static const uint8_t* getPixelAddress(const uint8_t* pPixels, uint16_t indexPixel)
{
return pPixels + indexPixel * PixelSize;
}
static void replicatePixel(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count)
{
uint8_t* pEnd = pPixelDest + (count * PixelSize);
while (pPixelDest < pEnd)
{
for (uint8_t iElement = 0; iElement < PixelSize; iElement++)
{
*pPixelDest++ = pPixelSrc[iElement];
}
}
}
static void movePixelsInc(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count)
{
uint8_t* pEnd = pPixelDest + (count * PixelSize);
while (pPixelDest < pEnd)
{
*pPixelDest++ = *pPixelSrc++;
}
}
static void movePixelsInc_P(uint8_t* pPixelDest, PGM_VOID_P pPixelSrc, uint16_t count)
{
uint8_t* pEnd = pPixelDest + (count * PixelSize);
const uint8_t* pSrc = (const uint8_t*)pPixelSrc;
while (pPixelDest < pEnd)
{
*pPixelDest++ = pgm_read_byte(pSrc++);
}
}
static void movePixelsDec(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count)
{
uint8_t* pDestBack = pPixelDest + (count * PixelSize);
const uint8_t* pSrcBack = pPixelSrc + (count * PixelSize);
while (pDestBack > pPixelDest)
{
*--pDestBack = *--pSrcBack;
}
}
typedef SevenSegDigit ColorObject;
};
// Abcdefg byte order
class NeoAbcdefgSegmentFeature : public Neo9Elements
{
public:
static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color)
{
uint8_t* p = getPixelAddress(pPixels, indexPixel);
uint8_t commonSize = (PixelSize < color.SegmentCount) ? PixelSize : color.SegmentCount;
for (uint8_t iSegment = 0; iSegment < commonSize; iSegment++)
{
*p++ = color.Segment[iSegment];
}
}
static ColorObject retrievePixelColor(uint8_t* pPixels, uint16_t indexPixel)
{
ColorObject color;
uint8_t* p = getPixelAddress(pPixels, indexPixel);
uint8_t commonSize = (PixelSize < color.SegmentCount) ? PixelSize : color.SegmentCount;
for (uint8_t iSegment = 0; iSegment < commonSize; iSegment++)
{
color.Segment[iSegment] = *p++;
}
return color;
}
static ColorObject retrievePixelColor_P(PGM_VOID_P pPixels, uint16_t indexPixel)
{
ColorObject color;
const uint8_t* p = getPixelAddress((const uint8_t*)pPixels, indexPixel);
uint8_t commonSize = (PixelSize < color.SegmentCount) ? PixelSize : color.SegmentCount;
for (uint8_t iSegment = 0; iSegment < commonSize; iSegment++)
{
color.Segment[iSegment] = pgm_read_byte(p++);
}
return color;
}
};
typedef NeoAbcdefgSegmentFeature SevenSegmentFeature; // Abcdefg order is default
+153
View File
@@ -0,0 +1,153 @@
/*-------------------------------------------------------------------------
SegmentDigit provides a color object that can be directly consumed by NeoPixelBus
Written by Michael C. Miller.
I invest time and resources providing this open source code,
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
-------------------------------------------------------------------------
This file is part of the Makuna/NeoPixelBus library.
NeoPixelBus 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.
NeoPixelBus 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 NeoPixel. If not, see
<http://www.gnu.org/licenses/>.
-------------------------------------------------------------------------*/
#include "SegmentDigit.h"
//
// https://en.wikichip.org/wiki/seven-segment_display/representing_letters
//
const uint8_t SevenSegDigit::DecodeNumbers[] = {
// 0 1 2 3 4 5 6 7 8 9
0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F };
const uint8_t SevenSegDigit::DecodeAlphaCaps[] = {
// A B C D E F G
0x77, 0x00, 0x39, 0x00, 0x79, 0x71, 0x3D,
// H I J K L M N
0x76, 0x30, 0x1E, 0x00, 0x38, 0x00, 0x00,
// O P Q R S
0x3F, 0x73, 0x00, 0x00, 0x6D,
// T U V W X Y Z
0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00 };
const uint8_t SevenSegDigit::DecodeAlpha[] = {
// a b c d e f g
0x00, 0x7C, 0x58, 0x5E, 0x00, 0x00, 0x00,
// h i j k l m n
0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54,
// o p q r s
0x5C, 0x00, 0x67, 0x50, 0x00,
// t u v w x y z
0x78, 0x1C, 0x00, 0x00, 0x00, 0x6E, 0x00 };
const uint8_t SevenSegDigit::DecodeSpecial[] = {
// , - . /
0x80, 0x40, 0x80, 0x40 };
void SevenSegDigit::init(uint8_t bitmask, uint8_t brightness, uint8_t defaultBrightness)
{
for (uint8_t iSegment = 0; iSegment < SegmentCount; iSegment++)
{
Segment[iSegment] = (bitmask & 0x01) ? brightness : defaultBrightness;
bitmask >>= 1;
}
}
SevenSegDigit::SevenSegDigit(uint8_t bitmask, uint8_t brightness, uint8_t defaultBrightness)
{
init(bitmask, brightness, defaultBrightness);
};
SevenSegDigit::SevenSegDigit(char letter, uint8_t brightness, uint8_t defaultBrightness)
{
if (letter >= '0' && letter <= '9')
{
init(DecodeNumbers[letter - '0'], brightness, defaultBrightness);
}
else if (letter >= 'a' && letter <= 'z')
{
init(DecodeAlpha[letter - 'a'], brightness, defaultBrightness);
}
else if (letter >= 'A' && letter <= 'Z')
{
init(DecodeAlphaCaps[letter - 'A'], brightness, defaultBrightness);
}
else if (letter >= ',' && letter <= '/')
{
init(DecodeSpecial[letter - ','], brightness, defaultBrightness);
}
else
{
memset(Segment, defaultBrightness, sizeof(Segment));
}
};
uint8_t SevenSegDigit::CalculateBrightness() const
{
uint16_t sum = 0;
for (uint8_t iSegment = 0; iSegment < SegmentCount; iSegment++)
{
sum += Segment[iSegment];
}
return (uint8_t)(sum / SegmentCount);
}
void SevenSegDigit::Darken(uint8_t delta)
{
for (uint8_t iSegment = 0; iSegment < SegmentCount; iSegment++)
{
uint8_t element = Segment[iSegment];
if (element > delta)
{
element -= delta;
}
else
{
element = 0;
}
Segment[iSegment] = element;
}
}
void SevenSegDigit::Lighten(uint8_t delta)
{
for (uint8_t iSegment = 0; iSegment < SegmentCount; iSegment++)
{
uint8_t element = Segment[iSegment];
if (element < 255 - delta)
{
element += delta;
}
else
{
element = 255;
}
Segment[iSegment] = element;
}
}
SevenSegDigit SevenSegDigit::LinearBlend(const SevenSegDigit& left, const SevenSegDigit& right, float progress)
{
SevenSegDigit result;
for (uint8_t iSegment = 0; iSegment < SegmentCount; iSegment++)
{
result.Segment[iSegment] = left.Segment[iSegment] + ((right.Segment[iSegment] - left.Segment[iSegment]) * progress);
}
return result;
}
+202
View File
@@ -0,0 +1,202 @@
/*-------------------------------------------------------------------------
SegmentDigit provides a color object that can be directly consumed by NeoPixelBus
Written by Michael C. Miller.
I invest time and resources providing this open source code,
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
-------------------------------------------------------------------------
This file is part of the Makuna/NeoPixelBus library.
NeoPixelBus 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.
NeoPixelBus 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 NeoPixel. If not, see
<http://www.gnu.org/licenses/>.
-------------------------------------------------------------------------*/
#pragma once
#include <Arduino.h>
enum LedSegment
{
LedSegment_A,
LedSegment_B,
LedSegment_C,
LedSegment_D,
LedSegment_E,
LedSegment_F,
LedSegment_G,
LedSegment_Decimal,
LedSegment_COUNT
};
// ------------------------------------------------------------------------
// SevenSegDigit represents a color object that is represented by the segments
// of a 7 segment LED display digit. It contains helpful routines to manipulate
// and set the elements.
//
// The order represents the physical LED location starting at A, through to G, then
// ending at the decimal point
// "abcdefg."
// ------------------------------------------------------------------------
struct SevenSegDigit
{
// ------------------------------------------------------------------------
// Construct a SevenSegDigit using
// the default brightness to apply to all segments
// ------------------------------------------------------------------------
SevenSegDigit(uint8_t defaultBrightness)
{
memset(Segment, defaultBrightness, sizeof(Segment));
}
// ------------------------------------------------------------------------
// Construct a SevenSegDigit using
// a bitmask for the segment (bit order is ".gfedcba")
// the brightness to apply to them, (0-255)
// the default brightness to apply to those not set in the bitmask (0-255)
// ------------------------------------------------------------------------
SevenSegDigit(uint8_t bitmask, uint8_t brightness, uint8_t defaultBrightness = 0);
// ------------------------------------------------------------------------
// Construct a SevenSegDigit using
// a char that will get mapped to the segments,
// the brightness to apply to them, (0-255)
// the default brightness to apply to those not set in the bitmask (0-255)
// ------------------------------------------------------------------------
SevenSegDigit(char letter, uint8_t brightness, uint8_t defaultBrightness = 0);
// ------------------------------------------------------------------------
// Construct a SevenSegDigit that will have its values set in latter operations
// CAUTION: The members are not initialized and may not be consistent
// ------------------------------------------------------------------------
SevenSegDigit()
{
};
// ------------------------------------------------------------------------
// Comparison operators
// ------------------------------------------------------------------------
bool operator==(const SevenSegDigit& other) const
{
for (uint8_t iSegment = 0; iSegment < SegmentCount; iSegment++)
{
if (Segment[iSegment] != other.Segment[iSegment])
{
return false;
}
}
return true;
};
bool operator!=(const SevenSegDigit& other) const
{
return !(*this == other);
};
// ------------------------------------------------------------------------
// CalculateBrightness will calculate the overall brightness
// NOTE: This is a simple linear brightness
// ------------------------------------------------------------------------
uint8_t CalculateBrightness() const;
// ------------------------------------------------------------------------
// Darken will adjust the color by the given delta toward black
// NOTE: This is a simple linear change
// delta - (0-255) the amount to dim the segment
// ------------------------------------------------------------------------
void Darken(uint8_t delta);
// ------------------------------------------------------------------------
// Lighten will adjust the color by the given delta toward white
// NOTE: This is a simple linear change
// delta - (0-255) the amount to lighten the segment
// ------------------------------------------------------------------------
void Lighten(uint8_t delta);
// ------------------------------------------------------------------------
// LinearBlend between two colors by the amount defined by progress variable
// left - the segment to start the blend at
// right - the segment to end the blend at
// progress - (0.0 - 1.0) value where 0 will return left and 1.0 will return right
// and a value between will blend the brightness of each element
// weighted linearly between them
// ------------------------------------------------------------------------
static SevenSegDigit LinearBlend(const SevenSegDigit& left, const SevenSegDigit& right, float progress);
template <typename T_SET_TARGET>
static void SetString(T_SET_TARGET& target, uint16_t indexDigit, const char* str, uint8_t brightness, uint8_t defaultBrightness = 0)
{
if (str == nullptr)
{
return;
}
const char* pFirst = str;
const char* pIter = str;
// digits are right to left
// so find the end
while (*pIter != '\0')
{
pIter++;
}
pIter--;
while (pIter >= pFirst)
{
bool decimal = false;
char value = *pIter;
// check if merging a decimal is required
if (pIter > pFirst && (*pIter == '.' || *pIter == ','))
{
// merge a decimal as long as they aren't the same
if (*(pIter - 1) != *pIter)
{
decimal = true;
pIter--;
value = *pIter; // use the next char
}
}
SevenSegDigit digit(value, brightness, defaultBrightness);
if (decimal)
{
digit.Segment[LedSegment_Decimal] = brightness;
}
target.SetPixelColor(indexDigit, digit);
indexDigit++;
}
}
// ------------------------------------------------------------------------
// segment members (0-255) where each represents the segment location
// and the value defines the brightnes (0) is off and (255) is full brightness
// ------------------------------------------------------------------------
static const uint8_t SegmentCount = 9;
uint8_t Segment[SegmentCount];
// segment decode maps from ascii relative first char in map to a bitmask of segments
//
static const uint8_t DecodeNumbers[10]; // 0-9
static const uint8_t DecodeAlphaCaps[26]; // A-Z
static const uint8_t DecodeAlpha[26]; // a-z
static const uint8_t DecodeSpecial[4]; // , - . /
protected:
void init(uint8_t bitmask, uint8_t brightness, uint8_t defaultBrightness);
};