IP Configuration
This commit is contained in:
180
lib/NeoPixelBus_by_Makuna/src/NeoPixelAnimator.h
Normal file
180
lib/NeoPixelBus_by_Makuna/src/NeoPixelAnimator.h
Normal file
@@ -0,0 +1,180 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
NeoPixelAnimator provides animation timing support.
|
||||
|
||||
Written by Michael C. Miller.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "internal/NeoEase.h"
|
||||
|
||||
enum AnimationState
|
||||
{
|
||||
AnimationState_Started,
|
||||
AnimationState_Progress,
|
||||
AnimationState_Completed
|
||||
};
|
||||
|
||||
struct AnimationParam
|
||||
{
|
||||
float progress;
|
||||
uint16_t index;
|
||||
AnimationState state;
|
||||
};
|
||||
|
||||
#if defined(NEOPIXEBUS_NO_STL)
|
||||
|
||||
typedef void(*AnimUpdateCallback)(const AnimationParam& param);
|
||||
|
||||
#else
|
||||
|
||||
#undef max
|
||||
#undef min
|
||||
#include <functional>
|
||||
typedef std::function<void(const AnimationParam& param)> AnimUpdateCallback;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#define NEO_MILLISECONDS 1 // ~65 seconds max duration, ms updates
|
||||
#define NEO_CENTISECONDS 10 // ~10.9 minutes max duration, centisecond updates
|
||||
#define NEO_DECISECONDS 100 // ~1.8 hours max duration, decisecond updates
|
||||
#define NEO_SECONDS 1000 // ~18.2 hours max duration, second updates
|
||||
#define NEO_DECASECONDS 10000 // ~7.5 days, 10 second updates
|
||||
|
||||
class NeoPixelAnimator
|
||||
{
|
||||
public:
|
||||
NeoPixelAnimator(uint16_t countAnimations, uint16_t timeScale = NEO_MILLISECONDS);
|
||||
~NeoPixelAnimator();
|
||||
|
||||
bool IsAnimating() const
|
||||
{
|
||||
return _activeAnimations > 0;
|
||||
}
|
||||
|
||||
|
||||
bool NextAvailableAnimation(uint16_t* indexAvailable, uint16_t indexStart = 0);
|
||||
|
||||
void StartAnimation(uint16_t indexAnimation, uint16_t duration, AnimUpdateCallback animUpdate);
|
||||
void StopAnimation(uint16_t indexAnimation);
|
||||
void StopAll();
|
||||
|
||||
void RestartAnimation(uint16_t indexAnimation)
|
||||
{
|
||||
if (indexAnimation >= _countAnimations || _animations[indexAnimation]._duration == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
StartAnimation(indexAnimation, _animations[indexAnimation]._duration, (_animations[indexAnimation]._fnCallback));
|
||||
}
|
||||
|
||||
bool IsAnimationActive(uint16_t indexAnimation) const
|
||||
{
|
||||
if (indexAnimation >= _countAnimations)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return (IsAnimating() && _animations[indexAnimation]._remaining != 0);
|
||||
}
|
||||
|
||||
uint16_t AnimationDuration(uint16_t indexAnimation)
|
||||
{
|
||||
if (indexAnimation >= _countAnimations)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return _animations[indexAnimation]._duration;
|
||||
}
|
||||
|
||||
void ChangeAnimationDuration(uint16_t indexAnimation, uint16_t newDuration);
|
||||
|
||||
void UpdateAnimations();
|
||||
|
||||
bool IsPaused()
|
||||
{
|
||||
return (!_isRunning);
|
||||
}
|
||||
|
||||
void Pause()
|
||||
{
|
||||
_isRunning = false;
|
||||
}
|
||||
|
||||
void Resume()
|
||||
{
|
||||
_isRunning = true;
|
||||
_animationLastTick = millis();
|
||||
}
|
||||
|
||||
uint16_t getTimeScale()
|
||||
{
|
||||
return _timeScale;
|
||||
}
|
||||
|
||||
void setTimeScale(uint16_t timeScale)
|
||||
{
|
||||
_timeScale = (timeScale < 1) ? (1) : (timeScale > 32768) ? 32768 : timeScale;
|
||||
}
|
||||
|
||||
private:
|
||||
struct AnimationContext
|
||||
{
|
||||
AnimationContext() :
|
||||
_duration(0),
|
||||
_remaining(0),
|
||||
_fnCallback(NULL)
|
||||
{}
|
||||
|
||||
void StartAnimation(uint16_t duration, AnimUpdateCallback animUpdate)
|
||||
{
|
||||
_duration = duration;
|
||||
_remaining = duration;
|
||||
_fnCallback = animUpdate;
|
||||
}
|
||||
|
||||
void StopAnimation()
|
||||
{
|
||||
_remaining = 0;
|
||||
}
|
||||
|
||||
float CurrentProgress()
|
||||
{
|
||||
return (float)(_duration - _remaining) / (float)_duration;
|
||||
}
|
||||
|
||||
uint16_t _duration;
|
||||
uint16_t _remaining;
|
||||
|
||||
AnimUpdateCallback _fnCallback;
|
||||
};
|
||||
|
||||
uint16_t _countAnimations;
|
||||
AnimationContext* _animations;
|
||||
uint32_t _animationLastTick;
|
||||
uint16_t _activeAnimations;
|
||||
uint16_t _timeScale;
|
||||
bool _isRunning;
|
||||
};
|
||||
142
lib/NeoPixelBus_by_Makuna/src/NeoPixelBrightnessBus.h
Normal file
142
lib/NeoPixelBus_by_Makuna/src/NeoPixelBrightnessBus.h
Normal file
@@ -0,0 +1,142 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
NeoPixelBus library wrapper template class that provides overall brightness control
|
||||
|
||||
Written by Michael C. Miller.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "NeoPixelBus.h"
|
||||
|
||||
template<typename T_COLOR_FEATURE, typename T_METHOD> class NeoPixelBrightnessBus :
|
||||
public NeoPixelBus<T_COLOR_FEATURE, T_METHOD>
|
||||
{
|
||||
private:
|
||||
|
||||
void ScaleColor(uint16_t scale, typename T_COLOR_FEATURE::ColorObject* color)
|
||||
{
|
||||
uint8_t* ptr = (uint8_t*)color;
|
||||
uint8_t* ptrEnd = ptr + sizeof(typename T_COLOR_FEATURE::ColorObject);
|
||||
|
||||
while (ptr != ptrEnd)
|
||||
{
|
||||
uint16_t value = *ptr;
|
||||
*ptr++ = (value * scale) >> 8;
|
||||
}
|
||||
}
|
||||
|
||||
void ConvertColor(typename T_COLOR_FEATURE::ColorObject* color)
|
||||
{
|
||||
uint16_t scale = _brightness + 1;
|
||||
ScaleColor(scale, color);
|
||||
}
|
||||
|
||||
void RecoverColor(typename T_COLOR_FEATURE::ColorObject* color) const
|
||||
{
|
||||
uint8_t* ptr = (uint8_t*)color;
|
||||
uint8_t* ptrEnd = ptr + sizeof(typename T_COLOR_FEATURE::ColorObject);
|
||||
uint16_t scale = _brightness + 1;
|
||||
|
||||
while (ptr != ptrEnd)
|
||||
{
|
||||
uint16_t value = *ptr;
|
||||
*ptr++ = (value << 8) / scale;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
NeoPixelBrightnessBus(uint16_t countPixels, uint8_t pin) :
|
||||
NeoPixelBus<T_COLOR_FEATURE, T_METHOD>(countPixels, pin),
|
||||
_brightness(255)
|
||||
{
|
||||
}
|
||||
|
||||
NeoPixelBrightnessBus(uint16_t countPixels, uint8_t pinClock, uint8_t pinData) :
|
||||
NeoPixelBus<T_COLOR_FEATURE, T_METHOD>(countPixels, pinClock, pinData),
|
||||
_brightness(255)
|
||||
{
|
||||
}
|
||||
|
||||
NeoPixelBrightnessBus(uint16_t countPixels) :
|
||||
NeoPixelBus<T_COLOR_FEATURE, T_METHOD>(countPixels),
|
||||
_brightness(255)
|
||||
{
|
||||
}
|
||||
|
||||
void SetBrightness(uint8_t brightness)
|
||||
{
|
||||
// Only update if there is a change
|
||||
if (brightness != _brightness)
|
||||
{
|
||||
uint16_t scale = (((uint16_t)brightness + 1) << 8) / ((uint16_t)_brightness + 1);
|
||||
|
||||
// scale existing pixels
|
||||
//
|
||||
for (uint16_t indexPixel = 0; indexPixel < NeoPixelBus<T_COLOR_FEATURE, T_METHOD>::PixelCount(); indexPixel++)
|
||||
{
|
||||
typename T_COLOR_FEATURE::ColorObject color = NeoPixelBus<T_COLOR_FEATURE, T_METHOD>::GetPixelColor(indexPixel);
|
||||
ScaleColor(scale, &color);
|
||||
NeoPixelBus<T_COLOR_FEATURE, T_METHOD>::SetPixelColor(indexPixel, color);
|
||||
}
|
||||
|
||||
_brightness = brightness;
|
||||
this->Dirty();
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t GetBrightness() const
|
||||
{
|
||||
return _brightness;
|
||||
}
|
||||
|
||||
void SetPixelColor(uint16_t indexPixel, typename T_COLOR_FEATURE::ColorObject color)
|
||||
{
|
||||
ConvertColor(&color);
|
||||
NeoPixelBus<T_COLOR_FEATURE, T_METHOD>::SetPixelColor(indexPixel, color);
|
||||
}
|
||||
|
||||
typename T_COLOR_FEATURE::ColorObject GetPixelColor(uint16_t indexPixel) const
|
||||
{
|
||||
typename T_COLOR_FEATURE::ColorObject color = NeoPixelBus<T_COLOR_FEATURE, T_METHOD>::GetPixelColor(indexPixel);
|
||||
RecoverColor(&color);
|
||||
return color;
|
||||
}
|
||||
|
||||
void ClearTo(typename T_COLOR_FEATURE::ColorObject color)
|
||||
{
|
||||
ConvertColor(&color);
|
||||
NeoPixelBus<T_COLOR_FEATURE, T_METHOD>::ClearTo(color);
|
||||
};
|
||||
|
||||
void ClearTo(typename T_COLOR_FEATURE::ColorObject color, uint16_t first, uint16_t last)
|
||||
{
|
||||
ConvertColor(&color);
|
||||
NeoPixelBus<T_COLOR_FEATURE, T_METHOD>::ClearTo(color, first, last);
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
uint8_t _brightness;
|
||||
};
|
||||
|
||||
|
||||
468
lib/NeoPixelBus_by_Makuna/src/NeoPixelBus.h
Normal file
468
lib/NeoPixelBus_by_Makuna/src/NeoPixelBus.h
Normal file
@@ -0,0 +1,468 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
NeoPixel library
|
||||
|
||||
Written by Michael C. Miller.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
// some platforms do not come with STL or properly defined one, specifically functional
|
||||
// if you see...
|
||||
// undefined reference to `std::__throw_bad_function_call()'
|
||||
// ...then you can either add the platform symbol to the list so NEOPIXEBUS_NO_STL gets defined or
|
||||
// go to boards.txt and enable c++ by adding (teensy31.build.flags.libs=-lstdc++) and set to "smallest code" option in Arduino
|
||||
//
|
||||
#if defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_MEGAAVR) || defined(STM32L432xx) || defined(STM32L476xx) || defined(ARDUINO_ARCH_SAM)
|
||||
#define NEOPIXEBUS_NO_STL 1
|
||||
#endif
|
||||
|
||||
// some platforms do not define this standard progmem type for some reason
|
||||
//
|
||||
#ifndef PGM_VOID_P
|
||||
#define PGM_VOID_P const void *
|
||||
#endif
|
||||
|
||||
// '_state' flags for internal state
|
||||
#define NEO_DIRTY 0x80 // a change was made to pixel data that requires a show
|
||||
|
||||
#include "internal/NeoHueBlend.h"
|
||||
|
||||
#include "internal/NeoSettings.h"
|
||||
|
||||
#include "internal/RgbColor.h"
|
||||
#include "internal/HslColor.h"
|
||||
#include "internal/HsbColor.h"
|
||||
#include "internal/HtmlColor.h"
|
||||
#include "internal/RgbwColor.h"
|
||||
#include "internal/SegmentDigit.h"
|
||||
|
||||
#include "internal/NeoColorFeatures.h"
|
||||
#include "internal/NeoTm1814ColorFeatures.h"
|
||||
#include "internal/DotStarColorFeatures.h"
|
||||
#include "internal/Lpd8806ColorFeatures.h"
|
||||
#include "internal/P9813ColorFeatures.h"
|
||||
#include "internal/NeoSegmentFeatures.h"
|
||||
|
||||
#include "internal/Layouts.h"
|
||||
#include "internal/NeoTopology.h"
|
||||
#include "internal/NeoRingTopology.h"
|
||||
#include "internal/NeoTiles.h"
|
||||
#include "internal/NeoMosaic.h"
|
||||
|
||||
#include "internal/NeoBufferContext.h"
|
||||
#include "internal/NeoBufferMethods.h"
|
||||
#include "internal/NeoBuffer.h"
|
||||
#include "internal/NeoSpriteSheet.h"
|
||||
#include "internal/NeoDib.h"
|
||||
#include "internal/NeoBitmapFile.h"
|
||||
|
||||
#include "internal/NeoEase.h"
|
||||
#include "internal/NeoGamma.h"
|
||||
|
||||
#include "internal/DotStarGenericMethod.h"
|
||||
#include "internal/Lpd8806GenericMethod.h"
|
||||
#include "internal/Ws2801GenericMethod.h"
|
||||
#include "internal/P9813GenericMethod.h"
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP8266)
|
||||
|
||||
#include "internal/NeoEsp8266DmaMethod.h"
|
||||
#include "internal/NeoEsp8266UartMethod.h"
|
||||
#include "internal/NeoEspBitBangMethod.h"
|
||||
|
||||
#elif defined(ARDUINO_ARCH_ESP32)
|
||||
|
||||
#include "internal/NeoEsp32I2sMethod.h"
|
||||
#include "internal/NeoEsp32RmtMethod.h"
|
||||
#include "internal/NeoEspBitBangMethod.h"
|
||||
|
||||
#elif defined(ARDUINO_ARCH_NRF52840) // must be before __arm__
|
||||
|
||||
#include "internal/NeoNrf52xMethod.h"
|
||||
|
||||
#elif defined(__arm__) // must be before ARDUINO_ARCH_AVR due to Teensy incorrectly having it set
|
||||
|
||||
#include "internal/NeoArmMethod.h"
|
||||
|
||||
#elif defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_MEGAAVR)
|
||||
|
||||
#include "internal/NeoAvrMethod.h"
|
||||
|
||||
#else
|
||||
#error "Platform Currently Not Supported, please add an Issue at Github/Makuna/NeoPixelBus"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
template<typename T_COLOR_FEATURE, typename T_METHOD> class NeoPixelBus
|
||||
{
|
||||
public:
|
||||
// Constructor: number of LEDs, pin number
|
||||
// NOTE: Pin Number maybe ignored due to hardware limitations of the method.
|
||||
|
||||
NeoPixelBus(uint16_t countPixels, uint8_t pin) :
|
||||
_countPixels(countPixels),
|
||||
_state(0),
|
||||
_method(pin, countPixels, T_COLOR_FEATURE::PixelSize, T_COLOR_FEATURE::SettingsSize)
|
||||
{
|
||||
}
|
||||
|
||||
NeoPixelBus(uint16_t countPixels, uint8_t pinClock, uint8_t pinData) :
|
||||
_countPixels(countPixels),
|
||||
_state(0),
|
||||
_method(pinClock, pinData, countPixels, T_COLOR_FEATURE::PixelSize, T_COLOR_FEATURE::SettingsSize)
|
||||
{
|
||||
}
|
||||
|
||||
NeoPixelBus(uint16_t countPixels) :
|
||||
_countPixels(countPixels),
|
||||
_state(0),
|
||||
_method(countPixels, T_COLOR_FEATURE::PixelSize, T_COLOR_FEATURE::SettingsSize)
|
||||
{
|
||||
}
|
||||
|
||||
~NeoPixelBus()
|
||||
{
|
||||
}
|
||||
|
||||
operator NeoBufferContext<T_COLOR_FEATURE>()
|
||||
{
|
||||
Dirty(); // we assume you are playing with bits
|
||||
return NeoBufferContext<T_COLOR_FEATURE>(_pixels(), PixelsSize());
|
||||
}
|
||||
|
||||
void Begin()
|
||||
{
|
||||
_method.Initialize();
|
||||
Dirty();
|
||||
}
|
||||
|
||||
// used by DotStartSpiMethod if pins can be configured
|
||||
void Begin(int8_t sck, int8_t miso, int8_t mosi, int8_t ss)
|
||||
{
|
||||
_method.Initialize(sck, miso, mosi, ss);
|
||||
Dirty();
|
||||
}
|
||||
|
||||
void Show(bool maintainBufferConsistency = true)
|
||||
{
|
||||
if (!IsDirty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_method.Update(maintainBufferConsistency);
|
||||
|
||||
ResetDirty();
|
||||
}
|
||||
|
||||
inline bool CanShow() const
|
||||
{
|
||||
return _method.IsReadyToUpdate();
|
||||
};
|
||||
|
||||
bool IsDirty() const
|
||||
{
|
||||
return (_state & NEO_DIRTY);
|
||||
};
|
||||
|
||||
void Dirty()
|
||||
{
|
||||
_state |= NEO_DIRTY;
|
||||
};
|
||||
|
||||
void ResetDirty()
|
||||
{
|
||||
_state &= ~NEO_DIRTY;
|
||||
};
|
||||
|
||||
uint8_t* Pixels()
|
||||
{
|
||||
return _pixels();
|
||||
};
|
||||
|
||||
size_t PixelsSize() const
|
||||
{
|
||||
return _method.getDataSize() - T_COLOR_FEATURE::SettingsSize;
|
||||
};
|
||||
|
||||
size_t PixelSize() const
|
||||
{
|
||||
return T_COLOR_FEATURE::PixelSize;
|
||||
};
|
||||
|
||||
uint16_t PixelCount() const
|
||||
{
|
||||
return _countPixels;
|
||||
};
|
||||
|
||||
void SetPixelColor(uint16_t indexPixel, typename T_COLOR_FEATURE::ColorObject color)
|
||||
{
|
||||
if (indexPixel < _countPixels)
|
||||
{
|
||||
T_COLOR_FEATURE::applyPixelColor(_pixels(), indexPixel, color);
|
||||
Dirty();
|
||||
}
|
||||
};
|
||||
|
||||
typename T_COLOR_FEATURE::ColorObject GetPixelColor(uint16_t indexPixel) const
|
||||
{
|
||||
if (indexPixel < _countPixels)
|
||||
{
|
||||
return T_COLOR_FEATURE::retrievePixelColor(_pixels(), indexPixel);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Pixel # is out of bounds, this will get converted to a
|
||||
// color object type initialized to 0 (black)
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
void ClearTo(typename T_COLOR_FEATURE::ColorObject color)
|
||||
{
|
||||
uint8_t temp[T_COLOR_FEATURE::PixelSize];
|
||||
uint8_t* pixels = _pixels();
|
||||
|
||||
T_COLOR_FEATURE::applyPixelColor(temp, 0, color);
|
||||
|
||||
T_COLOR_FEATURE::replicatePixel(pixels, temp, _countPixels);
|
||||
|
||||
Dirty();
|
||||
};
|
||||
|
||||
void ClearTo(typename T_COLOR_FEATURE::ColorObject color, uint16_t first, uint16_t last)
|
||||
{
|
||||
if (first < _countPixels &&
|
||||
last < _countPixels &&
|
||||
first <= last)
|
||||
{
|
||||
uint8_t temp[T_COLOR_FEATURE::PixelSize];
|
||||
uint8_t* pixels = _pixels();
|
||||
uint8_t* pFront = T_COLOR_FEATURE::getPixelAddress(pixels, first);
|
||||
|
||||
T_COLOR_FEATURE::applyPixelColor(temp, 0, color);
|
||||
|
||||
T_COLOR_FEATURE::replicatePixel(pFront, temp, last - first + 1);
|
||||
|
||||
Dirty();
|
||||
}
|
||||
}
|
||||
|
||||
void RotateLeft(uint16_t rotationCount)
|
||||
{
|
||||
if ((_countPixels - 1) >= rotationCount)
|
||||
{
|
||||
_rotateLeft(rotationCount, 0, _countPixels - 1);
|
||||
}
|
||||
}
|
||||
|
||||
void RotateLeft(uint16_t rotationCount, uint16_t first, uint16_t last)
|
||||
{
|
||||
if (first < _countPixels &&
|
||||
last < _countPixels &&
|
||||
first < last &&
|
||||
(last - first) >= rotationCount)
|
||||
{
|
||||
_rotateLeft(rotationCount, first, last);
|
||||
}
|
||||
}
|
||||
|
||||
void ShiftLeft(uint16_t shiftCount)
|
||||
{
|
||||
if ((_countPixels - 1) >= shiftCount)
|
||||
{
|
||||
_shiftLeft(shiftCount, 0, _countPixels - 1);
|
||||
Dirty();
|
||||
}
|
||||
}
|
||||
|
||||
void ShiftLeft(uint16_t shiftCount, uint16_t first, uint16_t last)
|
||||
{
|
||||
if (first < _countPixels &&
|
||||
last < _countPixels &&
|
||||
first < last &&
|
||||
(last - first) >= shiftCount)
|
||||
{
|
||||
_shiftLeft(shiftCount, first, last);
|
||||
Dirty();
|
||||
}
|
||||
}
|
||||
|
||||
void RotateRight(uint16_t rotationCount)
|
||||
{
|
||||
if ((_countPixels - 1) >= rotationCount)
|
||||
{
|
||||
_rotateRight(rotationCount, 0, _countPixels - 1);
|
||||
}
|
||||
}
|
||||
|
||||
void RotateRight(uint16_t rotationCount, uint16_t first, uint16_t last)
|
||||
{
|
||||
if (first < _countPixels &&
|
||||
last < _countPixels &&
|
||||
first < last &&
|
||||
(last - first) >= rotationCount)
|
||||
{
|
||||
_rotateRight(rotationCount, first, last);
|
||||
}
|
||||
}
|
||||
|
||||
void ShiftRight(uint16_t shiftCount)
|
||||
{
|
||||
if ((_countPixels - 1) >= shiftCount)
|
||||
{
|
||||
_shiftRight(shiftCount, 0, _countPixels - 1);
|
||||
Dirty();
|
||||
}
|
||||
}
|
||||
|
||||
void ShiftRight(uint16_t shiftCount, uint16_t first, uint16_t last)
|
||||
{
|
||||
if (first < _countPixels &&
|
||||
last < _countPixels &&
|
||||
first < last &&
|
||||
(last - first) >= shiftCount)
|
||||
{
|
||||
_shiftRight(shiftCount, first, last);
|
||||
Dirty();
|
||||
}
|
||||
}
|
||||
|
||||
void SwapPixelColor(uint16_t indexPixelOne, uint16_t indexPixelTwo)
|
||||
{
|
||||
auto colorOne = GetPixelColor(indexPixelOne);
|
||||
auto colorTwo = GetPixelColor(indexPixelTwo);
|
||||
|
||||
SetPixelColor(indexPixelOne, colorTwo);
|
||||
SetPixelColor(indexPixelTwo, colorOne);
|
||||
};
|
||||
|
||||
void SetPixelSettings(const typename T_COLOR_FEATURE::SettingsObject& settings)
|
||||
{
|
||||
T_COLOR_FEATURE::applySettings(_method.getData(), settings);
|
||||
Dirty();
|
||||
};
|
||||
|
||||
uint32_t CalcTotalMilliAmpere(const typename T_COLOR_FEATURE::ColorObject::SettingsObject& settings)
|
||||
{
|
||||
uint32_t total = 0; // in 1/10th milliamps
|
||||
|
||||
for (uint16_t index = 0; index < _countPixels; index++)
|
||||
{
|
||||
auto color = GetPixelColor(index);
|
||||
total += color.CalcTotalTenthMilliAmpere(settings);
|
||||
}
|
||||
|
||||
return total / 10; // return millamps
|
||||
}
|
||||
|
||||
protected:
|
||||
const uint16_t _countPixels; // Number of RGB LEDs in strip
|
||||
|
||||
uint8_t _state; // internal state
|
||||
T_METHOD _method;
|
||||
|
||||
uint8_t* _pixels()
|
||||
{
|
||||
// get pixels data within the data stream
|
||||
return T_COLOR_FEATURE::pixels(_method.getData());
|
||||
}
|
||||
|
||||
const uint8_t* _pixels() const
|
||||
{
|
||||
// get pixels data within the data stream
|
||||
return T_COLOR_FEATURE::pixels(_method.getData());
|
||||
}
|
||||
|
||||
void _rotateLeft(uint16_t rotationCount, uint16_t first, uint16_t last)
|
||||
{
|
||||
// store in temp
|
||||
uint8_t temp[rotationCount * T_COLOR_FEATURE::PixelSize];
|
||||
uint8_t* pixels = _pixels();
|
||||
|
||||
uint8_t* pFront = T_COLOR_FEATURE::getPixelAddress(pixels, first);
|
||||
|
||||
T_COLOR_FEATURE::movePixelsInc(temp, pFront, rotationCount);
|
||||
|
||||
// shift data
|
||||
_shiftLeft(rotationCount, first, last);
|
||||
|
||||
// move temp back
|
||||
pFront = T_COLOR_FEATURE::getPixelAddress(pixels, last - (rotationCount - 1));
|
||||
T_COLOR_FEATURE::movePixelsInc(pFront, temp, rotationCount);
|
||||
|
||||
Dirty();
|
||||
}
|
||||
|
||||
void _shiftLeft(uint16_t shiftCount, uint16_t first, uint16_t last)
|
||||
{
|
||||
uint16_t front = first + shiftCount;
|
||||
uint16_t count = last - front + 1;
|
||||
|
||||
uint8_t* pixels = _pixels();
|
||||
uint8_t* pFirst = T_COLOR_FEATURE::getPixelAddress(pixels, first);
|
||||
uint8_t* pFront = T_COLOR_FEATURE::getPixelAddress(pixels, front);
|
||||
|
||||
T_COLOR_FEATURE::movePixelsInc(pFirst, pFront, count);
|
||||
|
||||
// intentional no dirty
|
||||
}
|
||||
|
||||
void _rotateRight(uint16_t rotationCount, uint16_t first, uint16_t last)
|
||||
{
|
||||
// store in temp
|
||||
uint8_t temp[rotationCount * T_COLOR_FEATURE::PixelSize];
|
||||
uint8_t* pixels = _pixels();
|
||||
|
||||
uint8_t* pFront = T_COLOR_FEATURE::getPixelAddress(pixels, last - (rotationCount - 1));
|
||||
|
||||
T_COLOR_FEATURE::movePixelsDec(temp, pFront, rotationCount);
|
||||
|
||||
// shift data
|
||||
_shiftRight(rotationCount, first, last);
|
||||
|
||||
// move temp back
|
||||
pFront = T_COLOR_FEATURE::getPixelAddress(pixels, first);
|
||||
T_COLOR_FEATURE::movePixelsDec(pFront, temp, rotationCount);
|
||||
|
||||
Dirty();
|
||||
}
|
||||
|
||||
void _shiftRight(uint16_t shiftCount, uint16_t first, uint16_t last)
|
||||
{
|
||||
uint16_t front = first + shiftCount;
|
||||
uint16_t count = last - front + 1;
|
||||
|
||||
uint8_t* pixels = _pixels();
|
||||
uint8_t* pFirst = T_COLOR_FEATURE::getPixelAddress(pixels, first);
|
||||
uint8_t* pFront = T_COLOR_FEATURE::getPixelAddress(pixels, front);
|
||||
|
||||
T_COLOR_FEATURE::movePixelsDec(pFront, pFirst, count);
|
||||
// intentional no dirty
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
67
lib/NeoPixelBus_by_Makuna/src/NeoPixelSegmentBus.h
Normal file
67
lib/NeoPixelBus_by_Makuna/src/NeoPixelSegmentBus.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
NeoPixelBus library wrapper template class that provides enhanced methods
|
||||
for writing to segment based strips
|
||||
|
||||
Written by Michael C. Miller.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "NeoPixelBus.h"
|
||||
|
||||
template<typename T_COLOR_FEATURE, typename T_METHOD> class NeoPixelSegmentBus :
|
||||
public NeoPixelBus<T_COLOR_FEATURE, T_METHOD>
|
||||
{
|
||||
public:
|
||||
NeoPixelSegmentBus(uint16_t countPixels, uint8_t pin) :
|
||||
NeoPixelBus<T_COLOR_FEATURE, T_METHOD>(countPixels, pin)
|
||||
{
|
||||
}
|
||||
|
||||
NeoPixelSegmentBus(uint16_t countPixels) :
|
||||
NeoPixelBus<T_COLOR_FEATURE, T_METHOD>(countPixels)
|
||||
{
|
||||
}
|
||||
|
||||
void SetString(uint16_t indexDigit,
|
||||
const char* str,
|
||||
uint8_t brightness,
|
||||
uint8_t defaultBrightness = 0)
|
||||
{
|
||||
T_COLOR_FEATURE::ColorObject::SetString(*this,
|
||||
indexDigit,
|
||||
str,
|
||||
brightness,
|
||||
defaultBrightness);
|
||||
}
|
||||
|
||||
void SetString(uint16_t indexDigit,
|
||||
const String& str,
|
||||
uint8_t brightness,
|
||||
uint8_t defaultBrightness = 0)
|
||||
{
|
||||
SetString(indexDigit, str.c_str(), brightness, defaultBrightness);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
698
lib/NeoPixelBus_by_Makuna/src/internal/DotStarColorFeatures.h
Normal file
698
lib/NeoPixelBus_by_Makuna/src/internal/DotStarColorFeatures.h
Normal file
@@ -0,0 +1,698 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
DotStarColorFeatures provides feature classes to describe color order and
|
||||
color depth for NeoPixelBus template class when used with DotStars
|
||||
|
||||
Written by Michael C. Miller.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
#pragma once
|
||||
|
||||
class DotStar3Elements
|
||||
{
|
||||
public:
|
||||
static const size_t PixelSize = 4; // still requires 4 to be sent
|
||||
|
||||
static uint8_t* getPixelAddress(uint8_t* pPixels, uint16_t indexPixel)
|
||||
{
|
||||
return pPixels + indexPixel * PixelSize;
|
||||
}
|
||||
static const uint8_t* getPixelAddress(const uint8_t* pPixels, uint16_t indexPixel)
|
||||
{
|
||||
return pPixels + indexPixel * PixelSize;
|
||||
}
|
||||
|
||||
static void replicatePixel(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count)
|
||||
{
|
||||
uint8_t* pEnd = pPixelDest + (count * PixelSize);
|
||||
while (pPixelDest < pEnd)
|
||||
{
|
||||
*pPixelDest++ = pPixelSrc[0];
|
||||
*pPixelDest++ = pPixelSrc[1];
|
||||
*pPixelDest++ = pPixelSrc[2];
|
||||
*pPixelDest++ = pPixelSrc[3];
|
||||
}
|
||||
}
|
||||
|
||||
static void movePixelsInc(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count)
|
||||
{
|
||||
uint8_t* pEnd = pPixelDest + (count * PixelSize);
|
||||
while (pPixelDest < pEnd)
|
||||
{
|
||||
*pPixelDest++ = *pPixelSrc++;
|
||||
*pPixelDest++ = *pPixelSrc++;
|
||||
*pPixelDest++ = *pPixelSrc++;
|
||||
*pPixelDest++ = *pPixelSrc++;
|
||||
}
|
||||
}
|
||||
|
||||
static void movePixelsInc_P(uint8_t* pPixelDest, PGM_VOID_P pPixelSrc, uint16_t count)
|
||||
{
|
||||
uint8_t* pEnd = pPixelDest + (count * PixelSize);
|
||||
const uint8_t* pSrc = (const uint8_t*)pPixelSrc;
|
||||
while (pPixelDest < pEnd)
|
||||
{
|
||||
*pPixelDest++ = pgm_read_byte(pSrc++);
|
||||
*pPixelDest++ = pgm_read_byte(pSrc++);
|
||||
*pPixelDest++ = pgm_read_byte(pSrc++);
|
||||
*pPixelDest++ = pgm_read_byte(pSrc++);
|
||||
}
|
||||
}
|
||||
|
||||
static void movePixelsDec(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count)
|
||||
{
|
||||
uint8_t* pDestBack = pPixelDest + (count * PixelSize);
|
||||
const uint8_t* pSrcBack = pPixelSrc + (count * PixelSize);
|
||||
while (pDestBack > pPixelDest)
|
||||
{
|
||||
*--pDestBack = *--pSrcBack;
|
||||
*--pDestBack = *--pSrcBack;
|
||||
*--pDestBack = *--pSrcBack;
|
||||
*--pDestBack = *--pSrcBack;
|
||||
}
|
||||
}
|
||||
|
||||
typedef RgbColor ColorObject;
|
||||
};
|
||||
|
||||
class DotStar4Elements
|
||||
{
|
||||
public:
|
||||
static const size_t PixelSize = 4;
|
||||
|
||||
static uint8_t* getPixelAddress(uint8_t* pPixels, uint16_t indexPixel)
|
||||
{
|
||||
return pPixels + indexPixel * PixelSize;
|
||||
}
|
||||
static const uint8_t* getPixelAddress(const uint8_t* pPixels, uint16_t indexPixel)
|
||||
{
|
||||
return pPixels + indexPixel * PixelSize;
|
||||
}
|
||||
|
||||
static void replicatePixel(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count)
|
||||
{
|
||||
uint8_t* pEnd = pPixelDest + (count * PixelSize);
|
||||
while (pPixelDest < pEnd)
|
||||
{
|
||||
*pPixelDest++ = pPixelSrc[0];
|
||||
*pPixelDest++ = pPixelSrc[1];
|
||||
*pPixelDest++ = pPixelSrc[2];
|
||||
*pPixelDest++ = pPixelSrc[3];
|
||||
}
|
||||
}
|
||||
|
||||
static void movePixelsInc(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count)
|
||||
{
|
||||
uint8_t* pEnd = pPixelDest + (count * PixelSize);
|
||||
while (pPixelDest < pEnd)
|
||||
{
|
||||
*pPixelDest++ = *pPixelSrc++;
|
||||
*pPixelDest++ = *pPixelSrc++;
|
||||
*pPixelDest++ = *pPixelSrc++;
|
||||
*pPixelDest++ = *pPixelSrc++;
|
||||
}
|
||||
}
|
||||
|
||||
static void movePixelsInc_P(uint8_t* pPixelDest, PGM_VOID_P pPixelSrc, uint16_t count)
|
||||
{
|
||||
uint8_t* pEnd = pPixelDest + (count * PixelSize);
|
||||
const uint8_t* pSrc = (const uint8_t*)pPixelSrc;
|
||||
while (pPixelDest < pEnd)
|
||||
{
|
||||
*pPixelDest++ = pgm_read_byte(pSrc++);
|
||||
*pPixelDest++ = pgm_read_byte(pSrc++);
|
||||
*pPixelDest++ = pgm_read_byte(pSrc++);
|
||||
*pPixelDest++ = pgm_read_byte(pSrc++);
|
||||
}
|
||||
}
|
||||
|
||||
static void movePixelsDec(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count)
|
||||
{
|
||||
uint8_t* pDestBack = pPixelDest + (count * PixelSize);
|
||||
const uint8_t* pSrcBack = pPixelSrc + (count * PixelSize);
|
||||
while (pDestBack > pPixelDest)
|
||||
{
|
||||
*--pDestBack = *--pSrcBack;
|
||||
*--pDestBack = *--pSrcBack;
|
||||
*--pDestBack = *--pSrcBack;
|
||||
*--pDestBack = *--pSrcBack;
|
||||
}
|
||||
}
|
||||
|
||||
typedef RgbwColor ColorObject;
|
||||
};
|
||||
|
||||
|
||||
class DotStar3ElementsNoSettings : public DotStar3Elements
|
||||
{
|
||||
public:
|
||||
typedef NeoNoSettings SettingsObject;
|
||||
static const size_t SettingsSize = 0;
|
||||
|
||||
static void applySettings(uint8_t*, const SettingsObject&)
|
||||
{
|
||||
}
|
||||
|
||||
static uint8_t* pixels(uint8_t* pData)
|
||||
{
|
||||
return pData;
|
||||
}
|
||||
|
||||
static const uint8_t* pixels(const uint8_t* pData)
|
||||
{
|
||||
return pData;
|
||||
}
|
||||
};
|
||||
|
||||
class DotStar4ElementsNoSettings : public DotStar4Elements
|
||||
{
|
||||
public:
|
||||
typedef NeoNoSettings SettingsObject;
|
||||
static const size_t SettingsSize = 0;
|
||||
|
||||
static void applySettings(uint8_t*, const SettingsObject&)
|
||||
{
|
||||
}
|
||||
|
||||
static uint8_t* pixels(uint8_t* pData)
|
||||
{
|
||||
return pData;
|
||||
}
|
||||
|
||||
static const uint8_t* pixels(const uint8_t* pData)
|
||||
{
|
||||
return pData;
|
||||
}
|
||||
};
|
||||
|
||||
class DotStarBgrFeature : public DotStar3ElementsNoSettings
|
||||
{
|
||||
public:
|
||||
static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color)
|
||||
{
|
||||
uint8_t* p = getPixelAddress(pPixels, indexPixel);
|
||||
|
||||
*p++ = 0xff; // upper three bits are always 111 and brightness at max
|
||||
*p++ = color.B;
|
||||
*p++ = color.G;
|
||||
*p = color.R;
|
||||
}
|
||||
|
||||
static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel)
|
||||
{
|
||||
ColorObject color;
|
||||
const uint8_t* p = getPixelAddress(pPixels, indexPixel);
|
||||
|
||||
p++; // ignore the first byte
|
||||
color.B = *p++;
|
||||
color.G = *p++;
|
||||
color.R = *p;
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
static ColorObject retrievePixelColor_P(PGM_VOID_P pPixels, uint16_t indexPixel)
|
||||
{
|
||||
ColorObject color;
|
||||
const uint8_t* p = getPixelAddress((const uint8_t*)pPixels, indexPixel);
|
||||
|
||||
pgm_read_byte(p++); // ignore the first byte
|
||||
color.B = pgm_read_byte(p++);
|
||||
color.G = pgm_read_byte(p++);
|
||||
color.R = pgm_read_byte(p);
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class DotStarLbgrFeature : public DotStar4ElementsNoSettings
|
||||
{
|
||||
public:
|
||||
static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color)
|
||||
{
|
||||
uint8_t* p = getPixelAddress(pPixels, indexPixel);
|
||||
|
||||
*p++ = 0xE0 | (color.W < 31 ? color.W : 31); // upper three bits are always 111
|
||||
*p++ = color.B;
|
||||
*p++ = color.G;
|
||||
*p = color.R;
|
||||
}
|
||||
|
||||
static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel)
|
||||
{
|
||||
ColorObject color;
|
||||
const uint8_t* p = getPixelAddress(pPixels, indexPixel);
|
||||
|
||||
color.W = (*p++) & 0x1F; // mask out upper three bits
|
||||
color.B = *p++;
|
||||
color.G = *p++;
|
||||
color.R = *p;
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
static ColorObject retrievePixelColor_P(PGM_VOID_P pPixels, uint16_t indexPixel)
|
||||
{
|
||||
ColorObject color;
|
||||
const uint8_t* p = getPixelAddress((const uint8_t*)pPixels, indexPixel);
|
||||
|
||||
color.W = pgm_read_byte(p++) & 0x1F; // mask out upper three bits
|
||||
color.B = pgm_read_byte(p++);
|
||||
color.G = pgm_read_byte(p++);
|
||||
color.R = pgm_read_byte(p);
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class DotStarGrbFeature : public DotStar3ElementsNoSettings
|
||||
{
|
||||
public:
|
||||
static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color)
|
||||
{
|
||||
uint8_t* p = getPixelAddress(pPixels, indexPixel);
|
||||
|
||||
*p++ = 0xff; // upper three bits are always 111 and brightness at max
|
||||
*p++ = color.G;
|
||||
*p++ = color.R;
|
||||
*p = color.B;
|
||||
}
|
||||
|
||||
static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel)
|
||||
{
|
||||
ColorObject color;
|
||||
const uint8_t* p = getPixelAddress(pPixels, indexPixel);
|
||||
|
||||
p++; // ignore the first byte
|
||||
color.G = *p++;
|
||||
color.R = *p++;
|
||||
color.B = *p;
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
static ColorObject retrievePixelColor_P(PGM_VOID_P pPixels, uint16_t indexPixel)
|
||||
{
|
||||
ColorObject color;
|
||||
const uint8_t* p = getPixelAddress((const uint8_t*)pPixels, indexPixel);
|
||||
|
||||
pgm_read_byte(p++); // ignore the first byte
|
||||
color.G = pgm_read_byte(p++);
|
||||
color.R = pgm_read_byte(p++);
|
||||
color.B = pgm_read_byte(p);
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class DotStarLgrbFeature : public DotStar4ElementsNoSettings
|
||||
{
|
||||
public:
|
||||
static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color)
|
||||
{
|
||||
uint8_t* p = getPixelAddress(pPixels, indexPixel);
|
||||
|
||||
*p++ = 0xE0 | (color.W < 31 ? color.W : 31); // upper three bits are always 111
|
||||
*p++ = color.G;
|
||||
*p++ = color.R;
|
||||
*p = color.B;
|
||||
}
|
||||
|
||||
static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel)
|
||||
{
|
||||
ColorObject color;
|
||||
const uint8_t* p = getPixelAddress(pPixels, indexPixel);
|
||||
|
||||
color.W = (*p++) & 0x1F; // mask out upper three bits
|
||||
color.G = *p++;
|
||||
color.R = *p++;
|
||||
color.B = *p;
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
static ColorObject retrievePixelColor_P(PGM_VOID_P pPixels, uint16_t indexPixel)
|
||||
{
|
||||
ColorObject color;
|
||||
const uint8_t* p = getPixelAddress((const uint8_t*)pPixels, indexPixel);
|
||||
|
||||
color.W = pgm_read_byte(p++) & 0x1F; // mask out upper three bits
|
||||
color.G = pgm_read_byte(p++);
|
||||
color.R = pgm_read_byte(p++);
|
||||
color.B = pgm_read_byte(p);
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/* RGB Feature -- Some APA102s ship in RGB order */
|
||||
class DotStarRgbFeature : public DotStar3ElementsNoSettings
|
||||
{
|
||||
public:
|
||||
static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color)
|
||||
{
|
||||
uint8_t* p = getPixelAddress(pPixels, indexPixel);
|
||||
|
||||
*p++ = 0xff; // upper three bits are always 111 and brightness at max
|
||||
*p++ = color.R;
|
||||
*p++ = color.G;
|
||||
*p = color.B;
|
||||
}
|
||||
|
||||
static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel)
|
||||
{
|
||||
ColorObject color;
|
||||
const uint8_t* p = getPixelAddress(pPixels, indexPixel);
|
||||
|
||||
p++; // ignore the first byte
|
||||
color.R = *p++;
|
||||
color.G = *p++;
|
||||
color.B = *p;
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
static ColorObject retrievePixelColor_P(PGM_VOID_P pPixels, uint16_t indexPixel)
|
||||
{
|
||||
ColorObject color;
|
||||
const uint8_t* p = getPixelAddress((const uint8_t*)pPixels, indexPixel);
|
||||
|
||||
pgm_read_byte(p++); // ignore the first byte
|
||||
color.R = pgm_read_byte(p++);
|
||||
color.G = pgm_read_byte(p++);
|
||||
color.B = pgm_read_byte(p);
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class DotStarLrgbFeature : public DotStar4ElementsNoSettings
|
||||
{
|
||||
public:
|
||||
static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color)
|
||||
{
|
||||
uint8_t* p = getPixelAddress(pPixels, indexPixel);
|
||||
|
||||
*p++ = 0xE0 | (color.W < 31 ? color.W : 31); // upper three bits are always 111
|
||||
*p++ = color.R;
|
||||
*p++ = color.G;
|
||||
*p = color.B;
|
||||
}
|
||||
|
||||
static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel)
|
||||
{
|
||||
ColorObject color;
|
||||
const uint8_t* p = getPixelAddress(pPixels, indexPixel);
|
||||
|
||||
color.W = (*p++) & 0x1F; // mask out upper three bits
|
||||
color.R = *p++;
|
||||
color.G = *p++;
|
||||
color.B = *p;
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
static ColorObject retrievePixelColor_P(PGM_VOID_P pPixels, uint16_t indexPixel)
|
||||
{
|
||||
ColorObject color;
|
||||
const uint8_t* p = getPixelAddress((const uint8_t*)pPixels, indexPixel);
|
||||
|
||||
color.W = pgm_read_byte(p++) & 0x1F; // mask out upper three bits
|
||||
color.R = pgm_read_byte(p++);
|
||||
color.G = pgm_read_byte(p++);
|
||||
color.B = pgm_read_byte(p);
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
};
|
||||
/* RBG Feature -- Some APA102s ship in RBG order */
|
||||
class DotStarRbgFeature : public DotStar3ElementsNoSettings
|
||||
{
|
||||
public:
|
||||
static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color)
|
||||
{
|
||||
uint8_t* p = getPixelAddress(pPixels, indexPixel);
|
||||
|
||||
*p++ = 0xff; // upper three bits are always 111 and brightness at max
|
||||
*p++ = color.R;
|
||||
*p++ = color.B;
|
||||
*p = color.G;
|
||||
}
|
||||
|
||||
static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel)
|
||||
{
|
||||
ColorObject color;
|
||||
const uint8_t* p = getPixelAddress(pPixels, indexPixel);
|
||||
|
||||
p++; // ignore the first byte
|
||||
color.R = *p++;
|
||||
color.B = *p++;
|
||||
color.G = *p;
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
static ColorObject retrievePixelColor_P(PGM_VOID_P pPixels, uint16_t indexPixel)
|
||||
{
|
||||
ColorObject color;
|
||||
const uint8_t* p = getPixelAddress((const uint8_t*)pPixels, indexPixel);
|
||||
|
||||
pgm_read_byte(p++); // ignore the first byte
|
||||
color.R = pgm_read_byte(p++);
|
||||
color.B = pgm_read_byte(p++);
|
||||
color.G = pgm_read_byte(p);
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class DotStarLrbgFeature : public DotStar4ElementsNoSettings
|
||||
{
|
||||
public:
|
||||
static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color)
|
||||
{
|
||||
uint8_t* p = getPixelAddress(pPixels, indexPixel);
|
||||
|
||||
*p++ = 0xE0 | (color.W < 31 ? color.W : 31); // upper three bits are always 111
|
||||
*p++ = color.R;
|
||||
*p++ = color.B;
|
||||
*p = color.G;
|
||||
}
|
||||
|
||||
static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel)
|
||||
{
|
||||
ColorObject color;
|
||||
const uint8_t* p = getPixelAddress(pPixels, indexPixel);
|
||||
|
||||
color.W = (*p++) & 0x1F; // mask out upper three bits
|
||||
color.R = *p++;
|
||||
color.B = *p++;
|
||||
color.G = *p;
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
static ColorObject retrievePixelColor_P(PGM_VOID_P pPixels, uint16_t indexPixel)
|
||||
{
|
||||
ColorObject color;
|
||||
const uint8_t* p = getPixelAddress((const uint8_t*)pPixels, indexPixel);
|
||||
|
||||
color.W = pgm_read_byte(p++) & 0x1F; // mask out upper three bits
|
||||
color.R = pgm_read_byte(p++);
|
||||
color.B = pgm_read_byte(p++);
|
||||
color.G = pgm_read_byte(p);
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/* GBR Feature -- Some APA102s ship in GBR order */
|
||||
class DotStarGbrFeature : public DotStar3ElementsNoSettings
|
||||
{
|
||||
public:
|
||||
static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color)
|
||||
{
|
||||
uint8_t* p = getPixelAddress(pPixels, indexPixel);
|
||||
|
||||
*p++ = 0xff; // upper three bits are always 111 and brightness at max
|
||||
*p++ = color.G;
|
||||
*p++ = color.B;
|
||||
*p = color.R;
|
||||
}
|
||||
|
||||
static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel)
|
||||
{
|
||||
ColorObject color;
|
||||
const uint8_t* p = getPixelAddress(pPixels, indexPixel);
|
||||
|
||||
p++; // ignore the first byte
|
||||
color.G = *p++;
|
||||
color.B = *p++;
|
||||
color.R = *p;
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
static ColorObject retrievePixelColor_P(PGM_VOID_P pPixels, uint16_t indexPixel)
|
||||
{
|
||||
ColorObject color;
|
||||
const uint8_t* p = getPixelAddress((const uint8_t*)pPixels, indexPixel);
|
||||
|
||||
pgm_read_byte(p++); // ignore the first byte
|
||||
color.G = pgm_read_byte(p++);
|
||||
color.B = pgm_read_byte(p++);
|
||||
color.R = pgm_read_byte(p);
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class DotStarLgbrFeature : public DotStar4ElementsNoSettings
|
||||
{
|
||||
public:
|
||||
static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color)
|
||||
{
|
||||
uint8_t* p = getPixelAddress(pPixels, indexPixel);
|
||||
|
||||
*p++ = 0xE0 | (color.W < 31 ? color.W : 31); // upper three bits are always 111
|
||||
*p++ = color.G;
|
||||
*p++ = color.B;
|
||||
*p = color.R;
|
||||
}
|
||||
|
||||
static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel)
|
||||
{
|
||||
ColorObject color;
|
||||
const uint8_t* p = getPixelAddress(pPixels, indexPixel);
|
||||
|
||||
color.W = (*p++) & 0x1F; // mask out upper three bits
|
||||
color.G = *p++;
|
||||
color.B = *p++;
|
||||
color.R = *p;
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
static ColorObject retrievePixelColor_P(PGM_VOID_P pPixels, uint16_t indexPixel)
|
||||
{
|
||||
ColorObject color;
|
||||
const uint8_t* p = getPixelAddress((const uint8_t*)pPixels, indexPixel);
|
||||
|
||||
color.W = pgm_read_byte(p++) & 0x1F; // mask out upper three bits
|
||||
color.G = pgm_read_byte(p++);
|
||||
color.B = pgm_read_byte(p++);
|
||||
color.R = pgm_read_byte(p);
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
};
|
||||
/* BRG Feature -- Some APA102s ship in BRG order */
|
||||
class DotStarBrgFeature : public DotStar3ElementsNoSettings
|
||||
{
|
||||
public:
|
||||
static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color)
|
||||
{
|
||||
uint8_t* p = getPixelAddress(pPixels, indexPixel);
|
||||
|
||||
*p++ = 0xff; // upper three bits are always 111 and brightness at max
|
||||
*p++ = color.B;
|
||||
*p++ = color.R;
|
||||
*p = color.G;
|
||||
}
|
||||
|
||||
static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel)
|
||||
{
|
||||
ColorObject color;
|
||||
const uint8_t* p = getPixelAddress(pPixels, indexPixel);
|
||||
|
||||
p++; // ignore the first byte
|
||||
color.B = *p++;
|
||||
color.R = *p++;
|
||||
color.G = *p;
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
static ColorObject retrievePixelColor_P(PGM_VOID_P pPixels, uint16_t indexPixel)
|
||||
{
|
||||
ColorObject color;
|
||||
const uint8_t* p = getPixelAddress((const uint8_t*)pPixels, indexPixel);
|
||||
|
||||
pgm_read_byte(p++); // ignore the first byte
|
||||
color.B = pgm_read_byte(p++);
|
||||
color.R = pgm_read_byte(p++);
|
||||
color.G = pgm_read_byte(p);
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class DotStarLbrgFeature : public DotStar4ElementsNoSettings
|
||||
{
|
||||
public:
|
||||
static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color)
|
||||
{
|
||||
uint8_t* p = getPixelAddress(pPixels, indexPixel);
|
||||
|
||||
*p++ = 0xE0 | (color.W < 31 ? color.W : 31); // upper three bits are always 111
|
||||
*p++ = color.B;
|
||||
*p++ = color.R;
|
||||
*p = color.G;
|
||||
}
|
||||
|
||||
static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel)
|
||||
{
|
||||
ColorObject color;
|
||||
const uint8_t* p = getPixelAddress(pPixels, indexPixel);
|
||||
|
||||
color.W = (*p++) & 0x1F; // mask out upper three bits
|
||||
color.B = *p++;
|
||||
color.R = *p++;
|
||||
color.G = *p;
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
static ColorObject retrievePixelColor_P(PGM_VOID_P pPixels, uint16_t indexPixel)
|
||||
{
|
||||
ColorObject color;
|
||||
const uint8_t* p = getPixelAddress((const uint8_t*)pPixels, indexPixel);
|
||||
|
||||
color.W = pgm_read_byte(p++) & 0x1F; // mask out upper three bits
|
||||
color.B = pgm_read_byte(p++);
|
||||
color.R = pgm_read_byte(p++);
|
||||
color.G = pgm_read_byte(p);
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
};
|
||||
135
lib/NeoPixelBus_by_Makuna/src/internal/DotStarGenericMethod.h
Normal file
135
lib/NeoPixelBus_by_Makuna/src/internal/DotStarGenericMethod.h
Normal file
@@ -0,0 +1,135 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
NeoPixel library helper functions for DotStars using general Pins (APA102).
|
||||
|
||||
Written by Michael C. Miller.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// must also check for arm due to Teensy incorrectly having ARDUINO_ARCH_AVR set
|
||||
#if defined(ARDUINO_ARCH_AVR) && !defined(__arm__)
|
||||
#include "TwoWireBitBangImpleAvr.h"
|
||||
#else
|
||||
#include "TwoWireBitBangImple.h"
|
||||
#endif
|
||||
|
||||
|
||||
template<typename T_TWOWIRE> class DotStarMethodBase
|
||||
{
|
||||
public:
|
||||
DotStarMethodBase(uint8_t pinClock, uint8_t pinData, uint16_t pixelCount, size_t elementSize, size_t settingsSize) :
|
||||
_sizeData(pixelCount * elementSize + settingsSize),
|
||||
_sizeEndFrame((pixelCount + 15) / 16), // 16 = div 2 (bit for every two pixels) div 8 (bits to bytes)
|
||||
_wire(pinClock, pinData)
|
||||
{
|
||||
_data = static_cast<uint8_t*>(malloc(_sizeData));
|
||||
memset(_data, 0, _sizeData);
|
||||
}
|
||||
|
||||
#if !defined(__AVR_ATtiny85__) && !defined(ARDUINO_attiny)
|
||||
DotStarMethodBase(uint16_t pixelCount, size_t elementSize, size_t settingsSize) :
|
||||
DotStarMethodBase(SCK, MOSI, pixelCount, elementSize, settingsSize)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
~DotStarMethodBase()
|
||||
{
|
||||
free(_data);
|
||||
}
|
||||
|
||||
bool IsReadyToUpdate() const
|
||||
{
|
||||
return true; // dot stars don't have a required delay
|
||||
}
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP32)
|
||||
void Initialize(int8_t sck, int8_t miso, int8_t mosi, int8_t ss)
|
||||
{
|
||||
_wire.begin(sck, miso, mosi, ss);
|
||||
}
|
||||
#endif
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
_wire.begin();
|
||||
}
|
||||
|
||||
void Update(bool)
|
||||
{
|
||||
const uint8_t startFrame[4] = { 0x00 };
|
||||
const uint8_t resetFrame[4] = { 0x00 };
|
||||
|
||||
_wire.beginTransaction();
|
||||
|
||||
// start frame
|
||||
_wire.transmitBytes(startFrame, sizeof(startFrame));
|
||||
|
||||
// data
|
||||
_wire.transmitBytes(_data, _sizeData);
|
||||
|
||||
// reset frame
|
||||
_wire.transmitBytes(resetFrame, sizeof(resetFrame));
|
||||
|
||||
// end frame
|
||||
|
||||
// one bit for every two pixels with no less than 1 byte
|
||||
for (size_t endFrameByte = 0; endFrameByte < _sizeEndFrame; endFrameByte++)
|
||||
{
|
||||
_wire.transmitByte(0x00);
|
||||
}
|
||||
|
||||
_wire.endTransaction();
|
||||
}
|
||||
|
||||
uint8_t* getData() const
|
||||
{
|
||||
return _data;
|
||||
};
|
||||
|
||||
size_t getDataSize() const
|
||||
{
|
||||
return _sizeData;
|
||||
};
|
||||
|
||||
private:
|
||||
const size_t _sizeData; // Size of '_data' buffer below
|
||||
const size_t _sizeEndFrame;
|
||||
|
||||
T_TWOWIRE _wire;
|
||||
uint8_t* _data; // Holds LED color values
|
||||
};
|
||||
|
||||
typedef DotStarMethodBase<TwoWireBitBangImple> DotStarMethod;
|
||||
|
||||
#if !defined(__AVR_ATtiny85__) && !defined(ARDUINO_attiny)
|
||||
#include "TwoWireSpiImple.h"
|
||||
typedef DotStarMethodBase<TwoWireSpiImple<SpiSpeed40Mhz>> DotStarSpi40MhzMethod;
|
||||
typedef DotStarMethodBase<TwoWireSpiImple<SpiSpeed20Mhz>> DotStarSpi20MhzMethod;
|
||||
typedef DotStarMethodBase<TwoWireSpiImple<SpiSpeed10Mhz>> DotStarSpi10MhzMethod;
|
||||
typedef DotStarMethodBase<TwoWireSpiImple<SpiSpeed2Mhz>> DotStarSpi2MhzMethod;
|
||||
typedef DotStarSpi10MhzMethod DotStarSpiMethod;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
498
lib/NeoPixelBus_by_Makuna/src/internal/Esp32_i2s.c
Normal file
498
lib/NeoPixelBus_by_Makuna/src/internal/Esp32_i2s.c
Normal file
@@ -0,0 +1,498 @@
|
||||
// WARNING: This file contains code that is more than likely already
|
||||
// exposed from the Esp32 Arduino API. It will be removed once integration is complete.
|
||||
//
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP32)
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "stdlib.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/queue.h"
|
||||
|
||||
|
||||
#if ESP_IDF_VERSION_MAJOR>=4
|
||||
#include "esp_intr_alloc.h"
|
||||
#else
|
||||
#include "esp_intr.h"
|
||||
#endif
|
||||
|
||||
#include "soc/gpio_reg.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
#include "soc/i2s_struct.h"
|
||||
#include "soc/dport_reg.h"
|
||||
#include "soc/sens_reg.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/i2s.h"
|
||||
#include "driver/dac.h"
|
||||
#include "Esp32_i2s.h"
|
||||
#include "esp32-hal.h"
|
||||
|
||||
#if ESP_IDF_VERSION_MAJOR<4
|
||||
#define I2S_BASE_CLK (160000000L)
|
||||
#endif
|
||||
|
||||
#define ESP32_REG(addr) (*((volatile uint32_t*)(0x3FF00000+(addr))))
|
||||
|
||||
#define I2S_DMA_QUEUE_SIZE 16
|
||||
|
||||
#define I2S_DMA_SILENCE_LEN 256 // bytes
|
||||
|
||||
typedef struct i2s_dma_item_s {
|
||||
uint32_t blocksize: 12; // datalen
|
||||
uint32_t datalen : 12; // len*(bits_per_sample/8)*2 => max 2047*8bit/1023*16bit samples
|
||||
uint32_t unused : 5; // 0
|
||||
uint32_t sub_sof : 1; // 0
|
||||
uint32_t eof : 1; // 1 => last?
|
||||
uint32_t owner : 1; // 1
|
||||
|
||||
void* data; // malloc(datalen)
|
||||
struct i2s_dma_item_s* next;
|
||||
|
||||
// if this pointer is not null, it will be freed
|
||||
void* free_ptr;
|
||||
|
||||
// if DMA buffers are preallocated
|
||||
uint8_t* buf;
|
||||
} i2s_dma_item_t;
|
||||
|
||||
typedef struct {
|
||||
i2s_dev_t* bus;
|
||||
int8_t ws;
|
||||
int8_t bck;
|
||||
int8_t out;
|
||||
int8_t in;
|
||||
uint32_t rate;
|
||||
intr_handle_t isr_handle;
|
||||
xQueueHandle tx_queue;
|
||||
|
||||
uint8_t* silence_buf;
|
||||
size_t silence_len;
|
||||
|
||||
i2s_dma_item_t* dma_items;
|
||||
size_t dma_count;
|
||||
uint32_t dma_buf_len :12;
|
||||
uint32_t unused :20;
|
||||
} i2s_bus_t;
|
||||
|
||||
static uint8_t i2s_silence_buf[I2S_DMA_SILENCE_LEN];
|
||||
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
// (I2S_NUM_MAX == 2)
|
||||
static i2s_bus_t I2S[I2S_NUM_MAX] = {
|
||||
{&I2S0, -1, -1, -1, -1, 0, NULL, NULL, i2s_silence_buf, I2S_DMA_SILENCE_LEN, NULL, I2S_DMA_QUEUE_SIZE, 0, 0},
|
||||
{&I2S1, -1, -1, -1, -1, 0, NULL, NULL, i2s_silence_buf, I2S_DMA_SILENCE_LEN, NULL, I2S_DMA_QUEUE_SIZE, 0, 0}
|
||||
};
|
||||
#else
|
||||
static i2s_bus_t I2S[I2S_NUM_MAX] = {
|
||||
{&I2S0, -1, -1, -1, -1, 0, NULL, NULL, i2s_silence_buf, I2S_DMA_SILENCE_LEN, NULL, I2S_DMA_QUEUE_SIZE, 0, 0}
|
||||
};
|
||||
#endif
|
||||
|
||||
void IRAM_ATTR i2sDmaISR(void* arg);
|
||||
bool i2sInitDmaItems(uint8_t bus_num);
|
||||
|
||||
bool i2sInitDmaItems(uint8_t bus_num) {
|
||||
if (bus_num >= I2S_NUM_MAX) {
|
||||
return false;
|
||||
}
|
||||
if (I2S[bus_num].tx_queue) {// already set
|
||||
return true;
|
||||
}
|
||||
|
||||
if (I2S[bus_num].dma_items == NULL) {
|
||||
I2S[bus_num].dma_items = (i2s_dma_item_t*)(malloc(I2S[bus_num].dma_count* sizeof(i2s_dma_item_t)));
|
||||
if (I2S[bus_num].dma_items == NULL) {
|
||||
log_e("MEM ERROR!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int i, i2, a;
|
||||
i2s_dma_item_t* item;
|
||||
|
||||
for(i=0; i<I2S[bus_num].dma_count; i++) {
|
||||
i2 = (i+1) % I2S[bus_num].dma_count;
|
||||
item = &I2S[bus_num].dma_items[i];
|
||||
item->eof = 1;
|
||||
item->owner = 1;
|
||||
item->sub_sof = 0;
|
||||
item->unused = 0;
|
||||
item->data = I2S[bus_num].silence_buf;
|
||||
item->blocksize = I2S[bus_num].silence_len;
|
||||
item->datalen = I2S[bus_num].silence_len;
|
||||
item->next = &I2S[bus_num].dma_items[i2];
|
||||
item->free_ptr = NULL;
|
||||
if (I2S[bus_num].dma_buf_len) {
|
||||
item->buf = (uint8_t*)(malloc(I2S[bus_num].dma_buf_len));
|
||||
if (item->buf == NULL) {
|
||||
log_e("MEM ERROR!");
|
||||
for(a=0; a<i; a++) {
|
||||
free(I2S[bus_num].dma_items[i].buf);
|
||||
}
|
||||
free(I2S[bus_num].dma_items);
|
||||
I2S[bus_num].dma_items = NULL;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
item->buf = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
I2S[bus_num].tx_queue = xQueueCreate(I2S[bus_num].dma_count, sizeof(i2s_dma_item_t*));
|
||||
if (I2S[bus_num].tx_queue == NULL) {// memory error
|
||||
log_e("MEM ERROR!");
|
||||
free(I2S[bus_num].dma_items);
|
||||
I2S[bus_num].dma_items = NULL;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void i2sSetSilenceBuf(uint8_t bus_num, uint8_t* data, size_t len) {
|
||||
if (bus_num >= I2S_NUM_MAX || !data || !len) {
|
||||
return;
|
||||
}
|
||||
I2S[bus_num].silence_buf = data;
|
||||
I2S[bus_num].silence_len = len;
|
||||
}
|
||||
|
||||
esp_err_t i2sSetClock(uint8_t bus_num, uint8_t div_num, uint8_t div_b, uint8_t div_a, uint8_t bck, uint8_t bits) {
|
||||
if (bus_num >= I2S_NUM_MAX || div_a > 63 || div_b > 63 || bck > 63) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
i2s_dev_t* i2s = I2S[bus_num].bus;
|
||||
|
||||
typeof(i2s->clkm_conf) clkm_conf;
|
||||
|
||||
clkm_conf.val = 0;
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
clkm_conf.clka_en = 0;
|
||||
#else
|
||||
clkm_conf.clk_sel = 2;
|
||||
#endif
|
||||
|
||||
clkm_conf.clkm_div_a = div_a;
|
||||
clkm_conf.clkm_div_b = div_b;
|
||||
clkm_conf.clkm_div_num = div_num;
|
||||
i2s->clkm_conf.val = clkm_conf.val;
|
||||
|
||||
typeof(i2s->sample_rate_conf) sample_rate_conf;
|
||||
sample_rate_conf.val = 0;
|
||||
sample_rate_conf.tx_bck_div_num = bck;
|
||||
sample_rate_conf.rx_bck_div_num = bck;
|
||||
sample_rate_conf.tx_bits_mod = bits;
|
||||
sample_rate_conf.rx_bits_mod = bits;
|
||||
i2s->sample_rate_conf.val = sample_rate_conf.val;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void i2sSetDac(uint8_t bus_num, bool right, bool left) {
|
||||
if (bus_num >= I2S_NUM_MAX) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!right && !left) {
|
||||
dac_output_disable(DAC_CHANNEL_1);
|
||||
dac_output_disable(DAC_CHANNEL_2);
|
||||
dac_i2s_disable();
|
||||
I2S[bus_num].bus->conf2.lcd_en = 0;
|
||||
I2S[bus_num].bus->conf.tx_right_first = 0;
|
||||
I2S[bus_num].bus->conf2.camera_en = 0;
|
||||
I2S[bus_num].bus->conf.tx_msb_shift = 1;// I2S signaling
|
||||
return;
|
||||
}
|
||||
|
||||
i2sSetPins(bus_num, -1, false);
|
||||
I2S[bus_num].bus->conf2.lcd_en = 1;
|
||||
I2S[bus_num].bus->conf.tx_right_first = 0;
|
||||
I2S[bus_num].bus->conf2.camera_en = 0;
|
||||
I2S[bus_num].bus->conf.tx_msb_shift = 0;
|
||||
dac_i2s_enable();
|
||||
|
||||
if (right) {// DAC1, right channel, GPIO25
|
||||
dac_output_enable(DAC_CHANNEL_1);
|
||||
}
|
||||
if (left) { // DAC2, left channel, GPIO26
|
||||
dac_output_enable(DAC_CHANNEL_2);
|
||||
}
|
||||
}
|
||||
|
||||
void i2sSetPins(uint8_t bus_num, int8_t out, bool invert) {
|
||||
if (bus_num >= I2S_NUM_MAX) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (out >= 0) {
|
||||
if (I2S[bus_num].out != out) {
|
||||
if (I2S[bus_num].out >= 0) {
|
||||
gpio_matrix_out(I2S[bus_num].out, 0x100, invert, false);
|
||||
}
|
||||
I2S[bus_num].out = out;
|
||||
pinMode(out, OUTPUT);
|
||||
|
||||
int i2sSignal;
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
// (I2S_NUM_MAX == 2)
|
||||
if (bus_num == 1) {
|
||||
i2sSignal = I2S1O_DATA_OUT23_IDX;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
i2sSignal = I2S0O_DATA_OUT23_IDX;
|
||||
}
|
||||
|
||||
gpio_matrix_out(out, i2sSignal, invert, false);
|
||||
}
|
||||
} else if (I2S[bus_num].out >= 0) {
|
||||
gpio_matrix_out(I2S[bus_num].out, 0x100, invert, false);
|
||||
I2S[bus_num].out = -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool i2sWriteDone(uint8_t bus_num) {
|
||||
if (bus_num >= I2S_NUM_MAX) {
|
||||
return false;
|
||||
}
|
||||
return (I2S[bus_num].dma_items[I2S[bus_num].dma_count - 1].data == I2S[bus_num].silence_buf);
|
||||
}
|
||||
|
||||
void i2sInit(uint8_t bus_num, uint32_t bits_per_sample, uint32_t sample_rate, i2s_tx_chan_mod_t chan_mod, i2s_tx_fifo_mod_t fifo_mod, size_t dma_count, size_t dma_len) {
|
||||
if (bus_num >= I2S_NUM_MAX) {
|
||||
return;
|
||||
}
|
||||
|
||||
I2S[bus_num].dma_count = dma_count;
|
||||
I2S[bus_num].dma_buf_len = dma_len & 0xFFF;
|
||||
|
||||
if (!i2sInitDmaItems(bus_num)) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
// (I2S_NUM_MAX == 2)
|
||||
if (bus_num) {
|
||||
periph_module_enable(PERIPH_I2S1_MODULE);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
periph_module_enable(PERIPH_I2S0_MODULE);
|
||||
}
|
||||
|
||||
esp_intr_disable(I2S[bus_num].isr_handle);
|
||||
i2s_dev_t* i2s = I2S[bus_num].bus;
|
||||
i2s->out_link.stop = 1;
|
||||
i2s->conf.tx_start = 0;
|
||||
i2s->int_ena.val = 0;
|
||||
i2s->int_clr.val = 0xFFFFFFFF;
|
||||
i2s->fifo_conf.dscr_en = 0;
|
||||
|
||||
// reset fifo
|
||||
i2s->conf.rx_fifo_reset = 1;
|
||||
i2s->conf.rx_fifo_reset = 0;
|
||||
i2s->conf.tx_fifo_reset = 1;
|
||||
i2s->conf.tx_fifo_reset = 0;
|
||||
|
||||
// reset i2s
|
||||
i2s->conf.tx_reset = 1;
|
||||
i2s->conf.tx_reset = 0;
|
||||
i2s->conf.rx_reset = 1;
|
||||
i2s->conf.rx_reset = 0;
|
||||
|
||||
// reset dma
|
||||
i2s->lc_conf.in_rst = 1;
|
||||
i2s->lc_conf.in_rst = 0;
|
||||
i2s->lc_conf.out_rst = 1;
|
||||
i2s->lc_conf.out_rst = 0;
|
||||
|
||||
// Enable and configure DMA
|
||||
typeof(i2s->lc_conf) lc_conf;
|
||||
lc_conf.val = 0;
|
||||
lc_conf.out_eof_mode = 1;
|
||||
i2s->lc_conf.val = lc_conf.val;
|
||||
|
||||
i2s->pdm_conf.pcm2pdm_conv_en = 0;
|
||||
i2s->pdm_conf.pdm2pcm_conv_en = 0;
|
||||
// SET_PERI_REG_BITS(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_SOC_CLK_SEL, 0x1, RTC_CNTL_SOC_CLK_SEL_S);
|
||||
|
||||
typeof(i2s->conf_chan) conf_chan;
|
||||
conf_chan.val = 0;
|
||||
conf_chan.tx_chan_mod = chan_mod; // 0-two channel;1-right;2-left;3-righ;4-left
|
||||
conf_chan.rx_chan_mod = chan_mod; // 0-two channel;1-right;2-left;3-righ;4-left
|
||||
i2s->conf_chan.val = conf_chan.val;
|
||||
|
||||
typeof(i2s->fifo_conf) fifo_conf;
|
||||
fifo_conf.val = 0;
|
||||
fifo_conf.tx_fifo_mod = fifo_mod; // 0-right&left channel;1-one channel
|
||||
fifo_conf.rx_fifo_mod = fifo_mod; // 0-right&left channel;1-one channel
|
||||
i2s->fifo_conf.val = fifo_conf.val;
|
||||
|
||||
typeof(i2s->conf) conf;
|
||||
conf.val = 0;
|
||||
conf.tx_msb_shift = (bits_per_sample != 8);// 0:DAC/PCM, 1:I2S
|
||||
conf.tx_right_first = (bits_per_sample == 8);
|
||||
i2s->conf.val = conf.val;
|
||||
|
||||
typeof(i2s->conf2) conf2;
|
||||
conf2.val = 0;
|
||||
conf2.lcd_en = (bits_per_sample == 8);
|
||||
i2s->conf2.val = conf2.val;
|
||||
|
||||
i2s->fifo_conf.tx_fifo_mod_force_en = 1;
|
||||
|
||||
i2s->pdm_conf.rx_pdm_en = 0;
|
||||
i2s->pdm_conf.tx_pdm_en = 0;
|
||||
|
||||
i2sSetSampleRate(bus_num, sample_rate, bits_per_sample);
|
||||
|
||||
// enable intr in cpu //
|
||||
int i2sIntSource;
|
||||
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
// (I2S_NUM_MAX == 2)
|
||||
if (bus_num == 1) {
|
||||
i2sIntSource = ETS_I2S1_INTR_SOURCE;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
i2sIntSource = ETS_I2S0_INTR_SOURCE;
|
||||
}
|
||||
|
||||
|
||||
esp_intr_alloc(i2sIntSource, ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_LEVEL1, &i2sDmaISR, &I2S[bus_num], &I2S[bus_num].isr_handle);
|
||||
// enable send intr
|
||||
i2s->int_ena.out_eof = 1;
|
||||
i2s->int_ena.out_dscr_err = 1;
|
||||
|
||||
i2s->fifo_conf.dscr_en = 1;// enable dma
|
||||
i2s->out_link.start = 0;
|
||||
i2s->out_link.addr = (uint32_t)(&I2S[bus_num].dma_items[0]); // loads dma_struct to dma
|
||||
i2s->out_link.start = 1; // starts dma
|
||||
i2s->conf.tx_start = 1;// Start I2s module
|
||||
|
||||
esp_intr_enable(I2S[bus_num].isr_handle);
|
||||
}
|
||||
|
||||
esp_err_t i2sSetSampleRate(uint8_t bus_num, uint32_t rate, uint8_t bits) {
|
||||
if (bus_num >= I2S_NUM_MAX) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
if (I2S[bus_num].rate == rate) {
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
int clkmInteger, clkmDecimals, bck = 0;
|
||||
double denom = (double)1 / 63;
|
||||
int channel = 2;
|
||||
|
||||
// double mclk;
|
||||
double clkmdiv;
|
||||
|
||||
int factor;
|
||||
|
||||
if (bits == 8) {
|
||||
factor = 120;
|
||||
} else {
|
||||
factor = (256 % bits) ? 384 : 256;
|
||||
}
|
||||
|
||||
clkmdiv = (double)I2S_BASE_CLK / (rate* factor);
|
||||
if (clkmdiv > 256) {
|
||||
log_e("rate is too low");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
I2S[bus_num].rate = rate;
|
||||
|
||||
clkmInteger = clkmdiv;
|
||||
clkmDecimals = ((clkmdiv - clkmInteger) / denom);
|
||||
|
||||
if (bits == 8) {
|
||||
// mclk = rate* factor;
|
||||
bck = 60;
|
||||
bits = 16;
|
||||
} else {
|
||||
// mclk = (double)clkmInteger + (denom* clkmDecimals);
|
||||
bck = factor/(bits* channel);
|
||||
}
|
||||
|
||||
i2sSetClock(bus_num, clkmInteger, clkmDecimals, 63, bck, bits);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void IRAM_ATTR i2sDmaISR(void* arg)
|
||||
{
|
||||
i2s_dma_item_t* dummy = NULL;
|
||||
i2s_bus_t* dev = (i2s_bus_t*)(arg);
|
||||
portBASE_TYPE hpTaskAwoken = 0;
|
||||
|
||||
if (dev->bus->int_st.out_eof) {
|
||||
i2s_dma_item_t* item = (i2s_dma_item_t*)(dev->bus->out_eof_des_addr);
|
||||
item->data = dev->silence_buf;
|
||||
item->blocksize = dev->silence_len;
|
||||
item->datalen = dev->silence_len;
|
||||
if (xQueueIsQueueFullFromISR(dev->tx_queue) == pdTRUE) {
|
||||
xQueueReceiveFromISR(dev->tx_queue, &dummy, &hpTaskAwoken);
|
||||
}
|
||||
xQueueSendFromISR(dev->tx_queue, (void*)&item, &hpTaskAwoken);
|
||||
}
|
||||
dev->bus->int_clr.val = dev->bus->int_st.val;
|
||||
if (hpTaskAwoken == pdTRUE) {
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
}
|
||||
|
||||
size_t i2sWrite(uint8_t bus_num, uint8_t* data, size_t len, bool copy, bool free_when_sent) {
|
||||
if (bus_num >= I2S_NUM_MAX || !I2S[bus_num].tx_queue) {
|
||||
return 0;
|
||||
}
|
||||
size_t index = 0;
|
||||
size_t toSend = len;
|
||||
size_t limit = I2S_DMA_MAX_DATA_LEN;
|
||||
i2s_dma_item_t* item = NULL;
|
||||
|
||||
while (len) {
|
||||
toSend = len;
|
||||
if (toSend > limit) {
|
||||
toSend = limit;
|
||||
}
|
||||
|
||||
if (xQueueReceive(I2S[bus_num].tx_queue, &item, portMAX_DELAY) == pdFALSE) {
|
||||
log_e("xQueueReceive failed\n");
|
||||
break;
|
||||
}
|
||||
// data is constant. no need to copy
|
||||
item->data = data + index;
|
||||
item->blocksize = toSend;
|
||||
item->datalen = toSend;
|
||||
|
||||
len -= toSend;
|
||||
index += toSend;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
38
lib/NeoPixelBus_by_Makuna/src/internal/Esp32_i2s.h
Normal file
38
lib/NeoPixelBus_by_Makuna/src/internal/Esp32_i2s.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP32)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "esp_err.h"
|
||||
|
||||
#define I2S_DMA_MAX_DATA_LEN 4092// maximum bytes in one dma item
|
||||
|
||||
typedef enum {
|
||||
I2S_CHAN_STEREO, I2S_CHAN_RIGHT_TO_LEFT, I2S_CHAN_LEFT_TO_RIGHT, I2S_CHAN_RIGHT_ONLY, I2S_CHAN_LEFT_ONLY
|
||||
} i2s_tx_chan_mod_t;
|
||||
|
||||
typedef enum {
|
||||
I2S_FIFO_16BIT_DUAL, I2S_FIFO_16BIT_SINGLE, I2S_FIFO_32BIT_DUAL, I2S_FIFO_32BIT_SINGLE
|
||||
} i2s_tx_fifo_mod_t;
|
||||
|
||||
void i2sInit(uint8_t bus_num, uint32_t bits_per_sample, uint32_t sample_rate, i2s_tx_chan_mod_t chan_mod, i2s_tx_fifo_mod_t fifo_mod, size_t dma_count, size_t dma_len);
|
||||
|
||||
void i2sSetPins(uint8_t bus_num, int8_t out, bool invert);
|
||||
void i2sSetDac(uint8_t bus_num, bool right, bool left);
|
||||
|
||||
esp_err_t i2sSetClock(uint8_t bus_num, uint8_t div_num, uint8_t div_b, uint8_t div_a, uint8_t bck, uint8_t bits_per_sample);
|
||||
esp_err_t i2sSetSampleRate(uint8_t bus_num, uint32_t sample_rate, uint8_t bits_per_sample);
|
||||
|
||||
void i2sSetSilenceBuf(uint8_t bus_num, uint8_t* data, size_t len);
|
||||
|
||||
size_t i2sWrite(uint8_t bus_num, uint8_t* data, size_t len, bool copy, bool free_when_sent);
|
||||
bool i2sWriteDone(uint8_t bus_num);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
68
lib/NeoPixelBus_by_Makuna/src/internal/HsbColor.cpp
Normal file
68
lib/NeoPixelBus_by_Makuna/src/internal/HsbColor.cpp
Normal file
@@ -0,0 +1,68 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
HsbColor provides a color object that can be directly consumed by NeoPixelBus
|
||||
|
||||
Written by Michael C. Miller.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
|
||||
#include "RgbColor.h"
|
||||
#include "HsbColor.h"
|
||||
|
||||
|
||||
HsbColor::HsbColor(const RgbColor& color)
|
||||
{
|
||||
// convert colors to float between (0.0 - 1.0)
|
||||
float r = color.R / 255.0f;
|
||||
float g = color.G / 255.0f;
|
||||
float b = color.B / 255.0f;
|
||||
|
||||
float max = (r > g && r > b) ? r : (g > b) ? g : b;
|
||||
float min = (r < g && r < b) ? r : (g < b) ? g : b;
|
||||
|
||||
float d = max - min;
|
||||
|
||||
float h = 0.0;
|
||||
float v = max;
|
||||
float s = (v == 0.0f) ? 0 : (d / v);
|
||||
|
||||
if (d != 0.0f)
|
||||
{
|
||||
if (r == max)
|
||||
{
|
||||
h = (g - b) / d + (g < b ? 6.0f : 0.0f);
|
||||
}
|
||||
else if (g == max)
|
||||
{
|
||||
h = (b - r) / d + 2.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
h = (r - g) / d + 4.0f;
|
||||
}
|
||||
h /= 6.0f;
|
||||
}
|
||||
|
||||
|
||||
H = h;
|
||||
S = s;
|
||||
B = v;
|
||||
}
|
||||
113
lib/NeoPixelBus_by_Makuna/src/internal/HsbColor.h
Normal file
113
lib/NeoPixelBus_by_Makuna/src/internal/HsbColor.h
Normal file
@@ -0,0 +1,113 @@
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
HsbColor provides a color object that can be directly consumed by NeoPixelBus
|
||||
|
||||
Written by Michael C. Miller.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// HsbColor represents a color object that is represented by Hue, Saturation, Brightness
|
||||
// component values. It contains helpful color routines to manipulate the
|
||||
// color.
|
||||
// ------------------------------------------------------------------------
|
||||
struct HsbColor
|
||||
{
|
||||
// ------------------------------------------------------------------------
|
||||
// Construct a HsbColor using H, S, B values (0.0 - 1.0)
|
||||
// ------------------------------------------------------------------------
|
||||
HsbColor(float h, float s, float b) :
|
||||
H(h), S(s), B(b)
|
||||
{
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Construct a HsbColor using RgbColor
|
||||
// ------------------------------------------------------------------------
|
||||
HsbColor(const RgbColor& color);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Construct a HsbColor that will have its values set in latter operations
|
||||
// CAUTION: The H,S,B members are not initialized and may not be consistent
|
||||
// ------------------------------------------------------------------------
|
||||
HsbColor()
|
||||
{
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// LinearBlend between two colors by the amount defined by progress variable
|
||||
// left - the color to start the blend at
|
||||
// right - the color to end the blend at
|
||||
// progress - (0.0 - 1.0) value where 0.0 will return left and 1.0 will return right
|
||||
// and a value between will blend the color weighted linearly between them
|
||||
// ------------------------------------------------------------------------
|
||||
template <typename T_NEOHUEBLEND> static HsbColor LinearBlend(const HsbColor& left,
|
||||
const HsbColor& right,
|
||||
float progress)
|
||||
{
|
||||
return HsbColor(T_NEOHUEBLEND::HueBlend(left.H, right.H, progress),
|
||||
left.S + ((right.S - left.S) * progress),
|
||||
left.B + ((right.B - left.B) * progress));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// BilinearBlend between four colors by the amount defined by 2d variable
|
||||
// c00 - upper left quadrant color
|
||||
// c01 - upper right quadrant color
|
||||
// c10 - lower left quadrant color
|
||||
// c11 - lower right quadrant color
|
||||
// x - unit value (0.0 - 1.0) that defines the blend progress in horizontal space
|
||||
// y - unit value (0.0 - 1.0) that defines the blend progress in vertical space
|
||||
// ------------------------------------------------------------------------
|
||||
template <typename T_NEOHUEBLEND> static HsbColor BilinearBlend(const HsbColor& c00,
|
||||
const HsbColor& c01,
|
||||
const HsbColor& c10,
|
||||
const HsbColor& c11,
|
||||
float x,
|
||||
float y)
|
||||
{
|
||||
float v00 = (1.0f - x) * (1.0f - y);
|
||||
float v10 = x * (1.0f - y);
|
||||
float v01 = (1.0f - x) * y;
|
||||
float v11 = x * y;
|
||||
|
||||
return HsbColor(
|
||||
T_NEOHUEBLEND::HueBlend(
|
||||
T_NEOHUEBLEND::HueBlend(c00.H, c10.H, x),
|
||||
T_NEOHUEBLEND::HueBlend(c01.H, c11.H, x),
|
||||
y),
|
||||
c00.S * v00 + c10.S * v10 + c01.S * v01 + c11.S * v11,
|
||||
c00.B * v00 + c10.B * v10 + c01.B * v01 + c11.B * v11);
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Hue, Saturation, Brightness color members
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
float H;
|
||||
float S;
|
||||
float B;
|
||||
};
|
||||
|
||||
72
lib/NeoPixelBus_by_Makuna/src/internal/HslColor.cpp
Normal file
72
lib/NeoPixelBus_by_Makuna/src/internal/HslColor.cpp
Normal file
@@ -0,0 +1,72 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
HslColor provides a color object that can be directly consumed by NeoPixelBus
|
||||
|
||||
|
||||
Written by Michael C. Miller.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
|
||||
#include "RgbColor.h"
|
||||
#include "HslColor.h"
|
||||
|
||||
|
||||
HslColor::HslColor(const RgbColor& color)
|
||||
{
|
||||
// convert colors to float between (0.0 - 1.0)
|
||||
float r = color.R / 255.0f;
|
||||
float g = color.G / 255.0f;
|
||||
float b = color.B / 255.0f;
|
||||
|
||||
float max = (r > g && r > b) ? r : (g > b) ? g : b;
|
||||
float min = (r < g && r < b) ? r : (g < b) ? g : b;
|
||||
|
||||
float h, s, l;
|
||||
l = (max + min) / 2.0f;
|
||||
|
||||
if (max == min)
|
||||
{
|
||||
h = s = 0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
float d = max - min;
|
||||
s = (l > 0.5f) ? d / (2.0f - (max + min)) : d / (max + min);
|
||||
|
||||
if (r > g && r > b)
|
||||
{
|
||||
h = (g - b) / d + (g < b ? 6.0f : 0.0f);
|
||||
}
|
||||
else if (g > b)
|
||||
{
|
||||
h = (b - r) / d + 2.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
h = (r - g) / d + 4.0f;
|
||||
}
|
||||
h /= 6.0f;
|
||||
}
|
||||
|
||||
H = h;
|
||||
S = s;
|
||||
L = l;
|
||||
}
|
||||
113
lib/NeoPixelBus_by_Makuna/src/internal/HslColor.h
Normal file
113
lib/NeoPixelBus_by_Makuna/src/internal/HslColor.h
Normal file
@@ -0,0 +1,113 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
HslColor provides a color object that can be directly consumed by NeoPixelBus
|
||||
|
||||
Written by Michael C. Miller.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// HslColor represents a color object that is represented by Hue, Saturation, Lightness
|
||||
// component values. It contains helpful color routines to manipulate the
|
||||
// color.
|
||||
// ------------------------------------------------------------------------
|
||||
struct HslColor
|
||||
{
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Construct a HslColor using H, S, L values (0.0 - 1.0)
|
||||
// L should be limited to between (0.0 - 0.5)
|
||||
// ------------------------------------------------------------------------
|
||||
HslColor(float h, float s, float l) :
|
||||
H(h), S(s), L(l)
|
||||
{
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Construct a HslColor using RgbColor
|
||||
// ------------------------------------------------------------------------
|
||||
HslColor(const RgbColor& color);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Construct a HslColor that will have its values set in latter operations
|
||||
// CAUTION: The H,S,L members are not initialized and may not be consistent
|
||||
// ------------------------------------------------------------------------
|
||||
HslColor()
|
||||
{
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// LinearBlend between two colors by the amount defined by progress variable
|
||||
// left - the color to start the blend at
|
||||
// right - the color to end the blend at
|
||||
// progress - (0.0 - 1.0) value where 0.0 will return left and 1.0 will return right
|
||||
// and a value between will blend the color weighted linearly between them
|
||||
// ------------------------------------------------------------------------
|
||||
template <typename T_NEOHUEBLEND> static HslColor LinearBlend(const HslColor& left,
|
||||
const HslColor& right,
|
||||
float progress)
|
||||
{
|
||||
return HslColor(T_NEOHUEBLEND::HueBlend(left.H, right.H, progress),
|
||||
left.S + ((right.S - left.S) * progress),
|
||||
left.L + ((right.L - left.L) * progress));
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// BilinearBlend between four colors by the amount defined by 2d variable
|
||||
// c00 - upper left quadrant color
|
||||
// c01 - upper right quadrant color
|
||||
// c10 - lower left quadrant color
|
||||
// c11 - lower right quadrant color
|
||||
// x - unit value (0.0 - 1.0) that defines the blend progress in horizontal space
|
||||
// y - unit value (0.0 - 1.0) that defines the blend progress in vertical space
|
||||
// ------------------------------------------------------------------------
|
||||
template <typename T_NEOHUEBLEND> static HslColor BilinearBlend(const HslColor& c00,
|
||||
const HslColor& c01,
|
||||
const HslColor& c10,
|
||||
const HslColor& c11,
|
||||
float x,
|
||||
float y)
|
||||
{
|
||||
float v00 = (1.0f - x) * (1.0f - y);
|
||||
float v10 = x * (1.0f - y);
|
||||
float v01 = (1.0f - x) * y;
|
||||
float v11 = x * y;
|
||||
|
||||
return HslColor(
|
||||
T_NEOHUEBLEND::HueBlend(
|
||||
T_NEOHUEBLEND::HueBlend(c00.H, c10.H, x),
|
||||
T_NEOHUEBLEND::HueBlend(c01.H, c11.H, x),
|
||||
y),
|
||||
c00.S * v00 + c10.S * v10 + c01.S * v01 + c11.S * v11,
|
||||
c00.L * v00 + c10.L * v10 + c01.L * v01 + c11.L * v11);
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Hue, Saturation, Lightness color members
|
||||
// ------------------------------------------------------------------------
|
||||
float H;
|
||||
float S;
|
||||
float L;
|
||||
};
|
||||
|
||||
58
lib/NeoPixelBus_by_Makuna/src/internal/HtmlColor.cpp
Normal file
58
lib/NeoPixelBus_by_Makuna/src/internal/HtmlColor.cpp
Normal file
@@ -0,0 +1,58 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
This file contains the HtmlColor implementation
|
||||
|
||||
Written by Unai Uribarri
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
#include "HtmlColor.h"
|
||||
|
||||
static inline char hexdigit(uint8_t v)
|
||||
{
|
||||
return v + (v < 10 ? '0' : 'a' - 10);
|
||||
}
|
||||
|
||||
|
||||
size_t HtmlColor::ToNumericalString(char* buf, size_t bufSize) const
|
||||
{
|
||||
size_t bufLen = bufSize - 1;
|
||||
|
||||
if (bufLen-- > 0)
|
||||
{
|
||||
if (bufLen > 0)
|
||||
{
|
||||
buf[0] = '#';
|
||||
}
|
||||
|
||||
uint32_t color = Color;
|
||||
for (uint8_t indexDigit = 6; indexDigit > 0; indexDigit--)
|
||||
{
|
||||
if (bufLen > indexDigit)
|
||||
{
|
||||
buf[indexDigit] = hexdigit(color & 0x0000000f);
|
||||
}
|
||||
color >>= 4;
|
||||
}
|
||||
|
||||
buf[(bufLen < 7 ? bufLen : 7)] = 0;
|
||||
}
|
||||
return 7;
|
||||
}
|
||||
340
lib/NeoPixelBus_by_Makuna/src/internal/HtmlColor.h
Normal file
340
lib/NeoPixelBus_by_Makuna/src/internal/HtmlColor.h
Normal file
@@ -0,0 +1,340 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
HtmlColor provides a color object that can be directly consumed by NeoPixelBus
|
||||
|
||||
Written by Michael C. Miller.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "RgbColor.h"
|
||||
|
||||
#define MAX_HTML_COLOR_NAME_LEN 21
|
||||
|
||||
#ifndef pgm_read_ptr
|
||||
// ESP8266 doesn't define this macro
|
||||
#define pgm_read_ptr(addr) (*reinterpret_cast<const void* const *>(addr))
|
||||
#endif
|
||||
|
||||
#ifndef countof
|
||||
#define countof(array) (sizeof(array)/sizeof(array[0]))
|
||||
#endif
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// HtmlColorPair represents an association between a name and a HTML color code
|
||||
// ------------------------------------------------------------------------
|
||||
struct HtmlColorPair
|
||||
{
|
||||
PGM_P Name;
|
||||
uint32_t Color;
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// HtmlShortColorNames is a template class used for Parse and ToString
|
||||
// ------------------------------------------------------------------------
|
||||
class HtmlShortColorNames
|
||||
{
|
||||
public:
|
||||
static const HtmlColorPair* Pair(uint8_t index);
|
||||
static uint8_t Count();
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// HtmlColorNames is a template class used for Parse and ToString
|
||||
// ------------------------------------------------------------------------
|
||||
class HtmlColorNames
|
||||
{
|
||||
public:
|
||||
static const HtmlColorPair* Pair(uint8_t index);
|
||||
static uint8_t Count();
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// HtmlColor represents a color object that is represented by a single uint32
|
||||
// value. It contains minimal routines and used primarily as a helper to
|
||||
// initialize other color objects
|
||||
// ------------------------------------------------------------------------
|
||||
struct HtmlColor
|
||||
{
|
||||
// ------------------------------------------------------------------------
|
||||
// Construct a HtmlColor using a single value (0-0xffffff)
|
||||
// This works well for hexidecimal color definitions
|
||||
// 0xff0000 = red, 0x00ff00 = green, and 0x0000ff = blue
|
||||
// ------------------------------------------------------------------------
|
||||
HtmlColor(uint32_t color) :
|
||||
Color(color)
|
||||
{
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Construct a HtmlColor using RgbColor
|
||||
// ------------------------------------------------------------------------
|
||||
HtmlColor(const RgbColor& color)
|
||||
{
|
||||
Color = (uint32_t)color.R << 16 | (uint32_t)color.G << 8 | (uint32_t)color.B;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Construct a HtmlColor that will have its values set in latter operations
|
||||
// CAUTION: The Color member is not initialized and may not be consistent
|
||||
// ------------------------------------------------------------------------
|
||||
HtmlColor()
|
||||
{
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Comparison operators
|
||||
// ------------------------------------------------------------------------
|
||||
bool operator==(const HtmlColor& other) const
|
||||
{
|
||||
return (Color == other.Color);
|
||||
};
|
||||
|
||||
bool operator!=(const HtmlColor& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Parse a HTML4/CSS3 color name
|
||||
// T_HTMLCOLORNAMES - template class that defines the collection of names
|
||||
// name - the color name
|
||||
// nameSize - the max size of name to check
|
||||
//
|
||||
// returns - zero if failed, or the number of chars parsed
|
||||
//
|
||||
// It will stop parsing name when a null terminator is reached,
|
||||
// nameSize is reached, no match is found in the name/color pair table, or
|
||||
// a non-alphanumeric is read like seperators or whitespace.
|
||||
//
|
||||
// It also accepts 3 or 6 digit hexadecimal notation (#rgb or #rrggbb),
|
||||
// but it doesn't accept RGB, RGBA nor HSL values.
|
||||
//
|
||||
// See https://www.w3.org/TR/css3-color/#SRGB
|
||||
//
|
||||
// name must point to the first non-whitespace character to be parsed
|
||||
// parsing will stop at the first non-alpha numeric
|
||||
//
|
||||
// Name MUST NOT be a PROGMEM pointer
|
||||
//
|
||||
// examples:
|
||||
// Parse<HtmlShortColorNames>(buff, buffSize);
|
||||
// Parse<HtmlColorNames>(buff, buffSize);
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
template <typename T_HTMLCOLORNAMES> size_t Parse(const char* name, size_t nameSize)
|
||||
{
|
||||
if (nameSize > 0)
|
||||
{
|
||||
if (name[0] == '#')
|
||||
{
|
||||
// Parse an hexadecimal notation "#rrbbgg" or "#rgb"
|
||||
//
|
||||
uint8_t temp[6]; // stores preconverted chars to hex values
|
||||
uint8_t tempSize = 0;
|
||||
|
||||
for (uint8_t indexChar = 1; indexChar < nameSize && indexChar < 8; ++indexChar)
|
||||
{
|
||||
char c = name[indexChar];
|
||||
if (c >= '0' && c <= '9')
|
||||
{
|
||||
c -= '0';
|
||||
}
|
||||
else
|
||||
{
|
||||
// Convert a letter to lower case (only for ASCII letters)
|
||||
// It's faster & smaller than tolower()
|
||||
c |= 32;
|
||||
if (c >= 'a' && c <= 'f')
|
||||
{
|
||||
c = c - 'a' + 10;
|
||||
}
|
||||
else
|
||||
{
|
||||
// we found an non hexidecimal char
|
||||
// which could be null, deliminator, or other spacing
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
temp[tempSize] = c;
|
||||
tempSize++;
|
||||
}
|
||||
|
||||
if (tempSize != 3 && tempSize != 6)
|
||||
{
|
||||
// invalid count of numerical chars
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t color = 0;
|
||||
for (uint8_t indexChar = 0; indexChar < tempSize; ++indexChar)
|
||||
{
|
||||
color = color * 16 + temp[indexChar];
|
||||
if (tempSize == 3)
|
||||
{
|
||||
// 3 digit hexadecimal notation can be supported easily
|
||||
// duplicating digits.
|
||||
color = color * 16 + temp[indexChar];
|
||||
}
|
||||
}
|
||||
|
||||
Color = color;
|
||||
return tempSize;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// parse a standard name for the color
|
||||
//
|
||||
|
||||
// the normal list is small enough a binary search isn't interesting,
|
||||
for (uint8_t indexName = 0; indexName < T_HTMLCOLORNAMES::Count(); ++indexName)
|
||||
{
|
||||
const HtmlColorPair* colorPair = T_HTMLCOLORNAMES::Pair(indexName);
|
||||
PGM_P searchName = reinterpret_cast<PGM_P>(pgm_read_ptr(&(colorPair->Name)));
|
||||
size_t str1Size = nameSize;
|
||||
const char* str1 = name;
|
||||
const char* str2P = searchName;
|
||||
|
||||
uint16_t result;
|
||||
|
||||
while (str1Size > 0)
|
||||
{
|
||||
char ch1 = tolower(*str1++);
|
||||
char ch2 = tolower(pgm_read_byte(str2P++));
|
||||
result = ch1 - ch2;
|
||||
if (result != 0 || ch2 == '\0')
|
||||
{
|
||||
if (ch2 == '\0' && !isalnum(ch1))
|
||||
{
|
||||
// the string continues but is not part of a
|
||||
// valid color name,
|
||||
// ends in white space, deliminator, etc
|
||||
result = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
result = -1; // have not reached the end of searchName;
|
||||
str1Size--;
|
||||
}
|
||||
|
||||
if (result == 0)
|
||||
{
|
||||
Color = pgm_read_dword(&colorPair->Color);
|
||||
return nameSize - str1Size;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename T_HTMLCOLORNAMES> size_t Parse(const char* name)
|
||||
{
|
||||
return Parse<T_HTMLCOLORNAMES>(name, MAX_HTML_COLOR_NAME_LEN + 1);
|
||||
}
|
||||
|
||||
template <typename T_HTMLCOLORNAMES> size_t Parse(String const &name)
|
||||
{
|
||||
return Parse<T_HTMLCOLORNAMES>(name.c_str(), name.length() + 1);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Converts this color code to its HTML4/CSS3 name
|
||||
// T_HTMLCOLORNAMES - template class that defines the collection of names
|
||||
// buf - buffer to write the string
|
||||
// bufSize - actual size of buf array
|
||||
//
|
||||
// It returns the number of chars required not including the NUL terminator.
|
||||
//
|
||||
// If there is not enough space in the buffer, it will write as many
|
||||
// characters as allowed and will always finish the buffer with a NUL char
|
||||
//
|
||||
// examples:
|
||||
// ToString<HtmlShortColorNames>(buf, bufSize);
|
||||
// ToString<htmlColorNames>(buf, bufSize);
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
template <typename T_HTMLCOLORNAMES> size_t ToString(char* buf, size_t bufSize) const
|
||||
{
|
||||
// search for a color value/name pairs first
|
||||
for (uint8_t indexName = 0; indexName < T_HTMLCOLORNAMES::Count(); ++indexName)
|
||||
{
|
||||
const HtmlColorPair* colorPair = T_HTMLCOLORNAMES::Pair(indexName);
|
||||
if (pgm_read_dword(&colorPair->Color) == Color)
|
||||
{
|
||||
PGM_P name = (PGM_P)pgm_read_ptr(&colorPair->Name);
|
||||
strncpy_P(buf, name, bufSize);
|
||||
return strlen_P(name);
|
||||
}
|
||||
}
|
||||
|
||||
// no color name pair match, convert using numerical format
|
||||
return ToNumericalString(buf, bufSize);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Converts this color code to its HTML4/CSS3 numerical name
|
||||
//
|
||||
// buf - buffer to write the string
|
||||
// bufSize - actual size of buf array
|
||||
//
|
||||
// It returns the number of chars required not including the NUL terminator.
|
||||
//
|
||||
// If there is not enough space in the buffer, it will write as many
|
||||
// characters as allowed and will always finish the buffer with a NUL char
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
size_t ToNumericalString(char* buf, size_t bufSize) const;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// BilinearBlend between four colors by the amount defined by 2d variable
|
||||
// c00 - upper left quadrant color
|
||||
// c01 - upper right quadrant color
|
||||
// c10 - lower left quadrant color
|
||||
// c11 - lower right quadrant color
|
||||
// x - unit value (0.0 - 1.0) that defines the blend progress in horizontal space
|
||||
// y - unit value (0.0 - 1.0) that defines the blend progress in vertical space
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
static HtmlColor BilinearBlend(const HtmlColor& c00,
|
||||
const HtmlColor& c01,
|
||||
const HtmlColor& c10,
|
||||
const HtmlColor& c11,
|
||||
float x,
|
||||
float y)
|
||||
{
|
||||
return RgbColor::BilinearBlend(c00, c01, c10, c11, x, y);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Color member (0-0xffffff) where
|
||||
// 0xff0000 is red
|
||||
// 0x00ff00 is green
|
||||
// 0x0000ff is blue
|
||||
// ------------------------------------------------------------------------
|
||||
uint32_t Color;
|
||||
};
|
||||
|
||||
178
lib/NeoPixelBus_by_Makuna/src/internal/HtmlColorNameStrings.cpp
Normal file
178
lib/NeoPixelBus_by_Makuna/src/internal/HtmlColorNameStrings.cpp
Normal file
@@ -0,0 +1,178 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
HtmlColorNameStrings provides the implemenation of the color string names
|
||||
|
||||
Written by Michael C. Miller.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
|
||||
#include "HtmlColorNameStrings.h"
|
||||
|
||||
/* HTML4 color names */
|
||||
const char c_HtmlNameAqua[] PROGMEM = "aqua";
|
||||
const char c_HtmlNameBlack[] PROGMEM = "black";
|
||||
const char c_HtmlNameBlue[] PROGMEM = "blue";
|
||||
const char c_HtmlNameFuchsia[] PROGMEM = "fuchsia";
|
||||
const char c_HtmlNameGray[] PROGMEM = "gray";
|
||||
const char c_HtmlNameGreen[] PROGMEM = "green";
|
||||
const char c_HtmlNameLime[] PROGMEM = "lime";
|
||||
const char c_HtmlNameMaroon[] PROGMEM = "maroon";
|
||||
const char c_HtmlNameNavy[] PROGMEM = "navy";
|
||||
const char c_HtmlNameOlive[] PROGMEM = "olive";
|
||||
const char c_HtmlNameOrange[] PROGMEM = "orange";
|
||||
const char c_HtmlNamePurple[] PROGMEM = "purple";
|
||||
const char c_HtmlNameRed[] PROGMEM = "red";
|
||||
const char c_HtmlNameSilver[] PROGMEM = "silver";
|
||||
const char c_HtmlNameTeal[] PROGMEM = "teal";
|
||||
const char c_HtmlNameWhite[] PROGMEM = "white";
|
||||
const char c_HtmlNameYellow[] PROGMEM = "yellow";
|
||||
|
||||
/* Additional CSS3 color names */
|
||||
const char c_HtmlNameAliceBlue[] PROGMEM = "aliceblue";
|
||||
const char c_HtmlNameAntiqueWhite[] PROGMEM = "antiquewhite";
|
||||
const char c_HtmlNameAquamarine[] PROGMEM = "aquamarine";
|
||||
const char c_HtmlNameAzure[] PROGMEM = "azure";
|
||||
const char c_HtmlNameBeige[] PROGMEM = "beige";
|
||||
const char c_HtmlNameBisque[] PROGMEM = "bisque";
|
||||
const char c_HtmlNameBlanchedAlmond[] PROGMEM = "blanchedalmond";
|
||||
const char c_HtmlNameBlueViolet[] PROGMEM = "blueviolet";
|
||||
const char c_HtmlNameBrown[] PROGMEM = "brown";
|
||||
const char c_HtmlNameBurlyWood[] PROGMEM = "burlywood";
|
||||
const char c_HtmlNameCadetBlue[] PROGMEM = "cadetblue";
|
||||
const char c_HtmlNameChartreuse[] PROGMEM = "chartreuse";
|
||||
const char c_HtmlNameChocolate[] PROGMEM = "chocolate";
|
||||
const char c_HtmlNameCoral[] PROGMEM = "coral";
|
||||
const char c_HtmlNameCornflowerBlue[] PROGMEM = "cornflowerblue";
|
||||
const char c_HtmlNameCornsilk[] PROGMEM = "cornsilk";
|
||||
const char c_HtmlNameCrimson[] PROGMEM = "crimson";
|
||||
const char c_HtmlNameCyan[] PROGMEM = "cyan";
|
||||
const char c_HtmlNameDarkBlue[] PROGMEM = "darkblue";
|
||||
const char c_HtmlNameDarkCyan[] PROGMEM = "darkcyan";
|
||||
const char c_HtmlNameDarkGoldenrod[] PROGMEM = "darkgoldenrod";
|
||||
const char c_HtmlNameDarkGray[] PROGMEM = "darkgray";
|
||||
const char c_HtmlNameDarkGreen[] PROGMEM = "darkgreen";
|
||||
const char c_HtmlNameDarkGrey[] PROGMEM = "darkgrey";
|
||||
const char c_HtmlNameDarkKhaki[] PROGMEM = "darkkhaki";
|
||||
const char c_HtmlNameDarkMagenta[] PROGMEM = "darkmagenta";
|
||||
const char c_HtmlNameDarkOliveGreen[] PROGMEM = "darkolivegreen";
|
||||
const char c_HtmlNameDarkOrange[] PROGMEM = "darkorange";
|
||||
const char c_HtmlNameDarkOrchid[] PROGMEM = "darkorchid";
|
||||
const char c_HtmlNameDarkRed[] PROGMEM = "darkred";
|
||||
const char c_HtmlNameDarkSalmon[] PROGMEM = "darksalmon";
|
||||
const char c_HtmlNameDarkSeaGreen[] PROGMEM = "darkseagreen";
|
||||
const char c_HtmlNameDarkSlateBlue[] PROGMEM = "darkslateblue";
|
||||
const char c_HtmlNameDarkSlateGray[] PROGMEM = "darkslategray";
|
||||
const char c_HtmlNameDarkSlateGrey[] PROGMEM = "darkslategrey";
|
||||
const char c_HtmlNameDarkTurquoise[] PROGMEM = "darkturquoise";
|
||||
const char c_HtmlNameDarkViolet[] PROGMEM = "darkviolet";
|
||||
const char c_HtmlNameDeepPink[] PROGMEM = "deeppink";
|
||||
const char c_HtmlNameDeepSkyBlue[] PROGMEM = "deepskyblue";
|
||||
const char c_HtmlNameDimGray[] PROGMEM = "dimgray";
|
||||
const char c_HtmlNameDimGrey[] PROGMEM = "dimgrey";
|
||||
const char c_HtmlNameDodgerBlue[] PROGMEM = "dodgerblue";
|
||||
const char c_HtmlNameFirebrick[] PROGMEM = "firebrick";
|
||||
const char c_HtmlNameFloralWhite[] PROGMEM = "floralwhite";
|
||||
const char c_HtmlNameForestGreen[] PROGMEM = "forestgreen";
|
||||
const char c_HtmlNameGainsboro[] PROGMEM = "gainsboro";
|
||||
const char c_HtmlNameGhostWhite[] PROGMEM = "ghostwhite";
|
||||
const char c_HtmlNameGold[] PROGMEM = "gold";
|
||||
const char c_HtmlNameGoldenrod[] PROGMEM = "goldenrod";
|
||||
const char c_HtmlNameGreenYellow[] PROGMEM = "greenyellow";
|
||||
const char c_HtmlNameGrey[] PROGMEM = "grey";
|
||||
const char c_HtmlNameHoneydew[] PROGMEM = "honeydew";
|
||||
const char c_HtmlNameHotPink[] PROGMEM = "hotpink";
|
||||
const char c_HtmlNameIndianRed[] PROGMEM = "indianred";
|
||||
const char c_HtmlNameIndigo[] PROGMEM = "indigo";
|
||||
const char c_HtmlNameIvory[] PROGMEM = "ivory";
|
||||
const char c_HtmlNameKhaki[] PROGMEM = "khaki";
|
||||
const char c_HtmlNameLavender[] PROGMEM = "lavender";
|
||||
const char c_HtmlNameLavenderBlush[] PROGMEM = "lavenderblush";
|
||||
const char c_HtmlNameLawnGreen[] PROGMEM = "lawngreen";
|
||||
const char c_HtmlNameLemonChiffon[] PROGMEM = "lemonchiffon";
|
||||
const char c_HtmlNameLightBlue[] PROGMEM = "lightblue";
|
||||
const char c_HtmlNameLightCoral[] PROGMEM = "lightcoral";
|
||||
const char c_HtmlNameLightCyan[] PROGMEM = "lightcyan";
|
||||
const char c_HtmlNameLightGoldenrodYellow[] PROGMEM = "lightgoldenrodyellow";
|
||||
const char c_HtmlNameLightGray[] PROGMEM = "lightgray";
|
||||
const char c_HtmlNameLightGreen[] PROGMEM = "lightgreen";
|
||||
const char c_HtmlNameLightGrey[] PROGMEM = "lightgrey";
|
||||
const char c_HtmlNameLightPink[] PROGMEM = "lightpink";
|
||||
const char c_HtmlNameLightSalmon[] PROGMEM = "lightsalmon";
|
||||
const char c_HtmlNameLightSeaGreen[] PROGMEM = "lightseagreen";
|
||||
const char c_HtmlNameLightSkyBlue[] PROGMEM = "lightskyblue";
|
||||
const char c_HtmlNameLightSlateGray[] PROGMEM = "lightslategray";
|
||||
const char c_HtmlNameLightSlateGrey[] PROGMEM = "lightslategrey";
|
||||
const char c_HtmlNameLightSteelBlue[] PROGMEM = "lightsteelblue";
|
||||
const char c_HtmlNameLightYellow[] PROGMEM = "lightyellow";
|
||||
const char c_HtmlNameLimeGreen[] PROGMEM = "limegreen";
|
||||
const char c_HtmlNameLinen[] PROGMEM = "linen";
|
||||
const char c_HtmlNameMagenta[] PROGMEM = "magenta";
|
||||
const char c_HtmlNameMediumAquamarine[] PROGMEM = "mediumaquamarine";
|
||||
const char c_HtmlNameMediumBlue[] PROGMEM = "mediumblue";
|
||||
const char c_HtmlNameMediumOrchid[] PROGMEM = "mediumorchid";
|
||||
const char c_HtmlNameMediumPurple[] PROGMEM = "mediumpurple";
|
||||
const char c_HtmlNameMediumSeagreen[] PROGMEM = "mediumseagreen";
|
||||
const char c_HtmlNameMediumSlateBlue[] PROGMEM = "mediumslateblue";
|
||||
const char c_HtmlNameMediumSpringGreen[] PROGMEM = "mediumspringgreen";
|
||||
const char c_HtmlNameMediumTurquoise[] PROGMEM = "mediumturquoise";
|
||||
const char c_HtmlNameMediumVioletRed[] PROGMEM = "mediumvioletred";
|
||||
const char c_HtmlNameMidnightBlue[] PROGMEM = "midnightblue";
|
||||
const char c_HtmlNameMintCream[] PROGMEM = "mintcream";
|
||||
const char c_HtmlNameMistyRose[] PROGMEM = "mistyrose";
|
||||
const char c_HtmlNameMoccasin[] PROGMEM = "moccasin";
|
||||
const char c_HtmlNameNavajoWhite[] PROGMEM = "navajowhite";
|
||||
const char c_HtmlNameOldLace[] PROGMEM = "oldlace";
|
||||
const char c_HtmlNameOliveDrab[] PROGMEM = "olivedrab";
|
||||
const char c_HtmlNameOrangeRed[] PROGMEM = "orangered";
|
||||
const char c_HtmlNameOrchid[] PROGMEM = "orchid";
|
||||
const char c_HtmlNamePaleGoldenrod[] PROGMEM = "palegoldenrod";
|
||||
const char c_HtmlNamePaleGreen[] PROGMEM = "palegreen";
|
||||
const char c_HtmlNamePaleTurquoise[] PROGMEM = "paleturquoise";
|
||||
const char c_HtmlNamePaleVioletRed[] PROGMEM = "palevioletred";
|
||||
const char c_HtmlNamePapayaWhip[] PROGMEM = "papayawhip";
|
||||
const char c_HtmlNamePeachPuff[] PROGMEM = "peachpuff";
|
||||
const char c_HtmlNamePeru[] PROGMEM = "peru";
|
||||
const char c_HtmlNamePink[] PROGMEM = "pink";
|
||||
const char c_HtmlNamePlum[] PROGMEM = "plum";
|
||||
const char c_HtmlNamePowderBlue[] PROGMEM = "powderblue";
|
||||
const char c_HtmlNameRosyBrown[] PROGMEM = "rosybrown";
|
||||
const char c_HtmlNameRoyalBlue[] PROGMEM = "royalblue";
|
||||
const char c_HtmlNameSaddleBrown[] PROGMEM = "saddlebrown";
|
||||
const char c_HtmlNameSalmon[] PROGMEM = "salmon";
|
||||
const char c_HtmlNameSandyBrown[] PROGMEM = "sandybrown";
|
||||
const char c_HtmlNameSeaGreen[] PROGMEM = "seagreen";
|
||||
const char c_HtmlNameSeaShell[] PROGMEM = "seashell";
|
||||
const char c_HtmlNameSienna[] PROGMEM = "sienna";
|
||||
const char c_HtmlNameSkyBlue[] PROGMEM = "skyblue";
|
||||
const char c_HtmlNameSlateBlue[] PROGMEM = "slateblue";
|
||||
const char c_HtmlNameSlateGray[] PROGMEM = "slategray";
|
||||
const char c_HtmlNameSlateGrey[] PROGMEM = "slategrey";
|
||||
const char c_HtmlNameSnow[] PROGMEM = "snow";
|
||||
const char c_HtmlNameSpringGreen[] PROGMEM = "springgreen";
|
||||
const char c_HtmlNameSteelBlue[] PROGMEM = "steelblue";
|
||||
const char c_HtmlNameTan[] PROGMEM = "tan";
|
||||
const char c_HtmlNameThistle[] PROGMEM = "thistle";
|
||||
const char c_HtmlNameTomato[] PROGMEM = "tomato";
|
||||
const char c_HtmlNameTurquoise[] PROGMEM = "turquoise";
|
||||
const char c_HtmlNameViolet[] PROGMEM = "violet";
|
||||
const char c_HtmlNameWheat[] PROGMEM = "wheat";
|
||||
const char c_HtmlNameWhiteSmoke[] PROGMEM = "whitesmoke";
|
||||
const char c_HtmlNameYellowGreen[] PROGMEM = "yellowgreen";
|
||||
180
lib/NeoPixelBus_by_Makuna/src/internal/HtmlColorNameStrings.h
Normal file
180
lib/NeoPixelBus_by_Makuna/src/internal/HtmlColorNameStrings.h
Normal file
@@ -0,0 +1,180 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
HtmlColorNameStrings provides the declaration of the color string names
|
||||
|
||||
Written by Michael C. Miller.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
/* HTML4 color names */
|
||||
extern const char c_HtmlNameAqua[] PROGMEM;
|
||||
extern const char c_HtmlNameBlack[] PROGMEM;
|
||||
extern const char c_HtmlNameBlue[] PROGMEM;
|
||||
extern const char c_HtmlNameFuchsia[] PROGMEM;
|
||||
extern const char c_HtmlNameGray[] PROGMEM;
|
||||
extern const char c_HtmlNameGreen[] PROGMEM;
|
||||
extern const char c_HtmlNameLime[] PROGMEM;
|
||||
extern const char c_HtmlNameMaroon[] PROGMEM;
|
||||
extern const char c_HtmlNameNavy[] PROGMEM;
|
||||
extern const char c_HtmlNameOlive[] PROGMEM;
|
||||
extern const char c_HtmlNameOrange[] PROGMEM;
|
||||
extern const char c_HtmlNamePurple[] PROGMEM;
|
||||
extern const char c_HtmlNameRed[] PROGMEM;
|
||||
extern const char c_HtmlNameSilver[] PROGMEM;
|
||||
extern const char c_HtmlNameTeal[] PROGMEM;
|
||||
extern const char c_HtmlNameWhite[] PROGMEM;
|
||||
extern const char c_HtmlNameYellow[] PROGMEM;
|
||||
|
||||
/* Additional CSS3 color names */
|
||||
extern const char c_HtmlNameAliceBlue[] PROGMEM;
|
||||
extern const char c_HtmlNameAntiqueWhite[] PROGMEM;
|
||||
extern const char c_HtmlNameAquamarine[] PROGMEM;
|
||||
extern const char c_HtmlNameAzure[] PROGMEM;
|
||||
extern const char c_HtmlNameBeige[] PROGMEM;
|
||||
extern const char c_HtmlNameBisque[] PROGMEM;
|
||||
extern const char c_HtmlNameBlanchedAlmond[] PROGMEM;
|
||||
extern const char c_HtmlNameBlueViolet[] PROGMEM;
|
||||
extern const char c_HtmlNameBrown[] PROGMEM;
|
||||
extern const char c_HtmlNameBurlyWood[] PROGMEM;
|
||||
extern const char c_HtmlNameCadetBlue[] PROGMEM;
|
||||
extern const char c_HtmlNameChartreuse[] PROGMEM;
|
||||
extern const char c_HtmlNameChocolate[] PROGMEM;
|
||||
extern const char c_HtmlNameCoral[] PROGMEM;
|
||||
extern const char c_HtmlNameCornflowerBlue[] PROGMEM;
|
||||
extern const char c_HtmlNameCornsilk[] PROGMEM;
|
||||
extern const char c_HtmlNameCrimson[] PROGMEM;
|
||||
extern const char c_HtmlNameCyan[] PROGMEM;
|
||||
extern const char c_HtmlNameDarkBlue[] PROGMEM;
|
||||
extern const char c_HtmlNameDarkCyan[] PROGMEM;
|
||||
extern const char c_HtmlNameDarkGoldenrod[] PROGMEM;
|
||||
extern const char c_HtmlNameDarkGray[] PROGMEM;
|
||||
extern const char c_HtmlNameDarkGreen[] PROGMEM;
|
||||
extern const char c_HtmlNameDarkGrey[] PROGMEM;
|
||||
extern const char c_HtmlNameDarkKhaki[] PROGMEM;
|
||||
extern const char c_HtmlNameDarkMagenta[] PROGMEM;
|
||||
extern const char c_HtmlNameDarkOliveGreen[] PROGMEM;
|
||||
extern const char c_HtmlNameDarkOrange[] PROGMEM;
|
||||
extern const char c_HtmlNameDarkOrchid[] PROGMEM;
|
||||
extern const char c_HtmlNameDarkRed[] PROGMEM;
|
||||
extern const char c_HtmlNameDarkSalmon[] PROGMEM;
|
||||
extern const char c_HtmlNameDarkSeaGreen[] PROGMEM;
|
||||
extern const char c_HtmlNameDarkSlateBlue[] PROGMEM;
|
||||
extern const char c_HtmlNameDarkSlateGray[] PROGMEM;
|
||||
extern const char c_HtmlNameDarkSlateGrey[] PROGMEM;
|
||||
extern const char c_HtmlNameDarkTurquoise[] PROGMEM;
|
||||
extern const char c_HtmlNameDarkViolet[] PROGMEM;
|
||||
extern const char c_HtmlNameDeepPink[] PROGMEM;
|
||||
extern const char c_HtmlNameDeepSkyBlue[] PROGMEM;
|
||||
extern const char c_HtmlNameDimGray[] PROGMEM;
|
||||
extern const char c_HtmlNameDimGrey[] PROGMEM;
|
||||
extern const char c_HtmlNameDodgerBlue[] PROGMEM;
|
||||
extern const char c_HtmlNameFirebrick[] PROGMEM;
|
||||
extern const char c_HtmlNameFloralWhite[] PROGMEM;
|
||||
extern const char c_HtmlNameForestGreen[] PROGMEM;
|
||||
extern const char c_HtmlNameGainsboro[] PROGMEM;
|
||||
extern const char c_HtmlNameGhostWhite[] PROGMEM;
|
||||
extern const char c_HtmlNameGold[] PROGMEM;
|
||||
extern const char c_HtmlNameGoldenrod[] PROGMEM;
|
||||
extern const char c_HtmlNameGreenYellow[] PROGMEM;
|
||||
extern const char c_HtmlNameGrey[] PROGMEM;
|
||||
extern const char c_HtmlNameHoneydew[] PROGMEM;
|
||||
extern const char c_HtmlNameHotPink[] PROGMEM;
|
||||
extern const char c_HtmlNameIndianRed[] PROGMEM;
|
||||
extern const char c_HtmlNameIndigo[] PROGMEM;
|
||||
extern const char c_HtmlNameIvory[] PROGMEM;
|
||||
extern const char c_HtmlNameKhaki[] PROGMEM;
|
||||
extern const char c_HtmlNameLavender[] PROGMEM;
|
||||
extern const char c_HtmlNameLavenderBlush[] PROGMEM;
|
||||
extern const char c_HtmlNameLawnGreen[] PROGMEM;
|
||||
extern const char c_HtmlNameLemonChiffon[] PROGMEM;
|
||||
extern const char c_HtmlNameLightBlue[] PROGMEM;
|
||||
extern const char c_HtmlNameLightCoral[] PROGMEM;
|
||||
extern const char c_HtmlNameLightCyan[] PROGMEM;
|
||||
extern const char c_HtmlNameLightGoldenrodYellow[] PROGMEM;
|
||||
extern const char c_HtmlNameLightGray[] PROGMEM;
|
||||
extern const char c_HtmlNameLightGreen[] PROGMEM;
|
||||
extern const char c_HtmlNameLightGrey[] PROGMEM;
|
||||
extern const char c_HtmlNameLightPink[] PROGMEM;
|
||||
extern const char c_HtmlNameLightSalmon[] PROGMEM;
|
||||
extern const char c_HtmlNameLightSeaGreen[] PROGMEM;
|
||||
extern const char c_HtmlNameLightSkyBlue[] PROGMEM;
|
||||
extern const char c_HtmlNameLightSlateGray[] PROGMEM;
|
||||
extern const char c_HtmlNameLightSlateGrey[] PROGMEM;
|
||||
extern const char c_HtmlNameLightSteelBlue[] PROGMEM;
|
||||
extern const char c_HtmlNameLightYellow[] PROGMEM;
|
||||
extern const char c_HtmlNameLimeGreen[] PROGMEM;
|
||||
extern const char c_HtmlNameLinen[] PROGMEM;
|
||||
extern const char c_HtmlNameMagenta[] PROGMEM;
|
||||
extern const char c_HtmlNameMediumAquamarine[] PROGMEM;
|
||||
extern const char c_HtmlNameMediumBlue[] PROGMEM;
|
||||
extern const char c_HtmlNameMediumOrchid[] PROGMEM;
|
||||
extern const char c_HtmlNameMediumPurple[] PROGMEM;
|
||||
extern const char c_HtmlNameMediumSeagreen[] PROGMEM;
|
||||
extern const char c_HtmlNameMediumSlateBlue[] PROGMEM;
|
||||
extern const char c_HtmlNameMediumSpringGreen[] PROGMEM;
|
||||
extern const char c_HtmlNameMediumTurquoise[] PROGMEM;
|
||||
extern const char c_HtmlNameMediumVioletRed[] PROGMEM;
|
||||
extern const char c_HtmlNameMidnightBlue[] PROGMEM;
|
||||
extern const char c_HtmlNameMintCream[] PROGMEM;
|
||||
extern const char c_HtmlNameMistyRose[] PROGMEM;
|
||||
extern const char c_HtmlNameMoccasin[] PROGMEM;
|
||||
extern const char c_HtmlNameNavajoWhite[] PROGMEM;
|
||||
extern const char c_HtmlNameOldLace[] PROGMEM;
|
||||
extern const char c_HtmlNameOliveDrab[] PROGMEM;
|
||||
extern const char c_HtmlNameOrangeRed[] PROGMEM;
|
||||
extern const char c_HtmlNameOrchid[] PROGMEM;
|
||||
extern const char c_HtmlNamePaleGoldenrod[] PROGMEM;
|
||||
extern const char c_HtmlNamePaleGreen[] PROGMEM;
|
||||
extern const char c_HtmlNamePaleTurquoise[] PROGMEM;
|
||||
extern const char c_HtmlNamePaleVioletRed[] PROGMEM;
|
||||
extern const char c_HtmlNamePapayaWhip[] PROGMEM;
|
||||
extern const char c_HtmlNamePeachPuff[] PROGMEM;
|
||||
extern const char c_HtmlNamePeru[] PROGMEM;
|
||||
extern const char c_HtmlNamePink[] PROGMEM;
|
||||
extern const char c_HtmlNamePlum[] PROGMEM;
|
||||
extern const char c_HtmlNamePowderBlue[] PROGMEM;
|
||||
extern const char c_HtmlNameRosyBrown[] PROGMEM;
|
||||
extern const char c_HtmlNameRoyalBlue[] PROGMEM;
|
||||
extern const char c_HtmlNameSaddleBrown[] PROGMEM;
|
||||
extern const char c_HtmlNameSalmon[] PROGMEM;
|
||||
extern const char c_HtmlNameSandyBrown[] PROGMEM;
|
||||
extern const char c_HtmlNameSeaGreen[] PROGMEM;
|
||||
extern const char c_HtmlNameSeaShell[] PROGMEM;
|
||||
extern const char c_HtmlNameSienna[] PROGMEM;
|
||||
extern const char c_HtmlNameSkyBlue[] PROGMEM;
|
||||
extern const char c_HtmlNameSlateBlue[] PROGMEM;
|
||||
extern const char c_HtmlNameSlateGray[] PROGMEM;
|
||||
extern const char c_HtmlNameSlateGrey[] PROGMEM;
|
||||
extern const char c_HtmlNameSnow[] PROGMEM;
|
||||
extern const char c_HtmlNameSpringGreen[] PROGMEM;
|
||||
extern const char c_HtmlNameSteelBlue[] PROGMEM;
|
||||
extern const char c_HtmlNameTan[] PROGMEM;
|
||||
extern const char c_HtmlNameThistle[] PROGMEM;
|
||||
extern const char c_HtmlNameTomato[] PROGMEM;
|
||||
extern const char c_HtmlNameTurquoise[] PROGMEM;
|
||||
extern const char c_HtmlNameViolet[] PROGMEM;
|
||||
extern const char c_HtmlNameWheat[] PROGMEM;
|
||||
extern const char c_HtmlNameWhiteSmoke[] PROGMEM;
|
||||
extern const char c_HtmlNameYellowGreen[] PROGMEM;
|
||||
188
lib/NeoPixelBus_by_Makuna/src/internal/HtmlColorNames.cpp
Normal file
188
lib/NeoPixelBus_by_Makuna/src/internal/HtmlColorNames.cpp
Normal file
@@ -0,0 +1,188 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
HtmlColorNames provides a template class for access to the full name table
|
||||
|
||||
Written by Michael C. Miller.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
|
||||
#include "HtmlColor.h"
|
||||
#include "HtmlColorNameStrings.h"
|
||||
|
||||
static const HtmlColorPair c_ColorNames[] PROGMEM = {
|
||||
{ c_HtmlNameAliceBlue, 0xf0f8ff },
|
||||
{ c_HtmlNameAntiqueWhite, 0xfaebd7 },
|
||||
{ c_HtmlNameAqua, 0xffff },
|
||||
{ c_HtmlNameAquamarine, 0x7fffd4 },
|
||||
{ c_HtmlNameAzure, 0xf0ffff },
|
||||
{ c_HtmlNameBeige, 0xf5f5dc },
|
||||
{ c_HtmlNameBisque, 0xffe4c4 },
|
||||
{ c_HtmlNameBlack, 0x0 },
|
||||
{ c_HtmlNameBlanchedAlmond, 0xffebcd },
|
||||
{ c_HtmlNameBlue, 0xff },
|
||||
{ c_HtmlNameBlueViolet, 0x8a2be2 },
|
||||
{ c_HtmlNameBrown, 0xa52a2a },
|
||||
{ c_HtmlNameBurlyWood, 0xdeb887 },
|
||||
{ c_HtmlNameCadetBlue, 0x5f9ea0 },
|
||||
{ c_HtmlNameChartreuse, 0x7fff00 },
|
||||
{ c_HtmlNameChocolate, 0xd2691e },
|
||||
{ c_HtmlNameCoral, 0xff7f50 },
|
||||
{ c_HtmlNameCornflowerBlue, 0x6495ed },
|
||||
{ c_HtmlNameCornsilk, 0xfff8dc },
|
||||
{ c_HtmlNameCrimson, 0xdc143c },
|
||||
{ c_HtmlNameCyan, 0xffff },
|
||||
{ c_HtmlNameDarkBlue, 0x8b },
|
||||
{ c_HtmlNameDarkCyan, 0x8b8b },
|
||||
{ c_HtmlNameDarkGoldenrod, 0xb8860b },
|
||||
{ c_HtmlNameDarkGray, 0xa9a9a9 },
|
||||
{ c_HtmlNameDarkGreen, 0x6400 },
|
||||
{ c_HtmlNameDarkGrey, 0xa9a9a9 },
|
||||
{ c_HtmlNameDarkKhaki, 0xbdb76b },
|
||||
{ c_HtmlNameDarkMagenta, 0x8b008b },
|
||||
{ c_HtmlNameDarkOliveGreen, 0x556b2f },
|
||||
{ c_HtmlNameDarkOrange, 0xff8c00 },
|
||||
{ c_HtmlNameDarkOrchid, 0x9932cc },
|
||||
{ c_HtmlNameDarkRed, 0x8b0000 },
|
||||
{ c_HtmlNameDarkSalmon, 0xe9967a },
|
||||
{ c_HtmlNameDarkSeaGreen, 0x8fbc8f },
|
||||
{ c_HtmlNameDarkSlateBlue, 0x483d8b },
|
||||
{ c_HtmlNameDarkSlateGray, 0x2f4f4f },
|
||||
{ c_HtmlNameDarkSlateGrey, 0x2f4f4f },
|
||||
{ c_HtmlNameDarkTurquoise, 0xced1 },
|
||||
{ c_HtmlNameDarkViolet, 0x9400d3 },
|
||||
{ c_HtmlNameDeepPink, 0xff1493 },
|
||||
{ c_HtmlNameDeepSkyBlue, 0xbfff },
|
||||
{ c_HtmlNameDimGray, 0x696969 },
|
||||
{ c_HtmlNameDimGrey, 0x696969 },
|
||||
{ c_HtmlNameDodgerBlue, 0x1e90ff },
|
||||
{ c_HtmlNameFirebrick, 0xb22222 },
|
||||
{ c_HtmlNameFloralWhite, 0xfffaf0 },
|
||||
{ c_HtmlNameForestGreen, 0x228b22 },
|
||||
{ c_HtmlNameFuchsia, 0xff00ff },
|
||||
{ c_HtmlNameGainsboro, 0xdcdcdc },
|
||||
{ c_HtmlNameGhostWhite, 0xf8f8ff },
|
||||
{ c_HtmlNameGold, 0xffd700 },
|
||||
{ c_HtmlNameGoldenrod, 0xdaa520 },
|
||||
{ c_HtmlNameGray, 0x808080 },
|
||||
{ c_HtmlNameGreen, 0x8000 },
|
||||
{ c_HtmlNameGreenYellow, 0xadff2f },
|
||||
{ c_HtmlNameGrey, 0x808080 },
|
||||
{ c_HtmlNameHoneydew, 0xf0fff0 },
|
||||
{ c_HtmlNameHotPink, 0xff69b4 },
|
||||
{ c_HtmlNameIndianRed, 0xcd5c5c },
|
||||
{ c_HtmlNameIndigo, 0x4b0082 },
|
||||
{ c_HtmlNameIvory, 0xfffff0 },
|
||||
{ c_HtmlNameKhaki, 0xf0e68c },
|
||||
{ c_HtmlNameLavender, 0xe6e6fa },
|
||||
{ c_HtmlNameLavenderBlush, 0xfff0f5 },
|
||||
{ c_HtmlNameLawnGreen, 0x7cfc00 },
|
||||
{ c_HtmlNameLemonChiffon, 0xfffacd },
|
||||
{ c_HtmlNameLightBlue, 0xadd8e6 },
|
||||
{ c_HtmlNameLightCoral, 0xf08080 },
|
||||
{ c_HtmlNameLightCyan, 0xe0ffff },
|
||||
{ c_HtmlNameLightGoldenrodYellow, 0xfafad2 },
|
||||
{ c_HtmlNameLightGray, 0xd3d3d3 },
|
||||
{ c_HtmlNameLightGreen, 0x90ee90 },
|
||||
{ c_HtmlNameLightGrey, 0xd3d3d3 },
|
||||
{ c_HtmlNameLightPink, 0xffb6c1 },
|
||||
{ c_HtmlNameLightSalmon, 0xffa07a },
|
||||
{ c_HtmlNameLightSeaGreen, 0x20b2aa },
|
||||
{ c_HtmlNameLightSkyBlue, 0x87cefa },
|
||||
{ c_HtmlNameLightSlateGray, 0x778899 },
|
||||
{ c_HtmlNameLightSlateGrey, 0x778899 },
|
||||
{ c_HtmlNameLightSteelBlue, 0xb0c4de },
|
||||
{ c_HtmlNameLightYellow, 0xffffe0 },
|
||||
{ c_HtmlNameLime, 0xff00 },
|
||||
{ c_HtmlNameLimeGreen, 0x32cd32 },
|
||||
{ c_HtmlNameLinen, 0xfaf0e6 },
|
||||
{ c_HtmlNameMagenta, 0xff00ff },
|
||||
{ c_HtmlNameMaroon, 0x800000 },
|
||||
{ c_HtmlNameMediumAquamarine, 0x66cdaa },
|
||||
{ c_HtmlNameMediumBlue, 0xcd },
|
||||
{ c_HtmlNameMediumOrchid, 0xba55d3 },
|
||||
{ c_HtmlNameMediumPurple, 0x9370d8 },
|
||||
{ c_HtmlNameMediumSeagreen, 0x3cb371 },
|
||||
{ c_HtmlNameMediumSlateBlue, 0x7b68ee },
|
||||
{ c_HtmlNameMediumSpringGreen, 0xfa9a },
|
||||
{ c_HtmlNameMediumTurquoise, 0x48d1cc },
|
||||
{ c_HtmlNameMediumVioletRed, 0xc71585 },
|
||||
{ c_HtmlNameMidnightBlue, 0x191970 },
|
||||
{ c_HtmlNameMintCream, 0xf5fffa },
|
||||
{ c_HtmlNameMistyRose, 0xffe4e1 },
|
||||
{ c_HtmlNameMoccasin, 0xffe4b5 },
|
||||
{ c_HtmlNameNavajoWhite, 0xffdead },
|
||||
{ c_HtmlNameNavy, 0x80 },
|
||||
{ c_HtmlNameOldLace, 0xfdf5e6 },
|
||||
{ c_HtmlNameOlive, 0x808000 },
|
||||
{ c_HtmlNameOliveDrab, 0x6b8e23 },
|
||||
{ c_HtmlNameOrange, 0xffa500 },
|
||||
{ c_HtmlNameOrangeRed, 0xff4500 },
|
||||
{ c_HtmlNameOrchid, 0xda70d6 },
|
||||
{ c_HtmlNamePaleGoldenrod, 0xeee8aa },
|
||||
{ c_HtmlNamePaleGreen, 0x98fb98 },
|
||||
{ c_HtmlNamePaleTurquoise, 0xafeeee },
|
||||
{ c_HtmlNamePaleVioletRed, 0xd87093 },
|
||||
{ c_HtmlNamePapayaWhip, 0xffefd5 },
|
||||
{ c_HtmlNamePeachPuff, 0xffdab9 },
|
||||
{ c_HtmlNamePeru, 0xcd853f },
|
||||
{ c_HtmlNamePink, 0xffc0cb },
|
||||
{ c_HtmlNamePlum, 0xdda0dd },
|
||||
{ c_HtmlNamePowderBlue, 0xb0e0e6 },
|
||||
{ c_HtmlNamePurple, 0x800080 },
|
||||
{ c_HtmlNameRed, 0xff0000 },
|
||||
{ c_HtmlNameRosyBrown, 0xbc8f8f },
|
||||
{ c_HtmlNameRoyalBlue, 0x4169e1 },
|
||||
{ c_HtmlNameSaddleBrown, 0x8b4513 },
|
||||
{ c_HtmlNameSalmon, 0xfa8072 },
|
||||
{ c_HtmlNameSandyBrown, 0xf4a460 },
|
||||
{ c_HtmlNameSeaGreen, 0x2e8b57 },
|
||||
{ c_HtmlNameSeaShell, 0xfff5ee },
|
||||
{ c_HtmlNameSienna, 0xa0522d },
|
||||
{ c_HtmlNameSilver, 0xc0c0c0 },
|
||||
{ c_HtmlNameSkyBlue, 0x87ceeb },
|
||||
{ c_HtmlNameSlateBlue, 0x6a5acd },
|
||||
{ c_HtmlNameSlateGray, 0x708090 },
|
||||
{ c_HtmlNameSlateGrey, 0x708090 },
|
||||
{ c_HtmlNameSnow, 0xfffafa },
|
||||
{ c_HtmlNameSpringGreen, 0xff7f },
|
||||
{ c_HtmlNameSteelBlue, 0x4682b4 },
|
||||
{ c_HtmlNameTan, 0xd2b48c },
|
||||
{ c_HtmlNameTeal, 0x8080 },
|
||||
{ c_HtmlNameThistle, 0xd8bfd8 },
|
||||
{ c_HtmlNameTomato, 0xff6347 },
|
||||
{ c_HtmlNameTurquoise, 0x40e0d0 },
|
||||
{ c_HtmlNameViolet, 0xee82ee },
|
||||
{ c_HtmlNameWheat, 0xf5deb3 },
|
||||
{ c_HtmlNameWhite, 0xffffff },
|
||||
{ c_HtmlNameWhiteSmoke, 0xf5f5f5 },
|
||||
{ c_HtmlNameYellow, 0xffff00 },
|
||||
{ c_HtmlNameYellowGreen, 0x9acd32 },
|
||||
};
|
||||
|
||||
const HtmlColorPair* HtmlColorNames::Pair(uint8_t index)
|
||||
{
|
||||
return &c_ColorNames[index];
|
||||
}
|
||||
|
||||
uint8_t HtmlColorNames::Count()
|
||||
{
|
||||
return countof(c_ColorNames);
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
HtmlShortColorNames provides a template class for access to the short name table
|
||||
|
||||
Written by Michael C. Miller.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
|
||||
#include "HtmlColor.h"
|
||||
#include "HtmlColorNameStrings.h"
|
||||
|
||||
static const HtmlColorPair c_ShortColorNames[] PROGMEM = {
|
||||
{ c_HtmlNameAqua, 0xffff },
|
||||
{ c_HtmlNameBlack, 0x0 },
|
||||
{ c_HtmlNameBlue, 0xff },
|
||||
{ c_HtmlNameFuchsia, 0xff00ff },
|
||||
{ c_HtmlNameGray, 0x808080 },
|
||||
{ c_HtmlNameGreen, 0x8000 },
|
||||
{ c_HtmlNameLime, 0xff00 },
|
||||
{ c_HtmlNameMaroon, 0x800000 },
|
||||
{ c_HtmlNameNavy, 0x80 },
|
||||
{ c_HtmlNameOlive, 0x808000 },
|
||||
{ c_HtmlNameOrange, 0xffa500 },
|
||||
{ c_HtmlNamePurple, 0x800080 },
|
||||
{ c_HtmlNameRed, 0xff0000 },
|
||||
{ c_HtmlNameSilver, 0xc0c0c0 },
|
||||
{ c_HtmlNameTeal, 0x8080 },
|
||||
{ c_HtmlNameWhite, 0xffffff },
|
||||
{ c_HtmlNameYellow, 0xffff00 },
|
||||
};
|
||||
|
||||
|
||||
const HtmlColorPair* HtmlShortColorNames::Pair(uint8_t index)
|
||||
{
|
||||
return &c_ShortColorNames[index];
|
||||
}
|
||||
|
||||
uint8_t HtmlShortColorNames::Count()
|
||||
{
|
||||
return countof(c_ShortColorNames);
|
||||
}
|
||||
426
lib/NeoPixelBus_by_Makuna/src/internal/Layouts.h
Normal file
426
lib/NeoPixelBus_by_Makuna/src/internal/Layouts.h
Normal file
@@ -0,0 +1,426 @@
|
||||
#pragma once
|
||||
/*-------------------------------------------------------------------------
|
||||
Layout provides a collection of class objects that are used with NeoTopology
|
||||
object.
|
||||
They define the specific layout of pixels and do the math to change the 2d
|
||||
cordinate space to 1d cordinate space
|
||||
|
||||
Written by Michael C. Miller.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
|
||||
const uint16_t PixelIndex_OutOfBounds = 0xffff;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// RowMajor
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class RowMajorLayout;
|
||||
class RowMajor90Layout;
|
||||
class RowMajor180Layout;
|
||||
class RowMajor270Layout;
|
||||
|
||||
class RowMajorTilePreference
|
||||
{
|
||||
public:
|
||||
typedef RowMajorLayout EvenRowEvenColumnLayout;
|
||||
typedef RowMajor270Layout EvenRowOddColumnLayout;
|
||||
typedef RowMajor90Layout OddRowEvenColumnLayout;
|
||||
typedef RowMajor180Layout OddRowOddColumnLayout;
|
||||
};
|
||||
|
||||
// layout example of 4x4
|
||||
// 00 01 02 03
|
||||
// 04 05 06 07
|
||||
// 08 09 10 11
|
||||
// 12 13 14 15
|
||||
//
|
||||
class RowMajorLayout : public RowMajorTilePreference
|
||||
{
|
||||
public:
|
||||
static uint16_t Map(uint16_t width, uint16_t /* height */, uint16_t x, uint16_t y)
|
||||
{
|
||||
return x + y * width;
|
||||
}
|
||||
};
|
||||
|
||||
// layout example of 4x4
|
||||
// 12 08 04 00
|
||||
// 13 09 05 01
|
||||
// 14 10 06 02
|
||||
// 15 11 07 03
|
||||
//
|
||||
class RowMajor90Layout : public RowMajorTilePreference
|
||||
{
|
||||
public:
|
||||
static uint16_t Map(uint16_t width, uint16_t height, uint16_t x, uint16_t y)
|
||||
{
|
||||
return (width - 1 - x) * height + y;
|
||||
}
|
||||
};
|
||||
|
||||
// layout example of 4x4
|
||||
// 15 14 13 12
|
||||
// 11 10 09 08
|
||||
// 07 06 05 04
|
||||
// 03 02 01 00
|
||||
//
|
||||
class RowMajor180Layout : public RowMajorTilePreference
|
||||
{
|
||||
public:
|
||||
static uint16_t Map(uint16_t width, uint16_t height, uint16_t x, uint16_t y)
|
||||
{
|
||||
return (width - 1 - x) + (height - 1 - y) * width;
|
||||
}
|
||||
};
|
||||
|
||||
// layout example of 4x4
|
||||
// 03 07 11 15
|
||||
// 02 06 10 14
|
||||
// 01 05 09 13
|
||||
// 00 04 08 12
|
||||
//
|
||||
class RowMajor270Layout : public RowMajorTilePreference
|
||||
{
|
||||
public:
|
||||
static uint16_t Map(uint16_t /* width */, uint16_t height, uint16_t x, uint16_t y)
|
||||
{
|
||||
return x * height + (height - 1 - y);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// ColumnMajor
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class ColumnMajorLayout;
|
||||
class ColumnMajor90Layout;
|
||||
class ColumnMajor180Layout;
|
||||
class ColumnMajor270Layout;
|
||||
|
||||
class ColumnMajorTilePreference
|
||||
{
|
||||
public:
|
||||
typedef ColumnMajorLayout EvenRowEvenColumnLayout;
|
||||
typedef ColumnMajor270Layout EvenRowOddColumnLayout;
|
||||
typedef ColumnMajor90Layout OddRowEvenColumnLayout;
|
||||
typedef ColumnMajor180Layout OddRowOddColumnLayout;
|
||||
};
|
||||
|
||||
// layout example of 4x4
|
||||
// 00 04 08 12
|
||||
// 01 05 09 13
|
||||
// 02 06 10 14
|
||||
// 03 07 11 15
|
||||
//
|
||||
class ColumnMajorLayout : public ColumnMajorTilePreference
|
||||
{
|
||||
public:
|
||||
static uint16_t Map(uint16_t /* width */, uint16_t height, uint16_t x, uint16_t y)
|
||||
{
|
||||
return x * height + y;
|
||||
}
|
||||
};
|
||||
|
||||
// layout example of 4x4
|
||||
// 03 02 01 00
|
||||
// 07 06 05 04
|
||||
// 11 10 09 08
|
||||
// 15 14 13 12
|
||||
//
|
||||
class ColumnMajor90Layout : public ColumnMajorTilePreference
|
||||
{
|
||||
public:
|
||||
static uint16_t Map(uint16_t width, uint16_t /* height */, uint16_t x, uint16_t y)
|
||||
{
|
||||
return (width - 1 - x) + y * width;
|
||||
}
|
||||
};
|
||||
|
||||
// layout example of 4x4
|
||||
// 15 11 07 03
|
||||
// 14 10 06 02
|
||||
// 13 09 05 01
|
||||
// 12 08 04 00
|
||||
//
|
||||
class ColumnMajor180Layout : public ColumnMajorTilePreference
|
||||
{
|
||||
public:
|
||||
static uint16_t Map(uint16_t width, uint16_t height, uint16_t x, uint16_t y)
|
||||
{
|
||||
return (width - 1 - x) * height + (height - 1 - y);
|
||||
}
|
||||
};
|
||||
|
||||
// layout example of 4x4
|
||||
// 12 13 14 15
|
||||
// 08 09 10 11
|
||||
// 04 05 06 07
|
||||
// 00 01 02 03
|
||||
//
|
||||
class ColumnMajor270Layout : public ColumnMajorTilePreference
|
||||
{
|
||||
public:
|
||||
static uint16_t Map(uint16_t width, uint16_t height, uint16_t x, uint16_t y)
|
||||
{
|
||||
return x + (height - 1 - y) * width;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// RowMajorAlternating
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class RowMajorAlternating270Layout;
|
||||
class RowMajorAlternating90Layout;
|
||||
|
||||
class RowMajorAlternatingTilePreference
|
||||
{
|
||||
public:
|
||||
typedef RowMajorAlternating270Layout EvenRowEvenColumnLayout;
|
||||
typedef RowMajorAlternating270Layout EvenRowOddColumnLayout;
|
||||
typedef RowMajorAlternating90Layout OddRowEvenColumnLayout;
|
||||
typedef RowMajorAlternating90Layout OddRowOddColumnLayout;
|
||||
};
|
||||
|
||||
// layout example of 4x4
|
||||
// 00 01 02 03
|
||||
// 07 06 05 04
|
||||
// 08 09 10 11
|
||||
// 15 14 13 12
|
||||
//
|
||||
class RowMajorAlternatingLayout : public RowMajorAlternatingTilePreference
|
||||
{
|
||||
public:
|
||||
static uint16_t Map(uint16_t width, uint16_t /* height */, uint16_t x, uint16_t y)
|
||||
{
|
||||
uint16_t index = y * width;
|
||||
|
||||
if (y & 0x0001)
|
||||
{
|
||||
index += ((width - 1) - x);
|
||||
}
|
||||
else
|
||||
{
|
||||
index += x;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
};
|
||||
|
||||
// layout example of 4x4
|
||||
// 15 08 07 00
|
||||
// 14 09 06 01
|
||||
// 13 10 05 02
|
||||
// 12 11 04 03
|
||||
//
|
||||
class RowMajorAlternating90Layout : public RowMajorAlternatingTilePreference
|
||||
{
|
||||
public:
|
||||
static uint16_t Map(uint16_t width, uint16_t height, uint16_t x, uint16_t y)
|
||||
{
|
||||
uint16_t mx = ((width - 1) - x);
|
||||
uint16_t index = mx * height;
|
||||
|
||||
if (mx & 0x0001)
|
||||
{
|
||||
index += ((height - 1) - y);
|
||||
}
|
||||
else
|
||||
{
|
||||
index += y;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
};
|
||||
|
||||
// layout example of 4x4
|
||||
// 12 13 14 15
|
||||
// 11 10 09 08
|
||||
// 04 05 06 07
|
||||
// 03 02 01 00
|
||||
//
|
||||
class RowMajorAlternating180Layout : public RowMajorAlternatingTilePreference
|
||||
{
|
||||
public:
|
||||
static uint16_t Map(uint16_t width, uint16_t height, uint16_t x, uint16_t y)
|
||||
{
|
||||
uint16_t my = ((height - 1) - y);
|
||||
uint16_t index = my * width;
|
||||
|
||||
if (my & 0x0001)
|
||||
{
|
||||
index += x;
|
||||
}
|
||||
else
|
||||
{
|
||||
index += ((width - 1) - x);
|
||||
}
|
||||
return index;
|
||||
}
|
||||
};
|
||||
|
||||
// layout example of 4x4
|
||||
// 03 04 11 12
|
||||
// 02 05 10 13
|
||||
// 01 06 09 14
|
||||
// 00 07 08 15
|
||||
//
|
||||
class RowMajorAlternating270Layout : public RowMajorAlternatingTilePreference
|
||||
{
|
||||
public:
|
||||
static uint16_t Map(uint16_t /* width */, uint16_t height, uint16_t x, uint16_t y)
|
||||
{
|
||||
uint16_t index = x * height;
|
||||
|
||||
if (x & 0x0001)
|
||||
{
|
||||
index += y;
|
||||
}
|
||||
else
|
||||
{
|
||||
index += ((height - 1) - y);
|
||||
}
|
||||
return index;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// ColumnMajorAlternating
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class ColumnMajorAlternatingLayout;
|
||||
class ColumnMajorAlternating180Layout;
|
||||
|
||||
class ColumnMajorAlternatingTilePreference
|
||||
{
|
||||
public:
|
||||
typedef ColumnMajorAlternatingLayout EvenRowEvenColumnLayout;
|
||||
typedef ColumnMajorAlternatingLayout EvenRowOddColumnLayout;
|
||||
typedef ColumnMajorAlternating180Layout OddRowEvenColumnLayout;
|
||||
typedef ColumnMajorAlternating180Layout OddRowOddColumnLayout;
|
||||
};
|
||||
|
||||
// layout example of 4x4
|
||||
// 00 07 08 15
|
||||
// 01 06 09 14
|
||||
// 02 05 10 13
|
||||
// 03 04 11 12
|
||||
//
|
||||
class ColumnMajorAlternatingLayout : public ColumnMajorAlternatingTilePreference
|
||||
{
|
||||
public:
|
||||
static uint16_t Map(uint16_t /* width */, uint16_t height, uint16_t x, uint16_t y)
|
||||
{
|
||||
uint16_t index = x * height;
|
||||
|
||||
if (x & 0x0001)
|
||||
{
|
||||
index += ((height - 1) - y);
|
||||
}
|
||||
else
|
||||
{
|
||||
index += y;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
};
|
||||
|
||||
// layout example of 4x4
|
||||
// 03 02 01 00
|
||||
// 04 05 06 07
|
||||
// 11 10 09 08
|
||||
// 12 13 14 15
|
||||
//
|
||||
class ColumnMajorAlternating90Layout : public ColumnMajorAlternatingTilePreference
|
||||
{
|
||||
public:
|
||||
static uint16_t Map(uint16_t width, uint16_t /* height */, uint16_t x, uint16_t y)
|
||||
{
|
||||
uint16_t index = y * width;
|
||||
|
||||
if (y & 0x0001)
|
||||
{
|
||||
index += x;
|
||||
}
|
||||
else
|
||||
{
|
||||
index += ((width - 1) - x);
|
||||
}
|
||||
return index;
|
||||
}
|
||||
};
|
||||
|
||||
// layout example of 4x4
|
||||
// 12 11 04 03
|
||||
// 13 10 05 02
|
||||
// 14 09 06 01
|
||||
// 15 08 07 00
|
||||
//
|
||||
class ColumnMajorAlternating180Layout : public ColumnMajorAlternatingTilePreference
|
||||
{
|
||||
public:
|
||||
static uint16_t Map(uint16_t width, uint16_t height, uint16_t x, uint16_t y)
|
||||
{
|
||||
uint16_t mx = ((width - 1) - x);
|
||||
uint16_t index = mx * height;
|
||||
|
||||
if (mx & 0x0001)
|
||||
{
|
||||
index += y;
|
||||
}
|
||||
else
|
||||
{
|
||||
index += ((height - 1) - y);
|
||||
}
|
||||
return index;
|
||||
}
|
||||
};
|
||||
|
||||
// layout example of 4x4
|
||||
// 15 14 13 12
|
||||
// 08 09 10 11
|
||||
// 07 06 05 04
|
||||
// 00 01 02 03
|
||||
//
|
||||
class ColumnMajorAlternating270Layout : public ColumnMajorAlternatingTilePreference
|
||||
{
|
||||
public:
|
||||
static uint16_t Map(uint16_t width, uint16_t height, uint16_t x, uint16_t y)
|
||||
{
|
||||
uint16_t my = ((height - 1) - y);
|
||||
uint16_t index = my * width;
|
||||
|
||||
if (my & 0x0001)
|
||||
{
|
||||
index += ((width - 1) - x);
|
||||
}
|
||||
else
|
||||
{
|
||||
index += x;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
};
|
||||
189
lib/NeoPixelBus_by_Makuna/src/internal/Lpd8806ColorFeatures.h
Normal file
189
lib/NeoPixelBus_by_Makuna/src/internal/Lpd8806ColorFeatures.h
Normal file
@@ -0,0 +1,189 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
Lpd8806ColorFeatures provides feature classes to describe color order and
|
||||
color depth for NeoPixelBus template class when used with DotStar like chips
|
||||
|
||||
Written by Michael C. Miller.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
#pragma once
|
||||
|
||||
class Lpd88063ElementsNoSettings
|
||||
{
|
||||
public:
|
||||
typedef NeoNoSettings SettingsObject;
|
||||
static const size_t SettingsSize = 0;
|
||||
|
||||
static void applySettings(uint8_t*, const SettingsObject&)
|
||||
{
|
||||
}
|
||||
|
||||
static uint8_t* pixels(uint8_t* pData)
|
||||
{
|
||||
return pData;
|
||||
}
|
||||
|
||||
static const uint8_t* pixels(const uint8_t* pData)
|
||||
{
|
||||
return pData;
|
||||
}
|
||||
};
|
||||
|
||||
class Lpd88063Elements : public Lpd88063ElementsNoSettings
|
||||
{
|
||||
public:
|
||||
static const size_t PixelSize = 3;
|
||||
|
||||
|
||||
static uint8_t* getPixelAddress(uint8_t* pPixels, uint16_t indexPixel)
|
||||
{
|
||||
return pPixels + indexPixel * PixelSize;
|
||||
}
|
||||
static const uint8_t* getPixelAddress(const uint8_t* pPixels, uint16_t indexPixel)
|
||||
{
|
||||
return pPixels + indexPixel * PixelSize;
|
||||
}
|
||||
|
||||
static void replicatePixel(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count)
|
||||
{
|
||||
uint8_t* pEnd = pPixelDest + (count * PixelSize);
|
||||
while (pPixelDest < pEnd)
|
||||
{
|
||||
*pPixelDest++ = pPixelSrc[0];
|
||||
*pPixelDest++ = pPixelSrc[1];
|
||||
*pPixelDest++ = pPixelSrc[2];
|
||||
}
|
||||
}
|
||||
|
||||
static void movePixelsInc(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count)
|
||||
{
|
||||
uint8_t* pEnd = pPixelDest + (count * PixelSize);
|
||||
while (pPixelDest < pEnd)
|
||||
{
|
||||
*pPixelDest++ = *pPixelSrc++;
|
||||
*pPixelDest++ = *pPixelSrc++;
|
||||
*pPixelDest++ = *pPixelSrc++;
|
||||
}
|
||||
}
|
||||
|
||||
static void movePixelsInc_P(uint8_t* pPixelDest, PGM_VOID_P pPixelSrc, uint16_t count)
|
||||
{
|
||||
uint8_t* pEnd = pPixelDest + (count * PixelSize);
|
||||
const uint8_t* pSrc = (const uint8_t*)pPixelSrc;
|
||||
while (pPixelDest < pEnd)
|
||||
{
|
||||
*pPixelDest++ = pgm_read_byte(pSrc++);
|
||||
*pPixelDest++ = pgm_read_byte(pSrc++);
|
||||
*pPixelDest++ = pgm_read_byte(pSrc++);
|
||||
}
|
||||
}
|
||||
|
||||
static void movePixelsDec(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count)
|
||||
{
|
||||
uint8_t* pDestBack = pPixelDest + (count * PixelSize);
|
||||
const uint8_t* pSrcBack = pPixelSrc + (count * PixelSize);
|
||||
while (pDestBack > pPixelDest)
|
||||
{
|
||||
*--pDestBack = *--pSrcBack;
|
||||
*--pDestBack = *--pSrcBack;
|
||||
*--pDestBack = *--pSrcBack;
|
||||
}
|
||||
}
|
||||
|
||||
typedef RgbColor ColorObject;
|
||||
};
|
||||
|
||||
class Lpd8806BrgFeature : public Lpd88063Elements
|
||||
{
|
||||
public:
|
||||
static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color)
|
||||
{
|
||||
uint8_t* p = getPixelAddress(pPixels, indexPixel);
|
||||
|
||||
*p++ = (color.B >> 1) | 0x80;
|
||||
*p++ = (color.R >> 1) | 0x80;
|
||||
*p = (color.G >> 1) | 0x80;
|
||||
}
|
||||
|
||||
static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel)
|
||||
{
|
||||
ColorObject color;
|
||||
const uint8_t* p = getPixelAddress(pPixels, indexPixel);
|
||||
|
||||
color.B = (*p++) << 1;
|
||||
color.R = (*p++) << 1;
|
||||
color.G = (*p) << 1;
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
static ColorObject retrievePixelColor_P(PGM_VOID_P pPixels, uint16_t indexPixel)
|
||||
{
|
||||
ColorObject color;
|
||||
const uint8_t* p = getPixelAddress((const uint8_t*)pPixels, indexPixel);
|
||||
|
||||
color.B = (pgm_read_byte(p++)) << 1;
|
||||
color.R = (pgm_read_byte(p++)) << 1;
|
||||
color.G = (pgm_read_byte(p)) << 1;
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class Lpd8806GrbFeature : public Lpd88063Elements
|
||||
{
|
||||
public:
|
||||
static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color)
|
||||
{
|
||||
uint8_t* p = getPixelAddress(pPixels, indexPixel);
|
||||
|
||||
*p++ = (color.G >> 1) | 0x80;
|
||||
*p++ = (color.R >> 1) | 0x80;
|
||||
*p = (color.B >> 1) | 0x80;
|
||||
}
|
||||
|
||||
static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel)
|
||||
{
|
||||
ColorObject color;
|
||||
const uint8_t* p = getPixelAddress(pPixels, indexPixel);
|
||||
|
||||
color.G = (*p++) << 1;
|
||||
color.R = (*p++) << 1;
|
||||
color.B = (*p) << 1;
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
static ColorObject retrievePixelColor_P(PGM_VOID_P pPixels, uint16_t indexPixel)
|
||||
{
|
||||
ColorObject color;
|
||||
const uint8_t* p = getPixelAddress((const uint8_t*)pPixels, indexPixel);
|
||||
|
||||
color.G = (pgm_read_byte(p++)) << 1;
|
||||
color.R = (pgm_read_byte(p++)) << 1;
|
||||
color.B = (pgm_read_byte(p)) << 1;
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
130
lib/NeoPixelBus_by_Makuna/src/internal/Lpd8806GenericMethod.h
Normal file
130
lib/NeoPixelBus_by_Makuna/src/internal/Lpd8806GenericMethod.h
Normal file
@@ -0,0 +1,130 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
NeoPixel library helper functions for LPD8806 using general Pins
|
||||
|
||||
Written by Michael C. Miller.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// must also check for arm due to Teensy incorrectly having ARDUINO_ARCH_AVR set
|
||||
#if defined(ARDUINO_ARCH_AVR) && !defined(__arm__)
|
||||
#include "TwoWireBitBangImpleAvr.h"
|
||||
#else
|
||||
#include "TwoWireBitBangImple.h"
|
||||
#endif
|
||||
|
||||
|
||||
template<typename T_TWOWIRE> class Lpd8806MethodBase
|
||||
{
|
||||
public:
|
||||
Lpd8806MethodBase(uint8_t pinClock, uint8_t pinData, uint16_t pixelCount, size_t elementSize, size_t settingsSize) :
|
||||
_sizeData(pixelCount * elementSize + settingsSize),
|
||||
_sizeFrame((pixelCount + 31) / 32),
|
||||
_wire(pinClock, pinData)
|
||||
{
|
||||
_data = static_cast<uint8_t*>(malloc(_sizeData));
|
||||
memset(_data, 0, _sizeData);
|
||||
}
|
||||
|
||||
#if !defined(__AVR_ATtiny85__) && !defined(ARDUINO_attiny)
|
||||
Lpd8806MethodBase(uint16_t pixelCount, size_t elementSize, size_t settingsSize) :
|
||||
Lpd8806MethodBase(SCK, MOSI, pixelCount, elementSize, settingsSize)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
~Lpd8806MethodBase()
|
||||
{
|
||||
free(_data);
|
||||
}
|
||||
|
||||
bool IsReadyToUpdate() const
|
||||
{
|
||||
return true; // dot stars don't have a required delay
|
||||
}
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP32)
|
||||
void Initialize(int8_t sck, int8_t miso, int8_t mosi, int8_t ss)
|
||||
{
|
||||
_wire.begin(sck, miso, mosi, ss);
|
||||
}
|
||||
#endif
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
_wire.begin();
|
||||
}
|
||||
|
||||
void Update(bool)
|
||||
{
|
||||
_wire.beginTransaction();
|
||||
|
||||
// start frame
|
||||
for (size_t frameByte = 0; frameByte < _sizeFrame; frameByte++)
|
||||
{
|
||||
_wire.transmitByte(0x00);
|
||||
}
|
||||
|
||||
// data
|
||||
_wire.transmitBytes(_data, _sizeData);
|
||||
|
||||
// end frame
|
||||
for (size_t frameByte = 0; frameByte < _sizeFrame; frameByte++)
|
||||
{
|
||||
_wire.transmitByte(0xff);
|
||||
}
|
||||
|
||||
_wire.endTransaction();
|
||||
}
|
||||
|
||||
uint8_t* getData() const
|
||||
{
|
||||
return _data;
|
||||
};
|
||||
|
||||
size_t getDataSize() const
|
||||
{
|
||||
return _sizeData;
|
||||
};
|
||||
|
||||
private:
|
||||
const size_t _sizeData; // Size of '_data' buffer below
|
||||
const size_t _sizeFrame;
|
||||
|
||||
T_TWOWIRE _wire;
|
||||
uint8_t* _data; // Holds LED color values
|
||||
};
|
||||
|
||||
typedef Lpd8806MethodBase<TwoWireBitBangImple> Lpd8806Method;
|
||||
|
||||
#if !defined(__AVR_ATtiny85__) && !defined(ARDUINO_attiny)
|
||||
#include "TwoWireSpiImple.h"
|
||||
typedef Lpd8806MethodBase<TwoWireSpiImple<SpiSpeed20Mhz>> Lpd8806Spi20MhzMethod;
|
||||
typedef Lpd8806MethodBase<TwoWireSpiImple<SpiSpeed10Mhz>> Lpd8806Spi10MhzMethod;
|
||||
typedef Lpd8806MethodBase<TwoWireSpiImple<SpiSpeed2Mhz>> Lpd8806Spi2MhzMethod;
|
||||
typedef Lpd8806Spi10MhzMethod Lpd8806SpiMethod;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
818
lib/NeoPixelBus_by_Makuna/src/internal/NeoArmMethod.h
Normal file
818
lib/NeoPixelBus_by_Makuna/src/internal/NeoArmMethod.h
Normal file
@@ -0,0 +1,818 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
NeoPixel library helper functions for ARM MCUs.
|
||||
Teensy 3.0, 3.1, LC, Arduino Due
|
||||
|
||||
Written by Michael C. Miller.
|
||||
Some work taken from the Adafruit NeoPixel library.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
The contents of this file were taken from the Adafruit NeoPixel library
|
||||
and modified only to fit within individual calling functions.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if defined(__arm__) && !defined(ARDUINO_ARCH_NRF52840)
|
||||
|
||||
template<typename T_SPEED> class NeoArmMethodBase
|
||||
{
|
||||
public:
|
||||
NeoArmMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize) :
|
||||
_sizeData(pixelCount * elementSize + settingsSize),
|
||||
_pin(pin)
|
||||
{
|
||||
pinMode(pin, OUTPUT);
|
||||
|
||||
_data = static_cast<uint8_t*>(malloc(_sizeData));
|
||||
memset(_data, 0, _sizeData);
|
||||
}
|
||||
|
||||
~NeoArmMethodBase()
|
||||
{
|
||||
pinMode(_pin, INPUT);
|
||||
|
||||
free(_data);
|
||||
}
|
||||
|
||||
bool IsReadyToUpdate() const
|
||||
{
|
||||
uint32_t delta = micros() - _endTime;
|
||||
|
||||
return (delta >= T_SPEED::ResetTimeUs);
|
||||
}
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
digitalWrite(_pin, LOW);
|
||||
|
||||
_endTime = micros();
|
||||
}
|
||||
|
||||
void Update(bool)
|
||||
{
|
||||
// Data latch = 50+ microsecond pause in the output stream. Rather than
|
||||
// put a delay at the end of the function, the ending time is noted and
|
||||
// the function will simply hold off (if needed) on issuing the
|
||||
// subsequent round of data until the latch time has elapsed. This
|
||||
// allows the mainline code to start generating the next frame of data
|
||||
// rather than stalling for the latch.
|
||||
while (!IsReadyToUpdate())
|
||||
{
|
||||
yield(); // allows for system yield if needed
|
||||
}
|
||||
|
||||
noInterrupts(); // Need 100% focus on instruction timing
|
||||
|
||||
T_SPEED::send_pixels(_data, _sizeData, _pin);
|
||||
|
||||
interrupts();
|
||||
|
||||
// save EOD time for latch on next call
|
||||
_endTime = micros();
|
||||
}
|
||||
|
||||
uint8_t* getData() const
|
||||
{
|
||||
return _data;
|
||||
};
|
||||
|
||||
size_t getDataSize() const
|
||||
{
|
||||
return _sizeData;
|
||||
};
|
||||
|
||||
private:
|
||||
const size_t _sizeData; // Size of '_data' buffer below
|
||||
|
||||
uint32_t _endTime; // Latch timing reference
|
||||
uint8_t* _data; // Holds LED color values
|
||||
uint8_t _pin; // output pin number
|
||||
};
|
||||
|
||||
// Teensy 3.0 or 3.1 (3.2) or 3.5 or 3.6
|
||||
#if defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__)
|
||||
|
||||
class NeoArmMk20dxSpeedProps800KbpsBase
|
||||
{
|
||||
public:
|
||||
static const uint32_t CyclesT0h = (F_CPU / 4000000);
|
||||
static const uint32_t CyclesT1h = (F_CPU / 1250000);
|
||||
static const uint32_t Cycles = (F_CPU / 800000);
|
||||
};
|
||||
|
||||
class NeoArmMk20dxSpeedPropsWs2812x : public NeoArmMk20dxSpeedProps800KbpsBase
|
||||
{
|
||||
public:
|
||||
static const uint32_t ResetTimeUs = 300;
|
||||
};
|
||||
|
||||
class NeoArmMk20dxSpeedPropsSk6812 : public NeoArmMk20dxSpeedProps800KbpsBase
|
||||
{
|
||||
public:
|
||||
static const uint32_t ResetTimeUs = 80;
|
||||
};
|
||||
|
||||
class NeoArmMk20dxSpeedPropsTm1814 : public NeoArmMk20dxSpeedProps800KbpsBase
|
||||
{
|
||||
public:
|
||||
static const uint32_t ResetTimeUs = 200;
|
||||
};
|
||||
|
||||
class NeoArmMk20dxSpeedProps800Kbps : public NeoArmMk20dxSpeedProps800KbpsBase
|
||||
{
|
||||
public:
|
||||
static const uint32_t ResetTimeUs = 50;
|
||||
};
|
||||
|
||||
class NeoArmMk20dxSpeedProps400Kbps
|
||||
{
|
||||
public:
|
||||
static const uint32_t CyclesT0h = (F_CPU / 2000000);
|
||||
static const uint32_t CyclesT1h = (F_CPU / 833333);
|
||||
static const uint32_t Cycles = (F_CPU / 400000);
|
||||
static const uint32_t ResetTimeUs = 50;
|
||||
};
|
||||
|
||||
class NeoArmMk20dxSpeedPropsApa106
|
||||
{
|
||||
public:
|
||||
static const uint32_t CyclesT0h = (F_CPU / 4000000);
|
||||
static const uint32_t CyclesT1h = (F_CPU / 913750);
|
||||
static const uint32_t Cycles = (F_CPU / 584800);
|
||||
static const uint32_t ResetTimeUs = 50;
|
||||
};
|
||||
|
||||
template<typename T_SPEEDPROPS> class NeoArmMk20dxSpeedBase
|
||||
{
|
||||
public:
|
||||
static const uint32_t ResetTimeUs = T_SPEEDPROPS::ResetTimeUs;
|
||||
|
||||
static void send_pixels(uint8_t* pixels, size_t sizePixels, uint8_t pin)
|
||||
{
|
||||
uint8_t* p = pixels;
|
||||
uint8_t* end = p + sizePixels;
|
||||
uint8_t pix;
|
||||
uint8_t mask;
|
||||
|
||||
volatile uint8_t* set = portSetRegister(pin);
|
||||
volatile uint8_t* clr = portClearRegister(pin);
|
||||
|
||||
uint32_t cyc;
|
||||
|
||||
ARM_DEMCR |= ARM_DEMCR_TRCENA;
|
||||
ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA;
|
||||
|
||||
cyc = ARM_DWT_CYCCNT + T_SPEEDPROPS::Cycles;
|
||||
while (p < end)
|
||||
{
|
||||
pix = *p++;
|
||||
for (mask = 0x80; mask; mask >>= 1)
|
||||
{
|
||||
while (ARM_DWT_CYCCNT - cyc < T_SPEEDPROPS::Cycles);
|
||||
|
||||
cyc = ARM_DWT_CYCCNT;
|
||||
*set = 1;
|
||||
if (pix & mask)
|
||||
{
|
||||
while (ARM_DWT_CYCCNT - cyc < T_SPEEDPROPS::CyclesT1h);
|
||||
}
|
||||
else
|
||||
{
|
||||
while (ARM_DWT_CYCCNT - cyc < T_SPEEDPROPS::CyclesT0h);
|
||||
}
|
||||
*clr = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
typedef NeoArmMethodBase<NeoArmMk20dxSpeedBase<NeoArmMk20dxSpeedPropsWs2812x>> NeoArmWs2812xMethod;
|
||||
typedef NeoArmMethodBase<NeoArmMk20dxSpeedBase<NeoArmMk20dxSpeedPropsSk6812>> NeoArmSk6812Method;
|
||||
typedef NeoArmMethodBase<NeoArmMk20dxSpeedBase<NeoArmMk20dxSpeedPropsTm1814>> NeoArmTm1814InvertedMethod;
|
||||
typedef NeoArmMethodBase<NeoArmMk20dxSpeedBase<NeoArmMk20dxSpeedPropsApa106>> NeoArmApa106Method;
|
||||
typedef NeoArmMethodBase<NeoArmMk20dxSpeedBase<NeoArmMk20dxSpeedProps800Kbps>> NeoArm800KbpsMethod;
|
||||
typedef NeoArmMethodBase<NeoArmMk20dxSpeedBase<NeoArmMk20dxSpeedProps400Kbps>> NeoArm400KbpsMethod;
|
||||
|
||||
|
||||
#elif defined(__MKL26Z64__) // Teensy-LC
|
||||
|
||||
#if F_CPU == 48000000
|
||||
|
||||
class NeoArmMk26z64Speed800KbpsBase
|
||||
{
|
||||
public:
|
||||
static void send_pixels(uint8_t* pixels, size_t sizePixels, uint8_t pin)
|
||||
{
|
||||
uint8_t* p = pixels;
|
||||
uint8_t pix;
|
||||
uint8_t count;
|
||||
uint8_t dly;
|
||||
uint8_t bitmask = digitalPinToBitMask(pin);
|
||||
volatile uint8_t* reg = portSetRegister(pin);
|
||||
uint32_t num = sizePixels;
|
||||
|
||||
asm volatile(
|
||||
"L%=_begin:" "\n\t"
|
||||
"ldrb %[pix], [%[p], #0]" "\n\t"
|
||||
"lsl %[pix], #24" "\n\t"
|
||||
"movs %[count], #7" "\n\t"
|
||||
"L%=_loop:" "\n\t"
|
||||
"lsl %[pix], #1" "\n\t"
|
||||
"bcs L%=_loop_one" "\n\t"
|
||||
"L%=_loop_zero:"
|
||||
"strb %[bitmask], [%[reg], #0]" "\n\t"
|
||||
"movs %[dly], #4" "\n\t"
|
||||
"L%=_loop_delay_T0H:" "\n\t"
|
||||
"sub %[dly], #1" "\n\t"
|
||||
"bne L%=_loop_delay_T0H" "\n\t"
|
||||
"strb %[bitmask], [%[reg], #4]" "\n\t"
|
||||
"movs %[dly], #13" "\n\t"
|
||||
"L%=_loop_delay_T0L:" "\n\t"
|
||||
"sub %[dly], #1" "\n\t"
|
||||
"bne L%=_loop_delay_T0L" "\n\t"
|
||||
"b L%=_next" "\n\t"
|
||||
"L%=_loop_one:"
|
||||
"strb %[bitmask], [%[reg], #0]" "\n\t"
|
||||
"movs %[dly], #13" "\n\t"
|
||||
"L%=_loop_delay_T1H:" "\n\t"
|
||||
"sub %[dly], #1" "\n\t"
|
||||
"bne L%=_loop_delay_T1H" "\n\t"
|
||||
"strb %[bitmask], [%[reg], #4]" "\n\t"
|
||||
"movs %[dly], #4" "\n\t"
|
||||
"L%=_loop_delay_T1L:" "\n\t"
|
||||
"sub %[dly], #1" "\n\t"
|
||||
"bne L%=_loop_delay_T1L" "\n\t"
|
||||
"nop" "\n\t"
|
||||
"L%=_next:" "\n\t"
|
||||
"sub %[count], #1" "\n\t"
|
||||
"bne L%=_loop" "\n\t"
|
||||
"lsl %[pix], #1" "\n\t"
|
||||
"bcs L%=_last_one" "\n\t"
|
||||
"L%=_last_zero:"
|
||||
"strb %[bitmask], [%[reg], #0]" "\n\t"
|
||||
"movs %[dly], #4" "\n\t"
|
||||
"L%=_last_delay_T0H:" "\n\t"
|
||||
"sub %[dly], #1" "\n\t"
|
||||
"bne L%=_last_delay_T0H" "\n\t"
|
||||
"strb %[bitmask], [%[reg], #4]" "\n\t"
|
||||
"movs %[dly], #10" "\n\t"
|
||||
"L%=_last_delay_T0L:" "\n\t"
|
||||
"sub %[dly], #1" "\n\t"
|
||||
"bne L%=_last_delay_T0L" "\n\t"
|
||||
"b L%=_repeat" "\n\t"
|
||||
"L%=_last_one:"
|
||||
"strb %[bitmask], [%[reg], #0]" "\n\t"
|
||||
"movs %[dly], #13" "\n\t"
|
||||
"L%=_last_delay_T1H:" "\n\t"
|
||||
"sub %[dly], #1" "\n\t"
|
||||
"bne L%=_last_delay_T1H" "\n\t"
|
||||
"strb %[bitmask], [%[reg], #4]" "\n\t"
|
||||
"movs %[dly], #1" "\n\t"
|
||||
"L%=_last_delay_T1L:" "\n\t"
|
||||
"sub %[dly], #1" "\n\t"
|
||||
"bne L%=_last_delay_T1L" "\n\t"
|
||||
"nop" "\n\t"
|
||||
"L%=_repeat:" "\n\t"
|
||||
"add %[p], #1" "\n\t"
|
||||
"sub %[num], #1" "\n\t"
|
||||
"bne L%=_begin" "\n\t"
|
||||
"L%=_done:" "\n\t"
|
||||
: [p] "+r" (p),
|
||||
[pix] "=&r" (pix),
|
||||
[count] "=&r" (count),
|
||||
[dly] "=&r" (dly),
|
||||
[num] "+r" (num)
|
||||
: [bitmask] "r" (bitmask),
|
||||
[reg] "r" (reg)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
class NeoArmMk26z64SpeedWs2812x : public NeoArmMk26z64Speed800KbpsBase
|
||||
{
|
||||
public:
|
||||
const static uint32_t ResetTimeUs = 300;
|
||||
};
|
||||
|
||||
class NeoArmMk26z64SpeedSk6812 : public NeoArmMk26z64Speed800KbpsBase
|
||||
{
|
||||
public:
|
||||
const static uint32_t ResetTimeUs = 80;
|
||||
};
|
||||
|
||||
class NeoArmMk26z64SpeedTm1814 : public NeoArmMk26z64Speed800KbpsBase
|
||||
{
|
||||
public:
|
||||
const static uint32_t ResetTimeUs = 200;
|
||||
};
|
||||
|
||||
class NeoArmMk26z64Speed800Kbps : public NeoArmMk26z64Speed800KbpsBase
|
||||
{
|
||||
public:
|
||||
const static uint32_t ResetTimeUs = 50;
|
||||
};
|
||||
|
||||
typedef NeoArmMethodBase<NeoArmMk26z64SpeedWs2812x> NeoArmWs2812xMethod;
|
||||
typedef NeoArmMethodBase<NeoArmMk26z64SpeedSk6812> NeoArmSk6812Method;
|
||||
typedef NeoArmMethodBase<NeoArmMk26z64SpeedTm1814> NeoArmTm1814InvertedMethod;
|
||||
typedef NeoArmMethodBase<NeoArmMk26z64Speed800Kbps> NeoArm800KbpsMethod;
|
||||
typedef NeoArm800KbpsMethod NeoArmApa106Method
|
||||
|
||||
#else
|
||||
#error "Teensy-LC: Sorry, only 48 MHz is supported, please set Tools > CPU Speed to 48 MHz"
|
||||
#endif // F_CPU == 48000000
|
||||
|
||||
#elif defined(__SAMD21G18A__) // Arduino Zero
|
||||
|
||||
|
||||
class NeoArmSamd21g18aSpeedProps800KbpsBase
|
||||
{
|
||||
public:
|
||||
static void BitPreWait()
|
||||
{
|
||||
asm("nop; nop; nop; nop; nop; nop; nop; nop;");
|
||||
}
|
||||
static void BitT1hWait()
|
||||
{
|
||||
asm("nop; nop; nop; nop; nop; nop; nop; nop;"
|
||||
"nop; nop; nop; nop; nop; nop; nop; nop;"
|
||||
"nop; nop; nop; nop;");
|
||||
}
|
||||
static void BitT0lWait()
|
||||
{
|
||||
asm("nop; nop; nop; nop; nop; nop; nop; nop;"
|
||||
"nop; nop; nop; nop; nop; nop; nop; nop;"
|
||||
"nop; nop; nop; nop;");
|
||||
}
|
||||
static void BitPostWait()
|
||||
{
|
||||
asm("nop; nop; nop; nop; nop; nop; nop; nop; nop;");
|
||||
}
|
||||
};
|
||||
|
||||
class NeoArmSamd21g18aSpeedPropsWs2812x : public NeoArmSamd21g18aSpeedProps800KbpsBase
|
||||
{
|
||||
public:
|
||||
static const uint32_t ResetTimeUs = 300;
|
||||
};
|
||||
|
||||
class NeoArmSamd21g18aSpeedPropsSk6812 : public NeoArmSamd21g18aSpeedProps800KbpsBase
|
||||
{
|
||||
public:
|
||||
static const uint32_t ResetTimeUs = 80;
|
||||
};
|
||||
|
||||
class NeoArmSamd21g18aSpeedPropsTm1814 : public NeoArmSamd21g18aSpeedProps800KbpsBase
|
||||
{
|
||||
public:
|
||||
static const uint32_t ResetTimeUs = 200;
|
||||
};
|
||||
|
||||
class NeoArmSamd21g18aSpeedProps800Kbps : public NeoArmSamd21g18aSpeedProps800KbpsBase
|
||||
{
|
||||
public:
|
||||
static const uint32_t ResetTimeUs = 50;
|
||||
};
|
||||
|
||||
|
||||
class NeoArmSamd21g18aSpeedProps400Kbps
|
||||
{
|
||||
public:
|
||||
static void BitPreWait()
|
||||
{
|
||||
asm("nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop;");
|
||||
}
|
||||
static void BitT1hWait()
|
||||
{
|
||||
asm("nop; nop; nop; nop; nop; nop; nop; nop;"
|
||||
"nop; nop; nop; nop; nop; nop; nop; nop;"
|
||||
"nop; nop; nop; nop; nop; nop; nop; nop;"
|
||||
"nop; nop; nop;");
|
||||
}
|
||||
static void BitT0lWait()
|
||||
{
|
||||
asm("nop; nop; nop; nop; nop; nop; nop; nop;"
|
||||
"nop; nop; nop; nop; nop; nop; nop; nop;"
|
||||
"nop; nop; nop; nop; nop; nop; nop; nop;"
|
||||
"nop; nop; nop;");
|
||||
}
|
||||
static void BitPostWait()
|
||||
{
|
||||
asm("nop; nop; nop; nop; nop; nop; nop;");
|
||||
}
|
||||
static const uint32_t ResetTimeUs = 50;
|
||||
};
|
||||
|
||||
template<typename T_SPEEDPROPS> class NeoArmSamd21g18aSpeedBase
|
||||
{
|
||||
public:
|
||||
static const uint32_t ResetTimeUs = T_SPEEDPROPS::ResetTimeUs;
|
||||
|
||||
static void send_pixels(uint8_t* pixels, size_t sizePixels, uint8_t pin)
|
||||
{
|
||||
// Tried this with a timer/counter, couldn't quite get adequate
|
||||
// resolution. So yay, you get a load of goofball NOPs...
|
||||
uint8_t* ptr = pixels;
|
||||
uint8_t* end = ptr + sizePixels;;
|
||||
uint8_t p = *ptr++;
|
||||
uint8_t bitMask = 0x80;
|
||||
uint8_t portNum = g_APinDescription[pin].ulPort;
|
||||
uint32_t pinMask = 1ul << g_APinDescription[pin].ulPin;
|
||||
|
||||
volatile uint32_t* set = &(PORT->Group[portNum].OUTSET.reg);
|
||||
volatile uint32_t* clr = &(PORT->Group[portNum].OUTCLR.reg);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
*set = pinMask;
|
||||
T_SPEEDPROPS::BitPreWait();
|
||||
|
||||
if (p & bitMask)
|
||||
{
|
||||
T_SPEEDPROPS::BitT1hWait();
|
||||
*clr = pinMask;
|
||||
}
|
||||
else
|
||||
{
|
||||
*clr = pinMask;
|
||||
T_SPEEDPROPS::BitT0lWait();
|
||||
}
|
||||
if (bitMask >>= 1)
|
||||
{
|
||||
T_SPEEDPROPS::BitPostWait();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ptr >= end)
|
||||
{
|
||||
break;
|
||||
}
|
||||
p = *ptr++;
|
||||
bitMask = 0x80;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
typedef NeoArmMethodBase<NeoArmSamd21g18aSpeedBase<NeoArmSamd21g18aSpeedPropsWs2812x>> NeoArmWs2812xMethod;
|
||||
typedef NeoArmMethodBase<NeoArmSamd21g18aSpeedBase<NeoArmSamd21g18aSpeedPropsSk6812>> NeoArmSk6812Method;
|
||||
typedef NeoArmMethodBase<NeoArmSamd21g18aSpeedBase<NeoArmSamd21g18aSpeedPropsTm1814>> NeoArmTm1814InvertedMethod;
|
||||
typedef NeoArmMethodBase<NeoArmSamd21g18aSpeedBase<NeoArmSamd21g18aSpeedProps800Kbps>> NeoArm800KbpsMethod;
|
||||
typedef NeoArmMethodBase<NeoArmSamd21g18aSpeedBase<NeoArmSamd21g18aSpeedProps400Kbps>> NeoArm400KbpsMethod;
|
||||
typedef NeoArm400KbpsMethod NeoArmApa106Method;
|
||||
|
||||
#elif defined(ARDUINO_STM32_FEATHER) || defined(ARDUINO_ARCH_STM32L4) || defined(ARDUINO_ARCH_STM32F4) || defined(ARDUINO_ARCH_STM32F1)// FEATHER WICED (120MHz)
|
||||
|
||||
class NeoArmStm32SpeedProps800KbpsBase
|
||||
{
|
||||
public:
|
||||
static void BitT1hWait()
|
||||
{
|
||||
asm("nop; nop; nop; nop; nop; nop; nop; nop;"
|
||||
"nop; nop; nop; nop; nop; nop; nop; nop;"
|
||||
"nop; nop; nop; nop; nop; nop; nop; nop;"
|
||||
"nop; nop; nop; nop; nop; nop; nop; nop;"
|
||||
"nop; nop; nop; nop; nop; nop; nop; nop;"
|
||||
"nop; nop; nop; nop; nop; nop; nop; nop;"
|
||||
"nop; nop; nop; nop; nop; nop; nop; nop;"
|
||||
"nop; nop; nop; nop; nop; nop; nop; nop;"
|
||||
"nop; nop; nop; nop; nop; nop; nop; nop;"
|
||||
"nop; nop; nop; nop; nop; nop; nop; nop;"
|
||||
"nop; nop; nop; nop; nop; nop; nop; nop;"
|
||||
"nop; nop; nop; nop; nop; nop;");
|
||||
}
|
||||
static void BitT1lWait()
|
||||
{
|
||||
asm("nop; nop; nop; nop; nop; nop; nop; nop;"
|
||||
"nop; nop; nop; nop; nop; nop; nop; nop;"
|
||||
"nop; nop; nop; nop; nop; nop; nop; nop;"
|
||||
"nop; nop; nop; nop; nop; nop; nop; nop;"
|
||||
"nop; nop; nop; nop; nop; nop;");
|
||||
}
|
||||
static void BitT0hWait()
|
||||
{
|
||||
asm("nop; nop; nop; nop; nop; nop; nop; nop;"
|
||||
"nop; nop; nop; nop; nop; nop; nop; nop;"
|
||||
"nop; nop; nop; nop; nop; nop; nop; nop;"
|
||||
"nop; nop; nop; nop; nop; nop; nop; nop;"
|
||||
"nop; nop; nop; nop; nop; nop; nop; nop;"
|
||||
"nop;");
|
||||
}
|
||||
static void BitT0lWait()
|
||||
{
|
||||
asm("nop; nop; nop; nop; nop; nop; nop; nop;"
|
||||
"nop; nop; nop; nop; nop; nop; nop; nop;"
|
||||
"nop; nop; nop; nop; nop; nop; nop; nop;"
|
||||
"nop; nop; nop; nop; nop; nop; nop; nop;"
|
||||
"nop; nop; nop; nop; nop; nop; nop; nop;"
|
||||
"nop; nop; nop; nop; nop; nop; nop; nop;"
|
||||
"nop; nop; nop; nop; nop; nop; nop; nop;"
|
||||
"nop; nop; nop; nop; nop; nop; nop; nop;"
|
||||
"nop; nop; nop; nop; nop; nop; nop; nop;"
|
||||
"nop; nop; nop; nop; nop; nop; nop; nop;"
|
||||
"nop; nop; nop; nop; nop; nop; nop; nop;"
|
||||
"nop; nop; nop; nop;");
|
||||
}
|
||||
};
|
||||
|
||||
class NeoArmStm32SpeedPropsWs2812x : public NeoArmStm32SpeedProps800KbpsBase
|
||||
{
|
||||
public:
|
||||
static const uint32_t ResetTimeUs = 300;
|
||||
};
|
||||
|
||||
class NeoArmStm32SpeedPropsSk6812 : public NeoArmStm32SpeedProps800KbpsBase
|
||||
{
|
||||
public:
|
||||
static const uint32_t ResetTimeUs = 80;
|
||||
};
|
||||
|
||||
class NeoArmStm32SpeedPropsTm1814 : public NeoArmStm32SpeedProps800KbpsBase
|
||||
{
|
||||
public:
|
||||
static const uint32_t ResetTimeUs = 200;
|
||||
};
|
||||
|
||||
class NeoArmStm32SpeedProps800Kbps : public NeoArmStm32SpeedProps800KbpsBase
|
||||
{
|
||||
public:
|
||||
static const uint32_t ResetTimeUs = 50;
|
||||
};
|
||||
|
||||
/* TODO - not found in Adafruit library
|
||||
class NeoArmStm32SpeedProps400Kbps
|
||||
{
|
||||
static void BitT1hWait()
|
||||
{
|
||||
}
|
||||
static void BitT1lWait()
|
||||
{
|
||||
}
|
||||
static void BitT0hWait()
|
||||
{
|
||||
}
|
||||
static void BitT0lWait()
|
||||
{
|
||||
}
|
||||
};
|
||||
*/
|
||||
|
||||
template<typename T_SPEEDPROPS> class NeoArmStm32SpeedBase
|
||||
{
|
||||
public:
|
||||
static const uint32_t ResetTimeUs = T_SPEEDPROPS::ResetTimeUs;
|
||||
|
||||
static void send_pixels(uint8_t* pixels, size_t sizePixels, uint8_t pin)
|
||||
{
|
||||
// Tried this with a timer/counter, couldn't quite get adequate
|
||||
// resolution. So yay, you get a load of goofball NOPs...
|
||||
|
||||
uint8_t* ptr = pixels;
|
||||
uint8_t* end = ptr + sizePixels;
|
||||
uint8_t p = *ptr++;
|
||||
uint8_t bitMask = 0x80;
|
||||
|
||||
#if defined(ARDUINO_STM32_FEATHER)
|
||||
uint32_t pinMask = BIT(PIN_MAP[pin].gpio_bit);
|
||||
|
||||
volatile uint16_t* set = &(PIN_MAP[pin].gpio_device->regs->BSRRL);
|
||||
volatile uint16_t* clr = &(PIN_MAP[pin].gpio_device->regs->BSRRH);
|
||||
|
||||
#elif defined(ARDUINO_ARCH_STM32F4)
|
||||
uint32_t pinMask = BIT(pin & 0x0f);
|
||||
|
||||
volatile uint16_t* set = &(PIN_MAP[pin].gpio_device->regs->BSRRL);
|
||||
volatile uint16_t* clr = &(PIN_MAP[pin].gpio_device->regs->BSRRH);
|
||||
|
||||
#elif defined(ARDUINO_ARCH_STM32F1)
|
||||
|
||||
uint32_t pinMask = BIT(PIN_MAP[pin].gpio_bit);
|
||||
|
||||
volatile uint32_t* set = &(PIN_MAP[pin].gpio_device->regs->BRR);
|
||||
volatile uint32_t* clr = &(PIN_MAP[pin].gpio_device->regs->BSRR);
|
||||
|
||||
#elif defined(ARDUINO_ARCH_STM32L4)
|
||||
|
||||
uint32_t pinMask = g_APinDescription[pin].bit;
|
||||
|
||||
GPIO_TypeDef* GPIO = static_cast<GPIO_TypeDef*>(g_APinDescription[pin].GPIO);
|
||||
|
||||
volatile uint32_t* set = &(GPIO->BRR);
|
||||
volatile uint32_t* clr = &(GPIO->BSRR);
|
||||
|
||||
#endif
|
||||
for (;;)
|
||||
{
|
||||
if (p & bitMask)
|
||||
{
|
||||
// ONE
|
||||
// High 800ns
|
||||
*set = pinMask;
|
||||
T_SPEEDPROPS::BitT1hWait();
|
||||
// Low 450ns
|
||||
*clr = pinMask;
|
||||
T_SPEEDPROPS::BitT1lWait();
|
||||
}
|
||||
else
|
||||
{
|
||||
// ZERO
|
||||
// High 400ns
|
||||
*set = pinMask;
|
||||
T_SPEEDPROPS::BitT0hWait();
|
||||
// Low 850ns
|
||||
*clr = pinMask;
|
||||
T_SPEEDPROPS::BitT0lWait();
|
||||
}
|
||||
if (bitMask >>= 1)
|
||||
{
|
||||
// Move on to the next pixel
|
||||
asm("nop;");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ptr >= end)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
p = *ptr++;
|
||||
bitMask = 0x80;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
typedef NeoArmMethodBase<NeoArmStm32SpeedBase<NeoArmStm32SpeedPropsWs2812x>> NeoArmWs2812xMethod;
|
||||
typedef NeoArmMethodBase<NeoArmStm32SpeedBase<NeoArmStm32SpeedPropsSk6812>> NeoArmSk6812Method;
|
||||
typedef NeoArmMethodBase<NeoArmStm32SpeedBase<NeoArmStm32SpeedPropstm1814>> NeoArmTm1814InvertedMethod;
|
||||
typedef NeoArmMethodBase<NeoArmStm32SpeedBase<NeoArmStm32SpeedProps800Kbps>> NeoArm800KbpsMethod;
|
||||
typedef NeoArm800KbpsMethod NeoArmApa106Method;
|
||||
|
||||
#else // Other ARM architecture -- Presumed Arduino Due
|
||||
|
||||
|
||||
#define ARM_OTHER_SCALE VARIANT_MCK / 2UL / 1000000UL
|
||||
#define ARM_OTHER_INST (2UL * F_CPU / VARIANT_MCK)
|
||||
|
||||
class NeoArmOtherSpeedProps800KbpsBase
|
||||
{
|
||||
public:
|
||||
static const uint32_t CyclesT0h = ((uint32_t)(0.40 * ARM_OTHER_SCALE + 0.5) - (5 * ARM_OTHER_INST));
|
||||
static const uint32_t CyclesT1h = ((uint32_t)(0.80 * ARM_OTHER_SCALE + 0.5) - (5 * ARM_OTHER_INST));
|
||||
static const uint32_t Cycles = ((uint32_t)(1.25 * ARM_OTHER_SCALE + 0.5) - (5 * ARM_OTHER_INST));
|
||||
};
|
||||
|
||||
class NeoArmOtherSpeedPropsWs2812x : public NeoArmOtherSpeedProps800KbpsBase
|
||||
{
|
||||
public:
|
||||
static const uint32_t ResetTimeUs = 300;
|
||||
};
|
||||
|
||||
class NeoArmOtherSpeedPropsSk6812 : public NeoArmOtherSpeedProps800KbpsBase
|
||||
{
|
||||
public:
|
||||
static const uint32_t ResetTimeUs = 80;
|
||||
};
|
||||
|
||||
class NeoArmOtherSpeedPropsTm1814 : public NeoArmOtherSpeedProps800KbpsBase
|
||||
{
|
||||
public:
|
||||
static const uint32_t ResetTimeUs = 200;
|
||||
};
|
||||
|
||||
class NeoArmOtherSpeedProps800Kbps : public NeoArmOtherSpeedProps800KbpsBase
|
||||
{
|
||||
public:
|
||||
static const uint32_t ResetTimeUs = 50;
|
||||
};
|
||||
|
||||
class NeoArmOtherSpeedProps400Kbps
|
||||
{
|
||||
public:
|
||||
static const uint32_t CyclesT0h = ((uint32_t)(0.50 * ARM_OTHER_SCALE + 0.5) - (5 * ARM_OTHER_INST));
|
||||
static const uint32_t CyclesT1h = ((uint32_t)(1.20 * ARM_OTHER_SCALE + 0.5) - (5 * ARM_OTHER_INST));
|
||||
static const uint32_t Cycles = ((uint32_t)(2.50 * ARM_OTHER_SCALE + 0.5) - (5 * ARM_OTHER_INST));
|
||||
static const uint32_t ResetTimeUs = 50;
|
||||
};
|
||||
|
||||
template<typename T_SPEEDPROPS> class NeoArmOtherSpeedBase
|
||||
{
|
||||
public:
|
||||
static const uint32_t ResetTimeUs = T_SPEEDPROPS::ResetTimeUs;
|
||||
|
||||
static void send_pixels(uint8_t* pixels, size_t sizePixels, uint8_t pin)
|
||||
{
|
||||
uint32_t pinMask;
|
||||
uint32_t t;
|
||||
Pio* port;
|
||||
volatile WoReg* portSet;
|
||||
volatile WoReg* portClear;
|
||||
volatile WoReg* timeValue;
|
||||
volatile WoReg* timeReset;
|
||||
uint8_t* p;
|
||||
uint8_t* end;
|
||||
uint8_t pix;
|
||||
uint8_t mask;
|
||||
|
||||
pmc_set_writeprotect(false);
|
||||
pmc_enable_periph_clk((uint32_t)TC3_IRQn);
|
||||
|
||||
TC_Configure(TC1, 0,
|
||||
TC_CMR_WAVE | TC_CMR_WAVSEL_UP | TC_CMR_TCCLKS_TIMER_CLOCK1);
|
||||
TC_Start(TC1, 0);
|
||||
|
||||
pinMask = g_APinDescription[pin].ulPin; // Don't 'optimize' these into
|
||||
port = g_APinDescription[pin].pPort; // declarations above. Want to
|
||||
portSet = &(port->PIO_SODR); // burn a few cycles after
|
||||
portClear = &(port->PIO_CODR); // starting timer to minimize
|
||||
timeValue = &(TC1->TC_CHANNEL[0].TC_CV); // the initial 'while'.
|
||||
timeReset = &(TC1->TC_CHANNEL[0].TC_CCR);
|
||||
p = pixels;
|
||||
end = p + sizePixels;
|
||||
pix = *p++;
|
||||
mask = 0x80;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (pix & mask)
|
||||
{
|
||||
t = T_SPEEDPROPS::CyclesT1h;
|
||||
}
|
||||
else
|
||||
{
|
||||
t = T_SPEEDPROPS::CyclesT0h;
|
||||
}
|
||||
|
||||
// wait for the end of the previous cycle
|
||||
while (*timeValue < T_SPEEDPROPS::Cycles);
|
||||
|
||||
*portSet = pinMask;
|
||||
*timeReset = TC_CCR_CLKEN | TC_CCR_SWTRG;
|
||||
|
||||
while (*timeValue < t);
|
||||
|
||||
*portClear = pinMask;
|
||||
if (!(mask >>= 1))
|
||||
{
|
||||
// This 'inside-out' loop logic utilizes
|
||||
if (p >= end)
|
||||
{
|
||||
break; // idle time to minimize inter-byte delays.
|
||||
}
|
||||
pix = *p++;
|
||||
mask = 0x80;
|
||||
}
|
||||
}
|
||||
|
||||
// not really needed as the wait for latch does this and
|
||||
// while (*timeValue < T_SPEEDPROPS::Cycles); // Wait for last bit
|
||||
|
||||
TC_Stop(TC1, 0);
|
||||
}
|
||||
};
|
||||
|
||||
typedef NeoArmMethodBase<NeoArmOtherSpeedBase<NeoArmOtherSpeedPropsWs2812x>> NeoArmWs2812xMethod;
|
||||
typedef NeoArmMethodBase<NeoArmOtherSpeedBase<NeoArmOtherSpeedPropsSk6812>> NeoArmSk6812Method;
|
||||
typedef NeoArmMethodBase<NeoArmOtherSpeedBase<NeoArmOtherSpeedPropsTm1814>> NeoArmTm1814InvertedMethod;
|
||||
typedef NeoArmMethodBase<NeoArmOtherSpeedBase<NeoArmOtherSpeedProps800Kbps>> NeoArm800KbpsMethod;
|
||||
typedef NeoArmMethodBase<NeoArmOtherSpeedBase<NeoArmOtherSpeedProps400Kbps>> NeoArm400KbpsMethod;
|
||||
typedef NeoArm400KbpsMethod NeoArmApa106Method;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
// Arm doesn't have alternatives methods yet, so only one to make the default
|
||||
typedef NeoArmWs2812xMethod NeoWs2813Method;
|
||||
typedef NeoArmWs2812xMethod NeoWs2812xMethod;
|
||||
typedef NeoArmWs2812xMethod NeoWs2811Method;
|
||||
typedef NeoArmSk6812Method NeoSk6812Method;
|
||||
typedef NeoArmSk6812Method NeoLc8812Method;
|
||||
typedef NeoArm800KbpsMethod NeoWs2812Method;
|
||||
typedef NeoArmApa106Method NeoApa106Method;
|
||||
typedef NeoArmWs2812xMethod Neo800KbpsMethod;
|
||||
#ifdef NeoArm400KbpsMethod // this is needed due to missing 400Kbps for some platforms
|
||||
typedef NeoArm400KbpsMethod Neo400KbpsMethod;
|
||||
#endif
|
||||
// there is no invert methods for arm, but the norm for TM1814 is inverted, so
|
||||
typedef NeoArmTm1814InvertedMethod NeoTm1814InvertedMethod;
|
||||
|
||||
#endif // defined(__arm__)
|
||||
|
||||
224
lib/NeoPixelBus_by_Makuna/src/internal/NeoAvrMethod.h
Normal file
224
lib/NeoPixelBus_by_Makuna/src/internal/NeoAvrMethod.h
Normal file
@@ -0,0 +1,224 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
NeoPixel library helper functions for Atmel AVR.
|
||||
|
||||
Written by Michael C. Miller.
|
||||
Some work taken from the Adafruit NeoPixel library.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_MEGAAVR)
|
||||
|
||||
extern "C"
|
||||
{
|
||||
void send_data_8mhz_800_PortD(uint8_t* data, size_t sizeData, uint8_t pinMask);
|
||||
void send_data_8mhz_800_PortB(uint8_t* data, size_t sizeData, uint8_t pinMask);
|
||||
void send_data_8mhz_400(uint8_t* data, size_t sizeData, volatile uint8_t* port, uint8_t pinMask);
|
||||
void send_data_12mhz_800_PortD(uint8_t* data, size_t sizeData, uint8_t pinMask);
|
||||
void send_data_12mhz_800_PortB(uint8_t* data, size_t sizeData, uint8_t pinMask);
|
||||
void send_data_12mhz_400(uint8_t* data, size_t sizeData, volatile uint8_t* port, uint8_t pinMask);
|
||||
void send_data_16mhz_800(uint8_t* data, size_t sizeData, volatile uint8_t* port, uint8_t pinMask);
|
||||
void send_data_16mhz_400(uint8_t* data, size_t sizeData, volatile uint8_t* port, uint8_t pinMask);
|
||||
}
|
||||
|
||||
class NeoAvrSpeed800KbpsBase
|
||||
{
|
||||
public:
|
||||
static void send_data(uint8_t* data, size_t sizeData, volatile uint8_t* port, uint8_t pinMask)
|
||||
{
|
||||
#if (F_CPU >= 7400000UL) && (F_CPU <= 9500000UL) // 8Mhz CPU
|
||||
#ifdef PORTD // PORTD isn't present on ATtiny85, etc.
|
||||
if (port == &PORTD)
|
||||
send_data_8mhz_800_PortD(data, sizeData, pinMask);
|
||||
else if (port == &PORTB)
|
||||
#endif // PORTD
|
||||
send_data_8mhz_800_PortB(data, sizeData, pinMask);
|
||||
|
||||
#elif (F_CPU >= 11100000UL) && (F_CPU <= 14300000UL) // 12Mhz CPU
|
||||
#ifdef PORTD // PORTD
|
||||
if (port == &PORTD)
|
||||
send_data_12mhz_800_PortD(data, sizeData, pinMask);
|
||||
else if (port == &PORTB)
|
||||
#endif // PORTD
|
||||
send_data_12mhz_800_PortB(data, sizeData, pinMask);
|
||||
|
||||
#elif (F_CPU >= 15400000UL) && (F_CPU <= 19000000L) // 16Mhz CPU
|
||||
send_data_16mhz_800(data, sizeData, port, pinMask);
|
||||
#else
|
||||
#error "CPU SPEED NOT SUPPORTED"
|
||||
#endif
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class NeoAvrSpeedWs2812x : public NeoAvrSpeed800KbpsBase
|
||||
{
|
||||
public:
|
||||
static const uint32_t ResetTimeUs = 300;
|
||||
};
|
||||
|
||||
class NeoAvrSpeedSk6812 : public NeoAvrSpeed800KbpsBase
|
||||
{
|
||||
public:
|
||||
static const uint32_t ResetTimeUs = 80;
|
||||
};
|
||||
|
||||
class NeoAvrSpeedTm1814 : public NeoAvrSpeed800KbpsBase
|
||||
{
|
||||
public:
|
||||
static const uint32_t ResetTimeUs = 200;
|
||||
};
|
||||
|
||||
class NeoAvrSpeed800Kbps: public NeoAvrSpeed800KbpsBase
|
||||
{
|
||||
public:
|
||||
static const uint32_t ResetTimeUs = 50;
|
||||
};
|
||||
|
||||
class NeoAvrSpeed400Kbps
|
||||
{
|
||||
public:
|
||||
static void send_data(uint8_t* data, size_t sizeData, volatile uint8_t* port, uint8_t pinMask)
|
||||
{
|
||||
#if (F_CPU >= 7400000UL) && (F_CPU <= 9500000UL) // 8Mhz CPU
|
||||
send_data_8mhz_400(data, sizeData, port, pinMask);
|
||||
|
||||
#elif (F_CPU >= 11100000UL) && (F_CPU <= 14300000UL) // 12Mhz CPU
|
||||
send_data_12mhz_400(data, sizeData, port, pinMask);
|
||||
|
||||
#elif (F_CPU >= 15400000UL) && (F_CPU <= 19000000L) // 16Mhz CPU
|
||||
send_data_16mhz_400(data, sizeData, port, pinMask);
|
||||
#else
|
||||
#error "CPU SPEED NOT SUPPORTED"
|
||||
#endif
|
||||
}
|
||||
static const uint32_t ResetTimeUs = 50;
|
||||
};
|
||||
|
||||
template<typename T_SPEED> class NeoAvrMethodBase
|
||||
{
|
||||
public:
|
||||
NeoAvrMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize) :
|
||||
_sizeData(pixelCount * elementSize + settingsSize),
|
||||
_pin(pin),
|
||||
_port(NULL),
|
||||
_pinMask(0)
|
||||
{
|
||||
pinMode(pin, OUTPUT);
|
||||
|
||||
_data = static_cast<uint8_t*>(malloc(_sizeData));
|
||||
memset(_data, 0, _sizeData);
|
||||
|
||||
_port = portOutputRegister(digitalPinToPort(pin));
|
||||
_pinMask = digitalPinToBitMask(pin);
|
||||
}
|
||||
|
||||
~NeoAvrMethodBase()
|
||||
{
|
||||
pinMode(_pin, INPUT);
|
||||
|
||||
free(_data);
|
||||
}
|
||||
|
||||
bool IsReadyToUpdate() const
|
||||
{
|
||||
uint32_t delta = micros() - _endTime;
|
||||
|
||||
return (delta >= T_SPEED::ResetTimeUs);
|
||||
}
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
digitalWrite(_pin, LOW);
|
||||
|
||||
_endTime = micros();
|
||||
}
|
||||
|
||||
void Update(bool)
|
||||
{
|
||||
// Data latch = 50+ microsecond pause in the output stream. Rather than
|
||||
// put a delay at the end of the function, the ending time is noted and
|
||||
// the function will simply hold off (if needed) on issuing the
|
||||
// subsequent round of data until the latch time has elapsed. This
|
||||
// allows the mainline code to start generating the next frame of data
|
||||
// rather than stalling for the latch.
|
||||
while (!IsReadyToUpdate())
|
||||
{
|
||||
#if !defined(ARDUINO_TEEONARDU_LEO) && !defined(ARDUINO_TEEONARDU_FLORA)
|
||||
yield(); // allows for system yield if needed
|
||||
#endif
|
||||
}
|
||||
|
||||
noInterrupts(); // Need 100% focus on instruction timing
|
||||
|
||||
T_SPEED::send_data(_data, _sizeData, _port, _pinMask);
|
||||
|
||||
interrupts();
|
||||
|
||||
// save EOD time for latch on next call
|
||||
_endTime = micros();
|
||||
}
|
||||
|
||||
uint8_t* getData() const
|
||||
{
|
||||
return _data;
|
||||
};
|
||||
|
||||
size_t getDataSize() const
|
||||
{
|
||||
return _sizeData;
|
||||
};
|
||||
|
||||
private:
|
||||
const size_t _sizeData; // size of _data below
|
||||
const uint8_t _pin; // output pin number
|
||||
|
||||
uint32_t _endTime; // Latch timing reference
|
||||
uint8_t* _data; // Holds data stream which include LED color values and other settings as needed
|
||||
|
||||
volatile uint8_t* _port; // Output PORT register
|
||||
uint8_t _pinMask; // Output PORT bitmask
|
||||
};
|
||||
|
||||
|
||||
typedef NeoAvrMethodBase<NeoAvrSpeedWs2812x> NeoAvrWs2812xMethod;
|
||||
typedef NeoAvrMethodBase<NeoAvrSpeedSk6812> NeoAvrSk6812Method;
|
||||
typedef NeoAvrMethodBase<NeoAvrSpeedTm1814> NeoAvrTm1814InvertedMethod;
|
||||
typedef NeoAvrMethodBase<NeoAvrSpeed800Kbps> NeoAvr800KbpsMethod;
|
||||
typedef NeoAvrMethodBase<NeoAvrSpeed400Kbps> NeoAvr400KbpsMethod;
|
||||
|
||||
|
||||
// AVR doesn't have alternatives yet, so there is just the default
|
||||
typedef NeoAvrWs2812xMethod NeoWs2813Method;
|
||||
typedef NeoAvrWs2812xMethod NeoWs2812xMethod;
|
||||
typedef NeoAvr800KbpsMethod NeoWs2812Method;
|
||||
typedef NeoAvrWs2812xMethod NeoWs2811Method;
|
||||
typedef NeoAvrSk6812Method NeoSk6812Method;
|
||||
typedef NeoAvrSk6812Method NeoLc8812Method;
|
||||
typedef NeoAvr400KbpsMethod NeoApa106Method;
|
||||
typedef NeoAvrWs2812xMethod Neo800KbpsMethod;
|
||||
typedef NeoAvr400KbpsMethod Neo400KbpsMethod;
|
||||
|
||||
typedef NeoAvrTm1814InvertedMethod NeoTm1814InvertedMethod;
|
||||
#endif
|
||||
|
||||
388
lib/NeoPixelBus_by_Makuna/src/internal/NeoBitmapFile.h
Normal file
388
lib/NeoPixelBus_by_Makuna/src/internal/NeoBitmapFile.h
Normal file
@@ -0,0 +1,388 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
NeoPixel library
|
||||
|
||||
Written by Michael C. Miller.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
#pragma once
|
||||
|
||||
const uint16_t c_BitmapFileId = 0x4d42; // "BM"
|
||||
|
||||
#pragma pack(push, 2)
|
||||
struct BitmapFileHeader
|
||||
{
|
||||
uint16_t FileId; // only c_BitmapFileId is supported
|
||||
uint32_t FileSize;
|
||||
uint16_t Reserved0;
|
||||
uint16_t Reserved1;
|
||||
uint32_t PixelAddress;
|
||||
};
|
||||
|
||||
struct BitmapInfoHeader
|
||||
{
|
||||
uint32_t Size;
|
||||
int32_t Width;
|
||||
int32_t Height;
|
||||
uint16_t Planes; // only support 1
|
||||
uint16_t BitsPerPixel; // only support 24 and 32
|
||||
uint32_t Compression; // only support BI_Rgb
|
||||
uint32_t RawDateSize; // can be zero
|
||||
int32_t XPpm;
|
||||
int32_t YPpm;
|
||||
uint32_t PaletteLength;
|
||||
uint32_t ImportantColorCount;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
enum BmpCompression
|
||||
{
|
||||
BI_Rgb,
|
||||
BI_Rle8,
|
||||
BI_Rle4,
|
||||
BI_Bitfields,
|
||||
BI_Jpeg,
|
||||
BI_Png,
|
||||
BI_AlphaBitfields,
|
||||
BI_Cmyk = 11,
|
||||
BI_CmykRle8,
|
||||
BI_CmykRle4
|
||||
};
|
||||
|
||||
template<typename T_COLOR_FEATURE, typename T_FILE_METHOD> class NeoBitmapFile
|
||||
{
|
||||
public:
|
||||
NeoBitmapFile() :
|
||||
_fileAddressPixels(0),
|
||||
_width(0),
|
||||
_height(0),
|
||||
_sizeRow(0),
|
||||
_bytesPerPixel(0),
|
||||
_bottomToTop(true)
|
||||
{
|
||||
}
|
||||
|
||||
~NeoBitmapFile()
|
||||
{
|
||||
_file.close();
|
||||
}
|
||||
|
||||
bool Begin(T_FILE_METHOD file)
|
||||
{
|
||||
if (_file)
|
||||
{
|
||||
_file.close();
|
||||
}
|
||||
|
||||
if (!file || !file.seek(0))
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
|
||||
_file = file;
|
||||
|
||||
BitmapFileHeader bmpHeader;
|
||||
BitmapInfoHeader bmpInfoHeader;
|
||||
size_t result;
|
||||
|
||||
result = _file.read((uint8_t*)(&bmpHeader), sizeof(bmpHeader));
|
||||
|
||||
if (result != sizeof(bmpHeader) ||
|
||||
bmpHeader.FileId != c_BitmapFileId ||
|
||||
bmpHeader.FileSize != _file.size())
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
|
||||
result = _file.read((uint8_t*)(&bmpInfoHeader), sizeof(bmpInfoHeader));
|
||||
|
||||
if (result != sizeof(bmpInfoHeader) ||
|
||||
result != bmpInfoHeader.Size ||
|
||||
1 != bmpInfoHeader.Planes ||
|
||||
BI_Rgb != bmpInfoHeader.Compression)
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!(24 == bmpInfoHeader.BitsPerPixel ||
|
||||
32 == bmpInfoHeader.BitsPerPixel))
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
|
||||
// save the interesting information
|
||||
_width = abs(bmpInfoHeader.Width);
|
||||
_height = abs(bmpInfoHeader.Height);
|
||||
_fileAddressPixels = bmpHeader.PixelAddress;
|
||||
// negative height means rows are top to bottom
|
||||
_bottomToTop = (bmpInfoHeader.Height > 0);
|
||||
// rows are 32 bit aligned so they may have padding on each row
|
||||
_sizeRow = (bmpInfoHeader.BitsPerPixel * _width + 31) / 32 * 4;
|
||||
_bytesPerPixel = bmpInfoHeader.BitsPerPixel / 8;
|
||||
|
||||
return true;
|
||||
|
||||
error:
|
||||
_fileAddressPixels = 0;
|
||||
_width = 0;
|
||||
_height = 0;
|
||||
_sizeRow = 0;
|
||||
_bytesPerPixel = 0;
|
||||
|
||||
_file.close();
|
||||
return false;
|
||||
};
|
||||
|
||||
size_t PixelSize() const
|
||||
{
|
||||
return T_COLOR_FEATURE::PixelSize;
|
||||
};
|
||||
|
||||
uint16_t PixelCount() const
|
||||
{
|
||||
return _width * _height;
|
||||
};
|
||||
|
||||
uint16_t Width() const
|
||||
{
|
||||
return _width;
|
||||
};
|
||||
|
||||
uint16_t Height() const
|
||||
{
|
||||
return _height;
|
||||
};
|
||||
|
||||
typename T_COLOR_FEATURE::ColorObject GetPixelColor(int16_t x, int16_t y)
|
||||
{
|
||||
if (x < 0 || x >= _width || y < 0 || y >= _height)
|
||||
{
|
||||
// Pixel # is out of bounds, this will get converted to a
|
||||
// color object type initialized to 0 (black)
|
||||
return 0;
|
||||
}
|
||||
|
||||
typename T_COLOR_FEATURE::ColorObject color;
|
||||
if (!seek(x, y) || !readPixel(&color))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return color;
|
||||
};
|
||||
|
||||
|
||||
template <typename T_SHADER> void Render(NeoBufferContext<T_COLOR_FEATURE> destBuffer,
|
||||
T_SHADER& shader,
|
||||
uint16_t indexPixel,
|
||||
int16_t xSrc,
|
||||
int16_t ySrc,
|
||||
int16_t wSrc)
|
||||
{
|
||||
const uint16_t destPixelCount = destBuffer.PixelCount();
|
||||
typename T_COLOR_FEATURE::ColorObject color(0);
|
||||
xSrc = constrainX(xSrc);
|
||||
ySrc = constrainY(ySrc);
|
||||
|
||||
if (seek(xSrc, ySrc))
|
||||
{
|
||||
for (int16_t x = 0; x < wSrc && indexPixel < destPixelCount; x++, indexPixel++)
|
||||
{
|
||||
if ((uint16_t)xSrc < _width)
|
||||
{
|
||||
if (readPixel(&color))
|
||||
{
|
||||
color = shader.Apply(indexPixel, color);
|
||||
xSrc++;
|
||||
}
|
||||
}
|
||||
|
||||
T_COLOR_FEATURE::applyPixelColor(destBuffer.Pixels, indexPixel, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Blt(NeoBufferContext<T_COLOR_FEATURE> destBuffer,
|
||||
uint16_t indexPixel,
|
||||
int16_t xSrc,
|
||||
int16_t ySrc,
|
||||
int16_t wSrc)
|
||||
{
|
||||
NeoShaderNop<typename T_COLOR_FEATURE::ColorObject> shaderNop;
|
||||
|
||||
Render<NeoShaderNop<typename T_COLOR_FEATURE::ColorObject>>(destBuffer, shaderNop, indexPixel, xSrc, ySrc, wSrc);
|
||||
};
|
||||
|
||||
template <typename T_SHADER> void Render(NeoBufferContext<T_COLOR_FEATURE> destBuffer,
|
||||
T_SHADER& shader,
|
||||
int16_t xDest,
|
||||
int16_t yDest,
|
||||
int16_t xSrc,
|
||||
int16_t ySrc,
|
||||
int16_t wSrc,
|
||||
int16_t hSrc,
|
||||
LayoutMapCallback layoutMap)
|
||||
{
|
||||
const uint16_t destPixelCount = destBuffer.PixelCount();
|
||||
typename T_COLOR_FEATURE::ColorObject color(0);
|
||||
|
||||
for (int16_t y = 0; y < hSrc; y++)
|
||||
{
|
||||
int16_t xFile = constrainX(xSrc);
|
||||
int16_t yFile = constrainY(ySrc + y);
|
||||
|
||||
if (seek(xFile, yFile))
|
||||
{
|
||||
for (int16_t x = 0; x < wSrc; x++)
|
||||
{
|
||||
uint16_t indexDest = layoutMap(xDest + x, yDest + y);
|
||||
|
||||
if ((uint16_t)xFile < _width)
|
||||
{
|
||||
if (readPixel(&color))
|
||||
{
|
||||
color = shader.Apply(indexDest, color);
|
||||
xFile++;
|
||||
}
|
||||
}
|
||||
|
||||
if (indexDest < destPixelCount)
|
||||
{
|
||||
T_COLOR_FEATURE::applyPixelColor(destBuffer.Pixels, indexDest, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void Blt(NeoBufferContext<T_COLOR_FEATURE> destBuffer,
|
||||
int16_t xDest,
|
||||
int16_t yDest,
|
||||
int16_t xSrc,
|
||||
int16_t ySrc,
|
||||
int16_t wSrc,
|
||||
int16_t hSrc,
|
||||
LayoutMapCallback layoutMap)
|
||||
{
|
||||
NeoShaderNop<typename T_COLOR_FEATURE::ColorObject> shaderNop;
|
||||
|
||||
Render<NeoShaderNop<typename T_COLOR_FEATURE::ColorObject>>(destBuffer,
|
||||
shaderNop,
|
||||
xDest,
|
||||
yDest,
|
||||
xSrc,
|
||||
ySrc,
|
||||
wSrc,
|
||||
hSrc,
|
||||
layoutMap);
|
||||
};
|
||||
|
||||
|
||||
private:
|
||||
T_FILE_METHOD _file;
|
||||
uint32_t _fileAddressPixels;
|
||||
uint16_t _width;
|
||||
uint16_t _height;
|
||||
uint32_t _sizeRow;
|
||||
uint8_t _bytesPerPixel;
|
||||
bool _bottomToTop;
|
||||
|
||||
int16_t constrainX(int16_t x) const
|
||||
{
|
||||
if (x < 0)
|
||||
{
|
||||
x = 0;
|
||||
}
|
||||
else if ((uint16_t)x >= _width)
|
||||
{
|
||||
x = _width - 1;
|
||||
}
|
||||
return x;
|
||||
};
|
||||
|
||||
int16_t constrainY(int16_t y) const
|
||||
{
|
||||
if (y < 0)
|
||||
{
|
||||
y = 0;
|
||||
}
|
||||
else if ((uint16_t)y >= _height)
|
||||
{
|
||||
y = _height - 1;
|
||||
}
|
||||
return y;
|
||||
};
|
||||
|
||||
bool seek(int16_t x, int16_t y)
|
||||
{
|
||||
if (_bottomToTop)
|
||||
{
|
||||
y = (_height - 1) - y;
|
||||
}
|
||||
|
||||
uint32_t pos = y * _sizeRow + x * _bytesPerPixel;
|
||||
pos += _fileAddressPixels;
|
||||
|
||||
return _file.seek(pos);
|
||||
};
|
||||
|
||||
bool readPixel(RgbColor* color)
|
||||
{
|
||||
uint8_t bgr[4];
|
||||
int result;
|
||||
|
||||
result = _file.read(bgr, _bytesPerPixel);
|
||||
|
||||
if (result != _bytesPerPixel)
|
||||
{
|
||||
*color = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
color->B = bgr[0];
|
||||
color->G = bgr[1];
|
||||
color->R = bgr[2];
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
bool readPixel(RgbwColor* color)
|
||||
{
|
||||
uint8_t bgr[4];
|
||||
int result;
|
||||
|
||||
bgr[3] = 0; // init white channel as read maybe only 3 bytes
|
||||
result = _file.read(bgr, _bytesPerPixel);
|
||||
|
||||
if (result != _bytesPerPixel)
|
||||
{
|
||||
*color = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
color->B = bgr[0];
|
||||
color->G = bgr[1];
|
||||
color->R = bgr[2];
|
||||
color->W = bgr[3];
|
||||
|
||||
return true;
|
||||
};
|
||||
};
|
||||
173
lib/NeoPixelBus_by_Makuna/src/internal/NeoBuffer.h
Normal file
173
lib/NeoPixelBus_by_Makuna/src/internal/NeoBuffer.h
Normal file
@@ -0,0 +1,173 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
NeoPixel library
|
||||
|
||||
Written by Michael C. Miller.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
#pragma once
|
||||
|
||||
template<typename T_BUFFER_METHOD> class NeoBuffer
|
||||
{
|
||||
public:
|
||||
NeoBuffer(uint16_t width,
|
||||
uint16_t height,
|
||||
PGM_VOID_P pixels) :
|
||||
_method(width, height, pixels)
|
||||
{
|
||||
}
|
||||
|
||||
operator NeoBufferContext<typename T_BUFFER_METHOD::ColorFeature>()
|
||||
{
|
||||
return _method;
|
||||
}
|
||||
|
||||
uint16_t PixelCount() const
|
||||
{
|
||||
return _method.PixelCount();
|
||||
};
|
||||
|
||||
uint16_t Width() const
|
||||
{
|
||||
return _method.Width();
|
||||
};
|
||||
|
||||
uint16_t Height() const
|
||||
{
|
||||
return _method.Height();
|
||||
};
|
||||
|
||||
void SetPixelColor(
|
||||
int16_t x,
|
||||
int16_t y,
|
||||
typename T_BUFFER_METHOD::ColorObject color)
|
||||
{
|
||||
_method.SetPixelColor(pixelIndex(x, y), color);
|
||||
};
|
||||
|
||||
typename T_BUFFER_METHOD::ColorObject GetPixelColor(
|
||||
int16_t x,
|
||||
int16_t y) const
|
||||
{
|
||||
return _method.GetPixelColor(pixelIndex(x, y));
|
||||
};
|
||||
|
||||
void ClearTo(typename T_BUFFER_METHOD::ColorObject color)
|
||||
{
|
||||
_method.ClearTo(color);
|
||||
};
|
||||
|
||||
void Blt(NeoBufferContext<typename T_BUFFER_METHOD::ColorFeature> destBuffer,
|
||||
uint16_t indexPixel)
|
||||
{
|
||||
uint16_t destPixelCount = destBuffer.PixelCount();
|
||||
// validate indexPixel
|
||||
if (indexPixel >= destPixelCount)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// calc how many we can copy
|
||||
uint16_t copyCount = destPixelCount - indexPixel;
|
||||
uint16_t srcPixelCount = PixelCount();
|
||||
if (copyCount > srcPixelCount)
|
||||
{
|
||||
copyCount = srcPixelCount;
|
||||
}
|
||||
|
||||
uint8_t* pDest = T_BUFFER_METHOD::ColorFeature::getPixelAddress(destBuffer.Pixels, indexPixel);
|
||||
_method.CopyPixels(pDest, _method.Pixels(), copyCount);
|
||||
}
|
||||
|
||||
void Blt(NeoBufferContext<typename T_BUFFER_METHOD::ColorFeature> destBuffer,
|
||||
int16_t xDest,
|
||||
int16_t yDest,
|
||||
int16_t xSrc,
|
||||
int16_t ySrc,
|
||||
int16_t wSrc,
|
||||
int16_t hSrc,
|
||||
LayoutMapCallback layoutMap)
|
||||
{
|
||||
uint16_t destPixelCount = destBuffer.PixelCount();
|
||||
|
||||
for (int16_t y = 0; y < hSrc; y++)
|
||||
{
|
||||
for (int16_t x = 0; x < wSrc; x++)
|
||||
{
|
||||
uint16_t indexDest = layoutMap(xDest + x, yDest + y);
|
||||
|
||||
if (indexDest < destPixelCount)
|
||||
{
|
||||
const uint8_t* pSrc = T_BUFFER_METHOD::ColorFeature::getPixelAddress(_method.Pixels(), pixelIndex(xSrc + x, ySrc + y));
|
||||
uint8_t* pDest = T_BUFFER_METHOD::ColorFeature::getPixelAddress(destBuffer.Pixels, indexDest);
|
||||
|
||||
_method.CopyPixels(pDest, pSrc, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Blt(NeoBufferContext<typename T_BUFFER_METHOD::ColorFeature> destBuffer,
|
||||
int16_t xDest,
|
||||
int16_t yDest,
|
||||
LayoutMapCallback layoutMap)
|
||||
{
|
||||
Blt(destBuffer, xDest, yDest, 0, 0, Width(), Height(), layoutMap);
|
||||
}
|
||||
|
||||
template <typename T_SHADER> void Render(NeoBufferContext<typename T_BUFFER_METHOD::ColorFeature> destBuffer, T_SHADER& shader)
|
||||
{
|
||||
uint16_t countPixels = destBuffer.PixelCount();
|
||||
|
||||
if (countPixels > _method.PixelCount())
|
||||
{
|
||||
countPixels = _method.PixelCount();
|
||||
}
|
||||
|
||||
for (uint16_t indexPixel = 0; indexPixel < countPixels; indexPixel++)
|
||||
{
|
||||
typename T_BUFFER_METHOD::ColorObject color;
|
||||
|
||||
shader.Apply(indexPixel, (uint8_t*)(&color), _method.Pixels() + (indexPixel * _method.PixelSize()));
|
||||
|
||||
T_BUFFER_METHOD::ColorFeature::applyPixelColor(destBuffer.Pixels, indexPixel, color);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
T_BUFFER_METHOD _method;
|
||||
|
||||
uint16_t pixelIndex(
|
||||
int16_t x,
|
||||
int16_t y) const
|
||||
{
|
||||
uint16_t result = PixelIndex_OutOfBounds;
|
||||
|
||||
if (x >= 0 &&
|
||||
(uint16_t)x < Width() &&
|
||||
y >= 0 &&
|
||||
(uint16_t)y < Height())
|
||||
{
|
||||
result = x + y * Width();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
48
lib/NeoPixelBus_by_Makuna/src/internal/NeoBufferContext.h
Normal file
48
lib/NeoPixelBus_by_Makuna/src/internal/NeoBufferContext.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
NeoPixel library
|
||||
|
||||
Written by Michael C. Miller.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
#pragma once
|
||||
|
||||
// This is used to allow a template classes that share common buffer concept to
|
||||
// be able to pass that common information to functions
|
||||
// The template classes just need to expose a conversion operator to this type
|
||||
template <typename T_COLOR_FEATURE> struct NeoBufferContext
|
||||
{
|
||||
NeoBufferContext(uint8_t* pixels,
|
||||
size_t sizePixels) :
|
||||
Pixels(pixels),
|
||||
SizePixels(sizePixels)
|
||||
{
|
||||
}
|
||||
|
||||
uint16_t PixelCount() const
|
||||
{
|
||||
return SizePixels / T_COLOR_FEATURE::PixelSize;
|
||||
};
|
||||
|
||||
uint8_t* Pixels;
|
||||
const size_t SizePixels;
|
||||
|
||||
};
|
||||
263
lib/NeoPixelBus_by_Makuna/src/internal/NeoBufferMethods.h
Normal file
263
lib/NeoPixelBus_by_Makuna/src/internal/NeoBufferMethods.h
Normal file
@@ -0,0 +1,263 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
NeoPixel library
|
||||
|
||||
Written by Michael C. Miller.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#if defined(NEOPIXEBUS_NO_STL)
|
||||
|
||||
typedef uint16_t(*LayoutMapCallback)(int16_t x, int16_t y);
|
||||
|
||||
#else
|
||||
|
||||
#undef max
|
||||
#undef min
|
||||
#include <functional>
|
||||
typedef std::function<uint16_t(int16_t x, int16_t y)> LayoutMapCallback;
|
||||
|
||||
#endif
|
||||
|
||||
template<typename T_COLOR_FEATURE> class NeoBufferMethod
|
||||
{
|
||||
public:
|
||||
NeoBufferMethod(uint16_t width, uint16_t height, PGM_VOID_P pixels = NULL) :
|
||||
_width(width),
|
||||
_height(height)
|
||||
{
|
||||
_pixels = (uint8_t*)malloc(PixelsSize());
|
||||
if (pixels)
|
||||
{
|
||||
// copy from progmem to initialize
|
||||
T_COLOR_FEATURE::movePixelsInc_P(_pixels, pixels, PixelCount());
|
||||
}
|
||||
}
|
||||
|
||||
~NeoBufferMethod()
|
||||
{
|
||||
free(_pixels);
|
||||
}
|
||||
|
||||
operator NeoBufferContext<T_COLOR_FEATURE>()
|
||||
{
|
||||
return NeoBufferContext<T_COLOR_FEATURE>(Pixels(), PixelsSize());
|
||||
}
|
||||
|
||||
uint8_t* Pixels() const
|
||||
{
|
||||
return _pixels;
|
||||
};
|
||||
|
||||
size_t PixelsSize() const
|
||||
{
|
||||
return PixelSize() * PixelCount();
|
||||
};
|
||||
|
||||
size_t PixelSize() const
|
||||
{
|
||||
return T_COLOR_FEATURE::PixelSize;
|
||||
};
|
||||
|
||||
uint16_t PixelCount() const
|
||||
{
|
||||
return _width * _height;
|
||||
};
|
||||
|
||||
uint16_t Width() const
|
||||
{
|
||||
return _width;
|
||||
};
|
||||
|
||||
uint16_t Height() const
|
||||
{
|
||||
return _height;
|
||||
};
|
||||
|
||||
void SetPixelColor(uint16_t indexPixel, typename T_COLOR_FEATURE::ColorObject color)
|
||||
{
|
||||
if (indexPixel < PixelCount())
|
||||
{
|
||||
T_COLOR_FEATURE::applyPixelColor(_pixels, indexPixel, color);
|
||||
}
|
||||
};
|
||||
|
||||
void SetPixelColor(int16_t x, int16_t y, typename T_COLOR_FEATURE::ColorObject color)
|
||||
{
|
||||
if (x < 0 || x >= _width || y < 0 || y >= _height)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
uint16_t indexPixel = x + y * _width;
|
||||
T_COLOR_FEATURE::applyPixelColor(_pixels, indexPixel, color);
|
||||
};
|
||||
|
||||
typename T_COLOR_FEATURE::ColorObject GetPixelColor(uint16_t indexPixel) const
|
||||
{
|
||||
if (indexPixel >= PixelCount())
|
||||
{
|
||||
// Pixel # is out of bounds, this will get converted to a
|
||||
// color object type initialized to 0 (black)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return T_COLOR_FEATURE::retrievePixelColor(_pixels, indexPixel);
|
||||
};
|
||||
|
||||
typename T_COLOR_FEATURE::ColorObject GetPixelColor(int16_t x, int16_t y) const
|
||||
{
|
||||
if (x < 0 || x >= _width || y < 0 || y >= _height)
|
||||
{
|
||||
// Pixel # is out of bounds, this will get converted to a
|
||||
// color object type initialized to 0 (black)
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t indexPixel = x + y * _width;
|
||||
return T_COLOR_FEATURE::retrievePixelColor(_pixels, indexPixel);
|
||||
};
|
||||
|
||||
void ClearTo(typename T_COLOR_FEATURE::ColorObject color)
|
||||
{
|
||||
uint8_t temp[T_COLOR_FEATURE::PixelSize];
|
||||
|
||||
T_COLOR_FEATURE::applyPixelColor(temp, 0, color);
|
||||
|
||||
T_COLOR_FEATURE::replicatePixel(_pixels, temp, PixelCount());
|
||||
};
|
||||
|
||||
void CopyPixels(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count)
|
||||
{
|
||||
T_COLOR_FEATURE::movePixelsInc(pPixelDest, pPixelSrc, count);
|
||||
}
|
||||
|
||||
typedef typename T_COLOR_FEATURE::ColorObject ColorObject;
|
||||
typedef T_COLOR_FEATURE ColorFeature;
|
||||
|
||||
private:
|
||||
const uint16_t _width;
|
||||
const uint16_t _height;
|
||||
uint8_t* _pixels;
|
||||
};
|
||||
|
||||
template<typename T_COLOR_FEATURE> class NeoBufferProgmemMethod
|
||||
{
|
||||
public:
|
||||
NeoBufferProgmemMethod(uint16_t width, uint16_t height, PGM_VOID_P pixels) :
|
||||
_width(width),
|
||||
_height(height),
|
||||
_pixels(pixels)
|
||||
{
|
||||
}
|
||||
|
||||
operator NeoBufferContext<T_COLOR_FEATURE>()
|
||||
{
|
||||
return NeoBufferContext<T_COLOR_FEATURE>(Pixels(), PixelsSize());
|
||||
}
|
||||
|
||||
uint8_t* Pixels() const
|
||||
{
|
||||
return (uint8_t*)_pixels;
|
||||
};
|
||||
|
||||
size_t PixelsSize() const
|
||||
{
|
||||
return PixelSize() * PixelCount();
|
||||
};
|
||||
|
||||
size_t PixelSize() const
|
||||
{
|
||||
return T_COLOR_FEATURE::PixelSize;
|
||||
};
|
||||
|
||||
uint16_t PixelCount() const
|
||||
{
|
||||
return _width * _height;
|
||||
};
|
||||
|
||||
uint16_t Width() const
|
||||
{
|
||||
return _width;
|
||||
};
|
||||
|
||||
uint16_t Height() const
|
||||
{
|
||||
return _height;
|
||||
};
|
||||
|
||||
void SetPixelColor(uint16_t indexPixel, typename T_COLOR_FEATURE::ColorObject color)
|
||||
{
|
||||
// PROGMEM is read only, this will do nothing
|
||||
};
|
||||
|
||||
void SetPixelColor(uint16_t x, uint16_t y, typename T_COLOR_FEATURE::ColorObject color)
|
||||
{
|
||||
// PROGMEM is read only, this will do nothing
|
||||
};
|
||||
|
||||
typename T_COLOR_FEATURE::ColorObject GetPixelColor(uint16_t indexPixel) const
|
||||
{
|
||||
if (indexPixel >= PixelCount())
|
||||
{
|
||||
// Pixel # is out of bounds, this will get converted to a
|
||||
// color object type initialized to 0 (black)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return T_COLOR_FEATURE::retrievePixelColor_P(_pixels, indexPixel);
|
||||
};
|
||||
|
||||
typename T_COLOR_FEATURE::ColorObject GetPixelColor(int16_t x, int16_t y) const
|
||||
{
|
||||
if (x < 0 || x >= _width || y < 0 || y >= _height)
|
||||
{
|
||||
// Pixel # is out of bounds, this will get converted to a
|
||||
// color object type initialized to 0 (black)
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t indexPixel = x + y * _width;
|
||||
return T_COLOR_FEATURE::retrievePixelColor_P(_pixels, indexPixel);
|
||||
};
|
||||
|
||||
void ClearTo(typename T_COLOR_FEATURE::ColorObject color)
|
||||
{
|
||||
// PROGMEM is read only, this will do nothing
|
||||
};
|
||||
|
||||
void CopyPixels(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count)
|
||||
{
|
||||
T_COLOR_FEATURE::movePixelsInc_P(pPixelDest, pPixelSrc, count);
|
||||
}
|
||||
|
||||
typedef typename T_COLOR_FEATURE::ColorObject ColorObject;
|
||||
typedef T_COLOR_FEATURE ColorFeature;
|
||||
|
||||
private:
|
||||
const uint16_t _width;
|
||||
const uint16_t _height;
|
||||
PGM_VOID_P _pixels;
|
||||
};
|
||||
|
||||
427
lib/NeoPixelBus_by_Makuna/src/internal/NeoColorFeatures.h
Normal file
427
lib/NeoPixelBus_by_Makuna/src/internal/NeoColorFeatures.h
Normal file
@@ -0,0 +1,427 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
NeoColorFeatures provides feature classes to describe color order and
|
||||
color depth for NeoPixelBus template class
|
||||
|
||||
Written by Michael C. Miller.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
#pragma once
|
||||
|
||||
class Neo3Elements
|
||||
{
|
||||
public:
|
||||
static const size_t PixelSize = 3;
|
||||
|
||||
static uint8_t* getPixelAddress(uint8_t* pPixels, uint16_t indexPixel)
|
||||
{
|
||||
return pPixels + indexPixel * PixelSize;
|
||||
}
|
||||
static const uint8_t* getPixelAddress(const uint8_t* pPixels, uint16_t indexPixel)
|
||||
{
|
||||
return pPixels + indexPixel * PixelSize;
|
||||
}
|
||||
|
||||
static void replicatePixel(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count)
|
||||
{
|
||||
uint8_t* pEnd = pPixelDest + (count * PixelSize);
|
||||
while (pPixelDest < pEnd)
|
||||
{
|
||||
for (uint8_t iElement = 0; iElement < PixelSize; iElement++)
|
||||
{
|
||||
*pPixelDest++ = pPixelSrc[iElement];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void movePixelsInc(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count)
|
||||
{
|
||||
uint8_t* pEnd = pPixelDest + (count * PixelSize);
|
||||
while (pPixelDest < pEnd)
|
||||
{
|
||||
*pPixelDest++ = *pPixelSrc++;
|
||||
}
|
||||
}
|
||||
|
||||
static void movePixelsInc_P(uint8_t* pPixelDest, PGM_VOID_P pPixelSrc, uint16_t count)
|
||||
{
|
||||
uint8_t* pEnd = pPixelDest + (count * PixelSize);
|
||||
const uint8_t* pSrc = (const uint8_t*)pPixelSrc;
|
||||
while (pPixelDest < pEnd)
|
||||
{
|
||||
*pPixelDest++ = pgm_read_byte(pSrc++);
|
||||
}
|
||||
}
|
||||
|
||||
static void movePixelsDec(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count)
|
||||
{
|
||||
uint8_t* pDestBack = pPixelDest + (count * PixelSize);
|
||||
const uint8_t* pSrcBack = pPixelSrc + (count * PixelSize);
|
||||
while (pDestBack > pPixelDest)
|
||||
{
|
||||
*--pDestBack = *--pSrcBack;
|
||||
}
|
||||
}
|
||||
|
||||
typedef RgbColor ColorObject;
|
||||
};
|
||||
|
||||
class Neo4Elements
|
||||
{
|
||||
public:
|
||||
static const size_t PixelSize = 4;
|
||||
|
||||
static uint8_t* getPixelAddress(uint8_t* pPixels, uint16_t indexPixel)
|
||||
{
|
||||
return pPixels + indexPixel * PixelSize;
|
||||
}
|
||||
static const uint8_t* getPixelAddress(const uint8_t* pPixels, uint16_t indexPixel)
|
||||
{
|
||||
return pPixels + indexPixel * PixelSize;
|
||||
}
|
||||
|
||||
static void replicatePixel(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count)
|
||||
{
|
||||
uint32_t* pDest = (uint32_t*)pPixelDest;
|
||||
const uint32_t* pSrc = (const uint32_t*)pPixelSrc;
|
||||
|
||||
uint32_t* pEnd = pDest + count;
|
||||
while (pDest < pEnd)
|
||||
{
|
||||
*pDest++ = *pSrc;
|
||||
}
|
||||
}
|
||||
|
||||
static void movePixelsInc(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count)
|
||||
{
|
||||
uint32_t* pDest = (uint32_t*)pPixelDest;
|
||||
const uint32_t* pSrc = (uint32_t*)pPixelSrc;
|
||||
uint32_t* pEnd = pDest + count;
|
||||
while (pDest < pEnd)
|
||||
{
|
||||
*pDest++ = *pSrc++;
|
||||
}
|
||||
}
|
||||
|
||||
static void movePixelsInc_P(uint8_t* pPixelDest, PGM_VOID_P pPixelSrc, uint16_t count)
|
||||
{
|
||||
uint32_t* pDest = (uint32_t*)pPixelDest;
|
||||
const uint32_t* pSrc = (const uint32_t*)pPixelSrc;
|
||||
uint32_t* pEnd = pDest + count;
|
||||
while (pDest < pEnd)
|
||||
{
|
||||
*pDest++ = pgm_read_dword(pSrc++);
|
||||
}
|
||||
}
|
||||
|
||||
static void movePixelsDec(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count)
|
||||
{
|
||||
uint32_t* pDest = (uint32_t*)pPixelDest;
|
||||
const uint32_t* pSrc = (uint32_t*)pPixelSrc;
|
||||
uint32_t* pDestBack = pDest + count;
|
||||
const uint32_t* pSrcBack = pSrc + count;
|
||||
while (pDestBack > pDest)
|
||||
{
|
||||
*--pDestBack = *--pSrcBack;
|
||||
}
|
||||
}
|
||||
|
||||
typedef RgbwColor ColorObject;
|
||||
};
|
||||
|
||||
|
||||
class Neo3ElementsNoSettings : public Neo3Elements
|
||||
{
|
||||
public:
|
||||
typedef NeoNoSettings SettingsObject;
|
||||
static const size_t SettingsSize = 0;
|
||||
|
||||
static void applySettings(uint8_t*, const SettingsObject&)
|
||||
{
|
||||
}
|
||||
|
||||
static uint8_t* pixels(uint8_t* pData)
|
||||
{
|
||||
return pData;
|
||||
}
|
||||
|
||||
static const uint8_t* pixels(const uint8_t* pData)
|
||||
{
|
||||
return pData;
|
||||
}
|
||||
};
|
||||
|
||||
class Neo4ElementsNoSettings : public Neo4Elements
|
||||
{
|
||||
public:
|
||||
typedef NeoNoSettings SettingsObject;
|
||||
static const size_t SettingsSize = 0;
|
||||
|
||||
static void applySettings(uint8_t*, const SettingsObject&)
|
||||
{
|
||||
}
|
||||
|
||||
static uint8_t* pixels(uint8_t* pData)
|
||||
{
|
||||
return pData;
|
||||
}
|
||||
|
||||
static const uint8_t* pixels(const uint8_t* pData)
|
||||
{
|
||||
return pData;
|
||||
}
|
||||
};
|
||||
|
||||
class NeoGrbFeature : public Neo3ElementsNoSettings
|
||||
{
|
||||
public:
|
||||
static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color)
|
||||
{
|
||||
uint8_t* p = getPixelAddress(pPixels, indexPixel);
|
||||
|
||||
*p++ = color.G;
|
||||
*p++ = color.R;
|
||||
*p = color.B;
|
||||
}
|
||||
|
||||
static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel)
|
||||
{
|
||||
ColorObject color;
|
||||
const uint8_t* p = getPixelAddress(pPixels, indexPixel);
|
||||
|
||||
color.G = *p++;
|
||||
color.R = *p++;
|
||||
color.B = *p;
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
static ColorObject retrievePixelColor_P(PGM_VOID_P pPixels, uint16_t indexPixel)
|
||||
{
|
||||
ColorObject color;
|
||||
const uint8_t* p = getPixelAddress((const uint8_t*)pPixels, indexPixel);
|
||||
|
||||
color.G = pgm_read_byte(p++);
|
||||
color.R = pgm_read_byte(p++);
|
||||
color.B = pgm_read_byte(p);
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class NeoGrbwFeature : public Neo4ElementsNoSettings
|
||||
{
|
||||
public:
|
||||
static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color)
|
||||
{
|
||||
uint8_t* p = getPixelAddress(pPixels, indexPixel);
|
||||
|
||||
*p++ = color.G;
|
||||
*p++ = color.R;
|
||||
*p++ = color.B;
|
||||
*p = color.W;
|
||||
}
|
||||
|
||||
static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel)
|
||||
{
|
||||
ColorObject color;
|
||||
const uint8_t* p = getPixelAddress(pPixels, indexPixel);
|
||||
|
||||
color.G = *p++;
|
||||
color.R = *p++;
|
||||
color.B = *p++;
|
||||
color.W = *p;
|
||||
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
static ColorObject retrievePixelColor_P(PGM_VOID_P pPixels, uint16_t indexPixel)
|
||||
{
|
||||
ColorObject color;
|
||||
const uint8_t* p = getPixelAddress((const uint8_t*)pPixels, indexPixel);
|
||||
|
||||
color.G = pgm_read_byte(p++);
|
||||
color.R = pgm_read_byte(p++);
|
||||
color.B = pgm_read_byte(p++);
|
||||
color.W = pgm_read_byte(p);
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class NeoRgbwFeature : public Neo4ElementsNoSettings
|
||||
{
|
||||
public:
|
||||
static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color)
|
||||
{
|
||||
uint8_t* p = getPixelAddress(pPixels, indexPixel);
|
||||
|
||||
*p++ = color.R;
|
||||
*p++ = color.G;
|
||||
*p++ = color.B;
|
||||
*p = color.W;
|
||||
}
|
||||
|
||||
static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel)
|
||||
{
|
||||
ColorObject color;
|
||||
const uint8_t* p = getPixelAddress(pPixels, indexPixel);
|
||||
|
||||
color.R = *p++;
|
||||
color.G = *p++;
|
||||
color.B = *p++;
|
||||
color.W = *p;
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
static ColorObject retrievePixelColor_P(PGM_VOID_P pPixels, uint16_t indexPixel)
|
||||
{
|
||||
ColorObject color;
|
||||
const uint8_t* p = getPixelAddress((const uint8_t*)pPixels, indexPixel);
|
||||
|
||||
color.R = pgm_read_byte(p++);
|
||||
color.G = pgm_read_byte(p++);
|
||||
color.B = pgm_read_byte(p++);
|
||||
color.W = pgm_read_byte(p);
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class NeoRgbFeature : public Neo3ElementsNoSettings
|
||||
{
|
||||
public:
|
||||
static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color)
|
||||
{
|
||||
uint8_t* p = getPixelAddress(pPixels, indexPixel);
|
||||
|
||||
*p++ = color.R;
|
||||
*p++ = color.G;
|
||||
*p = color.B;
|
||||
}
|
||||
|
||||
static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel)
|
||||
{
|
||||
ColorObject color;
|
||||
const uint8_t* p = getPixelAddress(pPixels, indexPixel);
|
||||
|
||||
color.R = *p++;
|
||||
color.G = *p++;
|
||||
color.B = *p;
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
static ColorObject retrievePixelColor_P(PGM_VOID_P pPixels, uint16_t indexPixel)
|
||||
{
|
||||
ColorObject color;
|
||||
const uint8_t* p = getPixelAddress((const uint8_t*)pPixels, indexPixel);
|
||||
|
||||
color.R = pgm_read_byte(p++);
|
||||
color.G = pgm_read_byte(p++);
|
||||
color.B = pgm_read_byte(p);
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class NeoBrgFeature : public Neo3ElementsNoSettings
|
||||
{
|
||||
public:
|
||||
static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color)
|
||||
{
|
||||
uint8_t* p = getPixelAddress(pPixels, indexPixel);
|
||||
|
||||
*p++ = color.B;
|
||||
*p++ = color.R;
|
||||
*p = color.G;
|
||||
}
|
||||
|
||||
static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel)
|
||||
{
|
||||
ColorObject color;
|
||||
const uint8_t* p = getPixelAddress(pPixels, indexPixel);
|
||||
|
||||
color.B = *p++;
|
||||
color.R = *p++;
|
||||
color.G = *p;
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
static ColorObject retrievePixelColor_P(PGM_VOID_P pPixels, uint16_t indexPixel)
|
||||
{
|
||||
ColorObject color;
|
||||
const uint8_t* p = getPixelAddress((const uint8_t*)pPixels, indexPixel);
|
||||
|
||||
color.B = pgm_read_byte(p++);
|
||||
color.R = pgm_read_byte(p++);
|
||||
color.G = pgm_read_byte(p);
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class NeoRbgFeature : public Neo3ElementsNoSettings
|
||||
{
|
||||
public:
|
||||
static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color)
|
||||
{
|
||||
uint8_t* p = getPixelAddress(pPixels, indexPixel);
|
||||
|
||||
*p++ = color.R;
|
||||
*p++ = color.B;
|
||||
*p = color.G;
|
||||
}
|
||||
|
||||
static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel)
|
||||
{
|
||||
ColorObject color;
|
||||
const uint8_t* p = getPixelAddress(pPixels, indexPixel);
|
||||
|
||||
color.R = *p++;
|
||||
color.B = *p++;
|
||||
color.G = *p;
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
|
||||
static ColorObject retrievePixelColor_P(PGM_VOID_P pPixels, uint16_t indexPixel)
|
||||
{
|
||||
ColorObject color;
|
||||
const uint8_t* p = getPixelAddress((const uint8_t*)pPixels, indexPixel);
|
||||
|
||||
color.R = pgm_read_byte(p++);
|
||||
color.B = pgm_read_byte(p++);
|
||||
color.G = pgm_read_byte(p);
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
};
|
||||
208
lib/NeoPixelBus_by_Makuna/src/internal/NeoDib.h
Normal file
208
lib/NeoPixelBus_by_Makuna/src/internal/NeoDib.h
Normal file
@@ -0,0 +1,208 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
NeoPixel library
|
||||
|
||||
Written by Michael C. Miller.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
#pragma once
|
||||
|
||||
template<typename T_COLOR_OBJECT> class NeoShaderNop
|
||||
{
|
||||
public:
|
||||
NeoShaderNop()
|
||||
{
|
||||
}
|
||||
|
||||
bool IsDirty() const
|
||||
{
|
||||
return true;
|
||||
};
|
||||
|
||||
void Dirty()
|
||||
{
|
||||
};
|
||||
|
||||
void ResetDirty()
|
||||
{
|
||||
};
|
||||
|
||||
T_COLOR_OBJECT Apply(uint16_t, T_COLOR_OBJECT color)
|
||||
{
|
||||
return color;
|
||||
};
|
||||
};
|
||||
|
||||
class NeoShaderBase
|
||||
{
|
||||
public:
|
||||
NeoShaderBase() :
|
||||
_state(0)
|
||||
{
|
||||
}
|
||||
|
||||
bool IsDirty() const
|
||||
{
|
||||
return (_state & NEO_DIRTY);
|
||||
};
|
||||
|
||||
void Dirty()
|
||||
{
|
||||
_state |= NEO_DIRTY;
|
||||
};
|
||||
|
||||
void ResetDirty()
|
||||
{
|
||||
_state &= ~NEO_DIRTY;
|
||||
};
|
||||
|
||||
protected:
|
||||
uint8_t _state; // internal state
|
||||
};
|
||||
|
||||
template<typename T_COLOR_OBJECT> class NeoDib
|
||||
{
|
||||
public:
|
||||
NeoDib(uint16_t countPixels) :
|
||||
_countPixels(countPixels),
|
||||
_state(0)
|
||||
{
|
||||
_pixels = (T_COLOR_OBJECT*)malloc(PixelsSize());
|
||||
ResetDirty();
|
||||
}
|
||||
|
||||
~NeoDib()
|
||||
{
|
||||
free((uint8_t*)_pixels);
|
||||
}
|
||||
|
||||
NeoDib& operator=(const NeoDib& other)
|
||||
{
|
||||
// check for self-assignment
|
||||
if (&other == this)
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
uint16_t copyCount = other.PixelCount() < PixelCount() ? other.PixelCount() : PixelCount();
|
||||
|
||||
for (uint16_t pixel = 0; pixel < copyCount; pixel++)
|
||||
{
|
||||
_pixels[pixel] = other.Pixels()[pixel];
|
||||
}
|
||||
|
||||
Dirty();
|
||||
return *this;
|
||||
}
|
||||
|
||||
T_COLOR_OBJECT* Pixels() const
|
||||
{
|
||||
return _pixels;
|
||||
};
|
||||
|
||||
uint16_t PixelCount() const
|
||||
{
|
||||
return _countPixels;
|
||||
};
|
||||
|
||||
size_t PixelsSize() const
|
||||
{
|
||||
return _countPixels * PixelSize();
|
||||
};
|
||||
|
||||
size_t PixelSize() const
|
||||
{
|
||||
return sizeof(T_COLOR_OBJECT);
|
||||
};
|
||||
|
||||
void SetPixelColor(
|
||||
uint16_t indexPixel,
|
||||
T_COLOR_OBJECT color)
|
||||
{
|
||||
if (indexPixel < PixelCount())
|
||||
{
|
||||
_pixels[indexPixel] = color;
|
||||
Dirty();
|
||||
}
|
||||
};
|
||||
|
||||
T_COLOR_OBJECT GetPixelColor(
|
||||
uint16_t indexPixel) const
|
||||
{
|
||||
if (indexPixel >= PixelCount())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return _pixels[indexPixel];
|
||||
};
|
||||
|
||||
void ClearTo(T_COLOR_OBJECT color)
|
||||
{
|
||||
for (uint16_t pixel = 0; pixel < PixelCount(); pixel++)
|
||||
{
|
||||
_pixels[pixel] = color;
|
||||
}
|
||||
Dirty();
|
||||
};
|
||||
|
||||
template <typename T_COLOR_FEATURE, typename T_SHADER>
|
||||
void Render(NeoBufferContext<T_COLOR_FEATURE> destBuffer, T_SHADER& shader, uint16_t destIndexPixel = 0)
|
||||
{
|
||||
if (IsDirty() || shader.IsDirty())
|
||||
{
|
||||
uint16_t countPixels = destBuffer.PixelCount();
|
||||
|
||||
if (countPixels > _countPixels)
|
||||
{
|
||||
countPixels = _countPixels;
|
||||
}
|
||||
|
||||
for (uint16_t indexPixel = 0; indexPixel < countPixels; indexPixel++)
|
||||
{
|
||||
T_COLOR_OBJECT color = shader.Apply(indexPixel, _pixels[indexPixel]);
|
||||
T_COLOR_FEATURE::applyPixelColor(destBuffer.Pixels, destIndexPixel + indexPixel, color);
|
||||
}
|
||||
|
||||
shader.ResetDirty();
|
||||
ResetDirty();
|
||||
}
|
||||
}
|
||||
|
||||
bool IsDirty() const
|
||||
{
|
||||
return (_state & NEO_DIRTY);
|
||||
};
|
||||
|
||||
void Dirty()
|
||||
{
|
||||
_state |= NEO_DIRTY;
|
||||
};
|
||||
|
||||
void ResetDirty()
|
||||
{
|
||||
_state &= ~NEO_DIRTY;
|
||||
};
|
||||
|
||||
private:
|
||||
const uint16_t _countPixels; // Number of RGB LEDs in strip
|
||||
T_COLOR_OBJECT* _pixels;
|
||||
uint8_t _state; // internal state
|
||||
};
|
||||
313
lib/NeoPixelBus_by_Makuna/src/internal/NeoEase.h
Normal file
313
lib/NeoPixelBus_by_Makuna/src/internal/NeoEase.h
Normal file
@@ -0,0 +1,313 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
NeoEase provides animation curve equations for animation support.
|
||||
|
||||
Written by Michael C. Miller.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if defined(NEOPIXEBUS_NO_STL)
|
||||
|
||||
typedef float(*AnimEaseFunction)(float unitValue);
|
||||
|
||||
#else
|
||||
|
||||
#undef max
|
||||
#undef min
|
||||
#include <functional>
|
||||
typedef std::function<float(float unitValue)> AnimEaseFunction;
|
||||
|
||||
#endif
|
||||
|
||||
class NeoEase
|
||||
{
|
||||
public:
|
||||
static float Linear(float unitValue)
|
||||
{
|
||||
return unitValue;
|
||||
}
|
||||
|
||||
static float QuadraticIn(float unitValue)
|
||||
{
|
||||
return unitValue * unitValue;
|
||||
}
|
||||
|
||||
static float QuadraticOut(float unitValue)
|
||||
{
|
||||
return (-unitValue * (unitValue - 2.0f));
|
||||
}
|
||||
|
||||
static float QuadraticInOut(float unitValue)
|
||||
{
|
||||
unitValue *= 2.0f;
|
||||
if (unitValue < 1.0f)
|
||||
{
|
||||
return (0.5f * unitValue * unitValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
unitValue -= 1.0f;
|
||||
return (-0.5f * (unitValue * (unitValue - 2.0f) - 1.0f));
|
||||
}
|
||||
}
|
||||
|
||||
static float QuadraticCenter(float unitValue)
|
||||
{
|
||||
unitValue *= 2.0f;
|
||||
if (unitValue < 1.0f)
|
||||
{
|
||||
return (-0.5f * (unitValue * unitValue - 2.0f));
|
||||
}
|
||||
else
|
||||
{
|
||||
unitValue -= 1.0f;
|
||||
return (0.5f * (unitValue * unitValue + 1.0f));
|
||||
}
|
||||
}
|
||||
|
||||
static float CubicIn(float unitValue)
|
||||
{
|
||||
return (unitValue * unitValue * unitValue);
|
||||
}
|
||||
|
||||
static float CubicOut(float unitValue)
|
||||
{
|
||||
unitValue -= 1.0f;
|
||||
return (unitValue * unitValue * unitValue + 1.0f);
|
||||
}
|
||||
|
||||
static float CubicInOut(float unitValue)
|
||||
{
|
||||
unitValue *= 2.0f;
|
||||
if (unitValue < 1.0f)
|
||||
{
|
||||
return (0.5f * unitValue * unitValue * unitValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
unitValue -= 2.0f;
|
||||
return (0.5f * (unitValue * unitValue * unitValue + 2.0f));
|
||||
}
|
||||
}
|
||||
|
||||
static float CubicCenter(float unitValue)
|
||||
{
|
||||
unitValue *= 2.0f;
|
||||
unitValue -= 1.0f;
|
||||
return (0.5f * (unitValue * unitValue * unitValue + 1.0f));
|
||||
}
|
||||
|
||||
static float QuarticIn(float unitValue)
|
||||
{
|
||||
return (unitValue * unitValue * unitValue * unitValue);
|
||||
}
|
||||
|
||||
static float QuarticOut(float unitValue)
|
||||
{
|
||||
unitValue -= 1.0f;
|
||||
return -(unitValue * unitValue * unitValue * unitValue - 1.0f);
|
||||
}
|
||||
|
||||
static float QuarticInOut(float unitValue)
|
||||
{
|
||||
unitValue *= 2.0f;
|
||||
if (unitValue < 1.0f)
|
||||
{
|
||||
return (0.5f * unitValue * unitValue * unitValue * unitValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
unitValue -= 2.0f;
|
||||
return (-0.5f * (unitValue * unitValue * unitValue * unitValue - 2.0f));
|
||||
}
|
||||
}
|
||||
|
||||
static float QuarticCenter(float unitValue)
|
||||
{
|
||||
unitValue *= 2.0f;
|
||||
unitValue -= 1.0f;
|
||||
if (unitValue < 0.0f)
|
||||
{
|
||||
return (-0.5f * (unitValue * unitValue * unitValue * unitValue - 1.0f));
|
||||
}
|
||||
else
|
||||
{
|
||||
return (0.5f * (unitValue * unitValue * unitValue * unitValue + 1.0f));
|
||||
}
|
||||
}
|
||||
|
||||
static float QuinticIn(float unitValue)
|
||||
{
|
||||
return (unitValue * unitValue * unitValue * unitValue * unitValue);
|
||||
}
|
||||
|
||||
static float QuinticOut(float unitValue)
|
||||
{
|
||||
unitValue -= 1.0f;
|
||||
return (unitValue * unitValue * unitValue * unitValue * unitValue + 1.0f);
|
||||
}
|
||||
|
||||
static float QuinticInOut(float unitValue)
|
||||
{
|
||||
unitValue *= 2.0f;
|
||||
if (unitValue < 1.0f)
|
||||
{
|
||||
return (0.5f * unitValue * unitValue * unitValue * unitValue * unitValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
unitValue -= 2.0f;
|
||||
return (0.5f * (unitValue * unitValue * unitValue * unitValue * unitValue + 2.0f));
|
||||
}
|
||||
}
|
||||
|
||||
static float QuinticCenter(float unitValue)
|
||||
{
|
||||
unitValue *= 2.0f;
|
||||
unitValue -= 1.0f;
|
||||
return (0.5f * (unitValue * unitValue * unitValue * unitValue * unitValue + 1.0f));
|
||||
}
|
||||
|
||||
static float SinusoidalIn(float unitValue)
|
||||
{
|
||||
return (-cos(unitValue * HALF_PI) + 1.0f);
|
||||
}
|
||||
|
||||
static float SinusoidalOut(float unitValue)
|
||||
{
|
||||
return (sin(unitValue * HALF_PI));
|
||||
}
|
||||
|
||||
static float SinusoidalInOut(float unitValue)
|
||||
{
|
||||
return -0.5f * (cos(PI * unitValue) - 1.0f);
|
||||
}
|
||||
|
||||
static float SinusoidalCenter(float unitValue)
|
||||
{
|
||||
if (unitValue < 0.5f)
|
||||
{
|
||||
return (0.5f * sin(PI * unitValue));
|
||||
}
|
||||
else
|
||||
{
|
||||
return (-0.5f * (cos(PI * (unitValue-0.5f)) + 1.0f));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static float ExponentialIn(float unitValue)
|
||||
{
|
||||
return (pow(2, 10.0f * (unitValue - 1.0f)));
|
||||
}
|
||||
|
||||
static float ExponentialOut(float unitValue)
|
||||
{
|
||||
return (-pow(2, -10.0f * unitValue) + 1.0f);
|
||||
}
|
||||
|
||||
static float ExponentialInOut(float unitValue)
|
||||
{
|
||||
unitValue *= 2.0f;
|
||||
if (unitValue < 1.0f)
|
||||
{
|
||||
return (0.5f * pow(2, 10.0f * (unitValue - 1.0f)));
|
||||
}
|
||||
else
|
||||
{
|
||||
unitValue -= 1.0f;
|
||||
return (0.5f * (-pow(2, -10.0f * unitValue) + 2.0f));
|
||||
}
|
||||
}
|
||||
|
||||
static float ExponentialCenter(float unitValue)
|
||||
{
|
||||
unitValue *= 2.0f;
|
||||
if (unitValue < 1.0f)
|
||||
{
|
||||
return (0.5f * (-pow(2, -10.0f * unitValue) + 1.0f));
|
||||
}
|
||||
else
|
||||
{
|
||||
unitValue -= 2.0f;
|
||||
return (0.5f * (pow(2, 10.0f * unitValue) + 1.0f));
|
||||
}
|
||||
}
|
||||
|
||||
static float CircularIn(float unitValue)
|
||||
{
|
||||
if (unitValue == 1.0f)
|
||||
{
|
||||
return 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (-(sqrt(1.0f - unitValue * unitValue) - 1.0f));
|
||||
}
|
||||
}
|
||||
|
||||
static float CircularOut(float unitValue)
|
||||
{
|
||||
unitValue -= 1.0f;
|
||||
return (sqrt(1.0f - unitValue * unitValue));
|
||||
}
|
||||
|
||||
static float CircularInOut(float unitValue)
|
||||
{
|
||||
unitValue *= 2.0f;
|
||||
if (unitValue < 1.0f)
|
||||
{
|
||||
return (-0.5f * (sqrt(1.0f - unitValue * unitValue) - 1.0f));
|
||||
}
|
||||
else
|
||||
{
|
||||
unitValue -= 2.0f;
|
||||
return (0.5f * (sqrt(1.0f - unitValue * unitValue) + 1.0f));
|
||||
}
|
||||
}
|
||||
|
||||
static float CircularCenter(float unitValue)
|
||||
{
|
||||
unitValue *= 2.0f;
|
||||
unitValue -= 1.0f;
|
||||
|
||||
if (unitValue < 0.0f)
|
||||
{
|
||||
return (0.5f * sqrt(1.0f - unitValue * unitValue));
|
||||
}
|
||||
else if (unitValue > 0.0f)
|
||||
{
|
||||
unitValue -= 2.0f;
|
||||
return (-0.5f * (sqrt(1.0f - unitValue * unitValue) - 1.0f ) + 0.5f);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
static float Gamma(float unitValue)
|
||||
{
|
||||
return pow(unitValue, 1.0f / 0.45f);
|
||||
}
|
||||
};
|
||||
276
lib/NeoPixelBus_by_Makuna/src/internal/NeoEsp32I2sMethod.h
Normal file
276
lib/NeoPixelBus_by_Makuna/src/internal/NeoEsp32I2sMethod.h
Normal file
@@ -0,0 +1,276 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
NeoPixel library helper functions for Esp32.
|
||||
|
||||
Written by Michael C. Miller.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include <Arduino.h>
|
||||
#include "Esp32_i2s.h"
|
||||
}
|
||||
|
||||
const uint16_t c_dmaBytesPerPixelBytes = 4;
|
||||
|
||||
class NeoEsp32I2sSpeedWs2812x
|
||||
{
|
||||
public:
|
||||
const static uint32_t I2sSampleRate = 100000;
|
||||
const static uint16_t ByteSendTimeUs = 10;
|
||||
const static uint16_t ResetTimeUs = 300;
|
||||
};
|
||||
|
||||
class NeoEsp32I2sSpeedSk6812
|
||||
{
|
||||
public:
|
||||
const static uint32_t I2sSampleRate = 100000;
|
||||
const static uint16_t ByteSendTimeUs = 10;
|
||||
const static uint16_t ResetTimeUs = 80;
|
||||
};
|
||||
|
||||
class NeoEsp32I2sSpeedTm1814
|
||||
{
|
||||
public:
|
||||
const static uint32_t I2sSampleRate = 100000;
|
||||
const static uint16_t ByteSendTimeUs = 10;
|
||||
const static uint16_t ResetTimeUs = 200;
|
||||
};
|
||||
|
||||
class NeoEsp32I2sSpeed800Kbps
|
||||
{
|
||||
public:
|
||||
const static uint32_t I2sSampleRate = 100000;
|
||||
const static uint16_t ByteSendTimeUs = 10;
|
||||
const static uint16_t ResetTimeUs = 50;
|
||||
};
|
||||
|
||||
class NeoEsp32I2sSpeed400Kbps
|
||||
{
|
||||
public:
|
||||
const static uint32_t I2sSampleRate = 50000;
|
||||
const static uint16_t ByteSendTimeUs = 20;
|
||||
const static uint16_t ResetTimeUs = 50;
|
||||
};
|
||||
|
||||
class NeoEsp32I2sSpeedApa106
|
||||
{
|
||||
public:
|
||||
const static uint32_t I2sSampleRate = 76000;
|
||||
const static uint16_t ByteSendTimeUs = 14;
|
||||
const static uint16_t ResetTimeUs = 50;
|
||||
};
|
||||
|
||||
class NeoEsp32I2sBusZero
|
||||
{
|
||||
public:
|
||||
const static uint8_t I2sBusNumber = 0;
|
||||
};
|
||||
|
||||
class NeoEsp32I2sBusOne
|
||||
{
|
||||
public:
|
||||
const static uint8_t I2sBusNumber = 1;
|
||||
};
|
||||
|
||||
class NeoEsp32I2sNotInverted
|
||||
{
|
||||
public:
|
||||
const static bool Inverted = false;
|
||||
};
|
||||
|
||||
class NeoEsp32I2sInverted
|
||||
{
|
||||
public:
|
||||
const static bool Inverted = true;
|
||||
};
|
||||
|
||||
template<typename T_SPEED, typename T_BUS, typename T_INVERT> class NeoEsp32I2sMethodBase
|
||||
{
|
||||
public:
|
||||
NeoEsp32I2sMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize) :
|
||||
_sizeData(pixelCount * elementSize + settingsSize),
|
||||
_pin(pin)
|
||||
{
|
||||
uint16_t dmaSettingsSize = c_dmaBytesPerPixelBytes * settingsSize;
|
||||
uint16_t dmaPixelSize = c_dmaBytesPerPixelBytes * elementSize;
|
||||
uint16_t resetSize = c_dmaBytesPerPixelBytes * T_SPEED::ResetTimeUs / T_SPEED::ByteSendTimeUs;
|
||||
|
||||
_i2sBufferSize = pixelCount * dmaPixelSize + dmaSettingsSize + resetSize;
|
||||
|
||||
// must have a 4 byte aligned buffer for i2s
|
||||
uint32_t alignment = _i2sBufferSize % 4;
|
||||
if (alignment)
|
||||
{
|
||||
_i2sBufferSize += 4 - alignment;
|
||||
}
|
||||
|
||||
_data = static_cast<uint8_t*>(malloc(_sizeData));
|
||||
memset(_data, 0x00, _sizeData);
|
||||
|
||||
_i2sBuffer = static_cast<uint8_t*>(malloc(_i2sBufferSize));
|
||||
memset(_i2sBuffer, 0x00, _i2sBufferSize);
|
||||
}
|
||||
|
||||
~NeoEsp32I2sMethodBase()
|
||||
{
|
||||
while (!IsReadyToUpdate())
|
||||
{
|
||||
yield();
|
||||
}
|
||||
|
||||
pinMode(_pin, INPUT);
|
||||
|
||||
free(_data);
|
||||
free(_i2sBuffer);
|
||||
}
|
||||
|
||||
bool IsReadyToUpdate() const
|
||||
{
|
||||
return (i2sWriteDone(T_BUS::I2sBusNumber));
|
||||
}
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
size_t dmaCount = (_i2sBufferSize + I2S_DMA_MAX_DATA_LEN - 1) / I2S_DMA_MAX_DATA_LEN;
|
||||
i2sInit(T_BUS::I2sBusNumber, 16, T_SPEED::I2sSampleRate, I2S_CHAN_STEREO, I2S_FIFO_16BIT_DUAL, dmaCount, 0);
|
||||
i2sSetPins(T_BUS::I2sBusNumber, _pin, T_INVERT::Inverted);
|
||||
}
|
||||
|
||||
void Update(bool)
|
||||
{
|
||||
// wait for not actively sending data
|
||||
while (!IsReadyToUpdate())
|
||||
{
|
||||
yield();
|
||||
}
|
||||
|
||||
FillBuffers();
|
||||
|
||||
i2sWrite(T_BUS::I2sBusNumber, _i2sBuffer, _i2sBufferSize, false, false);
|
||||
}
|
||||
|
||||
uint8_t* getData() const
|
||||
{
|
||||
return _data;
|
||||
};
|
||||
|
||||
size_t getDataSize() const
|
||||
{
|
||||
return _sizeData;
|
||||
}
|
||||
|
||||
private:
|
||||
const size_t _sizeData; // Size of '_data' buffer
|
||||
const uint8_t _pin; // output pin number
|
||||
|
||||
uint8_t* _data; // Holds LED color values
|
||||
|
||||
uint32_t _i2sBufferSize; // total size of _i2sBuffer
|
||||
uint8_t* _i2sBuffer; // holds the DMA buffer that is referenced by _i2sBufDesc
|
||||
|
||||
void FillBuffers()
|
||||
{
|
||||
const uint16_t bitpatterns[16] =
|
||||
{
|
||||
0b1000100010001000, 0b1000100010001110, 0b1000100011101000, 0b1000100011101110,
|
||||
0b1000111010001000, 0b1000111010001110, 0b1000111011101000, 0b1000111011101110,
|
||||
0b1110100010001000, 0b1110100010001110, 0b1110100011101000, 0b1110100011101110,
|
||||
0b1110111010001000, 0b1110111010001110, 0b1110111011101000, 0b1110111011101110,
|
||||
};
|
||||
|
||||
uint16_t* pDma = reinterpret_cast<uint16_t*>(_i2sBuffer);
|
||||
uint8_t* pEnd = _data + _sizeData;
|
||||
for (uint8_t* pPixel = _data; pPixel < pEnd; pPixel++)
|
||||
{
|
||||
*(pDma++) = bitpatterns[((*pPixel) & 0x0f)];
|
||||
*(pDma++) = bitpatterns[((*pPixel) >> 4) & 0x0f];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeedWs2812x, NeoEsp32I2sBusZero, NeoEsp32I2sNotInverted> NeoEsp32I2s0Ws2812xMethod;
|
||||
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeedSk6812, NeoEsp32I2sBusZero, NeoEsp32I2sNotInverted> NeoEsp32I2s0Sk6812Method;
|
||||
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeedTm1814, NeoEsp32I2sBusZero, NeoEsp32I2sInverted> NeoEsp32I2s0Tm1814Method;
|
||||
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeed800Kbps, NeoEsp32I2sBusZero, NeoEsp32I2sNotInverted> NeoEsp32I2s0800KbpsMethod;
|
||||
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeed400Kbps, NeoEsp32I2sBusZero, NeoEsp32I2sNotInverted> NeoEsp32I2s0400KbpsMethod;
|
||||
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeedApa106, NeoEsp32I2sBusZero, NeoEsp32I2sNotInverted> NeoEsp32I2s0Apa106Method;
|
||||
|
||||
|
||||
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeedWs2812x, NeoEsp32I2sBusZero, NeoEsp32I2sInverted> NeoEsp32I2s0Ws2812xInvertedMethod;
|
||||
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeedSk6812, NeoEsp32I2sBusZero, NeoEsp32I2sInverted> NeoEsp32I2s0Sk6812InvertedMethod;
|
||||
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeedTm1814, NeoEsp32I2sBusZero, NeoEsp32I2sNotInverted> NeoEsp32I2s0Tm1814InvertedMethod;
|
||||
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeed800Kbps, NeoEsp32I2sBusZero, NeoEsp32I2sInverted> NeoEsp32I2s0800KbpsInvertedMethod;
|
||||
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeed400Kbps, NeoEsp32I2sBusZero, NeoEsp32I2sInverted> NeoEsp32I2s0400KbpsInvertedMethod;
|
||||
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeedApa106, NeoEsp32I2sBusZero, NeoEsp32I2sInverted> NeoEsp32I2s0Apa106InvertedMethod;
|
||||
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
// (I2S_NUM_MAX == 2)
|
||||
|
||||
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeedWs2812x, NeoEsp32I2sBusOne, NeoEsp32I2sNotInverted> NeoEsp32I2s1Ws2812xMethod;
|
||||
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeedSk6812, NeoEsp32I2sBusOne, NeoEsp32I2sNotInverted> NeoEsp32I2s1Sk6812Method;
|
||||
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeedTm1814, NeoEsp32I2sBusOne, NeoEsp32I2sInverted> NeoEsp32I2s1Tm1814Method;
|
||||
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeed800Kbps, NeoEsp32I2sBusOne, NeoEsp32I2sNotInverted> NeoEsp32I2s1800KbpsMethod;
|
||||
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeed400Kbps, NeoEsp32I2sBusOne, NeoEsp32I2sNotInverted> NeoEsp32I2s1400KbpsMethod;
|
||||
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeedApa106, NeoEsp32I2sBusOne, NeoEsp32I2sNotInverted> NeoEsp32I2s1Apa106Method;
|
||||
|
||||
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeedWs2812x, NeoEsp32I2sBusOne, NeoEsp32I2sInverted> NeoEsp32I2s1Ws2812xInvertedMethod;
|
||||
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeedSk6812, NeoEsp32I2sBusOne, NeoEsp32I2sInverted> NeoEsp32I2s1Sk6812InvertedMethod;
|
||||
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeedTm1814, NeoEsp32I2sBusOne, NeoEsp32I2sNotInverted> NeoEsp32I2s1Tm1814InvertedMethod;
|
||||
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeed800Kbps, NeoEsp32I2sBusOne, NeoEsp32I2sInverted> NeoEsp32I2s1800KbpsInvertedMethod;
|
||||
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeed400Kbps, NeoEsp32I2sBusOne, NeoEsp32I2sInverted> NeoEsp32I2s1400KbpsInvertedMethod;
|
||||
typedef NeoEsp32I2sMethodBase<NeoEsp32I2sSpeedApa106, NeoEsp32I2sBusOne, NeoEsp32I2sInverted> NeoEsp32I2s1Apa106InvertedMethod;
|
||||
|
||||
#endif
|
||||
|
||||
/* due to a core issue where requests to send aren't consistent, I2s is no longer the default
|
||||
// I2s Bus 1 method is the default method for Esp32
|
||||
typedef NeoEsp32I2s1Ws2812xMethod NeoWs2813Method;
|
||||
typedef NeoEsp32I2s1Ws2812xMethod NeoWs2812xMethod;
|
||||
typedef NeoEsp32I2s1800KbpsMethod NeoWs2812Method;
|
||||
typedef NeoEsp32I2s1Ws2812xMethod NeoWs2811Method;
|
||||
typedef NeoEsp32I2s1Sk6812Method NeoSk6812Method;
|
||||
typedef NeoEsp32I2s1Tm1814Method NeoTm1814Method;
|
||||
typedef NeoEsp32I2s1Sk6812Method NeoLc8812Method;
|
||||
typedef NeoEsp32I2s1Apa106Method NeoApa106Method;
|
||||
|
||||
typedef NeoEsp32I2s1Ws2812xMethod Neo800KbpsMethod;
|
||||
typedef NeoEsp32I2s1400KbpsMethod Neo400KbpsMethod;
|
||||
|
||||
typedef NeoEsp32I2s1Ws2812xInvertedMethod NeoWs2813InvertedMethod;
|
||||
typedef NeoEsp32I2s1Ws2812xInvertedMethod NeoWs2812xInvertedMethod;
|
||||
typedef NeoEsp32I2s1Ws2812xInvertedMethod NeoWs2811InvertedMethod;
|
||||
typedef NeoEsp32I2s1800KbpsInvertedMethod NeoWs2812InvertedMethod;
|
||||
typedef NeoEsp32I2s1Sk6812InvertedMethod NeoSk6812InvertedMethod;
|
||||
typedef NeoEsp32I2s1Tm1814InvertedMethod NeoTm1814InvertedMethod;
|
||||
typedef NeoEsp32I2s1Sk6812InvertedMethod NeoLc8812InvertedMethod;
|
||||
typedef NeoEsp32I2s1Apa106InvertedMethod NeoApa106InvertedMethod;
|
||||
|
||||
typedef NeoEsp32I2s1Ws2812xInvertedMethod Neo800KbpsInvertedMethod;
|
||||
typedef NeoEsp32I2s1400KbpsInvertedMethod Neo400KbpsInvertedMethod;
|
||||
*/
|
||||
|
||||
#endif
|
||||
262
lib/NeoPixelBus_by_Makuna/src/internal/NeoEsp32RmtMethod.cpp
Normal file
262
lib/NeoPixelBus_by_Makuna/src/internal/NeoEsp32RmtMethod.cpp
Normal file
@@ -0,0 +1,262 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
NeoPixel library helper functions for Esp32.
|
||||
|
||||
A BIG thanks to Andreas Merkle for the investigation and implementation of
|
||||
a workaround to the GCC bug that drops method attributes from template methods
|
||||
|
||||
Written by Michael C. Miller.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
|
||||
#include "NeoEsp32RmtMethod.h"
|
||||
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
|
||||
|
||||
// translate NeoPixelBuffer into RMT buffer
|
||||
// this is done on the fly so we don't require a send buffer in raw RMT format
|
||||
// which would be 32x larger than the primary buffer
|
||||
//
|
||||
// NOTE: This was moved from the template below to here to workaround a GCC bug
|
||||
// That bug is that the IRAM_ATTR attribute (any attributes) is lost on template classes.
|
||||
//
|
||||
// Further, it was removed from the header to support current Esp32 release
|
||||
// which will need to be removed when the latest GitHub branchis released
|
||||
// due to this method will not get inlined this way
|
||||
//
|
||||
void NeoEsp32RmtSpeed::_translate(const void* src,
|
||||
rmt_item32_t* dest,
|
||||
size_t src_size,
|
||||
size_t wanted_num,
|
||||
size_t* translated_size,
|
||||
size_t* item_num,
|
||||
const uint32_t rmtBit0,
|
||||
const uint32_t rmtBit1,
|
||||
const uint16_t rmtDurationReset)
|
||||
{
|
||||
if (src == NULL || dest == NULL)
|
||||
{
|
||||
*translated_size = 0;
|
||||
*item_num = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
size_t size = 0;
|
||||
size_t num = 0;
|
||||
const uint8_t* psrc = static_cast<const uint8_t*>(src);
|
||||
rmt_item32_t* pdest = dest;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
uint8_t data = *psrc;
|
||||
|
||||
for (uint8_t bit = 0; bit < 8; bit++)
|
||||
{
|
||||
pdest->val = (data & 0x80) ? rmtBit1 : rmtBit0;
|
||||
pdest++;
|
||||
data <<= 1;
|
||||
}
|
||||
num += 8;
|
||||
size++;
|
||||
|
||||
// if this is the last byte we need to adjust the length of the last pulse
|
||||
if (size >= src_size)
|
||||
{
|
||||
// extend the last bits LOW value to include the full reset signal length
|
||||
pdest--;
|
||||
pdest->duration1 = rmtDurationReset;
|
||||
// and stop updating data to send
|
||||
break;
|
||||
}
|
||||
|
||||
if (num >= wanted_num)
|
||||
{
|
||||
// stop updating data to send
|
||||
break;
|
||||
}
|
||||
|
||||
psrc++;
|
||||
}
|
||||
|
||||
*translated_size = size;
|
||||
*item_num = num;
|
||||
}
|
||||
|
||||
|
||||
// these are required due to the linker error with ISRs
|
||||
// dangerous relocation: l32r: literal placed after use
|
||||
// https://stackoverflow.com/questions/19532826/what-does-a-dangerous-relocation-error-mean
|
||||
//
|
||||
void NeoEsp32RmtSpeedWs2811::Translate(const void* src,
|
||||
rmt_item32_t* dest,
|
||||
size_t src_size,
|
||||
size_t wanted_num,
|
||||
size_t* translated_size,
|
||||
size_t* item_num)
|
||||
{
|
||||
_translate(src, dest, src_size, wanted_num, translated_size, item_num,
|
||||
RmtBit0, RmtBit1, RmtDurationReset);
|
||||
}
|
||||
|
||||
void NeoEsp32RmtSpeedWs2812x::Translate(const void* src,
|
||||
rmt_item32_t* dest,
|
||||
size_t src_size,
|
||||
size_t wanted_num,
|
||||
size_t* translated_size,
|
||||
size_t* item_num)
|
||||
{
|
||||
_translate(src, dest, src_size, wanted_num, translated_size, item_num,
|
||||
RmtBit0, RmtBit1, RmtDurationReset);
|
||||
}
|
||||
|
||||
void NeoEsp32RmtSpeedSk6812::Translate(const void* src,
|
||||
rmt_item32_t* dest,
|
||||
size_t src_size,
|
||||
size_t wanted_num,
|
||||
size_t* translated_size,
|
||||
size_t* item_num)
|
||||
{
|
||||
_translate(src, dest, src_size, wanted_num, translated_size, item_num,
|
||||
RmtBit0, RmtBit1, RmtDurationReset);
|
||||
}
|
||||
|
||||
void NeoEsp32RmtSpeedTm1814::Translate(const void* src,
|
||||
rmt_item32_t* dest,
|
||||
size_t src_size,
|
||||
size_t wanted_num,
|
||||
size_t* translated_size,
|
||||
size_t* item_num)
|
||||
{
|
||||
_translate(src, dest, src_size, wanted_num, translated_size, item_num,
|
||||
RmtBit0, RmtBit1, RmtDurationReset);
|
||||
}
|
||||
|
||||
void NeoEsp32RmtSpeed800Kbps::Translate(const void* src,
|
||||
rmt_item32_t* dest,
|
||||
size_t src_size,
|
||||
size_t wanted_num,
|
||||
size_t* translated_size,
|
||||
size_t* item_num)
|
||||
{
|
||||
_translate(src, dest, src_size, wanted_num, translated_size, item_num,
|
||||
RmtBit0, RmtBit1, RmtDurationReset);
|
||||
}
|
||||
|
||||
void NeoEsp32RmtSpeed400Kbps::Translate(const void* src,
|
||||
rmt_item32_t* dest,
|
||||
size_t src_size,
|
||||
size_t wanted_num,
|
||||
size_t* translated_size,
|
||||
size_t* item_num)
|
||||
{
|
||||
_translate(src, dest, src_size, wanted_num, translated_size, item_num,
|
||||
RmtBit0, RmtBit1, RmtDurationReset);
|
||||
}
|
||||
|
||||
void NeoEsp32RmtSpeedApa106::Translate(const void* src,
|
||||
rmt_item32_t* dest,
|
||||
size_t src_size,
|
||||
size_t wanted_num,
|
||||
size_t* translated_size,
|
||||
size_t* item_num)
|
||||
{
|
||||
_translate(src, dest, src_size, wanted_num, translated_size, item_num,
|
||||
RmtBit0, RmtBit1, RmtDurationReset);
|
||||
}
|
||||
|
||||
void NeoEsp32RmtInvertedSpeedWs2811::Translate(const void* src,
|
||||
rmt_item32_t* dest,
|
||||
size_t src_size,
|
||||
size_t wanted_num,
|
||||
size_t* translated_size,
|
||||
size_t* item_num)
|
||||
{
|
||||
_translate(src, dest, src_size, wanted_num, translated_size, item_num,
|
||||
RmtBit0, RmtBit1, RmtDurationReset);
|
||||
}
|
||||
|
||||
void NeoEsp32RmtInvertedSpeedWs2812x::Translate(const void* src,
|
||||
rmt_item32_t* dest,
|
||||
size_t src_size,
|
||||
size_t wanted_num,
|
||||
size_t* translated_size,
|
||||
size_t* item_num)
|
||||
{
|
||||
_translate(src, dest, src_size, wanted_num, translated_size, item_num,
|
||||
RmtBit0, RmtBit1, RmtDurationReset);
|
||||
}
|
||||
|
||||
void NeoEsp32RmtInvertedSpeedSk6812::Translate(const void* src,
|
||||
rmt_item32_t* dest,
|
||||
size_t src_size,
|
||||
size_t wanted_num,
|
||||
size_t* translated_size,
|
||||
size_t* item_num)
|
||||
{
|
||||
_translate(src, dest, src_size, wanted_num, translated_size, item_num,
|
||||
RmtBit0, RmtBit1, RmtDurationReset);
|
||||
}
|
||||
|
||||
void NeoEsp32RmtInvertedSpeedTm1814::Translate(const void* src,
|
||||
rmt_item32_t* dest,
|
||||
size_t src_size,
|
||||
size_t wanted_num,
|
||||
size_t* translated_size,
|
||||
size_t* item_num)
|
||||
{
|
||||
_translate(src, dest, src_size, wanted_num, translated_size, item_num,
|
||||
RmtBit0, RmtBit1, RmtDurationReset);
|
||||
}
|
||||
|
||||
void NeoEsp32RmtInvertedSpeed800Kbps::Translate(const void* src,
|
||||
rmt_item32_t* dest,
|
||||
size_t src_size,
|
||||
size_t wanted_num,
|
||||
size_t* translated_size,
|
||||
size_t* item_num)
|
||||
{
|
||||
_translate(src, dest, src_size, wanted_num, translated_size, item_num,
|
||||
RmtBit0, RmtBit1, RmtDurationReset);
|
||||
}
|
||||
|
||||
void NeoEsp32RmtInvertedSpeed400Kbps::Translate(const void* src,
|
||||
rmt_item32_t* dest,
|
||||
size_t src_size,
|
||||
size_t wanted_num,
|
||||
size_t* translated_size,
|
||||
size_t* item_num)
|
||||
{
|
||||
_translate(src, dest, src_size, wanted_num, translated_size, item_num,
|
||||
RmtBit0, RmtBit1, RmtDurationReset);
|
||||
}
|
||||
|
||||
void NeoEsp32RmtInvertedSpeedApa106::Translate(const void* src,
|
||||
rmt_item32_t* dest,
|
||||
size_t src_size,
|
||||
size_t wanted_num,
|
||||
size_t* translated_size,
|
||||
size_t* item_num)
|
||||
{
|
||||
_translate(src, dest, src_size, wanted_num, translated_size, item_num,
|
||||
RmtBit0, RmtBit1, RmtDurationReset);
|
||||
}
|
||||
#endif
|
||||
668
lib/NeoPixelBus_by_Makuna/src/internal/NeoEsp32RmtMethod.h
Normal file
668
lib/NeoPixelBus_by_Makuna/src/internal/NeoEsp32RmtMethod.h
Normal file
@@ -0,0 +1,668 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
NeoPixel library helper functions for Esp32.
|
||||
|
||||
A BIG thanks to Andreas Merkle for the investigation and implementation of
|
||||
a workaround to the GCC bug that drops method attributes from template methods
|
||||
|
||||
Written by Michael C. Miller.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
|
||||
/* General Reference documentation for the APIs used in this implementation
|
||||
LOW LEVEL: (what is actually used)
|
||||
DOCS: https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/peripherals/rmt.html
|
||||
EXAMPLE: https://github.com/espressif/esp-idf/blob/826ff7186ae07dc81e960a8ea09ebfc5304bfb3b/examples/peripherals/rmt_tx/main/rmt_tx_main.c
|
||||
|
||||
HIGHER LEVEL:
|
||||
NO TRANSLATE SUPPORT so this was not used
|
||||
NOTE: https://github.com/espressif/arduino-esp32/commit/50d142950d229b8fabca9b749dc4a5f2533bc426
|
||||
Esp32-hal-rmt.h
|
||||
Esp32-hal-rmt.c
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include <driver/rmt.h>
|
||||
}
|
||||
|
||||
class NeoEsp32RmtSpeed
|
||||
{
|
||||
public:
|
||||
// ClkDiv of 2 provides for good resolution and plenty of reset resolution; but
|
||||
// a ClkDiv of 1 will provide enough space for the longest reset and does show
|
||||
// little better pulse accuracy
|
||||
const static uint8_t RmtClockDivider = 2;
|
||||
|
||||
inline constexpr static uint32_t FromNs(uint32_t ns)
|
||||
{
|
||||
return ns / NsPerRmtTick;
|
||||
}
|
||||
|
||||
protected:
|
||||
const static uint32_t RmtCpu = 80000000L; // 80 mhz RMT clock
|
||||
const static uint32_t NsPerSecond = 1000000000L;
|
||||
const static uint32_t RmtTicksPerSecond = (RmtCpu / RmtClockDivider);
|
||||
const static uint32_t NsPerRmtTick = (NsPerSecond / RmtTicksPerSecond); // about 25
|
||||
|
||||
static void IRAM_ATTR _translate(const void* src,
|
||||
rmt_item32_t* dest,
|
||||
size_t src_size,
|
||||
size_t wanted_num,
|
||||
size_t* translated_size,
|
||||
size_t* item_num,
|
||||
const uint32_t rmtBit0,
|
||||
const uint32_t rmtBit1,
|
||||
const uint16_t rmtDurationReset);
|
||||
|
||||
};
|
||||
|
||||
class NeoEsp32RmtSpeedBase : public NeoEsp32RmtSpeed
|
||||
{
|
||||
public:
|
||||
// this is used rather than the rmt_item32_t as you can't correctly initialize
|
||||
// it as a static constexpr within the template
|
||||
inline constexpr static uint32_t Item32Val(uint16_t nsHigh, uint16_t nsLow)
|
||||
{
|
||||
return (FromNs(nsLow) << 16) | (1 << 15) | (FromNs(nsHigh));
|
||||
}
|
||||
|
||||
const static rmt_idle_level_t IdleLevel = RMT_IDLE_LEVEL_LOW;
|
||||
};
|
||||
|
||||
class NeoEsp32RmtInvertedSpeedBase : public NeoEsp32RmtSpeed
|
||||
{
|
||||
public:
|
||||
// this is used rather than the rmt_item32_t as you can't correctly initialize
|
||||
// it as a static constexpr within the template
|
||||
inline constexpr static uint32_t Item32Val(uint16_t nsHigh, uint16_t nsLow)
|
||||
{
|
||||
return (FromNs(nsLow) << 16) | (1 << 31) | (FromNs(nsHigh));
|
||||
}
|
||||
|
||||
const static rmt_idle_level_t IdleLevel = RMT_IDLE_LEVEL_HIGH;
|
||||
};
|
||||
|
||||
class NeoEsp32RmtSpeedWs2811 : public NeoEsp32RmtSpeedBase
|
||||
{
|
||||
public:
|
||||
const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(300, 950);
|
||||
const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(900, 350);
|
||||
const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(300000); // 300us
|
||||
|
||||
static void IRAM_ATTR Translate(const void* src,
|
||||
rmt_item32_t* dest,
|
||||
size_t src_size,
|
||||
size_t wanted_num,
|
||||
size_t* translated_size,
|
||||
size_t* item_num);
|
||||
};
|
||||
|
||||
class NeoEsp32RmtSpeedWs2812x : public NeoEsp32RmtSpeedBase
|
||||
{
|
||||
public:
|
||||
const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(400, 850);
|
||||
const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(800, 450);
|
||||
const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(300000); // 300us
|
||||
|
||||
static void IRAM_ATTR Translate(const void* src,
|
||||
rmt_item32_t* dest,
|
||||
size_t src_size,
|
||||
size_t wanted_num,
|
||||
size_t* translated_size,
|
||||
size_t* item_num);
|
||||
};
|
||||
|
||||
class NeoEsp32RmtSpeedSk6812 : public NeoEsp32RmtSpeedBase
|
||||
{
|
||||
public:
|
||||
const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(400, 850);
|
||||
const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(800, 450);
|
||||
const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(80000); // 80us
|
||||
|
||||
static void IRAM_ATTR Translate(const void* src,
|
||||
rmt_item32_t* dest,
|
||||
size_t src_size,
|
||||
size_t wanted_num,
|
||||
size_t* translated_size,
|
||||
size_t* item_num);
|
||||
};
|
||||
|
||||
// normal is inverted signal
|
||||
class NeoEsp32RmtSpeedTm1814 : public NeoEsp32RmtInvertedSpeedBase
|
||||
{
|
||||
public:
|
||||
const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(360, 890);
|
||||
const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(720, 530);
|
||||
const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(200000); // 200us
|
||||
|
||||
static void IRAM_ATTR Translate(const void* src,
|
||||
rmt_item32_t* dest,
|
||||
size_t src_size,
|
||||
size_t wanted_num,
|
||||
size_t* translated_size,
|
||||
size_t* item_num);
|
||||
};
|
||||
|
||||
class NeoEsp32RmtSpeed800Kbps : public NeoEsp32RmtSpeedBase
|
||||
{
|
||||
public:
|
||||
const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(400, 850);
|
||||
const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(800, 450);
|
||||
const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(50000); // 50us
|
||||
|
||||
static void IRAM_ATTR Translate(const void* src,
|
||||
rmt_item32_t* dest,
|
||||
size_t src_size,
|
||||
size_t wanted_num,
|
||||
size_t* translated_size,
|
||||
size_t* item_num);
|
||||
};
|
||||
|
||||
class NeoEsp32RmtSpeed400Kbps : public NeoEsp32RmtSpeedBase
|
||||
{
|
||||
public:
|
||||
const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(800, 1700);
|
||||
const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(1600, 900);
|
||||
const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(50000); // 50us
|
||||
|
||||
static void IRAM_ATTR Translate(const void* src,
|
||||
rmt_item32_t* dest,
|
||||
size_t src_size,
|
||||
size_t wanted_num,
|
||||
size_t* translated_size,
|
||||
size_t* item_num);
|
||||
};
|
||||
|
||||
class NeoEsp32RmtSpeedApa106 : public NeoEsp32RmtSpeedBase
|
||||
{
|
||||
public:
|
||||
const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(400, 1250);
|
||||
const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(1250, 400);
|
||||
const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(50000); // 50us
|
||||
|
||||
static void IRAM_ATTR Translate(const void* src,
|
||||
rmt_item32_t* dest,
|
||||
size_t src_size,
|
||||
size_t wanted_num,
|
||||
size_t* translated_size,
|
||||
size_t* item_num);
|
||||
};
|
||||
|
||||
class NeoEsp32RmtInvertedSpeedWs2811 : public NeoEsp32RmtInvertedSpeedBase
|
||||
{
|
||||
public:
|
||||
const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(300, 950);
|
||||
const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(900, 350);
|
||||
const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(300000); // 300us
|
||||
|
||||
static void IRAM_ATTR Translate(const void* src,
|
||||
rmt_item32_t* dest,
|
||||
size_t src_size,
|
||||
size_t wanted_num,
|
||||
size_t* translated_size,
|
||||
size_t* item_num);
|
||||
};
|
||||
|
||||
class NeoEsp32RmtInvertedSpeedWs2812x : public NeoEsp32RmtInvertedSpeedBase
|
||||
{
|
||||
public:
|
||||
const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(400, 850);
|
||||
const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(800, 450);
|
||||
const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(300000); // 300us
|
||||
|
||||
static void IRAM_ATTR Translate(const void* src,
|
||||
rmt_item32_t* dest,
|
||||
size_t src_size,
|
||||
size_t wanted_num,
|
||||
size_t* translated_size,
|
||||
size_t* item_num);
|
||||
};
|
||||
|
||||
class NeoEsp32RmtInvertedSpeedSk6812 : public NeoEsp32RmtInvertedSpeedBase
|
||||
{
|
||||
public:
|
||||
const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(400, 850);
|
||||
const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(800, 450);
|
||||
const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(80000); // 80us
|
||||
|
||||
static void IRAM_ATTR Translate(const void* src,
|
||||
rmt_item32_t* dest,
|
||||
size_t src_size,
|
||||
size_t wanted_num,
|
||||
size_t* translated_size,
|
||||
size_t* item_num);
|
||||
};
|
||||
|
||||
// normal is inverted signal
|
||||
class NeoEsp32RmtInvertedSpeedTm1814 : public NeoEsp32RmtSpeedBase
|
||||
{
|
||||
public:
|
||||
const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(360, 890);
|
||||
const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(720, 530);
|
||||
const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(200000); // 200us
|
||||
|
||||
static void IRAM_ATTR Translate(const void* src,
|
||||
rmt_item32_t* dest,
|
||||
size_t src_size,
|
||||
size_t wanted_num,
|
||||
size_t* translated_size,
|
||||
size_t* item_num);
|
||||
};
|
||||
|
||||
class NeoEsp32RmtInvertedSpeed800Kbps : public NeoEsp32RmtInvertedSpeedBase
|
||||
{
|
||||
public:
|
||||
const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(400, 850);
|
||||
const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(800, 450);
|
||||
const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(50000); // 50us
|
||||
|
||||
static void IRAM_ATTR Translate(const void* src,
|
||||
rmt_item32_t* dest,
|
||||
size_t src_size,
|
||||
size_t wanted_num,
|
||||
size_t* translated_size,
|
||||
size_t* item_num);
|
||||
};
|
||||
|
||||
class NeoEsp32RmtInvertedSpeed400Kbps : public NeoEsp32RmtInvertedSpeedBase
|
||||
{
|
||||
public:
|
||||
const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(800, 1700);
|
||||
const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(1600, 900);
|
||||
const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(50000); // 50us
|
||||
|
||||
static void IRAM_ATTR Translate(const void* src,
|
||||
rmt_item32_t* dest,
|
||||
size_t src_size,
|
||||
size_t wanted_num,
|
||||
size_t* translated_size,
|
||||
size_t* item_num);
|
||||
};
|
||||
|
||||
class NeoEsp32RmtInvertedSpeedApa106 : public NeoEsp32RmtInvertedSpeedBase
|
||||
{
|
||||
public:
|
||||
const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(400, 1250);
|
||||
const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(1250, 400);
|
||||
const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(50000); // 50us
|
||||
|
||||
static void IRAM_ATTR Translate(const void* src,
|
||||
rmt_item32_t* dest,
|
||||
size_t src_size,
|
||||
size_t wanted_num,
|
||||
size_t* translated_size,
|
||||
size_t* item_num);
|
||||
};
|
||||
|
||||
class NeoEsp32RmtChannel0
|
||||
{
|
||||
public:
|
||||
const static rmt_channel_t RmtChannelNumber = RMT_CHANNEL_0;
|
||||
};
|
||||
|
||||
class NeoEsp32RmtChannel1
|
||||
{
|
||||
public:
|
||||
const static rmt_channel_t RmtChannelNumber = RMT_CHANNEL_1;
|
||||
};
|
||||
|
||||
class NeoEsp32RmtChannel2
|
||||
{
|
||||
public:
|
||||
const static rmt_channel_t RmtChannelNumber = RMT_CHANNEL_2;
|
||||
};
|
||||
|
||||
class NeoEsp32RmtChannel3
|
||||
{
|
||||
public:
|
||||
const static rmt_channel_t RmtChannelNumber = RMT_CHANNEL_3;
|
||||
};
|
||||
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
|
||||
class NeoEsp32RmtChannel4
|
||||
{
|
||||
public:
|
||||
const static rmt_channel_t RmtChannelNumber = RMT_CHANNEL_4;
|
||||
};
|
||||
|
||||
class NeoEsp32RmtChannel5
|
||||
{
|
||||
public:
|
||||
const static rmt_channel_t RmtChannelNumber = RMT_CHANNEL_5;
|
||||
};
|
||||
|
||||
class NeoEsp32RmtChannel6
|
||||
{
|
||||
public:
|
||||
const static rmt_channel_t RmtChannelNumber = RMT_CHANNEL_6;
|
||||
};
|
||||
|
||||
class NeoEsp32RmtChannel7
|
||||
{
|
||||
public:
|
||||
const static rmt_channel_t RmtChannelNumber = RMT_CHANNEL_7;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
template<typename T_SPEED, typename T_CHANNEL> class NeoEsp32RmtMethodBase
|
||||
{
|
||||
public:
|
||||
NeoEsp32RmtMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize) :
|
||||
_sizeData(pixelCount * elementSize + settingsSize),
|
||||
_pin(pin)
|
||||
{
|
||||
_dataEditing = static_cast<uint8_t*>(malloc(_sizeData));
|
||||
memset(_dataEditing, 0x00, _sizeData);
|
||||
|
||||
_dataSending = static_cast<uint8_t*>(malloc(_sizeData));
|
||||
// no need to initialize it, it gets overwritten on every send
|
||||
}
|
||||
|
||||
~NeoEsp32RmtMethodBase()
|
||||
{
|
||||
// wait until the last send finishes before destructing everything
|
||||
// arbitrary time out of 10 seconds
|
||||
ESP_ERROR_CHECK_WITHOUT_ABORT(rmt_wait_tx_done(T_CHANNEL::RmtChannelNumber, 10000 / portTICK_PERIOD_MS));
|
||||
|
||||
ESP_ERROR_CHECK(rmt_driver_uninstall(T_CHANNEL::RmtChannelNumber));
|
||||
|
||||
free(_dataEditing);
|
||||
free(_dataSending);
|
||||
}
|
||||
|
||||
|
||||
bool IsReadyToUpdate() const
|
||||
{
|
||||
return (ESP_OK == rmt_wait_tx_done(T_CHANNEL::RmtChannelNumber, 0));
|
||||
}
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
rmt_config_t config;
|
||||
|
||||
config.rmt_mode = RMT_MODE_TX;
|
||||
config.channel = T_CHANNEL::RmtChannelNumber;
|
||||
config.gpio_num = static_cast<gpio_num_t>(_pin);
|
||||
config.mem_block_num = 1;
|
||||
config.tx_config.loop_en = false;
|
||||
|
||||
config.tx_config.idle_output_en = true;
|
||||
config.tx_config.idle_level = T_SPEED::IdleLevel;
|
||||
|
||||
config.tx_config.carrier_en = false;
|
||||
config.tx_config.carrier_level = RMT_CARRIER_LEVEL_LOW;
|
||||
|
||||
config.clk_div = T_SPEED::RmtClockDivider;
|
||||
|
||||
ESP_ERROR_CHECK(rmt_config(&config));
|
||||
ESP_ERROR_CHECK(rmt_driver_install(T_CHANNEL::RmtChannelNumber, 0, ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_LEVEL1));
|
||||
ESP_ERROR_CHECK(rmt_translator_init(T_CHANNEL::RmtChannelNumber, T_SPEED::Translate));
|
||||
}
|
||||
|
||||
void Update(bool maintainBufferConsistency)
|
||||
{
|
||||
// wait for not actively sending data
|
||||
// this will time out at 10 seconds, an arbitrarily long period of time
|
||||
// and do nothing if this happens
|
||||
if (ESP_OK == ESP_ERROR_CHECK_WITHOUT_ABORT(rmt_wait_tx_done(T_CHANNEL::RmtChannelNumber, 10000 / portTICK_PERIOD_MS)))
|
||||
{
|
||||
// now start the RMT transmit with the editing buffer before we swap
|
||||
ESP_ERROR_CHECK_WITHOUT_ABORT(rmt_write_sample(T_CHANNEL::RmtChannelNumber, _dataEditing, _sizeData, false));
|
||||
|
||||
if (maintainBufferConsistency)
|
||||
{
|
||||
// copy editing to sending,
|
||||
// this maintains the contract that "colors present before will
|
||||
// be the same after", otherwise GetPixelColor will be inconsistent
|
||||
memcpy(_dataSending, _dataEditing, _sizeData);
|
||||
}
|
||||
|
||||
// swap so the user can modify without affecting the async operation
|
||||
std::swap(_dataSending, _dataEditing);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t* getData() const
|
||||
{
|
||||
return _dataEditing;
|
||||
};
|
||||
|
||||
size_t getDataSize() const
|
||||
{
|
||||
return _sizeData;
|
||||
}
|
||||
|
||||
private:
|
||||
const size_t _sizeData; // Size of '_data*' buffers
|
||||
const uint8_t _pin; // output pin number
|
||||
|
||||
// Holds data stream which include LED color values and other settings as needed
|
||||
uint8_t* _dataEditing; // exposed for get and set
|
||||
uint8_t* _dataSending; // used for async send using RMT
|
||||
};
|
||||
|
||||
// normal
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedWs2811, NeoEsp32RmtChannel0> NeoEsp32Rmt0Ws2811Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedWs2812x, NeoEsp32RmtChannel0> NeoEsp32Rmt0Ws2812xMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedSk6812, NeoEsp32RmtChannel0> NeoEsp32Rmt0Sk6812Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTm1814, NeoEsp32RmtChannel0> NeoEsp32Rmt0Tm1814Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedApa106, NeoEsp32RmtChannel0> NeoEsp32Rmt0Apa106Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeed800Kbps, NeoEsp32RmtChannel0> NeoEsp32Rmt0800KbpsMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeed400Kbps, NeoEsp32RmtChannel0> NeoEsp32Rmt0400KbpsMethod;
|
||||
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedWs2811, NeoEsp32RmtChannel1> NeoEsp32Rmt1Ws2811Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedWs2812x, NeoEsp32RmtChannel1> NeoEsp32Rmt1Ws2812xMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedSk6812, NeoEsp32RmtChannel1> NeoEsp32Rmt1Sk6812Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTm1814, NeoEsp32RmtChannel1> NeoEsp32Rmt1Tm1814Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedApa106, NeoEsp32RmtChannel1> NeoEsp32Rmt1Apa106Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeed800Kbps, NeoEsp32RmtChannel1> NeoEsp32Rmt1800KbpsMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeed400Kbps, NeoEsp32RmtChannel1> NeoEsp32Rmt1400KbpsMethod;
|
||||
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedWs2811, NeoEsp32RmtChannel2> NeoEsp32Rmt2Ws2811Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedWs2812x, NeoEsp32RmtChannel2> NeoEsp32Rmt2Ws2812xMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedSk6812, NeoEsp32RmtChannel2> NeoEsp32Rmt2Sk6812Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTm1814, NeoEsp32RmtChannel2> NeoEsp32Rmt2Tm1814Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedApa106, NeoEsp32RmtChannel2> NeoEsp32Rmt2Apa106Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeed800Kbps, NeoEsp32RmtChannel2> NeoEsp32Rmt2800KbpsMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeed400Kbps, NeoEsp32RmtChannel2> NeoEsp32Rmt2400KbpsMethod;
|
||||
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedWs2811, NeoEsp32RmtChannel3> NeoEsp32Rmt3Ws2811Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedWs2812x, NeoEsp32RmtChannel3> NeoEsp32Rmt3Ws2812xMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedSk6812, NeoEsp32RmtChannel3> NeoEsp32Rmt3Sk6812Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTm1814, NeoEsp32RmtChannel3> NeoEsp32Rmt3Tm1814Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedApa106, NeoEsp32RmtChannel3> NeoEsp32Rmt3Apa106Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeed800Kbps, NeoEsp32RmtChannel3> NeoEsp32Rmt3800KbpsMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeed400Kbps, NeoEsp32RmtChannel3> NeoEsp32Rmt3400KbpsMethod;
|
||||
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
// (RMT_CHANNEL_MAX == 8)
|
||||
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedWs2811, NeoEsp32RmtChannel4> NeoEsp32Rmt4Ws2811Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedWs2812x, NeoEsp32RmtChannel4> NeoEsp32Rmt4Ws2812xMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedSk6812, NeoEsp32RmtChannel4> NeoEsp32Rmt4Sk6812Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTm1814, NeoEsp32RmtChannel4> NeoEsp32Rmt4Tm1814Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedApa106, NeoEsp32RmtChannel4> NeoEsp32Rmt4Apa106Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeed800Kbps, NeoEsp32RmtChannel4> NeoEsp32Rmt4800KbpsMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeed400Kbps, NeoEsp32RmtChannel4> NeoEsp32Rmt4400KbpsMethod;
|
||||
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedWs2811, NeoEsp32RmtChannel5> NeoEsp32Rmt5Ws2811Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedWs2812x, NeoEsp32RmtChannel5> NeoEsp32Rmt5Ws2812xMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedSk6812, NeoEsp32RmtChannel5> NeoEsp32Rmt5Sk6812Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTm1814, NeoEsp32RmtChannel5> NeoEsp32Rmt5Tm1814Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedApa106, NeoEsp32RmtChannel5> NeoEsp32Rmt5Apa106Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeed800Kbps, NeoEsp32RmtChannel5> NeoEsp32Rmt5800KbpsMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeed400Kbps, NeoEsp32RmtChannel5> NeoEsp32Rmt5400KbpsMethod;
|
||||
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedWs2811, NeoEsp32RmtChannel6> NeoEsp32Rmt6Ws2811Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedWs2812x, NeoEsp32RmtChannel6> NeoEsp32Rmt6Ws2812xMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedSk6812, NeoEsp32RmtChannel6> NeoEsp32Rmt6Sk6812Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTm1814, NeoEsp32RmtChannel6> NeoEsp32Rmt6Tm1814Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedApa106, NeoEsp32RmtChannel6> NeoEsp32Rmt6Apa106Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeed800Kbps, NeoEsp32RmtChannel6> NeoEsp32Rmt6800KbpsMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeed400Kbps, NeoEsp32RmtChannel6> NeoEsp32Rmt6400KbpsMethod;
|
||||
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedWs2811, NeoEsp32RmtChannel7> NeoEsp32Rmt7Ws2811Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedWs2812x, NeoEsp32RmtChannel7> NeoEsp32Rmt7Ws2812xMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedSk6812, NeoEsp32RmtChannel7> NeoEsp32Rmt7Sk6812Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTm1814, NeoEsp32RmtChannel7> NeoEsp32Rmt7Tm1814Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedApa106, NeoEsp32RmtChannel7> NeoEsp32Rmt7Apa106Method;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeed800Kbps, NeoEsp32RmtChannel7> NeoEsp32Rmt7800KbpsMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeed400Kbps, NeoEsp32RmtChannel7> NeoEsp32Rmt7400KbpsMethod;
|
||||
|
||||
#endif
|
||||
|
||||
// inverted
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedWs2811, NeoEsp32RmtChannel0> NeoEsp32Rmt0Ws2811InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedWs2812x, NeoEsp32RmtChannel0> NeoEsp32Rmt0Ws2812xInvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedSk6812, NeoEsp32RmtChannel0> NeoEsp32Rmt0Sk6812InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTm1814, NeoEsp32RmtChannel0> NeoEsp32Rmt0Tm1814InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedApa106, NeoEsp32RmtChannel0> NeoEsp32Rmt0Apa106InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeed800Kbps, NeoEsp32RmtChannel0> NeoEsp32Rmt0800KbpsInvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeed400Kbps, NeoEsp32RmtChannel0> NeoEsp32Rmt0400KbpsInvertedMethod;
|
||||
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedWs2811, NeoEsp32RmtChannel1> NeoEsp32Rmt1Ws2811InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedWs2812x, NeoEsp32RmtChannel1> NeoEsp32Rmt1Ws2812xInvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedSk6812, NeoEsp32RmtChannel1> NeoEsp32Rmt1Sk6812InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTm1814, NeoEsp32RmtChannel1> NeoEsp32Rmt1Tm1814InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedApa106, NeoEsp32RmtChannel1> NeoEsp32Rmt1Apa106InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeed800Kbps, NeoEsp32RmtChannel1> NeoEsp32Rmt1800KbpsInvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeed400Kbps, NeoEsp32RmtChannel1> NeoEsp32Rmt1400KbpsInvertedMethod;
|
||||
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedWs2811, NeoEsp32RmtChannel2> NeoEsp32Rmt2Ws2811InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedWs2812x, NeoEsp32RmtChannel2> NeoEsp32Rmt2Ws2812xInvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedSk6812, NeoEsp32RmtChannel2> NeoEsp32Rmt2Sk6812InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTm1814, NeoEsp32RmtChannel2> NeoEsp32Rmt2Tm1814InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedApa106, NeoEsp32RmtChannel2> NeoEsp32Rmt2Apa106InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeed800Kbps, NeoEsp32RmtChannel2> NeoEsp32Rmt2800KbpsInvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeed400Kbps, NeoEsp32RmtChannel2> NeoEsp32Rmt2400KbpsInvertedMethod;
|
||||
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedWs2811, NeoEsp32RmtChannel3> NeoEsp32Rmt3Ws2811InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedWs2812x, NeoEsp32RmtChannel3> NeoEsp32Rmt3Ws2812xInvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedSk6812, NeoEsp32RmtChannel3> NeoEsp32Rmt3Sk6812InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTm1814, NeoEsp32RmtChannel3> NeoEsp32Rmt3Tm1814InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedApa106, NeoEsp32RmtChannel3> NeoEsp32Rmt3Apa106InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeed800Kbps, NeoEsp32RmtChannel3> NeoEsp32Rmt3800KbpsInvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeed400Kbps, NeoEsp32RmtChannel3> NeoEsp32Rmt3400KbpsInvertedMethod;
|
||||
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
// (RMT_CHANNEL_MAX == 8)
|
||||
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedWs2811, NeoEsp32RmtChannel4> NeoEsp32Rmt4Ws2811InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedWs2812x, NeoEsp32RmtChannel4> NeoEsp32Rmt4Ws2812xInvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedSk6812, NeoEsp32RmtChannel4> NeoEsp32Rmt4Sk6812InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTm1814, NeoEsp32RmtChannel4> NeoEsp32Rmt4Tm1814InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedApa106, NeoEsp32RmtChannel4> NeoEsp32Rmt4Apa106InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeed800Kbps, NeoEsp32RmtChannel4> NeoEsp32Rmt4800KbpsInvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeed400Kbps, NeoEsp32RmtChannel4> NeoEsp32Rmt4400KbpsInvertedMethod;
|
||||
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedWs2811, NeoEsp32RmtChannel5> NeoEsp32Rmt5Ws2811InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedWs2812x, NeoEsp32RmtChannel5> NeoEsp32Rmt5Ws2812xInvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedSk6812, NeoEsp32RmtChannel5> NeoEsp32Rmt5Sk6812InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTm1814, NeoEsp32RmtChannel5> NeoEsp32Rmt5Tm1814InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedApa106, NeoEsp32RmtChannel5> NeoEsp32Rmt5Apa106InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeed800Kbps, NeoEsp32RmtChannel5> NeoEsp32Rmt5800KbpsInvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeed400Kbps, NeoEsp32RmtChannel5> NeoEsp32Rmt5400KbpsInvertedMethod;
|
||||
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedWs2811, NeoEsp32RmtChannel6> NeoEsp32Rmt6Ws2811InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedWs2812x, NeoEsp32RmtChannel6> NeoEsp32Rmt6Ws2812xInvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedSk6812, NeoEsp32RmtChannel6> NeoEsp32Rmt6Sk6812InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTm1814, NeoEsp32RmtChannel6> NeoEsp32Rmt6Tm1814InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedApa106, NeoEsp32RmtChannel6> NeoEsp32Rmt6Apa106InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeed800Kbps, NeoEsp32RmtChannel6> NeoEsp32Rmt6800KbpsInvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeed400Kbps, NeoEsp32RmtChannel6> NeoEsp32Rmt6400KbpsInvertedMethod;
|
||||
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedWs2811, NeoEsp32RmtChannel7> NeoEsp32Rmt7Ws2811InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedWs2812x, NeoEsp32RmtChannel7> NeoEsp32Rmt7Ws2812xInvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedSk6812, NeoEsp32RmtChannel7> NeoEsp32Rmt7Sk6812InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTm1814, NeoEsp32RmtChannel7> NeoEsp32Rmt7Tm1814InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedApa106, NeoEsp32RmtChannel7> NeoEsp32Rmt7Apa106InvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeed800Kbps, NeoEsp32RmtChannel7> NeoEsp32Rmt7800KbpsInvertedMethod;
|
||||
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeed400Kbps, NeoEsp32RmtChannel7> NeoEsp32Rmt7400KbpsInvertedMethod;
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
// (RMT_CHANNEL_MAX == 8)
|
||||
// due to a core issue where requests to send aren't consistent with I2s, RMT ch6 is temporarily the default
|
||||
// RMT channel 6 method is the default method for Esp32
|
||||
typedef NeoEsp32Rmt6Ws2812xMethod NeoWs2813Method;
|
||||
typedef NeoEsp32Rmt6Ws2812xMethod NeoWs2812xMethod;
|
||||
typedef NeoEsp32Rmt6800KbpsMethod NeoWs2812Method;
|
||||
typedef NeoEsp32Rmt6Ws2812xMethod NeoWs2811Method;
|
||||
typedef NeoEsp32Rmt6Sk6812Method NeoSk6812Method;
|
||||
typedef NeoEsp32Rmt6Tm1814Method NeoTm1814Method;
|
||||
typedef NeoEsp32Rmt6Sk6812Method NeoLc8812Method;
|
||||
typedef NeoEsp32Rmt6Apa106Method NeoApa106Method;
|
||||
|
||||
typedef NeoEsp32Rmt6Ws2812xMethod Neo800KbpsMethod;
|
||||
typedef NeoEsp32Rmt6400KbpsMethod Neo400KbpsMethod;
|
||||
|
||||
typedef NeoEsp32Rmt6Ws2812xInvertedMethod NeoWs2813InvertedMethod;
|
||||
typedef NeoEsp32Rmt6Ws2812xInvertedMethod NeoWs2812xInvertedMethod;
|
||||
typedef NeoEsp32Rmt6Ws2812xInvertedMethod NeoWs2811InvertedMethod;
|
||||
typedef NeoEsp32Rmt6800KbpsInvertedMethod NeoWs2812InvertedMethod;
|
||||
typedef NeoEsp32Rmt6Sk6812InvertedMethod NeoSk6812InvertedMethod;
|
||||
typedef NeoEsp32Rmt6Tm1814InvertedMethod NeoTm1814InvertedMethod;
|
||||
typedef NeoEsp32Rmt6Sk6812InvertedMethod NeoLc8812InvertedMethod;
|
||||
typedef NeoEsp32Rmt6Apa106InvertedMethod NeoApa106InvertedMethod;
|
||||
|
||||
typedef NeoEsp32Rmt6Ws2812xInvertedMethod Neo800KbpsInvertedMethod;
|
||||
typedef NeoEsp32Rmt6400KbpsInvertedMethod Neo400KbpsInvertedMethod;
|
||||
#else
|
||||
|
||||
// due to a core issue where requests to send aren't consistent with I2s, RMT ch3 is temporarily the default
|
||||
// RMT channel 3 method is the default method for Esp32S2
|
||||
typedef NeoEsp32Rmt3Ws2812xMethod NeoWs2813Method;
|
||||
typedef NeoEsp32Rmt3Ws2812xMethod NeoWs2812xMethod;
|
||||
typedef NeoEsp32Rmt3800KbpsMethod NeoWs2812Method;
|
||||
typedef NeoEsp32Rmt3Ws2812xMethod NeoWs2811Method;
|
||||
typedef NeoEsp32Rmt3Sk6812Method NeoSk6812Method;
|
||||
typedef NeoEsp32Rmt3Tm1814Method NeoTm1814Method;
|
||||
typedef NeoEsp32Rmt3Sk6812Method NeoLc8812Method;
|
||||
typedef NeoEsp32Rmt3Apa106Method NeoApa106Method;
|
||||
|
||||
typedef NeoEsp32Rmt3Ws2812xMethod Neo800KbpsMethod;
|
||||
typedef NeoEsp32Rmt3400KbpsMethod Neo400KbpsMethod;
|
||||
|
||||
typedef NeoEsp32Rmt3Ws2812xInvertedMethod NeoWs2813InvertedMethod;
|
||||
typedef NeoEsp32Rmt3Ws2812xInvertedMethod NeoWs2812xInvertedMethod;
|
||||
typedef NeoEsp32Rmt3Ws2812xInvertedMethod NeoWs2811InvertedMethod;
|
||||
typedef NeoEsp32Rmt3800KbpsInvertedMethod NeoWs2812InvertedMethod;
|
||||
typedef NeoEsp32Rmt3Sk6812InvertedMethod NeoSk6812InvertedMethod;
|
||||
typedef NeoEsp32Rmt3Tm1814InvertedMethod NeoTm1814InvertedMethod;
|
||||
typedef NeoEsp32Rmt3Sk6812InvertedMethod NeoLc8812InvertedMethod;
|
||||
typedef NeoEsp32Rmt3Apa106InvertedMethod NeoApa106InvertedMethod;
|
||||
|
||||
typedef NeoEsp32Rmt3Ws2812xInvertedMethod Neo800KbpsInvertedMethod;
|
||||
typedef NeoEsp32Rmt3400KbpsInvertedMethod Neo400KbpsInvertedMethod;
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
573
lib/NeoPixelBus_by_Makuna/src/internal/NeoEsp8266DmaMethod.h
Normal file
573
lib/NeoPixelBus_by_Makuna/src/internal/NeoEsp8266DmaMethod.h
Normal file
@@ -0,0 +1,573 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
NeoPixel library helper functions for Esp8266.
|
||||
|
||||
|
||||
Written by Michael C. Miller.
|
||||
Thanks to g3gg0.de for porting the initial DMA support which lead to this.
|
||||
Thanks to github/cnlohr for the original work on DMA support, which opend
|
||||
all our minds to a better way (located at https://github.com/cnlohr/esp8266ws2812i2s).
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef ARDUINO_ARCH_ESP8266
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "Arduino.h"
|
||||
#include "osapi.h"
|
||||
#include "ets_sys.h"
|
||||
|
||||
#include "i2s_reg.h"
|
||||
#include "i2s.h"
|
||||
#include "eagle_soc.h"
|
||||
#include "esp8266_peri.h"
|
||||
#include "slc_register.h"
|
||||
|
||||
#include "osapi.h"
|
||||
#include "ets_sys.h"
|
||||
#include "user_interface.h"
|
||||
|
||||
#if !defined(__CORE_ESP8266_VERSION_H) || defined(ARDUINO_ESP8266_RELEASE_2_5_0)
|
||||
void rom_i2c_writeReg_Mask(uint32_t block, uint32_t host_id, uint32_t reg_add, uint32_t Msb, uint32_t Lsb, uint32_t indata);
|
||||
#endif
|
||||
}
|
||||
|
||||
struct slc_queue_item
|
||||
{
|
||||
uint32 blocksize : 12;
|
||||
uint32 datalen : 12;
|
||||
uint32 unused : 5;
|
||||
uint32 sub_sof : 1;
|
||||
uint32 eof : 1;
|
||||
uint32 owner : 1;
|
||||
uint32 buf_ptr;
|
||||
uint32 next_link_ptr;
|
||||
};
|
||||
|
||||
class NeoEsp8266DmaSpeedBase
|
||||
{
|
||||
public:
|
||||
static const uint8_t Level = 0x00;
|
||||
static uint16_t Convert(uint8_t value)
|
||||
{
|
||||
const uint16_t bitpatterns[16] =
|
||||
{
|
||||
0b1000100010001000, 0b1000100010001110, 0b1000100011101000, 0b1000100011101110,
|
||||
0b1000111010001000, 0b1000111010001110, 0b1000111011101000, 0b1000111011101110,
|
||||
0b1110100010001000, 0b1110100010001110, 0b1110100011101000, 0b1110100011101110,
|
||||
0b1110111010001000, 0b1110111010001110, 0b1110111011101000, 0b1110111011101110,
|
||||
};
|
||||
|
||||
return bitpatterns[value];
|
||||
}
|
||||
};
|
||||
|
||||
class NeoEsp8266DmaInvertedSpeedBase
|
||||
{
|
||||
public:
|
||||
static const uint8_t Level = 0xFF;
|
||||
static uint16_t Convert(uint8_t value)
|
||||
{
|
||||
const uint16_t bitpatterns[16] =
|
||||
{
|
||||
0b0111011101110111, 0b0111011101110001, 0b0111011100010111, 0b0111011100010001,
|
||||
0b0111000101110111, 0b0111000101110001, 0b0111000100010111, 0b0111000100010001,
|
||||
0b0001011101110111, 0b0001011101110001, 0b0001011100010111, 0b0001011100010001,
|
||||
0b0001000101110111, 0b0001000101110001, 0b0001000100010111, 0b0001000100010001,
|
||||
};
|
||||
|
||||
return bitpatterns[value];
|
||||
}
|
||||
};
|
||||
|
||||
class NeoEsp8266DmaSpeed800KbpsBase : public NeoEsp8266DmaSpeedBase
|
||||
{
|
||||
public:
|
||||
const static uint32_t I2sClockDivisor = 3;
|
||||
const static uint32_t I2sBaseClockDivisor = 16;
|
||||
const static uint32_t ByteSendTimeUs = 10; // us it takes to send a single pixel element at 800khz speed
|
||||
};
|
||||
|
||||
class NeoEsp8266DmaSpeedWs2812x : public NeoEsp8266DmaSpeed800KbpsBase
|
||||
{
|
||||
public:
|
||||
const static uint32_t ResetTimeUs = 300;
|
||||
};
|
||||
|
||||
class NeoEsp8266DmaSpeedSk6812 : public NeoEsp8266DmaSpeed800KbpsBase
|
||||
{
|
||||
public:
|
||||
const static uint32_t ResetTimeUs = 80;
|
||||
};
|
||||
|
||||
class NeoEsp8266DmaInvertedSpeedTm1814 : public NeoEsp8266DmaSpeed800KbpsBase
|
||||
{
|
||||
public:
|
||||
const static uint32_t ResetTimeUs = 200;
|
||||
};
|
||||
|
||||
class NeoEsp8266DmaSpeed800Kbps : public NeoEsp8266DmaSpeed800KbpsBase
|
||||
{
|
||||
public:
|
||||
const static uint32_t ResetTimeUs = 50;
|
||||
};
|
||||
|
||||
class NeoEsp8266DmaSpeed400Kbps : public NeoEsp8266DmaSpeedBase
|
||||
{
|
||||
public:
|
||||
const static uint32_t I2sClockDivisor = 6;
|
||||
const static uint32_t I2sBaseClockDivisor = 16;
|
||||
const static uint32_t ByteSendTimeUs = 20; // us it takes to send a single pixel element at 400khz speed
|
||||
const static uint32_t ResetTimeUs = 50;
|
||||
};
|
||||
|
||||
class NeoEsp8266DmaSpeedApa106 : public NeoEsp8266DmaSpeedBase
|
||||
{
|
||||
public:
|
||||
const static uint32_t I2sClockDivisor = 4;
|
||||
const static uint32_t I2sBaseClockDivisor = 16;
|
||||
const static uint32_t ByteSendTimeUs = 17; // us it takes to send a single pixel element
|
||||
const static uint32_t ResetTimeUs = 50;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class NeoEsp8266DmaInvertedSpeed800KbpsBase : public NeoEsp8266DmaInvertedSpeedBase
|
||||
{
|
||||
public:
|
||||
const static uint32_t I2sClockDivisor = 3;
|
||||
const static uint32_t I2sBaseClockDivisor = 16;
|
||||
const static uint32_t ByteSendTimeUs = 10; // us it takes to send a single pixel element at 800khz speed
|
||||
};
|
||||
|
||||
class NeoEsp8266DmaInvertedSpeedWs2812x : public NeoEsp8266DmaInvertedSpeed800KbpsBase
|
||||
{
|
||||
public:
|
||||
const static uint32_t ResetTimeUs = 300;
|
||||
};
|
||||
|
||||
class NeoEsp8266DmaInvertedSpeedSk6812 : public NeoEsp8266DmaInvertedSpeed800KbpsBase
|
||||
{
|
||||
public:
|
||||
const static uint32_t ResetTimeUs = 80;
|
||||
};
|
||||
|
||||
class NeoEsp8266DmaSpeedTm1814 : public NeoEsp8266DmaInvertedSpeed800KbpsBase
|
||||
{
|
||||
public:
|
||||
const static uint32_t ResetTimeUs = 200;
|
||||
};
|
||||
|
||||
class NeoEsp8266DmaInvertedSpeed800Kbps : public NeoEsp8266DmaInvertedSpeed800KbpsBase
|
||||
{
|
||||
public:
|
||||
const static uint32_t ResetTimeUs = 50;
|
||||
};
|
||||
|
||||
class NeoEsp8266DmaInvertedSpeed400Kbps : public NeoEsp8266DmaInvertedSpeedBase
|
||||
{
|
||||
public:
|
||||
const static uint32_t I2sClockDivisor = 6;
|
||||
const static uint32_t I2sBaseClockDivisor = 16;
|
||||
const static uint32_t ByteSendTimeUs = 20; // us it takes to send a single pixel element at 400khz speed
|
||||
const static uint32_t ResetTimeUs = 50;
|
||||
};
|
||||
|
||||
class NeoEsp8266DmaInvertedSpeedApa106 : public NeoEsp8266DmaInvertedSpeedBase
|
||||
{
|
||||
public:
|
||||
const static uint32_t I2sClockDivisor = 4;
|
||||
const static uint32_t I2sBaseClockDivisor = 16;
|
||||
const static uint32_t ByteSendTimeUs = 17; // us it takes to send a single pixel element
|
||||
const static uint32_t ResetTimeUs = 50;
|
||||
};
|
||||
|
||||
enum NeoDmaState
|
||||
{
|
||||
NeoDmaState_Idle,
|
||||
NeoDmaState_Pending,
|
||||
NeoDmaState_Sending,
|
||||
NeoDmaState_Zeroing,
|
||||
};
|
||||
const uint16_t c_maxDmaBlockSize = 4095;
|
||||
const uint16_t c_dmaBytesPerPixelBytes = 4;
|
||||
const uint8_t c_I2sPin = 3; // due to I2S hardware, the pin used is restricted to this
|
||||
|
||||
template<typename T_SPEED> class NeoEsp8266DmaMethodBase
|
||||
{
|
||||
public:
|
||||
NeoEsp8266DmaMethodBase(uint16_t pixelCount, size_t elementSize, size_t settingsSize) :
|
||||
_sizeData(pixelCount * elementSize + settingsSize)
|
||||
{
|
||||
uint16_t dmaPixelSize = c_dmaBytesPerPixelBytes * elementSize;
|
||||
uint16_t dmaSettingsSize = c_dmaBytesPerPixelBytes * settingsSize;
|
||||
|
||||
_i2sBufferSize = pixelCount * dmaPixelSize + dmaSettingsSize;
|
||||
|
||||
_data = static_cast<uint8_t*>(malloc(_sizeData));
|
||||
memset(_data, 0x00, _sizeData);
|
||||
|
||||
_i2sBuffer = static_cast<uint8_t*>(malloc(_i2sBufferSize));
|
||||
memset(_i2sBuffer, T_SPEED::Level, _i2sBufferSize);
|
||||
|
||||
// _i2sBuffer[0] = 0b11101000; // debug, 1 bit then 0 bit
|
||||
|
||||
memset(_i2sZeroes, T_SPEED::Level, sizeof(_i2sZeroes));
|
||||
|
||||
_is2BufMaxBlockSize = (c_maxDmaBlockSize / dmaPixelSize) * dmaPixelSize;
|
||||
|
||||
_i2sBufDescCount = (_i2sBufferSize / _is2BufMaxBlockSize) + 1 + 2; // need two more for state/latch blocks
|
||||
_i2sBufDesc = (slc_queue_item*)malloc(_i2sBufDescCount * sizeof(slc_queue_item));
|
||||
|
||||
s_this = this; // store this for the ISR
|
||||
}
|
||||
|
||||
NeoEsp8266DmaMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize) :
|
||||
NeoEsp8266DmaMethodBase(pixelCount, elementSize, settingsSize)
|
||||
{
|
||||
}
|
||||
|
||||
~NeoEsp8266DmaMethodBase()
|
||||
{
|
||||
uint8_t waits = 1;
|
||||
while (!IsReadyToUpdate())
|
||||
{
|
||||
waits = 2;
|
||||
yield();
|
||||
}
|
||||
|
||||
// wait for any pending sends to complete
|
||||
// due to internal i2s caching/send delays, this can more that once the data size
|
||||
uint32_t time = micros();
|
||||
while ((micros() - time) < ((getPixelTime() + T_SPEED::ResetTimeUs) * waits))
|
||||
{
|
||||
yield();
|
||||
}
|
||||
|
||||
StopDma();
|
||||
|
||||
s_this = nullptr;
|
||||
pinMode(c_I2sPin, INPUT);
|
||||
|
||||
free(_data);
|
||||
free(_i2sBuffer);
|
||||
free(_i2sBufDesc);
|
||||
}
|
||||
|
||||
bool IsReadyToUpdate() const
|
||||
{
|
||||
return (_dmaState == NeoDmaState_Idle);
|
||||
}
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
StopDma();
|
||||
|
||||
pinMode(c_I2sPin, FUNCTION_1); // I2S0_DATA
|
||||
|
||||
uint8_t* is2Buffer = _i2sBuffer;
|
||||
uint32_t is2BufferSize = _i2sBufferSize;
|
||||
uint16_t indexDesc;
|
||||
|
||||
// prepare main data block decriptors that point into our one static dma buffer
|
||||
for (indexDesc = 0; indexDesc < (_i2sBufDescCount - 2); indexDesc++)
|
||||
{
|
||||
uint32_t blockSize = (is2BufferSize > _is2BufMaxBlockSize) ? _is2BufMaxBlockSize : is2BufferSize;
|
||||
|
||||
_i2sBufDesc[indexDesc].owner = 1;
|
||||
_i2sBufDesc[indexDesc].eof = 0; // no need to trigger interrupt generally
|
||||
_i2sBufDesc[indexDesc].sub_sof = 0;
|
||||
_i2sBufDesc[indexDesc].datalen = blockSize;
|
||||
_i2sBufDesc[indexDesc].blocksize = blockSize;
|
||||
_i2sBufDesc[indexDesc].buf_ptr = (uint32_t)is2Buffer;
|
||||
_i2sBufDesc[indexDesc].unused = 0;
|
||||
_i2sBufDesc[indexDesc].next_link_ptr = (uint32_t)&(_i2sBufDesc[indexDesc + 1]);
|
||||
|
||||
is2Buffer += blockSize;
|
||||
is2BufferSize -= blockSize;
|
||||
}
|
||||
|
||||
// prepare the two state/latch descriptors
|
||||
for (; indexDesc < _i2sBufDescCount; indexDesc++)
|
||||
{
|
||||
_i2sBufDesc[indexDesc].owner = 1;
|
||||
_i2sBufDesc[indexDesc].eof = 0; // no need to trigger interrupt generally
|
||||
_i2sBufDesc[indexDesc].sub_sof = 0;
|
||||
_i2sBufDesc[indexDesc].datalen = sizeof(_i2sZeroes);
|
||||
_i2sBufDesc[indexDesc].blocksize = sizeof(_i2sZeroes);
|
||||
_i2sBufDesc[indexDesc].buf_ptr = (uint32_t)_i2sZeroes;
|
||||
_i2sBufDesc[indexDesc].unused = 0;
|
||||
_i2sBufDesc[indexDesc].next_link_ptr = (uint32_t)&(_i2sBufDesc[indexDesc + 1]);
|
||||
}
|
||||
|
||||
// the first state block will trigger the interrupt
|
||||
_i2sBufDesc[indexDesc - 2].eof = 1;
|
||||
// the last state block will loop to the first state block by defualt
|
||||
_i2sBufDesc[indexDesc - 1].next_link_ptr = (uint32_t)&(_i2sBufDesc[indexDesc - 2]);
|
||||
|
||||
// setup the rest of i2s DMA
|
||||
//
|
||||
ETS_SLC_INTR_DISABLE();
|
||||
|
||||
// start off in sending state as that is what it will be all setup to be
|
||||
// for the interrupt
|
||||
_dmaState = NeoDmaState_Sending;
|
||||
|
||||
SLCC0 |= SLCRXLR | SLCTXLR;
|
||||
SLCC0 &= ~(SLCRXLR | SLCTXLR);
|
||||
SLCIC = 0xFFFFFFFF;
|
||||
|
||||
// Configure DMA
|
||||
SLCC0 &= ~(SLCMM << SLCM); // clear DMA MODE
|
||||
SLCC0 |= (1 << SLCM); // set DMA MODE to 1
|
||||
SLCRXDC |= SLCBINR | SLCBTNR; // enable INFOR_NO_REPLACE and TOKEN_NO_REPLACE
|
||||
SLCRXDC &= ~(SLCBRXFE | SLCBRXEM | SLCBRXFM); // disable RX_FILL, RX_EOF_MODE and RX_FILL_MODE
|
||||
|
||||
// Feed DMA the 1st buffer desc addr
|
||||
// To send data to the I2S subsystem, counter-intuitively we use the RXLINK part, not the TXLINK as you might
|
||||
// expect. The TXLINK part still needs a valid DMA descriptor, even if it's unused: the DMA engine will throw
|
||||
// an error at us otherwise. Just feed it any random descriptor.
|
||||
SLCTXL &= ~(SLCTXLAM << SLCTXLA); // clear TX descriptor address
|
||||
// set TX descriptor address. any random desc is OK, we don't use TX but it needs to be valid
|
||||
SLCTXL |= (uint32)&(_i2sBufDesc[_i2sBufDescCount-1]) << SLCTXLA;
|
||||
SLCRXL &= ~(SLCRXLAM << SLCRXLA); // clear RX descriptor address
|
||||
// set RX descriptor address. use first of the data addresses
|
||||
SLCRXL |= (uint32)&(_i2sBufDesc[0]) << SLCRXLA;
|
||||
|
||||
ETS_SLC_INTR_ATTACH(i2s_slc_isr, NULL);
|
||||
SLCIE = SLCIRXEOF; // Enable only for RX EOF interrupt
|
||||
|
||||
ETS_SLC_INTR_ENABLE();
|
||||
|
||||
//Start transmission
|
||||
SLCTXL |= SLCTXLS;
|
||||
SLCRXL |= SLCRXLS;
|
||||
|
||||
I2S_CLK_ENABLE();
|
||||
I2SIC = 0x3F;
|
||||
I2SIE = 0;
|
||||
|
||||
//Reset I2S
|
||||
I2SC &= ~(I2SRST);
|
||||
I2SC |= I2SRST;
|
||||
I2SC &= ~(I2SRST);
|
||||
|
||||
// Set RX/TX FIFO_MOD=0 and disable DMA (FIFO only)
|
||||
I2SFC &= ~(I2SDE | (I2STXFMM << I2STXFM) | (I2SRXFMM << I2SRXFM));
|
||||
I2SFC |= I2SDE; //Enable DMA
|
||||
// Set RX/TX CHAN_MOD=0
|
||||
I2SCC &= ~((I2STXCMM << I2STXCM) | (I2SRXCMM << I2SRXCM));
|
||||
|
||||
// set the rate
|
||||
uint32_t i2s_clock_div = T_SPEED::I2sClockDivisor & I2SCDM;
|
||||
uint8_t i2s_bck_div = T_SPEED::I2sBaseClockDivisor & I2SBDM;
|
||||
|
||||
//!trans master, !bits mod, rece slave mod, rece msb shift, right first, msb right
|
||||
I2SC &= ~(I2STSM | I2SRSM | (I2SBMM << I2SBM) | (I2SBDM << I2SBD) | (I2SCDM << I2SCD));
|
||||
I2SC |= I2SRF | I2SMR | I2SRSM | I2SRMS | (i2s_bck_div << I2SBD) | (i2s_clock_div << I2SCD);
|
||||
|
||||
I2SC |= I2STXS; // Start transmission
|
||||
}
|
||||
|
||||
void ICACHE_RAM_ATTR Update(bool)
|
||||
{
|
||||
// wait for not actively sending data
|
||||
while (!IsReadyToUpdate())
|
||||
{
|
||||
yield();
|
||||
}
|
||||
FillBuffers();
|
||||
|
||||
// toggle state so the ISR reacts
|
||||
_dmaState = NeoDmaState_Pending;
|
||||
}
|
||||
|
||||
uint8_t* getData() const
|
||||
{
|
||||
return _data;
|
||||
};
|
||||
|
||||
size_t getDataSize() const
|
||||
{
|
||||
return _sizeData;
|
||||
}
|
||||
|
||||
private:
|
||||
static NeoEsp8266DmaMethodBase* s_this; // for the ISR
|
||||
|
||||
const size_t _sizeData; // Size of '_data' buffer
|
||||
uint8_t* _data; // Holds LED color values
|
||||
|
||||
size_t _i2sBufferSize; // total size of _i2sBuffer
|
||||
uint8_t* _i2sBuffer; // holds the DMA buffer that is referenced by _i2sBufDesc
|
||||
|
||||
// normally 24 bytes creates the minimum 50us latch per spec, but
|
||||
// with the new logic, this latch is used to space between mulitple states
|
||||
// buffer size = (24 * (reset time / 50)) / 6
|
||||
uint8_t _i2sZeroes[(24L * (T_SPEED::ResetTimeUs / 50L)) / 6L];
|
||||
|
||||
slc_queue_item* _i2sBufDesc; // dma block descriptors
|
||||
uint16_t _i2sBufDescCount; // count of block descriptors in _i2sBufDesc
|
||||
uint16_t _is2BufMaxBlockSize; // max size based on size of a pixel of a single block
|
||||
|
||||
volatile NeoDmaState _dmaState;
|
||||
|
||||
// This routine is called as soon as the DMA routine has something to tell us. All we
|
||||
// handle here is the RX_EOF_INT status, which indicate the DMA has sent a buffer whose
|
||||
// descriptor has the 'EOF' field set to 1.
|
||||
// in the case of this code, the second to last state descriptor
|
||||
static void ICACHE_RAM_ATTR i2s_slc_isr(void)
|
||||
{
|
||||
ETS_SLC_INTR_DISABLE();
|
||||
|
||||
uint32_t slc_intr_status = SLCIS;
|
||||
|
||||
SLCIC = 0xFFFFFFFF;
|
||||
|
||||
if ((slc_intr_status & SLCIRXEOF) && s_this)
|
||||
{
|
||||
switch (s_this->_dmaState)
|
||||
{
|
||||
case NeoDmaState_Idle:
|
||||
break;
|
||||
|
||||
case NeoDmaState_Pending:
|
||||
{
|
||||
slc_queue_item* finished_item = (slc_queue_item*)SLCRXEDA;
|
||||
|
||||
// data block has pending data waiting to send, prepare it
|
||||
// point last state block to top
|
||||
(finished_item + 1)->next_link_ptr = (uint32_t)(s_this->_i2sBufDesc);
|
||||
|
||||
s_this->_dmaState = NeoDmaState_Sending;
|
||||
}
|
||||
break;
|
||||
|
||||
case NeoDmaState_Sending:
|
||||
{
|
||||
slc_queue_item* finished_item = (slc_queue_item*)SLCRXEDA;
|
||||
|
||||
// the data block had actual data sent
|
||||
// point last state block to first state block thus
|
||||
// just looping and not sending the data blocks
|
||||
(finished_item + 1)->next_link_ptr = (uint32_t)(finished_item);
|
||||
|
||||
s_this->_dmaState = NeoDmaState_Zeroing;
|
||||
}
|
||||
break;
|
||||
|
||||
case NeoDmaState_Zeroing:
|
||||
s_this->_dmaState = NeoDmaState_Idle;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ETS_SLC_INTR_ENABLE();
|
||||
}
|
||||
|
||||
void FillBuffers()
|
||||
{
|
||||
uint16_t* pDma = (uint16_t*)_i2sBuffer;
|
||||
uint8_t* pEnd = _data + _sizeData;
|
||||
for (uint8_t* pData = _data; pData < pEnd; pData++)
|
||||
{
|
||||
*(pDma++) = T_SPEED::Convert(((*pData) & 0x0f));
|
||||
*(pDma++) = T_SPEED::Convert(((*pData) >> 4) & 0x0f);
|
||||
}
|
||||
}
|
||||
|
||||
void StopDma()
|
||||
{
|
||||
ETS_SLC_INTR_DISABLE();
|
||||
|
||||
// Disable any I2S send or receive
|
||||
I2SC &= ~(I2STXS | I2SRXS);
|
||||
|
||||
// Reset I2S
|
||||
I2SC &= ~(I2SRST);
|
||||
I2SC |= I2SRST;
|
||||
I2SC &= ~(I2SRST);
|
||||
|
||||
|
||||
SLCIC = 0xFFFFFFFF;
|
||||
SLCIE = 0;
|
||||
SLCTXL &= ~(SLCTXLAM << SLCTXLA); // clear TX descriptor address
|
||||
SLCRXL &= ~(SLCRXLAM << SLCRXLA); // clear RX descriptor address
|
||||
|
||||
pinMode(c_I2sPin, INPUT);
|
||||
}
|
||||
|
||||
uint32_t getPixelTime() const
|
||||
{
|
||||
return (T_SPEED::ByteSendTimeUs * this->_sizeData);
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
|
||||
template<typename T_SPEED>
|
||||
NeoEsp8266DmaMethodBase<T_SPEED>* NeoEsp8266DmaMethodBase<T_SPEED>::s_this;
|
||||
|
||||
// normal
|
||||
typedef NeoEsp8266DmaMethodBase<NeoEsp8266DmaSpeedWs2812x> NeoEsp8266DmaWs2812xMethod;
|
||||
typedef NeoEsp8266DmaMethodBase<NeoEsp8266DmaSpeedSk6812> NeoEsp8266DmaSk6812Method;
|
||||
typedef NeoEsp8266DmaMethodBase<NeoEsp8266DmaSpeedTm1814> NeoEsp8266DmaTm1814Method;
|
||||
typedef NeoEsp8266DmaMethodBase<NeoEsp8266DmaSpeed800Kbps> NeoEsp8266Dma800KbpsMethod;
|
||||
typedef NeoEsp8266DmaMethodBase<NeoEsp8266DmaSpeed400Kbps> NeoEsp8266Dma400KbpsMethod;
|
||||
typedef NeoEsp8266DmaMethodBase<NeoEsp8266DmaSpeedApa106> NeoEsp8266DmaApa106Method;
|
||||
|
||||
// inverted
|
||||
typedef NeoEsp8266DmaMethodBase<NeoEsp8266DmaInvertedSpeedWs2812x> NeoEsp8266DmaInvertedWs2812xMethod;
|
||||
typedef NeoEsp8266DmaMethodBase<NeoEsp8266DmaInvertedSpeedSk6812> NeoEsp8266DmaInvertedSk6812Method;
|
||||
typedef NeoEsp8266DmaMethodBase<NeoEsp8266DmaInvertedSpeedTm1814> NeoEsp8266DmaInvertedTm1814Method;
|
||||
typedef NeoEsp8266DmaMethodBase<NeoEsp8266DmaInvertedSpeed800Kbps> NeoEsp8266DmaInverted800KbpsMethod;
|
||||
typedef NeoEsp8266DmaMethodBase<NeoEsp8266DmaInvertedSpeed400Kbps> NeoEsp8266DmaInverted400KbpsMethod;
|
||||
typedef NeoEsp8266DmaMethodBase<NeoEsp8266DmaInvertedSpeedApa106> NeoEsp8266DmaInvertedApa106Method;
|
||||
|
||||
// Dma method is the default method for Esp8266
|
||||
typedef NeoEsp8266DmaWs2812xMethod NeoWs2813Method;
|
||||
typedef NeoEsp8266DmaWs2812xMethod NeoWs2812xMethod;
|
||||
typedef NeoEsp8266Dma800KbpsMethod NeoWs2812Method;
|
||||
typedef NeoEsp8266DmaWs2812xMethod NeoWs2811Method;
|
||||
typedef NeoEsp8266DmaSk6812Method NeoSk6812Method;
|
||||
typedef NeoEsp8266DmaTm1814Method NeoTm1814Method;
|
||||
typedef NeoEsp8266DmaSk6812Method NeoLc8812Method;
|
||||
typedef NeoEsp8266DmaApa106Method NeoApa106Method;
|
||||
|
||||
typedef NeoEsp8266DmaWs2812xMethod Neo800KbpsMethod;
|
||||
typedef NeoEsp8266Dma400KbpsMethod Neo400KbpsMethod;
|
||||
|
||||
// inverted
|
||||
typedef NeoEsp8266DmaInvertedWs2812xMethod NeoWs2813InvertedMethod;
|
||||
typedef NeoEsp8266DmaInvertedWs2812xMethod NeoWs2812xInvertedMethod;
|
||||
typedef NeoEsp8266DmaInverted800KbpsMethod NeoWs2812InvertedMethod;
|
||||
typedef NeoEsp8266DmaInvertedWs2812xMethod NeoWs2811InvertedMethod;
|
||||
typedef NeoEsp8266DmaInvertedSk6812Method NeoSk6812InvertedMethod;
|
||||
typedef NeoEsp8266DmaInvertedTm1814Method NeoTm1814InvertedMethod;
|
||||
typedef NeoEsp8266DmaInvertedSk6812Method NeoLc8812InvertedMethod;
|
||||
typedef NeoEsp8266DmaInvertedApa106Method NeoApa106InvertedMethod;
|
||||
|
||||
typedef NeoEsp8266DmaInvertedWs2812xMethod Neo800KbpsInvertedMethod;
|
||||
typedef NeoEsp8266DmaInverted400KbpsMethod Neo400KbpsInvertedMethod;
|
||||
#endif
|
||||
171
lib/NeoPixelBus_by_Makuna/src/internal/NeoEsp8266UartMethod.cpp
Normal file
171
lib/NeoPixelBus_by_Makuna/src/internal/NeoEsp8266UartMethod.cpp
Normal file
@@ -0,0 +1,171 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
NeoPixel library helper functions for Esp8266 UART hardware
|
||||
|
||||
Written by Michael C. Miller.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
|
||||
#ifdef ARDUINO_ARCH_ESP8266
|
||||
#include "NeoEsp8266UartMethod.h"
|
||||
#include <utility>
|
||||
extern "C"
|
||||
{
|
||||
#include <ets_sys.h>
|
||||
}
|
||||
|
||||
const volatile uint8_t* ICACHE_RAM_ATTR NeoEsp8266UartContext::FillUartFifo(uint8_t uartNum,
|
||||
const volatile uint8_t* start,
|
||||
const volatile uint8_t* end)
|
||||
{
|
||||
// Remember: UARTs send less significant bit (LSB) first so
|
||||
// pushing ABCDEF byte will generate a 0FEDCBA1 signal,
|
||||
// including a LOW(0) start & a HIGH(1) stop bits.
|
||||
// Also, we have configured UART to invert logic levels, so:
|
||||
const uint8_t _uartData[4] = {
|
||||
0b110111, // On wire: 1 000 100 0 [Neopixel reads 00]
|
||||
0b000111, // On wire: 1 000 111 0 [Neopixel reads 01]
|
||||
0b110100, // On wire: 1 110 100 0 [Neopixel reads 10]
|
||||
0b000100, // On wire: 1 110 111 0 [NeoPixel reads 11]
|
||||
};
|
||||
uint8_t avail = (UART_TX_FIFO_SIZE - GetTxFifoLength(uartNum)) / 4;
|
||||
if (end - start > avail)
|
||||
{
|
||||
end = start + avail;
|
||||
}
|
||||
while (start < end)
|
||||
{
|
||||
uint8_t subpix = *start++;
|
||||
Enqueue(uartNum, _uartData[(subpix >> 6) & 0x3]);
|
||||
Enqueue(uartNum, _uartData[(subpix >> 4) & 0x3]);
|
||||
Enqueue(uartNum, _uartData[(subpix >> 2) & 0x3]);
|
||||
Enqueue(uartNum, _uartData[subpix & 0x3]);
|
||||
}
|
||||
return start;
|
||||
}
|
||||
|
||||
volatile NeoEsp8266UartInterruptContext* NeoEsp8266UartInterruptContext::s_uartInteruptContext[] = { nullptr, nullptr };
|
||||
|
||||
void NeoEsp8266UartInterruptContext::StartSending(uint8_t uartNum, uint8_t* start, uint8_t* end)
|
||||
{
|
||||
// send the pixels asynchronously
|
||||
_asyncBuff = start;
|
||||
_asyncBuffEnd = end;
|
||||
|
||||
// enable the transmit interrupt
|
||||
USIE(uartNum) |= (1 << UIFE);
|
||||
}
|
||||
|
||||
void NeoEsp8266UartInterruptContext::Attach(uint8_t uartNum)
|
||||
{
|
||||
// Disable all interrupts
|
||||
ETS_UART_INTR_DISABLE();
|
||||
|
||||
// Clear the RX & TX FIFOS
|
||||
const uint32_t fifoResetFlags = (1 << UCTXRST) | (1 << UCRXRST);
|
||||
USC0(uartNum) |= fifoResetFlags;
|
||||
USC0(uartNum) &= ~(fifoResetFlags);
|
||||
|
||||
// attach the ISR if needed
|
||||
if (s_uartInteruptContext[0] == nullptr &&
|
||||
s_uartInteruptContext[1] == nullptr)
|
||||
{
|
||||
ETS_UART_INTR_ATTACH(Isr, s_uartInteruptContext);
|
||||
}
|
||||
|
||||
// attach the context
|
||||
s_uartInteruptContext[uartNum] = this;
|
||||
|
||||
// Set tx fifo trigger. 80 bytes gives us 200 microsecs to refill the FIFO
|
||||
USC1(uartNum) = (80 << UCFET);
|
||||
|
||||
// Disable RX & TX interrupts. It maybe still enabled by uart.c in the SDK
|
||||
USIE(uartNum) &= ~((1 << UIFF) | (1 << UIFE));
|
||||
|
||||
// Clear all pending interrupts in UART1
|
||||
USIC(uartNum) = 0xffff;
|
||||
|
||||
// Reenable interrupts
|
||||
ETS_UART_INTR_ENABLE();
|
||||
}
|
||||
|
||||
void NeoEsp8266UartInterruptContext::Detach(uint8_t uartNum)
|
||||
{
|
||||
// Disable interrupts
|
||||
ETS_UART_INTR_DISABLE();
|
||||
|
||||
if (s_uartInteruptContext[uartNum] != nullptr)
|
||||
{
|
||||
// turn off uart
|
||||
USC1(uartNum) = 0;
|
||||
USIC(uartNum) = 0xffff;
|
||||
USIE(uartNum) = 0;
|
||||
|
||||
s_uartInteruptContext[uartNum] = nullptr;
|
||||
|
||||
if (s_uartInteruptContext[0] == nullptr &&
|
||||
s_uartInteruptContext[1] == nullptr)
|
||||
{
|
||||
// detach our ISR
|
||||
ETS_UART_INTR_ATTACH(NULL, NULL);
|
||||
|
||||
// return so we don't enable interrupts since there is no ISR anymore
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Reenable interrupts
|
||||
ETS_UART_INTR_ENABLE();
|
||||
}
|
||||
|
||||
void ICACHE_RAM_ATTR NeoEsp8266UartInterruptContext::Isr(void* param)
|
||||
{
|
||||
// make sure this is for us
|
||||
if (param == s_uartInteruptContext)
|
||||
{
|
||||
// Interrupt handler is shared between UART0 & UART1
|
||||
// so we need to test for both
|
||||
for (uint8_t uartNum = 0; uartNum < 2; uartNum++)
|
||||
{
|
||||
if (USIS(uartNum) && s_uartInteruptContext[uartNum] != nullptr)
|
||||
{
|
||||
// Fill the FIFO with new data
|
||||
s_uartInteruptContext[uartNum]->_asyncBuff = FillUartFifo(
|
||||
uartNum,
|
||||
s_uartInteruptContext[uartNum]->_asyncBuff,
|
||||
s_uartInteruptContext[uartNum]->_asyncBuffEnd);
|
||||
|
||||
// Disable TX interrupt when done
|
||||
if (s_uartInteruptContext[uartNum]->_asyncBuff == s_uartInteruptContext[uartNum]->_asyncBuffEnd)
|
||||
{
|
||||
// clear the TX FIFO Empty
|
||||
USIE(uartNum) &= ~(1 << UIFE);
|
||||
}
|
||||
|
||||
// Clear all interrupts flags (just in case)
|
||||
USIC(uartNum) = 0xffff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
514
lib/NeoPixelBus_by_Makuna/src/internal/NeoEsp8266UartMethod.h
Normal file
514
lib/NeoPixelBus_by_Makuna/src/internal/NeoEsp8266UartMethod.h
Normal file
@@ -0,0 +1,514 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
NeoPixel library helper functions for Esp8266 UART hardware
|
||||
|
||||
Written by Michael C. Miller.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef ARDUINO_ARCH_ESP8266
|
||||
#include <Arduino.h>
|
||||
|
||||
// this template method class is used to track the data being sent on the uart
|
||||
// when using the default serial ISR installed by the core
|
||||
// used with NeoEsp8266Uart and NeoEsp8266AsyncUart classes
|
||||
//
|
||||
class NeoEsp8266UartContext
|
||||
{
|
||||
public:
|
||||
// Gets the number of bytes waiting in the TX FIFO
|
||||
static inline uint8_t ICACHE_RAM_ATTR GetTxFifoLength(uint8_t uartNum)
|
||||
{
|
||||
return (USS(uartNum) >> USTXC) & 0xff;
|
||||
}
|
||||
// Append a byte to the TX FIFO
|
||||
static inline void ICACHE_RAM_ATTR Enqueue(uint8_t uartNum, uint8_t value)
|
||||
{
|
||||
USF(uartNum) = value;
|
||||
}
|
||||
|
||||
static const volatile uint8_t* ICACHE_RAM_ATTR FillUartFifo(uint8_t uartNum,
|
||||
const volatile uint8_t* start,
|
||||
const volatile uint8_t* end);
|
||||
};
|
||||
|
||||
// this template method class is used to track the data being sent on the uart
|
||||
// when using our own UART ISR
|
||||
// used with NeoEsp8266Uart and NeoEsp8266AsyncUart classes
|
||||
//
|
||||
class NeoEsp8266UartInterruptContext : NeoEsp8266UartContext
|
||||
{
|
||||
public:
|
||||
NeoEsp8266UartInterruptContext() :
|
||||
_asyncBuff(nullptr),
|
||||
_asyncBuffEnd(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
bool IsSending()
|
||||
{
|
||||
return (_asyncBuff != _asyncBuffEnd);
|
||||
}
|
||||
|
||||
void StartSending(uint8_t uartNum, uint8_t* start, uint8_t* end);
|
||||
void Attach(uint8_t uartNum);
|
||||
void Detach(uint8_t uartNum);
|
||||
|
||||
private:
|
||||
volatile const uint8_t* _asyncBuff;
|
||||
volatile const uint8_t* _asyncBuffEnd;
|
||||
volatile static NeoEsp8266UartInterruptContext* s_uartInteruptContext[2];
|
||||
|
||||
static void ICACHE_RAM_ATTR Isr(void* param);
|
||||
};
|
||||
|
||||
// this template feature class is used a base for all others and contains
|
||||
// common methods
|
||||
//
|
||||
class UartFeatureBase
|
||||
{
|
||||
protected:
|
||||
static void ConfigUart(uint8_t uartNum, bool invert)
|
||||
{
|
||||
// clear all invert bits
|
||||
USC0(uartNum) &= ~((1 << UCDTRI) | (1 << UCRTSI) | (1 << UCTXI) | (1 << UCDSRI) | (1 << UCCTSI) | (1 << UCRXI));
|
||||
|
||||
if (!invert)
|
||||
{
|
||||
// For normal operations,
|
||||
// Invert the TX voltage associated with logic level so:
|
||||
// - A logic level 0 will generate a Vcc signal
|
||||
// - A logic level 1 will generate a Gnd signal
|
||||
USC0(uartNum) |= (1 << UCTXI);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// this template feature class is used to define the specifics for uart0
|
||||
// used with NeoEsp8266Uart and NeoEsp8266AsyncUart classes
|
||||
//
|
||||
class UartFeature0 : UartFeatureBase
|
||||
{
|
||||
public:
|
||||
static const uint32_t Index = 0;
|
||||
static void Init(uint32_t baud, bool invert)
|
||||
{
|
||||
// Configure the serial line with 1 start bit (0), 6 data bits and 1 stop bit (1)
|
||||
Serial.begin(baud, SERIAL_6N1, SERIAL_TX_ONLY);
|
||||
ConfigUart(Index, invert);
|
||||
}
|
||||
};
|
||||
|
||||
// this template feature class is used to define the specifics for uart1
|
||||
// used with NeoEsp8266Uart and NeoEsp8266AsyncUart classes
|
||||
//
|
||||
class UartFeature1 : UartFeatureBase
|
||||
{
|
||||
public:
|
||||
static const uint32_t Index = 1;
|
||||
static void Init(uint32_t baud, bool invert)
|
||||
{
|
||||
// Configure the serial line with 1 start bit (0), 6 data bits and 1 stop bit (1)
|
||||
Serial1.begin(baud, SERIAL_6N1, SERIAL_TX_ONLY);
|
||||
ConfigUart(Index, invert);
|
||||
}
|
||||
};
|
||||
|
||||
// this template method class is used a base for all others and contains
|
||||
// common properties and methods
|
||||
//
|
||||
// used by NeoEsp8266Uart and NeoEsp8266AsyncUart
|
||||
//
|
||||
class NeoEsp8266UartBase
|
||||
{
|
||||
protected:
|
||||
const size_t _sizeData; // Size of '_data' buffer below
|
||||
uint8_t* _data; // Holds LED color values
|
||||
uint32_t _startTime; // Microsecond count when last update started
|
||||
|
||||
NeoEsp8266UartBase(uint16_t pixelCount, size_t elementSize, size_t settingsSize) :
|
||||
_sizeData(pixelCount * elementSize + settingsSize)
|
||||
{
|
||||
_data = static_cast<uint8_t*>(malloc(_sizeData));
|
||||
memset(_data, 0x00, _sizeData);
|
||||
}
|
||||
|
||||
~NeoEsp8266UartBase()
|
||||
{
|
||||
free(_data);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// this template method class is used to glue uart feature and context for
|
||||
// synchronous uart method
|
||||
//
|
||||
// used by NeoEsp8266UartMethodBase
|
||||
//
|
||||
template<typename T_UARTFEATURE, typename T_UARTCONTEXT> class NeoEsp8266Uart : public NeoEsp8266UartBase
|
||||
{
|
||||
protected:
|
||||
NeoEsp8266Uart(uint16_t pixelCount, size_t elementSize, size_t settingsSize) :
|
||||
NeoEsp8266UartBase(pixelCount, elementSize, settingsSize)
|
||||
{
|
||||
}
|
||||
|
||||
~NeoEsp8266Uart()
|
||||
{
|
||||
// Wait until the TX fifo is empty. This way we avoid broken frames
|
||||
// when destroying & creating a NeoPixelBus to change its length.
|
||||
while (T_UARTCONTEXT::GetTxFifoLength(T_UARTFEATURE::Index) > 0)
|
||||
{
|
||||
yield();
|
||||
}
|
||||
}
|
||||
|
||||
void InitializeUart(uint32_t uartBaud, bool invert)
|
||||
{
|
||||
T_UARTFEATURE::Init(uartBaud, invert);
|
||||
}
|
||||
|
||||
void UpdateUart(bool)
|
||||
{
|
||||
// Since the UART can finish sending queued bytes in the FIFO in
|
||||
// the background, instead of waiting for the FIFO to flush
|
||||
// we annotate the start time of the frame so we can calculate
|
||||
// when it will finish.
|
||||
_startTime = micros();
|
||||
|
||||
// Then keep filling the FIFO until done
|
||||
const uint8_t* ptr = _data;
|
||||
const uint8_t* end = ptr + _sizeData;
|
||||
while (ptr != end)
|
||||
{
|
||||
ptr = const_cast<uint8_t*>(T_UARTCONTEXT::FillUartFifo(T_UARTFEATURE::Index, ptr, end));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// this template method class is used to glue uart feature and context for
|
||||
// asynchronously uart method
|
||||
//
|
||||
// This UART controller uses two buffers that are swapped in every call to
|
||||
// NeoPixelBus.Show(). One buffer contains the data that is being sent
|
||||
// asynchronosly and another buffer contains the data that will be send
|
||||
// in the next call to NeoPixelBus.Show().
|
||||
//
|
||||
// Therefore, the result of NeoPixelBus.Pixels() is invalidated after
|
||||
// every call to NeoPixelBus.Show() and must not be cached.
|
||||
//
|
||||
// used by NeoEsp8266UartMethodBase
|
||||
//
|
||||
template<typename T_UARTFEATURE, typename T_UARTCONTEXT> class NeoEsp8266AsyncUart : public NeoEsp8266UartBase
|
||||
{
|
||||
protected:
|
||||
NeoEsp8266AsyncUart(uint16_t pixelCount, size_t elementSize, size_t settingsSize) :
|
||||
NeoEsp8266UartBase(pixelCount, elementSize, settingsSize)
|
||||
{
|
||||
_dataSending = static_cast<uint8_t*>(malloc(_sizeData));
|
||||
}
|
||||
|
||||
~NeoEsp8266AsyncUart()
|
||||
{
|
||||
// Remember: the UART interrupt can be sending data from _dataSending in the background
|
||||
while (_context.IsSending())
|
||||
{
|
||||
yield();
|
||||
}
|
||||
// detach context, which will disable intr, may disable ISR
|
||||
_context.Detach(T_UARTFEATURE::Index);
|
||||
|
||||
free(_dataSending);
|
||||
}
|
||||
|
||||
void ICACHE_RAM_ATTR InitializeUart(uint32_t uartBaud, bool invert)
|
||||
{
|
||||
T_UARTFEATURE::Init(uartBaud, invert);
|
||||
|
||||
// attach the context, which will enable the ISR
|
||||
_context.Attach(T_UARTFEATURE::Index);
|
||||
}
|
||||
|
||||
void UpdateUart(bool maintainBufferConsistency)
|
||||
{
|
||||
// Instruct ESP8266 hardware uart to send the pixels asynchronously
|
||||
_context.StartSending(T_UARTFEATURE::Index,
|
||||
_data,
|
||||
_data + _sizeData);
|
||||
|
||||
// Annotate when we started to send bytes, so we can calculate when we are ready to send again
|
||||
_startTime = micros();
|
||||
|
||||
if (maintainBufferConsistency)
|
||||
{
|
||||
// copy editing to sending,
|
||||
// this maintains the contract that "colors present before will
|
||||
// be the same after", otherwise GetPixelColor will be inconsistent
|
||||
memcpy(_dataSending, _data, _sizeData);
|
||||
}
|
||||
|
||||
// swap so the user can modify without affecting the async operation
|
||||
std::swap(_dataSending, _data);
|
||||
}
|
||||
|
||||
private:
|
||||
T_UARTCONTEXT _context;
|
||||
|
||||
uint8_t* _dataSending; // Holds a copy of LED color values taken when UpdateUart began
|
||||
};
|
||||
|
||||
class NeoEsp8266UartSpeed800KbpsBase
|
||||
{
|
||||
public:
|
||||
static const uint32_t ByteSendTimeUs = 10; // us it takes to send a single pixel element at 800khz speed
|
||||
static const uint32_t UartBaud = 3200000; // 800mhz, 4 serial bytes per NeoByte
|
||||
};
|
||||
|
||||
// NeoEsp8266UartSpeedWs2813 contains the timing constants used to get NeoPixelBus running with the Ws2813
|
||||
class NeoEsp8266UartSpeedWs2812x : public NeoEsp8266UartSpeed800KbpsBase
|
||||
{
|
||||
public:
|
||||
static const uint32_t ResetTimeUs = 300; // us between data send bursts to reset for next update
|
||||
};
|
||||
|
||||
class NeoEsp8266UartSpeedSk6812 : public NeoEsp8266UartSpeed800KbpsBase
|
||||
{
|
||||
public:
|
||||
static const uint32_t ResetTimeUs = 80; // us between data send bursts to reset for next update
|
||||
};
|
||||
|
||||
class NeoEsp8266UartSpeedTm1814 : public NeoEsp8266UartSpeed800KbpsBase
|
||||
{
|
||||
public:
|
||||
static const uint32_t ResetTimeUs = 200; // us between data send bursts to reset for next update
|
||||
};
|
||||
|
||||
// NeoEsp8266UartSpeed800Kbps contains the timing constant used to get NeoPixelBus running at 800Khz
|
||||
class NeoEsp8266UartSpeed800Kbps : public NeoEsp8266UartSpeed800KbpsBase
|
||||
{
|
||||
public:
|
||||
static const uint32_t ResetTimeUs = 50; // us between data send bursts to reset for next update
|
||||
};
|
||||
|
||||
// NeoEsp8266UartSpeed400Kbps contains the timing constant used to get NeoPixelBus running at 400Khz
|
||||
class NeoEsp8266UartSpeed400Kbps
|
||||
{
|
||||
public:
|
||||
static const uint32_t ByteSendTimeUs = 20; // us it takes to send a single pixel element at 400khz speed
|
||||
static const uint32_t UartBaud = 1600000; // 400mhz, 4 serial bytes per NeoByte
|
||||
static const uint32_t ResetTimeUs = 50; // us between data send bursts to reset for next update
|
||||
};
|
||||
|
||||
// NeoEsp8266UartSpeedApa106 contains the timing constant used to get NeoPixelBus running for Apa106
|
||||
// Pulse cycle = 1.71 = 1.368 longer than normal, 0.731 slower, NeoEsp8266UartSpeedApa1066
|
||||
class NeoEsp8266UartSpeedApa106
|
||||
{
|
||||
public:
|
||||
static const uint32_t ByteSendTimeUs = 14; // us it takes to send a single pixel element at 400khz speed
|
||||
static const uint32_t UartBaud = 2339181; // APA106 pulse cycle of 1.71us, 4 serial bytes per NeoByte
|
||||
static const uint32_t ResetTimeUs = 50; // us between data send bursts to reset for next update
|
||||
};
|
||||
|
||||
class NeoEsp8266UartNotInverted
|
||||
{
|
||||
public:
|
||||
const static bool Inverted = false;
|
||||
};
|
||||
|
||||
class NeoEsp8266UartInverted
|
||||
{
|
||||
public:
|
||||
const static bool Inverted = true;
|
||||
};
|
||||
|
||||
// NeoEsp8266UartMethodBase is a light shell arround NeoEsp8266Uart or NeoEsp8266AsyncUart that
|
||||
// implements the methods needed to operate as a NeoPixelBus method.
|
||||
template<typename T_SPEED, typename T_BASE, typename T_INVERT>
|
||||
class NeoEsp8266UartMethodBase: public T_BASE
|
||||
{
|
||||
public:
|
||||
NeoEsp8266UartMethodBase(uint16_t pixelCount, size_t elementSize, size_t settingsSize)
|
||||
: T_BASE(pixelCount, elementSize, settingsSize)
|
||||
{
|
||||
}
|
||||
NeoEsp8266UartMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize)
|
||||
: T_BASE(pixelCount, elementSize, settingsSize)
|
||||
{
|
||||
}
|
||||
|
||||
bool IsReadyToUpdate() const
|
||||
{
|
||||
uint32_t delta = micros() - this->_startTime;
|
||||
return delta >= getPixelTime() + T_SPEED::ResetTimeUs;
|
||||
}
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
this->InitializeUart(T_SPEED::UartBaud, T_INVERT::Inverted);
|
||||
|
||||
// Inverting logic levels can generate a phantom bit in the led strip bus
|
||||
// We need to delay 50+ microseconds the output stream to force a data
|
||||
// latch and discard this bit. Otherwise, that bit would be prepended to
|
||||
// the first frame corrupting it.
|
||||
this->_startTime = micros() - getPixelTime();
|
||||
}
|
||||
|
||||
void Update(bool maintainBufferConsistency)
|
||||
{
|
||||
// Data latch = 50+ microsecond pause in the output stream. Rather than
|
||||
// put a delay at the end of the function, the ending time is noted and
|
||||
// the function will simply hold off (if needed) on issuing the
|
||||
// subsequent round of data until the latch time has elapsed. This
|
||||
// allows the mainline code to start generating the next frame of data
|
||||
// rather than stalling for the latch.
|
||||
while (!this->IsReadyToUpdate())
|
||||
{
|
||||
yield();
|
||||
}
|
||||
this->UpdateUart(maintainBufferConsistency);
|
||||
}
|
||||
|
||||
uint8_t* getData() const
|
||||
{
|
||||
return this->_data;
|
||||
};
|
||||
|
||||
size_t getDataSize() const
|
||||
{
|
||||
return this->_sizeData;
|
||||
};
|
||||
|
||||
private:
|
||||
uint32_t getPixelTime() const
|
||||
{
|
||||
return (T_SPEED::ByteSendTimeUs * this->_sizeData);
|
||||
};
|
||||
};
|
||||
|
||||
// uart 0
|
||||
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedWs2812x, NeoEsp8266Uart<UartFeature0, NeoEsp8266UartContext>, NeoEsp8266UartNotInverted> NeoEsp8266Uart0Ws2812xMethod;
|
||||
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedSk6812, NeoEsp8266Uart<UartFeature0, NeoEsp8266UartContext>, NeoEsp8266UartNotInverted> NeoEsp8266Uart0Sk6812Method;
|
||||
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedTm1814, NeoEsp8266Uart<UartFeature0, NeoEsp8266UartContext>, NeoEsp8266UartInverted> NeoEsp8266Uart0Tm1814Method;
|
||||
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedApa106, NeoEsp8266Uart<UartFeature0, NeoEsp8266UartContext>, NeoEsp8266UartNotInverted> NeoEsp8266Uart0Apa106Method;
|
||||
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeed800Kbps, NeoEsp8266Uart<UartFeature0, NeoEsp8266UartContext>, NeoEsp8266UartNotInverted> NeoEsp8266Uart0800KbpsMethod;
|
||||
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeed400Kbps, NeoEsp8266Uart<UartFeature0, NeoEsp8266UartContext>, NeoEsp8266UartNotInverted> NeoEsp8266Uart0400KbpsMethod;
|
||||
|
||||
typedef NeoEsp8266Uart0Ws2812xMethod NeoEsp8266Uart0Ws2813Method;
|
||||
typedef NeoEsp8266Uart0800KbpsMethod NeoEsp8266Uart0Ws2812Method;
|
||||
typedef NeoEsp8266Uart0Ws2812xMethod NeoEsp8266Uart0Ws2811Method;
|
||||
typedef NeoEsp8266Uart0Sk6812Method NeoEsp8266Uart0Lc8812Method;
|
||||
|
||||
// uart 1
|
||||
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedWs2812x, NeoEsp8266Uart<UartFeature1, NeoEsp8266UartContext>, NeoEsp8266UartNotInverted> NeoEsp8266Uart1Ws2812xMethod;
|
||||
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedSk6812, NeoEsp8266Uart<UartFeature1, NeoEsp8266UartContext>, NeoEsp8266UartNotInverted> NeoEsp8266Uart1Sk6812Method;
|
||||
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedTm1814, NeoEsp8266Uart<UartFeature1, NeoEsp8266UartContext>, NeoEsp8266UartInverted> NeoEsp8266Uart1Tm1814Method;
|
||||
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedApa106, NeoEsp8266Uart<UartFeature1, NeoEsp8266UartContext>, NeoEsp8266UartNotInverted> NeoEsp8266Uart1Apa106Method;
|
||||
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeed800Kbps, NeoEsp8266Uart<UartFeature1, NeoEsp8266UartContext>, NeoEsp8266UartNotInverted> NeoEsp8266Uart1800KbpsMethod;
|
||||
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeed400Kbps, NeoEsp8266Uart<UartFeature1, NeoEsp8266UartContext>, NeoEsp8266UartNotInverted> NeoEsp8266Uart1400KbpsMethod;
|
||||
|
||||
typedef NeoEsp8266Uart1Ws2812xMethod NeoEsp8266Uart1Ws2813Method;
|
||||
typedef NeoEsp8266Uart1800KbpsMethod NeoEsp8266Uart1Ws2812Method;
|
||||
typedef NeoEsp8266Uart1Ws2812xMethod NeoEsp8266Uart1Ws2811Method;
|
||||
typedef NeoEsp8266Uart1Sk6812Method NeoEsp8266Uart1Lc8812Method;
|
||||
|
||||
// uart 0 async
|
||||
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedWs2812x, NeoEsp8266AsyncUart<UartFeature0, NeoEsp8266UartInterruptContext>, NeoEsp8266UartNotInverted> NeoEsp8266AsyncUart0Ws2812xMethod;
|
||||
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedSk6812, NeoEsp8266AsyncUart<UartFeature0, NeoEsp8266UartInterruptContext>, NeoEsp8266UartNotInverted> NeoEsp8266AsyncUart0Sk6812Method;
|
||||
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedTm1814, NeoEsp8266AsyncUart<UartFeature0, NeoEsp8266UartInterruptContext>, NeoEsp8266UartInverted> NeoEsp8266AsyncUart0Tm1814Method;
|
||||
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedApa106, NeoEsp8266AsyncUart<UartFeature0, NeoEsp8266UartInterruptContext>, NeoEsp8266UartNotInverted> NeoEsp8266AsyncUart0Apa106Method;
|
||||
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeed800Kbps, NeoEsp8266AsyncUart<UartFeature0, NeoEsp8266UartInterruptContext>, NeoEsp8266UartNotInverted> NeoEsp8266AsyncUart0800KbpsMethod;
|
||||
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeed400Kbps, NeoEsp8266AsyncUart<UartFeature0, NeoEsp8266UartInterruptContext>, NeoEsp8266UartNotInverted> NeoEsp8266AsyncUart0400KbpsMethod;
|
||||
|
||||
typedef NeoEsp8266AsyncUart0Ws2812xMethod NeoEsp8266AsyncUart0Ws2813Method;
|
||||
typedef NeoEsp8266AsyncUart0800KbpsMethod NeoEsp8266AsyncUart0Ws2812Method;
|
||||
typedef NeoEsp8266AsyncUart0Ws2812xMethod NeoEsp8266AsyncUart0Ws2811Method;
|
||||
typedef NeoEsp8266AsyncUart0Sk6812Method NeoEsp8266AsyncUart0Lc8812Method;
|
||||
|
||||
// uart 1 async
|
||||
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedWs2812x, NeoEsp8266AsyncUart<UartFeature1, NeoEsp8266UartInterruptContext>, NeoEsp8266UartNotInverted> NeoEsp8266AsyncUart1Ws2812xMethod;
|
||||
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedSk6812, NeoEsp8266AsyncUart<UartFeature1, NeoEsp8266UartInterruptContext>, NeoEsp8266UartNotInverted> NeoEsp8266AsyncUart1Sk6812Method;
|
||||
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedTm1814, NeoEsp8266AsyncUart<UartFeature1, NeoEsp8266UartInterruptContext>, NeoEsp8266UartInverted> NeoEsp8266AsyncUart1Tm1814Method;
|
||||
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedApa106, NeoEsp8266AsyncUart<UartFeature1, NeoEsp8266UartInterruptContext>, NeoEsp8266UartNotInverted> NeoEsp8266AsyncUart1Apa106Method;
|
||||
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeed800Kbps, NeoEsp8266AsyncUart<UartFeature1, NeoEsp8266UartInterruptContext>, NeoEsp8266UartNotInverted> NeoEsp8266AsyncUart1800KbpsMethod;
|
||||
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeed400Kbps, NeoEsp8266AsyncUart<UartFeature1, NeoEsp8266UartInterruptContext>, NeoEsp8266UartNotInverted> NeoEsp8266AsyncUart1400KbpsMethod;
|
||||
|
||||
typedef NeoEsp8266AsyncUart1Ws2812xMethod NeoEsp8266AsyncUart1Ws2813Method;
|
||||
typedef NeoEsp8266AsyncUart1800KbpsMethod NeoEsp8266AsyncUart1Ws2812Method;
|
||||
typedef NeoEsp8266AsyncUart1Ws2812xMethod NeoEsp8266AsyncUart1Ws2811Method;
|
||||
typedef NeoEsp8266AsyncUart1Sk6812Method NeoEsp8266AsyncUart1Lc8812Method;
|
||||
|
||||
// inverted
|
||||
//
|
||||
// uart 0
|
||||
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedWs2812x, NeoEsp8266Uart<UartFeature0, NeoEsp8266UartContext>, NeoEsp8266UartInverted> NeoEsp8266Uart0Ws2812xInvertedMethod;
|
||||
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedSk6812, NeoEsp8266Uart<UartFeature0, NeoEsp8266UartContext>, NeoEsp8266UartInverted> NeoEsp8266Uart0Sk6812InvertedMethod;
|
||||
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedTm1814, NeoEsp8266Uart<UartFeature0, NeoEsp8266UartContext>, NeoEsp8266UartNotInverted> NeoEsp8266Uart0Tm1814InvertedMethod;
|
||||
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedApa106, NeoEsp8266Uart<UartFeature0, NeoEsp8266UartContext>, NeoEsp8266UartInverted> NeoEsp8266Uart0Apa106InvertedMethod;
|
||||
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeed800Kbps, NeoEsp8266Uart<UartFeature0, NeoEsp8266UartContext>, NeoEsp8266UartInverted> NeoEsp8266Uart0800KbpsInvertedMethod;
|
||||
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeed400Kbps, NeoEsp8266Uart<UartFeature0, NeoEsp8266UartContext>, NeoEsp8266UartInverted> NeoEsp8266Uart0400KbpsInvertedMethod;
|
||||
|
||||
typedef NeoEsp8266Uart0Ws2812xInvertedMethod NeoEsp8266Uart0Ws2813InvertedMethod;
|
||||
typedef NeoEsp8266Uart0800KbpsInvertedMethod NeoEsp8266Uart0Ws2812InvertedMethod;
|
||||
typedef NeoEsp8266Uart0Ws2812xInvertedMethod NeoEsp8266Uart0Ws2811InvertedMethod;
|
||||
typedef NeoEsp8266Uart0Sk6812InvertedMethod NeoEsp8266Uart0Lc8812InvertedMethod;
|
||||
|
||||
// uart 1
|
||||
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedWs2812x, NeoEsp8266Uart<UartFeature1, NeoEsp8266UartContext>, NeoEsp8266UartInverted> NeoEsp8266Uart1Ws2812xInvertedMethod;
|
||||
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedSk6812, NeoEsp8266Uart<UartFeature1, NeoEsp8266UartContext>, NeoEsp8266UartInverted> NeoEsp8266Uart1Sk6812InvertedMethod;
|
||||
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedTm1814, NeoEsp8266Uart<UartFeature1, NeoEsp8266UartContext>, NeoEsp8266UartNotInverted> NeoEsp8266Uart1Tm1814InvertedMethod;
|
||||
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedApa106, NeoEsp8266Uart<UartFeature1, NeoEsp8266UartContext>, NeoEsp8266UartInverted> NeoEsp8266Uart1Apa106InvertedMethod;
|
||||
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeed800Kbps, NeoEsp8266Uart<UartFeature1, NeoEsp8266UartContext>, NeoEsp8266UartInverted> NeoEsp8266Uart1800KbpsInvertedMethod;
|
||||
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeed400Kbps, NeoEsp8266Uart<UartFeature1, NeoEsp8266UartContext>, NeoEsp8266UartInverted> NeoEsp8266Uart1400KbpsInvertedMethod;
|
||||
|
||||
typedef NeoEsp8266Uart1Ws2812xInvertedMethod NeoEsp8266Uart1Ws2813InvertedMethod;
|
||||
typedef NeoEsp8266Uart1800KbpsInvertedMethod NeoEsp8266Uart1Ws2812InvertedMethod;
|
||||
typedef NeoEsp8266Uart1Ws2812xInvertedMethod NeoEsp8266Uart1Ws2811InvertedMethod;
|
||||
typedef NeoEsp8266Uart1Sk6812InvertedMethod NeoEsp8266Uart1Lc8812InvertedMethod;
|
||||
|
||||
// uart 0 async
|
||||
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedWs2812x, NeoEsp8266AsyncUart<UartFeature0, NeoEsp8266UartInterruptContext>, NeoEsp8266UartInverted> NeoEsp8266AsyncUart0Ws2812xInvertedMethod;
|
||||
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedSk6812, NeoEsp8266AsyncUart<UartFeature0, NeoEsp8266UartInterruptContext>, NeoEsp8266UartInverted> NeoEsp8266AsyncUart0Sk6812InvertedMethod;
|
||||
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedTm1814, NeoEsp8266AsyncUart<UartFeature0, NeoEsp8266UartInterruptContext>, NeoEsp8266UartNotInverted> NeoEsp8266AsyncUart0Tm1814InvertedMethod;
|
||||
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedApa106, NeoEsp8266AsyncUart<UartFeature0, NeoEsp8266UartInterruptContext>, NeoEsp8266UartInverted> NeoEsp8266AsyncUart0Apa106InvertedMethod;
|
||||
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeed800Kbps, NeoEsp8266AsyncUart<UartFeature0, NeoEsp8266UartInterruptContext>, NeoEsp8266UartInverted> NeoEsp8266AsyncUart0800KbpsInvertedMethod;
|
||||
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeed400Kbps, NeoEsp8266AsyncUart<UartFeature0, NeoEsp8266UartInterruptContext>, NeoEsp8266UartInverted> NeoEsp8266AsyncUart0400KbpsInvertedMethod;
|
||||
|
||||
typedef NeoEsp8266AsyncUart0Ws2812xInvertedMethod NeoEsp8266AsyncUart0Ws2813InvertedMethod;
|
||||
typedef NeoEsp8266AsyncUart0800KbpsInvertedMethod NeoEsp8266AsyncUart0Ws2812InvertedMethod;
|
||||
typedef NeoEsp8266AsyncUart0Ws2812xInvertedMethod NeoEsp8266AsyncUart0Ws2811InvertedMethod;
|
||||
typedef NeoEsp8266AsyncUart0Sk6812InvertedMethod NeoEsp8266AsyncUart0Lc8812InvertedMethod;
|
||||
|
||||
// uart 1 async
|
||||
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedWs2812x, NeoEsp8266AsyncUart<UartFeature1, NeoEsp8266UartInterruptContext>, NeoEsp8266UartInverted> NeoEsp8266AsyncUart1Ws2812xInvertedMethod;
|
||||
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedSk6812, NeoEsp8266AsyncUart<UartFeature1, NeoEsp8266UartInterruptContext>, NeoEsp8266UartInverted> NeoEsp8266AsyncUart1Sk6812InvertedMethod;
|
||||
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedTm1814, NeoEsp8266AsyncUart<UartFeature1, NeoEsp8266UartInterruptContext>, NeoEsp8266UartNotInverted> NeoEsp8266AsyncUart1Tm1814InvertedMethod;
|
||||
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeedApa106, NeoEsp8266AsyncUart<UartFeature1, NeoEsp8266UartInterruptContext>, NeoEsp8266UartInverted> NeoEsp8266AsyncUart1Apa106InvertedMethod;
|
||||
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeed800Kbps, NeoEsp8266AsyncUart<UartFeature1, NeoEsp8266UartInterruptContext>, NeoEsp8266UartInverted> NeoEsp8266AsyncUart1800KbpsInvertedMethod;
|
||||
typedef NeoEsp8266UartMethodBase<NeoEsp8266UartSpeed400Kbps, NeoEsp8266AsyncUart<UartFeature1, NeoEsp8266UartInterruptContext>, NeoEsp8266UartInverted> NeoEsp8266AsyncUart1400KbpsInvertedMethod;
|
||||
|
||||
typedef NeoEsp8266AsyncUart1Ws2812xInvertedMethod NeoEsp8266AsyncUart1Ws2813InvertedMethod;
|
||||
typedef NeoEsp8266AsyncUart1800KbpsInvertedMethod NeoEsp8266AsyncUart1Ws2812InvertedMethod;
|
||||
typedef NeoEsp8266AsyncUart1Ws2812xInvertedMethod NeoEsp8266AsyncUart1Ws2811InvertedMethod;
|
||||
typedef NeoEsp8266AsyncUart1Sk6812InvertedMethod NeoEsp8266AsyncUart1Lc8812InvertedMethod;
|
||||
#endif
|
||||
|
||||
401
lib/NeoPixelBus_by_Makuna/src/internal/NeoEspBitBangMethod.h
Normal file
401
lib/NeoPixelBus_by_Makuna/src/internal/NeoEspBitBangMethod.h
Normal file
@@ -0,0 +1,401 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
NeoPixel library helper functions for Esp8266 and Esp32
|
||||
|
||||
Written by Michael C. Miller.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP8266)
|
||||
#include <eagle_soc.h>
|
||||
#endif
|
||||
|
||||
// ESP32 doesn't define ICACHE_RAM_ATTR
|
||||
#ifndef ICACHE_RAM_ATTR
|
||||
#define ICACHE_RAM_ATTR IRAM_ATTR
|
||||
#endif
|
||||
|
||||
#define CYCLES_LOOPTEST (4) // adjustment due to loop exit test instruction cycles
|
||||
|
||||
class NeoEspSpeedWs2811
|
||||
{
|
||||
public:
|
||||
const static uint32_t T0H = (F_CPU / 3333333 - CYCLES_LOOPTEST); // 0.3us
|
||||
const static uint32_t T1H = (F_CPU / 1052632 - CYCLES_LOOPTEST); // 0.95us
|
||||
const static uint32_t Period = (F_CPU / 800000 - CYCLES_LOOPTEST); // 1.25us per bit
|
||||
};
|
||||
|
||||
class NeoEspSpeedTm1814
|
||||
{
|
||||
public:
|
||||
const static uint32_t T0H = (F_CPU / 2916666 - CYCLES_LOOPTEST); // 0.35us
|
||||
const static uint32_t T1H = (F_CPU / 1666666 - CYCLES_LOOPTEST); // 0.75us
|
||||
const static uint32_t Period = (F_CPU / 800000 - CYCLES_LOOPTEST); // 1.25us per bit
|
||||
};
|
||||
|
||||
class NeoEspSpeed800Mhz
|
||||
{
|
||||
public:
|
||||
const static uint32_t T0H = (F_CPU / 2500000 - CYCLES_LOOPTEST); // 0.4us
|
||||
const static uint32_t T1H = (F_CPU / 1250000 - CYCLES_LOOPTEST); // 0.8us
|
||||
const static uint32_t Period = (F_CPU / 800000 - CYCLES_LOOPTEST); // 1.25us per bit
|
||||
};
|
||||
|
||||
class NeoEspSpeed400Mhz
|
||||
{
|
||||
public:
|
||||
const static uint32_t T0H = (F_CPU / 2000000 - CYCLES_LOOPTEST);
|
||||
const static uint32_t T1H = (F_CPU / 833333 - CYCLES_LOOPTEST);
|
||||
const static uint32_t Period = (F_CPU / 400000 - CYCLES_LOOPTEST);
|
||||
};
|
||||
|
||||
class NeoEspPinset
|
||||
{
|
||||
public:
|
||||
const static uint8_t IdleLevel = LOW;
|
||||
|
||||
inline static void setPin(const uint32_t pinRegister)
|
||||
{
|
||||
#if defined(ARDUINO_ARCH_ESP32)
|
||||
GPIO.out_w1ts = pinRegister;
|
||||
#else
|
||||
GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, pinRegister);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline static void resetPin(const uint32_t pinRegister)
|
||||
{
|
||||
#if defined(ARDUINO_ARCH_ESP32)
|
||||
GPIO.out_w1tc = pinRegister;
|
||||
#else
|
||||
GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, pinRegister);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
class NeoEspPinsetInverted
|
||||
{
|
||||
public:
|
||||
const static uint8_t IdleLevel = HIGH;
|
||||
|
||||
inline static void setPin(const uint32_t pinRegister)
|
||||
{
|
||||
#if defined(ARDUINO_ARCH_ESP32)
|
||||
GPIO.out_w1tc = pinRegister;
|
||||
#else
|
||||
GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, pinRegister);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline static void resetPin(const uint32_t pinRegister)
|
||||
{
|
||||
#if defined(ARDUINO_ARCH_ESP32)
|
||||
GPIO.out_w1ts = pinRegister;
|
||||
#else
|
||||
GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, pinRegister);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T_SPEED, typename T_PINSET> class NeoEspBitBangBase
|
||||
{
|
||||
public:
|
||||
__attribute__((noinline)) static void ICACHE_RAM_ATTR send_pixels(uint8_t* pixels, uint8_t* end, uint8_t pin)
|
||||
{
|
||||
const uint32_t pinRegister = _BV(pin);
|
||||
uint8_t mask = 0x80;
|
||||
uint8_t subpix = *pixels++;
|
||||
uint32_t cyclesStart = 0; // trigger emediately
|
||||
uint32_t cyclesNext = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
// do the checks here while we are waiting on time to pass
|
||||
uint32_t cyclesBit = T_SPEED::T0H;
|
||||
if (subpix & mask)
|
||||
{
|
||||
cyclesBit = T_SPEED::T1H;
|
||||
}
|
||||
|
||||
// after we have done as much work as needed for this next bit
|
||||
// now wait for the HIGH
|
||||
while (((cyclesStart = getCycleCount()) - cyclesNext) < T_SPEED::Period);
|
||||
|
||||
// set pin state
|
||||
T_PINSET::setPin(pinRegister);
|
||||
|
||||
// wait for the LOW
|
||||
while ((getCycleCount() - cyclesStart) < cyclesBit);
|
||||
|
||||
// reset pin start
|
||||
T_PINSET::resetPin(pinRegister);
|
||||
|
||||
cyclesNext = cyclesStart;
|
||||
|
||||
// next bit
|
||||
mask >>= 1;
|
||||
if (mask == 0)
|
||||
{
|
||||
// no more bits to send in this byte
|
||||
// check for another byte
|
||||
if (pixels >= end)
|
||||
{
|
||||
// no more bytes to send so stop
|
||||
break;
|
||||
}
|
||||
// reset mask to first bit and get the next byte
|
||||
mask = 0x80;
|
||||
subpix = *pixels++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
static inline uint32_t getCycleCount(void)
|
||||
{
|
||||
uint32_t ccount;
|
||||
__asm__ __volatile__("rsr %0,ccount":"=a" (ccount));
|
||||
return ccount;
|
||||
}
|
||||
};
|
||||
|
||||
class NeoEspBitBangSpeedWs2811 : public NeoEspBitBangBase<NeoEspSpeedWs2811, NeoEspPinset>
|
||||
{
|
||||
public:
|
||||
static const uint32_t ResetTimeUs = 300;
|
||||
};
|
||||
|
||||
class NeoEspBitBangSpeedWs2812x : public NeoEspBitBangBase<NeoEspSpeed800Mhz, NeoEspPinset>
|
||||
{
|
||||
public:
|
||||
static const uint32_t ResetTimeUs = 300;
|
||||
};
|
||||
|
||||
class NeoEspBitBangSpeedSk6812 : public NeoEspBitBangBase<NeoEspSpeed800Mhz, NeoEspPinset>
|
||||
{
|
||||
public:
|
||||
static const uint32_t ResetTimeUs = 80;
|
||||
};
|
||||
|
||||
// normal is inverted signal
|
||||
class NeoEspBitBangSpeedTm1814 : public NeoEspBitBangBase<NeoEspSpeedTm1814, NeoEspPinsetInverted>
|
||||
{
|
||||
public:
|
||||
static const uint32_t ResetTimeUs = 200;
|
||||
};
|
||||
|
||||
class NeoEspBitBangSpeed800Kbps : public NeoEspBitBangBase<NeoEspSpeed800Mhz, NeoEspPinset>
|
||||
{
|
||||
public:
|
||||
static const uint32_t ResetTimeUs = 50;
|
||||
};
|
||||
|
||||
class NeoEspBitBangSpeed400Kbps : public NeoEspBitBangBase<NeoEspSpeed400Mhz, NeoEspPinset>
|
||||
{
|
||||
public:
|
||||
static const uint32_t ResetTimeUs = 50;
|
||||
};
|
||||
|
||||
|
||||
class NeoEspBitBangInvertedSpeedWs2811 : public NeoEspBitBangBase<NeoEspSpeedWs2811, NeoEspPinsetInverted>
|
||||
{
|
||||
public:
|
||||
static const uint32_t ResetTimeUs = 300;
|
||||
};
|
||||
|
||||
class NeoEspBitBangInvertedSpeedWs2812x : public NeoEspBitBangBase<NeoEspSpeed800Mhz, NeoEspPinsetInverted>
|
||||
{
|
||||
public:
|
||||
static const uint32_t ResetTimeUs = 300;
|
||||
};
|
||||
|
||||
class NeoEspBitBangInvertedSpeedSk6812 : public NeoEspBitBangBase<NeoEspSpeed800Mhz, NeoEspPinsetInverted>
|
||||
{
|
||||
public:
|
||||
static const uint32_t ResetTimeUs = 80;
|
||||
};
|
||||
|
||||
// normal is inverted signal, so inverted is normal
|
||||
class NeoEspBitBangInvertedSpeedTm1814 : public NeoEspBitBangBase<NeoEspSpeedTm1814, NeoEspPinset>
|
||||
{
|
||||
public:
|
||||
static const uint32_t ResetTimeUs = 200;
|
||||
};
|
||||
|
||||
class NeoEspBitBangInvertedSpeed800Kbps : public NeoEspBitBangBase<NeoEspSpeed800Mhz, NeoEspPinsetInverted>
|
||||
{
|
||||
public:
|
||||
static const uint32_t ResetTimeUs = 50;
|
||||
};
|
||||
|
||||
class NeoEspBitBangInvertedSpeed400Kbps : public NeoEspBitBangBase<NeoEspSpeed400Mhz, NeoEspPinsetInverted>
|
||||
{
|
||||
public:
|
||||
static const uint32_t ResetTimeUs = 50;
|
||||
};
|
||||
|
||||
template<typename T_SPEED, typename T_PINSET> class NeoEspBitBangMethodBase
|
||||
{
|
||||
public:
|
||||
NeoEspBitBangMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize) :
|
||||
_sizeData(pixelCount * elementSize + settingsSize),
|
||||
_pin(pin)
|
||||
{
|
||||
pinMode(pin, OUTPUT);
|
||||
|
||||
_data = static_cast<uint8_t*>(malloc(_sizeData));
|
||||
memset(_data, 0, _sizeData);
|
||||
}
|
||||
|
||||
~NeoEspBitBangMethodBase()
|
||||
{
|
||||
pinMode(_pin, INPUT);
|
||||
|
||||
free(_data);
|
||||
}
|
||||
|
||||
bool IsReadyToUpdate() const
|
||||
{
|
||||
uint32_t delta = micros() - _endTime;
|
||||
|
||||
return (delta >= T_SPEED::ResetTimeUs);
|
||||
}
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
digitalWrite(_pin, T_PINSET::IdleLevel);
|
||||
|
||||
_endTime = micros();
|
||||
}
|
||||
|
||||
void Update(bool)
|
||||
{
|
||||
// Data latch = 50+ microsecond pause in the output stream. Rather than
|
||||
// put a delay at the end of the function, the ending time is noted and
|
||||
// the function will simply hold off (if needed) on issuing the
|
||||
// subsequent round of data until the latch time has elapsed. This
|
||||
// allows the mainline code to start generating the next frame of data
|
||||
// rather than stalling for the latch.
|
||||
while (!IsReadyToUpdate())
|
||||
{
|
||||
yield(); // allows for system yield if needed
|
||||
}
|
||||
|
||||
// Need 100% focus on instruction timing
|
||||
#if defined(ARDUINO_ARCH_ESP32)
|
||||
delay(1); // required
|
||||
portMUX_TYPE updateMux = portMUX_INITIALIZER_UNLOCKED;
|
||||
|
||||
portENTER_CRITICAL(&updateMux);
|
||||
#else
|
||||
noInterrupts();
|
||||
#endif
|
||||
|
||||
T_SPEED::send_pixels(_data, _data + _sizeData, _pin);
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP32)
|
||||
portEXIT_CRITICAL(&updateMux);
|
||||
#else
|
||||
interrupts();
|
||||
#endif
|
||||
|
||||
// save EOD time for latch on next call
|
||||
_endTime = micros();
|
||||
}
|
||||
|
||||
uint8_t* getData() const
|
||||
{
|
||||
return _data;
|
||||
};
|
||||
|
||||
size_t getDataSize() const
|
||||
{
|
||||
return _sizeData;
|
||||
};
|
||||
|
||||
private:
|
||||
const size_t _sizeData; // Size of '_data' buffer below
|
||||
const uint8_t _pin; // output pin number
|
||||
|
||||
uint32_t _endTime; // Latch timing reference
|
||||
uint8_t* _data; // Holds LED color values
|
||||
};
|
||||
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP32)
|
||||
|
||||
typedef NeoEspBitBangMethodBase<NeoEspBitBangSpeedWs2811, NeoEspPinset> NeoEsp32BitBangWs2811Method;
|
||||
typedef NeoEspBitBangMethodBase<NeoEspBitBangSpeedWs2812x, NeoEspPinset> NeoEsp32BitBangWs2812xMethod;
|
||||
typedef NeoEspBitBangMethodBase<NeoEspBitBangSpeedSk6812, NeoEspPinset> NeoEsp32BitBangSk6812Method;
|
||||
typedef NeoEspBitBangMethodBase<NeoEspBitBangSpeedTm1814, NeoEspPinsetInverted> NeoEsp32BitBangTm1814Method;
|
||||
typedef NeoEspBitBangMethodBase<NeoEspBitBangSpeed800Kbps, NeoEspPinset> NeoEsp32BitBang800KbpsMethod;
|
||||
typedef NeoEspBitBangMethodBase<NeoEspBitBangSpeed400Kbps, NeoEspPinset> NeoEsp32BitBang400KbpsMethod;
|
||||
|
||||
typedef NeoEsp32BitBangWs2812xMethod NeoEsp32BitBangWs2813Method;
|
||||
typedef NeoEsp32BitBang800KbpsMethod NeoEsp32BitBangWs2812Method;
|
||||
typedef NeoEsp32BitBangSk6812Method NeoEsp32BitBangLc8812Method;
|
||||
typedef NeoEsp32BitBang400KbpsMethod NeoEsp32BitBangApa106Method;
|
||||
|
||||
typedef NeoEspBitBangMethodBase<NeoEspBitBangInvertedSpeedWs2811, NeoEspPinsetInverted> NeoEsp32BitBangWs2811InvertedMethod;
|
||||
typedef NeoEspBitBangMethodBase<NeoEspBitBangInvertedSpeedWs2812x, NeoEspPinsetInverted> NeoEsp32BitBangWs2812xInvertedMethod;
|
||||
typedef NeoEspBitBangMethodBase<NeoEspBitBangInvertedSpeedSk6812, NeoEspPinsetInverted> NeoEsp32BitBangSk6812InvertedMethod;
|
||||
typedef NeoEspBitBangMethodBase<NeoEspBitBangInvertedSpeedTm1814, NeoEspPinset> NeoEsp32BitBangTm1814InvertedMethod;
|
||||
typedef NeoEspBitBangMethodBase<NeoEspBitBangInvertedSpeed800Kbps, NeoEspPinsetInverted> NeoEsp32BitBang800KbpsInvertedMethod;
|
||||
typedef NeoEspBitBangMethodBase<NeoEspBitBangInvertedSpeed400Kbps, NeoEspPinsetInverted> NeoEsp32BitBang400KbpsInvertedMethod;
|
||||
|
||||
typedef NeoEsp32BitBangWs2812xInvertedMethod NeoEsp32BitBangWs2813InvertedMethod;
|
||||
typedef NeoEsp32BitBang800KbpsInvertedMethod NeoEsp32BitBangWs2812InvertedMethod;
|
||||
typedef NeoEsp32BitBangSk6812InvertedMethod NeoEsp32BitBangLc8812InvertedMethod;
|
||||
typedef NeoEsp32BitBang400KbpsInvertedMethod NeoEsp32BitBangApa106InvertedMethod;
|
||||
|
||||
#else
|
||||
|
||||
typedef NeoEspBitBangMethodBase<NeoEspBitBangSpeedWs2811, NeoEspPinset> NeoEsp8266BitBangWs2811Method;
|
||||
typedef NeoEspBitBangMethodBase<NeoEspBitBangSpeedWs2812x, NeoEspPinset> NeoEsp8266BitBangWs2812xMethod;
|
||||
typedef NeoEspBitBangMethodBase<NeoEspBitBangSpeedSk6812, NeoEspPinset> NeoEsp8266BitBangSk6812Method;
|
||||
typedef NeoEspBitBangMethodBase<NeoEspBitBangSpeedTm1814, NeoEspPinsetInverted> NeoEsp8266BitBangTm1814Method;
|
||||
typedef NeoEspBitBangMethodBase<NeoEspBitBangSpeed800Kbps, NeoEspPinset> NeoEsp8266BitBang800KbpsMethod;
|
||||
typedef NeoEspBitBangMethodBase<NeoEspBitBangSpeed400Kbps, NeoEspPinset> NeoEsp8266BitBang400KbpsMethod;
|
||||
|
||||
typedef NeoEsp8266BitBangWs2812xMethod NeoEsp8266BitBangWs2813Method;
|
||||
typedef NeoEsp8266BitBang800KbpsMethod NeoEsp8266BitBangWs2812Method;
|
||||
typedef NeoEsp8266BitBangSk6812Method NeoEsp8266BitBangLc8812Method;
|
||||
typedef NeoEsp8266BitBang400KbpsMethod NeoEsp8266BitBangApa106Method;
|
||||
|
||||
typedef NeoEspBitBangMethodBase<NeoEspBitBangInvertedSpeedWs2811, NeoEspPinsetInverted> NeoEsp8266BitBangWs2811InvertedMethod;
|
||||
typedef NeoEspBitBangMethodBase<NeoEspBitBangInvertedSpeedWs2812x, NeoEspPinsetInverted> NeoEsp8266BitBangWs2812xInvertedMethod;
|
||||
typedef NeoEspBitBangMethodBase<NeoEspBitBangInvertedSpeedSk6812, NeoEspPinsetInverted> NeoEsp8266BitBangSk6812InvertedMethod;
|
||||
typedef NeoEspBitBangMethodBase<NeoEspBitBangInvertedSpeedTm1814, NeoEspPinset> NeoEsp8266BitBangTm1814InvertedMethod;
|
||||
typedef NeoEspBitBangMethodBase<NeoEspBitBangInvertedSpeed800Kbps, NeoEspPinsetInverted> NeoEsp8266BitBang800KbpsInvertedMethod;
|
||||
typedef NeoEspBitBangMethodBase<NeoEspBitBangInvertedSpeed400Kbps, NeoEspPinsetInverted> NeoEsp8266BitBang400KbpsInvertedMethod;
|
||||
|
||||
typedef NeoEsp8266BitBangWs2812xInvertedMethod NeoEsp8266BitBangWs2813InvertedMethod;
|
||||
typedef NeoEsp8266BitBang800KbpsInvertedMethod NeoEsp8266BitBangWs2812InvertedMethod;
|
||||
typedef NeoEsp8266BitBangSk6812InvertedMethod NeoEsp8266BitBangLc8812InvertedMethod;
|
||||
typedef NeoEsp8266BitBang400KbpsInvertedMethod NeoEsp8266BitBangApa106InvertedMethod;
|
||||
#endif
|
||||
|
||||
// ESP bitbang doesn't have defaults and should avoided except for testing
|
||||
#endif
|
||||
47
lib/NeoPixelBus_by_Makuna/src/internal/NeoGamma.cpp
Normal file
47
lib/NeoPixelBus_by_Makuna/src/internal/NeoGamma.cpp
Normal file
@@ -0,0 +1,47 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
NeoPixelGamma class is used to correct RGB colors for human eye gamma levels
|
||||
|
||||
Written by Michael C. Miller.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "NeoPixelBus.h"
|
||||
|
||||
const uint8_t NeoGammaTableMethod::_table[] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2,
|
||||
3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6,
|
||||
6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 11, 11, 11,
|
||||
12, 12, 13, 13, 14, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19,
|
||||
19, 20, 20, 21, 22, 22, 23, 23, 24, 25, 25, 26, 26, 27, 28, 28,
|
||||
29, 30, 30, 31, 32, 33, 33, 34, 35, 35, 36, 37, 38, 39, 39, 40,
|
||||
41, 42, 43, 43, 44, 45, 46, 47, 48, 49, 50, 50, 51, 52, 53, 54,
|
||||
55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 71,
|
||||
72, 73, 74, 75, 76, 77, 78, 80, 81, 82, 83, 84, 86, 87, 88, 89,
|
||||
91, 92, 93, 94, 96, 97, 98, 100, 101, 102, 104, 105, 106, 108, 109, 110,
|
||||
112, 113, 115, 116, 118, 119, 121, 122, 123, 125, 126, 128, 130, 131, 133, 134,
|
||||
136, 137, 139, 140, 142, 144, 145, 147, 149, 150, 152, 154, 155, 157, 159, 160,
|
||||
162, 164, 166, 167, 169, 171, 173, 175, 176, 178, 180, 182, 184, 186, 187, 189,
|
||||
191, 193, 195, 197, 199, 201, 203, 205, 207, 209, 211, 213, 215, 217, 219, 221,
|
||||
223, 225, 227, 229, 231, 233, 235, 238, 240, 242, 244, 246, 248, 251, 253, 255
|
||||
};
|
||||
74
lib/NeoPixelBus_by_Makuna/src/internal/NeoGamma.h
Normal file
74
lib/NeoPixelBus_by_Makuna/src/internal/NeoGamma.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
NeoGamma class is used to correct RGB colors for human eye gamma levels equally
|
||||
across all color channels
|
||||
|
||||
Written by Michael C. Miller.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
#pragma once
|
||||
|
||||
// NeoGammaEquationMethod uses no memory but is slower than NeoGammaTableMethod
|
||||
class NeoGammaEquationMethod
|
||||
{
|
||||
public:
|
||||
static uint8_t Correct(uint8_t value)
|
||||
{
|
||||
return static_cast<uint8_t>(255.0f * NeoEase::Gamma(value / 255.0f) + 0.5f);
|
||||
}
|
||||
};
|
||||
|
||||
// NeoGammaTableMethod uses 256 bytes of memory, but is significantly faster
|
||||
class NeoGammaTableMethod
|
||||
{
|
||||
public:
|
||||
static uint8_t Correct(uint8_t value)
|
||||
{
|
||||
return _table[value];
|
||||
}
|
||||
|
||||
private:
|
||||
static const uint8_t _table[256];
|
||||
};
|
||||
|
||||
|
||||
// use one of the method classes above as a converter for this template class
|
||||
template<typename T_METHOD> class NeoGamma
|
||||
{
|
||||
public:
|
||||
RgbColor Correct(const RgbColor& original)
|
||||
{
|
||||
return RgbColor(T_METHOD::Correct(original.R),
|
||||
T_METHOD::Correct(original.G),
|
||||
T_METHOD::Correct(original.B));
|
||||
}
|
||||
|
||||
RgbwColor Correct(const RgbwColor& original)
|
||||
{
|
||||
return RgbwColor(T_METHOD::Correct(original.R),
|
||||
T_METHOD::Correct(original.G),
|
||||
T_METHOD::Correct(original.B),
|
||||
T_METHOD::Correct(original.W) );
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
118
lib/NeoPixelBus_by_Makuna/src/internal/NeoHueBlend.h
Normal file
118
lib/NeoPixelBus_by_Makuna/src/internal/NeoHueBlend.h
Normal file
@@ -0,0 +1,118 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
NeoHueBlend provides method objects that can be directly consumed by
|
||||
blend template functions in HslColor and HsbColor
|
||||
|
||||
Written by Michael C. Miller.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
#pragma once
|
||||
|
||||
class NeoHueBlendBase
|
||||
{
|
||||
protected:
|
||||
static float FixWrap(float value)
|
||||
{
|
||||
if (value < 0.0f)
|
||||
{
|
||||
value += 1.0f;
|
||||
}
|
||||
else if (value > 1.0f)
|
||||
{
|
||||
value -= 1.0f;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
class NeoHueBlendShortestDistance : NeoHueBlendBase
|
||||
{
|
||||
public:
|
||||
static float HueBlend(float left, float right, float progress)
|
||||
{
|
||||
float delta = right - left;
|
||||
float base = left;
|
||||
if (delta > 0.5f)
|
||||
{
|
||||
base = right;
|
||||
delta = 1.0f - delta;
|
||||
progress = 1.0f - progress;
|
||||
}
|
||||
else if (delta < -0.5f)
|
||||
{
|
||||
delta = 1.0f + delta;
|
||||
}
|
||||
return FixWrap(base + (delta) * progress);
|
||||
};
|
||||
};
|
||||
|
||||
class NeoHueBlendLongestDistance : NeoHueBlendBase
|
||||
{
|
||||
public:
|
||||
static float HueBlend(float left, float right, float progress)
|
||||
{
|
||||
float delta = right - left;
|
||||
float base = left;
|
||||
if (delta < 0.5f && delta >= 0.0f)
|
||||
{
|
||||
base = right;
|
||||
delta = 1.0f - delta;
|
||||
progress = 1.0f - progress;
|
||||
}
|
||||
else if (delta > -0.5f && delta < 0.0f)
|
||||
{
|
||||
delta = 1.0f + delta;
|
||||
}
|
||||
return FixWrap(base + delta * progress);
|
||||
};
|
||||
};
|
||||
|
||||
class NeoHueBlendClockwiseDirection : NeoHueBlendBase
|
||||
{
|
||||
public:
|
||||
static float HueBlend(float left, float right, float progress)
|
||||
{
|
||||
float delta = right - left;
|
||||
float base = left;
|
||||
if (delta < 0.0f)
|
||||
{
|
||||
delta = 1.0f + delta;
|
||||
}
|
||||
|
||||
return FixWrap(base + delta * progress);
|
||||
};
|
||||
};
|
||||
|
||||
class NeoHueBlendCounterClockwiseDirection : NeoHueBlendBase
|
||||
{
|
||||
public:
|
||||
static float HueBlend(float left, float right, float progress)
|
||||
{
|
||||
float delta = right - left;
|
||||
float base = left;
|
||||
if (delta > 0.0f)
|
||||
{
|
||||
delta = delta - 1.0f;
|
||||
}
|
||||
|
||||
return FixWrap(base + delta * progress);
|
||||
};
|
||||
};
|
||||
191
lib/NeoPixelBus_by_Makuna/src/internal/NeoMosaic.h
Normal file
191
lib/NeoPixelBus_by_Makuna/src/internal/NeoMosaic.h
Normal file
@@ -0,0 +1,191 @@
|
||||
#pragma once
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
Mosiac provides a mapping feature of a 2d cordinate to linear 1d cordinate
|
||||
It is used to map tiles of matricies of NeoPixels to a index on the NeoPixelBus
|
||||
where the the matricies use a set of prefered topology and the tiles of
|
||||
those matricies use the RowMajorAlternating layout
|
||||
|
||||
Written by Michael C. Miller.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// class NeoMosaic
|
||||
// Complex Tile layout class that reduces distance of the interconnects between
|
||||
// the tiles by using different rotations of the layout at specific locations
|
||||
//
|
||||
// T_LAYOUT = the layout used for matrix panel (rotation is ignored)
|
||||
//
|
||||
// NOTE: The tiles in the mosaic are always laid out using RowMajorAlternating
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
template <typename T_LAYOUT> class NeoMosaic
|
||||
{
|
||||
public:
|
||||
NeoMosaic(uint16_t topoWidth, uint16_t topoHeight,
|
||||
uint16_t mosaicWidth, uint16_t mosaicHeight) :
|
||||
_topoWidth(topoWidth),
|
||||
_topoHeight(topoHeight),
|
||||
_mosaicWidth(mosaicWidth),
|
||||
_mosaicHeight(mosaicHeight)
|
||||
{
|
||||
}
|
||||
|
||||
uint16_t Map(int16_t x, int16_t y) const
|
||||
{
|
||||
uint16_t totalWidth = getWidth();
|
||||
uint16_t totalHeight = getHeight();
|
||||
|
||||
if (x >= totalWidth)
|
||||
{
|
||||
x = totalWidth - 1;
|
||||
}
|
||||
else if (x < 0)
|
||||
{
|
||||
x = 0;
|
||||
}
|
||||
|
||||
if (y >= totalHeight)
|
||||
{
|
||||
y = totalHeight - 1;
|
||||
}
|
||||
else if (y < 0)
|
||||
{
|
||||
y = 0;
|
||||
}
|
||||
|
||||
uint16_t localIndex;
|
||||
uint16_t tileOffset;
|
||||
|
||||
calculate(x, y, &localIndex, &tileOffset);
|
||||
|
||||
return localIndex + tileOffset;
|
||||
}
|
||||
|
||||
uint16_t MapProbe(int16_t x, int16_t y) const
|
||||
{
|
||||
uint16_t totalWidth = getWidth();
|
||||
uint16_t totalHeight = getHeight();
|
||||
|
||||
if (x < 0 || x >= totalWidth || y < 0 || y >= totalHeight)
|
||||
{
|
||||
return totalWidth * totalHeight; // count, out of bounds
|
||||
}
|
||||
|
||||
uint16_t localIndex;
|
||||
uint16_t tileOffset;
|
||||
|
||||
calculate(x, y, &localIndex, &tileOffset);
|
||||
|
||||
return localIndex + tileOffset;
|
||||
}
|
||||
|
||||
NeoTopologyHint TopologyHint(int16_t x, int16_t y) const
|
||||
{
|
||||
uint16_t totalWidth = getWidth();
|
||||
uint16_t totalHeight = getHeight();
|
||||
|
||||
if (x < 0 || x >= totalWidth || y < 0 || y >= totalHeight)
|
||||
{
|
||||
return NeoTopologyHint_OutOfBounds;
|
||||
}
|
||||
|
||||
uint16_t localIndex;
|
||||
uint16_t tileOffset;
|
||||
NeoTopologyHint result;
|
||||
|
||||
calculate(x, y, &localIndex, &tileOffset);
|
||||
|
||||
if (localIndex == 0)
|
||||
{
|
||||
result = NeoTopologyHint_FirstOnPanel;
|
||||
}
|
||||
else if (localIndex == (_topoWidth * _topoHeight - 1))
|
||||
{
|
||||
result = NeoTopologyHint_LastOnPanel;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = NeoTopologyHint_InPanel;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uint16_t getWidth() const
|
||||
{
|
||||
return _topoWidth * _mosaicWidth;
|
||||
}
|
||||
|
||||
uint16_t getHeight() const
|
||||
{
|
||||
return _topoHeight * _mosaicHeight;
|
||||
}
|
||||
|
||||
private:
|
||||
const uint16_t _topoWidth;
|
||||
const uint16_t _topoHeight;
|
||||
const uint16_t _mosaicWidth;
|
||||
const uint16_t _mosaicHeight;
|
||||
|
||||
void calculate(uint16_t x, uint16_t y, uint16_t* pLocalIndex, uint16_t* pTileOffset) const
|
||||
{
|
||||
uint16_t tileX = x / _topoWidth;
|
||||
uint16_t topoX = x % _topoWidth;
|
||||
|
||||
uint16_t tileY = y / _topoHeight;
|
||||
uint16_t topoY = y % _topoHeight;
|
||||
|
||||
*pTileOffset = RowMajorAlternatingLayout::Map(_mosaicWidth,
|
||||
_mosaicHeight,
|
||||
tileX,
|
||||
tileY) * _topoWidth * _topoHeight;
|
||||
|
||||
if (tileX & 0x0001)
|
||||
{
|
||||
// odd columns
|
||||
if (tileY & 0x0001)
|
||||
{
|
||||
*pLocalIndex = T_LAYOUT::OddRowOddColumnLayout::Map(_topoWidth, _topoHeight, topoX, topoY);
|
||||
}
|
||||
else
|
||||
{
|
||||
*pLocalIndex = T_LAYOUT::EvenRowOddColumnLayout::Map(_topoWidth, _topoHeight, topoX, topoY);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// even columns
|
||||
if (tileY & 0x0001)
|
||||
{
|
||||
*pLocalIndex = T_LAYOUT::OddRowEvenColumnLayout::Map(_topoWidth, _topoHeight, topoX, topoY);
|
||||
}
|
||||
else
|
||||
{
|
||||
*pLocalIndex = T_LAYOUT::EvenRowEvenColumnLayout::Map(_topoWidth, _topoHeight, topoX, topoY);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
490
lib/NeoPixelBus_by_Makuna/src/internal/NeoNrf52xMethod.h
Normal file
490
lib/NeoPixelBus_by_Makuna/src/internal/NeoNrf52xMethod.h
Normal file
@@ -0,0 +1,490 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
NeoPixel library helper classes for Nrf52* MCUs.
|
||||
Nano 33 BLE
|
||||
|
||||
Written by Michael C. Miller.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
The contents of this file were taken from the Adafruit NeoPixel library
|
||||
and modified only to fit within individual calling functions.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if defined(ARDUINO_ARCH_NRF52840)
|
||||
|
||||
const uint16_t c_dmaBytesPerDataByte = 8 * sizeof(nrf_pwm_values_common_t); // bits * bytes to represent pulse
|
||||
|
||||
// for Bit* variables
|
||||
// count 1 = 0.0625us, so max count (32768) is 2048us
|
||||
|
||||
class NeoNrf52xPwmSpeedWs2811
|
||||
{
|
||||
public:
|
||||
const static uint32_t CountTop = 20UL; // 1.25us
|
||||
const static nrf_pwm_values_common_t Bit0 = 5 | 0x8000; // ~0.3us
|
||||
const static nrf_pwm_values_common_t Bit1 = 14 | 0x8000; // ~0.9us
|
||||
const static nrf_pwm_values_common_t BitReset = 0x8000; // LOW
|
||||
const static uint16_t CountReset = 240; // 300 us / 1.25us
|
||||
const static PinStatus IdleLevel = LOW;
|
||||
};
|
||||
|
||||
class NeoNrf52xPwmSpeedWs2812x
|
||||
{
|
||||
public:
|
||||
const static uint32_t CountTop = 20UL; // 1.25us
|
||||
const static nrf_pwm_values_common_t Bit0 = 6 | 0x8000; // ~0.4us
|
||||
const static nrf_pwm_values_common_t Bit1 = 13 | 0x8000; // ~0.8us
|
||||
const static nrf_pwm_values_common_t BitReset = 0x8000; // LOW
|
||||
const static uint32_t CountReset = 240 ; // 300us / 1.25us pulse width
|
||||
const static PinStatus IdleLevel = LOW;
|
||||
};
|
||||
|
||||
class NeoNrf52xPwmSpeedSk6812
|
||||
{
|
||||
public:
|
||||
const static uint32_t CountTop = 20UL; // 1.25us
|
||||
const static nrf_pwm_values_common_t Bit0 = 6 | 0x8000; // ~0.4us
|
||||
const static nrf_pwm_values_common_t Bit1 = 13 | 0x8000; // ~0.8us
|
||||
const static nrf_pwm_values_common_t BitReset = 0x8000; // LOW
|
||||
const static uint32_t CountReset = 64; // 80us / 1.25us pulse width
|
||||
const static PinStatus IdleLevel = LOW;
|
||||
};
|
||||
|
||||
class NeoNrf52xPwmSpeedTm1814
|
||||
{
|
||||
public:
|
||||
const static uint32_t CountTop = 20UL; // 1.25us
|
||||
const static nrf_pwm_values_common_t Bit0 = 5; // ~0.3us
|
||||
const static nrf_pwm_values_common_t Bit1 = 12; // ~0.7us
|
||||
const static nrf_pwm_values_common_t BitReset = 0x0000; // HIGH
|
||||
const static uint32_t CountReset = 160; // 200us / 1.25us pulse width
|
||||
const static PinStatus IdleLevel = HIGH;
|
||||
};
|
||||
|
||||
class NeoNrf52xPwmSpeed800Kbps
|
||||
{
|
||||
public:
|
||||
const static uint32_t CountTop = 20UL; // 1.25us
|
||||
const static nrf_pwm_values_common_t Bit0 = 6 | 0x8000; // ~0.4us
|
||||
const static nrf_pwm_values_common_t Bit1 = 13 | 0x8000; // ~0.8us
|
||||
const static nrf_pwm_values_common_t BitReset = 0x8000; // LOW
|
||||
const static uint32_t CountReset = 40; // 50us / 1.25us pulse width
|
||||
const static PinStatus IdleLevel = LOW;
|
||||
};
|
||||
|
||||
class NeoNrf52xPwmSpeed400Kbps
|
||||
{
|
||||
public:
|
||||
const static uint32_t CountTop = 40UL; // 2.5us
|
||||
const static nrf_pwm_values_common_t Bit0 = 13 | 0x8000; // ~0.8us
|
||||
const static nrf_pwm_values_common_t Bit1 = 26 | 0x8000; // ~1.6us
|
||||
const static nrf_pwm_values_common_t BitReset = 0x8000; // LOW
|
||||
const static uint16_t CountReset = 20; // 50 us / 2.5us
|
||||
const static PinStatus IdleLevel = LOW;
|
||||
};
|
||||
|
||||
class NeoNrf52xPwmSpeedApa106
|
||||
{
|
||||
public:
|
||||
const static uint32_t CountTop = 26UL; // 1.65us
|
||||
const static nrf_pwm_values_common_t Bit0 = 6 | 0x8000; // ~0.4us
|
||||
const static nrf_pwm_values_common_t Bit1 = 20 | 0x8000; // ~1.25us
|
||||
const static nrf_pwm_values_common_t BitReset = 0x8000; // LOW
|
||||
const static uint32_t CountReset = 40; // 50us / 1.25us pulse width
|
||||
const static PinStatus IdleLevel = LOW;
|
||||
};
|
||||
|
||||
class NeoNrf52xPwmInvertedSpeedWs2811
|
||||
{
|
||||
public:
|
||||
const static uint32_t CountTop = 20UL; // 1.25us
|
||||
const static nrf_pwm_values_common_t Bit0 = 5; // ~0.3us
|
||||
const static nrf_pwm_values_common_t Bit1 = 14; // ~0.9us
|
||||
const static nrf_pwm_values_common_t BitReset = 0x0000; // HIGH
|
||||
const static uint16_t CountReset = 240; // 300 us / 1.25us
|
||||
const static PinStatus IdleLevel = HIGH;
|
||||
};
|
||||
|
||||
class NeoNrf52xPwmInvertedSpeedWs2812x
|
||||
{
|
||||
public:
|
||||
const static uint32_t CountTop = 20UL; // 1.25us
|
||||
const static nrf_pwm_values_common_t Bit0 = 6; // ~0.4us
|
||||
const static nrf_pwm_values_common_t Bit1 = 13; // ~0.8us
|
||||
const static nrf_pwm_values_common_t BitReset = 0x0000; // HIGH
|
||||
const static uint32_t CountReset = 240; // 300us / 1.25us pulse width
|
||||
const static PinStatus IdleLevel = HIGH;
|
||||
};
|
||||
|
||||
class NeoNrf52xPwmInvertedSpeedSk6812
|
||||
{
|
||||
public:
|
||||
const static uint32_t CountTop = 20UL; // 1.25us
|
||||
const static nrf_pwm_values_common_t Bit0 = 6; // ~0.4us
|
||||
const static nrf_pwm_values_common_t Bit1 = 13; // ~0.8us
|
||||
const static nrf_pwm_values_common_t BitReset = 0x0000; // HIGH
|
||||
const static uint32_t CountReset = 64; // 80us / 1.25us pulse width
|
||||
const static PinStatus IdleLevel = HIGH;
|
||||
};
|
||||
|
||||
class NeoNrf52xPwmInvertedSpeedTm1814
|
||||
{
|
||||
public:
|
||||
const static uint32_t CountTop = 20UL; // 1.25us
|
||||
const static nrf_pwm_values_common_t Bit0 = 5 | 0x8000; // ~0.3us
|
||||
const static nrf_pwm_values_common_t Bit1 = 12 | 0x8000; // ~0.7us
|
||||
const static nrf_pwm_values_common_t BitReset = 0x8000; // LOW
|
||||
const static uint32_t CountReset = 160; // 200us / 1.25us pulse width
|
||||
const static PinStatus IdleLevel = LOW;
|
||||
};
|
||||
|
||||
class NeoNrf52xPwmInvertedSpeed800Kbps
|
||||
{
|
||||
public:
|
||||
const static uint32_t CountTop = 20UL; // 1.25us
|
||||
const static nrf_pwm_values_common_t Bit0 = 6; // ~0.4us
|
||||
const static nrf_pwm_values_common_t Bit1 = 13; // ~0.8us
|
||||
const static nrf_pwm_values_common_t BitReset = 0x0000; // HIGH
|
||||
const static uint32_t CountReset = 40; // 50us / 1.25us pulse width
|
||||
const static PinStatus IdleLevel = HIGH;
|
||||
};
|
||||
|
||||
class NeoNrf52xPwmInvertedSpeed400Kbps
|
||||
{
|
||||
public:
|
||||
const static uint32_t CountTop = 40UL; // 2.5us
|
||||
const static nrf_pwm_values_common_t Bit0 = 13; // ~0.8us
|
||||
const static nrf_pwm_values_common_t Bit1 = 26; // ~1.6us
|
||||
const static nrf_pwm_values_common_t BitReset = 0x0000; // HIGH
|
||||
const static uint16_t CountReset = 20; // 50 us / 2.5us
|
||||
const static PinStatus IdleLevel = HIGH;
|
||||
};
|
||||
|
||||
class NeoNrf52xPwmInvertedSpeedApa106
|
||||
{
|
||||
public:
|
||||
const static uint32_t CountTop = 26UL; // 1.65us
|
||||
const static nrf_pwm_values_common_t Bit0 = 6; // ~0.4us
|
||||
const static nrf_pwm_values_common_t Bit1 = 20; // ~1.25us
|
||||
const static nrf_pwm_values_common_t BitReset = 0x0000; // HIGH
|
||||
const static uint32_t CountReset = 40; // 50us / 1.25us pulse width
|
||||
const static PinStatus IdleLevel = HIGH;
|
||||
};
|
||||
|
||||
class NeoNrf52xPwm0
|
||||
{
|
||||
public:
|
||||
inline static NRF_PWM_Type* Pwm()
|
||||
{
|
||||
return NRF_PWM0;
|
||||
}
|
||||
};
|
||||
|
||||
class NeoNrf52xPwm1
|
||||
{
|
||||
public:
|
||||
inline static NRF_PWM_Type* Pwm()
|
||||
{
|
||||
return NRF_PWM1;
|
||||
}
|
||||
};
|
||||
|
||||
class NeoNrf52xPwm2
|
||||
{
|
||||
public:
|
||||
inline static NRF_PWM_Type* Pwm()
|
||||
{
|
||||
return NRF_PWM2;
|
||||
}
|
||||
};
|
||||
|
||||
#if defined(NRF_PWM3)
|
||||
class NeoNrf52xPwm3
|
||||
{
|
||||
public:
|
||||
inline static NRF_PWM_Type* Pwm()
|
||||
{
|
||||
return NRF_PWM3;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
template<typename T_SPEED, typename T_BUS> class NeoNrf52xMethodBase
|
||||
{
|
||||
public:
|
||||
NeoNrf52xMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize) :
|
||||
_sizeData(pixelCount * elementSize + settingsSize),
|
||||
_pin(pin)
|
||||
{
|
||||
pinMode(pin, OUTPUT);
|
||||
|
||||
_data = static_cast<uint8_t*>(malloc(_sizeData));
|
||||
memset(_data, 0, _sizeData);
|
||||
|
||||
_dmaBufferSize = c_dmaBytesPerDataByte * _sizeData + sizeof(nrf_pwm_values_common_t);
|
||||
_dmaBuffer = static_cast<nrf_pwm_values_common_t*>(malloc(_dmaBufferSize));
|
||||
}
|
||||
|
||||
~NeoNrf52xMethodBase()
|
||||
{
|
||||
while (!IsReadyToUpdate())
|
||||
{
|
||||
yield();
|
||||
}
|
||||
|
||||
dmaDeinit();
|
||||
|
||||
pinMode(_pin, INPUT);
|
||||
|
||||
free(_data);
|
||||
free(_dmaBuffer);
|
||||
}
|
||||
|
||||
bool IsReadyToUpdate() const
|
||||
{
|
||||
return (T_BUS::Pwm()->EVENTS_STOPPED);
|
||||
}
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
digitalWrite(_pin, T_SPEED::IdleLevel);
|
||||
|
||||
dmaInit();
|
||||
|
||||
// must force a first update so the EVENTS_SEQEND gets set as
|
||||
// you can't set it manually
|
||||
FillBuffer();
|
||||
dmaStart();
|
||||
}
|
||||
|
||||
void Update(bool)
|
||||
{
|
||||
// Data latch = 50+ microsecond pause in the output stream. Rather than
|
||||
// put a delay at the end of the function, the ending time is noted and
|
||||
// the function will simply hold off (if needed) on issuing the
|
||||
// subsequent round of data until the latch time has elapsed. This
|
||||
// allows the mainline code to start generating the next frame of data
|
||||
// rather than stalling for the latch.
|
||||
while (!IsReadyToUpdate())
|
||||
{
|
||||
yield(); // allows for system yield if needed
|
||||
}
|
||||
|
||||
FillBuffer();
|
||||
dmaStart();
|
||||
}
|
||||
|
||||
uint8_t* getData() const
|
||||
{
|
||||
return _data;
|
||||
};
|
||||
|
||||
size_t getDataSize() const
|
||||
{
|
||||
return _sizeData;
|
||||
};
|
||||
|
||||
private:
|
||||
const size_t _sizeData; // Size of '_data' buffer below
|
||||
const uint8_t _pin; // output pin number
|
||||
|
||||
uint8_t* _data; // Holds LED color values
|
||||
size_t _dmaBufferSize; // total size of _dmaBuffer
|
||||
nrf_pwm_values_common_t* _dmaBuffer; // Holds pixel data in native format for PWM hardware
|
||||
|
||||
void dmaInit()
|
||||
{
|
||||
// only use channel zero
|
||||
T_BUS::Pwm()->PSEL.OUT[0] = digitalPinToPinName(_pin);
|
||||
T_BUS::Pwm()->PSEL.OUT[1] = NC;
|
||||
T_BUS::Pwm()->PSEL.OUT[2] = NC;
|
||||
T_BUS::Pwm()->PSEL.OUT[3] = NC;
|
||||
|
||||
T_BUS::Pwm()->ENABLE = 1;
|
||||
T_BUS::Pwm()->MODE = NRF_PWM_MODE_UP;
|
||||
T_BUS::Pwm()->PRESCALER = NRF_PWM_CLK_16MHz;
|
||||
T_BUS::Pwm()->COUNTERTOP = T_SPEED::CountTop;
|
||||
T_BUS::Pwm()->LOOP = 1; // single fire so events get set
|
||||
T_BUS::Pwm()->DECODER = NRF_PWM_LOAD_COMMON;
|
||||
|
||||
// sequence zero is the primary data with a BitReset entry on the end for
|
||||
// the delay repeating
|
||||
T_BUS::Pwm()->SEQ[0].PTR = reinterpret_cast<uint32_t>(_dmaBuffer);
|
||||
T_BUS::Pwm()->SEQ[0].CNT = _dmaBufferSize / sizeof(nrf_pwm_values_common_t);
|
||||
T_BUS::Pwm()->SEQ[0].REFRESH = 0; // ignored
|
||||
T_BUS::Pwm()->SEQ[0].ENDDELAY = T_SPEED::CountReset; // ignored still?
|
||||
|
||||
// sequence one is pointing to the BitReset entry at the end of the primary data
|
||||
T_BUS::Pwm()->SEQ[1].PTR = reinterpret_cast<uint32_t>(_dmaBuffer + (T_BUS::Pwm()->SEQ[0].CNT - 1));
|
||||
T_BUS::Pwm()->SEQ[1].CNT = 1;
|
||||
T_BUS::Pwm()->SEQ[1].REFRESH = 0; // ignored
|
||||
T_BUS::Pwm()->SEQ[1].ENDDELAY = 0; // ignored
|
||||
|
||||
// stop when the loop finishes
|
||||
T_BUS::Pwm()->SHORTS = PWM_SHORTS_LOOPSDONE_STOP_Msk;
|
||||
T_BUS::Pwm()->INTEN = 0;
|
||||
|
||||
dmaResetEvents();
|
||||
}
|
||||
|
||||
void dmaDeinit()
|
||||
{
|
||||
T_BUS::Pwm()->ENABLE = 0;
|
||||
T_BUS::Pwm()->PSEL.OUT[0] = NC;
|
||||
}
|
||||
|
||||
void FillBuffer()
|
||||
{
|
||||
nrf_pwm_values_common_t* pDma = _dmaBuffer;
|
||||
nrf_pwm_values_common_t* pDmaEnd = _dmaBuffer + (_dmaBufferSize / sizeof(nrf_pwm_values_common_t));
|
||||
uint8_t* pEnd = _data + _sizeData;
|
||||
|
||||
for (uint8_t* pData = _data; pData < pEnd; pData++)
|
||||
{
|
||||
uint8_t data = *pData;
|
||||
|
||||
for (uint8_t bit = 0; bit < 8; bit++)
|
||||
{
|
||||
*(pDma++) = (data & 0x80) ? T_SPEED::Bit1 : T_SPEED::Bit0;
|
||||
data <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
// fill the rest with BitReset as it will get repeated when delaying or
|
||||
// at the end before being stopped
|
||||
while (pDma < pDmaEnd)
|
||||
{
|
||||
*(pDma++) = T_SPEED::BitReset;
|
||||
}
|
||||
}
|
||||
|
||||
void dmaResetEvents()
|
||||
{
|
||||
T_BUS::Pwm()->EVENTS_LOOPSDONE = 0;
|
||||
T_BUS::Pwm()->EVENTS_SEQEND[0] = 0;
|
||||
T_BUS::Pwm()->EVENTS_SEQEND[1] = 0;
|
||||
T_BUS::Pwm()->EVENTS_STOPPED = 0;
|
||||
}
|
||||
|
||||
void dmaStart()
|
||||
{
|
||||
dmaResetEvents();
|
||||
T_BUS::Pwm()->TASKS_SEQSTART[0] = 1;
|
||||
}
|
||||
};
|
||||
|
||||
// normal
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedWs2811, NeoNrf52xPwm0> NeoNrf52xPwm0Ws2811Method;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedWs2812x, NeoNrf52xPwm0> NeoNrf52xPwm0Ws2812xMethod;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedSk6812, NeoNrf52xPwm0> NeoNrf52xPwm0Sk6812Method;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedTm1814, NeoNrf52xPwm0> NeoNrf52xPwm0Tm1814Method;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedApa106, NeoNrf52xPwm0> NeoNrf52xPwm0Apa106Method;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeed800Kbps, NeoNrf52xPwm0> NeoNrf52xPwm0800KbpsMethod;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeed400Kbps, NeoNrf52xPwm0> NeoNrf52xPwm0400KbpsMethod;
|
||||
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedWs2811, NeoNrf52xPwm1> NeoNrf52xPwm1Ws2811Method;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedWs2812x, NeoNrf52xPwm1> NeoNrf52xPwm1Ws2812xMethod;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedSk6812, NeoNrf52xPwm1> NeoNrf52xPwm1Sk6812Method;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedTm1814, NeoNrf52xPwm1> NeoNrf52xPwm1Tm1814Method;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedApa106, NeoNrf52xPwm1> NeoNrf52xPwm1Apa106Method;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeed800Kbps, NeoNrf52xPwm1> NeoNrf52xPwm1800KbpsMethod;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeed400Kbps, NeoNrf52xPwm1> NeoNrf52xPwm1400KbpsMethod;
|
||||
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedWs2811, NeoNrf52xPwm2> NeoNrf52xPwm2Ws2811Method;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedWs2812x, NeoNrf52xPwm2> NeoNrf52xPwm2Ws2812xMethod;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedSk6812, NeoNrf52xPwm2> NeoNrf52xPwm2Sk6812Method;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedTm1814, NeoNrf52xPwm2> NeoNrf52xPwm2Tm1814Method;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedApa106, NeoNrf52xPwm2> NeoNrf52xPwm2Apa106Method;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeed800Kbps, NeoNrf52xPwm2> NeoNrf52xPwm2800KbpsMethod;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeed400Kbps, NeoNrf52xPwm2> NeoNrf52xPwm2400KbpsMethod;
|
||||
|
||||
#if defined(NRF_PWM3)
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedWs2811, NeoNrf52xPwm3> NeoNrf52xPwm3Ws2811Method;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedWs2812x, NeoNrf52xPwm3> NeoNrf52xPwm3Ws2812xMethod;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedSk6812, NeoNrf52xPwm3> NeoNrf52xPwm3Sk6812Method;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedTm1814, NeoNrf52xPwm3> NeoNrf52xPwm3Tm1814Method;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeedApa106, NeoNrf52xPwm3> NeoNrf52xPwm3Apa106Method;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeed800Kbps, NeoNrf52xPwm3> NeoNrf52xPwm3800KbpsMethod;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmSpeed400Kbps, NeoNrf52xPwm3> NeoNrf52xPwm3400KbpsMethod;
|
||||
#endif
|
||||
|
||||
// inverted
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedWs2811, NeoNrf52xPwm0> NeoNrf52xPwm0Ws2811InvertedMethod;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedWs2812x, NeoNrf52xPwm0> NeoNrf52xPwm0Ws2812xInvertedMethod;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedSk6812, NeoNrf52xPwm0> NeoNrf52xPwm0Sk6812InvertedMethod;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedTm1814, NeoNrf52xPwm0> NeoNrf52xPwm0Tm1814InvertedMethod;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedApa106, NeoNrf52xPwm0> NeoNrf52xPwm0Apa106InvertedMethod;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeed800Kbps, NeoNrf52xPwm0> NeoNrf52xPwm0800KbpsInvertedMethod;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeed400Kbps, NeoNrf52xPwm0> NeoNrf52xPwm0400KbpsInvertedMethod;
|
||||
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedWs2811, NeoNrf52xPwm1> NeoNrf52xPwm1Ws2811InvertedMethod;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedWs2812x, NeoNrf52xPwm1> NeoNrf52xPwm1Ws2812xInvertedMethod;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedSk6812, NeoNrf52xPwm1> NeoNrf52xPwm1Sk6812InvertedMethod;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedTm1814, NeoNrf52xPwm1> NeoNrf52xPwm1Tm1814InvertedMethod;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedApa106, NeoNrf52xPwm1> NeoNrf52xPwm1Apa106InvertedMethod;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeed800Kbps, NeoNrf52xPwm1> NeoNrf52xPwm1800KbpsInvertedMethod;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeed400Kbps, NeoNrf52xPwm1> NeoNrf52xPwm1400KbpsInvertedMethod;
|
||||
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedWs2811, NeoNrf52xPwm2> NeoNrf52xPwm2Ws2811InvertedMethod;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedWs2812x, NeoNrf52xPwm2> NeoNrf52xPwm2Ws2812xInvertedMethod;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedSk6812, NeoNrf52xPwm2> NeoNrf52xPwm2Sk6812InvertedMethod;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedTm1814, NeoNrf52xPwm2> NeoNrf52xPwm2Tm1814InvertedMethod;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedApa106, NeoNrf52xPwm2> NeoNrf52xPwm2Apa106InvertedMethod;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeed800Kbps, NeoNrf52xPwm2> NeoNrf52xPwm2800KbpsInvertedMethod;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeed400Kbps, NeoNrf52xPwm2> NeoNrf52xPwm2400KbpsInvertedMethod;
|
||||
|
||||
#if defined(NRF_PWM3)
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedWs2811, NeoNrf52xPwm3> NeoNrf52xPwm3Ws2811InvertedMethod;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedWs2812x, NeoNrf52xPwm3> NeoNrf52xPwm3Ws2812xInvertedMethod;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedSk6812, NeoNrf52xPwm3> NeoNrf52xPwm3Sk6812InvertedMethod;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedTm1814, NeoNrf52xPwm3> NeoNrf52xPwm3Tm1814InvertedMethod;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeedApa106, NeoNrf52xPwm3> NeoNrf52xPwm3Apa106InvertedMethod;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeed800Kbps, NeoNrf52xPwm3> NeoNrf52xPwm3800KbpsInvertedMethod;
|
||||
typedef NeoNrf52xMethodBase<NeoNrf52xPwmInvertedSpeed400Kbps, NeoNrf52xPwm3> NeoNrf52xPwm3400KbpsInvertedMethod;
|
||||
#endif
|
||||
|
||||
// defaults
|
||||
typedef NeoNrf52xPwm2Ws2812xMethod NeoWs2813Method;
|
||||
typedef NeoNrf52xPwm2Ws2812xMethod NeoWs2812xMethod;
|
||||
typedef NeoNrf52xPwm2800KbpsMethod NeoWs2812Method;
|
||||
typedef NeoNrf52xPwm2Ws2812xMethod NeoWs2811Method;
|
||||
typedef NeoNrf52xPwm2Sk6812Method NeoSk6812Method;
|
||||
typedef NeoNrf52xPwm2Tm1814Method NeoTm1814Method;
|
||||
typedef NeoNrf52xPwm2Sk6812Method NeoLc8812Method;
|
||||
typedef NeoNrf52xPwm2Apa106Method NeoApa106Method;
|
||||
|
||||
typedef NeoNrf52xPwm2Ws2812xMethod Neo800KbpsMethod;
|
||||
typedef NeoNrf52xPwm2400KbpsMethod Neo400KbpsMethod;
|
||||
|
||||
typedef NeoNrf52xPwm2Ws2812xInvertedMethod NeoWs2813InvertedMethod;
|
||||
typedef NeoNrf52xPwm2Ws2812xInvertedMethod NeoWs2812xInvertedMethod;
|
||||
typedef NeoNrf52xPwm2Ws2812xInvertedMethod NeoWs2811InvertedMethod;
|
||||
typedef NeoNrf52xPwm2800KbpsInvertedMethod NeoWs2812InvertedMethod;
|
||||
typedef NeoNrf52xPwm2Sk6812InvertedMethod NeoSk6812InvertedMethod;
|
||||
typedef NeoNrf52xPwm2Tm1814InvertedMethod NeoTm1814InvertedMethod;
|
||||
typedef NeoNrf52xPwm2Sk6812InvertedMethod NeoLc8812InvertedMethod;
|
||||
typedef NeoNrf52xPwm2Apa106InvertedMethod NeoApa106InvertedMethod;
|
||||
|
||||
typedef NeoNrf52xPwm2Ws2812xInvertedMethod Neo800KbpsInvertedMethod;
|
||||
typedef NeoNrf52xPwm2400KbpsInvertedMethod Neo400KbpsInvertedMethod;
|
||||
|
||||
#endif
|
||||
197
lib/NeoPixelBus_by_Makuna/src/internal/NeoPixelAnimator.cpp
Normal file
197
lib/NeoPixelBus_by_Makuna/src/internal/NeoPixelAnimator.cpp
Normal file
@@ -0,0 +1,197 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
NeoPixelAnimator provides animation timing support.
|
||||
|
||||
Written by Michael C. Miller.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
|
||||
#include "NeoPixelBus.h"
|
||||
#include "NeoPixelAnimator.h"
|
||||
|
||||
NeoPixelAnimator::NeoPixelAnimator(uint16_t countAnimations, uint16_t timeScale) :
|
||||
_countAnimations(countAnimations),
|
||||
_animationLastTick(0),
|
||||
_activeAnimations(0),
|
||||
_isRunning(true)
|
||||
{
|
||||
setTimeScale(timeScale);
|
||||
_animations = new AnimationContext[_countAnimations];
|
||||
}
|
||||
|
||||
NeoPixelAnimator::~NeoPixelAnimator()
|
||||
{
|
||||
delete[] _animations;
|
||||
}
|
||||
|
||||
bool NeoPixelAnimator::NextAvailableAnimation(uint16_t* indexAvailable, uint16_t indexStart)
|
||||
{
|
||||
if (indexStart >= _countAnimations)
|
||||
{
|
||||
// last one
|
||||
indexStart = _countAnimations - 1;
|
||||
}
|
||||
|
||||
uint16_t next = indexStart;
|
||||
|
||||
do
|
||||
{
|
||||
if (!IsAnimationActive(next))
|
||||
{
|
||||
if (indexAvailable)
|
||||
{
|
||||
*indexAvailable = next;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
next = (next + 1) % _countAnimations;
|
||||
} while (next != indexStart);
|
||||
return false;
|
||||
}
|
||||
|
||||
void NeoPixelAnimator::StartAnimation(uint16_t indexAnimation,
|
||||
uint16_t duration,
|
||||
AnimUpdateCallback animUpdate)
|
||||
{
|
||||
if (indexAnimation >= _countAnimations || animUpdate == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_activeAnimations == 0)
|
||||
{
|
||||
_animationLastTick = millis();
|
||||
}
|
||||
|
||||
StopAnimation(indexAnimation);
|
||||
|
||||
// all animations must have at least non zero duration, otherwise
|
||||
// they are considered stopped
|
||||
if (duration == 0)
|
||||
{
|
||||
duration = 1;
|
||||
}
|
||||
|
||||
_animations[indexAnimation].StartAnimation(duration, animUpdate);
|
||||
|
||||
_activeAnimations++;
|
||||
}
|
||||
|
||||
void NeoPixelAnimator::StopAnimation(uint16_t indexAnimation)
|
||||
{
|
||||
if (indexAnimation >= _countAnimations)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsAnimationActive(indexAnimation))
|
||||
{
|
||||
_activeAnimations--;
|
||||
_animations[indexAnimation].StopAnimation();
|
||||
}
|
||||
}
|
||||
|
||||
void NeoPixelAnimator::StopAll()
|
||||
{
|
||||
for (uint16_t indexAnimation = 0; indexAnimation < _countAnimations; ++indexAnimation)
|
||||
{
|
||||
_animations[indexAnimation].StopAnimation();
|
||||
}
|
||||
_activeAnimations = 0;
|
||||
}
|
||||
|
||||
|
||||
void NeoPixelAnimator::UpdateAnimations()
|
||||
{
|
||||
if (_isRunning)
|
||||
{
|
||||
uint32_t currentTick = millis();
|
||||
uint32_t delta = currentTick - _animationLastTick;
|
||||
|
||||
if (delta >= _timeScale)
|
||||
{
|
||||
AnimationContext* pAnim;
|
||||
|
||||
delta /= _timeScale; // scale delta into animation time
|
||||
|
||||
for (uint16_t iAnim = 0; iAnim < _countAnimations; iAnim++)
|
||||
{
|
||||
pAnim = &_animations[iAnim];
|
||||
AnimUpdateCallback fnUpdate = pAnim->_fnCallback;
|
||||
AnimationParam param;
|
||||
|
||||
param.index = iAnim;
|
||||
|
||||
if (pAnim->_remaining > delta)
|
||||
{
|
||||
param.state = (pAnim->_remaining == pAnim->_duration) ? AnimationState_Started : AnimationState_Progress;
|
||||
param.progress = pAnim->CurrentProgress();
|
||||
|
||||
fnUpdate(param);
|
||||
|
||||
pAnim->_remaining -= delta;
|
||||
}
|
||||
else if (pAnim->_remaining > 0)
|
||||
{
|
||||
param.state = AnimationState_Completed;
|
||||
param.progress = 1.0f;
|
||||
|
||||
_activeAnimations--;
|
||||
pAnim->StopAnimation();
|
||||
|
||||
fnUpdate(param);
|
||||
}
|
||||
}
|
||||
|
||||
_animationLastTick = currentTick;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NeoPixelAnimator::ChangeAnimationDuration(uint16_t indexAnimation, uint16_t newDuration)
|
||||
{
|
||||
if (indexAnimation >= _countAnimations)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AnimationContext* pAnim = &_animations[indexAnimation];
|
||||
|
||||
// calc the current animation progress
|
||||
float progress = pAnim->CurrentProgress();
|
||||
|
||||
// keep progress in range just in case
|
||||
if (progress < 0.0f)
|
||||
{
|
||||
progress = 0.0f;
|
||||
}
|
||||
else if (progress > 1.0f)
|
||||
{
|
||||
progress = 1.0f;
|
||||
}
|
||||
|
||||
// change the duration
|
||||
pAnim->_duration = newDuration;
|
||||
|
||||
// _remaining time must also be reset after a duration change;
|
||||
// use the progress to recalculate it
|
||||
pAnim->_remaining = uint16_t(pAnim->_duration * (1.0f - progress));
|
||||
}
|
||||
648
lib/NeoPixelBus_by_Makuna/src/internal/NeoPixelAvr.c
Normal file
648
lib/NeoPixelBus_by_Makuna/src/internal/NeoPixelAvr.c
Normal file
@@ -0,0 +1,648 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
Arduino library to control a wide variety of WS2811- and WS2812-based RGB
|
||||
LED devices such as Adafruit FLORA RGB Smart Pixels and NeoPixel strips.
|
||||
Currently handles 400 and 800 KHz bitstreams on 8, 12 and 16 MHz ATmega
|
||||
MCUs, with LEDs wired for various color orders. 8 MHz MCUs provide
|
||||
output on PORTB and PORTD, while 16 MHz chips can handle most output pins
|
||||
(possible exception with upper PORT registers on the Arduino Mega).
|
||||
|
||||
Written by Phil Burgess / Paint Your Dragon for Adafruit Industries,
|
||||
contributions by PJRC, Michael Miller and other members of the open
|
||||
source community.
|
||||
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing products
|
||||
from Adafruit!
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
The contents of this file were taken from the Adafruit NeoPixel library
|
||||
and modified only to fit within individual calling functions.
|
||||
|
||||
NeoPixel is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixel is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
|
||||
// must also check for arm due to Teensy incorrectly having ARDUINO_ARCH_AVR set
|
||||
#if (defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_MEGAAVR)) && !defined(__arm__)
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
// Hand-tuned assembly code issues data to the LED drivers at a specific
|
||||
// rate. There's separate code for different CPU speeds (8, 12, 16 MHz)
|
||||
// for both the WS2811 (400 KHz) and WS2812 (800 KHz) drivers. The
|
||||
// datastream timing for the LED drivers allows a little wiggle room each
|
||||
// way (listed in the datasheets), so the conditions for compiling each
|
||||
// case are set up for a range of frequencies rather than just the exact
|
||||
// 8, 12 or 16 MHz values, permitting use with some close-but-not-spot-on
|
||||
// devices (e.g. 16.5 MHz DigiSpark). The ranges were arrived at based
|
||||
// on the datasheet figures and have not been extensively tested outside
|
||||
// the canonical 8/12/16 MHz speeds; there's no guarantee these will work
|
||||
// close to the extremes (or possibly they could be pushed further).
|
||||
// Keep in mind only one CPU speed case actually gets compiled; the
|
||||
// resulting program isn't as massive as it might look from source here.
|
||||
|
||||
#if (F_CPU >= 7400000UL) && (F_CPU <= 9500000UL) // 8Mhz CPU
|
||||
|
||||
#ifdef PORTD // PORTD isn't present on ATtiny85, etc.
|
||||
void send_data_8mhz_800_PortD(uint8_t* data, size_t sizeData, uint8_t pinMask)
|
||||
{
|
||||
volatile size_t i = sizeData; // Loop counter
|
||||
volatile uint8_t* ptr = data; // Pointer to next byte
|
||||
volatile uint8_t b = *ptr++; // Current byte value
|
||||
volatile uint8_t hi; // PORT w/output bit set high
|
||||
volatile uint8_t lo; // PORT w/output bit set low
|
||||
|
||||
volatile uint8_t n1;
|
||||
volatile uint8_t n2 = 0; // First, next bits out
|
||||
|
||||
// Squeezing an 800 KHz stream out of an 8 MHz chip requires code
|
||||
// specific to each PORT register. At present this is only written
|
||||
// to work with pins on PORTD or PORTB, the most likely use case --
|
||||
// this covers all the pins on the Adafruit Flora and the bulk of
|
||||
// digital pins on the Arduino Pro 8 MHz (keep in mind, this code
|
||||
// doesn't even get compiled for 16 MHz boards like the Uno, Mega,
|
||||
// Leonardo, etc., so don't bother extending this out of hand).
|
||||
// Additional PORTs could be added if you really need them, just
|
||||
// duplicate the else and loop and change the PORT. Each add'l
|
||||
// PORT will require about 150(ish) bytes of program space.
|
||||
|
||||
// 10 instruction clocks per bit: HHxxxxxLLL
|
||||
// OUT instructions: ^ ^ ^ (T=0,2,7)
|
||||
|
||||
hi = PORTD | pinMask;
|
||||
lo = PORTD & ~pinMask;
|
||||
n1 = lo;
|
||||
|
||||
if (b & 0x80)
|
||||
{
|
||||
n1 = hi;
|
||||
}
|
||||
|
||||
// Dirty trick: RJMPs proceeding to the next instruction are used
|
||||
// to delay two clock cycles in one instruction word (rather than
|
||||
// using two NOPs). This was necessary in order to squeeze the
|
||||
// loop down to exactly 64 words -- the maximum possible for a
|
||||
// relative branch.
|
||||
|
||||
asm volatile(
|
||||
"headD:" "\n\t" // Clk Pseudocode
|
||||
// Bit 7:
|
||||
"out %[port] , %[hi]" "\n\t" // 1 PORT = hi
|
||||
"mov %[n2] , %[lo]" "\n\t" // 1 n2 = lo
|
||||
"out %[port] , %[n1]" "\n\t" // 1 PORT = n1
|
||||
"rjmp .+0" "\n\t" // 2 nop nop
|
||||
"sbrc %[byte] , 6" "\n\t" // 1-2 if(b & 0x40)
|
||||
"mov %[n2] , %[hi]" "\n\t" // 0-1 n2 = hi
|
||||
"out %[port] , %[lo]" "\n\t" // 1 PORT = lo
|
||||
"rjmp .+0" "\n\t" // 2 nop nop
|
||||
// Bit 6:
|
||||
"out %[port] , %[hi]" "\n\t" // 1 PORT = hi
|
||||
"mov %[n1] , %[lo]" "\n\t" // 1 n1 = lo
|
||||
"out %[port] , %[n2]" "\n\t" // 1 PORT = n2
|
||||
"rjmp .+0" "\n\t" // 2 nop nop
|
||||
"sbrc %[byte] , 5" "\n\t" // 1-2 if(b & 0x20)
|
||||
"mov %[n1] , %[hi]" "\n\t" // 0-1 n1 = hi
|
||||
"out %[port] , %[lo]" "\n\t" // 1 PORT = lo
|
||||
"rjmp .+0" "\n\t" // 2 nop nop
|
||||
// Bit 5:
|
||||
"out %[port] , %[hi]" "\n\t" // 1 PORT = hi
|
||||
"mov %[n2] , %[lo]" "\n\t" // 1 n2 = lo
|
||||
"out %[port] , %[n1]" "\n\t" // 1 PORT = n1
|
||||
"rjmp .+0" "\n\t" // 2 nop nop
|
||||
"sbrc %[byte] , 4" "\n\t" // 1-2 if(b & 0x10)
|
||||
"mov %[n2] , %[hi]" "\n\t" // 0-1 n2 = hi
|
||||
"out %[port] , %[lo]" "\n\t" // 1 PORT = lo
|
||||
"rjmp .+0" "\n\t" // 2 nop nop
|
||||
// Bit 4:
|
||||
"out %[port] , %[hi]" "\n\t" // 1 PORT = hi
|
||||
"mov %[n1] , %[lo]" "\n\t" // 1 n1 = lo
|
||||
"out %[port] , %[n2]" "\n\t" // 1 PORT = n2
|
||||
"rjmp .+0" "\n\t" // 2 nop nop
|
||||
"sbrc %[byte] , 3" "\n\t" // 1-2 if(b & 0x08)
|
||||
"mov %[n1] , %[hi]" "\n\t" // 0-1 n1 = hi
|
||||
"out %[port] , %[lo]" "\n\t" // 1 PORT = lo
|
||||
"rjmp .+0" "\n\t" // 2 nop nop
|
||||
// Bit 3:
|
||||
"out %[port] , %[hi]" "\n\t" // 1 PORT = hi
|
||||
"mov %[n2] , %[lo]" "\n\t" // 1 n2 = lo
|
||||
"out %[port] , %[n1]" "\n\t" // 1 PORT = n1
|
||||
"rjmp .+0" "\n\t" // 2 nop nop
|
||||
"sbrc %[byte] , 2" "\n\t" // 1-2 if(b & 0x04)
|
||||
"mov %[n2] , %[hi]" "\n\t" // 0-1 n2 = hi
|
||||
"out %[port] , %[lo]" "\n\t" // 1 PORT = lo
|
||||
"rjmp .+0" "\n\t" // 2 nop nop
|
||||
// Bit 2:
|
||||
"out %[port] , %[hi]" "\n\t" // 1 PORT = hi
|
||||
"mov %[n1] , %[lo]" "\n\t" // 1 n1 = lo
|
||||
"out %[port] , %[n2]" "\n\t" // 1 PORT = n2
|
||||
"rjmp .+0" "\n\t" // 2 nop nop
|
||||
"sbrc %[byte] , 1" "\n\t" // 1-2 if(b & 0x02)
|
||||
"mov %[n1] , %[hi]" "\n\t" // 0-1 n1 = hi
|
||||
"out %[port] , %[lo]" "\n\t" // 1 PORT = lo
|
||||
"rjmp .+0" "\n\t" // 2 nop nop
|
||||
// Bit 1:
|
||||
"out %[port] , %[hi]" "\n\t" // 1 PORT = hi
|
||||
"mov %[n2] , %[lo]" "\n\t" // 1 n2 = lo
|
||||
"out %[port] , %[n1]" "\n\t" // 1 PORT = n1
|
||||
"rjmp .+0" "\n\t" // 2 nop nop
|
||||
"sbrc %[byte] , 0" "\n\t" // 1-2 if(b & 0x01)
|
||||
"mov %[n2] , %[hi]" "\n\t" // 0-1 n2 = hi
|
||||
"out %[port] , %[lo]" "\n\t" // 1 PORT = lo
|
||||
"sbiw %[count], 1" "\n\t" // 2 i-- (don't act on Z flag yet)
|
||||
// Bit 0:
|
||||
"out %[port] , %[hi]" "\n\t" // 1 PORT = hi
|
||||
"mov %[n1] , %[lo]" "\n\t" // 1 n1 = lo
|
||||
"out %[port] , %[n2]" "\n\t" // 1 PORT = n2
|
||||
"ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++
|
||||
"sbrc %[byte] , 7" "\n\t" // 1-2 if(b & 0x80)
|
||||
"mov %[n1] , %[hi]" "\n\t" // 0-1 n1 = hi
|
||||
"out %[port] , %[lo]" "\n\t" // 1 PORT = lo
|
||||
"brne headD" "\n" // 2 while(i) (Z flag set above)
|
||||
: [byte] "+r" (b),
|
||||
[n1] "+r" (n1),
|
||||
[n2] "+r" (n2),
|
||||
[count] "+w" (i)
|
||||
: [port] "I" (_SFR_IO_ADDR(PORTD)),
|
||||
[ptr] "e" (ptr),
|
||||
[hi] "r" (hi),
|
||||
[lo] "r" (lo) );
|
||||
}
|
||||
#endif
|
||||
|
||||
void send_data_8mhz_800_PortB(uint8_t* data, size_t sizeData, uint8_t pinMask)
|
||||
{
|
||||
volatile size_t i = sizeData; // Loop counter
|
||||
volatile uint8_t* ptr = data; // Pointer to next byte
|
||||
volatile uint8_t b = *ptr++; // Current byte value
|
||||
volatile uint8_t hi; // PORT w/output bit set high
|
||||
volatile uint8_t lo; // PORT w/output bit set low
|
||||
|
||||
volatile uint8_t n1;
|
||||
volatile uint8_t n2 = 0; // First, next bits out
|
||||
|
||||
// Same as above, just switched to PORTB and stripped of comments.
|
||||
hi = PORTB | pinMask;
|
||||
lo = PORTB & ~pinMask;
|
||||
n1 = lo;
|
||||
if (b & 0x80)
|
||||
{
|
||||
n1 = hi;
|
||||
}
|
||||
|
||||
asm volatile(
|
||||
"headB:" "\n\t"
|
||||
"out %[port] , %[hi]" "\n\t"
|
||||
"mov %[n2] , %[lo]" "\n\t"
|
||||
"out %[port] , %[n1]" "\n\t"
|
||||
"rjmp .+0" "\n\t"
|
||||
"sbrc %[byte] , 6" "\n\t"
|
||||
"mov %[n2] , %[hi]" "\n\t"
|
||||
"out %[port] , %[lo]" "\n\t"
|
||||
"rjmp .+0" "\n\t"
|
||||
"out %[port] , %[hi]" "\n\t"
|
||||
"mov %[n1] , %[lo]" "\n\t"
|
||||
"out %[port] , %[n2]" "\n\t"
|
||||
"rjmp .+0" "\n\t"
|
||||
"sbrc %[byte] , 5" "\n\t"
|
||||
"mov %[n1] , %[hi]" "\n\t"
|
||||
"out %[port] , %[lo]" "\n\t"
|
||||
"rjmp .+0" "\n\t"
|
||||
"out %[port] , %[hi]" "\n\t"
|
||||
"mov %[n2] , %[lo]" "\n\t"
|
||||
"out %[port] , %[n1]" "\n\t"
|
||||
"rjmp .+0" "\n\t"
|
||||
"sbrc %[byte] , 4" "\n\t"
|
||||
"mov %[n2] , %[hi]" "\n\t"
|
||||
"out %[port] , %[lo]" "\n\t"
|
||||
"rjmp .+0" "\n\t"
|
||||
"out %[port] , %[hi]" "\n\t"
|
||||
"mov %[n1] , %[lo]" "\n\t"
|
||||
"out %[port] , %[n2]" "\n\t"
|
||||
"rjmp .+0" "\n\t"
|
||||
"sbrc %[byte] , 3" "\n\t"
|
||||
"mov %[n1] , %[hi]" "\n\t"
|
||||
"out %[port] , %[lo]" "\n\t"
|
||||
"rjmp .+0" "\n\t"
|
||||
"out %[port] , %[hi]" "\n\t"
|
||||
"mov %[n2] , %[lo]" "\n\t"
|
||||
"out %[port] , %[n1]" "\n\t"
|
||||
"rjmp .+0" "\n\t"
|
||||
"sbrc %[byte] , 2" "\n\t"
|
||||
"mov %[n2] , %[hi]" "\n\t"
|
||||
"out %[port] , %[lo]" "\n\t"
|
||||
"rjmp .+0" "\n\t"
|
||||
"out %[port] , %[hi]" "\n\t"
|
||||
"mov %[n1] , %[lo]" "\n\t"
|
||||
"out %[port] , %[n2]" "\n\t"
|
||||
"rjmp .+0" "\n\t"
|
||||
"sbrc %[byte] , 1" "\n\t"
|
||||
"mov %[n1] , %[hi]" "\n\t"
|
||||
"out %[port] , %[lo]" "\n\t"
|
||||
"rjmp .+0" "\n\t"
|
||||
"out %[port] , %[hi]" "\n\t"
|
||||
"mov %[n2] , %[lo]" "\n\t"
|
||||
"out %[port] , %[n1]" "\n\t"
|
||||
"rjmp .+0" "\n\t"
|
||||
"sbrc %[byte] , 0" "\n\t"
|
||||
"mov %[n2] , %[hi]" "\n\t"
|
||||
"out %[port] , %[lo]" "\n\t"
|
||||
"sbiw %[count], 1" "\n\t"
|
||||
"out %[port] , %[hi]" "\n\t"
|
||||
"mov %[n1] , %[lo]" "\n\t"
|
||||
"out %[port] , %[n2]" "\n\t"
|
||||
"ld %[byte] , %a[ptr]+" "\n\t"
|
||||
"sbrc %[byte] , 7" "\n\t"
|
||||
"mov %[n1] , %[hi]" "\n\t"
|
||||
"out %[port] , %[lo]" "\n\t"
|
||||
"brne headB" "\n"
|
||||
: [byte] "+r" (b), [n1] "+r" (n1), [n2] "+r" (n2), [count] "+w" (i)
|
||||
: [port] "I" (_SFR_IO_ADDR(PORTB)), [ptr] "e" (ptr), [hi] "r" (hi),
|
||||
[lo] "r" (lo));
|
||||
}
|
||||
|
||||
void send_data_8mhz_400(uint8_t* data, size_t sizeData, volatile uint8_t* port, uint8_t pinMask)
|
||||
{
|
||||
volatile size_t i = sizeData; // Loop counter
|
||||
volatile uint8_t* ptr = data; // Pointer to next byte
|
||||
volatile uint8_t b = *ptr++; // Current byte value
|
||||
volatile uint8_t hi; // PORT w/output bit set high
|
||||
volatile uint8_t lo; // PORT w/output bit set low
|
||||
|
||||
// Timing is more relaxed; unrolling the inner loop for each bit is
|
||||
// not necessary. Still using the peculiar RJMPs as 2X NOPs, not out
|
||||
// of need but just to trim the code size down a little.
|
||||
// This 400-KHz-datastream-on-8-MHz-CPU code is not quite identical
|
||||
// to the 800-on-16 code later -- the hi/lo timing between WS2811 and
|
||||
// WS2812 is not simply a 2:1 scale!
|
||||
|
||||
// 20 inst. clocks per bit: HHHHxxxxxxLLLLLLLLLL
|
||||
// ST instructions: ^ ^ ^ (T=0,4,10)
|
||||
|
||||
volatile uint8_t next, bit;
|
||||
|
||||
hi = *port | pinMask;
|
||||
lo = *port & ~pinMask;
|
||||
next = lo;
|
||||
bit = 8;
|
||||
|
||||
asm volatile(
|
||||
"head20:" "\n\t" // Clk Pseudocode (T = 0)
|
||||
"st %a[port], %[hi]" "\n\t" // 2 PORT = hi (T = 2)
|
||||
"sbrc %[byte] , 7" "\n\t" // 1-2 if(b & 128)
|
||||
"mov %[next], %[hi]" "\n\t" // 0-1 next = hi (T = 4)
|
||||
"st %a[port], %[next]" "\n\t" // 2 PORT = next (T = 6)
|
||||
"mov %[next] , %[lo]" "\n\t" // 1 next = lo (T = 7)
|
||||
"dec %[bit]" "\n\t" // 1 bit-- (T = 8)
|
||||
"breq nextbyte20" "\n\t" // 1-2 if(bit == 0)
|
||||
"rol %[byte]" "\n\t" // 1 b <<= 1 (T = 10)
|
||||
"st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 12)
|
||||
"rjmp .+0" "\n\t" // 2 nop nop (T = 14)
|
||||
"rjmp .+0" "\n\t" // 2 nop nop (T = 16)
|
||||
"rjmp .+0" "\n\t" // 2 nop nop (T = 18)
|
||||
"rjmp head20" "\n\t" // 2 -> head20 (next bit out)
|
||||
"nextbyte20:" "\n\t" // (T = 10)
|
||||
"st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 12)
|
||||
"nop" "\n\t" // 1 nop (T = 13)
|
||||
"ldi %[bit] , 8" "\n\t" // 1 bit = 8 (T = 14)
|
||||
"ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 16)
|
||||
"sbiw %[count], 1" "\n\t" // 2 i-- (T = 18)
|
||||
"brne head20" "\n" // 2 if(i != 0) -> (next byte)
|
||||
: [port] "+e" (port),
|
||||
[byte] "+r" (b),
|
||||
[bit] "+r" (bit),
|
||||
[next] "+r" (next),
|
||||
[count] "+w" (i)
|
||||
: [hi] "r" (hi),
|
||||
[lo] "r" (lo),
|
||||
[ptr] "e" (ptr));
|
||||
}
|
||||
|
||||
#elif (F_CPU >= 11100000UL) && (F_CPU <= 14300000UL) // 12Mhz CPU
|
||||
|
||||
#ifdef PORTD // PORTD isn't present on ATtiny85, etc.
|
||||
void send_data_12mhz_800_PortD(uint8_t* data, size_t sizeData, uint8_t pinMask)
|
||||
{
|
||||
volatile size_t i = sizeData; // Loop counter
|
||||
volatile uint8_t* ptr = data; // Pointer to next byte
|
||||
volatile uint8_t b = *ptr++; // Current byte value
|
||||
volatile uint8_t hi; // PORT w/output bit set high
|
||||
volatile uint8_t lo; // PORT w/output bit set low
|
||||
|
||||
// In the 12 MHz case, an optimized 800 KHz datastream (no dead time
|
||||
// between bytes) requires a PORT-specific loop similar to the 8 MHz
|
||||
// code (but a little more relaxed in this case).
|
||||
|
||||
// 15 instruction clocks per bit: HHHHxxxxxxLLLLL
|
||||
// OUT instructions: ^ ^ ^ (T=0,4,10)
|
||||
|
||||
volatile uint8_t next;
|
||||
|
||||
hi = PORTD | pinMask;
|
||||
lo = PORTD & ~pinMask;
|
||||
next = lo;
|
||||
if (b & 0x80) next = hi;
|
||||
|
||||
// Don't "optimize" the OUT calls into the bitTime subroutine;
|
||||
// we're exploiting the RCALL and RET as 3- and 4-cycle NOPs!
|
||||
asm volatile(
|
||||
"headD:" "\n\t" // (T = 0)
|
||||
"out %[port], %[hi]" "\n\t" // (T = 1)
|
||||
"rcall bitTimeD" "\n\t" // Bit 7 (T = 15)
|
||||
"out %[port], %[hi]" "\n\t"
|
||||
"rcall bitTimeD" "\n\t" // Bit 6
|
||||
"out %[port], %[hi]" "\n\t"
|
||||
"rcall bitTimeD" "\n\t" // Bit 5
|
||||
"out %[port], %[hi]" "\n\t"
|
||||
"rcall bitTimeD" "\n\t" // Bit 4
|
||||
"out %[port], %[hi]" "\n\t"
|
||||
"rcall bitTimeD" "\n\t" // Bit 3
|
||||
"out %[port], %[hi]" "\n\t"
|
||||
"rcall bitTimeD" "\n\t" // Bit 2
|
||||
"out %[port], %[hi]" "\n\t"
|
||||
"rcall bitTimeD" "\n\t" // Bit 1
|
||||
// Bit 0:
|
||||
"out %[port] , %[hi]" "\n\t" // 1 PORT = hi (T = 1)
|
||||
"rjmp .+0" "\n\t" // 2 nop nop (T = 3)
|
||||
"ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 5)
|
||||
"out %[port] , %[next]" "\n\t" // 1 PORT = next (T = 6)
|
||||
"mov %[next] , %[lo]" "\n\t" // 1 next = lo (T = 7)
|
||||
"sbrc %[byte] , 7" "\n\t" // 1-2 if(b & 0x80) (T = 8)
|
||||
"mov %[next] , %[hi]" "\n\t" // 0-1 next = hi (T = 9)
|
||||
"nop" "\n\t" // 1 (T = 10)
|
||||
"out %[port] , %[lo]" "\n\t" // 1 PORT = lo (T = 11)
|
||||
"sbiw %[count], 1" "\n\t" // 2 i-- (T = 13)
|
||||
"brne headD" "\n\t" // 2 if(i != 0) -> (next byte)
|
||||
"rjmp doneD" "\n\t"
|
||||
"bitTimeD:" "\n\t" // nop nop nop (T = 4)
|
||||
"out %[port], %[next]" "\n\t" // 1 PORT = next (T = 5)
|
||||
"mov %[next], %[lo]" "\n\t" // 1 next = lo (T = 6)
|
||||
"rol %[byte]" "\n\t" // 1 b <<= 1 (T = 7)
|
||||
"sbrc %[byte], 7" "\n\t" // 1-2 if(b & 0x80) (T = 8)
|
||||
"mov %[next], %[hi]" "\n\t" // 0-1 next = hi (T = 9)
|
||||
"nop" "\n\t" // 1 (T = 10)
|
||||
"out %[port], %[lo]" "\n\t" // 1 PORT = lo (T = 11)
|
||||
"ret" "\n\t" // 4 nop nop nop nop (T = 15)
|
||||
"doneD:" "\n"
|
||||
: [byte] "+r" (b),
|
||||
[next] "+r" (next),
|
||||
[count] "+w" (i)
|
||||
: [port] "I" (_SFR_IO_ADDR(PORTD)),
|
||||
[ptr] "e" (ptr),
|
||||
[hi] "r" (hi),
|
||||
[lo] "r" (lo));
|
||||
}
|
||||
#endif
|
||||
|
||||
void send_data_12mhz_800_PortB(uint8_t* data, size_t sizeData, uint8_t pinMask)
|
||||
{
|
||||
volatile uint16_t i = (uint16_t)sizeData; // Loop counter
|
||||
volatile uint8_t* ptr = data; // Pointer to next byte
|
||||
volatile uint8_t b = *ptr++; // Current byte value
|
||||
volatile uint8_t hi; // PORT w/output bit set high
|
||||
volatile uint8_t lo; // PORT w/output bit set low
|
||||
|
||||
volatile uint8_t next;
|
||||
|
||||
hi = PORTB | pinMask;
|
||||
lo = PORTB & ~pinMask;
|
||||
next = lo;
|
||||
if (b & 0x80)
|
||||
{
|
||||
next = hi;
|
||||
}
|
||||
|
||||
// Same as above, just set for PORTB & stripped of comments
|
||||
asm volatile(
|
||||
"headB:" "\n\t"
|
||||
"out %[port], %[hi]" "\n\t"
|
||||
"rcall bitTimeB" "\n\t"
|
||||
"out %[port], %[hi]" "\n\t"
|
||||
"rcall bitTimeB" "\n\t"
|
||||
"out %[port], %[hi]" "\n\t"
|
||||
"rcall bitTimeB" "\n\t"
|
||||
"out %[port], %[hi]" "\n\t"
|
||||
"rcall bitTimeB" "\n\t"
|
||||
"out %[port], %[hi]" "\n\t"
|
||||
"rcall bitTimeB" "\n\t"
|
||||
"out %[port], %[hi]" "\n\t"
|
||||
"rcall bitTimeB" "\n\t"
|
||||
"out %[port], %[hi]" "\n\t"
|
||||
"rcall bitTimeB" "\n\t"
|
||||
"out %[port] , %[hi]" "\n\t"
|
||||
"rjmp .+0" "\n\t"
|
||||
"ld %[byte] , %a[ptr]+" "\n\t"
|
||||
"out %[port] , %[next]" "\n\t"
|
||||
"mov %[next] , %[lo]" "\n\t"
|
||||
"sbrc %[byte] , 7" "\n\t"
|
||||
"mov %[next] , %[hi]" "\n\t"
|
||||
"nop" "\n\t"
|
||||
"out %[port] , %[lo]" "\n\t"
|
||||
"sbiw %[count], 1" "\n\t"
|
||||
"brne headB" "\n\t"
|
||||
"rjmp doneB" "\n\t"
|
||||
"bitTimeB:" "\n\t"
|
||||
"out %[port], %[next]" "\n\t"
|
||||
"mov %[next], %[lo]" "\n\t"
|
||||
"rol %[byte]" "\n\t"
|
||||
"sbrc %[byte], 7" "\n\t"
|
||||
"mov %[next], %[hi]" "\n\t"
|
||||
"nop" "\n\t"
|
||||
"out %[port], %[lo]" "\n\t"
|
||||
"ret" "\n\t"
|
||||
"doneB:" "\n"
|
||||
: [byte] "+r" (b), [next] "+r" (next), [count] "+w" (i)
|
||||
: [port] "I" (_SFR_IO_ADDR(PORTB)), [ptr] "e" (ptr), [hi] "r" (hi),
|
||||
[lo] "r" (lo));
|
||||
}
|
||||
|
||||
void send_data_12mhz_400(uint8_t* data, size_t sizeData, volatile uint8_t* port, uint8_t pinMask)
|
||||
{
|
||||
volatile uint16_t i = (uint16_t)sizeData; // Loop counter
|
||||
volatile uint8_t* ptr = data; // Pointer to next byte
|
||||
volatile uint8_t b = *ptr++; // Current byte value
|
||||
volatile uint8_t hi; // PORT w/output bit set high
|
||||
volatile uint8_t lo; // PORT w/output bit set low
|
||||
|
||||
// 30 instruction clocks per bit: HHHHHHxxxxxxxxxLLLLLLLLLLLLLLL
|
||||
// ST instructions: ^ ^ ^ (T=0,6,15)
|
||||
|
||||
volatile uint8_t next, bit;
|
||||
|
||||
hi = *port | pinMask;
|
||||
lo = *port & ~pinMask;
|
||||
next = lo;
|
||||
bit = 8;
|
||||
|
||||
asm volatile(
|
||||
"head30:" "\n\t" // Clk Pseudocode (T = 0)
|
||||
"st %a[port], %[hi]" "\n\t" // 2 PORT = hi (T = 2)
|
||||
"sbrc %[byte] , 7" "\n\t" // 1-2 if(b & 128)
|
||||
"mov %[next], %[hi]" "\n\t" // 0-1 next = hi (T = 4)
|
||||
"rjmp .+0" "\n\t" // 2 nop nop (T = 6)
|
||||
"st %a[port], %[next]" "\n\t" // 2 PORT = next (T = 8)
|
||||
"rjmp .+0" "\n\t" // 2 nop nop (T = 10)
|
||||
"rjmp .+0" "\n\t" // 2 nop nop (T = 12)
|
||||
"rjmp .+0" "\n\t" // 2 nop nop (T = 14)
|
||||
"nop" "\n\t" // 1 nop (T = 15)
|
||||
"st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 17)
|
||||
"rjmp .+0" "\n\t" // 2 nop nop (T = 19)
|
||||
"dec %[bit]" "\n\t" // 1 bit-- (T = 20)
|
||||
"breq nextbyte30" "\n\t" // 1-2 if(bit == 0)
|
||||
"rol %[byte]" "\n\t" // 1 b <<= 1 (T = 22)
|
||||
"rjmp .+0" "\n\t" // 2 nop nop (T = 24)
|
||||
"rjmp .+0" "\n\t" // 2 nop nop (T = 26)
|
||||
"rjmp .+0" "\n\t" // 2 nop nop (T = 28)
|
||||
"rjmp head30" "\n\t" // 2 -> head30 (next bit out)
|
||||
"nextbyte30:" "\n\t" // (T = 22)
|
||||
"nop" "\n\t" // 1 nop (T = 23)
|
||||
"ldi %[bit] , 8" "\n\t" // 1 bit = 8 (T = 24)
|
||||
"ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 26)
|
||||
"sbiw %[count], 1" "\n\t" // 2 i-- (T = 28)
|
||||
"brne head30" "\n" // 1-2 if(i != 0) -> (next byte)
|
||||
: [port] "+e" (port),
|
||||
[byte] "+r" (b),
|
||||
[bit] "+r" (bit),
|
||||
[next] "+r" (next),
|
||||
[count] "+w" (i)
|
||||
: [hi] "r" (hi),
|
||||
[lo] "r" (lo),
|
||||
[ptr] "e" (ptr));
|
||||
}
|
||||
|
||||
#elif (F_CPU >= 15400000UL) && (F_CPU <= 19000000L) // 16Mhz CPU
|
||||
|
||||
void send_data_16mhz_800(uint8_t* data, size_t sizeData, volatile uint8_t* port, uint8_t pinMask)
|
||||
{
|
||||
volatile uint16_t i = (uint16_t)sizeData; // Loop counter
|
||||
volatile uint8_t* ptr = data; // Pointer to next byte
|
||||
volatile uint8_t b = *ptr++; // Current byte value
|
||||
volatile uint8_t hi; // PORT w/output bit set high
|
||||
volatile uint8_t lo; // PORT w/output bit set low
|
||||
|
||||
// WS2811 and WS2812 have different hi/lo duty cycles; this is
|
||||
// similar but NOT an exact copy of the prior 400-on-8 code.
|
||||
|
||||
// 20 inst. clocks per bit: HHHHHxxxxxxxxLLLLLLL
|
||||
// ST instructions: ^ ^ ^ (T=0,5,13)
|
||||
|
||||
volatile uint8_t next;
|
||||
volatile uint8_t bit;
|
||||
|
||||
hi = *port | pinMask;
|
||||
lo = *port & ~pinMask;
|
||||
next = lo;
|
||||
bit = 8;
|
||||
|
||||
asm volatile(
|
||||
"head20:" "\n\t" // Clk Pseudocode (T = 0)
|
||||
"st %a[port], %[hi]" "\n\t" // 2 PORT = hi (T = 2)
|
||||
"sbrc %[byte], 7" "\n\t" // 1-2 if(b & 128)
|
||||
"mov %[next], %[hi]" "\n\t" // 0-1 next = hi (T = 4)
|
||||
"dec %[bit]" "\n\t" // 1 bit-- (T = 5)
|
||||
"st %a[port], %[next]" "\n\t" // 2 PORT = next (T = 7)
|
||||
"mov %[next] , %[lo]" "\n\t" // 1 next = lo (T = 8)
|
||||
"breq nextbyte20" "\n\t" // 1-2 if(bit == 0) (from dec above)
|
||||
"rol %[byte]" "\n\t" // 1 b <<= 1 (T = 10)
|
||||
"rjmp .+0" "\n\t" // 2 nop nop (T = 12)
|
||||
"nop" "\n\t" // 1 nop (T = 13)
|
||||
"st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 15)
|
||||
"nop" "\n\t" // 1 nop (T = 16)
|
||||
"rjmp .+0" "\n\t" // 2 nop nop (T = 18)
|
||||
"rjmp head20" "\n\t" // 2 -> head20 (next bit out)
|
||||
"nextbyte20:" "\n\t" // (T = 10)
|
||||
"ldi %[bit] , 8" "\n\t" // 1 bit = 8 (T = 11)
|
||||
"ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 13)
|
||||
"st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 15)
|
||||
"nop" "\n\t" // 1 nop (T = 16)
|
||||
"sbiw %[count], 1" "\n\t" // 2 i-- (T = 18)
|
||||
"brne head20" "\n" // 2 if(i != 0) -> (next byte)
|
||||
: [port] "+e" (port),
|
||||
[byte] "+r" (b),
|
||||
[bit] "+r" (bit),
|
||||
[next] "+r" (next),
|
||||
[count] "+w" (i)
|
||||
: [ptr] "e" (ptr),
|
||||
[hi] "r" (hi),
|
||||
[lo] "r" (lo));
|
||||
}
|
||||
|
||||
void send_data_16mhz_400(uint8_t* data, size_t sizeData, volatile uint8_t* port, uint8_t pinMask)
|
||||
{
|
||||
volatile size_t i = sizeData; // Loop counter
|
||||
volatile uint8_t* ptr = data; // Pointer to next byte
|
||||
volatile uint8_t b = *ptr++; // Current byte value
|
||||
volatile uint8_t hi; // PORT w/output bit set high
|
||||
volatile uint8_t lo; // PORT w/output bit set low
|
||||
|
||||
// The 400 KHz clock on 16 MHz MCU is the most 'relaxed' version.
|
||||
|
||||
// 40 inst. clocks per bit: HHHHHHHHxxxxxxxxxxxxLLLLLLLLLLLLLLLLLLLL
|
||||
// ST instructions: ^ ^ ^ (T=0,8,20)
|
||||
|
||||
volatile uint8_t next, bit;
|
||||
|
||||
hi = *port | pinMask;
|
||||
lo = *port & ~pinMask;
|
||||
next = lo;
|
||||
bit = 8;
|
||||
|
||||
asm volatile(
|
||||
"head40:" "\n\t" // Clk Pseudocode (T = 0)
|
||||
"st %a[port], %[hi]" "\n\t" // 2 PORT = hi (T = 2)
|
||||
"sbrc %[byte] , 7" "\n\t" // 1-2 if(b & 128)
|
||||
"mov %[next] , %[hi]" "\n\t" // 0-1 next = hi (T = 4)
|
||||
"rjmp .+0" "\n\t" // 2 nop nop (T = 6)
|
||||
"rjmp .+0" "\n\t" // 2 nop nop (T = 8)
|
||||
"st %a[port], %[next]" "\n\t" // 2 PORT = next (T = 10)
|
||||
"rjmp .+0" "\n\t" // 2 nop nop (T = 12)
|
||||
"rjmp .+0" "\n\t" // 2 nop nop (T = 14)
|
||||
"rjmp .+0" "\n\t" // 2 nop nop (T = 16)
|
||||
"rjmp .+0" "\n\t" // 2 nop nop (T = 18)
|
||||
"rjmp .+0" "\n\t" // 2 nop nop (T = 20)
|
||||
"st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 22)
|
||||
"nop" "\n\t" // 1 nop (T = 23)
|
||||
"mov %[next] , %[lo]" "\n\t" // 1 next = lo (T = 24)
|
||||
"dec %[bit]" "\n\t" // 1 bit-- (T = 25)
|
||||
"breq nextbyte40" "\n\t" // 1-2 if(bit == 0)
|
||||
"rol %[byte]" "\n\t" // 1 b <<= 1 (T = 27)
|
||||
"nop" "\n\t" // 1 nop (T = 28)
|
||||
"rjmp .+0" "\n\t" // 2 nop nop (T = 30)
|
||||
"rjmp .+0" "\n\t" // 2 nop nop (T = 32)
|
||||
"rjmp .+0" "\n\t" // 2 nop nop (T = 34)
|
||||
"rjmp .+0" "\n\t" // 2 nop nop (T = 36)
|
||||
"rjmp .+0" "\n\t" // 2 nop nop (T = 38)
|
||||
"rjmp head40" "\n\t" // 2 -> head40 (next bit out)
|
||||
"nextbyte40:" "\n\t" // (T = 27)
|
||||
"ldi %[bit] , 8" "\n\t" // 1 bit = 8 (T = 28)
|
||||
"ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 30)
|
||||
"rjmp .+0" "\n\t" // 2 nop nop (T = 32)
|
||||
"st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 34)
|
||||
"rjmp .+0" "\n\t" // 2 nop nop (T = 36)
|
||||
"sbiw %[count], 1" "\n\t" // 2 i-- (T = 38)
|
||||
"brne head40" "\n" // 1-2 if(i != 0) -> (next byte)
|
||||
: [port] "+e" (port),
|
||||
[byte] "+r" (b),
|
||||
[bit] "+r" (bit),
|
||||
[next] "+r" (next),
|
||||
[count] "+w" (i)
|
||||
: [ptr] "e" (ptr),
|
||||
[hi] "r" (hi),
|
||||
[lo] "r" (lo));
|
||||
}
|
||||
|
||||
#else
|
||||
#error "CPU SPEED NOT SUPPORTED"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
116
lib/NeoPixelBus_by_Makuna/src/internal/NeoRingTopology.h
Normal file
116
lib/NeoPixelBus_by_Makuna/src/internal/NeoRingTopology.h
Normal file
@@ -0,0 +1,116 @@
|
||||
#pragma once
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
NeoRingTopology provides a mapping feature of a 2d polar cordinate to a
|
||||
linear 1d cordinate.
|
||||
It is used to map a series of concentric rings of NeoPixels to a index on
|
||||
the NeoPixelBus.
|
||||
|
||||
Written by Michael C. Miller.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
|
||||
template <typename T_LAYOUT> class NeoRingTopology : protected T_LAYOUT
|
||||
{
|
||||
public:
|
||||
NeoRingTopology()
|
||||
{
|
||||
}
|
||||
|
||||
uint16_t Map(uint8_t ring, uint16_t pixel) const
|
||||
{
|
||||
if (pixel >= getPixelCountAtRing(ring))
|
||||
{
|
||||
return 0; // invalid ring and/or pixel argument, always return a valid value, the first one
|
||||
}
|
||||
|
||||
return _map(ring, pixel);
|
||||
}
|
||||
|
||||
uint16_t MapProbe(uint8_t ring, uint16_t pixel) const
|
||||
{
|
||||
if (pixel >= getPixelCountAtRing(ring))
|
||||
{
|
||||
return getPixelCount(); // total count, out of bounds
|
||||
}
|
||||
|
||||
return _map(ring, pixel);
|
||||
}
|
||||
|
||||
uint16_t RingPixelShift(uint8_t ring, uint16_t pixel, int16_t shift)
|
||||
{
|
||||
int32_t ringPixel = pixel;
|
||||
ringPixel += shift;
|
||||
|
||||
if (ringPixel < 0)
|
||||
{
|
||||
ringPixel = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint16_t count = getPixelCountAtRing(ring);
|
||||
if (ringPixel >= count)
|
||||
{
|
||||
ringPixel = count - 1;
|
||||
}
|
||||
}
|
||||
return ringPixel;
|
||||
}
|
||||
|
||||
uint16_t RingPixelRotate(uint8_t ring, uint16_t pixel, int16_t rotate)
|
||||
{
|
||||
int32_t ringPixel = pixel;
|
||||
ringPixel += rotate;
|
||||
return ringPixel % getPixelCountAtRing(ring);
|
||||
}
|
||||
|
||||
uint8_t getCountOfRings() const
|
||||
{
|
||||
return _ringCount() - 1; // minus one as the Rings includes the extra value
|
||||
}
|
||||
|
||||
uint16_t getPixelCountAtRing(uint8_t ring) const
|
||||
{
|
||||
if (ring >= getCountOfRings())
|
||||
{
|
||||
return 0; // invalid, no pixels
|
||||
}
|
||||
|
||||
return T_LAYOUT::Rings[ring + 1] - T_LAYOUT::Rings[ring]; // using the extra value for count calc
|
||||
}
|
||||
|
||||
uint16_t getPixelCount() const
|
||||
{
|
||||
return T_LAYOUT::Rings[_ringCount() - 1]; // the last entry is the total count
|
||||
}
|
||||
|
||||
private:
|
||||
uint16_t _map(uint8_t ring, uint16_t pixel) const
|
||||
{
|
||||
return T_LAYOUT::Rings[ring] + pixel;
|
||||
}
|
||||
|
||||
uint8_t _ringCount() const
|
||||
{
|
||||
return sizeof(T_LAYOUT::Rings) / sizeof(T_LAYOUT::Rings[0]);
|
||||
}
|
||||
};
|
||||
130
lib/NeoPixelBus_by_Makuna/src/internal/NeoSegmentFeatures.h
Normal file
130
lib/NeoPixelBus_by_Makuna/src/internal/NeoSegmentFeatures.h
Normal file
@@ -0,0 +1,130 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
NeoSegmentFeatures provides feature classes to describe seven segment display
|
||||
elements for NeoPixelBus template class
|
||||
|
||||
Written by Michael C. Miller.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
#pragma once
|
||||
|
||||
class Neo9Elements
|
||||
{
|
||||
public:
|
||||
static const size_t PixelSize = 9; // three 3 element
|
||||
|
||||
static uint8_t* getPixelAddress(uint8_t* pPixels, uint16_t indexPixel)
|
||||
{
|
||||
return pPixels + indexPixel * PixelSize;
|
||||
}
|
||||
static const uint8_t* getPixelAddress(const uint8_t* pPixels, uint16_t indexPixel)
|
||||
{
|
||||
return pPixels + indexPixel * PixelSize;
|
||||
}
|
||||
|
||||
static void replicatePixel(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count)
|
||||
{
|
||||
uint8_t* pEnd = pPixelDest + (count * PixelSize);
|
||||
while (pPixelDest < pEnd)
|
||||
{
|
||||
for (uint8_t iElement = 0; iElement < PixelSize; iElement++)
|
||||
{
|
||||
*pPixelDest++ = pPixelSrc[iElement];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void movePixelsInc(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count)
|
||||
{
|
||||
uint8_t* pEnd = pPixelDest + (count * PixelSize);
|
||||
while (pPixelDest < pEnd)
|
||||
{
|
||||
*pPixelDest++ = *pPixelSrc++;
|
||||
}
|
||||
}
|
||||
|
||||
static void movePixelsInc_P(uint8_t* pPixelDest, PGM_VOID_P pPixelSrc, uint16_t count)
|
||||
{
|
||||
uint8_t* pEnd = pPixelDest + (count * PixelSize);
|
||||
const uint8_t* pSrc = (const uint8_t*)pPixelSrc;
|
||||
while (pPixelDest < pEnd)
|
||||
{
|
||||
*pPixelDest++ = pgm_read_byte(pSrc++);
|
||||
}
|
||||
}
|
||||
|
||||
static void movePixelsDec(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count)
|
||||
{
|
||||
uint8_t* pDestBack = pPixelDest + (count * PixelSize);
|
||||
const uint8_t* pSrcBack = pPixelSrc + (count * PixelSize);
|
||||
while (pDestBack > pPixelDest)
|
||||
{
|
||||
*--pDestBack = *--pSrcBack;
|
||||
}
|
||||
}
|
||||
|
||||
typedef SevenSegDigit ColorObject;
|
||||
};
|
||||
|
||||
// Abcdefg byte order
|
||||
class NeoAbcdefgSegmentFeature : public Neo9Elements
|
||||
{
|
||||
public:
|
||||
static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color)
|
||||
{
|
||||
uint8_t* p = getPixelAddress(pPixels, indexPixel);
|
||||
uint8_t commonSize = (PixelSize < color.SegmentCount) ? PixelSize : color.SegmentCount;
|
||||
for (uint8_t iSegment = 0; iSegment < commonSize; iSegment++)
|
||||
{
|
||||
*p++ = color.Segment[iSegment];
|
||||
}
|
||||
}
|
||||
|
||||
static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel)
|
||||
{
|
||||
ColorObject color;
|
||||
const uint8_t* p = getPixelAddress(pPixels, indexPixel);
|
||||
uint8_t commonSize = (PixelSize < color.SegmentCount) ? PixelSize : color.SegmentCount;
|
||||
|
||||
for (uint8_t iSegment = 0; iSegment < commonSize; iSegment++)
|
||||
{
|
||||
color.Segment[iSegment] = *p++;
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
static ColorObject retrievePixelColor_P(PGM_VOID_P pPixels, uint16_t indexPixel)
|
||||
{
|
||||
ColorObject color;
|
||||
const uint8_t* p = getPixelAddress((const uint8_t*)pPixels, indexPixel);
|
||||
uint8_t commonSize = (PixelSize < color.SegmentCount) ? PixelSize : color.SegmentCount;
|
||||
|
||||
for (uint8_t iSegment = 0; iSegment < commonSize; iSegment++)
|
||||
{
|
||||
color.Segment[iSegment] = pgm_read_byte(p++);
|
||||
}
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
typedef NeoAbcdefgSegmentFeature SevenSegmentFeature; // Abcdefg order is default
|
||||
62
lib/NeoPixelBus_by_Makuna/src/internal/NeoSettings.h
Normal file
62
lib/NeoPixelBus_by_Makuna/src/internal/NeoSettings.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
NeoSettings provides settings classes to describe settings
|
||||
|
||||
Written by Michael C. Miller.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
#pragma once
|
||||
|
||||
class NeoNoSettings
|
||||
{
|
||||
};
|
||||
|
||||
class NeoRgbCurrentSettings
|
||||
{
|
||||
public:
|
||||
NeoRgbCurrentSettings(uint16_t red, uint16_t green, uint16_t blue) :
|
||||
RedTenthMilliAmpere(red),
|
||||
GreenTenthMilliAmpere(green),
|
||||
BlueTenthMilliAmpere(blue)
|
||||
{
|
||||
}
|
||||
|
||||
uint16_t RedTenthMilliAmpere; // in 1/10th ma
|
||||
uint16_t GreenTenthMilliAmpere; // in 1/10th ma
|
||||
uint16_t BlueTenthMilliAmpere; // in 1/10th ma
|
||||
};
|
||||
|
||||
class NeoRgbwCurrentSettings
|
||||
{
|
||||
public:
|
||||
NeoRgbwCurrentSettings(uint16_t red, uint16_t green, uint16_t blue, uint16_t white) :
|
||||
RedTenthMilliAmpere(red),
|
||||
GreenTenthMilliAmpere(green),
|
||||
BlueTenthMilliAmpere(blue),
|
||||
WhiteCurrent(white)
|
||||
{
|
||||
}
|
||||
|
||||
uint16_t RedTenthMilliAmpere; // in 1/10th ma
|
||||
uint16_t GreenTenthMilliAmpere; // in 1/10th ma
|
||||
uint16_t BlueTenthMilliAmpere; // in 1/10th ma
|
||||
uint16_t WhiteCurrent; // in 1/10th ma
|
||||
};
|
||||
163
lib/NeoPixelBus_by_Makuna/src/internal/NeoSpriteSheet.h
Normal file
163
lib/NeoPixelBus_by_Makuna/src/internal/NeoSpriteSheet.h
Normal file
@@ -0,0 +1,163 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
NeoPixel library
|
||||
|
||||
Written by Michael C. Miller.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
#pragma once
|
||||
|
||||
|
||||
template<typename T_BUFFER_METHOD> class NeoVerticalSpriteSheet
|
||||
{
|
||||
public:
|
||||
NeoVerticalSpriteSheet(uint16_t width,
|
||||
uint16_t height,
|
||||
uint16_t spriteHeight,
|
||||
PGM_VOID_P pixels) :
|
||||
_method(width, height, pixels),
|
||||
_spriteHeight(spriteHeight),
|
||||
_spriteCount(height / spriteHeight)
|
||||
{
|
||||
}
|
||||
|
||||
operator NeoBufferContext<typename T_BUFFER_METHOD::ColorFeature>()
|
||||
{
|
||||
return _method;
|
||||
}
|
||||
|
||||
uint16_t SpriteWidth() const
|
||||
{
|
||||
return _method.Width();
|
||||
};
|
||||
|
||||
uint16_t SpriteHeight() const
|
||||
{
|
||||
return _spriteHeight;
|
||||
};
|
||||
|
||||
uint16_t SpriteCount() const
|
||||
{
|
||||
return _spriteCount;
|
||||
}
|
||||
|
||||
void SetPixelColor(uint16_t indexSprite,
|
||||
int16_t x,
|
||||
int16_t y,
|
||||
typename T_BUFFER_METHOD::ColorObject color)
|
||||
{
|
||||
_method.SetPixelColor(pixelIndex(indexSprite, x, y), color);
|
||||
};
|
||||
|
||||
typename T_BUFFER_METHOD::ColorObject GetPixelColor(uint16_t indexSprite,
|
||||
int16_t x,
|
||||
int16_t y) const
|
||||
{
|
||||
return _method.GetPixelColor(pixelIndex(indexSprite, x, y));
|
||||
};
|
||||
|
||||
void ClearTo(typename T_BUFFER_METHOD::ColorObject color)
|
||||
{
|
||||
_method.ClearTo(color);
|
||||
};
|
||||
|
||||
void Blt(NeoBufferContext<typename T_BUFFER_METHOD::ColorFeature> destBuffer,
|
||||
uint16_t indexPixel,
|
||||
uint16_t indexSprite)
|
||||
{
|
||||
uint16_t destPixelCount = destBuffer.PixelCount();
|
||||
// validate indexPixel
|
||||
if (indexPixel >= destPixelCount)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// validate indexSprite
|
||||
if (indexSprite >= _spriteCount)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// calc how many we can copy
|
||||
uint16_t copyCount = destPixelCount - indexPixel;
|
||||
|
||||
if (copyCount > SpriteWidth())
|
||||
{
|
||||
copyCount = SpriteWidth();
|
||||
}
|
||||
|
||||
uint8_t* pDest = T_BUFFER_METHOD::ColorFeature::getPixelAddress(destBuffer.Pixels, indexPixel);
|
||||
const uint8_t* pSrc = T_BUFFER_METHOD::ColorFeature::getPixelAddress(_method.Pixels(), pixelIndex(indexSprite, 0, 0));
|
||||
_method.CopyPixels(pDest, pSrc, copyCount);
|
||||
}
|
||||
|
||||
void Blt(NeoBufferContext<typename T_BUFFER_METHOD::ColorFeature> destBuffer,
|
||||
int16_t x,
|
||||
int16_t y,
|
||||
uint16_t indexSprite,
|
||||
LayoutMapCallback layoutMap)
|
||||
{
|
||||
if (indexSprite >= _spriteCount)
|
||||
{
|
||||
return;
|
||||
}
|
||||
uint16_t destPixelCount = destBuffer.PixelCount();
|
||||
|
||||
for (int16_t srcY = 0; srcY < SpriteHeight(); srcY++)
|
||||
{
|
||||
for (int16_t srcX = 0; srcX < SpriteWidth(); srcX++)
|
||||
{
|
||||
uint16_t indexDest = layoutMap(srcX + x, srcY + y);
|
||||
|
||||
if (indexDest < destPixelCount)
|
||||
{
|
||||
const uint8_t* pSrc = T_BUFFER_METHOD::ColorFeature::getPixelAddress(_method.Pixels(), pixelIndex(indexSprite, srcX, srcY));
|
||||
uint8_t* pDest = T_BUFFER_METHOD::ColorFeature::getPixelAddress(destBuffer.Pixels, indexDest);
|
||||
|
||||
_method.CopyPixels(pDest, pSrc, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private:
|
||||
T_BUFFER_METHOD _method;
|
||||
|
||||
const uint16_t _spriteHeight;
|
||||
const uint16_t _spriteCount;
|
||||
|
||||
uint16_t pixelIndex(uint16_t indexSprite,
|
||||
int16_t x,
|
||||
int16_t y) const
|
||||
{
|
||||
uint16_t result = PixelIndex_OutOfBounds;
|
||||
|
||||
if (indexSprite < _spriteCount &&
|
||||
x >= 0 &&
|
||||
(uint16_t)x < SpriteWidth() &&
|
||||
y >= 0 &&
|
||||
(uint16_t)y < SpriteHeight())
|
||||
{
|
||||
result = x + y * SpriteWidth() + indexSprite * _spriteHeight * SpriteWidth();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
158
lib/NeoPixelBus_by_Makuna/src/internal/NeoTiles.h
Normal file
158
lib/NeoPixelBus_by_Makuna/src/internal/NeoTiles.h
Normal file
@@ -0,0 +1,158 @@
|
||||
#pragma once
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
NeoTiles provides a mapping feature of a 2d cordinate to linear 1d cordinate
|
||||
It is used to map tiles of matricies of NeoPixels to a index on the NeoPixelBus
|
||||
where the the matricies use one topology and the tiles of those matricies can
|
||||
use another
|
||||
|
||||
Written by Michael C. Miller.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// class NeoTiles
|
||||
// Simple template Tile layout class
|
||||
// T_MATRIX_LAYOUT = the layout used on the pixel matrix panel (a tile)
|
||||
// T_TILE_LAYOUT = the layout used for the tiles.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename T_MATRIX_LAYOUT, typename T_TILE_LAYOUT> class NeoTiles
|
||||
{
|
||||
public:
|
||||
NeoTiles(uint16_t topoWidth, uint16_t topoHeight,
|
||||
uint16_t tilesWidth, uint16_t tilesHeight) :
|
||||
_topo(topoWidth, topoHeight),
|
||||
_width(tilesWidth),
|
||||
_height(tilesHeight)
|
||||
{
|
||||
}
|
||||
|
||||
uint16_t Map(int16_t x, int16_t y) const
|
||||
{
|
||||
uint16_t totalWidth = getWidth();
|
||||
uint16_t totalHeight = getHeight();
|
||||
|
||||
if (x >= totalWidth)
|
||||
{
|
||||
x = totalWidth - 1;
|
||||
}
|
||||
else if (x < 0)
|
||||
{
|
||||
x = 0;
|
||||
}
|
||||
|
||||
if (y >= totalHeight)
|
||||
{
|
||||
y = totalHeight - 1;
|
||||
}
|
||||
else if (y < 0)
|
||||
{
|
||||
y = 0;
|
||||
}
|
||||
|
||||
uint16_t localIndex;
|
||||
uint16_t tileOffset;
|
||||
|
||||
calculate(x, y, &localIndex, &tileOffset);
|
||||
|
||||
return localIndex + tileOffset;
|
||||
}
|
||||
|
||||
uint16_t MapProbe(int16_t x, int16_t y) const
|
||||
{
|
||||
uint16_t totalWidth = getWidth();
|
||||
uint16_t totalHeight = getHeight();
|
||||
|
||||
if (x < 0 || x >= totalWidth || y < 0 || y >= totalHeight)
|
||||
{
|
||||
return totalWidth * totalHeight; // count, out of bounds
|
||||
}
|
||||
|
||||
uint16_t localIndex;
|
||||
uint16_t tileOffset;
|
||||
|
||||
calculate(x, y, &localIndex, &tileOffset);
|
||||
|
||||
return localIndex + tileOffset;
|
||||
}
|
||||
|
||||
NeoTopologyHint TopologyHint(int16_t x, int16_t y) const
|
||||
{
|
||||
uint16_t totalWidth = getWidth();
|
||||
uint16_t totalHeight = getHeight();
|
||||
|
||||
if (x < 0 || x >= totalWidth || y < 0 || y >= totalHeight)
|
||||
{
|
||||
return NeoTopologyHint_OutOfBounds;
|
||||
}
|
||||
|
||||
uint16_t localIndex;
|
||||
uint16_t tileOffset;
|
||||
NeoTopologyHint result;
|
||||
|
||||
calculate(x, y, &localIndex, &tileOffset);
|
||||
|
||||
if (localIndex == 0)
|
||||
{
|
||||
result = NeoTopologyHint_FirstOnPanel;
|
||||
}
|
||||
else if (localIndex == (_topo.getWidth() * _topo.getHeight() - 1))
|
||||
{
|
||||
result = NeoTopologyHint_LastOnPanel;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = NeoTopologyHint_InPanel;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uint16_t getWidth() const
|
||||
{
|
||||
return _width * _topo.getWidth();
|
||||
}
|
||||
|
||||
uint16_t getHeight() const
|
||||
{
|
||||
return _height * _topo.getHeight();
|
||||
}
|
||||
|
||||
private:
|
||||
const NeoTopology<T_MATRIX_LAYOUT> _topo;
|
||||
const uint16_t _width;
|
||||
const uint16_t _height;
|
||||
|
||||
void calculate(uint16_t x, uint16_t y, uint16_t* pLocalIndex, uint16_t* pTileOffset) const
|
||||
{
|
||||
uint16_t tileX = x / _topo.getWidth();
|
||||
uint16_t topoX = x % _topo.getWidth();
|
||||
|
||||
uint16_t tileY = y / _topo.getHeight();
|
||||
uint16_t topoY = y % _topo.getHeight();
|
||||
|
||||
*pTileOffset = T_TILE_LAYOUT::Map(_width, _height, tileX, tileY) * _topo.getWidth() * _topo.getHeight();
|
||||
*pLocalIndex = _topo.Map(topoX, topoY);
|
||||
}
|
||||
};
|
||||
|
||||
131
lib/NeoPixelBus_by_Makuna/src/internal/NeoTm1814ColorFeatures.h
Normal file
131
lib/NeoPixelBus_by_Makuna/src/internal/NeoTm1814ColorFeatures.h
Normal file
@@ -0,0 +1,131 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
NeoTm1814ColorFeatures provides feature classes to describe color order and
|
||||
color depth for NeoPixelBus template class specific to the TM1814 chip
|
||||
|
||||
Written by Michael C. Miller.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
#pragma once
|
||||
|
||||
class NeoTm1814Settings : public NeoRgbwCurrentSettings
|
||||
{
|
||||
public:
|
||||
NeoTm1814Settings(uint16_t red, uint16_t green, uint16_t blue, uint16_t white) :
|
||||
NeoRgbwCurrentSettings(red, green, blue, white)
|
||||
{
|
||||
}
|
||||
|
||||
const static uint16_t MinCurrent = 65;
|
||||
const static uint16_t MaxCurrent = 380;
|
||||
|
||||
static uint16_t LimitCurrent(uint16_t value)
|
||||
{
|
||||
if (value < MinCurrent)
|
||||
{
|
||||
value = MinCurrent;
|
||||
}
|
||||
else if (value > MaxCurrent)
|
||||
{
|
||||
value = MaxCurrent;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
class Neo4ElementsTm1814Settings : public Neo4Elements
|
||||
{
|
||||
public:
|
||||
typedef NeoTm1814Settings SettingsObject;
|
||||
static const size_t SettingsSize = 8;
|
||||
|
||||
static void applySettings(uint8_t* pData, const SettingsObject& settings)
|
||||
{
|
||||
uint8_t* pSet = pData;
|
||||
|
||||
// C1
|
||||
*pSet++ = (SettingsObject::LimitCurrent(settings.WhiteCurrent) - SettingsObject::MinCurrent) / 5;
|
||||
*pSet++ = (SettingsObject::LimitCurrent(settings.RedTenthMilliAmpere) - SettingsObject::MinCurrent) / 5;
|
||||
*pSet++ = (SettingsObject::LimitCurrent(settings.GreenTenthMilliAmpere) - SettingsObject::MinCurrent) / 5;
|
||||
*pSet++ = (SettingsObject::LimitCurrent(settings.BlueTenthMilliAmpere) - SettingsObject::MinCurrent) / 5;
|
||||
|
||||
uint8_t* pC1 = pData;
|
||||
|
||||
// C2
|
||||
for (uint8_t elem = 0; elem < 4; elem++)
|
||||
{
|
||||
*pSet++ = ~(*pC1++);
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t* pixels(uint8_t* pData)
|
||||
{
|
||||
return pData + SettingsSize;
|
||||
}
|
||||
|
||||
static const uint8_t* pixels(const uint8_t* pData)
|
||||
{
|
||||
return pData;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class NeoWrgbTm1814Feature : public Neo4ElementsTm1814Settings
|
||||
{
|
||||
public:
|
||||
static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color)
|
||||
{
|
||||
uint8_t* p = getPixelAddress(pPixels, indexPixel);
|
||||
|
||||
*p++ = color.W;
|
||||
*p++ = color.R;
|
||||
*p++ = color.G;
|
||||
*p = color.B;
|
||||
}
|
||||
|
||||
static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel)
|
||||
{
|
||||
ColorObject color;
|
||||
const uint8_t* p = getPixelAddress(pPixels, indexPixel);
|
||||
|
||||
color.W = *p++;
|
||||
color.R = *p++;
|
||||
color.G = *p++;
|
||||
color.B = *p;
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
static ColorObject retrievePixelColor_P(PGM_VOID_P pPixels, uint16_t indexPixel)
|
||||
{
|
||||
ColorObject color;
|
||||
const uint8_t* p = getPixelAddress((const uint8_t*)pPixels, indexPixel);
|
||||
|
||||
color.W = pgm_read_byte(p++);
|
||||
color.R = pgm_read_byte(p++);
|
||||
color.G = pgm_read_byte(p++);
|
||||
color.B = pgm_read_byte(p);
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
91
lib/NeoPixelBus_by_Makuna/src/internal/NeoTopology.h
Normal file
91
lib/NeoPixelBus_by_Makuna/src/internal/NeoTopology.h
Normal file
@@ -0,0 +1,91 @@
|
||||
#pragma once
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
NeoTopology provides a mapping feature of a 2d cordinate to linear 1d cordinate
|
||||
It is used to map a matrix of NeoPixels to a index on the NeoPixelBus
|
||||
|
||||
Written by Michael C. Miller.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
|
||||
enum NeoTopologyHint
|
||||
{
|
||||
NeoTopologyHint_FirstOnPanel,
|
||||
NeoTopologyHint_InPanel,
|
||||
NeoTopologyHint_LastOnPanel,
|
||||
NeoTopologyHint_OutOfBounds
|
||||
};
|
||||
|
||||
template <typename T_LAYOUT> class NeoTopology
|
||||
{
|
||||
public:
|
||||
NeoTopology(uint16_t width, uint16_t height) :
|
||||
_width(width),
|
||||
_height(height)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
uint16_t Map(int16_t x, int16_t y) const
|
||||
{
|
||||
if (x >= _width)
|
||||
{
|
||||
x = _width - 1;
|
||||
}
|
||||
else if (x < 0)
|
||||
{
|
||||
x = 0;
|
||||
}
|
||||
if (y >= _height)
|
||||
{
|
||||
y = _height - 1;
|
||||
}
|
||||
else if (y < 0)
|
||||
{
|
||||
y = 0;
|
||||
}
|
||||
return T_LAYOUT::Map(_width, _height, x, y);
|
||||
}
|
||||
|
||||
uint16_t MapProbe(int16_t x, int16_t y) const
|
||||
{
|
||||
if (x < 0 || x >= _width || y < 0 || y >= _height)
|
||||
{
|
||||
return _width * _height; // count, out of bounds
|
||||
}
|
||||
return T_LAYOUT::Map(_width, _height, x, y);
|
||||
}
|
||||
|
||||
uint16_t getWidth() const
|
||||
{
|
||||
return _width;
|
||||
}
|
||||
|
||||
uint16_t getHeight() const
|
||||
{
|
||||
return _height;
|
||||
}
|
||||
|
||||
private:
|
||||
const uint16_t _width;
|
||||
const uint16_t _height;
|
||||
};
|
||||
162
lib/NeoPixelBus_by_Makuna/src/internal/P9813ColorFeatures.h
Normal file
162
lib/NeoPixelBus_by_Makuna/src/internal/P9813ColorFeatures.h
Normal file
@@ -0,0 +1,162 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
P9813ColorFeatures provides feature classes to describe color order and
|
||||
color depth for NeoPixelBus template class when used with P9813s
|
||||
|
||||
Written by Michael C. Miller.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
#pragma once
|
||||
|
||||
class P98133Elements
|
||||
{
|
||||
public:
|
||||
static const size_t PixelSize = 4; // still requires 4 to be sent
|
||||
|
||||
static uint8_t* getPixelAddress(uint8_t* pPixels, uint16_t indexPixel)
|
||||
{
|
||||
return pPixels + indexPixel * PixelSize;
|
||||
}
|
||||
static const uint8_t* getPixelAddress(const uint8_t* pPixels, uint16_t indexPixel)
|
||||
{
|
||||
return pPixels + indexPixel * PixelSize;
|
||||
}
|
||||
|
||||
static void replicatePixel(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count)
|
||||
{
|
||||
uint8_t* pEnd = pPixelDest + (count * PixelSize);
|
||||
while (pPixelDest < pEnd)
|
||||
{
|
||||
*pPixelDest++ = pPixelSrc[0];
|
||||
*pPixelDest++ = pPixelSrc[1];
|
||||
*pPixelDest++ = pPixelSrc[2];
|
||||
*pPixelDest++ = pPixelSrc[3];
|
||||
}
|
||||
}
|
||||
|
||||
static void movePixelsInc(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count)
|
||||
{
|
||||
uint8_t* pEnd = pPixelDest + (count * PixelSize);
|
||||
while (pPixelDest < pEnd)
|
||||
{
|
||||
*pPixelDest++ = *pPixelSrc++;
|
||||
*pPixelDest++ = *pPixelSrc++;
|
||||
*pPixelDest++ = *pPixelSrc++;
|
||||
*pPixelDest++ = *pPixelSrc++;
|
||||
}
|
||||
}
|
||||
|
||||
static void movePixelsInc_P(uint8_t* pPixelDest, PGM_VOID_P pPixelSrc, uint16_t count)
|
||||
{
|
||||
uint8_t* pEnd = pPixelDest + (count * PixelSize);
|
||||
const uint8_t* pSrc = (const uint8_t*)pPixelSrc;
|
||||
while (pPixelDest < pEnd)
|
||||
{
|
||||
*pPixelDest++ = pgm_read_byte(pSrc++);
|
||||
*pPixelDest++ = pgm_read_byte(pSrc++);
|
||||
*pPixelDest++ = pgm_read_byte(pSrc++);
|
||||
*pPixelDest++ = pgm_read_byte(pSrc++);
|
||||
}
|
||||
}
|
||||
|
||||
static void movePixelsDec(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count)
|
||||
{
|
||||
uint8_t* pDestBack = pPixelDest + (count * PixelSize);
|
||||
const uint8_t* pSrcBack = pPixelSrc + (count * PixelSize);
|
||||
while (pDestBack > pPixelDest)
|
||||
{
|
||||
*--pDestBack = *--pSrcBack;
|
||||
*--pDestBack = *--pSrcBack;
|
||||
*--pDestBack = *--pSrcBack;
|
||||
*--pDestBack = *--pSrcBack;
|
||||
}
|
||||
}
|
||||
|
||||
typedef RgbColor ColorObject;
|
||||
};
|
||||
|
||||
class P98133ElementsNoSettings : public P98133Elements
|
||||
{
|
||||
public:
|
||||
typedef NeoNoSettings SettingsObject;
|
||||
static const size_t SettingsSize = 0;
|
||||
|
||||
static void applySettings(uint8_t*, const SettingsObject&)
|
||||
{
|
||||
}
|
||||
|
||||
static uint8_t* pixels(uint8_t* pData)
|
||||
{
|
||||
return pData;
|
||||
}
|
||||
|
||||
static const uint8_t* pixels(const uint8_t* pData)
|
||||
{
|
||||
return pData;
|
||||
}
|
||||
};
|
||||
|
||||
class P9813BgrFeature : public P98133ElementsNoSettings
|
||||
{
|
||||
public:
|
||||
static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color)
|
||||
{
|
||||
uint8_t* p = getPixelAddress(pPixels, indexPixel);
|
||||
|
||||
*p++ = 0xC0 | ((~color.B & 0xC0) >> 2) | ((~color.G & 0xC0) >> 4) | ((~color.R & 0xC0) >> 6);
|
||||
*p++ = color.B;
|
||||
*p++ = color.G;
|
||||
*p = color.R;
|
||||
}
|
||||
|
||||
static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel)
|
||||
{
|
||||
ColorObject color;
|
||||
const uint8_t* p = getPixelAddress(pPixels, indexPixel);
|
||||
|
||||
p++; // ignore the first byte
|
||||
color.B = *p++;
|
||||
color.G = *p++;
|
||||
color.R = *p;
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
static ColorObject retrievePixelColor_P(PGM_VOID_P pPixels, uint16_t indexPixel)
|
||||
{
|
||||
ColorObject color;
|
||||
const uint8_t* p = getPixelAddress((const uint8_t*)pPixels, indexPixel);
|
||||
|
||||
pgm_read_byte(p++); // ignore the first byte
|
||||
color.B = pgm_read_byte(p++);
|
||||
color.G = pgm_read_byte(p++);
|
||||
color.R = pgm_read_byte(p);
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
126
lib/NeoPixelBus_by_Makuna/src/internal/P9813GenericMethod.h
Normal file
126
lib/NeoPixelBus_by_Makuna/src/internal/P9813GenericMethod.h
Normal file
@@ -0,0 +1,126 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
NeoPixel library helper functions for P9813s using general Pins (APA102).
|
||||
|
||||
Written by Michael C. Miller.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// must also check for arm due to Teensy incorrectly having ARDUINO_ARCH_AVR set
|
||||
#if defined(ARDUINO_ARCH_AVR) && !defined(__arm__)
|
||||
#include "TwoWireBitBangImpleAvr.h"
|
||||
#else
|
||||
#include "TwoWireBitBangImple.h"
|
||||
#endif
|
||||
|
||||
|
||||
template<typename T_TWOWIRE> class P9813MethodBase
|
||||
{
|
||||
public:
|
||||
P9813MethodBase(uint8_t pinClock, uint8_t pinData, uint16_t pixelCount, size_t elementSize, size_t settingsSize) :
|
||||
_sizeData(pixelCount * elementSize + settingsSize),
|
||||
_sizeEndFrame((pixelCount + 15) / 16), // 16 = div 2 (bit for every two pixels) div 8 (bits to bytes)
|
||||
_wire(pinClock, pinData)
|
||||
{
|
||||
_data = static_cast<uint8_t*>(malloc(_sizeData));
|
||||
memset(_data, 0, _sizeData);
|
||||
}
|
||||
|
||||
#if !defined(__AVR_ATtiny85__) && !defined(ARDUINO_attiny)
|
||||
P9813MethodBase(uint16_t pixelCount, size_t elementSize, size_t settingsSize) :
|
||||
P9813MethodBase(SCK, MOSI, pixelCount, elementSize, settingsSize)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
~P9813MethodBase()
|
||||
{
|
||||
free(_data);
|
||||
}
|
||||
|
||||
bool IsReadyToUpdate() const
|
||||
{
|
||||
return true; // dot stars don't have a required delay
|
||||
}
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP32)
|
||||
void Initialize(int8_t sck, int8_t miso, int8_t mosi, int8_t ss)
|
||||
{
|
||||
_wire.begin(sck, miso, mosi, ss);
|
||||
}
|
||||
#endif
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
_wire.begin();
|
||||
}
|
||||
|
||||
void Update(bool)
|
||||
{
|
||||
const uint8_t startFrame[4] = { 0x00 };
|
||||
const uint8_t endFrame[4] = { 0x00 };
|
||||
|
||||
_wire.beginTransaction();
|
||||
|
||||
// start frame
|
||||
_wire.transmitBytes(startFrame, sizeof(startFrame));
|
||||
|
||||
// data
|
||||
_wire.transmitBytes(_data, _sizeData);
|
||||
|
||||
// end frame
|
||||
_wire.transmitBytes(endFrame, sizeof(endFrame));
|
||||
|
||||
_wire.endTransaction();
|
||||
}
|
||||
|
||||
uint8_t* getData() const
|
||||
{
|
||||
return _data;
|
||||
};
|
||||
|
||||
size_t getDataSize() const
|
||||
{
|
||||
return _sizeData;
|
||||
};
|
||||
|
||||
private:
|
||||
const size_t _sizeData; // Size of '_data' buffer below
|
||||
const size_t _sizeEndFrame;
|
||||
|
||||
T_TWOWIRE _wire;
|
||||
uint8_t* _data; // Holds LED color values
|
||||
};
|
||||
|
||||
typedef P9813MethodBase<TwoWireBitBangImple> P9813Method;
|
||||
|
||||
#if !defined(__AVR_ATtiny85__) && !defined(ARDUINO_attiny)
|
||||
#include "TwoWireSpiImple.h"
|
||||
typedef P9813MethodBase<TwoWireSpiImple<SpiSpeed20Mhz>> P9813Spi20MhzMethod;
|
||||
typedef P9813MethodBase<TwoWireSpiImple<SpiSpeed10Mhz>> P9813Spi10MhzMethod;
|
||||
typedef P9813MethodBase<TwoWireSpiImple<SpiSpeed2Mhz>> P9813Spi2MhzMethod;
|
||||
typedef P9813Spi10MhzMethod P9813SpiMethod;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
261
lib/NeoPixelBus_by_Makuna/src/internal/RgbColor.cpp
Normal file
261
lib/NeoPixelBus_by_Makuna/src/internal/RgbColor.cpp
Normal file
@@ -0,0 +1,261 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
RgbColor provides a color object that can be directly consumed by NeoPixelBus
|
||||
|
||||
Written by Michael C. Miller.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
|
||||
#include "RgbColor.h"
|
||||
#include "HslColor.h"
|
||||
#include "HsbColor.h"
|
||||
#include "HtmlColor.h"
|
||||
|
||||
static float _CalcColor(float p, float q, float t)
|
||||
{
|
||||
if (t < 0.0f)
|
||||
t += 1.0f;
|
||||
if (t > 1.0f)
|
||||
t -= 1.0f;
|
||||
|
||||
if (t < 1.0f / 6.0f)
|
||||
return p + (q - p) * 6.0f * t;
|
||||
|
||||
if (t < 0.5f)
|
||||
return q;
|
||||
|
||||
if (t < 2.0f / 3.0f)
|
||||
return p + ((q - p) * (2.0f / 3.0f - t) * 6.0f);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
RgbColor::RgbColor(const HtmlColor& color)
|
||||
{
|
||||
uint32_t temp = color.Color;
|
||||
|
||||
B = (temp & 0xff);
|
||||
temp = temp >> 8;
|
||||
G = (temp & 0xff);
|
||||
temp = temp >> 8;
|
||||
R = (temp & 0xff);
|
||||
};
|
||||
|
||||
RgbColor::RgbColor(const HslColor& color)
|
||||
{
|
||||
float r;
|
||||
float g;
|
||||
float b;
|
||||
|
||||
float h = color.H;
|
||||
float s = color.S;
|
||||
float l = color.L;
|
||||
|
||||
|
||||
if (color.S == 0.0f || color.L == 0.0f)
|
||||
{
|
||||
r = g = b = l; // achromatic or black
|
||||
}
|
||||
else
|
||||
{
|
||||
float q = l < 0.5f ? l * (1.0f + s) : l + s - (l * s);
|
||||
float p = 2.0f * l - q;
|
||||
r = _CalcColor(p, q, h + 1.0f / 3.0f);
|
||||
g = _CalcColor(p, q, h);
|
||||
b = _CalcColor(p, q, h - 1.0f / 3.0f);
|
||||
}
|
||||
|
||||
R = (uint8_t)(r * 255.0f);
|
||||
G = (uint8_t)(g * 255.0f);
|
||||
B = (uint8_t)(b * 255.0f);
|
||||
}
|
||||
|
||||
RgbColor::RgbColor(const HsbColor& color)
|
||||
{
|
||||
float r;
|
||||
float g;
|
||||
float b;
|
||||
|
||||
float h = color.H;
|
||||
float s = color.S;
|
||||
float v = color.B;
|
||||
|
||||
if (color.S == 0.0f)
|
||||
{
|
||||
r = g = b = v; // achromatic or black
|
||||
}
|
||||
else
|
||||
{
|
||||
if (h < 0.0f)
|
||||
{
|
||||
h += 1.0f;
|
||||
}
|
||||
else if (h >= 1.0f)
|
||||
{
|
||||
h -= 1.0f;
|
||||
}
|
||||
h *= 6.0f;
|
||||
int i = (int)h;
|
||||
float f = h - i;
|
||||
float q = v * (1.0f - s * f);
|
||||
float p = v * (1.0f - s);
|
||||
float t = v * (1.0f - s * (1.0f - f));
|
||||
switch (i)
|
||||
{
|
||||
case 0:
|
||||
r = v;
|
||||
g = t;
|
||||
b = p;
|
||||
break;
|
||||
case 1:
|
||||
r = q;
|
||||
g = v;
|
||||
b = p;
|
||||
break;
|
||||
case 2:
|
||||
r = p;
|
||||
g = v;
|
||||
b = t;
|
||||
break;
|
||||
case 3:
|
||||
r = p;
|
||||
g = q;
|
||||
b = v;
|
||||
break;
|
||||
case 4:
|
||||
r = t;
|
||||
g = p;
|
||||
b = v;
|
||||
break;
|
||||
default:
|
||||
r = v;
|
||||
g = p;
|
||||
b = q;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
R = (uint8_t)(r * 255.0f);
|
||||
G = (uint8_t)(g * 255.0f);
|
||||
B = (uint8_t)(b * 255.0f);
|
||||
}
|
||||
|
||||
uint8_t RgbColor::CalculateBrightness() const
|
||||
{
|
||||
return (uint8_t)(((uint16_t)R + (uint16_t)G + (uint16_t)B) / 3);
|
||||
}
|
||||
|
||||
RgbColor RgbColor::Dim(uint8_t ratio) const
|
||||
{
|
||||
// specifically avoids float math
|
||||
return RgbColor(_elementDim(R, ratio), _elementDim(G, ratio), _elementDim(B, ratio));
|
||||
}
|
||||
|
||||
RgbColor RgbColor::Brighten(uint8_t ratio) const
|
||||
{
|
||||
// specifically avoids float math
|
||||
return RgbColor(_elementBrighten(R, ratio), _elementBrighten(G, ratio), _elementBrighten(B, ratio));
|
||||
}
|
||||
|
||||
void RgbColor::Darken(uint8_t delta)
|
||||
{
|
||||
if (R > delta)
|
||||
{
|
||||
R -= delta;
|
||||
}
|
||||
else
|
||||
{
|
||||
R = 0;
|
||||
}
|
||||
|
||||
if (G > delta)
|
||||
{
|
||||
G -= delta;
|
||||
}
|
||||
else
|
||||
{
|
||||
G = 0;
|
||||
}
|
||||
|
||||
if (B > delta)
|
||||
{
|
||||
B -= delta;
|
||||
}
|
||||
else
|
||||
{
|
||||
B = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void RgbColor::Lighten(uint8_t delta)
|
||||
{
|
||||
if (R < 255 - delta)
|
||||
{
|
||||
R += delta;
|
||||
}
|
||||
else
|
||||
{
|
||||
R = 255;
|
||||
}
|
||||
|
||||
if (G < 255 - delta)
|
||||
{
|
||||
G += delta;
|
||||
}
|
||||
else
|
||||
{
|
||||
G = 255;
|
||||
}
|
||||
|
||||
if (B < 255 - delta)
|
||||
{
|
||||
B += delta;
|
||||
}
|
||||
else
|
||||
{
|
||||
B = 255;
|
||||
}
|
||||
}
|
||||
|
||||
RgbColor RgbColor::LinearBlend(const RgbColor& left, const RgbColor& right, float progress)
|
||||
{
|
||||
return RgbColor( left.R + ((right.R - left.R) * progress),
|
||||
left.G + ((right.G - left.G) * progress),
|
||||
left.B + ((right.B - left.B) * progress));
|
||||
}
|
||||
|
||||
RgbColor RgbColor::BilinearBlend(const RgbColor& c00,
|
||||
const RgbColor& c01,
|
||||
const RgbColor& c10,
|
||||
const RgbColor& c11,
|
||||
float x,
|
||||
float y)
|
||||
{
|
||||
float v00 = (1.0f - x) * (1.0f - y);
|
||||
float v10 = x * (1.0f - y);
|
||||
float v01 = (1.0f - x) * y;
|
||||
float v11 = x * y;
|
||||
|
||||
return RgbColor(
|
||||
c00.R * v00 + c10.R * v10 + c01.R * v01 + c11.R * v11,
|
||||
c00.G * v00 + c10.G * v10 + c01.G * v01 + c11.G * v11,
|
||||
c00.B * v00 + c10.B * v10 + c01.B * v01 + c11.B * v11);
|
||||
}
|
||||
199
lib/NeoPixelBus_by_Makuna/src/internal/RgbColor.h
Normal file
199
lib/NeoPixelBus_by_Makuna/src/internal/RgbColor.h
Normal file
@@ -0,0 +1,199 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
RgbColor provides a color object that can be directly consumed by NeoPixelBus
|
||||
|
||||
Written by Michael C. Miller.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "NeoSettings.h"
|
||||
|
||||
struct HslColor;
|
||||
struct HsbColor;
|
||||
struct HtmlColor;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// RgbColor represents a color object that is represented by Red, Green, Blue
|
||||
// component values. It contains helpful color routines to manipulate the
|
||||
// color.
|
||||
// ------------------------------------------------------------------------
|
||||
struct RgbColor
|
||||
{
|
||||
typedef NeoRgbCurrentSettings SettingsObject;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Construct a RgbColor using R, G, B values (0-255)
|
||||
// ------------------------------------------------------------------------
|
||||
RgbColor(uint8_t r, uint8_t g, uint8_t b) :
|
||||
R(r), G(g), B(b)
|
||||
{
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Construct a RgbColor using a single brightness value (0-255)
|
||||
// This works well for creating gray tone colors
|
||||
// (0) = black, (255) = white, (128) = gray
|
||||
// ------------------------------------------------------------------------
|
||||
RgbColor(uint8_t brightness) :
|
||||
R(brightness), G(brightness), B(brightness)
|
||||
{
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Construct a RgbColor using HtmlColor
|
||||
// ------------------------------------------------------------------------
|
||||
RgbColor(const HtmlColor& color);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Construct a RgbColor using HslColor
|
||||
// ------------------------------------------------------------------------
|
||||
RgbColor(const HslColor& color);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Construct a RgbColor using HsbColor
|
||||
// ------------------------------------------------------------------------
|
||||
RgbColor(const HsbColor& color);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Construct a RgbColor that will have its values set in latter operations
|
||||
// CAUTION: The R,G,B members are not initialized and may not be consistent
|
||||
// ------------------------------------------------------------------------
|
||||
RgbColor()
|
||||
{
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Comparison operators
|
||||
// ------------------------------------------------------------------------
|
||||
bool operator==(const RgbColor& other) const
|
||||
{
|
||||
return (R == other.R && G == other.G && B == other.B);
|
||||
};
|
||||
|
||||
bool operator!=(const RgbColor& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// CalculateBrightness will calculate the overall brightness
|
||||
// NOTE: This is a simple linear brightness
|
||||
// ------------------------------------------------------------------------
|
||||
uint8_t CalculateBrightness() const;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Dim will return a new color that is blended to black with the given ratio
|
||||
// ratio - (0-255) where 255 will return the original color and 0 will return black
|
||||
//
|
||||
// NOTE: This is a simple linear blend
|
||||
// ------------------------------------------------------------------------
|
||||
RgbColor Dim(uint8_t ratio) const;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Brighten will return a new color that is blended to white with the given ratio
|
||||
// ratio - (0-255) where 255 will return the original color and 0 will return white
|
||||
//
|
||||
// NOTE: This is a simple linear blend
|
||||
// ------------------------------------------------------------------------
|
||||
RgbColor Brighten(uint8_t ratio) const;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Darken will adjust the color by the given delta toward black
|
||||
// NOTE: This is a simple linear change
|
||||
// delta - (0-255) the amount to dim the color
|
||||
// ------------------------------------------------------------------------
|
||||
void Darken(uint8_t delta);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Lighten will adjust the color by the given delta toward white
|
||||
// NOTE: This is a simple linear change
|
||||
// delta - (0-255) the amount to lighten the color
|
||||
// ------------------------------------------------------------------------
|
||||
void Lighten(uint8_t delta);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// LinearBlend between two colors by the amount defined by progress variable
|
||||
// left - the color to start the blend at
|
||||
// right - the color to end the blend at
|
||||
// progress - (0.0 - 1.0) value where 0 will return left and 1.0 will return right
|
||||
// and a value between will blend the color weighted linearly between them
|
||||
// ------------------------------------------------------------------------
|
||||
static RgbColor LinearBlend(const RgbColor& left, const RgbColor& right, float progress);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// BilinearBlend between four colors by the amount defined by 2d variable
|
||||
// c00 - upper left quadrant color
|
||||
// c01 - upper right quadrant color
|
||||
// c10 - lower left quadrant color
|
||||
// c11 - lower right quadrant color
|
||||
// x - unit value (0.0 - 1.0) that defines the blend progress in horizontal space
|
||||
// y - unit value (0.0 - 1.0) that defines the blend progress in vertical space
|
||||
// ------------------------------------------------------------------------
|
||||
static RgbColor BilinearBlend(const RgbColor& c00,
|
||||
const RgbColor& c01,
|
||||
const RgbColor& c10,
|
||||
const RgbColor& c11,
|
||||
float x,
|
||||
float y);
|
||||
|
||||
uint32_t CalcTotalTenthMilliAmpere(const SettingsObject& settings)
|
||||
{
|
||||
auto total = 0;
|
||||
|
||||
total += R * settings.RedTenthMilliAmpere / 255;
|
||||
total += G * settings.GreenTenthMilliAmpere / 255;
|
||||
total += B * settings.BlueTenthMilliAmpere / 255;
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Red, Green, Blue color members (0-255) where
|
||||
// (0,0,0) is black and (255,255,255) is white
|
||||
// ------------------------------------------------------------------------
|
||||
uint8_t R;
|
||||
uint8_t G;
|
||||
uint8_t B;
|
||||
|
||||
private:
|
||||
inline static uint8_t _elementDim(uint8_t value, uint8_t ratio)
|
||||
{
|
||||
return (static_cast<uint16_t>(value) * (static_cast<uint16_t>(ratio) + 1)) >> 8;
|
||||
}
|
||||
|
||||
inline static uint8_t _elementBrighten(uint8_t value, uint8_t ratio)
|
||||
{
|
||||
uint16_t element = ((static_cast<uint16_t>(value) + 1) << 8) / (static_cast<uint16_t>(ratio) + 1);
|
||||
|
||||
if (element > 255)
|
||||
{
|
||||
element = 255;
|
||||
}
|
||||
else
|
||||
{
|
||||
element -= 1;
|
||||
}
|
||||
return element;
|
||||
}
|
||||
};
|
||||
|
||||
190
lib/NeoPixelBus_by_Makuna/src/internal/RgbwColor.cpp
Normal file
190
lib/NeoPixelBus_by_Makuna/src/internal/RgbwColor.cpp
Normal file
@@ -0,0 +1,190 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
RgbwColor provides a color object that can be directly consumed by NeoPixelBus
|
||||
|
||||
Written by Michael C. Miller.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
|
||||
#include "RgbColor.h"
|
||||
#include "HslColor.h"
|
||||
#include "HsbColor.h"
|
||||
#include "RgbwColor.h"
|
||||
#include "HtmlColor.h"
|
||||
|
||||
RgbwColor::RgbwColor(const HtmlColor& color)
|
||||
{
|
||||
uint32_t temp = color.Color;
|
||||
B = (temp & 0xff);
|
||||
temp = temp >> 8;
|
||||
G = (temp & 0xff);
|
||||
temp = temp >> 8;
|
||||
R = (temp & 0xff);
|
||||
temp = temp >> 8;
|
||||
W = (temp & 0xff);
|
||||
};
|
||||
|
||||
RgbwColor::RgbwColor(const HslColor& color)
|
||||
{
|
||||
RgbColor rgbColor(color);
|
||||
*this = rgbColor;
|
||||
}
|
||||
|
||||
RgbwColor::RgbwColor(const HsbColor& color)
|
||||
{
|
||||
RgbColor rgbColor(color);
|
||||
*this = rgbColor;
|
||||
}
|
||||
|
||||
uint8_t RgbwColor::CalculateBrightness() const
|
||||
{
|
||||
uint8_t colorB = (uint8_t)(((uint16_t)R + (uint16_t)G + (uint16_t)B) / 3);
|
||||
if (W > colorB)
|
||||
{
|
||||
return W;
|
||||
}
|
||||
else
|
||||
{
|
||||
return colorB;
|
||||
}
|
||||
}
|
||||
|
||||
RgbwColor RgbwColor::Dim(uint8_t ratio) const
|
||||
{
|
||||
// specifically avoids float math
|
||||
return RgbwColor(_elementDim(R, ratio), _elementDim(G, ratio), _elementDim(B, ratio), _elementDim(W, ratio));
|
||||
}
|
||||
|
||||
RgbwColor RgbwColor::Brighten(uint8_t ratio) const
|
||||
{
|
||||
// specifically avoids float math
|
||||
return RgbwColor(_elementBrighten(R, ratio), _elementBrighten(G, ratio), _elementBrighten(B, ratio), _elementBrighten(W, ratio));
|
||||
}
|
||||
|
||||
void RgbwColor::Darken(uint8_t delta)
|
||||
{
|
||||
if (R > delta)
|
||||
{
|
||||
R -= delta;
|
||||
}
|
||||
else
|
||||
{
|
||||
R = 0;
|
||||
}
|
||||
|
||||
if (G > delta)
|
||||
{
|
||||
G -= delta;
|
||||
}
|
||||
else
|
||||
{
|
||||
G = 0;
|
||||
}
|
||||
|
||||
if (B > delta)
|
||||
{
|
||||
B -= delta;
|
||||
}
|
||||
else
|
||||
{
|
||||
B = 0;
|
||||
}
|
||||
|
||||
if (W > delta)
|
||||
{
|
||||
W -= delta;
|
||||
}
|
||||
else
|
||||
{
|
||||
W = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void RgbwColor::Lighten(uint8_t delta)
|
||||
{
|
||||
if (IsColorLess())
|
||||
{
|
||||
if (W < 255 - delta)
|
||||
{
|
||||
W += delta;
|
||||
}
|
||||
else
|
||||
{
|
||||
W = 255;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (R < 255 - delta)
|
||||
{
|
||||
R += delta;
|
||||
}
|
||||
else
|
||||
{
|
||||
R = 255;
|
||||
}
|
||||
|
||||
if (G < 255 - delta)
|
||||
{
|
||||
G += delta;
|
||||
}
|
||||
else
|
||||
{
|
||||
G = 255;
|
||||
}
|
||||
|
||||
if (B < 255 - delta)
|
||||
{
|
||||
B += delta;
|
||||
}
|
||||
else
|
||||
{
|
||||
B = 255;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RgbwColor RgbwColor::LinearBlend(const RgbwColor& left, const RgbwColor& right, float progress)
|
||||
{
|
||||
return RgbwColor( left.R + ((right.R - left.R) * progress),
|
||||
left.G + ((right.G - left.G) * progress),
|
||||
left.B + ((right.B - left.B) * progress),
|
||||
left.W + ((right.W - left.W) * progress) );
|
||||
}
|
||||
|
||||
RgbwColor RgbwColor::BilinearBlend(const RgbwColor& c00,
|
||||
const RgbwColor& c01,
|
||||
const RgbwColor& c10,
|
||||
const RgbwColor& c11,
|
||||
float x,
|
||||
float y)
|
||||
{
|
||||
float v00 = (1.0f - x) * (1.0f - y);
|
||||
float v10 = x * (1.0f - y);
|
||||
float v01 = (1.0f - x) * y;
|
||||
float v11 = x * y;
|
||||
|
||||
return RgbwColor(
|
||||
c00.R * v00 + c10.R * v10 + c01.R * v01 + c11.R * v11,
|
||||
c00.G * v00 + c10.G * v10 + c01.G * v01 + c11.G * v11,
|
||||
c00.B * v00 + c10.B * v10 + c01.B * v01 + c11.B * v11,
|
||||
c00.W * v00 + c10.W * v10 + c01.W * v01 + c11.W * v11 );
|
||||
}
|
||||
229
lib/NeoPixelBus_by_Makuna/src/internal/RgbwColor.h
Normal file
229
lib/NeoPixelBus_by_Makuna/src/internal/RgbwColor.h
Normal file
@@ -0,0 +1,229 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
RgbwColor provides a color object that can be directly consumed by NeoPixelBus
|
||||
|
||||
Written by Michael C. Miller.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
struct RgbColor;
|
||||
struct HslColor;
|
||||
struct HsbColor;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// RgbwColor represents a color object that is represented by Red, Green, Blue
|
||||
// component values and an extra White component. It contains helpful color
|
||||
// routines to manipulate the color.
|
||||
// ------------------------------------------------------------------------
|
||||
struct RgbwColor
|
||||
{
|
||||
typedef NeoRgbwCurrentSettings SettingsObject;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Construct a RgbwColor using R, G, B, W values (0-255)
|
||||
// ------------------------------------------------------------------------
|
||||
RgbwColor(uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0) :
|
||||
R(r), G(g), B(b), W(w)
|
||||
{
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Construct a RgbColor using a single brightness value (0-255)
|
||||
// This works well for creating gray tone colors
|
||||
// (0) = black, (255) = white, (128) = gray
|
||||
// ------------------------------------------------------------------------
|
||||
RgbwColor(uint8_t brightness) :
|
||||
R(0), G(0), B(0), W(brightness)
|
||||
{
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Construct a RgbwColor using RgbColor
|
||||
// ------------------------------------------------------------------------
|
||||
RgbwColor(const RgbColor& color) :
|
||||
R(color.R),
|
||||
G(color.G),
|
||||
B(color.B),
|
||||
W(0)
|
||||
{
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Construct a RgbwColor using HtmlColor
|
||||
// ------------------------------------------------------------------------
|
||||
RgbwColor(const HtmlColor& color);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Construct a RgbwColor using HslColor
|
||||
// ------------------------------------------------------------------------
|
||||
RgbwColor(const HslColor& color);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Construct a RgbwColor using HsbColor
|
||||
// ------------------------------------------------------------------------
|
||||
RgbwColor(const HsbColor& color);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Construct a RgbwColor that will have its values set in latter operations
|
||||
// CAUTION: The R,G,B, W members are not initialized and may not be consistent
|
||||
// ------------------------------------------------------------------------
|
||||
RgbwColor()
|
||||
{
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Comparison operators
|
||||
// ------------------------------------------------------------------------
|
||||
bool operator==(const RgbwColor& other) const
|
||||
{
|
||||
return (R == other.R && G == other.G && B == other.B && W == other.W);
|
||||
};
|
||||
|
||||
bool operator!=(const RgbwColor& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Returns if the color is grey, all values are equal other than white
|
||||
// ------------------------------------------------------------------------
|
||||
bool IsMonotone() const
|
||||
{
|
||||
return (R == B && R == G);
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Returns if the color components are all zero, the white component maybe
|
||||
// anything
|
||||
// ------------------------------------------------------------------------
|
||||
bool IsColorLess() const
|
||||
{
|
||||
return (R == 0 && B == 0 && G == 0);
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// CalculateBrightness will calculate the overall brightness
|
||||
// NOTE: This is a simple linear brightness
|
||||
// ------------------------------------------------------------------------
|
||||
uint8_t CalculateBrightness() const;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Dim will return a new color that is blended to black with the given ratio
|
||||
// ratio - (0-255) where 255 will return the original color and 0 will return black
|
||||
//
|
||||
// NOTE: This is a simple linear blend
|
||||
// ------------------------------------------------------------------------
|
||||
RgbwColor Dim(uint8_t ratio) const;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Brighten will return a new color that is blended to white with the given ratio
|
||||
// ratio - (0-255) where 255 will return the original color and 0 will return white
|
||||
//
|
||||
// NOTE: This is a simple linear blend
|
||||
// ------------------------------------------------------------------------
|
||||
RgbwColor Brighten(uint8_t ratio) const;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Darken will adjust the color by the given delta toward black
|
||||
// NOTE: This is a simple linear change
|
||||
// delta - (0-255) the amount to dim the color
|
||||
// ------------------------------------------------------------------------
|
||||
void Darken(uint8_t delta);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Lighten will adjust the color by the given delta toward white
|
||||
// NOTE: This is a simple linear change
|
||||
// delta - (0-255) the amount to lighten the color
|
||||
// ------------------------------------------------------------------------
|
||||
void Lighten(uint8_t delta);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// LinearBlend between two colors by the amount defined by progress variable
|
||||
// left - the color to start the blend at
|
||||
// right - the color to end the blend at
|
||||
// progress - (0.0 - 1.0) value where 0 will return left and 1.0 will return right
|
||||
// and a value between will blend the color weighted linearly between them
|
||||
// ------------------------------------------------------------------------
|
||||
static RgbwColor LinearBlend(const RgbwColor& left, const RgbwColor& right, float progress);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// BilinearBlend between four colors by the amount defined by 2d variable
|
||||
// c00 - upper left quadrant color
|
||||
// c01 - upper right quadrant color
|
||||
// c10 - lower left quadrant color
|
||||
// c11 - lower right quadrant color
|
||||
// x - unit value (0.0 - 1.0) that defines the blend progress in horizontal space
|
||||
// y - unit value (0.0 - 1.0) that defines the blend progress in vertical space
|
||||
// ------------------------------------------------------------------------
|
||||
static RgbwColor BilinearBlend(const RgbwColor& c00,
|
||||
const RgbwColor& c01,
|
||||
const RgbwColor& c10,
|
||||
const RgbwColor& c11,
|
||||
float x,
|
||||
float y);
|
||||
|
||||
uint16_t CalcTotalTenthMilliAmpere(const SettingsObject& settings)
|
||||
{
|
||||
auto total = 0;
|
||||
|
||||
total += R * settings.RedTenthMilliAmpere / 255;
|
||||
total += G * settings.GreenTenthMilliAmpere / 255;
|
||||
total += B * settings.BlueTenthMilliAmpere / 255;
|
||||
total += W * settings.WhiteCurrent / 255;
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Red, Green, Blue, White color members (0-255) where
|
||||
// (0,0,0,0) is black and (255,255,255, 0) and (0,0,0,255) is white
|
||||
// Note (255,255,255,255) is extreme bright white
|
||||
// ------------------------------------------------------------------------
|
||||
uint8_t R;
|
||||
uint8_t G;
|
||||
uint8_t B;
|
||||
uint8_t W;
|
||||
|
||||
private:
|
||||
inline static uint8_t _elementDim(uint8_t value, uint8_t ratio)
|
||||
{
|
||||
return (static_cast<uint16_t>(value) * (static_cast<uint16_t>(ratio) + 1)) >> 8;
|
||||
}
|
||||
|
||||
inline static uint8_t _elementBrighten(uint8_t value, uint8_t ratio)
|
||||
{
|
||||
uint16_t element = ((static_cast<uint16_t>(value) + 1) << 8) / (static_cast<uint16_t>(ratio) + 1);
|
||||
|
||||
if (element > 255)
|
||||
{
|
||||
element = 255;
|
||||
}
|
||||
else
|
||||
{
|
||||
element -= 1;
|
||||
}
|
||||
return element;
|
||||
}
|
||||
};
|
||||
|
||||
153
lib/NeoPixelBus_by_Makuna/src/internal/SegmentDigit.cpp
Normal file
153
lib/NeoPixelBus_by_Makuna/src/internal/SegmentDigit.cpp
Normal file
@@ -0,0 +1,153 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
SegmentDigit provides a color object that can be directly consumed by NeoPixelBus
|
||||
|
||||
Written by Michael C. Miller.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
|
||||
#include "SegmentDigit.h"
|
||||
|
||||
//
|
||||
// https://en.wikichip.org/wiki/seven-segment_display/representing_letters
|
||||
//
|
||||
const uint8_t SevenSegDigit::DecodeNumbers[] = {
|
||||
// 0 1 2 3 4 5 6 7 8 9
|
||||
0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F };
|
||||
|
||||
const uint8_t SevenSegDigit::DecodeAlphaCaps[] = {
|
||||
// A B C D E F G
|
||||
0x77, 0x00, 0x39, 0x00, 0x79, 0x71, 0x3D,
|
||||
// H I J K L M N
|
||||
0x76, 0x30, 0x1E, 0x00, 0x38, 0x00, 0x00,
|
||||
// O P Q R S
|
||||
0x3F, 0x73, 0x00, 0x00, 0x6D,
|
||||
// T U V W X Y Z
|
||||
0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
|
||||
const uint8_t SevenSegDigit::DecodeAlpha[] = {
|
||||
// a b c d e f g
|
||||
0x00, 0x7C, 0x58, 0x5E, 0x00, 0x00, 0x00,
|
||||
// h i j k l m n
|
||||
0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54,
|
||||
// o p q r s
|
||||
0x5C, 0x00, 0x67, 0x50, 0x00,
|
||||
// t u v w x y z
|
||||
0x78, 0x1C, 0x00, 0x00, 0x00, 0x6E, 0x00 };
|
||||
|
||||
const uint8_t SevenSegDigit::DecodeSpecial[] = {
|
||||
// , - . /
|
||||
0x80, 0x40, 0x80, 0x40 };
|
||||
|
||||
void SevenSegDigit::init(uint8_t bitmask, uint8_t brightness, uint8_t defaultBrightness)
|
||||
{
|
||||
for (uint8_t iSegment = 0; iSegment < SegmentCount; iSegment++)
|
||||
{
|
||||
Segment[iSegment] = (bitmask & 0x01) ? brightness : defaultBrightness;
|
||||
bitmask >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
SevenSegDigit::SevenSegDigit(uint8_t bitmask, uint8_t brightness, uint8_t defaultBrightness)
|
||||
{
|
||||
init(bitmask, brightness, defaultBrightness);
|
||||
};
|
||||
|
||||
SevenSegDigit::SevenSegDigit(char letter, uint8_t brightness, uint8_t defaultBrightness)
|
||||
{
|
||||
if (letter >= '0' && letter <= '9')
|
||||
{
|
||||
init(DecodeNumbers[letter - '0'], brightness, defaultBrightness);
|
||||
}
|
||||
else if (letter >= 'a' && letter <= 'z')
|
||||
{
|
||||
init(DecodeAlpha[letter - 'a'], brightness, defaultBrightness);
|
||||
}
|
||||
else if (letter >= 'A' && letter <= 'Z')
|
||||
{
|
||||
init(DecodeAlphaCaps[letter - 'A'], brightness, defaultBrightness);
|
||||
}
|
||||
else if (letter >= ',' && letter <= '/')
|
||||
{
|
||||
init(DecodeSpecial[letter - ','], brightness, defaultBrightness);
|
||||
}
|
||||
else
|
||||
{
|
||||
memset(Segment, defaultBrightness, sizeof(Segment));
|
||||
}
|
||||
};
|
||||
|
||||
uint8_t SevenSegDigit::CalculateBrightness() const
|
||||
{
|
||||
uint16_t sum = 0;
|
||||
|
||||
for (uint8_t iSegment = 0; iSegment < SegmentCount; iSegment++)
|
||||
{
|
||||
sum += Segment[iSegment];
|
||||
}
|
||||
|
||||
return (uint8_t)(sum / SegmentCount);
|
||||
}
|
||||
|
||||
void SevenSegDigit::Darken(uint8_t delta)
|
||||
{
|
||||
for (uint8_t iSegment = 0; iSegment < SegmentCount; iSegment++)
|
||||
{
|
||||
uint8_t element = Segment[iSegment];
|
||||
if (element > delta)
|
||||
{
|
||||
element -= delta;
|
||||
}
|
||||
else
|
||||
{
|
||||
element = 0;
|
||||
}
|
||||
Segment[iSegment] = element;
|
||||
}
|
||||
}
|
||||
|
||||
void SevenSegDigit::Lighten(uint8_t delta)
|
||||
{
|
||||
for (uint8_t iSegment = 0; iSegment < SegmentCount; iSegment++)
|
||||
{
|
||||
uint8_t element = Segment[iSegment];
|
||||
if (element < 255 - delta)
|
||||
{
|
||||
element += delta;
|
||||
}
|
||||
else
|
||||
{
|
||||
element = 255;
|
||||
}
|
||||
Segment[iSegment] = element;
|
||||
}
|
||||
}
|
||||
|
||||
SevenSegDigit SevenSegDigit::LinearBlend(const SevenSegDigit& left, const SevenSegDigit& right, float progress)
|
||||
{
|
||||
SevenSegDigit result;
|
||||
|
||||
for (uint8_t iSegment = 0; iSegment < SegmentCount; iSegment++)
|
||||
{
|
||||
result.Segment[iSegment] = left.Segment[iSegment] + ((right.Segment[iSegment] - left.Segment[iSegment]) * progress);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
202
lib/NeoPixelBus_by_Makuna/src/internal/SegmentDigit.h
Normal file
202
lib/NeoPixelBus_by_Makuna/src/internal/SegmentDigit.h
Normal file
@@ -0,0 +1,202 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
SegmentDigit provides a color object that can be directly consumed by NeoPixelBus
|
||||
|
||||
Written by Michael C. Miller.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
enum LedSegment
|
||||
{
|
||||
LedSegment_A,
|
||||
LedSegment_B,
|
||||
LedSegment_C,
|
||||
LedSegment_D,
|
||||
LedSegment_E,
|
||||
LedSegment_F,
|
||||
LedSegment_G,
|
||||
LedSegment_Decimal,
|
||||
LedSegment_COUNT
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// SevenSegDigit represents a color object that is represented by the segments
|
||||
// of a 7 segment LED display digit. It contains helpful routines to manipulate
|
||||
// and set the elements.
|
||||
//
|
||||
// The order represents the physical LED location starting at A, through to G, then
|
||||
// ending at the decimal point
|
||||
// "abcdefg."
|
||||
// ------------------------------------------------------------------------
|
||||
struct SevenSegDigit
|
||||
{
|
||||
// ------------------------------------------------------------------------
|
||||
// Construct a SevenSegDigit using
|
||||
// the default brightness to apply to all segments
|
||||
// ------------------------------------------------------------------------
|
||||
SevenSegDigit(uint8_t defaultBrightness)
|
||||
{
|
||||
memset(Segment, defaultBrightness, sizeof(Segment));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Construct a SevenSegDigit using
|
||||
// a bitmask for the segment (bit order is ".gfedcba")
|
||||
// the brightness to apply to them, (0-255)
|
||||
// the default brightness to apply to those not set in the bitmask (0-255)
|
||||
// ------------------------------------------------------------------------
|
||||
SevenSegDigit(uint8_t bitmask, uint8_t brightness, uint8_t defaultBrightness = 0);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Construct a SevenSegDigit using
|
||||
// a char that will get mapped to the segments,
|
||||
// the brightness to apply to them, (0-255)
|
||||
// the default brightness to apply to those not set in the bitmask (0-255)
|
||||
// ------------------------------------------------------------------------
|
||||
SevenSegDigit(char letter, uint8_t brightness, uint8_t defaultBrightness = 0);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Construct a SevenSegDigit that will have its values set in latter operations
|
||||
// CAUTION: The members are not initialized and may not be consistent
|
||||
// ------------------------------------------------------------------------
|
||||
SevenSegDigit()
|
||||
{
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Comparison operators
|
||||
// ------------------------------------------------------------------------
|
||||
bool operator==(const SevenSegDigit& other) const
|
||||
{
|
||||
for (uint8_t iSegment = 0; iSegment < SegmentCount; iSegment++)
|
||||
{
|
||||
if (Segment[iSegment] != other.Segment[iSegment])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
bool operator!=(const SevenSegDigit& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// CalculateBrightness will calculate the overall brightness
|
||||
// NOTE: This is a simple linear brightness
|
||||
// ------------------------------------------------------------------------
|
||||
uint8_t CalculateBrightness() const;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Darken will adjust the color by the given delta toward black
|
||||
// NOTE: This is a simple linear change
|
||||
// delta - (0-255) the amount to dim the segment
|
||||
// ------------------------------------------------------------------------
|
||||
void Darken(uint8_t delta);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Lighten will adjust the color by the given delta toward white
|
||||
// NOTE: This is a simple linear change
|
||||
// delta - (0-255) the amount to lighten the segment
|
||||
// ------------------------------------------------------------------------
|
||||
void Lighten(uint8_t delta);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// LinearBlend between two colors by the amount defined by progress variable
|
||||
// left - the segment to start the blend at
|
||||
// right - the segment to end the blend at
|
||||
// progress - (0.0 - 1.0) value where 0 will return left and 1.0 will return right
|
||||
// and a value between will blend the brightness of each element
|
||||
// weighted linearly between them
|
||||
// ------------------------------------------------------------------------
|
||||
static SevenSegDigit LinearBlend(const SevenSegDigit& left, const SevenSegDigit& right, float progress);
|
||||
|
||||
template <typename T_SET_TARGET>
|
||||
static void SetString(T_SET_TARGET& target, uint16_t indexDigit, const char* str, uint8_t brightness, uint8_t defaultBrightness = 0)
|
||||
{
|
||||
if (str == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const char* pFirst = str;
|
||||
const char* pIter = str;
|
||||
|
||||
// digits are right to left
|
||||
// so find the end
|
||||
while (*pIter != '\0')
|
||||
{
|
||||
pIter++;
|
||||
}
|
||||
pIter--;
|
||||
|
||||
|
||||
while (pIter >= pFirst)
|
||||
{
|
||||
bool decimal = false;
|
||||
char value = *pIter;
|
||||
|
||||
// check if merging a decimal is required
|
||||
if (pIter > pFirst && (*pIter == '.' || *pIter == ','))
|
||||
{
|
||||
// merge a decimal as long as they aren't the same
|
||||
if (*(pIter - 1) != *pIter)
|
||||
{
|
||||
decimal = true;
|
||||
pIter--;
|
||||
value = *pIter; // use the next char
|
||||
}
|
||||
}
|
||||
|
||||
SevenSegDigit digit(value, brightness, defaultBrightness);
|
||||
if (decimal)
|
||||
{
|
||||
digit.Segment[LedSegment_Decimal] = brightness;
|
||||
}
|
||||
target.SetPixelColor(indexDigit, digit);
|
||||
indexDigit++;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// segment members (0-255) where each represents the segment location
|
||||
// and the value defines the brightnes (0) is off and (255) is full brightness
|
||||
// ------------------------------------------------------------------------
|
||||
static const uint8_t SegmentCount = 9;
|
||||
uint8_t Segment[SegmentCount];
|
||||
|
||||
|
||||
// segment decode maps from ascii relative first char in map to a bitmask of segments
|
||||
//
|
||||
static const uint8_t DecodeNumbers[10]; // 0-9
|
||||
static const uint8_t DecodeAlphaCaps[26]; // A-Z
|
||||
static const uint8_t DecodeAlpha[26]; // a-z
|
||||
static const uint8_t DecodeSpecial[4]; // , - . /
|
||||
|
||||
protected:
|
||||
void init(uint8_t bitmask, uint8_t brightness, uint8_t defaultBrightness);
|
||||
};
|
||||
|
||||
92
lib/NeoPixelBus_by_Makuna/src/internal/TwoWireBitBangImple.h
Normal file
92
lib/NeoPixelBus_by_Makuna/src/internal/TwoWireBitBangImple.h
Normal file
@@ -0,0 +1,92 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
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:
|
||||
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++);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const uint8_t _pinClock; // output pin number for clock line
|
||||
const uint8_t _pinData; // output pin number for data line
|
||||
};
|
||||
112
lib/NeoPixelBus_by_Makuna/src/internal/TwoWireBitBangImpleAvr.h
Normal file
112
lib/NeoPixelBus_by_Makuna/src/internal/TwoWireBitBangImpleAvr.h
Normal file
@@ -0,0 +1,112 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
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:
|
||||
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++);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
};
|
||||
115
lib/NeoPixelBus_by_Makuna/src/internal/TwoWireSpiImple.h
Normal file
115
lib/NeoPixelBus_by_Makuna/src/internal/TwoWireSpiImple.h
Normal file
@@ -0,0 +1,115 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
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
|
||||
|
||||
#include <SPI.h>
|
||||
|
||||
class SpiSpeed40Mhz
|
||||
{
|
||||
public:
|
||||
static const uint32_t Clock = 40000000L;
|
||||
};
|
||||
|
||||
class SpiSpeed20Mhz
|
||||
{
|
||||
public:
|
||||
static const uint32_t Clock = 20000000L;
|
||||
};
|
||||
|
||||
class SpiSpeed10Mhz
|
||||
{
|
||||
public:
|
||||
static const uint32_t Clock = 10000000L;
|
||||
};
|
||||
|
||||
class SpiSpeed2Mhz
|
||||
{
|
||||
public:
|
||||
static const uint32_t Clock = 2000000L;
|
||||
};
|
||||
|
||||
template<typename T_SPISPEED> class TwoWireSpiImple
|
||||
{
|
||||
public:
|
||||
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(T_SPISPEED::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
|
||||
}
|
||||
|
||||
private:
|
||||
};
|
||||
130
lib/NeoPixelBus_by_Makuna/src/internal/Ws2801GenericMethod.h
Normal file
130
lib/NeoPixelBus_by_Makuna/src/internal/Ws2801GenericMethod.h
Normal file
@@ -0,0 +1,130 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
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:
|
||||
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));
|
||||
memset(_data, 0, _sizeData);
|
||||
}
|
||||
|
||||
#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);
|
||||
}
|
||||
#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;
|
||||
};
|
||||
|
||||
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<SpiSpeed2Mhz>> NeoWs2801Spi2MhzMethod;
|
||||
typedef NeoWs2801Spi10MhzMethod NeoWs2801SpiMethod;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user