/*
    4x5 Macropad

    if you are using the Numpad arrangement, use the numpad firmware
*/
#ifndef USER_USB_RAM
#error "Require USB RAM. Go Tools > USB Setting and pick the 2nd option in the dropdown list"
#endif

#include "src/userUsbHidMediaKeyboard/USBHIDMediaKeyboard.h"

////////////// HARDWARE CONFIG //////////
//LED OUTPUT
#define LED_OUT 14


//SCAN LINES
//Input Pins. Pull High (When reading is low = pressed)
#define COL_1 15
#define COL_2 16
#define COL_3 17
#define COL_4 11

//Output Pins. Set to low to scan that line
#define ROW_1 32
#define ROW_2 31
#define ROW_3 30
#define ROW_4 34
#define ROW_5 33

///////////////// RUNTIME ///////////////
const int readColSeq[4] = {COL_4, COL_3, COL_2, COL_1};
const int scanRowSeq[5] = {ROW_5, ROW_4, ROW_3, ROW_2, ROW_1};
bool funcMode = false; //If Fn key is hold (Default func key: [0,1]

//The layout is identical to the keypad when view from the front side (i.e. not the MCU side)
int keyPressState[5][4] = {
  {false,false,false,false},
  {false,false,false,false},
  {false,false,false,false},
  {false,false,false,false},
  {false,false,false,false},
};

///////////////// FUNC PROTOTYPES ///////////////
void HandleKeyPressEvents(int row, int col, bool previousState, bool currentState);
void PressNumericAsKeypad(char in);
void UpdateLEDState();


void setup() {
  delay(300);
  USBInit();
  //LED
  pinMode(LED_OUT, OUTPUT);

  //Sensing lines
  pinMode(COL_1, INPUT);
  pinMode(COL_2, INPUT);
  pinMode(COL_3, INPUT);
  pinMode(COL_4, INPUT);

  //Select lines
  pinMode(ROW_1, OUTPUT);
  pinMode(ROW_2, OUTPUT);
  pinMode(ROW_3, OUTPUT);
  pinMode(ROW_4, OUTPUT);
  pinMode(ROW_5, OUTPUT);

  //Set all lines to high (active low)
  digitalWrite(ROW_1, HIGH);
  digitalWrite(ROW_2, HIGH);
  digitalWrite(ROW_3, HIGH);
  digitalWrite(ROW_4, HIGH);
  digitalWrite(ROW_5, HIGH);
}

//Activate the row to be scanned
void setScanningRow(int rowNumber) {
  //Hardcoding the sequence save some RAM and faster :)
  (rowNumber==0)?digitalWrite(scanRowSeq[0], LOW):digitalWrite(scanRowSeq[0], HIGH);
  (rowNumber==1)?digitalWrite(scanRowSeq[1], LOW):digitalWrite(scanRowSeq[1], HIGH);
  (rowNumber==2)?digitalWrite(scanRowSeq[2], LOW):digitalWrite(scanRowSeq[2], HIGH);
  (rowNumber==3)?digitalWrite(scanRowSeq[3], LOW):digitalWrite(scanRowSeq[3], HIGH);
  (rowNumber==4)?digitalWrite(scanRowSeq[4], LOW):digitalWrite(scanRowSeq[4], HIGH);
  
  //Disable all and enable the target one not sure why it is not working
  
  //Activate the target row
  //int targetRowPin = scanRowSeq[rowNumber];
  //digitalWrite(targetRowPin, LOW);
  //delay(50);  //naive debouncing
}

//Read and return the key press status of a given column
//Notes: keys are low activated. When not press, the keys are pull HIGH
bool readKeyPress(int colNumber){
  int readPin = readColSeq[colNumber];
  return (digitalRead(readPin) == 0);
}


//Read all the switches states and update to the global array
void updateSwitchStatus() {
  for (int i = 0; i < 5; i++) {
    //For each of the row, read each of the col switch
    setScanningRow(i);
    for (int j = 0; j < 4; j++) {
      bool isKeyDown = readKeyPress(j);
      bool prevState = keyPressState[i][j];
      if (isKeyDown != prevState){
        //Trigger on change events
        
        HandleKeyPressEvents(i,j,prevState,isKeyDown);
        delay(10); //resp time
      }
      keyPressState[i][j] = isKeyDown;
    }
  }
}

//Update the LED status
void UpdateLEDState(){
  if (funcMode) {
    digitalWrite(LED_OUT, HIGH);
  } else {
    digitalWrite(LED_OUT, LOW);
  }
}

void loop() {
  //Read the mode of the keyboard
  updateSwitchStatus();
  
  //Update the NumLock LED
  UpdateLEDState();
}
