const char* info0 = "ECP4 Build-01   ";
const char* info1 = "F/W 0501C1_v0.12";
const char* info2 = "Assy: CES180501N";                                                                
const char* info3 = "Date: 09/21/2018";

/*    
 *  0501C1_v0.12 9/21/18 ---------------------
 *  Common F/W for ECP4
 *  Ready for Acceptance Test
 *    Pending LCD Display I2C Address update
 *    Pending Vin+ PS+ Ics Calibration 
 *    Program 49%, Memory 37%
 *    Modified from 0501M1_v0.12 9/21/18
 *  ------------------------------------------- 
 *  PCBASSY# CES180501N Pro Mini I2C 1602
 *    DMM V/A Input
 *    Counter Input
 *    DS1820B Temperature Sensor
 *    Optical Isolation I/O
 *  ------------------------------------------- 
 *    Pro Mini (TN168) PORT Assignments
 *      A7  
 *      A6  
 *      A5  I2C-SCL
 *      A4  I2C-SDA
 *      A3  DMM3 
 *      A2  DMM2 (Ics 50A)
 *      A1  DMM1 (PS+ 100V)
 *      A0  DMM0 (VIN+ 40V)
 *      D13 IDE Reserved Onboard LED (LoopBeat LED)
 *      D12 Temperatur DS18B20
 *      D11 
 *      D10 
 *      D9  nRDX LO=EDMon
 *      D8  nTDX LO=NotReady 
 *      D7  
 *      D6  
 *      D5  Key Selup
 *      D4  Key Seldn
 *      D3  
 *      D2  FREQ Counter INPUT
 *      D1  IDE Reserved Programming TXD
 *      D0  IDE Reserved Programming RXD
 *
 *  ============================================================
 *  (D9)(D8)(D7)(D6)(D5)(D4)(D3)(D2)(GND)(RES)(RXD)(TXD) < DTR >
 *        (GND) * * (RESET)                              < RX >
 *   (MOSI/D11) * * (SCK/D13)                            < TX >
 *       VCC+5V * * (MISO/D12)                           < VCC >
 *           A4 * * A6                                   < CTS >
 *           A5 * * A7                                   < GND >
 *  (D10)(D11)(D12)(D13)(A0)(A1)(A2)(A3)(VCC)(RES)(GND)(RAW) 
 *  ============================================================
 */
// DCOMM Console Interface btw PWMGen4
  #define nTXD 8
    #define Ready HIGH
    #define NotReady LOW
  #define nRXD 9
    #define EDMon LOW
    #define EDMoff HIGH
  byte EDMstatus;
  byte Readystatus;
  #define vinmin 11.5 //VIN threashold for Not Ready 
  
// LCD 1602 with I2C
  #include <FastIO.h>
  #include <I2CIO.h>
  #include <LiquidCrystal_I2C.h>
  // the pins on the I2C chip used for LCD connections:
  //                     addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
  //LiquidCrystal_I2C lcd2(0x3F, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); // TESTER LCD
  LiquidCrystal_I2C lcd2(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); // 

// DS18B20 Temperature Sensor(s)
  #include <OneWire.h>
  #include <DallasTemperature.h>
  #include <Wire.h>
  #define Tport 12  // Port for Sensor
  #define Tdata 9  // Resolution, 9-bit 0.5C 93.75mS, 10-bit 0.25C 187.5mS, 11-bit 0.125C 375mS, 12-bit 0.0625C 750mS
  // Setup a oneWire instance to communicate with any OneWire devices
  OneWire oneWire(Tport);
  // Pass our oneWire reference to Dallas Temperature. 
  DallasTemperature sensors(&oneWire);
  // Arrays to hold device addresses
  DeviceAddress Tsensor1, Tsensor2; // for Auto Config
  //DeviceAddress Tsensor1 = { 0x28, 0xFF, 0x77, 0x95, 0x94, 0x16, 0x04, 0x85 };  // RR= Brown
  //DeviceAddress Tsensor2 = { 0x28, 0xFF, 0xE8, 0x8E, 0x86, 0x16, 0x04, 0xF4 };  // LT= Blue
  float TempC;
  float TT1;
  float TT2;

// Analog Ports
  #define DMM0 A0  // VIN+
  #define DMM1 A1  // PS+
  #define DMM2 A2  // ICS
  //#define DMM3 A3  // 

// DMM PreScale
  double dmk0 = 0.037471489;  // 38.33V 220K/33K FSC @ 5.000V
  double dmk1 = 0.094493320;  // 96.67V 220K/12K FSC @ 5.000V 
  double dmk2 = 0.049873322;  // 51.02A 18K/10K CS=0.035 FSC @ 5.000V  
  //double dmk3 = ;  // notused
  //double dmk0 = 0.038329969;  // 38.61V 220K/33K FSC @ chk
  //double dmk1 = 0.098442563;  // 97.57V 220K/12K FSC @ chk 
  //double dmk2 = 0.050516031;  // 51.02A 18K/10K CS=0.035 FSC @ chk  

// DMM AnalogRead Array
  const int ARcount = 10;  // sample size
  unsigned int dm0[ARcount]; // array data
  unsigned int dm1[ARcount]; // array data
  unsigned int dm2[ARcount]; // array data
  //unsigned int dm3[ARcount]; // array data
  unsigned int Aindex = 0;  // array index
  unsigned int dm0min;  // MIN result byte
  unsigned int dm0avg;  // AVG result byte
  unsigned int dm0max;  // MAX result byte
  unsigned int dm1min;
  unsigned int dm1avg;
  unsigned int dm1max;
  unsigned int dm2min;
  unsigned int dm2avg;
  unsigned int dm2max;
  //unsigned int dm3min;
  //unsigned int dm3avg;
  //unsigned int dm3max;
  float dmmV;
  float dmmA;
  float dmmW;

// Counter 
  #define iFreq 2 // Frequencty Counter Input Port
  long TtimeMAX = 25000;  //10Hz minimum
  float Htime; // integer for storing high time
  float Ltime; // integer for storing low time
  float Ttime; // integer for storing total time of a cycle
  float frequency; // for storing frequency

// Key & SW
  #define kselup 4 // Sel-Up Key
  #define kseldn 5 // Sel-DN Key

// System Variable
  #define loopbeat 13  // toggle per Loop
  unsigned long msNow; //Current Wait Timer
  unsigned long msScreen = 3000; //default Screen Wait time
  unsigned long msLastscreen; //Last Screen Wait Timer
  byte keyuphold = 0; // Keyup Hold Index
  byte keydnhold = 0; // Keydn Hold Index
  String mfg; // Long MSG
  byte screen = 1; //Display Page index
  byte dispscan = 1;  // 1= scan mode
  byte startscreen = 1;  // Scan Start Screen
  
  #define firstscreen 1  // scan 1st screen
  #define DualTemp 1
  #define Vin 2
  #define PS 3
  #define Ics 4
  #define VAWavg 5
  #define VAWmax 6
  #define CntFreq 7
  #define CntTime 8
  #define lastscreen 8  // scan last screen
  #define maxscreen 8  // Max screen counts from 0

/* ------------------------------------------------------------------------*/
/// Setup Start Here
void setup() {

  //Temp DS18B20 setup
  sensors.begin();

  //DCOMM Console Interface
  pinMode(nRXD,INPUT_PULLUP);
  pinMode(nTXD,OUTPUT);

  //LCD setup
  lcd2.begin(16, 2);

  //Key-In Setup
  pinMode(kselup, INPUT_PULLUP);  // Page Up Hold for scan
  pinMode(kseldn, INPUT_PULLUP); // Page Dn Hold for scan

  //Loop Beat
  pinMode(loopbeat, OUTPUT); 

  //Display Info
  lcd2.setCursor(0,0); lcd2.print(info0);
  lcd2.setCursor(0,1); lcd2.print(info1);
  delay(2000);
  lcd2.setCursor(0,0); lcd2.print(info2);
  lcd2.setCursor(0,1); lcd2.print(info3);
  delay(2000);

}
/// Setup End Here
/* ------------------------------------------------------------------------*/
/// Program Start Here
void loop() {

  // Get Dual Temp Data
  sensors.requestTemperatures();

  // Get DMM Value
  DMMread();  // Read All Ports
  DMMproc();  // Processing Max/Avg/Min
  
  // Screen Display
  switch(screen) {

    case DualTemp: 
      //sensors.requestTemperaturesByAddress(Tsensor1);
      TT1 = sensors.getTempC(Tsensor1);
      //sensors.requestTemperaturesByAddress(Tsensor2);
      TT2 = sensors.getTempC(Tsensor2);
      lcd2.setCursor(0,0); // Temperatures
      //   print("0123456789012345")
      lcd2.print(" <Inlet>  <HS>  ");
      lcd2.setCursor(0,1); printTT( Tsensor1, 0, Tsensor2, 1 ); // Dual Temp
      break;

    case Vin: //dispV(int ddm1, double ddmk1, char* ddmn1)
        if ((dispscan==1) && (Readystatus>0)) {screen++; break;} //skip on scan
      lcd2.setCursor(0,0); dispV(dm0min, dmk0, "VIN+ min ");
      lcd2.setCursor(0,1); 
      if (Readystatus==0) lcd2.print("** Low Voltage !"); else dispV(dm0max, dmk0, "VIN+ max "); // VIN+
      break;

    case PS: 
        if (dispscan==1) {screen++; break;} //skip on scan
      lcd2.setCursor(0,0); dispV(dm1min, dmk1, "PS+ min  ");
      lcd2.setCursor(0,1); dispV(dm1max, dmk1, "PS+ max  "); // PS+
      break;

    case Ics: 
        if (dispscan==1) {screen++; break;} //skip on scan
      lcd2.setCursor(0,0); dispA(dm2min, dmk2, "Ics+ min ");
      lcd2.setCursor(0,1); dispA(dm2max, dmk2, "Ics+ max "); // Ics+
      break;

    case VAWavg:
        if (dispscan==1) {screen++; break;} //skip on scan
      lcd2.setCursor(0,0); // PS VAW AVG
      lcd2.print("<Avg. Power Out>");
      lcd2.setCursor(0,1); dispVAW(dm1max, dmk1, dm2avg, dmk2); // Max Power
      break;

    case VAWmax:
      lcd2.setCursor(0,0); // PS VAW MAX
      lcd2.print("<Max. Power Out>");
      lcd2.setCursor(0,1); dispVAW(dm1max, dmk1, dm2max, dmk2); // Max Power
      break;

    case CntFreq:
      lcd2.setCursor(0,0); lcd2.print("<EDM System PWM>");
      lcd2.setCursor(0,1); dispFD(frequency, Htime);
      break;

    case CntTime:
      lcd2.setCursor(0,0); // Counter H/L Display
      lcd2.print("<EDM H/L Timing>");
      lcd2.setCursor(0,1); dispHL(frequency, Htime);
      break;

  } //end screen

  // NotReady if VIN below vinmin
  if ((dm0min*dmk0) < vinmin) {
    Readystatus=0; 
    screen = Vin; msLastscreen = msNow;
  } else Readystatus=1;

  //DCOMM Console Status Interface
  if (Readystatus==0) digitalWrite(nTXD,NotReady); else digitalWrite(nTXD,Ready);
  if (digitalRead(nRXD)==EDMon) EDMstatus=1; else EDMstatus=0; //nRXD Active
  // EDMstatus=1; //In-active set to ON

  // Counter Input
  if (EDMstatus > 0) {
    Htime=pulseIn(iFreq,HIGH,TtimeMAX); //read high time
    Ltime=pulseIn(iFreq,LOW,TtimeMAX); //read low time
    Ttime = Htime+Ltime; // total time = high time + low time in uS
    frequency=1000000/Ttime; //calculate frequency from Ttime in Micro seconds
  }
  
  // UP Key Inputs
  if (digitalRead(kselup)==LOW) {
    if (dispscan>0) {
      lcd2.clear(); lcd2.print (" - Clear Scan   ");
      dispscan = 0;
    }
    if (keyuphold==0) {
      screen--;
      if ((screen < firstscreen) || (screen > maxscreen)) screen = maxscreen; 
    }
    keyuphold++;
    if (keyuphold>4) {
      dispscan=1;
      lcd2.clear(); lcd2.print (" + Scan Mode Set");
      do {} while ((digitalRead(kselup)==LOW));
    }
    delay(250);
  } else { keyuphold=0; }

  //DN Key Input
  if (digitalRead(kseldn)==LOW) {
    if (dispscan>0) {
      lcd2.clear(); lcd2.print (" - Clear Scan   ");
      dispscan = 0;
    }
    if (keydnhold==0) {
      screen++;
      if (screen > maxscreen) screen=firstscreen; 
    }
    keydnhold++;
    if (keydnhold>4) {
      dispscan=1;
      lcd2.clear(); lcd2.print (" + Scan Mode Set");
      do {} while ((digitalRead(kseldn)==LOW));
    }
    delay(250);
  } else { keydnhold=0; }
 
  // Display Timer updater
  msNow = millis();
  if ((msNow-msLastscreen > msScreen) && (dispscan > 0)) { 
    msLastscreen = msNow;  
    screen++;
    if (screen > lastscreen) screen = firstscreen;
  }

  // Loop Beat on D13 LED
  if (digitalRead(loopbeat)==LOW) digitalWrite(loopbeat,HIGH); else digitalWrite(loopbeat,LOW);

}
/// Program End Here
/* ------------------------------------------------------------------------*/

///  Frequency/Duty Display "xxx.xxxKHz D:xx%"
void dispFD(float freq, float Ht) {
    mfg = "";
    float Tt = 1000000 / freq; // in uS
    if (((freq/1000)>999) || (freq < 20)) { mfg=mfg+"! Invalid Data !"; } else {
    //if (((freq/1000)>999)) { mfg=mfg+"! Invalid Data !"; } else {
      if ((freq/1000)<10) { mfg=mfg+"  "; } else if ((freq/1000)<100) { mfg=mfg+" ";  }
      mfg=mfg + String(freq/1000,3) + "KHz D="+ String((Ht/Tt)*100,0) + "%";
    }
    lcd2.print(mfg);
}

/// H/L Time Display "+xxxxxuS-xxxxxuS" // 16 chr
void dispHL(float freq, float Ht) {
    mfg = "";
    float Lt = 1000000 / freq - Ht; // in uS
    if ((Ht)>1000) {
      if ((Ht/1000)<10) { mfg=mfg+" "; } 
      mfg=mfg + "H" + String(Ht/1000,2) + "mS";
    } 
    else {
      if (Ht<100) { mfg=mfg+"   "; } else if (Ht<1000) { mfg=mfg+"  "; } else if (Ht<10000) { mfg=mfg+" "; }
      mfg=mfg + "H" + String(Ht,0) + "uS";
    }
    if ((Lt)>1000) {     
      if ((Lt/1000)<10) { mfg=mfg+" "; } 
      mfg=mfg + "L" + String(Lt/1000,2) + "mS";
    }
    else {
    if (Lt<10) { mfg=mfg+"   "; } else if (Lt<100) { mfg=mfg+"   "; } else if (Lt<1000) { mfg=mfg+"  "; } else if (Lt<10000) { mfg=mfg+" "; }
    mfg=mfg + "L" + String(Lt,0) + "uS";
    }
    lcd2.print(mfg);
}

/// DMM Display 0123456789012345  Name(4)+Data(12)
/// V           Vin+:  nnn.nnVDC 
void dispV(int ddm1, double ddmk1, char* ddmn1) {
  mfg = (ddmn1);
  dmmV = ddm1 * ddmk1;
  if (dmmV<100)  mfg += " "; 
  if (dmmV<10)  mfg += " ";  
  mfg += String(dmmV,2); mfg += "V";
  lcd2.print (mfg);  
}

/// DMM Display 0123456789012345  (16-chr)
/// Ics+        Ics+:  nnn.nnADC 
void dispA(int ddm1, double ddmk1, char* ddmn1) {
  mfg = (ddmn1);
  dmmV = ddm1 * ddmk1;
  if (dmmV<100)  mfg += " "; 
  if (dmmV<10)  mfg += " ";  
  mfg += String(dmmV,2); mfg += "A";
  lcd2.print (mfg);  
}

/// DMM Display 0123456789012345  (16-chr)
/// VAW         nnnV nn.nA nnnnW  
void dispVAW( int dvm, double dvk, int dam, double dak ) {
  mfg = "";
  dmmV = dvm * dvk;
  dmmA = dam * dak;
  dmmW = dmmV * dmmA;
  if (dmmV<100)  mfg += " ";  
  mfg += String(dmmV,0) + "V ";
  if (dmmA<10)  mfg += " ";  
  mfg += String(dmmA,1) + "A "; 
  if (dmmW>9999) { mfg += " --- "; }
  else {
    if (dmmW<100) { mfg += "  ";  }  else if (dmmW<1000) { mfg += " ";  }
    mfg += String(dmmW,0) + "W"; 
  }
  lcd2.print (mfg);
}

/// TEMP Disp Temperatures Sensors in "-xxx.xoC" 8chr
void printTT(DeviceAddress paddress1, byte pindex1, DeviceAddress paddress2, byte pindex2) {
  mfg="";
  if (!sensors.getAddress(paddress1,pindex1)) { mfg += "   ---  "; lcd2.print (mfg);} 
  else { printT2(TT1); }  
  mfg="";
  if (!sensors.getAddress(paddress2,pindex2)) { mfg += "   ---  "; lcd2.print (mfg);} 
  else { printT2(TT2); }  
}

/// TEMP Disp Justify print =OK=
//  "01234567"
//  "-100.3oC" 
//  " -10.3oC" 
//  "  -1.3oC" 
//  "   0.3oC" 
//  "  10.3oC" 
//  " 100.3oC" 
void printT2(float TC) {
  if (TC<0) {
    if (TC>-100) mfg += " ";
    if (TC>-10) mfg += " ";
    mfg += String(TC,1);    
  } else {
    mfg += " ";
    if (TC<100) mfg += " ";
    if (TC<10) mfg += " ";
    mfg += String(TC,1);      
  }
  lcd2.print (mfg);
  lcd2.print("\xDF" "C");  
}

/// --------------------------------------------------------------
/// DMM Port Read
void DMMtest() {   
  Aindex++; if (Aindex == ARcount) Aindex = 0;
  dm0[Aindex]+=1.5;
  dm1[Aindex]+=2.8;
  dm2[Aindex]+=3.4;
  //dm3[Aindex]+=4.6;
}

void DMMread() {   
  Aindex++; if ((Aindex == ARcount) || (Aindex > ARcount)) Aindex = 0;
  int j;
    j = 3; if (j != 0) { dm0[Aindex] = analogRead(DMM0); j--; }
    j = 3; if (j != 0) { dm1[Aindex] = analogRead(DMM1); j--; }
    j = 3; if (j != 0) { dm2[Aindex] = analogRead(DMM2); j--; }
    //j = 2; if (j != 0) { dm3[Aindex] = analogRead(DMM3); j--; }
}

/// DMM Processing Max/Avg/Min
void DMMproc() {  
  dm0min = dm0[Aindex]; dm0avg = dm0min; dm0max = dm0min; 
  dm1min = dm1[Aindex]; dm1avg = dm1min; dm1max = dm1min; 
  dm2min = dm2[Aindex]; dm2avg = dm2min; dm2max = dm2min; 
  //dm3min = dm3[Aindex]; dm3avg = dm3min; dm3max = dm3min; 
  int i=0;
  for (i=0; i<ARcount; i++) {
    if (dm0min > dm0[i]) dm0min = dm0[i];
    if (dm1min > dm1[i]) dm1min = dm1[i];
    if (dm2min > dm2[i]) dm2min = dm2[i];
    //if (dm3min > dm3[i]) dm3min = dm3[i];  
    if (dm0max < dm0[i]) dm0max = dm0[i];
    if (dm1max < dm1[i]) dm1max = dm1[i];
    if (dm2max < dm2[i]) dm2max = dm2[i];
    //if (dm3max < dm3[i]) dm3max = dm3[i];
    dm0avg = ( dm0avg + dm0[i] ) /2;
    dm1avg = ( dm1avg + dm1[i] ) /2;
    dm2avg = ( dm2avg + dm2[i] ) /2;
    //dm3avg = ( dm3avg + dm3[i] ) /2;
  }
}

void DMMproc0() {  
  dm0min = dm0[Aindex]; dm0avg = dm0min; dm0max = dm0min; 
  int i=0;
  for (i=0; i<ARcount; i++) {
    if (dm0min > dm0[i]) dm0min = dm0[i];
    if (dm0max < dm0[i]) dm0max = dm0[i];
    dm0avg = ( dm0avg + dm0[i] ) /2;
  }
}

void DMMproc1() {  
  dm1min = dm1[Aindex]; dm1avg = dm1min; dm1max = dm1min; 
  int i=0;
  for (i=0; i<ARcount; i++) {
    if (dm1min > dm1[i]) dm1min = dm1[i];
    if (dm1max < dm1[i]) dm1max = dm1[i];
    dm1avg = ( dm1avg + dm1[i] ) /2;
  }
}

void DMMproc2() {  
  dm2min = dm2[Aindex]; dm2avg = dm2min; dm2max = dm2min; 
  int i=0;
  for (i=0; i<ARcount; i++) {
    if (dm2min > dm2[i]) dm2min = dm2[i];
    if (dm2max < dm2[i]) dm2max = dm2[i];
    dm2avg = ( dm2avg + dm2[i] ) /2;
  }
}

/// Software Reset
void resetBoot() {
  asm volatile ("  jmp 0");
}

/// F/W End Here
/* ------------------------------------------------------------------------*/