// https://forum.arduino.cc/t/hd44780-decoder/1143429
// https://wokwi.com/projects/369059701985585153

// LCD2004 Tiny Pacman on Wokwi

#include <LiquidCrystal.h>

LiquidCrystal lcd(12, 11, 27, 29, 31, 33);

uint8_t pacman[8] = {
  0b00000,
  0b00000,
  0b01110,
  0b11011,
  0b11111,
  0b01110,
  0b00000,
  0b00000
};

uint8_t pacmanOpen[] = {
  0b00000,
  0b00000,
  0b01110,
  0b11011,
  0b11100,
  0b01110,
  0b00000,
  0b00000
};

uint8_t dot[] = {
  0b00000,
  0b00000,
  0b00000,
  0b00110,
  0b00110,
  0b00000,
  0b00000,
  0b00000
};

void setup() {
  lcd.createChar(1, pacman);
  lcd.createChar(2, dot);
  lcd.begin(20, 4);
  lcd.setCursor(3, 0);
  lcd.print("wokwi-lcd2004");
  lcd.setCursor(2, 2);
  lcd.print("4 lines, 20 cols");

  decoderSetup();
}

void loop() {
  for (int i = 3; i < 16; i++) {
    lcd.setCursor(i, 3);
    lcd.print("\1");
    for (int j = i + 1; j < 16; j++) {
      lcd.setCursor(j, 3);
      lcd.print("\2");
    }
    lcd.createChar(1, pacman);
    delay(200);
    lcd.createChar(1, pacmanOpen);
    delay(200);
    lcd.setCursor(i, 3);
    lcd.print(" ");
  }
  delay(1000);

  dataSpill();
}

// HD44780 DECODER, WRITTEN BY LEONARDO MARTINS 19/01/2019

# define RS_PIN 23 // RS (Register Select) pin
// # define RW_PIN 11 // RW (Read/Write) pin
# define EN_PIN 21 // EN (Enable) pin
# define DATA_PINS {37, 39, 41, 43} // Data pins D4, D5, D6 and D7

bool previousEn = LOW; // Previous state of the EN pin
volatile byte data = 0; // Storage for data
volatile bool highBits = true; // Flag to indicate if we are reading high or low bits
volatile bool dataReady = false; // Flag to indicate when data is ready to read

void decoderSetup() {
  Serial.begin(9600); // Start serial communication

  // Set control pins as input
  pinMode(RS_PIN, INPUT);
//  pinMode(RW_PIN, INPUT);
  pinMode(EN_PIN, INPUT);

  // Set data pins as input
  int dataPins[] = DATA_PINS;
  for (int i = 0; i < 4; i++) {
    pinMode(dataPins[i], INPUT_PULLUP);
  }

  // Setup the interrupt
  attachInterrupt(digitalPinToInterrupt(EN_PIN), readData, FALLING);

// Serial.println(digitalPinToInterrupt(EN_PIN));
//  for (; ; );
}

void loopTEST() {
  if (dataReady) {
    // Print the corresponding ASCII character to the Serial
    Serial.print(data);
    dataReady = false; // Reset the data ready flag
  }
}

volatile char dataBuffer[128];
volatile byte charCount;

void readData() {
  // Check if it's a write operation (RW == 0) and data is being sent (RS == 1)
  if (digitalRead(RS_PIN) == HIGH) {
    // Read the 4-bit part of data
    int dataPins[] = DATA_PINS;
    byte part = 0;
    for (int i = 0; i < 4; i++) {
      part |= digitalRead(dataPins[i]) << i;
    }

    if (highBits) {
      // This is the high bits part
      data = part << 4;
    } else {
      // This is the low bits part
      data |= part;
      dataReady = true; // Indicate that data is ready to read

      dataBuffer[charCount] = data;
      charCount++;
    }

    // Flip the highBits flag
    highBits = !highBits;
  }
}

void dataSpill()
{
  if (!dataReady)
    return;

  noInterrupts();
  int myCount = charCount;
  charCount = 0;
  dataReady = false;
  interrupts();

  Serial.print("data ");

  for (unsigned char tt = 0; tt < myCount; tt++) {
//    Serial.print("0x");
    Serial.print((byte) dataBuffer[tt], HEX);
    Serial.print(" ");
  }

  Serial.println(".");
}