diff --git a/firmware/GyverLamp_v1.4_Arduino_v1.0/GyverLamp_v1.4_Arduino_v1.0.ino b/firmware/GyverLamp_v1.4_Arduino_v1.0/GyverLamp_v1.4_Arduino_v1.0.ino index 3d8bf1e..0eeceda 100644 --- a/firmware/GyverLamp_v1.4_Arduino_v1.0/GyverLamp_v1.4_Arduino_v1.0.ino +++ b/firmware/GyverLamp_v1.4_Arduino_v1.0/GyverLamp_v1.4_Arduino_v1.0.ino @@ -1,126 +1,152 @@ -/* - Скетч к проекту "Многофункциональный RGB светильник" - Страница проекта (схемы, описания): https://alexgyver.ru/GyverLamp/ - Исходники на GitHub: https://github.com/AlexGyver/GyverLamp/ - Нравится, как написан код? Поддержи автора! https://alexgyver.ru/support_alex/ - Автор: AlexGyver, AlexGyver Technologies, 2019 - https://AlexGyver.ru/ -*/ - -/* - Версия 1.4: - - Исправлен баг при смене режимов - - Исправлены тормоза в режиме точки доступа -*/ - -//// Ссылка для менеджера плат: -//// http://arduino.esp8266.com/stable/package_esp8266com_index.json - -// ============= НАСТРОЙКИ ============= - -//// -------- РАССВЕТ ------- -//#define DAWN_BRIGHT 200 // макс. яркость рассвета -//#define DAWN_TIMEOUT 1 // сколько рассвет светит после времени будильника, минут - -// ---------- МАТРИЦА --------- -#define BRIGHTNESS 40 // стандартная маскимальная яркость (0-255) -#define CURRENT_LIMIT 2000 // лимит по току в миллиамперах, автоматически управляет яркостью (пожалей свой блок питания!) 0 - выключить лимит - -#define WIDTH 16 // ширина матрицы -#define HEIGHT 16 // высота матрицы - -#define COLOR_ORDER GRB // порядок цветов на ленте. Если цвет отображается некорректно - меняйте. Начать можно с RGB - -#define MATRIX_TYPE 0 // тип матрицы: 0 - зигзаг, 1 - параллельная -#define CONNECTION_ANGLE 0 // угол подключения: 0 - левый нижний, 1 - левый верхний, 2 - правый верхний, 3 - правый нижний -#define STRIP_DIRECTION 0 // направление ленты из угла: 0 - вправо, 1 - вверх, 2 - влево, 3 - вниз -// при неправильной настройке матрицы вы получите предупреждение "Wrong matrix parameters! Set to default" -// шпаргалка по настройке матрицы здесь! https://alexgyver.ru/matrix_guide/ - -#define numHold_Time 1500 // время отображения индикатора уровня яркости/скорости/масштаба - -// ============= ДЛЯ РАЗРАБОТЧИКОВ ============= -#define LED_PIN 2 // пин ленты -#define BTN_PIN 4 -#define MODE_AMOUNT 18 -#define NUM_LEDS WIDTH * HEIGHT -#define SEGMENTS 1 // диодов в одном "пикселе" (для создания матрицы из кусков ленты) - -// ---------------- БИБЛИОТЕКИ ----------------- -//#include "timerMinim.h" -#include -#include -#include - -// ------------------- ТИПЫ -------------------- -CRGB leds[NUM_LEDS]; -//timerMinim timeTimer(3000); -GButton touch(BTN_PIN, LOW_PULL, NORM_OPEN); - -// ----------------- ПЕРЕМЕННЫЕ ------------------ - -//String inputBuffer; -static const byte maxDim = max(WIDTH, HEIGHT); -struct { - byte brightness = 50; - byte speed = 30; - byte scale = 10; -} modes[MODE_AMOUNT]; - -//struct { -// boolean state = false; -// int time = 0; -//} alarm[7]; - -//byte dawnOffsets[] = {5, 10, 15, 20, 25, 30, 40, 50, 60}; -//byte dawnMode; -//boolean dawnFlag = false; -//long thisTime; -//boolean manualOff = false; - -int8_t currentMode = 17; -boolean loadingFlag = true; -boolean ONflag = true; -byte numHold; -unsigned long numHold_Timer = 0; -//uint32_t eepromTimer; -//boolean settChanged = false; -// Конфетти, Огонь, Радуга верт., Радуга гориз., Смена цвета, -// Безумие 3D, Облака 3D, Лава 3D, Плазма 3D, Радуга 3D, -// Павлин 3D, Зебра 3D, Лес 3D, Океан 3D, -// colorRoutine, snowRoutine, полосы "Матрица" - -unsigned char matrixValue[8][16]; - -void setup() { - - // ЛЕНТА - FastLED.addLeds(leds, NUM_LEDS)/*.setCorrection( TypicalLEDStrip )*/; - FastLED.setBrightness(BRIGHTNESS); - if (CURRENT_LIMIT > 0) FastLED.setMaxPowerInVoltsAndMilliamps(5, CURRENT_LIMIT); - FastLED.clear(); - FastLED.show(); - - touch.setStepTimeout(100); - touch.setClickTimeout(500); - - Serial.begin(9600); - Serial.println(); - - if (EEPROM.read(0) == 102) { // если было сохранение настроек, то восстанавливаем их (с)НР - currentMode = EEPROM.read(1); - for (byte x = 0; x < MODE_AMOUNT; x++) { - modes[x].brightness = EEPROM.read(x * 3 + 11); // (2-10 байт - резерв) - modes[x].speed = EEPROM.read(x * 3 + 12); - modes[x].scale = EEPROM.read(x * 3 + 13); - } - - } -} - -void loop() { - effectsTick(); - //timeTick(); - buttonTick(); - //yield(); -} +/* + Скетч к проекту "Многофункциональный RGB светильник" + Страница проекта (схемы, описания): https://alexgyver.ru/GyverLamp/ + Исходники на GitHub: https://github.com/AlexGyver/GyverLamp/ + Нравится, как написан код? Поддержи автора! https://alexgyver.ru/support_alex/ + Автор: AlexGyver, AlexGyver Technologies, 2019 + https://AlexGyver.ru/ +*/ + +/* + Версия 1.4: + - Исправлен баг при смене режимов + - Исправлены тормоза в режиме точки доступа +*/ + +//// Ссылка для менеджера плат: +//// http://arduino.esp8266.com/stable/package_esp8266com_index.json + +// ============= НАСТРОЙКИ ============= + +//#define DEBUG // Дебаг(Нужен, расскоментируйте) +#define VERTGAUGE 0 // вертикальный/горизонтальный индикатор +#define DEMOTIME 5 // в секундах +#define RANDOM_DEMO 1 // 0,1 - включить рандомный выбор режима + +//// -------- РАССВЕТ ------- +//#define DAWN_BRIGHT 200 // макс. яркость рассвета +//#define DAWN_TIMEOUT 1 // сколько рассвет светит после времени будильника, минут + +// ---------- МАТРИЦА --------- +#define BRIGHTNESS 255 // стандартная маскимальная яркость (0-255) +#define MINBRIGHTNESS 25 // минимальная яркость режимов (0-100) для исключения черной лампы +#define CURRENT_LIMIT 2600 // лимит по току в миллиамперах, автоматически управляет яркостью (пожалей свой блок питания!) 0 - выключить лимит + +#define WIDTH 16 // ширина матрицы +#define HEIGHT 16 // высота матрицы + +#define COLOR_ORDER GRB // порядок цветов на ленте. Если цвет отображается некорректно - меняйте. Начать можно с RGB + +#define MATRIX_TYPE 0 // тип матрицы: 0 - зигзаг, 1 - параллельная +#define CONNECTION_ANGLE 0 // угол подключения: 0 - левый нижний, 1 - левый верхний, 2 - правый верхний, 3 - правый нижний +#define STRIP_DIRECTION 0 // направление ленты из угла: 0 - вправо, 1 - вверх, 2 - влево, 3 - вниз +// при неправильной настройке матрицы вы получите предупреждение "Wrong matrix parameters! Set to default" +// шпаргалка по настройке матрицы здесь! https://alexgyver.ru/matrix_guide/ + +#define numHold_Time 1500 // время отображения индикатора уровня яркости/скорости/масштаба + +// ============= ДЛЯ РАЗРАБОТЧИКОВ ============= +#define LED_PIN 2 // пин ленты +#define BTN_PIN 4 +#define MODE_AMOUNT 18 +#define NUM_LEDS WIDTH * HEIGHT +#define SEGMENTS 1 // диодов в одном "пикселе" (для создания матрицы из кусков ленты) + +// ---------------- БИБЛИОТЕКИ ----------------- +#include +#include +#include + +// ------------------- ТИПЫ -------------------- +CRGB leds[NUM_LEDS]; +GButton touch(BTN_PIN, LOW_PULL, NORM_OPEN); + +// ----------------- ПЕРЕМЕННЫЕ ------------------ + +static const byte maxDim = max(WIDTH, HEIGHT); +struct { + byte brightness = 50; + byte speed = 30; + byte scale = 10; +} modes[MODE_AMOUNT]; + + +int8_t currentMode = 17; +boolean loadingFlag = true; +boolean ONflag = true; +byte numHold; +unsigned long numHold_Timer = 0UL; +unsigned long userTimer = 0UL; +unsigned char matrixValue[8][16]; +byte xStep; +byte xCol; +byte yStep; +byte yCol; + +void setup() { + + // ЛЕНТА + FastLED.addLeds(leds, NUM_LEDS).setCorrection(0xFFB0F0); + FastLED.setBrightness(BRIGHTNESS); + if (CURRENT_LIMIT > 0) FastLED.setMaxPowerInVoltsAndMilliamps(5, CURRENT_LIMIT); + FastLED.clear(); + FastLED.show(); + + touch.setStepTimeout(100); + touch.setClickTimeout(500); + + //Serial.begin(9600); + //Serial.println(); + + xStep = WIDTH / 4; + xCol = 4; + if(xStep<2) { + xStep = WIDTH / 3; + xCol = 3; + } else if(xStep<2) { + xStep = WIDTH / 2; + xCol = 2; + } else if(xStep<2) { + xStep = 1; + xCol = 1; + } + + yStep = HEIGHT / 4; + yCol = 4; + if(yStep<2) { + yStep = HEIGHT / 3; + yCol = 3; + } else if(yStep<2) { + yStep = HEIGHT / 2; + yCol = 2; + } else if(yStep<2) { + yStep = 1; + yCol = 1; + } + + #ifdef DEBUG + Serial.print("xStep: "); + Serial.print(xStep); + Serial.print(" xCol:"); + Serial.println(xCol); + Serial.print("yStep: "); + Serial.print(yStep); + Serial.print(" yCol:"); + Serial.println(yCol); + #endif + + if (EEPROM.read(0) == 102) { // если было сохранение настроек, то восстанавливаем их (с)НР + currentMode = EEPROM.read(1); + for (byte x = 0; x < MODE_AMOUNT; x++) { + modes[x].brightness = EEPROM.read(x * 3 + 11); // (2-10 байт - резерв) + modes[x].speed = EEPROM.read(x * 3 + 12); + modes[x].scale = EEPROM.read(x * 3 + 13); + } + + } +} + +void loop() { + effectsTick(); + buttonTick(); //yield(); +} diff --git a/firmware/GyverLamp_v1.4_Arduino_v1.0/button.ino b/firmware/GyverLamp_v1.4_Arduino_v1.0/button.ino index cd87c85..a2e2a28 100644 --- a/firmware/GyverLamp_v1.4_Arduino_v1.0/button.ino +++ b/firmware/GyverLamp_v1.4_Arduino_v1.0/button.ino @@ -1,137 +1,223 @@ -boolean brightDirection, speedDirection, scaleDirection; -//byte numHold; - -void buttonTick() { - touch.tick(); - - if (touch.isSingle()) { - // if (dawnFlag) { - // //manualOff = true; - // dawnFlag = false; - // loadingFlag = true; - // FastLED.setBrightness(modes[currentMode].brightness); - // changePower(); - // } else - { - if (ONflag) { - ONflag = false; - changePower(); - } else { - ONflag = true; - changePower(); - } - } - } - -if (ONflag) { // если включено - if (touch.isDouble()) { - if (++currentMode >= MODE_AMOUNT) currentMode = 0; - FastLED.setBrightness(modes[currentMode].brightness); - loadingFlag = true; - //settChanged = true; - FastLED.clear(); - delay(1); - } - if (touch.isTriple()) { - if (--currentMode < 0) currentMode = MODE_AMOUNT - 1; - FastLED.setBrightness(modes[currentMode].brightness); - loadingFlag = true; - //settChanged = true; - FastLED.clear(); - delay(1); - } - - if ((touch.hasClicks()) && (touch.getClicks() == 5)) { // если было пятикратное нажатие на кнопку, то производим сохранение параметров // && (touch.hasClicks()) - if (EEPROM.read(0) != 102) EEPROM.write(0, 102); - if (EEPROM.read(1) != currentMode) EEPROM.write(1, currentMode); // запоминаем текущий эфект - for (byte x = 0; x < MODE_AMOUNT; x++) { // сохраняем настройки всех режимов - if (EEPROM.read(x * 3 + 11) != modes[x].brightness) EEPROM.write(x * 3 + 11, modes[x].brightness); - if (EEPROM.read(x * 3 + 12) != modes[x].speed) EEPROM.write(x * 3 + 12, modes[x].speed); - if (EEPROM.read(x * 3 + 13) != modes[x].scale) EEPROM.write(x * 3 + 13, modes[x].scale); - } - // индикация сохранения - ONflag = false; - changePower(); - delay(200); - ONflag = true; - changePower(); - } - - if (touch.isHolded()) { // изменение яркости при удержании кнопки - brightDirection = !brightDirection; - numHold = 1; - } - - if (touch.isHolded2()) { // изменение скорости "speed" при двойном нажатии и удержании кнопки - speedDirection = !speedDirection; - numHold = 2; - } - - if (touch.isHolded3()) { // изменение масштаба "scale" при тройном нажатии и удержании кнопки - scaleDirection = !scaleDirection; - numHold = 3; - } - - if (touch.isStep()) { -// Serial.print(numHold); -// Serial.print(" brightness:"); -// Serial.print(modes[currentMode].brightness); -// Serial.print(" speed:"); -// Serial.print(modes[currentMode].speed); -// Serial.print(" scale:"); -// Serial.println(modes[currentMode].scale); - if (numHold != 0) numHold_Timer = millis(); loadingFlag = true; - switch (numHold) { - case 1: - // if (brightDirection) { - // if (modes[currentMode].brightness < 10) modes[currentMode].brightness += 1; - // else if (modes[currentMode].brightness < 250) modes[currentMode].brightness += 5; - // else modes[currentMode].brightness = 255; - // } else { - // if (modes[currentMode].brightness > 15) modes[currentMode].brightness -= 5; - // else if (modes[currentMode].brightness > 1) modes[currentMode].brightness -= 1; - // else modes[currentMode].brightness = 1; - // } - modes[currentMode].brightness = constrain(modes[currentMode].brightness + (modes[currentMode].brightness / 25 + 1) * (brightDirection * 2 - 1), 1 , 255); - // byte x = sqrt(modes[currentMode].brightness); - // for (byte y = 0; y < HEIGHT - 1; y++) { - // if (x < y) drawPixelXY(1, y, CHSV(10,200,200)); - // else drawPixelXY(1, y, CHSV(1,0,0)); - // } - break; - - case 2: - // if (speedDirection) { - // if (modes[currentMode].speed < 10) modes[currentMode].speed += 1; - // else if (modes[currentMode].speed < 250) modes[currentMode].speed += 5; - // else modes[currentMode].speed = 255; - // } else { - // if (modes[currentMode].speed > 15) modes[currentMode].speed -= 5; - // else if (modes[currentMode].speed > 1) modes[currentMode].speed -= 1; - // else modes[currentMode].speed = 1; - // } - modes[currentMode].speed = constrain(modes[currentMode].speed + (modes[currentMode].speed / 25 + 1) * (speedDirection * 2 - 1), 1 , 255); - break; - - case 3: - // if (scaleDirection) { - // if (modes[currentMode].scale < 10) modes[currentMode].scale += 1; - // else if (modes[currentMode].scale < 250) modes[currentMode].scale += 5; - // else modes[currentMode].scale = 255; - // } else { - // if (modes[currentMode].scale > 15) modes[currentMode].scale -= 5; - // else if (modes[currentMode].scale > 1) modes[currentMode].scale -= 1; - // else modes[currentMode].scale = 1; - // } - modes[currentMode].scale = constrain(modes[currentMode].scale + (modes[currentMode].scale / 25 + 1) * (scaleDirection * 2 - 1), 1 , 255); - break; - } - } - if ((millis() - numHold_Timer) > numHold_Time) { - numHold = 0; - numHold_Timer = millis(); - } - FastLED.setBrightness(modes[currentMode].brightness); - //settChanged = true; - } -} +boolean brightDirection, speedDirection, scaleDirection; +//byte numHold; +#ifdef DEBUG +void debugPrint(){ + Serial.print(numHold); + Serial.print(F(" brightness:")); + Serial.print(modes[currentMode].brightness); + Serial.print(F(" speed:")); + Serial.print(modes[currentMode].speed); + Serial.print(F(" scale:")); + Serial.print(modes[currentMode].scale); + Serial.print(F(" numHold_Timer:")); + Serial.println(numHold_Timer); +} +#endif +void changeDirection(byte numHold){ + switch(numHold){ + case 0: case 1: brightDirection = !brightDirection; break; + case 2: speedDirection = !speedDirection; break; + case 3: scaleDirection = !scaleDirection; break; + } + numHold_Timer = millis(); +} + +void buttonTick() { + touch.tick(); + + if (!ONflag) { // Обработка из выключенного состояния + #ifdef DEBUG + if(touch.isPress()) + Serial.println(F("Off state")); + #endif + + if (touch.isDouble()) { // Демо-режим, с переключением каждые 30 секунд для двойного клика в выключенном состоянии + numHold = 254; + currentMode = random(0, 255)%17; // 17 скипаем + //modes[currentMode].brightness = BRIGHTNESS/2; // в половину яркости + FastLED.setBrightness(modes[currentMode].brightness); + ONflag = true; + userTimer = millis(); // момент включения для таймаута в DEMOTIME + numHold_Timer = millis(); + //brightDirection = 0; // на уменьшение + changePower(); + #ifdef DEBUG + Serial.print(F("Demo mode: ")); + Serial.println(currentMode); + #endif + } + + if (touch.isHolded()) { + #ifdef DEBUG + Serial.println(F("Holdeded from offed state")); + #endif + currentMode = 17; + modes[currentMode].brightness = BRIGHTNESS; + FastLED.setBrightness(modes[currentMode].brightness); + numHold = 255; + ONflag = true; + userTimer = millis(); // момент включения для таймаута в переключения в режим регулировки яркости + numHold_Timer = millis(); + brightDirection = 0; // на уменьшение + changePower(); + } + } + + if (touch.isSingle()) { // Включение/выключение одиночным + + { + if (ONflag) { + ONflag = false; + #ifdef DEBUG + Serial.println(F("Off lamp")); + #endif + changePower(); + } else { + ONflag = true; + #ifdef DEBUG + Serial.println(F("On lamp")); + debugPrint(); // отладка + #endif + + } + } + } + +if (ONflag) { // если включено + if (touch.isDouble()) { + #ifdef DEBUG + Serial.println(F("Double click")); + //debugPrint(); // отладка + #endif + if (++currentMode >= MODE_AMOUNT) currentMode = 0; + FastLED.setBrightness(modes[currentMode].brightness); + loadingFlag = true; + //settChanged = true; + FastLED.clear(); + delay(1); + } + if (touch.isTriple()) { + #ifdef DEBUG + Serial.println(F("Triple click")); + //debugPrint(); // отладка + #endif + if (--currentMode < 0) currentMode = MODE_AMOUNT - 1; + FastLED.setBrightness(modes[currentMode].brightness); + loadingFlag = true; + //settChanged = true; + FastLED.clear(); + delay(1); + } + + if ((touch.hasClicks()) && (touch.getClicks() == 5)) { // если было пятикратное нажатие на кнопку, то производим сохранение параметров // && (touch.hasClicks()) + if (EEPROM.read(0) != 102) EEPROM.write(0, 102); + if (EEPROM.read(1) != currentMode) EEPROM.write(1, currentMode); // запоминаем текущий эфект + for (byte x = 0; x < MODE_AMOUNT; x++) { // сохраняем настройки всех режимов + if (EEPROM.read(x * 3 + 11) != modes[x].brightness) EEPROM.write(x * 3 + 11, modes[x].brightness); + if (EEPROM.read(x * 3 + 12) != modes[x].speed) EEPROM.write(x * 3 + 12, modes[x].speed); + if (EEPROM.read(x * 3 + 13) != modes[x].scale) EEPROM.write(x * 3 + 13, modes[x].scale); + } + // индикация сохранения + ONflag = false; + changePower(); + delay(200); + ONflag = true; + changePower(); + } + + if (touch.isHolded() && numHold != 255) { // изменение яркости при удержании кнопки + if(modes[currentMode].brightness == BRIGHTNESS && numHold == 1){ + brightDirection = 0; + } else if (modes[currentMode].brightness <= 1 && numHold == 1){ + brightDirection = 1; + } else + changeDirection(numHold); + if(!numHold || numHold==254) + numHold = 1; + } + + if (touch.isHolded2()) { // изменение скорости "speed" при двойном нажатии и удержании кнопки + if(modes[currentMode].speed == 255 && numHold == 2){ + speedDirection = 0; + } else if (modes[currentMode].speed <= 1 && numHold == 2){ + speedDirection = 1; + } else + changeDirection(numHold); + if(!numHold) + numHold = 2; + } + + if (touch.isHolded3()) { // изменение масштаба "scale" при тройном нажатии и удержании кнопки + if(modes[currentMode].scale == 255 && numHold == 3){ + scaleDirection = 0; + } else if (modes[currentMode].scale <= 1 && numHold == 3){ + scaleDirection = 1; + } else + changeDirection(numHold); + if(!numHold) + numHold = 3; + } + + if (touch.isStep()) { + #ifdef DEBUG + debugPrint(); // отладка + #endif + if (numHold != 0 && numHold != 255) { + numHold_Timer = millis(); + loadingFlag = true; + } + + switch (numHold) { + case 1: + + modes[currentMode].brightness = constrain(modes[currentMode].brightness + (modes[currentMode].brightness / 25 + 1) * (brightDirection * 2 - 1), MINBRIGHTNESS , BRIGHTNESS); + break; + + case 2: + + modes[currentMode].speed = constrain(modes[currentMode].speed + (modes[currentMode].speed / 25 + 1) * (speedDirection * 2 - 1), 1 , 255); + break; + + case 3: + + modes[currentMode].scale = constrain(modes[currentMode].scale + (modes[currentMode].scale / 25 + 1) * (scaleDirection * 2 - 1), 1 , 255); + break; + } + } + + if ((millis() - userTimer) > numHold_Time && numHold>=250) { + if(numHold == 255){ + numHold = 1; + userTimer = millis(); + numHold_Timer = millis(); + } + } + + if ((millis() - numHold_Timer) > numHold_Time && !touch.isHolded() && numHold<250) { + numHold = 0; + numHold_Timer = millis(); + } + + if((millis() - userTimer > DEMOTIME*1000) && (numHold == 254)){ + //FastLED.clear(); + //delay(2); + for(byte i = 250; i>10; i-=10){ + fader(30); + FastLED.delay(33); + //FastLED.show(); + } + + if(RANDOM_DEMO) + currentMode = random(0, 255)%17; // 17 скипаем + else + currentMode=(currentMode+1)%17; // 17 скипаем и идем по наростанию + #ifdef DEBUG + Serial.print(F("Demo mode: ")); + Serial.println(currentMode); + #endif + userTimer = millis(); + } + + FastLED.setBrightness(modes[currentMode].brightness); + } +} diff --git a/firmware/GyverLamp_v1.4_Arduino_v1.0/effectTicker.ino b/firmware/GyverLamp_v1.4_Arduino_v1.0/effectTicker.ino index aab079d..193199c 100644 --- a/firmware/GyverLamp_v1.4_Arduino_v1.0/effectTicker.ino +++ b/firmware/GyverLamp_v1.4_Arduino_v1.0/effectTicker.ino @@ -1,99 +1,115 @@ -uint32_t effTimer; -byte ind; - -void effectsTick() { - // if (!dawnFlag) - { - if (ONflag && millis() - effTimer >= ((currentMode < 5 || currentMode > 13) ? modes[currentMode].speed : 50) ) { - effTimer = millis(); - switch (currentMode) { - case 0: sparklesRoutine(); - break; - case 1: fireRoutine(); - break; - case 2: rainbowVertical(); - break; - case 3: rainbowHorizontal(); - break; - case 4: colorsRoutine(); - break; - case 5: madnessNoise(); - break; - case 6: cloudNoise(); - break; - case 7: lavaNoise(); - break; - case 8: plasmaNoise(); - break; - case 9: rainbowNoise(); - break; - case 10: rainbowStripeNoise(); - break; - case 11: zebraNoise(); - break; - case 12: forestNoise(); - break; - case 13: oceanNoise(); - break; - case 14: colorRoutine(); - break; - case 15: snowRoutine(); - break; - case 16: matrixRoutine(); - break; - case 17: whiteLamp(); - // case 17: lightersRoutine(); - break; - } - switch (numHold) { // индикатор уровня яркости/скорости/масштаба - case 1: - ind = sqrt(modes[currentMode].brightness + 1); - for (byte y = 0; y < HEIGHT ; y++) { - if (ind > y) drawPixelXY(0, y, CHSV(10, 255, 255)); - else drawPixelXY(0, y, 0); - } - break; - case 2: - ind = sqrt(modes[currentMode].speed - 1); - for (byte y = 0; y <= HEIGHT ; y++) { - if (ind <= y) drawPixelXY(0, 15 - y, CHSV(100, 255, 255)); - else drawPixelXY(0, 15 - y, 0); - } - break; - case 3: - ind = sqrt(modes[currentMode].scale + 1); - for (byte y = 0; y < HEIGHT ; y++) { - if (ind > y) drawPixelXY(0, y, CHSV(150, 255, 255)); - else drawPixelXY(0, y, 0); - } - break; - - } - FastLED.show(); - } - } -} - -void changePower() { // плавное включение/выключение - if (ONflag) { - effectsTick(); - for (int i = 0; i < modes[currentMode].brightness; i += 8) { - FastLED.setBrightness(i); - delay(1); - FastLED.show(); - } - FastLED.setBrightness(modes[currentMode].brightness); - delay(2); - FastLED.show(); - } else { - effectsTick(); - for (int i = modes[currentMode].brightness; i > 8; i -= 8) { - FastLED.setBrightness(i); - delay(1); - FastLED.show(); - } - FastLED.clear(); - delay(2); - FastLED.show(); - } -} +uint32_t effTimer; +byte ind; + +void effectsTick() { + { + if (millis() - effTimer >= ((currentMode < 5 || currentMode > 13) ? modes[currentMode].speed : 50) ) { + effTimer = millis(); + if(ONflag){ + switch (currentMode) { + case 0: sparklesRoutine(); + break; + case 1: rainbowVertical(); + break; + case 2: rainbowHorizontal(); + break; + case 3: fireRoutine(); + break; + case 4: colorsRoutine(); + break; + case 5: madnessNoise(); + break; + case 6: cloudNoise(); + break; + case 7: lavaNoise(); + break; + case 8: plasmaNoise(); + break; + case 9: rainbowNoise(); + break; + case 10: rainbowStripeNoise(); + break; + case 11: zebraNoise(); + break; + case 12: forestNoise(); + break; + case 13: oceanNoise(); + break; + case 14: colorRoutine(); + break; + case 15: snowRoutine(); + break; + case 16: matrixRoutine(); + break; + case 17: whiteLampRoutine(); + break; + } + if(VERTGAUGE) + GaugeShowVertical(); + } + FastLED.show(); + } + } +} + +void GaugeShowVertical() { + switch (numHold) { // индикатор уровня яркости/скорости/масштаба + case 1: + ind = ind = sqrt(modes[currentMode].brightness + 1); + for (byte x = 0; x <= xCol*(xStep-1) ; x+=xStep) { + for (byte y = 0; y < HEIGHT ; y++) { + if (ind > y) + drawPixelXY(x, y, CHSV(10, 255, 255)); + else + drawPixelXY(x, y, 0); + } + } + break; + case 2: + ind = sqrt(modes[currentMode].speed - 1); + for (byte x = 0; x <= xCol*(xStep-1) ; x+=xStep) { + for (byte y = 0; y <= HEIGHT ; y++) { + if (ind <= y) + drawPixelXY(x, HEIGHT-1-y, CHSV(100, 255, 255)); + else + drawPixelXY(x, HEIGHT-1-y, 0); + } + } + break; + case 3: + ind = sqrt(modes[currentMode].scale + 1); + for (byte x = 0; x <= xCol*(xStep-1) ; x+=xStep) { + for (byte y = 0; y < HEIGHT ; y++) { + if (ind > y) + drawPixelXY(x, y, CHSV(150, 255, 255)); + else + drawPixelXY(x, y, 0); + } + } + break; + } +} + +void changePower() { // плавное включение/выключение + if (ONflag) { + effectsTick(); + for (int i = 0; i < modes[currentMode].brightness; i += 8) { + FastLED.setBrightness(i); + delay(1); + FastLED.show(); + } + FastLED.setBrightness(modes[currentMode].brightness); + delay(2); + FastLED.show(); + } else { + //effectsTick(); + for (int i = modes[currentMode].brightness; i > 8; i -= 8) { + FastLED.setBrightness(i); + delay(1); + FastLED.show(); + } + FastLED.clear(); + delay(2); + FastLED.show(); + } +} diff --git a/firmware/GyverLamp_v1.4_Arduino_v1.0/effects.ino b/firmware/GyverLamp_v1.4_Arduino_v1.0/effects.ino index 8fdb101..3f0ddd2 100644 --- a/firmware/GyverLamp_v1.4_Arduino_v1.0/effects.ino +++ b/firmware/GyverLamp_v1.4_Arduino_v1.0/effects.ino @@ -1,292 +1,263 @@ -// ================================= ЭФФЕКТЫ ==================================== - -// --------------------------------- конфетти ------------------------------------ -void sparklesRoutine() { - for (byte i = 0; i < modes[0].scale; i++) { - byte x = random(0, WIDTH); - byte y = random(0, HEIGHT); - if (getPixColorXY(x, y) == 0) - leds[getPixelNumber(x, y)] = CHSV(random(0, 255), 255, 255); - } - fader(70); -} - -// функция плавного угасания цвета для всех пикселей -void fader(byte step) { - for (byte i = 0; i < WIDTH; i++) { - for (byte j = 0; j < HEIGHT; j++) { - fadePixel(i, j, step); - } - } -} -void fadePixel(byte i, byte j, byte step) { // новый фейдер - int pixelNum = getPixelNumber(i, j); - if (getPixColor(pixelNum) == 0) return; - - if (leds[pixelNum].r >= 30 || - leds[pixelNum].g >= 30 || - leds[pixelNum].b >= 30) { - leds[pixelNum].fadeToBlackBy(step); - } else { - leds[pixelNum] = 0; - } -} - -// -------------------------------------- огонь --------------------------------------------- -// эффект "огонь" -#define SPARKLES 1 // вылетающие угольки вкл выкл -unsigned char line[WIDTH]; -int pcnt = 0; - -//these values are substracetd from the generated values to give a shape to the animation -const unsigned char valueMask[8][16] PROGMEM = { - {32 , 0 , 0 , 0 , 0 , 0 , 0 , 32 , 32 , 0 , 0 , 0 , 0 , 0 , 0 , 32 }, - {64 , 0 , 0 , 0 , 0 , 0 , 0 , 64 , 64 , 0 , 0 , 0 , 0 , 0 , 0 , 64 }, - {96 , 32 , 0 , 0 , 0 , 0 , 32 , 96 , 96 , 32 , 0 , 0 , 0 , 0 , 32 , 96 }, - {128, 64 , 32 , 0 , 0 , 32 , 64 , 128, 128, 64 , 32 , 0 , 0 , 32 , 64 , 128}, - {160, 96 , 64 , 32 , 32 , 64 , 96 , 160, 160, 96 , 64 , 32 , 32 , 64 , 96 , 160}, - {192, 128, 96 , 64 , 64 , 96 , 128, 192, 192, 128, 96 , 64 , 64 , 96 , 128, 192}, - {255, 160, 128, 96 , 96 , 128, 160, 255, 255, 160, 128, 96 , 96 , 128, 160, 255}, - {255, 192, 160, 128, 128, 160, 192, 255, 255, 192, 160, 128, 128, 160, 192, 255} -}; - -//these are the hues for the fire, -//should be between 0 (red) to about 25 (yellow) -const unsigned char hueMask[8][16] PROGMEM = { - {1 , 11, 19, 25, 25, 22, 11, 1 , 1 , 11, 19, 25, 25, 22, 11, 1 }, - {1 , 8 , 13, 19, 25, 19, 8 , 1 , 1 , 8 , 13, 19, 25, 19, 8 , 1 }, - {1 , 8 , 13, 16, 19, 16, 8 , 1 , 1 , 8 , 13, 16, 19, 16, 8 , 1 }, - {1 , 5 , 11, 13, 13, 13, 5 , 1 , 1 , 5 , 11, 13, 13, 13, 5 , 1 }, - {1 , 5 , 11, 11, 11, 11, 5 , 1 , 1 , 5 , 11, 11, 11, 11, 5 , 1 }, - {0 , 1 , 5 , 8 , 8 , 5 , 1 , 0 , 0 , 1 , 5 , 8 , 8 , 5 , 1 , 0 }, - {0 , 0 , 1 , 5 , 5 , 1 , 0 , 0 , 0 , 0 , 1 , 5 , 5 , 1 , 0 , 0 }, - {0 , 0 , 0 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 1 , 0 , 0 , 0 } -}; - -void fireRoutine() { - if (loadingFlag) { - loadingFlag = false; - //FastLED.clear(); - generateLine(); - } - if (pcnt >= 100) { - shiftUp(); - generateLine(); - pcnt = 0; - } - drawFrame(pcnt); - pcnt += 30; -} - -// Случайным образом генерирует следующую линию (matrix row) - -void generateLine() { - for (uint8_t x = 0; x < WIDTH; x++) { - line[x] = random(64, 255); - } -} - -void shiftUp() { - for (uint8_t y = HEIGHT - 1; y > 0; y--) { - for (uint8_t x = 0; x < WIDTH; x++) { - uint8_t newX = x; - if (x > 15) newX = x - 15; - if (y > 7) continue; - matrixValue[y][newX] = matrixValue[y - 1][newX]; - } - } - - for (uint8_t x = 0; x < WIDTH; x++) { - uint8_t newX = x; - if (x > 15) newX = x - 15; - matrixValue[0][newX] = line[newX]; - } -} - -// рисует кадр, интерполируя между 2 "ключевых кадров" -// параметр pcnt - процент интерполяции - -void drawFrame(int pcnt) { - int nextv; - - //each row interpolates with the one before it - for (unsigned char y = HEIGHT - 1; y > 0; y--) { - for (unsigned char x = 0; x < WIDTH; x++) { - uint8_t newX = x; - if (x > 15) newX = x - 15; - if (y < 8) { - nextv = - (((100.0 - pcnt) * matrixValue[y][newX] - + pcnt * matrixValue[y - 1][newX]) / 100.0) - - pgm_read_byte(&(valueMask[y][newX])); - - CRGB color = CHSV( - modes[1].scale * 2.5 + pgm_read_byte(&(hueMask[y][newX])), // H - 255, // S - (uint8_t)max(0, nextv) // V - ); - - leds[getPixelNumber(x, y)] = color; - } else if (y == 8 && SPARKLES) { - if (random(0, 20) == 0 && getPixColorXY(x, y - 1) != 0) drawPixelXY(x, y, getPixColorXY(x, y - 1)); - else drawPixelXY(x, y, 0); - } else if (SPARKLES) { - - // старая версия для яркости - if (getPixColorXY(x, y - 1) > 0) - drawPixelXY(x, y, getPixColorXY(x, y - 1)); - else drawPixelXY(x, y, 0); - - } - } - } - - //Перавя стрка интерполируется со следующей "next" линией - for (unsigned char x = 0; x < WIDTH; x++) { - uint8_t newX = x; - if (x > 15) newX = x - 15; - CRGB color = CHSV( - modes[1].scale * 2.5 + pgm_read_byte(&(hueMask[0][newX])), // H - 255, // S - (uint8_t)(((100.0 - pcnt) * matrixValue[0][newX] + pcnt * line[newX]) / 100.0) // V - ); - leds[getPixelNumber(newX, 0)] = color; - } -} - -byte hue; -// ---------------------------------------- радуга ------------------------------------------ -void rainbowVertical() { - hue += 2; - for (byte j = 0; j < HEIGHT; j++) { - CHSV thisColor = CHSV((byte)(hue + j * modes[2].scale), 255, 255); - for (byte i = 0; i < WIDTH; i++) - drawPixelXY(i, j, thisColor); - } -} -void rainbowHorizontal() { - hue += 2; - for (byte i = 0; i < WIDTH; i++) { - CHSV thisColor = CHSV((byte)(hue + i * modes[3].scale), 255, 255); - for (byte j = 0; j < HEIGHT; j++) - drawPixelXY(i, j, thisColor); //leds[getPixelNumber(i, j)] = thisColor; - } -} - -// ---------------------------------------- ЦВЕТА ------------------------------------------ -void colorsRoutine() { - hue += modes[4].scale; - for (int i = 0; i < NUM_LEDS; i++) { - leds[i] = CHSV(hue, 255, 255); - } -} - -// --------------------------------- ЦВЕТ ------------------------------------ -void colorRoutine() { - for (int i = 0; i < NUM_LEDS; i++) { - leds[i] = CHSV(modes[14].scale * 2.5, 255, 255); - } -} - -// ------------------------------ снегопад 2.0 -------------------------------- -void snowRoutine() { - // сдвигаем всё вниз - for (byte x = 0; x < WIDTH; x++) { - for (byte y = 0; y < HEIGHT - 1; y++) { - drawPixelXY(x, y, getPixColorXY(x, y + 1)); - } - } - - for (byte x = 0; x < WIDTH; x++) { - // заполняем случайно верхнюю строку - // а также не даём двум блокам по вертикали вместе быть - if (getPixColorXY(x, HEIGHT - 2) == 0 && (random(0, modes[15].scale) == 0)) - drawPixelXY(x, HEIGHT - 1, 0xE0FFFF - 0x101010 * random(0, 4)); - else - drawPixelXY(x, HEIGHT - 1, 0x000000); - } -} - -// ------------------------------ МАТРИЦА ------------------------------ -void matrixRoutine() { - for (byte x = 0; x < WIDTH; x++) { - // заполняем случайно верхнюю строку - uint32_t thisColor = getPixColorXY(x, HEIGHT - 1); - if (thisColor == 0) - drawPixelXY(x, HEIGHT - 1, 0x00FF00 * (random(0, modes[16].scale) == 0)); - else if (thisColor < 0x002000) - drawPixelXY(x, HEIGHT - 1, 0); - else - drawPixelXY(x, HEIGHT - 1, thisColor - 0x002000); - } - - // сдвигаем всё вниз - for (byte x = 0; x < WIDTH; x++) { - for (byte y = 0; y < HEIGHT - 1; y++) { - drawPixelXY(x, y, getPixColorXY(x, y + 1)); - } - } -} - -// ------------------------------ БЕЛАЯ ЛАМПА ------------------------------ -void whiteLamp() { - for (byte y = 0; y < (HEIGHT / 2); y++) { - CHSV color = CHSV(100, 1, constrain(modes[17].brightness - (long)modes[17].speed * modes[17].brightness / 255 * y / 2, 1, 255)); - for (byte x = 0; x < WIDTH; x++) { - drawPixelXY(x, y + 8, color); - drawPixelXY(x, 7 - y, color); - } - } -} - - -//// ----------------------------- СВЕТЛЯКИ ------------------------------ в ардуине под него не хватет пямяти -//#define LIGHTERS_AM 100 -//int lightersPos[2][LIGHTERS_AM]; -//int8_t lightersSpeed[2][LIGHTERS_AM]; -//CHSV lightersColor[LIGHTERS_AM]; -//byte loopCounter; -// -//int angle[LIGHTERS_AM]; -//int speedV[LIGHTERS_AM]; -//int8_t angleSpeed[LIGHTERS_AM]; -// -//void lightersRoutine() { -// if (loadingFlag) { -// loadingFlag = false; -// randomSeed(millis()); -// for (byte i = 0; i < LIGHTERS_AM; i++) { -// lightersPos[0][i] = random(0, WIDTH * 10); -// lightersPos[1][i] = random(0, HEIGHT * 10); -// lightersSpeed[0][i] = random(-10, 10); -// lightersSpeed[1][i] = random(-10, 10); -// lightersColor[i] = CHSV(random(0, 255), 255, 255); -// } -// } -// FastLED.clear(); -// if (++loopCounter > 20) loopCounter = 0; -// for (byte i = 0; i < modes[17].scale; i++) { -// if (loopCounter == 0) { // меняем скорость каждые 255 отрисовок -// lightersSpeed[0][i] += random(-3, 4); -// lightersSpeed[1][i] += random(-3, 4); -// lightersSpeed[0][i] = constrain(lightersSpeed[0][i], -20, 20); -// lightersSpeed[1][i] = constrain(lightersSpeed[1][i], -20, 20); -// } -// -// lightersPos[0][i] += lightersSpeed[0][i]; -// lightersPos[1][i] += lightersSpeed[1][i]; -// -// if (lightersPos[0][i] < 0) lightersPos[0][i] = (WIDTH - 1) * 10; -// if (lightersPos[0][i] >= WIDTH * 10) lightersPos[0][i] = 0; -// -// if (lightersPos[1][i] < 0) { -// lightersPos[1][i] = 0; -// lightersSpeed[1][i] = -lightersSpeed[1][i]; -// } -// if (lightersPos[1][i] >= (HEIGHT - 1) * 10) { -// lightersPos[1][i] = (HEIGHT - 1) * 10; -// lightersSpeed[1][i] = -lightersSpeed[1][i]; -// } -// drawPixelXY(lightersPos[0][i] / 10, lightersPos[1][i] / 10, lightersColor[i]); -// } -//} +// ================================= ЭФФЕКТЫ ==================================== +uint8_t pcnt; +uint8_t line[WIDTH]; +// --------------------------------- конфетти ------------------------------------ +#define FADE_OUT_SPEED (70U) // скорость затухания +void sparklesRoutine() +{ + for (uint8_t i = 0; i < modes[currentMode].scale; i++) + { + uint8_t x = random(0U, WIDTH); + uint8_t y = random(0U, HEIGHT); + if (getPixColorXY(x, y) == 0U) + { + drawPixelXY(x, y,CHSV(random(0U, 255U), 255U, 255U)); + } + } + fader(FADE_OUT_SPEED); +} +// -------------------------------------- огонь --------------------------------------------- +#define SPARKLES 0 // вылетающие угольки вкл выкл +//these values are substracetd from the generated values to give a shape to the animation +const unsigned char valueMask[8][16] PROGMEM = { + {0 , 0 , 0 , 32 , 32 , 0 , 0 , 0 , 0 , 0 , 0 , 32 , 32 , 0 , 0 , 0 }, + {0 , 0 , 0 , 64 , 64 , 0 , 0 , 0 , 0 , 0 , 0 , 64 , 64 , 0 , 0 , 0 }, + {0 , 0 , 32 , 96 , 96 , 32 , 0 , 0 , 0 , 0 , 32 , 96 , 96 , 32 , 0 , 0 }, + {0 , 32 , 64 , 128, 128, 64 , 32 , 0 , 0 , 32 , 64 , 128, 128, 64 , 32 , 0 }, + {32 , 64 , 96 , 160, 160, 96 , 64 , 32 , 32 , 64 , 96 , 160, 160, 96 , 64 , 32 }, + {64 , 96 , 128, 192, 192, 128, 96 , 64 , 64 , 96 , 128, 192, 192, 128, 96 , 64 }, + {96 , 128, 160, 255, 255, 160, 128, 96 , 96 , 128, 160, 255, 255, 160, 128, 96 }, + {128, 160, 192, 255, 255, 192, 160, 128, 128, 160, 192, 255, 255, 192, 160, 128} +}; + +//these are the hues for the fire, +//should be between 0 (red) to about 25 (yellow) +const unsigned char hueMask[8][16] PROGMEM = { + {25, 22, 11, 1 , 1 , 11, 19, 25, 25, 22, 11, 1 , 1 , 11, 19, 25 }, + {25, 19, 8 , 1 , 1 , 8 , 13, 19, 25, 19, 8 , 1 , 1 , 8 , 13, 19 }, + {19, 16, 8 , 1 , 1 , 8 , 13, 16, 19, 16, 8 , 1 , 1 , 8 , 13, 16 }, + {13, 13, 5 , 1 , 1 , 5 , 11, 13, 13, 13, 5 , 1 , 1 , 5 , 11, 13 }, + {11, 11, 5 , 1 , 1 , 5 , 11, 11, 11, 11, 5 , 1 , 1 , 5 , 11, 11 }, + {8 , 5 , 1 , 0 , 0 , 1 , 5 , 8 , 8 , 5 , 1 , 0 , 0 , 1 , 5 , 8 }, + {5 , 1 , 0 , 0 , 0 , 0 , 1 , 5 , 5 , 1 , 0 , 0 , 0 , 0 , 1 , 5 }, + {1 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 1 } +}; +void fireRoutine() { + if (loadingFlag) { + loadingFlag = false; + //FastLED.clear(); + generateLine(); + } + if (pcnt >= 100) { + shiftUp(); + generateLine(); + pcnt = 0; + } + drawFrame(pcnt); + pcnt += 25; +} + +// Случайным образом генерирует следующую линию (matrix row) + +void generateLine() { + for (uint8_t x = 0; x < WIDTH; x++) { + line[x] = random(127, 255); + } +} + +void shiftUp() { + for (uint8_t y = HEIGHT - 1; y > 0; y--) { + for (uint8_t x = 0; x < WIDTH; x++) { + uint8_t newX = x; + if (x > 15) newX = x - 15; + if (y > 7) continue; + matrixValue[y][newX] = matrixValue[y - 1][newX]; + } + } + + for (uint8_t x = 0; x < WIDTH; x++) { + uint8_t newX = x; + if (x > 15) newX = x - 15; + matrixValue[0][newX] = line[newX]; + } +} + +// рисует кадр, интерполируя между 2 "ключевых кадров" +// параметр pcnt - процент интерполяции + +void drawFrame(int pcnt) { + int nextv; + + //each row interpolates with the one before it + for (unsigned char y = HEIGHT - 1; y > 0; y--) { + for (unsigned char x = 0; x < WIDTH; x++) { + uint8_t newX = x; + if (x > 15) newX = x - 15; + if (y < 8) { + nextv = + (((100.0 - pcnt) * matrixValue[y][newX] + + pcnt * matrixValue[y - 1][newX]) / 100.0) + - pgm_read_byte(&(valueMask[y][newX])); + + CRGB color = CHSV( + modes[currentMode].scale * 2.5 + pgm_read_byte(&(hueMask[y][newX])), // H + 255, // S + (uint8_t)max(0, nextv) // V + ); + + leds[getPixelNumber(x, y)] = color; + } else if (y == 8 && SPARKLES) { + if (random(0, 20) == 0 && getPixColorXY(x, y - 1) != 0) drawPixelXY(x, y, getPixColorXY(x, y - 1)); + else drawPixelXY(x, y, 0); + } else if (SPARKLES) { + + // старая версия для яркости + if (getPixColorXY(x, y - 1) > 0) + drawPixelXY(x, y, getPixColorXY(x, y - 1)); + else drawPixelXY(x, y, 0); + + } + } + } + + //Перавя стрка интерполируется со следующей "next" линией + for (unsigned char x = 0; x < WIDTH; x++) { + uint8_t newX = x; + if (x > 15) newX = x - 15; + CRGB color = CHSV( + modes[currentMode].scale * 2.5 + pgm_read_byte(&(hueMask[0][newX])), // H + 255, // S + (uint8_t)(((100.0 - pcnt) * matrixValue[0][newX] + pcnt * line[newX]) / 100.0) // V + ); + leds[getPixelNumber(newX, 0)] = color; + } +} +byte hue; +// ---------------------------------------- радуга ------------------------------------------ +void rainbowVertical() { + hue += 2; + for (byte j = 0; j < HEIGHT; j++) { + CHSV thisColor = CHSV((byte)(hue + j * modes[currentMode].scale), 255, 255); + for (byte i = 0; i < WIDTH; i++) + drawPixelXY(i, j, thisColor); + } +} +void rainbowHorizontal() { + hue += 2; + for (byte i = 0; i < WIDTH; i++) { + CHSV thisColor = CHSV((byte)(hue + i * modes[currentMode].scale), 255, 255); + for (byte j = 0; j < HEIGHT; j++) + drawPixelXY(i, j, thisColor); //leds[getPixelNumber(i, j)] = thisColor; + } +} + +// ---------------------------------------- ЦВЕТА ------------------------------------------ +void colorsRoutine() { + hue += modes[currentMode].scale; + for (int i = 0; i < NUM_LEDS; i++) { + leds[i] = CHSV(hue, 255, 255); + } +} + +// --------------------------------- ЦВЕТ ------------------------------------ +void colorRoutine() { + for (int i = 0; i < NUM_LEDS; i++) { + //leds[i] = CHSV(modes[14].scale * 2.5, 255, 255); + leds[i] = CHSV(modes[currentMode].speed*(modes[currentMode].scale/16+1), 255, 255); + } +} + +// ------------------------------ снегопад 2.0 -------------------------------- +void snowRoutine() { + shiftDown(); + + for (byte x = 0; x < WIDTH; x++) { + // заполняем случайно верхнюю строку + // а также не даём двум блокам по вертикали вместе быть + if (getPixColorXY(x, HEIGHT - 2) == 0 && (random(0, modes[currentMode].scale) == 0)) + drawPixelXY(x, HEIGHT - 1U, 0xE0FFFF - 0x101010 * random(0, 4)); + else + drawPixelXY(x, HEIGHT - 1, 0x000000); + } +} +// ------------------------------ МАТРИЦА ------------------------------ +void matrixRoutine() +{ + for (uint8_t x = 0U; x < WIDTH; x++) + { + // обрабатываем нашу матрицу снизу вверх до второй сверху строчки + for (uint8_t y = 0U; y < HEIGHT - 1U; y++) + { + uint32_t thisColor = getPixColorXY(x, y); // берём цвет нашего пикселя + uint32_t upperColor = getPixColorXY(x, y + 1U); // берём цвет пикселя над нашим + if (upperColor >= 0x900000 && random(7 * HEIGHT) != 0U) // если выше нас максимальная яркость, игнорим этот факт с некой вероятностью или опускаем цепочку ниже + drawPixelXY(x, y, upperColor); + else if (thisColor == 0U && random((100 - modes[currentMode].scale) * HEIGHT) == 0U) // если наш пиксель ещё не горит, иногда зажигаем новые цепочки + //else if (thisColor == 0U && random((100 - modes[currentMode].Scale) * HEIGHT*3) == 0U) // для длинных хвостов + drawPixelXY(x, y, 0x9bf800); + else if (thisColor <= 0x050800) // если наш пиксель почти погас, стараемся сделать затухание медленней + { + if (thisColor >= 0x030000) + drawPixelXY(x, y, 0x020300); + else if (thisColor != 0U) + drawPixelXY(x, y, 0U); + } + else if (thisColor >= 0x900000) // если наш пиксель максимальной яркости, резко снижаем яркость + drawPixelXY(x, y, 0x558800); + else + drawPixelXY(x, y, thisColor - 0x0a1000); // в остальных случаях снижаем яркость на 1 уровень + //drawPixelXY(x, y, thisColor - 0x050800); // для длинных хвостов + } + // аналогично обрабатываем верхний ряд пикселей матрицы + uint32_t thisColor = getPixColorXY(x, HEIGHT - 1U); + if (thisColor == 0U) // если наш верхний пиксель не горит, заполняем его с вероятностью .Scale + { + if (random(100 - modes[currentMode].scale) == 0U) + drawPixelXY(x, HEIGHT - 1U, 0x9bf800); + } + else if (thisColor <= 0x050800) // если наш верхний пиксель почти погас, стараемся сделать затухание медленней + { + if (thisColor >= 0x030000) + drawPixelXY(x, HEIGHT - 1U, 0x020300); + else + drawPixelXY(x, HEIGHT - 1U, 0U); + } + else if (thisColor >= 0x900000) // если наш верхний пиксель максимальной яркости, резко снижаем яркость + drawPixelXY(x, HEIGHT - 1U, 0x558800); + else + drawPixelXY(x, HEIGHT - 1U, thisColor - 0x0a1000); // в остальных случаях снижаем яркость на 1 уровень + //drawPixelXY(x, HEIGHT - 1U, thisColor - 0x050800); // для длинных хвостов + } +} +// ------------------------------ БЕЛАЯ ЛАМПА ------------------------------ +void whiteLampRoutine() +{ + if (loadingFlag) + { + loadingFlag = false; + FastLED.clear(); + //delay(1); + + uint8_t centerY = (uint8_t)round(HEIGHT / 2.0F) - 1U;// max((uint8_t)round(HEIGHT / 2.0F) - 1, 0); нахрена тут максимум было вычислять? для ленты?! + uint8_t bottomOffset = (uint8_t)(!(HEIGHT & 0x01));// && (HEIGHT > 1)); и высота больше единицы. супер! // если высота матрицы чётная, линий с максимальной яркостью две, а линии с минимальной яркостью снизу будут смещены на один ряд + + uint8_t fullRows = centerY / 100.0 * modes[currentMode].scale; + uint8_t iPol = (centerY / 100.0 * modes[currentMode].scale - fullRows) * 255; + + for (int16_t y = centerY; y >= 0; y--) + { + CRGB color = CHSV( + 45U, // определяем тон + map(modes[currentMode].speed, 0U, 255U, 0U, 170U), // определяем насыщенность + y > (centerY - fullRows - 1) // определяем яркость + ? 255U // для центральных горизонтальных полос + : iPol * (y > centerY - fullRows - 2)); // для остальных горизонтальных полос яркость равна либо 255, либо 0 в зависимости от масштаба + + for (uint8_t x = 0U; x < WIDTH; x++) + { + drawPixelXY(x, y, color); // при чётной высоте матрицы максимально яркими отрисуются 2 центральных горизонтальных полосы + drawPixelXY(x, HEIGHT + bottomOffset - y - 2U, color); // при нечётной - одна, но дважды + } + } + } +} diff --git a/firmware/GyverLamp_v1.4_Arduino_v1.0/noiseEffects.ino b/firmware/GyverLamp_v1.4_Arduino_v1.0/noiseEffects.ino index fefccb6..11f3c90 100644 --- a/firmware/GyverLamp_v1.4_Arduino_v1.0/noiseEffects.ino +++ b/firmware/GyverLamp_v1.4_Arduino_v1.0/noiseEffects.ino @@ -1,205 +1,194 @@ -// ******************* НАСТРОЙКИ ***************** -// "масштаб" эффектов. Чем меньше, тем крупнее! -#define MADNESS_SCALE 100 -#define CLOUD_SCALE 30 -#define LAVA_SCALE 50 -#define PLASMA_SCALE 30 -#define RAINBOW_SCALE 30 -#define RAINBOW_S_SCALE 20 -#define ZEBRA_SCALE 30 -#define FOREST_SCALE 120 -#define OCEAN_SCALE 90 - -// ***************** ДЛЯ РАЗРАБОТЧИКОВ ****************** - -// The 16 bit version of our coordinates -static uint16_t x; -static uint16_t y; -static uint16_t z; - -uint16_t speed = 20; // speed is set dynamically once we've started up -uint16_t scale = 30; // scale is set dynamically once we've started up - -// This is the array that we keep our computed noise values in (это массив, в котором храним вычисленные значения шума) -#define MAX_DIMENSION (max(WIDTH, HEIGHT)) -#if (WIDTH > HEIGHT) -uint8_t noise[WIDTH][WIDTH]; -#else -uint8_t noise[HEIGHT][HEIGHT]; -#endif - -CRGBPalette16 currentPalette( PartyColors_p ); -uint8_t colorLoop = 1; -uint8_t ihue = 0; - -void madnessNoise() { - if (loadingFlag) { - loadingFlag = false; - scale = modes[5].scale; - speed = modes[5].speed; - } - fillnoise8(); - for (int i = 0; i < WIDTH; i++) { - for (int j = 0; j < HEIGHT; j++) { - CRGB thisColor = CHSV(noise[j][i], 255, noise[i][j]); - drawPixelXY(i, j, thisColor); //leds[getPixelNumber(i, j)] = CHSV(noise[j][i], 255, noise[i][j]); - } - } - ihue += 1; -} -void rainbowNoise() { - if (loadingFlag) { - loadingFlag = false; - currentPalette = RainbowColors_p; - scale = modes[9].scale; - speed = modes[9].speed; - colorLoop = 1; - } - fillNoiseLED(); -} -void rainbowStripeNoise() { - if (loadingFlag) { - loadingFlag = false; - currentPalette = RainbowStripeColors_p; - scale = modes[10].scale; - speed = modes[10].speed; - colorLoop = 1; - } - fillNoiseLED(); -} -void zebraNoise() { - if (loadingFlag) { - loadingFlag = false; - // 'black out' all 16 palette entries... - fill_solid( currentPalette, 16, CRGB::Black); - // and set every fourth one to white. - currentPalette[0] = CRGB::White; - currentPalette[4] = CRGB::White; - currentPalette[8] = CRGB::White; - currentPalette[12] = CRGB::White; - scale = modes[11].scale; - speed = modes[11].speed; - colorLoop = 1; - -// Serial.print(" speed:"); -// Serial.print(modes[currentMode].speed); -// Serial.print(" scale:"); -// Serial.println(modes[currentMode].scale); - } - fillNoiseLED(); -} -void forestNoise() { - if (loadingFlag) { - loadingFlag = false; - currentPalette = ForestColors_p; - scale = modes[12].scale; - speed = modes[12].speed; - colorLoop = 0; - } - fillNoiseLED(); -} -void oceanNoise() { - if (loadingFlag) { - loadingFlag = false; - currentPalette = OceanColors_p; - scale = modes[13].scale; - speed = modes[13].speed; - colorLoop = 0; - } - - fillNoiseLED(); -} -void plasmaNoise() { - if (loadingFlag) { - loadingFlag = false; - currentPalette = PartyColors_p; - scale = modes[8].scale; - speed = modes[8].speed; - colorLoop = 1; - } - fillNoiseLED(); -} -void cloudNoise() { - if (loadingFlag) { - loadingFlag = false; - currentPalette = CloudColors_p; - scale = modes[6].scale; - speed = modes[6].speed; - colorLoop = 0; - } - fillNoiseLED(); -} -void lavaNoise() { - if (loadingFlag) { - loadingFlag = false; - currentPalette = LavaColors_p; - scale = modes[7].scale; - speed = modes[7].speed; - colorLoop = 0; - } - fillNoiseLED(); -} - -// ******************* СЛУЖЕБНЫЕ ******************* -void fillNoiseLED() { - uint8_t dataSmoothing = 0; - if ( speed < 50) { - dataSmoothing = 200 - (speed * 4); - } - for (int i = 0; i < MAX_DIMENSION; i++) { - int ioffset = scale * i; - for (int j = 0; j < MAX_DIMENSION; j++) { - int joffset = scale * j; - - uint8_t data = inoise8(x + ioffset, y + joffset, z); - - data = qsub8(data, 16); - data = qadd8(data, scale8(data, 39)); - - if ( dataSmoothing ) { - uint8_t olddata = noise[i][j]; - uint8_t newdata = scale8( olddata, dataSmoothing) + scale8( data, 256 - dataSmoothing); - data = newdata; - } - - noise[i][j] = data; - } - } - z += speed; - - // apply slow drift to X and Y, just for visual variation. - x += speed / 8; - y -= speed / 16; - - for (int i = 0; i < WIDTH; i++) { - for (int j = 0; j < HEIGHT; j++) { - uint8_t index = noise[j][i]; - uint8_t bri = noise[i][j]; - // if this palette is a 'loop', add a slowly-changing base value - if ( colorLoop) { - index += ihue; - } - // brighten up, as the color palette itself often contains the - // light/dark dynamic range desired - if ( bri > 127 ) { - bri = 255; - } else { - bri = dim8_raw( bri * 2); - } - CRGB color = ColorFromPalette( currentPalette, index, bri); - drawPixelXY(i, j, color); //leds[getPixelNumber(i, j)] = color; - } - } - ihue += 1; -} - -void fillnoise8() { - for (int i = 0; i < MAX_DIMENSION; i++) { - int ioffset = scale * i; - for (int j = 0; j < MAX_DIMENSION; j++) { - int joffset = scale * j; - noise[i][j] = inoise8(x + ioffset, y + joffset, z); - } - } - z += speed; -} +// ******************* НАСТРОЙКИ ***************** +// ***************** ДЛЯ РАЗРАБОТЧИКОВ ****************** + +// The 16 bit version of our coordinates +static uint16_t x; +static uint16_t y; +static uint16_t z; + +uint16_t speed = 20; // speed is set dynamically once we've started up +uint16_t scale = 30; // scale is set dynamically once we've started up + +// This is the array that we keep our computed noise values in (это массив, в котором храним вычисленные значения шума) +#define MAX_DIMENSION (max(WIDTH, HEIGHT)) +#if (WIDTH > HEIGHT) +uint8_t noise[WIDTH][WIDTH]; +#else +uint8_t noise[HEIGHT][HEIGHT]; +#endif + +CRGBPalette16 currentPalette( PartyColors_p ); +uint8_t colorLoop = 1; +uint8_t ihue = 0; + +void madnessNoise() { + if (loadingFlag) { + loadingFlag = false; + scale = modes[5].scale; + speed = modes[5].speed; + } + fillnoise8(); + for (int i = 0; i < WIDTH; i++) { + for (int j = 0; j < HEIGHT; j++) { + CRGB thisColor = CHSV(noise[j][i], 255, noise[i][j]); + drawPixelXY(i, j, thisColor); //leds[getPixelNumber(i, j)] = CHSV(noise[j][i], 255, noise[i][j]); + } + } + ihue += 1; +} +void rainbowNoise() { + if (loadingFlag) { + loadingFlag = false; + currentPalette = RainbowColors_p; + scale = modes[currentMode].scale; + speed = modes[currentMode].speed; + colorLoop = 1; + } + fillNoiseLED(); +} +void rainbowStripeNoise() { + if (loadingFlag) { + loadingFlag = false; + currentPalette = RainbowStripeColors_p; + scale = modes[currentMode].scale; + speed = modes[currentMode].speed; + colorLoop = 1; + } + fillNoiseLED(); +} +void zebraNoise() { + if (loadingFlag) { + loadingFlag = false; + // 'black out' all 16 palette entries... + fill_solid( currentPalette, 16, CRGB::Black); + // and set every fourth one to white. + currentPalette[0] = CRGB::White; + currentPalette[4] = CRGB::White; + currentPalette[8] = CRGB::White; + currentPalette[12] = CRGB::White; + scale = modes[11].scale; + speed = modes[11].speed; + colorLoop = 1; + +// Serial.print(" speed:"); +// Serial.print(modes[currentMode].speed); +// Serial.print(" scale:"); +// Serial.println(modes[currentMode].scale); + } + fillNoiseLED(); +} +void forestNoise() { + if (loadingFlag) { + loadingFlag = false; + currentPalette = ForestColors_p; + scale = modes[currentMode].scale; + speed = modes[currentMode].speed; + colorLoop = 0; + } + fillNoiseLED(); +} +void oceanNoise() { + if (loadingFlag) { + loadingFlag = false; + currentPalette = OceanColors_p; + scale = modes[currentMode].scale; + speed = modes[currentMode].speed; + colorLoop = 0; + } + + fillNoiseLED(); +} +void plasmaNoise() { + if (loadingFlag) { + loadingFlag = false; + currentPalette = PartyColors_p; + scale = modes[currentMode].scale; + speed = modes[currentMode].speed; + colorLoop = 1; + } + fillNoiseLED(); +} +void cloudNoise() { + if (loadingFlag) { + loadingFlag = false; + currentPalette = CloudColors_p; + scale = modes[currentMode].scale; + speed = modes[currentMode].speed; + colorLoop = 0; + } + fillNoiseLED(); +} +void lavaNoise() { + if (loadingFlag) { + loadingFlag = false; + currentPalette = LavaColors_p; + scale = modes[currentMode].scale; + speed = modes[currentMode].speed; + colorLoop = 0; + } + fillNoiseLED(); +} + +// ******************* СЛУЖЕБНЫЕ ******************* +void fillNoiseLED() { + uint8_t dataSmoothing = 0; + if ( speed < 50) { + dataSmoothing = 200 - (speed * 4); + } + for (int i = 0; i < MAX_DIMENSION; i++) { + int ioffset = scale * i; + for (int j = 0; j < MAX_DIMENSION; j++) { + int joffset = scale * j; + + uint8_t data = inoise8(x + ioffset, y + joffset, z); + + data = qsub8(data, 16); + data = qadd8(data, scale8(data, 39)); + + if ( dataSmoothing ) { + uint8_t olddata = noise[i][j]; + uint8_t newdata = scale8( olddata, dataSmoothing) + scale8( data, 256 - dataSmoothing); + data = newdata; + } + + noise[i][j] = data; + } + } + z += speed; + + // apply slow drift to X and Y, just for visual variation. + x += speed / 8; + y -= speed / 16; + + for (int i = 0; i < WIDTH; i++) { + for (int j = 0; j < HEIGHT; j++) { + uint8_t index = noise[j][i]; + uint8_t bri = noise[i][j]; + // if this palette is a 'loop', add a slowly-changing base value + if ( colorLoop) { + index += ihue; + } + // brighten up, as the color palette itself often contains the + // light/dark dynamic range desired + if ( bri > 127 ) { + bri = 255; + } else { + bri = dim8_raw( bri * 2); + } + CRGB color = ColorFromPalette( currentPalette, index, bri); + drawPixelXY(i, j, color); //leds[getPixelNumber(i, j)] = color; + } + } + ihue += 1; +} + +void fillnoise8() { + for (int i = 0; i < MAX_DIMENSION; i++) { + int ioffset = scale * i; + for (int j = 0; j < MAX_DIMENSION; j++) { + int joffset = scale * j; + noise[i][j] = inoise8(x + ioffset, y + joffset, z); + } + } + z += speed; +} diff --git a/firmware/GyverLamp_v1.4_Arduino_v1.0/utility.ino b/firmware/GyverLamp_v1.4_Arduino_v1.0/utility.ino index 6110de5..c481eb4 100644 --- a/firmware/GyverLamp_v1.4_Arduino_v1.0/utility.ino +++ b/firmware/GyverLamp_v1.4_Arduino_v1.0/utility.ino @@ -1,87 +1,128 @@ -// служебные функции - -// залить все -void fillAll(CRGB color) { - for (int i = 0; i < NUM_LEDS; i++) { - leds[i] = color; - } -} - -// функция отрисовки точки по координатам X Y -void drawPixelXY(int8_t x, int8_t y, CRGB color) { - if (x < 0 || x > WIDTH - 1 || y < 0 || y > HEIGHT - 1) return; - int thisPixel = getPixelNumber(x, y) * SEGMENTS; - for (byte i = 0; i < SEGMENTS; i++) { - leds[thisPixel + i] = color; - } -} - -// функция получения цвета пикселя по его номеру -uint32_t getPixColor(int thisSegm) { - int thisPixel = thisSegm * SEGMENTS; - if (thisPixel < 0 || thisPixel > NUM_LEDS - 1) return 0; - return (((uint32_t)leds[thisPixel].r << 16) | ((long)leds[thisPixel].g << 8 ) | (long)leds[thisPixel].b); -} - -// функция получения цвета пикселя в матрице по его координатам -uint32_t getPixColorXY(int8_t x, int8_t y) { - return getPixColor(getPixelNumber(x, y)); -} - -// **************** НАСТРОЙКА МАТРИЦЫ **************** -#if (CONNECTION_ANGLE == 0 && STRIP_DIRECTION == 0) -#define _WIDTH WIDTH -#define THIS_X x -#define THIS_Y y - -#elif (CONNECTION_ANGLE == 0 && STRIP_DIRECTION == 1) -#define _WIDTH HEIGHT -#define THIS_X y -#define THIS_Y x - -#elif (CONNECTION_ANGLE == 1 && STRIP_DIRECTION == 0) -#define _WIDTH WIDTH -#define THIS_X x -#define THIS_Y (HEIGHT - y - 1) - -#elif (CONNECTION_ANGLE == 1 && STRIP_DIRECTION == 3) -#define _WIDTH HEIGHT -#define THIS_X (HEIGHT - y - 1) -#define THIS_Y x - -#elif (CONNECTION_ANGLE == 2 && STRIP_DIRECTION == 2) -#define _WIDTH WIDTH -#define THIS_X (WIDTH - x - 1) -#define THIS_Y (HEIGHT - y - 1) - -#elif (CONNECTION_ANGLE == 2 && STRIP_DIRECTION == 3) -#define _WIDTH HEIGHT -#define THIS_X (HEIGHT - y - 1) -#define THIS_Y (WIDTH - x - 1) - -#elif (CONNECTION_ANGLE == 3 && STRIP_DIRECTION == 2) -#define _WIDTH WIDTH -#define THIS_X (WIDTH - x - 1) -#define THIS_Y y - -#elif (CONNECTION_ANGLE == 3 && STRIP_DIRECTION == 1) -#define _WIDTH HEIGHT -#define THIS_X y -#define THIS_Y (WIDTH - x - 1) - -#else -#define _WIDTH WIDTH -#define THIS_X x -#define THIS_Y y -#pragma message "Wrong matrix parameters! Set to default" - -#endif - -// получить номер пикселя в ленте по координатам -uint16_t getPixelNumber(int8_t x, int8_t y) { - if ((THIS_Y % 2 == 0) || MATRIX_TYPE) { // если чётная строка - return (THIS_Y * _WIDTH + THIS_X); - } else { // если нечётная строка - return (THIS_Y * _WIDTH + _WIDTH - THIS_X - 1); - } -} +// служебные функции +// функция плавного угасания цвета для всех пикселей +void fader(uint8_t step) +{ + for (uint8_t i = 0U; i < WIDTH; i++) + { + for (uint8_t j = 0U; j < HEIGHT; j++) + { + fadePixel(i, j, step); + } + } +} +void fadePixel(uint8_t i, uint8_t j, uint8_t step) // новый фейдер +{ + int32_t pixelNum = XY(i, j); + if (getPixColor(pixelNum) == 0U) return; + + if (leds[pixelNum].r >= 30U || + leds[pixelNum].g >= 30U || + leds[pixelNum].b >= 30U) + { + leds[pixelNum].fadeToBlackBy(step); + } + else + { + leds[pixelNum] = 0U; + } +} +void shiftDown(){ + for (byte x = 0; x < WIDTH; x++) { + for (byte y = 0; y < HEIGHT - 1; y++) { + drawPixelXY(x, y, getPixColorXY(x, y + 1)); + }}} +// залить все +void fillAll(CRGB color) { + for (int i = 0; i < NUM_LEDS; i++) { + leds[i] = color; + } +} + + + +// функция отрисовки точки по координатам X Y +void drawPixelXY(uint8_t x, uint8_t y, CRGB color) +{ + if (x < 0 || x > (WIDTH - 1) || y < 0 || y > (HEIGHT - 1)) return; + uint32_t thisPixel = XY((uint8_t)x, (uint8_t)y) * SEGMENTS; + for (uint8_t i = 0; i < SEGMENTS; i++) + { + leds[thisPixel + i] = color; + } +} + +// функция получения цвета пикселя по его номеру +uint32_t getPixColor(uint32_t thisSegm) +{ + uint32_t thisPixel = thisSegm * SEGMENTS; + if (thisPixel > NUM_LEDS - 1) return 0; + return (((uint32_t)leds[thisPixel].r << 16) | ((uint32_t)leds[thisPixel].g << 8 ) | (uint32_t)leds[thisPixel].b); +} +// функция получения цвета пикселя в матрице по его координатам +uint32_t getPixColorXY(uint8_t x, uint8_t y) +{ + return getPixColor(XY(x, y)); +} + +// **************** НАСТРОЙКА МАТРИЦЫ **************** +#if (CONNECTION_ANGLE == 0 && STRIP_DIRECTION == 0) +#define _WIDTH WIDTH +#define THIS_X x +#define THIS_Y y + +#elif (CONNECTION_ANGLE == 0 && STRIP_DIRECTION == 1) +#define _WIDTH HEIGHT +#define THIS_X y +#define THIS_Y x + +#elif (CONNECTION_ANGLE == 1 && STRIP_DIRECTION == 0) +#define _WIDTH WIDTH +#define THIS_X x +#define THIS_Y (HEIGHT - y - 1) + +#elif (CONNECTION_ANGLE == 1 && STRIP_DIRECTION == 3) +#define _WIDTH HEIGHT +#define THIS_X (HEIGHT - y - 1) +#define THIS_Y x + +#elif (CONNECTION_ANGLE == 2 && STRIP_DIRECTION == 2) +#define _WIDTH WIDTH +#define THIS_X (WIDTH - x - 1) +#define THIS_Y (HEIGHT - y - 1) + +#elif (CONNECTION_ANGLE == 2 && STRIP_DIRECTION == 3) +#define _WIDTH HEIGHT +#define THIS_X (HEIGHT - y - 1) +#define THIS_Y (WIDTH - x - 1) + +#elif (CONNECTION_ANGLE == 3 && STRIP_DIRECTION == 2) +#define _WIDTH WIDTH +#define THIS_X (WIDTH - x - 1) +#define THIS_Y y + +#elif (CONNECTION_ANGLE == 3 && STRIP_DIRECTION == 1) +#define _WIDTH HEIGHT +#define THIS_X y +#define THIS_Y (WIDTH - x - 1) + +#else +#define _WIDTH WIDTH +#define THIS_X x +#define THIS_Y y +#pragma message "Wrong matrix parameters! Set to default" + +#endif + +uint16_t XY(uint8_t x, uint8_t y) +{ + if (!(THIS_Y & 0x01) || MATRIX_TYPE) // Even rows run forwards + return (THIS_Y * _WIDTH + THIS_X); + else + return (THIS_Y * _WIDTH + _WIDTH - THIS_X - 1); // Odd rows run backwards +} + +// оставлено для совместимости со эффектами из старых прошивок +uint16_t getPixelNumber(uint8_t x, uint8_t y) +{ + return XY(x, y); +}