#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 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