IP Configuration

This commit is contained in:
Gašper Dobrovoljc
2023-03-11 15:11:03 +01:00
commit ec125f27db
662 changed files with 103738 additions and 0 deletions

View File

@@ -0,0 +1,165 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.

View File

@@ -0,0 +1,35 @@
# NeoPixelBus
[![Donate](https://img.shields.io/badge/paypal-donate-yellow.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=6AA97KE54UJR4)
Arduino NeoPixel library
A library to control one wire protocol RGB and RGBW leds like APA106, SK6812, WS2811, WS2812 and WS2813 that are commonly refered to as NeoPixels and two wire protocol RGB like Lpd8806, APA102 and SK9822 commonly refered to as DotStars.
Supports most Arduino platforms.
Please read this best practices link before connecting your NeoPixels, it will save you a lot of time and effort.
[Adafruit NeoPixel Best Practices](https://learn.adafruit.com/adafruit-neopixel-uberguide/best-practices)
For quick questions and support jump on Gitter and ask away.
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/Makuna/NeoPixelBus?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
For bugs, make sure there isn't an active issue and then create one.
## Why this library and not FastLED or some other library?
See [Why this Library in the Wiki](https://github.com/Makuna/NeoPixelBus/wiki/Library-Comparisons).
## Documentation
[See Wiki](https://github.com/Makuna/NeoPixelBus/wiki)
## Installing This Library (prefered, you just want to use it)
Open the Library Manager and search for "NeoPixelBus by Makuna" and install
## Installing This Library From GitHub (advanced, you want to contribute)
Create a directory in your Arduino\Library folder named "NeoPixelBus"
Clone (Git) this project into that folder.
It should now show up in the import list when you restart Arduino IDE.

View File

@@ -0,0 +1,88 @@
// DotStarTest
// This example will cycle between showing four pixels as Red, Green, Blue, White
// and then showing those pixels as Black.
//
// There is serial output of the current state so you can confirm and follow along
//
#include <NeoPixelBus.h>
const uint16_t PixelCount = 4; // this example assumes 4 pixels, making it smaller will cause a failure
// make sure to set this to the correct pins
const uint8_t DotClockPin = 2;
const uint8_t DotDataPin = 3;
#define colorSaturation 128
// for software bit bang
NeoPixelBus<DotStarBgrFeature, DotStarMethod> strip(PixelCount, DotClockPin, DotDataPin);
// for hardware SPI (best performance but must use hardware pins)
//NeoPixelBus<DotStarBgrFeature, DotStarSpiMethod> strip(PixelCount);
// DotStars that support RGB color and a overall luminance/brightness value
// NeoPixelBus<DotStarLbgrFeature, DotStarMethod> strip(PixelCount, DotClockPin, DotDataPin);
// DotStars that support RGBW color with a seperate white element
//NeoPixelBus<DotStarWbgrFeature, DotStarMethod> strip(PixelCount, DotClockPin, DotDataPin);
RgbColor red(colorSaturation, 0, 0);
RgbColor green(0, colorSaturation, 0);
RgbColor blue(0, 0, colorSaturation);
RgbColor white(colorSaturation);
RgbColor black(0);
// for use with RGB DotStars when using the luminance/brightness global value
// note that its range is only 0 - 31 (31 is full bright) and
// also note that it is not useful for POV displays as it will cause more flicker
RgbwColor redL(colorSaturation, 0, 0, 31); // use white value to store luminance
RgbwColor greenL(0, colorSaturation, 0, 31); // use white value to store luminance
RgbwColor blueL(0, 0, colorSaturation, 31); // use white value to store luminance
RgbwColor whiteL(255, 255, 255, colorSaturation / 8); // luminance is only 0-31
void setup()
{
Serial.begin(115200);
while (!Serial); // wait for serial attach
Serial.println();
Serial.println("Initializing...");
Serial.flush();
// this resets all the neopixels to an off state
strip.Begin();
strip.ClearTo(black);
strip.Show();
Serial.println();
Serial.println("Running...");
}
void loop()
{
delay(5000);
Serial.println("Colors R, G, B, W...");
// set the colors,
strip.SetPixelColor(0, red);
strip.SetPixelColor(1, green);
strip.SetPixelColor(2, blue);
strip.SetPixelColor(3, white);
strip.Show();
delay(5000);
Serial.println("Off ...");
// turn off the pixels
strip.SetPixelColor(0, black);
strip.SetPixelColor(1, black);
strip.SetPixelColor(2, black);
strip.SetPixelColor(3, black);
strip.Show();
}

View File

@@ -0,0 +1,83 @@
// NeoPixelBrightness
// This example will cycle brightness from high to low of
// three pixels colored Red, Green, Blue.
// This demonstrates the use of the NeoPixelBrightnessBus
// with integrated brightness support
//
// There is serial output of the current state so you can
// confirm and follow along
//
#include <NeoPixelBrightnessBus.h> // instead of NeoPixelBus.h
const uint16_t PixelCount = 3; // this example assumes 3 pixels, making it smaller will cause a failure
const uint8_t PixelPin = 14; // make sure to set this to the correct pin, ignored for Esp8266
#define colorSaturation 255 // saturation of color constants
RgbColor red(colorSaturation, 0, 0);
RgbColor green(0, colorSaturation, 0);
RgbColor blue(0, 0, colorSaturation);
// Make sure to provide the correct color order feature
// for your NeoPixels
NeoPixelBrightnessBus<NeoRgbFeature, Neo800KbpsMethod> strip(PixelCount, PixelPin);
// you loose the original color the lower the dim value used
// here due to quantization
const uint8_t c_MinBrightness = 8;
const uint8_t c_MaxBrightness = 255;
int8_t direction; // current direction of dimming
void setup()
{
Serial.begin(115200);
while (!Serial); // wait for serial attach
Serial.println();
Serial.println("Initializing...");
Serial.flush();
// this resets all the neopixels to an off state
strip.Begin();
strip.Show();
direction = -1; // default to dim first
Serial.println();
Serial.println("Running...");
// set our three original colors
strip.SetPixelColor(0, red);
strip.SetPixelColor(1, green);
strip.SetPixelColor(2, blue);
strip.Show();
}
void loop()
{
uint8_t brightness = strip.GetBrightness();
Serial.println(brightness);
delay(100);
// swap diection of dim when limits are reached
//
if (direction < 0 && brightness <= c_MinBrightness)
{
direction = 1;
}
else if (direction > 0 && brightness >= c_MaxBrightness)
{
direction = -1;
}
// apply dimming
brightness += direction;
strip.SetBrightness(brightness);
// show the results
strip.Show();
}

View File

@@ -0,0 +1,95 @@
// NeoPixelGamma
// This example will display a timed series of color gradiants with gamma correction
// and then without.
// If the last pixel is on, then the colors being shown are color corrected.
// It will show Red grandiant, Green grandiant, Blue grandiant, a White grandiant, and
// then repeat.
//
// This will demonstrate the use of the NeoGamma class
//
//
#include <NeoPixelBus.h>
#include <NeoPixelAnimator.h>
const uint16_t PixelCount = 16; // make sure to set this to the number of pixels in your strip
const uint8_t PixelPin = 2; // make sure to set this to the correct pin, ignored for Esp8266
NeoPixelBus<NeoGrbFeature, Neo800KbpsMethod> strip(PixelCount, PixelPin);
// for esp8266 omit the pin
//NeoPixelBus<NeoGrbFeature, Neo800KbpsMethod> strip(PixelCount);
// uncomment only one of these to compare memory use or speed
//
// NeoGamma<NeoGammaEquationMethod> colorGamma;
NeoGamma<NeoGammaTableMethod> colorGamma;
void DrawPixels(bool corrected, HslColor startColor, HslColor stopColor)
{
for (uint16_t index = 0; index < strip.PixelCount() - 1; index++)
{
float progress = index / static_cast<float>(strip.PixelCount() - 2);
RgbColor color = HslColor::LinearBlend<NeoHueBlendShortestDistance>(startColor, stopColor, progress);
if (corrected)
{
color = colorGamma.Correct(color);
}
strip.SetPixelColor(index, color);
}
// use the last pixel to indicate if we are showing corrected colors or not
if (corrected)
{
strip.SetPixelColor(strip.PixelCount() - 1, RgbColor(64));
}
else
{
strip.SetPixelColor(strip.PixelCount() - 1, RgbColor(0));
}
strip.Show();
}
void setup()
{
strip.Begin();
strip.Show();
}
void loop()
{
HslColor startColor;
HslColor stopColor;
// red color
startColor = HslColor(0.0f, 1.0f, 0.0f);
stopColor = HslColor(0.0f, 1.0f, 0.5f);
DrawPixels(true, startColor, stopColor);
delay(5000);
DrawPixels(false, startColor, stopColor);
delay(5000);
// green color
startColor = HslColor(0.33f, 1.0f, 0.0f);
stopColor = HslColor(0.33f, 1.0f, 0.5f);
DrawPixels(true, startColor, stopColor);
delay(5000);
DrawPixels(false, startColor, stopColor);
delay(5000);
// blue color
startColor = HslColor(0.66f, 1.0f, 0.0f);
stopColor = HslColor(0.66f, 1.0f, 0.5f);
DrawPixels(true, startColor, stopColor);
delay(5000);
DrawPixels(false, startColor, stopColor);
delay(5000);
// white color
startColor = HslColor(0.0f, 0.0f, 0.0f);
stopColor = HslColor(0.0f, 0.0f, 0.5f);
DrawPixels(true, startColor, stopColor);
delay(5000);
DrawPixels(false, startColor, stopColor);
delay(5000);
}

View File

@@ -0,0 +1,139 @@
// NeoPixelTest
// This example will cycle between showing four pixels as Red, Green, Blue, White
// and then showing those pixels as Black.
//
// Included but commented out are examples of configuring a NeoPixelBus for
// different color order including an extra white channel, different data speeds, and
// for Esp8266 different methods to send the data.
// NOTE: You will need to make sure to pick the one for your platform
//
//
// There is serial output of the current state so you can confirm and follow along
//
#include <NeoPixelBus.h>
const uint16_t PixelCount = 4; // this example assumes 4 pixels, making it smaller will cause a failure
const uint8_t PixelPin = 2; // make sure to set this to the correct pin, ignored for Esp8266
#define colorSaturation 128
// three element pixels, in different order and speeds
NeoPixelBus<NeoGrbFeature, Neo800KbpsMethod> strip(PixelCount, PixelPin);
//NeoPixelBus<NeoRgbFeature, Neo400KbpsMethod> strip(PixelCount, PixelPin);
// For Esp8266, the Pin is omitted and it uses GPIO3 due to DMA hardware use.
// There are other Esp8266 alternative methods that provide more pin options, but also have
// other side effects.
// for details see wiki linked here https://github.com/Makuna/NeoPixelBus/wiki/ESP8266-NeoMethods
// You can also use one of these for Esp8266,
// each having their own restrictions
//
// These two are the same as above as the DMA method is the default
// NOTE: These will ignore the PIN and use GPI03 pin
//NeoPixelBus<NeoGrbFeature, NeoEsp8266Dma800KbpsMethod> strip(PixelCount, PixelPin);
//NeoPixelBus<NeoRgbFeature, NeoEsp8266Dma400KbpsMethod> strip(PixelCount, PixelPin);
// Uart method is good for the Esp-01 or other pin restricted modules
// for details see wiki linked here https://github.com/Makuna/NeoPixelBus/wiki/ESP8266-NeoMethods
// NOTE: These will ignore the PIN and use GPI02 pin
//NeoPixelBus<NeoGrbFeature, NeoEsp8266Uart1800KbpsMethod> strip(PixelCount, PixelPin);
//NeoPixelBus<NeoRgbFeature, NeoEsp8266Uart1400KbpsMethod> strip(PixelCount, PixelPin);
// The bitbang method is really only good if you are not using WiFi features of the ESP
// It works with all but pin 16
//NeoPixelBus<NeoGrbFeature, NeoEsp8266BitBang800KbpsMethod> strip(PixelCount, PixelPin);
//NeoPixelBus<NeoRgbFeature, NeoEsp8266BitBang400KbpsMethod> strip(PixelCount, PixelPin);
// four element pixels, RGBW
//NeoPixelBus<NeoRgbwFeature, Neo800KbpsMethod> strip(PixelCount, PixelPin);
RgbColor red(colorSaturation, 0, 0);
RgbColor green(0, colorSaturation, 0);
RgbColor blue(0, 0, colorSaturation);
RgbColor white(colorSaturation);
RgbColor black(0);
HslColor hslRed(red);
HslColor hslGreen(green);
HslColor hslBlue(blue);
HslColor hslWhite(white);
HslColor hslBlack(black);
void setup()
{
Serial.begin(115200);
while (!Serial); // wait for serial attach
Serial.println();
Serial.println("Initializing...");
Serial.flush();
// this resets all the neopixels to an off state
strip.Begin();
strip.Show();
Serial.println();
Serial.println("Running...");
}
void loop()
{
delay(5000);
Serial.println("Colors R, G, B, W...");
// set the colors,
// if they don't match in order, you need to use NeoGrbFeature feature
strip.SetPixelColor(0, red);
strip.SetPixelColor(1, green);
strip.SetPixelColor(2, blue);
strip.SetPixelColor(3, white);
// the following line demonstrates rgbw color support
// if the NeoPixels are rgbw types the following line will compile
// if the NeoPixels are anything else, the following line will give an error
//strip.SetPixelColor(3, RgbwColor(colorSaturation));
strip.Show();
delay(5000);
Serial.println("Off ...");
// turn off the pixels
strip.SetPixelColor(0, black);
strip.SetPixelColor(1, black);
strip.SetPixelColor(2, black);
strip.SetPixelColor(3, black);
strip.Show();
delay(5000);
Serial.println("HSL Colors R, G, B, W...");
// set the colors,
// if they don't match in order, you may need to use NeoGrbFeature feature
strip.SetPixelColor(0, hslRed);
strip.SetPixelColor(1, hslGreen);
strip.SetPixelColor(2, hslBlue);
strip.SetPixelColor(3, hslWhite);
strip.Show();
delay(5000);
Serial.println("Off again...");
// turn off the pixels
strip.SetPixelColor(0, hslBlack);
strip.SetPixelColor(1, hslBlack);
strip.SetPixelColor(2, hslBlack);
strip.SetPixelColor(3, hslBlack);
strip.Show();
}

View File

@@ -0,0 +1,222 @@
// NeoPixelAnimation
// This example will randomly pick a new color for each pixel and animate
// the current color to the new color over a random small amount of time, using
// a randomly selected animation curve.
// It will repeat this process once all pixels have finished the animation
//
// This will demonstrate the use of the NeoPixelAnimator extended time feature.
// This feature allows for different time scales to be used, allowing slow extended
// animations to be created.
//
// This will demonstrate the use of the NeoEase animation ease methods; that provide
// simulated acceleration to the animations.
//
// It also includes platform specific code for Esp8266 that demonstrates easy
// animation state and function definition inline. This is not available on AVR
// Arduinos; but the AVR compatible code is also included for comparison.
//
// The example includes some serial output that you can follow along with as it
// does the animation.
//
#include <NeoPixelBus.h>
#include <NeoPixelAnimator.h>
const uint16_t PixelCount = 4; // make sure to set this to the number of pixels in your strip
const uint8_t PixelPin = 2; // make sure to set this to the correct pin, ignored for Esp8266
NeoPixelBus<NeoGrbFeature, Neo800KbpsMethod> strip(PixelCount, PixelPin);
// For Esp8266, the Pin is omitted and it uses GPIO3 due to DMA hardware use.
// There are other Esp8266 alternative methods that provide more pin options, but also have
// other side effects.
// for details see wiki linked here https://github.com/Makuna/NeoPixelBus/wiki/ESP8266-NeoMethods
// NeoPixel animation time management object
NeoPixelAnimator animations(PixelCount, NEO_CENTISECONDS);
// create with enough animations to have one per pixel, depending on the animation
// effect, you may need more or less.
//
// since the normal animation time range is only about 65 seconds, by passing timescale value
// to the NeoPixelAnimator constructor we can increase the time range, but we also increase
// the time between the animation updates.
// NEO_CENTISECONDS will update the animations every 100th of a second rather than the default
// of a 1000th of a second, but the time range will now extend from about 65 seconds to about
// 10.9 minutes. But you must remember that the values passed to StartAnimations are now
// in centiseconds.
//
// Possible values from 1 to 32768, and there some helpful constants defined as...
// NEO_MILLISECONDS 1 // ~65 seconds max duration, ms updates
// NEO_CENTISECONDS 10 // ~10.9 minutes max duration, centisecond updates
// NEO_DECISECONDS 100 // ~1.8 hours max duration, decisecond updates
// NEO_SECONDS 1000 // ~18.2 hours max duration, second updates
// NEO_DECASECONDS 10000 // ~7.5 days, 10 second updates
//
#if defined(NEOPIXEBUS_NO_STL)
// for AVR, you need to manage the state due to lack of STL/compiler support
// for Esp8266 you can define the function using a lambda and state is created for you
// see below for an example
struct MyAnimationState
{
RgbColor StartingColor; // the color the animation starts at
RgbColor EndingColor; // the color the animation will end at
AnimEaseFunction Easeing; // the acceleration curve it will use
};
MyAnimationState animationState[PixelCount];
// one entry per pixel to match the animation timing manager
void AnimUpdate(const AnimationParam& param)
{
// first apply an easing (curve) to the animation
// this simulates acceleration to the effect
float progress = animationState[param.index].Easeing(param.progress);
// this gets called for each animation on every time step
// progress will start at 0.0 and end at 1.0
// we use the blend function on the RgbColor to mix
// color based on the progress given to us in the animation
RgbColor updatedColor = RgbColor::LinearBlend(
animationState[param.index].StartingColor,
animationState[param.index].EndingColor,
progress);
// apply the color to the strip
strip.SetPixelColor(param.index, updatedColor);
}
#endif
void SetRandomSeed()
{
uint32_t seed;
// random works best with a seed that can use 31 bits
// analogRead on a unconnected pin tends toward less than four bits
seed = analogRead(0);
delay(1);
for (int shifts = 3; shifts < 31; shifts += 3)
{
seed ^= analogRead(0) << shifts;
delay(1);
}
// Serial.println(seed);
randomSeed(seed);
}
void setup()
{
Serial.begin(115200);
while (!Serial); // wait for serial attach
strip.Begin();
strip.Show();
SetRandomSeed();
// just pick some colors
for (uint16_t pixel = 0; pixel < PixelCount; pixel++)
{
RgbColor color = RgbColor(random(255), random(255), random(255));
strip.SetPixelColor(pixel, color);
}
Serial.println();
Serial.println("Running...");
}
void SetupAnimationSet()
{
// setup some animations
for (uint16_t pixel = 0; pixel < PixelCount; pixel++)
{
const uint8_t peak = 128;
// pick a random duration of the animation for this pixel
// since values are centiseconds, the range is 1 - 4 seconds
uint16_t time = random(100, 400);
// each animation starts with the color that was present
RgbColor originalColor = strip.GetPixelColor(pixel);
// and ends with a random color
RgbColor targetColor = RgbColor(random(peak), random(peak), random(peak));
// with the random ease function
AnimEaseFunction easing;
switch (random(3))
{
case 0:
easing = NeoEase::CubicIn;
break;
case 1:
easing = NeoEase::CubicOut;
break;
case 2:
easing = NeoEase::QuadraticInOut;
break;
}
#if defined(NEOPIXEBUS_NO_STL)
// each animation starts with the color that was present
animationState[pixel].StartingColor = originalColor;
// and ends with a random color
animationState[pixel].EndingColor = targetColor;
// using the specific curve
animationState[pixel].Easeing = easing;
// now use the animation state we just calculated and start the animation
// which will continue to run and call the update function until it completes
animations.StartAnimation(pixel, time, AnimUpdate);
#else
// we must supply a function that will define the animation, in this example
// we are using "lambda expression" to define the function inline, which gives
// us an easy way to "capture" the originalColor and targetColor for the call back.
//
// this function will get called back when ever the animation needs to change
// the state of the pixel, it will provide a animation progress value
// from 0.0 (start of animation) to 1.0 (end of animation)
//
// we use this progress value to define how we want to animate in this case
// we call RgbColor::LinearBlend which will return a color blended between
// the values given, by the amount passed, hich is also a float value from 0.0-1.0.
// then we set the color.
//
// There is no need for the MyAnimationState struct as the compiler takes care
// of those details for us
AnimUpdateCallback animUpdate = [=](const AnimationParam& param)
{
// progress will start at 0.0 and end at 1.0
// we convert to the curve we want
float progress = easing(param.progress);
// use the curve value to apply to the animation
RgbColor updatedColor = RgbColor::LinearBlend(originalColor, targetColor, progress);
strip.SetPixelColor(pixel, updatedColor);
};
// now use the animation properties we just calculated and start the animation
// which will continue to run and call the update function until it completes
animations.StartAnimation(pixel, time, animUpdate);
#endif
}
}
void loop()
{
if (animations.IsAnimating())
{
// the normal loop just needs these two to run the active animations
animations.UpdateAnimations();
strip.Show();
}
else
{
Serial.println();
Serial.println("Setup Next Set...");
// example function that sets up some animations
SetupAnimationSet();
}
}

View File

@@ -0,0 +1,123 @@
// NeoPixelCylon
// This example will move a Cylon Red Eye back and forth across the
// the full collection of pixels on the strip.
//
// This will demonstrate the use of the NeoEase animation ease methods; that provide
// simulated acceleration to the animations.
//
//
#include <NeoPixelBus.h>
#include <NeoPixelAnimator.h>
const uint16_t PixelCount = 16; // make sure to set this to the number of pixels in your strip
const uint8_t PixelPin = 2; // make sure to set this to the correct pin, ignored for Esp8266
const RgbColor CylonEyeColor(HtmlColor(0x7f0000));
NeoPixelBus<NeoGrbFeature, Neo800KbpsMethod> strip(PixelCount, PixelPin);
// for esp8266 omit the pin
//NeoPixelBus<NeoGrbFeature, Neo800KbpsMethod> strip(PixelCount);
NeoPixelAnimator animations(2); // only ever need 2 animations
uint16_t lastPixel = 0; // track the eye position
int8_t moveDir = 1; // track the direction of movement
// uncomment one of the lines below to see the effects of
// changing the ease function on the movement animation
AnimEaseFunction moveEase =
// NeoEase::Linear;
// NeoEase::QuadraticInOut;
// NeoEase::CubicInOut;
NeoEase::QuarticInOut;
// NeoEase::QuinticInOut;
// NeoEase::SinusoidalInOut;
// NeoEase::ExponentialInOut;
// NeoEase::CircularInOut;
void FadeAll(uint8_t darkenBy)
{
RgbColor color;
for (uint16_t indexPixel = 0; indexPixel < strip.PixelCount(); indexPixel++)
{
color = strip.GetPixelColor(indexPixel);
color.Darken(darkenBy);
strip.SetPixelColor(indexPixel, color);
}
}
void FadeAnimUpdate(const AnimationParam& param)
{
if (param.state == AnimationState_Completed)
{
FadeAll(10);
animations.RestartAnimation(param.index);
}
}
void MoveAnimUpdate(const AnimationParam& param)
{
// apply the movement animation curve
float progress = moveEase(param.progress);
// use the curved progress to calculate the pixel to effect
uint16_t nextPixel;
if (moveDir > 0)
{
nextPixel = progress * PixelCount;
}
else
{
nextPixel = (1.0f - progress) * PixelCount;
}
// if progress moves fast enough, we may move more than
// one pixel, so we update all between the calculated and
// the last
if (lastPixel != nextPixel)
{
for (uint16_t i = lastPixel + moveDir; i != nextPixel; i += moveDir)
{
strip.SetPixelColor(i, CylonEyeColor);
}
}
strip.SetPixelColor(nextPixel, CylonEyeColor);
lastPixel = nextPixel;
if (param.state == AnimationState_Completed)
{
// reverse direction of movement
moveDir *= -1;
// done, time to restart this position tracking animation/timer
animations.RestartAnimation(param.index);
}
}
void SetupAnimations()
{
// fade all pixels providing a tail that is longer the faster
// the pixel moves.
animations.StartAnimation(0, 5, FadeAnimUpdate);
// take several seconds to move eye fron one side to the other
animations.StartAnimation(1, 2000, MoveAnimUpdate);
}
void setup()
{
strip.Begin();
strip.Show();
SetupAnimations();
}
void loop()
{
// this is all that is needed to keep it running
// and avoiding using delay() is always a good thing for
// any timing related routines
animations.UpdateAnimations();
strip.Show();
}

View File

@@ -0,0 +1,130 @@
// NeoPixelFunFadeInOut
// This example will randomly pick a color and fade all pixels to that color, then
// it will fade them to black and restart over
//
// This example demonstrates the use of a single animation channel to animate all
// the pixels at once.
//
#include <NeoPixelBus.h>
#include <NeoPixelAnimator.h>
const uint16_t PixelCount = 16; // make sure to set this to the number of pixels in your strip
const uint8_t PixelPin = 2; // make sure to set this to the correct pin, ignored for Esp8266
const uint8_t AnimationChannels = 1; // we only need one as all the pixels are animated at once
NeoPixelBus<NeoGrbFeature, Neo800KbpsMethod> strip(PixelCount, PixelPin);
// For Esp8266, the Pin is omitted and it uses GPIO3 due to DMA hardware use.
// There are other Esp8266 alternative methods that provide more pin options, but also have
// other side effects.
// for details see wiki linked here https://github.com/Makuna/NeoPixelBus/wiki/ESP8266-NeoMethods
NeoPixelAnimator animations(AnimationChannels); // NeoPixel animation management object
boolean fadeToColor = true; // general purpose variable used to store effect state
// what is stored for state is specific to the need, in this case, the colors.
// basically what ever you need inside the animation update function
struct MyAnimationState
{
RgbColor StartingColor;
RgbColor EndingColor;
};
// one entry per pixel to match the animation timing manager
MyAnimationState animationState[AnimationChannels];
void SetRandomSeed()
{
uint32_t seed;
// random works best with a seed that can use 31 bits
// analogRead on a unconnected pin tends toward less than four bits
seed = analogRead(0);
delay(1);
for (int shifts = 3; shifts < 31; shifts += 3)
{
seed ^= analogRead(0) << shifts;
delay(1);
}
randomSeed(seed);
}
// simple blend function
void BlendAnimUpdate(const AnimationParam& param)
{
// this gets called for each animation on every time step
// progress will start at 0.0 and end at 1.0
// we use the blend function on the RgbColor to mix
// color based on the progress given to us in the animation
RgbColor updatedColor = RgbColor::LinearBlend(
animationState[param.index].StartingColor,
animationState[param.index].EndingColor,
param.progress);
// apply the color to the strip
for (uint16_t pixel = 0; pixel < PixelCount; pixel++)
{
strip.SetPixelColor(pixel, updatedColor);
}
}
void FadeInFadeOutRinseRepeat(float luminance)
{
if (fadeToColor)
{
// Fade upto a random color
// we use HslColor object as it allows us to easily pick a hue
// with the same saturation and luminance so the colors picked
// will have similiar overall brightness
RgbColor target = HslColor(random(360) / 360.0f, 1.0f, luminance);
uint16_t time = random(800, 2000);
animationState[0].StartingColor = strip.GetPixelColor(0);
animationState[0].EndingColor = target;
animations.StartAnimation(0, time, BlendAnimUpdate);
}
else
{
// fade to black
uint16_t time = random(600, 700);
animationState[0].StartingColor = strip.GetPixelColor(0);
animationState[0].EndingColor = RgbColor(0);
animations.StartAnimation(0, time, BlendAnimUpdate);
}
// toggle to the next effect state
fadeToColor = !fadeToColor;
}
void setup()
{
strip.Begin();
strip.Show();
SetRandomSeed();
}
void loop()
{
if (animations.IsAnimating())
{
// the normal loop just needs these two to run the active animations
animations.UpdateAnimations();
strip.Show();
}
else
{
// no animation runnning, start some
//
FadeInFadeOutRinseRepeat(0.2f); // 0.0 = black, 0.25 is normal, 0.5 is bright
}
}

View File

@@ -0,0 +1,139 @@
// NeoPixelFunLoop
// This example will move a trail of light around a series of pixels.
// A ring formation of pixels looks best.
// The trail will have a slowly fading tail.
//
// This will demonstrate the use of the NeoPixelAnimator.
// It shows the advanced use an animation to control the modification and
// starting of other animations.
// It also shows the normal use of animating colors.
// It also demonstrates the ability to share an animation channel rather than
// hard code them to pixels.
//
#include <NeoPixelBus.h>
#include <NeoPixelAnimator.h>
const uint16_t PixelCount = 16; // make sure to set this to the number of pixels in your strip
const uint16_t PixelPin = 2; // make sure to set this to the correct pin, ignored for Esp8266
const uint16_t AnimCount = PixelCount / 5 * 2 + 1; // we only need enough animations for the tail and one extra
const uint16_t PixelFadeDuration = 300; // third of a second
// one second divide by the number of pixels = loop once a second
const uint16_t NextPixelMoveDuration = 1000 / PixelCount; // how fast we move through the pixels
NeoGamma<NeoGammaTableMethod> colorGamma; // for any fade animations, best to correct gamma
NeoPixelBus<NeoGrbFeature, Neo800KbpsMethod> strip(PixelCount, PixelPin);
// For Esp8266, the Pin is omitted and it uses GPIO3 due to DMA hardware use.
// There are other Esp8266 alternative methods that provide more pin options, but also have
// other side effects.
// for details see wiki linked here https://github.com/Makuna/NeoPixelBus/wiki/ESP8266-NeoMethods
// what is stored for state is specific to the need, in this case, the colors and
// the pixel to animate;
// basically what ever you need inside the animation update function
struct MyAnimationState
{
RgbColor StartingColor;
RgbColor EndingColor;
uint16_t IndexPixel; // which pixel this animation is effecting
};
NeoPixelAnimator animations(AnimCount); // NeoPixel animation management object
MyAnimationState animationState[AnimCount];
uint16_t frontPixel = 0; // the front of the loop
RgbColor frontColor; // the color at the front of the loop
void SetRandomSeed()
{
uint32_t seed;
// random works best with a seed that can use 31 bits
// analogRead on a unconnected pin tends toward less than four bits
seed = analogRead(0);
delay(1);
for (int shifts = 3; shifts < 31; shifts += 3)
{
seed ^= analogRead(0) << shifts;
delay(1);
}
// Serial.println(seed);
randomSeed(seed);
}
void FadeOutAnimUpdate(const AnimationParam& param)
{
// this gets called for each animation on every time step
// progress will start at 0.0 and end at 1.0
// we use the blend function on the RgbColor to mix
// color based on the progress given to us in the animation
RgbColor updatedColor = RgbColor::LinearBlend(
animationState[param.index].StartingColor,
animationState[param.index].EndingColor,
param.progress);
// apply the color to the strip
strip.SetPixelColor(animationState[param.index].IndexPixel,
colorGamma.Correct(updatedColor));
}
void LoopAnimUpdate(const AnimationParam& param)
{
// wait for this animation to complete,
// we are using it as a timer of sorts
if (param.state == AnimationState_Completed)
{
// done, time to restart this position tracking animation/timer
animations.RestartAnimation(param.index);
// pick the next pixel inline to start animating
//
frontPixel = (frontPixel + 1) % PixelCount; // increment and wrap
if (frontPixel == 0)
{
// we looped, lets pick a new front color
frontColor = HslColor(random(360) / 360.0f, 1.0f, 0.25f);
}
uint16_t indexAnim;
// do we have an animation available to use to animate the next front pixel?
// if you see skipping, then either you are going to fast or need to increase
// the number of animation channels
if (animations.NextAvailableAnimation(&indexAnim, 1))
{
animationState[indexAnim].StartingColor = frontColor;
animationState[indexAnim].EndingColor = RgbColor(0, 0, 0);
animationState[indexAnim].IndexPixel = frontPixel;
animations.StartAnimation(indexAnim, PixelFadeDuration, FadeOutAnimUpdate);
}
}
}
void setup()
{
strip.Begin();
strip.Show();
SetRandomSeed();
// we use the index 0 animation to time how often we move to the next
// pixel in the strip
animations.StartAnimation(0, NextPixelMoveDuration, LoopAnimUpdate);
}
void loop()
{
// this is all that is needed to keep it running
// and avoiding using delay() is always a good thing for
// any timing related routines
animations.UpdateAnimations();
strip.Show();
}

View File

@@ -0,0 +1,114 @@
// NeoPixelFunRandomChange
// This example will randomly select a number pixels and then
// start an animation to blend them from their current color to
// randomly selected a color
//
#include <NeoPixelBus.h>
#include <NeoPixelAnimator.h>
const uint16_t PixelCount = 16; // make sure to set this to the number of pixels in your strip
const uint8_t PixelPin = 2; // make sure to set this to the correct pin, ignored for Esp8266
NeoPixelBus<NeoGrbFeature, Neo800KbpsMethod> strip(PixelCount, PixelPin);
// For Esp8266, the Pin is omitted and it uses GPIO3 due to DMA hardware use.
// There are other Esp8266 alternative methods that provide more pin options, but also have
// other side effects.
// for details see wiki linked here https://github.com/Makuna/NeoPixelBus/wiki/ESP8266-NeoMethods
NeoPixelAnimator animations(PixelCount); // NeoPixel animation management object
// what is stored for state is specific to the need, in this case, the colors.
// Basically what ever you need inside the animation update function
struct MyAnimationState
{
RgbColor StartingColor;
RgbColor EndingColor;
};
// one entry per pixel to match the animation timing manager
MyAnimationState animationState[PixelCount];
void SetRandomSeed()
{
uint32_t seed;
// random works best with a seed that can use 31 bits
// analogRead on a unconnected pin tends toward less than four bits
seed = analogRead(0);
delay(1);
for (int shifts = 3; shifts < 31; shifts += 3)
{
seed ^= analogRead(0) << shifts;
delay(1);
}
// Serial.println(seed);
randomSeed(seed);
}
// simple blend function
void BlendAnimUpdate(const AnimationParam& param)
{
// this gets called for each animation on every time step
// progress will start at 0.0 and end at 1.0
// we use the blend function on the RgbColor to mix
// color based on the progress given to us in the animation
RgbColor updatedColor = RgbColor::LinearBlend(
animationState[param.index].StartingColor,
animationState[param.index].EndingColor,
param.progress);
// apply the color to the strip
strip.SetPixelColor(param.index, updatedColor);
}
void PickRandom(float luminance)
{
// pick random count of pixels to animate
uint16_t count = random(PixelCount);
while (count > 0)
{
// pick a random pixel
uint16_t pixel = random(PixelCount);
// pick random time and random color
// we use HslColor object as it allows us to easily pick a color
// with the same saturation and luminance
uint16_t time = random(100, 400);
animationState[pixel].StartingColor = strip.GetPixelColor(pixel);
animationState[pixel].EndingColor = HslColor(random(360) / 360.0f, 1.0f, luminance);
animations.StartAnimation(pixel, time, BlendAnimUpdate);
count--;
}
}
void setup()
{
strip.Begin();
strip.Show();
SetRandomSeed();
}
void loop()
{
if (animations.IsAnimating())
{
// the normal loop just needs these two to run the active animations
animations.UpdateAnimations();
strip.Show();
}
else
{
// no animations runnning, start some
//
PickRandom(0.2f); // 0.0 = black, 0.25 is normal, 0.5 is bright
}
}

View File

@@ -0,0 +1,97 @@
// NeoPixelFunLoop
// This example will move a trail of light around a series of pixels.
// A ring formation of pixels looks best.
// The trail will have a slowly fading tail.
//
// This will demonstrate the use of the RotateRight method.
//
#include <NeoPixelBus.h>
#include <NeoPixelAnimator.h>
const uint16_t PixelCount = 16; // make sure to set this to the number of pixels in your strip
const uint16_t PixelPin = 2; // make sure to set this to the correct pin, ignored for Esp8266
const uint16_t AnimCount = 1; // we only need one
const uint16_t TailLength = 6; // length of the tail, must be shorter than PixelCount
const float MaxLightness = 0.4f; // max lightness at the head of the tail (0.5f is full bright)
NeoGamma<NeoGammaTableMethod> colorGamma; // for any fade animations, best to correct gamma
NeoPixelBus<NeoGrbFeature, Neo800KbpsMethod> strip(PixelCount, PixelPin);
// for esp8266 omit the pin
//NeoPixelBus<NeoGrbFeature, Neo800KbpsMethod> strip(PixelCount);
NeoPixelAnimator animations(AnimCount); // NeoPixel animation management object
void SetRandomSeed()
{
uint32_t seed;
// random works best with a seed that can use 31 bits
// analogRead on a unconnected pin tends toward less than four bits
seed = analogRead(0);
delay(1);
for (int shifts = 3; shifts < 31; shifts += 3)
{
seed ^= analogRead(0) << shifts;
delay(1);
}
// Serial.println(seed);
randomSeed(seed);
}
void LoopAnimUpdate(const AnimationParam& param)
{
// wait for this animation to complete,
// we are using it as a timer of sorts
if (param.state == AnimationState_Completed)
{
// done, time to restart this position tracking animation/timer
animations.RestartAnimation(param.index);
// rotate the complete strip one pixel to the right on every update
strip.RotateRight(1);
}
}
void DrawTailPixels()
{
// using Hsl as it makes it easy to pick from similiar saturated colors
float hue = random(360) / 360.0f;
for (uint16_t index = 0; index < strip.PixelCount() && index <= TailLength; index++)
{
float lightness = index * MaxLightness / TailLength;
RgbColor color = HslColor(hue, 1.0f, lightness);
strip.SetPixelColor(index, colorGamma.Correct(color));
}
}
void setup()
{
strip.Begin();
strip.Show();
SetRandomSeed();
// Draw the tail that will be rotated through all the rest of the pixels
DrawTailPixels();
// we use the index 0 animation to time how often we rotate all the pixels
animations.StartAnimation(0, 66, LoopAnimUpdate);
}
void loop()
{
// this is all that is needed to keep it running
// and avoiding using delay() is always a good thing for
// any timing related routines
animations.UpdateAnimations();
strip.Show();
}

View File

@@ -0,0 +1,98 @@
// NeoPixelBuffer
// This example will animate pixels using a bitmap stored on a SD card
//
//
// This will demonstrate the use of the NeoBitmapFile object
// NOTE: The images provided in the example directory should be copied to
// the root of the SD card so the below code will find it.
// NOTE: This sample and the included images were built for a 144 pixel strip so
// running this with a smaller string may not look as interesting. Try providing
// your own 24 bit bitmap for better results.
#include <NeoPixelBus.h>
#include <NeoPixelAnimator.h>
#include <SPI.h>
#include <SD.h>
const int chipSelect = D8; // make sure to set this to your SD carder reader CS
//typedef NeoGrbFeature MyPixelColorFeature;
typedef NeoGrbwFeature MyPixelColorFeature;
const uint16_t PixelCount = 144; // the sample images are meant for 144 pixels
const uint16_t PixelPin = 2;
const uint16_t AnimCount = 1; // we only need one
NeoPixelBus<MyPixelColorFeature, Neo800KbpsMethod> strip(PixelCount, PixelPin);
// for esp8266 omit the pin
//NeoPixelBus<MyPixelColorFeature, Neo800KbpsMethod> strip(PixelCount);
NeoPixelAnimator animations(AnimCount); // NeoPixel animation management object
// our NeoBitmapFile will use the same color feature as NeoPixelBus and
// we want it to use the SD File object
NeoBitmapFile<MyPixelColorFeature, File> image;
uint16_t animState;
void LoopAnimUpdate(const AnimationParam& param)
{
// wait for this animation to complete,
// we are using it as a timer of sorts
if (param.state == AnimationState_Completed)
{
// done, time to restart this position tracking animation/timer
animations.RestartAnimation(param.index);
// draw the complete row at animState to the complete strip
image.Blt(strip, 0, 0, animState, image.Width());
animState = (animState + 1) % image.Height(); // increment and wrap
}
}
void setup() {
Serial.begin(115200);
while (!Serial); // wait for serial attach
strip.Begin();
strip.Show();
Serial.print("Initializing SD card...");
// see if the card is present and can be initialized:
if (!SD.begin(chipSelect))
{
Serial.println("Card failed, or not present");
// don't do anything more:
return;
}
Serial.println("card initialized.");
// open the file
File bitmapFile = SD.open("strings.bmp");
if (!bitmapFile)
{
Serial.println("File open fail, or not present");
// don't do anything more:
return;
}
// initialize the image with the file
if (!image.Begin(bitmapFile))
{
Serial.println("File format fail, not a supported bitmap");
// don't do anything more:
return;
}
animState = 0;
// we use the index 0 animation to time how often we rotate all the pixels
animations.StartAnimation(0, 30, LoopAnimUpdate);
}
void loop() {
// this is all that is needed to keep it running
// and avoiding using delay() is always a good thing for
// any timing related routines
animations.UpdateAnimations();
strip.Show();
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

View File

@@ -0,0 +1,30 @@
// To recreate the data below, use the Paint.Net plugin "Arduino Progmem NeoPixel FileType"
// to save as/export the included Cylon.pdn
// Paint.Net - http://www.getpaint.net/download.html#download
// Plugin - http://forums.getpaint.net/index.php?/topic/107921-arduino-neopixel-sketch-exporter/
// This uses Flatten, GRB, Hexadecimal
//
const uint16_t myImageWidth = 16;
const uint16_t myImageHeight = 20;
const uint8_t PROGMEM myImage[] = { // (16 x 20) GRB in Hexadecimal
0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x3f, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x7f, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x7f, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x7f, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x7f, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x7f, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x7f, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x3f, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xff, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xff, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xff, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xff, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xff, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };

View File

@@ -0,0 +1,30 @@
// To recreate the data below, use the Paint.Net plugin "Arduino Progmem NeoPixel FileType"
// to save as/export the included Cylon.pdn
// Paint.Net - http://www.getpaint.net/download.html#download
// Plugin - http://forums.getpaint.net/index.php?/topic/107921-arduino-neopixel-sketch-exporter/
// This uses Flatten, GRBW, Hexadecimal
//
const uint16_t myImageWidth = 16;
const uint16_t myImageHeight = 20;
const uint8_t PROGMEM myImage[] = { // (16 x 20) GRBW in Hexadecimal
0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x3f, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };

View File

@@ -0,0 +1,74 @@
// NeoPixelBufferCylon
// This example will move a Cylon Red Eye back and forth across the
// the full collection of pixels on the strip.
//
// This will demonstrate the use of the NeoVerticalSpriteSheet
//
#include <NeoPixelBus.h>
#include <NeoPixelAnimator.h>
// The actual image is contained in the data structure in one of the Cylon*.h files
// You will need to use the one that has the same color feature as your NeoPixelBus
// There are two provided, but you can create your own easily enough using
// free versions of Paint.Net and the plugin
#include "CylonGrb.h"
typedef NeoGrbFeature MyPixelColorFeature;
// #include "CylonGrbw.h"
// typedef NeoGrbwFeature MyPixelColorFeature;
const uint16_t PixelCount = 16; // the sample images are meant for 16 pixels
const uint16_t PixelPin = 2;
const uint16_t AnimCount = 1; // we only need one
NeoPixelBus<MyPixelColorFeature, Neo800KbpsMethod> strip(PixelCount, PixelPin);
// for esp8266 omit the pin
//NeoPixelBus<MyPixelColorFeature, Neo800KbpsMethod> strip(PixelCount);
NeoPixelAnimator animations(AnimCount); // NeoPixel animation management object
// sprite sheet stored in progmem using the same pixel feature as the NeoPixelBus
NeoVerticalSpriteSheet<NeoBufferProgmemMethod<MyPixelColorFeature>> spriteSheet(
myImageWidth, // image width and sprite width since its vertical sprite sheet
myImageHeight, // image height
1, // sprite is only one pixel high
myImage);
uint16_t indexSprite;
void LoopAnimUpdate(const AnimationParam& param)
{
// wait for this animation to complete,
// we are using it as a timer of sorts
if (param.state == AnimationState_Completed)
{
// done, time to restart this position tracking animation/timer
animations.RestartAnimation(param.index);
// draw the next frame in the sprite
spriteSheet.Blt(strip, 0, indexSprite);
indexSprite = (indexSprite + 1) % myImageHeight; // increment and wrap
}
}
void setup()
{
strip.Begin();
strip.Show();
indexSprite = 0;
// we use the index 0 animation to time how often we rotate all the pixels
animations.StartAnimation(0, 60, LoopAnimUpdate);
}
void loop()
{
// this is all that is needed to keep it running
// and avoiding using delay() is always a good thing for
// any timing related routines
animations.UpdateAnimations();
strip.Show();
}

View File

@@ -0,0 +1,167 @@
// NeoPixelBufferShader
// This example will provide a shader class to the NeoPixelBuffer that will dim and brighten
// the pixels that are in the buffer (a device dependent bitmap)
//
#include <NeoPixelBus.h>
const uint16_t PixelCount = 64; // set this to the size of your strip
const uint8_t PixelPin = 2; // make sure to set this to the correct pin, ignored for Esp8266
// three element GRB pixels, change to your needs
NeoPixelBus<NeoGrbFeature, Neo800KbpsMethod> strip(PixelCount, PixelPin);
// the buffer object,
// defined to use memory with the same feature as the strip
// initialized with the same number of pixels as our strip
NeoBuffer<NeoBufferMethod<NeoGrbFeature>> image(8,8,NULL);
const RgbColor BrightRed(255, 0, 0);
const RgbColor BrightGreen(0, 255, 0);
const RgbColor BrightBlue(0, 0, 255);
const RgbColor BrightYellow(255, 255, 0);
const RgbColor BrightCyan(0, 255, 255);
const RgbColor BrightPurple(255, 0, 255);
const RgbColor DarkRed(32, 0, 0);
const RgbColor DarkGreen(0, 32, 0);
const RgbColor DarkBlue(0, 0, 32);
const RgbColor DarkYellow(32, 32, 0);
const RgbColor DarkCyan(0, 32, 32);
const RgbColor DarkPurple(32, 0, 32);
const RgbColor White(255);
const RgbColor Black(0);
// define a custom shader object that provides brightness support
// based upon the NeoShaderBase
template<typename T_COLOR_FEATURE> class BrightnessShader : public NeoShaderBase
{
public:
BrightnessShader():
NeoShaderBase(),
_brightness(255) // default to full bright
{}
// required for a shader object, it will be called for
// every pixel
void Apply(uint16_t index, uint8_t* pDest, uint8_t* pSrc)
{
// we don't care what the index is so we ignore it
//
// to apply our brightness shader,
// use the source color, modify, and apply to the destination
// for every byte in the pixel,
// scale the source value by the brightness and
// store it in the destination byte
const uint8_t* pSrcEnd = pSrc + T_COLOR_FEATURE::PixelSize;
while (pSrc != pSrcEnd)
{
*pDest++ = (*pSrc++ * (uint16_t(_brightness) + 1)) >> 8;
}
}
// provide an accessor to set brightness
void setBrightness(uint8_t brightness)
{
_brightness = brightness;
Dirty(); // must call dirty when a property changes
}
// provide an accessor to get brightness
uint8_t getBrightness()
{
return _brightness;
}
private:
uint8_t _brightness;
};
// create an instance of our shader object with the same feature as our buffer
BrightnessShader<NeoGrbFeature> shader;
// some dimming tracking variables and settings
int8_t delta;
void setup()
{
Serial.begin(115200);
while (!Serial); // wait for serial attach
Serial.println();
Serial.println("Initializing...");
Serial.flush();
// this resets all the neopixels to an off state
strip.Begin();
strip.Show();
// dibs do not default to any color,
// so clear it to black if you aren't going to draw
// into every pixel
image.ClearTo(Black);
// draw a pattern into the image
uint8_t x = 0;
uint8_t y = 0;
image.SetPixelColor(x++, y, DarkRed);
image.SetPixelColor(x++, y, DarkYellow);
image.SetPixelColor(x++, y, DarkGreen);
image.SetPixelColor(x++, y, DarkCyan);
image.SetPixelColor(x++, y, DarkBlue);
image.SetPixelColor(x++, y, DarkPurple);
x = 0;
y = 1;
image.SetPixelColor(x++, y, BrightRed);
image.SetPixelColor(x++, y, BrightYellow);
image.SetPixelColor(x++, y, BrightGreen);
image.SetPixelColor(x++, y, BrightCyan);
image.SetPixelColor(x++, y, BrightBlue);
image.SetPixelColor(x++, y, BrightPurple);
Serial.println();
Serial.println("Running...");
delta = -1; // start by dimming downward
}
void loop()
{
// we increment by delta every 30ms
delay(30);
// update the brightness in shader
//
uint8_t brightness = shader.getBrightness();
// check if we flip directions
if (brightness == 0)
{
delta = 1; // increment
}
else if (brightness == 255)
{
delta = -1; // decrement
}
// modify and apply
brightness += delta;
shader.setBrightness(brightness);
Serial.println(brightness);
// render the image using the shader and then call Show()
// these two should be called together in order
//
// need to provide the type of color feature for the strip and
// the type of our custom shader
image.Render<BrightnessShader<NeoGrbFeature>>(strip, shader);
strip.Show();
}

View File

@@ -0,0 +1,158 @@
// NeoPixelDibTest
// This example will provide a shader class to the NeoPixelDib that will dim and brighten
// the pixels that are in the Dib (Device Independant Bitmap)
//
#include <NeoPixelBus.h>
const uint16_t PixelCount = 64; // set this to the size of your strip
const uint8_t PixelPin = 2; // make sure to set this to the correct pin, ignored for Esp8266
// three element GRB pixels, change to your needs
NeoPixelBus<NeoGrbFeature, Neo800KbpsMethod> strip(PixelCount, PixelPin);
// the DIB object, using RgbColor and initialized with the same number of pixels as our strip
NeoDib<RgbColor> image(PixelCount);
const RgbColor BrightRed(255, 0, 0);
const RgbColor BrightGreen(0, 255, 0);
const RgbColor BrightBlue(0, 0, 255);
const RgbColor BrightYellow(255, 255, 0);
const RgbColor BrightCyan(0, 255, 255);
const RgbColor BrightPurple(255, 0, 255);
const RgbColor DarkRed(32, 0, 0);
const RgbColor DarkGreen(0, 32, 0);
const RgbColor DarkBlue(0, 0, 32);
const RgbColor DarkYellow(32, 32, 0);
const RgbColor DarkCyan(0, 32, 32);
const RgbColor DarkPurple(32, 0, 32);
const RgbColor White(255);
const RgbColor Black(0);
// define a custom shader object that provides brightness support
// based upon the NeoShaderBase
class BrightnessShader : public NeoShaderBase
{
public:
BrightnessShader():
NeoShaderBase(),
_brightness(255) // default to full bright
{}
// required for a shader object, it will be called for
// every pixel
RgbColor Apply(uint16_t index, RgbColor original)
{
// we don't care what the index is so we ignore it
//
// to apply our brightness shader, modify the original color and return the color we want
// blend from black (_brightness == 0.0) to the original color (_brightness == 1.0)
return RgbColor::LinearBlend(Black, original, (float)_brightness / 255.0f);
}
// provide an accessor to set brightness
void setBrightness(uint8_t brightness)
{
_brightness = brightness;
Dirty(); // must call dirty when a property changes
}
// provide an accessor to get brightness
uint8_t getBrightness()
{
return _brightness;
}
private:
uint8_t _brightness;
};
// create an instance of our shader object
BrightnessShader shader;
// some dimming tracking variables and settings
int8_t delta;
void setup()
{
Serial.begin(115200);
while (!Serial); // wait for serial attach
Serial.println();
Serial.println("Initializing...");
Serial.flush();
// this resets all the neopixels to an off state
strip.Begin();
strip.Show();
// dibs do not default to any color,
// so clear it to black if you aren't going to draw
// into every pixel
image.ClearTo(Black);
// draw a pattern into the image
uint8_t index = 0;
image.SetPixelColor(index++, DarkRed);
image.SetPixelColor(index++, DarkYellow);
image.SetPixelColor(index++, DarkGreen);
image.SetPixelColor(index++, DarkCyan);
image.SetPixelColor(index++, DarkBlue);
image.SetPixelColor(index++, DarkPurple);
image.SetPixelColor(index++, Black);
image.SetPixelColor(index++, Black);
image.SetPixelColor(index++, BrightRed);
image.SetPixelColor(index++, BrightYellow);
image.SetPixelColor(index++, BrightGreen);
image.SetPixelColor(index++, BrightCyan);
image.SetPixelColor(index++, BrightBlue);
image.SetPixelColor(index++, BrightPurple);
Serial.println();
Serial.println("Running...");
delta = -1; // start by dimming downward
}
void loop()
{
// we increment by delta every 30ms
delay(30);
// update the brightness in shader
//
uint8_t brightness = shader.getBrightness();
// check if we flip directions
if (brightness == 0)
{
delta = 1; // increment
}
else if (brightness == 255)
{
delta = -1; // decrement
}
// modify and apply
brightness += delta;
shader.setBrightness(brightness);
Serial.println(brightness);
// render the image using the shader and then call Show()
// these two should be called together in order
//
// need to provide the type of color feature for the strip and
// the type of our custom shader
image.Render<NeoGrbFeature, BrightnessShader>(strip, shader);
strip.Show();
}

View File

@@ -0,0 +1,36 @@
// NeoSegmentBus
// This example will demonstrate using the NeoSegmentBus which provides support for a
// seven segment LED digit driven by three WS2811; connected in series with other digits
//
// See https://shop.idlehandsdev.com/products/addressable-7-segment-display for a hardware example
//
// This example will print the string "3.14" and then rotate it through the available digits
//
#include <NeoPixelSegmentBus.h>
const uint16_t DigitCount = 4; // Max Digits, not segments, not pixels
const uint8_t BusPin = 2; // make sure to set this to the correct pin, ignored for Esp8266
#define brightness 128
NeoPixelSegmentBus<SevenSegmentFeature, NeoWs2811Method> strip(DigitCount, BusPin);
void setup()
{
strip.Begin();
strip.Show(); // clears all digits by default
delay(500);
strip.SetString(0, "3.14", brightness);
strip.Show();
}
void loop()
{
delay(2000);
strip.RotateLeft(1);
strip.Show();
}

View File

@@ -0,0 +1,144 @@
// NeoSegmentBus
// This example will demonstrate using the NeoSegmentBus which provides support for a
// seven segment LED digit driven by three WS2811; connected in series with other digits
//
// See https://shop.idlehandsdev.com/products/addressable-7-segment-display for a hardware example
//
// This example will print current seconds since start of the Arduino
// with a digit animating a circling path for each second
//
#include <NeoPixelSegmentBus.h>
#include <NeoPixelAnimator.h>
const uint16_t DigitCount = 5; // Max Digits, not segments, not pixels
const uint8_t BusPin = 2; // make sure to set this to the correct pin, ignored for Esp8266
const uint16_t CycleDigit = 0;
const uint16_t SecondsDigit = 1;
#define brightness 128
NeoPixelSegmentBus<SevenSegmentFeature, NeoWs2811Method> strip(DigitCount, BusPin);
enum Animation
{
Animation_Cycle, // animation for the cycle indicator
Animation_Fade, // animation for fade of seconds
Animation_COUNT
};
NeoPixelAnimator animations(Animation_COUNT);
void CycleAnimation(const AnimationParam& param)
{
// calculate which segment should be on using the animation progress
uint8_t bitfield = 1 << (uint8_t)(param.progress * LedSegment_F);
// instant a digit with that segment on
SevenSegDigit digit(bitfield, brightness);
// apply it to the strip
strip.SetPixelColor(CycleDigit, digit);
}
// for the animation of fading the new number in, we use
// two digit DIBs (Device Independant Bitmaps) of SevenSegDigit to blend with;
// each sized one less than the strip due to the first is a used for the cycle
// animation.
typedef NeoDib<SevenSegDigit> SevenSegDib;
SevenSegDib StartingDigits(DigitCount - 1);
SevenSegDib EndingDigits(DigitCount - 1);
// shader class that will do the "string" blending
//
class DigitBlendShader
{
public:
// this shader always renders and doesn't track a dirty state
bool IsDirty() const
{
return true;
}
void ResetDirty()
{
}
SevenSegDigit Apply(uint16_t indexDigit, SevenSegDigit digit)
{
// since we call EndingDigits.Render below, the digit argument is
// from the EndingDigits so no need to call GetPixelColor to get it
// create a digit that is a blend between the last seconds
// value and the next seconds value using the BlendAmount
SevenSegDigit blendDigit = SevenSegDigit::LinearBlend(
StartingDigits.GetPixelColor(indexDigit),
digit,
BlendAmount);
return blendDigit;
}
float BlendAmount;
};
// the instance of our shader class
DigitBlendShader blendShader;
void FadeAnimation(const AnimationParam& param)
{
// set the shader property BlendAmount to the animation progress
blendShader.BlendAmount = param.progress;
// apply it to the strip at the SecondsDigit location
EndingDigits.Render<SevenSegmentFeature, DigitBlendShader>(strip,
blendShader,
SecondsDigit);
}
uint32_t lastSeconds;
void setup()
{
lastSeconds = millis() / 1000;
strip.Begin();
strip.Show();
// init animation Dibs as cleared
StartingDigits.ClearTo(0);
EndingDigits.ClearTo(0);
}
void loop()
{
uint32_t seconds = millis() / 1000;
// when the seconds change, start animations for the update
//
if (seconds != lastSeconds)
{
// copy last animation ending digits as starting digits
StartingDigits = EndingDigits;
// format and display new value in ending digits dib
String display(seconds);
SevenSegDigit::SetString<SevenSegDib>(EndingDigits,
0,
display.c_str(),
brightness);
// start the seconds fade animation
animations.StartAnimation(Animation_Fade, 1000, FadeAnimation);
// start the cycle animation for the next second
animations.StartAnimation(Animation_Cycle, 1000, CycleAnimation);
lastSeconds = seconds;
}
if (animations.IsAnimating())
{
// the normal loop just needs these two to run the active animations
animations.UpdateAnimations();
strip.Show();
}
}

View File

@@ -0,0 +1,98 @@
//----------------------------------------------------------------------
// NeoPixelMosaicDump
// This will dump to the serial output a grid map of the defined mosaic
// The output is displayed as row column labeled grid with the NeoPixelBus
// index of the pixel at the intersection of the row and column.
//
// To help with physical layout, there maybe included a symbol following the index
// < means the index is the input index for the panel, the first on the panel
// > means the index is the output index for the panel, the last on the panel
//
// This is useful in visualising the mosaic layout of your panels to
// confirm you have them correctly wired together for this mosaic pattern
//
// It does not require that you have the actual panel connected
//----------------------------------------------------------------------
#include <NeoPixelAnimator.h>
#include <NeoPixelBus.h>
// uncomment one of these that matches your panel pixel layouts
// rotation is ignored for mosaic as it applies a rotation for you
// that is specific to the location of the panel within the mosaic
// to reduce connection lengths
typedef ColumnMajorAlternatingLayout MyPanelLayout;
// typedef ColumnMajorLayout MyPanelLayout;
// typedef RowMajorAlternatingLayout MyPanelLayout;
// typedef RowMajorLayout MyPanelLayout;
// make sure to set these panel and tile layout to match your sizes
const uint8_t PanelWidth = 8; // a 8 pixel x 8 pixel matrix of leds on the panel
const uint8_t PanelHeight = 8;
const uint8_t TileWidth = 4; // laid out in 4 panels x 2 panels mosaic
const uint8_t TileHeight = 2;
NeoMosaic <MyPanelLayout> mosaic(
PanelWidth,
PanelHeight,
TileWidth,
TileHeight);
void DumpMosaic()
{
Serial.println();
Serial.print("\t\t");
for (int x = 0; x < mosaic.getWidth(); x++)
{
Serial.print(x);
Serial.print("\t");
}
Serial.println();
Serial.print("\t---");
for (int x = 0; x < mosaic.getWidth(); x++)
{
Serial.print("--------");
}
Serial.println();
for (int y = 0; y < mosaic.getHeight(); y++)
{
Serial.print(" ");
Serial.print(y);
Serial.print("\t|\t");
for (int x = 0; x < mosaic.getWidth(); x++)
{
NeoTopologyHint hint = mosaic.TopologyHint(x, y);
Serial.print(mosaic.Map(x, y));
if (hint == NeoTopologyHint_FirstOnPanel)
{
Serial.print("<");
}
else if (hint == NeoTopologyHint_LastOnPanel)
{
Serial.print(">");
}
Serial.print("\t");
}
Serial.println();
}
}
void setup()
{
Serial.begin(115200);
while (!Serial); // wait for serial attach
DumpMosaic();
}
void loop()
{
}

View File

@@ -0,0 +1,97 @@
//----------------------------------------------------------------------
// NeoPixelTopologyTest
// This will display specific colors in specific locations on the led panels
//
// This is useful in confirming the layout of your panels
//
// It does require that you have the actual panels connected
//----------------------------------------------------------------------
#include <NeoPixelAnimator.h>
#include <NeoPixelBus.h>
// uncomment one of these that matches your panel pixel layouts
// rotation is ignored for mosaic as it applies a rotation for you
// that is specific to the location of the panel within the mosaic
// to reduce connection lengths
typedef ColumnMajorAlternatingLayout MyPanelLayout;
// typedef ColumnMajorLayout MyPanelLayout;
// typedef RowMajorAlternatingLayout MyPanelLayout;
// typedef RowMajorLayout MyPanelLayout;
// make sure to set these panel values to the sizes of yours
const uint8_t PanelWidth = 8; // 8 pixel x 8 pixel matrix of leds
const uint8_t PanelHeight = 8;
const uint8_t TileWidth = 4; // laid out in 4 panels x 2 panels mosaic
const uint8_t TileHeight = 2;
const uint16_t PixelCount = PanelWidth * PanelHeight * TileWidth * TileHeight;
const uint8_t PixelPin = 2;
NeoMosaic <MyPanelLayout> mosaic(
PanelWidth,
PanelHeight,
TileWidth,
TileHeight);
NeoPixelBus<NeoGrbFeature, Neo800KbpsMethod> strip(PixelCount, PixelPin);
// for esp8266 omit the pin
//NeoPixelBus<NeoGrbFeature, Neo800KbpsMethod> strip(PixelCount);
RgbColor red(128, 0, 0);
RgbColor green(0, 128, 0);
RgbColor blue(0, 0, 128);
RgbColor white(128);
// if using NeoRgbwFeature above, use this white instead to use
// the correct white element of the LED
//RgbwColor white(128);
RgbColor black(0);
const uint16_t left = 0;
const uint16_t right = PanelWidth - 1;
const uint16_t top = 0;
const uint16_t bottom = PanelHeight - 1;
void setup()
{
Serial.begin(115200);
while (!Serial); // wait for serial attach
Serial.println();
Serial.println("Initializing...");
strip.Begin();
strip.Show();
Serial.println();
Serial.println("Running...");
}
void loop()
{
delay(2500);
Serial.println();
Serial.println("If your panel is correctly defined, you should see ...");
Serial.println("Upper left is white.");
Serial.println("Upper right is Red.");
Serial.println("Lower right is Green");
Serial.println("Lower Left is Blue");
// use the topo to map the 2d cordinate to the pixel
// and use that to SetPixelColor
strip.SetPixelColor(mosaic.Map(left, top), white);
strip.SetPixelColor(mosaic.Map(right, top), red);
strip.SetPixelColor(mosaic.Map(right, bottom), green);
strip.SetPixelColor(mosaic.Map(left, bottom), blue);
strip.Show();
delay(5000);
Serial.println();
Serial.println("Cleared to black ...");
strip.ClearTo(black);
strip.Show();
}

View File

@@ -0,0 +1,100 @@
//----------------------------------------------------------------------
// NeoPixelRingTopologyTest
// This will display specific colors in specific locations on the led rings
//
// This is useful in confirming the layout of your rings
//
// It does require that you have the actual series of rings connected
//----------------------------------------------------------------------
#include <NeoPixelBus.h>
const uint8_t PixelCount = 119;
const uint8_t PixelPin = 2; // make sure to set this to the correct pin, ignored for Esp8266
// define the layout of your series of rings
//
// This example is using all of Adafruits rings and a Jewel in the center.
// The center is the input and all the rings are connected in series going outward
//
// Rings:
// 0 - 1 (virtual ring, the center of the jewel)
// 1 - 6 (virtual ring, the outer ring of the jewel)
// 2 - 12 count ring
// 3 - 16 count ring
// 4 - 24 count ring
// 5 - 60 count ring comprised of four arc segments
//
// The values below in Rings[] are the index of the first pixel in each ring.
// An extra value is appended for a virtual ring start that also
// represents the total count of pixels in the complete series and this extra
// value is required.
//
class MyRingsLayout
{
protected:
const uint16_t Rings[7] = {0, 1, 7, 19, 35, 59, PixelCount};
};
// use the MyRingsLayout to declare the topo object
//
NeoRingTopology<MyRingsLayout> topo;
// declare our strip
//
NeoPixelBus<NeoGrbFeature, Neo800KbpsMethod> strip(PixelCount, PixelPin);
// define some handy colors
//
RgbColor red(128, 0, 0);
RgbColor green(0, 128, 0);
RgbColor blue(0, 0, 128);
RgbColor black(0);
void setup()
{
Serial.begin(115200);
while (!Serial); // wait for serial attach
Serial.println();
Serial.println("Initializing...");
strip.Begin();
strip.Show();
Serial.println();
Serial.println("Running...");
}
void loop()
{
delay(2500);
Serial.println();
Serial.println("If your panel is correctly defined, you should see ...");
Serial.println("First pixel in each ring is Red.");
Serial.println("Middle pixel in each ring is Green.");
Serial.println("Last Pixel in each ring is Blue.");
// use the topo to map the 2d polar cordinate to the pixel
// and use that to SetPixelColor
for (uint16_t ring = 0; ring < topo.getCountOfRings(); ring++)
{
// first pixel in each ring is red
strip.SetPixelColor(topo.Map(ring, 0), red);
// last pixel in each ring is blue
strip.SetPixelColor(topo.Map(ring, topo.getPixelCountAtRing(ring) - 1), blue);
// middle pixel in each ring is green
strip.SetPixelColor(topo.Map(ring, topo.getPixelCountAtRing(ring) / 2), green);
}
strip.Show();
delay(5000);
Serial.println();
Serial.println("Cleared to black ...");
strip.ClearTo(black);
strip.Show();
}

View File

@@ -0,0 +1,102 @@
//----------------------------------------------------------------------
// NeoPixelTileDump
// This will dump to the serial output a grid map of the defined tiles
// The output is displayed as row column labeled grid with the NeoPixelBus
// index of the pixel at the intersection of the row and column
//
// To help with physical layout, there maybe included a symbol following the index
// < means the index is the input index for the panel, the first on the panel
// > means the index is the output index for the panel, the last on the panel
//
// This is useful in visualising the tile layout of your panels to
// confirm you have them correctly wired together for the defined pattern
//
// It does not require that you have the actual panel connected
//----------------------------------------------------------------------
#include <NeoPixelAnimator.h>
#include <NeoPixelBus.h>
// uncomment one of these that matches your panel pixel layouts and
// how you want them rotated. Not all the rotations are listed here
// but you can modifiy the name to include the rotation of 90,180, or 270.
typedef ColumnMajorAlternatingLayout MyPanelLayout;
// typedef ColumnMajorLayout MyPanelLayout;
// typedef RowMajorAlternatingLayout MyPanelLayout;
// typedef RowMajorLayout MyPanelLayout;
// typedef RowMajor90Layout MyPanelLayout; // note rotation 90 was used
// change this to be one of the layouts which will define the layout
// of the panels themselves
typedef ColumnMajorLayout MyTilesLayout;
// make sure to set these panel and tile layout to match your sizes
const uint8_t PanelWidth = 8; // 8 pixel x 8 pixel matrix of leds
const uint8_t PanelHeight = 8;
const uint8_t TileWidth = 4; // laid out in 4 panels x 2 panels mosaic
const uint8_t TileHeight = 2;
NeoTiles <MyPanelLayout, MyTilesLayout> tiles(
PanelWidth,
PanelHeight,
TileWidth,
TileHeight);
void DumpTopo()
{
Serial.println();
Serial.print("\t\t");
for (int x = 0; x < tiles.getWidth(); x++)
{
Serial.print(x);
Serial.print("\t");
}
Serial.println();
Serial.print("\t---");
for (int x = 0; x < tiles.getWidth(); x++)
{
Serial.print("--------");
}
Serial.println();
for (int y = 0; y < tiles.getHeight(); y++)
{
Serial.print(" ");
Serial.print(y);
Serial.print("\t|\t");
for (int x = 0; x < tiles.getWidth(); x++)
{
NeoTopologyHint hint = tiles.TopologyHint(x, y);
Serial.print(tiles.Map(x, y));
if (hint == NeoTopologyHint_FirstOnPanel)
{
Serial.print("<");
}
else if (hint == NeoTopologyHint_LastOnPanel)
{
Serial.print(">");
}
Serial.print("\t");
}
Serial.println();
}
}
void setup()
{
Serial.begin(115200);
while (!Serial); // wait for serial attach
DumpTopo();
}
void loop()
{
}

View File

@@ -0,0 +1,103 @@
//----------------------------------------------------------------------
// NeoPixelTilesTest
// This will display specific colors in specific locations on the led panels
//
// This is useful in confirming the layout of your panels
//
// It does require that you have the actual panels connected
//----------------------------------------------------------------------
#include <NeoPixelAnimator.h>
#include <NeoPixelBus.h>
// uncomment one of these that matches your panel pixel layouts and
// how you want them rotated. Not all the rotations are listed here
// but you can modifiy the name to include the rotation of 90,180, or 270.
typedef ColumnMajorAlternatingLayout MyPanelLayout;
// typedef ColumnMajorLayout MyPanelLayout;
// typedef RowMajorAlternatingLayout MyPanelLayout;
// typedef RowMajorLayout MyPanelLayout;
// typedef RowMajor90Layout MyPanelLayout; // note rotation 90 was used
// change this to be one of the layouts which will define the layout
// of the panels themselves
typedef ColumnMajorLayout MyTilesLayout;
// make sure to set these panel values to the sizes of yours
const uint8_t PanelWidth = 8; // 8 pixel x 8 pixel matrix of leds
const uint8_t PanelHeight = 8;
const uint8_t TileWidth = 4; // laid out in 4 panels x 2 panels mosaic
const uint8_t TileHeight = 2;
const uint16_t PixelCount = PanelWidth * PanelHeight * TileWidth * TileHeight;
const uint8_t PixelPin = 2;
NeoTiles <MyPanelLayout, MyTilesLayout> tiles(
PanelWidth,
PanelHeight,
TileWidth,
TileHeight);
NeoPixelBus<NeoGrbFeature, Neo800KbpsMethod> strip(PixelCount, PixelPin);
//NeoPixelBus<NeoRgbFeature, Neo800KbpsMethod> strip(PixelCount, PixelPin);
//NeoPixelBus<NeoRgbwFeature, Neo800KbpsMethod> strip(PixelCount, PixelPin);
// for esp8266 omit the pin
//NeoPixelBus<NeoGrbFeature, Neo800KbpsMethod> strip(PixelCount);
RgbColor red(128, 0, 0);
RgbColor green(0, 128, 0);
RgbColor blue(0, 0, 128);
RgbColor white(128);
// if using NeoRgbwFeature above, use this white instead to use
// the correct white element of the LED
//RgbwColor white(128);
RgbColor black(0);
const uint16_t left = 0;
const uint16_t right = PanelWidth - 1;
const uint16_t top = 0;
const uint16_t bottom = PanelHeight - 1;
void setup()
{
Serial.begin(115200);
while (!Serial); // wait for serial attach
Serial.println();
Serial.println("Initializing...");
strip.Begin();
strip.Show();
Serial.println();
Serial.println("Running...");
}
void loop()
{
delay(2500);
Serial.println();
Serial.println("If your panel is correctly defined, you should see ...");
Serial.println("Upper left is white.");
Serial.println("Upper right is Red.");
Serial.println("Lower right is Green");
Serial.println("Lower Left is Blue");
// use the topo to map the 2d cordinate to the pixel
// and use that to SetPixelColor
strip.SetPixelColor(tiles.Map(left, top), white);
strip.SetPixelColor(tiles.Map(right, top), red);
strip.SetPixelColor(tiles.Map(right, bottom), green);
strip.SetPixelColor(tiles.Map(left, bottom), blue);
strip.Show();
delay(5000);
Serial.println();
Serial.println("Cleared to black ...");
strip.ClearTo(black);
strip.Show();
}

View File

@@ -0,0 +1,78 @@
//----------------------------------------------------------------------
// NeoPixelTopologyDump
// This will dump to the serial output a grid map of the defined topology
// The output is displayed as row column labeled grid with the NeoPixelBus
// index of the pixel at the intersection of the row and column
//
// This is useful in visualising the layout of your panel so you can
// confirm you have the correct pattern
//
// It does not require that you have the actual panel connected
//----------------------------------------------------------------------
#include <NeoPixelAnimator.h>
#include <NeoPixelBus.h>
// uncomment one of these that matches your panel pixel layouts and
// how you want them rotated. Not all the rotations are listed here
// but you can modifiy the name to include the rotation of 90,180, or 270.
typedef ColumnMajorAlternatingLayout MyPanelLayout;
// typedef ColumnMajorLayout MyPanelLayout;
// typedef RowMajorAlternatingLayout MyPanelLayout;
// typedef RowMajorLayout MyPanelLayout;
// typedef RowMajor90Layout MyPanelLayout; // note rotation 90 was used
// make sure to set these panel values to the sizes of yours
const uint8_t PanelWidth = 8; // 8 pixel x 8 pixel matrix of leds
const uint8_t PanelHeight = 8;
NeoTopology<MyPanelLayout> topo(PanelWidth, PanelHeight);
void DumpTopo()
{
Serial.println();
Serial.print("\t\t");
for (int x = 0; x < topo.getWidth(); x++)
{
Serial.print(x);
Serial.print("\t");
}
Serial.println();
Serial.print("\t--");
for (int x = 0; x < topo.getWidth(); x++)
{
Serial.print("--------");
}
Serial.println();
for (int y = 0; y < topo.getHeight(); y++)
{
Serial.print(" ");
Serial.print(y);
Serial.print("\t|\t");
for (int x = 0; x < topo.getWidth(); x++)
{
Serial.print(topo.Map(x, y));
Serial.print("\t");
}
Serial.println();
}
}
void setup()
{
Serial.begin(115200);
while (!Serial); // wait for serial attach
DumpTopo();
}
void loop()
{
}

View File

@@ -0,0 +1,92 @@
//----------------------------------------------------------------------
// NeoPixelTopologyTest
// This will display specific colors in specific locations on the led panel
//
// This is useful in confirming the layout of your panel
//
// It does require that you have the actual panel connected
//----------------------------------------------------------------------
#include <NeoPixelAnimator.h>
#include <NeoPixelBus.h>
// uncomment one of these that matches your panel pixel layouts and
// how you want them rotated. Not all the rotations are listed here
// but you can modifiy the name to include the rotation of 90,180, or 270.
typedef ColumnMajorAlternatingLayout MyPanelLayout;
// typedef ColumnMajorLayout MyPanelLayout;
// typedef RowMajorAlternatingLayout MyPanelLayout;
// typedef RowMajorLayout MyPanelLayout;
// typedef RowMajor90Layout MyPanelLayout; // note rotation 90 was used
// make sure to set these panel values to the sizes of yours
const uint8_t PanelWidth = 8; // 8 pixel x 8 pixel matrix of leds
const uint8_t PanelHeight = 8;
const uint16_t PixelCount = PanelWidth * PanelHeight;
const uint8_t PixelPin = 2; // make sure to set this to the correct pin, ignored for Esp8266
NeoTopology<MyPanelLayout> topo(PanelWidth, PanelHeight);
NeoPixelBus<NeoGrbFeature, Neo800KbpsMethod> strip(PixelCount, PixelPin);
//NeoPixelBus<NeoRgbFeature, Neo800KbpsMethod> strip(PixelCount, PixelPin);
//NeoPixelBus<NeoRgbwFeature, Neo800KbpsMethod> strip(PixelCount, PixelPin);
// for esp8266 omit the pin
//NeoPixelBus<NeoGrbFeature, Neo800KbpsMethod> strip(PixelCount);
RgbColor red(128, 0, 0);
RgbColor green(0, 128, 0);
RgbColor blue(0, 0, 128);
RgbColor white(128);
// if using NeoRgbwFeature above, use this white instead to use
// the correct white element of the LED
//RgbwColor white(128);
RgbColor black(0);
const uint16_t left = 0;
const uint16_t right = PanelWidth - 1;
const uint16_t top = 0;
const uint16_t bottom = PanelHeight - 1;
void setup()
{
Serial.begin(115200);
while (!Serial); // wait for serial attach
Serial.println();
Serial.println("Initializing...");
strip.Begin();
strip.Show();
Serial.println();
Serial.println("Running...");
}
void loop()
{
delay(2500);
Serial.println();
Serial.println("If your panel is correctly defined, you should see ...");
Serial.println("Upper left is white.");
Serial.println("Upper right is Red.");
Serial.println("Lower right is Green");
Serial.println("Lower Left is Blue");
// use the topo to map the 2d cordinate to the pixel
// and use that to SetPixelColor
strip.SetPixelColor(topo.Map(left, top), white);
strip.SetPixelColor(topo.Map(right, top), red);
strip.SetPixelColor(topo.Map(right, bottom), green);
strip.SetPixelColor(topo.Map(left, bottom), blue);
strip.Show();
delay(5000);
Serial.println();
Serial.println("Cleared to black ...");
strip.ClearTo(black);
strip.Show();
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

View File

@@ -0,0 +1,539 @@
#######################################
# Syntax Coloring Map NeoPixelBus
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
NeoPixelBus KEYWORD1
NeoPixelSegmentBus KEYWORD1
RgbwColor KEYWORD1
RgbColor KEYWORD1
HslColor KEYWORD1
HsbColor KEYWORD1
HtmlColor KEYWORD1
NeoNoSettings KEYWORD1
NeoTm1814Settings KEYWORD1
NeoGrbFeature KEYWORD1
NeoGrbwFeature KEYWORD1
NeoRgbwFeature KEYWORD1
NeoRgbFeature KEYWORD1
NeoBrgFeature KEYWORD1
NeoRbgFeature KEYWORD1
NeoWrgbTm1814Feature KEYWORD1
DotStarBgrFeature KEYWORD1
DotStarLbgrFeature KEYWORD1
Lpd8806GrbFeature KEYWORD1
P9813BgrFeature KEYWORD1
SevenSegmentFeature KEYWORD1
Neo800KbpsMethod KEYWORD1
Neo400KbpsMethod KEYWORD1
NeoWs2813Method KEYWORD1
NeoWs2812xMethod KEYWORD1
NeoWs2812Method KEYWORD1
NeoWs2811Method KEYWORD1
NeoSk6812Method KEYWORD1
NeoTm1814Method KEYWORD1
NeoLc8812Method KEYWORD1
NeoApa106Method KEYWORD1
Neo800KbpsInvertedMethod KEYWORD1
Neo400KbpsInvertedMethod KEYWORD1
NeoWs2813InvertedMethod KEYWORD1
NeoWs2812xInvertedMethod KEYWORD1
NeoWs2812InvertedMethod KEYWORD1
NeoWs2811InvertedMethod KEYWORD1
NeoSk6812InvertedMethod KEYWORD1
NeoTm1814InvertedMethod KEYWORD1
NeoLc8812InvertedMethod KEYWORD1
NeoApa106InvertedMethod KEYWORD1
NeoEsp8266DmaWs2812xMethod KEYWORD1
NeoEsp8266DmaSk6812Method KEYWORD1
NeoEsp8266DmaTm1814Method KEYWORD1
NeoEsp8266DmaApa106Method KEYWORD1
NeoEsp8266Dma800KbpsMethod KEYWORD1
NeoEsp8266Dma400KbpsMethod KEYWORD1
NeoEsp8266DmaInvertedWs2812xMethod KEYWORD1
NeoEsp8266DmaInvertedSk6812Method KEYWORD1
NeoEsp8266DmaInvertedTm1814Method KEYWORD1
NeoEsp8266DmaInvertedApa106Method KEYWORD1
NeoEsp8266DmaInverted800KbpsMethod KEYWORD1
NeoEsp8266DmaInverted400KbpsMethod KEYWORD1
NeoEsp8266Uart0Ws2813Method KEYWORD1
NeoEsp8266Uart0Ws2812xMethod KEYWORD1
NeoEsp8266Uart0Ws2812Method KEYWORD1
NeoEsp8266Uart0Ws2811Method KEYWORD1
NeoEsp8266Uart0Sk6812Method KEYWORD1
NeoEsp8266Uart0Tm1814Method KEYWORD1
NeoEsp8266Uart0Lc8812Method KEYWORD1
NeoEsp8266Uart0Apa106Method KEYWORD1
NeoEsp8266Uart0800KbpsMethod KEYWORD1
NeoEsp8266Uart0400KbpsMethod KEYWORD1
NeoEsp8266AsyncUart0Ws2813Method KEYWORD1
NeoEsp8266AsyncUart0Ws2812xMethod KEYWORD1
NeoEsp8266AsyncUart0Ws2812Method KEYWORD1
NeoEsp8266AsyncUart0Ws2811Method KEYWORD1
NeoEsp8266AsyncUart0Sk6812Method KEYWORD1
NeoEsp8266AsyncUart0Tm1814Method KEYWORD1
NeoEsp8266AsyncUart0Lc8812Method KEYWORD1
NeoEsp8266AsyncUart0Apa106Method KEYWORD1
NeoEsp8266AsyncUart0800KbpsMethod KEYWORD1
NeoEsp8266AsyncUart0400KbpsMethod KEYWORD1
NeoEsp8266Uart1Ws2813Method KEYWORD1
NeoEsp8266Uart1Ws2812xMethod KEYWORD1
NeoEsp8266Uart1Ws2812Method KEYWORD1
NeoEsp8266Uart1Ws2811Method KEYWORD1
NeoEsp8266Uart1Sk6812Method KEYWORD1
NeoEsp8266Uart1Tm1814 KEYWORD1
NeoEsp8266Uart1Lc8812Method KEYWORD1
NeoEsp8266Uart1Apa106Method KEYWORD1
NeoEsp8266Uart1800KbpsMethod KEYWORD1
NeoEsp8266Uart1400KbpsMethod KEYWORD1
NeoEsp8266AsyncUart1Ws2813Method KEYWORD1
NeoEsp8266AsyncUart1Ws2812xMethod KEYWORD1
NeoEsp8266AsyncUart1Ws2812Method KEYWORD1
NeoEsp8266AsyncUart1Ws2811Method KEYWORD1
NeoEsp8266AsyncUart1Sk6812Method KEYWORD1
NeoEsp8266AsyncUart1Tm1814 KEYWORD1
NeoEsp8266AsyncUart1Lc8812Method KEYWORD1
NeoEsp8266AsyncUart1Apa106Method KEYWORD1
NeoEsp8266AsyncUart1800KbpsMethod KEYWORD1
NeoEsp8266AsyncUart1400KbpsMethod KEYWORD1
NeoEsp8266Uart0Ws2813InvertedMethod KEYWORD1
NeoEsp8266Uart0Ws2812xInvertedMethod KEYWORD1
NeoEsp8266Uart0Ws2812InvertedMethod KEYWORD1
NeoEsp8266Uart0Ws2811InvertedMethod KEYWORD1
NeoEsp8266Uart0Sk6812InvertedMethod KEYWORD1
NeoEsp8266Uart0Tm1814InvertedMethod KEYWORD1
NeoEsp8266Uart0Lc8812InvertedMethod KEYWORD1
NeoEsp8266Uart0Apa106InvertedMethod KEYWORD1
NeoEsp8266Uart0800KbpsInvertedMethod KEYWORD1
NeoEsp8266Uart0400KbpsInvertedMethod KEYWORD1
NeoEsp8266AsyncUart0Ws2813InvertedMethod KEYWORD1
NeoEsp8266AsyncUart0Ws2812xInvertedMethod KEYWORD1
NeoEsp8266AsyncUart0Ws2812InvertedMethod KEYWORD1
NeoEsp8266AsyncUart0Ws2811InvertedMethod KEYWORD1
NeoEsp8266AsyncUart0Sk6812InvertedMethod KEYWORD1
NeoEsp8266AsyncUart0Tm1814InvertedMethod KEYWORD1
NeoEsp8266AsyncUart0Lc8812InvertedMethod KEYWORD1
NeoEsp8266AsyncUart0Apa106InvertedMethod KEYWORD1
NeoEsp8266AsyncUart0800KbpsInvertedMethod KEYWORD1
NeoEsp8266AsyncUart0400KbpsInvertedMethod KEYWORD1
NeoEsp8266Uart1Ws2813InvertedMethod KEYWORD1
NeoEsp8266Uart1Ws2812xInvertedMethod KEYWORD1
NeoEsp8266Uart1Ws2812InvertedMethod KEYWORD1
NeoEsp8266Uart1Ws2811InvertedMethod KEYWORD1
NeoEsp8266Uart1Sk6812InvertedMethod KEYWORD1
NeoEsp8266Uart1Tm1814InvertedMethod KEYWORD1
NeoEsp8266Uart1Lc8812InvertedMethod KEYWORD1
NeoEsp8266Uart1Apa106InvertedMethod KEYWORD1
NeoEsp8266Uart1800KbpsInvertedMethod KEYWORD1
NeoEsp8266Uart1400KbpsInvertedMethod KEYWORD1
NeoEsp8266AsyncUart1Ws2813InvertedMethod KEYWORD1
NeoEsp8266AsyncUart1Ws2812xInvertedMethod KEYWORD1
NeoEsp8266AsyncUart1Ws2812InvertedMethod KEYWORD1
NeoEsp8266AsyncUart1Ws2811InvertedMethod KEYWORD1
NeoEsp8266AsyncUart1Sk6812InvertedMethod KEYWORD1
NeoEsp8266AsyncUart1Tm1814InvertedMethod KEYWORD1
NeoEsp8266AsyncUart1Lc8812InvertedMethod KEYWORD1
NeoEsp8266AsyncUart1Apa106InvertedMethod KEYWORD1
NeoEsp8266AsyncUart1800KbpsInvertedMethod KEYWORD1
NeoEsp8266AsyncUart1400KbpsInvertedMethod KEYWORD1
NeoEsp8266BitBangWs2813Method KEYWORD1
NeoEsp8266BitBangWs2812xMethod KEYWORD1
NeoEsp8266BitBangWs2812Method KEYWORD1
NeoEsp8266BitBangWs2811Method KEYWORD1
NeoEsp8266BitBangSk6812Method KEYWORD1
NeoEsp8266BitBangTm1814Method KEYWORD1
NeoEsp8266BitBangLc8812Method KEYWORD1
NeoEsp8266BitBangApa106Method KEYWORD1
NeoEsp8266BitBang800KbpsMethod KEYWORD1
NeoEsp8266BitBang400KbpsMethod KEYWORD1
NeoEsp8266BitBangWs2813InvertedMethod KEYWORD1
NeoEsp8266BitBangWs2812xInvertedMethod KEYWORD1
NeoEsp8266BitBangWs2812InvertedMethod KEYWORD1
NeoEsp8266BitBangWs2811InvertedMethod KEYWORD1
NeoEsp8266BitBangSk6812InvertedMethod KEYWORD1
NeoEsp8266BitBangTm1814InvertedMethod KEYWORD1
NeoEsp8266BitBangLc8812InvertedMethod KEYWORD1
NeoEsp8266BitBangApa106InvertedMethod KEYWORD1
NeoEsp8266BitBang800KbpsInvertedMethod KEYWORD1
NeoEsp8266BitBang400KbpsInvertedMethod KEYWORD1
NeoEsp32I2s0Ws2812xMethod KEYWORD1
NeoEsp32I2s0Sk6812Method KEYWORD1
NeoEsp32I2s0Tm1814Method KEYWORD1
NeoEsp32I2s0800KbpsMethod KEYWORD1
NeoEsp32I2s0400KbpsMethod KEYWORD1
NeoEsp32I2s0Apa106Method KEYWORD1
NeoEsp32I2s1Ws2812xMethod KEYWORD1
NeoEsp32I2s1Sk6812Method KEYWORD1
NeoEsp32I2s1Tm1814Method KEYWORD1
NeoEsp32I2s1800KbpsMethod KEYWORD1
NeoEsp32I2s1400KbpsMethod KEYWORD1
NeoEsp32I2s1Apa106Method KEYWORD1
NeoEsp32I2s0Ws2812xInvertedMethod KEYWORD1
NeoEsp32I2s0Sk6812InvertedMethod KEYWORD1
NeoEsp32I2s0Tm1814InvertedMethod KEYWORD1
NeoEsp32I2s0800KbpsInvertedMethod KEYWORD1
NeoEsp32I2s0400KbpsInvertedMethod KEYWORD1
NeoEsp32I2s0Apa106InvertedMethod KEYWORD1
NeoEsp32I2s1Ws2812xInvertedMethod KEYWORD1
NeoEsp32I2s1Sk6812InvertedMethod KEYWORD1
NeoEsp32I2s1Tm1814InvertedMethod KEYWORD1
NeoEsp32I2s1800KbpsInvertedMethod KEYWORD1
NeoEsp32I2s1400KbpsInvertedMethod KEYWORD1
NeoEsp32I2s1Apa106InvertedMethod KEYWORD1
NeoEsp32Rmt0Ws2811Method KEYWORD1
NeoEsp32Rmt0Ws2812xMethod KEYWORD1
NeoEsp32Rmt0Sk6812Method KEYWORD1
NeoEsp32Rmt0Tm1814Method KEYWORD1
NeoEsp32Rmt0Apa106Method KEYWORD1
NeoEsp32Rmt0800KbpsMethod KEYWORD1
NeoEsp32Rmt0400KbpsMethod KEYWORD1
NeoEsp32Rmt1Ws2811Method KEYWORD1
NeoEsp32Rmt1Ws2812xMethod KEYWORD1
NeoEsp32Rmt1Sk6812Method KEYWORD1
NeoEsp32Rmt1Tm1814Method KEYWORD1
NeoEsp32Rmt1Apa106Method KEYWORD1
NeoEsp32Rmt1800KbpsMethod KEYWORD1
NeoEsp32Rmt1400KbpsMethod KEYWORD1
NeoEsp32Rmt2Ws2811Method KEYWORD1
NeoEsp32Rmt2Ws2812xMethod KEYWORD1
NeoEsp32Rmt2Sk6812Method KEYWORD1
NeoEsp32Rmt2Tm1814Method KEYWORD1
NeoEsp32Rmt2Apa106Method KEYWORD1
NeoEsp32Rmt2800KbpsMethod KEYWORD1
NeoEsp32Rmt2400KbpsMethod KEYWORD1
NeoEsp32Rmt3Ws2811Method KEYWORD1
NeoEsp32Rmt3Ws2812xMethod KEYWORD1
NeoEsp32Rmt3Sk6812Method KEYWORD1
NeoEsp32Rmt3Tm1814Method KEYWORD1
NeoEsp32Rmt3Apa106Method KEYWORD1
NeoEsp32Rmt3800KbpsMethod KEYWORD1
NeoEsp32Rmt3400KbpsMethod KEYWORD1
NeoEsp32Rmt4Ws2811Method KEYWORD1
NeoEsp32Rmt4Ws2812xMethod KEYWORD1
NeoEsp32Rmt4Sk6812Method KEYWORD1
NeoEsp32Rmt4Tm1814Method KEYWORD1
NeoEsp32Rmt4Apa106Method KEYWORD1
NeoEsp32Rmt4800KbpsMethod KEYWORD1
NeoEsp32Rmt4400KbpsMethod KEYWORD1
NeoEsp32Rmt5Ws2811Method KEYWORD1
NeoEsp32Rmt5Ws2812xMethod KEYWORD1
NeoEsp32Rmt5Sk6812Method KEYWORD1
NeoEsp32Rmt5Tm1814Method KEYWORD1
NeoEsp32Rmt5Apa106Method KEYWORD1
NeoEsp32Rmt5800KbpsMethod KEYWORD1
NeoEsp32Rmt5400KbpsMethod KEYWORD1
NeoEsp32Rmt6Ws2811Method KEYWORD1
NeoEsp32Rmt6Ws2812xMethod KEYWORD1
NeoEsp32Rmt6Sk6812Method KEYWORD1
NeoEsp32Rmt6Tm1814Method KEYWORD1
NeoEsp32Rmt6Apa106Method KEYWORD1
NeoEsp32Rmt6800KbpsMethod KEYWORD1
NeoEsp32Rmt6400KbpsMethod KEYWORD1
NeoEsp32Rmt7Ws2811Method KEYWORD1
NeoEsp32Rmt7Ws2812xMethod KEYWORD1
NeoEsp32Rmt7Sk6812Method KEYWORD1
NeoEsp32Rmt7Tm1814Method KEYWORD1
NeoEsp32Rmt7Apa106Method KEYWORD1
NeoEsp32Rmt7800KbpsMethod KEYWORD1
NeoEsp32Rmt7400KbpsMethod KEYWORD1
NeoEsp32Rmt0Ws2811InvertedMethod KEYWORD1
NeoEsp32Rmt0Ws2812xInvertedMethod KEYWORD1
NeoEsp32Rmt0Sk6812InvertedMethod KEYWORD1
NeoEsp32Rmt0Tm1814InvertedMethod KEYWORD1
NeoEsp32Rmt0Apa106InvertedMethod KEYWORD1
NeoEsp32Rmt0800KbpsInvertedMethod KEYWORD1
NeoEsp32Rmt0400KbpsInvertedMethod KEYWORD1
NeoEsp32Rmt1Ws2811InvertedMethod KEYWORD1
NeoEsp32Rmt1Ws2812xInvertedMethod KEYWORD1
NeoEsp32Rmt1Sk6812InvertedMethod KEYWORD1
NeoEsp32Rmt1Tm1814InvertedMethod KEYWORD1
NeoEsp32Rmt1Apa106InvertedMethod KEYWORD1
NeoEsp32Rmt1800KbpsInvertedMethod KEYWORD1
NeoEsp32Rmt1400KbpsInvertedMethod KEYWORD1
NeoEsp32Rmt2Ws2811InvertedMethod KEYWORD1
NeoEsp32Rmt2Ws2812xInvertedMethod KEYWORD1
NeoEsp32Rmt2Sk6812InvertedMethod KEYWORD1
NeoEsp32Rmt2Tm1814InvertedMethod KEYWORD1
NeoEsp32Rmt2Apa106InvertedMethod KEYWORD1
NeoEsp32Rmt2800KbpsInvertedMethod KEYWORD1
NeoEsp32Rmt2400KbpsInvertedMethod KEYWORD1
NeoEsp32Rmt3Ws2811InvertedMethod KEYWORD1
NeoEsp32Rmt3Ws2812xInvertedMethod KEYWORD1
NeoEsp32Rmt3Sk6812InvertedMethod KEYWORD1
NeoEsp32Rmt3Tm1814InvertedMethod KEYWORD1
NeoEsp32Rmt3Apa106InvertedMethod KEYWORD1
NeoEsp32Rmt3800KbpsInvertedMethod KEYWORD1
NeoEsp32Rmt3400KbpsInvertedMethod KEYWORD1
NeoEsp32Rmt4Ws2811InvertedMethod KEYWORD1
NeoEsp32Rmt4Ws2812xInvertedMethod KEYWORD1
NeoEsp32Rmt4Sk6812InvertedMethod KEYWORD1
NeoEsp32Rmt4Tm1814InvertedMethod KEYWORD1
NeoEsp32Rmt4Apa106InvertedMethod KEYWORD1
NeoEsp32Rmt4800KbpsInvertedMethod KEYWORD1
NeoEsp32Rmt4400KbpsInvertedMethod KEYWORD1
NeoEsp32Rmt5Ws2811InvertedMethod KEYWORD1
NeoEsp32Rmt5Ws2812xInvertedMethod KEYWORD1
NeoEsp32Rmt5Sk6812InvertedMethod KEYWORD1
NeoEsp32Rmt5Tm1814InvertedMethod KEYWORD1
NeoEsp32Rmt5Apa106InvertedMethod KEYWORD1
NeoEsp32Rmt5800KbpsInvertedMethod KEYWORD1
NeoEsp32Rmt5400KbpsInvertedMethod KEYWORD1
NeoEsp32Rmt6Ws2811InvertedMethod KEYWORD1
NeoEsp32Rmt6Ws2812xInvertedMethod KEYWORD1
NeoEsp32Rmt6Sk6812InvertedMethod KEYWORD1
NeoEsp32Rmt6Tm1814InvertedMethod KEYWORD1
NeoEsp32Rmt6Apa106InvertedMethod KEYWORD1
NeoEsp32Rmt6800KbpsInvertedMethod KEYWORD1
NeoEsp32Rmt6400KbpsInvertedMethod KEYWORD1
NeoEsp32Rmt7Ws2811InvertedMethod KEYWORD1
NeoEsp32Rmt7Ws2812xInvertedMethod KEYWORD1
NeoEsp32Rmt7Sk6812InvertedMethod KEYWORD1
NeoEsp32Rmt7Tm1814InvertedMethod KEYWORD1
NeoEsp32Rmt7Apa106InvertedMethod KEYWORD1
NeoEsp32Rmt7800KbpsInvertedMethod KEYWORD1
NeoEsp32Rmt7400KbpsInvertedMethod KEYWORD1
NeoEsp32BitBangWs2813Method KEYWORD1
NeoEsp32BitBangWs2812xMethod KEYWORD1
NeoEsp32BitBangWs2812Method KEYWORD1
NeoEsp32BitBangWs2811Method KEYWORD1
NeoEsp32BitBangSk6812Method KEYWORD1
NeoEsp32BitBangTm1814Method KEYWORD1
NeoEsp32BitBangLc8812Method KEYWORD1
NeoEsp32BitBangApa106Method KEYWORD1
NeoEsp32BitBang800KbpsMethod KEYWORD1
NeoEsp32BitBang400KbpsMethod KEYWORD1
NeoEsp32BitBangWs2813InvertedMethod KEYWORD1
NeoEsp32BitBangWs2812xInvertedMethod KEYWORD1
NeoEsp32BitBangWs2812InvertedMethod KEYWORD1
NeoEsp32BitBangWs2811InvertedMethod KEYWORD1
NeoEsp32BitBangSk6812InvertedMethod KEYWORD1
NeoEsp32BitBangTm1814InvertedMethod KEYWORD1
NeoEsp32BitBangLc8812InvertedMethod KEYWORD1
NeoEsp32BitBangApa106InvertedMethod KEYWORD1
NeoEsp32BitBang800KbpsInvertedMethod KEYWORD1
NeoEsp32BitBang400KbpsInvertedMethod KEYWORD1
NeoNrf52xPwm0Ws2812xMethod KEYWORD1
NeoNrf52xPwm0Sk6812Method KEYWORD1
NeoNrf52xPwm0Tm1814Method KEYWORD1
NeoNrf52xPwm0800KbpsMethod KEYWORD1
NeoNrf52xPwm0400KbpsMethod KEYWORD1
NeoNrf52xPwm0Apa106Method KEYWORD1
NeoNrf52xPwm1Ws2812xMethod KEYWORD1
NeoNrf52xPwm1Sk6812Method KEYWORD1
NeoNrf52xPwm1Tm1814Method KEYWORD1
NeoNrf52xPwm1800KbpsMethod KEYWORD1
NeoNrf52xPwm1400KbpsMethod KEYWORD1
NeoNrf52xPwm1Apa106Method KEYWORD1
NeoNrf52xPwm2Ws2812xMethod KEYWORD1
NeoNrf52xPwm2Sk6812Method KEYWORD1
NeoNrf52xPwm2Tm1814Method KEYWORD1
NeoNrf52xPwm2800KbpsMethod KEYWORD1
NeoNrf52xPwm2400KbpsMethod KEYWORD1
NeoNrf52xPwm2Apa106Method KEYWORD1
NeoNrf52xPwm3Ws2812xMethod KEYWORD1
NeoNrf52xPwm3Sk6812Method KEYWORD1
NeoNrf52xPwm3Tm1814Method KEYWORD1
NeoNrf52xPwm3800KbpsMethod KEYWORD1
NeoNrf52xPwm3400KbpsMethod KEYWORD1
NeoNrf52xPwm3Apa106Method KEYWORD1
NeoNrf52xPwm0Ws2812xInvertedMethod KEYWORD1
NeoNrf52xPwm0Sk6812InvertedMethod KEYWORD1
NeoNrf52xPwm0Tm1814InvertedMethod KEYWORD1
NeoNrf52xPwm0800KbpsInvertedMethod KEYWORD1
NeoNrf52xPwm0400KbpsInvertedMethod KEYWORD1
NeoNrf52xPwm0Apa106InvertedMethod KEYWORD1
NeoNrf52xPwm1Ws2812xInvertedMethod KEYWORD1
NeoNrf52xPwm1Sk6812InvertedMethod KEYWORD1
NeoNrf52xPwm1Tm1814InvertedMethod KEYWORD1
NeoNrf52xPwm1800KbpsInvertedMethod KEYWORD1
NeoNrf52xPwm1400KbpsInvertedMethod KEYWORD1
NeoNrf52xPwm1Apa106InvertedMethod KEYWORD1
NeoNrf52xPwm2Ws2812xInvertedMethod KEYWORD1
NeoNrf52xPwm2Sk6812InvertedMethod KEYWORD1
NeoNrf52xPwm2Tm1814InvertedMethod KEYWORD1
NeoNrf52xPwm2800KbpsInvertedMethod KEYWORD1
NeoNrf52xPwm2400KbpsInvertedMethod KEYWORD1
NeoNrf52xPwm2Apa106InvertedMethod KEYWORD1
NeoNrf52xPwm3Ws2812xInvertedMethod KEYWORD1
NeoNrf52xPwm3Sk6812InvertedMethod KEYWORD1
NeoNrf52xPwm3Tm1814InvertedMethod KEYWORD1
NeoNrf52xPwm3800KbpsInvertedMethod KEYWORD1
NeoNrf52xPwm3400KbpsInvertedMethod KEYWORD1
NeoNrf52xPwm3Apa106InvertedMethod KEYWORD1
DotStarMethod KEYWORD1
DotStarSpiMethod KEYWORD1
DotStarSpi20MhzMethod KEYWORD1
DotStarSpi10MhzMethod KEYWORD1
DotStarSpi2MhzMethod KEYWORD1
NeoWs2801Method KEYWORD1
NeoWs2801SpiMethod KEYWORD1
NeoWs2801Spi20MhzMethod KEYWORD1
NeoWs2801Spi10MhzMethod KEYWORD1
NeoWs2801Spi2MhzMethod KEYWORD1
Lpd8806Method KEYWORD1
Lpd8806SpiMethod KEYWORD1
Lpd8806Spi20MhzMethod KEYWORD1
Lpd8806Spi10MhzMethod KEYWORD1
Lpd8806Spi2MhzMethod KEYWORD1
P9813Method KEYWORD1
P9813SpiMethod KEYWORD1
P9813Spi20MhzMethod KEYWORD1
P9813Spi10MhzMethod KEYWORD1
P9813Spi2MhzMethod KEYWORD1
NeoPixelAnimator KEYWORD1
AnimUpdateCallback KEYWORD1
AnimationParam KEYWORD1
NeoEase KEYWORD1
AnimEaseFunction KEYWORD1
RowMajorLayout KEYWORD1
RowMajor90Layout KEYWORD1
RowMajor180Layout KEYWORD1
RowMajor270Layout KEYWORD1
RowMajorAlternatingLayout KEYWORD1
RowMajorAlternating90Layout KEYWORD1
RowMajorAlternating180Layout KEYWORD1
RowMajorAlternating270Layout KEYWORD1
ColumnMajorLayout KEYWORD1
ColumnMajor90Layout KEYWORD1
ColumnMajor180Layout KEYWORD1
ColumnMajor270Layout KEYWORD1
ColumnMajorAlternatingLayout KEYWORD1
ColumnMajorAlternating90Layout KEYWORD1
ColumnMajorAlternating180Layout KEYWORD1
ColumnMajorAlternating270Layout KEYWORD1
NeoTopology KEYWORD1
NeoRingTopology KEYWORD1
NeoTiles KEYWORD1
NeoMosaic KEYWORD1
NeoGammaEquationMethod KEYWORD1
NeoGammaTableMethod KEYWORD1
NeoGamma KEYWORD1
NeoHueBlendShortestDistance KEYWORD1
NeoHueBlendLongestDistance KEYWORD1
NeoHueBlendClockwiseDirection KEYWORD1
NeoHueBlendCounterClockwiseDirection KEYWORD1
NeoBufferContext KEYWORD1
LayoutMapCallback KEYWORD1
NeoBufferMethod KEYWORD1
NeoBufferProgmemMethod KEYWORD1
NeoBuffer KEYWORD1
NeoVerticalSpriteSheet KEYWORD1
NeoBitmapFile KEYWORD1
HtmlShortColorNames KEYWORD1
HtmlColorNames KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
Begin KEYWORD2
Show KEYWORD2
CanShow KEYWORD2
ClearTo KEYWORD2
RotateLeft KEYWORD2
ShiftLeft KEYWORD2
RotateRight KEYWORD2
ShiftRight KEYWORD2
IsDirty KEYWORD2
Dirty KEYWORD2
ResetDirty KEYWORD2
Pixels KEYWORD2
PixelSize KEYWORD2
PixelsSize KEYWORD2
PixelCount KEYWORD2
SetPixelColor KEYWORD2
GetPixelColor KEYWORD2
SwapPixelColor KEYWORD2
CalculateBrightness KEYWORD2
Dim KEYWORD2
Brighten KEYWORD2
Darken KEYWORD2
Lighten KEYWORD2
SetPixelSettings KEYWORD2
LinearBlend KEYWORD2
BilinearBlend KEYWORD2
IsAnimating KEYWORD2
NextAvailableAnimation KEYWORD2
StartAnimation KEYWORD2
StopAnimation KEYWORD2
RestartAnimation KEYWORD2
IsAnimationActive KEYWORD2
AnimationDuration KEYWORD2
ChangeAnimationDuration KEYWORD2
UpdateAnimations KEYWORD2
IsPaused KEYWORD2
Pause KEYWORD2
Resume KEYWORD2
getTimeScale KEYWORD2
setTimeScale KEYWORD2
QuadraticIn KEYWORD2
QuadraticOut KEYWORD2
QuadraticInOut KEYWORD2
QuadraticCenter KEYWORD2
CubicIn KEYWORD2
CubicOut KEYWORD2
CubicInOut KEYWORD2
CubicCenter KEYWORD2
QuarticIn KEYWORD2
QuarticOut KEYWORD2
QuarticInOut KEYWORD2
QuarticCenter KEYWORD2
QuinticIn KEYWORD2
QuinticOut KEYWORD2
QuinticInOut KEYWORD2
QuinticCenter KEYWORD2
SinusoidalIn KEYWORD2
SinusoidalOut KEYWORD2
SinusoidalInOut KEYWORD2
SinusoidalCenter KEYWORD2
ExponentialIn KEYWORD2
ExponentialOut KEYWORD2
ExponentialInOut KEYWORD2
ExponentialCenter KEYWORD2
CircularIn KEYWORD2
CircularOut KEYWORD2
CircularInOut KEYWORD2
CircularCenter KEYWORD2
Gamma KEYWORD2
Map KEYWORD2
MapProbe KEYWORD2
getWidth KEYWORD2
getHeight KEYWORD2
RingPixelShift KEYWORD2
RingPixelRotate KEYWORD2
getCountOfRings KEYWORD2
getPixelCountAtRing KEYWORD2
getPixelCount KEYWORD2
TopologyHint KEYWORD2
Correct KEYWORD2
SpriteWidth KEYWORD2
SpriteHeight KEYWORD2
SpriteCount KEYWORD2
Blt KEYWORD2
Width KEYWORD2
Height KEYWORD2
Parse KEYWORD2
ToString KEYWORD2
ToNumericalString KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################
NEO_MILLISECONDS LITERAL1
NEO_CENTISECONDS LITERAL1
NEO_DECISECONDS LITERAL1
NEO_SECONDS LITERAL1
NEO_DECASECONDS LITERAL1
AnimationState_Started LITERAL1
AnimationState_Progress LITERAL1
AnimationState_Completed LITERAL1
NeoTopologyHint_FirstOnPanel LITERAL1
NeoTopologyHint_InPanel LITERAL1
NeoTopologyHint_LastOnPanel LITERAL1
NeoTopologyHint_OutOfBounds LITERAL1
PixelIndex_OutOfBounds LITERAL1

View File

@@ -0,0 +1,14 @@
{
"name": "NeoPixelBus",
"keywords": "NeoPixel, WS2811, WS2812, WS2813, SK6812, DotStar, APA102, SK9822, APA106, LPD8806, P9813, WS2801 RGB, RGBW",
"description": "A library that makes controlling NeoPixels (APA106, WS2811, WS2812, WS2813 & SK6812) and DotStars (APA102, LPD8806, SK9822, WS2801, P9813) easy. Supports most Arduino platforms, including async hardware support for Esp8266, Esp32, and Nrf52 (Nano 33 BLE). Support for RGBW pixels. Includes seperate RgbColor, RgbwColor, HslColor, and HsbColor objects. Includes an animator class that helps create asyncronous animations. For Esp8266 it has three methods of sending NeoPixel data, DMA, UART, and Bit Bang. For Esp32 it has two base methods of sending NeoPixel data, i2s and RMT. For all platforms, there are two methods of sending DotStar data, hardware SPI and software SPI.",
"homepage": "https://github.com/Makuna/NeoPixelBus/wiki",
"repository": {
"type": "git",
"url": "https://github.com/Makuna/NeoPixelBus"
},
"version": "2.6.0",
"frameworks": "arduino",
"platforms": "*"
}

View File

@@ -0,0 +1,9 @@
name=NeoPixelBus by Makuna
version=2.6.0
author=Michael C. Miller (makuna@live.com)
maintainer=Michael C. Miller (makuna@live.com)
sentence=A library that makes controlling NeoPixels (APA106, WS2811, WS2812, WS2813 & SK6812) and DotStars (APA102, LPD8806, SK9822, WS2801, P9813) easy.
paragraph=Supports most Arduino platforms, including async hardware support for Esp8266, Esp32, and Nrf52 (Nano 33 BLE). Support for RGBW pixels. Includes seperate RgbColor, RgbwColor, HslColor, and HsbColor objects. Includes an animator class that helps create asyncronous animations. Supports Matrix layout of pixels. Includes Gamma corretion object. For Esp8266 it has three methods of sending NeoPixel data, DMA, UART, and Bit Bang. For Esp32 it has two base methods of sending NeoPixel data, i2s and RMT. For all platforms, there are two methods of sending DotStar data, hardware SPI and software SPI.
category=Display
url=https://github.com/Makuna/NeoPixelBus/wiki
architectures=*

View File

@@ -0,0 +1,180 @@
/*-------------------------------------------------------------------------
NeoPixelAnimator provides animation timing support.
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>
#include "internal/NeoEase.h"
enum AnimationState
{
AnimationState_Started,
AnimationState_Progress,
AnimationState_Completed
};
struct AnimationParam
{
float progress;
uint16_t index;
AnimationState state;
};
#if defined(NEOPIXEBUS_NO_STL)
typedef void(*AnimUpdateCallback)(const AnimationParam& param);
#else
#undef max
#undef min
#include <functional>
typedef std::function<void(const AnimationParam& param)> AnimUpdateCallback;
#endif
#define NEO_MILLISECONDS 1 // ~65 seconds max duration, ms updates
#define NEO_CENTISECONDS 10 // ~10.9 minutes max duration, centisecond updates
#define NEO_DECISECONDS 100 // ~1.8 hours max duration, decisecond updates
#define NEO_SECONDS 1000 // ~18.2 hours max duration, second updates
#define NEO_DECASECONDS 10000 // ~7.5 days, 10 second updates
class NeoPixelAnimator
{
public:
NeoPixelAnimator(uint16_t countAnimations, uint16_t timeScale = NEO_MILLISECONDS);
~NeoPixelAnimator();
bool IsAnimating() const
{
return _activeAnimations > 0;
}
bool NextAvailableAnimation(uint16_t* indexAvailable, uint16_t indexStart = 0);
void StartAnimation(uint16_t indexAnimation, uint16_t duration, AnimUpdateCallback animUpdate);
void StopAnimation(uint16_t indexAnimation);
void StopAll();
void RestartAnimation(uint16_t indexAnimation)
{
if (indexAnimation >= _countAnimations || _animations[indexAnimation]._duration == 0)
{
return;
}
StartAnimation(indexAnimation, _animations[indexAnimation]._duration, (_animations[indexAnimation]._fnCallback));
}
bool IsAnimationActive(uint16_t indexAnimation) const
{
if (indexAnimation >= _countAnimations)
{
return false;
}
return (IsAnimating() && _animations[indexAnimation]._remaining != 0);
}
uint16_t AnimationDuration(uint16_t indexAnimation)
{
if (indexAnimation >= _countAnimations)
{
return 0;
}
return _animations[indexAnimation]._duration;
}
void ChangeAnimationDuration(uint16_t indexAnimation, uint16_t newDuration);
void UpdateAnimations();
bool IsPaused()
{
return (!_isRunning);
}
void Pause()
{
_isRunning = false;
}
void Resume()
{
_isRunning = true;
_animationLastTick = millis();
}
uint16_t getTimeScale()
{
return _timeScale;
}
void setTimeScale(uint16_t timeScale)
{
_timeScale = (timeScale < 1) ? (1) : (timeScale > 32768) ? 32768 : timeScale;
}
private:
struct AnimationContext
{
AnimationContext() :
_duration(0),
_remaining(0),
_fnCallback(NULL)
{}
void StartAnimation(uint16_t duration, AnimUpdateCallback animUpdate)
{
_duration = duration;
_remaining = duration;
_fnCallback = animUpdate;
}
void StopAnimation()
{
_remaining = 0;
}
float CurrentProgress()
{
return (float)(_duration - _remaining) / (float)_duration;
}
uint16_t _duration;
uint16_t _remaining;
AnimUpdateCallback _fnCallback;
};
uint16_t _countAnimations;
AnimationContext* _animations;
uint32_t _animationLastTick;
uint16_t _activeAnimations;
uint16_t _timeScale;
bool _isRunning;
};

View File

@@ -0,0 +1,142 @@
/*-------------------------------------------------------------------------
NeoPixelBus library wrapper template class that provides overall brightness control
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 NeoPixelBrightnessBus :
public NeoPixelBus<T_COLOR_FEATURE, T_METHOD>
{
private:
void ScaleColor(uint16_t scale, typename T_COLOR_FEATURE::ColorObject* color)
{
uint8_t* ptr = (uint8_t*)color;
uint8_t* ptrEnd = ptr + sizeof(typename T_COLOR_FEATURE::ColorObject);
while (ptr != ptrEnd)
{
uint16_t value = *ptr;
*ptr++ = (value * scale) >> 8;
}
}
void ConvertColor(typename T_COLOR_FEATURE::ColorObject* color)
{
uint16_t scale = _brightness + 1;
ScaleColor(scale, color);
}
void RecoverColor(typename T_COLOR_FEATURE::ColorObject* color) const
{
uint8_t* ptr = (uint8_t*)color;
uint8_t* ptrEnd = ptr + sizeof(typename T_COLOR_FEATURE::ColorObject);
uint16_t scale = _brightness + 1;
while (ptr != ptrEnd)
{
uint16_t value = *ptr;
*ptr++ = (value << 8) / scale;
}
}
public:
NeoPixelBrightnessBus(uint16_t countPixels, uint8_t pin) :
NeoPixelBus<T_COLOR_FEATURE, T_METHOD>(countPixels, pin),
_brightness(255)
{
}
NeoPixelBrightnessBus(uint16_t countPixels, uint8_t pinClock, uint8_t pinData) :
NeoPixelBus<T_COLOR_FEATURE, T_METHOD>(countPixels, pinClock, pinData),
_brightness(255)
{
}
NeoPixelBrightnessBus(uint16_t countPixels) :
NeoPixelBus<T_COLOR_FEATURE, T_METHOD>(countPixels),
_brightness(255)
{
}
void SetBrightness(uint8_t brightness)
{
// Only update if there is a change
if (brightness != _brightness)
{
uint16_t scale = (((uint16_t)brightness + 1) << 8) / ((uint16_t)_brightness + 1);
// scale existing pixels
//
for (uint16_t indexPixel = 0; indexPixel < NeoPixelBus<T_COLOR_FEATURE, T_METHOD>::PixelCount(); indexPixel++)
{
typename T_COLOR_FEATURE::ColorObject color = NeoPixelBus<T_COLOR_FEATURE, T_METHOD>::GetPixelColor(indexPixel);
ScaleColor(scale, &color);
NeoPixelBus<T_COLOR_FEATURE, T_METHOD>::SetPixelColor(indexPixel, color);
}
_brightness = brightness;
this->Dirty();
}
}
uint8_t GetBrightness() const
{
return _brightness;
}
void SetPixelColor(uint16_t indexPixel, typename T_COLOR_FEATURE::ColorObject color)
{
ConvertColor(&color);
NeoPixelBus<T_COLOR_FEATURE, T_METHOD>::SetPixelColor(indexPixel, color);
}
typename T_COLOR_FEATURE::ColorObject GetPixelColor(uint16_t indexPixel) const
{
typename T_COLOR_FEATURE::ColorObject color = NeoPixelBus<T_COLOR_FEATURE, T_METHOD>::GetPixelColor(indexPixel);
RecoverColor(&color);
return color;
}
void ClearTo(typename T_COLOR_FEATURE::ColorObject color)
{
ConvertColor(&color);
NeoPixelBus<T_COLOR_FEATURE, T_METHOD>::ClearTo(color);
};
void ClearTo(typename T_COLOR_FEATURE::ColorObject color, uint16_t first, uint16_t last)
{
ConvertColor(&color);
NeoPixelBus<T_COLOR_FEATURE, T_METHOD>::ClearTo(color, first, last);
}
protected:
uint8_t _brightness;
};

View File

@@ -0,0 +1,468 @@
/*-------------------------------------------------------------------------
NeoPixel library
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>
// some platforms do not come with STL or properly defined one, specifically functional
// if you see...
// undefined reference to `std::__throw_bad_function_call()'
// ...then you can either add the platform symbol to the list so NEOPIXEBUS_NO_STL gets defined or
// go to boards.txt and enable c++ by adding (teensy31.build.flags.libs=-lstdc++) and set to "smallest code" option in Arduino
//
#if defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_MEGAAVR) || defined(STM32L432xx) || defined(STM32L476xx) || defined(ARDUINO_ARCH_SAM)
#define NEOPIXEBUS_NO_STL 1
#endif
// some platforms do not define this standard progmem type for some reason
//
#ifndef PGM_VOID_P
#define PGM_VOID_P const void *
#endif
// '_state' flags for internal state
#define NEO_DIRTY 0x80 // a change was made to pixel data that requires a show
#include "internal/NeoHueBlend.h"
#include "internal/NeoSettings.h"
#include "internal/RgbColor.h"
#include "internal/HslColor.h"
#include "internal/HsbColor.h"
#include "internal/HtmlColor.h"
#include "internal/RgbwColor.h"
#include "internal/SegmentDigit.h"
#include "internal/NeoColorFeatures.h"
#include "internal/NeoTm1814ColorFeatures.h"
#include "internal/DotStarColorFeatures.h"
#include "internal/Lpd8806ColorFeatures.h"
#include "internal/P9813ColorFeatures.h"
#include "internal/NeoSegmentFeatures.h"
#include "internal/Layouts.h"
#include "internal/NeoTopology.h"
#include "internal/NeoRingTopology.h"
#include "internal/NeoTiles.h"
#include "internal/NeoMosaic.h"
#include "internal/NeoBufferContext.h"
#include "internal/NeoBufferMethods.h"
#include "internal/NeoBuffer.h"
#include "internal/NeoSpriteSheet.h"
#include "internal/NeoDib.h"
#include "internal/NeoBitmapFile.h"
#include "internal/NeoEase.h"
#include "internal/NeoGamma.h"
#include "internal/DotStarGenericMethod.h"
#include "internal/Lpd8806GenericMethod.h"
#include "internal/Ws2801GenericMethod.h"
#include "internal/P9813GenericMethod.h"
#if defined(ARDUINO_ARCH_ESP8266)
#include "internal/NeoEsp8266DmaMethod.h"
#include "internal/NeoEsp8266UartMethod.h"
#include "internal/NeoEspBitBangMethod.h"
#elif defined(ARDUINO_ARCH_ESP32)
#include "internal/NeoEsp32I2sMethod.h"
#include "internal/NeoEsp32RmtMethod.h"
#include "internal/NeoEspBitBangMethod.h"
#elif defined(ARDUINO_ARCH_NRF52840) // must be before __arm__
#include "internal/NeoNrf52xMethod.h"
#elif defined(__arm__) // must be before ARDUINO_ARCH_AVR due to Teensy incorrectly having it set
#include "internal/NeoArmMethod.h"
#elif defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_MEGAAVR)
#include "internal/NeoAvrMethod.h"
#else
#error "Platform Currently Not Supported, please add an Issue at Github/Makuna/NeoPixelBus"
#endif
template<typename T_COLOR_FEATURE, typename T_METHOD> class NeoPixelBus
{
public:
// Constructor: number of LEDs, pin number
// NOTE: Pin Number maybe ignored due to hardware limitations of the method.
NeoPixelBus(uint16_t countPixels, uint8_t pin) :
_countPixels(countPixels),
_state(0),
_method(pin, countPixels, T_COLOR_FEATURE::PixelSize, T_COLOR_FEATURE::SettingsSize)
{
}
NeoPixelBus(uint16_t countPixels, uint8_t pinClock, uint8_t pinData) :
_countPixels(countPixels),
_state(0),
_method(pinClock, pinData, countPixels, T_COLOR_FEATURE::PixelSize, T_COLOR_FEATURE::SettingsSize)
{
}
NeoPixelBus(uint16_t countPixels) :
_countPixels(countPixels),
_state(0),
_method(countPixels, T_COLOR_FEATURE::PixelSize, T_COLOR_FEATURE::SettingsSize)
{
}
~NeoPixelBus()
{
}
operator NeoBufferContext<T_COLOR_FEATURE>()
{
Dirty(); // we assume you are playing with bits
return NeoBufferContext<T_COLOR_FEATURE>(_pixels(), PixelsSize());
}
void Begin()
{
_method.Initialize();
Dirty();
}
// used by DotStartSpiMethod if pins can be configured
void Begin(int8_t sck, int8_t miso, int8_t mosi, int8_t ss)
{
_method.Initialize(sck, miso, mosi, ss);
Dirty();
}
void Show(bool maintainBufferConsistency = true)
{
if (!IsDirty())
{
return;
}
_method.Update(maintainBufferConsistency);
ResetDirty();
}
inline bool CanShow() const
{
return _method.IsReadyToUpdate();
};
bool IsDirty() const
{
return (_state & NEO_DIRTY);
};
void Dirty()
{
_state |= NEO_DIRTY;
};
void ResetDirty()
{
_state &= ~NEO_DIRTY;
};
uint8_t* Pixels()
{
return _pixels();
};
size_t PixelsSize() const
{
return _method.getDataSize() - T_COLOR_FEATURE::SettingsSize;
};
size_t PixelSize() const
{
return T_COLOR_FEATURE::PixelSize;
};
uint16_t PixelCount() const
{
return _countPixels;
};
void SetPixelColor(uint16_t indexPixel, typename T_COLOR_FEATURE::ColorObject color)
{
if (indexPixel < _countPixels)
{
T_COLOR_FEATURE::applyPixelColor(_pixels(), indexPixel, color);
Dirty();
}
};
typename T_COLOR_FEATURE::ColorObject GetPixelColor(uint16_t indexPixel) const
{
if (indexPixel < _countPixels)
{
return T_COLOR_FEATURE::retrievePixelColor(_pixels(), indexPixel);
}
else
{
// Pixel # is out of bounds, this will get converted to a
// color object type initialized to 0 (black)
return 0;
}
};
void ClearTo(typename T_COLOR_FEATURE::ColorObject color)
{
uint8_t temp[T_COLOR_FEATURE::PixelSize];
uint8_t* pixels = _pixels();
T_COLOR_FEATURE::applyPixelColor(temp, 0, color);
T_COLOR_FEATURE::replicatePixel(pixels, temp, _countPixels);
Dirty();
};
void ClearTo(typename T_COLOR_FEATURE::ColorObject color, uint16_t first, uint16_t last)
{
if (first < _countPixels &&
last < _countPixels &&
first <= last)
{
uint8_t temp[T_COLOR_FEATURE::PixelSize];
uint8_t* pixels = _pixels();
uint8_t* pFront = T_COLOR_FEATURE::getPixelAddress(pixels, first);
T_COLOR_FEATURE::applyPixelColor(temp, 0, color);
T_COLOR_FEATURE::replicatePixel(pFront, temp, last - first + 1);
Dirty();
}
}
void RotateLeft(uint16_t rotationCount)
{
if ((_countPixels - 1) >= rotationCount)
{
_rotateLeft(rotationCount, 0, _countPixels - 1);
}
}
void RotateLeft(uint16_t rotationCount, uint16_t first, uint16_t last)
{
if (first < _countPixels &&
last < _countPixels &&
first < last &&
(last - first) >= rotationCount)
{
_rotateLeft(rotationCount, first, last);
}
}
void ShiftLeft(uint16_t shiftCount)
{
if ((_countPixels - 1) >= shiftCount)
{
_shiftLeft(shiftCount, 0, _countPixels - 1);
Dirty();
}
}
void ShiftLeft(uint16_t shiftCount, uint16_t first, uint16_t last)
{
if (first < _countPixels &&
last < _countPixels &&
first < last &&
(last - first) >= shiftCount)
{
_shiftLeft(shiftCount, first, last);
Dirty();
}
}
void RotateRight(uint16_t rotationCount)
{
if ((_countPixels - 1) >= rotationCount)
{
_rotateRight(rotationCount, 0, _countPixels - 1);
}
}
void RotateRight(uint16_t rotationCount, uint16_t first, uint16_t last)
{
if (first < _countPixels &&
last < _countPixels &&
first < last &&
(last - first) >= rotationCount)
{
_rotateRight(rotationCount, first, last);
}
}
void ShiftRight(uint16_t shiftCount)
{
if ((_countPixels - 1) >= shiftCount)
{
_shiftRight(shiftCount, 0, _countPixels - 1);
Dirty();
}
}
void ShiftRight(uint16_t shiftCount, uint16_t first, uint16_t last)
{
if (first < _countPixels &&
last < _countPixels &&
first < last &&
(last - first) >= shiftCount)
{
_shiftRight(shiftCount, first, last);
Dirty();
}
}
void SwapPixelColor(uint16_t indexPixelOne, uint16_t indexPixelTwo)
{
auto colorOne = GetPixelColor(indexPixelOne);
auto colorTwo = GetPixelColor(indexPixelTwo);
SetPixelColor(indexPixelOne, colorTwo);
SetPixelColor(indexPixelTwo, colorOne);
};
void SetPixelSettings(const typename T_COLOR_FEATURE::SettingsObject& settings)
{
T_COLOR_FEATURE::applySettings(_method.getData(), settings);
Dirty();
};
uint32_t CalcTotalMilliAmpere(const typename T_COLOR_FEATURE::ColorObject::SettingsObject& settings)
{
uint32_t total = 0; // in 1/10th milliamps
for (uint16_t index = 0; index < _countPixels; index++)
{
auto color = GetPixelColor(index);
total += color.CalcTotalTenthMilliAmpere(settings);
}
return total / 10; // return millamps
}
protected:
const uint16_t _countPixels; // Number of RGB LEDs in strip
uint8_t _state; // internal state
T_METHOD _method;
uint8_t* _pixels()
{
// get pixels data within the data stream
return T_COLOR_FEATURE::pixels(_method.getData());
}
const uint8_t* _pixels() const
{
// get pixels data within the data stream
return T_COLOR_FEATURE::pixels(_method.getData());
}
void _rotateLeft(uint16_t rotationCount, uint16_t first, uint16_t last)
{
// store in temp
uint8_t temp[rotationCount * T_COLOR_FEATURE::PixelSize];
uint8_t* pixels = _pixels();
uint8_t* pFront = T_COLOR_FEATURE::getPixelAddress(pixels, first);
T_COLOR_FEATURE::movePixelsInc(temp, pFront, rotationCount);
// shift data
_shiftLeft(rotationCount, first, last);
// move temp back
pFront = T_COLOR_FEATURE::getPixelAddress(pixels, last - (rotationCount - 1));
T_COLOR_FEATURE::movePixelsInc(pFront, temp, rotationCount);
Dirty();
}
void _shiftLeft(uint16_t shiftCount, uint16_t first, uint16_t last)
{
uint16_t front = first + shiftCount;
uint16_t count = last - front + 1;
uint8_t* pixels = _pixels();
uint8_t* pFirst = T_COLOR_FEATURE::getPixelAddress(pixels, first);
uint8_t* pFront = T_COLOR_FEATURE::getPixelAddress(pixels, front);
T_COLOR_FEATURE::movePixelsInc(pFirst, pFront, count);
// intentional no dirty
}
void _rotateRight(uint16_t rotationCount, uint16_t first, uint16_t last)
{
// store in temp
uint8_t temp[rotationCount * T_COLOR_FEATURE::PixelSize];
uint8_t* pixels = _pixels();
uint8_t* pFront = T_COLOR_FEATURE::getPixelAddress(pixels, last - (rotationCount - 1));
T_COLOR_FEATURE::movePixelsDec(temp, pFront, rotationCount);
// shift data
_shiftRight(rotationCount, first, last);
// move temp back
pFront = T_COLOR_FEATURE::getPixelAddress(pixels, first);
T_COLOR_FEATURE::movePixelsDec(pFront, temp, rotationCount);
Dirty();
}
void _shiftRight(uint16_t shiftCount, uint16_t first, uint16_t last)
{
uint16_t front = first + shiftCount;
uint16_t count = last - front + 1;
uint8_t* pixels = _pixels();
uint8_t* pFirst = T_COLOR_FEATURE::getPixelAddress(pixels, first);
uint8_t* pFront = T_COLOR_FEATURE::getPixelAddress(pixels, front);
T_COLOR_FEATURE::movePixelsDec(pFront, pFirst, count);
// intentional no dirty
}
};

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);
}
};

View File

@@ -0,0 +1,698 @@
/*-------------------------------------------------------------------------
DotStarColorFeatures provides feature classes to describe color order and
color depth for NeoPixelBus template class when used with DotStars
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 DotStar3Elements
{
public:
static const size_t PixelSize = 4; // still requires 4 to be sent
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)
{
*pPixelDest++ = pPixelSrc[0];
*pPixelDest++ = pPixelSrc[1];
*pPixelDest++ = pPixelSrc[2];
*pPixelDest++ = pPixelSrc[3];
}
}
static void movePixelsInc(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count)
{
uint8_t* pEnd = pPixelDest + (count * PixelSize);
while (pPixelDest < pEnd)
{
*pPixelDest++ = *pPixelSrc++;
*pPixelDest++ = *pPixelSrc++;
*pPixelDest++ = *pPixelSrc++;
*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++);
*pPixelDest++ = pgm_read_byte(pSrc++);
*pPixelDest++ = pgm_read_byte(pSrc++);
*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;
*--pDestBack = *--pSrcBack;
*--pDestBack = *--pSrcBack;
*--pDestBack = *--pSrcBack;
}
}
typedef RgbColor ColorObject;
};
class DotStar4Elements
{
public:
static const size_t PixelSize = 4;
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)
{
*pPixelDest++ = pPixelSrc[0];
*pPixelDest++ = pPixelSrc[1];
*pPixelDest++ = pPixelSrc[2];
*pPixelDest++ = pPixelSrc[3];
}
}
static void movePixelsInc(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count)
{
uint8_t* pEnd = pPixelDest + (count * PixelSize);
while (pPixelDest < pEnd)
{
*pPixelDest++ = *pPixelSrc++;
*pPixelDest++ = *pPixelSrc++;
*pPixelDest++ = *pPixelSrc++;
*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++);
*pPixelDest++ = pgm_read_byte(pSrc++);
*pPixelDest++ = pgm_read_byte(pSrc++);
*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;
*--pDestBack = *--pSrcBack;
*--pDestBack = *--pSrcBack;
*--pDestBack = *--pSrcBack;
}
}
typedef RgbwColor ColorObject;
};
class DotStar3ElementsNoSettings : public DotStar3Elements
{
public:
typedef NeoNoSettings SettingsObject;
static const size_t SettingsSize = 0;
static void applySettings(uint8_t*, const SettingsObject&)
{
}
static uint8_t* pixels(uint8_t* pData)
{
return pData;
}
static const uint8_t* pixels(const uint8_t* pData)
{
return pData;
}
};
class DotStar4ElementsNoSettings : public DotStar4Elements
{
public:
typedef NeoNoSettings SettingsObject;
static const size_t SettingsSize = 0;
static void applySettings(uint8_t*, const SettingsObject&)
{
}
static uint8_t* pixels(uint8_t* pData)
{
return pData;
}
static const uint8_t* pixels(const uint8_t* pData)
{
return pData;
}
};
class DotStarBgrFeature : public DotStar3ElementsNoSettings
{
public:
static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color)
{
uint8_t* p = getPixelAddress(pPixels, indexPixel);
*p++ = 0xff; // upper three bits are always 111 and brightness at max
*p++ = color.B;
*p++ = color.G;
*p = color.R;
}
static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel)
{
ColorObject color;
const uint8_t* p = getPixelAddress(pPixels, indexPixel);
p++; // ignore the first byte
color.B = *p++;
color.G = *p++;
color.R = *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);
pgm_read_byte(p++); // ignore the first byte
color.B = pgm_read_byte(p++);
color.G = pgm_read_byte(p++);
color.R = pgm_read_byte(p);
return color;
}
};
class DotStarLbgrFeature : public DotStar4ElementsNoSettings
{
public:
static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color)
{
uint8_t* p = getPixelAddress(pPixels, indexPixel);
*p++ = 0xE0 | (color.W < 31 ? color.W : 31); // upper three bits are always 111
*p++ = color.B;
*p++ = color.G;
*p = color.R;
}
static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel)
{
ColorObject color;
const uint8_t* p = getPixelAddress(pPixels, indexPixel);
color.W = (*p++) & 0x1F; // mask out upper three bits
color.B = *p++;
color.G = *p++;
color.R = *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);
color.W = pgm_read_byte(p++) & 0x1F; // mask out upper three bits
color.B = pgm_read_byte(p++);
color.G = pgm_read_byte(p++);
color.R = pgm_read_byte(p);
return color;
}
};
class DotStarGrbFeature : public DotStar3ElementsNoSettings
{
public:
static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color)
{
uint8_t* p = getPixelAddress(pPixels, indexPixel);
*p++ = 0xff; // upper three bits are always 111 and brightness at max
*p++ = color.G;
*p++ = color.R;
*p = color.B;
}
static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel)
{
ColorObject color;
const uint8_t* p = getPixelAddress(pPixels, indexPixel);
p++; // ignore the first byte
color.G = *p++;
color.R = *p++;
color.B = *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);
pgm_read_byte(p++); // ignore the first byte
color.G = pgm_read_byte(p++);
color.R = pgm_read_byte(p++);
color.B = pgm_read_byte(p);
return color;
}
};
class DotStarLgrbFeature : public DotStar4ElementsNoSettings
{
public:
static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color)
{
uint8_t* p = getPixelAddress(pPixels, indexPixel);
*p++ = 0xE0 | (color.W < 31 ? color.W : 31); // upper three bits are always 111
*p++ = color.G;
*p++ = color.R;
*p = color.B;
}
static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel)
{
ColorObject color;
const uint8_t* p = getPixelAddress(pPixels, indexPixel);
color.W = (*p++) & 0x1F; // mask out upper three bits
color.G = *p++;
color.R = *p++;
color.B = *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);
color.W = pgm_read_byte(p++) & 0x1F; // mask out upper three bits
color.G = pgm_read_byte(p++);
color.R = pgm_read_byte(p++);
color.B = pgm_read_byte(p);
return color;
}
};
/* RGB Feature -- Some APA102s ship in RGB order */
class DotStarRgbFeature : public DotStar3ElementsNoSettings
{
public:
static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color)
{
uint8_t* p = getPixelAddress(pPixels, indexPixel);
*p++ = 0xff; // upper three bits are always 111 and brightness at max
*p++ = color.R;
*p++ = color.G;
*p = color.B;
}
static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel)
{
ColorObject color;
const uint8_t* p = getPixelAddress(pPixels, indexPixel);
p++; // ignore the first byte
color.R = *p++;
color.G = *p++;
color.B = *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);
pgm_read_byte(p++); // ignore the first byte
color.R = pgm_read_byte(p++);
color.G = pgm_read_byte(p++);
color.B = pgm_read_byte(p);
return color;
}
};
class DotStarLrgbFeature : public DotStar4ElementsNoSettings
{
public:
static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color)
{
uint8_t* p = getPixelAddress(pPixels, indexPixel);
*p++ = 0xE0 | (color.W < 31 ? color.W : 31); // upper three bits are always 111
*p++ = color.R;
*p++ = color.G;
*p = color.B;
}
static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel)
{
ColorObject color;
const uint8_t* p = getPixelAddress(pPixels, indexPixel);
color.W = (*p++) & 0x1F; // mask out upper three bits
color.R = *p++;
color.G = *p++;
color.B = *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);
color.W = pgm_read_byte(p++) & 0x1F; // mask out upper three bits
color.R = pgm_read_byte(p++);
color.G = pgm_read_byte(p++);
color.B = pgm_read_byte(p);
return color;
}
};
/* RBG Feature -- Some APA102s ship in RBG order */
class DotStarRbgFeature : public DotStar3ElementsNoSettings
{
public:
static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color)
{
uint8_t* p = getPixelAddress(pPixels, indexPixel);
*p++ = 0xff; // upper three bits are always 111 and brightness at max
*p++ = color.R;
*p++ = color.B;
*p = color.G;
}
static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel)
{
ColorObject color;
const uint8_t* p = getPixelAddress(pPixels, indexPixel);
p++; // ignore the first byte
color.R = *p++;
color.B = *p++;
color.G = *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);
pgm_read_byte(p++); // ignore the first byte
color.R = pgm_read_byte(p++);
color.B = pgm_read_byte(p++);
color.G = pgm_read_byte(p);
return color;
}
};
class DotStarLrbgFeature : public DotStar4ElementsNoSettings
{
public:
static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color)
{
uint8_t* p = getPixelAddress(pPixels, indexPixel);
*p++ = 0xE0 | (color.W < 31 ? color.W : 31); // upper three bits are always 111
*p++ = color.R;
*p++ = color.B;
*p = color.G;
}
static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel)
{
ColorObject color;
const uint8_t* p = getPixelAddress(pPixels, indexPixel);
color.W = (*p++) & 0x1F; // mask out upper three bits
color.R = *p++;
color.B = *p++;
color.G = *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);
color.W = pgm_read_byte(p++) & 0x1F; // mask out upper three bits
color.R = pgm_read_byte(p++);
color.B = pgm_read_byte(p++);
color.G = pgm_read_byte(p);
return color;
}
};
/* GBR Feature -- Some APA102s ship in GBR order */
class DotStarGbrFeature : public DotStar3ElementsNoSettings
{
public:
static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color)
{
uint8_t* p = getPixelAddress(pPixels, indexPixel);
*p++ = 0xff; // upper three bits are always 111 and brightness at max
*p++ = color.G;
*p++ = color.B;
*p = color.R;
}
static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel)
{
ColorObject color;
const uint8_t* p = getPixelAddress(pPixels, indexPixel);
p++; // ignore the first byte
color.G = *p++;
color.B = *p++;
color.R = *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);
pgm_read_byte(p++); // ignore the first byte
color.G = pgm_read_byte(p++);
color.B = pgm_read_byte(p++);
color.R = pgm_read_byte(p);
return color;
}
};
class DotStarLgbrFeature : public DotStar4ElementsNoSettings
{
public:
static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color)
{
uint8_t* p = getPixelAddress(pPixels, indexPixel);
*p++ = 0xE0 | (color.W < 31 ? color.W : 31); // upper three bits are always 111
*p++ = color.G;
*p++ = color.B;
*p = color.R;
}
static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel)
{
ColorObject color;
const uint8_t* p = getPixelAddress(pPixels, indexPixel);
color.W = (*p++) & 0x1F; // mask out upper three bits
color.G = *p++;
color.B = *p++;
color.R = *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);
color.W = pgm_read_byte(p++) & 0x1F; // mask out upper three bits
color.G = pgm_read_byte(p++);
color.B = pgm_read_byte(p++);
color.R = pgm_read_byte(p);
return color;
}
};
/* BRG Feature -- Some APA102s ship in BRG order */
class DotStarBrgFeature : public DotStar3ElementsNoSettings
{
public:
static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color)
{
uint8_t* p = getPixelAddress(pPixels, indexPixel);
*p++ = 0xff; // upper three bits are always 111 and brightness at max
*p++ = color.B;
*p++ = color.R;
*p = color.G;
}
static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel)
{
ColorObject color;
const uint8_t* p = getPixelAddress(pPixels, indexPixel);
p++; // ignore the first byte
color.B = *p++;
color.R = *p++;
color.G = *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);
pgm_read_byte(p++); // ignore the first byte
color.B = pgm_read_byte(p++);
color.R = pgm_read_byte(p++);
color.G = pgm_read_byte(p);
return color;
}
};
class DotStarLbrgFeature : public DotStar4ElementsNoSettings
{
public:
static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color)
{
uint8_t* p = getPixelAddress(pPixels, indexPixel);
*p++ = 0xE0 | (color.W < 31 ? color.W : 31); // upper three bits are always 111
*p++ = color.B;
*p++ = color.R;
*p = color.G;
}
static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel)
{
ColorObject color;
const uint8_t* p = getPixelAddress(pPixels, indexPixel);
color.W = (*p++) & 0x1F; // mask out upper three bits
color.B = *p++;
color.R = *p++;
color.G = *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);
color.W = pgm_read_byte(p++) & 0x1F; // mask out upper three bits
color.B = pgm_read_byte(p++);
color.R = pgm_read_byte(p++);
color.G = pgm_read_byte(p);
return color;
}
};

View File

@@ -0,0 +1,135 @@
/*-------------------------------------------------------------------------
NeoPixel library helper functions for DotStars using general Pins (APA102).
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
// must also check for arm due to Teensy incorrectly having ARDUINO_ARCH_AVR set
#if defined(ARDUINO_ARCH_AVR) && !defined(__arm__)
#include "TwoWireBitBangImpleAvr.h"
#else
#include "TwoWireBitBangImple.h"
#endif
template<typename T_TWOWIRE> class DotStarMethodBase
{
public:
DotStarMethodBase(uint8_t pinClock, uint8_t pinData, uint16_t pixelCount, size_t elementSize, size_t settingsSize) :
_sizeData(pixelCount * elementSize + settingsSize),
_sizeEndFrame((pixelCount + 15) / 16), // 16 = div 2 (bit for every two pixels) div 8 (bits to bytes)
_wire(pinClock, pinData)
{
_data = static_cast<uint8_t*>(malloc(_sizeData));
memset(_data, 0, _sizeData);
}
#if !defined(__AVR_ATtiny85__) && !defined(ARDUINO_attiny)
DotStarMethodBase(uint16_t pixelCount, size_t elementSize, size_t settingsSize) :
DotStarMethodBase(SCK, MOSI, pixelCount, elementSize, settingsSize)
{
}
#endif
~DotStarMethodBase()
{
free(_data);
}
bool IsReadyToUpdate() const
{
return true; // dot stars don't have a required delay
}
#if defined(ARDUINO_ARCH_ESP32)
void Initialize(int8_t sck, int8_t miso, int8_t mosi, int8_t ss)
{
_wire.begin(sck, miso, mosi, ss);
}
#endif
void Initialize()
{
_wire.begin();
}
void Update(bool)
{
const uint8_t startFrame[4] = { 0x00 };
const uint8_t resetFrame[4] = { 0x00 };
_wire.beginTransaction();
// start frame
_wire.transmitBytes(startFrame, sizeof(startFrame));
// data
_wire.transmitBytes(_data, _sizeData);
// reset frame
_wire.transmitBytes(resetFrame, sizeof(resetFrame));
// end frame
// one bit for every two pixels with no less than 1 byte
for (size_t endFrameByte = 0; endFrameByte < _sizeEndFrame; endFrameByte++)
{
_wire.transmitByte(0x00);
}
_wire.endTransaction();
}
uint8_t* getData() const
{
return _data;
};
size_t getDataSize() const
{
return _sizeData;
};
private:
const size_t _sizeData; // Size of '_data' buffer below
const size_t _sizeEndFrame;
T_TWOWIRE _wire;
uint8_t* _data; // Holds LED color values
};
typedef DotStarMethodBase<TwoWireBitBangImple> DotStarMethod;
#if !defined(__AVR_ATtiny85__) && !defined(ARDUINO_attiny)
#include "TwoWireSpiImple.h"
typedef DotStarMethodBase<TwoWireSpiImple<SpiSpeed40Mhz>> DotStarSpi40MhzMethod;
typedef DotStarMethodBase<TwoWireSpiImple<SpiSpeed20Mhz>> DotStarSpi20MhzMethod;
typedef DotStarMethodBase<TwoWireSpiImple<SpiSpeed10Mhz>> DotStarSpi10MhzMethod;
typedef DotStarMethodBase<TwoWireSpiImple<SpiSpeed2Mhz>> DotStarSpi2MhzMethod;
typedef DotStarSpi10MhzMethod DotStarSpiMethod;
#endif

View File

@@ -0,0 +1,498 @@
// WARNING: This file contains code that is more than likely already
// exposed from the Esp32 Arduino API. It will be removed once integration is complete.
//
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#if defined(ARDUINO_ARCH_ESP32)
#include <string.h>
#include <stdio.h>
#include "stdlib.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "freertos/queue.h"
#if ESP_IDF_VERSION_MAJOR>=4
#include "esp_intr_alloc.h"
#else
#include "esp_intr.h"
#endif
#include "soc/gpio_reg.h"
#include "soc/gpio_sig_map.h"
#include "soc/io_mux_reg.h"
#include "soc/rtc_cntl_reg.h"
#include "soc/i2s_struct.h"
#include "soc/dport_reg.h"
#include "soc/sens_reg.h"
#include "driver/gpio.h"
#include "driver/i2s.h"
#include "driver/dac.h"
#include "Esp32_i2s.h"
#include "esp32-hal.h"
#if ESP_IDF_VERSION_MAJOR<4
#define I2S_BASE_CLK (160000000L)
#endif
#define ESP32_REG(addr) (*((volatile uint32_t*)(0x3FF00000+(addr))))
#define I2S_DMA_QUEUE_SIZE 16
#define I2S_DMA_SILENCE_LEN 256 // bytes
typedef struct i2s_dma_item_s {
uint32_t blocksize: 12; // datalen
uint32_t datalen : 12; // len*(bits_per_sample/8)*2 => max 2047*8bit/1023*16bit samples
uint32_t unused : 5; // 0
uint32_t sub_sof : 1; // 0
uint32_t eof : 1; // 1 => last?
uint32_t owner : 1; // 1
void* data; // malloc(datalen)
struct i2s_dma_item_s* next;
// if this pointer is not null, it will be freed
void* free_ptr;
// if DMA buffers are preallocated
uint8_t* buf;
} i2s_dma_item_t;
typedef struct {
i2s_dev_t* bus;
int8_t ws;
int8_t bck;
int8_t out;
int8_t in;
uint32_t rate;
intr_handle_t isr_handle;
xQueueHandle tx_queue;
uint8_t* silence_buf;
size_t silence_len;
i2s_dma_item_t* dma_items;
size_t dma_count;
uint32_t dma_buf_len :12;
uint32_t unused :20;
} i2s_bus_t;
static uint8_t i2s_silence_buf[I2S_DMA_SILENCE_LEN];
#if !defined(CONFIG_IDF_TARGET_ESP32S2)
// (I2S_NUM_MAX == 2)
static i2s_bus_t I2S[I2S_NUM_MAX] = {
{&I2S0, -1, -1, -1, -1, 0, NULL, NULL, i2s_silence_buf, I2S_DMA_SILENCE_LEN, NULL, I2S_DMA_QUEUE_SIZE, 0, 0},
{&I2S1, -1, -1, -1, -1, 0, NULL, NULL, i2s_silence_buf, I2S_DMA_SILENCE_LEN, NULL, I2S_DMA_QUEUE_SIZE, 0, 0}
};
#else
static i2s_bus_t I2S[I2S_NUM_MAX] = {
{&I2S0, -1, -1, -1, -1, 0, NULL, NULL, i2s_silence_buf, I2S_DMA_SILENCE_LEN, NULL, I2S_DMA_QUEUE_SIZE, 0, 0}
};
#endif
void IRAM_ATTR i2sDmaISR(void* arg);
bool i2sInitDmaItems(uint8_t bus_num);
bool i2sInitDmaItems(uint8_t bus_num) {
if (bus_num >= I2S_NUM_MAX) {
return false;
}
if (I2S[bus_num].tx_queue) {// already set
return true;
}
if (I2S[bus_num].dma_items == NULL) {
I2S[bus_num].dma_items = (i2s_dma_item_t*)(malloc(I2S[bus_num].dma_count* sizeof(i2s_dma_item_t)));
if (I2S[bus_num].dma_items == NULL) {
log_e("MEM ERROR!");
return false;
}
}
int i, i2, a;
i2s_dma_item_t* item;
for(i=0; i<I2S[bus_num].dma_count; i++) {
i2 = (i+1) % I2S[bus_num].dma_count;
item = &I2S[bus_num].dma_items[i];
item->eof = 1;
item->owner = 1;
item->sub_sof = 0;
item->unused = 0;
item->data = I2S[bus_num].silence_buf;
item->blocksize = I2S[bus_num].silence_len;
item->datalen = I2S[bus_num].silence_len;
item->next = &I2S[bus_num].dma_items[i2];
item->free_ptr = NULL;
if (I2S[bus_num].dma_buf_len) {
item->buf = (uint8_t*)(malloc(I2S[bus_num].dma_buf_len));
if (item->buf == NULL) {
log_e("MEM ERROR!");
for(a=0; a<i; a++) {
free(I2S[bus_num].dma_items[i].buf);
}
free(I2S[bus_num].dma_items);
I2S[bus_num].dma_items = NULL;
return false;
}
} else {
item->buf = NULL;
}
}
I2S[bus_num].tx_queue = xQueueCreate(I2S[bus_num].dma_count, sizeof(i2s_dma_item_t*));
if (I2S[bus_num].tx_queue == NULL) {// memory error
log_e("MEM ERROR!");
free(I2S[bus_num].dma_items);
I2S[bus_num].dma_items = NULL;
return false;
}
return true;
}
void i2sSetSilenceBuf(uint8_t bus_num, uint8_t* data, size_t len) {
if (bus_num >= I2S_NUM_MAX || !data || !len) {
return;
}
I2S[bus_num].silence_buf = data;
I2S[bus_num].silence_len = len;
}
esp_err_t i2sSetClock(uint8_t bus_num, uint8_t div_num, uint8_t div_b, uint8_t div_a, uint8_t bck, uint8_t bits) {
if (bus_num >= I2S_NUM_MAX || div_a > 63 || div_b > 63 || bck > 63) {
return ESP_FAIL;
}
i2s_dev_t* i2s = I2S[bus_num].bus;
typeof(i2s->clkm_conf) clkm_conf;
clkm_conf.val = 0;
#if !defined(CONFIG_IDF_TARGET_ESP32S2)
clkm_conf.clka_en = 0;
#else
clkm_conf.clk_sel = 2;
#endif
clkm_conf.clkm_div_a = div_a;
clkm_conf.clkm_div_b = div_b;
clkm_conf.clkm_div_num = div_num;
i2s->clkm_conf.val = clkm_conf.val;
typeof(i2s->sample_rate_conf) sample_rate_conf;
sample_rate_conf.val = 0;
sample_rate_conf.tx_bck_div_num = bck;
sample_rate_conf.rx_bck_div_num = bck;
sample_rate_conf.tx_bits_mod = bits;
sample_rate_conf.rx_bits_mod = bits;
i2s->sample_rate_conf.val = sample_rate_conf.val;
return ESP_OK;
}
void i2sSetDac(uint8_t bus_num, bool right, bool left) {
if (bus_num >= I2S_NUM_MAX) {
return;
}
if (!right && !left) {
dac_output_disable(DAC_CHANNEL_1);
dac_output_disable(DAC_CHANNEL_2);
dac_i2s_disable();
I2S[bus_num].bus->conf2.lcd_en = 0;
I2S[bus_num].bus->conf.tx_right_first = 0;
I2S[bus_num].bus->conf2.camera_en = 0;
I2S[bus_num].bus->conf.tx_msb_shift = 1;// I2S signaling
return;
}
i2sSetPins(bus_num, -1, false);
I2S[bus_num].bus->conf2.lcd_en = 1;
I2S[bus_num].bus->conf.tx_right_first = 0;
I2S[bus_num].bus->conf2.camera_en = 0;
I2S[bus_num].bus->conf.tx_msb_shift = 0;
dac_i2s_enable();
if (right) {// DAC1, right channel, GPIO25
dac_output_enable(DAC_CHANNEL_1);
}
if (left) { // DAC2, left channel, GPIO26
dac_output_enable(DAC_CHANNEL_2);
}
}
void i2sSetPins(uint8_t bus_num, int8_t out, bool invert) {
if (bus_num >= I2S_NUM_MAX) {
return;
}
if (out >= 0) {
if (I2S[bus_num].out != out) {
if (I2S[bus_num].out >= 0) {
gpio_matrix_out(I2S[bus_num].out, 0x100, invert, false);
}
I2S[bus_num].out = out;
pinMode(out, OUTPUT);
int i2sSignal;
#if !defined(CONFIG_IDF_TARGET_ESP32S2)
// (I2S_NUM_MAX == 2)
if (bus_num == 1) {
i2sSignal = I2S1O_DATA_OUT23_IDX;
}
else
#endif
{
i2sSignal = I2S0O_DATA_OUT23_IDX;
}
gpio_matrix_out(out, i2sSignal, invert, false);
}
} else if (I2S[bus_num].out >= 0) {
gpio_matrix_out(I2S[bus_num].out, 0x100, invert, false);
I2S[bus_num].out = -1;
}
}
bool i2sWriteDone(uint8_t bus_num) {
if (bus_num >= I2S_NUM_MAX) {
return false;
}
return (I2S[bus_num].dma_items[I2S[bus_num].dma_count - 1].data == I2S[bus_num].silence_buf);
}
void i2sInit(uint8_t bus_num, uint32_t bits_per_sample, uint32_t sample_rate, i2s_tx_chan_mod_t chan_mod, i2s_tx_fifo_mod_t fifo_mod, size_t dma_count, size_t dma_len) {
if (bus_num >= I2S_NUM_MAX) {
return;
}
I2S[bus_num].dma_count = dma_count;
I2S[bus_num].dma_buf_len = dma_len & 0xFFF;
if (!i2sInitDmaItems(bus_num)) {
return;
}
#if !defined(CONFIG_IDF_TARGET_ESP32S2)
// (I2S_NUM_MAX == 2)
if (bus_num) {
periph_module_enable(PERIPH_I2S1_MODULE);
} else
#endif
{
periph_module_enable(PERIPH_I2S0_MODULE);
}
esp_intr_disable(I2S[bus_num].isr_handle);
i2s_dev_t* i2s = I2S[bus_num].bus;
i2s->out_link.stop = 1;
i2s->conf.tx_start = 0;
i2s->int_ena.val = 0;
i2s->int_clr.val = 0xFFFFFFFF;
i2s->fifo_conf.dscr_en = 0;
// reset fifo
i2s->conf.rx_fifo_reset = 1;
i2s->conf.rx_fifo_reset = 0;
i2s->conf.tx_fifo_reset = 1;
i2s->conf.tx_fifo_reset = 0;
// reset i2s
i2s->conf.tx_reset = 1;
i2s->conf.tx_reset = 0;
i2s->conf.rx_reset = 1;
i2s->conf.rx_reset = 0;
// reset dma
i2s->lc_conf.in_rst = 1;
i2s->lc_conf.in_rst = 0;
i2s->lc_conf.out_rst = 1;
i2s->lc_conf.out_rst = 0;
// Enable and configure DMA
typeof(i2s->lc_conf) lc_conf;
lc_conf.val = 0;
lc_conf.out_eof_mode = 1;
i2s->lc_conf.val = lc_conf.val;
i2s->pdm_conf.pcm2pdm_conv_en = 0;
i2s->pdm_conf.pdm2pcm_conv_en = 0;
// SET_PERI_REG_BITS(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_SOC_CLK_SEL, 0x1, RTC_CNTL_SOC_CLK_SEL_S);
typeof(i2s->conf_chan) conf_chan;
conf_chan.val = 0;
conf_chan.tx_chan_mod = chan_mod; // 0-two channel;1-right;2-left;3-righ;4-left
conf_chan.rx_chan_mod = chan_mod; // 0-two channel;1-right;2-left;3-righ;4-left
i2s->conf_chan.val = conf_chan.val;
typeof(i2s->fifo_conf) fifo_conf;
fifo_conf.val = 0;
fifo_conf.tx_fifo_mod = fifo_mod; // 0-right&left channel;1-one channel
fifo_conf.rx_fifo_mod = fifo_mod; // 0-right&left channel;1-one channel
i2s->fifo_conf.val = fifo_conf.val;
typeof(i2s->conf) conf;
conf.val = 0;
conf.tx_msb_shift = (bits_per_sample != 8);// 0:DAC/PCM, 1:I2S
conf.tx_right_first = (bits_per_sample == 8);
i2s->conf.val = conf.val;
typeof(i2s->conf2) conf2;
conf2.val = 0;
conf2.lcd_en = (bits_per_sample == 8);
i2s->conf2.val = conf2.val;
i2s->fifo_conf.tx_fifo_mod_force_en = 1;
i2s->pdm_conf.rx_pdm_en = 0;
i2s->pdm_conf.tx_pdm_en = 0;
i2sSetSampleRate(bus_num, sample_rate, bits_per_sample);
// enable intr in cpu //
int i2sIntSource;
#if !defined(CONFIG_IDF_TARGET_ESP32S2)
// (I2S_NUM_MAX == 2)
if (bus_num == 1) {
i2sIntSource = ETS_I2S1_INTR_SOURCE;
}
else
#endif
{
i2sIntSource = ETS_I2S0_INTR_SOURCE;
}
esp_intr_alloc(i2sIntSource, ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_LEVEL1, &i2sDmaISR, &I2S[bus_num], &I2S[bus_num].isr_handle);
// enable send intr
i2s->int_ena.out_eof = 1;
i2s->int_ena.out_dscr_err = 1;
i2s->fifo_conf.dscr_en = 1;// enable dma
i2s->out_link.start = 0;
i2s->out_link.addr = (uint32_t)(&I2S[bus_num].dma_items[0]); // loads dma_struct to dma
i2s->out_link.start = 1; // starts dma
i2s->conf.tx_start = 1;// Start I2s module
esp_intr_enable(I2S[bus_num].isr_handle);
}
esp_err_t i2sSetSampleRate(uint8_t bus_num, uint32_t rate, uint8_t bits) {
if (bus_num >= I2S_NUM_MAX) {
return ESP_FAIL;
}
if (I2S[bus_num].rate == rate) {
return ESP_OK;
}
int clkmInteger, clkmDecimals, bck = 0;
double denom = (double)1 / 63;
int channel = 2;
// double mclk;
double clkmdiv;
int factor;
if (bits == 8) {
factor = 120;
} else {
factor = (256 % bits) ? 384 : 256;
}
clkmdiv = (double)I2S_BASE_CLK / (rate* factor);
if (clkmdiv > 256) {
log_e("rate is too low");
return ESP_FAIL;
}
I2S[bus_num].rate = rate;
clkmInteger = clkmdiv;
clkmDecimals = ((clkmdiv - clkmInteger) / denom);
if (bits == 8) {
// mclk = rate* factor;
bck = 60;
bits = 16;
} else {
// mclk = (double)clkmInteger + (denom* clkmDecimals);
bck = factor/(bits* channel);
}
i2sSetClock(bus_num, clkmInteger, clkmDecimals, 63, bck, bits);
return ESP_OK;
}
void IRAM_ATTR i2sDmaISR(void* arg)
{
i2s_dma_item_t* dummy = NULL;
i2s_bus_t* dev = (i2s_bus_t*)(arg);
portBASE_TYPE hpTaskAwoken = 0;
if (dev->bus->int_st.out_eof) {
i2s_dma_item_t* item = (i2s_dma_item_t*)(dev->bus->out_eof_des_addr);
item->data = dev->silence_buf;
item->blocksize = dev->silence_len;
item->datalen = dev->silence_len;
if (xQueueIsQueueFullFromISR(dev->tx_queue) == pdTRUE) {
xQueueReceiveFromISR(dev->tx_queue, &dummy, &hpTaskAwoken);
}
xQueueSendFromISR(dev->tx_queue, (void*)&item, &hpTaskAwoken);
}
dev->bus->int_clr.val = dev->bus->int_st.val;
if (hpTaskAwoken == pdTRUE) {
portYIELD_FROM_ISR();
}
}
size_t i2sWrite(uint8_t bus_num, uint8_t* data, size_t len, bool copy, bool free_when_sent) {
if (bus_num >= I2S_NUM_MAX || !I2S[bus_num].tx_queue) {
return 0;
}
size_t index = 0;
size_t toSend = len;
size_t limit = I2S_DMA_MAX_DATA_LEN;
i2s_dma_item_t* item = NULL;
while (len) {
toSend = len;
if (toSend > limit) {
toSend = limit;
}
if (xQueueReceive(I2S[bus_num].tx_queue, &item, portMAX_DELAY) == pdFALSE) {
log_e("xQueueReceive failed\n");
break;
}
// data is constant. no need to copy
item->data = data + index;
item->blocksize = toSend;
item->datalen = toSend;
len -= toSend;
index += toSend;
}
return index;
}
#endif

View File

@@ -0,0 +1,38 @@
#pragma once
#if defined(ARDUINO_ARCH_ESP32)
#ifdef __cplusplus
extern "C" {
#endif
#include "esp_err.h"
#define I2S_DMA_MAX_DATA_LEN 4092// maximum bytes in one dma item
typedef enum {
I2S_CHAN_STEREO, I2S_CHAN_RIGHT_TO_LEFT, I2S_CHAN_LEFT_TO_RIGHT, I2S_CHAN_RIGHT_ONLY, I2S_CHAN_LEFT_ONLY
} i2s_tx_chan_mod_t;
typedef enum {
I2S_FIFO_16BIT_DUAL, I2S_FIFO_16BIT_SINGLE, I2S_FIFO_32BIT_DUAL, I2S_FIFO_32BIT_SINGLE
} i2s_tx_fifo_mod_t;
void i2sInit(uint8_t bus_num, uint32_t bits_per_sample, uint32_t sample_rate, i2s_tx_chan_mod_t chan_mod, i2s_tx_fifo_mod_t fifo_mod, size_t dma_count, size_t dma_len);
void i2sSetPins(uint8_t bus_num, int8_t out, bool invert);
void i2sSetDac(uint8_t bus_num, bool right, bool left);
esp_err_t i2sSetClock(uint8_t bus_num, uint8_t div_num, uint8_t div_b, uint8_t div_a, uint8_t bck, uint8_t bits_per_sample);
esp_err_t i2sSetSampleRate(uint8_t bus_num, uint32_t sample_rate, uint8_t bits_per_sample);
void i2sSetSilenceBuf(uint8_t bus_num, uint8_t* data, size_t len);
size_t i2sWrite(uint8_t bus_num, uint8_t* data, size_t len, bool copy, bool free_when_sent);
bool i2sWriteDone(uint8_t bus_num);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,68 @@
/*-------------------------------------------------------------------------
HsbColor 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 "RgbColor.h"
#include "HsbColor.h"
HsbColor::HsbColor(const RgbColor& color)
{
// convert colors to float between (0.0 - 1.0)
float r = color.R / 255.0f;
float g = color.G / 255.0f;
float b = color.B / 255.0f;
float max = (r > g && r > b) ? r : (g > b) ? g : b;
float min = (r < g && r < b) ? r : (g < b) ? g : b;
float d = max - min;
float h = 0.0;
float v = max;
float s = (v == 0.0f) ? 0 : (d / v);
if (d != 0.0f)
{
if (r == max)
{
h = (g - b) / d + (g < b ? 6.0f : 0.0f);
}
else if (g == max)
{
h = (b - r) / d + 2.0f;
}
else
{
h = (r - g) / d + 4.0f;
}
h /= 6.0f;
}
H = h;
S = s;
B = v;
}

View File

@@ -0,0 +1,113 @@
/*-------------------------------------------------------------------------
HsbColor 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>
// ------------------------------------------------------------------------
// HsbColor represents a color object that is represented by Hue, Saturation, Brightness
// component values. It contains helpful color routines to manipulate the
// color.
// ------------------------------------------------------------------------
struct HsbColor
{
// ------------------------------------------------------------------------
// Construct a HsbColor using H, S, B values (0.0 - 1.0)
// ------------------------------------------------------------------------
HsbColor(float h, float s, float b) :
H(h), S(s), B(b)
{
};
// ------------------------------------------------------------------------
// Construct a HsbColor using RgbColor
// ------------------------------------------------------------------------
HsbColor(const RgbColor& color);
// ------------------------------------------------------------------------
// Construct a HsbColor that will have its values set in latter operations
// CAUTION: The H,S,B members are not initialized and may not be consistent
// ------------------------------------------------------------------------
HsbColor()
{
};
// ------------------------------------------------------------------------
// LinearBlend between two colors by the amount defined by progress variable
// left - the color to start the blend at
// right - the color to end the blend at
// progress - (0.0 - 1.0) value where 0.0 will return left and 1.0 will return right
// and a value between will blend the color weighted linearly between them
// ------------------------------------------------------------------------
template <typename T_NEOHUEBLEND> static HsbColor LinearBlend(const HsbColor& left,
const HsbColor& right,
float progress)
{
return HsbColor(T_NEOHUEBLEND::HueBlend(left.H, right.H, progress),
left.S + ((right.S - left.S) * progress),
left.B + ((right.B - left.B) * progress));
}
// ------------------------------------------------------------------------
// BilinearBlend between four colors by the amount defined by 2d variable
// c00 - upper left quadrant color
// c01 - upper right quadrant color
// c10 - lower left quadrant color
// c11 - lower right quadrant color
// x - unit value (0.0 - 1.0) that defines the blend progress in horizontal space
// y - unit value (0.0 - 1.0) that defines the blend progress in vertical space
// ------------------------------------------------------------------------
template <typename T_NEOHUEBLEND> static HsbColor BilinearBlend(const HsbColor& c00,
const HsbColor& c01,
const HsbColor& c10,
const HsbColor& c11,
float x,
float y)
{
float v00 = (1.0f - x) * (1.0f - y);
float v10 = x * (1.0f - y);
float v01 = (1.0f - x) * y;
float v11 = x * y;
return HsbColor(
T_NEOHUEBLEND::HueBlend(
T_NEOHUEBLEND::HueBlend(c00.H, c10.H, x),
T_NEOHUEBLEND::HueBlend(c01.H, c11.H, x),
y),
c00.S * v00 + c10.S * v10 + c01.S * v01 + c11.S * v11,
c00.B * v00 + c10.B * v10 + c01.B * v01 + c11.B * v11);
};
// ------------------------------------------------------------------------
// Hue, Saturation, Brightness color members
// ------------------------------------------------------------------------
float H;
float S;
float B;
};

View File

@@ -0,0 +1,72 @@
/*-------------------------------------------------------------------------
HslColor 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 "RgbColor.h"
#include "HslColor.h"
HslColor::HslColor(const RgbColor& color)
{
// convert colors to float between (0.0 - 1.0)
float r = color.R / 255.0f;
float g = color.G / 255.0f;
float b = color.B / 255.0f;
float max = (r > g && r > b) ? r : (g > b) ? g : b;
float min = (r < g && r < b) ? r : (g < b) ? g : b;
float h, s, l;
l = (max + min) / 2.0f;
if (max == min)
{
h = s = 0.0f;
}
else
{
float d = max - min;
s = (l > 0.5f) ? d / (2.0f - (max + min)) : d / (max + min);
if (r > g && r > b)
{
h = (g - b) / d + (g < b ? 6.0f : 0.0f);
}
else if (g > b)
{
h = (b - r) / d + 2.0f;
}
else
{
h = (r - g) / d + 4.0f;
}
h /= 6.0f;
}
H = h;
S = s;
L = l;
}

View File

@@ -0,0 +1,113 @@
/*-------------------------------------------------------------------------
HslColor 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>
// ------------------------------------------------------------------------
// HslColor represents a color object that is represented by Hue, Saturation, Lightness
// component values. It contains helpful color routines to manipulate the
// color.
// ------------------------------------------------------------------------
struct HslColor
{
// ------------------------------------------------------------------------
// Construct a HslColor using H, S, L values (0.0 - 1.0)
// L should be limited to between (0.0 - 0.5)
// ------------------------------------------------------------------------
HslColor(float h, float s, float l) :
H(h), S(s), L(l)
{
};
// ------------------------------------------------------------------------
// Construct a HslColor using RgbColor
// ------------------------------------------------------------------------
HslColor(const RgbColor& color);
// ------------------------------------------------------------------------
// Construct a HslColor that will have its values set in latter operations
// CAUTION: The H,S,L members are not initialized and may not be consistent
// ------------------------------------------------------------------------
HslColor()
{
};
// ------------------------------------------------------------------------
// LinearBlend between two colors by the amount defined by progress variable
// left - the color to start the blend at
// right - the color to end the blend at
// progress - (0.0 - 1.0) value where 0.0 will return left and 1.0 will return right
// and a value between will blend the color weighted linearly between them
// ------------------------------------------------------------------------
template <typename T_NEOHUEBLEND> static HslColor LinearBlend(const HslColor& left,
const HslColor& right,
float progress)
{
return HslColor(T_NEOHUEBLEND::HueBlend(left.H, right.H, progress),
left.S + ((right.S - left.S) * progress),
left.L + ((right.L - left.L) * progress));
};
// ------------------------------------------------------------------------
// BilinearBlend between four colors by the amount defined by 2d variable
// c00 - upper left quadrant color
// c01 - upper right quadrant color
// c10 - lower left quadrant color
// c11 - lower right quadrant color
// x - unit value (0.0 - 1.0) that defines the blend progress in horizontal space
// y - unit value (0.0 - 1.0) that defines the blend progress in vertical space
// ------------------------------------------------------------------------
template <typename T_NEOHUEBLEND> static HslColor BilinearBlend(const HslColor& c00,
const HslColor& c01,
const HslColor& c10,
const HslColor& c11,
float x,
float y)
{
float v00 = (1.0f - x) * (1.0f - y);
float v10 = x * (1.0f - y);
float v01 = (1.0f - x) * y;
float v11 = x * y;
return HslColor(
T_NEOHUEBLEND::HueBlend(
T_NEOHUEBLEND::HueBlend(c00.H, c10.H, x),
T_NEOHUEBLEND::HueBlend(c01.H, c11.H, x),
y),
c00.S * v00 + c10.S * v10 + c01.S * v01 + c11.S * v11,
c00.L * v00 + c10.L * v10 + c01.L * v01 + c11.L * v11);
};
// ------------------------------------------------------------------------
// Hue, Saturation, Lightness color members
// ------------------------------------------------------------------------
float H;
float S;
float L;
};

View File

@@ -0,0 +1,58 @@
/*-------------------------------------------------------------------------
This file contains the HtmlColor implementation
Written by Unai Uribarri
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 "HtmlColor.h"
static inline char hexdigit(uint8_t v)
{
return v + (v < 10 ? '0' : 'a' - 10);
}
size_t HtmlColor::ToNumericalString(char* buf, size_t bufSize) const
{
size_t bufLen = bufSize - 1;
if (bufLen-- > 0)
{
if (bufLen > 0)
{
buf[0] = '#';
}
uint32_t color = Color;
for (uint8_t indexDigit = 6; indexDigit > 0; indexDigit--)
{
if (bufLen > indexDigit)
{
buf[indexDigit] = hexdigit(color & 0x0000000f);
}
color >>= 4;
}
buf[(bufLen < 7 ? bufLen : 7)] = 0;
}
return 7;
}

View File

@@ -0,0 +1,340 @@
/*-------------------------------------------------------------------------
HtmlColor 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>
#include "RgbColor.h"
#define MAX_HTML_COLOR_NAME_LEN 21
#ifndef pgm_read_ptr
// ESP8266 doesn't define this macro
#define pgm_read_ptr(addr) (*reinterpret_cast<const void* const *>(addr))
#endif
#ifndef countof
#define countof(array) (sizeof(array)/sizeof(array[0]))
#endif
// ------------------------------------------------------------------------
// HtmlColorPair represents an association between a name and a HTML color code
// ------------------------------------------------------------------------
struct HtmlColorPair
{
PGM_P Name;
uint32_t Color;
};
// ------------------------------------------------------------------------
// HtmlShortColorNames is a template class used for Parse and ToString
// ------------------------------------------------------------------------
class HtmlShortColorNames
{
public:
static const HtmlColorPair* Pair(uint8_t index);
static uint8_t Count();
};
// ------------------------------------------------------------------------
// HtmlColorNames is a template class used for Parse and ToString
// ------------------------------------------------------------------------
class HtmlColorNames
{
public:
static const HtmlColorPair* Pair(uint8_t index);
static uint8_t Count();
};
// ------------------------------------------------------------------------
// HtmlColor represents a color object that is represented by a single uint32
// value. It contains minimal routines and used primarily as a helper to
// initialize other color objects
// ------------------------------------------------------------------------
struct HtmlColor
{
// ------------------------------------------------------------------------
// Construct a HtmlColor using a single value (0-0xffffff)
// This works well for hexidecimal color definitions
// 0xff0000 = red, 0x00ff00 = green, and 0x0000ff = blue
// ------------------------------------------------------------------------
HtmlColor(uint32_t color) :
Color(color)
{
};
// ------------------------------------------------------------------------
// Construct a HtmlColor using RgbColor
// ------------------------------------------------------------------------
HtmlColor(const RgbColor& color)
{
Color = (uint32_t)color.R << 16 | (uint32_t)color.G << 8 | (uint32_t)color.B;
}
// ------------------------------------------------------------------------
// Construct a HtmlColor that will have its values set in latter operations
// CAUTION: The Color member is not initialized and may not be consistent
// ------------------------------------------------------------------------
HtmlColor()
{
};
// ------------------------------------------------------------------------
// Comparison operators
// ------------------------------------------------------------------------
bool operator==(const HtmlColor& other) const
{
return (Color == other.Color);
};
bool operator!=(const HtmlColor& other) const
{
return !(*this == other);
};
// ------------------------------------------------------------------------
// Parse a HTML4/CSS3 color name
// T_HTMLCOLORNAMES - template class that defines the collection of names
// name - the color name
// nameSize - the max size of name to check
//
// returns - zero if failed, or the number of chars parsed
//
// It will stop parsing name when a null terminator is reached,
// nameSize is reached, no match is found in the name/color pair table, or
// a non-alphanumeric is read like seperators or whitespace.
//
// It also accepts 3 or 6 digit hexadecimal notation (#rgb or #rrggbb),
// but it doesn't accept RGB, RGBA nor HSL values.
//
// See https://www.w3.org/TR/css3-color/#SRGB
//
// name must point to the first non-whitespace character to be parsed
// parsing will stop at the first non-alpha numeric
//
// Name MUST NOT be a PROGMEM pointer
//
// examples:
// Parse<HtmlShortColorNames>(buff, buffSize);
// Parse<HtmlColorNames>(buff, buffSize);
// ------------------------------------------------------------------------
template <typename T_HTMLCOLORNAMES> size_t Parse(const char* name, size_t nameSize)
{
if (nameSize > 0)
{
if (name[0] == '#')
{
// Parse an hexadecimal notation "#rrbbgg" or "#rgb"
//
uint8_t temp[6]; // stores preconverted chars to hex values
uint8_t tempSize = 0;
for (uint8_t indexChar = 1; indexChar < nameSize && indexChar < 8; ++indexChar)
{
char c = name[indexChar];
if (c >= '0' && c <= '9')
{
c -= '0';
}
else
{
// Convert a letter to lower case (only for ASCII letters)
// It's faster & smaller than tolower()
c |= 32;
if (c >= 'a' && c <= 'f')
{
c = c - 'a' + 10;
}
else
{
// we found an non hexidecimal char
// which could be null, deliminator, or other spacing
break;
}
}
temp[tempSize] = c;
tempSize++;
}
if (tempSize != 3 && tempSize != 6)
{
// invalid count of numerical chars
return 0;
}
else
{
uint32_t color = 0;
for (uint8_t indexChar = 0; indexChar < tempSize; ++indexChar)
{
color = color * 16 + temp[indexChar];
if (tempSize == 3)
{
// 3 digit hexadecimal notation can be supported easily
// duplicating digits.
color = color * 16 + temp[indexChar];
}
}
Color = color;
return tempSize;
}
}
else
{
// parse a standard name for the color
//
// the normal list is small enough a binary search isn't interesting,
for (uint8_t indexName = 0; indexName < T_HTMLCOLORNAMES::Count(); ++indexName)
{
const HtmlColorPair* colorPair = T_HTMLCOLORNAMES::Pair(indexName);
PGM_P searchName = reinterpret_cast<PGM_P>(pgm_read_ptr(&(colorPair->Name)));
size_t str1Size = nameSize;
const char* str1 = name;
const char* str2P = searchName;
uint16_t result;
while (str1Size > 0)
{
char ch1 = tolower(*str1++);
char ch2 = tolower(pgm_read_byte(str2P++));
result = ch1 - ch2;
if (result != 0 || ch2 == '\0')
{
if (ch2 == '\0' && !isalnum(ch1))
{
// the string continues but is not part of a
// valid color name,
// ends in white space, deliminator, etc
result = 0;
}
break;
}
result = -1; // have not reached the end of searchName;
str1Size--;
}
if (result == 0)
{
Color = pgm_read_dword(&colorPair->Color);
return nameSize - str1Size;
}
}
}
}
return 0;
}
template <typename T_HTMLCOLORNAMES> size_t Parse(const char* name)
{
return Parse<T_HTMLCOLORNAMES>(name, MAX_HTML_COLOR_NAME_LEN + 1);
}
template <typename T_HTMLCOLORNAMES> size_t Parse(String const &name)
{
return Parse<T_HTMLCOLORNAMES>(name.c_str(), name.length() + 1);
}
// ------------------------------------------------------------------------
// Converts this color code to its HTML4/CSS3 name
// T_HTMLCOLORNAMES - template class that defines the collection of names
// buf - buffer to write the string
// bufSize - actual size of buf array
//
// It returns the number of chars required not including the NUL terminator.
//
// If there is not enough space in the buffer, it will write as many
// characters as allowed and will always finish the buffer with a NUL char
//
// examples:
// ToString<HtmlShortColorNames>(buf, bufSize);
// ToString<htmlColorNames>(buf, bufSize);
// ------------------------------------------------------------------------
template <typename T_HTMLCOLORNAMES> size_t ToString(char* buf, size_t bufSize) const
{
// search for a color value/name pairs first
for (uint8_t indexName = 0; indexName < T_HTMLCOLORNAMES::Count(); ++indexName)
{
const HtmlColorPair* colorPair = T_HTMLCOLORNAMES::Pair(indexName);
if (pgm_read_dword(&colorPair->Color) == Color)
{
PGM_P name = (PGM_P)pgm_read_ptr(&colorPair->Name);
strncpy_P(buf, name, bufSize);
return strlen_P(name);
}
}
// no color name pair match, convert using numerical format
return ToNumericalString(buf, bufSize);
}
// ------------------------------------------------------------------------
// Converts this color code to its HTML4/CSS3 numerical name
//
// buf - buffer to write the string
// bufSize - actual size of buf array
//
// It returns the number of chars required not including the NUL terminator.
//
// If there is not enough space in the buffer, it will write as many
// characters as allowed and will always finish the buffer with a NUL char
// ------------------------------------------------------------------------
size_t ToNumericalString(char* buf, size_t bufSize) const;
// ------------------------------------------------------------------------
// BilinearBlend between four colors by the amount defined by 2d variable
// c00 - upper left quadrant color
// c01 - upper right quadrant color
// c10 - lower left quadrant color
// c11 - lower right quadrant color
// x - unit value (0.0 - 1.0) that defines the blend progress in horizontal space
// y - unit value (0.0 - 1.0) that defines the blend progress in vertical space
// ------------------------------------------------------------------------
static HtmlColor BilinearBlend(const HtmlColor& c00,
const HtmlColor& c01,
const HtmlColor& c10,
const HtmlColor& c11,
float x,
float y)
{
return RgbColor::BilinearBlend(c00, c01, c10, c11, x, y);
}
// ------------------------------------------------------------------------
// Color member (0-0xffffff) where
// 0xff0000 is red
// 0x00ff00 is green
// 0x0000ff is blue
// ------------------------------------------------------------------------
uint32_t Color;
};

View File

@@ -0,0 +1,178 @@
/*-------------------------------------------------------------------------
HtmlColorNameStrings provides the implemenation of the color string names
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 "HtmlColorNameStrings.h"
/* HTML4 color names */
const char c_HtmlNameAqua[] PROGMEM = "aqua";
const char c_HtmlNameBlack[] PROGMEM = "black";
const char c_HtmlNameBlue[] PROGMEM = "blue";
const char c_HtmlNameFuchsia[] PROGMEM = "fuchsia";
const char c_HtmlNameGray[] PROGMEM = "gray";
const char c_HtmlNameGreen[] PROGMEM = "green";
const char c_HtmlNameLime[] PROGMEM = "lime";
const char c_HtmlNameMaroon[] PROGMEM = "maroon";
const char c_HtmlNameNavy[] PROGMEM = "navy";
const char c_HtmlNameOlive[] PROGMEM = "olive";
const char c_HtmlNameOrange[] PROGMEM = "orange";
const char c_HtmlNamePurple[] PROGMEM = "purple";
const char c_HtmlNameRed[] PROGMEM = "red";
const char c_HtmlNameSilver[] PROGMEM = "silver";
const char c_HtmlNameTeal[] PROGMEM = "teal";
const char c_HtmlNameWhite[] PROGMEM = "white";
const char c_HtmlNameYellow[] PROGMEM = "yellow";
/* Additional CSS3 color names */
const char c_HtmlNameAliceBlue[] PROGMEM = "aliceblue";
const char c_HtmlNameAntiqueWhite[] PROGMEM = "antiquewhite";
const char c_HtmlNameAquamarine[] PROGMEM = "aquamarine";
const char c_HtmlNameAzure[] PROGMEM = "azure";
const char c_HtmlNameBeige[] PROGMEM = "beige";
const char c_HtmlNameBisque[] PROGMEM = "bisque";
const char c_HtmlNameBlanchedAlmond[] PROGMEM = "blanchedalmond";
const char c_HtmlNameBlueViolet[] PROGMEM = "blueviolet";
const char c_HtmlNameBrown[] PROGMEM = "brown";
const char c_HtmlNameBurlyWood[] PROGMEM = "burlywood";
const char c_HtmlNameCadetBlue[] PROGMEM = "cadetblue";
const char c_HtmlNameChartreuse[] PROGMEM = "chartreuse";
const char c_HtmlNameChocolate[] PROGMEM = "chocolate";
const char c_HtmlNameCoral[] PROGMEM = "coral";
const char c_HtmlNameCornflowerBlue[] PROGMEM = "cornflowerblue";
const char c_HtmlNameCornsilk[] PROGMEM = "cornsilk";
const char c_HtmlNameCrimson[] PROGMEM = "crimson";
const char c_HtmlNameCyan[] PROGMEM = "cyan";
const char c_HtmlNameDarkBlue[] PROGMEM = "darkblue";
const char c_HtmlNameDarkCyan[] PROGMEM = "darkcyan";
const char c_HtmlNameDarkGoldenrod[] PROGMEM = "darkgoldenrod";
const char c_HtmlNameDarkGray[] PROGMEM = "darkgray";
const char c_HtmlNameDarkGreen[] PROGMEM = "darkgreen";
const char c_HtmlNameDarkGrey[] PROGMEM = "darkgrey";
const char c_HtmlNameDarkKhaki[] PROGMEM = "darkkhaki";
const char c_HtmlNameDarkMagenta[] PROGMEM = "darkmagenta";
const char c_HtmlNameDarkOliveGreen[] PROGMEM = "darkolivegreen";
const char c_HtmlNameDarkOrange[] PROGMEM = "darkorange";
const char c_HtmlNameDarkOrchid[] PROGMEM = "darkorchid";
const char c_HtmlNameDarkRed[] PROGMEM = "darkred";
const char c_HtmlNameDarkSalmon[] PROGMEM = "darksalmon";
const char c_HtmlNameDarkSeaGreen[] PROGMEM = "darkseagreen";
const char c_HtmlNameDarkSlateBlue[] PROGMEM = "darkslateblue";
const char c_HtmlNameDarkSlateGray[] PROGMEM = "darkslategray";
const char c_HtmlNameDarkSlateGrey[] PROGMEM = "darkslategrey";
const char c_HtmlNameDarkTurquoise[] PROGMEM = "darkturquoise";
const char c_HtmlNameDarkViolet[] PROGMEM = "darkviolet";
const char c_HtmlNameDeepPink[] PROGMEM = "deeppink";
const char c_HtmlNameDeepSkyBlue[] PROGMEM = "deepskyblue";
const char c_HtmlNameDimGray[] PROGMEM = "dimgray";
const char c_HtmlNameDimGrey[] PROGMEM = "dimgrey";
const char c_HtmlNameDodgerBlue[] PROGMEM = "dodgerblue";
const char c_HtmlNameFirebrick[] PROGMEM = "firebrick";
const char c_HtmlNameFloralWhite[] PROGMEM = "floralwhite";
const char c_HtmlNameForestGreen[] PROGMEM = "forestgreen";
const char c_HtmlNameGainsboro[] PROGMEM = "gainsboro";
const char c_HtmlNameGhostWhite[] PROGMEM = "ghostwhite";
const char c_HtmlNameGold[] PROGMEM = "gold";
const char c_HtmlNameGoldenrod[] PROGMEM = "goldenrod";
const char c_HtmlNameGreenYellow[] PROGMEM = "greenyellow";
const char c_HtmlNameGrey[] PROGMEM = "grey";
const char c_HtmlNameHoneydew[] PROGMEM = "honeydew";
const char c_HtmlNameHotPink[] PROGMEM = "hotpink";
const char c_HtmlNameIndianRed[] PROGMEM = "indianred";
const char c_HtmlNameIndigo[] PROGMEM = "indigo";
const char c_HtmlNameIvory[] PROGMEM = "ivory";
const char c_HtmlNameKhaki[] PROGMEM = "khaki";
const char c_HtmlNameLavender[] PROGMEM = "lavender";
const char c_HtmlNameLavenderBlush[] PROGMEM = "lavenderblush";
const char c_HtmlNameLawnGreen[] PROGMEM = "lawngreen";
const char c_HtmlNameLemonChiffon[] PROGMEM = "lemonchiffon";
const char c_HtmlNameLightBlue[] PROGMEM = "lightblue";
const char c_HtmlNameLightCoral[] PROGMEM = "lightcoral";
const char c_HtmlNameLightCyan[] PROGMEM = "lightcyan";
const char c_HtmlNameLightGoldenrodYellow[] PROGMEM = "lightgoldenrodyellow";
const char c_HtmlNameLightGray[] PROGMEM = "lightgray";
const char c_HtmlNameLightGreen[] PROGMEM = "lightgreen";
const char c_HtmlNameLightGrey[] PROGMEM = "lightgrey";
const char c_HtmlNameLightPink[] PROGMEM = "lightpink";
const char c_HtmlNameLightSalmon[] PROGMEM = "lightsalmon";
const char c_HtmlNameLightSeaGreen[] PROGMEM = "lightseagreen";
const char c_HtmlNameLightSkyBlue[] PROGMEM = "lightskyblue";
const char c_HtmlNameLightSlateGray[] PROGMEM = "lightslategray";
const char c_HtmlNameLightSlateGrey[] PROGMEM = "lightslategrey";
const char c_HtmlNameLightSteelBlue[] PROGMEM = "lightsteelblue";
const char c_HtmlNameLightYellow[] PROGMEM = "lightyellow";
const char c_HtmlNameLimeGreen[] PROGMEM = "limegreen";
const char c_HtmlNameLinen[] PROGMEM = "linen";
const char c_HtmlNameMagenta[] PROGMEM = "magenta";
const char c_HtmlNameMediumAquamarine[] PROGMEM = "mediumaquamarine";
const char c_HtmlNameMediumBlue[] PROGMEM = "mediumblue";
const char c_HtmlNameMediumOrchid[] PROGMEM = "mediumorchid";
const char c_HtmlNameMediumPurple[] PROGMEM = "mediumpurple";
const char c_HtmlNameMediumSeagreen[] PROGMEM = "mediumseagreen";
const char c_HtmlNameMediumSlateBlue[] PROGMEM = "mediumslateblue";
const char c_HtmlNameMediumSpringGreen[] PROGMEM = "mediumspringgreen";
const char c_HtmlNameMediumTurquoise[] PROGMEM = "mediumturquoise";
const char c_HtmlNameMediumVioletRed[] PROGMEM = "mediumvioletred";
const char c_HtmlNameMidnightBlue[] PROGMEM = "midnightblue";
const char c_HtmlNameMintCream[] PROGMEM = "mintcream";
const char c_HtmlNameMistyRose[] PROGMEM = "mistyrose";
const char c_HtmlNameMoccasin[] PROGMEM = "moccasin";
const char c_HtmlNameNavajoWhite[] PROGMEM = "navajowhite";
const char c_HtmlNameOldLace[] PROGMEM = "oldlace";
const char c_HtmlNameOliveDrab[] PROGMEM = "olivedrab";
const char c_HtmlNameOrangeRed[] PROGMEM = "orangered";
const char c_HtmlNameOrchid[] PROGMEM = "orchid";
const char c_HtmlNamePaleGoldenrod[] PROGMEM = "palegoldenrod";
const char c_HtmlNamePaleGreen[] PROGMEM = "palegreen";
const char c_HtmlNamePaleTurquoise[] PROGMEM = "paleturquoise";
const char c_HtmlNamePaleVioletRed[] PROGMEM = "palevioletred";
const char c_HtmlNamePapayaWhip[] PROGMEM = "papayawhip";
const char c_HtmlNamePeachPuff[] PROGMEM = "peachpuff";
const char c_HtmlNamePeru[] PROGMEM = "peru";
const char c_HtmlNamePink[] PROGMEM = "pink";
const char c_HtmlNamePlum[] PROGMEM = "plum";
const char c_HtmlNamePowderBlue[] PROGMEM = "powderblue";
const char c_HtmlNameRosyBrown[] PROGMEM = "rosybrown";
const char c_HtmlNameRoyalBlue[] PROGMEM = "royalblue";
const char c_HtmlNameSaddleBrown[] PROGMEM = "saddlebrown";
const char c_HtmlNameSalmon[] PROGMEM = "salmon";
const char c_HtmlNameSandyBrown[] PROGMEM = "sandybrown";
const char c_HtmlNameSeaGreen[] PROGMEM = "seagreen";
const char c_HtmlNameSeaShell[] PROGMEM = "seashell";
const char c_HtmlNameSienna[] PROGMEM = "sienna";
const char c_HtmlNameSkyBlue[] PROGMEM = "skyblue";
const char c_HtmlNameSlateBlue[] PROGMEM = "slateblue";
const char c_HtmlNameSlateGray[] PROGMEM = "slategray";
const char c_HtmlNameSlateGrey[] PROGMEM = "slategrey";
const char c_HtmlNameSnow[] PROGMEM = "snow";
const char c_HtmlNameSpringGreen[] PROGMEM = "springgreen";
const char c_HtmlNameSteelBlue[] PROGMEM = "steelblue";
const char c_HtmlNameTan[] PROGMEM = "tan";
const char c_HtmlNameThistle[] PROGMEM = "thistle";
const char c_HtmlNameTomato[] PROGMEM = "tomato";
const char c_HtmlNameTurquoise[] PROGMEM = "turquoise";
const char c_HtmlNameViolet[] PROGMEM = "violet";
const char c_HtmlNameWheat[] PROGMEM = "wheat";
const char c_HtmlNameWhiteSmoke[] PROGMEM = "whitesmoke";
const char c_HtmlNameYellowGreen[] PROGMEM = "yellowgreen";

View File

@@ -0,0 +1,180 @@
/*-------------------------------------------------------------------------
HtmlColorNameStrings provides the declaration of the color string names
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>
/* HTML4 color names */
extern const char c_HtmlNameAqua[] PROGMEM;
extern const char c_HtmlNameBlack[] PROGMEM;
extern const char c_HtmlNameBlue[] PROGMEM;
extern const char c_HtmlNameFuchsia[] PROGMEM;
extern const char c_HtmlNameGray[] PROGMEM;
extern const char c_HtmlNameGreen[] PROGMEM;
extern const char c_HtmlNameLime[] PROGMEM;
extern const char c_HtmlNameMaroon[] PROGMEM;
extern const char c_HtmlNameNavy[] PROGMEM;
extern const char c_HtmlNameOlive[] PROGMEM;
extern const char c_HtmlNameOrange[] PROGMEM;
extern const char c_HtmlNamePurple[] PROGMEM;
extern const char c_HtmlNameRed[] PROGMEM;
extern const char c_HtmlNameSilver[] PROGMEM;
extern const char c_HtmlNameTeal[] PROGMEM;
extern const char c_HtmlNameWhite[] PROGMEM;
extern const char c_HtmlNameYellow[] PROGMEM;
/* Additional CSS3 color names */
extern const char c_HtmlNameAliceBlue[] PROGMEM;
extern const char c_HtmlNameAntiqueWhite[] PROGMEM;
extern const char c_HtmlNameAquamarine[] PROGMEM;
extern const char c_HtmlNameAzure[] PROGMEM;
extern const char c_HtmlNameBeige[] PROGMEM;
extern const char c_HtmlNameBisque[] PROGMEM;
extern const char c_HtmlNameBlanchedAlmond[] PROGMEM;
extern const char c_HtmlNameBlueViolet[] PROGMEM;
extern const char c_HtmlNameBrown[] PROGMEM;
extern const char c_HtmlNameBurlyWood[] PROGMEM;
extern const char c_HtmlNameCadetBlue[] PROGMEM;
extern const char c_HtmlNameChartreuse[] PROGMEM;
extern const char c_HtmlNameChocolate[] PROGMEM;
extern const char c_HtmlNameCoral[] PROGMEM;
extern const char c_HtmlNameCornflowerBlue[] PROGMEM;
extern const char c_HtmlNameCornsilk[] PROGMEM;
extern const char c_HtmlNameCrimson[] PROGMEM;
extern const char c_HtmlNameCyan[] PROGMEM;
extern const char c_HtmlNameDarkBlue[] PROGMEM;
extern const char c_HtmlNameDarkCyan[] PROGMEM;
extern const char c_HtmlNameDarkGoldenrod[] PROGMEM;
extern const char c_HtmlNameDarkGray[] PROGMEM;
extern const char c_HtmlNameDarkGreen[] PROGMEM;
extern const char c_HtmlNameDarkGrey[] PROGMEM;
extern const char c_HtmlNameDarkKhaki[] PROGMEM;
extern const char c_HtmlNameDarkMagenta[] PROGMEM;
extern const char c_HtmlNameDarkOliveGreen[] PROGMEM;
extern const char c_HtmlNameDarkOrange[] PROGMEM;
extern const char c_HtmlNameDarkOrchid[] PROGMEM;
extern const char c_HtmlNameDarkRed[] PROGMEM;
extern const char c_HtmlNameDarkSalmon[] PROGMEM;
extern const char c_HtmlNameDarkSeaGreen[] PROGMEM;
extern const char c_HtmlNameDarkSlateBlue[] PROGMEM;
extern const char c_HtmlNameDarkSlateGray[] PROGMEM;
extern const char c_HtmlNameDarkSlateGrey[] PROGMEM;
extern const char c_HtmlNameDarkTurquoise[] PROGMEM;
extern const char c_HtmlNameDarkViolet[] PROGMEM;
extern const char c_HtmlNameDeepPink[] PROGMEM;
extern const char c_HtmlNameDeepSkyBlue[] PROGMEM;
extern const char c_HtmlNameDimGray[] PROGMEM;
extern const char c_HtmlNameDimGrey[] PROGMEM;
extern const char c_HtmlNameDodgerBlue[] PROGMEM;
extern const char c_HtmlNameFirebrick[] PROGMEM;
extern const char c_HtmlNameFloralWhite[] PROGMEM;
extern const char c_HtmlNameForestGreen[] PROGMEM;
extern const char c_HtmlNameGainsboro[] PROGMEM;
extern const char c_HtmlNameGhostWhite[] PROGMEM;
extern const char c_HtmlNameGold[] PROGMEM;
extern const char c_HtmlNameGoldenrod[] PROGMEM;
extern const char c_HtmlNameGreenYellow[] PROGMEM;
extern const char c_HtmlNameGrey[] PROGMEM;
extern const char c_HtmlNameHoneydew[] PROGMEM;
extern const char c_HtmlNameHotPink[] PROGMEM;
extern const char c_HtmlNameIndianRed[] PROGMEM;
extern const char c_HtmlNameIndigo[] PROGMEM;
extern const char c_HtmlNameIvory[] PROGMEM;
extern const char c_HtmlNameKhaki[] PROGMEM;
extern const char c_HtmlNameLavender[] PROGMEM;
extern const char c_HtmlNameLavenderBlush[] PROGMEM;
extern const char c_HtmlNameLawnGreen[] PROGMEM;
extern const char c_HtmlNameLemonChiffon[] PROGMEM;
extern const char c_HtmlNameLightBlue[] PROGMEM;
extern const char c_HtmlNameLightCoral[] PROGMEM;
extern const char c_HtmlNameLightCyan[] PROGMEM;
extern const char c_HtmlNameLightGoldenrodYellow[] PROGMEM;
extern const char c_HtmlNameLightGray[] PROGMEM;
extern const char c_HtmlNameLightGreen[] PROGMEM;
extern const char c_HtmlNameLightGrey[] PROGMEM;
extern const char c_HtmlNameLightPink[] PROGMEM;
extern const char c_HtmlNameLightSalmon[] PROGMEM;
extern const char c_HtmlNameLightSeaGreen[] PROGMEM;
extern const char c_HtmlNameLightSkyBlue[] PROGMEM;
extern const char c_HtmlNameLightSlateGray[] PROGMEM;
extern const char c_HtmlNameLightSlateGrey[] PROGMEM;
extern const char c_HtmlNameLightSteelBlue[] PROGMEM;
extern const char c_HtmlNameLightYellow[] PROGMEM;
extern const char c_HtmlNameLimeGreen[] PROGMEM;
extern const char c_HtmlNameLinen[] PROGMEM;
extern const char c_HtmlNameMagenta[] PROGMEM;
extern const char c_HtmlNameMediumAquamarine[] PROGMEM;
extern const char c_HtmlNameMediumBlue[] PROGMEM;
extern const char c_HtmlNameMediumOrchid[] PROGMEM;
extern const char c_HtmlNameMediumPurple[] PROGMEM;
extern const char c_HtmlNameMediumSeagreen[] PROGMEM;
extern const char c_HtmlNameMediumSlateBlue[] PROGMEM;
extern const char c_HtmlNameMediumSpringGreen[] PROGMEM;
extern const char c_HtmlNameMediumTurquoise[] PROGMEM;
extern const char c_HtmlNameMediumVioletRed[] PROGMEM;
extern const char c_HtmlNameMidnightBlue[] PROGMEM;
extern const char c_HtmlNameMintCream[] PROGMEM;
extern const char c_HtmlNameMistyRose[] PROGMEM;
extern const char c_HtmlNameMoccasin[] PROGMEM;
extern const char c_HtmlNameNavajoWhite[] PROGMEM;
extern const char c_HtmlNameOldLace[] PROGMEM;
extern const char c_HtmlNameOliveDrab[] PROGMEM;
extern const char c_HtmlNameOrangeRed[] PROGMEM;
extern const char c_HtmlNameOrchid[] PROGMEM;
extern const char c_HtmlNamePaleGoldenrod[] PROGMEM;
extern const char c_HtmlNamePaleGreen[] PROGMEM;
extern const char c_HtmlNamePaleTurquoise[] PROGMEM;
extern const char c_HtmlNamePaleVioletRed[] PROGMEM;
extern const char c_HtmlNamePapayaWhip[] PROGMEM;
extern const char c_HtmlNamePeachPuff[] PROGMEM;
extern const char c_HtmlNamePeru[] PROGMEM;
extern const char c_HtmlNamePink[] PROGMEM;
extern const char c_HtmlNamePlum[] PROGMEM;
extern const char c_HtmlNamePowderBlue[] PROGMEM;
extern const char c_HtmlNameRosyBrown[] PROGMEM;
extern const char c_HtmlNameRoyalBlue[] PROGMEM;
extern const char c_HtmlNameSaddleBrown[] PROGMEM;
extern const char c_HtmlNameSalmon[] PROGMEM;
extern const char c_HtmlNameSandyBrown[] PROGMEM;
extern const char c_HtmlNameSeaGreen[] PROGMEM;
extern const char c_HtmlNameSeaShell[] PROGMEM;
extern const char c_HtmlNameSienna[] PROGMEM;
extern const char c_HtmlNameSkyBlue[] PROGMEM;
extern const char c_HtmlNameSlateBlue[] PROGMEM;
extern const char c_HtmlNameSlateGray[] PROGMEM;
extern const char c_HtmlNameSlateGrey[] PROGMEM;
extern const char c_HtmlNameSnow[] PROGMEM;
extern const char c_HtmlNameSpringGreen[] PROGMEM;
extern const char c_HtmlNameSteelBlue[] PROGMEM;
extern const char c_HtmlNameTan[] PROGMEM;
extern const char c_HtmlNameThistle[] PROGMEM;
extern const char c_HtmlNameTomato[] PROGMEM;
extern const char c_HtmlNameTurquoise[] PROGMEM;
extern const char c_HtmlNameViolet[] PROGMEM;
extern const char c_HtmlNameWheat[] PROGMEM;
extern const char c_HtmlNameWhiteSmoke[] PROGMEM;
extern const char c_HtmlNameYellowGreen[] PROGMEM;

View File

@@ -0,0 +1,188 @@
/*-------------------------------------------------------------------------
HtmlColorNames provides a template class for access to the full name table
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 "HtmlColor.h"
#include "HtmlColorNameStrings.h"
static const HtmlColorPair c_ColorNames[] PROGMEM = {
{ c_HtmlNameAliceBlue, 0xf0f8ff },
{ c_HtmlNameAntiqueWhite, 0xfaebd7 },
{ c_HtmlNameAqua, 0xffff },
{ c_HtmlNameAquamarine, 0x7fffd4 },
{ c_HtmlNameAzure, 0xf0ffff },
{ c_HtmlNameBeige, 0xf5f5dc },
{ c_HtmlNameBisque, 0xffe4c4 },
{ c_HtmlNameBlack, 0x0 },
{ c_HtmlNameBlanchedAlmond, 0xffebcd },
{ c_HtmlNameBlue, 0xff },
{ c_HtmlNameBlueViolet, 0x8a2be2 },
{ c_HtmlNameBrown, 0xa52a2a },
{ c_HtmlNameBurlyWood, 0xdeb887 },
{ c_HtmlNameCadetBlue, 0x5f9ea0 },
{ c_HtmlNameChartreuse, 0x7fff00 },
{ c_HtmlNameChocolate, 0xd2691e },
{ c_HtmlNameCoral, 0xff7f50 },
{ c_HtmlNameCornflowerBlue, 0x6495ed },
{ c_HtmlNameCornsilk, 0xfff8dc },
{ c_HtmlNameCrimson, 0xdc143c },
{ c_HtmlNameCyan, 0xffff },
{ c_HtmlNameDarkBlue, 0x8b },
{ c_HtmlNameDarkCyan, 0x8b8b },
{ c_HtmlNameDarkGoldenrod, 0xb8860b },
{ c_HtmlNameDarkGray, 0xa9a9a9 },
{ c_HtmlNameDarkGreen, 0x6400 },
{ c_HtmlNameDarkGrey, 0xa9a9a9 },
{ c_HtmlNameDarkKhaki, 0xbdb76b },
{ c_HtmlNameDarkMagenta, 0x8b008b },
{ c_HtmlNameDarkOliveGreen, 0x556b2f },
{ c_HtmlNameDarkOrange, 0xff8c00 },
{ c_HtmlNameDarkOrchid, 0x9932cc },
{ c_HtmlNameDarkRed, 0x8b0000 },
{ c_HtmlNameDarkSalmon, 0xe9967a },
{ c_HtmlNameDarkSeaGreen, 0x8fbc8f },
{ c_HtmlNameDarkSlateBlue, 0x483d8b },
{ c_HtmlNameDarkSlateGray, 0x2f4f4f },
{ c_HtmlNameDarkSlateGrey, 0x2f4f4f },
{ c_HtmlNameDarkTurquoise, 0xced1 },
{ c_HtmlNameDarkViolet, 0x9400d3 },
{ c_HtmlNameDeepPink, 0xff1493 },
{ c_HtmlNameDeepSkyBlue, 0xbfff },
{ c_HtmlNameDimGray, 0x696969 },
{ c_HtmlNameDimGrey, 0x696969 },
{ c_HtmlNameDodgerBlue, 0x1e90ff },
{ c_HtmlNameFirebrick, 0xb22222 },
{ c_HtmlNameFloralWhite, 0xfffaf0 },
{ c_HtmlNameForestGreen, 0x228b22 },
{ c_HtmlNameFuchsia, 0xff00ff },
{ c_HtmlNameGainsboro, 0xdcdcdc },
{ c_HtmlNameGhostWhite, 0xf8f8ff },
{ c_HtmlNameGold, 0xffd700 },
{ c_HtmlNameGoldenrod, 0xdaa520 },
{ c_HtmlNameGray, 0x808080 },
{ c_HtmlNameGreen, 0x8000 },
{ c_HtmlNameGreenYellow, 0xadff2f },
{ c_HtmlNameGrey, 0x808080 },
{ c_HtmlNameHoneydew, 0xf0fff0 },
{ c_HtmlNameHotPink, 0xff69b4 },
{ c_HtmlNameIndianRed, 0xcd5c5c },
{ c_HtmlNameIndigo, 0x4b0082 },
{ c_HtmlNameIvory, 0xfffff0 },
{ c_HtmlNameKhaki, 0xf0e68c },
{ c_HtmlNameLavender, 0xe6e6fa },
{ c_HtmlNameLavenderBlush, 0xfff0f5 },
{ c_HtmlNameLawnGreen, 0x7cfc00 },
{ c_HtmlNameLemonChiffon, 0xfffacd },
{ c_HtmlNameLightBlue, 0xadd8e6 },
{ c_HtmlNameLightCoral, 0xf08080 },
{ c_HtmlNameLightCyan, 0xe0ffff },
{ c_HtmlNameLightGoldenrodYellow, 0xfafad2 },
{ c_HtmlNameLightGray, 0xd3d3d3 },
{ c_HtmlNameLightGreen, 0x90ee90 },
{ c_HtmlNameLightGrey, 0xd3d3d3 },
{ c_HtmlNameLightPink, 0xffb6c1 },
{ c_HtmlNameLightSalmon, 0xffa07a },
{ c_HtmlNameLightSeaGreen, 0x20b2aa },
{ c_HtmlNameLightSkyBlue, 0x87cefa },
{ c_HtmlNameLightSlateGray, 0x778899 },
{ c_HtmlNameLightSlateGrey, 0x778899 },
{ c_HtmlNameLightSteelBlue, 0xb0c4de },
{ c_HtmlNameLightYellow, 0xffffe0 },
{ c_HtmlNameLime, 0xff00 },
{ c_HtmlNameLimeGreen, 0x32cd32 },
{ c_HtmlNameLinen, 0xfaf0e6 },
{ c_HtmlNameMagenta, 0xff00ff },
{ c_HtmlNameMaroon, 0x800000 },
{ c_HtmlNameMediumAquamarine, 0x66cdaa },
{ c_HtmlNameMediumBlue, 0xcd },
{ c_HtmlNameMediumOrchid, 0xba55d3 },
{ c_HtmlNameMediumPurple, 0x9370d8 },
{ c_HtmlNameMediumSeagreen, 0x3cb371 },
{ c_HtmlNameMediumSlateBlue, 0x7b68ee },
{ c_HtmlNameMediumSpringGreen, 0xfa9a },
{ c_HtmlNameMediumTurquoise, 0x48d1cc },
{ c_HtmlNameMediumVioletRed, 0xc71585 },
{ c_HtmlNameMidnightBlue, 0x191970 },
{ c_HtmlNameMintCream, 0xf5fffa },
{ c_HtmlNameMistyRose, 0xffe4e1 },
{ c_HtmlNameMoccasin, 0xffe4b5 },
{ c_HtmlNameNavajoWhite, 0xffdead },
{ c_HtmlNameNavy, 0x80 },
{ c_HtmlNameOldLace, 0xfdf5e6 },
{ c_HtmlNameOlive, 0x808000 },
{ c_HtmlNameOliveDrab, 0x6b8e23 },
{ c_HtmlNameOrange, 0xffa500 },
{ c_HtmlNameOrangeRed, 0xff4500 },
{ c_HtmlNameOrchid, 0xda70d6 },
{ c_HtmlNamePaleGoldenrod, 0xeee8aa },
{ c_HtmlNamePaleGreen, 0x98fb98 },
{ c_HtmlNamePaleTurquoise, 0xafeeee },
{ c_HtmlNamePaleVioletRed, 0xd87093 },
{ c_HtmlNamePapayaWhip, 0xffefd5 },
{ c_HtmlNamePeachPuff, 0xffdab9 },
{ c_HtmlNamePeru, 0xcd853f },
{ c_HtmlNamePink, 0xffc0cb },
{ c_HtmlNamePlum, 0xdda0dd },
{ c_HtmlNamePowderBlue, 0xb0e0e6 },
{ c_HtmlNamePurple, 0x800080 },
{ c_HtmlNameRed, 0xff0000 },
{ c_HtmlNameRosyBrown, 0xbc8f8f },
{ c_HtmlNameRoyalBlue, 0x4169e1 },
{ c_HtmlNameSaddleBrown, 0x8b4513 },
{ c_HtmlNameSalmon, 0xfa8072 },
{ c_HtmlNameSandyBrown, 0xf4a460 },
{ c_HtmlNameSeaGreen, 0x2e8b57 },
{ c_HtmlNameSeaShell, 0xfff5ee },
{ c_HtmlNameSienna, 0xa0522d },
{ c_HtmlNameSilver, 0xc0c0c0 },
{ c_HtmlNameSkyBlue, 0x87ceeb },
{ c_HtmlNameSlateBlue, 0x6a5acd },
{ c_HtmlNameSlateGray, 0x708090 },
{ c_HtmlNameSlateGrey, 0x708090 },
{ c_HtmlNameSnow, 0xfffafa },
{ c_HtmlNameSpringGreen, 0xff7f },
{ c_HtmlNameSteelBlue, 0x4682b4 },
{ c_HtmlNameTan, 0xd2b48c },
{ c_HtmlNameTeal, 0x8080 },
{ c_HtmlNameThistle, 0xd8bfd8 },
{ c_HtmlNameTomato, 0xff6347 },
{ c_HtmlNameTurquoise, 0x40e0d0 },
{ c_HtmlNameViolet, 0xee82ee },
{ c_HtmlNameWheat, 0xf5deb3 },
{ c_HtmlNameWhite, 0xffffff },
{ c_HtmlNameWhiteSmoke, 0xf5f5f5 },
{ c_HtmlNameYellow, 0xffff00 },
{ c_HtmlNameYellowGreen, 0x9acd32 },
};
const HtmlColorPair* HtmlColorNames::Pair(uint8_t index)
{
return &c_ColorNames[index];
}
uint8_t HtmlColorNames::Count()
{
return countof(c_ColorNames);
}

View File

@@ -0,0 +1,59 @@
/*-------------------------------------------------------------------------
HtmlShortColorNames provides a template class for access to the short name table
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 "HtmlColor.h"
#include "HtmlColorNameStrings.h"
static const HtmlColorPair c_ShortColorNames[] PROGMEM = {
{ c_HtmlNameAqua, 0xffff },
{ c_HtmlNameBlack, 0x0 },
{ c_HtmlNameBlue, 0xff },
{ c_HtmlNameFuchsia, 0xff00ff },
{ c_HtmlNameGray, 0x808080 },
{ c_HtmlNameGreen, 0x8000 },
{ c_HtmlNameLime, 0xff00 },
{ c_HtmlNameMaroon, 0x800000 },
{ c_HtmlNameNavy, 0x80 },
{ c_HtmlNameOlive, 0x808000 },
{ c_HtmlNameOrange, 0xffa500 },
{ c_HtmlNamePurple, 0x800080 },
{ c_HtmlNameRed, 0xff0000 },
{ c_HtmlNameSilver, 0xc0c0c0 },
{ c_HtmlNameTeal, 0x8080 },
{ c_HtmlNameWhite, 0xffffff },
{ c_HtmlNameYellow, 0xffff00 },
};
const HtmlColorPair* HtmlShortColorNames::Pair(uint8_t index)
{
return &c_ShortColorNames[index];
}
uint8_t HtmlShortColorNames::Count()
{
return countof(c_ShortColorNames);
}

View File

@@ -0,0 +1,426 @@
#pragma once
/*-------------------------------------------------------------------------
Layout provides a collection of class objects that are used with NeoTopology
object.
They define the specific layout of pixels and do the math to change the 2d
cordinate space to 1d cordinate space
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/>.
-------------------------------------------------------------------------*/
const uint16_t PixelIndex_OutOfBounds = 0xffff;
//-----------------------------------------------------------------------------
// RowMajor
//-----------------------------------------------------------------------------
class RowMajorLayout;
class RowMajor90Layout;
class RowMajor180Layout;
class RowMajor270Layout;
class RowMajorTilePreference
{
public:
typedef RowMajorLayout EvenRowEvenColumnLayout;
typedef RowMajor270Layout EvenRowOddColumnLayout;
typedef RowMajor90Layout OddRowEvenColumnLayout;
typedef RowMajor180Layout OddRowOddColumnLayout;
};
// layout example of 4x4
// 00 01 02 03
// 04 05 06 07
// 08 09 10 11
// 12 13 14 15
//
class RowMajorLayout : public RowMajorTilePreference
{
public:
static uint16_t Map(uint16_t width, uint16_t /* height */, uint16_t x, uint16_t y)
{
return x + y * width;
}
};
// layout example of 4x4
// 12 08 04 00
// 13 09 05 01
// 14 10 06 02
// 15 11 07 03
//
class RowMajor90Layout : public RowMajorTilePreference
{
public:
static uint16_t Map(uint16_t width, uint16_t height, uint16_t x, uint16_t y)
{
return (width - 1 - x) * height + y;
}
};
// layout example of 4x4
// 15 14 13 12
// 11 10 09 08
// 07 06 05 04
// 03 02 01 00
//
class RowMajor180Layout : public RowMajorTilePreference
{
public:
static uint16_t Map(uint16_t width, uint16_t height, uint16_t x, uint16_t y)
{
return (width - 1 - x) + (height - 1 - y) * width;
}
};
// layout example of 4x4
// 03 07 11 15
// 02 06 10 14
// 01 05 09 13
// 00 04 08 12
//
class RowMajor270Layout : public RowMajorTilePreference
{
public:
static uint16_t Map(uint16_t /* width */, uint16_t height, uint16_t x, uint16_t y)
{
return x * height + (height - 1 - y);
}
};
//-----------------------------------------------------------------------------
// ColumnMajor
//-----------------------------------------------------------------------------
class ColumnMajorLayout;
class ColumnMajor90Layout;
class ColumnMajor180Layout;
class ColumnMajor270Layout;
class ColumnMajorTilePreference
{
public:
typedef ColumnMajorLayout EvenRowEvenColumnLayout;
typedef ColumnMajor270Layout EvenRowOddColumnLayout;
typedef ColumnMajor90Layout OddRowEvenColumnLayout;
typedef ColumnMajor180Layout OddRowOddColumnLayout;
};
// layout example of 4x4
// 00 04 08 12
// 01 05 09 13
// 02 06 10 14
// 03 07 11 15
//
class ColumnMajorLayout : public ColumnMajorTilePreference
{
public:
static uint16_t Map(uint16_t /* width */, uint16_t height, uint16_t x, uint16_t y)
{
return x * height + y;
}
};
// layout example of 4x4
// 03 02 01 00
// 07 06 05 04
// 11 10 09 08
// 15 14 13 12
//
class ColumnMajor90Layout : public ColumnMajorTilePreference
{
public:
static uint16_t Map(uint16_t width, uint16_t /* height */, uint16_t x, uint16_t y)
{
return (width - 1 - x) + y * width;
}
};
// layout example of 4x4
// 15 11 07 03
// 14 10 06 02
// 13 09 05 01
// 12 08 04 00
//
class ColumnMajor180Layout : public ColumnMajorTilePreference
{
public:
static uint16_t Map(uint16_t width, uint16_t height, uint16_t x, uint16_t y)
{
return (width - 1 - x) * height + (height - 1 - y);
}
};
// layout example of 4x4
// 12 13 14 15
// 08 09 10 11
// 04 05 06 07
// 00 01 02 03
//
class ColumnMajor270Layout : public ColumnMajorTilePreference
{
public:
static uint16_t Map(uint16_t width, uint16_t height, uint16_t x, uint16_t y)
{
return x + (height - 1 - y) * width;
}
};
//-----------------------------------------------------------------------------
// RowMajorAlternating
//-----------------------------------------------------------------------------
class RowMajorAlternating270Layout;
class RowMajorAlternating90Layout;
class RowMajorAlternatingTilePreference
{
public:
typedef RowMajorAlternating270Layout EvenRowEvenColumnLayout;
typedef RowMajorAlternating270Layout EvenRowOddColumnLayout;
typedef RowMajorAlternating90Layout OddRowEvenColumnLayout;
typedef RowMajorAlternating90Layout OddRowOddColumnLayout;
};
// layout example of 4x4
// 00 01 02 03
// 07 06 05 04
// 08 09 10 11
// 15 14 13 12
//
class RowMajorAlternatingLayout : public RowMajorAlternatingTilePreference
{
public:
static uint16_t Map(uint16_t width, uint16_t /* height */, uint16_t x, uint16_t y)
{
uint16_t index = y * width;
if (y & 0x0001)
{
index += ((width - 1) - x);
}
else
{
index += x;
}
return index;
}
};
// layout example of 4x4
// 15 08 07 00
// 14 09 06 01
// 13 10 05 02
// 12 11 04 03
//
class RowMajorAlternating90Layout : public RowMajorAlternatingTilePreference
{
public:
static uint16_t Map(uint16_t width, uint16_t height, uint16_t x, uint16_t y)
{
uint16_t mx = ((width - 1) - x);
uint16_t index = mx * height;
if (mx & 0x0001)
{
index += ((height - 1) - y);
}
else
{
index += y;
}
return index;
}
};
// layout example of 4x4
// 12 13 14 15
// 11 10 09 08
// 04 05 06 07
// 03 02 01 00
//
class RowMajorAlternating180Layout : public RowMajorAlternatingTilePreference
{
public:
static uint16_t Map(uint16_t width, uint16_t height, uint16_t x, uint16_t y)
{
uint16_t my = ((height - 1) - y);
uint16_t index = my * width;
if (my & 0x0001)
{
index += x;
}
else
{
index += ((width - 1) - x);
}
return index;
}
};
// layout example of 4x4
// 03 04 11 12
// 02 05 10 13
// 01 06 09 14
// 00 07 08 15
//
class RowMajorAlternating270Layout : public RowMajorAlternatingTilePreference
{
public:
static uint16_t Map(uint16_t /* width */, uint16_t height, uint16_t x, uint16_t y)
{
uint16_t index = x * height;
if (x & 0x0001)
{
index += y;
}
else
{
index += ((height - 1) - y);
}
return index;
}
};
//-----------------------------------------------------------------------------
// ColumnMajorAlternating
//-----------------------------------------------------------------------------
class ColumnMajorAlternatingLayout;
class ColumnMajorAlternating180Layout;
class ColumnMajorAlternatingTilePreference
{
public:
typedef ColumnMajorAlternatingLayout EvenRowEvenColumnLayout;
typedef ColumnMajorAlternatingLayout EvenRowOddColumnLayout;
typedef ColumnMajorAlternating180Layout OddRowEvenColumnLayout;
typedef ColumnMajorAlternating180Layout OddRowOddColumnLayout;
};
// layout example of 4x4
// 00 07 08 15
// 01 06 09 14
// 02 05 10 13
// 03 04 11 12
//
class ColumnMajorAlternatingLayout : public ColumnMajorAlternatingTilePreference
{
public:
static uint16_t Map(uint16_t /* width */, uint16_t height, uint16_t x, uint16_t y)
{
uint16_t index = x * height;
if (x & 0x0001)
{
index += ((height - 1) - y);
}
else
{
index += y;
}
return index;
}
};
// layout example of 4x4
// 03 02 01 00
// 04 05 06 07
// 11 10 09 08
// 12 13 14 15
//
class ColumnMajorAlternating90Layout : public ColumnMajorAlternatingTilePreference
{
public:
static uint16_t Map(uint16_t width, uint16_t /* height */, uint16_t x, uint16_t y)
{
uint16_t index = y * width;
if (y & 0x0001)
{
index += x;
}
else
{
index += ((width - 1) - x);
}
return index;
}
};
// layout example of 4x4
// 12 11 04 03
// 13 10 05 02
// 14 09 06 01
// 15 08 07 00
//
class ColumnMajorAlternating180Layout : public ColumnMajorAlternatingTilePreference
{
public:
static uint16_t Map(uint16_t width, uint16_t height, uint16_t x, uint16_t y)
{
uint16_t mx = ((width - 1) - x);
uint16_t index = mx * height;
if (mx & 0x0001)
{
index += y;
}
else
{
index += ((height - 1) - y);
}
return index;
}
};
// layout example of 4x4
// 15 14 13 12
// 08 09 10 11
// 07 06 05 04
// 00 01 02 03
//
class ColumnMajorAlternating270Layout : public ColumnMajorAlternatingTilePreference
{
public:
static uint16_t Map(uint16_t width, uint16_t height, uint16_t x, uint16_t y)
{
uint16_t my = ((height - 1) - y);
uint16_t index = my * width;
if (my & 0x0001)
{
index += ((width - 1) - x);
}
else
{
index += x;
}
return index;
}
};

View File

@@ -0,0 +1,189 @@
/*-------------------------------------------------------------------------
Lpd8806ColorFeatures provides feature classes to describe color order and
color depth for NeoPixelBus template class when used with DotStar like chips
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 Lpd88063ElementsNoSettings
{
public:
typedef NeoNoSettings SettingsObject;
static const size_t SettingsSize = 0;
static void applySettings(uint8_t*, const SettingsObject&)
{
}
static uint8_t* pixels(uint8_t* pData)
{
return pData;
}
static const uint8_t* pixels(const uint8_t* pData)
{
return pData;
}
};
class Lpd88063Elements : public Lpd88063ElementsNoSettings
{
public:
static const size_t PixelSize = 3;
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)
{
*pPixelDest++ = pPixelSrc[0];
*pPixelDest++ = pPixelSrc[1];
*pPixelDest++ = pPixelSrc[2];
}
}
static void movePixelsInc(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count)
{
uint8_t* pEnd = pPixelDest + (count * PixelSize);
while (pPixelDest < pEnd)
{
*pPixelDest++ = *pPixelSrc++;
*pPixelDest++ = *pPixelSrc++;
*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++);
*pPixelDest++ = pgm_read_byte(pSrc++);
*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;
*--pDestBack = *--pSrcBack;
*--pDestBack = *--pSrcBack;
}
}
typedef RgbColor ColorObject;
};
class Lpd8806BrgFeature : public Lpd88063Elements
{
public:
static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color)
{
uint8_t* p = getPixelAddress(pPixels, indexPixel);
*p++ = (color.B >> 1) | 0x80;
*p++ = (color.R >> 1) | 0x80;
*p = (color.G >> 1) | 0x80;
}
static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel)
{
ColorObject color;
const uint8_t* p = getPixelAddress(pPixels, indexPixel);
color.B = (*p++) << 1;
color.R = (*p++) << 1;
color.G = (*p) << 1;
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);
color.B = (pgm_read_byte(p++)) << 1;
color.R = (pgm_read_byte(p++)) << 1;
color.G = (pgm_read_byte(p)) << 1;
return color;
}
};
class Lpd8806GrbFeature : public Lpd88063Elements
{
public:
static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color)
{
uint8_t* p = getPixelAddress(pPixels, indexPixel);
*p++ = (color.G >> 1) | 0x80;
*p++ = (color.R >> 1) | 0x80;
*p = (color.B >> 1) | 0x80;
}
static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel)
{
ColorObject color;
const uint8_t* p = getPixelAddress(pPixels, indexPixel);
color.G = (*p++) << 1;
color.R = (*p++) << 1;
color.B = (*p) << 1;
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);
color.G = (pgm_read_byte(p++)) << 1;
color.R = (pgm_read_byte(p++)) << 1;
color.B = (pgm_read_byte(p)) << 1;
return color;
}
};

View File

@@ -0,0 +1,130 @@
/*-------------------------------------------------------------------------
NeoPixel library helper functions for LPD8806 using general Pins
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
// must also check for arm due to Teensy incorrectly having ARDUINO_ARCH_AVR set
#if defined(ARDUINO_ARCH_AVR) && !defined(__arm__)
#include "TwoWireBitBangImpleAvr.h"
#else
#include "TwoWireBitBangImple.h"
#endif
template<typename T_TWOWIRE> class Lpd8806MethodBase
{
public:
Lpd8806MethodBase(uint8_t pinClock, uint8_t pinData, uint16_t pixelCount, size_t elementSize, size_t settingsSize) :
_sizeData(pixelCount * elementSize + settingsSize),
_sizeFrame((pixelCount + 31) / 32),
_wire(pinClock, pinData)
{
_data = static_cast<uint8_t*>(malloc(_sizeData));
memset(_data, 0, _sizeData);
}
#if !defined(__AVR_ATtiny85__) && !defined(ARDUINO_attiny)
Lpd8806MethodBase(uint16_t pixelCount, size_t elementSize, size_t settingsSize) :
Lpd8806MethodBase(SCK, MOSI, pixelCount, elementSize, settingsSize)
{
}
#endif
~Lpd8806MethodBase()
{
free(_data);
}
bool IsReadyToUpdate() const
{
return true; // dot stars don't have a required delay
}
#if defined(ARDUINO_ARCH_ESP32)
void Initialize(int8_t sck, int8_t miso, int8_t mosi, int8_t ss)
{
_wire.begin(sck, miso, mosi, ss);
}
#endif
void Initialize()
{
_wire.begin();
}
void Update(bool)
{
_wire.beginTransaction();
// start frame
for (size_t frameByte = 0; frameByte < _sizeFrame; frameByte++)
{
_wire.transmitByte(0x00);
}
// data
_wire.transmitBytes(_data, _sizeData);
// end frame
for (size_t frameByte = 0; frameByte < _sizeFrame; frameByte++)
{
_wire.transmitByte(0xff);
}
_wire.endTransaction();
}
uint8_t* getData() const
{
return _data;
};
size_t getDataSize() const
{
return _sizeData;
};
private:
const size_t _sizeData; // Size of '_data' buffer below
const size_t _sizeFrame;
T_TWOWIRE _wire;
uint8_t* _data; // Holds LED color values
};
typedef Lpd8806MethodBase<TwoWireBitBangImple> Lpd8806Method;
#if !defined(__AVR_ATtiny85__) && !defined(ARDUINO_attiny)
#include "TwoWireSpiImple.h"
typedef Lpd8806MethodBase<TwoWireSpiImple<SpiSpeed20Mhz>> Lpd8806Spi20MhzMethod;
typedef Lpd8806MethodBase<TwoWireSpiImple<SpiSpeed10Mhz>> Lpd8806Spi10MhzMethod;
typedef Lpd8806MethodBase<TwoWireSpiImple<SpiSpeed2Mhz>> Lpd8806Spi2MhzMethod;
typedef Lpd8806Spi10MhzMethod Lpd8806SpiMethod;
#endif

View File

@@ -0,0 +1,818 @@
/*-------------------------------------------------------------------------
NeoPixel library helper functions for ARM MCUs.
Teensy 3.0, 3.1, LC, Arduino Due
Written by Michael C. Miller.
Some work taken from the Adafruit NeoPixel library.
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.
The contents of this file were taken from the Adafruit NeoPixel library
and modified only to fit within individual calling functions.
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
#if defined(__arm__) && !defined(ARDUINO_ARCH_NRF52840)
template<typename T_SPEED> class NeoArmMethodBase
{
public:
NeoArmMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize) :
_sizeData(pixelCount * elementSize + settingsSize),
_pin(pin)
{
pinMode(pin, OUTPUT);
_data = static_cast<uint8_t*>(malloc(_sizeData));
memset(_data, 0, _sizeData);
}
~NeoArmMethodBase()
{
pinMode(_pin, INPUT);
free(_data);
}
bool IsReadyToUpdate() const
{
uint32_t delta = micros() - _endTime;
return (delta >= T_SPEED::ResetTimeUs);
}
void Initialize()
{
digitalWrite(_pin, LOW);
_endTime = micros();
}
void Update(bool)
{
// Data latch = 50+ microsecond pause in the output stream. Rather than
// put a delay at the end of the function, the ending time is noted and
// the function will simply hold off (if needed) on issuing the
// subsequent round of data until the latch time has elapsed. This
// allows the mainline code to start generating the next frame of data
// rather than stalling for the latch.
while (!IsReadyToUpdate())
{
yield(); // allows for system yield if needed
}
noInterrupts(); // Need 100% focus on instruction timing
T_SPEED::send_pixels(_data, _sizeData, _pin);
interrupts();
// save EOD time for latch on next call
_endTime = micros();
}
uint8_t* getData() const
{
return _data;
};
size_t getDataSize() const
{
return _sizeData;
};
private:
const size_t _sizeData; // Size of '_data' buffer below
uint32_t _endTime; // Latch timing reference
uint8_t* _data; // Holds LED color values
uint8_t _pin; // output pin number
};
// Teensy 3.0 or 3.1 (3.2) or 3.5 or 3.6
#if defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__)
class NeoArmMk20dxSpeedProps800KbpsBase
{
public:
static const uint32_t CyclesT0h = (F_CPU / 4000000);
static const uint32_t CyclesT1h = (F_CPU / 1250000);
static const uint32_t Cycles = (F_CPU / 800000);
};
class NeoArmMk20dxSpeedPropsWs2812x : public NeoArmMk20dxSpeedProps800KbpsBase
{
public:
static const uint32_t ResetTimeUs = 300;
};
class NeoArmMk20dxSpeedPropsSk6812 : public NeoArmMk20dxSpeedProps800KbpsBase
{
public:
static const uint32_t ResetTimeUs = 80;
};
class NeoArmMk20dxSpeedPropsTm1814 : public NeoArmMk20dxSpeedProps800KbpsBase
{
public:
static const uint32_t ResetTimeUs = 200;
};
class NeoArmMk20dxSpeedProps800Kbps : public NeoArmMk20dxSpeedProps800KbpsBase
{
public:
static const uint32_t ResetTimeUs = 50;
};
class NeoArmMk20dxSpeedProps400Kbps
{
public:
static const uint32_t CyclesT0h = (F_CPU / 2000000);
static const uint32_t CyclesT1h = (F_CPU / 833333);
static const uint32_t Cycles = (F_CPU / 400000);
static const uint32_t ResetTimeUs = 50;
};
class NeoArmMk20dxSpeedPropsApa106
{
public:
static const uint32_t CyclesT0h = (F_CPU / 4000000);
static const uint32_t CyclesT1h = (F_CPU / 913750);
static const uint32_t Cycles = (F_CPU / 584800);
static const uint32_t ResetTimeUs = 50;
};
template<typename T_SPEEDPROPS> class NeoArmMk20dxSpeedBase
{
public:
static const uint32_t ResetTimeUs = T_SPEEDPROPS::ResetTimeUs;
static void send_pixels(uint8_t* pixels, size_t sizePixels, uint8_t pin)
{
uint8_t* p = pixels;
uint8_t* end = p + sizePixels;
uint8_t pix;
uint8_t mask;
volatile uint8_t* set = portSetRegister(pin);
volatile uint8_t* clr = portClearRegister(pin);
uint32_t cyc;
ARM_DEMCR |= ARM_DEMCR_TRCENA;
ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA;
cyc = ARM_DWT_CYCCNT + T_SPEEDPROPS::Cycles;
while (p < end)
{
pix = *p++;
for (mask = 0x80; mask; mask >>= 1)
{
while (ARM_DWT_CYCCNT - cyc < T_SPEEDPROPS::Cycles);
cyc = ARM_DWT_CYCCNT;
*set = 1;
if (pix & mask)
{
while (ARM_DWT_CYCCNT - cyc < T_SPEEDPROPS::CyclesT1h);
}
else
{
while (ARM_DWT_CYCCNT - cyc < T_SPEEDPROPS::CyclesT0h);
}
*clr = 1;
}
}
}
};
typedef NeoArmMethodBase<NeoArmMk20dxSpeedBase<NeoArmMk20dxSpeedPropsWs2812x>> NeoArmWs2812xMethod;
typedef NeoArmMethodBase<NeoArmMk20dxSpeedBase<NeoArmMk20dxSpeedPropsSk6812>> NeoArmSk6812Method;
typedef NeoArmMethodBase<NeoArmMk20dxSpeedBase<NeoArmMk20dxSpeedPropsTm1814>> NeoArmTm1814InvertedMethod;
typedef NeoArmMethodBase<NeoArmMk20dxSpeedBase<NeoArmMk20dxSpeedPropsApa106>> NeoArmApa106Method;
typedef NeoArmMethodBase<NeoArmMk20dxSpeedBase<NeoArmMk20dxSpeedProps800Kbps>> NeoArm800KbpsMethod;
typedef NeoArmMethodBase<NeoArmMk20dxSpeedBase<NeoArmMk20dxSpeedProps400Kbps>> NeoArm400KbpsMethod;
#elif defined(__MKL26Z64__) // Teensy-LC
#if F_CPU == 48000000
class NeoArmMk26z64Speed800KbpsBase
{
public:
static void send_pixels(uint8_t* pixels, size_t sizePixels, uint8_t pin)
{
uint8_t* p = pixels;
uint8_t pix;
uint8_t count;
uint8_t dly;
uint8_t bitmask = digitalPinToBitMask(pin);
volatile uint8_t* reg = portSetRegister(pin);
uint32_t num = sizePixels;
asm volatile(
"L%=_begin:" "\n\t"
"ldrb %[pix], [%[p], #0]" "\n\t"
"lsl %[pix], #24" "\n\t"
"movs %[count], #7" "\n\t"
"L%=_loop:" "\n\t"
"lsl %[pix], #1" "\n\t"
"bcs L%=_loop_one" "\n\t"
"L%=_loop_zero:"
"strb %[bitmask], [%[reg], #0]" "\n\t"
"movs %[dly], #4" "\n\t"
"L%=_loop_delay_T0H:" "\n\t"
"sub %[dly], #1" "\n\t"
"bne L%=_loop_delay_T0H" "\n\t"
"strb %[bitmask], [%[reg], #4]" "\n\t"
"movs %[dly], #13" "\n\t"
"L%=_loop_delay_T0L:" "\n\t"
"sub %[dly], #1" "\n\t"
"bne L%=_loop_delay_T0L" "\n\t"
"b L%=_next" "\n\t"
"L%=_loop_one:"
"strb %[bitmask], [%[reg], #0]" "\n\t"
"movs %[dly], #13" "\n\t"
"L%=_loop_delay_T1H:" "\n\t"
"sub %[dly], #1" "\n\t"
"bne L%=_loop_delay_T1H" "\n\t"
"strb %[bitmask], [%[reg], #4]" "\n\t"
"movs %[dly], #4" "\n\t"
"L%=_loop_delay_T1L:" "\n\t"
"sub %[dly], #1" "\n\t"
"bne L%=_loop_delay_T1L" "\n\t"
"nop" "\n\t"
"L%=_next:" "\n\t"
"sub %[count], #1" "\n\t"
"bne L%=_loop" "\n\t"
"lsl %[pix], #1" "\n\t"
"bcs L%=_last_one" "\n\t"
"L%=_last_zero:"
"strb %[bitmask], [%[reg], #0]" "\n\t"
"movs %[dly], #4" "\n\t"
"L%=_last_delay_T0H:" "\n\t"
"sub %[dly], #1" "\n\t"
"bne L%=_last_delay_T0H" "\n\t"
"strb %[bitmask], [%[reg], #4]" "\n\t"
"movs %[dly], #10" "\n\t"
"L%=_last_delay_T0L:" "\n\t"
"sub %[dly], #1" "\n\t"
"bne L%=_last_delay_T0L" "\n\t"
"b L%=_repeat" "\n\t"
"L%=_last_one:"
"strb %[bitmask], [%[reg], #0]" "\n\t"
"movs %[dly], #13" "\n\t"
"L%=_last_delay_T1H:" "\n\t"
"sub %[dly], #1" "\n\t"
"bne L%=_last_delay_T1H" "\n\t"
"strb %[bitmask], [%[reg], #4]" "\n\t"
"movs %[dly], #1" "\n\t"
"L%=_last_delay_T1L:" "\n\t"
"sub %[dly], #1" "\n\t"
"bne L%=_last_delay_T1L" "\n\t"
"nop" "\n\t"
"L%=_repeat:" "\n\t"
"add %[p], #1" "\n\t"
"sub %[num], #1" "\n\t"
"bne L%=_begin" "\n\t"
"L%=_done:" "\n\t"
: [p] "+r" (p),
[pix] "=&r" (pix),
[count] "=&r" (count),
[dly] "=&r" (dly),
[num] "+r" (num)
: [bitmask] "r" (bitmask),
[reg] "r" (reg)
);
}
};
class NeoArmMk26z64SpeedWs2812x : public NeoArmMk26z64Speed800KbpsBase
{
public:
const static uint32_t ResetTimeUs = 300;
};
class NeoArmMk26z64SpeedSk6812 : public NeoArmMk26z64Speed800KbpsBase
{
public:
const static uint32_t ResetTimeUs = 80;
};
class NeoArmMk26z64SpeedTm1814 : public NeoArmMk26z64Speed800KbpsBase
{
public:
const static uint32_t ResetTimeUs = 200;
};
class NeoArmMk26z64Speed800Kbps : public NeoArmMk26z64Speed800KbpsBase
{
public:
const static uint32_t ResetTimeUs = 50;
};
typedef NeoArmMethodBase<NeoArmMk26z64SpeedWs2812x> NeoArmWs2812xMethod;
typedef NeoArmMethodBase<NeoArmMk26z64SpeedSk6812> NeoArmSk6812Method;
typedef NeoArmMethodBase<NeoArmMk26z64SpeedTm1814> NeoArmTm1814InvertedMethod;
typedef NeoArmMethodBase<NeoArmMk26z64Speed800Kbps> NeoArm800KbpsMethod;
typedef NeoArm800KbpsMethod NeoArmApa106Method
#else
#error "Teensy-LC: Sorry, only 48 MHz is supported, please set Tools > CPU Speed to 48 MHz"
#endif // F_CPU == 48000000
#elif defined(__SAMD21G18A__) // Arduino Zero
class NeoArmSamd21g18aSpeedProps800KbpsBase
{
public:
static void BitPreWait()
{
asm("nop; nop; nop; nop; nop; nop; nop; nop;");
}
static void BitT1hWait()
{
asm("nop; nop; nop; nop; nop; nop; nop; nop;"
"nop; nop; nop; nop; nop; nop; nop; nop;"
"nop; nop; nop; nop;");
}
static void BitT0lWait()
{
asm("nop; nop; nop; nop; nop; nop; nop; nop;"
"nop; nop; nop; nop; nop; nop; nop; nop;"
"nop; nop; nop; nop;");
}
static void BitPostWait()
{
asm("nop; nop; nop; nop; nop; nop; nop; nop; nop;");
}
};
class NeoArmSamd21g18aSpeedPropsWs2812x : public NeoArmSamd21g18aSpeedProps800KbpsBase
{
public:
static const uint32_t ResetTimeUs = 300;
};
class NeoArmSamd21g18aSpeedPropsSk6812 : public NeoArmSamd21g18aSpeedProps800KbpsBase
{
public:
static const uint32_t ResetTimeUs = 80;
};
class NeoArmSamd21g18aSpeedPropsTm1814 : public NeoArmSamd21g18aSpeedProps800KbpsBase
{
public:
static const uint32_t ResetTimeUs = 200;
};
class NeoArmSamd21g18aSpeedProps800Kbps : public NeoArmSamd21g18aSpeedProps800KbpsBase
{
public:
static const uint32_t ResetTimeUs = 50;
};
class NeoArmSamd21g18aSpeedProps400Kbps
{
public:
static void BitPreWait()
{
asm("nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop;");
}
static void BitT1hWait()
{
asm("nop; nop; nop; nop; nop; nop; nop; nop;"
"nop; nop; nop; nop; nop; nop; nop; nop;"
"nop; nop; nop; nop; nop; nop; nop; nop;"
"nop; nop; nop;");
}
static void BitT0lWait()
{
asm("nop; nop; nop; nop; nop; nop; nop; nop;"
"nop; nop; nop; nop; nop; nop; nop; nop;"
"nop; nop; nop; nop; nop; nop; nop; nop;"
"nop; nop; nop;");
}
static void BitPostWait()
{
asm("nop; nop; nop; nop; nop; nop; nop;");
}
static const uint32_t ResetTimeUs = 50;
};
template<typename T_SPEEDPROPS> class NeoArmSamd21g18aSpeedBase
{
public:
static const uint32_t ResetTimeUs = T_SPEEDPROPS::ResetTimeUs;
static void send_pixels(uint8_t* pixels, size_t sizePixels, uint8_t pin)
{
// Tried this with a timer/counter, couldn't quite get adequate
// resolution. So yay, you get a load of goofball NOPs...
uint8_t* ptr = pixels;
uint8_t* end = ptr + sizePixels;;
uint8_t p = *ptr++;
uint8_t bitMask = 0x80;
uint8_t portNum = g_APinDescription[pin].ulPort;
uint32_t pinMask = 1ul << g_APinDescription[pin].ulPin;
volatile uint32_t* set = &(PORT->Group[portNum].OUTSET.reg);
volatile uint32_t* clr = &(PORT->Group[portNum].OUTCLR.reg);
for (;;)
{
*set = pinMask;
T_SPEEDPROPS::BitPreWait();
if (p & bitMask)
{
T_SPEEDPROPS::BitT1hWait();
*clr = pinMask;
}
else
{
*clr = pinMask;
T_SPEEDPROPS::BitT0lWait();
}
if (bitMask >>= 1)
{
T_SPEEDPROPS::BitPostWait();
}
else
{
if (ptr >= end)
{
break;
}
p = *ptr++;
bitMask = 0x80;
}
}
}
};
typedef NeoArmMethodBase<NeoArmSamd21g18aSpeedBase<NeoArmSamd21g18aSpeedPropsWs2812x>> NeoArmWs2812xMethod;
typedef NeoArmMethodBase<NeoArmSamd21g18aSpeedBase<NeoArmSamd21g18aSpeedPropsSk6812>> NeoArmSk6812Method;
typedef NeoArmMethodBase<NeoArmSamd21g18aSpeedBase<NeoArmSamd21g18aSpeedPropsTm1814>> NeoArmTm1814InvertedMethod;
typedef NeoArmMethodBase<NeoArmSamd21g18aSpeedBase<NeoArmSamd21g18aSpeedProps800Kbps>> NeoArm800KbpsMethod;
typedef NeoArmMethodBase<NeoArmSamd21g18aSpeedBase<NeoArmSamd21g18aSpeedProps400Kbps>> NeoArm400KbpsMethod;
typedef NeoArm400KbpsMethod NeoArmApa106Method;
#elif defined(ARDUINO_STM32_FEATHER) || defined(ARDUINO_ARCH_STM32L4) || defined(ARDUINO_ARCH_STM32F4) || defined(ARDUINO_ARCH_STM32F1)// FEATHER WICED (120MHz)
class NeoArmStm32SpeedProps800KbpsBase
{
public:
static void BitT1hWait()
{
asm("nop; nop; nop; nop; nop; nop; nop; nop;"
"nop; nop; nop; nop; nop; nop; nop; nop;"
"nop; nop; nop; nop; nop; nop; nop; nop;"
"nop; nop; nop; nop; nop; nop; nop; nop;"
"nop; nop; nop; nop; nop; nop; nop; nop;"
"nop; nop; nop; nop; nop; nop; nop; nop;"
"nop; nop; nop; nop; nop; nop; nop; nop;"
"nop; nop; nop; nop; nop; nop; nop; nop;"
"nop; nop; nop; nop; nop; nop; nop; nop;"
"nop; nop; nop; nop; nop; nop; nop; nop;"
"nop; nop; nop; nop; nop; nop; nop; nop;"
"nop; nop; nop; nop; nop; nop;");
}
static void BitT1lWait()
{
asm("nop; nop; nop; nop; nop; nop; nop; nop;"
"nop; nop; nop; nop; nop; nop; nop; nop;"
"nop; nop; nop; nop; nop; nop; nop; nop;"
"nop; nop; nop; nop; nop; nop; nop; nop;"
"nop; nop; nop; nop; nop; nop;");
}
static void BitT0hWait()
{
asm("nop; nop; nop; nop; nop; nop; nop; nop;"
"nop; nop; nop; nop; nop; nop; nop; nop;"
"nop; nop; nop; nop; nop; nop; nop; nop;"
"nop; nop; nop; nop; nop; nop; nop; nop;"
"nop; nop; nop; nop; nop; nop; nop; nop;"
"nop;");
}
static void BitT0lWait()
{
asm("nop; nop; nop; nop; nop; nop; nop; nop;"
"nop; nop; nop; nop; nop; nop; nop; nop;"
"nop; nop; nop; nop; nop; nop; nop; nop;"
"nop; nop; nop; nop; nop; nop; nop; nop;"
"nop; nop; nop; nop; nop; nop; nop; nop;"
"nop; nop; nop; nop; nop; nop; nop; nop;"
"nop; nop; nop; nop; nop; nop; nop; nop;"
"nop; nop; nop; nop; nop; nop; nop; nop;"
"nop; nop; nop; nop; nop; nop; nop; nop;"
"nop; nop; nop; nop; nop; nop; nop; nop;"
"nop; nop; nop; nop; nop; nop; nop; nop;"
"nop; nop; nop; nop;");
}
};
class NeoArmStm32SpeedPropsWs2812x : public NeoArmStm32SpeedProps800KbpsBase
{
public:
static const uint32_t ResetTimeUs = 300;
};
class NeoArmStm32SpeedPropsSk6812 : public NeoArmStm32SpeedProps800KbpsBase
{
public:
static const uint32_t ResetTimeUs = 80;
};
class NeoArmStm32SpeedPropsTm1814 : public NeoArmStm32SpeedProps800KbpsBase
{
public:
static const uint32_t ResetTimeUs = 200;
};
class NeoArmStm32SpeedProps800Kbps : public NeoArmStm32SpeedProps800KbpsBase
{
public:
static const uint32_t ResetTimeUs = 50;
};
/* TODO - not found in Adafruit library
class NeoArmStm32SpeedProps400Kbps
{
static void BitT1hWait()
{
}
static void BitT1lWait()
{
}
static void BitT0hWait()
{
}
static void BitT0lWait()
{
}
};
*/
template<typename T_SPEEDPROPS> class NeoArmStm32SpeedBase
{
public:
static const uint32_t ResetTimeUs = T_SPEEDPROPS::ResetTimeUs;
static void send_pixels(uint8_t* pixels, size_t sizePixels, uint8_t pin)
{
// Tried this with a timer/counter, couldn't quite get adequate
// resolution. So yay, you get a load of goofball NOPs...
uint8_t* ptr = pixels;
uint8_t* end = ptr + sizePixels;
uint8_t p = *ptr++;
uint8_t bitMask = 0x80;
#if defined(ARDUINO_STM32_FEATHER)
uint32_t pinMask = BIT(PIN_MAP[pin].gpio_bit);
volatile uint16_t* set = &(PIN_MAP[pin].gpio_device->regs->BSRRL);
volatile uint16_t* clr = &(PIN_MAP[pin].gpio_device->regs->BSRRH);
#elif defined(ARDUINO_ARCH_STM32F4)
uint32_t pinMask = BIT(pin & 0x0f);
volatile uint16_t* set = &(PIN_MAP[pin].gpio_device->regs->BSRRL);
volatile uint16_t* clr = &(PIN_MAP[pin].gpio_device->regs->BSRRH);
#elif defined(ARDUINO_ARCH_STM32F1)
uint32_t pinMask = BIT(PIN_MAP[pin].gpio_bit);
volatile uint32_t* set = &(PIN_MAP[pin].gpio_device->regs->BRR);
volatile uint32_t* clr = &(PIN_MAP[pin].gpio_device->regs->BSRR);
#elif defined(ARDUINO_ARCH_STM32L4)
uint32_t pinMask = g_APinDescription[pin].bit;
GPIO_TypeDef* GPIO = static_cast<GPIO_TypeDef*>(g_APinDescription[pin].GPIO);
volatile uint32_t* set = &(GPIO->BRR);
volatile uint32_t* clr = &(GPIO->BSRR);
#endif
for (;;)
{
if (p & bitMask)
{
// ONE
// High 800ns
*set = pinMask;
T_SPEEDPROPS::BitT1hWait();
// Low 450ns
*clr = pinMask;
T_SPEEDPROPS::BitT1lWait();
}
else
{
// ZERO
// High 400ns
*set = pinMask;
T_SPEEDPROPS::BitT0hWait();
// Low 850ns
*clr = pinMask;
T_SPEEDPROPS::BitT0lWait();
}
if (bitMask >>= 1)
{
// Move on to the next pixel
asm("nop;");
}
else
{
if (ptr >= end)
{
break;
}
p = *ptr++;
bitMask = 0x80;
}
}
}
};
typedef NeoArmMethodBase<NeoArmStm32SpeedBase<NeoArmStm32SpeedPropsWs2812x>> NeoArmWs2812xMethod;
typedef NeoArmMethodBase<NeoArmStm32SpeedBase<NeoArmStm32SpeedPropsSk6812>> NeoArmSk6812Method;
typedef NeoArmMethodBase<NeoArmStm32SpeedBase<NeoArmStm32SpeedPropstm1814>> NeoArmTm1814InvertedMethod;
typedef NeoArmMethodBase<NeoArmStm32SpeedBase<NeoArmStm32SpeedProps800Kbps>> NeoArm800KbpsMethod;
typedef NeoArm800KbpsMethod NeoArmApa106Method;
#else // Other ARM architecture -- Presumed Arduino Due
#define ARM_OTHER_SCALE VARIANT_MCK / 2UL / 1000000UL
#define ARM_OTHER_INST (2UL * F_CPU / VARIANT_MCK)
class NeoArmOtherSpeedProps800KbpsBase
{
public:
static const uint32_t CyclesT0h = ((uint32_t)(0.40 * ARM_OTHER_SCALE + 0.5) - (5 * ARM_OTHER_INST));
static const uint32_t CyclesT1h = ((uint32_t)(0.80 * ARM_OTHER_SCALE + 0.5) - (5 * ARM_OTHER_INST));
static const uint32_t Cycles = ((uint32_t)(1.25 * ARM_OTHER_SCALE + 0.5) - (5 * ARM_OTHER_INST));
};
class NeoArmOtherSpeedPropsWs2812x : public NeoArmOtherSpeedProps800KbpsBase
{
public:
static const uint32_t ResetTimeUs = 300;
};
class NeoArmOtherSpeedPropsSk6812 : public NeoArmOtherSpeedProps800KbpsBase
{
public:
static const uint32_t ResetTimeUs = 80;
};
class NeoArmOtherSpeedPropsTm1814 : public NeoArmOtherSpeedProps800KbpsBase
{
public:
static const uint32_t ResetTimeUs = 200;
};
class NeoArmOtherSpeedProps800Kbps : public NeoArmOtherSpeedProps800KbpsBase
{
public:
static const uint32_t ResetTimeUs = 50;
};
class NeoArmOtherSpeedProps400Kbps
{
public:
static const uint32_t CyclesT0h = ((uint32_t)(0.50 * ARM_OTHER_SCALE + 0.5) - (5 * ARM_OTHER_INST));
static const uint32_t CyclesT1h = ((uint32_t)(1.20 * ARM_OTHER_SCALE + 0.5) - (5 * ARM_OTHER_INST));
static const uint32_t Cycles = ((uint32_t)(2.50 * ARM_OTHER_SCALE + 0.5) - (5 * ARM_OTHER_INST));
static const uint32_t ResetTimeUs = 50;
};
template<typename T_SPEEDPROPS> class NeoArmOtherSpeedBase
{
public:
static const uint32_t ResetTimeUs = T_SPEEDPROPS::ResetTimeUs;
static void send_pixels(uint8_t* pixels, size_t sizePixels, uint8_t pin)
{
uint32_t pinMask;
uint32_t t;
Pio* port;
volatile WoReg* portSet;
volatile WoReg* portClear;
volatile WoReg* timeValue;
volatile WoReg* timeReset;
uint8_t* p;
uint8_t* end;
uint8_t pix;
uint8_t mask;
pmc_set_writeprotect(false);
pmc_enable_periph_clk((uint32_t)TC3_IRQn);
TC_Configure(TC1, 0,
TC_CMR_WAVE | TC_CMR_WAVSEL_UP | TC_CMR_TCCLKS_TIMER_CLOCK1);
TC_Start(TC1, 0);
pinMask = g_APinDescription[pin].ulPin; // Don't 'optimize' these into
port = g_APinDescription[pin].pPort; // declarations above. Want to
portSet = &(port->PIO_SODR); // burn a few cycles after
portClear = &(port->PIO_CODR); // starting timer to minimize
timeValue = &(TC1->TC_CHANNEL[0].TC_CV); // the initial 'while'.
timeReset = &(TC1->TC_CHANNEL[0].TC_CCR);
p = pixels;
end = p + sizePixels;
pix = *p++;
mask = 0x80;
for (;;)
{
if (pix & mask)
{
t = T_SPEEDPROPS::CyclesT1h;
}
else
{
t = T_SPEEDPROPS::CyclesT0h;
}
// wait for the end of the previous cycle
while (*timeValue < T_SPEEDPROPS::Cycles);
*portSet = pinMask;
*timeReset = TC_CCR_CLKEN | TC_CCR_SWTRG;
while (*timeValue < t);
*portClear = pinMask;
if (!(mask >>= 1))
{
// This 'inside-out' loop logic utilizes
if (p >= end)
{
break; // idle time to minimize inter-byte delays.
}
pix = *p++;
mask = 0x80;
}
}
// not really needed as the wait for latch does this and
// while (*timeValue < T_SPEEDPROPS::Cycles); // Wait for last bit
TC_Stop(TC1, 0);
}
};
typedef NeoArmMethodBase<NeoArmOtherSpeedBase<NeoArmOtherSpeedPropsWs2812x>> NeoArmWs2812xMethod;
typedef NeoArmMethodBase<NeoArmOtherSpeedBase<NeoArmOtherSpeedPropsSk6812>> NeoArmSk6812Method;
typedef NeoArmMethodBase<NeoArmOtherSpeedBase<NeoArmOtherSpeedPropsTm1814>> NeoArmTm1814InvertedMethod;
typedef NeoArmMethodBase<NeoArmOtherSpeedBase<NeoArmOtherSpeedProps800Kbps>> NeoArm800KbpsMethod;
typedef NeoArmMethodBase<NeoArmOtherSpeedBase<NeoArmOtherSpeedProps400Kbps>> NeoArm400KbpsMethod;
typedef NeoArm400KbpsMethod NeoArmApa106Method;
#endif
// Arm doesn't have alternatives methods yet, so only one to make the default
typedef NeoArmWs2812xMethod NeoWs2813Method;
typedef NeoArmWs2812xMethod NeoWs2812xMethod;
typedef NeoArmWs2812xMethod NeoWs2811Method;
typedef NeoArmSk6812Method NeoSk6812Method;
typedef NeoArmSk6812Method NeoLc8812Method;
typedef NeoArm800KbpsMethod NeoWs2812Method;
typedef NeoArmApa106Method NeoApa106Method;
typedef NeoArmWs2812xMethod Neo800KbpsMethod;
#ifdef NeoArm400KbpsMethod // this is needed due to missing 400Kbps for some platforms
typedef NeoArm400KbpsMethod Neo400KbpsMethod;
#endif
// there is no invert methods for arm, but the norm for TM1814 is inverted, so
typedef NeoArmTm1814InvertedMethod NeoTm1814InvertedMethod;
#endif // defined(__arm__)

View File

@@ -0,0 +1,224 @@
/*-------------------------------------------------------------------------
NeoPixel library helper functions for Atmel AVR.
Written by Michael C. Miller.
Some work taken from the Adafruit NeoPixel library.
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
#if defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_MEGAAVR)
extern "C"
{
void send_data_8mhz_800_PortD(uint8_t* data, size_t sizeData, uint8_t pinMask);
void send_data_8mhz_800_PortB(uint8_t* data, size_t sizeData, uint8_t pinMask);
void send_data_8mhz_400(uint8_t* data, size_t sizeData, volatile uint8_t* port, uint8_t pinMask);
void send_data_12mhz_800_PortD(uint8_t* data, size_t sizeData, uint8_t pinMask);
void send_data_12mhz_800_PortB(uint8_t* data, size_t sizeData, uint8_t pinMask);
void send_data_12mhz_400(uint8_t* data, size_t sizeData, volatile uint8_t* port, uint8_t pinMask);
void send_data_16mhz_800(uint8_t* data, size_t sizeData, volatile uint8_t* port, uint8_t pinMask);
void send_data_16mhz_400(uint8_t* data, size_t sizeData, volatile uint8_t* port, uint8_t pinMask);
}
class NeoAvrSpeed800KbpsBase
{
public:
static void send_data(uint8_t* data, size_t sizeData, volatile uint8_t* port, uint8_t pinMask)
{
#if (F_CPU >= 7400000UL) && (F_CPU <= 9500000UL) // 8Mhz CPU
#ifdef PORTD // PORTD isn't present on ATtiny85, etc.
if (port == &PORTD)
send_data_8mhz_800_PortD(data, sizeData, pinMask);
else if (port == &PORTB)
#endif // PORTD
send_data_8mhz_800_PortB(data, sizeData, pinMask);
#elif (F_CPU >= 11100000UL) && (F_CPU <= 14300000UL) // 12Mhz CPU
#ifdef PORTD // PORTD
if (port == &PORTD)
send_data_12mhz_800_PortD(data, sizeData, pinMask);
else if (port == &PORTB)
#endif // PORTD
send_data_12mhz_800_PortB(data, sizeData, pinMask);
#elif (F_CPU >= 15400000UL) && (F_CPU <= 19000000L) // 16Mhz CPU
send_data_16mhz_800(data, sizeData, port, pinMask);
#else
#error "CPU SPEED NOT SUPPORTED"
#endif
}
};
class NeoAvrSpeedWs2812x : public NeoAvrSpeed800KbpsBase
{
public:
static const uint32_t ResetTimeUs = 300;
};
class NeoAvrSpeedSk6812 : public NeoAvrSpeed800KbpsBase
{
public:
static const uint32_t ResetTimeUs = 80;
};
class NeoAvrSpeedTm1814 : public NeoAvrSpeed800KbpsBase
{
public:
static const uint32_t ResetTimeUs = 200;
};
class NeoAvrSpeed800Kbps: public NeoAvrSpeed800KbpsBase
{
public:
static const uint32_t ResetTimeUs = 50;
};
class NeoAvrSpeed400Kbps
{
public:
static void send_data(uint8_t* data, size_t sizeData, volatile uint8_t* port, uint8_t pinMask)
{
#if (F_CPU >= 7400000UL) && (F_CPU <= 9500000UL) // 8Mhz CPU
send_data_8mhz_400(data, sizeData, port, pinMask);
#elif (F_CPU >= 11100000UL) && (F_CPU <= 14300000UL) // 12Mhz CPU
send_data_12mhz_400(data, sizeData, port, pinMask);
#elif (F_CPU >= 15400000UL) && (F_CPU <= 19000000L) // 16Mhz CPU
send_data_16mhz_400(data, sizeData, port, pinMask);
#else
#error "CPU SPEED NOT SUPPORTED"
#endif
}
static const uint32_t ResetTimeUs = 50;
};
template<typename T_SPEED> class NeoAvrMethodBase
{
public:
NeoAvrMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize) :
_sizeData(pixelCount * elementSize + settingsSize),
_pin(pin),
_port(NULL),
_pinMask(0)
{
pinMode(pin, OUTPUT);
_data = static_cast<uint8_t*>(malloc(_sizeData));
memset(_data, 0, _sizeData);
_port = portOutputRegister(digitalPinToPort(pin));
_pinMask = digitalPinToBitMask(pin);
}
~NeoAvrMethodBase()
{
pinMode(_pin, INPUT);
free(_data);
}
bool IsReadyToUpdate() const
{
uint32_t delta = micros() - _endTime;
return (delta >= T_SPEED::ResetTimeUs);
}
void Initialize()
{
digitalWrite(_pin, LOW);
_endTime = micros();
}
void Update(bool)
{
// Data latch = 50+ microsecond pause in the output stream. Rather than
// put a delay at the end of the function, the ending time is noted and
// the function will simply hold off (if needed) on issuing the
// subsequent round of data until the latch time has elapsed. This
// allows the mainline code to start generating the next frame of data
// rather than stalling for the latch.
while (!IsReadyToUpdate())
{
#if !defined(ARDUINO_TEEONARDU_LEO) && !defined(ARDUINO_TEEONARDU_FLORA)
yield(); // allows for system yield if needed
#endif
}
noInterrupts(); // Need 100% focus on instruction timing
T_SPEED::send_data(_data, _sizeData, _port, _pinMask);
interrupts();
// save EOD time for latch on next call
_endTime = micros();
}
uint8_t* getData() const
{
return _data;
};
size_t getDataSize() const
{
return _sizeData;
};
private:
const size_t _sizeData; // size of _data below
const uint8_t _pin; // output pin number
uint32_t _endTime; // Latch timing reference
uint8_t* _data; // Holds data stream which include LED color values and other settings as needed
volatile uint8_t* _port; // Output PORT register
uint8_t _pinMask; // Output PORT bitmask
};
typedef NeoAvrMethodBase<NeoAvrSpeedWs2812x> NeoAvrWs2812xMethod;
typedef NeoAvrMethodBase<NeoAvrSpeedSk6812> NeoAvrSk6812Method;
typedef NeoAvrMethodBase<NeoAvrSpeedTm1814> NeoAvrTm1814InvertedMethod;
typedef NeoAvrMethodBase<NeoAvrSpeed800Kbps> NeoAvr800KbpsMethod;
typedef NeoAvrMethodBase<NeoAvrSpeed400Kbps> NeoAvr400KbpsMethod;
// AVR doesn't have alternatives yet, so there is just the default
typedef NeoAvrWs2812xMethod NeoWs2813Method;
typedef NeoAvrWs2812xMethod NeoWs2812xMethod;
typedef NeoAvr800KbpsMethod NeoWs2812Method;
typedef NeoAvrWs2812xMethod NeoWs2811Method;
typedef NeoAvrSk6812Method NeoSk6812Method;
typedef NeoAvrSk6812Method NeoLc8812Method;
typedef NeoAvr400KbpsMethod NeoApa106Method;
typedef NeoAvrWs2812xMethod Neo800KbpsMethod;
typedef NeoAvr400KbpsMethod Neo400KbpsMethod;
typedef NeoAvrTm1814InvertedMethod NeoTm1814InvertedMethod;
#endif

View File

@@ -0,0 +1,388 @@
/*-------------------------------------------------------------------------
NeoPixel library
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
const uint16_t c_BitmapFileId = 0x4d42; // "BM"
#pragma pack(push, 2)
struct BitmapFileHeader
{
uint16_t FileId; // only c_BitmapFileId is supported
uint32_t FileSize;
uint16_t Reserved0;
uint16_t Reserved1;
uint32_t PixelAddress;
};
struct BitmapInfoHeader
{
uint32_t Size;
int32_t Width;
int32_t Height;
uint16_t Planes; // only support 1
uint16_t BitsPerPixel; // only support 24 and 32
uint32_t Compression; // only support BI_Rgb
uint32_t RawDateSize; // can be zero
int32_t XPpm;
int32_t YPpm;
uint32_t PaletteLength;
uint32_t ImportantColorCount;
};
#pragma pack(pop)
enum BmpCompression
{
BI_Rgb,
BI_Rle8,
BI_Rle4,
BI_Bitfields,
BI_Jpeg,
BI_Png,
BI_AlphaBitfields,
BI_Cmyk = 11,
BI_CmykRle8,
BI_CmykRle4
};
template<typename T_COLOR_FEATURE, typename T_FILE_METHOD> class NeoBitmapFile
{
public:
NeoBitmapFile() :
_fileAddressPixels(0),
_width(0),
_height(0),
_sizeRow(0),
_bytesPerPixel(0),
_bottomToTop(true)
{
}
~NeoBitmapFile()
{
_file.close();
}
bool Begin(T_FILE_METHOD file)
{
if (_file)
{
_file.close();
}
if (!file || !file.seek(0))
{
goto error;
}
_file = file;
BitmapFileHeader bmpHeader;
BitmapInfoHeader bmpInfoHeader;
size_t result;
result = _file.read((uint8_t*)(&bmpHeader), sizeof(bmpHeader));
if (result != sizeof(bmpHeader) ||
bmpHeader.FileId != c_BitmapFileId ||
bmpHeader.FileSize != _file.size())
{
goto error;
}
result = _file.read((uint8_t*)(&bmpInfoHeader), sizeof(bmpInfoHeader));
if (result != sizeof(bmpInfoHeader) ||
result != bmpInfoHeader.Size ||
1 != bmpInfoHeader.Planes ||
BI_Rgb != bmpInfoHeader.Compression)
{
goto error;
}
if (!(24 == bmpInfoHeader.BitsPerPixel ||
32 == bmpInfoHeader.BitsPerPixel))
{
goto error;
}
// save the interesting information
_width = abs(bmpInfoHeader.Width);
_height = abs(bmpInfoHeader.Height);
_fileAddressPixels = bmpHeader.PixelAddress;
// negative height means rows are top to bottom
_bottomToTop = (bmpInfoHeader.Height > 0);
// rows are 32 bit aligned so they may have padding on each row
_sizeRow = (bmpInfoHeader.BitsPerPixel * _width + 31) / 32 * 4;
_bytesPerPixel = bmpInfoHeader.BitsPerPixel / 8;
return true;
error:
_fileAddressPixels = 0;
_width = 0;
_height = 0;
_sizeRow = 0;
_bytesPerPixel = 0;
_file.close();
return false;
};
size_t PixelSize() const
{
return T_COLOR_FEATURE::PixelSize;
};
uint16_t PixelCount() const
{
return _width * _height;
};
uint16_t Width() const
{
return _width;
};
uint16_t Height() const
{
return _height;
};
typename T_COLOR_FEATURE::ColorObject GetPixelColor(int16_t x, int16_t y)
{
if (x < 0 || x >= _width || y < 0 || y >= _height)
{
// Pixel # is out of bounds, this will get converted to a
// color object type initialized to 0 (black)
return 0;
}
typename T_COLOR_FEATURE::ColorObject color;
if (!seek(x, y) || !readPixel(&color))
{
return 0;
}
return color;
};
template <typename T_SHADER> void Render(NeoBufferContext<T_COLOR_FEATURE> destBuffer,
T_SHADER& shader,
uint16_t indexPixel,
int16_t xSrc,
int16_t ySrc,
int16_t wSrc)
{
const uint16_t destPixelCount = destBuffer.PixelCount();
typename T_COLOR_FEATURE::ColorObject color(0);
xSrc = constrainX(xSrc);
ySrc = constrainY(ySrc);
if (seek(xSrc, ySrc))
{
for (int16_t x = 0; x < wSrc && indexPixel < destPixelCount; x++, indexPixel++)
{
if ((uint16_t)xSrc < _width)
{
if (readPixel(&color))
{
color = shader.Apply(indexPixel, color);
xSrc++;
}
}
T_COLOR_FEATURE::applyPixelColor(destBuffer.Pixels, indexPixel, color);
}
}
}
void Blt(NeoBufferContext<T_COLOR_FEATURE> destBuffer,
uint16_t indexPixel,
int16_t xSrc,
int16_t ySrc,
int16_t wSrc)
{
NeoShaderNop<typename T_COLOR_FEATURE::ColorObject> shaderNop;
Render<NeoShaderNop<typename T_COLOR_FEATURE::ColorObject>>(destBuffer, shaderNop, indexPixel, xSrc, ySrc, wSrc);
};
template <typename T_SHADER> void Render(NeoBufferContext<T_COLOR_FEATURE> destBuffer,
T_SHADER& shader,
int16_t xDest,
int16_t yDest,
int16_t xSrc,
int16_t ySrc,
int16_t wSrc,
int16_t hSrc,
LayoutMapCallback layoutMap)
{
const uint16_t destPixelCount = destBuffer.PixelCount();
typename T_COLOR_FEATURE::ColorObject color(0);
for (int16_t y = 0; y < hSrc; y++)
{
int16_t xFile = constrainX(xSrc);
int16_t yFile = constrainY(ySrc + y);
if (seek(xFile, yFile))
{
for (int16_t x = 0; x < wSrc; x++)
{
uint16_t indexDest = layoutMap(xDest + x, yDest + y);
if ((uint16_t)xFile < _width)
{
if (readPixel(&color))
{
color = shader.Apply(indexDest, color);
xFile++;
}
}
if (indexDest < destPixelCount)
{
T_COLOR_FEATURE::applyPixelColor(destBuffer.Pixels, indexDest, color);
}
}
}
}
};
void Blt(NeoBufferContext<T_COLOR_FEATURE> destBuffer,
int16_t xDest,
int16_t yDest,
int16_t xSrc,
int16_t ySrc,
int16_t wSrc,
int16_t hSrc,
LayoutMapCallback layoutMap)
{
NeoShaderNop<typename T_COLOR_FEATURE::ColorObject> shaderNop;
Render<NeoShaderNop<typename T_COLOR_FEATURE::ColorObject>>(destBuffer,
shaderNop,
xDest,
yDest,
xSrc,
ySrc,
wSrc,
hSrc,
layoutMap);
};
private:
T_FILE_METHOD _file;
uint32_t _fileAddressPixels;
uint16_t _width;
uint16_t _height;
uint32_t _sizeRow;
uint8_t _bytesPerPixel;
bool _bottomToTop;
int16_t constrainX(int16_t x) const
{
if (x < 0)
{
x = 0;
}
else if ((uint16_t)x >= _width)
{
x = _width - 1;
}
return x;
};
int16_t constrainY(int16_t y) const
{
if (y < 0)
{
y = 0;
}
else if ((uint16_t)y >= _height)
{
y = _height - 1;
}
return y;
};
bool seek(int16_t x, int16_t y)
{
if (_bottomToTop)
{
y = (_height - 1) - y;
}
uint32_t pos = y * _sizeRow + x * _bytesPerPixel;
pos += _fileAddressPixels;
return _file.seek(pos);
};
bool readPixel(RgbColor* color)
{
uint8_t bgr[4];
int result;
result = _file.read(bgr, _bytesPerPixel);
if (result != _bytesPerPixel)
{
*color = 0;
return false;
}
color->B = bgr[0];
color->G = bgr[1];
color->R = bgr[2];
return true;
};
bool readPixel(RgbwColor* color)
{
uint8_t bgr[4];
int result;
bgr[3] = 0; // init white channel as read maybe only 3 bytes
result = _file.read(bgr, _bytesPerPixel);
if (result != _bytesPerPixel)
{
*color = 0;
return false;
}
color->B = bgr[0];
color->G = bgr[1];
color->R = bgr[2];
color->W = bgr[3];
return true;
};
};

View File

@@ -0,0 +1,173 @@
/*-------------------------------------------------------------------------
NeoPixel library
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
template<typename T_BUFFER_METHOD> class NeoBuffer
{
public:
NeoBuffer(uint16_t width,
uint16_t height,
PGM_VOID_P pixels) :
_method(width, height, pixels)
{
}
operator NeoBufferContext<typename T_BUFFER_METHOD::ColorFeature>()
{
return _method;
}
uint16_t PixelCount() const
{
return _method.PixelCount();
};
uint16_t Width() const
{
return _method.Width();
};
uint16_t Height() const
{
return _method.Height();
};
void SetPixelColor(
int16_t x,
int16_t y,
typename T_BUFFER_METHOD::ColorObject color)
{
_method.SetPixelColor(pixelIndex(x, y), color);
};
typename T_BUFFER_METHOD::ColorObject GetPixelColor(
int16_t x,
int16_t y) const
{
return _method.GetPixelColor(pixelIndex(x, y));
};
void ClearTo(typename T_BUFFER_METHOD::ColorObject color)
{
_method.ClearTo(color);
};
void Blt(NeoBufferContext<typename T_BUFFER_METHOD::ColorFeature> destBuffer,
uint16_t indexPixel)
{
uint16_t destPixelCount = destBuffer.PixelCount();
// validate indexPixel
if (indexPixel >= destPixelCount)
{
return;
}
// calc how many we can copy
uint16_t copyCount = destPixelCount - indexPixel;
uint16_t srcPixelCount = PixelCount();
if (copyCount > srcPixelCount)
{
copyCount = srcPixelCount;
}
uint8_t* pDest = T_BUFFER_METHOD::ColorFeature::getPixelAddress(destBuffer.Pixels, indexPixel);
_method.CopyPixels(pDest, _method.Pixels(), copyCount);
}
void Blt(NeoBufferContext<typename T_BUFFER_METHOD::ColorFeature> destBuffer,
int16_t xDest,
int16_t yDest,
int16_t xSrc,
int16_t ySrc,
int16_t wSrc,
int16_t hSrc,
LayoutMapCallback layoutMap)
{
uint16_t destPixelCount = destBuffer.PixelCount();
for (int16_t y = 0; y < hSrc; y++)
{
for (int16_t x = 0; x < wSrc; x++)
{
uint16_t indexDest = layoutMap(xDest + x, yDest + y);
if (indexDest < destPixelCount)
{
const uint8_t* pSrc = T_BUFFER_METHOD::ColorFeature::getPixelAddress(_method.Pixels(), pixelIndex(xSrc + x, ySrc + y));
uint8_t* pDest = T_BUFFER_METHOD::ColorFeature::getPixelAddress(destBuffer.Pixels, indexDest);
_method.CopyPixels(pDest, pSrc, 1);
}
}
}
}
void Blt(NeoBufferContext<typename T_BUFFER_METHOD::ColorFeature> destBuffer,
int16_t xDest,
int16_t yDest,
LayoutMapCallback layoutMap)
{
Blt(destBuffer, xDest, yDest, 0, 0, Width(), Height(), layoutMap);
}
template <typename T_SHADER> void Render(NeoBufferContext<typename T_BUFFER_METHOD::ColorFeature> destBuffer, T_SHADER& shader)
{
uint16_t countPixels = destBuffer.PixelCount();
if (countPixels > _method.PixelCount())
{
countPixels = _method.PixelCount();
}
for (uint16_t indexPixel = 0; indexPixel < countPixels; indexPixel++)
{
typename T_BUFFER_METHOD::ColorObject color;
shader.Apply(indexPixel, (uint8_t*)(&color), _method.Pixels() + (indexPixel * _method.PixelSize()));
T_BUFFER_METHOD::ColorFeature::applyPixelColor(destBuffer.Pixels, indexPixel, color);
}
}
private:
T_BUFFER_METHOD _method;
uint16_t pixelIndex(
int16_t x,
int16_t y) const
{
uint16_t result = PixelIndex_OutOfBounds;
if (x >= 0 &&
(uint16_t)x < Width() &&
y >= 0 &&
(uint16_t)y < Height())
{
result = x + y * Width();
}
return result;
}
};

View File

@@ -0,0 +1,48 @@
/*-------------------------------------------------------------------------
NeoPixel library
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
// This is used to allow a template classes that share common buffer concept to
// be able to pass that common information to functions
// The template classes just need to expose a conversion operator to this type
template <typename T_COLOR_FEATURE> struct NeoBufferContext
{
NeoBufferContext(uint8_t* pixels,
size_t sizePixels) :
Pixels(pixels),
SizePixels(sizePixels)
{
}
uint16_t PixelCount() const
{
return SizePixels / T_COLOR_FEATURE::PixelSize;
};
uint8_t* Pixels;
const size_t SizePixels;
};

View File

@@ -0,0 +1,263 @@
/*-------------------------------------------------------------------------
NeoPixel library
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
#if defined(NEOPIXEBUS_NO_STL)
typedef uint16_t(*LayoutMapCallback)(int16_t x, int16_t y);
#else
#undef max
#undef min
#include <functional>
typedef std::function<uint16_t(int16_t x, int16_t y)> LayoutMapCallback;
#endif
template<typename T_COLOR_FEATURE> class NeoBufferMethod
{
public:
NeoBufferMethod(uint16_t width, uint16_t height, PGM_VOID_P pixels = NULL) :
_width(width),
_height(height)
{
_pixels = (uint8_t*)malloc(PixelsSize());
if (pixels)
{
// copy from progmem to initialize
T_COLOR_FEATURE::movePixelsInc_P(_pixels, pixels, PixelCount());
}
}
~NeoBufferMethod()
{
free(_pixels);
}
operator NeoBufferContext<T_COLOR_FEATURE>()
{
return NeoBufferContext<T_COLOR_FEATURE>(Pixels(), PixelsSize());
}
uint8_t* Pixels() const
{
return _pixels;
};
size_t PixelsSize() const
{
return PixelSize() * PixelCount();
};
size_t PixelSize() const
{
return T_COLOR_FEATURE::PixelSize;
};
uint16_t PixelCount() const
{
return _width * _height;
};
uint16_t Width() const
{
return _width;
};
uint16_t Height() const
{
return _height;
};
void SetPixelColor(uint16_t indexPixel, typename T_COLOR_FEATURE::ColorObject color)
{
if (indexPixel < PixelCount())
{
T_COLOR_FEATURE::applyPixelColor(_pixels, indexPixel, color);
}
};
void SetPixelColor(int16_t x, int16_t y, typename T_COLOR_FEATURE::ColorObject color)
{
if (x < 0 || x >= _width || y < 0 || y >= _height)
{
return;
}
uint16_t indexPixel = x + y * _width;
T_COLOR_FEATURE::applyPixelColor(_pixels, indexPixel, color);
};
typename T_COLOR_FEATURE::ColorObject GetPixelColor(uint16_t indexPixel) const
{
if (indexPixel >= PixelCount())
{
// Pixel # is out of bounds, this will get converted to a
// color object type initialized to 0 (black)
return 0;
}
return T_COLOR_FEATURE::retrievePixelColor(_pixels, indexPixel);
};
typename T_COLOR_FEATURE::ColorObject GetPixelColor(int16_t x, int16_t y) const
{
if (x < 0 || x >= _width || y < 0 || y >= _height)
{
// Pixel # is out of bounds, this will get converted to a
// color object type initialized to 0 (black)
return 0;
}
uint16_t indexPixel = x + y * _width;
return T_COLOR_FEATURE::retrievePixelColor(_pixels, indexPixel);
};
void ClearTo(typename T_COLOR_FEATURE::ColorObject color)
{
uint8_t temp[T_COLOR_FEATURE::PixelSize];
T_COLOR_FEATURE::applyPixelColor(temp, 0, color);
T_COLOR_FEATURE::replicatePixel(_pixels, temp, PixelCount());
};
void CopyPixels(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count)
{
T_COLOR_FEATURE::movePixelsInc(pPixelDest, pPixelSrc, count);
}
typedef typename T_COLOR_FEATURE::ColorObject ColorObject;
typedef T_COLOR_FEATURE ColorFeature;
private:
const uint16_t _width;
const uint16_t _height;
uint8_t* _pixels;
};
template<typename T_COLOR_FEATURE> class NeoBufferProgmemMethod
{
public:
NeoBufferProgmemMethod(uint16_t width, uint16_t height, PGM_VOID_P pixels) :
_width(width),
_height(height),
_pixels(pixels)
{
}
operator NeoBufferContext<T_COLOR_FEATURE>()
{
return NeoBufferContext<T_COLOR_FEATURE>(Pixels(), PixelsSize());
}
uint8_t* Pixels() const
{
return (uint8_t*)_pixels;
};
size_t PixelsSize() const
{
return PixelSize() * PixelCount();
};
size_t PixelSize() const
{
return T_COLOR_FEATURE::PixelSize;
};
uint16_t PixelCount() const
{
return _width * _height;
};
uint16_t Width() const
{
return _width;
};
uint16_t Height() const
{
return _height;
};
void SetPixelColor(uint16_t indexPixel, typename T_COLOR_FEATURE::ColorObject color)
{
// PROGMEM is read only, this will do nothing
};
void SetPixelColor(uint16_t x, uint16_t y, typename T_COLOR_FEATURE::ColorObject color)
{
// PROGMEM is read only, this will do nothing
};
typename T_COLOR_FEATURE::ColorObject GetPixelColor(uint16_t indexPixel) const
{
if (indexPixel >= PixelCount())
{
// Pixel # is out of bounds, this will get converted to a
// color object type initialized to 0 (black)
return 0;
}
return T_COLOR_FEATURE::retrievePixelColor_P(_pixels, indexPixel);
};
typename T_COLOR_FEATURE::ColorObject GetPixelColor(int16_t x, int16_t y) const
{
if (x < 0 || x >= _width || y < 0 || y >= _height)
{
// Pixel # is out of bounds, this will get converted to a
// color object type initialized to 0 (black)
return 0;
}
uint16_t indexPixel = x + y * _width;
return T_COLOR_FEATURE::retrievePixelColor_P(_pixels, indexPixel);
};
void ClearTo(typename T_COLOR_FEATURE::ColorObject color)
{
// PROGMEM is read only, this will do nothing
};
void CopyPixels(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count)
{
T_COLOR_FEATURE::movePixelsInc_P(pPixelDest, pPixelSrc, count);
}
typedef typename T_COLOR_FEATURE::ColorObject ColorObject;
typedef T_COLOR_FEATURE ColorFeature;
private:
const uint16_t _width;
const uint16_t _height;
PGM_VOID_P _pixels;
};

View File

@@ -0,0 +1,427 @@
/*-------------------------------------------------------------------------
NeoColorFeatures provides feature classes to describe color order and
color depth 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 Neo3Elements
{
public:
static const size_t PixelSize = 3;
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 RgbColor ColorObject;
};
class Neo4Elements
{
public:
static const size_t PixelSize = 4;
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)
{
uint32_t* pDest = (uint32_t*)pPixelDest;
const uint32_t* pSrc = (const uint32_t*)pPixelSrc;
uint32_t* pEnd = pDest + count;
while (pDest < pEnd)
{
*pDest++ = *pSrc;
}
}
static void movePixelsInc(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count)
{
uint32_t* pDest = (uint32_t*)pPixelDest;
const uint32_t* pSrc = (uint32_t*)pPixelSrc;
uint32_t* pEnd = pDest + count;
while (pDest < pEnd)
{
*pDest++ = *pSrc++;
}
}
static void movePixelsInc_P(uint8_t* pPixelDest, PGM_VOID_P pPixelSrc, uint16_t count)
{
uint32_t* pDest = (uint32_t*)pPixelDest;
const uint32_t* pSrc = (const uint32_t*)pPixelSrc;
uint32_t* pEnd = pDest + count;
while (pDest < pEnd)
{
*pDest++ = pgm_read_dword(pSrc++);
}
}
static void movePixelsDec(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count)
{
uint32_t* pDest = (uint32_t*)pPixelDest;
const uint32_t* pSrc = (uint32_t*)pPixelSrc;
uint32_t* pDestBack = pDest + count;
const uint32_t* pSrcBack = pSrc + count;
while (pDestBack > pDest)
{
*--pDestBack = *--pSrcBack;
}
}
typedef RgbwColor ColorObject;
};
class Neo3ElementsNoSettings : public Neo3Elements
{
public:
typedef NeoNoSettings SettingsObject;
static const size_t SettingsSize = 0;
static void applySettings(uint8_t*, const SettingsObject&)
{
}
static uint8_t* pixels(uint8_t* pData)
{
return pData;
}
static const uint8_t* pixels(const uint8_t* pData)
{
return pData;
}
};
class Neo4ElementsNoSettings : public Neo4Elements
{
public:
typedef NeoNoSettings SettingsObject;
static const size_t SettingsSize = 0;
static void applySettings(uint8_t*, const SettingsObject&)
{
}
static uint8_t* pixels(uint8_t* pData)
{
return pData;
}
static const uint8_t* pixels(const uint8_t* pData)
{
return pData;
}
};
class NeoGrbFeature : public Neo3ElementsNoSettings
{
public:
static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color)
{
uint8_t* p = getPixelAddress(pPixels, indexPixel);
*p++ = color.G;
*p++ = color.R;
*p = color.B;
}
static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel)
{
ColorObject color;
const uint8_t* p = getPixelAddress(pPixels, indexPixel);
color.G = *p++;
color.R = *p++;
color.B = *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);
color.G = pgm_read_byte(p++);
color.R = pgm_read_byte(p++);
color.B = pgm_read_byte(p);
return color;
}
};
class NeoGrbwFeature : public Neo4ElementsNoSettings
{
public:
static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color)
{
uint8_t* p = getPixelAddress(pPixels, indexPixel);
*p++ = color.G;
*p++ = color.R;
*p++ = color.B;
*p = color.W;
}
static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel)
{
ColorObject color;
const uint8_t* p = getPixelAddress(pPixels, indexPixel);
color.G = *p++;
color.R = *p++;
color.B = *p++;
color.W = *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);
color.G = pgm_read_byte(p++);
color.R = pgm_read_byte(p++);
color.B = pgm_read_byte(p++);
color.W = pgm_read_byte(p);
return color;
}
};
class NeoRgbwFeature : public Neo4ElementsNoSettings
{
public:
static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color)
{
uint8_t* p = getPixelAddress(pPixels, indexPixel);
*p++ = color.R;
*p++ = color.G;
*p++ = color.B;
*p = color.W;
}
static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel)
{
ColorObject color;
const uint8_t* p = getPixelAddress(pPixels, indexPixel);
color.R = *p++;
color.G = *p++;
color.B = *p++;
color.W = *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);
color.R = pgm_read_byte(p++);
color.G = pgm_read_byte(p++);
color.B = pgm_read_byte(p++);
color.W = pgm_read_byte(p);
return color;
}
};
class NeoRgbFeature : public Neo3ElementsNoSettings
{
public:
static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color)
{
uint8_t* p = getPixelAddress(pPixels, indexPixel);
*p++ = color.R;
*p++ = color.G;
*p = color.B;
}
static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel)
{
ColorObject color;
const uint8_t* p = getPixelAddress(pPixels, indexPixel);
color.R = *p++;
color.G = *p++;
color.B = *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);
color.R = pgm_read_byte(p++);
color.G = pgm_read_byte(p++);
color.B = pgm_read_byte(p);
return color;
}
};
class NeoBrgFeature : public Neo3ElementsNoSettings
{
public:
static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color)
{
uint8_t* p = getPixelAddress(pPixels, indexPixel);
*p++ = color.B;
*p++ = color.R;
*p = color.G;
}
static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel)
{
ColorObject color;
const uint8_t* p = getPixelAddress(pPixels, indexPixel);
color.B = *p++;
color.R = *p++;
color.G = *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);
color.B = pgm_read_byte(p++);
color.R = pgm_read_byte(p++);
color.G = pgm_read_byte(p);
return color;
}
};
class NeoRbgFeature : public Neo3ElementsNoSettings
{
public:
static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color)
{
uint8_t* p = getPixelAddress(pPixels, indexPixel);
*p++ = color.R;
*p++ = color.B;
*p = color.G;
}
static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel)
{
ColorObject color;
const uint8_t* p = getPixelAddress(pPixels, indexPixel);
color.R = *p++;
color.B = *p++;
color.G = *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);
color.R = pgm_read_byte(p++);
color.B = pgm_read_byte(p++);
color.G = pgm_read_byte(p);
return color;
}
};

View File

@@ -0,0 +1,208 @@
/*-------------------------------------------------------------------------
NeoPixel library
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
template<typename T_COLOR_OBJECT> class NeoShaderNop
{
public:
NeoShaderNop()
{
}
bool IsDirty() const
{
return true;
};
void Dirty()
{
};
void ResetDirty()
{
};
T_COLOR_OBJECT Apply(uint16_t, T_COLOR_OBJECT color)
{
return color;
};
};
class NeoShaderBase
{
public:
NeoShaderBase() :
_state(0)
{
}
bool IsDirty() const
{
return (_state & NEO_DIRTY);
};
void Dirty()
{
_state |= NEO_DIRTY;
};
void ResetDirty()
{
_state &= ~NEO_DIRTY;
};
protected:
uint8_t _state; // internal state
};
template<typename T_COLOR_OBJECT> class NeoDib
{
public:
NeoDib(uint16_t countPixels) :
_countPixels(countPixels),
_state(0)
{
_pixels = (T_COLOR_OBJECT*)malloc(PixelsSize());
ResetDirty();
}
~NeoDib()
{
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;
};
uint16_t PixelCount() const
{
return _countPixels;
};
size_t PixelsSize() const
{
return _countPixels * PixelSize();
};
size_t PixelSize() const
{
return sizeof(T_COLOR_OBJECT);
};
void SetPixelColor(
uint16_t indexPixel,
T_COLOR_OBJECT color)
{
if (indexPixel < PixelCount())
{
_pixels[indexPixel] = color;
Dirty();
}
};
T_COLOR_OBJECT GetPixelColor(
uint16_t indexPixel) const
{
if (indexPixel >= PixelCount())
{
return 0;
}
return _pixels[indexPixel];
};
void ClearTo(T_COLOR_OBJECT color)
{
for (uint16_t pixel = 0; pixel < PixelCount(); pixel++)
{
_pixels[pixel] = color;
}
Dirty();
};
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())
{
uint16_t countPixels = destBuffer.PixelCount();
if (countPixels > _countPixels)
{
countPixels = _countPixels;
}
for (uint16_t indexPixel = 0; indexPixel < countPixels; indexPixel++)
{
T_COLOR_OBJECT color = shader.Apply(indexPixel, _pixels[indexPixel]);
T_COLOR_FEATURE::applyPixelColor(destBuffer.Pixels, destIndexPixel + indexPixel, color);
}
shader.ResetDirty();
ResetDirty();
}
}
bool IsDirty() const
{
return (_state & NEO_DIRTY);
};
void Dirty()
{
_state |= NEO_DIRTY;
};
void ResetDirty()
{
_state &= ~NEO_DIRTY;
};
private:
const uint16_t _countPixels; // Number of RGB LEDs in strip
T_COLOR_OBJECT* _pixels;
uint8_t _state; // internal state
};

View File

@@ -0,0 +1,313 @@
/*-------------------------------------------------------------------------
NeoEase provides animation curve equations for animation support.
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
#if defined(NEOPIXEBUS_NO_STL)
typedef float(*AnimEaseFunction)(float unitValue);
#else
#undef max
#undef min
#include <functional>
typedef std::function<float(float unitValue)> AnimEaseFunction;
#endif
class NeoEase
{
public:
static float Linear(float unitValue)
{
return unitValue;
}
static float QuadraticIn(float unitValue)
{
return unitValue * unitValue;
}
static float QuadraticOut(float unitValue)
{
return (-unitValue * (unitValue - 2.0f));
}
static float QuadraticInOut(float unitValue)
{
unitValue *= 2.0f;
if (unitValue < 1.0f)
{
return (0.5f * unitValue * unitValue);
}
else
{
unitValue -= 1.0f;
return (-0.5f * (unitValue * (unitValue - 2.0f) - 1.0f));
}
}
static float QuadraticCenter(float unitValue)
{
unitValue *= 2.0f;
if (unitValue < 1.0f)
{
return (-0.5f * (unitValue * unitValue - 2.0f));
}
else
{
unitValue -= 1.0f;
return (0.5f * (unitValue * unitValue + 1.0f));
}
}
static float CubicIn(float unitValue)
{
return (unitValue * unitValue * unitValue);
}
static float CubicOut(float unitValue)
{
unitValue -= 1.0f;
return (unitValue * unitValue * unitValue + 1.0f);
}
static float CubicInOut(float unitValue)
{
unitValue *= 2.0f;
if (unitValue < 1.0f)
{
return (0.5f * unitValue * unitValue * unitValue);
}
else
{
unitValue -= 2.0f;
return (0.5f * (unitValue * unitValue * unitValue + 2.0f));
}
}
static float CubicCenter(float unitValue)
{
unitValue *= 2.0f;
unitValue -= 1.0f;
return (0.5f * (unitValue * unitValue * unitValue + 1.0f));
}
static float QuarticIn(float unitValue)
{
return (unitValue * unitValue * unitValue * unitValue);
}
static float QuarticOut(float unitValue)
{
unitValue -= 1.0f;
return -(unitValue * unitValue * unitValue * unitValue - 1.0f);
}
static float QuarticInOut(float unitValue)
{
unitValue *= 2.0f;
if (unitValue < 1.0f)
{
return (0.5f * unitValue * unitValue * unitValue * unitValue);
}
else
{
unitValue -= 2.0f;
return (-0.5f * (unitValue * unitValue * unitValue * unitValue - 2.0f));
}
}
static float QuarticCenter(float unitValue)
{
unitValue *= 2.0f;
unitValue -= 1.0f;
if (unitValue < 0.0f)
{
return (-0.5f * (unitValue * unitValue * unitValue * unitValue - 1.0f));
}
else
{
return (0.5f * (unitValue * unitValue * unitValue * unitValue + 1.0f));
}
}
static float QuinticIn(float unitValue)
{
return (unitValue * unitValue * unitValue * unitValue * unitValue);
}
static float QuinticOut(float unitValue)
{
unitValue -= 1.0f;
return (unitValue * unitValue * unitValue * unitValue * unitValue + 1.0f);
}
static float QuinticInOut(float unitValue)
{
unitValue *= 2.0f;
if (unitValue < 1.0f)
{
return (0.5f * unitValue * unitValue * unitValue * unitValue * unitValue);
}
else
{
unitValue -= 2.0f;
return (0.5f * (unitValue * unitValue * unitValue * unitValue * unitValue + 2.0f));
}
}
static float QuinticCenter(float unitValue)
{
unitValue *= 2.0f;
unitValue -= 1.0f;
return (0.5f * (unitValue * unitValue * unitValue * unitValue * unitValue + 1.0f));
}
static float SinusoidalIn(float unitValue)
{
return (-cos(unitValue * HALF_PI) + 1.0f);
}
static float SinusoidalOut(float unitValue)
{
return (sin(unitValue * HALF_PI));
}
static float SinusoidalInOut(float unitValue)
{
return -0.5f * (cos(PI * unitValue) - 1.0f);
}
static float SinusoidalCenter(float unitValue)
{
if (unitValue < 0.5f)
{
return (0.5f * sin(PI * unitValue));
}
else
{
return (-0.5f * (cos(PI * (unitValue-0.5f)) + 1.0f));
}
}
static float ExponentialIn(float unitValue)
{
return (pow(2, 10.0f * (unitValue - 1.0f)));
}
static float ExponentialOut(float unitValue)
{
return (-pow(2, -10.0f * unitValue) + 1.0f);
}
static float ExponentialInOut(float unitValue)
{
unitValue *= 2.0f;
if (unitValue < 1.0f)
{
return (0.5f * pow(2, 10.0f * (unitValue - 1.0f)));
}
else
{
unitValue -= 1.0f;
return (0.5f * (-pow(2, -10.0f * unitValue) + 2.0f));
}
}
static float ExponentialCenter(float unitValue)
{
unitValue *= 2.0f;
if (unitValue < 1.0f)
{
return (0.5f * (-pow(2, -10.0f * unitValue) + 1.0f));
}
else
{
unitValue -= 2.0f;
return (0.5f * (pow(2, 10.0f * unitValue) + 1.0f));
}
}
static float CircularIn(float unitValue)
{
if (unitValue == 1.0f)
{
return 1.0f;
}
else
{
return (-(sqrt(1.0f - unitValue * unitValue) - 1.0f));
}
}
static float CircularOut(float unitValue)
{
unitValue -= 1.0f;
return (sqrt(1.0f - unitValue * unitValue));
}
static float CircularInOut(float unitValue)
{
unitValue *= 2.0f;
if (unitValue < 1.0f)
{
return (-0.5f * (sqrt(1.0f - unitValue * unitValue) - 1.0f));
}
else
{
unitValue -= 2.0f;
return (0.5f * (sqrt(1.0f - unitValue * unitValue) + 1.0f));
}
}
static float CircularCenter(float unitValue)
{
unitValue *= 2.0f;
unitValue -= 1.0f;
if (unitValue < 0.0f)
{
return (0.5f * sqrt(1.0f - unitValue * unitValue));
}
else if (unitValue > 0.0f)
{
unitValue -= 2.0f;
return (-0.5f * (sqrt(1.0f - unitValue * unitValue) - 1.0f ) + 0.5f);
}
else
{
return 1.0f;
}
}
static float Gamma(float unitValue)
{
return pow(unitValue, 1.0f / 0.45f);
}
};

View File

@@ -0,0 +1,276 @@
/*-------------------------------------------------------------------------
NeoPixel library helper functions for Esp32.
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
#ifdef ARDUINO_ARCH_ESP32
extern "C"
{
#include <Arduino.h>
#include "Esp32_i2s.h"
}
const uint16_t c_dmaBytesPerPixelBytes = 4;
class NeoEsp32I2sSpeedWs2812x
{
public:
const static uint32_t I2sSampleRate = 100000;
const static uint16_t ByteSendTimeUs = 10;
const static uint16_t ResetTimeUs = 300;
};
class NeoEsp32I2sSpeedSk6812
{
public:
const static uint32_t I2sSampleRate = 100000;
const static uint16_t ByteSendTimeUs = 10;
const static uint16_t ResetTimeUs = 80;
};
class NeoEsp32I2sSpeedTm1814
{
public:
const static uint32_t I2sSampleRate = 100000;
const static uint16_t ByteSendTimeUs = 10;
const static uint16_t ResetTimeUs = 200;
};
class NeoEsp32I2sSpeed800Kbps
{
public:
const static uint32_t I2sSampleRate = 100000;
const static uint16_t ByteSendTimeUs = 10;
const static uint16_t ResetTimeUs = 50;
};
class NeoEsp32I2sSpeed400Kbps
{
public:
const static uint32_t I2sSampleRate = 50000;
const static uint16_t ByteSendTimeUs = 20;
const static uint16_t ResetTimeUs = 50;
};
class NeoEsp32I2sSpeedApa106
{
public:
const static uint32_t I2sSampleRate = 76000;
const static uint16_t ByteSendTimeUs = 14;
const static uint16_t ResetTimeUs = 50;
};
class NeoEsp32I2sBusZero
{
public:
const static uint8_t I2sBusNumber = 0;
};
class NeoEsp32I2sBusOne
{
public:
const static uint8_t I2sBusNumber = 1;
};
class NeoEsp32I2sNotInverted
{
public:
const static bool Inverted = false;
};
class NeoEsp32I2sInverted
{
public:
const static bool Inverted = true;
};
template<typename T_SPEED, typename T_BUS, typename T_INVERT> class NeoEsp32I2sMethodBase
{
public:
NeoEsp32I2sMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize) :
_sizeData(pixelCount * elementSize + settingsSize),
_pin(pin)
{
uint16_t dmaSettingsSize = c_dmaBytesPerPixelBytes * settingsSize;
uint16_t dmaPixelSize = c_dmaBytesPerPixelBytes * elementSize;
uint16_t resetSize = c_dmaBytesPerPixelBytes * T_SPEED::ResetTimeUs / T_SPEED::ByteSendTimeUs;
_i2sBufferSize = pixelCount * dmaPixelSize + dmaSettingsSize + resetSize;
// must have a 4 byte aligned buffer for i2s
uint32_t alignment = _i2sBufferSize % 4;
if (alignment)
{
_i2sBufferSize += 4 - alignment;
}
_data = static_cast<uint8_t*>(malloc(_sizeData));
memset(_data, 0x00, _sizeData);
_i2sBuffer = static_cast<uint8_t*>(malloc(_i2sBufferSize));
memset(_i2sBuffer, 0x00, _i2sBufferSize);
}
~NeoEsp32I2sMethodBase()
{
while (!IsReadyToUpdate())
{
yield();
}
pinMode(_pin, INPUT);
free(_data);
free(_i2sBuffer);
}
bool IsReadyToUpdate() const
{
return (i2sWriteDone(T_BUS::I2sBusNumber));
}
void Initialize()
{
size_t dmaCount = (_i2sBufferSize + I2S_DMA_MAX_DATA_LEN - 1) / I2S_DMA_MAX_DATA_LEN;
i2sInit(T_BUS::I2sBusNumber, 16, T_SPEED::I2sSampleRate, I2S_CHAN_STEREO, I2S_FIFO_16BIT_DUAL, dmaCount, 0);
i2sSetPins(T_BUS::I2sBusNumber, _pin, T_INVERT::Inverted);
}
void Update(bool)
{
// wait for not actively sending data
while (!IsReadyToUpdate())
{
yield();
}
FillBuffers();
i2sWrite(T_BUS::I2sBusNumber, _i2sBuffer, _i2sBufferSize, false, false);
}
uint8_t* getData() const
{
return _data;
};
size_t getDataSize() const
{
return _sizeData;
}
private:
const size_t _sizeData; // Size of '_data' buffer
const uint8_t _pin; // output pin number
uint8_t* _data; // Holds LED color values
uint32_t _i2sBufferSize; // total size of _i2sBuffer
uint8_t* _i2sBuffer; // holds the DMA buffer that is referenced by _i2sBufDesc
void FillBuffers()
{
const uint16_t bitpatterns[16] =
{
0b1000100010001000, 0b1000100010001110, 0b1000100011101000, 0b1000100011101110,
0b1000111010001000, 0b1000111010001110, 0b1000111011101000, 0b1000111011101110,
0b1110100010001000, 0b1110100010001110, 0b1110100011101000, 0b1110100011101110,
0b1110111010001000, 0b1110111010001110, 0b1110111011101000, 0b1110111011101110,
};
uint16_t* pDma = reinterpret_cast<uint16_t*>(_i2sBuffer);
uint8_t* pEnd = _data + _sizeData;
for (uint8_t* pPixel = _data; pPixel < pEnd; pPixel++)
{
*(pDma++) = bitpatterns[((*pPixel) & 0x0f)];
*(pDma++) = bitpatterns[((*pPixel) >> 4) & 0x0f];
}
}
};
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeedWs2812x, NeoEsp32I2sBusZero, NeoEsp32I2sNotInverted> NeoEsp32I2s0Ws2812xMethod;
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeedSk6812, NeoEsp32I2sBusZero, NeoEsp32I2sNotInverted> NeoEsp32I2s0Sk6812Method;
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeedTm1814, NeoEsp32I2sBusZero, NeoEsp32I2sInverted> NeoEsp32I2s0Tm1814Method;
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeed800Kbps, NeoEsp32I2sBusZero, NeoEsp32I2sNotInverted> NeoEsp32I2s0800KbpsMethod;
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeed400Kbps, NeoEsp32I2sBusZero, NeoEsp32I2sNotInverted> NeoEsp32I2s0400KbpsMethod;
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeedApa106, NeoEsp32I2sBusZero, NeoEsp32I2sNotInverted> NeoEsp32I2s0Apa106Method;
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeedWs2812x, NeoEsp32I2sBusZero, NeoEsp32I2sInverted> NeoEsp32I2s0Ws2812xInvertedMethod;
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeedSk6812, NeoEsp32I2sBusZero, NeoEsp32I2sInverted> NeoEsp32I2s0Sk6812InvertedMethod;
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeedTm1814, NeoEsp32I2sBusZero, NeoEsp32I2sNotInverted> NeoEsp32I2s0Tm1814InvertedMethod;
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeed800Kbps, NeoEsp32I2sBusZero, NeoEsp32I2sInverted> NeoEsp32I2s0800KbpsInvertedMethod;
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeed400Kbps, NeoEsp32I2sBusZero, NeoEsp32I2sInverted> NeoEsp32I2s0400KbpsInvertedMethod;
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeedApa106, NeoEsp32I2sBusZero, NeoEsp32I2sInverted> NeoEsp32I2s0Apa106InvertedMethod;
#if !defined(CONFIG_IDF_TARGET_ESP32S2)
// (I2S_NUM_MAX == 2)
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeedWs2812x, NeoEsp32I2sBusOne, NeoEsp32I2sNotInverted> NeoEsp32I2s1Ws2812xMethod;
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeedSk6812, NeoEsp32I2sBusOne, NeoEsp32I2sNotInverted> NeoEsp32I2s1Sk6812Method;
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeedTm1814, NeoEsp32I2sBusOne, NeoEsp32I2sInverted> NeoEsp32I2s1Tm1814Method;
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeed800Kbps, NeoEsp32I2sBusOne, NeoEsp32I2sNotInverted> NeoEsp32I2s1800KbpsMethod;
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeed400Kbps, NeoEsp32I2sBusOne, NeoEsp32I2sNotInverted> NeoEsp32I2s1400KbpsMethod;
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeedApa106, NeoEsp32I2sBusOne, NeoEsp32I2sNotInverted> NeoEsp32I2s1Apa106Method;
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeedWs2812x, NeoEsp32I2sBusOne, NeoEsp32I2sInverted> NeoEsp32I2s1Ws2812xInvertedMethod;
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeedSk6812, NeoEsp32I2sBusOne, NeoEsp32I2sInverted> NeoEsp32I2s1Sk6812InvertedMethod;
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeedTm1814, NeoEsp32I2sBusOne, NeoEsp32I2sNotInverted> NeoEsp32I2s1Tm1814InvertedMethod;
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeed800Kbps, NeoEsp32I2sBusOne, NeoEsp32I2sInverted> NeoEsp32I2s1800KbpsInvertedMethod;
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeed400Kbps, NeoEsp32I2sBusOne, NeoEsp32I2sInverted> NeoEsp32I2s1400KbpsInvertedMethod;
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeedApa106, NeoEsp32I2sBusOne, NeoEsp32I2sInverted> NeoEsp32I2s1Apa106InvertedMethod;
#endif
/* due to a core issue where requests to send aren't consistent, I2s is no longer the default
// I2s Bus 1 method is the default method for Esp32
typedef NeoEsp32I2s1Ws2812xMethod NeoWs2813Method;
typedef NeoEsp32I2s1Ws2812xMethod NeoWs2812xMethod;
typedef NeoEsp32I2s1800KbpsMethod NeoWs2812Method;
typedef NeoEsp32I2s1Ws2812xMethod NeoWs2811Method;
typedef NeoEsp32I2s1Sk6812Method NeoSk6812Method;
typedef NeoEsp32I2s1Tm1814Method NeoTm1814Method;
typedef NeoEsp32I2s1Sk6812Method NeoLc8812Method;
typedef NeoEsp32I2s1Apa106Method NeoApa106Method;
typedef NeoEsp32I2s1Ws2812xMethod Neo800KbpsMethod;
typedef NeoEsp32I2s1400KbpsMethod Neo400KbpsMethod;
typedef NeoEsp32I2s1Ws2812xInvertedMethod NeoWs2813InvertedMethod;
typedef NeoEsp32I2s1Ws2812xInvertedMethod NeoWs2812xInvertedMethod;
typedef NeoEsp32I2s1Ws2812xInvertedMethod NeoWs2811InvertedMethod;
typedef NeoEsp32I2s1800KbpsInvertedMethod NeoWs2812InvertedMethod;
typedef NeoEsp32I2s1Sk6812InvertedMethod NeoSk6812InvertedMethod;
typedef NeoEsp32I2s1Tm1814InvertedMethod NeoTm1814InvertedMethod;
typedef NeoEsp32I2s1Sk6812InvertedMethod NeoLc8812InvertedMethod;
typedef NeoEsp32I2s1Apa106InvertedMethod NeoApa106InvertedMethod;
typedef NeoEsp32I2s1Ws2812xInvertedMethod Neo800KbpsInvertedMethod;
typedef NeoEsp32I2s1400KbpsInvertedMethod Neo400KbpsInvertedMethod;
*/
#endif

View File

@@ -0,0 +1,262 @@
/*-------------------------------------------------------------------------
NeoPixel library helper functions for Esp32.
A BIG thanks to Andreas Merkle for the investigation and implementation of
a workaround to the GCC bug that drops method attributes from template methods
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 "NeoEsp32RmtMethod.h"
#ifdef ARDUINO_ARCH_ESP32
// translate NeoPixelBuffer into RMT buffer
// this is done on the fly so we don't require a send buffer in raw RMT format
// which would be 32x larger than the primary buffer
//
// NOTE: This was moved from the template below to here to workaround a GCC bug
// That bug is that the IRAM_ATTR attribute (any attributes) is lost on template classes.
//
// Further, it was removed from the header to support current Esp32 release
// which will need to be removed when the latest GitHub branchis released
// due to this method will not get inlined this way
//
void NeoEsp32RmtSpeed::_translate(const void* src,
rmt_item32_t* dest,
size_t src_size,
size_t wanted_num,
size_t* translated_size,
size_t* item_num,
const uint32_t rmtBit0,
const uint32_t rmtBit1,
const uint16_t rmtDurationReset)
{
if (src == NULL || dest == NULL)
{
*translated_size = 0;
*item_num = 0;
return;
}
size_t size = 0;
size_t num = 0;
const uint8_t* psrc = static_cast<const uint8_t*>(src);
rmt_item32_t* pdest = dest;
for (;;)
{
uint8_t data = *psrc;
for (uint8_t bit = 0; bit < 8; bit++)
{
pdest->val = (data & 0x80) ? rmtBit1 : rmtBit0;
pdest++;
data <<= 1;
}
num += 8;
size++;
// if this is the last byte we need to adjust the length of the last pulse
if (size >= src_size)
{
// extend the last bits LOW value to include the full reset signal length
pdest--;
pdest->duration1 = rmtDurationReset;
// and stop updating data to send
break;
}
if (num >= wanted_num)
{
// stop updating data to send
break;
}
psrc++;
}
*translated_size = size;
*item_num = num;
}
// these are required due to the linker error with ISRs
// dangerous relocation: l32r: literal placed after use
// https://stackoverflow.com/questions/19532826/what-does-a-dangerous-relocation-error-mean
//
void NeoEsp32RmtSpeedWs2811::Translate(const void* src,
rmt_item32_t* dest,
size_t src_size,
size_t wanted_num,
size_t* translated_size,
size_t* item_num)
{
_translate(src, dest, src_size, wanted_num, translated_size, item_num,
RmtBit0, RmtBit1, RmtDurationReset);
}
void NeoEsp32RmtSpeedWs2812x::Translate(const void* src,
rmt_item32_t* dest,
size_t src_size,
size_t wanted_num,
size_t* translated_size,
size_t* item_num)
{
_translate(src, dest, src_size, wanted_num, translated_size, item_num,
RmtBit0, RmtBit1, RmtDurationReset);
}
void NeoEsp32RmtSpeedSk6812::Translate(const void* src,
rmt_item32_t* dest,
size_t src_size,
size_t wanted_num,
size_t* translated_size,
size_t* item_num)
{
_translate(src, dest, src_size, wanted_num, translated_size, item_num,
RmtBit0, RmtBit1, RmtDurationReset);
}
void NeoEsp32RmtSpeedTm1814::Translate(const void* src,
rmt_item32_t* dest,
size_t src_size,
size_t wanted_num,
size_t* translated_size,
size_t* item_num)
{
_translate(src, dest, src_size, wanted_num, translated_size, item_num,
RmtBit0, RmtBit1, RmtDurationReset);
}
void NeoEsp32RmtSpeed800Kbps::Translate(const void* src,
rmt_item32_t* dest,
size_t src_size,
size_t wanted_num,
size_t* translated_size,
size_t* item_num)
{
_translate(src, dest, src_size, wanted_num, translated_size, item_num,
RmtBit0, RmtBit1, RmtDurationReset);
}
void NeoEsp32RmtSpeed400Kbps::Translate(const void* src,
rmt_item32_t* dest,
size_t src_size,
size_t wanted_num,
size_t* translated_size,
size_t* item_num)
{
_translate(src, dest, src_size, wanted_num, translated_size, item_num,
RmtBit0, RmtBit1, RmtDurationReset);
}
void NeoEsp32RmtSpeedApa106::Translate(const void* src,
rmt_item32_t* dest,
size_t src_size,
size_t wanted_num,
size_t* translated_size,
size_t* item_num)
{
_translate(src, dest, src_size, wanted_num, translated_size, item_num,
RmtBit0, RmtBit1, RmtDurationReset);
}
void NeoEsp32RmtInvertedSpeedWs2811::Translate(const void* src,
rmt_item32_t* dest,
size_t src_size,
size_t wanted_num,
size_t* translated_size,
size_t* item_num)
{
_translate(src, dest, src_size, wanted_num, translated_size, item_num,
RmtBit0, RmtBit1, RmtDurationReset);
}
void NeoEsp32RmtInvertedSpeedWs2812x::Translate(const void* src,
rmt_item32_t* dest,
size_t src_size,
size_t wanted_num,
size_t* translated_size,
size_t* item_num)
{
_translate(src, dest, src_size, wanted_num, translated_size, item_num,
RmtBit0, RmtBit1, RmtDurationReset);
}
void NeoEsp32RmtInvertedSpeedSk6812::Translate(const void* src,
rmt_item32_t* dest,
size_t src_size,
size_t wanted_num,
size_t* translated_size,
size_t* item_num)
{
_translate(src, dest, src_size, wanted_num, translated_size, item_num,
RmtBit0, RmtBit1, RmtDurationReset);
}
void NeoEsp32RmtInvertedSpeedTm1814::Translate(const void* src,
rmt_item32_t* dest,
size_t src_size,
size_t wanted_num,
size_t* translated_size,
size_t* item_num)
{
_translate(src, dest, src_size, wanted_num, translated_size, item_num,
RmtBit0, RmtBit1, RmtDurationReset);
}
void NeoEsp32RmtInvertedSpeed800Kbps::Translate(const void* src,
rmt_item32_t* dest,
size_t src_size,
size_t wanted_num,
size_t* translated_size,
size_t* item_num)
{
_translate(src, dest, src_size, wanted_num, translated_size, item_num,
RmtBit0, RmtBit1, RmtDurationReset);
}
void NeoEsp32RmtInvertedSpeed400Kbps::Translate(const void* src,
rmt_item32_t* dest,
size_t src_size,
size_t wanted_num,
size_t* translated_size,
size_t* item_num)
{
_translate(src, dest, src_size, wanted_num, translated_size, item_num,
RmtBit0, RmtBit1, RmtDurationReset);
}
void NeoEsp32RmtInvertedSpeedApa106::Translate(const void* src,
rmt_item32_t* dest,
size_t src_size,
size_t wanted_num,
size_t* translated_size,
size_t* item_num)
{
_translate(src, dest, src_size, wanted_num, translated_size, item_num,
RmtBit0, RmtBit1, RmtDurationReset);
}
#endif

View File

@@ -0,0 +1,668 @@
/*-------------------------------------------------------------------------
NeoPixel library helper functions for Esp32.
A BIG thanks to Andreas Merkle for the investigation and implementation of
a workaround to the GCC bug that drops method attributes from template methods
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
#ifdef ARDUINO_ARCH_ESP32
/* General Reference documentation for the APIs used in this implementation
LOW LEVEL: (what is actually used)
DOCS: https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/peripherals/rmt.html
EXAMPLE: https://github.com/espressif/esp-idf/blob/826ff7186ae07dc81e960a8ea09ebfc5304bfb3b/examples/peripherals/rmt_tx/main/rmt_tx_main.c
HIGHER LEVEL:
NO TRANSLATE SUPPORT so this was not used
NOTE: https://github.com/espressif/arduino-esp32/commit/50d142950d229b8fabca9b749dc4a5f2533bc426
Esp32-hal-rmt.h
Esp32-hal-rmt.c
*/
#include <Arduino.h>
extern "C"
{
#include <driver/rmt.h>
}
class NeoEsp32RmtSpeed
{
public:
// ClkDiv of 2 provides for good resolution and plenty of reset resolution; but
// a ClkDiv of 1 will provide enough space for the longest reset and does show
// little better pulse accuracy
const static uint8_t RmtClockDivider = 2;
inline constexpr static uint32_t FromNs(uint32_t ns)
{
return ns / NsPerRmtTick;
}
protected:
const static uint32_t RmtCpu = 80000000L; // 80 mhz RMT clock
const static uint32_t NsPerSecond = 1000000000L;
const static uint32_t RmtTicksPerSecond = (RmtCpu / RmtClockDivider);
const static uint32_t NsPerRmtTick = (NsPerSecond / RmtTicksPerSecond); // about 25
static void IRAM_ATTR _translate(const void* src,
rmt_item32_t* dest,
size_t src_size,
size_t wanted_num,
size_t* translated_size,
size_t* item_num,
const uint32_t rmtBit0,
const uint32_t rmtBit1,
const uint16_t rmtDurationReset);
};
class NeoEsp32RmtSpeedBase : public NeoEsp32RmtSpeed
{
public:
// this is used rather than the rmt_item32_t as you can't correctly initialize
// it as a static constexpr within the template
inline constexpr static uint32_t Item32Val(uint16_t nsHigh, uint16_t nsLow)
{
return (FromNs(nsLow) << 16) | (1 << 15) | (FromNs(nsHigh));
}
const static rmt_idle_level_t IdleLevel = RMT_IDLE_LEVEL_LOW;
};
class NeoEsp32RmtInvertedSpeedBase : public NeoEsp32RmtSpeed
{
public:
// this is used rather than the rmt_item32_t as you can't correctly initialize
// it as a static constexpr within the template
inline constexpr static uint32_t Item32Val(uint16_t nsHigh, uint16_t nsLow)
{
return (FromNs(nsLow) << 16) | (1 << 31) | (FromNs(nsHigh));
}
const static rmt_idle_level_t IdleLevel = RMT_IDLE_LEVEL_HIGH;
};
class NeoEsp32RmtSpeedWs2811 : public NeoEsp32RmtSpeedBase
{
public:
const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(300, 950);
const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(900, 350);
const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(300000); // 300us
static void IRAM_ATTR Translate(const void* src,
rmt_item32_t* dest,
size_t src_size,
size_t wanted_num,
size_t* translated_size,
size_t* item_num);
};
class NeoEsp32RmtSpeedWs2812x : public NeoEsp32RmtSpeedBase
{
public:
const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(400, 850);
const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(800, 450);
const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(300000); // 300us
static void IRAM_ATTR Translate(const void* src,
rmt_item32_t* dest,
size_t src_size,
size_t wanted_num,
size_t* translated_size,
size_t* item_num);
};
class NeoEsp32RmtSpeedSk6812 : public NeoEsp32RmtSpeedBase
{
public:
const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(400, 850);
const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(800, 450);
const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(80000); // 80us
static void IRAM_ATTR Translate(const void* src,
rmt_item32_t* dest,
size_t src_size,
size_t wanted_num,
size_t* translated_size,
size_t* item_num);
};
// normal is inverted signal
class NeoEsp32RmtSpeedTm1814 : public NeoEsp32RmtInvertedSpeedBase
{
public:
const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(360, 890);
const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(720, 530);
const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(200000); // 200us
static void IRAM_ATTR Translate(const void* src,
rmt_item32_t* dest,
size_t src_size,
size_t wanted_num,
size_t* translated_size,
size_t* item_num);
};
class NeoEsp32RmtSpeed800Kbps : public NeoEsp32RmtSpeedBase
{
public:
const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(400, 850);
const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(800, 450);
const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(50000); // 50us
static void IRAM_ATTR Translate(const void* src,
rmt_item32_t* dest,
size_t src_size,
size_t wanted_num,
size_t* translated_size,
size_t* item_num);
};
class NeoEsp32RmtSpeed400Kbps : public NeoEsp32RmtSpeedBase
{
public:
const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(800, 1700);
const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(1600, 900);
const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(50000); // 50us
static void IRAM_ATTR Translate(const void* src,
rmt_item32_t* dest,
size_t src_size,
size_t wanted_num,
size_t* translated_size,
size_t* item_num);
};
class NeoEsp32RmtSpeedApa106 : public NeoEsp32RmtSpeedBase
{
public:
const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(400, 1250);
const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(1250, 400);
const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(50000); // 50us
static void IRAM_ATTR Translate(const void* src,
rmt_item32_t* dest,
size_t src_size,
size_t wanted_num,
size_t* translated_size,
size_t* item_num);
};
class NeoEsp32RmtInvertedSpeedWs2811 : public NeoEsp32RmtInvertedSpeedBase
{
public:
const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(300, 950);
const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(900, 350);
const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(300000); // 300us
static void IRAM_ATTR Translate(const void* src,
rmt_item32_t* dest,
size_t src_size,
size_t wanted_num,
size_t* translated_size,
size_t* item_num);
};
class NeoEsp32RmtInvertedSpeedWs2812x : public NeoEsp32RmtInvertedSpeedBase
{
public:
const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(400, 850);
const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(800, 450);
const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(300000); // 300us
static void IRAM_ATTR Translate(const void* src,
rmt_item32_t* dest,
size_t src_size,
size_t wanted_num,
size_t* translated_size,
size_t* item_num);
};
class NeoEsp32RmtInvertedSpeedSk6812 : public NeoEsp32RmtInvertedSpeedBase
{
public:
const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(400, 850);
const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(800, 450);
const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(80000); // 80us
static void IRAM_ATTR Translate(const void* src,
rmt_item32_t* dest,
size_t src_size,
size_t wanted_num,
size_t* translated_size,
size_t* item_num);
};
// normal is inverted signal
class NeoEsp32RmtInvertedSpeedTm1814 : public NeoEsp32RmtSpeedBase
{
public:
const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(360, 890);
const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(720, 530);
const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(200000); // 200us
static void IRAM_ATTR Translate(const void* src,
rmt_item32_t* dest,
size_t src_size,
size_t wanted_num,
size_t* translated_size,
size_t* item_num);
};
class NeoEsp32RmtInvertedSpeed800Kbps : public NeoEsp32RmtInvertedSpeedBase
{
public:
const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(400, 850);
const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(800, 450);
const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(50000); // 50us
static void IRAM_ATTR Translate(const void* src,
rmt_item32_t* dest,
size_t src_size,
size_t wanted_num,
size_t* translated_size,
size_t* item_num);
};
class NeoEsp32RmtInvertedSpeed400Kbps : public NeoEsp32RmtInvertedSpeedBase
{
public:
const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(800, 1700);
const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(1600, 900);
const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(50000); // 50us
static void IRAM_ATTR Translate(const void* src,
rmt_item32_t* dest,
size_t src_size,
size_t wanted_num,
size_t* translated_size,
size_t* item_num);
};
class NeoEsp32RmtInvertedSpeedApa106 : public NeoEsp32RmtInvertedSpeedBase
{
public:
const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(400, 1250);
const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(1250, 400);
const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(50000); // 50us
static void IRAM_ATTR Translate(const void* src,
rmt_item32_t* dest,
size_t src_size,
size_t wanted_num,
size_t* translated_size,
size_t* item_num);
};
class NeoEsp32RmtChannel0
{
public:
const static rmt_channel_t RmtChannelNumber = RMT_CHANNEL_0;
};
class NeoEsp32RmtChannel1
{
public:
const static rmt_channel_t RmtChannelNumber = RMT_CHANNEL_1;
};
class NeoEsp32RmtChannel2
{
public:
const static rmt_channel_t RmtChannelNumber = RMT_CHANNEL_2;
};
class NeoEsp32RmtChannel3
{
public:
const static rmt_channel_t RmtChannelNumber = RMT_CHANNEL_3;
};
#if !defined(CONFIG_IDF_TARGET_ESP32S2)
class NeoEsp32RmtChannel4
{
public:
const static rmt_channel_t RmtChannelNumber = RMT_CHANNEL_4;
};
class NeoEsp32RmtChannel5
{
public:
const static rmt_channel_t RmtChannelNumber = RMT_CHANNEL_5;
};
class NeoEsp32RmtChannel6
{
public:
const static rmt_channel_t RmtChannelNumber = RMT_CHANNEL_6;
};
class NeoEsp32RmtChannel7
{
public:
const static rmt_channel_t RmtChannelNumber = RMT_CHANNEL_7;
};
#endif
template<typename T_SPEED, typename T_CHANNEL> class NeoEsp32RmtMethodBase
{
public:
NeoEsp32RmtMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize) :
_sizeData(pixelCount * elementSize + settingsSize),
_pin(pin)
{
_dataEditing = static_cast<uint8_t*>(malloc(_sizeData));
memset(_dataEditing, 0x00, _sizeData);
_dataSending = static_cast<uint8_t*>(malloc(_sizeData));
// no need to initialize it, it gets overwritten on every send
}
~NeoEsp32RmtMethodBase()
{
// wait until the last send finishes before destructing everything
// arbitrary time out of 10 seconds
ESP_ERROR_CHECK_WITHOUT_ABORT(rmt_wait_tx_done(T_CHANNEL::RmtChannelNumber, 10000 / portTICK_PERIOD_MS));
ESP_ERROR_CHECK(rmt_driver_uninstall(T_CHANNEL::RmtChannelNumber));
free(_dataEditing);
free(_dataSending);
}
bool IsReadyToUpdate() const
{
return (ESP_OK == rmt_wait_tx_done(T_CHANNEL::RmtChannelNumber, 0));
}
void Initialize()
{
rmt_config_t config;
config.rmt_mode = RMT_MODE_TX;
config.channel = T_CHANNEL::RmtChannelNumber;
config.gpio_num = static_cast<gpio_num_t>(_pin);
config.mem_block_num = 1;
config.tx_config.loop_en = false;
config.tx_config.idle_output_en = true;
config.tx_config.idle_level = T_SPEED::IdleLevel;
config.tx_config.carrier_en = false;
config.tx_config.carrier_level = RMT_CARRIER_LEVEL_LOW;
config.clk_div = T_SPEED::RmtClockDivider;
ESP_ERROR_CHECK(rmt_config(&config));
ESP_ERROR_CHECK(rmt_driver_install(T_CHANNEL::RmtChannelNumber, 0, ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_LEVEL1));
ESP_ERROR_CHECK(rmt_translator_init(T_CHANNEL::RmtChannelNumber, T_SPEED::Translate));
}
void Update(bool maintainBufferConsistency)
{
// wait for not actively sending data
// this will time out at 10 seconds, an arbitrarily long period of time
// and do nothing if this happens
if (ESP_OK == ESP_ERROR_CHECK_WITHOUT_ABORT(rmt_wait_tx_done(T_CHANNEL::RmtChannelNumber, 10000 / portTICK_PERIOD_MS)))
{
// now start the RMT transmit with the editing buffer before we swap
ESP_ERROR_CHECK_WITHOUT_ABORT(rmt_write_sample(T_CHANNEL::RmtChannelNumber, _dataEditing, _sizeData, false));
if (maintainBufferConsistency)
{
// copy editing to sending,
// this maintains the contract that "colors present before will
// be the same after", otherwise GetPixelColor will be inconsistent
memcpy(_dataSending, _dataEditing, _sizeData);
}
// swap so the user can modify without affecting the async operation
std::swap(_dataSending, _dataEditing);
}
}
uint8_t* getData() const
{
return _dataEditing;
};
size_t getDataSize() const
{
return _sizeData;
}
private:
const size_t _sizeData; // Size of '_data*' buffers
const uint8_t _pin; // output pin number
// Holds data stream which include LED color values and other settings as needed
uint8_t* _dataEditing; // exposed for get and set
uint8_t* _dataSending; // used for async send using RMT
};
// normal
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedWs2811, NeoEsp32RmtChannel0> NeoEsp32Rmt0Ws2811Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedWs2812x, NeoEsp32RmtChannel0> NeoEsp32Rmt0Ws2812xMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedSk6812, NeoEsp32RmtChannel0> NeoEsp32Rmt0Sk6812Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTm1814, NeoEsp32RmtChannel0> NeoEsp32Rmt0Tm1814Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedApa106, NeoEsp32RmtChannel0> NeoEsp32Rmt0Apa106Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeed800Kbps, NeoEsp32RmtChannel0> NeoEsp32Rmt0800KbpsMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeed400Kbps, NeoEsp32RmtChannel0> NeoEsp32Rmt0400KbpsMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedWs2811, NeoEsp32RmtChannel1> NeoEsp32Rmt1Ws2811Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedWs2812x, NeoEsp32RmtChannel1> NeoEsp32Rmt1Ws2812xMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedSk6812, NeoEsp32RmtChannel1> NeoEsp32Rmt1Sk6812Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTm1814, NeoEsp32RmtChannel1> NeoEsp32Rmt1Tm1814Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedApa106, NeoEsp32RmtChannel1> NeoEsp32Rmt1Apa106Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeed800Kbps, NeoEsp32RmtChannel1> NeoEsp32Rmt1800KbpsMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeed400Kbps, NeoEsp32RmtChannel1> NeoEsp32Rmt1400KbpsMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedWs2811, NeoEsp32RmtChannel2> NeoEsp32Rmt2Ws2811Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedWs2812x, NeoEsp32RmtChannel2> NeoEsp32Rmt2Ws2812xMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedSk6812, NeoEsp32RmtChannel2> NeoEsp32Rmt2Sk6812Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTm1814, NeoEsp32RmtChannel2> NeoEsp32Rmt2Tm1814Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedApa106, NeoEsp32RmtChannel2> NeoEsp32Rmt2Apa106Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeed800Kbps, NeoEsp32RmtChannel2> NeoEsp32Rmt2800KbpsMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeed400Kbps, NeoEsp32RmtChannel2> NeoEsp32Rmt2400KbpsMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedWs2811, NeoEsp32RmtChannel3> NeoEsp32Rmt3Ws2811Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedWs2812x, NeoEsp32RmtChannel3> NeoEsp32Rmt3Ws2812xMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedSk6812, NeoEsp32RmtChannel3> NeoEsp32Rmt3Sk6812Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTm1814, NeoEsp32RmtChannel3> NeoEsp32Rmt3Tm1814Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedApa106, NeoEsp32RmtChannel3> NeoEsp32Rmt3Apa106Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeed800Kbps, NeoEsp32RmtChannel3> NeoEsp32Rmt3800KbpsMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeed400Kbps, NeoEsp32RmtChannel3> NeoEsp32Rmt3400KbpsMethod;
#if !defined(CONFIG_IDF_TARGET_ESP32S2)
// (RMT_CHANNEL_MAX == 8)
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedWs2811, NeoEsp32RmtChannel4> NeoEsp32Rmt4Ws2811Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedWs2812x, NeoEsp32RmtChannel4> NeoEsp32Rmt4Ws2812xMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedSk6812, NeoEsp32RmtChannel4> NeoEsp32Rmt4Sk6812Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTm1814, NeoEsp32RmtChannel4> NeoEsp32Rmt4Tm1814Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedApa106, NeoEsp32RmtChannel4> NeoEsp32Rmt4Apa106Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeed800Kbps, NeoEsp32RmtChannel4> NeoEsp32Rmt4800KbpsMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeed400Kbps, NeoEsp32RmtChannel4> NeoEsp32Rmt4400KbpsMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedWs2811, NeoEsp32RmtChannel5> NeoEsp32Rmt5Ws2811Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedWs2812x, NeoEsp32RmtChannel5> NeoEsp32Rmt5Ws2812xMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedSk6812, NeoEsp32RmtChannel5> NeoEsp32Rmt5Sk6812Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTm1814, NeoEsp32RmtChannel5> NeoEsp32Rmt5Tm1814Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedApa106, NeoEsp32RmtChannel5> NeoEsp32Rmt5Apa106Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeed800Kbps, NeoEsp32RmtChannel5> NeoEsp32Rmt5800KbpsMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeed400Kbps, NeoEsp32RmtChannel5> NeoEsp32Rmt5400KbpsMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedWs2811, NeoEsp32RmtChannel6> NeoEsp32Rmt6Ws2811Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedWs2812x, NeoEsp32RmtChannel6> NeoEsp32Rmt6Ws2812xMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedSk6812, NeoEsp32RmtChannel6> NeoEsp32Rmt6Sk6812Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTm1814, NeoEsp32RmtChannel6> NeoEsp32Rmt6Tm1814Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedApa106, NeoEsp32RmtChannel6> NeoEsp32Rmt6Apa106Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeed800Kbps, NeoEsp32RmtChannel6> NeoEsp32Rmt6800KbpsMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeed400Kbps, NeoEsp32RmtChannel6> NeoEsp32Rmt6400KbpsMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedWs2811, NeoEsp32RmtChannel7> NeoEsp32Rmt7Ws2811Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedWs2812x, NeoEsp32RmtChannel7> NeoEsp32Rmt7Ws2812xMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedSk6812, NeoEsp32RmtChannel7> NeoEsp32Rmt7Sk6812Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTm1814, NeoEsp32RmtChannel7> NeoEsp32Rmt7Tm1814Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedApa106, NeoEsp32RmtChannel7> NeoEsp32Rmt7Apa106Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeed800Kbps, NeoEsp32RmtChannel7> NeoEsp32Rmt7800KbpsMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeed400Kbps, NeoEsp32RmtChannel7> NeoEsp32Rmt7400KbpsMethod;
#endif
// inverted
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedWs2811, NeoEsp32RmtChannel0> NeoEsp32Rmt0Ws2811InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedWs2812x, NeoEsp32RmtChannel0> NeoEsp32Rmt0Ws2812xInvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedSk6812, NeoEsp32RmtChannel0> NeoEsp32Rmt0Sk6812InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTm1814, NeoEsp32RmtChannel0> NeoEsp32Rmt0Tm1814InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedApa106, NeoEsp32RmtChannel0> NeoEsp32Rmt0Apa106InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeed800Kbps, NeoEsp32RmtChannel0> NeoEsp32Rmt0800KbpsInvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeed400Kbps, NeoEsp32RmtChannel0> NeoEsp32Rmt0400KbpsInvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedWs2811, NeoEsp32RmtChannel1> NeoEsp32Rmt1Ws2811InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedWs2812x, NeoEsp32RmtChannel1> NeoEsp32Rmt1Ws2812xInvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedSk6812, NeoEsp32RmtChannel1> NeoEsp32Rmt1Sk6812InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTm1814, NeoEsp32RmtChannel1> NeoEsp32Rmt1Tm1814InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedApa106, NeoEsp32RmtChannel1> NeoEsp32Rmt1Apa106InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeed800Kbps, NeoEsp32RmtChannel1> NeoEsp32Rmt1800KbpsInvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeed400Kbps, NeoEsp32RmtChannel1> NeoEsp32Rmt1400KbpsInvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedWs2811, NeoEsp32RmtChannel2> NeoEsp32Rmt2Ws2811InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedWs2812x, NeoEsp32RmtChannel2> NeoEsp32Rmt2Ws2812xInvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedSk6812, NeoEsp32RmtChannel2> NeoEsp32Rmt2Sk6812InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTm1814, NeoEsp32RmtChannel2> NeoEsp32Rmt2Tm1814InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedApa106, NeoEsp32RmtChannel2> NeoEsp32Rmt2Apa106InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeed800Kbps, NeoEsp32RmtChannel2> NeoEsp32Rmt2800KbpsInvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeed400Kbps, NeoEsp32RmtChannel2> NeoEsp32Rmt2400KbpsInvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedWs2811, NeoEsp32RmtChannel3> NeoEsp32Rmt3Ws2811InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedWs2812x, NeoEsp32RmtChannel3> NeoEsp32Rmt3Ws2812xInvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedSk6812, NeoEsp32RmtChannel3> NeoEsp32Rmt3Sk6812InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTm1814, NeoEsp32RmtChannel3> NeoEsp32Rmt3Tm1814InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedApa106, NeoEsp32RmtChannel3> NeoEsp32Rmt3Apa106InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeed800Kbps, NeoEsp32RmtChannel3> NeoEsp32Rmt3800KbpsInvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeed400Kbps, NeoEsp32RmtChannel3> NeoEsp32Rmt3400KbpsInvertedMethod;
#if !defined(CONFIG_IDF_TARGET_ESP32S2)
// (RMT_CHANNEL_MAX == 8)
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedWs2811, NeoEsp32RmtChannel4> NeoEsp32Rmt4Ws2811InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedWs2812x, NeoEsp32RmtChannel4> NeoEsp32Rmt4Ws2812xInvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedSk6812, NeoEsp32RmtChannel4> NeoEsp32Rmt4Sk6812InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTm1814, NeoEsp32RmtChannel4> NeoEsp32Rmt4Tm1814InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedApa106, NeoEsp32RmtChannel4> NeoEsp32Rmt4Apa106InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeed800Kbps, NeoEsp32RmtChannel4> NeoEsp32Rmt4800KbpsInvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeed400Kbps, NeoEsp32RmtChannel4> NeoEsp32Rmt4400KbpsInvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedWs2811, NeoEsp32RmtChannel5> NeoEsp32Rmt5Ws2811InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedWs2812x, NeoEsp32RmtChannel5> NeoEsp32Rmt5Ws2812xInvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedSk6812, NeoEsp32RmtChannel5> NeoEsp32Rmt5Sk6812InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTm1814, NeoEsp32RmtChannel5> NeoEsp32Rmt5Tm1814InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedApa106, NeoEsp32RmtChannel5> NeoEsp32Rmt5Apa106InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeed800Kbps, NeoEsp32RmtChannel5> NeoEsp32Rmt5800KbpsInvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeed400Kbps, NeoEsp32RmtChannel5> NeoEsp32Rmt5400KbpsInvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedWs2811, NeoEsp32RmtChannel6> NeoEsp32Rmt6Ws2811InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedWs2812x, NeoEsp32RmtChannel6> NeoEsp32Rmt6Ws2812xInvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedSk6812, NeoEsp32RmtChannel6> NeoEsp32Rmt6Sk6812InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTm1814, NeoEsp32RmtChannel6> NeoEsp32Rmt6Tm1814InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedApa106, NeoEsp32RmtChannel6> NeoEsp32Rmt6Apa106InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeed800Kbps, NeoEsp32RmtChannel6> NeoEsp32Rmt6800KbpsInvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeed400Kbps, NeoEsp32RmtChannel6> NeoEsp32Rmt6400KbpsInvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedWs2811, NeoEsp32RmtChannel7> NeoEsp32Rmt7Ws2811InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedWs2812x, NeoEsp32RmtChannel7> NeoEsp32Rmt7Ws2812xInvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedSk6812, NeoEsp32RmtChannel7> NeoEsp32Rmt7Sk6812InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTm1814, NeoEsp32RmtChannel7> NeoEsp32Rmt7Tm1814InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedApa106, NeoEsp32RmtChannel7> NeoEsp32Rmt7Apa106InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeed800Kbps, NeoEsp32RmtChannel7> NeoEsp32Rmt7800KbpsInvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeed400Kbps, NeoEsp32RmtChannel7> NeoEsp32Rmt7400KbpsInvertedMethod;
#endif
#if !defined(CONFIG_IDF_TARGET_ESP32S2)
// (RMT_CHANNEL_MAX == 8)
// due to a core issue where requests to send aren't consistent with I2s, RMT ch6 is temporarily the default
// RMT channel 6 method is the default method for Esp32
typedef NeoEsp32Rmt6Ws2812xMethod NeoWs2813Method;
typedef NeoEsp32Rmt6Ws2812xMethod NeoWs2812xMethod;
typedef NeoEsp32Rmt6800KbpsMethod NeoWs2812Method;
typedef NeoEsp32Rmt6Ws2812xMethod NeoWs2811Method;
typedef NeoEsp32Rmt6Sk6812Method NeoSk6812Method;
typedef NeoEsp32Rmt6Tm1814Method NeoTm1814Method;
typedef NeoEsp32Rmt6Sk6812Method NeoLc8812Method;
typedef NeoEsp32Rmt6Apa106Method NeoApa106Method;
typedef NeoEsp32Rmt6Ws2812xMethod Neo800KbpsMethod;
typedef NeoEsp32Rmt6400KbpsMethod Neo400KbpsMethod;
typedef NeoEsp32Rmt6Ws2812xInvertedMethod NeoWs2813InvertedMethod;
typedef NeoEsp32Rmt6Ws2812xInvertedMethod NeoWs2812xInvertedMethod;
typedef NeoEsp32Rmt6Ws2812xInvertedMethod NeoWs2811InvertedMethod;
typedef NeoEsp32Rmt6800KbpsInvertedMethod NeoWs2812InvertedMethod;
typedef NeoEsp32Rmt6Sk6812InvertedMethod NeoSk6812InvertedMethod;
typedef NeoEsp32Rmt6Tm1814InvertedMethod NeoTm1814InvertedMethod;
typedef NeoEsp32Rmt6Sk6812InvertedMethod NeoLc8812InvertedMethod;
typedef NeoEsp32Rmt6Apa106InvertedMethod NeoApa106InvertedMethod;
typedef NeoEsp32Rmt6Ws2812xInvertedMethod Neo800KbpsInvertedMethod;
typedef NeoEsp32Rmt6400KbpsInvertedMethod Neo400KbpsInvertedMethod;
#else
// due to a core issue where requests to send aren't consistent with I2s, RMT ch3 is temporarily the default
// RMT channel 3 method is the default method for Esp32S2
typedef NeoEsp32Rmt3Ws2812xMethod NeoWs2813Method;
typedef NeoEsp32Rmt3Ws2812xMethod NeoWs2812xMethod;
typedef NeoEsp32Rmt3800KbpsMethod NeoWs2812Method;
typedef NeoEsp32Rmt3Ws2812xMethod NeoWs2811Method;
typedef NeoEsp32Rmt3Sk6812Method NeoSk6812Method;
typedef NeoEsp32Rmt3Tm1814Method NeoTm1814Method;
typedef NeoEsp32Rmt3Sk6812Method NeoLc8812Method;
typedef NeoEsp32Rmt3Apa106Method NeoApa106Method;
typedef NeoEsp32Rmt3Ws2812xMethod Neo800KbpsMethod;
typedef NeoEsp32Rmt3400KbpsMethod Neo400KbpsMethod;
typedef NeoEsp32Rmt3Ws2812xInvertedMethod NeoWs2813InvertedMethod;
typedef NeoEsp32Rmt3Ws2812xInvertedMethod NeoWs2812xInvertedMethod;
typedef NeoEsp32Rmt3Ws2812xInvertedMethod NeoWs2811InvertedMethod;
typedef NeoEsp32Rmt3800KbpsInvertedMethod NeoWs2812InvertedMethod;
typedef NeoEsp32Rmt3Sk6812InvertedMethod NeoSk6812InvertedMethod;
typedef NeoEsp32Rmt3Tm1814InvertedMethod NeoTm1814InvertedMethod;
typedef NeoEsp32Rmt3Sk6812InvertedMethod NeoLc8812InvertedMethod;
typedef NeoEsp32Rmt3Apa106InvertedMethod NeoApa106InvertedMethod;
typedef NeoEsp32Rmt3Ws2812xInvertedMethod Neo800KbpsInvertedMethod;
typedef NeoEsp32Rmt3400KbpsInvertedMethod Neo400KbpsInvertedMethod;
#endif
#endif

View File

@@ -0,0 +1,573 @@
/*-------------------------------------------------------------------------
NeoPixel library helper functions for Esp8266.
Written by Michael C. Miller.
Thanks to g3gg0.de for porting the initial DMA support which lead to this.
Thanks to github/cnlohr for the original work on DMA support, which opend
all our minds to a better way (located at https://github.com/cnlohr/esp8266ws2812i2s).
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
#ifdef ARDUINO_ARCH_ESP8266
extern "C"
{
#include "Arduino.h"
#include "osapi.h"
#include "ets_sys.h"
#include "i2s_reg.h"
#include "i2s.h"
#include "eagle_soc.h"
#include "esp8266_peri.h"
#include "slc_register.h"
#include "osapi.h"
#include "ets_sys.h"
#include "user_interface.h"
#if !defined(__CORE_ESP8266_VERSION_H) || defined(ARDUINO_ESP8266_RELEASE_2_5_0)
void rom_i2c_writeReg_Mask(uint32_t block, uint32_t host_id, uint32_t reg_add, uint32_t Msb, uint32_t Lsb, uint32_t indata);
#endif
}
struct slc_queue_item
{
uint32 blocksize : 12;
uint32 datalen : 12;
uint32 unused : 5;
uint32 sub_sof : 1;
uint32 eof : 1;
uint32 owner : 1;
uint32 buf_ptr;
uint32 next_link_ptr;
};
class NeoEsp8266DmaSpeedBase
{
public:
static const uint8_t Level = 0x00;
static uint16_t Convert(uint8_t value)
{
const uint16_t bitpatterns[16] =
{
0b1000100010001000, 0b1000100010001110, 0b1000100011101000, 0b1000100011101110,
0b1000111010001000, 0b1000111010001110, 0b1000111011101000, 0b1000111011101110,
0b1110100010001000, 0b1110100010001110, 0b1110100011101000, 0b1110100011101110,
0b1110111010001000, 0b1110111010001110, 0b1110111011101000, 0b1110111011101110,
};
return bitpatterns[value];
}
};
class NeoEsp8266DmaInvertedSpeedBase
{
public:
static const uint8_t Level = 0xFF;
static uint16_t Convert(uint8_t value)
{
const uint16_t bitpatterns[16] =
{
0b0111011101110111, 0b0111011101110001, 0b0111011100010111, 0b0111011100010001,
0b0111000101110111, 0b0111000101110001, 0b0111000100010111, 0b0111000100010001,
0b0001011101110111, 0b0001011101110001, 0b0001011100010111, 0b0001011100010001,
0b0001000101110111, 0b0001000101110001, 0b0001000100010111, 0b0001000100010001,
};
return bitpatterns[value];
}
};
class NeoEsp8266DmaSpeed800KbpsBase : public NeoEsp8266DmaSpeedBase
{
public:
const static uint32_t I2sClockDivisor = 3;
const static uint32_t I2sBaseClockDivisor = 16;
const static uint32_t ByteSendTimeUs = 10; // us it takes to send a single pixel element at 800khz speed
};
class NeoEsp8266DmaSpeedWs2812x : public NeoEsp8266DmaSpeed800KbpsBase
{
public:
const static uint32_t ResetTimeUs = 300;
};
class NeoEsp8266DmaSpeedSk6812 : public NeoEsp8266DmaSpeed800KbpsBase
{
public:
const static uint32_t ResetTimeUs = 80;
};
class NeoEsp8266DmaInvertedSpeedTm1814 : public NeoEsp8266DmaSpeed800KbpsBase
{
public:
const static uint32_t ResetTimeUs = 200;
};
class NeoEsp8266DmaSpeed800Kbps : public NeoEsp8266DmaSpeed800KbpsBase
{
public:
const static uint32_t ResetTimeUs = 50;
};
class NeoEsp8266DmaSpeed400Kbps : public NeoEsp8266DmaSpeedBase
{
public:
const static uint32_t I2sClockDivisor = 6;
const static uint32_t I2sBaseClockDivisor = 16;
const static uint32_t ByteSendTimeUs = 20; // us it takes to send a single pixel element at 400khz speed
const static uint32_t ResetTimeUs = 50;
};
class NeoEsp8266DmaSpeedApa106 : public NeoEsp8266DmaSpeedBase
{
public:
const static uint32_t I2sClockDivisor = 4;
const static uint32_t I2sBaseClockDivisor = 16;
const static uint32_t ByteSendTimeUs = 17; // us it takes to send a single pixel element
const static uint32_t ResetTimeUs = 50;
};
class NeoEsp8266DmaInvertedSpeed800KbpsBase : public NeoEsp8266DmaInvertedSpeedBase
{
public:
const static uint32_t I2sClockDivisor = 3;
const static uint32_t I2sBaseClockDivisor = 16;
const static uint32_t ByteSendTimeUs = 10; // us it takes to send a single pixel element at 800khz speed
};
class NeoEsp8266DmaInvertedSpeedWs2812x : public NeoEsp8266DmaInvertedSpeed800KbpsBase
{
public:
const static uint32_t ResetTimeUs = 300;
};
class NeoEsp8266DmaInvertedSpeedSk6812 : public NeoEsp8266DmaInvertedSpeed800KbpsBase
{
public:
const static uint32_t ResetTimeUs = 80;
};
class NeoEsp8266DmaSpeedTm1814 : public NeoEsp8266DmaInvertedSpeed800KbpsBase
{
public:
const static uint32_t ResetTimeUs = 200;
};
class NeoEsp8266DmaInvertedSpeed800Kbps : public NeoEsp8266DmaInvertedSpeed800KbpsBase
{
public:
const static uint32_t ResetTimeUs = 50;
};
class NeoEsp8266DmaInvertedSpeed400Kbps : public NeoEsp8266DmaInvertedSpeedBase
{
public:
const static uint32_t I2sClockDivisor = 6;
const static uint32_t I2sBaseClockDivisor = 16;
const static uint32_t ByteSendTimeUs = 20; // us it takes to send a single pixel element at 400khz speed
const static uint32_t ResetTimeUs = 50;
};
class NeoEsp8266DmaInvertedSpeedApa106 : public NeoEsp8266DmaInvertedSpeedBase
{
public:
const static uint32_t I2sClockDivisor = 4;
const static uint32_t I2sBaseClockDivisor = 16;
const static uint32_t ByteSendTimeUs = 17; // us it takes to send a single pixel element
const static uint32_t ResetTimeUs = 50;
};
enum NeoDmaState
{
NeoDmaState_Idle,
NeoDmaState_Pending,
NeoDmaState_Sending,
NeoDmaState_Zeroing,
};
const uint16_t c_maxDmaBlockSize = 4095;
const uint16_t c_dmaBytesPerPixelBytes = 4;
const uint8_t c_I2sPin = 3; // due to I2S hardware, the pin used is restricted to this
template<typename T_SPEED> class NeoEsp8266DmaMethodBase
{
public:
NeoEsp8266DmaMethodBase(uint16_t pixelCount, size_t elementSize, size_t settingsSize) :
_sizeData(pixelCount * elementSize + settingsSize)
{
uint16_t dmaPixelSize = c_dmaBytesPerPixelBytes * elementSize;
uint16_t dmaSettingsSize = c_dmaBytesPerPixelBytes * settingsSize;
_i2sBufferSize = pixelCount * dmaPixelSize + dmaSettingsSize;
_data = static_cast<uint8_t*>(malloc(_sizeData));
memset(_data, 0x00, _sizeData);
_i2sBuffer = static_cast<uint8_t*>(malloc(_i2sBufferSize));
memset(_i2sBuffer, T_SPEED::Level, _i2sBufferSize);
// _i2sBuffer[0] = 0b11101000; // debug, 1 bit then 0 bit
memset(_i2sZeroes, T_SPEED::Level, sizeof(_i2sZeroes));
_is2BufMaxBlockSize = (c_maxDmaBlockSize / dmaPixelSize) * dmaPixelSize;
_i2sBufDescCount = (_i2sBufferSize / _is2BufMaxBlockSize) + 1 + 2; // need two more for state/latch blocks
_i2sBufDesc = (slc_queue_item*)malloc(_i2sBufDescCount * sizeof(slc_queue_item));
s_this = this; // store this for the ISR
}
NeoEsp8266DmaMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize) :
NeoEsp8266DmaMethodBase(pixelCount, elementSize, settingsSize)
{
}
~NeoEsp8266DmaMethodBase()
{
uint8_t waits = 1;
while (!IsReadyToUpdate())
{
waits = 2;
yield();
}
// wait for any pending sends to complete
// due to internal i2s caching/send delays, this can more that once the data size
uint32_t time = micros();
while ((micros() - time) < ((getPixelTime() + T_SPEED::ResetTimeUs) * waits))
{
yield();
}
StopDma();
s_this = nullptr;
pinMode(c_I2sPin, INPUT);
free(_data);
free(_i2sBuffer);
free(_i2sBufDesc);
}
bool IsReadyToUpdate() const
{
return (_dmaState == NeoDmaState_Idle);
}
void Initialize()
{
StopDma();
pinMode(c_I2sPin, FUNCTION_1); // I2S0_DATA
uint8_t* is2Buffer = _i2sBuffer;
uint32_t is2BufferSize = _i2sBufferSize;
uint16_t indexDesc;
// prepare main data block decriptors that point into our one static dma buffer
for (indexDesc = 0; indexDesc < (_i2sBufDescCount - 2); indexDesc++)
{
uint32_t blockSize = (is2BufferSize > _is2BufMaxBlockSize) ? _is2BufMaxBlockSize : is2BufferSize;
_i2sBufDesc[indexDesc].owner = 1;
_i2sBufDesc[indexDesc].eof = 0; // no need to trigger interrupt generally
_i2sBufDesc[indexDesc].sub_sof = 0;
_i2sBufDesc[indexDesc].datalen = blockSize;
_i2sBufDesc[indexDesc].blocksize = blockSize;
_i2sBufDesc[indexDesc].buf_ptr = (uint32_t)is2Buffer;
_i2sBufDesc[indexDesc].unused = 0;
_i2sBufDesc[indexDesc].next_link_ptr = (uint32_t)&(_i2sBufDesc[indexDesc + 1]);
is2Buffer += blockSize;
is2BufferSize -= blockSize;
}
// prepare the two state/latch descriptors
for (; indexDesc < _i2sBufDescCount; indexDesc++)
{
_i2sBufDesc[indexDesc].owner = 1;
_i2sBufDesc[indexDesc].eof = 0; // no need to trigger interrupt generally
_i2sBufDesc[indexDesc].sub_sof = 0;
_i2sBufDesc[indexDesc].datalen = sizeof(_i2sZeroes);
_i2sBufDesc[indexDesc].blocksize = sizeof(_i2sZeroes);
_i2sBufDesc[indexDesc].buf_ptr = (uint32_t)_i2sZeroes;
_i2sBufDesc[indexDesc].unused = 0;
_i2sBufDesc[indexDesc].next_link_ptr = (uint32_t)&(_i2sBufDesc[indexDesc + 1]);
}
// the first state block will trigger the interrupt
_i2sBufDesc[indexDesc - 2].eof = 1;
// the last state block will loop to the first state block by defualt
_i2sBufDesc[indexDesc - 1].next_link_ptr = (uint32_t)&(_i2sBufDesc[indexDesc - 2]);
// setup the rest of i2s DMA
//
ETS_SLC_INTR_DISABLE();
// start off in sending state as that is what it will be all setup to be
// for the interrupt
_dmaState = NeoDmaState_Sending;
SLCC0 |= SLCRXLR | SLCTXLR;
SLCC0 &= ~(SLCRXLR | SLCTXLR);
SLCIC = 0xFFFFFFFF;
// Configure DMA
SLCC0 &= ~(SLCMM << SLCM); // clear DMA MODE
SLCC0 |= (1 << SLCM); // set DMA MODE to 1
SLCRXDC |= SLCBINR | SLCBTNR; // enable INFOR_NO_REPLACE and TOKEN_NO_REPLACE
SLCRXDC &= ~(SLCBRXFE | SLCBRXEM | SLCBRXFM); // disable RX_FILL, RX_EOF_MODE and RX_FILL_MODE
// Feed DMA the 1st buffer desc addr
// To send data to the I2S subsystem, counter-intuitively we use the RXLINK part, not the TXLINK as you might
// expect. The TXLINK part still needs a valid DMA descriptor, even if it's unused: the DMA engine will throw
// an error at us otherwise. Just feed it any random descriptor.
SLCTXL &= ~(SLCTXLAM << SLCTXLA); // clear TX descriptor address
// set TX descriptor address. any random desc is OK, we don't use TX but it needs to be valid
SLCTXL |= (uint32)&(_i2sBufDesc[_i2sBufDescCount-1]) << SLCTXLA;
SLCRXL &= ~(SLCRXLAM << SLCRXLA); // clear RX descriptor address
// set RX descriptor address. use first of the data addresses
SLCRXL |= (uint32)&(_i2sBufDesc[0]) << SLCRXLA;
ETS_SLC_INTR_ATTACH(i2s_slc_isr, NULL);
SLCIE = SLCIRXEOF; // Enable only for RX EOF interrupt
ETS_SLC_INTR_ENABLE();
//Start transmission
SLCTXL |= SLCTXLS;
SLCRXL |= SLCRXLS;
I2S_CLK_ENABLE();
I2SIC = 0x3F;
I2SIE = 0;
//Reset I2S
I2SC &= ~(I2SRST);
I2SC |= I2SRST;
I2SC &= ~(I2SRST);
// Set RX/TX FIFO_MOD=0 and disable DMA (FIFO only)
I2SFC &= ~(I2SDE | (I2STXFMM << I2STXFM) | (I2SRXFMM << I2SRXFM));
I2SFC |= I2SDE; //Enable DMA
// Set RX/TX CHAN_MOD=0
I2SCC &= ~((I2STXCMM << I2STXCM) | (I2SRXCMM << I2SRXCM));
// set the rate
uint32_t i2s_clock_div = T_SPEED::I2sClockDivisor & I2SCDM;
uint8_t i2s_bck_div = T_SPEED::I2sBaseClockDivisor & I2SBDM;
//!trans master, !bits mod, rece slave mod, rece msb shift, right first, msb right
I2SC &= ~(I2STSM | I2SRSM | (I2SBMM << I2SBM) | (I2SBDM << I2SBD) | (I2SCDM << I2SCD));
I2SC |= I2SRF | I2SMR | I2SRSM | I2SRMS | (i2s_bck_div << I2SBD) | (i2s_clock_div << I2SCD);
I2SC |= I2STXS; // Start transmission
}
void ICACHE_RAM_ATTR Update(bool)
{
// wait for not actively sending data
while (!IsReadyToUpdate())
{
yield();
}
FillBuffers();
// toggle state so the ISR reacts
_dmaState = NeoDmaState_Pending;
}
uint8_t* getData() const
{
return _data;
};
size_t getDataSize() const
{
return _sizeData;
}
private:
static NeoEsp8266DmaMethodBase* s_this; // for the ISR
const size_t _sizeData; // Size of '_data' buffer
uint8_t* _data; // Holds LED color values
size_t _i2sBufferSize; // total size of _i2sBuffer
uint8_t* _i2sBuffer; // holds the DMA buffer that is referenced by _i2sBufDesc
// normally 24 bytes creates the minimum 50us latch per spec, but
// with the new logic, this latch is used to space between mulitple states
// buffer size = (24 * (reset time / 50)) / 6
uint8_t _i2sZeroes[(24L * (T_SPEED::ResetTimeUs / 50L)) / 6L];
slc_queue_item* _i2sBufDesc; // dma block descriptors
uint16_t _i2sBufDescCount; // count of block descriptors in _i2sBufDesc
uint16_t _is2BufMaxBlockSize; // max size based on size of a pixel of a single block
volatile NeoDmaState _dmaState;
// This routine is called as soon as the DMA routine has something to tell us. All we
// handle here is the RX_EOF_INT status, which indicate the DMA has sent a buffer whose
// descriptor has the 'EOF' field set to 1.
// in the case of this code, the second to last state descriptor
static void ICACHE_RAM_ATTR i2s_slc_isr(void)
{
ETS_SLC_INTR_DISABLE();
uint32_t slc_intr_status = SLCIS;
SLCIC = 0xFFFFFFFF;
if ((slc_intr_status & SLCIRXEOF) && s_this)
{
switch (s_this->_dmaState)
{
case NeoDmaState_Idle:
break;
case NeoDmaState_Pending:
{
slc_queue_item* finished_item = (slc_queue_item*)SLCRXEDA;
// data block has pending data waiting to send, prepare it
// point last state block to top
(finished_item + 1)->next_link_ptr = (uint32_t)(s_this->_i2sBufDesc);
s_this->_dmaState = NeoDmaState_Sending;
}
break;
case NeoDmaState_Sending:
{
slc_queue_item* finished_item = (slc_queue_item*)SLCRXEDA;
// the data block had actual data sent
// point last state block to first state block thus
// just looping and not sending the data blocks
(finished_item + 1)->next_link_ptr = (uint32_t)(finished_item);
s_this->_dmaState = NeoDmaState_Zeroing;
}
break;
case NeoDmaState_Zeroing:
s_this->_dmaState = NeoDmaState_Idle;
break;
}
}
ETS_SLC_INTR_ENABLE();
}
void FillBuffers()
{
uint16_t* pDma = (uint16_t*)_i2sBuffer;
uint8_t* pEnd = _data + _sizeData;
for (uint8_t* pData = _data; pData < pEnd; pData++)
{
*(pDma++) = T_SPEED::Convert(((*pData) & 0x0f));
*(pDma++) = T_SPEED::Convert(((*pData) >> 4) & 0x0f);
}
}
void StopDma()
{
ETS_SLC_INTR_DISABLE();
// Disable any I2S send or receive
I2SC &= ~(I2STXS | I2SRXS);
// Reset I2S
I2SC &= ~(I2SRST);
I2SC |= I2SRST;
I2SC &= ~(I2SRST);
SLCIC = 0xFFFFFFFF;
SLCIE = 0;
SLCTXL &= ~(SLCTXLAM << SLCTXLA); // clear TX descriptor address
SLCRXL &= ~(SLCRXLAM << SLCRXLA); // clear RX descriptor address
pinMode(c_I2sPin, INPUT);
}
uint32_t getPixelTime() const
{
return (T_SPEED::ByteSendTimeUs * this->_sizeData);
};
};
template<typename T_SPEED>
NeoEsp8266DmaMethodBase<T_SPEED>* NeoEsp8266DmaMethodBase<T_SPEED>::s_this;
// normal
typedef NeoEsp8266DmaMethodBase<NeoEsp8266DmaSpeedWs2812x> NeoEsp8266DmaWs2812xMethod;
typedef NeoEsp8266DmaMethodBase<NeoEsp8266DmaSpeedSk6812> NeoEsp8266DmaSk6812Method;
typedef NeoEsp8266DmaMethodBase<NeoEsp8266DmaSpeedTm1814> NeoEsp8266DmaTm1814Method;
typedef NeoEsp8266DmaMethodBase<NeoEsp8266DmaSpeed800Kbps> NeoEsp8266Dma800KbpsMethod;
typedef NeoEsp8266DmaMethodBase<NeoEsp8266DmaSpeed400Kbps> NeoEsp8266Dma400KbpsMethod;
typedef NeoEsp8266DmaMethodBase<NeoEsp8266DmaSpeedApa106> NeoEsp8266DmaApa106Method;
// inverted
typedef NeoEsp8266DmaMethodBase<NeoEsp8266DmaInvertedSpeedWs2812x> NeoEsp8266DmaInvertedWs2812xMethod;
typedef NeoEsp8266DmaMethodBase<NeoEsp8266DmaInvertedSpeedSk6812> NeoEsp8266DmaInvertedSk6812Method;
typedef NeoEsp8266DmaMethodBase<NeoEsp8266DmaInvertedSpeedTm1814> NeoEsp8266DmaInvertedTm1814Method;
typedef NeoEsp8266DmaMethodBase<NeoEsp8266DmaInvertedSpeed800Kbps> NeoEsp8266DmaInverted800KbpsMethod;
typedef NeoEsp8266DmaMethodBase<NeoEsp8266DmaInvertedSpeed400Kbps> NeoEsp8266DmaInverted400KbpsMethod;
typedef NeoEsp8266DmaMethodBase<NeoEsp8266DmaInvertedSpeedApa106> NeoEsp8266DmaInvertedApa106Method;
// Dma method is the default method for Esp8266
typedef NeoEsp8266DmaWs2812xMethod NeoWs2813Method;
typedef NeoEsp8266DmaWs2812xMethod NeoWs2812xMethod;
typedef NeoEsp8266Dma800KbpsMethod NeoWs2812Method;
typedef NeoEsp8266DmaWs2812xMethod NeoWs2811Method;
typedef NeoEsp8266DmaSk6812Method NeoSk6812Method;
typedef NeoEsp8266DmaTm1814Method NeoTm1814Method;
typedef NeoEsp8266DmaSk6812Method NeoLc8812Method;
typedef NeoEsp8266DmaApa106Method NeoApa106Method;
typedef NeoEsp8266DmaWs2812xMethod Neo800KbpsMethod;
typedef NeoEsp8266Dma400KbpsMethod Neo400KbpsMethod;
// inverted
typedef NeoEsp8266DmaInvertedWs2812xMethod NeoWs2813InvertedMethod;
typedef NeoEsp8266DmaInvertedWs2812xMethod NeoWs2812xInvertedMethod;
typedef NeoEsp8266DmaInverted800KbpsMethod NeoWs2812InvertedMethod;
typedef NeoEsp8266DmaInvertedWs2812xMethod NeoWs2811InvertedMethod;
typedef NeoEsp8266DmaInvertedSk6812Method NeoSk6812InvertedMethod;
typedef NeoEsp8266DmaInvertedTm1814Method NeoTm1814InvertedMethod;
typedef NeoEsp8266DmaInvertedSk6812Method NeoLc8812InvertedMethod;
typedef NeoEsp8266DmaInvertedApa106Method NeoApa106InvertedMethod;
typedef NeoEsp8266DmaInvertedWs2812xMethod Neo800KbpsInvertedMethod;
typedef NeoEsp8266DmaInverted400KbpsMethod Neo400KbpsInvertedMethod;
#endif

View File

@@ -0,0 +1,171 @@
/*-------------------------------------------------------------------------
NeoPixel library helper functions for Esp8266 UART hardware
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/>.
-------------------------------------------------------------------------*/
#ifdef ARDUINO_ARCH_ESP8266
#include "NeoEsp8266UartMethod.h"
#include <utility>
extern "C"
{
#include <ets_sys.h>
}
const volatile uint8_t* ICACHE_RAM_ATTR NeoEsp8266UartContext::FillUartFifo(uint8_t uartNum,
const volatile uint8_t* start,
const volatile uint8_t* end)
{
// Remember: UARTs send less significant bit (LSB) first so
// pushing ABCDEF byte will generate a 0FEDCBA1 signal,
// including a LOW(0) start & a HIGH(1) stop bits.
// Also, we have configured UART to invert logic levels, so:
const uint8_t _uartData[4] = {
0b110111, // On wire: 1 000 100 0 [Neopixel reads 00]
0b000111, // On wire: 1 000 111 0 [Neopixel reads 01]
0b110100, // On wire: 1 110 100 0 [Neopixel reads 10]
0b000100, // On wire: 1 110 111 0 [NeoPixel reads 11]
};
uint8_t avail = (UART_TX_FIFO_SIZE - GetTxFifoLength(uartNum)) / 4;
if (end - start > avail)
{
end = start + avail;
}
while (start < end)
{
uint8_t subpix = *start++;
Enqueue(uartNum, _uartData[(subpix >> 6) & 0x3]);
Enqueue(uartNum, _uartData[(subpix >> 4) & 0x3]);
Enqueue(uartNum, _uartData[(subpix >> 2) & 0x3]);
Enqueue(uartNum, _uartData[subpix & 0x3]);
}
return start;
}
volatile NeoEsp8266UartInterruptContext* NeoEsp8266UartInterruptContext::s_uartInteruptContext[] = { nullptr, nullptr };
void NeoEsp8266UartInterruptContext::StartSending(uint8_t uartNum, uint8_t* start, uint8_t* end)
{
// send the pixels asynchronously
_asyncBuff = start;
_asyncBuffEnd = end;
// enable the transmit interrupt
USIE(uartNum) |= (1 << UIFE);
}
void NeoEsp8266UartInterruptContext::Attach(uint8_t uartNum)
{
// Disable all interrupts
ETS_UART_INTR_DISABLE();
// Clear the RX & TX FIFOS
const uint32_t fifoResetFlags = (1 << UCTXRST) | (1 << UCRXRST);
USC0(uartNum) |= fifoResetFlags;
USC0(uartNum) &= ~(fifoResetFlags);
// attach the ISR if needed
if (s_uartInteruptContext[0] == nullptr &&
s_uartInteruptContext[1] == nullptr)
{
ETS_UART_INTR_ATTACH(Isr, s_uartInteruptContext);
}
// attach the context
s_uartInteruptContext[uartNum] = this;
// Set tx fifo trigger. 80 bytes gives us 200 microsecs to refill the FIFO
USC1(uartNum) = (80 << UCFET);
// Disable RX & TX interrupts. It maybe still enabled by uart.c in the SDK
USIE(uartNum) &= ~((1 << UIFF) | (1 << UIFE));
// Clear all pending interrupts in UART1
USIC(uartNum) = 0xffff;
// Reenable interrupts
ETS_UART_INTR_ENABLE();
}
void NeoEsp8266UartInterruptContext::Detach(uint8_t uartNum)
{
// Disable interrupts
ETS_UART_INTR_DISABLE();
if (s_uartInteruptContext[uartNum] != nullptr)
{
// turn off uart
USC1(uartNum) = 0;
USIC(uartNum) = 0xffff;
USIE(uartNum) = 0;
s_uartInteruptContext[uartNum] = nullptr;
if (s_uartInteruptContext[0] == nullptr &&
s_uartInteruptContext[1] == nullptr)
{
// detach our ISR
ETS_UART_INTR_ATTACH(NULL, NULL);
// return so we don't enable interrupts since there is no ISR anymore
return;
}
}
// Reenable interrupts
ETS_UART_INTR_ENABLE();
}
void ICACHE_RAM_ATTR NeoEsp8266UartInterruptContext::Isr(void* param)
{
// make sure this is for us
if (param == s_uartInteruptContext)
{
// Interrupt handler is shared between UART0 & UART1
// so we need to test for both
for (uint8_t uartNum = 0; uartNum < 2; uartNum++)
{
if (USIS(uartNum) && s_uartInteruptContext[uartNum] != nullptr)
{
// Fill the FIFO with new data
s_uartInteruptContext[uartNum]->_asyncBuff = FillUartFifo(
uartNum,
s_uartInteruptContext[uartNum]->_asyncBuff,
s_uartInteruptContext[uartNum]->_asyncBuffEnd);
// Disable TX interrupt when done
if (s_uartInteruptContext[uartNum]->_asyncBuff == s_uartInteruptContext[uartNum]->_asyncBuffEnd)
{
// clear the TX FIFO Empty
USIE(uartNum) &= ~(1 << UIFE);
}
// Clear all interrupts flags (just in case)
USIC(uartNum) = 0xffff;
}
}
}
}
#endif

View File

@@ -0,0 +1,514 @@
/*-------------------------------------------------------------------------
NeoPixel library helper functions for Esp8266 UART hardware
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
#ifdef ARDUINO_ARCH_ESP8266
#include <Arduino.h>
// this template method class is used to track the data being sent on the uart
// when using the default serial ISR installed by the core
// used with NeoEsp8266Uart and NeoEsp8266AsyncUart classes
//
class NeoEsp8266UartContext
{
public:
// Gets the number of bytes waiting in the TX FIFO
static inline uint8_t ICACHE_RAM_ATTR GetTxFifoLength(uint8_t uartNum)
{
return (USS(uartNum) >> USTXC) & 0xff;
}
// Append a byte to the TX FIFO
static inline void ICACHE_RAM_ATTR Enqueue(uint8_t uartNum, uint8_t value)
{
USF(uartNum) = value;
}
static const volatile uint8_t* ICACHE_RAM_ATTR FillUartFifo(uint8_t uartNum,
const volatile uint8_t* start,
const volatile uint8_t* end);
};
// this template method class is used to track the data being sent on the uart
// when using our own UART ISR
// used with NeoEsp8266Uart and NeoEsp8266AsyncUart classes
//
class NeoEsp8266UartInterruptContext : NeoEsp8266UartContext
{
public:
NeoEsp8266UartInterruptContext() :
_asyncBuff(nullptr),
_asyncBuffEnd(nullptr)
{
}
bool IsSending()
{
return (_asyncBuff != _asyncBuffEnd);
}
void StartSending(uint8_t uartNum, uint8_t* start, uint8_t* end);
void Attach(uint8_t uartNum);
void Detach(uint8_t uartNum);
private:
volatile const uint8_t* _asyncBuff;
volatile const uint8_t* _asyncBuffEnd;
volatile static NeoEsp8266UartInterruptContext* s_uartInteruptContext[2];
static void ICACHE_RAM_ATTR Isr(void* param);
};
// this template feature class is used a base for all others and contains
// common methods
//
class UartFeatureBase
{
protected:
static void ConfigUart(uint8_t uartNum, bool invert)
{
// clear all invert bits
USC0(uartNum) &= ~((1 << UCDTRI) | (1 << UCRTSI) | (1 << UCTXI) | (1 << UCDSRI) | (1 << UCCTSI) | (1 << UCRXI));
if (!invert)
{
// For normal operations,
// Invert the TX voltage associated with logic level so:
// - A logic level 0 will generate a Vcc signal
// - A logic level 1 will generate a Gnd signal
USC0(uartNum) |= (1 << UCTXI);
}
}
};
// this template feature class is used to define the specifics for uart0
// used with NeoEsp8266Uart and NeoEsp8266AsyncUart classes
//
class UartFeature0 : UartFeatureBase
{
public:
static const uint32_t Index = 0;
static void Init(uint32_t baud, bool invert)
{
// Configure the serial line with 1 start bit (0), 6 data bits and 1 stop bit (1)
Serial.begin(baud, SERIAL_6N1, SERIAL_TX_ONLY);
ConfigUart(Index, invert);
}
};
// this template feature class is used to define the specifics for uart1
// used with NeoEsp8266Uart and NeoEsp8266AsyncUart classes
//
class UartFeature1 : UartFeatureBase
{
public:
static const uint32_t Index = 1;
static void Init(uint32_t baud, bool invert)
{
// Configure the serial line with 1 start bit (0), 6 data bits and 1 stop bit (1)
Serial1.begin(baud, SERIAL_6N1, SERIAL_TX_ONLY);
ConfigUart(Index, invert);
}
};
// this template method class is used a base for all others and contains
// common properties and methods
//
// used by NeoEsp8266Uart and NeoEsp8266AsyncUart
//
class NeoEsp8266UartBase
{
protected:
const size_t _sizeData; // Size of '_data' buffer below
uint8_t* _data; // Holds LED color values
uint32_t _startTime; // Microsecond count when last update started
NeoEsp8266UartBase(uint16_t pixelCount, size_t elementSize, size_t settingsSize) :
_sizeData(pixelCount * elementSize + settingsSize)
{
_data = static_cast<uint8_t*>(malloc(_sizeData));
memset(_data, 0x00, _sizeData);
}
~NeoEsp8266UartBase()
{
free(_data);
}
};
// this template method class is used to glue uart feature and context for
// synchronous uart method
//
// used by NeoEsp8266UartMethodBase
//
template<typename T_UARTFEATURE, typename T_UARTCONTEXT> class NeoEsp8266Uart : public NeoEsp8266UartBase
{
protected:
NeoEsp8266Uart(uint16_t pixelCount, size_t elementSize, size_t settingsSize) :
NeoEsp8266UartBase(pixelCount, elementSize, settingsSize)
{
}
~NeoEsp8266Uart()
{
// Wait until the TX fifo is empty. This way we avoid broken frames
// when destroying & creating a NeoPixelBus to change its length.
while (T_UARTCONTEXT::GetTxFifoLength(T_UARTFEATURE::Index) > 0)
{
yield();
}
}
void InitializeUart(uint32_t uartBaud, bool invert)
{
T_UARTFEATURE::Init(uartBaud, invert);
}
void UpdateUart(bool)
{
// Since the UART can finish sending queued bytes in the FIFO in
// the background, instead of waiting for the FIFO to flush
// we annotate the start time of the frame so we can calculate
// when it will finish.
_startTime = micros();
// Then keep filling the FIFO until done
const uint8_t* ptr = _data;
const uint8_t* end = ptr + _sizeData;
while (ptr != end)
{
ptr = const_cast<uint8_t*>(T_UARTCONTEXT::FillUartFifo(T_UARTFEATURE::Index, ptr, end));
}
}
};
// this template method class is used to glue uart feature and context for
// asynchronously uart method
//
// This UART controller uses two buffers that are swapped in every call to
// NeoPixelBus.Show(). One buffer contains the data that is being sent
// asynchronosly and another buffer contains the data that will be send
// in the next call to NeoPixelBus.Show().
//
// Therefore, the result of NeoPixelBus.Pixels() is invalidated after
// every call to NeoPixelBus.Show() and must not be cached.
//
// used by NeoEsp8266UartMethodBase
//
template<typename T_UARTFEATURE, typename T_UARTCONTEXT> class NeoEsp8266AsyncUart : public NeoEsp8266UartBase
{
protected:
NeoEsp8266AsyncUart(uint16_t pixelCount, size_t elementSize, size_t settingsSize) :
NeoEsp8266UartBase(pixelCount, elementSize, settingsSize)
{
_dataSending = static_cast<uint8_t*>(malloc(_sizeData));
}
~NeoEsp8266AsyncUart()
{
// Remember: the UART interrupt can be sending data from _dataSending in the background
while (_context.IsSending())
{
yield();
}
// detach context, which will disable intr, may disable ISR
_context.Detach(T_UARTFEATURE::Index);
free(_dataSending);
}
void ICACHE_RAM_ATTR InitializeUart(uint32_t uartBaud, bool invert)
{
T_UARTFEATURE::Init(uartBaud, invert);
// attach the context, which will enable the ISR
_context.Attach(T_UARTFEATURE::Index);
}
void UpdateUart(bool maintainBufferConsistency)
{
// Instruct ESP8266 hardware uart to send the pixels asynchronously
_context.StartSending(T_UARTFEATURE::Index,
_data,
_data + _sizeData);
// Annotate when we started to send bytes, so we can calculate when we are ready to send again
_startTime = micros();
if (maintainBufferConsistency)
{
// copy editing to sending,
// this maintains the contract that "colors present before will
// be the same after", otherwise GetPixelColor will be inconsistent
memcpy(_dataSending, _data, _sizeData);
}
// swap so the user can modify without affecting the async operation
std::swap(_dataSending, _data);
}
private:
T_UARTCONTEXT _context;
uint8_t* _dataSending; // Holds a copy of LED color values taken when UpdateUart began
};
class NeoEsp8266UartSpeed800KbpsBase
{
public:
static const uint32_t ByteSendTimeUs = 10; // us it takes to send a single pixel element at 800khz speed
static const uint32_t UartBaud = 3200000; // 800mhz, 4 serial bytes per NeoByte
};
// NeoEsp8266UartSpeedWs2813 contains the timing constants used to get NeoPixelBus running with the Ws2813
class NeoEsp8266UartSpeedWs2812x : public NeoEsp8266UartSpeed800KbpsBase
{
public:
static const uint32_t ResetTimeUs = 300; // us between data send bursts to reset for next update
};
class NeoEsp8266UartSpeedSk6812 : public NeoEsp8266UartSpeed800KbpsBase
{
public:
static const uint32_t ResetTimeUs = 80; // us between data send bursts to reset for next update
};
class NeoEsp8266UartSpeedTm1814 : public NeoEsp8266UartSpeed800KbpsBase
{
public:
static const uint32_t ResetTimeUs = 200; // us between data send bursts to reset for next update
};
// NeoEsp8266UartSpeed800Kbps contains the timing constant used to get NeoPixelBus running at 800Khz
class NeoEsp8266UartSpeed800Kbps : public NeoEsp8266UartSpeed800KbpsBase
{
public:
static const uint32_t ResetTimeUs = 50; // us between data send bursts to reset for next update
};
// NeoEsp8266UartSpeed400Kbps contains the timing constant used to get NeoPixelBus running at 400Khz
class NeoEsp8266UartSpeed400Kbps
{
public:
static const uint32_t ByteSendTimeUs = 20; // us it takes to send a single pixel element at 400khz speed
static const uint32_t UartBaud = 1600000; // 400mhz, 4 serial bytes per NeoByte
static const uint32_t ResetTimeUs = 50; // us between data send bursts to reset for next update
};
// NeoEsp8266UartSpeedApa106 contains the timing constant used to get NeoPixelBus running for Apa106
// Pulse cycle = 1.71 = 1.368 longer than normal, 0.731 slower, NeoEsp8266UartSpeedApa1066
class NeoEsp8266UartSpeedApa106
{
public:
static const uint32_t ByteSendTimeUs = 14; // us it takes to send a single pixel element at 400khz speed
static const uint32_t UartBaud = 2339181; // APA106 pulse cycle of 1.71us, 4 serial bytes per NeoByte
static const uint32_t ResetTimeUs = 50; // us between data send bursts to reset for next update
};
class NeoEsp8266UartNotInverted
{
public:
const static bool Inverted = false;
};
class NeoEsp8266UartInverted
{
public:
const static bool Inverted = true;
};
// NeoEsp8266UartMethodBase is a light shell arround NeoEsp8266Uart or NeoEsp8266AsyncUart that
// implements the methods needed to operate as a NeoPixelBus method.
template<typename T_SPEED, typename T_BASE, typename T_INVERT>
class NeoEsp8266UartMethodBase: public T_BASE
{
public:
NeoEsp8266UartMethodBase(uint16_t pixelCount, size_t elementSize, size_t settingsSize)
: T_BASE(pixelCount, elementSize, settingsSize)
{
}
NeoEsp8266UartMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize)
: T_BASE(pixelCount, elementSize, settingsSize)
{
}
bool IsReadyToUpdate() const
{
uint32_t delta = micros() - this->_startTime;
return delta >= getPixelTime() + T_SPEED::ResetTimeUs;
}
void Initialize()
{
this->InitializeUart(T_SPEED::UartBaud, T_INVERT::Inverted);
// Inverting logic levels can generate a phantom bit in the led strip bus
// We need to delay 50+ microseconds the output stream to force a data
// latch and discard this bit. Otherwise, that bit would be prepended to
// the first frame corrupting it.
this->_startTime = micros() - getPixelTime();
}
void Update(bool maintainBufferConsistency)
{
// Data latch = 50+ microsecond pause in the output stream. Rather than
// put a delay at the end of the function, the ending time is noted and
// the function will simply hold off (if needed) on issuing the
// subsequent round of data until the latch time has elapsed. This
// allows the mainline code to start generating the next frame of data
// rather than stalling for the latch.
while (!this->IsReadyToUpdate())
{
yield();
}
this->UpdateUart(maintainBufferConsistency);
}
uint8_t* getData() const
{
return this->_data;
};
size_t getDataSize() const
{
return this->_sizeData;
};
private:
uint32_t getPixelTime() const
{
return (T_SPEED::ByteSendTimeUs * this->_sizeData);
};
};
// uart 0
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedWs2812x, NeoEsp8266Uart<UartFeature0, NeoEsp8266UartContext>, NeoEsp8266UartNotInverted> NeoEsp8266Uart0Ws2812xMethod;
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedSk6812, NeoEsp8266Uart<UartFeature0, NeoEsp8266UartContext>, NeoEsp8266UartNotInverted> NeoEsp8266Uart0Sk6812Method;
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedTm1814, NeoEsp8266Uart<UartFeature0, NeoEsp8266UartContext>, NeoEsp8266UartInverted> NeoEsp8266Uart0Tm1814Method;
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedApa106, NeoEsp8266Uart<UartFeature0, NeoEsp8266UartContext>, NeoEsp8266UartNotInverted> NeoEsp8266Uart0Apa106Method;
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeed800Kbps, NeoEsp8266Uart<UartFeature0, NeoEsp8266UartContext>, NeoEsp8266UartNotInverted> NeoEsp8266Uart0800KbpsMethod;
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeed400Kbps, NeoEsp8266Uart<UartFeature0, NeoEsp8266UartContext>, NeoEsp8266UartNotInverted> NeoEsp8266Uart0400KbpsMethod;
typedef NeoEsp8266Uart0Ws2812xMethod NeoEsp8266Uart0Ws2813Method;
typedef NeoEsp8266Uart0800KbpsMethod NeoEsp8266Uart0Ws2812Method;
typedef NeoEsp8266Uart0Ws2812xMethod NeoEsp8266Uart0Ws2811Method;
typedef NeoEsp8266Uart0Sk6812Method NeoEsp8266Uart0Lc8812Method;
// uart 1
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedWs2812x, NeoEsp8266Uart<UartFeature1, NeoEsp8266UartContext>, NeoEsp8266UartNotInverted> NeoEsp8266Uart1Ws2812xMethod;
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedSk6812, NeoEsp8266Uart<UartFeature1, NeoEsp8266UartContext>, NeoEsp8266UartNotInverted> NeoEsp8266Uart1Sk6812Method;
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedTm1814, NeoEsp8266Uart<UartFeature1, NeoEsp8266UartContext>, NeoEsp8266UartInverted> NeoEsp8266Uart1Tm1814Method;
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedApa106, NeoEsp8266Uart<UartFeature1, NeoEsp8266UartContext>, NeoEsp8266UartNotInverted> NeoEsp8266Uart1Apa106Method;
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeed800Kbps, NeoEsp8266Uart<UartFeature1, NeoEsp8266UartContext>, NeoEsp8266UartNotInverted> NeoEsp8266Uart1800KbpsMethod;
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeed400Kbps, NeoEsp8266Uart<UartFeature1, NeoEsp8266UartContext>, NeoEsp8266UartNotInverted> NeoEsp8266Uart1400KbpsMethod;
typedef NeoEsp8266Uart1Ws2812xMethod NeoEsp8266Uart1Ws2813Method;
typedef NeoEsp8266Uart1800KbpsMethod NeoEsp8266Uart1Ws2812Method;
typedef NeoEsp8266Uart1Ws2812xMethod NeoEsp8266Uart1Ws2811Method;
typedef NeoEsp8266Uart1Sk6812Method NeoEsp8266Uart1Lc8812Method;
// uart 0 async
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedWs2812x, NeoEsp8266AsyncUart<UartFeature0, NeoEsp8266UartInterruptContext>, NeoEsp8266UartNotInverted> NeoEsp8266AsyncUart0Ws2812xMethod;
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedSk6812, NeoEsp8266AsyncUart<UartFeature0, NeoEsp8266UartInterruptContext>, NeoEsp8266UartNotInverted> NeoEsp8266AsyncUart0Sk6812Method;
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedTm1814, NeoEsp8266AsyncUart<UartFeature0, NeoEsp8266UartInterruptContext>, NeoEsp8266UartInverted> NeoEsp8266AsyncUart0Tm1814Method;
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedApa106, NeoEsp8266AsyncUart<UartFeature0, NeoEsp8266UartInterruptContext>, NeoEsp8266UartNotInverted> NeoEsp8266AsyncUart0Apa106Method;
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeed800Kbps, NeoEsp8266AsyncUart<UartFeature0, NeoEsp8266UartInterruptContext>, NeoEsp8266UartNotInverted> NeoEsp8266AsyncUart0800KbpsMethod;
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeed400Kbps, NeoEsp8266AsyncUart<UartFeature0, NeoEsp8266UartInterruptContext>, NeoEsp8266UartNotInverted> NeoEsp8266AsyncUart0400KbpsMethod;
typedef NeoEsp8266AsyncUart0Ws2812xMethod NeoEsp8266AsyncUart0Ws2813Method;
typedef NeoEsp8266AsyncUart0800KbpsMethod NeoEsp8266AsyncUart0Ws2812Method;
typedef NeoEsp8266AsyncUart0Ws2812xMethod NeoEsp8266AsyncUart0Ws2811Method;
typedef NeoEsp8266AsyncUart0Sk6812Method NeoEsp8266AsyncUart0Lc8812Method;
// uart 1 async
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedWs2812x, NeoEsp8266AsyncUart<UartFeature1, NeoEsp8266UartInterruptContext>, NeoEsp8266UartNotInverted> NeoEsp8266AsyncUart1Ws2812xMethod;
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedSk6812, NeoEsp8266AsyncUart<UartFeature1, NeoEsp8266UartInterruptContext>, NeoEsp8266UartNotInverted> NeoEsp8266AsyncUart1Sk6812Method;
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedTm1814, NeoEsp8266AsyncUart<UartFeature1, NeoEsp8266UartInterruptContext>, NeoEsp8266UartInverted> NeoEsp8266AsyncUart1Tm1814Method;
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedApa106, NeoEsp8266AsyncUart<UartFeature1, NeoEsp8266UartInterruptContext>, NeoEsp8266UartNotInverted> NeoEsp8266AsyncUart1Apa106Method;
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeed800Kbps, NeoEsp8266AsyncUart<UartFeature1, NeoEsp8266UartInterruptContext>, NeoEsp8266UartNotInverted> NeoEsp8266AsyncUart1800KbpsMethod;
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeed400Kbps, NeoEsp8266AsyncUart<UartFeature1, NeoEsp8266UartInterruptContext>, NeoEsp8266UartNotInverted> NeoEsp8266AsyncUart1400KbpsMethod;
typedef NeoEsp8266AsyncUart1Ws2812xMethod NeoEsp8266AsyncUart1Ws2813Method;
typedef NeoEsp8266AsyncUart1800KbpsMethod NeoEsp8266AsyncUart1Ws2812Method;
typedef NeoEsp8266AsyncUart1Ws2812xMethod NeoEsp8266AsyncUart1Ws2811Method;
typedef NeoEsp8266AsyncUart1Sk6812Method NeoEsp8266AsyncUart1Lc8812Method;
// inverted
//
// uart 0
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedWs2812x, NeoEsp8266Uart<UartFeature0, NeoEsp8266UartContext>, NeoEsp8266UartInverted> NeoEsp8266Uart0Ws2812xInvertedMethod;
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedSk6812, NeoEsp8266Uart<UartFeature0, NeoEsp8266UartContext>, NeoEsp8266UartInverted> NeoEsp8266Uart0Sk6812InvertedMethod;
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedTm1814, NeoEsp8266Uart<UartFeature0, NeoEsp8266UartContext>, NeoEsp8266UartNotInverted> NeoEsp8266Uart0Tm1814InvertedMethod;
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedApa106, NeoEsp8266Uart<UartFeature0, NeoEsp8266UartContext>, NeoEsp8266UartInverted> NeoEsp8266Uart0Apa106InvertedMethod;
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeed800Kbps, NeoEsp8266Uart<UartFeature0, NeoEsp8266UartContext>, NeoEsp8266UartInverted> NeoEsp8266Uart0800KbpsInvertedMethod;
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeed400Kbps, NeoEsp8266Uart<UartFeature0, NeoEsp8266UartContext>, NeoEsp8266UartInverted> NeoEsp8266Uart0400KbpsInvertedMethod;
typedef NeoEsp8266Uart0Ws2812xInvertedMethod NeoEsp8266Uart0Ws2813InvertedMethod;
typedef NeoEsp8266Uart0800KbpsInvertedMethod NeoEsp8266Uart0Ws2812InvertedMethod;
typedef NeoEsp8266Uart0Ws2812xInvertedMethod NeoEsp8266Uart0Ws2811InvertedMethod;
typedef NeoEsp8266Uart0Sk6812InvertedMethod NeoEsp8266Uart0Lc8812InvertedMethod;
// uart 1
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedWs2812x, NeoEsp8266Uart<UartFeature1, NeoEsp8266UartContext>, NeoEsp8266UartInverted> NeoEsp8266Uart1Ws2812xInvertedMethod;
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedSk6812, NeoEsp8266Uart<UartFeature1, NeoEsp8266UartContext>, NeoEsp8266UartInverted> NeoEsp8266Uart1Sk6812InvertedMethod;
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedTm1814, NeoEsp8266Uart<UartFeature1, NeoEsp8266UartContext>, NeoEsp8266UartNotInverted> NeoEsp8266Uart1Tm1814InvertedMethod;
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedApa106, NeoEsp8266Uart<UartFeature1, NeoEsp8266UartContext>, NeoEsp8266UartInverted> NeoEsp8266Uart1Apa106InvertedMethod;
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeed800Kbps, NeoEsp8266Uart<UartFeature1, NeoEsp8266UartContext>, NeoEsp8266UartInverted> NeoEsp8266Uart1800KbpsInvertedMethod;
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeed400Kbps, NeoEsp8266Uart<UartFeature1, NeoEsp8266UartContext>, NeoEsp8266UartInverted> NeoEsp8266Uart1400KbpsInvertedMethod;
typedef NeoEsp8266Uart1Ws2812xInvertedMethod NeoEsp8266Uart1Ws2813InvertedMethod;
typedef NeoEsp8266Uart1800KbpsInvertedMethod NeoEsp8266Uart1Ws2812InvertedMethod;
typedef NeoEsp8266Uart1Ws2812xInvertedMethod NeoEsp8266Uart1Ws2811InvertedMethod;
typedef NeoEsp8266Uart1Sk6812InvertedMethod NeoEsp8266Uart1Lc8812InvertedMethod;
// uart 0 async
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedWs2812x, NeoEsp8266AsyncUart<UartFeature0, NeoEsp8266UartInterruptContext>, NeoEsp8266UartInverted> NeoEsp8266AsyncUart0Ws2812xInvertedMethod;
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedSk6812, NeoEsp8266AsyncUart<UartFeature0, NeoEsp8266UartInterruptContext>, NeoEsp8266UartInverted> NeoEsp8266AsyncUart0Sk6812InvertedMethod;
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedTm1814, NeoEsp8266AsyncUart<UartFeature0, NeoEsp8266UartInterruptContext>, NeoEsp8266UartNotInverted> NeoEsp8266AsyncUart0Tm1814InvertedMethod;
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedApa106, NeoEsp8266AsyncUart<UartFeature0, NeoEsp8266UartInterruptContext>, NeoEsp8266UartInverted> NeoEsp8266AsyncUart0Apa106InvertedMethod;
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeed800Kbps, NeoEsp8266AsyncUart<UartFeature0, NeoEsp8266UartInterruptContext>, NeoEsp8266UartInverted> NeoEsp8266AsyncUart0800KbpsInvertedMethod;
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeed400Kbps, NeoEsp8266AsyncUart<UartFeature0, NeoEsp8266UartInterruptContext>, NeoEsp8266UartInverted> NeoEsp8266AsyncUart0400KbpsInvertedMethod;
typedef NeoEsp8266AsyncUart0Ws2812xInvertedMethod NeoEsp8266AsyncUart0Ws2813InvertedMethod;
typedef NeoEsp8266AsyncUart0800KbpsInvertedMethod NeoEsp8266AsyncUart0Ws2812InvertedMethod;
typedef NeoEsp8266AsyncUart0Ws2812xInvertedMethod NeoEsp8266AsyncUart0Ws2811InvertedMethod;
typedef NeoEsp8266AsyncUart0Sk6812InvertedMethod NeoEsp8266AsyncUart0Lc8812InvertedMethod;
// uart 1 async
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedWs2812x, NeoEsp8266AsyncUart<UartFeature1, NeoEsp8266UartInterruptContext>, NeoEsp8266UartInverted> NeoEsp8266AsyncUart1Ws2812xInvertedMethod;
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedSk6812, NeoEsp8266AsyncUart<UartFeature1, NeoEsp8266UartInterruptContext>, NeoEsp8266UartInverted> NeoEsp8266AsyncUart1Sk6812InvertedMethod;
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedTm1814, NeoEsp8266AsyncUart<UartFeature1, NeoEsp8266UartInterruptContext>, NeoEsp8266UartNotInverted> NeoEsp8266AsyncUart1Tm1814InvertedMethod;
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedApa106, NeoEsp8266AsyncUart<UartFeature1, NeoEsp8266UartInterruptContext>, NeoEsp8266UartInverted> NeoEsp8266AsyncUart1Apa106InvertedMethod;
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeed800Kbps, NeoEsp8266AsyncUart<UartFeature1, NeoEsp8266UartInterruptContext>, NeoEsp8266UartInverted> NeoEsp8266AsyncUart1800KbpsInvertedMethod;
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeed400Kbps, NeoEsp8266AsyncUart<UartFeature1, NeoEsp8266UartInterruptContext>, NeoEsp8266UartInverted> NeoEsp8266AsyncUart1400KbpsInvertedMethod;
typedef NeoEsp8266AsyncUart1Ws2812xInvertedMethod NeoEsp8266AsyncUart1Ws2813InvertedMethod;
typedef NeoEsp8266AsyncUart1800KbpsInvertedMethod NeoEsp8266AsyncUart1Ws2812InvertedMethod;
typedef NeoEsp8266AsyncUart1Ws2812xInvertedMethod NeoEsp8266AsyncUart1Ws2811InvertedMethod;
typedef NeoEsp8266AsyncUart1Sk6812InvertedMethod NeoEsp8266AsyncUart1Lc8812InvertedMethod;
#endif

View File

@@ -0,0 +1,401 @@
/*-------------------------------------------------------------------------
NeoPixel library helper functions for Esp8266 and Esp32
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
#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
#if defined(ARDUINO_ARCH_ESP8266)
#include <eagle_soc.h>
#endif
// ESP32 doesn't define ICACHE_RAM_ATTR
#ifndef ICACHE_RAM_ATTR
#define ICACHE_RAM_ATTR IRAM_ATTR
#endif
#define CYCLES_LOOPTEST (4) // adjustment due to loop exit test instruction cycles
class NeoEspSpeedWs2811
{
public:
const static uint32_t T0H = (F_CPU / 3333333 - CYCLES_LOOPTEST); // 0.3us
const static uint32_t T1H = (F_CPU / 1052632 - CYCLES_LOOPTEST); // 0.95us
const static uint32_t Period = (F_CPU / 800000 - CYCLES_LOOPTEST); // 1.25us per bit
};
class NeoEspSpeedTm1814
{
public:
const static uint32_t T0H = (F_CPU / 2916666 - CYCLES_LOOPTEST); // 0.35us
const static uint32_t T1H = (F_CPU / 1666666 - CYCLES_LOOPTEST); // 0.75us
const static uint32_t Period = (F_CPU / 800000 - CYCLES_LOOPTEST); // 1.25us per bit
};
class NeoEspSpeed800Mhz
{
public:
const static uint32_t T0H = (F_CPU / 2500000 - CYCLES_LOOPTEST); // 0.4us
const static uint32_t T1H = (F_CPU / 1250000 - CYCLES_LOOPTEST); // 0.8us
const static uint32_t Period = (F_CPU / 800000 - CYCLES_LOOPTEST); // 1.25us per bit
};
class NeoEspSpeed400Mhz
{
public:
const static uint32_t T0H = (F_CPU / 2000000 - CYCLES_LOOPTEST);
const static uint32_t T1H = (F_CPU / 833333 - CYCLES_LOOPTEST);
const static uint32_t Period = (F_CPU / 400000 - CYCLES_LOOPTEST);
};
class NeoEspPinset
{
public:
const static uint8_t IdleLevel = LOW;
inline static void setPin(const uint32_t pinRegister)
{
#if defined(ARDUINO_ARCH_ESP32)
GPIO.out_w1ts = pinRegister;
#else
GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, pinRegister);
#endif
}
inline static void resetPin(const uint32_t pinRegister)
{
#if defined(ARDUINO_ARCH_ESP32)
GPIO.out_w1tc = pinRegister;
#else
GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, pinRegister);
#endif
}
};
class NeoEspPinsetInverted
{
public:
const static uint8_t IdleLevel = HIGH;
inline static void setPin(const uint32_t pinRegister)
{
#if defined(ARDUINO_ARCH_ESP32)
GPIO.out_w1tc = pinRegister;
#else
GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, pinRegister);
#endif
}
inline static void resetPin(const uint32_t pinRegister)
{
#if defined(ARDUINO_ARCH_ESP32)
GPIO.out_w1ts = pinRegister;
#else
GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, pinRegister);
#endif
}
};
template<typename T_SPEED, typename T_PINSET> class NeoEspBitBangBase
{
public:
__attribute__((noinline)) static void ICACHE_RAM_ATTR send_pixels(uint8_t* pixels, uint8_t* end, uint8_t pin)
{
const uint32_t pinRegister = _BV(pin);
uint8_t mask = 0x80;
uint8_t subpix = *pixels++;
uint32_t cyclesStart = 0; // trigger emediately
uint32_t cyclesNext = 0;
for (;;)
{
// do the checks here while we are waiting on time to pass
uint32_t cyclesBit = T_SPEED::T0H;
if (subpix & mask)
{
cyclesBit = T_SPEED::T1H;
}
// after we have done as much work as needed for this next bit
// now wait for the HIGH
while (((cyclesStart = getCycleCount()) - cyclesNext) < T_SPEED::Period);
// set pin state
T_PINSET::setPin(pinRegister);
// wait for the LOW
while ((getCycleCount() - cyclesStart) < cyclesBit);
// reset pin start
T_PINSET::resetPin(pinRegister);
cyclesNext = cyclesStart;
// next bit
mask >>= 1;
if (mask == 0)
{
// no more bits to send in this byte
// check for another byte
if (pixels >= end)
{
// no more bytes to send so stop
break;
}
// reset mask to first bit and get the next byte
mask = 0x80;
subpix = *pixels++;
}
}
}
protected:
static inline uint32_t getCycleCount(void)
{
uint32_t ccount;
__asm__ __volatile__("rsr %0,ccount":"=a" (ccount));
return ccount;
}
};
class NeoEspBitBangSpeedWs2811 : public NeoEspBitBangBase<NeoEspSpeedWs2811, NeoEspPinset>
{
public:
static const uint32_t ResetTimeUs = 300;
};
class NeoEspBitBangSpeedWs2812x : public NeoEspBitBangBase<NeoEspSpeed800Mhz, NeoEspPinset>
{
public:
static const uint32_t ResetTimeUs = 300;
};
class NeoEspBitBangSpeedSk6812 : public NeoEspBitBangBase<NeoEspSpeed800Mhz, NeoEspPinset>
{
public:
static const uint32_t ResetTimeUs = 80;
};
// normal is inverted signal
class NeoEspBitBangSpeedTm1814 : public NeoEspBitBangBase<NeoEspSpeedTm1814, NeoEspPinsetInverted>
{
public:
static const uint32_t ResetTimeUs = 200;
};
class NeoEspBitBangSpeed800Kbps : public NeoEspBitBangBase<NeoEspSpeed800Mhz, NeoEspPinset>
{
public:
static const uint32_t ResetTimeUs = 50;
};
class NeoEspBitBangSpeed400Kbps : public NeoEspBitBangBase<NeoEspSpeed400Mhz, NeoEspPinset>
{
public:
static const uint32_t ResetTimeUs = 50;
};
class NeoEspBitBangInvertedSpeedWs2811 : public NeoEspBitBangBase<NeoEspSpeedWs2811, NeoEspPinsetInverted>
{
public:
static const uint32_t ResetTimeUs = 300;
};
class NeoEspBitBangInvertedSpeedWs2812x : public NeoEspBitBangBase<NeoEspSpeed800Mhz, NeoEspPinsetInverted>
{
public:
static const uint32_t ResetTimeUs = 300;
};
class NeoEspBitBangInvertedSpeedSk6812 : public NeoEspBitBangBase<NeoEspSpeed800Mhz, NeoEspPinsetInverted>
{
public:
static const uint32_t ResetTimeUs = 80;
};
// normal is inverted signal, so inverted is normal
class NeoEspBitBangInvertedSpeedTm1814 : public NeoEspBitBangBase<NeoEspSpeedTm1814, NeoEspPinset>
{
public:
static const uint32_t ResetTimeUs = 200;
};
class NeoEspBitBangInvertedSpeed800Kbps : public NeoEspBitBangBase<NeoEspSpeed800Mhz, NeoEspPinsetInverted>
{
public:
static const uint32_t ResetTimeUs = 50;
};
class NeoEspBitBangInvertedSpeed400Kbps : public NeoEspBitBangBase<NeoEspSpeed400Mhz, NeoEspPinsetInverted>
{
public:
static const uint32_t ResetTimeUs = 50;
};
template<typename T_SPEED, typename T_PINSET> class NeoEspBitBangMethodBase
{
public:
NeoEspBitBangMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize) :
_sizeData(pixelCount * elementSize + settingsSize),
_pin(pin)
{
pinMode(pin, OUTPUT);
_data = static_cast<uint8_t*>(malloc(_sizeData));
memset(_data, 0, _sizeData);
}
~NeoEspBitBangMethodBase()
{
pinMode(_pin, INPUT);
free(_data);
}
bool IsReadyToUpdate() const
{
uint32_t delta = micros() - _endTime;
return (delta >= T_SPEED::ResetTimeUs);
}
void Initialize()
{
digitalWrite(_pin, T_PINSET::IdleLevel);
_endTime = micros();
}
void Update(bool)
{
// Data latch = 50+ microsecond pause in the output stream. Rather than
// put a delay at the end of the function, the ending time is noted and
// the function will simply hold off (if needed) on issuing the
// subsequent round of data until the latch time has elapsed. This
// allows the mainline code to start generating the next frame of data
// rather than stalling for the latch.
while (!IsReadyToUpdate())
{
yield(); // allows for system yield if needed
}
// Need 100% focus on instruction timing
#if defined(ARDUINO_ARCH_ESP32)
delay(1); // required
portMUX_TYPE updateMux = portMUX_INITIALIZER_UNLOCKED;
portENTER_CRITICAL(&updateMux);
#else
noInterrupts();
#endif
T_SPEED::send_pixels(_data, _data + _sizeData, _pin);
#if defined(ARDUINO_ARCH_ESP32)
portEXIT_CRITICAL(&updateMux);
#else
interrupts();
#endif
// save EOD time for latch on next call
_endTime = micros();
}
uint8_t* getData() const
{
return _data;
};
size_t getDataSize() const
{
return _sizeData;
};
private:
const size_t _sizeData; // Size of '_data' buffer below
const uint8_t _pin; // output pin number
uint32_t _endTime; // Latch timing reference
uint8_t* _data; // Holds LED color values
};
#if defined(ARDUINO_ARCH_ESP32)
typedef NeoEspBitBangMethodBase<NeoEspBitBangSpeedWs2811, NeoEspPinset> NeoEsp32BitBangWs2811Method;
typedef NeoEspBitBangMethodBase<NeoEspBitBangSpeedWs2812x, NeoEspPinset> NeoEsp32BitBangWs2812xMethod;
typedef NeoEspBitBangMethodBase<NeoEspBitBangSpeedSk6812, NeoEspPinset> NeoEsp32BitBangSk6812Method;
typedef NeoEspBitBangMethodBase<NeoEspBitBangSpeedTm1814, NeoEspPinsetInverted> NeoEsp32BitBangTm1814Method;
typedef NeoEspBitBangMethodBase<NeoEspBitBangSpeed800Kbps, NeoEspPinset> NeoEsp32BitBang800KbpsMethod;
typedef NeoEspBitBangMethodBase<NeoEspBitBangSpeed400Kbps, NeoEspPinset> NeoEsp32BitBang400KbpsMethod;
typedef NeoEsp32BitBangWs2812xMethod NeoEsp32BitBangWs2813Method;
typedef NeoEsp32BitBang800KbpsMethod NeoEsp32BitBangWs2812Method;
typedef NeoEsp32BitBangSk6812Method NeoEsp32BitBangLc8812Method;
typedef NeoEsp32BitBang400KbpsMethod NeoEsp32BitBangApa106Method;
typedef NeoEspBitBangMethodBase<NeoEspBitBangInvertedSpeedWs2811, NeoEspPinsetInverted> NeoEsp32BitBangWs2811InvertedMethod;
typedef NeoEspBitBangMethodBase<NeoEspBitBangInvertedSpeedWs2812x, NeoEspPinsetInverted> NeoEsp32BitBangWs2812xInvertedMethod;
typedef NeoEspBitBangMethodBase<NeoEspBitBangInvertedSpeedSk6812, NeoEspPinsetInverted> NeoEsp32BitBangSk6812InvertedMethod;
typedef NeoEspBitBangMethodBase<NeoEspBitBangInvertedSpeedTm1814, NeoEspPinset> NeoEsp32BitBangTm1814InvertedMethod;
typedef NeoEspBitBangMethodBase<NeoEspBitBangInvertedSpeed800Kbps, NeoEspPinsetInverted> NeoEsp32BitBang800KbpsInvertedMethod;
typedef NeoEspBitBangMethodBase<NeoEspBitBangInvertedSpeed400Kbps, NeoEspPinsetInverted> NeoEsp32BitBang400KbpsInvertedMethod;
typedef NeoEsp32BitBangWs2812xInvertedMethod NeoEsp32BitBangWs2813InvertedMethod;
typedef NeoEsp32BitBang800KbpsInvertedMethod NeoEsp32BitBangWs2812InvertedMethod;
typedef NeoEsp32BitBangSk6812InvertedMethod NeoEsp32BitBangLc8812InvertedMethod;
typedef NeoEsp32BitBang400KbpsInvertedMethod NeoEsp32BitBangApa106InvertedMethod;
#else
typedef NeoEspBitBangMethodBase<NeoEspBitBangSpeedWs2811, NeoEspPinset> NeoEsp8266BitBangWs2811Method;
typedef NeoEspBitBangMethodBase<NeoEspBitBangSpeedWs2812x, NeoEspPinset> NeoEsp8266BitBangWs2812xMethod;
typedef NeoEspBitBangMethodBase<NeoEspBitBangSpeedSk6812, NeoEspPinset> NeoEsp8266BitBangSk6812Method;
typedef NeoEspBitBangMethodBase<NeoEspBitBangSpeedTm1814, NeoEspPinsetInverted> NeoEsp8266BitBangTm1814Method;
typedef NeoEspBitBangMethodBase<NeoEspBitBangSpeed800Kbps, NeoEspPinset> NeoEsp8266BitBang800KbpsMethod;
typedef NeoEspBitBangMethodBase<NeoEspBitBangSpeed400Kbps, NeoEspPinset> NeoEsp8266BitBang400KbpsMethod;
typedef NeoEsp8266BitBangWs2812xMethod NeoEsp8266BitBangWs2813Method;
typedef NeoEsp8266BitBang800KbpsMethod NeoEsp8266BitBangWs2812Method;
typedef NeoEsp8266BitBangSk6812Method NeoEsp8266BitBangLc8812Method;
typedef NeoEsp8266BitBang400KbpsMethod NeoEsp8266BitBangApa106Method;
typedef NeoEspBitBangMethodBase<NeoEspBitBangInvertedSpeedWs2811, NeoEspPinsetInverted> NeoEsp8266BitBangWs2811InvertedMethod;
typedef NeoEspBitBangMethodBase<NeoEspBitBangInvertedSpeedWs2812x, NeoEspPinsetInverted> NeoEsp8266BitBangWs2812xInvertedMethod;
typedef NeoEspBitBangMethodBase<NeoEspBitBangInvertedSpeedSk6812, NeoEspPinsetInverted> NeoEsp8266BitBangSk6812InvertedMethod;
typedef NeoEspBitBangMethodBase<NeoEspBitBangInvertedSpeedTm1814, NeoEspPinset> NeoEsp8266BitBangTm1814InvertedMethod;
typedef NeoEspBitBangMethodBase<NeoEspBitBangInvertedSpeed800Kbps, NeoEspPinsetInverted> NeoEsp8266BitBang800KbpsInvertedMethod;
typedef NeoEspBitBangMethodBase<NeoEspBitBangInvertedSpeed400Kbps, NeoEspPinsetInverted> NeoEsp8266BitBang400KbpsInvertedMethod;
typedef NeoEsp8266BitBangWs2812xInvertedMethod NeoEsp8266BitBangWs2813InvertedMethod;
typedef NeoEsp8266BitBang800KbpsInvertedMethod NeoEsp8266BitBangWs2812InvertedMethod;
typedef NeoEsp8266BitBangSk6812InvertedMethod NeoEsp8266BitBangLc8812InvertedMethod;
typedef NeoEsp8266BitBang400KbpsInvertedMethod NeoEsp8266BitBangApa106InvertedMethod;
#endif
// ESP bitbang doesn't have defaults and should avoided except for testing
#endif

View File

@@ -0,0 +1,47 @@
/*-------------------------------------------------------------------------
NeoPixelGamma class is used to correct RGB colors for human eye gamma levels
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 <Arduino.h>
#include "NeoPixelBus.h"
const uint8_t NeoGammaTableMethod::_table[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2,
3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6,
6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 11, 11, 11,
12, 12, 13, 13, 14, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19,
19, 20, 20, 21, 22, 22, 23, 23, 24, 25, 25, 26, 26, 27, 28, 28,
29, 30, 30, 31, 32, 33, 33, 34, 35, 35, 36, 37, 38, 39, 39, 40,
41, 42, 43, 43, 44, 45, 46, 47, 48, 49, 50, 50, 51, 52, 53, 54,
55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 71,
72, 73, 74, 75, 76, 77, 78, 80, 81, 82, 83, 84, 86, 87, 88, 89,
91, 92, 93, 94, 96, 97, 98, 100, 101, 102, 104, 105, 106, 108, 109, 110,
112, 113, 115, 116, 118, 119, 121, 122, 123, 125, 126, 128, 130, 131, 133, 134,
136, 137, 139, 140, 142, 144, 145, 147, 149, 150, 152, 154, 155, 157, 159, 160,
162, 164, 166, 167, 169, 171, 173, 175, 176, 178, 180, 182, 184, 186, 187, 189,
191, 193, 195, 197, 199, 201, 203, 205, 207, 209, 211, 213, 215, 217, 219, 221,
223, 225, 227, 229, 231, 233, 235, 238, 240, 242, 244, 246, 248, 251, 253, 255
};

View File

@@ -0,0 +1,74 @@
/*-------------------------------------------------------------------------
NeoGamma class is used to correct RGB colors for human eye gamma levels equally
across all color channels
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
// NeoGammaEquationMethod uses no memory but is slower than NeoGammaTableMethod
class NeoGammaEquationMethod
{
public:
static uint8_t Correct(uint8_t value)
{
return static_cast<uint8_t>(255.0f * NeoEase::Gamma(value / 255.0f) + 0.5f);
}
};
// NeoGammaTableMethod uses 256 bytes of memory, but is significantly faster
class NeoGammaTableMethod
{
public:
static uint8_t Correct(uint8_t value)
{
return _table[value];
}
private:
static const uint8_t _table[256];
};
// use one of the method classes above as a converter for this template class
template<typename T_METHOD> class NeoGamma
{
public:
RgbColor Correct(const RgbColor& original)
{
return RgbColor(T_METHOD::Correct(original.R),
T_METHOD::Correct(original.G),
T_METHOD::Correct(original.B));
}
RgbwColor Correct(const RgbwColor& original)
{
return RgbwColor(T_METHOD::Correct(original.R),
T_METHOD::Correct(original.G),
T_METHOD::Correct(original.B),
T_METHOD::Correct(original.W) );
}
};

View File

@@ -0,0 +1,118 @@
/*-------------------------------------------------------------------------
NeoHueBlend provides method objects that can be directly consumed by
blend template functions in HslColor and HsbColor
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 NeoHueBlendBase
{
protected:
static float FixWrap(float value)
{
if (value < 0.0f)
{
value += 1.0f;
}
else if (value > 1.0f)
{
value -= 1.0f;
}
return value;
}
};
class NeoHueBlendShortestDistance : NeoHueBlendBase
{
public:
static float HueBlend(float left, float right, float progress)
{
float delta = right - left;
float base = left;
if (delta > 0.5f)
{
base = right;
delta = 1.0f - delta;
progress = 1.0f - progress;
}
else if (delta < -0.5f)
{
delta = 1.0f + delta;
}
return FixWrap(base + (delta) * progress);
};
};
class NeoHueBlendLongestDistance : NeoHueBlendBase
{
public:
static float HueBlend(float left, float right, float progress)
{
float delta = right - left;
float base = left;
if (delta < 0.5f && delta >= 0.0f)
{
base = right;
delta = 1.0f - delta;
progress = 1.0f - progress;
}
else if (delta > -0.5f && delta < 0.0f)
{
delta = 1.0f + delta;
}
return FixWrap(base + delta * progress);
};
};
class NeoHueBlendClockwiseDirection : NeoHueBlendBase
{
public:
static float HueBlend(float left, float right, float progress)
{
float delta = right - left;
float base = left;
if (delta < 0.0f)
{
delta = 1.0f + delta;
}
return FixWrap(base + delta * progress);
};
};
class NeoHueBlendCounterClockwiseDirection : NeoHueBlendBase
{
public:
static float HueBlend(float left, float right, float progress)
{
float delta = right - left;
float base = left;
if (delta > 0.0f)
{
delta = delta - 1.0f;
}
return FixWrap(base + delta * progress);
};
};

View File

@@ -0,0 +1,191 @@
#pragma once
/*-------------------------------------------------------------------------
Mosiac provides a mapping feature of a 2d cordinate to linear 1d cordinate
It is used to map tiles of matricies of NeoPixels to a index on the NeoPixelBus
where the the matricies use a set of prefered topology and the tiles of
those matricies use the RowMajorAlternating layout
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/>.
-------------------------------------------------------------------------*/
//-----------------------------------------------------------------------------
// class NeoMosaic
// Complex Tile layout class that reduces distance of the interconnects between
// the tiles by using different rotations of the layout at specific locations
//
// T_LAYOUT = the layout used for matrix panel (rotation is ignored)
//
// NOTE: The tiles in the mosaic are always laid out using RowMajorAlternating
//
//-----------------------------------------------------------------------------
template <typename T_LAYOUT> class NeoMosaic
{
public:
NeoMosaic(uint16_t topoWidth, uint16_t topoHeight,
uint16_t mosaicWidth, uint16_t mosaicHeight) :
_topoWidth(topoWidth),
_topoHeight(topoHeight),
_mosaicWidth(mosaicWidth),
_mosaicHeight(mosaicHeight)
{
}
uint16_t Map(int16_t x, int16_t y) const
{
uint16_t totalWidth = getWidth();
uint16_t totalHeight = getHeight();
if (x >= totalWidth)
{
x = totalWidth - 1;
}
else if (x < 0)
{
x = 0;
}
if (y >= totalHeight)
{
y = totalHeight - 1;
}
else if (y < 0)
{
y = 0;
}
uint16_t localIndex;
uint16_t tileOffset;
calculate(x, y, &localIndex, &tileOffset);
return localIndex + tileOffset;
}
uint16_t MapProbe(int16_t x, int16_t y) const
{
uint16_t totalWidth = getWidth();
uint16_t totalHeight = getHeight();
if (x < 0 || x >= totalWidth || y < 0 || y >= totalHeight)
{
return totalWidth * totalHeight; // count, out of bounds
}
uint16_t localIndex;
uint16_t tileOffset;
calculate(x, y, &localIndex, &tileOffset);
return localIndex + tileOffset;
}
NeoTopologyHint TopologyHint(int16_t x, int16_t y) const
{
uint16_t totalWidth = getWidth();
uint16_t totalHeight = getHeight();
if (x < 0 || x >= totalWidth || y < 0 || y >= totalHeight)
{
return NeoTopologyHint_OutOfBounds;
}
uint16_t localIndex;
uint16_t tileOffset;
NeoTopologyHint result;
calculate(x, y, &localIndex, &tileOffset);
if (localIndex == 0)
{
result = NeoTopologyHint_FirstOnPanel;
}
else if (localIndex == (_topoWidth * _topoHeight - 1))
{
result = NeoTopologyHint_LastOnPanel;
}
else
{
result = NeoTopologyHint_InPanel;
}
return result;
}
uint16_t getWidth() const
{
return _topoWidth * _mosaicWidth;
}
uint16_t getHeight() const
{
return _topoHeight * _mosaicHeight;
}
private:
const uint16_t _topoWidth;
const uint16_t _topoHeight;
const uint16_t _mosaicWidth;
const uint16_t _mosaicHeight;
void calculate(uint16_t x, uint16_t y, uint16_t* pLocalIndex, uint16_t* pTileOffset) const
{
uint16_t tileX = x / _topoWidth;
uint16_t topoX = x % _topoWidth;
uint16_t tileY = y / _topoHeight;
uint16_t topoY = y % _topoHeight;
*pTileOffset = RowMajorAlternatingLayout::Map(_mosaicWidth,
_mosaicHeight,
tileX,
tileY) * _topoWidth * _topoHeight;
if (tileX & 0x0001)
{
// odd columns
if (tileY & 0x0001)
{
*pLocalIndex = T_LAYOUT::OddRowOddColumnLayout::Map(_topoWidth, _topoHeight, topoX, topoY);
}
else
{
*pLocalIndex = T_LAYOUT::EvenRowOddColumnLayout::Map(_topoWidth, _topoHeight, topoX, topoY);
}
}
else
{
// even columns
if (tileY & 0x0001)
{
*pLocalIndex = T_LAYOUT::OddRowEvenColumnLayout::Map(_topoWidth, _topoHeight, topoX, topoY);
}
else
{
*pLocalIndex = T_LAYOUT::EvenRowEvenColumnLayout::Map(_topoWidth, _topoHeight, topoX, topoY);
}
}
}
};

View File

@@ -0,0 +1,490 @@
/*-------------------------------------------------------------------------
NeoPixel library helper classes for Nrf52* MCUs.
Nano 33 BLE
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.
The contents of this file were taken from the Adafruit NeoPixel library
and modified only to fit within individual calling functions.
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
#if defined(ARDUINO_ARCH_NRF52840)
const uint16_t c_dmaBytesPerDataByte = 8 * sizeof(nrf_pwm_values_common_t); // bits * bytes to represent pulse
// for Bit* variables
// count 1 = 0.0625us, so max count (32768) is 2048us
class NeoNrf52xPwmSpeedWs2811
{
public:
const static uint32_t CountTop = 20UL; // 1.25us
const static nrf_pwm_values_common_t Bit0 = 5 | 0x8000; // ~0.3us
const static nrf_pwm_values_common_t Bit1 = 14 | 0x8000; // ~0.9us
const static nrf_pwm_values_common_t BitReset = 0x8000; // LOW
const static uint16_t CountReset = 240; // 300 us / 1.25us
const static PinStatus IdleLevel = LOW;
};
class NeoNrf52xPwmSpeedWs2812x
{
public:
const static uint32_t CountTop = 20UL; // 1.25us
const static nrf_pwm_values_common_t Bit0 = 6 | 0x8000; // ~0.4us
const static nrf_pwm_values_common_t Bit1 = 13 | 0x8000; // ~0.8us
const static nrf_pwm_values_common_t BitReset = 0x8000; // LOW
const static uint32_t CountReset = 240 ; // 300us / 1.25us pulse width
const static PinStatus IdleLevel = LOW;
};
class NeoNrf52xPwmSpeedSk6812
{
public:
const static uint32_t CountTop = 20UL; // 1.25us
const static nrf_pwm_values_common_t Bit0 = 6 | 0x8000; // ~0.4us
const static nrf_pwm_values_common_t Bit1 = 13 | 0x8000; // ~0.8us
const static nrf_pwm_values_common_t BitReset = 0x8000; // LOW
const static uint32_t CountReset = 64; // 80us / 1.25us pulse width
const static PinStatus IdleLevel = LOW;
};
class NeoNrf52xPwmSpeedTm1814
{
public:
const static uint32_t CountTop = 20UL; // 1.25us
const static nrf_pwm_values_common_t Bit0 = 5; // ~0.3us
const static nrf_pwm_values_common_t Bit1 = 12; // ~0.7us
const static nrf_pwm_values_common_t BitReset = 0x0000; // HIGH
const static uint32_t CountReset = 160; // 200us / 1.25us pulse width
const static PinStatus IdleLevel = HIGH;
};
class NeoNrf52xPwmSpeed800Kbps
{
public:
const static uint32_t CountTop = 20UL; // 1.25us
const static nrf_pwm_values_common_t Bit0 = 6 | 0x8000; // ~0.4us
const static nrf_pwm_values_common_t Bit1 = 13 | 0x8000; // ~0.8us
const static nrf_pwm_values_common_t BitReset = 0x8000; // LOW
const static uint32_t CountReset = 40; // 50us / 1.25us pulse width
const static PinStatus IdleLevel = LOW;
};
class NeoNrf52xPwmSpeed400Kbps
{
public:
const static uint32_t CountTop = 40UL; // 2.5us
const static nrf_pwm_values_common_t Bit0 = 13 | 0x8000; // ~0.8us
const static nrf_pwm_values_common_t Bit1 = 26 | 0x8000; // ~1.6us
const static nrf_pwm_values_common_t BitReset = 0x8000; // LOW
const static uint16_t CountReset = 20; // 50 us / 2.5us
const static PinStatus IdleLevel = LOW;
};
class NeoNrf52xPwmSpeedApa106
{
public:
const static uint32_t CountTop = 26UL; // 1.65us
const static nrf_pwm_values_common_t Bit0 = 6 | 0x8000; // ~0.4us
const static nrf_pwm_values_common_t Bit1 = 20 | 0x8000; // ~1.25us
const static nrf_pwm_values_common_t BitReset = 0x8000; // LOW
const static uint32_t CountReset = 40; // 50us / 1.25us pulse width
const static PinStatus IdleLevel = LOW;
};
class NeoNrf52xPwmInvertedSpeedWs2811
{
public:
const static uint32_t CountTop = 20UL; // 1.25us
const static nrf_pwm_values_common_t Bit0 = 5; // ~0.3us
const static nrf_pwm_values_common_t Bit1 = 14; // ~0.9us
const static nrf_pwm_values_common_t BitReset = 0x0000; // HIGH
const static uint16_t CountReset = 240; // 300 us / 1.25us
const static PinStatus IdleLevel = HIGH;
};
class NeoNrf52xPwmInvertedSpeedWs2812x
{
public:
const static uint32_t CountTop = 20UL; // 1.25us
const static nrf_pwm_values_common_t Bit0 = 6; // ~0.4us
const static nrf_pwm_values_common_t Bit1 = 13; // ~0.8us
const static nrf_pwm_values_common_t BitReset = 0x0000; // HIGH
const static uint32_t CountReset = 240; // 300us / 1.25us pulse width
const static PinStatus IdleLevel = HIGH;
};
class NeoNrf52xPwmInvertedSpeedSk6812
{
public:
const static uint32_t CountTop = 20UL; // 1.25us
const static nrf_pwm_values_common_t Bit0 = 6; // ~0.4us
const static nrf_pwm_values_common_t Bit1 = 13; // ~0.8us
const static nrf_pwm_values_common_t BitReset = 0x0000; // HIGH
const static uint32_t CountReset = 64; // 80us / 1.25us pulse width
const static PinStatus IdleLevel = HIGH;
};
class NeoNrf52xPwmInvertedSpeedTm1814
{
public:
const static uint32_t CountTop = 20UL; // 1.25us
const static nrf_pwm_values_common_t Bit0 = 5 | 0x8000; // ~0.3us
const static nrf_pwm_values_common_t Bit1 = 12 | 0x8000; // ~0.7us
const static nrf_pwm_values_common_t BitReset = 0x8000; // LOW
const static uint32_t CountReset = 160; // 200us / 1.25us pulse width
const static PinStatus IdleLevel = LOW;
};
class NeoNrf52xPwmInvertedSpeed800Kbps
{
public:
const static uint32_t CountTop = 20UL; // 1.25us
const static nrf_pwm_values_common_t Bit0 = 6; // ~0.4us
const static nrf_pwm_values_common_t Bit1 = 13; // ~0.8us
const static nrf_pwm_values_common_t BitReset = 0x0000; // HIGH
const static uint32_t CountReset = 40; // 50us / 1.25us pulse width
const static PinStatus IdleLevel = HIGH;
};
class NeoNrf52xPwmInvertedSpeed400Kbps
{
public:
const static uint32_t CountTop = 40UL; // 2.5us
const static nrf_pwm_values_common_t Bit0 = 13; // ~0.8us
const static nrf_pwm_values_common_t Bit1 = 26; // ~1.6us
const static nrf_pwm_values_common_t BitReset = 0x0000; // HIGH
const static uint16_t CountReset = 20; // 50 us / 2.5us
const static PinStatus IdleLevel = HIGH;
};
class NeoNrf52xPwmInvertedSpeedApa106
{
public:
const static uint32_t CountTop = 26UL; // 1.65us
const static nrf_pwm_values_common_t Bit0 = 6; // ~0.4us
const static nrf_pwm_values_common_t Bit1 = 20; // ~1.25us
const static nrf_pwm_values_common_t BitReset = 0x0000; // HIGH
const static uint32_t CountReset = 40; // 50us / 1.25us pulse width
const static PinStatus IdleLevel = HIGH;
};
class NeoNrf52xPwm0
{
public:
inline static NRF_PWM_Type* Pwm()
{
return NRF_PWM0;
}
};
class NeoNrf52xPwm1
{
public:
inline static NRF_PWM_Type* Pwm()
{
return NRF_PWM1;
}
};
class NeoNrf52xPwm2
{
public:
inline static NRF_PWM_Type* Pwm()
{
return NRF_PWM2;
}
};
#if defined(NRF_PWM3)
class NeoNrf52xPwm3
{
public:
inline static NRF_PWM_Type* Pwm()
{
return NRF_PWM3;
}
};
#endif
template<typename T_SPEED, typename T_BUS> class NeoNrf52xMethodBase
{
public:
NeoNrf52xMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize) :
_sizeData(pixelCount * elementSize + settingsSize),
_pin(pin)
{
pinMode(pin, OUTPUT);
_data = static_cast<uint8_t*>(malloc(_sizeData));
memset(_data, 0, _sizeData);
_dmaBufferSize = c_dmaBytesPerDataByte * _sizeData + sizeof(nrf_pwm_values_common_t);
_dmaBuffer = static_cast<nrf_pwm_values_common_t*>(malloc(_dmaBufferSize));
}
~NeoNrf52xMethodBase()
{
while (!IsReadyToUpdate())
{
yield();
}
dmaDeinit();
pinMode(_pin, INPUT);
free(_data);
free(_dmaBuffer);
}
bool IsReadyToUpdate() const
{
return (T_BUS::Pwm()->EVENTS_STOPPED);
}
void Initialize()
{
digitalWrite(_pin, T_SPEED::IdleLevel);
dmaInit();
// must force a first update so the EVENTS_SEQEND gets set as
// you can't set it manually
FillBuffer();
dmaStart();
}
void Update(bool)
{
// Data latch = 50+ microsecond pause in the output stream. Rather than
// put a delay at the end of the function, the ending time is noted and
// the function will simply hold off (if needed) on issuing the
// subsequent round of data until the latch time has elapsed. This
// allows the mainline code to start generating the next frame of data
// rather than stalling for the latch.
while (!IsReadyToUpdate())
{
yield(); // allows for system yield if needed
}
FillBuffer();
dmaStart();
}
uint8_t* getData() const
{
return _data;
};
size_t getDataSize() const
{
return _sizeData;
};
private:
const size_t _sizeData; // Size of '_data' buffer below
const uint8_t _pin; // output pin number
uint8_t* _data; // Holds LED color values
size_t _dmaBufferSize; // total size of _dmaBuffer
nrf_pwm_values_common_t* _dmaBuffer; // Holds pixel data in native format for PWM hardware
void dmaInit()
{
// only use channel zero
T_BUS::Pwm()->PSEL.OUT[0] = digitalPinToPinName(_pin);
T_BUS::Pwm()->PSEL.OUT[1] = NC;
T_BUS::Pwm()->PSEL.OUT[2] = NC;
T_BUS::Pwm()->PSEL.OUT[3] = NC;
T_BUS::Pwm()->ENABLE = 1;
T_BUS::Pwm()->MODE = NRF_PWM_MODE_UP;
T_BUS::Pwm()->PRESCALER = NRF_PWM_CLK_16MHz;
T_BUS::Pwm()->COUNTERTOP = T_SPEED::CountTop;
T_BUS::Pwm()->LOOP = 1; // single fire so events get set
T_BUS::Pwm()->DECODER = NRF_PWM_LOAD_COMMON;
// sequence zero is the primary data with a BitReset entry on the end for
// the delay repeating
T_BUS::Pwm()->SEQ[0].PTR = reinterpret_cast<uint32_t>(_dmaBuffer);
T_BUS::Pwm()->SEQ[0].CNT = _dmaBufferSize / sizeof(nrf_pwm_values_common_t);
T_BUS::Pwm()->SEQ[0].REFRESH = 0; // ignored
T_BUS::Pwm()->SEQ[0].ENDDELAY = T_SPEED::CountReset; // ignored still?
// sequence one is pointing to the BitReset entry at the end of the primary data
T_BUS::Pwm()->SEQ[1].PTR = reinterpret_cast<uint32_t>(_dmaBuffer + (T_BUS::Pwm()->SEQ[0].CNT - 1));
T_BUS::Pwm()->SEQ[1].CNT = 1;
T_BUS::Pwm()->SEQ[1].REFRESH = 0; // ignored
T_BUS::Pwm()->SEQ[1].ENDDELAY = 0; // ignored
// stop when the loop finishes
T_BUS::Pwm()->SHORTS = PWM_SHORTS_LOOPSDONE_STOP_Msk;
T_BUS::Pwm()->INTEN = 0;
dmaResetEvents();
}
void dmaDeinit()
{
T_BUS::Pwm()->ENABLE = 0;
T_BUS::Pwm()->PSEL.OUT[0] = NC;
}
void FillBuffer()
{
nrf_pwm_values_common_t* pDma = _dmaBuffer;
nrf_pwm_values_common_t* pDmaEnd = _dmaBuffer + (_dmaBufferSize / sizeof(nrf_pwm_values_common_t));
uint8_t* pEnd = _data + _sizeData;
for (uint8_t* pData = _data; pData < pEnd; pData++)
{
uint8_t data = *pData;
for (uint8_t bit = 0; bit < 8; bit++)
{
*(pDma++) = (data & 0x80) ? T_SPEED::Bit1 : T_SPEED::Bit0;
data <<= 1;
}
}
// fill the rest with BitReset as it will get repeated when delaying or
// at the end before being stopped
while (pDma < pDmaEnd)
{
*(pDma++) = T_SPEED::BitReset;
}
}
void dmaResetEvents()
{
T_BUS::Pwm()->EVENTS_LOOPSDONE = 0;
T_BUS::Pwm()->EVENTS_SEQEND[0] = 0;
T_BUS::Pwm()->EVENTS_SEQEND[1] = 0;
T_BUS::Pwm()->EVENTS_STOPPED = 0;
}
void dmaStart()
{
dmaResetEvents();
T_BUS::Pwm()->TASKS_SEQSTART[0] = 1;
}
};
// normal
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedWs2811, NeoNrf52xPwm0> NeoNrf52xPwm0Ws2811Method;
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedWs2812x, NeoNrf52xPwm0> NeoNrf52xPwm0Ws2812xMethod;
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedSk6812, NeoNrf52xPwm0> NeoNrf52xPwm0Sk6812Method;
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedTm1814, NeoNrf52xPwm0> NeoNrf52xPwm0Tm1814Method;
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedApa106, NeoNrf52xPwm0> NeoNrf52xPwm0Apa106Method;
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeed800Kbps, NeoNrf52xPwm0> NeoNrf52xPwm0800KbpsMethod;
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeed400Kbps, NeoNrf52xPwm0> NeoNrf52xPwm0400KbpsMethod;
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedWs2811, NeoNrf52xPwm1> NeoNrf52xPwm1Ws2811Method;
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedWs2812x, NeoNrf52xPwm1> NeoNrf52xPwm1Ws2812xMethod;
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedSk6812, NeoNrf52xPwm1> NeoNrf52xPwm1Sk6812Method;
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedTm1814, NeoNrf52xPwm1> NeoNrf52xPwm1Tm1814Method;
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedApa106, NeoNrf52xPwm1> NeoNrf52xPwm1Apa106Method;
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeed800Kbps, NeoNrf52xPwm1> NeoNrf52xPwm1800KbpsMethod;
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeed400Kbps, NeoNrf52xPwm1> NeoNrf52xPwm1400KbpsMethod;
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedWs2811, NeoNrf52xPwm2> NeoNrf52xPwm2Ws2811Method;
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedWs2812x, NeoNrf52xPwm2> NeoNrf52xPwm2Ws2812xMethod;
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedSk6812, NeoNrf52xPwm2> NeoNrf52xPwm2Sk6812Method;
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedTm1814, NeoNrf52xPwm2> NeoNrf52xPwm2Tm1814Method;
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedApa106, NeoNrf52xPwm2> NeoNrf52xPwm2Apa106Method;
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeed800Kbps, NeoNrf52xPwm2> NeoNrf52xPwm2800KbpsMethod;
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeed400Kbps, NeoNrf52xPwm2> NeoNrf52xPwm2400KbpsMethod;
#if defined(NRF_PWM3)
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedWs2811, NeoNrf52xPwm3> NeoNrf52xPwm3Ws2811Method;
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedWs2812x, NeoNrf52xPwm3> NeoNrf52xPwm3Ws2812xMethod;
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedSk6812, NeoNrf52xPwm3> NeoNrf52xPwm3Sk6812Method;
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedTm1814, NeoNrf52xPwm3> NeoNrf52xPwm3Tm1814Method;
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedApa106, NeoNrf52xPwm3> NeoNrf52xPwm3Apa106Method;
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeed800Kbps, NeoNrf52xPwm3> NeoNrf52xPwm3800KbpsMethod;
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeed400Kbps, NeoNrf52xPwm3> NeoNrf52xPwm3400KbpsMethod;
#endif
// inverted
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedWs2811, NeoNrf52xPwm0> NeoNrf52xPwm0Ws2811InvertedMethod;
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedWs2812x, NeoNrf52xPwm0> NeoNrf52xPwm0Ws2812xInvertedMethod;
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedSk6812, NeoNrf52xPwm0> NeoNrf52xPwm0Sk6812InvertedMethod;
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedTm1814, NeoNrf52xPwm0> NeoNrf52xPwm0Tm1814InvertedMethod;
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedApa106, NeoNrf52xPwm0> NeoNrf52xPwm0Apa106InvertedMethod;
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeed800Kbps, NeoNrf52xPwm0> NeoNrf52xPwm0800KbpsInvertedMethod;
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeed400Kbps, NeoNrf52xPwm0> NeoNrf52xPwm0400KbpsInvertedMethod;
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedWs2811, NeoNrf52xPwm1> NeoNrf52xPwm1Ws2811InvertedMethod;
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedWs2812x, NeoNrf52xPwm1> NeoNrf52xPwm1Ws2812xInvertedMethod;
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedSk6812, NeoNrf52xPwm1> NeoNrf52xPwm1Sk6812InvertedMethod;
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedTm1814, NeoNrf52xPwm1> NeoNrf52xPwm1Tm1814InvertedMethod;
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedApa106, NeoNrf52xPwm1> NeoNrf52xPwm1Apa106InvertedMethod;
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeed800Kbps, NeoNrf52xPwm1> NeoNrf52xPwm1800KbpsInvertedMethod;
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeed400Kbps, NeoNrf52xPwm1> NeoNrf52xPwm1400KbpsInvertedMethod;
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedWs2811, NeoNrf52xPwm2> NeoNrf52xPwm2Ws2811InvertedMethod;
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedWs2812x, NeoNrf52xPwm2> NeoNrf52xPwm2Ws2812xInvertedMethod;
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedSk6812, NeoNrf52xPwm2> NeoNrf52xPwm2Sk6812InvertedMethod;
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedTm1814, NeoNrf52xPwm2> NeoNrf52xPwm2Tm1814InvertedMethod;
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedApa106, NeoNrf52xPwm2> NeoNrf52xPwm2Apa106InvertedMethod;
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeed800Kbps, NeoNrf52xPwm2> NeoNrf52xPwm2800KbpsInvertedMethod;
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeed400Kbps, NeoNrf52xPwm2> NeoNrf52xPwm2400KbpsInvertedMethod;
#if defined(NRF_PWM3)
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedWs2811, NeoNrf52xPwm3> NeoNrf52xPwm3Ws2811InvertedMethod;
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedWs2812x, NeoNrf52xPwm3> NeoNrf52xPwm3Ws2812xInvertedMethod;
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedSk6812, NeoNrf52xPwm3> NeoNrf52xPwm3Sk6812InvertedMethod;
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedTm1814, NeoNrf52xPwm3> NeoNrf52xPwm3Tm1814InvertedMethod;
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedApa106, NeoNrf52xPwm3> NeoNrf52xPwm3Apa106InvertedMethod;
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeed800Kbps, NeoNrf52xPwm3> NeoNrf52xPwm3800KbpsInvertedMethod;
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeed400Kbps, NeoNrf52xPwm3> NeoNrf52xPwm3400KbpsInvertedMethod;
#endif
// defaults
typedef NeoNrf52xPwm2Ws2812xMethod NeoWs2813Method;
typedef NeoNrf52xPwm2Ws2812xMethod NeoWs2812xMethod;
typedef NeoNrf52xPwm2800KbpsMethod NeoWs2812Method;
typedef NeoNrf52xPwm2Ws2812xMethod NeoWs2811Method;
typedef NeoNrf52xPwm2Sk6812Method NeoSk6812Method;
typedef NeoNrf52xPwm2Tm1814Method NeoTm1814Method;
typedef NeoNrf52xPwm2Sk6812Method NeoLc8812Method;
typedef NeoNrf52xPwm2Apa106Method NeoApa106Method;
typedef NeoNrf52xPwm2Ws2812xMethod Neo800KbpsMethod;
typedef NeoNrf52xPwm2400KbpsMethod Neo400KbpsMethod;
typedef NeoNrf52xPwm2Ws2812xInvertedMethod NeoWs2813InvertedMethod;
typedef NeoNrf52xPwm2Ws2812xInvertedMethod NeoWs2812xInvertedMethod;
typedef NeoNrf52xPwm2Ws2812xInvertedMethod NeoWs2811InvertedMethod;
typedef NeoNrf52xPwm2800KbpsInvertedMethod NeoWs2812InvertedMethod;
typedef NeoNrf52xPwm2Sk6812InvertedMethod NeoSk6812InvertedMethod;
typedef NeoNrf52xPwm2Tm1814InvertedMethod NeoTm1814InvertedMethod;
typedef NeoNrf52xPwm2Sk6812InvertedMethod NeoLc8812InvertedMethod;
typedef NeoNrf52xPwm2Apa106InvertedMethod NeoApa106InvertedMethod;
typedef NeoNrf52xPwm2Ws2812xInvertedMethod Neo800KbpsInvertedMethod;
typedef NeoNrf52xPwm2400KbpsInvertedMethod Neo400KbpsInvertedMethod;
#endif

View File

@@ -0,0 +1,197 @@
/*-------------------------------------------------------------------------
NeoPixelAnimator provides animation timing support.
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 "NeoPixelBus.h"
#include "NeoPixelAnimator.h"
NeoPixelAnimator::NeoPixelAnimator(uint16_t countAnimations, uint16_t timeScale) :
_countAnimations(countAnimations),
_animationLastTick(0),
_activeAnimations(0),
_isRunning(true)
{
setTimeScale(timeScale);
_animations = new AnimationContext[_countAnimations];
}
NeoPixelAnimator::~NeoPixelAnimator()
{
delete[] _animations;
}
bool NeoPixelAnimator::NextAvailableAnimation(uint16_t* indexAvailable, uint16_t indexStart)
{
if (indexStart >= _countAnimations)
{
// last one
indexStart = _countAnimations - 1;
}
uint16_t next = indexStart;
do
{
if (!IsAnimationActive(next))
{
if (indexAvailable)
{
*indexAvailable = next;
}
return true;
}
next = (next + 1) % _countAnimations;
} while (next != indexStart);
return false;
}
void NeoPixelAnimator::StartAnimation(uint16_t indexAnimation,
uint16_t duration,
AnimUpdateCallback animUpdate)
{
if (indexAnimation >= _countAnimations || animUpdate == NULL)
{
return;
}
if (_activeAnimations == 0)
{
_animationLastTick = millis();
}
StopAnimation(indexAnimation);
// all animations must have at least non zero duration, otherwise
// they are considered stopped
if (duration == 0)
{
duration = 1;
}
_animations[indexAnimation].StartAnimation(duration, animUpdate);
_activeAnimations++;
}
void NeoPixelAnimator::StopAnimation(uint16_t indexAnimation)
{
if (indexAnimation >= _countAnimations)
{
return;
}
if (IsAnimationActive(indexAnimation))
{
_activeAnimations--;
_animations[indexAnimation].StopAnimation();
}
}
void NeoPixelAnimator::StopAll()
{
for (uint16_t indexAnimation = 0; indexAnimation < _countAnimations; ++indexAnimation)
{
_animations[indexAnimation].StopAnimation();
}
_activeAnimations = 0;
}
void NeoPixelAnimator::UpdateAnimations()
{
if (_isRunning)
{
uint32_t currentTick = millis();
uint32_t delta = currentTick - _animationLastTick;
if (delta >= _timeScale)
{
AnimationContext* pAnim;
delta /= _timeScale; // scale delta into animation time
for (uint16_t iAnim = 0; iAnim < _countAnimations; iAnim++)
{
pAnim = &_animations[iAnim];
AnimUpdateCallback fnUpdate = pAnim->_fnCallback;
AnimationParam param;
param.index = iAnim;
if (pAnim->_remaining > delta)
{
param.state = (pAnim->_remaining == pAnim->_duration) ? AnimationState_Started : AnimationState_Progress;
param.progress = pAnim->CurrentProgress();
fnUpdate(param);
pAnim->_remaining -= delta;
}
else if (pAnim->_remaining > 0)
{
param.state = AnimationState_Completed;
param.progress = 1.0f;
_activeAnimations--;
pAnim->StopAnimation();
fnUpdate(param);
}
}
_animationLastTick = currentTick;
}
}
}
void NeoPixelAnimator::ChangeAnimationDuration(uint16_t indexAnimation, uint16_t newDuration)
{
if (indexAnimation >= _countAnimations)
{
return;
}
AnimationContext* pAnim = &_animations[indexAnimation];
// calc the current animation progress
float progress = pAnim->CurrentProgress();
// keep progress in range just in case
if (progress < 0.0f)
{
progress = 0.0f;
}
else if (progress > 1.0f)
{
progress = 1.0f;
}
// change the duration
pAnim->_duration = newDuration;
// _remaining time must also be reset after a duration change;
// use the progress to recalculate it
pAnim->_remaining = uint16_t(pAnim->_duration * (1.0f - progress));
}

View File

@@ -0,0 +1,648 @@
/*-------------------------------------------------------------------------
Arduino library to control a wide variety of WS2811- and WS2812-based RGB
LED devices such as Adafruit FLORA RGB Smart Pixels and NeoPixel strips.
Currently handles 400 and 800 KHz bitstreams on 8, 12 and 16 MHz ATmega
MCUs, with LEDs wired for various color orders. 8 MHz MCUs provide
output on PORTB and PORTD, while 16 MHz chips can handle most output pins
(possible exception with upper PORT registers on the Arduino Mega).
Written by Phil Burgess / Paint Your Dragon for Adafruit Industries,
contributions by PJRC, Michael Miller and other members of the open
source community.
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing products
from Adafruit!
-------------------------------------------------------------------------
The contents of this file were taken from the Adafruit NeoPixel library
and modified only to fit within individual calling functions.
NeoPixel 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.
NeoPixel 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/>.
-------------------------------------------------------------------------*/
// must also check for arm due to Teensy incorrectly having ARDUINO_ARCH_AVR set
#if (defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_MEGAAVR)) && !defined(__arm__)
#include <Arduino.h>
// Hand-tuned assembly code issues data to the LED drivers at a specific
// rate. There's separate code for different CPU speeds (8, 12, 16 MHz)
// for both the WS2811 (400 KHz) and WS2812 (800 KHz) drivers. The
// datastream timing for the LED drivers allows a little wiggle room each
// way (listed in the datasheets), so the conditions for compiling each
// case are set up for a range of frequencies rather than just the exact
// 8, 12 or 16 MHz values, permitting use with some close-but-not-spot-on
// devices (e.g. 16.5 MHz DigiSpark). The ranges were arrived at based
// on the datasheet figures and have not been extensively tested outside
// the canonical 8/12/16 MHz speeds; there's no guarantee these will work
// close to the extremes (or possibly they could be pushed further).
// Keep in mind only one CPU speed case actually gets compiled; the
// resulting program isn't as massive as it might look from source here.
#if (F_CPU >= 7400000UL) && (F_CPU <= 9500000UL) // 8Mhz CPU
#ifdef PORTD // PORTD isn't present on ATtiny85, etc.
void send_data_8mhz_800_PortD(uint8_t* data, size_t sizeData, uint8_t pinMask)
{
volatile size_t i = sizeData; // Loop counter
volatile uint8_t* ptr = data; // Pointer to next byte
volatile uint8_t b = *ptr++; // Current byte value
volatile uint8_t hi; // PORT w/output bit set high
volatile uint8_t lo; // PORT w/output bit set low
volatile uint8_t n1;
volatile uint8_t n2 = 0; // First, next bits out
// Squeezing an 800 KHz stream out of an 8 MHz chip requires code
// specific to each PORT register. At present this is only written
// to work with pins on PORTD or PORTB, the most likely use case --
// this covers all the pins on the Adafruit Flora and the bulk of
// digital pins on the Arduino Pro 8 MHz (keep in mind, this code
// doesn't even get compiled for 16 MHz boards like the Uno, Mega,
// Leonardo, etc., so don't bother extending this out of hand).
// Additional PORTs could be added if you really need them, just
// duplicate the else and loop and change the PORT. Each add'l
// PORT will require about 150(ish) bytes of program space.
// 10 instruction clocks per bit: HHxxxxxLLL
// OUT instructions: ^ ^ ^ (T=0,2,7)
hi = PORTD | pinMask;
lo = PORTD & ~pinMask;
n1 = lo;
if (b & 0x80)
{
n1 = hi;
}
// Dirty trick: RJMPs proceeding to the next instruction are used
// to delay two clock cycles in one instruction word (rather than
// using two NOPs). This was necessary in order to squeeze the
// loop down to exactly 64 words -- the maximum possible for a
// relative branch.
asm volatile(
"headD:" "\n\t" // Clk Pseudocode
// Bit 7:
"out %[port] , %[hi]" "\n\t" // 1 PORT = hi
"mov %[n2] , %[lo]" "\n\t" // 1 n2 = lo
"out %[port] , %[n1]" "\n\t" // 1 PORT = n1
"rjmp .+0" "\n\t" // 2 nop nop
"sbrc %[byte] , 6" "\n\t" // 1-2 if(b & 0x40)
"mov %[n2] , %[hi]" "\n\t" // 0-1 n2 = hi
"out %[port] , %[lo]" "\n\t" // 1 PORT = lo
"rjmp .+0" "\n\t" // 2 nop nop
// Bit 6:
"out %[port] , %[hi]" "\n\t" // 1 PORT = hi
"mov %[n1] , %[lo]" "\n\t" // 1 n1 = lo
"out %[port] , %[n2]" "\n\t" // 1 PORT = n2
"rjmp .+0" "\n\t" // 2 nop nop
"sbrc %[byte] , 5" "\n\t" // 1-2 if(b & 0x20)
"mov %[n1] , %[hi]" "\n\t" // 0-1 n1 = hi
"out %[port] , %[lo]" "\n\t" // 1 PORT = lo
"rjmp .+0" "\n\t" // 2 nop nop
// Bit 5:
"out %[port] , %[hi]" "\n\t" // 1 PORT = hi
"mov %[n2] , %[lo]" "\n\t" // 1 n2 = lo
"out %[port] , %[n1]" "\n\t" // 1 PORT = n1
"rjmp .+0" "\n\t" // 2 nop nop
"sbrc %[byte] , 4" "\n\t" // 1-2 if(b & 0x10)
"mov %[n2] , %[hi]" "\n\t" // 0-1 n2 = hi
"out %[port] , %[lo]" "\n\t" // 1 PORT = lo
"rjmp .+0" "\n\t" // 2 nop nop
// Bit 4:
"out %[port] , %[hi]" "\n\t" // 1 PORT = hi
"mov %[n1] , %[lo]" "\n\t" // 1 n1 = lo
"out %[port] , %[n2]" "\n\t" // 1 PORT = n2
"rjmp .+0" "\n\t" // 2 nop nop
"sbrc %[byte] , 3" "\n\t" // 1-2 if(b & 0x08)
"mov %[n1] , %[hi]" "\n\t" // 0-1 n1 = hi
"out %[port] , %[lo]" "\n\t" // 1 PORT = lo
"rjmp .+0" "\n\t" // 2 nop nop
// Bit 3:
"out %[port] , %[hi]" "\n\t" // 1 PORT = hi
"mov %[n2] , %[lo]" "\n\t" // 1 n2 = lo
"out %[port] , %[n1]" "\n\t" // 1 PORT = n1
"rjmp .+0" "\n\t" // 2 nop nop
"sbrc %[byte] , 2" "\n\t" // 1-2 if(b & 0x04)
"mov %[n2] , %[hi]" "\n\t" // 0-1 n2 = hi
"out %[port] , %[lo]" "\n\t" // 1 PORT = lo
"rjmp .+0" "\n\t" // 2 nop nop
// Bit 2:
"out %[port] , %[hi]" "\n\t" // 1 PORT = hi
"mov %[n1] , %[lo]" "\n\t" // 1 n1 = lo
"out %[port] , %[n2]" "\n\t" // 1 PORT = n2
"rjmp .+0" "\n\t" // 2 nop nop
"sbrc %[byte] , 1" "\n\t" // 1-2 if(b & 0x02)
"mov %[n1] , %[hi]" "\n\t" // 0-1 n1 = hi
"out %[port] , %[lo]" "\n\t" // 1 PORT = lo
"rjmp .+0" "\n\t" // 2 nop nop
// Bit 1:
"out %[port] , %[hi]" "\n\t" // 1 PORT = hi
"mov %[n2] , %[lo]" "\n\t" // 1 n2 = lo
"out %[port] , %[n1]" "\n\t" // 1 PORT = n1
"rjmp .+0" "\n\t" // 2 nop nop
"sbrc %[byte] , 0" "\n\t" // 1-2 if(b & 0x01)
"mov %[n2] , %[hi]" "\n\t" // 0-1 n2 = hi
"out %[port] , %[lo]" "\n\t" // 1 PORT = lo
"sbiw %[count], 1" "\n\t" // 2 i-- (don't act on Z flag yet)
// Bit 0:
"out %[port] , %[hi]" "\n\t" // 1 PORT = hi
"mov %[n1] , %[lo]" "\n\t" // 1 n1 = lo
"out %[port] , %[n2]" "\n\t" // 1 PORT = n2
"ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++
"sbrc %[byte] , 7" "\n\t" // 1-2 if(b & 0x80)
"mov %[n1] , %[hi]" "\n\t" // 0-1 n1 = hi
"out %[port] , %[lo]" "\n\t" // 1 PORT = lo
"brne headD" "\n" // 2 while(i) (Z flag set above)
: [byte] "+r" (b),
[n1] "+r" (n1),
[n2] "+r" (n2),
[count] "+w" (i)
: [port] "I" (_SFR_IO_ADDR(PORTD)),
[ptr] "e" (ptr),
[hi] "r" (hi),
[lo] "r" (lo) );
}
#endif
void send_data_8mhz_800_PortB(uint8_t* data, size_t sizeData, uint8_t pinMask)
{
volatile size_t i = sizeData; // Loop counter
volatile uint8_t* ptr = data; // Pointer to next byte
volatile uint8_t b = *ptr++; // Current byte value
volatile uint8_t hi; // PORT w/output bit set high
volatile uint8_t lo; // PORT w/output bit set low
volatile uint8_t n1;
volatile uint8_t n2 = 0; // First, next bits out
// Same as above, just switched to PORTB and stripped of comments.
hi = PORTB | pinMask;
lo = PORTB & ~pinMask;
n1 = lo;
if (b & 0x80)
{
n1 = hi;
}
asm volatile(
"headB:" "\n\t"
"out %[port] , %[hi]" "\n\t"
"mov %[n2] , %[lo]" "\n\t"
"out %[port] , %[n1]" "\n\t"
"rjmp .+0" "\n\t"
"sbrc %[byte] , 6" "\n\t"
"mov %[n2] , %[hi]" "\n\t"
"out %[port] , %[lo]" "\n\t"
"rjmp .+0" "\n\t"
"out %[port] , %[hi]" "\n\t"
"mov %[n1] , %[lo]" "\n\t"
"out %[port] , %[n2]" "\n\t"
"rjmp .+0" "\n\t"
"sbrc %[byte] , 5" "\n\t"
"mov %[n1] , %[hi]" "\n\t"
"out %[port] , %[lo]" "\n\t"
"rjmp .+0" "\n\t"
"out %[port] , %[hi]" "\n\t"
"mov %[n2] , %[lo]" "\n\t"
"out %[port] , %[n1]" "\n\t"
"rjmp .+0" "\n\t"
"sbrc %[byte] , 4" "\n\t"
"mov %[n2] , %[hi]" "\n\t"
"out %[port] , %[lo]" "\n\t"
"rjmp .+0" "\n\t"
"out %[port] , %[hi]" "\n\t"
"mov %[n1] , %[lo]" "\n\t"
"out %[port] , %[n2]" "\n\t"
"rjmp .+0" "\n\t"
"sbrc %[byte] , 3" "\n\t"
"mov %[n1] , %[hi]" "\n\t"
"out %[port] , %[lo]" "\n\t"
"rjmp .+0" "\n\t"
"out %[port] , %[hi]" "\n\t"
"mov %[n2] , %[lo]" "\n\t"
"out %[port] , %[n1]" "\n\t"
"rjmp .+0" "\n\t"
"sbrc %[byte] , 2" "\n\t"
"mov %[n2] , %[hi]" "\n\t"
"out %[port] , %[lo]" "\n\t"
"rjmp .+0" "\n\t"
"out %[port] , %[hi]" "\n\t"
"mov %[n1] , %[lo]" "\n\t"
"out %[port] , %[n2]" "\n\t"
"rjmp .+0" "\n\t"
"sbrc %[byte] , 1" "\n\t"
"mov %[n1] , %[hi]" "\n\t"
"out %[port] , %[lo]" "\n\t"
"rjmp .+0" "\n\t"
"out %[port] , %[hi]" "\n\t"
"mov %[n2] , %[lo]" "\n\t"
"out %[port] , %[n1]" "\n\t"
"rjmp .+0" "\n\t"
"sbrc %[byte] , 0" "\n\t"
"mov %[n2] , %[hi]" "\n\t"
"out %[port] , %[lo]" "\n\t"
"sbiw %[count], 1" "\n\t"
"out %[port] , %[hi]" "\n\t"
"mov %[n1] , %[lo]" "\n\t"
"out %[port] , %[n2]" "\n\t"
"ld %[byte] , %a[ptr]+" "\n\t"
"sbrc %[byte] , 7" "\n\t"
"mov %[n1] , %[hi]" "\n\t"
"out %[port] , %[lo]" "\n\t"
"brne headB" "\n"
: [byte] "+r" (b), [n1] "+r" (n1), [n2] "+r" (n2), [count] "+w" (i)
: [port] "I" (_SFR_IO_ADDR(PORTB)), [ptr] "e" (ptr), [hi] "r" (hi),
[lo] "r" (lo));
}
void send_data_8mhz_400(uint8_t* data, size_t sizeData, volatile uint8_t* port, uint8_t pinMask)
{
volatile size_t i = sizeData; // Loop counter
volatile uint8_t* ptr = data; // Pointer to next byte
volatile uint8_t b = *ptr++; // Current byte value
volatile uint8_t hi; // PORT w/output bit set high
volatile uint8_t lo; // PORT w/output bit set low
// Timing is more relaxed; unrolling the inner loop for each bit is
// not necessary. Still using the peculiar RJMPs as 2X NOPs, not out
// of need but just to trim the code size down a little.
// This 400-KHz-datastream-on-8-MHz-CPU code is not quite identical
// to the 800-on-16 code later -- the hi/lo timing between WS2811 and
// WS2812 is not simply a 2:1 scale!
// 20 inst. clocks per bit: HHHHxxxxxxLLLLLLLLLL
// ST instructions: ^ ^ ^ (T=0,4,10)
volatile uint8_t next, bit;
hi = *port | pinMask;
lo = *port & ~pinMask;
next = lo;
bit = 8;
asm volatile(
"head20:" "\n\t" // Clk Pseudocode (T = 0)
"st %a[port], %[hi]" "\n\t" // 2 PORT = hi (T = 2)
"sbrc %[byte] , 7" "\n\t" // 1-2 if(b & 128)
"mov %[next], %[hi]" "\n\t" // 0-1 next = hi (T = 4)
"st %a[port], %[next]" "\n\t" // 2 PORT = next (T = 6)
"mov %[next] , %[lo]" "\n\t" // 1 next = lo (T = 7)
"dec %[bit]" "\n\t" // 1 bit-- (T = 8)
"breq nextbyte20" "\n\t" // 1-2 if(bit == 0)
"rol %[byte]" "\n\t" // 1 b <<= 1 (T = 10)
"st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 12)
"rjmp .+0" "\n\t" // 2 nop nop (T = 14)
"rjmp .+0" "\n\t" // 2 nop nop (T = 16)
"rjmp .+0" "\n\t" // 2 nop nop (T = 18)
"rjmp head20" "\n\t" // 2 -> head20 (next bit out)
"nextbyte20:" "\n\t" // (T = 10)
"st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 12)
"nop" "\n\t" // 1 nop (T = 13)
"ldi %[bit] , 8" "\n\t" // 1 bit = 8 (T = 14)
"ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 16)
"sbiw %[count], 1" "\n\t" // 2 i-- (T = 18)
"brne head20" "\n" // 2 if(i != 0) -> (next byte)
: [port] "+e" (port),
[byte] "+r" (b),
[bit] "+r" (bit),
[next] "+r" (next),
[count] "+w" (i)
: [hi] "r" (hi),
[lo] "r" (lo),
[ptr] "e" (ptr));
}
#elif (F_CPU >= 11100000UL) && (F_CPU <= 14300000UL) // 12Mhz CPU
#ifdef PORTD // PORTD isn't present on ATtiny85, etc.
void send_data_12mhz_800_PortD(uint8_t* data, size_t sizeData, uint8_t pinMask)
{
volatile size_t i = sizeData; // Loop counter
volatile uint8_t* ptr = data; // Pointer to next byte
volatile uint8_t b = *ptr++; // Current byte value
volatile uint8_t hi; // PORT w/output bit set high
volatile uint8_t lo; // PORT w/output bit set low
// In the 12 MHz case, an optimized 800 KHz datastream (no dead time
// between bytes) requires a PORT-specific loop similar to the 8 MHz
// code (but a little more relaxed in this case).
// 15 instruction clocks per bit: HHHHxxxxxxLLLLL
// OUT instructions: ^ ^ ^ (T=0,4,10)
volatile uint8_t next;
hi = PORTD | pinMask;
lo = PORTD & ~pinMask;
next = lo;
if (b & 0x80) next = hi;
// Don't "optimize" the OUT calls into the bitTime subroutine;
// we're exploiting the RCALL and RET as 3- and 4-cycle NOPs!
asm volatile(
"headD:" "\n\t" // (T = 0)
"out %[port], %[hi]" "\n\t" // (T = 1)
"rcall bitTimeD" "\n\t" // Bit 7 (T = 15)
"out %[port], %[hi]" "\n\t"
"rcall bitTimeD" "\n\t" // Bit 6
"out %[port], %[hi]" "\n\t"
"rcall bitTimeD" "\n\t" // Bit 5
"out %[port], %[hi]" "\n\t"
"rcall bitTimeD" "\n\t" // Bit 4
"out %[port], %[hi]" "\n\t"
"rcall bitTimeD" "\n\t" // Bit 3
"out %[port], %[hi]" "\n\t"
"rcall bitTimeD" "\n\t" // Bit 2
"out %[port], %[hi]" "\n\t"
"rcall bitTimeD" "\n\t" // Bit 1
// Bit 0:
"out %[port] , %[hi]" "\n\t" // 1 PORT = hi (T = 1)
"rjmp .+0" "\n\t" // 2 nop nop (T = 3)
"ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 5)
"out %[port] , %[next]" "\n\t" // 1 PORT = next (T = 6)
"mov %[next] , %[lo]" "\n\t" // 1 next = lo (T = 7)
"sbrc %[byte] , 7" "\n\t" // 1-2 if(b & 0x80) (T = 8)
"mov %[next] , %[hi]" "\n\t" // 0-1 next = hi (T = 9)
"nop" "\n\t" // 1 (T = 10)
"out %[port] , %[lo]" "\n\t" // 1 PORT = lo (T = 11)
"sbiw %[count], 1" "\n\t" // 2 i-- (T = 13)
"brne headD" "\n\t" // 2 if(i != 0) -> (next byte)
"rjmp doneD" "\n\t"
"bitTimeD:" "\n\t" // nop nop nop (T = 4)
"out %[port], %[next]" "\n\t" // 1 PORT = next (T = 5)
"mov %[next], %[lo]" "\n\t" // 1 next = lo (T = 6)
"rol %[byte]" "\n\t" // 1 b <<= 1 (T = 7)
"sbrc %[byte], 7" "\n\t" // 1-2 if(b & 0x80) (T = 8)
"mov %[next], %[hi]" "\n\t" // 0-1 next = hi (T = 9)
"nop" "\n\t" // 1 (T = 10)
"out %[port], %[lo]" "\n\t" // 1 PORT = lo (T = 11)
"ret" "\n\t" // 4 nop nop nop nop (T = 15)
"doneD:" "\n"
: [byte] "+r" (b),
[next] "+r" (next),
[count] "+w" (i)
: [port] "I" (_SFR_IO_ADDR(PORTD)),
[ptr] "e" (ptr),
[hi] "r" (hi),
[lo] "r" (lo));
}
#endif
void send_data_12mhz_800_PortB(uint8_t* data, size_t sizeData, uint8_t pinMask)
{
volatile uint16_t i = (uint16_t)sizeData; // Loop counter
volatile uint8_t* ptr = data; // Pointer to next byte
volatile uint8_t b = *ptr++; // Current byte value
volatile uint8_t hi; // PORT w/output bit set high
volatile uint8_t lo; // PORT w/output bit set low
volatile uint8_t next;
hi = PORTB | pinMask;
lo = PORTB & ~pinMask;
next = lo;
if (b & 0x80)
{
next = hi;
}
// Same as above, just set for PORTB & stripped of comments
asm volatile(
"headB:" "\n\t"
"out %[port], %[hi]" "\n\t"
"rcall bitTimeB" "\n\t"
"out %[port], %[hi]" "\n\t"
"rcall bitTimeB" "\n\t"
"out %[port], %[hi]" "\n\t"
"rcall bitTimeB" "\n\t"
"out %[port], %[hi]" "\n\t"
"rcall bitTimeB" "\n\t"
"out %[port], %[hi]" "\n\t"
"rcall bitTimeB" "\n\t"
"out %[port], %[hi]" "\n\t"
"rcall bitTimeB" "\n\t"
"out %[port], %[hi]" "\n\t"
"rcall bitTimeB" "\n\t"
"out %[port] , %[hi]" "\n\t"
"rjmp .+0" "\n\t"
"ld %[byte] , %a[ptr]+" "\n\t"
"out %[port] , %[next]" "\n\t"
"mov %[next] , %[lo]" "\n\t"
"sbrc %[byte] , 7" "\n\t"
"mov %[next] , %[hi]" "\n\t"
"nop" "\n\t"
"out %[port] , %[lo]" "\n\t"
"sbiw %[count], 1" "\n\t"
"brne headB" "\n\t"
"rjmp doneB" "\n\t"
"bitTimeB:" "\n\t"
"out %[port], %[next]" "\n\t"
"mov %[next], %[lo]" "\n\t"
"rol %[byte]" "\n\t"
"sbrc %[byte], 7" "\n\t"
"mov %[next], %[hi]" "\n\t"
"nop" "\n\t"
"out %[port], %[lo]" "\n\t"
"ret" "\n\t"
"doneB:" "\n"
: [byte] "+r" (b), [next] "+r" (next), [count] "+w" (i)
: [port] "I" (_SFR_IO_ADDR(PORTB)), [ptr] "e" (ptr), [hi] "r" (hi),
[lo] "r" (lo));
}
void send_data_12mhz_400(uint8_t* data, size_t sizeData, volatile uint8_t* port, uint8_t pinMask)
{
volatile uint16_t i = (uint16_t)sizeData; // Loop counter
volatile uint8_t* ptr = data; // Pointer to next byte
volatile uint8_t b = *ptr++; // Current byte value
volatile uint8_t hi; // PORT w/output bit set high
volatile uint8_t lo; // PORT w/output bit set low
// 30 instruction clocks per bit: HHHHHHxxxxxxxxxLLLLLLLLLLLLLLL
// ST instructions: ^ ^ ^ (T=0,6,15)
volatile uint8_t next, bit;
hi = *port | pinMask;
lo = *port & ~pinMask;
next = lo;
bit = 8;
asm volatile(
"head30:" "\n\t" // Clk Pseudocode (T = 0)
"st %a[port], %[hi]" "\n\t" // 2 PORT = hi (T = 2)
"sbrc %[byte] , 7" "\n\t" // 1-2 if(b & 128)
"mov %[next], %[hi]" "\n\t" // 0-1 next = hi (T = 4)
"rjmp .+0" "\n\t" // 2 nop nop (T = 6)
"st %a[port], %[next]" "\n\t" // 2 PORT = next (T = 8)
"rjmp .+0" "\n\t" // 2 nop nop (T = 10)
"rjmp .+0" "\n\t" // 2 nop nop (T = 12)
"rjmp .+0" "\n\t" // 2 nop nop (T = 14)
"nop" "\n\t" // 1 nop (T = 15)
"st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 17)
"rjmp .+0" "\n\t" // 2 nop nop (T = 19)
"dec %[bit]" "\n\t" // 1 bit-- (T = 20)
"breq nextbyte30" "\n\t" // 1-2 if(bit == 0)
"rol %[byte]" "\n\t" // 1 b <<= 1 (T = 22)
"rjmp .+0" "\n\t" // 2 nop nop (T = 24)
"rjmp .+0" "\n\t" // 2 nop nop (T = 26)
"rjmp .+0" "\n\t" // 2 nop nop (T = 28)
"rjmp head30" "\n\t" // 2 -> head30 (next bit out)
"nextbyte30:" "\n\t" // (T = 22)
"nop" "\n\t" // 1 nop (T = 23)
"ldi %[bit] , 8" "\n\t" // 1 bit = 8 (T = 24)
"ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 26)
"sbiw %[count], 1" "\n\t" // 2 i-- (T = 28)
"brne head30" "\n" // 1-2 if(i != 0) -> (next byte)
: [port] "+e" (port),
[byte] "+r" (b),
[bit] "+r" (bit),
[next] "+r" (next),
[count] "+w" (i)
: [hi] "r" (hi),
[lo] "r" (lo),
[ptr] "e" (ptr));
}
#elif (F_CPU >= 15400000UL) && (F_CPU <= 19000000L) // 16Mhz CPU
void send_data_16mhz_800(uint8_t* data, size_t sizeData, volatile uint8_t* port, uint8_t pinMask)
{
volatile uint16_t i = (uint16_t)sizeData; // Loop counter
volatile uint8_t* ptr = data; // Pointer to next byte
volatile uint8_t b = *ptr++; // Current byte value
volatile uint8_t hi; // PORT w/output bit set high
volatile uint8_t lo; // PORT w/output bit set low
// WS2811 and WS2812 have different hi/lo duty cycles; this is
// similar but NOT an exact copy of the prior 400-on-8 code.
// 20 inst. clocks per bit: HHHHHxxxxxxxxLLLLLLL
// ST instructions: ^ ^ ^ (T=0,5,13)
volatile uint8_t next;
volatile uint8_t bit;
hi = *port | pinMask;
lo = *port & ~pinMask;
next = lo;
bit = 8;
asm volatile(
"head20:" "\n\t" // Clk Pseudocode (T = 0)
"st %a[port], %[hi]" "\n\t" // 2 PORT = hi (T = 2)
"sbrc %[byte], 7" "\n\t" // 1-2 if(b & 128)
"mov %[next], %[hi]" "\n\t" // 0-1 next = hi (T = 4)
"dec %[bit]" "\n\t" // 1 bit-- (T = 5)
"st %a[port], %[next]" "\n\t" // 2 PORT = next (T = 7)
"mov %[next] , %[lo]" "\n\t" // 1 next = lo (T = 8)
"breq nextbyte20" "\n\t" // 1-2 if(bit == 0) (from dec above)
"rol %[byte]" "\n\t" // 1 b <<= 1 (T = 10)
"rjmp .+0" "\n\t" // 2 nop nop (T = 12)
"nop" "\n\t" // 1 nop (T = 13)
"st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 15)
"nop" "\n\t" // 1 nop (T = 16)
"rjmp .+0" "\n\t" // 2 nop nop (T = 18)
"rjmp head20" "\n\t" // 2 -> head20 (next bit out)
"nextbyte20:" "\n\t" // (T = 10)
"ldi %[bit] , 8" "\n\t" // 1 bit = 8 (T = 11)
"ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 13)
"st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 15)
"nop" "\n\t" // 1 nop (T = 16)
"sbiw %[count], 1" "\n\t" // 2 i-- (T = 18)
"brne head20" "\n" // 2 if(i != 0) -> (next byte)
: [port] "+e" (port),
[byte] "+r" (b),
[bit] "+r" (bit),
[next] "+r" (next),
[count] "+w" (i)
: [ptr] "e" (ptr),
[hi] "r" (hi),
[lo] "r" (lo));
}
void send_data_16mhz_400(uint8_t* data, size_t sizeData, volatile uint8_t* port, uint8_t pinMask)
{
volatile size_t i = sizeData; // Loop counter
volatile uint8_t* ptr = data; // Pointer to next byte
volatile uint8_t b = *ptr++; // Current byte value
volatile uint8_t hi; // PORT w/output bit set high
volatile uint8_t lo; // PORT w/output bit set low
// The 400 KHz clock on 16 MHz MCU is the most 'relaxed' version.
// 40 inst. clocks per bit: HHHHHHHHxxxxxxxxxxxxLLLLLLLLLLLLLLLLLLLL
// ST instructions: ^ ^ ^ (T=0,8,20)
volatile uint8_t next, bit;
hi = *port | pinMask;
lo = *port & ~pinMask;
next = lo;
bit = 8;
asm volatile(
"head40:" "\n\t" // Clk Pseudocode (T = 0)
"st %a[port], %[hi]" "\n\t" // 2 PORT = hi (T = 2)
"sbrc %[byte] , 7" "\n\t" // 1-2 if(b & 128)
"mov %[next] , %[hi]" "\n\t" // 0-1 next = hi (T = 4)
"rjmp .+0" "\n\t" // 2 nop nop (T = 6)
"rjmp .+0" "\n\t" // 2 nop nop (T = 8)
"st %a[port], %[next]" "\n\t" // 2 PORT = next (T = 10)
"rjmp .+0" "\n\t" // 2 nop nop (T = 12)
"rjmp .+0" "\n\t" // 2 nop nop (T = 14)
"rjmp .+0" "\n\t" // 2 nop nop (T = 16)
"rjmp .+0" "\n\t" // 2 nop nop (T = 18)
"rjmp .+0" "\n\t" // 2 nop nop (T = 20)
"st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 22)
"nop" "\n\t" // 1 nop (T = 23)
"mov %[next] , %[lo]" "\n\t" // 1 next = lo (T = 24)
"dec %[bit]" "\n\t" // 1 bit-- (T = 25)
"breq nextbyte40" "\n\t" // 1-2 if(bit == 0)
"rol %[byte]" "\n\t" // 1 b <<= 1 (T = 27)
"nop" "\n\t" // 1 nop (T = 28)
"rjmp .+0" "\n\t" // 2 nop nop (T = 30)
"rjmp .+0" "\n\t" // 2 nop nop (T = 32)
"rjmp .+0" "\n\t" // 2 nop nop (T = 34)
"rjmp .+0" "\n\t" // 2 nop nop (T = 36)
"rjmp .+0" "\n\t" // 2 nop nop (T = 38)
"rjmp head40" "\n\t" // 2 -> head40 (next bit out)
"nextbyte40:" "\n\t" // (T = 27)
"ldi %[bit] , 8" "\n\t" // 1 bit = 8 (T = 28)
"ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 30)
"rjmp .+0" "\n\t" // 2 nop nop (T = 32)
"st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 34)
"rjmp .+0" "\n\t" // 2 nop nop (T = 36)
"sbiw %[count], 1" "\n\t" // 2 i-- (T = 38)
"brne head40" "\n" // 1-2 if(i != 0) -> (next byte)
: [port] "+e" (port),
[byte] "+r" (b),
[bit] "+r" (bit),
[next] "+r" (next),
[count] "+w" (i)
: [ptr] "e" (ptr),
[hi] "r" (hi),
[lo] "r" (lo));
}
#else
#error "CPU SPEED NOT SUPPORTED"
#endif
#endif

View File

@@ -0,0 +1,116 @@
#pragma once
/*-------------------------------------------------------------------------
NeoRingTopology provides a mapping feature of a 2d polar cordinate to a
linear 1d cordinate.
It is used to map a series of concentric rings of NeoPixels to a index on
the 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/>.
-------------------------------------------------------------------------*/
template <typename T_LAYOUT> class NeoRingTopology : protected T_LAYOUT
{
public:
NeoRingTopology()
{
}
uint16_t Map(uint8_t ring, uint16_t pixel) const
{
if (pixel >= getPixelCountAtRing(ring))
{
return 0; // invalid ring and/or pixel argument, always return a valid value, the first one
}
return _map(ring, pixel);
}
uint16_t MapProbe(uint8_t ring, uint16_t pixel) const
{
if (pixel >= getPixelCountAtRing(ring))
{
return getPixelCount(); // total count, out of bounds
}
return _map(ring, pixel);
}
uint16_t RingPixelShift(uint8_t ring, uint16_t pixel, int16_t shift)
{
int32_t ringPixel = pixel;
ringPixel += shift;
if (ringPixel < 0)
{
ringPixel = 0;
}
else
{
uint16_t count = getPixelCountAtRing(ring);
if (ringPixel >= count)
{
ringPixel = count - 1;
}
}
return ringPixel;
}
uint16_t RingPixelRotate(uint8_t ring, uint16_t pixel, int16_t rotate)
{
int32_t ringPixel = pixel;
ringPixel += rotate;
return ringPixel % getPixelCountAtRing(ring);
}
uint8_t getCountOfRings() const
{
return _ringCount() - 1; // minus one as the Rings includes the extra value
}
uint16_t getPixelCountAtRing(uint8_t ring) const
{
if (ring >= getCountOfRings())
{
return 0; // invalid, no pixels
}
return T_LAYOUT::Rings[ring + 1] - T_LAYOUT::Rings[ring]; // using the extra value for count calc
}
uint16_t getPixelCount() const
{
return T_LAYOUT::Rings[_ringCount() - 1]; // the last entry is the total count
}
private:
uint16_t _map(uint8_t ring, uint16_t pixel) const
{
return T_LAYOUT::Rings[ring] + pixel;
}
uint8_t _ringCount() const
{
return sizeof(T_LAYOUT::Rings) / sizeof(T_LAYOUT::Rings[0]);
}
};

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(const uint8_t* pPixels, uint16_t indexPixel)
{
ColorObject color;
const 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

View File

@@ -0,0 +1,62 @@
/*-------------------------------------------------------------------------
NeoSettings provides settings classes to describe settings
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 NeoNoSettings
{
};
class NeoRgbCurrentSettings
{
public:
NeoRgbCurrentSettings(uint16_t red, uint16_t green, uint16_t blue) :
RedTenthMilliAmpere(red),
GreenTenthMilliAmpere(green),
BlueTenthMilliAmpere(blue)
{
}
uint16_t RedTenthMilliAmpere; // in 1/10th ma
uint16_t GreenTenthMilliAmpere; // in 1/10th ma
uint16_t BlueTenthMilliAmpere; // in 1/10th ma
};
class NeoRgbwCurrentSettings
{
public:
NeoRgbwCurrentSettings(uint16_t red, uint16_t green, uint16_t blue, uint16_t white) :
RedTenthMilliAmpere(red),
GreenTenthMilliAmpere(green),
BlueTenthMilliAmpere(blue),
WhiteCurrent(white)
{
}
uint16_t RedTenthMilliAmpere; // in 1/10th ma
uint16_t GreenTenthMilliAmpere; // in 1/10th ma
uint16_t BlueTenthMilliAmpere; // in 1/10th ma
uint16_t WhiteCurrent; // in 1/10th ma
};

View File

@@ -0,0 +1,163 @@
/*-------------------------------------------------------------------------
NeoPixel library
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
template<typename T_BUFFER_METHOD> class NeoVerticalSpriteSheet
{
public:
NeoVerticalSpriteSheet(uint16_t width,
uint16_t height,
uint16_t spriteHeight,
PGM_VOID_P pixels) :
_method(width, height, pixels),
_spriteHeight(spriteHeight),
_spriteCount(height / spriteHeight)
{
}
operator NeoBufferContext<typename T_BUFFER_METHOD::ColorFeature>()
{
return _method;
}
uint16_t SpriteWidth() const
{
return _method.Width();
};
uint16_t SpriteHeight() const
{
return _spriteHeight;
};
uint16_t SpriteCount() const
{
return _spriteCount;
}
void SetPixelColor(uint16_t indexSprite,
int16_t x,
int16_t y,
typename T_BUFFER_METHOD::ColorObject color)
{
_method.SetPixelColor(pixelIndex(indexSprite, x, y), color);
};
typename T_BUFFER_METHOD::ColorObject GetPixelColor(uint16_t indexSprite,
int16_t x,
int16_t y) const
{
return _method.GetPixelColor(pixelIndex(indexSprite, x, y));
};
void ClearTo(typename T_BUFFER_METHOD::ColorObject color)
{
_method.ClearTo(color);
};
void Blt(NeoBufferContext<typename T_BUFFER_METHOD::ColorFeature> destBuffer,
uint16_t indexPixel,
uint16_t indexSprite)
{
uint16_t destPixelCount = destBuffer.PixelCount();
// validate indexPixel
if (indexPixel >= destPixelCount)
{
return;
}
// validate indexSprite
if (indexSprite >= _spriteCount)
{
return;
}
// calc how many we can copy
uint16_t copyCount = destPixelCount - indexPixel;
if (copyCount > SpriteWidth())
{
copyCount = SpriteWidth();
}
uint8_t* pDest = T_BUFFER_METHOD::ColorFeature::getPixelAddress(destBuffer.Pixels, indexPixel);
const uint8_t* pSrc = T_BUFFER_METHOD::ColorFeature::getPixelAddress(_method.Pixels(), pixelIndex(indexSprite, 0, 0));
_method.CopyPixels(pDest, pSrc, copyCount);
}
void Blt(NeoBufferContext<typename T_BUFFER_METHOD::ColorFeature> destBuffer,
int16_t x,
int16_t y,
uint16_t indexSprite,
LayoutMapCallback layoutMap)
{
if (indexSprite >= _spriteCount)
{
return;
}
uint16_t destPixelCount = destBuffer.PixelCount();
for (int16_t srcY = 0; srcY < SpriteHeight(); srcY++)
{
for (int16_t srcX = 0; srcX < SpriteWidth(); srcX++)
{
uint16_t indexDest = layoutMap(srcX + x, srcY + y);
if (indexDest < destPixelCount)
{
const uint8_t* pSrc = T_BUFFER_METHOD::ColorFeature::getPixelAddress(_method.Pixels(), pixelIndex(indexSprite, srcX, srcY));
uint8_t* pDest = T_BUFFER_METHOD::ColorFeature::getPixelAddress(destBuffer.Pixels, indexDest);
_method.CopyPixels(pDest, pSrc, 1);
}
}
}
}
private:
T_BUFFER_METHOD _method;
const uint16_t _spriteHeight;
const uint16_t _spriteCount;
uint16_t pixelIndex(uint16_t indexSprite,
int16_t x,
int16_t y) const
{
uint16_t result = PixelIndex_OutOfBounds;
if (indexSprite < _spriteCount &&
x >= 0 &&
(uint16_t)x < SpriteWidth() &&
y >= 0 &&
(uint16_t)y < SpriteHeight())
{
result = x + y * SpriteWidth() + indexSprite * _spriteHeight * SpriteWidth();
}
return result;
}
};

View File

@@ -0,0 +1,158 @@
#pragma once
/*-------------------------------------------------------------------------
NeoTiles provides a mapping feature of a 2d cordinate to linear 1d cordinate
It is used to map tiles of matricies of NeoPixels to a index on the NeoPixelBus
where the the matricies use one topology and the tiles of those matricies can
use another
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/>.
-------------------------------------------------------------------------*/
//-----------------------------------------------------------------------------
// class NeoTiles
// Simple template Tile layout class
// T_MATRIX_LAYOUT = the layout used on the pixel matrix panel (a tile)
// T_TILE_LAYOUT = the layout used for the tiles.
//
//-----------------------------------------------------------------------------
template <typename T_MATRIX_LAYOUT, typename T_TILE_LAYOUT> class NeoTiles
{
public:
NeoTiles(uint16_t topoWidth, uint16_t topoHeight,
uint16_t tilesWidth, uint16_t tilesHeight) :
_topo(topoWidth, topoHeight),
_width(tilesWidth),
_height(tilesHeight)
{
}
uint16_t Map(int16_t x, int16_t y) const
{
uint16_t totalWidth = getWidth();
uint16_t totalHeight = getHeight();
if (x >= totalWidth)
{
x = totalWidth - 1;
}
else if (x < 0)
{
x = 0;
}
if (y >= totalHeight)
{
y = totalHeight - 1;
}
else if (y < 0)
{
y = 0;
}
uint16_t localIndex;
uint16_t tileOffset;
calculate(x, y, &localIndex, &tileOffset);
return localIndex + tileOffset;
}
uint16_t MapProbe(int16_t x, int16_t y) const
{
uint16_t totalWidth = getWidth();
uint16_t totalHeight = getHeight();
if (x < 0 || x >= totalWidth || y < 0 || y >= totalHeight)
{
return totalWidth * totalHeight; // count, out of bounds
}
uint16_t localIndex;
uint16_t tileOffset;
calculate(x, y, &localIndex, &tileOffset);
return localIndex + tileOffset;
}
NeoTopologyHint TopologyHint(int16_t x, int16_t y) const
{
uint16_t totalWidth = getWidth();
uint16_t totalHeight = getHeight();
if (x < 0 || x >= totalWidth || y < 0 || y >= totalHeight)
{
return NeoTopologyHint_OutOfBounds;
}
uint16_t localIndex;
uint16_t tileOffset;
NeoTopologyHint result;
calculate(x, y, &localIndex, &tileOffset);
if (localIndex == 0)
{
result = NeoTopologyHint_FirstOnPanel;
}
else if (localIndex == (_topo.getWidth() * _topo.getHeight() - 1))
{
result = NeoTopologyHint_LastOnPanel;
}
else
{
result = NeoTopologyHint_InPanel;
}
return result;
}
uint16_t getWidth() const
{
return _width * _topo.getWidth();
}
uint16_t getHeight() const
{
return _height * _topo.getHeight();
}
private:
const NeoTopology<T_MATRIX_LAYOUT> _topo;
const uint16_t _width;
const uint16_t _height;
void calculate(uint16_t x, uint16_t y, uint16_t* pLocalIndex, uint16_t* pTileOffset) const
{
uint16_t tileX = x / _topo.getWidth();
uint16_t topoX = x % _topo.getWidth();
uint16_t tileY = y / _topo.getHeight();
uint16_t topoY = y % _topo.getHeight();
*pTileOffset = T_TILE_LAYOUT::Map(_width, _height, tileX, tileY) * _topo.getWidth() * _topo.getHeight();
*pLocalIndex = _topo.Map(topoX, topoY);
}
};

View File

@@ -0,0 +1,131 @@
/*-------------------------------------------------------------------------
NeoTm1814ColorFeatures provides feature classes to describe color order and
color depth for NeoPixelBus template class specific to the TM1814 chip
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 NeoTm1814Settings : public NeoRgbwCurrentSettings
{
public:
NeoTm1814Settings(uint16_t red, uint16_t green, uint16_t blue, uint16_t white) :
NeoRgbwCurrentSettings(red, green, blue, white)
{
}
const static uint16_t MinCurrent = 65;
const static uint16_t MaxCurrent = 380;
static uint16_t LimitCurrent(uint16_t value)
{
if (value < MinCurrent)
{
value = MinCurrent;
}
else if (value > MaxCurrent)
{
value = MaxCurrent;
}
return value;
}
};
class Neo4ElementsTm1814Settings : public Neo4Elements
{
public:
typedef NeoTm1814Settings SettingsObject;
static const size_t SettingsSize = 8;
static void applySettings(uint8_t* pData, const SettingsObject& settings)
{
uint8_t* pSet = pData;
// C1
*pSet++ = (SettingsObject::LimitCurrent(settings.WhiteCurrent) - SettingsObject::MinCurrent) / 5;
*pSet++ = (SettingsObject::LimitCurrent(settings.RedTenthMilliAmpere) - SettingsObject::MinCurrent) / 5;
*pSet++ = (SettingsObject::LimitCurrent(settings.GreenTenthMilliAmpere) - SettingsObject::MinCurrent) / 5;
*pSet++ = (SettingsObject::LimitCurrent(settings.BlueTenthMilliAmpere) - SettingsObject::MinCurrent) / 5;
uint8_t* pC1 = pData;
// C2
for (uint8_t elem = 0; elem < 4; elem++)
{
*pSet++ = ~(*pC1++);
}
}
static uint8_t* pixels(uint8_t* pData)
{
return pData + SettingsSize;
}
static const uint8_t* pixels(const uint8_t* pData)
{
return pData;
}
};
class NeoWrgbTm1814Feature : public Neo4ElementsTm1814Settings
{
public:
static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color)
{
uint8_t* p = getPixelAddress(pPixels, indexPixel);
*p++ = color.W;
*p++ = color.R;
*p++ = color.G;
*p = color.B;
}
static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel)
{
ColorObject color;
const uint8_t* p = getPixelAddress(pPixels, indexPixel);
color.W = *p++;
color.R = *p++;
color.G = *p++;
color.B = *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);
color.W = pgm_read_byte(p++);
color.R = pgm_read_byte(p++);
color.G = pgm_read_byte(p++);
color.B = pgm_read_byte(p);
return color;
}
};

View File

@@ -0,0 +1,91 @@
#pragma once
/*-------------------------------------------------------------------------
NeoTopology provides a mapping feature of a 2d cordinate to linear 1d cordinate
It is used to map a matrix of NeoPixels to a index on the 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/>.
-------------------------------------------------------------------------*/
enum NeoTopologyHint
{
NeoTopologyHint_FirstOnPanel,
NeoTopologyHint_InPanel,
NeoTopologyHint_LastOnPanel,
NeoTopologyHint_OutOfBounds
};
template <typename T_LAYOUT> class NeoTopology
{
public:
NeoTopology(uint16_t width, uint16_t height) :
_width(width),
_height(height)
{
}
uint16_t Map(int16_t x, int16_t y) const
{
if (x >= _width)
{
x = _width - 1;
}
else if (x < 0)
{
x = 0;
}
if (y >= _height)
{
y = _height - 1;
}
else if (y < 0)
{
y = 0;
}
return T_LAYOUT::Map(_width, _height, x, y);
}
uint16_t MapProbe(int16_t x, int16_t y) const
{
if (x < 0 || x >= _width || y < 0 || y >= _height)
{
return _width * _height; // count, out of bounds
}
return T_LAYOUT::Map(_width, _height, x, y);
}
uint16_t getWidth() const
{
return _width;
}
uint16_t getHeight() const
{
return _height;
}
private:
const uint16_t _width;
const uint16_t _height;
};

View File

@@ -0,0 +1,162 @@
/*-------------------------------------------------------------------------
P9813ColorFeatures provides feature classes to describe color order and
color depth for NeoPixelBus template class when used with P9813s
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 P98133Elements
{
public:
static const size_t PixelSize = 4; // still requires 4 to be sent
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)
{
*pPixelDest++ = pPixelSrc[0];
*pPixelDest++ = pPixelSrc[1];
*pPixelDest++ = pPixelSrc[2];
*pPixelDest++ = pPixelSrc[3];
}
}
static void movePixelsInc(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count)
{
uint8_t* pEnd = pPixelDest + (count * PixelSize);
while (pPixelDest < pEnd)
{
*pPixelDest++ = *pPixelSrc++;
*pPixelDest++ = *pPixelSrc++;
*pPixelDest++ = *pPixelSrc++;
*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++);
*pPixelDest++ = pgm_read_byte(pSrc++);
*pPixelDest++ = pgm_read_byte(pSrc++);
*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;
*--pDestBack = *--pSrcBack;
*--pDestBack = *--pSrcBack;
*--pDestBack = *--pSrcBack;
}
}
typedef RgbColor ColorObject;
};
class P98133ElementsNoSettings : public P98133Elements
{
public:
typedef NeoNoSettings SettingsObject;
static const size_t SettingsSize = 0;
static void applySettings(uint8_t*, const SettingsObject&)
{
}
static uint8_t* pixels(uint8_t* pData)
{
return pData;
}
static const uint8_t* pixels(const uint8_t* pData)
{
return pData;
}
};
class P9813BgrFeature : public P98133ElementsNoSettings
{
public:
static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color)
{
uint8_t* p = getPixelAddress(pPixels, indexPixel);
*p++ = 0xC0 | ((~color.B & 0xC0) >> 2) | ((~color.G & 0xC0) >> 4) | ((~color.R & 0xC0) >> 6);
*p++ = color.B;
*p++ = color.G;
*p = color.R;
}
static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel)
{
ColorObject color;
const uint8_t* p = getPixelAddress(pPixels, indexPixel);
p++; // ignore the first byte
color.B = *p++;
color.G = *p++;
color.R = *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);
pgm_read_byte(p++); // ignore the first byte
color.B = pgm_read_byte(p++);
color.G = pgm_read_byte(p++);
color.R = pgm_read_byte(p);
return color;
}
};

View File

@@ -0,0 +1,126 @@
/*-------------------------------------------------------------------------
NeoPixel library helper functions for P9813s using general Pins (APA102).
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
// must also check for arm due to Teensy incorrectly having ARDUINO_ARCH_AVR set
#if defined(ARDUINO_ARCH_AVR) && !defined(__arm__)
#include "TwoWireBitBangImpleAvr.h"
#else
#include "TwoWireBitBangImple.h"
#endif
template<typename T_TWOWIRE> class P9813MethodBase
{
public:
P9813MethodBase(uint8_t pinClock, uint8_t pinData, uint16_t pixelCount, size_t elementSize, size_t settingsSize) :
_sizeData(pixelCount * elementSize + settingsSize),
_sizeEndFrame((pixelCount + 15) / 16), // 16 = div 2 (bit for every two pixels) div 8 (bits to bytes)
_wire(pinClock, pinData)
{
_data = static_cast<uint8_t*>(malloc(_sizeData));
memset(_data, 0, _sizeData);
}
#if !defined(__AVR_ATtiny85__) && !defined(ARDUINO_attiny)
P9813MethodBase(uint16_t pixelCount, size_t elementSize, size_t settingsSize) :
P9813MethodBase(SCK, MOSI, pixelCount, elementSize, settingsSize)
{
}
#endif
~P9813MethodBase()
{
free(_data);
}
bool IsReadyToUpdate() const
{
return true; // dot stars don't have a required delay
}
#if defined(ARDUINO_ARCH_ESP32)
void Initialize(int8_t sck, int8_t miso, int8_t mosi, int8_t ss)
{
_wire.begin(sck, miso, mosi, ss);
}
#endif
void Initialize()
{
_wire.begin();
}
void Update(bool)
{
const uint8_t startFrame[4] = { 0x00 };
const uint8_t endFrame[4] = { 0x00 };
_wire.beginTransaction();
// start frame
_wire.transmitBytes(startFrame, sizeof(startFrame));
// data
_wire.transmitBytes(_data, _sizeData);
// end frame
_wire.transmitBytes(endFrame, sizeof(endFrame));
_wire.endTransaction();
}
uint8_t* getData() const
{
return _data;
};
size_t getDataSize() const
{
return _sizeData;
};
private:
const size_t _sizeData; // Size of '_data' buffer below
const size_t _sizeEndFrame;
T_TWOWIRE _wire;
uint8_t* _data; // Holds LED color values
};
typedef P9813MethodBase<TwoWireBitBangImple> P9813Method;
#if !defined(__AVR_ATtiny85__) && !defined(ARDUINO_attiny)
#include "TwoWireSpiImple.h"
typedef P9813MethodBase<TwoWireSpiImple<SpiSpeed20Mhz>> P9813Spi20MhzMethod;
typedef P9813MethodBase<TwoWireSpiImple<SpiSpeed10Mhz>> P9813Spi10MhzMethod;
typedef P9813MethodBase<TwoWireSpiImple<SpiSpeed2Mhz>> P9813Spi2MhzMethod;
typedef P9813Spi10MhzMethod P9813SpiMethod;
#endif

View File

@@ -0,0 +1,261 @@
/*-------------------------------------------------------------------------
RgbColor 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 "RgbColor.h"
#include "HslColor.h"
#include "HsbColor.h"
#include "HtmlColor.h"
static float _CalcColor(float p, float q, float t)
{
if (t < 0.0f)
t += 1.0f;
if (t > 1.0f)
t -= 1.0f;
if (t < 1.0f / 6.0f)
return p + (q - p) * 6.0f * t;
if (t < 0.5f)
return q;
if (t < 2.0f / 3.0f)
return p + ((q - p) * (2.0f / 3.0f - t) * 6.0f);
return p;
}
RgbColor::RgbColor(const HtmlColor& color)
{
uint32_t temp = color.Color;
B = (temp & 0xff);
temp = temp >> 8;
G = (temp & 0xff);
temp = temp >> 8;
R = (temp & 0xff);
};
RgbColor::RgbColor(const HslColor& color)
{
float r;
float g;
float b;
float h = color.H;
float s = color.S;
float l = color.L;
if (color.S == 0.0f || color.L == 0.0f)
{
r = g = b = l; // achromatic or black
}
else
{
float q = l < 0.5f ? l * (1.0f + s) : l + s - (l * s);
float p = 2.0f * l - q;
r = _CalcColor(p, q, h + 1.0f / 3.0f);
g = _CalcColor(p, q, h);
b = _CalcColor(p, q, h - 1.0f / 3.0f);
}
R = (uint8_t)(r * 255.0f);
G = (uint8_t)(g * 255.0f);
B = (uint8_t)(b * 255.0f);
}
RgbColor::RgbColor(const HsbColor& color)
{
float r;
float g;
float b;
float h = color.H;
float s = color.S;
float v = color.B;
if (color.S == 0.0f)
{
r = g = b = v; // achromatic or black
}
else
{
if (h < 0.0f)
{
h += 1.0f;
}
else if (h >= 1.0f)
{
h -= 1.0f;
}
h *= 6.0f;
int i = (int)h;
float f = h - i;
float q = v * (1.0f - s * f);
float p = v * (1.0f - s);
float t = v * (1.0f - s * (1.0f - f));
switch (i)
{
case 0:
r = v;
g = t;
b = p;
break;
case 1:
r = q;
g = v;
b = p;
break;
case 2:
r = p;
g = v;
b = t;
break;
case 3:
r = p;
g = q;
b = v;
break;
case 4:
r = t;
g = p;
b = v;
break;
default:
r = v;
g = p;
b = q;
break;
}
}
R = (uint8_t)(r * 255.0f);
G = (uint8_t)(g * 255.0f);
B = (uint8_t)(b * 255.0f);
}
uint8_t RgbColor::CalculateBrightness() const
{
return (uint8_t)(((uint16_t)R + (uint16_t)G + (uint16_t)B) / 3);
}
RgbColor RgbColor::Dim(uint8_t ratio) const
{
// specifically avoids float math
return RgbColor(_elementDim(R, ratio), _elementDim(G, ratio), _elementDim(B, ratio));
}
RgbColor RgbColor::Brighten(uint8_t ratio) const
{
// specifically avoids float math
return RgbColor(_elementBrighten(R, ratio), _elementBrighten(G, ratio), _elementBrighten(B, ratio));
}
void RgbColor::Darken(uint8_t delta)
{
if (R > delta)
{
R -= delta;
}
else
{
R = 0;
}
if (G > delta)
{
G -= delta;
}
else
{
G = 0;
}
if (B > delta)
{
B -= delta;
}
else
{
B = 0;
}
}
void RgbColor::Lighten(uint8_t delta)
{
if (R < 255 - delta)
{
R += delta;
}
else
{
R = 255;
}
if (G < 255 - delta)
{
G += delta;
}
else
{
G = 255;
}
if (B < 255 - delta)
{
B += delta;
}
else
{
B = 255;
}
}
RgbColor RgbColor::LinearBlend(const RgbColor& left, const RgbColor& right, float progress)
{
return RgbColor( left.R + ((right.R - left.R) * progress),
left.G + ((right.G - left.G) * progress),
left.B + ((right.B - left.B) * progress));
}
RgbColor RgbColor::BilinearBlend(const RgbColor& c00,
const RgbColor& c01,
const RgbColor& c10,
const RgbColor& c11,
float x,
float y)
{
float v00 = (1.0f - x) * (1.0f - y);
float v10 = x * (1.0f - y);
float v01 = (1.0f - x) * y;
float v11 = x * y;
return RgbColor(
c00.R * v00 + c10.R * v10 + c01.R * v01 + c11.R * v11,
c00.G * v00 + c10.G * v10 + c01.G * v01 + c11.G * v11,
c00.B * v00 + c10.B * v10 + c01.B * v01 + c11.B * v11);
}

View File

@@ -0,0 +1,199 @@
/*-------------------------------------------------------------------------
RgbColor 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>
#include "NeoSettings.h"
struct HslColor;
struct HsbColor;
struct HtmlColor;
// ------------------------------------------------------------------------
// RgbColor represents a color object that is represented by Red, Green, Blue
// component values. It contains helpful color routines to manipulate the
// color.
// ------------------------------------------------------------------------
struct RgbColor
{
typedef NeoRgbCurrentSettings SettingsObject;
// ------------------------------------------------------------------------
// Construct a RgbColor using R, G, B values (0-255)
// ------------------------------------------------------------------------
RgbColor(uint8_t r, uint8_t g, uint8_t b) :
R(r), G(g), B(b)
{
};
// ------------------------------------------------------------------------
// Construct a RgbColor using a single brightness value (0-255)
// This works well for creating gray tone colors
// (0) = black, (255) = white, (128) = gray
// ------------------------------------------------------------------------
RgbColor(uint8_t brightness) :
R(brightness), G(brightness), B(brightness)
{
};
// ------------------------------------------------------------------------
// Construct a RgbColor using HtmlColor
// ------------------------------------------------------------------------
RgbColor(const HtmlColor& color);
// ------------------------------------------------------------------------
// Construct a RgbColor using HslColor
// ------------------------------------------------------------------------
RgbColor(const HslColor& color);
// ------------------------------------------------------------------------
// Construct a RgbColor using HsbColor
// ------------------------------------------------------------------------
RgbColor(const HsbColor& color);
// ------------------------------------------------------------------------
// Construct a RgbColor that will have its values set in latter operations
// CAUTION: The R,G,B members are not initialized and may not be consistent
// ------------------------------------------------------------------------
RgbColor()
{
};
// ------------------------------------------------------------------------
// Comparison operators
// ------------------------------------------------------------------------
bool operator==(const RgbColor& other) const
{
return (R == other.R && G == other.G && B == other.B);
};
bool operator!=(const RgbColor& other) const
{
return !(*this == other);
};
// ------------------------------------------------------------------------
// CalculateBrightness will calculate the overall brightness
// NOTE: This is a simple linear brightness
// ------------------------------------------------------------------------
uint8_t CalculateBrightness() const;
// ------------------------------------------------------------------------
// Dim will return a new color that is blended to black with the given ratio
// ratio - (0-255) where 255 will return the original color and 0 will return black
//
// NOTE: This is a simple linear blend
// ------------------------------------------------------------------------
RgbColor Dim(uint8_t ratio) const;
// ------------------------------------------------------------------------
// Brighten will return a new color that is blended to white with the given ratio
// ratio - (0-255) where 255 will return the original color and 0 will return white
//
// NOTE: This is a simple linear blend
// ------------------------------------------------------------------------
RgbColor Brighten(uint8_t ratio) 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 color
// ------------------------------------------------------------------------
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 color
// ------------------------------------------------------------------------
void Lighten(uint8_t delta);
// ------------------------------------------------------------------------
// LinearBlend between two colors by the amount defined by progress variable
// left - the color to start the blend at
// right - the color 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 color weighted linearly between them
// ------------------------------------------------------------------------
static RgbColor LinearBlend(const RgbColor& left, const RgbColor& right, float progress);
// ------------------------------------------------------------------------
// BilinearBlend between four colors by the amount defined by 2d variable
// c00 - upper left quadrant color
// c01 - upper right quadrant color
// c10 - lower left quadrant color
// c11 - lower right quadrant color
// x - unit value (0.0 - 1.0) that defines the blend progress in horizontal space
// y - unit value (0.0 - 1.0) that defines the blend progress in vertical space
// ------------------------------------------------------------------------
static RgbColor BilinearBlend(const RgbColor& c00,
const RgbColor& c01,
const RgbColor& c10,
const RgbColor& c11,
float x,
float y);
uint32_t CalcTotalTenthMilliAmpere(const SettingsObject& settings)
{
auto total = 0;
total += R * settings.RedTenthMilliAmpere / 255;
total += G * settings.GreenTenthMilliAmpere / 255;
total += B * settings.BlueTenthMilliAmpere / 255;
return total;
}
// ------------------------------------------------------------------------
// Red, Green, Blue color members (0-255) where
// (0,0,0) is black and (255,255,255) is white
// ------------------------------------------------------------------------
uint8_t R;
uint8_t G;
uint8_t B;
private:
inline static uint8_t _elementDim(uint8_t value, uint8_t ratio)
{
return (static_cast<uint16_t>(value) * (static_cast<uint16_t>(ratio) + 1)) >> 8;
}
inline static uint8_t _elementBrighten(uint8_t value, uint8_t ratio)
{
uint16_t element = ((static_cast<uint16_t>(value) + 1) << 8) / (static_cast<uint16_t>(ratio) + 1);
if (element > 255)
{
element = 255;
}
else
{
element -= 1;
}
return element;
}
};

View File

@@ -0,0 +1,190 @@
/*-------------------------------------------------------------------------
RgbwColor 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 "RgbColor.h"
#include "HslColor.h"
#include "HsbColor.h"
#include "RgbwColor.h"
#include "HtmlColor.h"
RgbwColor::RgbwColor(const HtmlColor& color)
{
uint32_t temp = color.Color;
B = (temp & 0xff);
temp = temp >> 8;
G = (temp & 0xff);
temp = temp >> 8;
R = (temp & 0xff);
temp = temp >> 8;
W = (temp & 0xff);
};
RgbwColor::RgbwColor(const HslColor& color)
{
RgbColor rgbColor(color);
*this = rgbColor;
}
RgbwColor::RgbwColor(const HsbColor& color)
{
RgbColor rgbColor(color);
*this = rgbColor;
}
uint8_t RgbwColor::CalculateBrightness() const
{
uint8_t colorB = (uint8_t)(((uint16_t)R + (uint16_t)G + (uint16_t)B) / 3);
if (W > colorB)
{
return W;
}
else
{
return colorB;
}
}
RgbwColor RgbwColor::Dim(uint8_t ratio) const
{
// specifically avoids float math
return RgbwColor(_elementDim(R, ratio), _elementDim(G, ratio), _elementDim(B, ratio), _elementDim(W, ratio));
}
RgbwColor RgbwColor::Brighten(uint8_t ratio) const
{
// specifically avoids float math
return RgbwColor(_elementBrighten(R, ratio), _elementBrighten(G, ratio), _elementBrighten(B, ratio), _elementBrighten(W, ratio));
}
void RgbwColor::Darken(uint8_t delta)
{
if (R > delta)
{
R -= delta;
}
else
{
R = 0;
}
if (G > delta)
{
G -= delta;
}
else
{
G = 0;
}
if (B > delta)
{
B -= delta;
}
else
{
B = 0;
}
if (W > delta)
{
W -= delta;
}
else
{
W = 0;
}
}
void RgbwColor::Lighten(uint8_t delta)
{
if (IsColorLess())
{
if (W < 255 - delta)
{
W += delta;
}
else
{
W = 255;
}
}
else
{
if (R < 255 - delta)
{
R += delta;
}
else
{
R = 255;
}
if (G < 255 - delta)
{
G += delta;
}
else
{
G = 255;
}
if (B < 255 - delta)
{
B += delta;
}
else
{
B = 255;
}
}
}
RgbwColor RgbwColor::LinearBlend(const RgbwColor& left, const RgbwColor& right, float progress)
{
return RgbwColor( left.R + ((right.R - left.R) * progress),
left.G + ((right.G - left.G) * progress),
left.B + ((right.B - left.B) * progress),
left.W + ((right.W - left.W) * progress) );
}
RgbwColor RgbwColor::BilinearBlend(const RgbwColor& c00,
const RgbwColor& c01,
const RgbwColor& c10,
const RgbwColor& c11,
float x,
float y)
{
float v00 = (1.0f - x) * (1.0f - y);
float v10 = x * (1.0f - y);
float v01 = (1.0f - x) * y;
float v11 = x * y;
return RgbwColor(
c00.R * v00 + c10.R * v10 + c01.R * v01 + c11.R * v11,
c00.G * v00 + c10.G * v10 + c01.G * v01 + c11.G * v11,
c00.B * v00 + c10.B * v10 + c01.B * v01 + c11.B * v11,
c00.W * v00 + c10.W * v10 + c01.W * v01 + c11.W * v11 );
}

View File

@@ -0,0 +1,229 @@
/*-------------------------------------------------------------------------
RgbwColor 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>
struct RgbColor;
struct HslColor;
struct HsbColor;
// ------------------------------------------------------------------------
// RgbwColor represents a color object that is represented by Red, Green, Blue
// component values and an extra White component. It contains helpful color
// routines to manipulate the color.
// ------------------------------------------------------------------------
struct RgbwColor
{
typedef NeoRgbwCurrentSettings SettingsObject;
// ------------------------------------------------------------------------
// Construct a RgbwColor using R, G, B, W values (0-255)
// ------------------------------------------------------------------------
RgbwColor(uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0) :
R(r), G(g), B(b), W(w)
{
};
// ------------------------------------------------------------------------
// Construct a RgbColor using a single brightness value (0-255)
// This works well for creating gray tone colors
// (0) = black, (255) = white, (128) = gray
// ------------------------------------------------------------------------
RgbwColor(uint8_t brightness) :
R(0), G(0), B(0), W(brightness)
{
};
// ------------------------------------------------------------------------
// Construct a RgbwColor using RgbColor
// ------------------------------------------------------------------------
RgbwColor(const RgbColor& color) :
R(color.R),
G(color.G),
B(color.B),
W(0)
{
};
// ------------------------------------------------------------------------
// Construct a RgbwColor using HtmlColor
// ------------------------------------------------------------------------
RgbwColor(const HtmlColor& color);
// ------------------------------------------------------------------------
// Construct a RgbwColor using HslColor
// ------------------------------------------------------------------------
RgbwColor(const HslColor& color);
// ------------------------------------------------------------------------
// Construct a RgbwColor using HsbColor
// ------------------------------------------------------------------------
RgbwColor(const HsbColor& color);
// ------------------------------------------------------------------------
// Construct a RgbwColor that will have its values set in latter operations
// CAUTION: The R,G,B, W members are not initialized and may not be consistent
// ------------------------------------------------------------------------
RgbwColor()
{
};
// ------------------------------------------------------------------------
// Comparison operators
// ------------------------------------------------------------------------
bool operator==(const RgbwColor& other) const
{
return (R == other.R && G == other.G && B == other.B && W == other.W);
};
bool operator!=(const RgbwColor& other) const
{
return !(*this == other);
};
// ------------------------------------------------------------------------
// Returns if the color is grey, all values are equal other than white
// ------------------------------------------------------------------------
bool IsMonotone() const
{
return (R == B && R == G);
};
// ------------------------------------------------------------------------
// Returns if the color components are all zero, the white component maybe
// anything
// ------------------------------------------------------------------------
bool IsColorLess() const
{
return (R == 0 && B == 0 && G == 0);
};
// ------------------------------------------------------------------------
// CalculateBrightness will calculate the overall brightness
// NOTE: This is a simple linear brightness
// ------------------------------------------------------------------------
uint8_t CalculateBrightness() const;
// ------------------------------------------------------------------------
// Dim will return a new color that is blended to black with the given ratio
// ratio - (0-255) where 255 will return the original color and 0 will return black
//
// NOTE: This is a simple linear blend
// ------------------------------------------------------------------------
RgbwColor Dim(uint8_t ratio) const;
// ------------------------------------------------------------------------
// Brighten will return a new color that is blended to white with the given ratio
// ratio - (0-255) where 255 will return the original color and 0 will return white
//
// NOTE: This is a simple linear blend
// ------------------------------------------------------------------------
RgbwColor Brighten(uint8_t ratio) 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 color
// ------------------------------------------------------------------------
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 color
// ------------------------------------------------------------------------
void Lighten(uint8_t delta);
// ------------------------------------------------------------------------
// LinearBlend between two colors by the amount defined by progress variable
// left - the color to start the blend at
// right - the color 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 color weighted linearly between them
// ------------------------------------------------------------------------
static RgbwColor LinearBlend(const RgbwColor& left, const RgbwColor& right, float progress);
// ------------------------------------------------------------------------
// BilinearBlend between four colors by the amount defined by 2d variable
// c00 - upper left quadrant color
// c01 - upper right quadrant color
// c10 - lower left quadrant color
// c11 - lower right quadrant color
// x - unit value (0.0 - 1.0) that defines the blend progress in horizontal space
// y - unit value (0.0 - 1.0) that defines the blend progress in vertical space
// ------------------------------------------------------------------------
static RgbwColor BilinearBlend(const RgbwColor& c00,
const RgbwColor& c01,
const RgbwColor& c10,
const RgbwColor& c11,
float x,
float y);
uint16_t CalcTotalTenthMilliAmpere(const SettingsObject& settings)
{
auto total = 0;
total += R * settings.RedTenthMilliAmpere / 255;
total += G * settings.GreenTenthMilliAmpere / 255;
total += B * settings.BlueTenthMilliAmpere / 255;
total += W * settings.WhiteCurrent / 255;
return total;
}
// ------------------------------------------------------------------------
// Red, Green, Blue, White color members (0-255) where
// (0,0,0,0) is black and (255,255,255, 0) and (0,0,0,255) is white
// Note (255,255,255,255) is extreme bright white
// ------------------------------------------------------------------------
uint8_t R;
uint8_t G;
uint8_t B;
uint8_t W;
private:
inline static uint8_t _elementDim(uint8_t value, uint8_t ratio)
{
return (static_cast<uint16_t>(value) * (static_cast<uint16_t>(ratio) + 1)) >> 8;
}
inline static uint8_t _elementBrighten(uint8_t value, uint8_t ratio)
{
uint16_t element = ((static_cast<uint16_t>(value) + 1) << 8) / (static_cast<uint16_t>(ratio) + 1);
if (element > 255)
{
element = 255;
}
else
{
element -= 1;
}
return element;
}
};

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;
}

Some files were not shown because too many files have changed in this diff Show More