/**
 * Драйвер модуля LED-индикаторов
 */

#include "stm8s.h"
#include "led.h"

#define GPIO_HIGH(a,b)    a->ODR |= b
#define GPIO_LOW(a,b)     a->ODR &= ~b
#define GPIO_TOGGLE(a,b)  a->ODR ^= b

uint8_t LedDigits[LED_DIGITS_NUM] = {0xff}; // digits to dsplay
uint8_t LedPoint[LED_DIGITS_NUM] = {0, 1, 0, 0, 0, 0, 0, 1}; // dots for digits
/*                                                 1     2     3     4     5     6     7     8 */
static const uint8_t led_num[LED_DIGITS_NUM] = {0x08, 0x04, 0x02, 0x01, 0x10, 0x20, 0x40, 0x80};

static void led_SelectDigit (const uint8_t pos);

/*
 * Output current value to next led
 */
void led_OutputValue(void) {
  static uint8_t ledn = 0;

  /* all off */
  LED_OUT_OFF;

  /* Fire on nex led */
  led_SelectDigit(ledn);

  /* out next value */
  switch (LedDigits[ledn]) {
    case 0:
      LED_OUT_0;
      break;
    case 1:
      LED_OUT_1;
      break;
    case 2:
      LED_OUT_2;
      break;
    case 3:
      LED_OUT_3;
      break;
    case 4:
      LED_OUT_4;
      break;
    case 5:
      LED_OUT_5;
      break;
    case 6:
      LED_OUT_6;
      break;
    case 7:
      LED_OUT_7;
      break;
    case 8:
      LED_OUT_8;
      break;
    case 9:
      LED_OUT_9;
      break;
    case led_A:
      LED_OUT_A;
      break;
    case led_B:
      LED_OUT_B;
      break;
    case led_C:
      LED_OUT_C;
      break;
    case led_D:
      LED_OUT_D;
      break;
    case led_E:
      LED_OUT_E;
      break;
    case led_F:
      LED_OUT_F;
      break;
    case led_H:
      LED_OUT_H;
      break;
    case led_U:
      LED_OUT_U;
      break;
    case led_Plus:
      LED_OUT_PL;
      break;
    case led_Minus:
      LED_OUT_MM;
      break;
    case led_O:
      LED_OUT_O;
      break;
    case led_Off:
      break;
    default:
      LED_OUT_MM;
  }

  if(LedPoint[ledn] != 0) {
    LED_OUT_DP;
  }

  ledn ++;
  if (ledn >= LED_DIGITS_NUM) {
    ledn = 0;
  }
}

/*
 * Select LED Digit.
 * led digits sequence (b - bottom, t - top):
 * t1, t2, t4, t3, b1, b2, b3, b4.
 */
static void led_SelectDigit (const uint8_t pos) {
  uint8_t i;
  uint8_t data = led_num[pos];
  for (i=0; i<8; i++) {
    GPIO_LOW(SPI_PORT, SPI_SCK); // prepare CLK
    if (data & 0x80) { // if msb == 1
      GPIO_HIGH(SPI_PORT, SPI_DATA); // DATA = 1
    } else {
      GPIO_LOW(SPI_PORT, SPI_DATA); // DATA = 0
    }
    GPIO_HIGH(SPI_PORT, SPI_SCK); // shift bit
    data <<= 1;
  }
  /* hack for LATCH */
  GPIO_LOW(SPI_PORT, SPI_DATA);
  GPIO_LOW(SPI_PORT, SPI_SCK);
  GPIO_HIGH(SPI_PORT, SPI_SCK);
}
