307 lines
5.9 KiB
C++
307 lines
5.9 KiB
C++
#ifndef WS2812B_H
|
|
#define WS2812B_H
|
|
|
|
#include "../../io/fastGPIO.h"
|
|
|
|
struct Color {
|
|
|
|
uint8_t r;
|
|
uint8_t g;
|
|
uint8_t b;
|
|
|
|
/** no-init */
|
|
Color() {
|
|
;
|
|
}
|
|
|
|
private:
|
|
|
|
/** Hidden ctor. RGB */
|
|
Color(const uint8_t r, const uint8_t g, const uint8_t b) : r(r), g(g), b(b) {
|
|
;
|
|
}
|
|
|
|
public:
|
|
|
|
/** get X-percent [0:100] of this color = darker/brighter */
|
|
Color inline getPercent(const int percent) const {
|
|
return Color(r*percent/100, g*percent/100, b*percent/100);
|
|
}
|
|
|
|
/** mix the two given colors */
|
|
static Color mix(const Color c1, const Color c2, int percentC1) {
|
|
return Color(
|
|
((c1.r * percentC1) + (c2.r * (100-percentC1))) / 100,
|
|
((c1.g * percentC1) + (c2.g * (100-percentC1))) / 100,
|
|
((c1.b * percentC1) + (c2.b * (100-percentC1))) / 100
|
|
);
|
|
}
|
|
|
|
static inline Color fromRGB(const uint8_t r, const uint8_t g, const uint8_t b) {
|
|
return Color(r,g,b);
|
|
}
|
|
|
|
static inline Color fromHSV(const uint8_t h, const uint8_t s, const uint8_t v) {
|
|
Color c; c.setHSV(h,s,v); return c;
|
|
}
|
|
|
|
void setHSV(const uint8_t h, const uint8_t s, const uint8_t v) {
|
|
|
|
uint8_t region, remainder, p, q, t;
|
|
|
|
region = h / 43;
|
|
remainder = (h - (region * 43)) * 6;
|
|
|
|
p = (v * (255 - s)) >> 8;
|
|
q = (v * (255 - ((s * remainder) >> 8))) >> 8;
|
|
t = (v * (255 - ((s * (255 - remainder)) >> 8))) >> 8;
|
|
|
|
switch (region) {
|
|
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;
|
|
}
|
|
|
|
}
|
|
|
|
void setRGB(const uint8_t r, const uint8_t g, const uint8_t b) {
|
|
this->r = r;
|
|
this->g = g;
|
|
this->b = b;
|
|
}
|
|
|
|
void setOff() {
|
|
this->r = 0;
|
|
this->g = 0;
|
|
this->b = 0;
|
|
}
|
|
|
|
|
|
/** add two colors */
|
|
Color operator + (const Color o) const {
|
|
return Color(r+o.r, g+o.g, b+o.g);
|
|
}
|
|
|
|
Color operator * (const float f) const {
|
|
return Color(r*f, g*f, b*f);
|
|
}
|
|
|
|
};
|
|
|
|
template <int numLEDs> class WS2812B {
|
|
|
|
#define LED_SET_PIN_TO_OUTPUT GPIO5_OUTPUT_SET
|
|
#define LED_SET_PIN_H GPIO5_H
|
|
#define LED_SET_PIN_L GPIO5_L
|
|
|
|
//#define NS_PER_TICK ( (1000ul*1000ul*1000ul) / (80ul*1000ul*1000ul) )
|
|
|
|
/** color-value for each attached LED */
|
|
Color colors[numLEDs];
|
|
|
|
/** enable/disable each led */
|
|
bool enabled[numLEDs] = {true};
|
|
|
|
public:
|
|
|
|
/** ctor */
|
|
WS2812B() {
|
|
init();
|
|
}
|
|
|
|
void init() {
|
|
LED_SET_PIN_TO_OUTPUT;
|
|
}
|
|
|
|
/** set the color for the given LED */
|
|
void setColor(const uint8_t idx, const Color rgb) {
|
|
colors[idx] = rgb;
|
|
}
|
|
|
|
/** set the color for all LEDs */
|
|
void setColor(const Color rgb) {
|
|
for (int idx = 0; idx < numLEDs; ++idx) {
|
|
colors[idx] = rgb;
|
|
}
|
|
}
|
|
|
|
/** enable/disable the given LED */
|
|
void setEnabled(const uint8_t idx, const bool en) {
|
|
enabled[idx] = en;
|
|
}
|
|
|
|
/** enable/disable all LEDs */
|
|
void setEnabled(const bool en) {
|
|
for (int idx = 0; idx < numLEDs; ++idx) {
|
|
enabled[idx] = en;
|
|
}
|
|
}
|
|
|
|
/** is the given LED enabled? */
|
|
bool isEnabled(const uint8_t idx) const {
|
|
return enabled[idx];
|
|
}
|
|
|
|
Color& getColor(const uint8_t idx) {
|
|
return colors[idx];
|
|
}
|
|
|
|
/** flush configured changes */
|
|
void flush() {
|
|
|
|
LED_SET_PIN_TO_OUTPUT;
|
|
|
|
ets_intr_lock();
|
|
|
|
// process each LED
|
|
for (uint8_t i = 0; i < numLEDs; ++i) {
|
|
|
|
// send each LEDs 24-bit GRB data
|
|
if (enabled[i]) {
|
|
const Color rgb = colors[i];
|
|
sendByte(rgb.g);
|
|
sendByte(rgb.r);
|
|
sendByte(rgb.b);
|
|
} else {
|
|
sendByte(0);
|
|
sendByte(0);
|
|
sendByte(0);
|
|
}
|
|
|
|
}
|
|
|
|
ets_intr_unlock();
|
|
|
|
reset();
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
inline void sendByte(uint8_t b) {
|
|
// for (uint8_t i = 0; i < 8; ++i) {
|
|
// if (b & 0b10000000) {
|
|
// send1();
|
|
// } else {
|
|
// send0();
|
|
// }
|
|
// b <<= 1;
|
|
// }
|
|
if (b & 0b10000000) {send1();} else {send0();}
|
|
if (b & 0b01000000) {send1();} else {send0();}
|
|
if (b & 0b00100000) {send1();} else {send0();}
|
|
if (b & 0b00010000) {send1();} else {send0();}
|
|
if (b & 0b00001000) {send1();} else {send0();}
|
|
if (b & 0b00000100) {send1();} else {send0();}
|
|
if (b & 0b00000010) {send1();} else {send0();}
|
|
if (b & 0b00000001) {send1();} else {send0();}
|
|
}
|
|
|
|
__attribute__((always_inline)) inline void send1() { // 800ns high, 450ns low
|
|
LED_SET_PIN_H;
|
|
delay800();
|
|
LED_SET_PIN_L;
|
|
delay100();
|
|
}
|
|
|
|
__attribute__((always_inline)) inline void send0() { // 400ns high, 850ns low
|
|
LED_SET_PIN_H;
|
|
delay100();
|
|
LED_SET_PIN_L;
|
|
delay800();
|
|
}
|
|
|
|
__attribute__((always_inline)) inline void reset() {
|
|
LED_SET_PIN_L;
|
|
os_delay_us(50);
|
|
//delayMicroseconds(50);
|
|
}
|
|
|
|
|
|
//#pragma GCC optimize 0
|
|
|
|
__attribute__((always_inline)) inline void delay50() {
|
|
asm volatile("nop");
|
|
asm volatile("nop");
|
|
asm volatile("nop");
|
|
asm volatile("nop");
|
|
}
|
|
|
|
|
|
// 100 ns delay. @80 MHz one nop = 12,5ns
|
|
__attribute__((always_inline)) inline void delay100() {
|
|
delay50();
|
|
delay50();
|
|
}
|
|
|
|
/*
|
|
__attribute__((always_inline)) inline void delay200() {
|
|
delay100();
|
|
delay100();
|
|
}
|
|
|
|
__attribute__((always_inline)) inline void delay400() {
|
|
delay100();
|
|
delay100();
|
|
delay100();
|
|
delay100();
|
|
}
|
|
|
|
__attribute__((always_inline)) inline void delay500() {
|
|
delay100();
|
|
delay100();
|
|
delay100();
|
|
delay100();
|
|
delay100();
|
|
}
|
|
|
|
__attribute__((always_inline)) inline void delay600() {
|
|
delay100();
|
|
delay100();
|
|
delay100();
|
|
delay100();
|
|
delay100();
|
|
delay100();
|
|
}
|
|
*/
|
|
|
|
__attribute__((always_inline)) inline void delay800() {
|
|
delay100();
|
|
delay100();
|
|
delay100();
|
|
delay100();
|
|
delay100();
|
|
delay100();
|
|
delay100();
|
|
delay100();
|
|
}
|
|
|
|
|
|
// #pragma GCC reset_options
|
|
|
|
|
|
|
|
// inline void delayNS(const uint16_t ns) {
|
|
// const uint16_t ticks = ns / NS_PER_TICK / 2;
|
|
// for (uint16_t i = 0; i < ticks; ++i) {asm("nop");}
|
|
// }
|
|
|
|
};
|
|
|
|
#endif // WS2812B_H
|