#include "clock.h"

/* type defs */
typedef struct t_btn {
  uint8_t     time;
  es_event_t  pressed;
  es_event_t  holded;
  uint32_t    pin;
  //(GPIO_TypeDef *) GPIOA; // ?->IDR
} btn_t;

/* variables */
rtc_t Clock;
static rtc_t setClock;
static btn_t Button[BTN_NUM] = {
  {0, evBTN1Pressed, evBTN1Holded,  BTN1_PIN},
  {0, evBTN2Pressed, evBTN2Pressed, BTN2_PIN},
  {0, evBTN3Pressed, evBTN3Pressed, BTN3_PIN},
  {0, evBTN4Pressed, evBTN4Holded,  BTN4_PIN}
};
//convert linear bright level to logariphmic
const uint8_t cie[MAX_BRIGHT_LVL + 1] = {
  0, 2, 4, 8, 13, 20, 29, 40, 54, 72, 92, 116, 145, 177, 214, 255
};
volatile static uint8_t dispWDT = 0;
static in15_pin_t symToFade = 0;
static uint8_t BrightLevel;
static flash_data_t Lighting, setLighting;

/* function prototypes */
static void check_DayNight(void);
static void HSV2LED(const uint8_t hue, const uint8_t val);
static void MinusFadeIn(void);
static void MinusFadeOut(void);
static void PlusFadeIn(void);
static void PercentFadeIn(void);
static void PressureFadeIn(void);
static void IN15_FadeIn(void);
static void IN15_FadeOut(void);
static void valIncrease(uint8_t * val, const uint8_t max);
static void valDecrease(uint8_t * val, const uint8_t max);
static void dvalIncrease(uint8_t * val, const uint8_t max);
static void dvalDecrease(uint8_t * val, const uint8_t max);

/* funcions */
void Clock_Init(void) {
  RTC_ReadAll(&Clock);
  showTime();

  //Lighting.u64 = flash_read();
  Lighting.name.DayHour = MORNING_HOUR;
  Lighting.name.NightHour = EVENING_HOUR;
  Lighting.name.DayBright = DAY_BR_LVL;
  Lighting.name.NightBright = NIGHT_BR_LVL;
  Lighting.name.DayMode = light_Rainbow;
  Lighting.name.NightMode = light_Colour;
  Lighting.name.NightColour = COLOUR_NIXIE;

  check_DayNight();
}

static void check_DayNight(void) {
  if ((Clock.Hr >= Lighting.name.DayHour) && (Clock.Hr < Lighting.name.NightHour)) {
    Flag.Now_Day = 1;
    BrightLevel = cie[Lighting.name.DayBright];
  } else {
    Flag.Now_Day = 0;
    BrightLevel = cie[Lighting.name.NightBright];
  }

  tube_BrightLevel(Tube_All, BrightLevel);
  //TUBES_BRIGHT(BrightLevel);
}

/**
  * @brief  Обработка кнопок.
  * @param  : None
  * @retval : None
  */
void btnProcess(void) {
  /* get pin state */
  uint32_t pins = BTNS_STATE;

  int i;
  for (i=0; i<BTN_NUM; i++) {
    if ((pins & Button[i].pin) == 0) {
    /* button pressed */
      Button[i].time ++;
      if (Button[i].time >= (BTN_TIME_HOLDED/BTN_SCAN_PERIOD)) {
        Button[i].time -= (BTN_TIME_REPEATED/BTN_SCAN_PERIOD);
        if (Button[i].holded == Button[i].pressed) {
          /* if pressed and holded - same function, then button pressed auto repeat */
          ES_PlaceEvent(Button[i].pressed);
        }
      }
    } else if (Button[i].time != 0) {
    /* button released */
      if (Button[i].time >= ((BTN_TIME_HOLDED - BTN_TIME_REPEATED)/BTN_SCAN_PERIOD)) {
        /* process long press */
        ES_PlaceEvent(Button[i].holded);
      } else if (Button[i].time >= (BTN_TIME_PRESSED/BTN_SCAN_PERIOD)) {
        /* process short press */
        ES_PlaceEvent(Button[i].pressed);
      }
      Button[i].time = 0;
      RTOS_SetTask(btnProcess, BTN_SCAN_PAUSE, BTN_SCAN_PERIOD);
    }
  } /* end FOR */
}

void new_Second(void) {
  RTC_ReadAll(&Clock);

  // new hour
  if (Clock.Min == 0 && Clock.Sec == 0) {
    check_DayNight();
  }

  // check display watch dog timer
  if (dispWDT != 0) {
    dispWDT--;
    if (dispWDT == 0) {
			Blink_Stop();
      ES_PlaceEvent(evDisplayWDT);
    }
  }
}

/**
  * On/off symbols on IN-15 tube.
  */
void in15Off(void) {
  IN15_OFF;
  TUBE_C_OFF;
}

void in15Minus(void) {
  IN15_OFF;
  IN15_Minus;
  TUBE_C_ON;
}

void in15Plus(void) {
  IN15_OFF;
  IN15_Plus;
  TUBE_C_ON;
}

void in15Percent(void) {
  IN15_OFF;
  IN15_Percent;
  TUBE_C_ON;
}

void in15P(void) {
  IN15_OFF;
  IN15_P;
  TUBE_C_ON;
}

/** 'Faded' funcions */
static void MinusFadeIn(void) {
  static uint8_t on = FADE_START;
  static uint8_t off = FADE_STOP;
  static uint8_t st = 0;

  if (st == 0) {
    st = 1;
    IN15_Minus;
    on += FADE_STEP;
    if (on < FADE_STOP) {
      RTOS_SetTask(MinusFadeIn, on, 0);
    } else {
      on = FADE_START; off = FADE_STOP; st = 0;
    }
  } else {
    st = 0;
    IN15_OFF;
    off -= FADE_STEP;
    RTOS_SetTask(MinusFadeIn, off, 0);
  }
}

static void MinusFadeOut(void) {
  static uint8_t off = FADE_START;
  static uint8_t on = FADE_STOP;
  static uint8_t st = 0;

  if (st == 0) {
    st = 1;
    IN15_OFF;
    off += FADE_STEP;
    if (off < FADE_STOP) {
      RTOS_SetTask(MinusFadeOut, off, 0);
    } else {
      off = FADE_START; on = FADE_STOP; st = 0;
    }
  } else {
    st = 0;
    IN15_Minus;
    on -= FADE_STEP;
    RTOS_SetTask(MinusFadeOut, on, 0);
  }
}

static void PlusFadeIn(void) {
  static uint8_t on = FADE_START;
  static uint8_t off = FADE_STOP;
  static uint8_t st = 0;

  if (st == 0) {
    st = 1;
    IN15_Plus;
    on += FADE_STEP;
    if (on < FADE_STOP) {
      RTOS_SetTask(PlusFadeIn, on, 0);
    } else {
      on = FADE_START; off = FADE_STOP; st = 0;
    }
  } else {
    st = 0;
    IN15_OFF;
    off -= FADE_STEP;
    RTOS_SetTask(PlusFadeIn, off, 0);
  }
}

static void PercentFadeIn(void) {
  static uint8_t on = FADE_START;
  static uint8_t off = FADE_STOP;
  static uint8_t st = 0;

  if (st == 0) {
    st = 1;
    IN15_Percent;
    on += FADE_STEP;
    if (on < FADE_STOP) {
      RTOS_SetTask(PercentFadeIn, on, 0);
    } else {
      on = FADE_START; off = FADE_STOP; st = 0;
    }
  } else {
    st = 0;
    IN15_OFF;
    off -= FADE_STEP;
    RTOS_SetTask(PercentFadeIn, off, 0);
  }
}

static void PressureFadeIn(void) {
  static uint8_t on = FADE_START;
  static uint8_t off = FADE_STOP;
  static uint8_t st = 0;

  if (st == 0) {
    st = 1;
    IN15_P;
    on += FADE_STEP;
    if (on < FADE_STOP) {
      RTOS_SetTask(PressureFadeIn, on, 0);
    } else {
      on = FADE_START; off = FADE_STOP; st = 0;
    }
  } else {
    st = 0;
    IN15_OFF;
    off -= FADE_STEP;
    RTOS_SetTask(PressureFadeIn, off, 0);
  }
}

static void IN15_FadeIn(void) {
  static uint8_t on = FADE_START;
  static uint8_t off = FADE_STOP;
  static uint8_t st = 0;

	if (symToFade != 0) {
		if (st == 0) {
			st = 1;
			GPIOA->BSRR = symToFade;
			on += FADE_STEP;
			if (on < FADE_STOP) {
				RTOS_SetTask(IN15_FadeIn, on, 0);
			} else {
				on = FADE_START; off = FADE_STOP; st = 0; symToFade = 0;
			}
		} else {
			st = 0;
			IN15_OFF;
			off -= FADE_STEP;
			RTOS_SetTask(IN15_FadeIn, off, 0);
		}
	}
}

static void IN15_FadeOut(void) {
  static uint8_t off = FADE_START;
  static uint8_t on = FADE_STOP;
  static uint8_t st = 0;

	if (symToFade != 0) {
		if (st == 0) {
			st = 1;
			IN15_OFF;
			off += FADE_STEP;
			if (off < FADE_STOP) {
				RTOS_SetTask(IN15_FadeOut, off, 0);
			} else {
				off = FADE_START; on = FADE_STOP; st = 0; symToFade = 0;
			}
		} else {
			st = 0;
			GPIOA->BSRR = symToFade;
			on -= FADE_STEP;
			RTOS_SetTask(IN15_FadeOut, on, 0);
		}
	}
}

/**
 * @brief  HSV to RGB convertion
 * @param  hue: 0-59, sat: allways max, val (lightness): 0-255
 * @return none. RGB value output direct to LED.
 */
static void HSV2LED(const uint8_t hue, const uint8_t val) {
  uint32_t r=0, g=0, b=0;

  switch (hue / 10) {
  case 0:
    r = val;
      g = (val * hue) / 10;
      b = 0;
      break;
  case 1:
    r = (val * (10 - (hue % 10))) / 10;
    g = val;
    b = 0;
    break;
  case 2:
    r = 0;
    g = val;
    b = (val * (hue % 10)) / 10;
    break;
  case 3:
    r = 0;
    g = (val * (10 - (hue % 10))) / 10;
    b = val;
    break;
  case 4:
    r = (val * (hue % 10)) / 10;
    g = 0;
    b = val;
    break;
  case 5:
    r = val;
    g = 0;
    b = (val * (10 - (hue % 10))) / 10;
    break;
  }

  COLOR_R((uint8_t)r);
  COLOR_G((uint8_t)g);
  COLOR_B((uint8_t)b);
}

/**
  * Show info on tubes.
  */
void showTime(void) {
  MinusFadeIn();
  RTOS_SetTask(MinusFadeOut, 500, 0);

  if (Flag.Now_Day != 0) {
    uint8_t hue = bcd2bin(Clock.Sec);
    HSV2LED(hue, BrightLevel);
  } else {
    HSV2LED(COLOUR_NIXIE, BrightLevel);
  }

  tube4_t buf;
  buf.s8.tA = Clock.Hr >> 4;
  buf.s8.tB = Clock.Hr & 0xf;
  buf.s8.tD = Clock.Min >> 4;
  buf.s8.tE = Clock.Min & 0xf;
  showDigits(buf);
}

void showMMSS(void) {
  RTOS_DeleteTask(MinusFadeOut);
  IN15_Minus;

  uint8_t hue = bcd2bin(Clock.Sec);
  HSV2LED(hue, BrightLevel);

  tube4_t buf;
  buf.s8.tA = Clock.Min >> 4;
  buf.s8.tB = Clock.Min & 0xf;
  buf.s8.tD = Clock.Sec >> 4;
  buf.s8.tE = Clock.Sec & 0xf;
  showDigits(buf);
}

void showWD(void) {
  dispWDT = DISP_WDT_TIME;
  IN15_OFF;

  tube4_t buf;
  buf.s8.tA = 0xf;
  buf.s8.tB = Clock.WD & 0xf;
  buf.s8.tD = 0xf;
  buf.s8.tE = 0xf;
  showDigits(buf);
}

void showDayMon(void) {
  dispWDT = DISP_WDT_TIME;
  IN15_OFF;

  tube4_t buf;
  buf.s8.tA = Clock.Day >> 4;
  buf.s8.tB = Clock.Day & 0xf;
  buf.s8.tD = Clock.Mon >> 4;
  buf.s8.tE = Clock.Mon & 0xf;
  showDigits(buf);
}

void showYear(void) {
  dispWDT = DISP_WDT_TIME;
  IN15_OFF;

  tube4_t buf;
  buf.s8.tA = 2;
  buf.s8.tB = 0;
  buf.s8.tD = Clock.Year >> 4;
  buf.s8.tE = Clock.Year & 0xf;
  showDigits(buf);
}

void showHumidity(void) {
  dispWDT = DISP_WDT_TIME;
  HSV2LED(COLOUR_BLUE, BrightLevel);
  symToFade = sym_Percent;
  IN15_FadeIn();

  tube4_t buf;
  buf.s8.tA = Humidity / 10;
  buf.s8.tB = Humidity % 10;
  buf.s8.tD = 0xf;
  buf.s8.tE = 0xf;
  showDigits(buf);
}

void showTemperature(void) {
  dispWDT = DISP_WDT_TIME;
  HSV2LED(COLOUR_RED, BrightLevel);
  RTOS_DeleteTask(MinusFadeIn);
  RTOS_DeleteTask(MinusFadeOut);
  symToFade = sym_Plus;
  IN15_FadeIn();

  tube4_t buf;
  buf.s8.tA = 0xf;
  buf.s8.tB = 0xf;
  buf.s8.tD = Temperature / 10;
  buf.s8.tE = Temperature % 10;
  showDigits(buf);
}

void showPressure(void) {
  dispWDT = DISP_WDT_TIME;
  HSV2LED(COLOUR_GREEN, BrightLevel);
  symToFade = sym_Pressure;
  IN15_FadeIn();

  tube4_t buf;
  int tmp;
  buf.s8.tA = 0xf;
  buf.s8.tB = Pressure / 100;
  tmp = Pressure % 100;
  buf.s8.tD = tmp / 10;
  buf.s8.tE = tmp % 10;
  showDigits(buf);
}

/* Simple function for cyclic show all sensor data */
void showSensorData(void) {
  RTOS_DeleteTask(MinusFadeOut);

  showTemperature();
  tdelay_ms(3000);

  showHumidity();
  tdelay_ms(3000);

  showPressure();
  tdelay_ms(2700);

  ES_SetState(stShowTime);
//  showTime();
}

void setTimeShow(void) {
	dispWDT = DISP_WDT_TIME;

  tube4_t buf;
  buf.s8.tA = setClock.Hr >> 4;
  buf.s8.tB = setClock.Hr & 0xf;
  buf.s8.tD = setClock.Min >> 4;
  buf.s8.tE = setClock.Min & 0xf;
  showDigits(buf);
}

void setTimeBegin(void) {
	RTOS_DeleteTask(MinusFadeOut);
  in15Minus();
  HSV2LED(COLOUR_NIXIE, BrightLevel);
  RTOS_SetTask(btnProcess, BTN_TIME_HOLDED, BTN_SCAN_PERIOD);
  RTC_ReadAll(&setClock);
}

void setHHBegin(void) {
  Flag.Blink_1 = 1;
  Flag.Blink_2 = 1;
  Flag.Blink_4 = 0;
  Flag.Blink_5 = 0;
  Blink_Start();
  setTimeShow();
}

void setHHInc(void) {
  valIncrease(&setClock.Hr, 23);
}

void setHHDec(void) {
  valDecrease(&setClock.Hr, 23);
}

void setMMBegin(void) {
  Flag.Blink_1 = 0;
  Flag.Blink_2 = 0;
  Flag.Blink_4 = 1;
  Flag.Blink_5 = 1;
  Blink_Start();
  setTimeShow();
}

void setMMInc(void) {
  valIncrease(&setClock.Min, 59);
}

void setMMDec(void) {
  valDecrease(&setClock.Min, 59);
}

void setTimeEnd(void) {
	dispWDT = 0;
  RTOS_SetTask(btnProcess, BTN_TIME_HOLDED, BTN_SCAN_PERIOD);

  setClock.Sec = 0;
  RTC_WriteTime(&setClock);

  Blink_Stop();

  RTC_ReadAll(&Clock);
}

void setDateBegin(void) {
  IN15_OFF;
  HSV2LED(COLOUR_NIXIE, BrightLevel);
  RTOS_SetTask(btnProcess, BTN_TIME_HOLDED, BTN_SCAN_PERIOD);
  RTC_ReadAll(&setClock);
}

void setDateEnd(void) {
	dispWDT =  0;
  RTOS_SetTask(btnProcess, BTN_TIME_HOLDED, BTN_SCAN_PERIOD);
  
  RTC_WriteCalendar(&setClock);

  Blink_Stop();

  RTC_ReadAll(&Clock);
}

void setWDBegin(void) {
  Flag.Blink_1 = 0;
  Flag.Blink_2 = 1;
  Flag.Blink_4 = 0;
  Flag.Blink_5 = 0;
  Blink_Start();
  setWDShow();
}

void setWDShow(void) {
	dispWDT = DISP_WDT_TIME;

  tube4_t buf;
  buf.s8.tA = 0xf;
  buf.s8.tB = setClock.WD & 0xf;
  buf.s8.tD = 0xf;
  buf.s8.tE = 0xf;
  showDigits(buf);
}

void setDMShow(void) {
	dispWDT = DISP_WDT_TIME;

  tube4_t buf;
  buf.s8.tA = setClock.Day >> 4;
  buf.s8.tB = setClock.Day & 0xf;
  buf.s8.tD = setClock.Mon >> 4;
  buf.s8.tE = setClock.Mon & 0xf;
  showDigits(buf);
}

void setYearShow(void) {
	dispWDT = DISP_WDT_TIME;

  tube4_t buf;
  buf.s8.tA = 2;
  buf.s8.tB = 0;
  buf.s8.tD = setClock.Year >> 4;
  buf.s8.tE = setClock.Year & 0xf;
  showDigits(buf);
}

void setMDBegin(void) {
  Flag.Blink_1 = 1;
  Flag.Blink_2 = 1;
  Flag.Blink_4 = 0;
  Flag.Blink_5 = 0;
  Blink_Start();
  setDMShow();
}

void setMonthBegin(void) {
  Flag.Blink_1 = 0;
  Flag.Blink_2 = 0;
  Flag.Blink_4 = 1;
  Flag.Blink_5 = 1;
  Blink_Start();
  setDMShow();
}

void setYearBegin(void) {
  Flag.Blink_1 = 0;
  Flag.Blink_2 = 0;
  Flag.Blink_4 = 1;
  Flag.Blink_5 = 1;
  Blink_Start();
  setYearShow();
}

void setIncWDay(void) {
  valIncrease(&setClock.WD, 7);
}

void setIncMDay(void) {
  valIncrease(&setClock.Day, 31);
}

void setIncMonth(void) {
  valIncrease(&setClock.Mon, 12);
}

void setIncYear(void) {
  valIncrease(&setClock.Year, 99);
}

void setDecWDay(void) {
  valDecrease(&setClock.WD, 7);
}

void setDecMDay(void) {
  valDecrease(&setClock.Day, 31);
}

void setDecMonth(void) {
  valDecrease(&setClock.Mon, 12);
}

void setDecYear(void) {
  valDecrease(&setClock.Year, 99);
}

void showDNhour(void) {
	dispWDT = DISP_WDT_TIME;

  tube4_t buf;
  es_state_t e_st = ES_GetState();

  if (e_st == stShowDNhours){
    buf.s8.tA = Lighting.name.DayHour / 10;
    buf.s8.tB = Lighting.name.DayHour % 10;
    buf.s8.tD = Lighting.name.NightHour / 10;
    buf.s8.tE = Lighting.name.NightHour % 10;
  } else {
    buf.s8.tA = setLighting.name.DayHour / 10;
    buf.s8.tB = setLighting.name.DayHour % 10;
    buf.s8.tD = setLighting.name.NightHour / 10;
    buf.s8.tE = setLighting.name.NightHour % 10;
  }
  showDigits(buf);
}

void showDNbright(void) {
	dispWDT = DISP_WDT_TIME;

  tube4_t buf;
  es_state_t e_st = ES_GetState();

  if (e_st == stShowDNbright){
    buf.s8.tA = Lighting.name.DayBright / 10;
    buf.s8.tB = Lighting.name.DayBright % 10;
    buf.s8.tD = Lighting.name.NightBright / 10;
    buf.s8.tE = Lighting.name.NightBright % 10;
  } else {
    buf.s8.tA = setLighting.name.DayBright / 10;
    buf.s8.tB = setLighting.name.DayBright % 10;
    buf.s8.tD = setLighting.name.NightBright / 10;
    buf.s8.tE = setLighting.name.NightBright % 10;
  }
  showDigits(buf);
}

void showDNmode(void) {
	dispWDT = DISP_WDT_TIME;

  tube4_t buf;
  es_state_t e_st = ES_GetState();

  if (e_st == stShowDNmode){
    buf.s8.tA = Lighting.name.DayMode / 10;
    buf.s8.tB = Lighting.name.DayMode % 10;
    buf.s8.tD = Lighting.name.NightMode / 10;
    buf.s8.tE = Lighting.name.NightMode % 10;
  } else {
    buf.s8.tA = setLighting.name.DayMode / 10;
    buf.s8.tB = setLighting.name.DayMode % 10;
    buf.s8.tD = setLighting.name.NightMode / 10;
    buf.s8.tE = setLighting.name.NightMode % 10;
  }
  showDigits(buf);
}

void showDNcolour(void) {
	dispWDT = DISP_WDT_TIME;

  tube4_t buf;
  es_state_t e_st = ES_GetState();

  if (e_st == stShowDNcolour){
    buf.s8.tA = Lighting.name.DayColour / 10;
    buf.s8.tB = Lighting.name.DayColour % 10;
    buf.s8.tD = Lighting.name.NightColour / 10;
    buf.s8.tE = Lighting.name.NightColour % 10;
  } else {
    buf.s8.tA = setLighting.name.DayColour / 10;
    buf.s8.tB = setLighting.name.DayColour % 10;
    buf.s8.tD = setLighting.name.NightColour / 10;
    buf.s8.tE = setLighting.name.NightColour % 10;
  }
  showDigits(buf);
}

void setDNbegin(void) {
  IN15_OFF;
  RTOS_SetTask(btnProcess, BTN_TIME_HOLDED, BTN_SCAN_PERIOD);
  setLighting.u64 = Lighting.u64;
  //Flash_Read(&setLighting.u64);
}

void setDNend(void) {
	dispWDT =  0;
  RTOS_SetTask(btnProcess, BTN_TIME_HOLDED, BTN_SCAN_PERIOD);
  Blink_Stop();
  LEDS_OFF;
  Flash_Write(&setLighting.u64);
  Lighting.u64 = setLighting.u64;
  check_DayNight();
}

void setDayHourBegin(void) {
  LEDS_OFF;
  Flag.Blink_1 = 1;
  Flag.Blink_2 = 1;
  Flag.Blink_4 = 0;
  Flag.Blink_5 = 0;
  Blink_Start();
  showDNhour();
}

void setNightHourBegin(void) {
  Flag.Blink_1 = 0;
  Flag.Blink_2 = 0;
  Flag.Blink_4 = 1;
  Flag.Blink_5 = 1;
  Blink_Start();
  showDNhour();
}

void setDayBrightBegin(void) {
  Flag.Blink_1 = 1;
  Flag.Blink_2 = 1;
  Flag.Blink_4 = 0;
  Flag.Blink_5 = 0;
  Blink_Start();
  showDNbright();
}

void setNightBrightBegin(void) {
  Flag.Blink_1 = 0;
  Flag.Blink_2 = 0;
  Flag.Blink_4 = 1;
  Flag.Blink_5 = 1;
  Blink_Start();
  showDNbright();
}

void setDayModeBegin(void) {
  Flag.Blink_1 = 1;
  Flag.Blink_2 = 1;
  Flag.Blink_4 = 0;
  Flag.Blink_5 = 0;
  Blink_Start();
  showDNmode();
}

void setNightModeBegin(void) {
  Flag.Blink_1 = 0;
  Flag.Blink_2 = 0;
  Flag.Blink_4 = 1;
  Flag.Blink_5 = 1;
  Blink_Start();
  showDNmode();
}

void setDayColourBegin(void) {
  Flag.Blink_1 = 1;
  Flag.Blink_2 = 1;
  Flag.Blink_4 = 0;
  Flag.Blink_5 = 0;
  Blink_Start();
  HSV2LED(setLighting.name.DayColour, BrightLevel);
  showDNcolour();
}

void setNightColourBegin(void) {
  Flag.Blink_1 = 0;
  Flag.Blink_2 = 0;
  Flag.Blink_4 = 1;
  Flag.Blink_5 = 1;
  Blink_Start();
  HSV2LED(setLighting.name.NightColour, BrightLevel);
  showDNcolour();
}

void setIncDayHour(void) {
  dvalIncrease(&setLighting.name.DayHour, 23);
}

void setIncDayBright(void) {
  dvalIncrease(&setLighting.name.DayBright, MAX_BRIGHT_LVL);
  tube_BrightLevel(Tube_All, setLighting.name.DayBright);
}

void setIncDayMode(void) {
  dvalIncrease(&setLighting.name.DayMode, MAX_LIGHT_MODE);
}

void setIncDayColour(void) {
  dvalIncrease(&setLighting.name.DayColour, MAX_COLOR_VAL);
  HSV2LED(setLighting.name.DayColour, BrightLevel);
}

void setDecDayHour(void) {
  dvalDecrease(&setLighting.name.DayHour, 23);
}

void setDecDayBright(void) {
  dvalDecrease(&setLighting.name.DayBright, MAX_BRIGHT_LVL);
  tube_BrightLevel(Tube_All, setLighting.name.DayBright);
}

void setDecDayMode(void) {
  dvalDecrease(&setLighting.name.DayMode, MAX_LIGHT_MODE);
}

void setDecDayColour(void) {
  dvalDecrease(&setLighting.name.DayColour, MAX_COLOR_VAL);
  HSV2LED(setLighting.name.DayColour, BrightLevel);
}

void setIncNightHour(void) {
  dvalIncrease(&setLighting.name.NightHour, 23);
}

void setIncNightBright(void) {
  dvalIncrease(&setLighting.name.NightBright, MAX_BRIGHT_LVL);
  tube_BrightLevel(Tube_All, setLighting.name.NightBright);
}

void setIncNightMode(void) {
  dvalIncrease(&setLighting.name.NightMode, MAX_LIGHT_MODE);
}

void setIncNightColour(void) {
  dvalIncrease(&setLighting.name.NightColour, MAX_COLOR_VAL);
  HSV2LED(setLighting.name.NightColour, BrightLevel);
}

void setDecNightHour(void) {
  dvalDecrease(&setLighting.name.NightHour, 23);
}

void setDecNightBright(void) {
  dvalDecrease(&setLighting.name.NightBright, MAX_BRIGHT_LVL);
  tube_BrightLevel(Tube_All, setLighting.name.NightBright);
}

void setDecNightMode(void) {
  dvalDecrease(&setLighting.name.NightMode, MAX_LIGHT_MODE);
}

void setDecNightColour(void) {
  dvalDecrease(&setLighting.name.NightColour, MAX_COLOR_VAL);
  HSV2LED(setLighting.name.NightColour, BrightLevel);
}

void setDNbreak(void) {
  // restore led and tube bright level
  check_DayNight();
}

/**
  * @brief  Increase BCD value.
  * @param  : val, max
  * @retval : None
  */
static void valIncrease(uint8_t * val, uint8_t max) {
  uint8_t bin = 10 * (*val >> 4) + (*val & 0x0f);
  if (bin < max) {
    bin ++;
  } else {
    bin = 0;
  }
  *val = ((bin / 10 ) << 4) | (bin % 10);
}

/**
  * @brief  Decrease BCD value.
  * @param  : value, max
  * @retval : None
  */
static void valDecrease(uint8_t * val, uint8_t max) {
  uint8_t bin = 10 * (*val >> 4) + (*val & 0x0f);
  if (bin > 0) {
    bin --;
  } else {
    bin = max;
  }
  *val = ((bin / 10 ) << 4) | (bin % 10);
}

/**
  * @brief Increase/Decrease decimal value.
  * @param val
  * @param max 
  * @retval : None, change value
  */
static void dvalIncrease(uint8_t * val, uint8_t max) {
  if (*val < max) {
    *val += 1;
  } else {
    *val = 0;
  }
}

static void dvalDecrease(uint8_t * val, uint8_t max) {
  if (*val > 0) {
    *val -= 1;
  } else {
    *val = max;
  }
}
