  /*######################################################################################  
 ##########################################################################################
## ######################################################## ####################          ##
## ########  #######   ###      ## ########    ######   ### ####### ########  ###      ## ##
## ###    ## ###    #  ####    ### ###    ##  ###   ##  ### ###     ###    ## ####    ### ##
## ###   ### ###    ## #######  ## ###   ### ###     ## ### ###     ###   ### #######  ## ##
## #######   ######### ### ###  ## ########  ###     ## ### ####### #######   ### ###  ## ##
## ###   ### ###    ## ###  ##  ## ###   ### ###     ## ### ###     ###   ### ###  ##  ## ##
## ###    ## ###    ## ###      ## ###    ##  ###   ##  ### ###     ###    ## ###      ## ##
## ###    ## ###    ## ###      ## ########    ######   ### ####### ###    ## ###      ## ##
## #################################################### ### ############################# ##
############################################################################################
##### CURRENT / ramboTerm 2.2_ino / 04-04-2020                                            ##
##### ramboTerm: CLI Tool-set for fire alarm interfacing and communications.              ##
##### Matthew Stroble / matthewstroble@gmail.com / firealarmhackery.com                   ##
 ##                                                                                      ##
  ######################################################################################*/


#include <SPI.h>
#include <SD.h>
#include "Wire.h"
#include "EEPROM.h"

#include "rTerm.h"

// -- SYS VARS --
  int rTerm::opMode;
  int rTerm::smsEN;
  int rTerm::loopIndex;
  
// -- FCP VARS --
  int rTerm::fcpEN;
  int rTerm::lineIndex;
  int rTerm::logIndexFCP;
  long rTerm::fcpBaud;
  int rTerm::fcpConfig;
  char rTerm::configText[4];
  int rTerm::smsFCP;
  
// -- GSM VARS --
  char _csq[3];
  int rTerm::procIndexFCP;
  int rTerm::procIndexCID;
  int rTerm::destIndex;
  char rTerm::telNum[12];
  
// -- CID Vars --
  int rTerm::cidEN;
  int rTerm::logIndexCID;
  int rTerm::smsCID;
  
// -- Initialize the rt (rt) Class -- 
  rTerm::rTerm(){
    // Moved initializing stuff to rTerm::rtInit();
  }

  void rTerm::rtInit(){
    // -- SET DEFAULT VALS FOR VARS --
      EEPROM.get(1, rTerm::opMode); delay(10);
      EEPROM.get(4, rTerm::destIndex); delay(10);
      EEPROM.get(7, rTerm::smsEN); delay(10);
      EEPROM.get(10, rTerm::fcpEN); delay(10);
      EEPROM.get(13, rTerm::cidEN); delay(10);
      EEPROM.get(rTerm::destIndex, rTerm::telNum); delay(10);
      EEPROM.get(15, rTerm::lineIndex);
      EEPROM.get(180, rTerm::logIndexFCP); delay(10);
      EEPROM.get(183, rTerm::procIndexFCP); delay(10);
      EEPROM.get(186, rTerm::logIndexCID); delay(10);
      EEPROM.get(189, rTerm::procIndexCID); delay(10);
      EEPROM.get(192, rTerm::smsFCP); delay(10);
      EEPROM.get(195, rTerm::smsCID); delay(10);
      rTerm::loopIndex = 0; delay(10);
      SD.mkdir("/cid/"); delay(20);
      SD.mkdir("/fcp/"); delay(20);
      
  }
bool rTerm::memReset(){
  
  Serial.println(F("-- Resetting EEPROM VALS to default --"));
  
  long wipeTime = millis();
  
  // -- WIPE EEPROM FIRST --
    for(int i=0; i<2056; i++){
      EEPROM.update(i, 0xFF);
    }

    wipeTime = millis()-wipeTime;

  delay(100);
  
  long writeTime = millis();
  uint8_t xc;
    
  // -- DEFAULT SYS VARS --
    if(!EEPROM.put(1, int(1)) == NULL){ xc++; }                                // opMode                                            / INT
    if(!EEPROM.put(4, int(120)) == NULL){ xc++; }                   // destIndex -- byte address of char telNum[12]      / INT
    if(!EEPROM.put(7, int(1)) == NULL){ xc++; }                     // smsEN                                             / INT
    if(!EEPROM.put(10, int(1)) == NULL){ xc++; }                    // cidEN                                             / INT
    if(!EEPROM.put(13, int(1)) == NULL){ xc++; }                    // fcpEN                                             / INT
    if(!EEPROM.put(15, int(4)) == NULL){ xc++; }                    // lineIndex / max LF chars per fcpEvent             / INT
    //if(!EEPROM.put(30, int(1)) == NULL){ xc++; }                    // fcpBaud                                         / INT
    //if(!EEPROM.put(40, int(1)) == NULL){ xc++; }                    // fcpConfig                                       / INT
    //if(!EEPROM.put(50, int(1)) == NULL){ xc++; }                    // textConfig                                      / INT
   
  // -- CMD FLAG CHARS --
    if(!EEPROM.put(80, "!#$<>~%&*") == NULL){ xc++; }               // CMD FLAG / SYS Commands                           / CHAR[10]
        
  // -- SMS DEST TELNUM / CHAR[11] --
    if(!EEPROM.put(120, "5551234567") == NULL){ xc++; }             // telNum index 0 / ADMIN RIGHTS                     / CHAR[11]
    if(!EEPROM.put(131, "5551234567") == NULL){ xc++; }             // telNum index 1 / BACKUP                           / CHAR[11]
    if(!EEPROM.put(142, "5551234567") == NULL){ xc++; }             // telNum index 2 / Variable                         / CHAR[11]

    if(!EEPROM.put(180, int(1)) == NULL){ xc++; }                   // logIndexFCP                                       / INT
    if(!EEPROM.put(183, int(1)) == NULL){ xc++; }                   // procIndexFCP                                      / INT
    if(!EEPROM.put(186, int(1)) == NULL){ xc++; }                   // logIndexCID                                       / INT
    if(!EEPROM.put(189, int(1)) == NULL){ xc++; }                   // procIndexCID                                      / INT
    if(!EEPROM.put(192, int(0)) == NULL){ xc++; }                   // smsFCP                                            / INT
    if(!EEPROM.put(195, int(0)) == NULL){ xc++; }                   // smsCID                                            / INT
    
  // -- SERIAL BAUD / LONG --
    if(!EEPROM.put(300, long(1200)) == NULL){ xc++; }               // BAUD RATE:    1200 bps                            / LONG
    if(!EEPROM.put(305, long(2400)) == NULL){ xc++; }               // BAUD RATE:    2400 bps                            / LONG
    if(!EEPROM.put(310, long(4800)) == NULL){ xc++; }               // BAUD RATE:    4800 bps                            / LONG
    if(!EEPROM.put(315, long(9600)) == NULL){ xc++; }               // BAUD RATE:    9600 bps                            / LONG
    if(!EEPROM.put(320, long(19200)) == NULL){ xc++; }              // BAUD RATE:   19200 bps                            / LONG
    if(!EEPROM.put(325, long(38400)) == NULL){ xc++; }              // BAUD RATE:   38400 bps                            / LONG
    if(!EEPROM.put(330, long(56800)) == NULL){ xc++; }              // BAUD RATE:   56800 bps                            / LONG
    if(!EEPROM.put(335, long(115200)) == NULL){ xc++; }             // BAUD RATE:  115200 bps                            / LONG

  // -- SERIAL CONFIG RAW VAL / PARITY: NONE --
    if(!EEPROM.put(340, int(0)) == NULL){ xc++; }                   // DATA: 5 / PARITY: NONE / STOP: 1                  / INT
    if(!EEPROM.put(345, int(2)) == NULL){ xc++; }                   // DATA: 6 / PARITY: NONE / STOP: 1                  / INT
    if(!EEPROM.put(350, int(4)) == NULL){ xc++; }                   // DATA: 7 / PARITY: NONE / STOP: 1                  / INT
    if(!EEPROM.put(355, int(6)) == NULL){ xc++; }                   // DATA: 8 / PARITY: NONE / STOP: 1                  / INT
    if(!EEPROM.put(360, int(8)) == NULL){ xc++; }                   // DATA: 5 / PARITY: NONE / STOP: 2                  / INT
    if(!EEPROM.put(365, int(10)) == NULL){ xc++; }                  // DATA: 6 / PARITY: NONE / STOP: 2                  / INT
    if(!EEPROM.put(370, int(12)) == NULL){ xc++; }                  // DATA: 7 / PARITY: NONE / STOP: 2                  / INT
    if(!EEPROM.put(375, int(14)) == NULL){ xc++; }                  // DATA: 8 / PARITY: NONE / STOP: 2                  / INT
  
  // -- SERIAL CONFIG RAW VAL / PARITY: EVEN --    
    if(!EEPROM.put(380, int(32)) == NULL){ xc++; }                  // DATA: 5 / PARITY: ODD / STOP: 1                  / INT
    if(!EEPROM.put(385, int(34)) == NULL){ xc++; }                  // DATA: 6 / PARITY: ODD / STOP: 1                  / INT
    if(!EEPROM.put(390, int(36)) == NULL){ xc++; }                  // DATA: 7 / PARITY: ODD / STOP: 1                  / INT
    if(!EEPROM.put(395, int(38)) == NULL){ xc++; }                  // DATA: 8 / PARITY: ODD / STOP: 1                  / INT
    if(!EEPROM.put(400, int(40)) == NULL){ xc++; }                  // DATA: 5 / PARITY: ODD / STOP: 2                  / INT
    if(!EEPROM.put(405, int(42)) == NULL){ xc++; }                  // DATA: 6 / PARITY: ODD / STOP: 2                  / INT
    if(!EEPROM.put(410, int(44)) == NULL){ xc++; }                  // DATA: 7 / PARITY: ODD / STOP: 2                  / INT
    if(!EEPROM.put(415, int(46)) == NULL){ xc++; }                  // DATA: 8 / PARITY: ODD / STOP: 2                  / INT

  // -- SERIAL CONFIG RAW VAL / PARITY: NONE --    
    if(!EEPROM.put(420, int(48)) == NULL){ xc++; }                  // DATA: 5 / PARITY: EVEN / STOP: 1                  / INT
    if(!EEPROM.put(425, int(50)) == NULL){ xc++; }                  // DATA: 6 / PARITY: EVEN / STOP: 1                  / INT
    if(!EEPROM.put(430, int(52)) == NULL){ xc++; }                  // DATA: 7 / PARITY: EVEN / STOP: 1                  / INT
    if(!EEPROM.put(435, int(54)) == NULL){ xc++; }                  // DATA: 8 / PARITY: EVEN / STOP: 1                  / INT
    if(!EEPROM.put(440, int(56)) == NULL){ xc++; }                  // DATA: 5 / PARITY: EVEN / STOP: 2                  / INT
    if(!EEPROM.put(445, int(58)) == NULL){ xc++; }                  // DATA: 6 / PARITY: EVEN / STOP: 2                  / INT
    if(!EEPROM.put(450, int(60)) == NULL){ xc++; }                  // DATA: 7 / PARITY: EVEN / STOP: 2                  / INT
    if(!EEPROM.put(455, int(62)) == NULL){ xc++; }                  // DATA: 8 / PARITY: EVEN / STOP: 2                  / INT
  
  // -- SERIAL CONIG TXT / PARITY: NONE --
    if(!EEPROM.put(460, "5N1") == NULL){ xc++; }                     // SERIAL CONFIG TXT                                 / CHAR[4]
    if(!EEPROM.put(465, "6N1") == NULL){ xc++; }                     // SERIAL CONFIG TXT                                 / CHAR[4]
    if(!EEPROM.put(470, "7N1") == NULL){ xc++; }                     // SERIAL CONFIG TXT                                 / CHAR[4]
    if(!EEPROM.put(475, "8N1") == NULL){ xc++; }                     // SERIAL CONFIG TXT                                 / CHAR[4]
    if(!EEPROM.put(480, "5N2") == NULL){ xc++; }                     // SERIAL CONFIG TXT                                 / CHAR[4]
    if(!EEPROM.put(485, "6N2") == NULL){ xc++; }                     // SERIAL CONFIG TXT                                 / CHAR[4]
    if(!EEPROM.put(490, "7N2") == NULL){ xc++; }                     // SERIAL CONFIG TXT                                 / CHAR[4]
    if(!EEPROM.put(495, "8N2") == NULL){ xc++; }                     // SERIAL CONFIG TXT                                 / CHAR[4]
   
   // -- SERIAL CONIG TXT / PARITY: EVEN -- 
    if(!EEPROM.put(500, "5E1") == NULL){ xc++; }                     // SERIAL CONFIG TXT                                 / CHAR[4]
    if(!EEPROM.put(505, "6E1") == NULL){ xc++; }                     // SERIAL CONFIG TXT                                 / CHAR[4]
    if(!EEPROM.put(510, "7E1") == NULL){ xc++; }                     // SERIAL CONFIG TXT                                 / CHAR[4]
    if(!EEPROM.put(515, "8E1") == NULL){ xc++; }                     // SERIAL CONFIG TXT                                 / CHAR[4]
    if(!EEPROM.put(520, "5E2") == NULL){ xc++; }                     // SERIAL CONFIG TXT                                 / CHAR[4]
    if(!EEPROM.put(525, "6E2") == NULL){ xc++; }                     // SERIAL CONFIG TXT                                 / CHAR[4]
    if(!EEPROM.put(530, "7E2") == NULL){ xc++; }                     // SERIAL CONFIG TXT                                 / CHAR[4]
    if(!EEPROM.put(535, "8E2") == NULL){ xc++; }                     // SERIAL CONFIG TXT                                 / CHAR[4]

  // -- SERIAL CONIG TXT / PARITY: ODD --
    if(!EEPROM.put(540, "5O1") == NULL){ xc++; }                     // SERIAL CONFIG TXT                                 / CHAR[4]
    if(!EEPROM.put(545, "6O1") == NULL){ xc++; }                     // SERIAL CONFIG TXT                                 / CHAR[4]
    if(!EEPROM.put(550, "7O1") == NULL){ xc++; }                     // SERIAL CONFIG TXT                                 / CHAR[4]
    if(!EEPROM.put(555, "8O1") == NULL){ xc++; }                     // SERIAL CONFIG TXT                                 / CHAR[4]
    if(!EEPROM.put(560, "5O2") == NULL){ xc++; }                     // SERIAL CONFIG TXT                                 / CHAR[4]
    if(!EEPROM.put(565, "6O2") == NULL){ xc++; }                     // SERIAL CONFIG TXT                                 / CHAR[4]
    if(!EEPROM.put(570, "7O2") == NULL){ xc++; }                     // SERIAL CONFIG TXT                                 / CHAR[4]
    if(!EEPROM.put(575, "8O2") == NULL){ xc++; }                     // SERIAL CONFIG TXT                                 / CHAR[4]

    writeTime = millis()-writeTime;
    
    Serial.println(F(" -- Done"));
    Serial.print(F("    ")); Serial.print(wipeTime); Serial.println(F(" ms elapsed during wipe -- "));
    Serial.print(F("    ")); Serial.print(xc); Serial.print(F(" vals updated / ")); Serial.print(writeTime); Serial.println(F(" ms elapsed -- "));
    
    if(xc){ return true; }else{ return false; }
    
}

void rTerm::memRead(){

  Serial.println(F("Dumping EEPROM ADDRESS 0-1023"));
  
  long dumpTime=millis();
  int c = 0;

  for(int i=1; i<1024; i++){
    
    Serial.print(F("  |  "));
    Serial.print(i); 
    
    if(i < 10){
      Serial.print(F(":    "));
    }else if(i < 100){
      Serial.print(F(":   "));
    }else if(i < 1000){
      Serial.print(F(":  "));
    }else{
      Serial.print(F(": "));
    }
    
    Serial.print(EEPROM.read(i)); 
    if((int)EEPROM.read(i) < 10){
      Serial.print(F("    "));
    }else if((int)EEPROM.read(i) < 100){
      Serial.print(F("   "));
    }else{
      Serial.print(F("  "));
    }
    
    if(i >= 1022){
      c = i;
      dumpTime = millis()-dumpTime;
    }else if(c > 2){
      Serial.println(F("  |  "));
      c=0;
    }else{
      c++;
    }
    
  }
  
  Serial.println(F(" -- DONE"));
  Serial.print(F("    ")); Serial.print(c); Serial.println(F(" bytes read"));
  Serial.print(F("    ")); Serial.print(dumpTime); Serial.println(F("ms elapsed --"));
  Serial.println();
  
}

// -- paramReset / Write the default data to the EEPROM  and flush the logs --
  void rTerm::paramReset(){
    
     rTerm::flushLogsCID(); delay(100);
     rTerm::flushLogsFCP(); delay(100);
     
     rTerm::memReset(); delay(1000);
     rTerm::memRead(); delay(1000);

  }


// -- RX FUNCTIONS --
  void rTerm::usbRx(){
  
    if(Serial.available() > 0){
  
      rTerm::loopIndex = 0;
      
      while(Serial.available()){
  
        char inChar = char(Serial.read());
  
        if(inChar == char(Serial.peek())){
  
          if(rTerm::isCMD(inChar)){
  
            char cmdBuff[16];
            Serial.readBytesUntil(char('\r'), cmdBuff, 14);           
            cmdBuff[strlen(cmdBuff)] = char('\0');
    
            rTerm::cmd(cmdBuff);
            
            for(int i=0; i<14; i++){
              cmdBuff[i] = char('\0');
            }
            
          }
          
        }
  
        if(opMode == 1){
          Serial1.print(inChar); }else if(opMode == 2){
          Serial2.print(inChar); }else if(opMode == 3){
          Serial3.print(inChar); }
  
      }
  
    }
    
  }

// -- dipPin Initialization --

  void rTerm::dipInit(){
    
    Serial.println(F("FCP Serial DIP SETTINGS: "));

    // -- BAUD RATE --
      pinMode(A9, INPUT); delay(20);
      pinMode(A8, INPUT); delay(20);
      pinMode(A11, INPUT); delay(20);
    
    // -- SERIAL CONFIG --
      pinMode(A10, INPUT); delay(20);
      pinMode(A13, INPUT); delay(20);
      pinMode(A12, INPUT); delay(20);
      pinMode(A15, INPUT); delay(20);
      pinMode(A14, INPUT); delay(20);

    delay(100);

    // -- CALC EEPROM ADDRESS FOR BAUD --
      if(digitalRead(A9)){ rTerm::fcpBaud += 1; } delay(20);
      if(digitalRead(A8)){ rTerm::fcpBaud += 2; } delay(20);
      if(digitalRead(A11)){ rTerm::fcpBaud += 4; } delay(20);

      rTerm::fcpBaud = rTerm::fcpBaud * 5;
      rTerm::fcpBaud += 300;

    // -- SET BAUD --
      EEPROM.get(rTerm::fcpBaud, rTerm::fcpBaud); delay(10);
  
    // -- CALC EEPROM ADDRESS FOR SERIAL CONFIG --    
      int px = 0;
      int pc = 0;
      
      if(digitalRead(A10)){ px += 1; pc += 1; } delay(20);
      if(digitalRead(A13)){ px += 2; pc += 2; } delay(20);
      if(digitalRead(A12)){ px += 4; pc += 4; } delay(20);
      if(digitalRead(A15)){ px += 8; pc += 8; } delay(20);
      if(digitalRead(A14)){ px += 16; pc += 16; } delay(20);
      
      px = px*5; px += 340;
      pc = pc * 5; pc += 460;
      
    // -- READ EEPROM ADDRESS FOR SERIAL CONFIG --  
      EEPROM.get(px, rTerm::fcpConfig);

    // -- READ EEPROM ADDRESS FOR SERIAL CONFIG TXT --
      EEPROM.get(pc, rTerm::configText);
      
    // -- WRITE CURRENT VALS TO EEPROM --
    
      // Clear CURRENT EEPROM VALS SINCE THEY ARE VARIABLE AND MIGHT CHANGE --
      for(int i=30; i<70; i++){
        EEPROM.write(i, 255);
      }

      delay(20);

      // Write new vals
      EEPROM.put(30, rTerm::fcpBaud); delay(20);
      EEPROM.put(40, rTerm::fcpConfig); delay(20);
      EEPROM.put(50, rTerm::configText); delay(20);
    
    // -- Initialize FCP Serial --
      Serial2.begin(rTerm::fcpBaud, rTerm::fcpConfig);
      delay(100);
      
      Serial.println(F(" -- FCP Serial Initialized --")); 
      Serial.print(rTerm::fcpBaud); Serial.print(F(" bps / ")); Serial.println(rTerm::configText);
      Serial.println();
      
  }

// -- GET CURRENT BATTERY VOLTAGE --
  float rTerm::vBatt(){
  
    int battRaw = 0;
    float bv;
    
    for (int i = 1; i < 11; i++) {
      
      battRaw += analogRead(A2); // add the raw analog reading to battRaw.
      delay(100); // Delay interval in milliseconds.
      
    }
    
    battRaw = battRaw / 10; // Average out the readings.
    
    bv = 1023.0 / 5.0;

    bv = battRaw / bv; // Convert reading to float.
    
    return bv;
    
  }

// -- GET CURRENT Input Voltage --
  float rTerm::vIn(){

    /*
     * 1024.0 / 5.0 = 204.6
     * 205 RAW = 1.0 Vdc
     * RAW Voltage Value = vRaw / 204.6;
     * 836 RAW = 
     * 9.2 * 0.267 = 2.45;
     * 3.29
     * inV = inV / 0.267; // Vin(R2/R1+R2) = 12000/45000 = 0.26666666666667 * vIn = vOut at A6 = vIn = vOut / 0.267
     * inV = vRaw * 5.0; // Convert reading to float.
     * 
     */
     
    int vRaw = 0;
    float inV;
    
    for (int i = 1; i < 11; i++) {
      
      vRaw += analogRead(A3); // add the raw analog reading to battRaw.
      delay(100); // Delay interval in milliseconds.
      
    }
    
    vRaw = vRaw / 10; // Average out the readings.
    inV = 1023.0 / 5.0;
    inV = vRaw / inV;
    inV = inV / 0.267;
    
    
    return inV;
    
  }
