#include <FastLED.h>
#include "tables.h"


#define SENSOR_START 4  // пин датчика движения  4
#define SENSOR_END 5     // пин датчика движения  1
#define LED_PIN     13  // пин ленты             2
#define COUNT_STEPS   16 // количество ступенек
#define LED_STEP  20  // лампочек на ступеньке
#define LED_TYPE    WS2812 //тип ленты
#define COLOR_ORDER GRB  //порядок цветов
#define CUSTOM_BRIGHT 100  // ручная яркость
#define TIMEOUT 2           // секунд, таймаут выключения ступенек после срабатывания одного из датчиков движения 
#define NUMLEDS 762 // кол-во светодиодов
#define SPEED 300 // скорость переключения
#define SPEEDani 80 // скорость анимацыи
#define ON  CRGB::Red  // цвет включения
#define OF  CRGB::Black



struct Step {
  byte led_amount; //количество чипов в ступеньке
  byte status_step; //статус ступеньки(0-выключена,1включяется,2-включена,3-выключается)
  byte num_animation; //номер кадра анимации
  uint16_t night_mode_bitmask;// маска
  int start_chip;// номер начального чипа в ступеньке вычесляется програмно
};
// описание всех ступенек с возможностью подсветки ЛЮБЫХ ступенек в ночном режиме
Step steps[COUNT_STEPS] = {
  { 47, 0,0,0,0 },  // первая ступенька 16 чипов, 0b0100100100100100 - каждый третий чип активен в ночном режиме
  { 48, 0,0,0,0  },    // вторая ступенька 16 чипов, 0b0000000000000000 - не активен в ночном режиме
  { 48, 0,0,0,0  },
  { 48, 0,0,0,0  },  // первая ступенька 16 чипов, 0b0100100100100100 - каждый третий чип активен в ночном режиме
  { 48, 0,0,0,0  },    // вторая ступенька 16 чипов, 0b0000000000000000 - не активен в ночном режиме
  { 46, 0,0,0,0  },
  { 47, 0,0,0,0  },  // первая ступенька 16 чипов, 0b0100100100100100 - каждый третий чип активен в ночном режиме
  { 47, 0,0,0,0  },    // вторая ступенька 16 чипов, 0b0000000000000000 - не активен в ночном режиме
  { 47, 0,0,0,0  },
  { 48, 0,0,0,0  },  // первая ступенька 16 чипов, 0b0100100100100100 - каждый третий чип активен в ночном режиме
  { 48, 0,0,0,0  },    // вторая ступенька 16 чипов, 0b0000000000000000 - не активен в ночном режиме
  { 48, 0,0,0,0  },
  { 48, 0,0,0,0  },  // первая ступенька 16 чипов, 0b0100100100100100 - каждый третий чип активен в ночном режиме
  { 48, 0,0,0,0  },    // вторая ступенька 16 чипов, 0b0000000000000000 - не активен в ночном режиме
  { 48, 0,0,0,0  },
  { 48, 0,0,0,0  }  // 3
};
CRGB leds[NUMLEDS];    // буфер ленты

// ==== удобные макросы ====================================================
#define FOR_i(from, to) for (int i = (from); i < (to); i++)
#define FOR_j(from, to) for (int j = (from); j < (to); j++)
#define FOR_k(from, to) for (int k = (from); k > (to); k--)
#define ANIMATE_TM(x) \
  static uint32_t Tmr=0;\
  bool flag = millis() - Tmr >= (x);\
  if (flag)Tmr += (x);\
  if (flag)

//===========================
bool M_stat = 0;// ----------глобальнве переменные
int effSpeed;
int8_t effectDirection;
byte curBright = CUSTOM_BRIGHT;

byte effectCounter;
uint32_t timeoutCounter;
bool TIMEstat = false;
byte poslednyi;
// bool systemOffState;


struct PirSensor {  //--------------датчик
  int8_t effectDirection;
  int8_t pin;
  bool lastState;
  CRGB cvet;
  byte zag_tuh;
  uint32_t time; //загорается или тухнет или 0 ничего не делает
};
PirSensor startPirSensor = { 1, SENSOR_START, false, OF, false, millis()};
PirSensor endPirSensor = { -1, SENSOR_END, false, OF, false, millis()};
//--------------------------------------------------
// CRGBPalette16 firePalette;

void setup() {
  Serial2.begin(9600);
  FastLED.addLeds< LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUMLEDS);
  avtonum_startled();// автоматически находим и проставляем стартовый чип на каждой ступеньке
 FastLED.setBrightness(250) ;
  FastLED.clear();
  FastLED.show();
  FastLED.showColor(CRGB::Red);
  FastLED.show();
 
  FastLED.clear();
  FastLED.show();
}
void loop() {
  {
    ANIMATE_TM(SPEEDani)  animSTEP();//крутим анимацыю ступеньки
  }
  if (!startPirSensor.lastState)handlePirSensor(&startPirSensor); //опрашивается датчик если не сработал только что
  if (!endPirSensor.lastState)handlePirSensor(&endPirSensor); //опрашивается датчик если не сработал только что
  ANIMATE_TM(SPEED)  anim(); // крутим переключение со скоростью переключения ступенек
  if (TIMEstat) handleTimeout();// если таймер на выключение то проверяем


}

void anim_start() {
  static int step = 0;
  if (startPirSensor.lastState) { // когда сработал датчик надо загаратся
    step = 0; 
     if(endPirSensor.zag_tuh==2)endPirSensor.zag_tuh =0;// если с другой стороны тухнет то прекрати
     startPirSensor.lastState = false; // услышали что надо загоратся и сбросили флаг
    startPirSensor.zag_tuh = 1;
  }

  if (startPirSensor.zag_tuh == 2 && steps[step].status_step != 0)steps[step].status_step = 3;
  if (startPirSensor.zag_tuh == 1 && steps[step].status_step != 2 )steps[step].status_step = 1;

  if (step == COUNT_STEPS - 1) { // дошел до конца
    // Serial2.println("ok") ;
    step = 0;
    if ( startPirSensor.zag_tuh == 1) {//если загорелась
      TIMEstat = true; // запустить таймер через сколько потухнет
      timeoutCounter = millis();
    }
    startPirSensor.zag_tuh = 0;
  } else {
    step += 1;
  }
}

void anim_end() {

  static int step = COUNT_STEPS - 1;
  if (endPirSensor.lastState) { //когда сработал датчик надо загаратся
    step = COUNT_STEPS - 1; endPirSensor.lastState = false; // услышали что надо загоратся и сбросили флаг
     if(startPirSensor.zag_tuh==2)startPirSensor.zag_tuh=0;// если с другой стороны тухнет то прекрати
      
    endPirSensor.zag_tuh = 1;
  }

  if (endPirSensor.zag_tuh == 2 && steps[step].status_step != 0)steps[step].status_step = 3;
  if (endPirSensor.zag_tuh == 1 && steps[step].status_step != 2 )steps[step].status_step = 1;

  // Serial2.println() ;


  if (step == 0) {// дошол до конца
    step = COUNT_STEPS - 1;
    if ( endPirSensor.zag_tuh == 1) {//если загорелась
      TIMEstat = true; // запустить таймер через сколько потухнет
      timeoutCounter = millis();
    }
    endPirSensor.zag_tuh = 0;
  } else {
    step -= 1;
  }
}

void anim() {
  if (endPirSensor.zag_tuh > 0)anim_end();
  if (startPirSensor.zag_tuh > 0)anim_start();
}

void handleTimeout() {// таймер

  if (millis() - timeoutCounter >= (TIMEOUT * 1000)) {
    TIMEstat = false;
    if (poslednyi == 2) {
      
      startPirSensor.zag_tuh = 2;
      Serial2.print("тай-");
    }
    if (poslednyi == 3) {
     Serial2.print("тай-");
      endPirSensor.zag_tuh = 2;
    }
  }
}
void handlePirSensor(PirSensor * sensor) { //прослушивание сенсора
if ( millis() - sensor->time > 1500) {// не раньше 1,5 секунды
  if (digitalRead(sensor->pin)) {
      sensor->lastState =true ; sensor->time = millis(); sensor->zag_tuh = 1;
    poslednyi = sensor->pin;
    TIMEstat = false; Serial2.println("тут");
  }
}
}
void avtonum_startled() {
  FOR_i(1, COUNT_STEPS) {
    steps[i].start_chip = steps[i - 1].start_chip + steps[i - 1].led_amount;
    // Serial2.println(steps[i].start_chip) ;
  }
  // Serial2.println();
}
// заливка лесинки массивом

void animSTEP() {
  FOR_i(0, COUNT_STEPS) {
    if (steps[i].status_step == 0 || steps[i].status_step == 2)continue;
    int vel = (steps[i].status_step == 1) ? 1 : -1;

    steps[i].num_animation += vel;
    fill_Array(steps[i].start_chip, steps[i]. led_amount, steps[i].num_animation);
    if (steps[i].num_animation == 0 )steps[i].status_step = 0;
    if (steps[i].num_animation == 9)steps[i].status_step = 2;
  }
  FastLED.show();

}
void fill_Array(int start, byte num, byte  numan ) {
  for (int i = 0; i < num ; i++) {
    leds[i + start] = pgm_read_word(&Mask1[numan*50+i]);
  }
}