From 6e860c939da621ba2d173c6d56b3fa9851d678b4 Mon Sep 17 00:00:00 2001 From: Makuna Date: Wed, 6 Apr 2016 17:52:17 -0700 Subject: [PATCH] RotateAndShift New Rotate and Shift, both Left and Right methods Optimized ClearTo method Updated keywords Updated version --- .../NeoPixelRotateLoop/NeoPixelRotateLoop.ino | 96 ++++++++++++ keywords.txt | 6 + library.properties | 2 +- src/NeoPixelBus.h | 140 +++++++++++++++++- src/internal/NeoColorFeatures.h | 47 ++++++ 5 files changed, 288 insertions(+), 3 deletions(-) create mode 100644 examples/NeoPixelRotateLoop/NeoPixelRotateLoop.ino diff --git a/examples/NeoPixelRotateLoop/NeoPixelRotateLoop.ino b/examples/NeoPixelRotateLoop/NeoPixelRotateLoop.ino new file mode 100644 index 0000000..84edb74 --- /dev/null +++ b/examples/NeoPixelRotateLoop/NeoPixelRotateLoop.ino @@ -0,0 +1,96 @@ +// 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 +#include + + +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 colorGamma; // for any fade animations, best to correct gamma + +NeoPixelBus strip(PixelCount, PixelPin); +//NeoPixelBus strip(PixelCount, PixelPin); + +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(); +} + + diff --git a/keywords.txt b/keywords.txt index b8f22da..2fc6e10 100644 --- a/keywords.txt +++ b/keywords.txt @@ -13,9 +13,11 @@ HslColor KEYWORD1 HsbColor KEYWORD1 HtmlColor KEYWORD1 NeoGrbFeature KEYWORD1 +NeoGrbwFeature KEYWORD1 NeoRgbwFeature KEYWORD1 NeoRgbFeature KEYWORD1 NeoBrgFeature KEYWORD1 +NeoRbgFeature KEYWORD1 Neo800KbpsMethod KEYWORD1 Neo400KbpsMethod KEYWORD1 NeoAvr800KbpsMethod KEYWORD1 @@ -66,6 +68,10 @@ Begin KEYWORD2 Show KEYWORD2 CanShow KEYWORD2 ClearTo KEYWORD2 +RotateLeft KEYWORD2 +ShiftLeft KEYWORD2 +RotateRight KEYWORD2 +ShiftRight KEYWORD2 IsDirty KEYWORD2 Dirty KEYWORD2 ResetDirty KEYWORD2 diff --git a/library.properties b/library.properties index 7122fee..9f39c0e 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=NeoPixelBus by Makuna -version=2.0.8 +version=2.0.9 author=Michael C. Miller (makuna@live.com) maintainer=Michael C. Miller (makuna@live.com) sentence=A library that makes controlling NeoPixels (WS2811, WS2812 & SK6812) easy. diff --git a/src/NeoPixelBus.h b/src/NeoPixelBus.h index 44458cd..71ced96 100644 --- a/src/NeoPixelBus.h +++ b/src/NeoPixelBus.h @@ -160,14 +160,150 @@ public: void ClearTo(typename T_COLOR_FEATURE::ColorObject color) { + uint8_t temp[T_COLOR_FEATURE::PixelSize]; + + T_COLOR_FEATURE::applyPixelColor(temp, 0, color); + uint8_t* pixels = _method.getPixels(); - for (uint16_t n = 0; n < _countPixels; n++) + uint8_t* pFirst = T_COLOR_FEATURE::getPixelAddress(pixels, 0); + uint8_t* pLast = T_COLOR_FEATURE::getPixelAddress(pixels, _countPixels); + uint8_t* pFront = temp; + while (pFirst < pLast) { - T_COLOR_FEATURE::applyPixelColor(pixels, n, color); + T_COLOR_FEATURE::copyIncPixel(pFirst, pFront); } + Dirty(); }; + void RotateLeft(uint16_t rotationCount, uint16_t first = 0, uint16_t last = 0xffff) + { + if (last >= _countPixels) + { + last = _countPixels - 1; + } + + if (first < _countPixels && + last < _countPixels && + first < last && + (last - first) >= rotationCount) + { + + // store in temp + uint8_t temp[rotationCount * T_COLOR_FEATURE::PixelSize]; + uint8_t* pixels = _method.getPixels(); + uint8_t* pFirst = T_COLOR_FEATURE::getPixelAddress(temp, 0); + uint8_t* pLast = T_COLOR_FEATURE::getPixelAddress(temp, rotationCount - 1); + uint8_t* pFront = T_COLOR_FEATURE::getPixelAddress(pixels, first); + while (pFirst <= pLast) + { + T_COLOR_FEATURE::moveIncPixel(pFirst, pFront); + } + + // shift data + ShiftLeft(rotationCount, first, last); + + // move temp back + pFirst = T_COLOR_FEATURE::getPixelAddress(temp, 0); + pFront = T_COLOR_FEATURE::getPixelAddress(pixels, last - (rotationCount - 1)); + while (pFirst <= pLast) + { + T_COLOR_FEATURE::moveIncPixel(pFront, pFirst); + } + + Dirty(); + } + } + + void ShiftLeft(uint16_t shiftCount, uint16_t first = 0, uint16_t last = 0xffff) + { + if (last >= _countPixels) + { + last = _countPixels - 1; + } + + if (first < _countPixels && + last < _countPixels && + first < last && + (last - first) >= shiftCount) + { + uint8_t* pixels = _method.getPixels(); + uint8_t* pFirst = T_COLOR_FEATURE::getPixelAddress(pixels, first); + uint8_t* pLast = T_COLOR_FEATURE::getPixelAddress(pixels, last); + uint8_t* pFront = T_COLOR_FEATURE::getPixelAddress(pixels, first + shiftCount); + while (pFront <= pLast) + { + T_COLOR_FEATURE::moveIncPixel(pFirst, pFront); + } + + Dirty(); + } + } + + void RotateRight(uint16_t rotationCount, uint16_t first = 0, uint16_t last = 0xffff) + { + if (last >= _countPixels) + { + last = _countPixels - 1; + } + + if (first < _countPixels && + last < _countPixels && + first < last && + (last - first) >= rotationCount) + { + + // store in temp + uint8_t temp[rotationCount * T_COLOR_FEATURE::PixelSize]; + uint8_t* pixels = _method.getPixels(); + uint8_t* pFirst = T_COLOR_FEATURE::getPixelAddress(temp, 0); + uint8_t* pLast = T_COLOR_FEATURE::getPixelAddress(temp, rotationCount - 1); + uint8_t* pBack = T_COLOR_FEATURE::getPixelAddress(pixels, last); + while (pLast >= pFirst) + { + T_COLOR_FEATURE::moveDecPixel(pLast, pBack); + } + + // shift data + ShiftRight(rotationCount, first, last); + + // move temp back + pLast = T_COLOR_FEATURE::getPixelAddress(temp, rotationCount - 1); + pBack = T_COLOR_FEATURE::getPixelAddress(pixels, first + rotationCount - 1); + while (pLast >= pFirst) + { + T_COLOR_FEATURE::moveDecPixel(pBack, pLast); + } + + Dirty(); + } + } + + void ShiftRight(uint16_t shiftCount, uint16_t first = 0, uint16_t last = 0xffff) + { + if (last >= _countPixels) + { + last = _countPixels - 1; + } + + if (first < _countPixels && + last < _countPixels && + first < last && + (last - first) >= shiftCount) + { + uint8_t* pixels = _method.getPixels(); + uint8_t* pFirst = T_COLOR_FEATURE::getPixelAddress(pixels, first); + uint8_t* pLast = T_COLOR_FEATURE::getPixelAddress(pixels, last); + uint8_t* pBack = T_COLOR_FEATURE::getPixelAddress(pixels, last - shiftCount); + while (pBack >= pFirst) + { + T_COLOR_FEATURE::moveDecPixel(pLast, pBack); + } + + Dirty(); + } + } + private: const uint16_t _countPixels; // Number of RGB LEDs in strip diff --git a/src/internal/NeoColorFeatures.h b/src/internal/NeoColorFeatures.h index 3062645..26e5cda 100644 --- a/src/internal/NeoColorFeatures.h +++ b/src/internal/NeoColorFeatures.h @@ -36,6 +36,27 @@ public: return pPixels + indexPixel * PixelSize; } + static void copyIncPixel(uint8_t*& pPixelDest, uint8_t* pPixelSrc) + { + *pPixelDest++ = *pPixelSrc++; + *pPixelDest++ = *pPixelSrc++; + *pPixelDest++ = *pPixelSrc; + } + + static void moveIncPixel(uint8_t*& pPixelDest, uint8_t*& pPixelSrc) + { + *pPixelDest++ = *pPixelSrc++; + *pPixelDest++ = *pPixelSrc++; + *pPixelDest++ = *pPixelSrc++; + } + + static void moveDecPixel(uint8_t*& pPixelDest, uint8_t*& pPixelSrc) + { + *pPixelDest-- = *pPixelSrc--; + *pPixelDest-- = *pPixelSrc--; + *pPixelDest-- = *pPixelSrc--; + } + typedef RgbColor ColorObject; }; @@ -49,6 +70,32 @@ public: return pPixels + indexPixel * PixelSize; } + static void copyIncPixel(uint8_t*& pPixelDest, uint8_t* pPixelSrc) + { + uint32_t* pDest = (uint32_t*)pPixelDest; + uint32_t* pSrc = (uint32_t*)pPixelSrc; + *pDest++ = *pSrc; + pPixelDest = (uint8_t*)pDest; + } + + static void moveIncPixel(uint8_t*& pPixelDest, uint8_t*& pPixelSrc) + { + uint32_t* pDest = (uint32_t*)pPixelDest; + uint32_t* pSrc = (uint32_t*)pPixelSrc; + *pDest++ = *pSrc++; + pPixelDest = (uint8_t*)pDest; + pPixelSrc = (uint8_t*)pSrc; + } + + static void moveDecPixel(uint8_t*& pPixelDest, uint8_t*& pPixelSrc) + { + uint32_t* pDest = (uint32_t*)pPixelDest; + uint32_t* pSrc = (uint32_t*)pPixelSrc; + *pDest-- = *pSrc--; + pPixelDest = (uint8_t*)pDest; + pPixelSrc = (uint8_t*)pSrc; + } + typedef RgbwColor ColorObject; };