first compile

This commit is contained in:
Michael Miller
2024-04-08 15:58:07 -07:00
parent b8f33709aa
commit 6711f5d823
6 changed files with 229 additions and 248 deletions

View File

@@ -43,7 +43,8 @@ const uint16_t PixelIndex_OutOfBounds = 0xffff;
#include "internal/NeoMethods.h" #include "internal/NeoMethods.h"
template<typename T_COLOR_FEATURE, typename T_METHOD> class NeoPixelBus template<typename T_COLOR_FEATURE, typename T_METHOD>
class NeoPixelBus
{ {
public: public:
// Constructor: number of LEDs, pin number // Constructor: number of LEDs, pin number

View File

@@ -28,7 +28,9 @@ License along with NeoPixel. If not, see
#include "NeoPixelBus.h" #include "NeoPixelBus.h"
// // T_EXPOSED_COLOR_OBJECT-
// The color object to use for the front buffer, does not need to match the
// T_COLOR_FEATURE::ColorObject but must be auto-converted, so no loss of data
// //
// T_GAMMA - // T_GAMMA -
// NeoGammaEquationMethod // NeoGammaEquationMethod
@@ -37,44 +39,30 @@ License along with NeoPixel. If not, see
// NeoGammaNullMethod // NeoGammaNullMethod
// NeoGammaInvert<one of the above> // NeoGammaInvert<one of the above>
template<typename T_COLOR_FEATURE, typename T_METHOD, typename T_GAMMA = NeoGammaEquationMethod> class NeoPixelBusLg : template<typename T_COLOR_FEATURE,
public NeoPixelBus<T_COLOR_FEATURE, T_METHOD> typename T_METHOD,
typename T_EXPOSED_COLOR_OBJECT, // = T_COLOR_FEATURE::ColorObject,
typename T_GAMMA = NeoGammaEquationMethod>
class NeoPixelBusLg
{ {
public: public:
class LuminanceShader class LuminanceShader
{ {
public: public:
LuminanceShader(uint8_t luminance = 255) : LuminanceShader(typename T_EXPOSED_COLOR_OBJECT::ElementType luminance = T_EXPOSED_COLOR_OBJECT::Max) :
_luminance(luminance) _luminance(luminance)
{ {
} }
// our shader is always dirty, but these are needed for standard typename T_COLOR_FEATURE::ColorObject Apply(const T_EXPOSED_COLOR_OBJECT& original) const
// shader support
bool IsDirty() const
{
return true;
};
void Dirty()
{
};
void ResetDirty()
{
};
typename T_COLOR_FEATURE::ColorObject Apply(uint16_t, const typename T_COLOR_FEATURE::ColorObject& original)
{ {
// dim and then return gamma adjusted // dim and then return gamma adjusted
typename T_COLOR_FEATURE::ColorObject color = original.Dim(_luminance); typename T_COLOR_FEATURE::ColorObject color(original.Dim(_luminance));
return NeoGamma<T_GAMMA>::Correct(color); return NeoGamma<T_GAMMA>::Correct(color);
} }
protected: protected:
uint8_t _luminance; bool setLuminance(typename T_EXPOSED_COLOR_OBJECT::ElementType luminance)
bool setLuminance(uint8_t luminance)
{ {
bool different = (_luminance != luminance); bool different = (_luminance != luminance);
@@ -86,117 +74,188 @@ public:
return different; return different;
} }
uint8_t getLuminance() const typename T_EXPOSED_COLOR_OBJECT::ElementType getLuminance() const
{ {
return _luminance; return _luminance;
} }
friend class NeoPixelBusLg; friend class NeoPixelBusLg;
};
// Exposed Shader instance for use with NeoDib.Render like private:
// typename T_EXPOSED_COLOR_OBJECT::ElementType _luminance;
// image.Render<NeoGrbFeature, MyBusType::LuminanceShader>(strip, strip.Shader); };
// where MyBusType is defined like
// typedef NeoPixelBusLg<NeoGrbFeature, NeoWs2812xMethod> MyBusType;
//
LuminanceShader Shader;
public: public:
NeoPixelBusLg(uint16_t countPixels, uint8_t pin) : NeoPixelBusLg(uint16_t countPixels, uint8_t pin) :
NeoPixelBus<T_COLOR_FEATURE, T_METHOD>(countPixels, pin), _countPixels(countPixels),
Shader() _pixels(nullptr),
_method(pin, countPixels, T_COLOR_FEATURE::PixelSize, T_COLOR_FEATURE::SettingsSize),
_shader()
{ {
} }
NeoPixelBusLg(uint16_t countPixels, uint8_t pin, NeoBusChannel channel) : NeoPixelBusLg(uint16_t countPixels, uint8_t pin, NeoBusChannel channel) :
NeoPixelBus<T_COLOR_FEATURE, T_METHOD>(countPixels, pin, channel), _countPixels(countPixels),
Shader() _pixels(nullptr),
_method(pin, countPixels, T_COLOR_FEATURE::PixelSize, T_COLOR_FEATURE::SettingsSize, channel),
_shader()
{ {
} }
NeoPixelBusLg(uint16_t countPixels, uint8_t pinClock, uint8_t pinData) : NeoPixelBusLg(uint16_t countPixels, uint8_t pinClock, uint8_t pinData) :
NeoPixelBus<T_COLOR_FEATURE, T_METHOD>(countPixels, pinClock, pinData), _countPixels(countPixels),
Shader() _pixels(nullptr),
_method(pinClock, pinData, countPixels, T_COLOR_FEATURE::PixelSize, T_COLOR_FEATURE::SettingsSize),
_shader()
{ {
} }
NeoPixelBusLg(uint16_t countPixels, uint8_t pinClock, uint8_t pinData, uint8_t pinLatch, uint8_t pinOutputEnable = NOT_A_PIN) : NeoPixelBusLg(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), _countPixels(countPixels),
Shader() _pixels(nullptr),
_method(pinClock, pinData, pinLatch, pinOutputEnable, countPixels, T_COLOR_FEATURE::PixelSize, T_COLOR_FEATURE::SettingsSize),
_shader()
{ {
} }
NeoPixelBusLg(uint16_t countPixels) : NeoPixelBusLg(uint16_t countPixels) :
NeoPixelBus<T_COLOR_FEATURE, T_METHOD>(countPixels), _countPixels(countPixels),
Shader() _pixels(nullptr),
_method(countPixels, T_COLOR_FEATURE::PixelSize, T_COLOR_FEATURE::SettingsSize),
_shader()
{ {
} }
NeoPixelBusLg(uint16_t countPixels, Stream* pixieStream) : NeoPixelBusLg(uint16_t countPixels, Stream* pixieStream) :
NeoPixelBus<T_COLOR_FEATURE, T_METHOD>(countPixels, pixieStream), _countPixels(countPixels),
Shader() _pixels(nullptr),
_method(countPixels, T_COLOR_FEATURE::PixelSize, T_COLOR_FEATURE::SettingsSize, pixieStream),
_shader()
{ {
} }
~NeoPixelBusLg() ~NeoPixelBusLg()
{ {
delete [] _pixels;
} }
void SetLuminance(uint8_t luminance) void Begin()
{ {
// does NOT affect current pixel data as there is no safe way _method.Initialize();
// to reconstruct the original color values after being _initialize();
// modified with both luminance and gamma without storing them }
if (Shader.setLuminance(luminance))
// used by DotStarSpiMethod/DotStarEsp32DmaSpiMethod if pins can be configured
void Begin(int8_t sck, int8_t miso, int8_t mosi, int8_t ss)
{ {
this->Dirty(); _method.Initialize(sck, miso, mosi, ss);
_initialize();
}
// 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);
_initialize();
}
// used by DotStarEsp32DmaSpiMethod if pins can be configured - reordered and extended version supporting oct SPI
void Begin(int8_t sck, int8_t dat0, int8_t dat1, int8_t dat2, int8_t dat3, int8_t dat4, int8_t dat5, int8_t dat6, int8_t dat7, int8_t ss)
{
_method.Initialize(sck, dat0, dat1, dat2, dat3, dat4, dat5, dat6, dat7, ss);
_initialize();
}
void SetFeatureSettings(const typename T_COLOR_FEATURE::SettingsObject& settings)
{
_featureSettings = settings;
}
void SetMethodSettings(const typename T_METHOD::SettingsObject& settings)
{
_method.applySettings(settings);
}
void Show()
{
_method.template Update<T_EXPOSED_COLOR_OBJECT, T_COLOR_FEATURE, LuminanceShader>(_pixels,
_countPixels,
_featureSettings,
_shader);
}
inline bool CanShow() const
{
return _method.IsReadyToUpdate();
}
uint16_t PixelCount() const
{
return _countPixels;
}
void SetLuminance(typename T_EXPOSED_COLOR_OBJECT::ElementType luminance)
{
_shader.setLuminance(luminance);
}
typename T_EXPOSED_COLOR_OBJECT::ElementType GetLuminance() const
{
return _shader.getLuminance();
}
void SetPixelColor(uint16_t indexPixel, const T_EXPOSED_COLOR_OBJECT& color)
{
if (indexPixel < _countPixels)
{
_pixels[indexPixel] = color;
} }
} }
uint8_t GetLuminance() const T_EXPOSED_COLOR_OBJECT GetPixelColor(uint16_t indexPixel) const
{ {
return Shader.getLuminance(); if (indexPixel >= _countPixels)
{
return 0;
}
return _pixels[indexPixel];
} }
void SetPixelColor(uint16_t indexPixel, typename T_COLOR_FEATURE::ColorObject color) void ClearTo(const T_EXPOSED_COLOR_OBJECT& color)
{ {
color = Shader.Apply(indexPixel, color); ClearTo(color, 0, _countPixels - 1);
NeoPixelBus<T_COLOR_FEATURE, T_METHOD>::SetPixelColor(indexPixel, color);
} }
/* void ClearTo(const T_EXPOSED_COLOR_OBJECT& color, uint16_t first, uint16_t last)
GetPixelColor is not overloaded as the original will be used
to just return the fully adjusted color value directly with
no reverse conversion since it is fraught with inaccuracy
*/
void ClearTo(typename T_COLOR_FEATURE::ColorObject color)
{ {
color = Shader.Apply(0, color); if (first < _countPixels &&
NeoPixelBus<T_COLOR_FEATURE, T_METHOD>::ClearTo(color); last < _countPixels &&
}; first <= last)
void ClearTo(typename T_COLOR_FEATURE::ColorObject color, uint16_t first, uint16_t last)
{ {
color = Shader.Apply(0, color); T_EXPOSED_COLOR_OBJECT* pixels = _pixels + last + 1;
NeoPixelBus<T_COLOR_FEATURE, T_METHOD>::ClearTo(color, first, last); T_EXPOSED_COLOR_OBJECT* pixelsFirst = _pixels + first;
while (pixelsFirst <= --pixels)
{
*pixels = color;
}
}
} }
// if the Pixels buffer is manipulated directly, then this can be called // TODO: Move other modification methods over
// to apply the luminance and gamma correction to those changes
void ApplyPostAdjustments() protected:
const uint16_t _countPixels;
T_EXPOSED_COLOR_OBJECT* _pixels;
T_METHOD _method;
LuminanceShader _shader;
typename T_COLOR_FEATURE::SettingsObject _featureSettings;
void _initialize()
{ {
if (this->IsDirty()) _pixels = new T_EXPOSED_COLOR_OBJECT[_countPixels];
{ ClearTo(0);
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);
color = Shader.Apply(indexPixel, color);
NeoPixelBus<T_COLOR_FEATURE, T_METHOD>::SetPixelColor(indexPixel, color);
}
this->Dirty();
}
} }
}; };

View File

@@ -39,12 +39,13 @@ struct Rgbww80Color;
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
struct RgbColor : RgbColorBase struct RgbColor : RgbColorBase
{ {
typedef uint8_t ElementType;
typedef NeoRgbCurrentSettings SettingsObject; typedef NeoRgbCurrentSettings SettingsObject;
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Construct a RgbColor using R, G, B values (0-255) // Construct a RgbColor using R, G, B values (0-255)
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
RgbColor(uint8_t r, uint8_t g, uint8_t b) : RgbColor(ElementType r, ElementType g, ElementType b) :
R(r), G(g), B(b) R(r), G(g), B(b)
{ {
}; };
@@ -54,7 +55,7 @@ struct RgbColor : RgbColorBase
// This works well for creating gray tone colors // This works well for creating gray tone colors
// (0) = black, (255) = white, (128) = gray // (0) = black, (255) = white, (128) = gray
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
RgbColor(uint8_t brightness) : RgbColor(ElementType brightness) :
R(brightness), G(brightness), B(brightness) R(brightness), G(brightness), B(brightness)
{ {
}; };
@@ -139,7 +140,7 @@ struct RgbColor : RgbColorBase
// negative - this is less than other // negative - this is less than other
// positive - this is greater than other // positive - this is greater than other
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
int16_t CompareTo(const RgbColor& other, uint8_t epsilon = 1) int16_t CompareTo(const RgbColor& other, ElementType epsilon = 1)
{ {
return _Compare<RgbColor, int16_t>(*this, other, epsilon); return _Compare<RgbColor, int16_t>(*this, other, epsilon);
} }
@@ -152,7 +153,7 @@ struct RgbColor : RgbColorBase
// negative - left is less than right // negative - left is less than right
// positive - left is greater than right // positive - left is greater than right
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
static int16_t Compare(const RgbColor& left, const RgbColor& right, uint8_t epsilon = 1) static int16_t Compare(const RgbColor& left, const RgbColor& right, ElementType epsilon = 1)
{ {
return _Compare<RgbColor, int16_t>(left, right, epsilon); return _Compare<RgbColor, int16_t>(left, right, epsilon);
} }
@@ -162,7 +163,7 @@ struct RgbColor : RgbColorBase
// access elements in order by index rather than R,G,B // access elements in order by index rather than R,G,B
// see static Count for the number of elements // see static Count for the number of elements
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
uint8_t operator[](size_t idx) const ElementType operator[](size_t idx) const
{ {
switch (idx) switch (idx)
{ {
@@ -180,7 +181,7 @@ struct RgbColor : RgbColorBase
// access elements in order by index rather than R,G,B // access elements in order by index rather than R,G,B
// see static Count for the number of elements // see static Count for the number of elements
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
uint8_t& operator[](size_t idx) ElementType& operator[](size_t idx)
{ {
switch (idx) switch (idx)
{ {
@@ -197,7 +198,7 @@ struct RgbColor : RgbColorBase
// CalculateBrightness will calculate the overall brightness // CalculateBrightness will calculate the overall brightness
// NOTE: This is a simple linear brightness // NOTE: This is a simple linear brightness
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
uint8_t CalculateBrightness() const; ElementType CalculateBrightness() const;
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Dim will return a new color that is blended to black with the given ratio // Dim will return a new color that is blended to black with the given ratio
@@ -205,7 +206,7 @@ struct RgbColor : RgbColorBase
// //
// NOTE: This is a simple linear blend // NOTE: This is a simple linear blend
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
RgbColor Dim(uint8_t ratio) const; RgbColor Dim(ElementType ratio) const;
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Brighten will return a new color that is blended to white with the given ratio // Brighten will return a new color that is blended to white with the given ratio
@@ -213,21 +214,21 @@ struct RgbColor : RgbColorBase
// //
// NOTE: This is a simple linear blend // NOTE: This is a simple linear blend
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
RgbColor Brighten(uint8_t ratio) const; RgbColor Brighten(ElementType ratio) const;
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Darken will adjust the color by the given delta toward black // Darken will adjust the color by the given delta toward black
// NOTE: This is a simple linear change // NOTE: This is a simple linear change
// delta - (0-255) the amount to dim the color // delta - (0-255) the amount to dim the color
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
void Darken(uint8_t delta); void Darken(ElementType delta);
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Lighten will adjust the color by the given delta toward white // Lighten will adjust the color by the given delta toward white
// NOTE: This is a simple linear change // NOTE: This is a simple linear change
// delta - (0-255) the amount to lighten the color // delta - (0-255) the amount to lighten the color
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
void Lighten(uint8_t delta); void Lighten(ElementType delta);
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// LinearBlend between two colors by the amount defined by progress variable // LinearBlend between two colors by the amount defined by progress variable
@@ -273,20 +274,21 @@ struct RgbColor : RgbColorBase
// Red, Green, Blue color members (0-255) where // Red, Green, Blue color members (0-255) where
// (0,0,0) is black and (255,255,255) is white // (0,0,0) is black and (255,255,255) is white
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
uint8_t R; ElementType R;
uint8_t G; ElementType G;
uint8_t B; ElementType B;
const static uint8_t Max = 255; const static ElementType Max = 255;
const static size_t Count = 3; // three elements in [] const static size_t Count = 3; // three elements in []
const static size_t Size = Count * sizeof(ElementType);
private: private:
inline static uint8_t _elementDim(uint8_t value, uint8_t ratio) inline static ElementType _elementDim(ElementType value, ElementType ratio)
{ {
return (static_cast<uint16_t>(value) * (static_cast<uint16_t>(ratio) + 1)) >> 8; return (static_cast<uint16_t>(value) * (static_cast<uint16_t>(ratio) + 1)) >> 8;
} }
inline static uint8_t _elementBrighten(uint8_t value, uint8_t ratio) inline static ElementType _elementBrighten(ElementType value, ElementType ratio)
{ {
uint16_t element = ((static_cast<uint16_t>(value) + 1) << 8) / (static_cast<uint16_t>(ratio) + 1); uint16_t element = ((static_cast<uint16_t>(value) + 1) << 8) / (static_cast<uint16_t>(ratio) + 1);

View File

@@ -31,37 +31,15 @@ class Neo3ByteFeature :
public NeoByteElements<3, RgbColor, uint8_t> public NeoByteElements<3, RgbColor, uint8_t>
{ {
public: public:
static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color) static void applyPixelColor(uint8_t* pixel, size_t pixelSize, ColorObject color)
{ {
uint8_t* p = getPixelAddress(pPixels, indexPixel); if (PixelSize <= pixelSize)
{
uint8_t* p = pixel;
*p++ = color[V_IC_1]; *p++ = color[V_IC_1];
*p++ = color[V_IC_2]; *p++ = color[V_IC_2];
*p = color[V_IC_3]; *p = color[V_IC_3];
} }
static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel)
{
ColorObject color;
const uint8_t* p = getPixelAddress(pPixels, indexPixel);
color[V_IC_1] = *p++;
color[V_IC_2] = *p++;
color[V_IC_3] = *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[V_IC_1] = pgm_read_byte(p++);
color[V_IC_2] = pgm_read_byte(p++);
color[V_IC_3] = pgm_read_byte(p);
return color;
} }
}; };

View File

@@ -32,17 +32,14 @@ public:
typedef NeoNoSettings SettingsObject; typedef NeoNoSettings SettingsObject;
static const size_t SettingsSize = 0; 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 bool applyFrontSettings([[maybe_unused]] uint8_t* pData, [[maybe_unused]] size_t sizeData, [[maybe_unused]] const SettingsObject& settings)
{ {
return false;
} }
static uint8_t* pixels([[maybe_unused]] uint8_t* pData, [[maybe_unused]] size_t sizeData) static bool applyBackSettings([[maybe_unused]] uint8_t* pData, [[maybe_unused]] size_t sizeData, [[maybe_unused]] const SettingsObject& settings)
{ {
return pData; return false;
} }
static const uint8_t* pixels([[maybe_unused]] const uint8_t* pData, [[maybe_unused]] size_t sizeData)
{
return pData;
}
}; };

View File

@@ -125,13 +125,6 @@ public:
static const uint32_t ResetTimeUs = 100; static const uint32_t ResetTimeUs = 100;
}; };
class NeoAvrSpeed600KbpsIps : public NeoAvrSpeed600KbpsBase
{
public:
static const uint32_t ResetTimeUs = 300;
static const uint16_t InterpixelTimeUs = 8; // 12.4, with loop overhead of about 5us for loop
};
class NeoAvrSpeedTm1814 : public NeoAvrSpeed800KbpsBase class NeoAvrSpeedTm1814 : public NeoAvrSpeed800KbpsBase
{ {
public: public:
@@ -177,17 +170,13 @@ template<typename T_SPEED> class NeoAvrMethodBase
public: public:
typedef NeoNoSettings SettingsObject; typedef NeoNoSettings SettingsObject;
NeoAvrMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize) : NeoAvrMethodBase(uint8_t pin,
_sizeData(pixelCount * elementSize + settingsSize), [[maybe_unused]] uint16_t pixelCount,
_pin(pin), [[maybe_unused]] size_t elementSize,
_port(NULL), [[maybe_unused]] size_t settingsSize) :
_pinMask(0) _pin(pin)
{ {
pinMode(pin, OUTPUT); pinMode(pin, OUTPUT);
_data = static_cast<uint8_t*>(malloc(_sizeData));
// data cleared later in Begin()
_port = portOutputRegister(digitalPinToPort(pin)); _port = portOutputRegister(digitalPinToPort(pin));
_pinMask = digitalPinToBitMask(pin); _pinMask = digitalPinToBitMask(pin);
} }
@@ -195,8 +184,6 @@ public:
~NeoAvrMethodBase() ~NeoAvrMethodBase()
{ {
pinMode(_pin, INPUT); pinMode(_pin, INPUT);
free(_data);
} }
bool IsReadyToUpdate() const bool IsReadyToUpdate() const
@@ -213,14 +200,15 @@ public:
_endTime = micros(); _endTime = micros();
} }
void Update(bool) template <typename T_COLOR_OBJECT,
typename T_COLOR_FEATURE,
typename T_SHADER>
void Update(
T_COLOR_OBJECT* pixels,
size_t countPixels,
const typename T_COLOR_FEATURE::SettingsObject& featureSettings,
const T_SHADER& shader)
{ {
// 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()) while (!IsReadyToUpdate())
{ {
#if !defined(ARDUINO_TEEONARDU_LEO) && !defined(ARDUINO_TEEONARDU_FLORA) && !defined(ARDUINO_AVR_DIGISPARK) #if !defined(ARDUINO_TEEONARDU_LEO) && !defined(ARDUINO_TEEONARDU_FLORA) && !defined(ARDUINO_AVR_DIGISPARK)
@@ -228,104 +216,60 @@ public:
#endif #endif
} }
const size_t sendDataSize = T_COLOR_FEATURE::SettingsSize >= T_COLOR_FEATURE::PixelSize ? T_COLOR_FEATURE::SettingsSize : T_COLOR_FEATURE::PixelSize;
uint8_t sendData[sendDataSize];
// if there are settings at the front
if (T_COLOR_FEATURE::applyFrontSettings(sendData, sendDataSize, featureSettings))
{
noInterrupts(); // Need 100% focus on instruction timing noInterrupts(); // Need 100% focus on instruction timing
T_SPEED::send_data(sendData, T_COLOR_FEATURE::SettingsSize, _port, _pinMask);
T_SPEED::send_data(_data, _sizeData, _port, _pinMask);
interrupts(); interrupts();
}
// send primary color data
T_COLOR_OBJECT* pixel = pixels;
T_COLOR_OBJECT* pixelEnd = pixel + countPixels;
while (pixel < pixelEnd)
{
typename T_COLOR_FEATURE::ColorObject color = shader.Apply(*pixel);
T_COLOR_FEATURE::applyPixelColor(sendData, T_COLOR_FEATURE::PixelSize, color);
noInterrupts(); // Need 100% focus on instruction timing
T_SPEED::send_data(sendData, T_COLOR_FEATURE::PixelSize, _port, _pinMask);
interrupts();
pixel++;
}
// if there are settings at the back
if (T_COLOR_FEATURE::applyBackSettings(sendData, sendDataSize, featureSettings))
{
noInterrupts(); // Need 100% focus on instruction timing
T_SPEED::send_data(sendData, T_COLOR_FEATURE::SettingsSize, _port, _pinMask);
interrupts();
}
// save EOD time for latch on next call // save EOD time for latch on next call
_endTime = micros(); _endTime = micros();
} }
bool AlwaysUpdate()
{
// this method requires update to be called only if changes to buffer
return false;
}
uint8_t* getData() const
{
return _data;
};
size_t getDataSize() const
{
return _sizeData;
};
void applySettings([[maybe_unused]] const SettingsObject& settings) void applySettings([[maybe_unused]] const SettingsObject& settings)
{ {
} }
protected: protected:
const size_t _sizeData; // size of _data below
const uint8_t _pin; // output pin number const uint8_t _pin; // output pin number
volatile uint8_t* _port; // Output PORT register
uint32_t _endTime; // Latch timing reference 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 uint8_t _pinMask; // Output PORT bitmask
}; };
template<typename T_SPEED> class NeoAvrIpsMethodBase : public NeoAvrMethodBase<T_SPEED>
{
public:
NeoAvrIpsMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize) :
NeoAvrMethodBase<T_SPEED>(pin, pixelCount, elementSize, settingsSize),
_elementSize(elementSize)
{
}
~NeoAvrIpsMethodBase()
{
}
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 (!NeoAvrMethodBase<T_SPEED>::IsReadyToUpdate())
{
#if !defined(ARDUINO_TEEONARDU_LEO) && !defined(ARDUINO_TEEONARDU_FLORA) && !defined(ARDUINO_AVR_DIGISPARK)
yield(); // allows for system yield if needed
#endif
}
noInterrupts(); // Need 100% focus on instruction timing
uint8_t* dataPixel = NeoAvrMethodBase<T_SPEED>::_data;
const uint8_t* dataEnd = dataPixel + NeoAvrMethodBase<T_SPEED>::_sizeData;
while (dataPixel < dataEnd)
{
T_SPEED::send_data(dataPixel,
_elementSize,
NeoAvrMethodBase<T_SPEED>::_port,
NeoAvrMethodBase<T_SPEED>::_pinMask);
dataPixel += _elementSize;
delayMicroseconds(T_SPEED::InterpixelTimeUs);
}
interrupts();
// save EOD time for latch on next call
NeoAvrMethodBase<T_SPEED>::_endTime = micros();
}
private:
const size_t _elementSize; // size of a single pixel
};
typedef NeoAvrMethodBase<NeoAvrSpeedWs2812x> NeoAvrWs2812xMethod; typedef NeoAvrMethodBase<NeoAvrSpeedWs2812x> NeoAvrWs2812xMethod;
typedef NeoAvrMethodBase<NeoAvrSpeedSk6812> NeoAvrSk6812Method; typedef NeoAvrMethodBase<NeoAvrSpeedSk6812> NeoAvrSk6812Method;
typedef NeoAvrMethodBase<NeoAvrSpeedApa106> NeoAvrApa106Method; typedef NeoAvrMethodBase<NeoAvrSpeedApa106> NeoAvrApa106Method;
typedef NeoAvrIpsMethodBase<NeoAvrSpeed600KbpsIps> NeoAvr600KbpsIpsMethod;
typedef NeoAvrMethodBase<NeoAvrSpeedTm1814> NeoAvrTm1814InvertedMethod; typedef NeoAvrMethodBase<NeoAvrSpeedTm1814> NeoAvrTm1814InvertedMethod;
typedef NeoAvrMethodBase<NeoAvrSpeedTm1829> NeoAvrTm1829InvertedMethod; typedef NeoAvrMethodBase<NeoAvrSpeedTm1829> NeoAvrTm1829InvertedMethod;