Import ESP_UniClock (upstream 1189810)
Vendored from https://github.com/gpeter62/ESP_UniClock: the sketch source, the web UI and the libraries the ESP8266 build needs, unpacked from the bundled zips. Adds a PlatformIO project for the ESP-12. The source is unchanged; local changes follow as separate commits. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
8efa810e4e
commit
b347f1c63f
843 files changed
+122061
No files matched your search
@@ -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;
|
||||
};
|
||||
@@ -0,0 +1,154 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
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 pin, NeoBusChannel channel) :
|
||||
NeoPixelBus<T_COLOR_FEATURE, T_METHOD>(countPixels, pin, channel),
|
||||
_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, uint8_t pinClock, uint8_t pinData, uint8_t pinLatch, uint8_t pinOutputEnable = NOT_A_PIN) :
|
||||
NeoPixelBus<T_COLOR_FEATURE, T_METHOD>(countPixels, pinClock, pinData, pinLatch, pinOutputEnable),
|
||||
_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 = ((static_cast<uint16_t>(brightness) + 1) << 8) / (static_cast<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;
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,510 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
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/NeoUtil.h"
|
||||
|
||||
#include "internal/NeoHueBlend.h"
|
||||
|
||||
#include "internal/NeoSettings.h"
|
||||
|
||||
#include "internal/RgbColor.h"
|
||||
#include "internal/Rgb16Color.h"
|
||||
#include "internal/Rgb48Color.h"
|
||||
|
||||
#include "internal/HslColor.h"
|
||||
#include "internal/HsbColor.h"
|
||||
#include "internal/HtmlColor.h"
|
||||
|
||||
#include "internal/RgbwColor.h"
|
||||
#include "internal/Rgbw64Color.h"
|
||||
|
||||
#include "internal/SegmentDigit.h"
|
||||
|
||||
#include "internal/NeoColorFeatures.h"
|
||||
#include "internal/NeoTm1814ColorFeatures.h"
|
||||
#include "internal/NeoTm1914ColorFeatures.h"
|
||||
#include "internal/NeoSm168xxColorFeatures.h"
|
||||
#include "internal/DotStarColorFeatures.h"
|
||||
#include "internal/Lpd8806ColorFeatures.h"
|
||||
#include "internal/Lpd6803ColorFeatures.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/NeoBusChannel.h"
|
||||
|
||||
#include "internal/DotStarGenericMethod.h"
|
||||
#include "internal/Lpd8806GenericMethod.h"
|
||||
#include "internal/Lpd6803GenericMethod.h"
|
||||
#include "internal/Ws2801GenericMethod.h"
|
||||
#include "internal/P9813GenericMethod.h"
|
||||
#include "internal/Tlc5947GenericMethod.h"
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP8266)
|
||||
|
||||
#include "internal/NeoEsp8266DmaMethod.h"
|
||||
#include "internal/NeoEsp8266I2sDmx512Method.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"
|
||||
#include "internal/DotStarEsp32DmaSpiMethod.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 pin, NeoBusChannel channel) :
|
||||
_countPixels(countPixels),
|
||||
_state(0),
|
||||
_method(pin, countPixels, T_COLOR_FEATURE::PixelSize, T_COLOR_FEATURE::SettingsSize, channel)
|
||||
{
|
||||
}
|
||||
|
||||
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, uint8_t pinClock, uint8_t pinData, uint8_t pinLatch, uint8_t pinOutputEnable = NOT_A_PIN) :
|
||||
_countPixels(countPixels),
|
||||
_state(0),
|
||||
_method(pinClock, pinData, pinLatch, pinOutputEnable, 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();
|
||||
ClearTo(0);
|
||||
}
|
||||
|
||||
// used by DotStarSpiMethod/DotStarEsp32DmaSpiMethod 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);
|
||||
ClearTo(0);
|
||||
}
|
||||
|
||||
// used by DotStarEsp32DmaSpiMethod if pins can be configured - reordered and extended version supporting quad SPI
|
||||
void Begin(int8_t sck, int8_t dat0, int8_t dat1, int8_t dat2, int8_t dat3, int8_t ss)
|
||||
{
|
||||
_method.Initialize(sck, dat0, dat1, dat2, dat3, ss);
|
||||
ClearTo(0);
|
||||
}
|
||||
|
||||
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(), _method.getDataSize(), settings);
|
||||
Dirty();
|
||||
};
|
||||
|
||||
void SetMethodSettings(const typename T_METHOD::SettingsObject& settings)
|
||||
{
|
||||
_method.applySettings(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(), _method.getDataSize());
|
||||
}
|
||||
|
||||
const uint8_t* _pixels() const
|
||||
{
|
||||
// get pixels data within the data stream
|
||||
return T_COLOR_FEATURE::pixels(_method.getData(), _method.getDataSize());
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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([[maybe_unused]] uint8_t* pData, [[maybe_unused]] size_t sizeData, [[maybe_unused]] const SettingsObject& settings)
|
||||
{
|
||||
}
|
||||
|
||||
static uint8_t* pixels([[maybe_unused]] uint8_t* pData, [[maybe_unused]] size_t sizeData)
|
||||
{
|
||||
return pData;
|
||||
}
|
||||
|
||||
static const uint8_t* pixels([[maybe_unused]] const uint8_t* pData, [[maybe_unused]] size_t sizeData)
|
||||
{
|
||||
return pData;
|
||||
}
|
||||
};
|
||||
|
||||
class DotStar4ElementsNoSettings : public DotStar4Elements
|
||||
{
|
||||
public:
|
||||
typedef NeoNoSettings SettingsObject;
|
||||
static const size_t SettingsSize = 0;
|
||||
|
||||
static void applySettings([[maybe_unused]] uint8_t* pData, [[maybe_unused]] size_t sizeData, [[maybe_unused]] const SettingsObject& settings)
|
||||
{
|
||||
}
|
||||
|
||||
static uint8_t* pixels([[maybe_unused]] uint8_t* pData, [[maybe_unused]] size_t sizeData)
|
||||
{
|
||||
return pData;
|
||||
}
|
||||
|
||||
static const uint8_t* pixels([[maybe_unused]] const uint8_t* pData, [[maybe_unused]] size_t sizeData)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
};
|
||||
@@ -0,0 +1,356 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
NeoPixel library helper functions for DotStars using Esp32, DMA and SPI (APA102).
|
||||
|
||||
Written by Michael C. Miller.
|
||||
DotStarEsp32DmaSpiMethod written by Louis Beaudoin (Pixelvation)
|
||||
|
||||
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 "driver/spi_master.h"
|
||||
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(HSPI_HOST)
|
||||
// HSPI_HOST depreciated in C3
|
||||
#define HSPI_HOST SPI2_HOST
|
||||
#endif
|
||||
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
class Esp32VspiBus
|
||||
{
|
||||
public:
|
||||
const static spi_host_device_t SpiHostDevice = VSPI_HOST;
|
||||
const static int DmaChannel = 1; // arbitrary assignment, but based on the fact there are only two DMA channels and two available SPI ports, we need to split them somehow
|
||||
const static int ParallelBits = 1;
|
||||
};
|
||||
#endif
|
||||
|
||||
class Esp32HspiBus
|
||||
{
|
||||
public:
|
||||
const static spi_host_device_t SpiHostDevice = HSPI_HOST;
|
||||
const static int DmaChannel = 2; // arbitrary assignment, but based on the fact there are only two DMA channels and two available SPI ports, we need to split them somehow
|
||||
const static int ParallelBits = 1;
|
||||
};
|
||||
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
class Esp32Vspi2BitBus
|
||||
{
|
||||
public:
|
||||
const static spi_host_device_t SpiHostDevice = VSPI_HOST;
|
||||
const static int DmaChannel = 1; // arbitrary assignment, but based on the fact there are only two DMA channels and two available SPI ports, we need to split them somehow
|
||||
const static int ParallelBits = 2;
|
||||
};
|
||||
#endif
|
||||
|
||||
class Esp32Hspi2BitBus
|
||||
{
|
||||
public:
|
||||
const static spi_host_device_t SpiHostDevice = HSPI_HOST;
|
||||
const static int DmaChannel = 2; // arbitrary assignment, but based on the fact there are only two DMA channels and two available SPI ports, we need to split them somehow
|
||||
const static int ParallelBits = 2;
|
||||
};
|
||||
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
class Esp32Vspi4BitBus
|
||||
{
|
||||
public:
|
||||
const static spi_host_device_t SpiHostDevice = VSPI_HOST;
|
||||
const static int DmaChannel = 1; // arbitrary assignment, but based on the fact there are only two DMA channels and two available SPI ports, we need to split them somehow
|
||||
const static int ParallelBits = 4;
|
||||
};
|
||||
#endif
|
||||
|
||||
class Esp32Hspi4BitBus
|
||||
{
|
||||
public:
|
||||
const static spi_host_device_t SpiHostDevice = HSPI_HOST;
|
||||
const static int DmaChannel = 2; // arbitrary assignment, but based on the fact there are only two DMA channels and two available SPI ports, we need to split them somehow
|
||||
const static int ParallelBits = 4;
|
||||
};
|
||||
|
||||
template<typename T_SPISPEED, typename T_SPIBUS> class DotStarEsp32DmaSpiMethod
|
||||
{
|
||||
public:
|
||||
typedef typename T_SPISPEED::SettingsObject SettingsObject;
|
||||
|
||||
DotStarEsp32DmaSpiMethod(uint16_t pixelCount, size_t elementSize, size_t settingsSize) :
|
||||
_sizePixelData(pixelCount * elementSize + settingsSize),
|
||||
_sizeEndFrame((pixelCount + 15) / 16) // 16 = div 2 (bit for every two pixels) div 8 (bits to bytes)
|
||||
{
|
||||
_spiBufferSize = _sizeStartFrame + _sizePixelData + _sizeEndFrame;
|
||||
|
||||
// must have a 4 byte aligned buffer for i2s
|
||||
uint32_t alignment = _spiBufferSize % 4;
|
||||
if (alignment)
|
||||
{
|
||||
_spiBufferSize += 4 - alignment;
|
||||
}
|
||||
|
||||
_data = static_cast<uint8_t*>(malloc(_spiBufferSize));
|
||||
_dmadata = static_cast<uint8_t*>(heap_caps_malloc(_spiBufferSize, MALLOC_CAP_DMA));
|
||||
|
||||
// data cleared later in NeoPixelBus::Begin()
|
||||
}
|
||||
|
||||
// Support constructor specifying pins by ignoring pins
|
||||
DotStarEsp32DmaSpiMethod(uint8_t, uint8_t, uint16_t pixelCount, size_t elementSize, size_t settingsSize) :
|
||||
DotStarEsp32DmaSpiMethod(pixelCount, elementSize, settingsSize)
|
||||
{
|
||||
}
|
||||
|
||||
~DotStarEsp32DmaSpiMethod()
|
||||
{
|
||||
if (_spiHandle)
|
||||
{
|
||||
deinitSpiDevice();
|
||||
esp_err_t ret = spi_bus_free(T_SPIBUS::SpiHostDevice);
|
||||
ESP_ERROR_CHECK(ret);
|
||||
}
|
||||
free(_data);
|
||||
heap_caps_free(_dmadata);
|
||||
_spiHandle = NULL;
|
||||
}
|
||||
|
||||
bool IsReadyToUpdate() const
|
||||
{
|
||||
spi_transaction_t t;
|
||||
spi_transaction_t * tptr = &t;
|
||||
esp_err_t ret = spi_device_get_trans_result(_spiHandle, &tptr, 0);
|
||||
|
||||
// We know the previous transaction completed if we got ESP_OK, and we know there's no transactions queued if tptr is unmodified
|
||||
return (ret == ESP_OK || tptr == &t);
|
||||
}
|
||||
|
||||
void Initialize(int8_t sck, int8_t dat0, int8_t dat1, int8_t dat2, int8_t dat3, int8_t ss)
|
||||
{
|
||||
memset(_data, 0x00, _sizeStartFrame);
|
||||
memset(_data + _sizeStartFrame + _sizePixelData, 0x00, _spiBufferSize - (_sizeStartFrame + _sizePixelData));
|
||||
|
||||
_ssPin = ss;
|
||||
|
||||
esp_err_t ret;
|
||||
spi_bus_config_t buscfg;
|
||||
memset(&buscfg, 0x00, sizeof(buscfg));
|
||||
|
||||
buscfg.miso_io_num = dat1;
|
||||
buscfg.mosi_io_num = dat0;
|
||||
buscfg.sclk_io_num = sck;
|
||||
buscfg.quadwp_io_num = dat2;
|
||||
buscfg.quadhd_io_num = dat3;
|
||||
buscfg.max_transfer_sz = _spiBufferSize;
|
||||
|
||||
//Initialize the SPI bus
|
||||
ret = spi_bus_initialize(T_SPIBUS::SpiHostDevice, &buscfg, T_SPIBUS::DmaChannel);
|
||||
ESP_ERROR_CHECK(ret);
|
||||
|
||||
initSpiDevice();
|
||||
}
|
||||
|
||||
void Initialize(int8_t sck, int8_t miso, int8_t mosi, int8_t ss)
|
||||
{
|
||||
Initialize(sck, mosi, miso, -1, -1, ss);
|
||||
}
|
||||
|
||||
// If pins aren't specified, initialize bus with just the default SCK and MOSI pins for the SPI peripheral (no SS, no >1-bit pins)
|
||||
void Initialize()
|
||||
{
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
if (T_SPIBUS::SpiHostDevice == VSPI_HOST)
|
||||
{
|
||||
Initialize(SCK, -1, MOSI, -1, -1, -1);
|
||||
}
|
||||
else
|
||||
{
|
||||
Initialize(14, -1, 13, -1, -1, -1);
|
||||
}
|
||||
#else
|
||||
Initialize(SCK, -1, MOSI, -1, -1, -1);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Update(bool)
|
||||
{
|
||||
while(!IsReadyToUpdate());
|
||||
|
||||
memcpy(_dmadata, _data, _spiBufferSize);
|
||||
|
||||
memset(&_spiTransaction, 0, sizeof(spi_transaction_t));
|
||||
_spiTransaction.length = (_spiBufferSize) * 8; // in bits not bytes!
|
||||
if (T_SPIBUS::ParallelBits == 1)
|
||||
{
|
||||
_spiTransaction.flags = 0;
|
||||
}
|
||||
if (T_SPIBUS::ParallelBits == 2)
|
||||
{
|
||||
_spiTransaction.flags = SPI_TRANS_MODE_DIO;
|
||||
}
|
||||
if (T_SPIBUS::ParallelBits == 4)
|
||||
{
|
||||
_spiTransaction.flags = SPI_TRANS_MODE_QIO;
|
||||
}
|
||||
_spiTransaction.tx_buffer = _dmadata;
|
||||
|
||||
esp_err_t ret = spi_device_queue_trans(_spiHandle, &_spiTransaction, 0); //Transmit!
|
||||
assert(ret == ESP_OK); //Should have had no issues.
|
||||
}
|
||||
|
||||
uint8_t* getData() const
|
||||
{
|
||||
return _data + _sizeStartFrame;
|
||||
};
|
||||
|
||||
size_t getDataSize() const
|
||||
{
|
||||
return _sizePixelData;
|
||||
};
|
||||
|
||||
void applySettings([[maybe_unused]] const SettingsObject& settings)
|
||||
{
|
||||
_speed.applySettings(settings);
|
||||
if (_spiHandle)
|
||||
{
|
||||
deinitSpiDevice();
|
||||
initSpiDevice();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void initSpiDevice()
|
||||
{
|
||||
spi_device_interface_config_t devcfg = {};
|
||||
|
||||
devcfg.clock_speed_hz = _speed.Clock;
|
||||
devcfg.mode = 0; //SPI mode 0
|
||||
devcfg.spics_io_num = _ssPin; //CS pin
|
||||
devcfg.queue_size = 1;
|
||||
if (T_SPIBUS::ParallelBits == 1)
|
||||
{
|
||||
devcfg.flags = 0;
|
||||
}
|
||||
if (T_SPIBUS::ParallelBits >= 2)
|
||||
{
|
||||
devcfg.flags = SPI_DEVICE_HALFDUPLEX;
|
||||
}
|
||||
|
||||
//Allocate the LEDs on the SPI bus
|
||||
esp_err_t ret = spi_bus_add_device(T_SPIBUS::SpiHostDevice, &devcfg, &_spiHandle);
|
||||
ESP_ERROR_CHECK(ret);
|
||||
}
|
||||
|
||||
void deinitSpiDevice()
|
||||
{
|
||||
while(!IsReadyToUpdate());
|
||||
esp_err_t ret = spi_bus_remove_device(_spiHandle);
|
||||
ESP_ERROR_CHECK(ret);
|
||||
}
|
||||
|
||||
const size_t _sizeStartFrame = 4;
|
||||
const size_t _sizePixelData; // Size of '_data' buffer below, minus (_sizeStartFrame + _sizeEndFrame)
|
||||
const size_t _sizeEndFrame;
|
||||
|
||||
size_t _spiBufferSize;
|
||||
uint8_t* _data; // Holds start/end frames and LED color values
|
||||
uint8_t* _dmadata; // Holds start/end frames and LED color values
|
||||
spi_device_handle_t _spiHandle = NULL;
|
||||
spi_transaction_t _spiTransaction;
|
||||
T_SPISPEED _speed;
|
||||
int8_t _ssPin;
|
||||
};
|
||||
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
// Clock Speed and Default Definitions for DotStarEsp32DmaVspi
|
||||
typedef DotStarEsp32DmaSpiMethod<SpiSpeed40Mhz, Esp32VspiBus> DotStarEsp32DmaVspi40MhzMethod;
|
||||
typedef DotStarEsp32DmaSpiMethod<SpiSpeed20Mhz, Esp32VspiBus> DotStarEsp32DmaVspi20MhzMethod;
|
||||
typedef DotStarEsp32DmaSpiMethod<SpiSpeed10Mhz, Esp32VspiBus> DotStarEsp32DmaVspi10MhzMethod;
|
||||
typedef DotStarEsp32DmaSpiMethod<SpiSpeed5Mhz, Esp32VspiBus> DotStarEsp32DmaVspi5MhzMethod;
|
||||
typedef DotStarEsp32DmaSpiMethod<SpiSpeed2Mhz, Esp32VspiBus> DotStarEsp32DmaVspi2MhzMethod;
|
||||
typedef DotStarEsp32DmaSpiMethod<SpiSpeed1Mhz, Esp32VspiBus> DotStarEsp32DmaVspi1MhzMethod;
|
||||
typedef DotStarEsp32DmaSpiMethod<SpiSpeed500Khz, Esp32VspiBus> DotStarEsp32DmaVspi500KhzMethod;
|
||||
typedef DotStarEsp32DmaSpiMethod<SpiSpeedHz, Esp32VspiBus> DotStarEsp32DmaVspiHzMethod;
|
||||
|
||||
typedef DotStarEsp32DmaVspi10MhzMethod DotStarEsp32DmaVspiMethod;
|
||||
#endif
|
||||
|
||||
// Clock Speed and Default Definitions for DotStarEsp32DmaHspi
|
||||
typedef DotStarEsp32DmaSpiMethod<SpiSpeed40Mhz, Esp32HspiBus> DotStarEsp32DmaHspi40MhzMethod;
|
||||
typedef DotStarEsp32DmaSpiMethod<SpiSpeed20Mhz, Esp32HspiBus> DotStarEsp32DmaHspi20MhzMethod;
|
||||
typedef DotStarEsp32DmaSpiMethod<SpiSpeed10Mhz, Esp32HspiBus> DotStarEsp32DmaHspi10MhzMethod;
|
||||
typedef DotStarEsp32DmaSpiMethod<SpiSpeed5Mhz, Esp32HspiBus> DotStarEsp32DmaHspi5MhzMethod;
|
||||
typedef DotStarEsp32DmaSpiMethod<SpiSpeed2Mhz, Esp32HspiBus> DotStarEsp32DmaHspi2MhzMethod;
|
||||
typedef DotStarEsp32DmaSpiMethod<SpiSpeed1Mhz, Esp32HspiBus> DotStarEsp32DmaHspi1MhzMethod;
|
||||
typedef DotStarEsp32DmaSpiMethod<SpiSpeed500Khz, Esp32HspiBus> DotStarEsp32DmaHspi500KhzMethod;
|
||||
typedef DotStarEsp32DmaSpiMethod<SpiSpeedHz, Esp32HspiBus> DotStarEsp32DmaHspiHzMethod;
|
||||
|
||||
typedef DotStarEsp32DmaHspi10MhzMethod DotStarEsp32DmaHspiMethod;
|
||||
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
// Clock Speed and Default Definitions for DotStarEsp32DmaVspi2Bit
|
||||
typedef DotStarEsp32DmaSpiMethod<SpiSpeed40Mhz,Esp32Vspi2BitBus> DotStarEsp32DmaVspi2Bit40MhzMethod;
|
||||
typedef DotStarEsp32DmaSpiMethod<SpiSpeed20Mhz,Esp32Vspi2BitBus> DotStarEsp32DmaVspi2Bit20MhzMethod;
|
||||
typedef DotStarEsp32DmaSpiMethod<SpiSpeed10Mhz,Esp32Vspi2BitBus> DotStarEsp32DmaVspi2Bit10MhzMethod;
|
||||
typedef DotStarEsp32DmaSpiMethod<SpiSpeed5Mhz,Esp32Vspi2BitBus> DotStarEsp32DmaVspi2Bit5MhzMethod;
|
||||
typedef DotStarEsp32DmaSpiMethod<SpiSpeed2Mhz,Esp32Vspi2BitBus> DotStarEsp32DmaVspi2Bit2MhzMethod;
|
||||
typedef DotStarEsp32DmaSpiMethod<SpiSpeed1Mhz,Esp32Vspi2BitBus> DotStarEsp32DmaVspi2Bit1MhzMethod;
|
||||
typedef DotStarEsp32DmaSpiMethod<SpiSpeed500Khz,Esp32Vspi2BitBus> DotStarEsp32DmaVspi2Bit500KhzMethod;
|
||||
typedef DotStarEsp32DmaSpiMethod<SpiSpeedHz,Esp32Vspi2BitBus> DotStarEsp32DmaVspi2BitHzMethod;
|
||||
|
||||
typedef DotStarEsp32DmaVspi2Bit10MhzMethod DotStarEsp32DmaVspi2BitMethod;
|
||||
#endif
|
||||
|
||||
// Clock Speed and Default Definitions for DotStarEsp32DmaHspi2Bit
|
||||
typedef DotStarEsp32DmaSpiMethod<SpiSpeed40Mhz,Esp32Hspi2BitBus> DotStarEsp32DmaHspi2Bit40MhzMethod;
|
||||
typedef DotStarEsp32DmaSpiMethod<SpiSpeed20Mhz,Esp32Hspi2BitBus> DotStarEsp32DmaHspi2Bit20MhzMethod;
|
||||
typedef DotStarEsp32DmaSpiMethod<SpiSpeed10Mhz,Esp32Hspi2BitBus> DotStarEsp32DmaHspi2Bit10MhzMethod;
|
||||
typedef DotStarEsp32DmaSpiMethod<SpiSpeed5Mhz,Esp32Hspi2BitBus> DotStarEsp32DmaHspi2Bit5MhzMethod;
|
||||
typedef DotStarEsp32DmaSpiMethod<SpiSpeed2Mhz,Esp32Hspi2BitBus> DotStarEsp32DmaHspi2Bit2MhzMethod;
|
||||
typedef DotStarEsp32DmaSpiMethod<SpiSpeed1Mhz,Esp32Hspi2BitBus> DotStarEsp32DmaHspi2Bit1MhzMethod;
|
||||
typedef DotStarEsp32DmaSpiMethod<SpiSpeed500Khz,Esp32Hspi2BitBus> DotStarEsp32DmaHspi2Bit500KhzMethod;
|
||||
typedef DotStarEsp32DmaSpiMethod<SpiSpeedHz,Esp32Hspi2BitBus> DotStarEsp32DmaHspi2BitHzMethod;
|
||||
|
||||
typedef DotStarEsp32DmaHspi2Bit10MhzMethod DotStarEsp32DmaHspi2BitMethod;
|
||||
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
// Clock Speed and Default Definitions for DotStarEsp32DmaVspi4Bit
|
||||
typedef DotStarEsp32DmaSpiMethod<SpiSpeed40Mhz,Esp32Vspi4BitBus> DotStarEsp32DmaVspi4Bit40MhzMethod;
|
||||
typedef DotStarEsp32DmaSpiMethod<SpiSpeed20Mhz,Esp32Vspi4BitBus> DotStarEsp32DmaVspi4Bit20MhzMethod;
|
||||
typedef DotStarEsp32DmaSpiMethod<SpiSpeed10Mhz,Esp32Vspi4BitBus> DotStarEsp32DmaVspi4Bit10MhzMethod;
|
||||
typedef DotStarEsp32DmaSpiMethod<SpiSpeed5Mhz,Esp32Vspi4BitBus> DotStarEsp32DmaVspi4Bit5MhzMethod;
|
||||
typedef DotStarEsp32DmaSpiMethod<SpiSpeed2Mhz,Esp32Vspi4BitBus> DotStarEsp32DmaVspi4Bit2MhzMethod;
|
||||
typedef DotStarEsp32DmaSpiMethod<SpiSpeed1Mhz,Esp32Vspi4BitBus> DotStarEsp32DmaVspi4Bit1MhzMethod;
|
||||
typedef DotStarEsp32DmaSpiMethod<SpiSpeed500Khz,Esp32Vspi4BitBus> DotStarEsp32DmaVspi4Bit500KhzMethod;
|
||||
typedef DotStarEsp32DmaSpiMethod<SpiSpeedHz,Esp32Vspi4BitBus> DotStarEsp32DmaVspi4BitHzMethod;
|
||||
|
||||
typedef DotStarEsp32DmaVspi4Bit10MhzMethod DotStarEsp32DmaVspi4BitMethod;
|
||||
#endif
|
||||
|
||||
// Clock Speed and Default Definitions for DotStarEsp32DmaHspi4Bit
|
||||
typedef DotStarEsp32DmaSpiMethod<SpiSpeed40Mhz,Esp32Hspi4BitBus> DotStarEsp32DmaHspi4Bit40MhzMethod;
|
||||
typedef DotStarEsp32DmaSpiMethod<SpiSpeed20Mhz,Esp32Hspi4BitBus> DotStarEsp32DmaHspi4Bit20MhzMethod;
|
||||
typedef DotStarEsp32DmaSpiMethod<SpiSpeed10Mhz,Esp32Hspi4BitBus> DotStarEsp32DmaHspi4Bit10MhzMethod;
|
||||
typedef DotStarEsp32DmaSpiMethod<SpiSpeed5Mhz,Esp32Hspi4BitBus> DotStarEsp32DmaHspi4Bit5MhzMethod;
|
||||
typedef DotStarEsp32DmaSpiMethod<SpiSpeed2Mhz,Esp32Hspi4BitBus> DotStarEsp32DmaHspi4Bit2MhzMethod;
|
||||
typedef DotStarEsp32DmaSpiMethod<SpiSpeed1Mhz,Esp32Hspi4BitBus> DotStarEsp32DmaHspi4Bit1MhzMethod;
|
||||
typedef DotStarEsp32DmaSpiMethod<SpiSpeed500Khz,Esp32Hspi4BitBus> DotStarEsp32DmaHspi4Bit500KhzMethod;
|
||||
typedef DotStarEsp32DmaSpiMethod<SpiSpeedHz,Esp32Hspi4BitBus> DotStarEsp32DmaHspi4BitHzMethod;
|
||||
|
||||
typedef DotStarEsp32DmaHspi4Bit10MhzMethod DotStarEsp32DmaHspi4BitMethod;
|
||||
@@ -0,0 +1,170 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
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:
|
||||
typedef typename T_TWOWIRE::SettingsObject SettingsObject;
|
||||
|
||||
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));
|
||||
// data cleared later in Begin()
|
||||
}
|
||||
|
||||
#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;
|
||||
};
|
||||
|
||||
void applySettings([[maybe_unused]] const SettingsObject& settings)
|
||||
{
|
||||
_wire.applySettings(settings);
|
||||
}
|
||||
|
||||
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<SpiSpeed5Mhz>> DotStarSpi5MhzMethod;
|
||||
typedef DotStarMethodBase<TwoWireSpiImple<SpiSpeed2Mhz>> DotStarSpi2MhzMethod;
|
||||
typedef DotStarMethodBase<TwoWireSpiImple<SpiSpeed1Mhz>> DotStarSpi1MhzMethod;
|
||||
typedef DotStarMethodBase<TwoWireSpiImple<SpiSpeed500Khz>> DotStarSpi500KhzMethod;
|
||||
typedef DotStarMethodBase<TwoWireSpiImple<SpiSpeedHz>> DotStarSpiHzMethod;
|
||||
|
||||
typedef DotStarSpi10MhzMethod DotStarSpiMethod;
|
||||
#endif
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP32)
|
||||
// Give option to use Vspi alias of Spi class if wanting to specify which SPI peripheral is used on the ESP32
|
||||
typedef DotStarMethodBase<TwoWireSpiImple<SpiSpeed40Mhz>> DotStarVspi40MhzMethod;
|
||||
typedef DotStarMethodBase<TwoWireSpiImple<SpiSpeed20Mhz>> DotStarVspi20MhzMethod;
|
||||
typedef DotStarMethodBase<TwoWireSpiImple<SpiSpeed10Mhz>> DotStarVspi10MhzMethod;
|
||||
typedef DotStarMethodBase<TwoWireSpiImple<SpiSpeed5Mhz>> DotStarVspi5MhzMethod;
|
||||
typedef DotStarMethodBase<TwoWireSpiImple<SpiSpeed2Mhz>> DotStarVspi2MhzMethod;
|
||||
typedef DotStarMethodBase<TwoWireSpiImple<SpiSpeed1Mhz>> DotStarVspi1MhzMethod;
|
||||
typedef DotStarMethodBase<TwoWireSpiImple<SpiSpeed500Khz>> DotStarVspi500KhzMethod;
|
||||
typedef DotStarMethodBase<TwoWireSpiImple<SpiSpeedHz>> DotStarVspiHzMethod;
|
||||
|
||||
typedef DotStarSpi10MhzMethod DotStarVspiMethod;
|
||||
|
||||
#include "TwoWireHspiImple.h"
|
||||
typedef DotStarMethodBase<TwoWireHspiImple<SpiSpeed40Mhz>> DotStarHspi40MhzMethod;
|
||||
typedef DotStarMethodBase<TwoWireHspiImple<SpiSpeed20Mhz>> DotStarHspi20MhzMethod;
|
||||
typedef DotStarMethodBase<TwoWireHspiImple<SpiSpeed10Mhz>> DotStarHspi10MhzMethod;
|
||||
typedef DotStarMethodBase<TwoWireHspiImple<SpiSpeed5Mhz>> DotStarHspi5MhzMethod;
|
||||
typedef DotStarMethodBase<TwoWireHspiImple<SpiSpeed2Mhz>> DotStarHspi2MhzMethod;
|
||||
typedef DotStarMethodBase<TwoWireHspiImple<SpiSpeed1Mhz>> DotStarHspi1MhzMethod;
|
||||
typedef DotStarMethodBase<TwoWireHspiImple<SpiSpeed500Khz>> DotStarHspi500KhzMethod;
|
||||
typedef DotStarMethodBase<TwoWireHspiImple<SpiSpeedHz>> DotStarHspiHzMethod;
|
||||
|
||||
typedef DotStarHspi10MhzMethod DotStarHspiMethod;
|
||||
#endif
|
||||
@@ -0,0 +1,525 @@
|
||||
// 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 "sdkconfig.h" // this sets useful config symbols, like CONFIG_IDF_TARGET_ESP32C3
|
||||
|
||||
// ESP32C3/S3 I2S is not supported yet due to significant changes to interface
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||
|
||||
#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"
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32)
|
||||
/* included here for ESP-IDF v4.x compatibility */
|
||||
#include "soc/dport_reg.h"
|
||||
#endif
|
||||
#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_BLOCK_COUNT_DEFAULT 16
|
||||
// 24 bytes gives us enough time if we use single stage idle
|
||||
// with the two stage idle we can use the minimum of 4 bytes
|
||||
#define I2S_DMA_SILENCE_SIZE 4*1
|
||||
#define I2S_DMA_SILENCE_BLOCK_COUNT 3 // two front, one back
|
||||
#define I2S_DMA_QUEUE_COUNT 2
|
||||
|
||||
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;
|
||||
volatile uint32_t is_sending_data;
|
||||
} i2s_bus_t;
|
||||
|
||||
// is_sending_data values
|
||||
#define I2s_Is_Idle 0
|
||||
#define I2s_Is_Pending 1
|
||||
#define I2s_Is_Sending 2
|
||||
|
||||
static uint8_t i2s_silence_buf[I2S_DMA_SILENCE_SIZE] = { 0 };
|
||||
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
// (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_SIZE, NULL, I2S_DMA_BLOCK_COUNT_DEFAULT, 0, 0, I2s_Is_Idle},
|
||||
{&I2S1, -1, -1, -1, -1, 0, NULL, NULL, i2s_silence_buf, I2S_DMA_SILENCE_SIZE, NULL, I2S_DMA_BLOCK_COUNT_DEFAULT, 0, 0, I2s_Is_Idle}
|
||||
};
|
||||
#else
|
||||
static i2s_bus_t I2S[I2S_NUM_MAX] = {
|
||||
{&I2S0, -1, -1, -1, -1, 0, NULL, NULL, i2s_silence_buf, I2S_DMA_SILENCE_SIZE, NULL, I2S_DMA_BLOCK_COUNT_DEFAULT, 0, 0, I2s_Is_Idle}
|
||||
};
|
||||
#endif
|
||||
|
||||
void IRAM_ATTR i2sDmaISR(void* arg);
|
||||
|
||||
|
||||
bool i2sInitDmaItems(uint8_t bus_num) {
|
||||
if (bus_num >= I2S_NUM_MAX) {
|
||||
return false;
|
||||
}
|
||||
if (I2S[bus_num].tx_queue) {// already set
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t dmaCount = I2S[bus_num].dma_count;
|
||||
|
||||
if (I2S[bus_num].dma_items == NULL) {
|
||||
I2S[bus_num].dma_items = (i2s_dma_item_t*)heap_caps_malloc(dmaCount * sizeof(i2s_dma_item_t), MALLOC_CAP_DMA);
|
||||
if (I2S[bus_num].dma_items == NULL) {
|
||||
log_e("MEM ERROR!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int i, i2;
|
||||
i2s_dma_item_t* item = NULL;
|
||||
i2s_dma_item_t* itemPrev = NULL;
|
||||
|
||||
for(i=0; i< dmaCount; i++) {
|
||||
itemPrev = item;
|
||||
|
||||
i2 = (i+1) % dmaCount;
|
||||
item = &I2S[bus_num].dma_items[i];
|
||||
item->eof = 0;
|
||||
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;
|
||||
item->buf = NULL;
|
||||
}
|
||||
itemPrev->eof = 1;
|
||||
item->eof = 1;
|
||||
|
||||
I2S[bus_num].tx_queue = xQueueCreate(I2S_DMA_QUEUE_COUNT, sizeof(i2s_dma_item_t*));
|
||||
if (I2S[bus_num].tx_queue == NULL) {// memory error
|
||||
log_e("MEM ERROR!");
|
||||
heap_caps_free(I2S[bus_num].dma_items);
|
||||
I2S[bus_num].dma_items = NULL;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool i2sDeinitDmaItems(uint8_t bus_num) {
|
||||
if (bus_num >= I2S_NUM_MAX) {
|
||||
return false;
|
||||
}
|
||||
if (!I2S[bus_num].tx_queue) {
|
||||
return false; // nothing to deinit
|
||||
}
|
||||
|
||||
vQueueDelete(I2S[bus_num].tx_queue);
|
||||
I2S[bus_num].tx_queue = NULL;
|
||||
heap_caps_free(I2S[bus_num].dma_items);
|
||||
I2S[bus_num].dma_items = NULL;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
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) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
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 i2sSetPins(uint8_t bus_num, int8_t out, bool invert)
|
||||
{
|
||||
if (bus_num >= I2S_NUM_MAX)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int8_t outOld = I2S[bus_num].out;
|
||||
|
||||
I2S[bus_num].out = out;
|
||||
|
||||
// disable old pin
|
||||
if (outOld >= 0)
|
||||
{
|
||||
gpio_matrix_out(outOld, 0x100, false, false);
|
||||
pinMode(outOld, INPUT);
|
||||
}
|
||||
|
||||
if (out >= 0)
|
||||
{
|
||||
pinMode(out, OUTPUT);
|
||||
|
||||
int i2sSignal;
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
// (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);
|
||||
}
|
||||
}
|
||||
|
||||
bool i2sWriteDone(uint8_t bus_num) {
|
||||
if (bus_num >= I2S_NUM_MAX) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (I2S[bus_num].is_sending_data == I2s_Is_Idle);
|
||||
}
|
||||
|
||||
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_DMA_SILENCE_BLOCK_COUNT; // an extra two for looping silence
|
||||
I2S[bus_num].dma_buf_len = dma_len & 0xFFF;
|
||||
|
||||
if (!i2sInitDmaItems(bus_num)) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
// (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;
|
||||
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
i2s->pdm_conf.pcm2pdm_conv_en = 0;
|
||||
i2s->pdm_conf.pdm2pcm_conv_en = 0;
|
||||
#endif
|
||||
// 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;
|
||||
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
i2s->pdm_conf.rx_pdm_en = 0;
|
||||
i2s->pdm_conf.tx_pdm_en = 0;
|
||||
#endif
|
||||
|
||||
i2sSetSampleRate(bus_num, sample_rate, bits_per_sample);
|
||||
|
||||
// enable intr in cpu //
|
||||
int i2sIntSource;
|
||||
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
// (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);
|
||||
}
|
||||
|
||||
void i2sDeinit(uint8_t bus_num) {
|
||||
i2sDeinitDmaItems(bus_num);
|
||||
}
|
||||
|
||||
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_bus_t* dev = (i2s_bus_t*)(arg);
|
||||
|
||||
if (dev->bus->int_st.out_eof)
|
||||
{
|
||||
// i2s_dma_item_t* item = (i2s_dma_item_t*)(dev->bus->out_eof_des_addr);
|
||||
if (dev->is_sending_data == I2s_Is_Pending)
|
||||
{
|
||||
dev->is_sending_data = I2s_Is_Idle;
|
||||
}
|
||||
else if (dev->is_sending_data == I2s_Is_Sending)
|
||||
{
|
||||
// loop the silent items
|
||||
i2s_dma_item_t* itemSilence = &dev->dma_items[1];
|
||||
itemSilence->next = &dev->dma_items[0];
|
||||
|
||||
dev->is_sending_data = I2s_Is_Pending;
|
||||
}
|
||||
}
|
||||
|
||||
dev->bus->int_clr.val = dev->bus->int_st.val;
|
||||
}
|
||||
|
||||
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 blockSize = len;
|
||||
|
||||
i2s_dma_item_t* item = &I2S[bus_num].dma_items[0];
|
||||
size_t dataLeft = len;
|
||||
uint8_t* pos = data;
|
||||
|
||||
// skip front two silent items
|
||||
item += 2;
|
||||
|
||||
while (dataLeft) {
|
||||
|
||||
blockSize = dataLeft;
|
||||
if (blockSize > I2S_DMA_MAX_DATA_LEN) {
|
||||
blockSize = I2S_DMA_MAX_DATA_LEN;
|
||||
}
|
||||
dataLeft -= blockSize;
|
||||
|
||||
// data is constant. no need to copy
|
||||
item->data = pos;
|
||||
item->blocksize = blockSize;
|
||||
item->datalen = blockSize;
|
||||
|
||||
item++;
|
||||
|
||||
pos += blockSize;
|
||||
}
|
||||
|
||||
|
||||
// reset silence item to not loop
|
||||
item = &I2S[bus_num].dma_items[1];
|
||||
item->next = &I2S[bus_num].dma_items[2];
|
||||
I2S[bus_num].is_sending_data = I2s_Is_Sending;
|
||||
|
||||
|
||||
xQueueReset(I2S[bus_num].tx_queue);
|
||||
xQueueSend(I2S[bus_num].tx_queue, (void*)&I2S[bus_num].dma_items[0], 10);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
#endif // !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
#endif // defined(ARDUINO_ARCH_ESP32)
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
|
||||
// ESP32C3 I2S is not supported yet due to significant changes to interface
|
||||
#if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
|
||||
#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 i2sDeinit(uint8_t bus_num);
|
||||
|
||||
void i2sSetPins(uint8_t bus_num, int8_t out, bool invert);
|
||||
|
||||
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);
|
||||
|
||||
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
|
||||
@@ -0,0 +1,83 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
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 "Rgb48Color.h"
|
||||
#include "HsbColor.h"
|
||||
|
||||
void HsbColor::_RgbToHsb(float r, float g, float b, HsbColor* color)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
color->H = h;
|
||||
color->S = s;
|
||||
color->B = v;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
_RgbToHsb(r, g, b, this);
|
||||
}
|
||||
|
||||
HsbColor::HsbColor(const Rgb48Color& color)
|
||||
{
|
||||
// convert colors to float between (0.0 - 1.0)
|
||||
float r = color.R / 65535.0f;
|
||||
float g = color.G / 65535.0f;
|
||||
float b = color.B / 65535.0f;
|
||||
|
||||
_RgbToHsb(r, g, b, this);
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
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 using Rgb48Color
|
||||
// ------------------------------------------------------------------------
|
||||
HsbColor(const Rgb48Color& 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;
|
||||
|
||||
private:
|
||||
static void _RgbToHsb(float r, float g, float b, HsbColor* color);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
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 "Rgb48Color.h"
|
||||
#include "HslColor.h"
|
||||
|
||||
void HslColor::_RgbToHsl(float r, float g, float b, HslColor* color)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
color->H = h;
|
||||
color->S = s;
|
||||
color->L = l;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
_RgbToHsl(r, g, b, this);
|
||||
}
|
||||
|
||||
HslColor::HslColor(const Rgb48Color& color)
|
||||
{
|
||||
// convert colors to float between (0.0 - 1.0)
|
||||
float r = color.R / 65535.0f;
|
||||
float g = color.G / 65535.0f;
|
||||
float b = color.B / 65535.0f;
|
||||
|
||||
_RgbToHsl(r, g, b, this);
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
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 using Rgb48Color
|
||||
// ------------------------------------------------------------------------
|
||||
HslColor(const Rgb48Color& 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;
|
||||
|
||||
private:
|
||||
static void _RgbToHsl(float r, float g, float b, HslColor* color);
|
||||
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -0,0 +1,336 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
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 "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
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 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 = static_cast<uint32_t>(color.R) << 16 | static_cast<uint32_t>(color.G) << 8 | static_cast<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;
|
||||
};
|
||||
|
||||
@@ -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";
|
||||
@@ -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;
|
||||
@@ -0,0 +1,191 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
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 <Arduino.h>
|
||||
#include "NeoUtil.h"
|
||||
#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);
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
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 <Arduino.h>
|
||||
#include "NeoUtil.h"
|
||||
#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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,301 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
Lpd6803ColorFeatures 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 Lpd68033ElementsNoSettings
|
||||
{
|
||||
public:
|
||||
typedef NeoNoSettings SettingsObject;
|
||||
static const size_t SettingsSize = 0;
|
||||
|
||||
static void applySettings([[maybe_unused]] uint8_t* pData, [[maybe_unused]] size_t sizeData, [[maybe_unused]] const SettingsObject& settings)
|
||||
{
|
||||
}
|
||||
|
||||
static uint8_t* pixels([[maybe_unused]] uint8_t* pData, [[maybe_unused]] size_t sizeData)
|
||||
{
|
||||
return pData;
|
||||
}
|
||||
|
||||
static const uint8_t* pixels([[maybe_unused]] const uint8_t* pData, [[maybe_unused]] size_t sizeData)
|
||||
{
|
||||
return pData;
|
||||
}
|
||||
};
|
||||
|
||||
class Lpd68033Elements : public Lpd68033ElementsNoSettings
|
||||
{
|
||||
public:
|
||||
static const size_t PixelSize = 2; // 1 bit + 555 encoded elements
|
||||
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
||||
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++;
|
||||
}
|
||||
}
|
||||
|
||||
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++);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
typedef RgbColor ColorObject;
|
||||
|
||||
protected:
|
||||
static void encodePixel(uint8_t c1, uint8_t c2, uint8_t c3, uint16_t* color555)
|
||||
{
|
||||
*color555 = (0x8000 |
|
||||
((c1 & 0xf8) << 7) |
|
||||
((c2 & 0xf8) << 2) |
|
||||
((c3 & 0xf8) >> 3));
|
||||
}
|
||||
|
||||
static void decodePixel(uint16_t color555, uint8_t* c1, uint8_t* c2, uint8_t* c3)
|
||||
{
|
||||
*c1 = (color555 >> 7) & 0xf8;
|
||||
*c2 = (color555 >> 2) & 0xf8;
|
||||
*c3 = (color555 << 3) & 0xf8;
|
||||
}
|
||||
};
|
||||
|
||||
class Lpd6803BrgFeature : public Lpd68033Elements
|
||||
{
|
||||
public:
|
||||
static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color)
|
||||
{
|
||||
uint8_t* p = getPixelAddress(pPixels, indexPixel);
|
||||
uint16_t color555;
|
||||
|
||||
encodePixel(color.B, color.R, color.G, &color555);
|
||||
*p++ = color555 >> 8;
|
||||
*p = color555 & 0xff;
|
||||
}
|
||||
|
||||
static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel)
|
||||
{
|
||||
ColorObject color;
|
||||
const uint8_t* p = getPixelAddress(pPixels, indexPixel);
|
||||
|
||||
uint16_t color555;
|
||||
|
||||
color555 = ((*p++) << 8);
|
||||
color555 |= (*p);
|
||||
|
||||
decodePixel(color555, &color.B, &color.R, &color.G);
|
||||
|
||||
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);
|
||||
|
||||
uint16_t color555;
|
||||
|
||||
color555 = (pgm_read_byte(p++) << 8);
|
||||
color555 |= pgm_read_byte(p);
|
||||
|
||||
decodePixel(color555, &color.B, &color.R, &color.G);
|
||||
|
||||
return color;
|
||||
}
|
||||
};
|
||||
|
||||
class Lpd6803GrbFeature : public Lpd68033Elements
|
||||
{
|
||||
public:
|
||||
static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color)
|
||||
{
|
||||
uint8_t* p = getPixelAddress(pPixels, indexPixel);
|
||||
uint16_t color555;
|
||||
|
||||
encodePixel(color.G, color.R, color.B, &color555);
|
||||
*p++ = color555 >> 8;
|
||||
*p = color555 & 0xff;
|
||||
}
|
||||
|
||||
static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel)
|
||||
{
|
||||
ColorObject color;
|
||||
const uint8_t* p = getPixelAddress(pPixels, indexPixel);
|
||||
|
||||
uint16_t color555;
|
||||
|
||||
color555 = ((*p++) << 8);
|
||||
color555 |= (*p);
|
||||
|
||||
decodePixel(color555, &color.G, &color.R, &color.B);
|
||||
|
||||
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);
|
||||
|
||||
uint16_t color555;
|
||||
|
||||
color555 = (pgm_read_byte(p++) << 8);
|
||||
color555 |= pgm_read_byte(p);
|
||||
|
||||
decodePixel(color555, &color.G, &color.R, &color.B);
|
||||
|
||||
return color;
|
||||
}
|
||||
};
|
||||
|
||||
class Lpd6803GbrFeature : public Lpd68033Elements
|
||||
{
|
||||
public:
|
||||
static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color)
|
||||
{
|
||||
uint8_t* p = getPixelAddress(pPixels, indexPixel);
|
||||
uint16_t color555;
|
||||
|
||||
encodePixel(color.G, color.B, color.R, &color555);
|
||||
*p++ = color555 >> 8;
|
||||
*p = color555 & 0xff;
|
||||
}
|
||||
|
||||
static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel)
|
||||
{
|
||||
ColorObject color;
|
||||
const uint8_t* p = getPixelAddress(pPixels, indexPixel);
|
||||
|
||||
uint16_t color555;
|
||||
|
||||
color555 = ((*p++) << 8);
|
||||
color555 |= (*p);
|
||||
|
||||
decodePixel(color555, &color.G, &color.B, &color.R);
|
||||
|
||||
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);
|
||||
|
||||
uint16_t color555;
|
||||
|
||||
color555 = (pgm_read_byte(p++) << 8);
|
||||
color555 |= pgm_read_byte(p);
|
||||
|
||||
decodePixel(color555, &color.G, &color.B, &color.R);
|
||||
|
||||
return color;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class Lpd6803RgbFeature : public Lpd68033Elements
|
||||
{
|
||||
public:
|
||||
static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color)
|
||||
{
|
||||
uint8_t* p = getPixelAddress(pPixels, indexPixel);
|
||||
uint16_t color555;
|
||||
|
||||
encodePixel(color.R, color.G, color.B, &color555);
|
||||
*p++ = color555 >> 8;
|
||||
*p = color555 & 0xff;
|
||||
}
|
||||
|
||||
static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel)
|
||||
{
|
||||
ColorObject color;
|
||||
const uint8_t* p = getPixelAddress(pPixels, indexPixel);
|
||||
|
||||
uint16_t color555;
|
||||
|
||||
color555 = ((*p++) << 8);
|
||||
color555 |= (*p);
|
||||
|
||||
decodePixel(color555, &color.R, &color.G, &color.B);
|
||||
|
||||
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);
|
||||
|
||||
uint16_t color555;
|
||||
|
||||
color555 = (pgm_read_byte(p++) << 8);
|
||||
color555 |= pgm_read_byte(p);
|
||||
|
||||
decodePixel(color555, &color.R, &color.G, &color.B);
|
||||
|
||||
return color;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
NeoPixel library helper functions for LPD6803 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 Lpd6803MethodBase
|
||||
{
|
||||
public:
|
||||
typedef typename T_TWOWIRE::SettingsObject SettingsObject;
|
||||
|
||||
Lpd6803MethodBase(uint8_t pinClock, uint8_t pinData, uint16_t pixelCount, size_t elementSize, size_t settingsSize) :
|
||||
_sizeData(pixelCount * elementSize + settingsSize),
|
||||
_sizeFrame((pixelCount + 7) / 8), // bit for every pixel at least
|
||||
_wire(pinClock, pinData)
|
||||
{
|
||||
_data = static_cast<uint8_t*>(malloc(_sizeData));
|
||||
// data cleared later in Begin()
|
||||
}
|
||||
|
||||
#if !defined(__AVR_ATtiny85__) && !defined(ARDUINO_attiny)
|
||||
Lpd6803MethodBase(uint16_t pixelCount, size_t elementSize, size_t settingsSize) :
|
||||
Lpd6803MethodBase(SCK, MOSI, pixelCount, elementSize, settingsSize)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
~Lpd6803MethodBase()
|
||||
{
|
||||
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 };
|
||||
|
||||
_wire.beginTransaction();
|
||||
|
||||
// start frame
|
||||
_wire.transmitBytes(startFrame, sizeof(startFrame));
|
||||
|
||||
// data
|
||||
_wire.transmitBytes(_data, _sizeData);
|
||||
|
||||
// end frame
|
||||
// one bit for every pixel with no less than 1 byte
|
||||
for (size_t frameByte = 0; frameByte < _sizeFrame; frameByte++)
|
||||
{
|
||||
_wire.transmitByte(0x00);
|
||||
}
|
||||
|
||||
_wire.endTransaction();
|
||||
}
|
||||
|
||||
uint8_t* getData() const
|
||||
{
|
||||
return _data;
|
||||
};
|
||||
|
||||
size_t getDataSize() const
|
||||
{
|
||||
return _sizeData;
|
||||
};
|
||||
|
||||
void applySettings([[maybe_unused]] const SettingsObject& settings)
|
||||
{
|
||||
_wire.applySettings(settings);
|
||||
}
|
||||
|
||||
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 Lpd6803MethodBase<TwoWireBitBangImple> Lpd6803Method;
|
||||
|
||||
#if !defined(__AVR_ATtiny85__) && !defined(ARDUINO_attiny)
|
||||
#include "TwoWireSpiImple.h"
|
||||
typedef Lpd6803MethodBase<TwoWireSpiImple<SpiSpeed20Mhz>> Lpd6803Spi20MhzMethod;
|
||||
typedef Lpd6803MethodBase<TwoWireSpiImple<SpiSpeed10Mhz>> Lpd6803Spi10MhzMethod;
|
||||
typedef Lpd6803MethodBase<TwoWireSpiImple<SpiSpeed5Mhz>> Lpd6803Spi5MhzMethod;
|
||||
typedef Lpd6803MethodBase<TwoWireSpiImple<SpiSpeed2Mhz>> Lpd6803Spi2MhzMethod;
|
||||
typedef Lpd6803MethodBase<TwoWireSpiImple<SpiSpeed1Mhz>> Lpd6803Spi1MhzMethod;
|
||||
typedef Lpd6803MethodBase<TwoWireSpiImple<SpiSpeed500Khz>> Lpd6803Spi500KhzMethod;
|
||||
|
||||
typedef Lpd6803MethodBase<TwoWireSpiImple<SpiSpeedHz>> Lpd6803SpiHzMethod;
|
||||
|
||||
typedef Lpd6803Spi10MhzMethod Lpd6803SpiMethod;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -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([[maybe_unused]] uint8_t* pData, [[maybe_unused]] size_t sizeData, [[maybe_unused]] const SettingsObject& settings)
|
||||
{
|
||||
}
|
||||
|
||||
static uint8_t* pixels([[maybe_unused]] uint8_t* pData, [[maybe_unused]] size_t sizeData)
|
||||
{
|
||||
return pData;
|
||||
}
|
||||
|
||||
static const uint8_t* pixels([[maybe_unused]] const uint8_t* pData, [[maybe_unused]] size_t sizeData)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
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:
|
||||
typedef typename T_TWOWIRE::SettingsObject SettingsObject;
|
||||
|
||||
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));
|
||||
// data cleared later in Begin()
|
||||
}
|
||||
|
||||
#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;
|
||||
};
|
||||
|
||||
void applySettings([[maybe_unused]] const SettingsObject& settings)
|
||||
{
|
||||
_wire.applySettings(settings);
|
||||
}
|
||||
|
||||
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<SpiSpeed5Mhz>> Lpd8806Spi5MhzMethod;
|
||||
typedef Lpd8806MethodBase<TwoWireSpiImple<SpiSpeed2Mhz>> Lpd8806Spi2MhzMethod;
|
||||
typedef Lpd8806MethodBase<TwoWireSpiImple<SpiSpeed1Mhz>> Lpd8806Spi1MhzMethod;
|
||||
typedef Lpd8806MethodBase<TwoWireSpiImple<SpiSpeed500Khz>> Lpd8806Spi500KhzMethod;
|
||||
|
||||
typedef Lpd8806MethodBase<TwoWireSpiImple<SpiSpeedHz>> Lpd8806SpiHzMethod;
|
||||
|
||||
typedef Lpd8806Spi10MhzMethod Lpd8806SpiMethod;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,866 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
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:
|
||||
typedef NeoNoSettings SettingsObject;
|
||||
|
||||
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));
|
||||
// data cleared later in Begin()
|
||||
}
|
||||
|
||||
~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;
|
||||
};
|
||||
|
||||
void applySettings([[maybe_unused]] const SettingsObject& settings)
|
||||
{
|
||||
}
|
||||
|
||||
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 NeoArmMk20dxSpeedPropsTm1829 : 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<NeoArmMk20dxSpeedPropsTm1829>> NeoArmTm1829InvertedMethod;
|
||||
typedef NeoArmMethodBase<NeoArmMk20dxSpeedBase<NeoArmMk20dxSpeedPropsApa106>> NeoArmApa106Method;
|
||||
typedef NeoArmMethodBase<NeoArmMk20dxSpeedBase<NeoArmMk20dxSpeedProps800Kbps>> NeoArm800KbpsMethod;
|
||||
typedef NeoArmMethodBase<NeoArmMk20dxSpeedBase<NeoArmMk20dxSpeedProps400Kbps>> NeoArm400KbpsMethod;
|
||||
|
||||
typedef NeoArmTm1814InvertedMethod NeoArmTm1914InvertedMethod;
|
||||
|
||||
#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 NeoArmMk26z64SpeedTm1829 : 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<NeoArmMk26z64SpeedTm1829> NeoArmTm1829InvertedMethod;
|
||||
typedef NeoArmMethodBase<NeoArmMk26z64Speed800Kbps> NeoArm800KbpsMethod;
|
||||
typedef NeoArm800KbpsMethod NeoArmApa106Method;
|
||||
typedef NeoArmTm1814InvertedMethod NeoArmTm1914InvertedMethod;
|
||||
|
||||
#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 NeoArmSamd21g18aSpeedPropsTm1829 : 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<NeoArmSamd21g18aSpeedPropsTm1829>> NeoArmTm1829InvertedMethod;
|
||||
typedef NeoArmMethodBase<NeoArmSamd21g18aSpeedBase<NeoArmSamd21g18aSpeedProps800Kbps>> NeoArm800KbpsMethod;
|
||||
typedef NeoArmMethodBase<NeoArmSamd21g18aSpeedBase<NeoArmSamd21g18aSpeedProps400Kbps>> NeoArm400KbpsMethod;
|
||||
typedef NeoArm400KbpsMethod NeoArmApa106Method;
|
||||
typedef NeoArmTm1814InvertedMethod NeoArmTm1914InvertedMethod;
|
||||
|
||||
#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 NeoArmStm32SpeedPropsTm1829 : 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<NeoArmStm32SpeedPropsTm1829>> NeoArmTm1829InvertedMethod;
|
||||
typedef NeoArmMethodBase<NeoArmStm32SpeedBase<NeoArmStm32SpeedProps800Kbps>> NeoArm800KbpsMethod;
|
||||
typedef NeoArm800KbpsMethod NeoArmApa106Method;
|
||||
typedef NeoArmTm1814InvertedMethod NeoArmTm1914InvertedMethod;
|
||||
|
||||
#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 = static_cast<uint32_t>((0.40 * ARM_OTHER_SCALE + 0.5) - (5 * ARM_OTHER_INST));
|
||||
static const uint32_t CyclesT1h = static_cast<uint32_t>((0.80 * ARM_OTHER_SCALE + 0.5) - (5 * ARM_OTHER_INST));
|
||||
static const uint32_t Cycles = static_cast<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 NeoArmOtherSpeedPropsTm1829 : 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 = static_cast<uint32_t>((0.50 * ARM_OTHER_SCALE + 0.5) - (5 * ARM_OTHER_INST));
|
||||
static const uint32_t CyclesT1h = static_cast<uint32_t>((1.20 * ARM_OTHER_SCALE + 0.5) - (5 * ARM_OTHER_INST));
|
||||
static const uint32_t Cycles = static_cast<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(static_cast<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<NeoArmOtherSpeedPropsTm1829>> NeoArmTm1829InvertedMethod;
|
||||
typedef NeoArmMethodBase<NeoArmOtherSpeedBase<NeoArmOtherSpeedProps800Kbps>> NeoArm800KbpsMethod;
|
||||
typedef NeoArmMethodBase<NeoArmOtherSpeedBase<NeoArmOtherSpeedProps400Kbps>> NeoArm400KbpsMethod;
|
||||
typedef NeoArm400KbpsMethod NeoArmApa106Method;
|
||||
typedef NeoArmTm1814InvertedMethod NeoArmTm1914InvertedMethod;
|
||||
|
||||
#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 non-invert methods for arm, but the norm for TM1814 is inverted, so
|
||||
typedef NeoArmTm1814InvertedMethod NeoTm1814InvertedMethod;
|
||||
typedef NeoArmTm1914InvertedMethod NeoTm1914InvertedMethod;
|
||||
typedef NeoArmTm1829InvertedMethod NeoTm1829InvertedMethod;
|
||||
|
||||
#endif // defined(__arm__)
|
||||
|
||||
@@ -0,0 +1,240 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
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 NeoAvrSpeedTm1829 : 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:
|
||||
typedef NeoNoSettings SettingsObject;
|
||||
|
||||
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));
|
||||
// data cleared later in Begin()
|
||||
|
||||
_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;
|
||||
};
|
||||
|
||||
void applySettings([[maybe_unused]] const SettingsObject& settings)
|
||||
{
|
||||
}
|
||||
|
||||
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<NeoAvrSpeedTm1829> NeoAvrTm1829InvertedMethod;
|
||||
typedef NeoAvrMethodBase<NeoAvrSpeed800Kbps> NeoAvr800KbpsMethod;
|
||||
typedef NeoAvrMethodBase<NeoAvrSpeed400Kbps> NeoAvr400KbpsMethod;
|
||||
typedef NeoAvrTm1814InvertedMethod NeoAvrTm1914InvertedMethod;
|
||||
|
||||
// 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;
|
||||
|
||||
// there is no non-invert methods for avr, but the norm for TM1814 is inverted, so
|
||||
typedef NeoAvrTm1814InvertedMethod NeoTm1814InvertedMethod;
|
||||
typedef NeoAvrTm1914InvertedMethod NeoTm1914InvertedMethod;
|
||||
typedef NeoAvrTm1829InvertedMethod NeoTm1829InvertedMethod;
|
||||
#endif
|
||||
|
||||
@@ -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 (static_cast<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 (static_cast<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 (static_cast<uint16_t>(x) >= _width)
|
||||
{
|
||||
x = _width - 1;
|
||||
}
|
||||
return x;
|
||||
};
|
||||
|
||||
int16_t constrainY(int16_t y) const
|
||||
{
|
||||
if (y < 0)
|
||||
{
|
||||
y = 0;
|
||||
}
|
||||
else if (static_cast<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;
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,172 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
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++)
|
||||
{
|
||||
const uint8_t* pSrc = T_BUFFER_METHOD::ColorFeature::getPixelAddress(_method.Pixels(), indexPixel);
|
||||
uint8_t* pDest = T_BUFFER_METHOD::ColorFeature::getPixelAddress(destBuffer.Pixels, indexPixel);
|
||||
|
||||
shader.Apply(indexPixel, pDest, pSrc);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
T_BUFFER_METHOD _method;
|
||||
|
||||
uint16_t pixelIndex(
|
||||
int16_t x,
|
||||
int16_t y) const
|
||||
{
|
||||
uint16_t result = PixelIndex_OutOfBounds;
|
||||
|
||||
if (x >= 0 &&
|
||||
static_cast<uint16_t>(x) < Width() &&
|
||||
y >= 0 &&
|
||||
static_cast<uint16_t>(y) < Height())
|
||||
{
|
||||
result = x + y * Width();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
@@ -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;
|
||||
|
||||
};
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
|
||||
// For those platforms/methods that support dynamic channel setting
|
||||
//
|
||||
// ESP32 - 8 TX channels
|
||||
// ESP32S2 - 4 TX channels
|
||||
// ESP32C3 - 2 TX channels
|
||||
// NRF52840 - 3 or 4 channels (some variants only have 3)
|
||||
|
||||
enum NeoBusChannel
|
||||
{
|
||||
NeoBusChannel_0,
|
||||
NeoBusChannel_1,
|
||||
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
|
||||
NeoBusChannel_2,
|
||||
|
||||
// NRF52x has only 3 or 4 channels of PWM
|
||||
#if defined(ARDUINO_ARCH_NRF52840)
|
||||
|
||||
#if defined(NRF_PWM3)
|
||||
NeoBusChannel_3,
|
||||
#endif
|
||||
|
||||
// ESP32 has either 8, 4, or 2 channels (S2 has only 4, C3 only 2)
|
||||
#elif defined(ARDUINO_ARCH_ESP32)
|
||||
|
||||
NeoBusChannel_3,
|
||||
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
NeoBusChannel_4,
|
||||
NeoBusChannel_5,
|
||||
NeoBusChannel_6,
|
||||
NeoBusChannel_7,
|
||||
#endif // !defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
|
||||
#endif // !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
|
||||
#endif // ARDUINO_ARCH_ESP32
|
||||
|
||||
NeoBusChannel_COUNT
|
||||
};
|
||||
@@ -0,0 +1,713 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
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 Neo3ByteElements
|
||||
{
|
||||
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 = reinterpret_cast<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 Neo4ByteElements
|
||||
{
|
||||
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 = reinterpret_cast<uint32_t*>(pPixelDest);
|
||||
const uint32_t* pSrc = reinterpret_cast<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 = reinterpret_cast<uint32_t*>(pPixelDest);
|
||||
const uint32_t* pSrc = reinterpret_cast<const 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 = reinterpret_cast<uint32_t*>(pPixelDest);
|
||||
const uint32_t* pSrc = reinterpret_cast<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 = reinterpret_cast<uint32_t*>(pPixelDest);
|
||||
const uint32_t* pSrc = reinterpret_cast<const uint32_t*>(pPixelSrc);
|
||||
uint32_t* pDestBack = pDest + count;
|
||||
const uint32_t* pSrcBack = pSrc + count;
|
||||
while (pDestBack > pDest)
|
||||
{
|
||||
*--pDestBack = *--pSrcBack;
|
||||
}
|
||||
}
|
||||
|
||||
typedef RgbwColor ColorObject;
|
||||
};
|
||||
|
||||
class Neo6ByteElements
|
||||
{
|
||||
public:
|
||||
static const size_t PixelSize = 6;
|
||||
|
||||
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)
|
||||
{
|
||||
uint16_t* pDest = reinterpret_cast<uint16_t*>(pPixelDest);
|
||||
const uint16_t* pSrc = reinterpret_cast<const uint16_t*>(pPixelSrc);
|
||||
|
||||
uint16_t* pEnd = pDest + (count * PixelSize / 2);
|
||||
while (pDest < pEnd)
|
||||
{
|
||||
*pDest++ = *pSrc;
|
||||
}
|
||||
}
|
||||
|
||||
static void movePixelsInc(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count)
|
||||
{
|
||||
uint16_t* pDest = reinterpret_cast<uint16_t*>(pPixelDest);
|
||||
const uint16_t* pSrc = reinterpret_cast<const uint16_t*>(pPixelSrc);
|
||||
uint16_t* pEnd = pDest + (count * PixelSize / 2);
|
||||
while (pDest < pEnd)
|
||||
{
|
||||
*pDest++ = *pSrc++;
|
||||
}
|
||||
}
|
||||
|
||||
static void movePixelsInc_P(uint8_t* pPixelDest, PGM_VOID_P pPixelSrc, uint16_t count)
|
||||
{
|
||||
uint16_t* pDest = reinterpret_cast<uint16_t*>(pPixelDest);
|
||||
const uint16_t* pSrc = reinterpret_cast<const uint16_t*>(pPixelSrc);
|
||||
uint16_t* pEnd = pDest + (count * PixelSize / 2);
|
||||
while (pDest < pEnd)
|
||||
{
|
||||
*pDest++ = pgm_read_word(pSrc++);
|
||||
}
|
||||
}
|
||||
|
||||
static void movePixelsDec(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count)
|
||||
{
|
||||
uint16_t* pDest = reinterpret_cast<uint16_t*>(pPixelDest);
|
||||
const uint16_t* pSrc = reinterpret_cast<const uint16_t*>(pPixelSrc);
|
||||
uint16_t* pDestBack = pDest + (count * PixelSize / 2);
|
||||
const uint16_t* pSrcBack = pSrc + (count * PixelSize / 2);
|
||||
while (pDestBack > pDest)
|
||||
{
|
||||
*--pDestBack = *--pSrcBack;
|
||||
}
|
||||
}
|
||||
|
||||
typedef Rgb48Color ColorObject;
|
||||
};
|
||||
|
||||
class Neo8ByteElements
|
||||
{
|
||||
public:
|
||||
static const size_t PixelSize = 8;
|
||||
|
||||
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 = reinterpret_cast<uint32_t*>(pPixelDest);
|
||||
const uint32_t* pSrc = reinterpret_cast<const uint32_t*>(pPixelSrc);
|
||||
|
||||
uint32_t* pEnd = pDest + (count * PixelSize);
|
||||
while (pDest < pEnd)
|
||||
{
|
||||
*pDest++ = *pSrc;
|
||||
}
|
||||
}
|
||||
|
||||
static void movePixelsInc(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count)
|
||||
{
|
||||
uint32_t* pDest = reinterpret_cast<uint32_t*>(pPixelDest);
|
||||
const uint32_t* pSrc = reinterpret_cast<const uint32_t*>(pPixelSrc);
|
||||
uint32_t* pEnd = pDest + (count * PixelSize);
|
||||
while (pDest < pEnd)
|
||||
{
|
||||
*pDest++ = *pSrc++;
|
||||
}
|
||||
}
|
||||
|
||||
static void movePixelsInc_P(uint8_t* pPixelDest, PGM_VOID_P pPixelSrc, uint16_t count)
|
||||
{
|
||||
uint32_t* pDest = reinterpret_cast<uint32_t*>(pPixelDest);
|
||||
const uint32_t* pSrc = reinterpret_cast<const uint32_t*>(pPixelSrc);
|
||||
uint32_t* pEnd = pDest + (count * PixelSize);
|
||||
while (pDest < pEnd)
|
||||
{
|
||||
*pDest++ = pgm_read_dword(pSrc++);
|
||||
}
|
||||
}
|
||||
|
||||
static void movePixelsDec(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count)
|
||||
{
|
||||
uint32_t* pDest = reinterpret_cast<uint32_t*>(pPixelDest);
|
||||
const uint32_t* pSrc = reinterpret_cast<const uint32_t*>(pPixelSrc);
|
||||
uint32_t* pDestBack = pDest + (count * PixelSize);
|
||||
const uint32_t* pSrcBack = pSrc + (count * PixelSize);
|
||||
while (pDestBack > pDest)
|
||||
{
|
||||
*--pDestBack = *--pSrcBack;
|
||||
}
|
||||
}
|
||||
|
||||
typedef Rgbw64Color ColorObject;
|
||||
};
|
||||
|
||||
class Neo3ByteElementsNoSettings : public Neo3ByteElements
|
||||
{
|
||||
public:
|
||||
typedef NeoNoSettings SettingsObject;
|
||||
static const size_t SettingsSize = 0;
|
||||
|
||||
static void applySettings([[maybe_unused]] uint8_t* pData, [[maybe_unused]] size_t sizeData, [[maybe_unused]] const SettingsObject& settings)
|
||||
{
|
||||
}
|
||||
|
||||
static uint8_t* pixels([[maybe_unused]] uint8_t* pData, [[maybe_unused]] size_t sizeData)
|
||||
{
|
||||
return pData;
|
||||
}
|
||||
|
||||
static const uint8_t* pixels([[maybe_unused]] const uint8_t* pData, [[maybe_unused]] size_t sizeData)
|
||||
{
|
||||
return pData;
|
||||
}
|
||||
};
|
||||
|
||||
class Neo4ByteElementsNoSettings : public Neo4ByteElements
|
||||
{
|
||||
public:
|
||||
typedef NeoNoSettings SettingsObject;
|
||||
static const size_t SettingsSize = 0;
|
||||
|
||||
static void applySettings([[maybe_unused]] uint8_t* pData, [[maybe_unused]] size_t sizeData, [[maybe_unused]] const SettingsObject& settings)
|
||||
{
|
||||
}
|
||||
|
||||
static uint8_t* pixels([[maybe_unused]] uint8_t* pData, [[maybe_unused]] size_t sizeData)
|
||||
{
|
||||
return pData;
|
||||
}
|
||||
|
||||
static const uint8_t* pixels([[maybe_unused]] const uint8_t* pData, [[maybe_unused]] size_t sizeData)
|
||||
{
|
||||
return pData;
|
||||
}
|
||||
};
|
||||
|
||||
class Neo6ByteElementsNoSettings : public Neo6ByteElements
|
||||
{
|
||||
public:
|
||||
typedef NeoNoSettings SettingsObject;
|
||||
static const size_t SettingsSize = 0;
|
||||
|
||||
static void applySettings([[maybe_unused]] uint8_t* pData, [[maybe_unused]] size_t sizeData, [[maybe_unused]] const SettingsObject& settings)
|
||||
{
|
||||
}
|
||||
|
||||
static uint8_t* pixels([[maybe_unused]] uint8_t* pData, [[maybe_unused]] size_t sizeData)
|
||||
{
|
||||
return pData;
|
||||
}
|
||||
|
||||
static const uint8_t* pixels([[maybe_unused]] const uint8_t* pData, [[maybe_unused]] size_t sizeData)
|
||||
{
|
||||
return pData;
|
||||
}
|
||||
};
|
||||
|
||||
class Neo8ByteElementsNoSettings : public Neo8ByteElements
|
||||
{
|
||||
public:
|
||||
typedef NeoNoSettings SettingsObject;
|
||||
static const size_t SettingsSize = 0;
|
||||
|
||||
static void applySettings([[maybe_unused]] uint8_t* pData, [[maybe_unused]] size_t sizeData, [[maybe_unused]] const SettingsObject& settings)
|
||||
{
|
||||
}
|
||||
|
||||
static uint8_t* pixels([[maybe_unused]] uint8_t* pData, [[maybe_unused]] size_t sizeData)
|
||||
{
|
||||
return pData;
|
||||
}
|
||||
|
||||
static const uint8_t* pixels([[maybe_unused]] const uint8_t* pData, [[maybe_unused]] size_t sizeData)
|
||||
{
|
||||
return pData;
|
||||
}
|
||||
};
|
||||
|
||||
class NeoGrbFeature : public Neo3ByteElementsNoSettings
|
||||
{
|
||||
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(reinterpret_cast<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 Neo4ByteElementsNoSettings
|
||||
{
|
||||
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(reinterpret_cast<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 Neo4ByteElementsNoSettings
|
||||
{
|
||||
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(reinterpret_cast<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 Neo3ByteElementsNoSettings
|
||||
{
|
||||
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(reinterpret_cast<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 Neo3ByteElementsNoSettings
|
||||
{
|
||||
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(reinterpret_cast<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 Neo3ByteElementsNoSettings
|
||||
{
|
||||
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(reinterpret_cast<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;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class NeoBgrFeature : public Neo3ByteElementsNoSettings
|
||||
{
|
||||
public:
|
||||
static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color)
|
||||
{
|
||||
uint8_t* p = getPixelAddress(pPixels, indexPixel);
|
||||
|
||||
*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.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(reinterpret_cast<const uint8_t*>(pPixels), indexPixel);
|
||||
|
||||
color.B = pgm_read_byte(p++);
|
||||
color.G = pgm_read_byte(p++);
|
||||
color.R = pgm_read_byte(p);
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class NeoRgbw64Feature : public Neo8ByteElementsNoSettings
|
||||
{
|
||||
public:
|
||||
static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color)
|
||||
{
|
||||
uint16_t* p = reinterpret_cast<uint16_t *>(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 uint16_t* p = reinterpret_cast<const uint16_t*>(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 uint16_t* p = reinterpret_cast<const uint16_t*>(getPixelAddress(reinterpret_cast<const uint8_t*>(pPixels), indexPixel));
|
||||
|
||||
color.R = pgm_read_word(p++);
|
||||
color.G = pgm_read_word(p++);
|
||||
color.B = pgm_read_word(p++);
|
||||
color.W = pgm_read_word(p);
|
||||
|
||||
return color;
|
||||
}
|
||||
};
|
||||
|
||||
class NeoRgb48Feature : public Neo6ByteElementsNoSettings
|
||||
{
|
||||
public:
|
||||
static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color)
|
||||
{
|
||||
uint16_t* p = reinterpret_cast<uint16_t*>(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 uint16_t* p = reinterpret_cast<const uint16_t*>(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 uint16_t* p = reinterpret_cast<const uint16_t*>(getPixelAddress(reinterpret_cast<const uint8_t*>(pPixels), indexPixel));
|
||||
|
||||
color.R = pgm_read_word(p++);
|
||||
color.G = pgm_read_word(p++);
|
||||
color.B = pgm_read_word(p);
|
||||
|
||||
return color;
|
||||
}
|
||||
};
|
||||
|
||||
typedef NeoRgb48Feature NeoRgbUcs8903Feature;
|
||||
typedef NeoRgbw64Feature NeoRgbwUcs8904Feature;
|
||||
@@ -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
|
||||
};
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,379 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
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
|
||||
|
||||
// ESP32C3 I2S is not supported yet due to significant changes to interface
|
||||
#if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
|
||||
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 NeoEsp32I2sSpeedTm1914
|
||||
{
|
||||
public:
|
||||
const static uint32_t I2sSampleRate = 100000;
|
||||
const static uint16_t ByteSendTimeUs = 10;
|
||||
const static uint16_t ResetTimeUs = 200;
|
||||
};
|
||||
|
||||
class NeoEsp32I2sSpeedTm1829
|
||||
{
|
||||
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:
|
||||
NeoEsp32I2sBusZero() {};
|
||||
|
||||
const static uint8_t I2sBusNumber = 0;
|
||||
};
|
||||
|
||||
class NeoEsp32I2sBusOne
|
||||
{
|
||||
public:
|
||||
NeoEsp32I2sBusOne() {};
|
||||
|
||||
const static uint8_t I2sBusNumber = 1;
|
||||
};
|
||||
|
||||
// dynamic channel support
|
||||
class NeoEsp32I2sBusN
|
||||
{
|
||||
public:
|
||||
NeoEsp32I2sBusN(NeoBusChannel channel) :
|
||||
I2sBusNumber(static_cast<uint8_t>(channel))
|
||||
{
|
||||
}
|
||||
NeoEsp32I2sBusN() = delete; // no default constructor
|
||||
|
||||
const uint8_t I2sBusNumber;
|
||||
};
|
||||
|
||||
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:
|
||||
typedef NeoNoSettings SettingsObject;
|
||||
|
||||
NeoEsp32I2sMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize) :
|
||||
_sizeData(pixelCount * elementSize + settingsSize),
|
||||
_pin(pin)
|
||||
{
|
||||
construct(pixelCount, elementSize, settingsSize);
|
||||
}
|
||||
|
||||
NeoEsp32I2sMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize, NeoBusChannel channel) :
|
||||
_sizeData(pixelCount * elementSize + settingsSize),
|
||||
_pin(pin),
|
||||
_bus(channel)
|
||||
{
|
||||
construct(pixelCount, elementSize, settingsSize);
|
||||
}
|
||||
|
||||
~NeoEsp32I2sMethodBase()
|
||||
{
|
||||
while (!IsReadyToUpdate())
|
||||
{
|
||||
yield();
|
||||
}
|
||||
|
||||
i2sSetPins(_bus.I2sBusNumber, -1, false);
|
||||
i2sDeinit(_bus.I2sBusNumber);
|
||||
free(_data);
|
||||
heap_caps_free(_i2sBuffer);
|
||||
}
|
||||
|
||||
bool IsReadyToUpdate() const
|
||||
{
|
||||
return (i2sWriteDone(_bus.I2sBusNumber));
|
||||
}
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
size_t dmaBlockCount = (_i2sBufferSize + I2S_DMA_MAX_DATA_LEN - 1) / I2S_DMA_MAX_DATA_LEN;
|
||||
|
||||
i2sInit(_bus.I2sBusNumber,
|
||||
16,
|
||||
T_SPEED::I2sSampleRate,
|
||||
I2S_CHAN_STEREO,
|
||||
I2S_FIFO_16BIT_DUAL,
|
||||
dmaBlockCount,
|
||||
0);
|
||||
i2sSetPins(_bus.I2sBusNumber, _pin, T_INVERT::Inverted);
|
||||
}
|
||||
|
||||
void Update(bool)
|
||||
{
|
||||
// wait for not actively sending data
|
||||
while (!IsReadyToUpdate())
|
||||
{
|
||||
yield();
|
||||
}
|
||||
|
||||
FillBuffers();
|
||||
|
||||
i2sWrite(_bus.I2sBusNumber, _i2sBuffer, _i2sBufferSize, false, false);
|
||||
}
|
||||
|
||||
uint8_t* getData() const
|
||||
{
|
||||
return _data;
|
||||
};
|
||||
|
||||
size_t getDataSize() const
|
||||
{
|
||||
return _sizeData;
|
||||
}
|
||||
|
||||
void applySettings([[maybe_unused]] const SettingsObject& settings)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
const size_t _sizeData; // Size of '_data' buffer
|
||||
const uint8_t _pin; // output pin number
|
||||
const T_BUS _bus; // holds instance for multi bus support
|
||||
|
||||
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 construct(uint16_t pixelCount, size_t elementSize, size_t settingsSize)
|
||||
{
|
||||
// DMA is too fast to support a single pixel and maintain consistency
|
||||
if (pixelCount < 2)
|
||||
{
|
||||
pixelCount = 2;
|
||||
}
|
||||
|
||||
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));
|
||||
// data cleared later in Begin()
|
||||
|
||||
_i2sBuffer = static_cast<uint8_t*>(heap_caps_malloc(_i2sBufferSize, MALLOC_CAP_DMA));
|
||||
// no need to initialize all of it, but since it contains
|
||||
// "reset" bits that don't latter get overwritten we just clear it all
|
||||
memset(_i2sBuffer, 0x00, _i2sBufferSize);
|
||||
}
|
||||
|
||||
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<NeoEsp32I2sSpeedTm1829, NeoEsp32I2sBusZero, NeoEsp32I2sInverted> NeoEsp32I2s0Tm1829Method;
|
||||
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeedTm1914, NeoEsp32I2sBusZero, NeoEsp32I2sInverted> NeoEsp32I2s0Tm1914Method;
|
||||
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<NeoEsp32I2sSpeedTm1914, NeoEsp32I2sBusZero, NeoEsp32I2sNotInverted> NeoEsp32I2s0Tm1914InvertedMethod;
|
||||
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeedTm1829, NeoEsp32I2sBusZero, NeoEsp32I2sNotInverted> NeoEsp32I2s0Tm1829InvertedMethod;
|
||||
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeed800Kbps, NeoEsp32I2sBusZero, NeoEsp32I2sInverted> NeoEsp32I2s0800KbpsInvertedMethod;
|
||||
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeed400Kbps, NeoEsp32I2sBusZero, NeoEsp32I2sInverted> NeoEsp32I2s0400KbpsInvertedMethod;
|
||||
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeedApa106, NeoEsp32I2sBusZero, NeoEsp32I2sInverted> NeoEsp32I2s0Apa106InvertedMethod;
|
||||
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
// (I2S_NUM_MAX == 2)
|
||||
|
||||
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeedWs2812x, NeoEsp32I2sBusOne, NeoEsp32I2sNotInverted> NeoEsp32I2s1Ws2812xMethod;
|
||||
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeedSk6812, NeoEsp32I2sBusOne, NeoEsp32I2sNotInverted> NeoEsp32I2s1Sk6812Method;
|
||||
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeedTm1814, NeoEsp32I2sBusOne, NeoEsp32I2sInverted> NeoEsp32I2s1Tm1814Method;
|
||||
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeedTm1829, NeoEsp32I2sBusOne, NeoEsp32I2sInverted> NeoEsp32I2s1Tm1829Method;
|
||||
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeedTm1914, NeoEsp32I2sBusOne, NeoEsp32I2sInverted> NeoEsp32I2s1Tm1914Method;
|
||||
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<NeoEsp32I2sSpeedTm1829, NeoEsp32I2sBusOne, NeoEsp32I2sNotInverted> NeoEsp32I2s1Tm1829InvertedMethod;
|
||||
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeedTm1914, NeoEsp32I2sBusOne, NeoEsp32I2sNotInverted> NeoEsp32I2s1Tm1914InvertedMethod;
|
||||
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeed800Kbps, NeoEsp32I2sBusOne, NeoEsp32I2sInverted> NeoEsp32I2s1800KbpsInvertedMethod;
|
||||
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeed400Kbps, NeoEsp32I2sBusOne, NeoEsp32I2sInverted> NeoEsp32I2s1400KbpsInvertedMethod;
|
||||
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeedApa106, NeoEsp32I2sBusOne, NeoEsp32I2sInverted> NeoEsp32I2s1Apa106InvertedMethod;
|
||||
|
||||
|
||||
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeedWs2812x, NeoEsp32I2sBusN, NeoEsp32I2sNotInverted> NeoEsp32I2sNWs2812xMethod;
|
||||
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeedSk6812, NeoEsp32I2sBusN, NeoEsp32I2sNotInverted> NeoEsp32I2sNSk6812Method;
|
||||
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeedTm1814, NeoEsp32I2sBusN, NeoEsp32I2sInverted> NeoEsp32I2sNTm1814Method;
|
||||
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeedTm1829, NeoEsp32I2sBusN, NeoEsp32I2sInverted> NeoEsp32I2sNTm1829Method;
|
||||
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeedTm1914, NeoEsp32I2sBusN, NeoEsp32I2sInverted> NeoEsp32I2sNTm1914Method;
|
||||
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeed800Kbps, NeoEsp32I2sBusN, NeoEsp32I2sNotInverted> NeoEsp32I2sN800KbpsMethod;
|
||||
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeed400Kbps, NeoEsp32I2sBusN, NeoEsp32I2sNotInverted> NeoEsp32I2sN400KbpsMethod;
|
||||
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeedApa106, NeoEsp32I2sBusN, NeoEsp32I2sNotInverted> NeoEsp32I2sNApa106Method;
|
||||
|
||||
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeedWs2812x, NeoEsp32I2sBusN, NeoEsp32I2sInverted> NeoEsp32I2sNWs2812xInvertedMethod;
|
||||
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeedSk6812, NeoEsp32I2sBusN, NeoEsp32I2sInverted> NeoEsp32I2sNSk6812InvertedMethod;
|
||||
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeedTm1814, NeoEsp32I2sBusN, NeoEsp32I2sNotInverted> NeoEsp32I2sNTm1814InvertedMethod;
|
||||
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeedTm1829, NeoEsp32I2sBusN, NeoEsp32I2sNotInverted> NeoEsp32I2sNTm1829InvertedMethod;
|
||||
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeedTm1914, NeoEsp32I2sBusN, NeoEsp32I2sNotInverted> NeoEsp32I2sNTm1914InvertedMethod;
|
||||
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeed800Kbps, NeoEsp32I2sBusN, NeoEsp32I2sInverted> NeoEsp32I2sN800KbpsInvertedMethod;
|
||||
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeed400Kbps, NeoEsp32I2sBusN, NeoEsp32I2sInverted> NeoEsp32I2sN400KbpsInvertedMethod;
|
||||
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeedApa106, NeoEsp32I2sBusN, NeoEsp32I2sInverted> NeoEsp32I2sNApa106InvertedMethod;
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined(NEOPIXEL_ESP32_RMT_DEFAULT) && !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
|
||||
// I2s Bus 1 method is the default method for Esp32
|
||||
// Esp32S2 & Esp32C3 will use RMT as the default allways
|
||||
typedef NeoEsp32I2s1Ws2812xMethod NeoWs2813Method;
|
||||
typedef NeoEsp32I2s1Ws2812xMethod NeoWs2812xMethod;
|
||||
typedef NeoEsp32I2s1800KbpsMethod NeoWs2812Method;
|
||||
typedef NeoEsp32I2s1Ws2812xMethod NeoWs2811Method;
|
||||
typedef NeoEsp32I2s1Sk6812Method NeoSk6812Method;
|
||||
typedef NeoEsp32I2s1Tm1814Method NeoTm1814Method;
|
||||
typedef NeoEsp32I2s1Tm1829Method NeoTm1829Method;
|
||||
typedef NeoEsp32I2s1Tm1914Method NeoTm1914Method;
|
||||
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 NeoEsp32I2s1Tm1829InvertedMethod NeoTm1829InvertedMethod;
|
||||
typedef NeoEsp32I2s1Tm1914InvertedMethod NeoTm1914InvertedMethod;
|
||||
typedef NeoEsp32I2s1Sk6812InvertedMethod NeoLc8812InvertedMethod;
|
||||
typedef NeoEsp32I2s1Apa106InvertedMethod NeoApa106InvertedMethod;
|
||||
|
||||
typedef NeoEsp32I2s1Ws2812xInvertedMethod Neo800KbpsInvertedMethod;
|
||||
typedef NeoEsp32I2s1400KbpsInvertedMethod Neo400KbpsInvertedMethod;
|
||||
|
||||
#endif // !defined(NEOPIXEL_ESP32_RMT_DEFAULT) && !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,331 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
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 <Arduino.h>
|
||||
#include "NeoSettings.h"
|
||||
#include "NeoBusChannel.h"
|
||||
#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 NeoEsp32RmtSpeedTm1829::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 NeoEsp32RmtSpeedTm1914::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 NeoEsp32RmtSpeedTx1812::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 NeoEsp32RmtInvertedSpeedTm1829::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 NeoEsp32RmtInvertedSpeedTm1914::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);
|
||||
}
|
||||
|
||||
void NeoEsp32RmtInvertedSpeedTx1812::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
|
||||
@@ -0,0 +1,915 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
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>
|
||||
}
|
||||
|
||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 3, 0)
|
||||
#define NEOPIXELBUS_RMT_INT_FLAGS (ESP_INTR_FLAG_LOWMED)
|
||||
#else
|
||||
#define NEOPIXELBUS_RMT_INT_FLAGS (ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_LEVEL1)
|
||||
#endif
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
// normal is inverted signal
|
||||
class NeoEsp32RmtSpeedTm1829 : public NeoEsp32RmtInvertedSpeedBase
|
||||
{
|
||||
public:
|
||||
const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(300, 900);
|
||||
const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(800, 400);
|
||||
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);
|
||||
};
|
||||
|
||||
// normal is inverted signal
|
||||
class NeoEsp32RmtSpeedTm1914 : 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(350, 1350);
|
||||
const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(1350, 350);
|
||||
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 NeoEsp32RmtSpeedTx1812 : public NeoEsp32RmtSpeedBase
|
||||
{
|
||||
public:
|
||||
const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(300, 600);
|
||||
const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(600, 300);
|
||||
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);
|
||||
};
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
// normal is inverted signal
|
||||
class NeoEsp32RmtInvertedSpeedTm1829 : public NeoEsp32RmtSpeedBase
|
||||
{
|
||||
public:
|
||||
const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(300, 900);
|
||||
const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(800, 400);
|
||||
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);
|
||||
};
|
||||
|
||||
// normal is inverted signal
|
||||
class NeoEsp32RmtInvertedSpeedTm1914 : 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(350, 1350);
|
||||
const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(1350, 350);
|
||||
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 NeoEsp32RmtInvertedSpeedTx1812 : public NeoEsp32RmtInvertedSpeedBase
|
||||
{
|
||||
public:
|
||||
const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(300, 600);
|
||||
const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(600, 300);
|
||||
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);
|
||||
};
|
||||
|
||||
class NeoEsp32RmtChannel0
|
||||
{
|
||||
public:
|
||||
NeoEsp32RmtChannel0() {};
|
||||
|
||||
const static rmt_channel_t RmtChannelNumber = RMT_CHANNEL_0;
|
||||
};
|
||||
|
||||
class NeoEsp32RmtChannel1
|
||||
{
|
||||
public:
|
||||
NeoEsp32RmtChannel1() {};
|
||||
|
||||
const static rmt_channel_t RmtChannelNumber = RMT_CHANNEL_1;
|
||||
};
|
||||
|
||||
class NeoEsp32RmtChannel2
|
||||
{
|
||||
public:
|
||||
NeoEsp32RmtChannel2() {};
|
||||
|
||||
const static rmt_channel_t RmtChannelNumber = RMT_CHANNEL_2;
|
||||
};
|
||||
|
||||
class NeoEsp32RmtChannel3
|
||||
{
|
||||
public:
|
||||
NeoEsp32RmtChannel3() {};
|
||||
|
||||
const static rmt_channel_t RmtChannelNumber = RMT_CHANNEL_3;
|
||||
};
|
||||
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
|
||||
class NeoEsp32RmtChannel4
|
||||
{
|
||||
public:
|
||||
NeoEsp32RmtChannel4() {};
|
||||
|
||||
const static rmt_channel_t RmtChannelNumber = RMT_CHANNEL_4;
|
||||
};
|
||||
|
||||
class NeoEsp32RmtChannel5
|
||||
{
|
||||
public:
|
||||
NeoEsp32RmtChannel5() {};
|
||||
|
||||
const static rmt_channel_t RmtChannelNumber = RMT_CHANNEL_5;
|
||||
};
|
||||
|
||||
class NeoEsp32RmtChannel6
|
||||
{
|
||||
public:
|
||||
NeoEsp32RmtChannel6() {};
|
||||
|
||||
const static rmt_channel_t RmtChannelNumber = RMT_CHANNEL_6;
|
||||
};
|
||||
|
||||
class NeoEsp32RmtChannel7
|
||||
{
|
||||
public:
|
||||
NeoEsp32RmtChannel7() {};
|
||||
|
||||
const static rmt_channel_t RmtChannelNumber = RMT_CHANNEL_7;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
// dynamic channel support
|
||||
class NeoEsp32RmtChannelN
|
||||
{
|
||||
public:
|
||||
NeoEsp32RmtChannelN(NeoBusChannel channel) :
|
||||
RmtChannelNumber(static_cast<rmt_channel_t>(channel))
|
||||
{
|
||||
}
|
||||
NeoEsp32RmtChannelN() = delete; // no default constructor
|
||||
|
||||
const rmt_channel_t RmtChannelNumber;
|
||||
};
|
||||
|
||||
template<typename T_SPEED, typename T_CHANNEL> class NeoEsp32RmtMethodBase
|
||||
{
|
||||
public:
|
||||
typedef NeoNoSettings SettingsObject;
|
||||
|
||||
NeoEsp32RmtMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize) :
|
||||
_sizeData(pixelCount * elementSize + settingsSize),
|
||||
_pin(pin)
|
||||
{
|
||||
construct();
|
||||
}
|
||||
|
||||
NeoEsp32RmtMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize, NeoBusChannel channel) :
|
||||
_sizeData(pixelCount* elementSize + settingsSize),
|
||||
_pin(pin),
|
||||
_channel(channel)
|
||||
{
|
||||
construct();
|
||||
}
|
||||
|
||||
~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(_channel.RmtChannelNumber, 10000 / portTICK_PERIOD_MS));
|
||||
|
||||
ESP_ERROR_CHECK(rmt_driver_uninstall(_channel.RmtChannelNumber));
|
||||
|
||||
gpio_matrix_out(_pin, 0x100, false, false);
|
||||
pinMode(_pin, INPUT);
|
||||
|
||||
free(_dataEditing);
|
||||
free(_dataSending);
|
||||
}
|
||||
|
||||
|
||||
bool IsReadyToUpdate() const
|
||||
{
|
||||
return (ESP_OK == rmt_wait_tx_done(_channel.RmtChannelNumber, 0));
|
||||
}
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
rmt_config_t config = {};
|
||||
|
||||
config.rmt_mode = RMT_MODE_TX;
|
||||
config.channel = _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(_channel.RmtChannelNumber, 0, NEOPIXELBUS_RMT_INT_FLAGS));
|
||||
ESP_ERROR_CHECK(rmt_translator_init(_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(_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(_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;
|
||||
}
|
||||
|
||||
void applySettings([[maybe_unused]] const SettingsObject& settings)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
const size_t _sizeData; // Size of '_data*' buffers
|
||||
const uint8_t _pin; // output pin number
|
||||
const T_CHANNEL _channel; // holds instance for multi channel support
|
||||
|
||||
// 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
|
||||
|
||||
|
||||
void construct()
|
||||
{
|
||||
_dataEditing = static_cast<uint8_t*>(malloc(_sizeData));
|
||||
// data cleared later in Begin()
|
||||
|
||||
_dataSending = static_cast<uint8_t*>(malloc(_sizeData));
|
||||
// no need to initialize it, it gets overwritten on every send
|
||||
}
|
||||
};
|
||||
|
||||
// normal
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedWs2811, NeoEsp32RmtChannelN> NeoEsp32RmtNWs2811Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedWs2812x, NeoEsp32RmtChannelN> NeoEsp32RmtNWs2812xMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedSk6812, NeoEsp32RmtChannelN> NeoEsp32RmtNSk6812Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTm1814, NeoEsp32RmtChannelN> NeoEsp32RmtNTm1814Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTm1829, NeoEsp32RmtChannelN> NeoEsp32RmtNTm1829Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTm1914, NeoEsp32RmtChannelN> NeoEsp32RmtNTm1914Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedApa106, NeoEsp32RmtChannelN> NeoEsp32RmtNApa106Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTx1812, NeoEsp32RmtChannelN> NeoEsp32RmtNTx1812Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeed800Kbps, NeoEsp32RmtChannelN> NeoEsp32RmtN800KbpsMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeed400Kbps, NeoEsp32RmtChannelN> NeoEsp32RmtN400KbpsMethod;
|
||||
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedWs2811, NeoEsp32RmtChannel0> NeoEsp32Rmt0Ws2811Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedWs2812x, NeoEsp32RmtChannel0> NeoEsp32Rmt0Ws2812xMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedSk6812, NeoEsp32RmtChannel0> NeoEsp32Rmt0Sk6812Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTm1814, NeoEsp32RmtChannel0> NeoEsp32Rmt0Tm1814Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTm1829, NeoEsp32RmtChannel0> NeoEsp32Rmt0Tm1829Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTm1914, NeoEsp32RmtChannel0> NeoEsp32Rmt0Tm1914Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedApa106, NeoEsp32RmtChannel0> NeoEsp32Rmt0Apa106Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTx1812, NeoEsp32RmtChannel0> NeoEsp32Rmt0Tx1812Method;
|
||||
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<NeoEsp32RmtSpeedTm1829, NeoEsp32RmtChannel1> NeoEsp32Rmt1Tm1829Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTm1914, NeoEsp32RmtChannel1> NeoEsp32Rmt1Tm1914Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedApa106, NeoEsp32RmtChannel1> NeoEsp32Rmt1Apa106Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTx1812, NeoEsp32RmtChannel1> NeoEsp32Rmt1Tx1812Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeed800Kbps, NeoEsp32RmtChannel1> NeoEsp32Rmt1800KbpsMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeed400Kbps, NeoEsp32RmtChannel1> NeoEsp32Rmt1400KbpsMethod;
|
||||
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedWs2811, NeoEsp32RmtChannel2> NeoEsp32Rmt2Ws2811Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedWs2812x, NeoEsp32RmtChannel2> NeoEsp32Rmt2Ws2812xMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedSk6812, NeoEsp32RmtChannel2> NeoEsp32Rmt2Sk6812Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTm1814, NeoEsp32RmtChannel2> NeoEsp32Rmt2Tm1814Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTm1829, NeoEsp32RmtChannel2> NeoEsp32Rmt2Tm1829Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTm1914, NeoEsp32RmtChannel2> NeoEsp32Rmt2Tm1914Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedApa106, NeoEsp32RmtChannel2> NeoEsp32Rmt2Apa106Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTx1812, NeoEsp32RmtChannel2> NeoEsp32Rmt2Tx1812Method;
|
||||
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<NeoEsp32RmtSpeedTm1829, NeoEsp32RmtChannel3> NeoEsp32Rmt3Tm1829Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTm1914, NeoEsp32RmtChannel3> NeoEsp32Rmt3Tm1914Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedApa106, NeoEsp32RmtChannel3> NeoEsp32Rmt3Apa106Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTx1812, NeoEsp32RmtChannel3> NeoEsp32Rmt3Tx1812Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeed800Kbps, NeoEsp32RmtChannel3> NeoEsp32Rmt3800KbpsMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeed400Kbps, NeoEsp32RmtChannel3> NeoEsp32Rmt3400KbpsMethod;
|
||||
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedWs2811, NeoEsp32RmtChannel4> NeoEsp32Rmt4Ws2811Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedWs2812x, NeoEsp32RmtChannel4> NeoEsp32Rmt4Ws2812xMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedSk6812, NeoEsp32RmtChannel4> NeoEsp32Rmt4Sk6812Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTm1814, NeoEsp32RmtChannel4> NeoEsp32Rmt4Tm1814Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTm1829, NeoEsp32RmtChannel4> NeoEsp32Rmt4Tm1829Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTm1914, NeoEsp32RmtChannel4> NeoEsp32Rmt4Tm1914Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedApa106, NeoEsp32RmtChannel4> NeoEsp32Rmt4Apa106Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTx1812, NeoEsp32RmtChannel4> NeoEsp32Rmt4Tx1812Method;
|
||||
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<NeoEsp32RmtSpeedTm1829, NeoEsp32RmtChannel5> NeoEsp32Rmt5Tm1829Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTm1914, NeoEsp32RmtChannel5> NeoEsp32Rmt5Tm1914Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedApa106, NeoEsp32RmtChannel5> NeoEsp32Rmt5Apa106Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTx1812, NeoEsp32RmtChannel5> NeoEsp32Rmt5Tx1812Method;
|
||||
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<NeoEsp32RmtSpeedTm1829, NeoEsp32RmtChannel6> NeoEsp32Rmt6Tm1829Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTm1914, NeoEsp32RmtChannel6> NeoEsp32Rmt6Tm1914Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedApa106, NeoEsp32RmtChannel6> NeoEsp32Rmt6Apa106Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTx1812, NeoEsp32RmtChannel6> NeoEsp32Rmt6Tx1812Method;
|
||||
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<NeoEsp32RmtSpeedTm1829, NeoEsp32RmtChannel7> NeoEsp32Rmt7Tm1829Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTm1914, NeoEsp32RmtChannel7> NeoEsp32Rmt7Tm1914Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedApa106, NeoEsp32RmtChannel7> NeoEsp32Rmt7Apa106Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTx1812, NeoEsp32RmtChannel7> NeoEsp32Rmt7Tx1812Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeed800Kbps, NeoEsp32RmtChannel7> NeoEsp32Rmt7800KbpsMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeed400Kbps, NeoEsp32RmtChannel7> NeoEsp32Rmt7400KbpsMethod;
|
||||
|
||||
#endif // !defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
#endif // !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
|
||||
// inverted
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedWs2811, NeoEsp32RmtChannelN> NeoEsp32RmtNWs2811InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedWs2812x, NeoEsp32RmtChannelN> NeoEsp32RmtNWs2812xInvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedSk6812, NeoEsp32RmtChannelN> NeoEsp32RmtNSk6812InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTm1814, NeoEsp32RmtChannelN> NeoEsp32RmtNTm1814InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTm1829, NeoEsp32RmtChannelN> NeoEsp32RmtNTm1829InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTm1914, NeoEsp32RmtChannelN> NeoEsp32RmtNTm1914InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedApa106, NeoEsp32RmtChannelN> NeoEsp32RmtNApa106InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTx1812, NeoEsp32RmtChannelN> NeoEsp32RmtNTx1812InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeed800Kbps, NeoEsp32RmtChannelN> NeoEsp32RmtN800KbpsInvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeed400Kbps, NeoEsp32RmtChannelN> NeoEsp32RmtN400KbpsInvertedMethod;
|
||||
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedWs2811, NeoEsp32RmtChannel0> NeoEsp32Rmt0Ws2811InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedWs2812x, NeoEsp32RmtChannel0> NeoEsp32Rmt0Ws2812xInvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedSk6812, NeoEsp32RmtChannel0> NeoEsp32Rmt0Sk6812InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTm1814, NeoEsp32RmtChannel0> NeoEsp32Rmt0Tm1814InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTm1829, NeoEsp32RmtChannel0> NeoEsp32Rmt0Tm1829InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTm1914, NeoEsp32RmtChannel0> NeoEsp32Rmt0Tm1914InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedApa106, NeoEsp32RmtChannel0> NeoEsp32Rmt0Apa106InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTx1812, NeoEsp32RmtChannel0> NeoEsp32Rmt0Tx1812InvertedMethod;
|
||||
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<NeoEsp32RmtInvertedSpeedTm1829, NeoEsp32RmtChannel1> NeoEsp32Rmt1Tm1829InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTm1914, NeoEsp32RmtChannel1> NeoEsp32Rmt1Tm1914InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedApa106, NeoEsp32RmtChannel1> NeoEsp32Rmt1Apa106InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTx1812, NeoEsp32RmtChannel1> NeoEsp32Rmt1Tx1812InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeed800Kbps, NeoEsp32RmtChannel1> NeoEsp32Rmt1800KbpsInvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeed400Kbps, NeoEsp32RmtChannel1> NeoEsp32Rmt1400KbpsInvertedMethod;
|
||||
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedWs2811, NeoEsp32RmtChannel2> NeoEsp32Rmt2Ws2811InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedWs2812x, NeoEsp32RmtChannel2> NeoEsp32Rmt2Ws2812xInvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedSk6812, NeoEsp32RmtChannel2> NeoEsp32Rmt2Sk6812InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTm1814, NeoEsp32RmtChannel2> NeoEsp32Rmt2Tm1814InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTm1829, NeoEsp32RmtChannel2> NeoEsp32Rmt2Tm1829InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTm1914, NeoEsp32RmtChannel2> NeoEsp32Rmt2Tm1914InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedApa106, NeoEsp32RmtChannel2> NeoEsp32Rmt2Apa106InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTx1812, NeoEsp32RmtChannel2> NeoEsp32Rmt2Tx1812InvertedMethod;
|
||||
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<NeoEsp32RmtInvertedSpeedTm1829, NeoEsp32RmtChannel3> NeoEsp32Rmt3Tm1829InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTm1914, NeoEsp32RmtChannel3> NeoEsp32Rmt3Tm1914InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedApa106, NeoEsp32RmtChannel3> NeoEsp32Rmt3Apa106InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTx1812, NeoEsp32RmtChannel3> NeoEsp32Rmt3Tx1812InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeed800Kbps, NeoEsp32RmtChannel3> NeoEsp32Rmt3800KbpsInvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeed400Kbps, NeoEsp32RmtChannel3> NeoEsp32Rmt3400KbpsInvertedMethod;
|
||||
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedWs2811, NeoEsp32RmtChannel4> NeoEsp32Rmt4Ws2811InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedWs2812x, NeoEsp32RmtChannel4> NeoEsp32Rmt4Ws2812xInvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedSk6812, NeoEsp32RmtChannel4> NeoEsp32Rmt4Sk6812InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTm1814, NeoEsp32RmtChannel4> NeoEsp32Rmt4Tm1814InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTm1829, NeoEsp32RmtChannel4> NeoEsp32Rmt4Tm1829InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTm1914, NeoEsp32RmtChannel4> NeoEsp32Rmt4Tm1914InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedApa106, NeoEsp32RmtChannel4> NeoEsp32Rmt4Apa106InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTx1812, NeoEsp32RmtChannel4> NeoEsp32Rmt4Tx1812InvertedMethod;
|
||||
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<NeoEsp32RmtInvertedSpeedTm1829, NeoEsp32RmtChannel5> NeoEsp32Rmt5Tm1829InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTm1914, NeoEsp32RmtChannel5> NeoEsp32Rmt5Tm1914InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedApa106, NeoEsp32RmtChannel5> NeoEsp32Rmt5Apa106InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTx1812, NeoEsp32RmtChannel5> NeoEsp32Rmt5Tx1812InvertedMethod;
|
||||
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<NeoEsp32RmtInvertedSpeedTm1829, NeoEsp32RmtChannel6> NeoEsp32Rmt6Tm1829InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTm1914, NeoEsp32RmtChannel6> NeoEsp32Rmt6Tm1914InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedApa106, NeoEsp32RmtChannel6> NeoEsp32Rmt6Apa106InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTx1812, NeoEsp32RmtChannel6> NeoEsp32Rmt6Tx1812InvertedMethod;
|
||||
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<NeoEsp32RmtInvertedSpeedTm1829, NeoEsp32RmtChannel7> NeoEsp32Rmt7Tm1829InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTm1914, NeoEsp32RmtChannel7> NeoEsp32Rmt7Tm1914InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedApa106, NeoEsp32RmtChannel7> NeoEsp32Rmt7Apa106InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTx1812, NeoEsp32RmtChannel7> NeoEsp32Rmt7Tx1812InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeed800Kbps, NeoEsp32RmtChannel7> NeoEsp32Rmt7800KbpsInvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeed400Kbps, NeoEsp32RmtChannel7> NeoEsp32Rmt7400KbpsInvertedMethod;
|
||||
|
||||
#endif // !defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
#endif // !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
|
||||
|
||||
#if defined(NEOPIXEL_ESP32_RMT_DEFAULT) || defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
|
||||
// Normally I2s method is the default, defining NEOPIXEL_ESP32_RMT_DEFAULT
|
||||
// will switch to use RMT as the default method
|
||||
// The ESP32S2 & ESP32C3 will always defualt to RMT
|
||||
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
|
||||
// RMT channel 1 method is the default method for Esp32S2 & Esp32C3
|
||||
typedef NeoEsp32Rmt1Ws2812xMethod NeoWs2813Method;
|
||||
typedef NeoEsp32Rmt1Ws2812xMethod NeoWs2812xMethod;
|
||||
typedef NeoEsp32Rmt1800KbpsMethod NeoWs2812Method;
|
||||
typedef NeoEsp32Rmt1Ws2812xMethod NeoWs2811Method;
|
||||
typedef NeoEsp32Rmt1Sk6812Method NeoSk6812Method;
|
||||
typedef NeoEsp32Rmt1Tm1814Method NeoTm1814Method;
|
||||
typedef NeoEsp32Rmt1Tm1829Method NeoTm1829Method;
|
||||
typedef NeoEsp32Rmt1Tm1914Method NeoTm1914Method;
|
||||
typedef NeoEsp32Rmt1Sk6812Method NeoLc8812Method;
|
||||
typedef NeoEsp32Rmt1Apa106Method NeoApa106Method;
|
||||
typedef NeoEsp32Rmt1Tx1812Method NeoTx1812Method;
|
||||
|
||||
typedef NeoEsp32Rmt1Ws2812xMethod Neo800KbpsMethod;
|
||||
typedef NeoEsp32Rmt1400KbpsMethod Neo400KbpsMethod;
|
||||
|
||||
typedef NeoEsp32Rmt1Ws2812xInvertedMethod NeoWs2813InvertedMethod;
|
||||
typedef NeoEsp32Rmt1Ws2812xInvertedMethod NeoWs2812xInvertedMethod;
|
||||
typedef NeoEsp32Rmt1Ws2812xInvertedMethod NeoWs2811InvertedMethod;
|
||||
typedef NeoEsp32Rmt1800KbpsInvertedMethod NeoWs2812InvertedMethod;
|
||||
typedef NeoEsp32Rmt1Sk6812InvertedMethod NeoSk6812InvertedMethod;
|
||||
typedef NeoEsp32Rmt1Tm1814InvertedMethod NeoTm1814InvertedMethod;
|
||||
typedef NeoEsp32Rmt1Tm1829InvertedMethod NeoTm1829InvertedMethod;
|
||||
typedef NeoEsp32Rmt1Tm1914InvertedMethod NeoTm1914InvertedMethod;
|
||||
typedef NeoEsp32Rmt1Sk6812InvertedMethod NeoLc8812InvertedMethod;
|
||||
typedef NeoEsp32Rmt1Apa106InvertedMethod NeoApa106InvertedMethod;
|
||||
typedef NeoEsp32Rmt1Tx1812InvertedMethod NeoTx1812InvertedMethod;
|
||||
|
||||
typedef NeoEsp32Rmt1Ws2812xInvertedMethod Neo800KbpsInvertedMethod;
|
||||
typedef NeoEsp32Rmt1400KbpsInvertedMethod Neo400KbpsInvertedMethod;
|
||||
|
||||
#else // defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
|
||||
// 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 NeoEsp32Rmt6Tm1829Method NeoTm1829Method;
|
||||
typedef NeoEsp32Rmt6Tm1914Method NeoTm1914Method;
|
||||
typedef NeoEsp32Rmt6Sk6812Method NeoLc8812Method;
|
||||
typedef NeoEsp32Rmt6Apa106Method NeoApa106Method;
|
||||
typedef NeoEsp32Rmt6Tx1812Method NeoTx1812Method;
|
||||
|
||||
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 NeoEsp32Rmt6Tm1829InvertedMethod NeoTm1829InvertedMethod;
|
||||
typedef NeoEsp32Rmt6Tm1914InvertedMethod NeoTm1914InvertedMethod;
|
||||
typedef NeoEsp32Rmt6Sk6812InvertedMethod NeoLc8812InvertedMethod;
|
||||
typedef NeoEsp32Rmt6Apa106InvertedMethod NeoApa106InvertedMethod;
|
||||
typedef NeoEsp32Rmt6Tx1812InvertedMethod NeoTx1812InvertedMethod;
|
||||
|
||||
typedef NeoEsp32Rmt6Ws2812xInvertedMethod Neo800KbpsInvertedMethod;
|
||||
typedef NeoEsp32Rmt6400KbpsInvertedMethod Neo400KbpsInvertedMethod;
|
||||
|
||||
#endif // defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
|
||||
#endif // defined(NEOPIXEL_ESP32_RMT_DEFAULT) || defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,355 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
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
|
||||
#include "NeoEsp8266I2sMethodCore.h"
|
||||
|
||||
class NeoEsp8266DmaSpeedBase
|
||||
{
|
||||
public:
|
||||
static const uint8_t IdleLevel = 0;
|
||||
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 IdleLevel = 1;
|
||||
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; // 0-63
|
||||
const static uint32_t I2sBaseClockDivisor = 16; // 0-63
|
||||
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 NeoEsp8266DmaInvertedSpeedTm1829 : 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; // 0-63
|
||||
const static uint32_t I2sBaseClockDivisor = 16; // 0-63
|
||||
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; // 0-63
|
||||
const static uint32_t I2sBaseClockDivisor = 16; // 0-63
|
||||
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; // 0-63
|
||||
const static uint32_t I2sBaseClockDivisor = 16; // 0-63
|
||||
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 NeoEsp8266DmaSpeedTm1829 : 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; // 0-63
|
||||
const static uint32_t I2sBaseClockDivisor = 16; // 0-63
|
||||
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; // 0-63
|
||||
const static uint32_t I2sBaseClockDivisor = 16; // 0-63
|
||||
const static uint32_t ByteSendTimeUs = 17; // us it takes to send a single pixel element
|
||||
const static uint32_t ResetTimeUs = 50;
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<typename T_SPEED> class NeoEsp8266DmaMethodBase : NeoEsp8266I2sMethodCore
|
||||
{
|
||||
public:
|
||||
typedef NeoNoSettings SettingsObject;
|
||||
|
||||
NeoEsp8266DmaMethodBase(uint16_t pixelCount, size_t elementSize, size_t settingsSize) :
|
||||
_sizeData(pixelCount * elementSize + settingsSize)
|
||||
{
|
||||
size_t dmaPixelSize = DmaBytesPerPixelBytes * elementSize;
|
||||
size_t dmaSettingsSize = DmaBytesPerPixelBytes * settingsSize;
|
||||
|
||||
size_t i2sBufferSize = pixelCount * dmaPixelSize + dmaSettingsSize;
|
||||
|
||||
// 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
|
||||
size_t i2sZeroesSize = (24L * (T_SPEED::ResetTimeUs / 50L)) / 6L;
|
||||
|
||||
size_t is2BufMaxBlockSize = (c_maxDmaBlockSize / dmaPixelSize) * dmaPixelSize;
|
||||
|
||||
_data = static_cast<uint8_t*>(malloc(_sizeData));
|
||||
// data cleared later in Begin()
|
||||
|
||||
AllocateI2s(i2sBufferSize, i2sZeroesSize, is2BufMaxBlockSize, T_SPEED::IdleLevel);
|
||||
}
|
||||
|
||||
NeoEsp8266DmaMethodBase([[maybe_unused]] 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();
|
||||
}
|
||||
|
||||
FreeI2s();
|
||||
|
||||
free(_data);
|
||||
}
|
||||
|
||||
bool IsReadyToUpdate() const
|
||||
{
|
||||
return IsIdle();
|
||||
}
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
InitializeI2s(T_SPEED::I2sClockDivisor, T_SPEED::I2sBaseClockDivisor);
|
||||
}
|
||||
|
||||
void IRAM_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;
|
||||
}
|
||||
|
||||
void applySettings([[maybe_unused]] const SettingsObject& settings)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
// due to encoding required for i2s, we need 4 bytes to encode the pulses
|
||||
static const uint16_t DmaBytesPerPixelBytes = 4;
|
||||
|
||||
const size_t _sizeData; // Size of '_data' buffer
|
||||
uint8_t* _data; // Holds LED color values
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t getPixelTime() const
|
||||
{
|
||||
return (T_SPEED::ByteSendTimeUs * this->_sizeData);
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
// normal
|
||||
typedef NeoEsp8266DmaMethodBase<NeoEsp8266DmaSpeedWs2812x> NeoEsp8266DmaWs2812xMethod;
|
||||
typedef NeoEsp8266DmaMethodBase<NeoEsp8266DmaSpeedSk6812> NeoEsp8266DmaSk6812Method;
|
||||
typedef NeoEsp8266DmaMethodBase<NeoEsp8266DmaSpeedTm1814> NeoEsp8266DmaTm1814Method;
|
||||
typedef NeoEsp8266DmaMethodBase<NeoEsp8266DmaSpeedTm1829> NeoEsp8266DmaTm1829Method;
|
||||
typedef NeoEsp8266DmaTm1814Method NeoEsp8266DmaTm1914Method;
|
||||
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<NeoEsp8266DmaInvertedSpeedTm1829> NeoEsp8266DmaInvertedTm1829Method;
|
||||
typedef NeoEsp8266DmaInvertedTm1814Method NeoEsp8266DmaInvertedTm1914Method;
|
||||
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 NeoEsp8266DmaTm1829Method NeoTm1829Method;
|
||||
typedef NeoEsp8266DmaTm1914Method NeoTm1914Method;
|
||||
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 NeoEsp8266DmaInvertedTm1829Method NeoTm1829InvertedMethod;
|
||||
typedef NeoEsp8266DmaInvertedTm1914Method NeoTm1914InvertedMethod;
|
||||
typedef NeoEsp8266DmaInvertedSk6812Method NeoLc8812InvertedMethod;
|
||||
typedef NeoEsp8266DmaInvertedApa106Method NeoApa106InvertedMethod;
|
||||
|
||||
typedef NeoEsp8266DmaInvertedWs2812xMethod Neo800KbpsInvertedMethod;
|
||||
typedef NeoEsp8266DmaInverted400KbpsMethod Neo400KbpsInvertedMethod;
|
||||
#endif
|
||||
@@ -0,0 +1,335 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
NeoPixel library helper functions for Esp8266.
|
||||
|
||||
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 "NeoEsp8266I2sMethodCore.h"
|
||||
|
||||
|
||||
class NeoEsp8266I2sDmx512SpeedBase
|
||||
{
|
||||
public:
|
||||
// 4.2 us bit send, 250Kbps
|
||||
static const uint32_t I2sClockDivisor = 21; // 0-63
|
||||
static const uint32_t I2sBaseClockDivisor = 32; // 0-63
|
||||
static const uint32_t ByteSendTimeUs = 47; // us it takes to send a single pixel element
|
||||
static const uint32_t MtbpUs = 100; // min 88
|
||||
// DMX requires the first slot to be zero
|
||||
static const size_t HeaderSize = 1;
|
||||
};
|
||||
|
||||
class NeoEsp8266I2sDmx512Speed : public NeoEsp8266I2sDmx512SpeedBase
|
||||
{
|
||||
public:
|
||||
static const uint8_t MtbpLevel = 0x1; // high
|
||||
static const uint8_t StartBit = 0b00000000;
|
||||
static const uint8_t StopBits = 0b00000011;
|
||||
static const uint32_t BreakMab = 0x00000007; // Break + Mab
|
||||
|
||||
static uint8_t Convert(uint8_t value)
|
||||
{
|
||||
// DMX requires LSB order
|
||||
return NeoUtil::Reverse8Bits( value );
|
||||
}
|
||||
};
|
||||
|
||||
class NeoEsp8266I2sDmx512InvertedSpeed : public NeoEsp8266I2sDmx512SpeedBase
|
||||
{
|
||||
public:
|
||||
static const uint8_t MtbpLevel = 0x00; // low
|
||||
static const uint8_t StartBit = 0b00000001;
|
||||
static const uint8_t StopBits = 0b00000000;
|
||||
static const uint32_t BreakMab = 0xfffffff8; // Break + Mab
|
||||
|
||||
static uint8_t Convert(uint8_t value)
|
||||
{
|
||||
// DMX requires LSB order
|
||||
return NeoUtil::Reverse8Bits( ~value );
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class NeoEsp8266I2sWs2821SpeedBase
|
||||
{
|
||||
public:
|
||||
// 1.4 us bit send, 750Kbps
|
||||
static const uint32_t I2sClockDivisor = 7; // 0-63
|
||||
static const uint32_t I2sBaseClockDivisor = 32; // 0-63
|
||||
static const uint32_t ByteSendTimeUs = 16; // us it takes to send a single pixel element
|
||||
static const uint32_t MtbpUs = 33; // min 88
|
||||
// DMX/WS2821 requires the first slot to be zero
|
||||
static const size_t HeaderSize = 1;
|
||||
};
|
||||
|
||||
class NeoEsp8266I2sWs2821Speed : public NeoEsp8266I2sWs2821SpeedBase
|
||||
{
|
||||
public:
|
||||
static const uint8_t MtbpLevel = 0x1; // high
|
||||
static const uint8_t StartBit = 0b00000000;
|
||||
static const uint8_t StopBits = 0b00000011;
|
||||
static const uint32_t BreakMab = 0x00000007; // Break + Mab
|
||||
|
||||
static uint8_t Convert(uint8_t value)
|
||||
{
|
||||
// DMX requires LSB order
|
||||
return NeoUtil::Reverse8Bits(value);
|
||||
}
|
||||
};
|
||||
|
||||
class NeoEsp8266I2sWs2821InvertedSpeed : public NeoEsp8266I2sWs2821SpeedBase
|
||||
{
|
||||
public:
|
||||
static const uint8_t MtbpLevel = 0x00; // low
|
||||
static const uint8_t StartBit = 0b00000001;
|
||||
static const uint8_t StopBits = 0b00000000;
|
||||
static const uint32_t BreakMab = 0xfffffff8; // Break + Mab
|
||||
|
||||
static uint8_t Convert(uint8_t value)
|
||||
{
|
||||
// DMX requires LSB order
|
||||
return NeoUtil::Reverse8Bits(~value);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T_SPEED> class NeoEsp8266I2sDmx512MethodBase : NeoEsp8266I2sMethodCore
|
||||
{
|
||||
public:
|
||||
typedef NeoNoSettings SettingsObject;
|
||||
|
||||
NeoEsp8266I2sDmx512MethodBase(uint16_t pixelCount, size_t elementSize, size_t settingsSize) :
|
||||
_sizeData(pixelCount * elementSize + settingsSize + T_SPEED::HeaderSize)
|
||||
{
|
||||
size_t dmaPixelBits = I2sBitsPerPixelBytes * elementSize;
|
||||
size_t dmaSettingsBits = I2sBitsPerPixelBytes * (settingsSize + T_SPEED::HeaderSize);
|
||||
|
||||
// bits + half rounding byte of bits / bits per byte
|
||||
size_t i2sBufferSize = (pixelCount * dmaPixelBits + dmaSettingsBits + 4) / 8;
|
||||
|
||||
i2sBufferSize = i2sBufferSize + sizeof(T_SPEED::BreakMab);
|
||||
|
||||
// size is rounded up to nearest I2sByteBoundarySize
|
||||
i2sBufferSize = NeoUtil::RoundUp(i2sBufferSize, I2sByteBoundarySize);
|
||||
|
||||
// 4.2 us per bit
|
||||
size_t i2sZeroesBitsSize = (T_SPEED::MtbpUs) / 4;
|
||||
size_t i2sZeroesSize = NeoUtil::RoundUp(i2sZeroesBitsSize, 8) / 8;
|
||||
|
||||
// protocol limits use of full block size to I2sByteBoundarySize
|
||||
size_t is2BufMaxBlockSize = (c_maxDmaBlockSize / I2sByteBoundarySize) * I2sByteBoundarySize;
|
||||
|
||||
_data = static_cast<uint8_t*>(malloc(_sizeData));
|
||||
// first "slot" cleared due to protocol requiring it to be zero
|
||||
memset(_data, 0x00, 1);
|
||||
|
||||
AllocateI2s(i2sBufferSize, i2sZeroesSize, is2BufMaxBlockSize, T_SPEED::MtbpLevel);
|
||||
}
|
||||
|
||||
NeoEsp8266I2sDmx512MethodBase([[maybe_unused]] uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize) :
|
||||
NeoEsp8266I2sDmx512MethodBase(pixelCount, elementSize, settingsSize)
|
||||
{
|
||||
}
|
||||
|
||||
~NeoEsp8266I2sDmx512MethodBase()
|
||||
{
|
||||
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::MtbpUs) * waits))
|
||||
{
|
||||
yield();
|
||||
}
|
||||
|
||||
FreeI2s();
|
||||
|
||||
free(_data);
|
||||
}
|
||||
|
||||
bool IsReadyToUpdate() const
|
||||
{
|
||||
return IsIdle();
|
||||
}
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
InitializeI2s(T_SPEED::I2sClockDivisor, T_SPEED::I2sBaseClockDivisor);
|
||||
}
|
||||
|
||||
void IRAM_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 + T_SPEED::HeaderSize;
|
||||
};
|
||||
|
||||
size_t getDataSize() const
|
||||
{
|
||||
return _sizeData - T_SPEED::HeaderSize;
|
||||
}
|
||||
|
||||
void applySettings([[maybe_unused]] const SettingsObject& settings)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
// given 11 sending bits per pixel byte,
|
||||
static const uint16_t I2sBitsPerPixelBytes = 11;
|
||||
// i2s sends 4 byte elements,
|
||||
static const uint16_t I2sByteBoundarySize = 4;
|
||||
|
||||
const size_t _sizeData; // Size of '_data' buffer
|
||||
uint8_t* _data; // Holds LED color values
|
||||
|
||||
// encodes the data with start and stop bits
|
||||
// input buffer is bytes
|
||||
// output stream is uint31_t
|
||||
static void Encoder(const uint8_t* pSrc, const uint8_t* pSrcEnd,
|
||||
uint32_t* pOutput, const uint32_t* pOutputEnd)
|
||||
{
|
||||
static const uint32_t Mtbp = 0xffffffff * T_SPEED::MtbpLevel;
|
||||
const uint8_t* pData = pSrc;
|
||||
|
||||
int8_t outputBit = 32;
|
||||
uint32_t output = 0;
|
||||
|
||||
// DATA stream, one start, two stop
|
||||
while (pData < pSrcEnd)
|
||||
{
|
||||
uint8_t data = T_SPEED::Convert( *(pData++) );
|
||||
|
||||
if (outputBit > 10)
|
||||
{
|
||||
// simple
|
||||
outputBit -= 1;
|
||||
output |= T_SPEED::StartBit << outputBit;
|
||||
|
||||
outputBit -= 8;
|
||||
output |= data << outputBit;
|
||||
|
||||
outputBit -= 2;
|
||||
output |= T_SPEED::StopBits << outputBit;
|
||||
}
|
||||
else
|
||||
{
|
||||
// split across an output uint32_t
|
||||
// handle start bit
|
||||
if (outputBit < 1)
|
||||
{
|
||||
*(pOutput++) = output;
|
||||
output = 0;
|
||||
outputBit += 32;
|
||||
}
|
||||
outputBit -= 1;
|
||||
output |= (T_SPEED::StartBit << outputBit);
|
||||
|
||||
// handle data bits
|
||||
if (outputBit < 8)
|
||||
{
|
||||
output |= data >> (8 - outputBit);
|
||||
|
||||
*(pOutput++) = output;
|
||||
output = 0;
|
||||
outputBit += 32;
|
||||
}
|
||||
outputBit -= 8;
|
||||
output |= data << outputBit;
|
||||
|
||||
// handle stop bits
|
||||
if (outputBit < 2)
|
||||
{
|
||||
output |= T_SPEED::StopBits >> (2 - outputBit);
|
||||
|
||||
*(pOutput++) = output;
|
||||
output = 0;
|
||||
outputBit += 32;
|
||||
}
|
||||
outputBit -= 2;
|
||||
output |= T_SPEED::StopBits << outputBit;
|
||||
}
|
||||
}
|
||||
if (outputBit > 0)
|
||||
{
|
||||
// padd last output uint32_t with Mtbp
|
||||
output |= Mtbp >> (32 - outputBit);
|
||||
*(pOutput++) = output;
|
||||
}
|
||||
// fill the rest of the output with Mtbp
|
||||
while (pOutput < pOutputEnd)
|
||||
{
|
||||
*(pOutput++) = Mtbp;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FillBuffers()
|
||||
{
|
||||
uint32_t* pDma32 = reinterpret_cast<uint32_t*>(_i2sBuffer);
|
||||
const uint32_t* pDma32End = reinterpret_cast<uint32_t*>(_i2sBuffer + _i2sBufferSize);
|
||||
|
||||
// first put Break and MAB at front
|
||||
//
|
||||
// BREAK 121.8us @ 4.2us per bit
|
||||
// MAB 12.6us
|
||||
*(pDma32++) = T_SPEED::BreakMab;
|
||||
|
||||
Encoder(_data, _data + _sizeData, pDma32, pDma32End);
|
||||
}
|
||||
|
||||
uint32_t getPixelTime() const
|
||||
{
|
||||
return (T_SPEED::ByteSendTimeUs * this->_sizeData);
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
|
||||
// normal
|
||||
typedef NeoEsp8266I2sDmx512MethodBase<NeoEsp8266I2sDmx512Speed> NeoEsp8266Dmx512Method;
|
||||
typedef NeoEsp8266I2sDmx512MethodBase<NeoEsp8266I2sWs2821Speed> NeoEsp8266Ws2821Method;
|
||||
|
||||
// inverted
|
||||
typedef NeoEsp8266I2sDmx512MethodBase<NeoEsp8266I2sDmx512InvertedSpeed> NeoEsp8266Dmx512InvertedMethod;
|
||||
typedef NeoEsp8266I2sDmx512MethodBase<NeoEsp8266I2sWs2821InvertedSpeed> NeoEsp8266Ws2821InvertedMethod;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,34 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
NeoPixel library helper functions for Esp8266.
|
||||
|
||||
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 "NeoEsp8266I2sMethodCore.h"
|
||||
|
||||
#ifdef ARDUINO_ARCH_ESP8266
|
||||
|
||||
NeoEsp8266I2sMethodCore* NeoEsp8266I2sMethodCore::s_this;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,325 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
NeoPixel library helper functions for Esp8266.
|
||||
|
||||
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"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "osapi.h"
|
||||
#include "ets_sys.h"
|
||||
|
||||
#include "i2s_reg.h"
|
||||
|
||||
#ifdef ARDUINO_ESP8266_MAJOR //this define was added in ESP8266 Arduino Core version v3.0.1
|
||||
#include "core_esp8266_i2s.h" //for Arduino core >= 3.0.1
|
||||
#else
|
||||
#include "i2s.h" //for Arduino core <= 3.0.0
|
||||
#endif
|
||||
|
||||
#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;
|
||||
uint8* buf_ptr;
|
||||
struct slc_queue_item* next_link_ptr;
|
||||
};
|
||||
|
||||
enum NeoDmaState
|
||||
{
|
||||
NeoDmaState_Idle,
|
||||
NeoDmaState_Pending,
|
||||
NeoDmaState_Sending,
|
||||
NeoDmaState_Zeroing,
|
||||
};
|
||||
|
||||
const uint16_t c_maxDmaBlockSize = 4095;
|
||||
|
||||
const uint8_t c_I2sPin = 3; // due to I2S hardware, the pin used is restricted to this
|
||||
|
||||
class NeoEsp8266I2sMethodCore
|
||||
{
|
||||
protected:
|
||||
static NeoEsp8266I2sMethodCore* s_this; // for the ISR
|
||||
|
||||
volatile NeoDmaState _dmaState;
|
||||
|
||||
slc_queue_item* _i2sBufDesc; // dma block descriptors
|
||||
uint16_t _i2sBufDescCount; // count of block descriptors in _i2sBufDesc
|
||||
|
||||
size_t _i2sBufferSize; // total size of _i2sBuffer
|
||||
uint8_t* _i2sBuffer; // holds the DMA buffer that is referenced by _i2sBufDesc
|
||||
|
||||
size_t _i2sZeroesSize; // total size of _i2sZeroes
|
||||
uint8_t* _i2sZeroes;
|
||||
|
||||
uint16_t _is2BufMaxBlockSize; // max size based on size of a pixel of a single block
|
||||
|
||||
|
||||
// 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 IRAM_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 = 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 = finished_item;
|
||||
|
||||
s_this->_dmaState = NeoDmaState_Zeroing;
|
||||
}
|
||||
break;
|
||||
|
||||
case NeoDmaState_Zeroing:
|
||||
s_this->_dmaState = NeoDmaState_Idle;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ETS_SLC_INTR_ENABLE();
|
||||
}
|
||||
|
||||
NeoEsp8266I2sMethodCore()
|
||||
{ };
|
||||
|
||||
void AllocateI2s(const size_t i2sBufferSize,
|
||||
const size_t i2sZeroesSize,
|
||||
const size_t is2BufMaxBlockSize,
|
||||
const uint8_t idleLevel)
|
||||
{
|
||||
_i2sBufferSize = i2sBufferSize;
|
||||
_i2sZeroesSize = i2sZeroesSize;
|
||||
_is2BufMaxBlockSize = is2BufMaxBlockSize;
|
||||
|
||||
_i2sBuffer = static_cast<uint8_t*>(malloc(_i2sBufferSize));
|
||||
// no need to initialize it, it gets overwritten on every send
|
||||
_i2sZeroes = static_cast<uint8_t*>(malloc(_i2sZeroesSize));
|
||||
memset(_i2sZeroes, idleLevel * 0xff, _i2sZeroesSize);
|
||||
|
||||
_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
|
||||
}
|
||||
|
||||
void FreeI2s()
|
||||
{
|
||||
StopI2s();
|
||||
|
||||
s_this = nullptr;
|
||||
pinMode(c_I2sPin, INPUT);
|
||||
|
||||
free(_i2sBuffer);
|
||||
free(_i2sBufDesc);
|
||||
free(_i2sZeroes);
|
||||
}
|
||||
|
||||
bool IsIdle() const
|
||||
{
|
||||
return (_dmaState == NeoDmaState_Idle);
|
||||
}
|
||||
|
||||
void InitializeI2s(const uint32_t i2sClockDivisor, const uint32_t i2sBaseClockDivisor)
|
||||
{
|
||||
StopI2s();
|
||||
|
||||
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 = is2Buffer;
|
||||
_i2sBufDesc[indexDesc].unused = 0;
|
||||
_i2sBufDesc[indexDesc].next_link_ptr = reinterpret_cast<struct slc_queue_item*>(&(_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 = _i2sZeroes;
|
||||
_i2sBufDesc[indexDesc].unused = 0;
|
||||
_i2sBufDesc[indexDesc].next_link_ptr = reinterpret_cast<struct slc_queue_item*>(&(_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 = reinterpret_cast<struct slc_queue_item*>(&(_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 = i2sClockDivisor & I2SCDM;
|
||||
uint8_t i2s_bck_div = 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 StopI2s()
|
||||
{
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // ARDUINO_ARCH_ESP8266
|
||||
@@ -0,0 +1,176 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
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 <Arduino.h>
|
||||
#include "NeoSettings.h"
|
||||
#include "NeoEsp8266UartMethod.h"
|
||||
#include <utility>
|
||||
extern "C"
|
||||
{
|
||||
#include <ets_sys.h>
|
||||
}
|
||||
|
||||
const volatile uint8_t* IRAM_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();
|
||||
}
|
||||
|
||||
// The xtos_1int handler calls with param1 as the arg, param2 as a pointer
|
||||
// to an exception frame in memory.
|
||||
void IRAM_ATTR NeoEsp8266UartInterruptContext::Isr(void* param, [[maybe_unused]] void* exceptionFrame)
|
||||
{
|
||||
// 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
|
||||
|
||||
@@ -0,0 +1,542 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
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 IRAM_ATTR GetTxFifoLength(uint8_t uartNum)
|
||||
{
|
||||
return (USS(uartNum) >> USTXC) & 0xff;
|
||||
}
|
||||
// Append a byte to the TX FIFO
|
||||
static inline void IRAM_ATTR Enqueue(uint8_t uartNum, uint8_t value)
|
||||
{
|
||||
USF(uartNum) = value;
|
||||
}
|
||||
|
||||
static const volatile uint8_t* IRAM_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 IRAM_ATTR Isr(void* param, void* exceptionFrame);
|
||||
};
|
||||
|
||||
// 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));
|
||||
// data cleared later in Begin()
|
||||
}
|
||||
|
||||
~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 IRAM_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
|
||||
};
|
||||
|
||||
class NeoEsp8266UartSpeedTm1829 : 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:
|
||||
typedef NeoNoSettings SettingsObject;
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
void applySettings([[maybe_unused]] const SettingsObject& settings)
|
||||
{
|
||||
}
|
||||
|
||||
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<NeoEsp8266UartSpeedTm1829, NeoEsp8266Uart<UartFeature0, NeoEsp8266UartContext>, NeoEsp8266UartInverted> NeoEsp8266Uart0Tm1829Method;
|
||||
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 NeoEsp8266Uart0Tm1814Method NeoEsp8266Uart0Tm1914Method;
|
||||
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<NeoEsp8266UartSpeedTm1829, NeoEsp8266Uart<UartFeature1, NeoEsp8266UartContext>, NeoEsp8266UartInverted> NeoEsp8266Uart1Tm1829Method;
|
||||
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 NeoEsp8266Uart1Tm1814Method NeoEsp8266Uart1Tm1914Method;
|
||||
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<NeoEsp8266UartSpeedTm1829, NeoEsp8266AsyncUart<UartFeature0, NeoEsp8266UartInterruptContext>, NeoEsp8266UartInverted> NeoEsp8266AsyncUart0Tm1829Method;
|
||||
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 NeoEsp8266AsyncUart0Tm1814Method NeoEsp8266AsyncUart0Tm1914Method;
|
||||
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<NeoEsp8266UartSpeedTm1829, NeoEsp8266AsyncUart<UartFeature1, NeoEsp8266UartInterruptContext>, NeoEsp8266UartInverted> NeoEsp8266AsyncUart1Tm1829Method;
|
||||
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 NeoEsp8266AsyncUart1Tm1814Method NeoEsp8266AsyncUart1Tm1914Method;
|
||||
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<NeoEsp8266UartSpeedTm1829, NeoEsp8266Uart<UartFeature0, NeoEsp8266UartContext>, NeoEsp8266UartNotInverted> NeoEsp8266Uart0Tm1829InvertedMethod;
|
||||
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 NeoEsp8266Uart0Tm1814InvertedMethod NeoEsp8266Uart0Tm1914InvertedMethod;
|
||||
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<NeoEsp8266UartSpeedTm1829, NeoEsp8266Uart<UartFeature1, NeoEsp8266UartContext>, NeoEsp8266UartNotInverted> NeoEsp8266Uart1Tm1829InvertedMethod;
|
||||
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 NeoEsp8266Uart1Tm1814InvertedMethod NeoEsp8266Uart1Tm1914InvertedMethod;
|
||||
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<NeoEsp8266UartSpeedTm1829, NeoEsp8266AsyncUart<UartFeature0, NeoEsp8266UartInterruptContext>, NeoEsp8266UartNotInverted> NeoEsp8266AsyncUart0Tm1829InvertedMethod;
|
||||
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 NeoEsp8266AsyncUart0Tm1814InvertedMethod NeoEsp8266AsyncUart0Tm1914InvertedMethod;
|
||||
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<NeoEsp8266UartSpeedTm1829, NeoEsp8266AsyncUart<UartFeature1, NeoEsp8266UartInterruptContext>, NeoEsp8266UartNotInverted> NeoEsp8266AsyncUart1Tm1829InvertedMethod;
|
||||
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 NeoEsp8266AsyncUart1Tm1814InvertedMethod NeoEsp8266AsyncUart1Tm1914InvertedMethod;
|
||||
typedef NeoEsp8266AsyncUart1Sk6812InvertedMethod NeoEsp8266AsyncUart1Lc8812InvertedMethod;
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,267 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
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/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
// ESP32C3 I2S is not supported yet
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
|
||||
static inline uint32_t getCycleCount(void)
|
||||
{
|
||||
uint32_t ccount;
|
||||
__asm__ __volatile__("rsr %0,ccount":"=a" (ccount));
|
||||
return ccount;
|
||||
}
|
||||
|
||||
void IRAM_ATTR NeoEspBitBangBase_send_pixels(uint8_t* pixels, uint8_t* end, uint8_t pin, uint32_t t0h, uint32_t t1h, uint32_t period)
|
||||
{
|
||||
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 = t0h;
|
||||
if (subpix & mask)
|
||||
{
|
||||
cyclesBit = t1h;
|
||||
}
|
||||
|
||||
// after we have done as much work as needed for this next bit
|
||||
// now wait for the HIGH
|
||||
while (((cyclesStart = getCycleCount()) - cyclesNext) < period);
|
||||
|
||||
// set pin state
|
||||
#if defined(ARDUINO_ARCH_ESP32)
|
||||
GPIO.out_w1ts = pinRegister;
|
||||
#else
|
||||
GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, pinRegister);
|
||||
#endif
|
||||
|
||||
// wait for the LOW
|
||||
while ((getCycleCount() - cyclesStart) < cyclesBit);
|
||||
|
||||
// reset pin start
|
||||
#if defined(ARDUINO_ARCH_ESP32)
|
||||
GPIO.out_w1tc = pinRegister;
|
||||
#else
|
||||
GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, pinRegister);
|
||||
#endif
|
||||
|
||||
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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP8266)
|
||||
void IRAM_ATTR NeoEspBitBangBase_send_pixels_pin16(uint8_t *pixels, uint8_t *end, uint32_t t0h, uint32_t t1h, uint32_t period)
|
||||
{
|
||||
uint8_t mask = 0x80;
|
||||
uint8_t subpix = *pixels++;
|
||||
uint32_t cyclesStart = 0; // trigger emediately
|
||||
uint32_t cyclesNext = 0;
|
||||
|
||||
// reading and writing RTC_GPIO_OUT is too slow inside the loop
|
||||
uint32_t gpio_clear = (READ_PERI_REG(RTC_GPIO_OUT) & (uint32)0xfffffffe);
|
||||
uint32_t gpio_set = gpio_clear | 1;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
// do the checks here while we are waiting on time to pass
|
||||
uint32_t cyclesBit = t0h;
|
||||
if (subpix & mask)
|
||||
{
|
||||
cyclesBit = t1h;
|
||||
}
|
||||
|
||||
// after we have done as much work as needed for this next bit
|
||||
// now wait for the HIGH
|
||||
while (((cyclesStart = getCycleCount()) - cyclesNext) < period);
|
||||
|
||||
// set pin state
|
||||
WRITE_PERI_REG(RTC_GPIO_OUT, gpio_set);
|
||||
|
||||
// wait for the LOW
|
||||
while ((getCycleCount() - cyclesStart) < cyclesBit);
|
||||
|
||||
// reset pin start
|
||||
WRITE_PERI_REG(RTC_GPIO_OUT, gpio_clear);
|
||||
|
||||
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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // defined(ARDUINO_ARCH_ESP8266)
|
||||
|
||||
void IRAM_ATTR NeoEspBitBangBase_send_pixels_inv(uint8_t* pixels, uint8_t* end, uint8_t pin, uint32_t t0h, uint32_t t1h, uint32_t period)
|
||||
{
|
||||
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 = t0h;
|
||||
if (subpix & mask)
|
||||
{
|
||||
cyclesBit = t1h;
|
||||
}
|
||||
|
||||
// after we have done as much work as needed for this next bit
|
||||
// now wait for the HIGH
|
||||
while (((cyclesStart = getCycleCount()) - cyclesNext) < period);
|
||||
|
||||
// set pin state
|
||||
#if defined(ARDUINO_ARCH_ESP32)
|
||||
GPIO.out_w1tc = pinRegister;
|
||||
#else
|
||||
GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, pinRegister);
|
||||
#endif
|
||||
|
||||
// wait for the LOW
|
||||
while ((getCycleCount() - cyclesStart) < cyclesBit);
|
||||
|
||||
// reset pin start
|
||||
#if defined(ARDUINO_ARCH_ESP32)
|
||||
GPIO.out_w1ts = pinRegister;
|
||||
#else
|
||||
GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, pinRegister);
|
||||
#endif
|
||||
|
||||
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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP8266)
|
||||
void IRAM_ATTR NeoEspBitBangBase_send_pixels_inv_pin16(uint8_t *pixels, uint8_t *end, uint32_t t0h, uint32_t t1h, uint32_t period)
|
||||
{
|
||||
uint8_t mask = 0x80;
|
||||
uint8_t subpix = *pixels++;
|
||||
uint32_t cyclesStart = 0; // trigger emediately
|
||||
uint32_t cyclesNext = 0;
|
||||
|
||||
// reading and writing RTC_GPIO_OUT is too slow inside the loop
|
||||
uint32_t gpio_clear = (READ_PERI_REG(RTC_GPIO_OUT) & (uint32)0xfffffffe);
|
||||
uint32_t gpio_set = gpio_clear | 1;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
// do the checks here while we are waiting on time to pass
|
||||
uint32_t cyclesBit = t0h;
|
||||
if (subpix & mask)
|
||||
{
|
||||
cyclesBit = t1h;
|
||||
}
|
||||
|
||||
// after we have done as much work as needed for this next bit
|
||||
// now wait for the HIGH
|
||||
while (((cyclesStart = getCycleCount()) - cyclesNext) < period);
|
||||
|
||||
// set pin state
|
||||
WRITE_PERI_REG(RTC_GPIO_OUT, gpio_clear);
|
||||
|
||||
// wait for the LOW
|
||||
while ((getCycleCount() - cyclesStart) < cyclesBit);
|
||||
|
||||
// reset pin start
|
||||
WRITE_PERI_REG(RTC_GPIO_OUT, gpio_set);
|
||||
|
||||
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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // defined(ARDUINO_ARCH_ESP8266)
|
||||
#endif // !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
#endif // defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
|
||||
@@ -0,0 +1,399 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
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)
|
||||
|
||||
// ESP32C3 I2S is not supported yet
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP8266)
|
||||
#include <eagle_soc.h>
|
||||
#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 NeoEspSpeedTm1829
|
||||
{
|
||||
public:
|
||||
const static uint32_t T0H = (F_CPU / 3333333 - CYCLES_LOOPTEST); // 0.3us
|
||||
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 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 NeoEspSpeedApa106
|
||||
{
|
||||
public:
|
||||
const static uint32_t T0H = (F_CPU / 2857143 - CYCLES_LOOPTEST); // 0.35us
|
||||
const static uint32_t T1H = (F_CPU / 740741 - CYCLES_LOOPTEST); // 1.35
|
||||
const static uint32_t Period = (F_CPU / 606061 - CYCLES_LOOPTEST); // 1.65us
|
||||
};
|
||||
|
||||
extern void NeoEspBitBangBase_send_pixels(uint8_t* pixels, uint8_t* end, uint8_t pin, uint32_t t0h, uint32_t t1h, uint32_t period);
|
||||
extern void NeoEspBitBangBase_send_pixels_inv(uint8_t *pixels, uint8_t *end, uint8_t pin, uint32_t t0h, uint32_t t1h, uint32_t period);
|
||||
#if defined(ARDUINO_ARCH_ESP8266)
|
||||
extern void NeoEspBitBangBase_send_pixels_pin16(uint8_t *pixels, uint8_t *end, uint32_t t0h, uint32_t t1h, uint32_t period);
|
||||
extern void NeoEspBitBangBase_send_pixels_inv_pin16(uint8_t *pixels, uint8_t *end, uint32_t t0h, uint32_t t1h, uint32_t period);
|
||||
#endif
|
||||
|
||||
class NeoEspPinset
|
||||
{
|
||||
public:
|
||||
const static uint8_t IdleLevel = LOW;
|
||||
|
||||
inline static void send_pixels_impl(uint8_t* pixels, uint8_t* end, uint8_t pin, uint32_t t0h, uint32_t t1h, uint32_t period)
|
||||
{
|
||||
#if defined(ARDUINO_ARCH_ESP8266)
|
||||
if (pin == 16)
|
||||
NeoEspBitBangBase_send_pixels_pin16(pixels, end, t0h, t1h, period);
|
||||
else
|
||||
NeoEspBitBangBase_send_pixels(pixels, end, pin, t0h, t1h, period);
|
||||
#else
|
||||
NeoEspBitBangBase_send_pixels(pixels, end, pin, t0h, t1h, period);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
class NeoEspPinsetInverted
|
||||
{
|
||||
public:
|
||||
const static uint8_t IdleLevel = HIGH;
|
||||
|
||||
inline static void send_pixels_impl(uint8_t* pixels, uint8_t* end, uint8_t pin, uint32_t t0h, uint32_t t1h, uint32_t period)
|
||||
{
|
||||
#if defined(ARDUINO_ARCH_ESP8266)
|
||||
if (pin == 16)
|
||||
NeoEspBitBangBase_send_pixels_inv_pin16(pixels, end, t0h, t1h, period);
|
||||
else
|
||||
NeoEspBitBangBase_send_pixels_inv(pixels, end, pin, t0h, t1h, period);
|
||||
#else
|
||||
NeoEspBitBangBase_send_pixels_inv(pixels, end, pin, t0h, t1h, period);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T_SPEED, typename T_PINSET> class NeoEspBitBangBase
|
||||
{
|
||||
public:
|
||||
static void send_pixels(uint8_t* pixels, uint8_t* end, uint8_t pin)
|
||||
{
|
||||
T_PINSET::send_pixels_impl(pixels, end, pin, T_SPEED::T0H, T_SPEED::T1H, T_SPEED::Period);
|
||||
}
|
||||
};
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
// normal is inverted signal
|
||||
class NeoEspBitBangSpeedTm1829 : public NeoEspBitBangBase<NeoEspSpeedTm1829, 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 NeoEspBitBangSpeedApa106 : public NeoEspBitBangBase<NeoEspSpeedApa106, 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;
|
||||
};
|
||||
|
||||
// normal is inverted signal, so inverted is normal
|
||||
class NeoEspBitBangInvertedSpeedTm1829 : public NeoEspBitBangBase<NeoEspSpeedTm1829, 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;
|
||||
};
|
||||
|
||||
class NeoEspBitBangInvertedSpeedApa106 : public NeoEspBitBangBase<NeoEspSpeedApa106, NeoEspPinsetInverted>
|
||||
{
|
||||
public:
|
||||
static const uint32_t ResetTimeUs = 50;
|
||||
};
|
||||
|
||||
template<typename T_SPEED, typename T_PINSET> class NeoEspBitBangMethodBase
|
||||
{
|
||||
public:
|
||||
typedef NeoNoSettings SettingsObject;
|
||||
|
||||
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));
|
||||
// data cleared later in Begin()
|
||||
}
|
||||
|
||||
~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;
|
||||
};
|
||||
|
||||
void applySettings([[maybe_unused]] const SettingsObject& settings)
|
||||
{
|
||||
}
|
||||
|
||||
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<NeoEspBitBangSpeedTm1829, NeoEspPinsetInverted> NeoEsp32BitBangTm1829Method;
|
||||
typedef NeoEspBitBangMethodBase<NeoEspBitBangSpeed800Kbps, NeoEspPinset> NeoEsp32BitBang800KbpsMethod;
|
||||
typedef NeoEspBitBangMethodBase<NeoEspBitBangSpeed400Kbps, NeoEspPinset> NeoEsp32BitBang400KbpsMethod;
|
||||
typedef NeoEspBitBangMethodBase<NeoEspBitBangSpeedApa106, NeoEspPinset> NeoEsp32BitBangApa106Method;
|
||||
|
||||
typedef NeoEsp32BitBangWs2812xMethod NeoEsp32BitBangWs2813Method;
|
||||
typedef NeoEsp32BitBang800KbpsMethod NeoEsp32BitBangWs2812Method;
|
||||
typedef NeoEsp32BitBangTm1814Method NeoEsp32BitBangTm1914Method;
|
||||
typedef NeoEsp32BitBangSk6812Method NeoEsp32BitBangLc8812Method;
|
||||
|
||||
typedef NeoEspBitBangMethodBase<NeoEspBitBangInvertedSpeedWs2811, NeoEspPinsetInverted> NeoEsp32BitBangWs2811InvertedMethod;
|
||||
typedef NeoEspBitBangMethodBase<NeoEspBitBangInvertedSpeedWs2812x, NeoEspPinsetInverted> NeoEsp32BitBangWs2812xInvertedMethod;
|
||||
typedef NeoEspBitBangMethodBase<NeoEspBitBangInvertedSpeedSk6812, NeoEspPinsetInverted> NeoEsp32BitBangSk6812InvertedMethod;
|
||||
typedef NeoEspBitBangMethodBase<NeoEspBitBangInvertedSpeedTm1814, NeoEspPinset> NeoEsp32BitBangTm1814InvertedMethod;
|
||||
typedef NeoEspBitBangMethodBase<NeoEspBitBangInvertedSpeedTm1829, NeoEspPinset> NeoEsp32BitBangTm1829InvertedMethod;
|
||||
typedef NeoEspBitBangMethodBase<NeoEspBitBangInvertedSpeed800Kbps, NeoEspPinsetInverted> NeoEsp32BitBang800KbpsInvertedMethod;
|
||||
typedef NeoEspBitBangMethodBase<NeoEspBitBangInvertedSpeed400Kbps, NeoEspPinsetInverted> NeoEsp32BitBang400KbpsInvertedMethod;
|
||||
typedef NeoEspBitBangMethodBase<NeoEspBitBangInvertedSpeedApa106, NeoEspPinsetInverted> NeoEsp32BitBangApa106InvertedMethod;
|
||||
|
||||
typedef NeoEsp32BitBangWs2812xInvertedMethod NeoEsp32BitBangWs2813InvertedMethod;
|
||||
typedef NeoEsp32BitBang800KbpsInvertedMethod NeoEsp32BitBangWs2812InvertedMethod;
|
||||
typedef NeoEsp32BitBangTm1814InvertedMethod NeoEsp32BitBangTm1914InvertedMethod;
|
||||
typedef NeoEsp32BitBangSk6812InvertedMethod NeoEsp32BitBangLc8812InvertedMethod;
|
||||
|
||||
#else
|
||||
|
||||
typedef NeoEspBitBangMethodBase<NeoEspBitBangSpeedWs2811, NeoEspPinset> NeoEsp8266BitBangWs2811Method;
|
||||
typedef NeoEspBitBangMethodBase<NeoEspBitBangSpeedWs2812x, NeoEspPinset> NeoEsp8266BitBangWs2812xMethod;
|
||||
typedef NeoEspBitBangMethodBase<NeoEspBitBangSpeedSk6812, NeoEspPinset> NeoEsp8266BitBangSk6812Method;
|
||||
typedef NeoEspBitBangMethodBase<NeoEspBitBangSpeedTm1814, NeoEspPinsetInverted> NeoEsp8266BitBangTm1814Method;
|
||||
typedef NeoEspBitBangMethodBase<NeoEspBitBangSpeedTm1829, NeoEspPinsetInverted> NeoEsp8266BitBangTm1829Method;
|
||||
typedef NeoEspBitBangMethodBase<NeoEspBitBangSpeed800Kbps, NeoEspPinset> NeoEsp8266BitBang800KbpsMethod;
|
||||
typedef NeoEspBitBangMethodBase<NeoEspBitBangSpeed400Kbps, NeoEspPinset> NeoEsp8266BitBang400KbpsMethod;
|
||||
typedef NeoEspBitBangMethodBase<NeoEspBitBangSpeedApa106, NeoEspPinset> NeoEsp8266BitBangApa106Method;
|
||||
|
||||
typedef NeoEsp8266BitBangWs2812xMethod NeoEsp8266BitBangWs2813Method;
|
||||
typedef NeoEsp8266BitBang800KbpsMethod NeoEsp8266BitBangWs2812Method;
|
||||
typedef NeoEsp8266BitBangTm1814Method NeoEsp8266BitBangTm1914Method;
|
||||
typedef NeoEsp8266BitBangSk6812Method NeoEsp8266BitBangLc8812Method;
|
||||
|
||||
typedef NeoEspBitBangMethodBase<NeoEspBitBangInvertedSpeedWs2811, NeoEspPinsetInverted> NeoEsp8266BitBangWs2811InvertedMethod;
|
||||
typedef NeoEspBitBangMethodBase<NeoEspBitBangInvertedSpeedWs2812x, NeoEspPinsetInverted> NeoEsp8266BitBangWs2812xInvertedMethod;
|
||||
typedef NeoEspBitBangMethodBase<NeoEspBitBangInvertedSpeedSk6812, NeoEspPinsetInverted> NeoEsp8266BitBangSk6812InvertedMethod;
|
||||
typedef NeoEspBitBangMethodBase<NeoEspBitBangInvertedSpeedTm1814, NeoEspPinset> NeoEsp8266BitBangTm1814InvertedMethod;
|
||||
typedef NeoEspBitBangMethodBase<NeoEspBitBangInvertedSpeedTm1829, NeoEspPinset> NeoEsp8266BitBangTm1829InvertedMethod;
|
||||
typedef NeoEspBitBangMethodBase<NeoEspBitBangInvertedSpeed800Kbps, NeoEspPinsetInverted> NeoEsp8266BitBang800KbpsInvertedMethod;
|
||||
typedef NeoEspBitBangMethodBase<NeoEspBitBangInvertedSpeed400Kbps, NeoEspPinsetInverted> NeoEsp8266BitBang400KbpsInvertedMethod;
|
||||
typedef NeoEspBitBangMethodBase<NeoEspBitBangInvertedSpeedApa106, NeoEspPinsetInverted> NeoEsp8266BitBangApa106InvertedMethod;
|
||||
|
||||
typedef NeoEsp8266BitBangWs2812xInvertedMethod NeoEsp8266BitBangWs2813InvertedMethod;
|
||||
typedef NeoEsp8266BitBang800KbpsInvertedMethod NeoEsp8266BitBangWs2812InvertedMethod;
|
||||
typedef NeoEsp8266BitBangTm1814InvertedMethod NeoEsp8266BitBangTm1914InvertedMethod;
|
||||
typedef NeoEsp8266BitBangSk6812InvertedMethod NeoEsp8266BitBangLc8812InvertedMethod;
|
||||
|
||||
#endif
|
||||
|
||||
// ESP bitbang doesn't have defaults and should avoided except for testing
|
||||
|
||||
#endif // !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
#endif // defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
|
||||
@@ -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
|
||||
};
|
||||
@@ -0,0 +1,100 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
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);
|
||||
}
|
||||
static uint16_t Correct(uint16_t value)
|
||||
{
|
||||
return static_cast<uint16_t>(65535.0f * NeoEase::Gamma(value / 65535.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];
|
||||
}
|
||||
/*
|
||||
static uint16_t Correct(uint16_t value)
|
||||
{
|
||||
// NOTE: 16 bit color elements not supported with NeoGammaTableMethod, use NeoGammaEquationMethod
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
|
||||
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) );
|
||||
}
|
||||
|
||||
Rgb48Color Correct(const Rgb48Color& original)
|
||||
{
|
||||
return RgbColor(T_METHOD::Correct(original.R),
|
||||
T_METHOD::Correct(original.G),
|
||||
T_METHOD::Correct(original.B));
|
||||
}
|
||||
|
||||
Rgbw64Color Correct(const Rgbw64Color& original)
|
||||
{
|
||||
return RgbwColor(T_METHOD::Correct(original.R),
|
||||
T_METHOD::Correct(original.G),
|
||||
T_METHOD::Correct(original.B),
|
||||
T_METHOD::Correct(original.W));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
};
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,665 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
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 NeoNrf52xPwmSpeedTm1829
|
||||
{
|
||||
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 = 13 | 0x8000; // ~0.8us
|
||||
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 NeoNrf52xPwmSpeedTm1914
|
||||
{
|
||||
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;
|
||||
};
|
||||
|
||||
// count 1 = 0.0625us, so max count (32768) is 2048us
|
||||
class NeoNrf52xPwmSpeedApa106
|
||||
{
|
||||
public:
|
||||
const static uint32_t CountTop = 26UL; // ~1.525us (target is 1.65us)
|
||||
const static nrf_pwm_values_common_t Bit0 = 6 | 0x8000; // ~0.375us (target is 0.35)
|
||||
const static nrf_pwm_values_common_t Bit1 = 21 | 0x8000; // ~1.3125us (target is 1.350)
|
||||
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 NeoNrf52xPwmSpeedTx1812
|
||||
{
|
||||
public:
|
||||
const static uint32_t CountTop = 14UL; // ~0.875us (target is 0.9us)
|
||||
const static nrf_pwm_values_common_t Bit0 = 5 | 0x8000; // ~0.3125us (target is 0.3)
|
||||
const static nrf_pwm_values_common_t Bit1 = 10 | 0x8000; // ~0.625us (target is 0.6)
|
||||
const static nrf_pwm_values_common_t BitReset = 0x8000; // LOW
|
||||
const static uint32_t CountReset = 228; // 200us / 0.875us 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 NeoNrf52xPwmInvertedSpeedTm1829
|
||||
{
|
||||
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 = 13; // ~0.8us
|
||||
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 NeoNrf52xPwmInvertedSpeedTm1914
|
||||
{
|
||||
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.525us (target is 1.65us)
|
||||
const static nrf_pwm_values_common_t Bit0 = 6; // ~0.375us (target is 0.35)
|
||||
const static nrf_pwm_values_common_t Bit1 = 21; // ~1.3125us (target is 1.350)
|
||||
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 NeoNrf52xPwmInvertedSpeedTx1812
|
||||
{
|
||||
public:
|
||||
const static uint32_t CountTop = 14UL; // ~0.875us (target is 0.9us)
|
||||
const static nrf_pwm_values_common_t Bit0 = 5; // ~0.3125us (target is 0.3)
|
||||
const static nrf_pwm_values_common_t Bit1 = 10; // ~0.625us (target is 0.6)
|
||||
const static nrf_pwm_values_common_t BitReset = 0x0000; // HIGH
|
||||
const static uint32_t CountReset = 228; // 200us / 0.875us pulse width
|
||||
const static PinStatus IdleLevel = HIGH;
|
||||
};
|
||||
|
||||
class NeoNrf52xPwm0
|
||||
{
|
||||
public:
|
||||
NeoNrf52xPwm0() {};
|
||||
|
||||
inline static NRF_PWM_Type* Pwm()
|
||||
{
|
||||
return NRF_PWM0;
|
||||
}
|
||||
};
|
||||
|
||||
class NeoNrf52xPwm1
|
||||
{
|
||||
public:
|
||||
NeoNrf52xPwm1() {};
|
||||
|
||||
inline static NRF_PWM_Type* Pwm()
|
||||
{
|
||||
return NRF_PWM1;
|
||||
}
|
||||
};
|
||||
|
||||
class NeoNrf52xPwm2
|
||||
{
|
||||
public:
|
||||
NeoNrf52xPwm2() {};
|
||||
|
||||
inline static NRF_PWM_Type* Pwm()
|
||||
{
|
||||
return NRF_PWM2;
|
||||
}
|
||||
};
|
||||
|
||||
#if defined(NRF_PWM3)
|
||||
class NeoNrf52xPwm3
|
||||
{
|
||||
public:
|
||||
NeoNrf52xPwm3() {};
|
||||
|
||||
inline static NRF_PWM_Type* Pwm()
|
||||
{
|
||||
return NRF_PWM3;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
// dynamic channel support
|
||||
class NeoNrf52xPwmN
|
||||
{
|
||||
public:
|
||||
NeoNrf52xPwmN(NeoBusChannel channel)
|
||||
{
|
||||
NRF_PWM_Type* PWM[] = {
|
||||
NRF_PWM0,
|
||||
NRF_PWM1,
|
||||
NRF_PWM2
|
||||
#ifdef NRF_PWM3
|
||||
,NRF_PWM3
|
||||
#endif
|
||||
};
|
||||
_pwm = PWM[channel];
|
||||
}
|
||||
|
||||
inline NRF_PWM_Type* Pwm() const
|
||||
{
|
||||
return _pwm;
|
||||
}
|
||||
|
||||
protected:
|
||||
NRF_PWM_Type* _pwm;
|
||||
|
||||
NeoNrf52xPwmN() {};
|
||||
};
|
||||
|
||||
template<typename T_SPEED, typename T_BUS> class NeoNrf52xMethodBase
|
||||
{
|
||||
public:
|
||||
typedef NeoNoSettings SettingsObject;
|
||||
|
||||
NeoNrf52xMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize) :
|
||||
_sizeData(pixelCount * elementSize + settingsSize),
|
||||
_pin(pin)
|
||||
{
|
||||
construct();
|
||||
}
|
||||
|
||||
NeoNrf52xMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize, NeoBusChannel channel) :
|
||||
_sizeData(pixelCount* elementSize + settingsSize),
|
||||
_pin(pin),
|
||||
_bus(channel)
|
||||
{
|
||||
construct();
|
||||
}
|
||||
|
||||
~NeoNrf52xMethodBase()
|
||||
{
|
||||
while (!IsReadyToUpdate())
|
||||
{
|
||||
yield();
|
||||
}
|
||||
|
||||
dmaDeinit();
|
||||
|
||||
pinMode(_pin, INPUT);
|
||||
|
||||
free(_data);
|
||||
free(_dmaBuffer);
|
||||
}
|
||||
|
||||
bool IsReadyToUpdate() const
|
||||
{
|
||||
return (_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;
|
||||
};
|
||||
|
||||
void applySettings([[maybe_unused]] const SettingsObject& settings)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
const size_t _sizeData; // Size of '_data' buffer below
|
||||
const uint8_t _pin; // output pin number
|
||||
const T_BUS _bus; // holds instance for multi channel support
|
||||
|
||||
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 construct()
|
||||
{
|
||||
pinMode(_pin, OUTPUT);
|
||||
|
||||
_data = static_cast<uint8_t*>(malloc(_sizeData));
|
||||
// data cleared later in Begin()
|
||||
|
||||
_dmaBufferSize = c_dmaBytesPerDataByte * _sizeData + sizeof(nrf_pwm_values_common_t);
|
||||
_dmaBuffer = static_cast<nrf_pwm_values_common_t*>(malloc(_dmaBufferSize));
|
||||
}
|
||||
|
||||
void dmaInit()
|
||||
{
|
||||
// only use channel zero
|
||||
_bus.Pwm()->PSEL.OUT[0] = digitalPinToPinName(_pin);
|
||||
_bus.Pwm()->PSEL.OUT[1] = NC;
|
||||
_bus.Pwm()->PSEL.OUT[2] = NC;
|
||||
_bus.Pwm()->PSEL.OUT[3] = NC;
|
||||
|
||||
_bus.Pwm()->ENABLE = 1;
|
||||
_bus.Pwm()->MODE = NRF_PWM_MODE_UP;
|
||||
_bus.Pwm()->PRESCALER = NRF_PWM_CLK_16MHz;
|
||||
_bus.Pwm()->COUNTERTOP = T_SPEED::CountTop;
|
||||
_bus.Pwm()->LOOP = 1; // single fire so events get set
|
||||
_bus.Pwm()->DECODER = NRF_PWM_LOAD_COMMON;
|
||||
|
||||
// sequence zero is the primary data with a BitReset entry on the end for
|
||||
// the delay repeating
|
||||
_bus.Pwm()->SEQ[0].PTR = reinterpret_cast<uint32_t>(_dmaBuffer);
|
||||
_bus.Pwm()->SEQ[0].CNT = _dmaBufferSize / sizeof(nrf_pwm_values_common_t);
|
||||
_bus.Pwm()->SEQ[0].REFRESH = 0; // ignored
|
||||
_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
|
||||
_bus.Pwm()->SEQ[1].PTR = reinterpret_cast<uint32_t>(_dmaBuffer + (_bus.Pwm()->SEQ[0].CNT - 1));
|
||||
_bus.Pwm()->SEQ[1].CNT = 1;
|
||||
_bus.Pwm()->SEQ[1].REFRESH = 0; // ignored
|
||||
_bus.Pwm()->SEQ[1].ENDDELAY = 0; // ignored
|
||||
|
||||
// stop when the loop finishes
|
||||
_bus.Pwm()->SHORTS = PWM_SHORTS_LOOPSDONE_STOP_Msk;
|
||||
_bus.Pwm()->INTEN = 0;
|
||||
|
||||
dmaResetEvents();
|
||||
}
|
||||
|
||||
void dmaDeinit()
|
||||
{
|
||||
_bus.Pwm()->ENABLE = 0;
|
||||
_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()
|
||||
{
|
||||
_bus.Pwm()->EVENTS_LOOPSDONE = 0;
|
||||
_bus.Pwm()->EVENTS_SEQEND[0] = 0;
|
||||
_bus.Pwm()->EVENTS_SEQEND[1] = 0;
|
||||
_bus.Pwm()->EVENTS_STOPPED = 0;
|
||||
}
|
||||
|
||||
void dmaStart()
|
||||
{
|
||||
dmaResetEvents();
|
||||
_bus.Pwm()->TASKS_SEQSTART[0] = 1;
|
||||
}
|
||||
};
|
||||
|
||||
// normal
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedWs2811, NeoNrf52xPwmN> NeoNrf52xPwmNWs2811Method;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedWs2812x, NeoNrf52xPwmN> NeoNrf52xPwmNWs2812xMethod;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedSk6812, NeoNrf52xPwmN> NeoNrf52xPwmNSk6812Method;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedTm1814, NeoNrf52xPwmN> NeoNrf52xPwmNTm1814Method;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedTm1829, NeoNrf52xPwmN> NeoNrf52xPwmNTm1829Method;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedTm1914, NeoNrf52xPwmN> NeoNrf52xPwmNTm1914Method;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedTx1812, NeoNrf52xPwmN> NeoNrf52xPwmNTx1812Method;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedApa106, NeoNrf52xPwmN> NeoNrf52xPwmNApa106Method;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeed800Kbps, NeoNrf52xPwmN> NeoNrf52xPwmN800KbpsMethod;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeed400Kbps, NeoNrf52xPwmN> NeoNrf52xPwmN400KbpsMethod;
|
||||
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedWs2811, NeoNrf52xPwm0> NeoNrf52xPwm0Ws2811Method;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedWs2812x, NeoNrf52xPwm0> NeoNrf52xPwm0Ws2812xMethod;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedSk6812, NeoNrf52xPwm0> NeoNrf52xPwm0Sk6812Method;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedTm1814, NeoNrf52xPwm0> NeoNrf52xPwm0Tm1814Method;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedTm1829, NeoNrf52xPwm0> NeoNrf52xPwm0Tm1829Method;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedTm1914, NeoNrf52xPwm0> NeoNrf52xPwm0Tm1914Method;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedTx1812, NeoNrf52xPwm0> NeoNrf52xPwm0Tx1812Method;
|
||||
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<NeoNrf52xPwmSpeedTm1829, NeoNrf52xPwm1> NeoNrf52xPwm1Tm1829Method;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedTm1914, NeoNrf52xPwm1> NeoNrf52xPwm1Tm1914Method;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedTx1812, NeoNrf52xPwm1> NeoNrf52xPwm1Tx1812Method;
|
||||
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<NeoNrf52xPwmSpeedTm1829, NeoNrf52xPwm2> NeoNrf52xPwm2Tm1829Method;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedTm1914, NeoNrf52xPwm2> NeoNrf52xPwm2Tm1914Method;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedTx1812, NeoNrf52xPwm2> NeoNrf52xPwm2Tx1812Method;
|
||||
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<NeoNrf52xPwmSpeedTm1829, NeoNrf52xPwm3> NeoNrf52xPwm3Tm1829Method;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedTm1914, NeoNrf52xPwm3> NeoNrf52xPwm3Tm1914Method;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedTx1812, NeoNrf52xPwm3> NeoNrf52xPwm3Tx1812Method;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedApa106, NeoNrf52xPwm3> NeoNrf52xPwm3Apa106Method;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeed800Kbps, NeoNrf52xPwm3> NeoNrf52xPwm3800KbpsMethod;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeed400Kbps, NeoNrf52xPwm3> NeoNrf52xPwm3400KbpsMethod;
|
||||
#endif
|
||||
|
||||
// inverted
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedWs2811, NeoNrf52xPwmN> NeoNrf52xPwmNWs2811InvertedMethod;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedWs2812x, NeoNrf52xPwmN> NeoNrf52xPwmNWs2812xInvertedMethod;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedSk6812, NeoNrf52xPwmN> NeoNrf52xPwmNSk6812InvertedMethod;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedTm1814, NeoNrf52xPwmN> NeoNrf52xPwmNTm1814InvertedMethod;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedTm1829, NeoNrf52xPwmN> NeoNrf52xPwmNTm1829InvertedMethod;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedTm1914, NeoNrf52xPwmN> NeoNrf52xPwmNTm1914InvertedMethod;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedTx1812, NeoNrf52xPwmN> NeoNrf52xPwmNTx1812InvertedMethod;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedApa106, NeoNrf52xPwmN> NeoNrf52xPwmNApa106InvertedMethod;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeed800Kbps, NeoNrf52xPwmN> NeoNrf52xPwmN800KbpsInvertedMethod;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeed400Kbps, NeoNrf52xPwmN> NeoNrf52xPwmN400KbpsInvertedMethod;
|
||||
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedWs2811, NeoNrf52xPwm0> NeoNrf52xPwm0Ws2811InvertedMethod;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedWs2812x, NeoNrf52xPwm0> NeoNrf52xPwm0Ws2812xInvertedMethod;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedSk6812, NeoNrf52xPwm0> NeoNrf52xPwm0Sk6812InvertedMethod;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedTm1814, NeoNrf52xPwm0> NeoNrf52xPwm0Tm1814InvertedMethod;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedTm1829, NeoNrf52xPwm0> NeoNrf52xPwm0Tm1829InvertedMethod;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedTm1914, NeoNrf52xPwm0> NeoNrf52xPwm0Tm1914InvertedMethod;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedTx1812, NeoNrf52xPwm0> NeoNrf52xPwm0Tx1812InvertedMethod;
|
||||
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<NeoNrf52xPwmInvertedSpeedTm1829, NeoNrf52xPwm1> NeoNrf52xPwm1Tm1829InvertedMethod;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedTm1914, NeoNrf52xPwm1> NeoNrf52xPwm1Tm1914InvertedMethod;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedTx1812, NeoNrf52xPwm1> NeoNrf52xPwm1Tx1812InvertedMethod;
|
||||
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<NeoNrf52xPwmInvertedSpeedTm1829, NeoNrf52xPwm2> NeoNrf52xPwm2Tm1829InvertedMethod;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedTm1914, NeoNrf52xPwm2> NeoNrf52xPwm2Tm1914InvertedMethod;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedTx1812, NeoNrf52xPwm2> NeoNrf52xPwm2Tx1812InvertedMethod;
|
||||
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<NeoNrf52xPwmInvertedSpeedTm1829, NeoNrf52xPwm3> NeoNrf52xPwm3Tm1829InvertedMethod;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedTm1914, NeoNrf52xPwm3> NeoNrf52xPwm3Tm1914InvertedMethod;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedTx1812, NeoNrf52xPwm3> NeoNrf52xPwm3Tx1812InvertedMethod;
|
||||
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 NeoNrf52xPwm2Tm1829Method NeoTm1829Method;
|
||||
typedef NeoNrf52xPwm2Tm1914Method NeoTm1914Method;
|
||||
typedef NeoNrf52xPwm2Tx1812Method NeoTx1812Method;
|
||||
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 NeoNrf52xPwm2Tm1829InvertedMethod NeoTm1829InvertedMethod;
|
||||
typedef NeoNrf52xPwm2Tm1914InvertedMethod NeoTm1914InvertedMethod;
|
||||
typedef NeoNrf52xPwm2Tx1812InvertedMethod NeoTx1812InvertedMethod;
|
||||
typedef NeoNrf52xPwm2Sk6812InvertedMethod NeoLc8812InvertedMethod;
|
||||
typedef NeoNrf52xPwm2Apa106InvertedMethod NeoApa106InvertedMethod;
|
||||
|
||||
typedef NeoNrf52xPwm2Ws2812xInvertedMethod Neo800KbpsInvertedMethod;
|
||||
typedef NeoNrf52xPwm2400KbpsInvertedMethod Neo400KbpsInvertedMethod;
|
||||
|
||||
#endif
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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
|
||||
@@ -0,0 +1,112 @@
|
||||
#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 : public 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 T_LAYOUT::_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[T_LAYOUT::_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;
|
||||
}
|
||||
|
||||
};
|
||||
@@ -0,0 +1,216 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
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;
|
||||
};
|
||||
|
||||
class Neo9ElementsNoSettings : public Neo9Elements
|
||||
{
|
||||
public:
|
||||
typedef NeoNoSettings SettingsObject;
|
||||
static const size_t SettingsSize = 0;
|
||||
|
||||
static void applySettings([[maybe_unused]] uint8_t* pData, [[maybe_unused]] size_t sizeData, [[maybe_unused]] const SettingsObject& settings)
|
||||
{
|
||||
}
|
||||
|
||||
static uint8_t* pixels([[maybe_unused]] uint8_t* pData, [[maybe_unused]] size_t sizeData)
|
||||
{
|
||||
return pData;
|
||||
}
|
||||
|
||||
static const uint8_t* pixels([[maybe_unused]] const uint8_t* pData, [[maybe_unused]] size_t sizeData)
|
||||
{
|
||||
return pData;
|
||||
}
|
||||
};
|
||||
|
||||
// Abcdefgps byte order
|
||||
class NeoAbcdefgSegmentFeature : public Neo9ElementsNoSettings
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
// BACEDF.G+ byte order
|
||||
class NeoBacedfpgsSegmentFeature : public Neo9ElementsNoSettings
|
||||
{
|
||||
public:
|
||||
static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color)
|
||||
{
|
||||
uint8_t* p = getPixelAddress(pPixels, indexPixel);
|
||||
|
||||
// Segment Digit is Abcdefgps order
|
||||
*p++ = color.Segment[LedSegment_B];
|
||||
*p++ = color.Segment[LedSegment_A];
|
||||
*p++ = color.Segment[LedSegment_C];
|
||||
|
||||
*p++ = color.Segment[LedSegment_E];
|
||||
*p++ = color.Segment[LedSegment_D];
|
||||
*p++ = color.Segment[LedSegment_F];
|
||||
|
||||
*p++ = color.Segment[LedSegment_Decimal];
|
||||
*p++ = color.Segment[LedSegment_G];
|
||||
*p++ = color.Segment[LedSegment_Custom];
|
||||
}
|
||||
|
||||
static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel)
|
||||
{
|
||||
ColorObject color;
|
||||
const uint8_t* p = getPixelAddress(pPixels, indexPixel);
|
||||
|
||||
color.Segment[LedSegment_B] = *p++;
|
||||
color.Segment[LedSegment_A] = *p++;
|
||||
color.Segment[LedSegment_C] = *p++;
|
||||
|
||||
color.Segment[LedSegment_E] = *p++;
|
||||
color.Segment[LedSegment_D] = *p++;
|
||||
color.Segment[LedSegment_F] = *p++;
|
||||
|
||||
color.Segment[LedSegment_Decimal] = *p++;
|
||||
color.Segment[LedSegment_G] = *p++;
|
||||
color.Segment[LedSegment_Custom] = *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.Segment[LedSegment_B] = pgm_read_byte(p++);
|
||||
color.Segment[LedSegment_A] = pgm_read_byte(p++);
|
||||
color.Segment[LedSegment_C] = pgm_read_byte(p++);
|
||||
|
||||
color.Segment[LedSegment_E] = pgm_read_byte(p++);
|
||||
color.Segment[LedSegment_D] = pgm_read_byte(p++);
|
||||
color.Segment[LedSegment_F] = pgm_read_byte(p++);
|
||||
|
||||
color.Segment[LedSegment_Decimal] = pgm_read_byte(p++);
|
||||
color.Segment[LedSegment_G] = pgm_read_byte(p++);
|
||||
color.Segment[LedSegment_Custom] = pgm_read_byte(p++);
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
typedef NeoBacedfpgsSegmentFeature SevenSegmentFeature; // Abcdefg order is default
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
const uint16_t RedTenthMilliAmpere; // in 1/10th ma
|
||||
const uint16_t GreenTenthMilliAmpere; // in 1/10th ma
|
||||
const 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),
|
||||
WhiteTenthMilliAmpere(white)
|
||||
{
|
||||
}
|
||||
|
||||
const uint16_t RedTenthMilliAmpere; // in 1/10th ma
|
||||
const uint16_t GreenTenthMilliAmpere; // in 1/10th ma
|
||||
const uint16_t BlueTenthMilliAmpere; // in 1/10th ma
|
||||
const uint16_t WhiteTenthMilliAmpere; // in 1/10th ma
|
||||
};
|
||||
@@ -0,0 +1,326 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
NeoSm168xxColorFeatures provides feature classes to describe color order and
|
||||
color depth for NeoPixelBus template class specific to the SM168xx chips/leds
|
||||
|
||||
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
|
||||
/*
|
||||
3 channel RGB
|
||||
SM16803P 1.8~60mA << need spec sheet to get accurate implementation
|
||||
SM16813PB 1.8~19mA
|
||||
SM16823E 60~350mA
|
||||
4 channel RGBW
|
||||
SM16804PB 1.5~60mA << need spec sheet to get accurate implementation
|
||||
SM16804EB 1.8~19mA
|
||||
SM16824E 60~350mA
|
||||
*/
|
||||
|
||||
class NeoSm168x3SettingsBase : public NeoRgbCurrentSettings
|
||||
{
|
||||
public:
|
||||
NeoSm168x3SettingsBase(uint8_t redGain,
|
||||
uint8_t greenGain,
|
||||
uint8_t blueGain,
|
||||
uint16_t redCurrent,
|
||||
uint16_t greenCurrent,
|
||||
uint16_t blueCurrent) :
|
||||
NeoRgbCurrentSettings(redCurrent, greenCurrent, blueCurrent),
|
||||
RedGain(redGain & 0x0f),
|
||||
GreenGain(greenGain & 0x0f),
|
||||
BlueGain(blueGain & 0x0f) {}
|
||||
|
||||
const uint8_t RedGain : 4;
|
||||
const uint8_t GreenGain : 4;
|
||||
const uint8_t BlueGain : 4;
|
||||
};
|
||||
|
||||
class NeoSm16803pbSettings : public NeoSm168x3SettingsBase
|
||||
{
|
||||
public:
|
||||
NeoSm16803pbSettings(uint8_t redGain, uint8_t greenGain, uint8_t blueGain) :
|
||||
NeoSm168x3SettingsBase(redGain,
|
||||
greenGain,
|
||||
blueGain,
|
||||
CurrentLookup[redGain],
|
||||
CurrentLookup[greenGain],
|
||||
CurrentLookup[blueGain])
|
||||
{
|
||||
}
|
||||
|
||||
void Encode(uint8_t* encoded) const
|
||||
{
|
||||
// 0RGB 4 bits each
|
||||
encoded[0] = RedGain;
|
||||
encoded[1] = GreenGain << 4 | BlueGain;
|
||||
}
|
||||
|
||||
protected:
|
||||
static constexpr uint8_t CurrentLookup[16] = {
|
||||
18, 30, 41, 53, 64, 76, 87, 99,
|
||||
110, 133, 145, 156, 168, 179, 19};
|
||||
};
|
||||
|
||||
class NeoSm16823eSettings : public NeoSm168x3SettingsBase
|
||||
{
|
||||
public:
|
||||
NeoSm16823eSettings(uint8_t redGain, uint8_t greenGain, uint8_t blueGain, uint16_t resisterOhms) :
|
||||
NeoSm168x3SettingsBase(redGain,
|
||||
greenGain,
|
||||
blueGain,
|
||||
calcCurrent(resisterOhms, redGain),
|
||||
calcCurrent(resisterOhms, greenGain),
|
||||
calcCurrent(resisterOhms, blueGain)),
|
||||
extROhms(resisterOhms)
|
||||
{
|
||||
}
|
||||
|
||||
void Encode(uint8_t* encoded) const
|
||||
{
|
||||
// RGB0 4 bits each
|
||||
encoded[0] = RedGain << 4 | GreenGain;
|
||||
encoded[1] = BlueGain << 4;
|
||||
}
|
||||
|
||||
protected:
|
||||
const uint16_t extROhms;
|
||||
|
||||
static uint16_t calcCurrent(const uint16_t ohms, const uint8_t gain)
|
||||
{
|
||||
uint16_t mA = (967 * (240 + (gain * 32)) / ohms); // from spec sheet, gain 0-15 instead
|
||||
return mA * 10; // return tenths of mA
|
||||
}
|
||||
};
|
||||
|
||||
// RGBW versions
|
||||
|
||||
class NeoSm168x4SettingsBase : public NeoRgbwCurrentSettings
|
||||
{
|
||||
public:
|
||||
NeoSm168x4SettingsBase(uint8_t redGain,
|
||||
uint8_t greenGain,
|
||||
uint8_t blueGain,
|
||||
uint8_t whiteGain,
|
||||
uint16_t redCurrent,
|
||||
uint16_t greenCurrent,
|
||||
uint16_t blueCurrent,
|
||||
uint16_t whiteCurrent) :
|
||||
NeoRgbwCurrentSettings(redCurrent, greenCurrent, blueCurrent, whiteCurrent),
|
||||
RedGain(redGain & 0x0f),
|
||||
GreenGain(greenGain & 0x0f),
|
||||
BlueGain(blueGain & 0x0f),
|
||||
WhiteGain(whiteGain & 0x0f) {}
|
||||
|
||||
const uint8_t RedGain : 4;
|
||||
const uint8_t GreenGain : 4;
|
||||
const uint8_t BlueGain : 4;
|
||||
const uint8_t WhiteGain : 4;
|
||||
};
|
||||
|
||||
class NeoSm16804ebSettings : public NeoSm168x4SettingsBase
|
||||
{
|
||||
public:
|
||||
NeoSm16804ebSettings(uint8_t redGain, uint8_t greenGain, uint8_t blueGain, uint8_t whiteGain) :
|
||||
NeoSm168x4SettingsBase(redGain,
|
||||
greenGain,
|
||||
blueGain,
|
||||
whiteGain,
|
||||
CurrentLookup[redGain],
|
||||
CurrentLookup[greenGain],
|
||||
CurrentLookup[blueGain],
|
||||
CurrentLookup[whiteGain])
|
||||
{
|
||||
}
|
||||
|
||||
void Encode(uint8_t* encoded) const
|
||||
{
|
||||
// RGBW 4 bits each
|
||||
encoded[0] = RedGain << 4 | GreenGain;
|
||||
encoded[1] = BlueGain << 4 | WhiteGain;
|
||||
}
|
||||
|
||||
protected:
|
||||
static constexpr uint8_t CurrentLookup[16] = {
|
||||
18, 30, 41, 53, 64, 76, 87, 99,
|
||||
110, 133, 145, 156, 168, 179, 19 };
|
||||
};
|
||||
|
||||
class NeoSm16824eSettings : public NeoSm168x4SettingsBase
|
||||
{
|
||||
public:
|
||||
NeoSm16824eSettings(uint8_t redGain, uint8_t greenGain, uint8_t blueGain, uint8_t whiteGain, uint16_t resisterOhms) :
|
||||
NeoSm168x4SettingsBase(redGain,
|
||||
greenGain,
|
||||
blueGain,
|
||||
whiteGain,
|
||||
calcCurrent(resisterOhms, redGain),
|
||||
calcCurrent(resisterOhms, greenGain),
|
||||
calcCurrent(resisterOhms, blueGain),
|
||||
calcCurrent(resisterOhms, whiteGain)),
|
||||
extROhms(resisterOhms)
|
||||
{
|
||||
}
|
||||
|
||||
void Encode(uint8_t* encoded) const
|
||||
{
|
||||
// RGBW 4 bits each
|
||||
encoded[0] = RedGain << 4 | GreenGain;
|
||||
encoded[1] = BlueGain << 4 | WhiteGain;
|
||||
}
|
||||
|
||||
protected:
|
||||
const uint16_t extROhms;
|
||||
|
||||
static uint16_t calcCurrent(const uint16_t ohms, const uint8_t gain)
|
||||
{
|
||||
uint16_t mA = (1100 * (240 + (gain * 32)) / ohms); // from spec sheet, gain 0-15 instead
|
||||
return mA * 10; // return tenths of mA
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template<typename T_SETTINGS> class NeoRgbwSm168x4Elements : public Neo4ByteElements
|
||||
{
|
||||
public:
|
||||
typedef T_SETTINGS SettingsObject;
|
||||
static const size_t SettingsSize = 2;
|
||||
|
||||
static void applySettings([[maybe_unused]] uint8_t* pData, [[maybe_unused]] size_t sizeData, [[maybe_unused]] const SettingsObject& settings)
|
||||
{
|
||||
// settings are at the end of the data stream
|
||||
uint8_t* pDest = pData + sizeData - SettingsSize;
|
||||
|
||||
settings.Encode(pDest);
|
||||
}
|
||||
|
||||
static uint8_t* pixels([[maybe_unused]] uint8_t* pData, [[maybe_unused]] size_t sizeData)
|
||||
{
|
||||
return pData;
|
||||
}
|
||||
|
||||
static const uint8_t* pixels([[maybe_unused]] const uint8_t* pData, [[maybe_unused]] size_t sizeData)
|
||||
{
|
||||
return pData;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T_SETTINGS> class NeoRgbSm168x3Elements : public Neo3ByteElements
|
||||
{
|
||||
public:
|
||||
typedef T_SETTINGS SettingsObject;
|
||||
static const size_t SettingsSize = 2;
|
||||
|
||||
static void applySettings([[maybe_unused]] uint8_t* pData, [[maybe_unused]] size_t sizeData, [[maybe_unused]] const SettingsObject& settings)
|
||||
{
|
||||
// settings are at the end of the data stream
|
||||
uint8_t* pDest = pData + sizeData - SettingsSize;
|
||||
|
||||
settings.Encode(pDest);
|
||||
}
|
||||
|
||||
static uint8_t* pixels([[maybe_unused]] uint8_t* pData, [[maybe_unused]] size_t sizeData)
|
||||
{
|
||||
return pData;
|
||||
}
|
||||
|
||||
static const uint8_t* pixels([[maybe_unused]] const uint8_t* pData, [[maybe_unused]] size_t sizeData)
|
||||
{
|
||||
return pData;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
typedef NeoRgbSm168x3Elements<NeoSm16803pbSettings> NeoRgbSm16803pbColorFeature;
|
||||
typedef NeoRgbSm168x3Elements<NeoSm16823eSettings> NeoRgbSm16823eColorFeature;
|
||||
typedef NeoRgbwSm168x4Elements<NeoSm16804ebSettings> NeoRgbwSm16804ebColorFeature;
|
||||
typedef NeoRgbwSm168x4Elements<NeoSm16824eSettings> NeoRgbwSm16824eColorFeature;
|
||||
|
||||
|
||||
@@ -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 &&
|
||||
static_cast<uint16_t>(x) < SpriteWidth() &&
|
||||
y >= 0 &&
|
||||
static_cast<uint16_t>(y) < SpriteHeight())
|
||||
{
|
||||
result = x + y * SpriteWidth() + indexSprite * _spriteHeight * SpriteWidth();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
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 Neo4ByteElementsTm1814Settings : public Neo4ByteElements
|
||||
{
|
||||
private:
|
||||
const static uint16_t EncodeDivisor = 5;
|
||||
|
||||
public:
|
||||
typedef NeoTm1814Settings SettingsObject;
|
||||
static const size_t SettingsSize = 8;
|
||||
|
||||
static void applySettings([[maybe_unused]] uint8_t* pData, [[maybe_unused]] size_t sizeData, [[maybe_unused]] const SettingsObject& settings)
|
||||
{
|
||||
// settings are at the front of the data stream
|
||||
uint8_t* pSet = pData;
|
||||
|
||||
// C1
|
||||
*pSet++ = (SettingsObject::LimitCurrent(settings.WhiteTenthMilliAmpere) - SettingsObject::MinCurrent) / EncodeDivisor;
|
||||
*pSet++ = (SettingsObject::LimitCurrent(settings.RedTenthMilliAmpere) - SettingsObject::MinCurrent) / EncodeDivisor;
|
||||
*pSet++ = (SettingsObject::LimitCurrent(settings.GreenTenthMilliAmpere) - SettingsObject::MinCurrent) / EncodeDivisor;
|
||||
*pSet++ = (SettingsObject::LimitCurrent(settings.BlueTenthMilliAmpere) - SettingsObject::MinCurrent) / EncodeDivisor;
|
||||
|
||||
uint8_t* pC1 = pData;
|
||||
|
||||
// C2
|
||||
for (uint8_t elem = 0; elem < 4; elem++)
|
||||
{
|
||||
*pSet++ = ~(*pC1++);
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t* pixels([[maybe_unused]] uint8_t* pData, [[maybe_unused]] size_t sizeData)
|
||||
{
|
||||
// settings are at the front of the data stream
|
||||
return pData + SettingsSize;
|
||||
}
|
||||
|
||||
static const uint8_t* pixels([[maybe_unused]] const uint8_t* pData, [[maybe_unused]] size_t sizeData)
|
||||
{
|
||||
// settings are at the front of the data stream
|
||||
return pData + SettingsSize;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class NeoWrgbTm1814Feature : public Neo4ByteElementsTm1814Settings
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@@ -0,0 +1,177 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
NeoTm1914ColorFeatures provides feature classes to describe color order and
|
||||
color depth for NeoPixelBus template class specific to the TM1914 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
|
||||
|
||||
enum NeoTm1914_Mode
|
||||
{
|
||||
NeoTm1914_Mode_DinFdinAutoSwitch, // Switches between DIN and FDIN on any signal pause > 300ms
|
||||
NeoTm1914_Mode_DinOnly, // DIN input pin used exclusively
|
||||
NeoTm1914_Mode_FdinOnly // FDIN input pin used exclusively
|
||||
};
|
||||
|
||||
class NeoTm1914Settings
|
||||
{
|
||||
public:
|
||||
NeoTm1914Settings(NeoTm1914_Mode mode = NeoTm1914_Mode_DinOnly) :
|
||||
Mode(mode)
|
||||
{
|
||||
}
|
||||
|
||||
NeoTm1914_Mode Mode;
|
||||
};
|
||||
|
||||
class Neo3ByteElementsTm1914Settings : public Neo3ByteElements
|
||||
{
|
||||
public:
|
||||
typedef NeoTm1914Settings SettingsObject;
|
||||
static const size_t SettingsSize = 6;
|
||||
|
||||
static void applySettings([[maybe_unused]] uint8_t* pData, [[maybe_unused]] size_t sizeData, [[maybe_unused]] const SettingsObject& settings)
|
||||
{
|
||||
// settings are at the front of the data stream
|
||||
uint8_t* pSet = pData;
|
||||
uint8_t mode = 0xff;
|
||||
|
||||
// C1 - the mode
|
||||
*pSet++ = 0xff;
|
||||
*pSet++ = 0xff;
|
||||
|
||||
switch (settings.Mode)
|
||||
{
|
||||
case NeoTm1914_Mode_DinFdinAutoSwitch:
|
||||
mode = 0xff;
|
||||
break;
|
||||
|
||||
case NeoTm1914_Mode_FdinOnly:
|
||||
mode = 0xfa;
|
||||
break;
|
||||
|
||||
case NeoTm1914_Mode_DinOnly:
|
||||
default:
|
||||
mode = 0xf5;
|
||||
break;
|
||||
}
|
||||
*pSet++ = mode;
|
||||
|
||||
// C2 - ones compliment of the above
|
||||
uint8_t* pC1 = pData;
|
||||
for (uint8_t elem = 0; elem < 3; elem++)
|
||||
{
|
||||
*pSet++ = ~(*pC1++);
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t* pixels([[maybe_unused]] uint8_t* pData, [[maybe_unused]] size_t sizeData)
|
||||
{
|
||||
// settings are at the front of the data stream
|
||||
return pData + SettingsSize;
|
||||
}
|
||||
|
||||
static const uint8_t* pixels([[maybe_unused]] const uint8_t* pData, [[maybe_unused]] size_t sizeData)
|
||||
{
|
||||
// settings are at the front of the data stream
|
||||
return pData + SettingsSize;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class NeoRgbTm1914Feature : public Neo3ByteElementsTm1914Settings
|
||||
{
|
||||
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 NeoGrbTm1914Feature : public Neo3ByteElementsTm1914Settings
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
};
|
||||
@@ -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;
|
||||
};
|
||||
@@ -0,0 +1,69 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
NeoPixel library helper functions
|
||||
|
||||
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
|
||||
|
||||
#ifndef countof
|
||||
#define countof(array) (sizeof(array)/sizeof(array[0]))
|
||||
#endif
|
||||
|
||||
class NeoUtil
|
||||
{
|
||||
private:
|
||||
static constexpr uint8_t Reverse8BitsLookup[16] = {
|
||||
0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe,
|
||||
0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf };
|
||||
|
||||
public:
|
||||
inline static uint8_t Reverse8Bits(uint8_t n)
|
||||
{
|
||||
return (Reverse8BitsLookup[n & 0b1111] << 4) | Reverse8BitsLookup[n >> 4];
|
||||
}
|
||||
|
||||
inline static size_t RoundUp(size_t numToRound, size_t multiple)
|
||||
{
|
||||
return ((numToRound + multiple - 1) / multiple) * multiple;
|
||||
}
|
||||
|
||||
// alternatives that proved to be slower but left for more periodic testing
|
||||
/*
|
||||
// marginally slower than the table
|
||||
static uint8_t Reverse8Bits(uint8_t b)
|
||||
{
|
||||
b = (b & 0b11110000) >> 4 | (b & 0b00001111) << 4;
|
||||
b = (b & 0b11001100) >> 2 | (b & 0b00110011) << 2;
|
||||
b = (b & 0b10101010) >> 1 | (b & 0b01010101) << 1;
|
||||
return b;
|
||||
}
|
||||
*/
|
||||
|
||||
/* WAY TO SLOW
|
||||
static uint8_t Reverse8Bits(uint8_t b)
|
||||
{
|
||||
return (b * 0x0202020202ULL & 0x010884422010ULL) % 1023;
|
||||
}
|
||||
*/
|
||||
};
|
||||
@@ -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([[maybe_unused]] uint8_t* pData, [[maybe_unused]] size_t sizeData, [[maybe_unused]] const SettingsObject& settings)
|
||||
{
|
||||
}
|
||||
|
||||
static uint8_t* pixels([[maybe_unused]] uint8_t* pData, [[maybe_unused]] size_t sizeData)
|
||||
{
|
||||
return pData;
|
||||
}
|
||||
|
||||
static const uint8_t* pixels([[maybe_unused]] const uint8_t* pData, [[maybe_unused]] size_t sizeData)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
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:
|
||||
typedef typename T_TWOWIRE::SettingsObject SettingsObject;
|
||||
|
||||
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));
|
||||
// data cleared later in Begin()
|
||||
}
|
||||
|
||||
#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;
|
||||
};
|
||||
|
||||
void applySettings([[maybe_unused]] const SettingsObject& settings)
|
||||
{
|
||||
_wire.applySettings(settings);
|
||||
}
|
||||
|
||||
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<SpiSpeed5Mhz>> P9813Spi5MhzMethod;
|
||||
typedef P9813MethodBase<TwoWireSpiImple<SpiSpeed2Mhz>> P9813Spi2MhzMethod;
|
||||
typedef P9813MethodBase<TwoWireSpiImple<SpiSpeed1Mhz>> P9813Spi1MhzMethod;
|
||||
typedef P9813MethodBase<TwoWireSpiImple<SpiSpeed500Khz>> P9813Spi500KhzMethod;
|
||||
|
||||
typedef P9813MethodBase<TwoWireSpiImple<SpiSpeedHz>> P9813SpiHzMethod;
|
||||
|
||||
typedef P9813Spi10MhzMethod P9813SpiMethod;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,281 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
Rgb16Color provides a color object that stores in only 16 bits, aka 565 format
|
||||
|
||||
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"
|
||||
#include "RgbColorBase.h"
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Rgb16Color represents a color object that is represented by Red, Green, Blue
|
||||
// component values stored in a single 16 bit value using 565 model.
|
||||
// It contains helpful color routines to manipulate the color.
|
||||
// ------------------------------------------------------------------------
|
||||
struct Rgb16Color : RgbColorBase
|
||||
{
|
||||
typedef NeoRgbCurrentSettings SettingsObject;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Construct a Rgb16Color using R, G, B values (0-255)
|
||||
// ------------------------------------------------------------------------
|
||||
Rgb16Color(uint8_t r, uint8_t g, uint8_t b)
|
||||
{
|
||||
setR(r);
|
||||
setG(g);
|
||||
setB(b);
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Construct a Rgb16Color using a single brightness value (0-255)
|
||||
// This works well for creating gray tone colors
|
||||
// (0) = black, (255) = white, (128) = gray
|
||||
// ------------------------------------------------------------------------
|
||||
Rgb16Color(uint8_t brightness)
|
||||
{
|
||||
setR(brightness);
|
||||
setG(brightness);
|
||||
setB(brightness);
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Construct a Rgb16Color using a single 16bit encoded value
|
||||
// CAUTION: the color value must follow a 5/6/5 encoding model otherwise an
|
||||
// incorrect color will be generated
|
||||
// ------------------------------------------------------------------------
|
||||
Rgb16Color(uint16_t color) :
|
||||
Color565(color)
|
||||
{
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Construct a Rgb16Color using HtmlColor
|
||||
// ------------------------------------------------------------------------
|
||||
Rgb16Color(const HtmlColor& color)
|
||||
{
|
||||
RgbColor converted = color;
|
||||
|
||||
setR(converted.R);
|
||||
setG(converted.G);
|
||||
setB(converted.B);
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Construct a Rgb16Color using HslColor
|
||||
// ------------------------------------------------------------------------
|
||||
Rgb16Color(const HslColor& color)
|
||||
{
|
||||
RgbColor converted = color;
|
||||
|
||||
setR(converted.R);
|
||||
setG(converted.G);
|
||||
setB(converted.B);
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Construct a Rgb16Color using HsbColor
|
||||
// ------------------------------------------------------------------------
|
||||
Rgb16Color(const HsbColor& color)
|
||||
{
|
||||
RgbColor converted = color;
|
||||
|
||||
setR(converted.R);
|
||||
setG(converted.G);
|
||||
setB(converted.B);
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Construct a Rgb16Color that will have its values set in latter operations
|
||||
// CAUTION: The Color565 member is not initialized and may not be consistent
|
||||
// ------------------------------------------------------------------------
|
||||
Rgb16Color()
|
||||
{
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// properties
|
||||
// ------------------------------------------------------------------------
|
||||
void setR(uint8_t r)
|
||||
{
|
||||
Color565 &= 0x07ff;
|
||||
Color565 |= ((r & 0xf8) << 8);
|
||||
};
|
||||
uint8_t getR() const
|
||||
{
|
||||
return (Color565 & 0xf800) >> 8;
|
||||
};
|
||||
|
||||
void setG(uint8_t g)
|
||||
{
|
||||
Color565 &= 0xf81f;
|
||||
Color565 |= ((g & 0xfe) << 3);
|
||||
};
|
||||
uint8_t getG() const
|
||||
{
|
||||
return (Color565 & 0x07e0) >> 3;
|
||||
};
|
||||
|
||||
void setB(uint8_t b)
|
||||
{
|
||||
Color565 &= 0xffe0;
|
||||
Color565 |= ((b & 0xf8) >> 3);
|
||||
};
|
||||
uint8_t getB() const
|
||||
{
|
||||
return (Color565 & 0x001f) << 3;
|
||||
};
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Comparison operators
|
||||
// ------------------------------------------------------------------------
|
||||
bool operator==(const Rgb16Color& other) const
|
||||
{
|
||||
return (Color565 == other.Color565);
|
||||
};
|
||||
|
||||
bool operator!=(const Rgb16Color& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// CalculateBrightness will calculate the overall brightness
|
||||
// NOTE: This is a simple linear brightness
|
||||
// ------------------------------------------------------------------------
|
||||
uint8_t CalculateBrightness() const
|
||||
{
|
||||
RgbColor converted = *this;
|
||||
return converted.CalculateBrightness();
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 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
|
||||
// ------------------------------------------------------------------------
|
||||
Rgb16Color Dim(uint8_t ratio) const
|
||||
{
|
||||
RgbColor converted = *this;
|
||||
RgbColor result = converted.Dim(ratio);
|
||||
|
||||
return Rgb16Color(result.R, result.G, result.B);
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 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
|
||||
// ------------------------------------------------------------------------
|
||||
Rgb16Color Brighten(uint8_t ratio) const
|
||||
{
|
||||
RgbColor converted = *this;
|
||||
RgbColor result = converted.Brighten(ratio);
|
||||
|
||||
return Rgb16Color(result.R, result.G, result.B);
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 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)
|
||||
{
|
||||
RgbColor converted = *this;
|
||||
|
||||
converted.Darken(delta);
|
||||
setR(converted.R);
|
||||
setG(converted.G);
|
||||
setB(converted.B);
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 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)
|
||||
{
|
||||
RgbColor converted = *this;
|
||||
|
||||
converted.Lighten(delta);
|
||||
setR(converted.R);
|
||||
setG(converted.G);
|
||||
setB(converted.B);
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 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 Rgb16Color LinearBlend(const Rgb16Color& left, const Rgb16Color& right, float progress)
|
||||
{
|
||||
RgbColor result = RgbColor::LinearBlend(left, right, progress);
|
||||
|
||||
return Rgb16Color(result.R, result.G, result.B);
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 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 Rgb16Color BilinearBlend(const Rgb16Color& c00,
|
||||
const Rgb16Color& c01,
|
||||
const Rgb16Color& c10,
|
||||
const Rgb16Color& c11,
|
||||
float x,
|
||||
float y)
|
||||
{
|
||||
RgbColor result = RgbColor::BilinearBlend(c00, c01, c10, c11, x, y);
|
||||
|
||||
return Rgb16Color(result.R, result.G, result.B);
|
||||
};
|
||||
|
||||
uint32_t CalcTotalTenthMilliAmpere(const SettingsObject& settings)
|
||||
{
|
||||
auto total = 0;
|
||||
|
||||
total += getR() * settings.RedTenthMilliAmpere / 255;
|
||||
total += getG() * settings.GreenTenthMilliAmpere / 255;
|
||||
total += getB() * settings.BlueTenthMilliAmpere / 255;
|
||||
|
||||
return total;
|
||||
};
|
||||
|
||||
uint16_t Color565;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
Rgb48Color 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 "Rgb48Color.h"
|
||||
#include "RgbColor.h"
|
||||
#include "HslColor.h"
|
||||
#include "HsbColor.h"
|
||||
#include "HtmlColor.h"
|
||||
|
||||
Rgb48Color::Rgb48Color(const HslColor& color)
|
||||
{
|
||||
float r;
|
||||
float g;
|
||||
float b;
|
||||
|
||||
_HslToRgb(color, &r, &g, &b);
|
||||
|
||||
R = static_cast<uint16_t>(r * Max);
|
||||
G = static_cast<uint16_t>(g * Max);
|
||||
B = static_cast<uint16_t>(b * Max);
|
||||
}
|
||||
|
||||
Rgb48Color::Rgb48Color(const HsbColor& color)
|
||||
{
|
||||
float r;
|
||||
float g;
|
||||
float b;
|
||||
|
||||
_HsbToRgb(color, &r, &g, &b);
|
||||
|
||||
R = static_cast<uint16_t>(r * Max);
|
||||
G = static_cast<uint16_t>(g * Max);
|
||||
B = static_cast<uint16_t>(b * Max);
|
||||
}
|
||||
|
||||
uint16_t Rgb48Color::CalculateBrightness() const
|
||||
{
|
||||
return static_cast<uint16_t>((static_cast<uint32_t>(R) + static_cast<uint32_t>(G) + static_cast<uint32_t>(B)) / 3);
|
||||
}
|
||||
|
||||
Rgb48Color Rgb48Color::Dim(uint16_t ratio) const
|
||||
{
|
||||
// specifically avoids float math
|
||||
return Rgb48Color(_elementDim(R, ratio), _elementDim(G, ratio), _elementDim(B, ratio));
|
||||
}
|
||||
|
||||
Rgb48Color Rgb48Color::Brighten(uint16_t ratio) const
|
||||
{
|
||||
// specifically avoids float math
|
||||
return Rgb48Color(_elementBrighten(R, ratio), _elementBrighten(G, ratio), _elementBrighten(B, ratio));
|
||||
}
|
||||
|
||||
void Rgb48Color::Darken(uint16_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 Rgb48Color::Lighten(uint16_t delta)
|
||||
{
|
||||
if (R < Max - delta)
|
||||
{
|
||||
R += delta;
|
||||
}
|
||||
else
|
||||
{
|
||||
R = Max;
|
||||
}
|
||||
|
||||
if (G < Max - delta)
|
||||
{
|
||||
G += delta;
|
||||
}
|
||||
else
|
||||
{
|
||||
G = Max;
|
||||
}
|
||||
|
||||
if (B < Max - delta)
|
||||
{
|
||||
B += delta;
|
||||
}
|
||||
else
|
||||
{
|
||||
B = Max;
|
||||
}
|
||||
}
|
||||
|
||||
Rgb48Color Rgb48Color::LinearBlend(const Rgb48Color& left, const Rgb48Color& right, float progress)
|
||||
{
|
||||
return Rgb48Color( left.R + ((right.R - left.R) * progress),
|
||||
left.G + ((right.G - left.G) * progress),
|
||||
left.B + ((right.B - left.B) * progress));
|
||||
}
|
||||
|
||||
Rgb48Color Rgb48Color::BilinearBlend(const Rgb48Color& c00,
|
||||
const Rgb48Color& c01,
|
||||
const Rgb48Color& c10,
|
||||
const Rgb48Color& 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 Rgb48Color(
|
||||
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);
|
||||
}
|
||||
@@ -0,0 +1,213 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
Rgb48Color provides a color object that contains 16bit color elements
|
||||
|
||||
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"
|
||||
#include "RgbColorBase.h"
|
||||
#include "RgbColor.h"
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Rgb48Color represents a color object that is represented by Red, Green, Blue
|
||||
// component values. It contains helpful color routines to manipulate the
|
||||
// color.
|
||||
// ------------------------------------------------------------------------
|
||||
struct Rgb48Color : RgbColorBase
|
||||
{
|
||||
typedef NeoRgbCurrentSettings SettingsObject;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Construct a Rgb48Color using R, G, B values (0-65535)
|
||||
// ------------------------------------------------------------------------
|
||||
Rgb48Color(uint16_t r, uint16_t g, uint16_t b) :
|
||||
R(r), G(g), B(b)
|
||||
{
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Construct a Rgb48Color using a single brightness value (0-65535)
|
||||
// This works well for creating gray tone colors
|
||||
// (0) = black, (65535) = white, (32768) = gray
|
||||
// ------------------------------------------------------------------------
|
||||
Rgb48Color(uint16_t brightness) :
|
||||
R(brightness), G(brightness), B(brightness)
|
||||
{
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Construct a Rgb48Color using RgbColor
|
||||
// ------------------------------------------------------------------------
|
||||
Rgb48Color(const RgbColor& color)
|
||||
{
|
||||
R = (color.R == 0) ? 0 : (color.R << 8 | 0xff);
|
||||
G = (color.G == 0) ? 0 : (color.G << 8 | 0xff);
|
||||
B = (color.B == 0) ? 0 : (color.B << 8 | 0xff);
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Construct a Rgb48Color using HtmlColor
|
||||
// ------------------------------------------------------------------------
|
||||
Rgb48Color(const HtmlColor& color)
|
||||
{
|
||||
*this = RgbColor(color);
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Construct a Rgb48Color using HslColor
|
||||
// ------------------------------------------------------------------------
|
||||
Rgb48Color(const HslColor& color);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Construct a Rgb48Color using HsbColor
|
||||
// ------------------------------------------------------------------------
|
||||
Rgb48Color(const HsbColor& color);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Construct a Rgb48Color that will have its values set in latter operations
|
||||
// CAUTION: The R,G,B members are not initialized and may not be consistent
|
||||
// ------------------------------------------------------------------------
|
||||
Rgb48Color()
|
||||
{
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Comparison operators
|
||||
// ------------------------------------------------------------------------
|
||||
bool operator==(const Rgb48Color& other) const
|
||||
{
|
||||
return (R == other.R && G == other.G && B == other.B);
|
||||
};
|
||||
|
||||
bool operator!=(const Rgb48Color& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// CalculateBrightness will calculate the overall brightness
|
||||
// NOTE: This is a simple linear brightness
|
||||
// ------------------------------------------------------------------------
|
||||
uint16_t CalculateBrightness() const;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Dim will return a new color that is blended to black with the given ratio
|
||||
// ratio - (0-65535) where 65535 will return the original color and 0 will return black
|
||||
//
|
||||
// NOTE: This is a simple linear blend
|
||||
// ------------------------------------------------------------------------
|
||||
Rgb48Color Dim(uint16_t ratio) const;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Brighten will return a new color that is blended to white with the given ratio
|
||||
// ratio - (0-65535) where 65535 will return the original color and 0 will return white
|
||||
//
|
||||
// NOTE: This is a simple linear blend
|
||||
// ------------------------------------------------------------------------
|
||||
Rgb48Color Brighten(uint16_t ratio) const;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Darken will adjust the color by the given delta toward black
|
||||
// NOTE: This is a simple linear change
|
||||
// delta - (0-65535) the amount to dim the color
|
||||
// ------------------------------------------------------------------------
|
||||
void Darken(uint16_t delta);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Lighten will adjust the color by the given delta toward white
|
||||
// NOTE: This is a simple linear change
|
||||
// delta - (0-65535) the amount to lighten the color
|
||||
// ------------------------------------------------------------------------
|
||||
void Lighten(uint16_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 Rgb48Color LinearBlend(const Rgb48Color& left, const Rgb48Color& 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 Rgb48Color BilinearBlend(const Rgb48Color& c00,
|
||||
const Rgb48Color& c01,
|
||||
const Rgb48Color& c10,
|
||||
const Rgb48Color& c11,
|
||||
float x,
|
||||
float y);
|
||||
|
||||
uint32_t CalcTotalTenthMilliAmpere(const SettingsObject& settings)
|
||||
{
|
||||
auto total = 0;
|
||||
|
||||
total += R * settings.RedTenthMilliAmpere / Max;
|
||||
total += G * settings.GreenTenthMilliAmpere / Max;
|
||||
total += B * settings.BlueTenthMilliAmpere / Max;
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Red, Green, Blue color members (0-65535) where
|
||||
// (0,0,0) is black and (65535,65535,65535) is white
|
||||
// ------------------------------------------------------------------------
|
||||
uint16_t R;
|
||||
uint16_t G;
|
||||
uint16_t B;
|
||||
|
||||
const static uint16_t Max = 65535;
|
||||
|
||||
private:
|
||||
inline static uint16_t _elementDim(uint16_t value, uint16_t ratio)
|
||||
{
|
||||
return (static_cast<uint32_t>(value) * (static_cast<uint32_t>(ratio) + 1)) >> 16;
|
||||
}
|
||||
|
||||
inline static uint16_t _elementBrighten(uint16_t value, uint16_t ratio)
|
||||
{
|
||||
uint32_t element = ((static_cast<uint32_t>(value) + 1) << 16) / (static_cast<uint32_t>(ratio) + 1);
|
||||
|
||||
if (element > Max)
|
||||
{
|
||||
element = Max;
|
||||
}
|
||||
else
|
||||
{
|
||||
element -= 1;
|
||||
}
|
||||
return element;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,186 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
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 "Rgb16Color.h"
|
||||
#include "Rgb48Color.h"
|
||||
#include "HslColor.h"
|
||||
#include "HsbColor.h"
|
||||
#include "HtmlColor.h"
|
||||
#include "RgbwColor.h"
|
||||
|
||||
RgbColor::RgbColor(const RgbwColor& color) :
|
||||
R(color.R),
|
||||
G(color.G),
|
||||
B(color.B)
|
||||
{
|
||||
};
|
||||
|
||||
RgbColor::RgbColor(const Rgb16Color& color)
|
||||
{
|
||||
R = color.getR();
|
||||
G = color.getG();
|
||||
B = color.getB();
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
_HslToRgb(color, &r, &g, &b);
|
||||
|
||||
R = static_cast<uint8_t>(r * Max);
|
||||
G = static_cast<uint8_t>(g * Max);
|
||||
B = static_cast<uint8_t>(b * Max);
|
||||
}
|
||||
|
||||
RgbColor::RgbColor(const HsbColor& color)
|
||||
{
|
||||
float r;
|
||||
float g;
|
||||
float b;
|
||||
|
||||
_HsbToRgb(color, &r, &g, &b);
|
||||
|
||||
R = static_cast<uint8_t>(r * Max);
|
||||
G = static_cast<uint8_t>(g * Max);
|
||||
B = static_cast<uint8_t>(b * Max);
|
||||
}
|
||||
|
||||
uint8_t RgbColor::CalculateBrightness() const
|
||||
{
|
||||
return static_cast<uint8_t>((static_cast<uint16_t>(R) + static_cast<uint16_t>(G) + static_cast<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 < Max - delta)
|
||||
{
|
||||
R += delta;
|
||||
}
|
||||
else
|
||||
{
|
||||
R = Max;
|
||||
}
|
||||
|
||||
if (G < Max - delta)
|
||||
{
|
||||
G += delta;
|
||||
}
|
||||
else
|
||||
{
|
||||
G = Max;
|
||||
}
|
||||
|
||||
if (B < Max - delta)
|
||||
{
|
||||
B += delta;
|
||||
}
|
||||
else
|
||||
{
|
||||
B = Max;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -0,0 +1,211 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
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"
|
||||
#include "RgbColorBase.h"
|
||||
|
||||
struct RgbwColor;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 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 : RgbColorBase
|
||||
{
|
||||
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)
|
||||
{
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// explicitly Construct a RgbColor using RgbwColor
|
||||
// ------------------------------------------------------------------------
|
||||
explicit RgbColor(const RgbwColor& color);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Construct a RgbColor using Rgb16Color
|
||||
// ------------------------------------------------------------------------
|
||||
RgbColor(const Rgb16Color& color);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 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 / Max;
|
||||
total += G * settings.GreenTenthMilliAmpere / Max;
|
||||
total += B * settings.BlueTenthMilliAmpere / Max;
|
||||
|
||||
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;
|
||||
|
||||
const static uint8_t Max = 255;
|
||||
|
||||
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 > Max)
|
||||
{
|
||||
element = Max;
|
||||
}
|
||||
else
|
||||
{
|
||||
element -= 1;
|
||||
}
|
||||
return element;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
RgbColorBase provides a RGB color object common 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 "RgbColorBase.h"
|
||||
#include "RgbColor.h"
|
||||
#include "Rgb48Color.h"
|
||||
#include "HslColor.h"
|
||||
#include "HsbColor.h"
|
||||
#include "HtmlColor.h"
|
||||
|
||||
float RgbColorBase::_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;
|
||||
}
|
||||
|
||||
void RgbColorBase::_HslToRgb(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);
|
||||
}
|
||||
}
|
||||
|
||||
void RgbColorBase::_HsbToRgb(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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
RgbColorBase provides a RGB color object common 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
|
||||
|
||||
struct HslColor;
|
||||
struct HsbColor;
|
||||
struct HtmlColor;
|
||||
struct Rgb16Color;
|
||||
|
||||
struct RgbColorBase
|
||||
{
|
||||
|
||||
protected:
|
||||
static float _CalcColor(float p, float q, float t);
|
||||
|
||||
static void _HslToRgb(const HslColor& color, float* r, float* g, float* b);
|
||||
|
||||
static void _HsbToRgb(const HsbColor& color, float* r, float* g, float* b);
|
||||
};
|
||||
@@ -0,0 +1,188 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
Rgbw64Color 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 "RgbwColor.h"
|
||||
#include "Rgb48Color.h"
|
||||
#include "HslColor.h"
|
||||
#include "HsbColor.h"
|
||||
#include "Rgbw64Color.h"
|
||||
#include "HtmlColor.h"
|
||||
|
||||
Rgbw64Color::Rgbw64Color(const RgbwColor& color)
|
||||
{
|
||||
R = (color.R == 0) ? 0 : (color.R << 8 | 0xff);
|
||||
G = (color.G == 0) ? 0 : (color.G << 8 | 0xff);
|
||||
B = (color.B == 0) ? 0 : (color.B << 8 | 0xff);
|
||||
W = (color.W == 0) ? 0 : (color.W << 8 | 0xff);
|
||||
};
|
||||
|
||||
Rgbw64Color::Rgbw64Color(const HslColor& color)
|
||||
{
|
||||
Rgb48Color rgbColor(color);
|
||||
*this = rgbColor;
|
||||
}
|
||||
|
||||
Rgbw64Color::Rgbw64Color(const HsbColor& color)
|
||||
{
|
||||
Rgb48Color rgbColor(color);
|
||||
*this = rgbColor;
|
||||
}
|
||||
|
||||
uint16_t Rgbw64Color::CalculateBrightness() const
|
||||
{
|
||||
uint16_t colorB = static_cast<uint16_t>((static_cast<uint32_t>(R) + static_cast<uint32_t>(G) + static_cast<uint32_t>(B)) / 3);
|
||||
if (W > colorB)
|
||||
{
|
||||
return W;
|
||||
}
|
||||
else
|
||||
{
|
||||
return colorB;
|
||||
}
|
||||
}
|
||||
|
||||
Rgbw64Color Rgbw64Color::Dim(uint16_t ratio) const
|
||||
{
|
||||
// specifically avoids float math
|
||||
return Rgbw64Color(_elementDim(R, ratio), _elementDim(G, ratio), _elementDim(B, ratio), _elementDim(W, ratio));
|
||||
}
|
||||
|
||||
Rgbw64Color Rgbw64Color::Brighten(uint16_t ratio) const
|
||||
{
|
||||
// specifically avoids float math
|
||||
return Rgbw64Color(_elementBrighten(R, ratio), _elementBrighten(G, ratio), _elementBrighten(B, ratio), _elementBrighten(W, ratio));
|
||||
}
|
||||
|
||||
void Rgbw64Color::Darken(uint16_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 Rgbw64Color::Lighten(uint16_t delta)
|
||||
{
|
||||
if (IsColorLess())
|
||||
{
|
||||
if (W < Max - delta)
|
||||
{
|
||||
W += delta;
|
||||
}
|
||||
else
|
||||
{
|
||||
W = Max;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (R < Max - delta)
|
||||
{
|
||||
R += delta;
|
||||
}
|
||||
else
|
||||
{
|
||||
R = Max;
|
||||
}
|
||||
|
||||
if (G < Max - delta)
|
||||
{
|
||||
G += delta;
|
||||
}
|
||||
else
|
||||
{
|
||||
G = Max;
|
||||
}
|
||||
|
||||
if (B < Max - delta)
|
||||
{
|
||||
B += delta;
|
||||
}
|
||||
else
|
||||
{
|
||||
B = Max;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rgbw64Color Rgbw64Color::LinearBlend(const Rgbw64Color& left, const Rgbw64Color& right, float progress)
|
||||
{
|
||||
return Rgbw64Color( 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) );
|
||||
}
|
||||
|
||||
Rgbw64Color Rgbw64Color::BilinearBlend(const Rgbw64Color& c00,
|
||||
const Rgbw64Color& c01,
|
||||
const Rgbw64Color& c10,
|
||||
const Rgbw64Color& 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 Rgbw64Color(
|
||||
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 );
|
||||
}
|
||||
@@ -0,0 +1,248 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
Rgbw64Color 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 RgbColor;
|
||||
struct HslColor;
|
||||
struct HsbColor;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Rgbw64Color 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 Rgbw64Color
|
||||
{
|
||||
typedef NeoRgbwCurrentSettings SettingsObject;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Construct a Rgbw64Color using R, G, B, W values (0-65535)
|
||||
// ------------------------------------------------------------------------
|
||||
Rgbw64Color(uint16_t r, uint16_t g, uint16_t b, uint16_t w = 0) :
|
||||
R(r), G(g), B(b), W(w)
|
||||
{
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Construct a RgbColor using a single brightness value (0-65535)
|
||||
// This works well for creating gray tone colors
|
||||
// (0) = black, (65535) = white, (32768) = gray
|
||||
// ------------------------------------------------------------------------
|
||||
Rgbw64Color(uint16_t brightness) :
|
||||
R(0), G(0), B(0), W(brightness)
|
||||
{
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Construct a Rgbw64Color using RgbColor
|
||||
// ------------------------------------------------------------------------
|
||||
Rgbw64Color(const RgbColor& color)
|
||||
{
|
||||
*this = Rgb48Color(color);
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Construct a Rgbw64Color using Rgb48Color
|
||||
// ------------------------------------------------------------------------
|
||||
Rgbw64Color(const Rgb48Color& color) :
|
||||
R(color.R),
|
||||
G(color.G),
|
||||
B(color.B),
|
||||
W(0)
|
||||
{
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Construct a Rgbw64Color using RgbwColor
|
||||
// ------------------------------------------------------------------------
|
||||
Rgbw64Color(const RgbwColor& color);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Construct a Rgbw64Color using HtmlColor
|
||||
// ------------------------------------------------------------------------
|
||||
Rgbw64Color(const HtmlColor& color)
|
||||
{
|
||||
*this = RgbwColor(color);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Construct a Rgbw64Color using HslColor
|
||||
// ------------------------------------------------------------------------
|
||||
Rgbw64Color(const HslColor& color);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Construct a Rgbw64Color using HsbColor
|
||||
// ------------------------------------------------------------------------
|
||||
Rgbw64Color(const HsbColor& color);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Construct a Rgbw64Color that will have its values set in latter operations
|
||||
// CAUTION: The R,G,B, W members are not initialized and may not be consistent
|
||||
// ------------------------------------------------------------------------
|
||||
Rgbw64Color()
|
||||
{
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Comparison operators
|
||||
// ------------------------------------------------------------------------
|
||||
bool operator==(const Rgbw64Color& other) const
|
||||
{
|
||||
return (R == other.R && G == other.G && B == other.B && W == other.W);
|
||||
};
|
||||
|
||||
bool operator!=(const Rgbw64Color& 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
|
||||
// ------------------------------------------------------------------------
|
||||
uint16_t CalculateBrightness() const;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Dim will return a new color that is blended to black with the given ratio
|
||||
// ratio - (0-65535) where 65535 will return the original color and 0 will return black
|
||||
//
|
||||
// NOTE: This is a simple linear blend
|
||||
// ------------------------------------------------------------------------
|
||||
Rgbw64Color Dim(uint16_t ratio) const;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Brighten will return a new color that is blended to white with the given ratio
|
||||
// ratio - (0-65535) where 65535 will return the original color and 0 will return white
|
||||
//
|
||||
// NOTE: This is a simple linear blend
|
||||
// ------------------------------------------------------------------------
|
||||
Rgbw64Color Brighten(uint16_t ratio) const;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Darken will adjust the color by the given delta toward black
|
||||
// NOTE: This is a simple linear change
|
||||
// delta - (0-65535) the amount to dim the color
|
||||
// ------------------------------------------------------------------------
|
||||
void Darken(uint16_t delta);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Lighten will adjust the color by the given delta toward white
|
||||
// NOTE: This is a simple linear change
|
||||
// delta - (0-65535) the amount to lighten the color
|
||||
// ------------------------------------------------------------------------
|
||||
void Lighten(uint16_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 Rgbw64Color LinearBlend(const Rgbw64Color& left, const Rgbw64Color& 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 Rgbw64Color BilinearBlend(const Rgbw64Color& c00,
|
||||
const Rgbw64Color& c01,
|
||||
const Rgbw64Color& c10,
|
||||
const Rgbw64Color& c11,
|
||||
float x,
|
||||
float y);
|
||||
|
||||
uint16_t CalcTotalTenthMilliAmpere(const SettingsObject& settings)
|
||||
{
|
||||
auto total = 0;
|
||||
|
||||
total += R * settings.RedTenthMilliAmpere / Max;
|
||||
total += G * settings.GreenTenthMilliAmpere / Max;
|
||||
total += B * settings.BlueTenthMilliAmpere / Max;
|
||||
total += W * settings.WhiteTenthMilliAmpere / Max;
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Red, Green, Blue, White color members (0-65535) where
|
||||
// (0,0,0,0) is black and (65535,65535,65535, 0) and (0,0,0,65535) is white
|
||||
// Note (65535,65535,65535,65535) is extreme bright white
|
||||
// ------------------------------------------------------------------------
|
||||
uint16_t R;
|
||||
uint16_t G;
|
||||
uint16_t B;
|
||||
uint16_t W;
|
||||
|
||||
const static uint16_t Max = 65535;
|
||||
|
||||
private:
|
||||
inline static uint16_t _elementDim(uint16_t value, uint16_t ratio)
|
||||
{
|
||||
return (static_cast<uint32_t>(value) * (static_cast<uint32_t>(ratio) + 1)) >> 16;
|
||||
}
|
||||
|
||||
inline static uint16_t _elementBrighten(uint16_t value, uint16_t ratio)
|
||||
{
|
||||
uint32_t element = ((static_cast<uint32_t>(value) + 1) << 16) / (static_cast<uint32_t>(ratio) + 1);
|
||||
|
||||
if (element > Max)
|
||||
{
|
||||
element = Max;
|
||||
}
|
||||
else
|
||||
{
|
||||
element -= 1;
|
||||
}
|
||||
return element;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,191 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
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 "Rgb48Color.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 = static_cast<uint8_t>((static_cast<uint16_t>(R) + static_cast<uint16_t>(G) + static_cast<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 );
|
||||
}
|
||||
@@ -0,0 +1,231 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
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 / Max;
|
||||
total += G * settings.GreenTenthMilliAmpere / Max;
|
||||
total += B * settings.BlueTenthMilliAmpere / Max;
|
||||
total += W * settings.WhiteTenthMilliAmpere / Max;
|
||||
|
||||
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;
|
||||
|
||||
const static uint8_t Max = 255;
|
||||
|
||||
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 > Max)
|
||||
{
|
||||
element = Max;
|
||||
}
|
||||
else
|
||||
{
|
||||
element -= 1;
|
||||
}
|
||||
return element;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
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, 0x7F, 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, 0x76, 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, bool maintainCase)
|
||||
{
|
||||
if (letter >= '0' && letter <= '9')
|
||||
{
|
||||
init(DecodeNumbers[letter - '0'], brightness, defaultBrightness);
|
||||
}
|
||||
else if (letter >= 'a' && letter <= 'z')
|
||||
{
|
||||
uint8_t index = letter - 'a';
|
||||
uint8_t bitmask = DecodeAlpha[index];
|
||||
if (!bitmask && !maintainCase)
|
||||
{
|
||||
bitmask = DecodeAlphaCaps[index];
|
||||
}
|
||||
init(bitmask, brightness, defaultBrightness);
|
||||
}
|
||||
else if (letter >= 'A' && letter <= 'Z')
|
||||
{
|
||||
uint8_t index = letter - 'A';
|
||||
uint8_t bitmask = DecodeAlphaCaps[index];
|
||||
if (!bitmask && !maintainCase)
|
||||
{
|
||||
bitmask = DecodeAlpha[index];
|
||||
}
|
||||
init(bitmask, 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 static_cast<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;
|
||||
}
|
||||
@@ -0,0 +1,267 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
SegmentDigit provides a color object that can be directly consumed by NeoPixelBus
|
||||
|
||||
Written by Michael C. Miller.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
enum LedSegment
|
||||
{
|
||||
LedSegment_A,
|
||||
LedSegment_B,
|
||||
LedSegment_C,
|
||||
LedSegment_D,
|
||||
LedSegment_E,
|
||||
LedSegment_F,
|
||||
LedSegment_G,
|
||||
LedSegment_Decimal, // maybe jumpered to alternate custom segment
|
||||
LedSegment_Custom, // generally not used but maybe connected to a custom segment
|
||||
LedSegment_COUNT
|
||||
};
|
||||
|
||||
class NeoSevenSegCurrentSettings
|
||||
{
|
||||
public:
|
||||
NeoSevenSegCurrentSettings(uint16_t segments, uint16_t decimal, uint16_t special = 0) :
|
||||
SegmentTenthMilliAmpere(segments),
|
||||
DecimalTenthMilliAmpere(decimal),
|
||||
SpecialTenthMilliAmpere(special)
|
||||
{
|
||||
}
|
||||
|
||||
uint16_t SegmentTenthMilliAmpere; // in 1/10th ma
|
||||
uint16_t DecimalTenthMilliAmpere; // in 1/10th ma
|
||||
uint16_t SpecialTenthMilliAmpere; // in 1/10th ma
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// SevenSegDigit represents a color object that is represented by the segments
|
||||
// of a 7 segment LED display digit. It contains helpful routines to manipulate
|
||||
// and set the elements.
|
||||
//
|
||||
// The order represents the physical LED location starting at A, through to G, then
|
||||
// ending at the decimal point
|
||||
// "abcdefg."
|
||||
// ------------------------------------------------------------------------
|
||||
struct SevenSegDigit
|
||||
{
|
||||
typedef NeoSevenSegCurrentSettings SettingsObject;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Construct a SevenSegDigit using
|
||||
// the default brightness to apply to all segments
|
||||
// ------------------------------------------------------------------------
|
||||
SevenSegDigit(uint8_t defaultBrightness)
|
||||
{
|
||||
memset(Segment, defaultBrightness, sizeof(Segment));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Construct a SevenSegDigit using
|
||||
// a bitmask for the segment (bit order is ".gfedcba")
|
||||
// the brightness to apply to them, (0-255)
|
||||
// the default brightness to apply to those not set in the bitmask (0-255)
|
||||
// ------------------------------------------------------------------------
|
||||
SevenSegDigit(uint8_t bitmask, uint8_t brightness, uint8_t defaultBrightness = 0);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Construct a SevenSegDigit using
|
||||
// a char that will get mapped to the segments,
|
||||
// the brightness to apply to them, (0-255)
|
||||
// the default brightness to apply to those not set in the bitmask (0-255)
|
||||
// ------------------------------------------------------------------------
|
||||
SevenSegDigit(char letter, uint8_t brightness, uint8_t defaultBrightness = 0, bool maintainCase = false);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Construct a SevenSegDigit that will have its values set in latter operations
|
||||
// CAUTION: The members are not initialized and may not be consistent
|
||||
// ------------------------------------------------------------------------
|
||||
SevenSegDigit()
|
||||
{
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Comparison operators
|
||||
// ------------------------------------------------------------------------
|
||||
bool operator==(const SevenSegDigit& other) const
|
||||
{
|
||||
for (uint8_t iSegment = 0; iSegment < SegmentCount; iSegment++)
|
||||
{
|
||||
if (Segment[iSegment] != other.Segment[iSegment])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
bool operator!=(const SevenSegDigit& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// CalculateBrightness will calculate the overall brightness
|
||||
// NOTE: This is a simple linear brightness
|
||||
// ------------------------------------------------------------------------
|
||||
uint8_t CalculateBrightness() const;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Darken will adjust the color by the given delta toward black
|
||||
// NOTE: This is a simple linear change
|
||||
// delta - (0-255) the amount to dim the segment
|
||||
// ------------------------------------------------------------------------
|
||||
void Darken(uint8_t delta);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Lighten will adjust the color by the given delta toward white
|
||||
// NOTE: This is a simple linear change
|
||||
// delta - (0-255) the amount to lighten the segment
|
||||
// ------------------------------------------------------------------------
|
||||
void Lighten(uint8_t delta);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// LinearBlend between two colors by the amount defined by progress variable
|
||||
// left - the segment to start the blend at
|
||||
// right - the segment to end the blend at
|
||||
// progress - (0.0 - 1.0) value where 0 will return left and 1.0 will return right
|
||||
// and a value between will blend the brightness of each element
|
||||
// weighted linearly between them
|
||||
// ------------------------------------------------------------------------
|
||||
static SevenSegDigit LinearBlend(const SevenSegDigit& left, const SevenSegDigit& right, float progress);
|
||||
|
||||
|
||||
uint32_t CalcTotalTenthMilliAmpere(const SettingsObject& settings)
|
||||
{
|
||||
auto total = 0;
|
||||
|
||||
for (uint8_t segment = LedSegment_A; segment < SegmentCount - 2; segment++)
|
||||
{
|
||||
total += Segment[segment] * settings.SegmentTenthMilliAmpere / Max;
|
||||
}
|
||||
|
||||
total += Segment[SegmentCount - 2] * settings.DecimalTenthMilliAmpere / Max;
|
||||
total += Segment[SegmentCount - 1] * settings.SpecialTenthMilliAmpere / Max;
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
template <typename T_SET_TARGET>
|
||||
static void SetString(T_SET_TARGET& target,
|
||||
uint16_t indexDigit,
|
||||
const char* str,
|
||||
uint8_t brightness,
|
||||
uint8_t defaultBrightness = 0)
|
||||
{
|
||||
if (str == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const char* pFirst = str;
|
||||
const char* pIter = str;
|
||||
|
||||
// digits are right to left
|
||||
// so find the end and start there
|
||||
while (*pIter != '\0')
|
||||
{
|
||||
pIter++;
|
||||
}
|
||||
pIter--;
|
||||
|
||||
|
||||
while (pIter >= pFirst)
|
||||
{
|
||||
bool decimal = false;
|
||||
bool special = false;
|
||||
char value = *pIter--;
|
||||
|
||||
// must always be merged by previous char
|
||||
// (the one to the right)
|
||||
// so if repeated ignore it
|
||||
//
|
||||
if (value == ':' || value == ';')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// check if merging a decimal with the next char is required
|
||||
// (the one to the left)
|
||||
//
|
||||
if (pIter >= pFirst && (value == '.' || value == ','))
|
||||
{
|
||||
// merge a decimal as long as they aren't the same
|
||||
if (*(pIter) != value)
|
||||
{
|
||||
decimal = true;
|
||||
value = *pIter--; // use the next char
|
||||
}
|
||||
}
|
||||
|
||||
// check next char for colon
|
||||
//
|
||||
if (pIter >= pFirst && (*pIter == ':' || *pIter == ';'))
|
||||
{
|
||||
// the colon is custom extension using the decimal AND the special
|
||||
// channels
|
||||
special = true;
|
||||
decimal = true;
|
||||
pIter--; // skip colon
|
||||
}
|
||||
|
||||
SevenSegDigit digit(value, brightness, defaultBrightness);
|
||||
if (decimal)
|
||||
{
|
||||
digit.Segment[LedSegment_Decimal] = brightness;
|
||||
}
|
||||
if (special)
|
||||
{
|
||||
digit.Segment[LedSegment_Custom] = brightness;
|
||||
}
|
||||
target.SetPixelColor(indexDigit, digit);
|
||||
indexDigit++;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// segment members (0-255) where each represents the segment location
|
||||
// and the value defines the brightnes (0) is off and (255) is full brightness
|
||||
// ------------------------------------------------------------------------
|
||||
static const uint8_t SegmentCount = 9;
|
||||
uint8_t Segment[SegmentCount];
|
||||
|
||||
const static uint8_t Max = 255;
|
||||
|
||||
// segment decode maps from ascii relative first char in map to a bitmask of segments
|
||||
//
|
||||
static const uint8_t DecodeNumbers[10]; // 0-9
|
||||
static const uint8_t DecodeAlphaCaps[26]; // A-Z
|
||||
static const uint8_t DecodeAlpha[26]; // a-z
|
||||
static const uint8_t DecodeSpecial[4]; // , - . /
|
||||
|
||||
protected:
|
||||
void init(uint8_t bitmask, uint8_t brightness, uint8_t defaultBrightness);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,214 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
NeoPixel library helper functions for Tlc5947 24 channel PWM controller using general Pins.
|
||||
|
||||
Written by Michael C. Miller.
|
||||
Written by Dennis Kasprzyk.
|
||||
|
||||
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
|
||||
|
||||
#define TLC5947_MODULE_PWM_CHANNEL_COUNT 24
|
||||
|
||||
class Tlc5947Converter8Bit
|
||||
{
|
||||
public:
|
||||
static const size_t sizeChannel = 1;
|
||||
static void ConvertFrame(uint8_t* sendBufferPtr, uint8_t* channelPtr)
|
||||
{
|
||||
// Write 2 channels into 3 bytes scaling 8-bit to 12-bit per channel
|
||||
for (int indexChannel = 0; indexChannel < TLC5947_MODULE_PWM_CHANNEL_COUNT; indexChannel += 2)
|
||||
{
|
||||
uint8_t ch1 = *channelPtr--;
|
||||
uint8_t ch2 = *channelPtr--;
|
||||
|
||||
*sendBufferPtr++ = ch1;
|
||||
*sendBufferPtr++ = (ch1 & 0xf0) | (ch2 >> 4);
|
||||
*sendBufferPtr++ = ((ch2 << 4) & 0xf0) | (ch2 >> 4);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class Tlc5947Converter16Bit
|
||||
{
|
||||
public:
|
||||
static const size_t sizeChannel = 2;
|
||||
static void ConvertFrame(uint8_t* sendBufferPtr, uint8_t* sourceBufferPtr)
|
||||
{
|
||||
uint16_t* channelPtr = (uint16_t*)sourceBufferPtr;
|
||||
|
||||
// Write 2 channels into 3 bytes using upper 12-bit of each channel
|
||||
for (int indexChannel = 0; indexChannel < TLC5947_MODULE_PWM_CHANNEL_COUNT; indexChannel += 2)
|
||||
{
|
||||
uint8_t ch1 = *channelPtr--;
|
||||
uint8_t ch2 = *channelPtr--;
|
||||
|
||||
*sendBufferPtr++ = ch1 >> 8;
|
||||
*sendBufferPtr++ = (ch1 & 0xf0) | (ch2 >> 12);
|
||||
*sendBufferPtr++ = ch2 >> 4;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename T_BITCONVERT, typename T_TWOWIRE> class Tlc5947MethodBase
|
||||
{
|
||||
public:
|
||||
typedef typename T_TWOWIRE::SettingsObject SettingsObject;
|
||||
|
||||
// 24 channel * 12 bit
|
||||
static const size_t sizeSendBuffer = 36;
|
||||
|
||||
Tlc5947MethodBase(uint8_t pinClock, uint8_t pinData, uint8_t pinLatch, uint8_t pinOutputEnable, uint16_t pixelCount, size_t elementSize, size_t settingsSize) :
|
||||
_countModule((pixelCount * elementSize + TLC5947_MODULE_PWM_CHANNEL_COUNT - 1) / TLC5947_MODULE_PWM_CHANNEL_COUNT),
|
||||
_sizeData(_countModule * TLC5947_MODULE_PWM_CHANNEL_COUNT + settingsSize),
|
||||
_wire(pinClock, pinData),
|
||||
_pinLatch(pinLatch),
|
||||
_pinOutputEnable(pinOutputEnable)
|
||||
{
|
||||
_data = static_cast<uint8_t*>(malloc(_sizeData));
|
||||
pinMode(pinLatch, OUTPUT);
|
||||
pinMode(pinOutputEnable, OUTPUT);
|
||||
digitalWrite(pinOutputEnable, HIGH);
|
||||
}
|
||||
|
||||
Tlc5947MethodBase(uint8_t pinClock, uint8_t pinData, uint8_t pinLatch, uint16_t pixelCount, size_t elementSize, size_t settingsSize) :
|
||||
Tlc5947MethodBase(pinClock, pinData, pinLatch, -1, pixelCount, elementSize, settingsSize)
|
||||
{
|
||||
}
|
||||
|
||||
#if !defined(__AVR_ATtiny85__) && !defined(ARDUINO_attiny)
|
||||
Tlc5947MethodBase(uint8_t pinLatch, uint8_t pinOutputEnable, uint16_t pixelCount, size_t elementSize, size_t settingsSize) :
|
||||
Tlc5947MethodBase(SCK, MOSI, pinLatch, pinOutputEnable, pixelCount, elementSize, settingsSize)
|
||||
{
|
||||
}
|
||||
|
||||
Tlc5947MethodBase(uint8_t pinLatch, uint16_t pixelCount, size_t elementSize, size_t settingsSize) :
|
||||
Tlc5947MethodBase(SCK, MOSI, pinLatch, -1, pixelCount, elementSize, settingsSize)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
~Tlc5947MethodBase()
|
||||
{
|
||||
free(_data);
|
||||
pinMode(_pinLatch, INPUT);
|
||||
pinMode(_pinOutputEnable, INPUT);
|
||||
}
|
||||
|
||||
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();
|
||||
memset(_data, 0, _sizeData);
|
||||
}
|
||||
|
||||
void Update(bool)
|
||||
{
|
||||
|
||||
digitalWrite(_pinOutputEnable, HIGH);
|
||||
|
||||
digitalWrite(_pinLatch, LOW);
|
||||
_wire.beginTransaction();
|
||||
|
||||
// We need to write the channels in reverse order. Get a Pointer to the last channel.
|
||||
uint8_t* lastChannelPtr = _data + ((_countModule * TLC5947_MODULE_PWM_CHANNEL_COUNT - 1) * T_BITCONVERT::sizeChannel);
|
||||
for (uint16_t countSend = 0; countSend < _countModule; countSend++)
|
||||
{
|
||||
// We pass a pointer to the last channel and ConvertFrame reads the channels backwards
|
||||
T_BITCONVERT::ConvertFrame(_sendBuffer, lastChannelPtr);
|
||||
_wire.transmitBytes(_sendBuffer, sizeSendBuffer);
|
||||
lastChannelPtr -= TLC5947_MODULE_PWM_CHANNEL_COUNT * T_BITCONVERT::sizeChannel;
|
||||
}
|
||||
|
||||
_wire.endTransaction();
|
||||
digitalWrite(_pinLatch, HIGH);
|
||||
digitalWrite(_pinLatch, LOW);
|
||||
digitalWrite(_pinOutputEnable, LOW);
|
||||
}
|
||||
|
||||
uint8_t* getData() const
|
||||
{
|
||||
return _data;
|
||||
};
|
||||
|
||||
size_t getDataSize() const
|
||||
{
|
||||
return _sizeData;
|
||||
};
|
||||
|
||||
void applySettings([[maybe_unused]] const SettingsObject& settings)
|
||||
{
|
||||
_wire.applySettings(settings);
|
||||
}
|
||||
|
||||
private:
|
||||
const uint16_t _countModule; // Number of tlc5947 modules
|
||||
const size_t _sizeData; // Size of '_data' buffer below
|
||||
|
||||
T_TWOWIRE _wire;
|
||||
uint8_t* _data; // Holds LED color values
|
||||
uint8_t _sendBuffer[sizeSendBuffer]; // Holds channel values for one module
|
||||
uint8_t _pinLatch;
|
||||
uint8_t _pinOutputEnable;
|
||||
};
|
||||
|
||||
typedef Tlc5947MethodBase<Tlc5947Converter8Bit, TwoWireBitBangImple> Tlc5947Method;
|
||||
typedef Tlc5947MethodBase<Tlc5947Converter16Bit, TwoWireBitBangImple> Tlc5947Method16Bit;
|
||||
|
||||
#if !defined(__AVR_ATtiny85__) && !defined(ARDUINO_attiny)
|
||||
#include "TwoWireSpiImple.h"
|
||||
|
||||
// for standalone
|
||||
typedef Tlc5947MethodBase<Tlc5947Converter8Bit, TwoWireSpiImple<SpiSpeed30Mhz>> Tlc5947Spi30MhzMethod;
|
||||
typedef Tlc5947MethodBase<Tlc5947Converter16Bit, TwoWireSpiImple<SpiSpeed30Mhz>> Tlc5947Spi30MhzMethod16Bit;
|
||||
|
||||
// for cascaded devices
|
||||
typedef Tlc5947MethodBase<Tlc5947Converter8Bit, TwoWireSpiImple<SpiSpeed15Mhz>> Tlc5947Spi15MhzMethod;
|
||||
typedef Tlc5947MethodBase<Tlc5947Converter16Bit, TwoWireSpiImple<SpiSpeed15Mhz>> Tlc5947Spi15MhzMethod16Bit;
|
||||
|
||||
typedef Tlc5947MethodBase<Tlc5947Converter8Bit, TwoWireSpiImple<SpiSpeed15Mhz>> Tlc5947SpiMethod;
|
||||
typedef Tlc5947MethodBase<Tlc5947Converter16Bit, TwoWireSpiImple<SpiSpeed15Mhz>> Tlc5947SpiMethod16Bit;
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
NeoPixel library helper functions for DotStars using general Pins (APA102/LPD8806).
|
||||
|
||||
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 TwoWireBitBangImple
|
||||
{
|
||||
public:
|
||||
typedef NeoNoSettings SettingsObject;
|
||||
|
||||
TwoWireBitBangImple(uint8_t pinClock, uint8_t pinData) :
|
||||
_pinClock(pinClock),
|
||||
_pinData(pinData)
|
||||
{
|
||||
pinMode(pinClock, OUTPUT);
|
||||
pinMode(pinData, OUTPUT);
|
||||
}
|
||||
|
||||
~TwoWireBitBangImple()
|
||||
{
|
||||
pinMode(_pinClock, INPUT);
|
||||
pinMode(_pinData, INPUT);
|
||||
}
|
||||
|
||||
void begin()
|
||||
{
|
||||
digitalWrite(_pinClock, LOW);
|
||||
digitalWrite(_pinData, LOW);
|
||||
}
|
||||
|
||||
void beginTransaction()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void endTransaction()
|
||||
{
|
||||
digitalWrite(_pinData, LOW);
|
||||
}
|
||||
|
||||
void transmitByte(uint8_t data)
|
||||
{
|
||||
for (int bit = 7; bit >= 0; bit--)
|
||||
{
|
||||
// set data bit on pin
|
||||
digitalWrite(_pinData, (data & 0x80) == 0x80 ? HIGH : LOW);
|
||||
|
||||
// set clock high as data is ready
|
||||
digitalWrite(_pinClock, HIGH);
|
||||
|
||||
data <<= 1;
|
||||
|
||||
// set clock low as data pin is changed
|
||||
digitalWrite(_pinClock, LOW);
|
||||
}
|
||||
}
|
||||
|
||||
void transmitBytes(const uint8_t* data, size_t dataSize)
|
||||
{
|
||||
const uint8_t* endData = data + dataSize;
|
||||
while (data < endData)
|
||||
{
|
||||
transmitByte(*data++);
|
||||
}
|
||||
}
|
||||
|
||||
void applySettings([[maybe_unused]] const SettingsObject& settings)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
const uint8_t _pinClock; // output pin number for clock line
|
||||
const uint8_t _pinData; // output pin number for data line
|
||||
};
|
||||
@@ -0,0 +1,118 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
NeoPixel library helper functions for DotStars using general Pins (APA102/LPD8806).
|
||||
|
||||
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 TwoWireBitBangImple
|
||||
{
|
||||
public:
|
||||
typedef NeoNoSettings SettingsObject;
|
||||
|
||||
TwoWireBitBangImple(uint8_t pinClock, uint8_t pinData) :
|
||||
_pinClock(pinClock),
|
||||
_pinData(pinData)
|
||||
{
|
||||
pinMode(pinClock, OUTPUT);
|
||||
pinMode(pinData, OUTPUT);
|
||||
|
||||
_portClock = portOutputRegister(digitalPinToPort(_pinClock));
|
||||
_pinMaskClock = digitalPinToBitMask(_pinClock);
|
||||
_portData = portOutputRegister(digitalPinToPort(_pinData));
|
||||
_pinMaskData = digitalPinToBitMask(_pinData);
|
||||
}
|
||||
|
||||
~TwoWireBitBangImple()
|
||||
{
|
||||
pinMode(_pinClock, INPUT);
|
||||
pinMode(_pinData, INPUT);
|
||||
}
|
||||
|
||||
void begin()
|
||||
{
|
||||
digitalWrite(_pinClock, LOW);
|
||||
digitalWrite(_pinData, LOW);
|
||||
}
|
||||
|
||||
void beginTransaction()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void endTransaction()
|
||||
{
|
||||
digitalWrite(_pinData, LOW);
|
||||
}
|
||||
|
||||
void transmitByte(uint8_t data)
|
||||
{
|
||||
for (int bit = 7; bit >= 0; bit--)
|
||||
{
|
||||
// set data bit on pin
|
||||
// digitalWrite(_pinData, (data & 0x80) == 0x80 ? HIGH : LOW);
|
||||
if (data & 0x80)
|
||||
{
|
||||
*_portData |= _pinMaskData;
|
||||
}
|
||||
else
|
||||
{
|
||||
*_portData &= ~_pinMaskData;
|
||||
}
|
||||
|
||||
// set clock high as data is ready
|
||||
// digitalWrite(_pinClock, HIGH);
|
||||
*_portClock |= _pinMaskClock;
|
||||
|
||||
data <<= 1;
|
||||
|
||||
// set clock low as data pin is changed
|
||||
// digitalWrite(_pinClock, LOW);
|
||||
*_portClock &= ~_pinMaskClock;
|
||||
}
|
||||
}
|
||||
|
||||
void transmitBytes(const uint8_t* data, size_t dataSize)
|
||||
{
|
||||
const uint8_t* endData = data + dataSize;
|
||||
while (data < endData)
|
||||
{
|
||||
transmitByte(*data++);
|
||||
}
|
||||
}
|
||||
|
||||
void applySettings([[maybe_unused]] const SettingsObject& settings)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
const uint8_t _pinClock; // output pin number for clock line
|
||||
const uint8_t _pinData; // output pin number for data line
|
||||
|
||||
volatile uint8_t* _portData; // Output PORT register
|
||||
uint8_t _pinMaskData; // Output PORT bitmask
|
||||
volatile uint8_t* _portClock; // Output PORT register
|
||||
uint8_t _pinMaskClock; // Output PORT bitmask
|
||||
};
|
||||
@@ -0,0 +1,92 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
NeoPixel library helper functions for DotStars using ESP32's alternate SPI (HSPI) (APA102/LPD8806).
|
||||
|
||||
Written by Michael C. Miller.
|
||||
Minor changes adapting TwoWireSpiImple to support HSPI by Louis Beaudoin (Pixelvation)
|
||||
|
||||
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 <SPI.h>
|
||||
|
||||
template<typename T_SPISPEED> class TwoWireHspiImple
|
||||
{
|
||||
public:
|
||||
typedef typename T_SPISPEED::SettingsObject SettingsObject;
|
||||
|
||||
TwoWireHspiImple(uint8_t, uint8_t) // clock and data pins ignored for hardware SPI
|
||||
{
|
||||
_hspi = new SPIClass(HSPI);
|
||||
}
|
||||
|
||||
~TwoWireHspiImple()
|
||||
{
|
||||
_hspi->end();
|
||||
delete _hspi;
|
||||
}
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP32)
|
||||
// for cases where hardware SPI can have pins changed
|
||||
void begin(int8_t sck, int8_t miso, int8_t mosi, int8_t ss)
|
||||
{
|
||||
_hspi->begin(sck, miso, mosi, ss);
|
||||
}
|
||||
#endif
|
||||
|
||||
void begin()
|
||||
{
|
||||
_hspi->begin();
|
||||
}
|
||||
|
||||
void beginTransaction()
|
||||
{
|
||||
_hspi->beginTransaction(SPISettings(_speed.Clock, MSBFIRST, SPI_MODE0));
|
||||
}
|
||||
|
||||
void endTransaction()
|
||||
{
|
||||
_hspi->endTransaction();
|
||||
}
|
||||
|
||||
void transmitByte(uint8_t data)
|
||||
{
|
||||
_hspi->transfer(data);
|
||||
}
|
||||
|
||||
void transmitBytes(const uint8_t* data, size_t dataSize)
|
||||
{
|
||||
// ESPs have a method to write without inplace overwriting the send buffer
|
||||
// since we don't care what gets received, use it for performance
|
||||
// FIX: but for what ever reason on Esp32, its not const
|
||||
_hspi->writeBytes(const_cast<uint8_t*>(data), dataSize);
|
||||
}
|
||||
|
||||
void applySettings([[maybe_unused]] const SettingsObject& settings)
|
||||
{
|
||||
_speed.applySettings(settings);
|
||||
}
|
||||
|
||||
private:
|
||||
SPIClass * _hspi = NULL;
|
||||
T_SPISPEED _speed;
|
||||
};
|
||||
@@ -0,0 +1,225 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
NeoPixel library helper functions for DotStars using SPI (APA102/LPD8806).
|
||||
|
||||
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 <SPI.h>
|
||||
|
||||
class SpiSpeed40Mhz
|
||||
{
|
||||
public:
|
||||
typedef NeoNoSettings SettingsObject;
|
||||
SpiSpeed40Mhz() {};
|
||||
|
||||
static void applySettings([[maybe_unused]] const SettingsObject& settings) {}
|
||||
|
||||
static const uint32_t Clock = 40000000L;
|
||||
};
|
||||
|
||||
class SpiSpeed30Mhz
|
||||
{
|
||||
public:
|
||||
typedef NeoNoSettings SettingsObject;
|
||||
SpiSpeed30Mhz() {};
|
||||
|
||||
static void applySettings([[maybe_unused]] const SettingsObject& settings) {}
|
||||
|
||||
static const uint32_t Clock = 30000000L;
|
||||
};
|
||||
|
||||
class SpiSpeed20Mhz
|
||||
{
|
||||
public:
|
||||
typedef NeoNoSettings SettingsObject;
|
||||
SpiSpeed20Mhz() {};
|
||||
|
||||
static void applySettings([[maybe_unused]] const SettingsObject& settings) {}
|
||||
|
||||
static const uint32_t Clock = 20000000L;
|
||||
};
|
||||
|
||||
class SpiSpeed15Mhz
|
||||
{
|
||||
public:
|
||||
typedef NeoNoSettings SettingsObject;
|
||||
SpiSpeed15Mhz() {};
|
||||
|
||||
static void applySettings([[maybe_unused]] const SettingsObject& settings) {}
|
||||
|
||||
static const uint32_t Clock = 15000000L;
|
||||
};
|
||||
|
||||
class SpiSpeed10Mhz
|
||||
{
|
||||
public:
|
||||
typedef NeoNoSettings SettingsObject;
|
||||
SpiSpeed10Mhz() {};
|
||||
|
||||
static void applySettings([[maybe_unused]] const SettingsObject& settings) {}
|
||||
|
||||
static const uint32_t Clock = 10000000L;
|
||||
};
|
||||
|
||||
class SpiSpeed5Mhz
|
||||
{
|
||||
public:
|
||||
typedef NeoNoSettings SettingsObject;
|
||||
SpiSpeed5Mhz() {};
|
||||
|
||||
static void applySettings([[maybe_unused]] const SettingsObject& settings) {}
|
||||
|
||||
static const uint32_t Clock = 5000000L;
|
||||
};
|
||||
|
||||
class SpiSpeed2Mhz
|
||||
{
|
||||
public:
|
||||
typedef NeoNoSettings SettingsObject;
|
||||
SpiSpeed2Mhz() {};
|
||||
|
||||
static void applySettings([[maybe_unused]] const SettingsObject& settings) {}
|
||||
|
||||
static const uint32_t Clock = 2000000L;
|
||||
};
|
||||
|
||||
class SpiSpeed1Mhz
|
||||
{
|
||||
public:
|
||||
typedef NeoNoSettings SettingsObject;
|
||||
SpiSpeed1Mhz() {};
|
||||
|
||||
static void applySettings([[maybe_unused]] const SettingsObject& settings) {}
|
||||
|
||||
static const uint32_t Clock = 1000000L;
|
||||
};
|
||||
|
||||
class SpiSpeed500Khz
|
||||
{
|
||||
public:
|
||||
typedef NeoNoSettings SettingsObject;
|
||||
SpiSpeed500Khz() {};
|
||||
|
||||
static void applySettings([[maybe_unused]] const SettingsObject& settings) {}
|
||||
|
||||
static const uint32_t Clock = 500000L;
|
||||
};
|
||||
|
||||
class NeoSpiSettings
|
||||
{
|
||||
public:
|
||||
NeoSpiSettings(uint32_t clock) :
|
||||
Clock(clock)
|
||||
{
|
||||
}
|
||||
uint32_t Clock;
|
||||
};
|
||||
|
||||
class SpiSpeedHz
|
||||
{
|
||||
public:
|
||||
typedef NeoSpiSettings SettingsObject;
|
||||
|
||||
SpiSpeedHz() :
|
||||
Clock(10000000)
|
||||
{};
|
||||
|
||||
void applySettings([[maybe_unused]] const SettingsObject& settings)
|
||||
{
|
||||
Clock = settings.Clock;
|
||||
}
|
||||
|
||||
uint32_t Clock;
|
||||
};
|
||||
|
||||
template<typename T_SPISPEED> class TwoWireSpiImple
|
||||
{
|
||||
public:
|
||||
typedef typename T_SPISPEED::SettingsObject SettingsObject;
|
||||
|
||||
TwoWireSpiImple(uint8_t, uint8_t) // clock and data pins ignored for hardware SPI
|
||||
{
|
||||
}
|
||||
|
||||
~TwoWireSpiImple()
|
||||
{
|
||||
SPI.end();
|
||||
}
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP32)
|
||||
// for cases where hardware SPI can have pins changed
|
||||
void begin(int8_t sck, int8_t miso, int8_t mosi, int8_t ss)
|
||||
{
|
||||
SPI.begin(sck, miso, mosi, ss);
|
||||
}
|
||||
#endif
|
||||
|
||||
void begin()
|
||||
{
|
||||
SPI.begin();
|
||||
}
|
||||
|
||||
void beginTransaction()
|
||||
{
|
||||
SPI.beginTransaction(SPISettings(_speed.Clock, MSBFIRST, SPI_MODE0));
|
||||
}
|
||||
|
||||
void endTransaction()
|
||||
{
|
||||
SPI.endTransaction();
|
||||
}
|
||||
|
||||
void transmitByte(uint8_t data)
|
||||
{
|
||||
SPI.transfer(data);
|
||||
}
|
||||
|
||||
void transmitBytes(const uint8_t* data, size_t dataSize)
|
||||
{
|
||||
#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
|
||||
// ESPs have a method to write without inplace overwriting the send buffer
|
||||
// since we don't care what gets received, use it for performance
|
||||
// FIX: but for what ever reason on Esp32, its not const
|
||||
SPI.writeBytes(const_cast<uint8_t*>(data), dataSize);
|
||||
|
||||
#else
|
||||
// default ARDUINO transfer inplace overwrites the send buffer
|
||||
// which is bad in this case, so we have to send one byte at a time
|
||||
const uint8_t* endData = data + dataSize;
|
||||
while (data < endData)
|
||||
{
|
||||
SPI.transfer(*data++);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void applySettings([[maybe_unused]] const SettingsObject& settings)
|
||||
{
|
||||
_speed.applySettings(settings);
|
||||
}
|
||||
|
||||
private:
|
||||
T_SPISPEED _speed;
|
||||
};
|
||||
@@ -0,0 +1,145 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
NeoPixel library helper functions for WS2801
|
||||
|
||||
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 Ws2801MethodBase
|
||||
{
|
||||
public:
|
||||
typedef typename T_TWOWIRE::SettingsObject SettingsObject;
|
||||
|
||||
Ws2801MethodBase(uint8_t pinClock, uint8_t pinData, uint16_t pixelCount, size_t elementSize, size_t settingsSize) :
|
||||
_sizeData(pixelCount * elementSize + settingsSize),
|
||||
_wire(pinClock, pinData)
|
||||
{
|
||||
_data = static_cast<uint8_t*>(malloc(_sizeData));
|
||||
// data cleared later in Begin()
|
||||
}
|
||||
|
||||
#if !defined(__AVR_ATtiny85__) && !defined(ARDUINO_attiny)
|
||||
Ws2801MethodBase(uint16_t pixelCount, size_t elementSize, size_t settingsSize) :
|
||||
Ws2801MethodBase(SCK, MOSI, pixelCount, elementSize, settingsSize)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
~Ws2801MethodBase()
|
||||
{
|
||||
free(_data);
|
||||
}
|
||||
|
||||
bool IsReadyToUpdate() const
|
||||
{
|
||||
uint32_t delta = micros() - _endTime;
|
||||
|
||||
return (delta >= 500);
|
||||
}
|
||||
|
||||
#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);
|
||||
|
||||
_endTime = micros();
|
||||
}
|
||||
#endif
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
_wire.begin();
|
||||
|
||||
_endTime = micros();
|
||||
}
|
||||
|
||||
void Update(bool)
|
||||
{
|
||||
while (!IsReadyToUpdate())
|
||||
{
|
||||
#if !defined(ARDUINO_TEEONARDU_LEO) && !defined(ARDUINO_TEEONARDU_FLORA)
|
||||
yield(); // allows for system yield if needed
|
||||
#endif
|
||||
}
|
||||
|
||||
_wire.beginTransaction();
|
||||
|
||||
// data
|
||||
_wire.transmitBytes(_data, _sizeData);
|
||||
|
||||
_wire.endTransaction();
|
||||
|
||||
// save EOD time for latch on next call
|
||||
_endTime = micros();
|
||||
}
|
||||
|
||||
uint8_t* getData() const
|
||||
{
|
||||
return _data;
|
||||
};
|
||||
|
||||
size_t getDataSize() const
|
||||
{
|
||||
return _sizeData;
|
||||
};
|
||||
|
||||
void applySettings([[maybe_unused]] const SettingsObject& settings)
|
||||
{
|
||||
_wire.applySettings(settings);
|
||||
}
|
||||
|
||||
private:
|
||||
const size_t _sizeData; // Size of '_data' buffer below
|
||||
|
||||
uint32_t _endTime; // Latch timing reference
|
||||
T_TWOWIRE _wire;
|
||||
uint8_t* _data; // Holds LED color values
|
||||
};
|
||||
|
||||
typedef Ws2801MethodBase<TwoWireBitBangImple> NeoWs2801Method;
|
||||
|
||||
#if !defined(__AVR_ATtiny85__) && !defined(ARDUINO_attiny)
|
||||
#include "TwoWireSpiImple.h"
|
||||
typedef Ws2801MethodBase<TwoWireSpiImple<SpiSpeed20Mhz>> NeoWs2801Spi20MhzMethod;
|
||||
typedef Ws2801MethodBase<TwoWireSpiImple<SpiSpeed10Mhz>> NeoWs2801Spi10MhzMethod;
|
||||
typedef Ws2801MethodBase<TwoWireSpiImple<SpiSpeed5Mhz>> NeoWs2801Spi5MhzMethod;
|
||||
typedef Ws2801MethodBase<TwoWireSpiImple<SpiSpeed2Mhz>> NeoWs2801Spi2MhzMethod;
|
||||
typedef Ws2801MethodBase<TwoWireSpiImple<SpiSpeed1Mhz>> NeoWs2801Spi1MhzMethod;
|
||||
typedef Ws2801MethodBase<TwoWireSpiImple<SpiSpeed500Khz>> NeoWs2801Spi500KhzMethod;
|
||||
|
||||
typedef Ws2801MethodBase<TwoWireSpiImple<SpiSpeedHz>> NeoWs2801SpiHzMethod;
|
||||
|
||||
typedef NeoWs2801Spi10MhzMethod NeoWs2801SpiMethod;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user