#include "clock.h"

/* variables */
rtc_t Clock;
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}
};
static volatile uint8_t dispWDT = 0;

/* function prototypes */
static void Color_RGB(const uint8_t r, const uint8_t g, const uint8_t b);
static void MinusFadeIn(void);
static void MinusFadeOut(void);

/* funcions */
/**
  * @brief  Вывод HEX значений цвета в таймер.
  * @param  : RGB value in range 0x00-0xFF
  * @retval : None
  */
static void Color_RGB(uint8_t r, uint8_t g, uint8_t b) {
  COLOR_R(r);
  COLOR_G(g);
  COLOR_B(b);
}

/**
  * @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) {
//  Blink_Start(); // !!! TODO
  RTC_ReadAll(&Clock);

  if (dispWDT != 0) {
    dispWDT--;
    if (dispWDT == 0) {
      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 = 0;
  static uint8_t off = 20;
  static uint8_t st = 0;

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

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

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

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

  uint8_t hue = bcd2bin(Clock.Sec);// * 6;
  HSV2LED(hue, 255, 63);

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

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

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

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

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

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

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

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

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

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

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

void showHumidity(void) {
  dispWDT = DISP_WDT_TIME;
  in15Percent();

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

void showTemperature(void) {
  dispWDT = DISP_WDT_TIME;
  in15Plus();

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

void showPressure(void) {
  dispWDT = DISP_WDT_TIME;
  in15P();

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

/* Simple function for cyclic show all sensor data */
void showSensorData(void) {
  ES_SetState(stShowSensorData);
  RTOS_DeleteTask(MinusFadeOut);
  Color_RGB(0xFF, 0x12, 0x0); // Nixie color. FF1200 or FF7E00 or FFBF00

  showTemperature();
  tdelay_ms(3000);

  showHumidity();
  tdelay_ms(3000);

  showPressure();
  tdelay_ms(2500);

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