264 lines
7.1 KiB
C++
264 lines
7.1 KiB
C++
// Ovladani signalizacni chytre LED diody
|
|
#include "WSLed.hpp"
|
|
#include <ACPU.hpp>
|
|
#if defined(ARDUINO_ARCH_ESP32)
|
|
// # include "esp_task.h"
|
|
// https://github.com/JSchaenzle/ESP32-NeoPixel-WS2812-RMT/blob/master/ws2812_control.c
|
|
#include <set>
|
|
#ifndef LED_RMT_TX_CHANNEL
|
|
#define LED_RMT_TX_CHANNEL RMT_CHANNEL_0
|
|
#endif
|
|
// These values are determined by measuring pulse timing with logic analyzer and adjusting to match datasheet.
|
|
#define T0H 16 // 0 bit high time
|
|
#define T1H 32 // 1 bit high time
|
|
#define T0L 34 // 0 bit low time
|
|
#define T1L 18 // 1 bit low time
|
|
#endif
|
|
#if defined(ARDUINO_ARCH_ESP8266)
|
|
// due to linker overriding the ICACHE_RAM_ATTR for cpp files, these methods are
|
|
// moved into a C file so the attribute will be applied correctly
|
|
extern "C" IRAM_ATTR void espShow(uint8_t pin, uint8_t * pixels, uint32_t numBytes, boolean is800KHz);
|
|
#endif
|
|
// TODO: Proverit ESP32 s https://github.com/adafruit/Adafruit_NeoPixel/blob/master/esp.c
|
|
// ... a s https://github.com/Freenove/Freenove_WS2812_Lib_for_ESP32
|
|
|
|
#define countof(a) (sizeof(a) / sizeof(a[0]))
|
|
|
|
static const uint16_t LB[] PROGMEM = {
|
|
0x201, 0x202, 0x103, 0x104, 0x105, 0x106, 0x107, 0x109, 0x10a, 0x10c, 0x10e, 0x110, 0x112, 0x114, 0x116, 0x119, 0x11c, 0x11e, 0x122, 0x125, 0x128, 0x12c, 0x130, 0x134,
|
|
0x139, 0x13d, 0x142, 0x147, 0x14d, 0x152, 0x158, 0x15e, 0x165, 0x16b, 0x172, 0x179, 0x180, 0x187, 0x18e, 0x196, 0x19d, 0x1a5, 0x1ac, 0x1b3, 0x1bb, 0x1c2, 0x1c9, 0x1cf,
|
|
0x1d6, 0x1dc, 0x1e2, 0x1e7, 0x1ec, 0x1f0, 0x1f4, 0x1f7, 0x1fa, 0x1fc, 0x1fd, 0x3fe, 0x1fd, 0x1fb, 0x1f8, 0x1f5, 0x1f2, 0x1ed, 0x1e9, 0x1e4, 0x1de, 0x1d8, 0x1d2, 0x1cb,
|
|
0x1c4, 0x1bd, 0x1b6, 0x1af, 0x1a7, 0x1a0, 0x198, 0x191, 0x18a, 0x182, 0x17b, 0x174, 0x16d, 0x167, 0x161, 0x15a, 0x154, 0x14f, 0x149, 0x144, 0x13f, 0x13a, 0x136, 0x131,
|
|
0x12d, 0x12a, 0x126, 0x123, 0x11f, 0x11c, 0x11a, 0x117, 0x115, 0x112, 0x110, 0x10e, 0x10c, 0x10b, 0x109, 0x108, 0x107, 0x105, 0x104, 0x203, 0x102, 0x201, 0x2900};
|
|
|
|
static void ledTrampoline(wsLED * ptr)
|
|
{
|
|
|
|
ptr->rtLed();
|
|
}
|
|
|
|
inline bool wsLED::canShow() const
|
|
{
|
|
|
|
return (micros() - mEndTime) >= 70L;
|
|
}
|
|
|
|
void wsLED::show()
|
|
{
|
|
uint8_t color[3];
|
|
|
|
for (uint8_t i = 0; i < 3; i++) {
|
|
// https://github.com/FastLED/FastLED/wiki/FastLED-Color-Correction
|
|
uint16_t c = (uint16_t) mColor[i] * (1 + (uint16_t) mScale);
|
|
color[i] = (uint8_t) (c >> 8);
|
|
}
|
|
while (!canShow())
|
|
__asm__ volatile("nop");
|
|
#if defined(ARDUINO_ARCH_ESP32)
|
|
uint32_t bits_to_send = ((uint32_t) color[0] << 16) | ((uint32_t) color[1] << 8) | (uint32_t) color[2];
|
|
uint32_t mask = 1 << (BITS_PER_LED_CMD - 1);
|
|
for (uint32_t bit = 0; bit < BITS_PER_LED_CMD; bit++) {
|
|
uint32_t bit_is_set = bits_to_send & mask;
|
|
|
|
led_data_buffer[bit] = bit_is_set ? (rmt_item32_t){{{T1H, 1, T1L, 0}}} : (rmt_item32_t){{{T0H, 1, T0L, 0}}};
|
|
mask >>= 1;
|
|
}
|
|
ESP_ERROR_CHECK(rmt_write_items(LED_RMT_TX_CHANNEL, led_data_buffer, LED_BUFFER_ITEMS, false));
|
|
mEndTime = micros() + 100; // TODO: unfortunately this time is not valid for ESP32 using RMT peripheral
|
|
#else
|
|
ACPU::disableInterrupts();
|
|
#if defined(WSLED_PL9823)
|
|
espShow(mPin, color, 1 * 3, false);
|
|
#else
|
|
espShow(mPin, color, 1 * 3, true);
|
|
#endif
|
|
ACPU::enableInterrupts();
|
|
mEndTime = micros();
|
|
#endif
|
|
}
|
|
|
|
wsLED::wsLED(int pin, int order)
|
|
: mPin(pin), mOrder(order)
|
|
{
|
|
}
|
|
|
|
wsLED::wsLED()
|
|
: mPin(NOT_A_PIN), mOrder(RGB)
|
|
{
|
|
}
|
|
|
|
void wsLED::begin(int pin)
|
|
{
|
|
|
|
mPin = pin;
|
|
begin();
|
|
}
|
|
|
|
void wsLED::begin()
|
|
{
|
|
|
|
if (NOT_A_PIN != mPin) {
|
|
#if defined(ARDUINO_ARCH_ESP8266)
|
|
pinMode(mPin, OUTPUT);
|
|
#endif
|
|
#if defined(ARDUINO_ARCH_ESP32)
|
|
// TODO: mozna nejak zkusit najit volny RMT kanal?
|
|
rmt_config_t config;
|
|
|
|
config.rmt_mode = RMT_MODE_TX;
|
|
config.channel = LED_RMT_TX_CHANNEL;
|
|
config.gpio_num = (gpio_num_t) mPin;
|
|
config.mem_block_num = 3;
|
|
config.tx_config.loop_en = false;
|
|
config.tx_config.carrier_en = false;
|
|
config.tx_config.idle_output_en = true;
|
|
config.tx_config.idle_level = RMT_IDLE_LEVEL_LOW;
|
|
config.clk_div = 2;
|
|
|
|
ESP_ERROR_CHECK(rmt_config(&config));
|
|
ESP_ERROR_CHECK(rmt_driver_install(config.channel, 0, 0));
|
|
#endif
|
|
show();
|
|
}
|
|
}
|
|
|
|
void wsLED::setColor(const LEDRGB & color)
|
|
{
|
|
|
|
mColor[(mOrder >> 6) & 7] = color.r;
|
|
mColor[(mOrder >> 3) & 7] = color.g;
|
|
mColor[mOrder & 7] = color.b;
|
|
}
|
|
|
|
void wsLED::rtLed()
|
|
{
|
|
uint32_t timing;
|
|
|
|
mTimer.detach();
|
|
switch (mLedState) {
|
|
case LED_BLINK:
|
|
if (mSubState) {
|
|
setColor(mColor2);
|
|
} else {
|
|
setColor(mColor1);
|
|
}
|
|
mSubState = !mSubState;
|
|
timing = mBlinkSpeed;
|
|
break;
|
|
|
|
case LED_BREATH: {
|
|
++mSubState;
|
|
mSubState %= countof(LB);
|
|
uint16_t val = pgm_read_word(&LB[mSubState]);
|
|
mScale = (uint8_t) val;
|
|
val >>= 8;
|
|
timing = 30ul * val;
|
|
if (timing < 30) {
|
|
timing = 30;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case LED_PULSE: {
|
|
mLedState = mSavedState;
|
|
mSubState = 0;
|
|
setColor(mColor1);
|
|
timing = 5;
|
|
break;
|
|
}
|
|
|
|
case LED_PULSE_START:
|
|
setColor(mPulseColor);
|
|
mLedState = LED_PULSE;
|
|
timing = mPulseDuration;
|
|
break;
|
|
|
|
default:
|
|
timing = 5000;
|
|
break;
|
|
}
|
|
show();
|
|
mTimer.attach_ms(timing, ledTrampoline, this);
|
|
}
|
|
|
|
void wsLED::setColors(const LEDRGB & color1, const LEDRGB & color2)
|
|
{
|
|
|
|
mColor1 = color1;
|
|
mColor2 = color2;
|
|
if (LED_BREATH == mLedState) {
|
|
setColor(mColor1);
|
|
}
|
|
}
|
|
|
|
void wsLED::blink(uint32_t speed)
|
|
{
|
|
|
|
if (NOT_A_PIN != mPin) {
|
|
if (LED_BLINK != mLedState) {
|
|
mTimer.detach();
|
|
mLedState = LED_BLINK;
|
|
mScale = 0xff;
|
|
mSubState = 1;
|
|
mBlinkSpeed = speed;
|
|
mTimer.attach_ms(5, ledTrampoline, this);
|
|
}
|
|
}
|
|
}
|
|
|
|
void wsLED::breath()
|
|
{
|
|
|
|
if (NOT_A_PIN != mPin) {
|
|
if (LED_BREATH != mLedState) {
|
|
mTimer.detach();
|
|
mLedState = LED_BREATH;
|
|
mSubState = 0;
|
|
setColor(mColor1);
|
|
mTimer.attach_ms(5, ledTrampoline, this);
|
|
}
|
|
}
|
|
}
|
|
|
|
void wsLED::setOrder(int neworder)
|
|
{
|
|
|
|
mOrder = neworder;
|
|
}
|
|
|
|
void wsLED::pulse(const LEDRGB & color, uint32_t duration)
|
|
{
|
|
|
|
if (NOT_A_PIN != mPin) {
|
|
mTimer.detach();
|
|
mScale = 0xff;
|
|
mPulseColor = color;
|
|
if (LED_BREATH == mLedState || LED_BLINK == mLedState) {
|
|
mSavedState = mLedState;
|
|
} else {
|
|
mSavedState = LED_STOP;
|
|
}
|
|
mPulseDuration = duration;
|
|
mLedState = LED_PULSE_START;
|
|
mTimer.attach_ms(5, ledTrampoline, this);
|
|
}
|
|
}
|
|
|
|
ledstate_t wsLED::getState()
|
|
{
|
|
|
|
return mLedState;
|
|
}
|
|
|
|
void wsLED::stop(const LEDRGB & color)
|
|
{
|
|
|
|
if (NOT_A_PIN != mPin) {
|
|
mTimer.detach();
|
|
mLedState = LED_STOP;
|
|
mScale = 0xff;
|
|
setColor(color);
|
|
show();
|
|
}
|
|
}
|