/*
   Project:       Basic IR Tester
   Description:   Displays the "key name", decoded code,
                  protocol type, and raw data from the
                  Wokwi NEC IR remote
   Creation date: 3/30/23
   Author:        AnonEngineering

   Inspired by the Wokwi example
   https://wokwi.com/projects/298934082074575369
   and
   https://forum.arduino.cc/t/reversed-byte-order/699873/6

   https://github.com/Arduino-IRremote/Arduino-IRremote#quick-comparison-of-5-arduino-ir-receiving-libraries

   License: https://en.wikipedia.org/wiki/Beerware

   needs update
*/

#include <IRremote.hpp>
#include <LiquidCrystal_I2C.h>

const int RX_PIN = 2;
const int LED_PIN = 13;
const int MAX_KEYS = 20;
const byte KEY_CODES[MAX_KEYS] = {
  /* see https://docs.wokwi.com/parts/wokwi-ir-remote */
  162, 226, 34, 2, 194,
  224, 168, 144, 152, 176,
  104, 48, 24, 122, 16,
  56, 90, 66, 74, 82
};
const char KEY_NAMES[][MAX_KEYS] = {
  /* see remote */
  "Power", "Menu", "Test", "Plus", "Back",
  "Prev", "Play", "Next", "Minus", "C",
  "0", "1", "2", "3", "4",
  "5", "6", "7", "8", "9"
};

IRrecv receiver(RX_PIN);
LiquidCrystal_I2C lcd(0x27, 20, 4);

char* getKeyName()  {
  bool isCodeFound = false;
  char* keyName;

  for (int keyIdx = 0; keyIdx < MAX_KEYS; keyIdx++) {
    if (KEY_CODES[keyIdx] == receiver.decodedIRData.command) {
    //if (KEY_CODES[keyIdx] == 999) {  // for test
      keyName = KEY_NAMES[keyIdx];
      isCodeFound = true;
    }
  }
  if (!isCodeFound)  {
    keyName = "Unknown";
  }
  return keyName;
}

void showKeyData(char* keyText) {
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Key : ");
  lcd.print(keyText);
  lcd.setCursor(0, 1);
  lcd.print("Code: ");
  lcd.print(receiver.decodedIRData.command);
  lcd.setCursor(0, 2);
  lcd.print("Type: ");
  lcd.print(receiver.getProtocolString());
  lcd.setCursor(0, 3);
  lcd.print("Data: ");
  //lcd.print(receiver.decodedIRData.decodedRawData, HEX);  // little Endian
  lcd.print(toOtherEndian(receiver.decodedIRData.decodedRawData), HEX);
}

uint32_t toOtherEndian(uint32_t oneEndian) {
  uint32_t otherEndian    = 0x0;

  otherEndian = (oneEndian & 0xFF) << 24;          // shift 4th byte to 1st
  otherEndian |= ((oneEndian >> 8) & 0xFF) << 16;  // or and shift 3rd byte
  otherEndian |= ((oneEndian >> 16) & 0xFF) << 8;  // or and shift 2nd byte
  otherEndian |= ((oneEndian >> 24) & 0xFF);       // or and shift 1st byte to 4th
  return otherEndian;
}

void showSplash() {
  lcd.setCursor(3, 0);
  lcd.print("IR Tester v1.00");
  // Serial.println(VERSION_IRREMOTE);
  lcd.setCursor(4, 2);
  lcd.print("Press any key");
  lcd.setCursor(6, 3);
  lcd.print("to begin");
}

void setup()  {
  Serial.begin(9600);
  lcd.begin(20, 4);
  lcd.backlight();
  pinMode(LED_PIN, OUTPUT);
  receiver.enableIRIn(); // start the receiver
  showSplash();
}

void loop() {
  if (receiver.decode()) {      // we received IR
    Serial.println(receiver.decodedIRData.command); // for test
    digitalWrite(LED_PIN, HIGH);
    showKeyData(getKeyName());  // get key name, show key data
    receiver.resume();          // prepare for the next IR
  } else {
    digitalWrite(LED_PIN, LOW);
  }
}