/*
  Minimal VFD / HV5812 demo for the Single-AA NiMH VFD Clock
  -----------------------------------------------------------
  Displays "10-18-47". Separators are segment G only.

  Pins used:
    PB3 / D11 = HV5812 DATA
    PB5 / D13 = HV5812 CLOCK
    PB2 / D10 = HV5812 STROBE / LATCH
    PB1 / D9  = HV5812 BLANK

  IMPORTANT:
    SEG_* and GRID_BITS[] are example mappings.
    Adjust them to match your own HV5812 wiring.
*/

#include <Arduino.h>

#define HV_DATA    11
#define HV_CLOCK   13
#define HV_LATCH   10
#define HV_BLANK    9

const uint32_t SEG_A  = 1UL << 0;
const uint32_t SEG_B  = 1UL << 1;
const uint32_t SEG_C  = 1UL << 2;
const uint32_t SEG_D  = 1UL << 3;
const uint32_t SEG_E  = 1UL << 4;
const uint32_t SEG_F  = 1UL << 5;
const uint32_t SEG_G  = 1UL << 6;
const uint32_t SEG_DP = 1UL << 7;

const uint32_t GRID_BITS[8] = {
  1UL << 8,
  1UL << 9,
  1UL << 10,
  1UL << 11,
  1UL << 12,
  1UL << 13,
  1UL << 14,
  1UL << 15
};

const char DISPLAY_TEXT[8] = { '1', '0', '-', '1', '8', '-', '4', '7' };

uint32_t segmentsForChar(char c)
{
  switch (c)
  {
    case '0': return SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F;
    case '1': return SEG_B | SEG_C;
    case '2': return SEG_A | SEG_B | SEG_D | SEG_E | SEG_G;
    case '3': return SEG_A | SEG_B | SEG_C | SEG_D | SEG_G;
    case '4': return SEG_F | SEG_G | SEG_B | SEG_C;
    case '5': return SEG_A | SEG_F | SEG_G | SEG_C | SEG_D;
    case '6': return SEG_A | SEG_F | SEG_E | SEG_D | SEG_C | SEG_G;
    case '7': return SEG_A | SEG_B | SEG_C;
    case '8': return SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G;
    case '9': return SEG_A | SEG_B | SEG_C | SEG_D | SEG_F | SEG_G;
    case '-': return SEG_G;
    default:  return 0;
  }
}

void hvLatch()
{
  digitalWrite(HV_LATCH, HIGH);
  delayMicroseconds(1);
  digitalWrite(HV_LATCH, LOW);
}

void hvSend32(uint32_t data)
{
  for (int8_t i = 31; i >= 0; i--)
  {
    digitalWrite(HV_CLOCK, LOW);
    digitalWrite(HV_DATA, (data & (1UL << i)) ? HIGH : LOW);
    digitalWrite(HV_CLOCK, HIGH);
  }
  digitalWrite(HV_CLOCK, LOW);
}

void hvAllOff()
{
  digitalWrite(HV_BLANK, HIGH);
  hvSend32(0);
  hvLatch();
}

void showDigit(uint8_t pos, uint32_t seg)
{
  uint32_t word = seg | GRID_BITS[pos];

  digitalWrite(HV_BLANK, HIGH);
  delayMicroseconds(20);

  hvSend32(word);
  hvLatch();

  delayMicroseconds(10);
  digitalWrite(HV_BLANK, LOW);
}

void setup()
{
  pinMode(HV_DATA, OUTPUT);
  pinMode(HV_CLOCK, OUTPUT);
  pinMode(HV_LATCH, OUTPUT);
  pinMode(HV_BLANK, OUTPUT);

  digitalWrite(HV_DATA, LOW);
  digitalWrite(HV_CLOCK, LOW);
  digitalWrite(HV_LATCH, LOW);

  digitalWrite(HV_BLANK, HIGH);
  delay(50);

  hvAllOff();
}

void loop()
{
  for (uint8_t pos = 0; pos < 8; pos++)
  {
    showDigit(pos, segmentsForChar(DISPLAY_TEXT[pos]));
    delayMicroseconds(900);

    digitalWrite(HV_BLANK, HIGH);
    delayMicroseconds(40);
  }
}
