// Please note that automatic in-circuit verification is not working yet ;)
#include <stdint.h>

// Expected outputs (7 bits as hex values)
uint8_t expected[32] = {0x7D, 0x77, 0x1F, 0x0D, 0x3D, 0x4F, 0x47, 0x5E, 0x17, 0x06, 0x3C, 0x57, 0x0E, 0x54, 0x15, 0x7E, 0x67, 0x73, 0x05, 0x5B, 0x0F, 0x3E, 0x2A, 0x2B, 0x37, 0x3B, 0x6C, 0x4E, 0x12, 0x78, 0x40, 0x08};

void setup() {
  bool tests_passed = true;
  Serial.begin(230400);

  // initialize digital pin LED_BUILTIN as an output
  // note that pins 1 and 0 are used for Serial (UART) and should not be used
  // as GPIO pins
  pinMode(14, OUTPUT); // input a
  pinMode(15, OUTPUT); // input b
  pinMode(2, OUTPUT); // input c
  pinMode(3, OUTPUT); // input d
  pinMode(4, OUTPUT); // input e
  // TODO: - add one LED to signal test is running
  //       - add another two LEDs to signal if 
  //         ALL tests have passed or ANY test has failed

  pinMode(6, INPUT); // output A
  pinMode(7, INPUT); // output B
  pinMode(8, INPUT); // output C
  pinMode(9, INPUT); // output D
  pinMode(10, INPUT); // output E
  pinMode(11, INPUT); // output F
  pinMode(12, INPUT); // output G

  Serial.println("Testing all input combinations.");

  /* cycle from '@' / 0x40 to '_' / 0x5F */
  for(uint8_t character = '@'; character <= '_'; character++)
  {
    set_character(character);

    // wait some time before checking outputs
    delay(300);

    tests_passed &= verify_outputs(character);

    delay(400);
  }

  Serial.println();
  if(tests_passed)
  {
    Serial.println("[PASSED]");
  }
  else
  {
    Serial.println("[FAILED]");
  }
}

void set_character(uint8_t character)
{
  // set logic design inputs at Arduino's output pins
  digitalWrite(15, character & (1 << 0));
  digitalWrite(14, character & (1 << 1));
  digitalWrite(2, character & (1 << 2));
  digitalWrite(3, character & (1 << 3));
  digitalWrite(4, character & (1 << 4));

  Serial.print("Wrote character '");
  Serial.write(character);
  Serial.println("'");
}

bool verify_outputs(uint8_t character)
{
  // read value from logic design outputs at Arduino's input pins
 
  uint8_t outputs = 0; 
  outputs |= digitalRead(6);
  outputs <<= 1;
  outputs |= digitalRead(7);
  outputs <<= 1;
  outputs |= digitalRead(8);
  outputs <<= 1;
  outputs |= digitalRead(9);
  outputs <<= 1;
  outputs |= digitalRead(10);
  outputs <<= 1;
  outputs |= digitalRead(11);
  outputs <<= 1;
  outputs |= digitalRead(12);
  // 8 bit variable; so MSB is not set
  Serial.print("  Read back ");

  // print single bits to make sure that no preceeding zeros are cut off
  //Serial.print(outputs, BIN);
  Serial.print((outputs >> 6) & 1, BIN);
  Serial.print((outputs >> 5) & 1, BIN);
  Serial.print((outputs >> 4) & 1, BIN);
  Serial.print((outputs >> 3) & 1, BIN);
  Serial.print((outputs >> 2) & 1, BIN);
  Serial.print((outputs >> 1) & 1, BIN);
  Serial.print((outputs >> 0) & 1, BIN);

  Serial.print("b / 0x");
  Serial.print(outputs, HEX);

  Serial.print(" == 0x");
  Serial.print(expected[character & 0x1F], HEX);

  if( outputs == expected[character & 0x1F] )
  {
    Serial.println("? [PASS]");
    return true;
  }
  else
  {
    Serial.println("? [FAIL]");
    return false;
  }
}

void loop() {
  /* no need to loop */
}