const char* info0 = "EXP4 Build-01 MH";
const char* info1 = "F/W 0501M1_v0.22";
const char* info2 = "Assy: CES180501N";                                                                
const char* info3 = "Date: 10/14/2018";

/*    
 *  0501M1_v0.22 10/14/18 ---------------------
 *  Deploy I2C_Anything on I2C DCOM -OK-
 *  0501M1_v0.21 10/13/18 ---------------------
 *    Deploy I2C_Anything on I2C DCOM -OK-
 *    Add LCD Backlight Controls -OK-
 *    jm_Wire NotWorking
 *      conflict with embedded Wire.h can't be remove
 *  Add Watchdog and cause Loop locked (reload Bootloader)
 *  Add I2C Communication btw CPU -tested -OK-
 *    Set as I2C Master ID = 8
 *      Local PWM Gen [ prescaler2, ocra, ocrb ] 3-byte
 *      Local DATA [ float ] 4-byte
 *    Program %, Memory %
 *  0501M1_v0.13 10/12/18 ---------------------
 *    Check PWM Prescaller, update calculation OK
 *    Program 52%, Memory 54%
 *  Ready for Acceptance Test
 *    Pending LCD Display I2C Address update
 *    Pending Vin+ PS+ Ics Calibration 
 *    Program 54%, Memory 52%
 *  ------------------------------------------- 
 *  PCBASSY# CES180501N Pro Mini I2C 1602
 *    DMM V/A Input
 *    Counter Input
 *    DS1820B Temperature Sensor
 *    PWM Output
 *    Optical Isolation I/O
 *  ------------------------------------------- 
 *    Pro Mini (TN168) PORT Assignments
 *      A7  RANGE Pot
 *      A6  DUTY Pot
 *      A5  I2C-SCL
 *      A4  I2C-SDA
 *      A3  DMM3 (FREQ Pot)
 *      A2  DMM2 (Ics 50A)
 *      A1  DMM1 (PS+ 100V)
 *      A0  DMM0 (VIN+ 40V)
 *      D13 IDE Reserved Onboard LED (LoopBeat LED)
 *      D12 Temperatur DS18B20
 *      D11 FreqOUT F/2 50% (OCR2A)
 *      D10 
 *      D9  RDX EDM Status LO=ON
 *      D8  TDX Ready Status LO=NotReady 
 *      D7  
 *      D6  Key MODE Local(Lo)
 *      D5  Key Selup
 *      D4  Key Seldn
 *      D3  PWM OUTPUT (OCR2B)
 *      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) 
 *  ============================================================
 */

// I2C DCOM
  #include <I2C_Anything.h>
  #define I2Cslave 8  //I2C Slave Address
  float nTT1;
  float nTT2;
  
// 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>
  #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  // FREQ
  #define DMM6 A6  // DUTY
  #define DMM7 A7  // RANGE

// 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;

// PWM I/O
  #define freqout 11  // F/2 50% dutycycle output port
  #define pwmout 3  // PWM output port
  #define sFreq A3  //POT Freq Adj
  #define sDutycycle A6  //POT Dutycycle Adj
  #define sPrescaler A7  //POT Range Adj

// PWM Controls
  char* scalerPWM[]={
    "0  INOP Not Used",
    "1  F= 32K~1.3MHz",
    "8   F= 4K~166KHz",
    "32  F= 977~40KHz",
    "64  F= 496~20KHz",
    "128 F= 248~10KHz",
    "256 F=124~5.2KHz",
    "1024 F=31~1.3KHz"};
  int divider2[8] = { 0,1,8,32,64,128,256,1024 };
  //float freqmax[8] = { 0, 1333333, 166667, 41667, 20833, 10417, 5208, 1302 };
  //float freqmin[8] = { 0, 31746, 3968, 996, 496, 248, 124, 31 };
  byte ocra = 126; // set to 1KHz
  byte ocrb = 63;  // OCRA/2 50% dutycycle Phase Corrected
  double sysclk = 16000000; //system clock 16MHz default
  
// PWM POT
  byte potfreq; //Freq ADC Value
  byte lastpotfreq; //save value
  byte potduty; //dutycycle ADC Value
  byte lastpotduty; //save value
  byte potprescale; //Prescaler ADC Value
  byte lastpotprescale;  //save value

// PWM Output
  byte pwmfreq; //Freq ADC Value
  byte pwmduty; //dutycycle ADC Value
  byte pwmprescale; //Prescaler ADC Value
  float pwmHt; // integer for storing high time
  float pwmTt; // integer for storing total time of a cycle
  float pwmfrequency; // for storing frequency

// 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
  #define kmode 6 // Mode SW Local
  int kmodeset; //Mode SW
  int kmodelast; // Mode SW LastSetting

// System Variable
  #define loopbeat 13  // toggle per Loop
  unsigned long msNow; //Current Wait Timer data
  unsigned long msScreen = 3000; //default Screen Wait time
  unsigned long msLastscreen; //Last Screen Wait Timer
  unsigned long msLCD = 60000; //default LCD backligh Wait Time
  unsigned long msLastLCD; //Last LCD Wait Timer
  unsigned long msDCOMM = 500; //default DCOM Wait Timer
  unsigned long msLastDCOMM; //Last DCOM Wait Timer
  byte keyuphold = 0; // Keyup Hold Index
  byte keydnhold = 0; // Keydn Hold Index
  String mfg; // Long MSG
  byte backlight = 1; //Display Backlight 1=ON
  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 lastscreen 7  // scan last screen
  #define CntTime 8
  #define pwmF 9
  #define pwmT 10
  #define pwmS 11
  #define maxscreen 11  // Max screen counts from 0
  #define pwmTF 12

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

  // I2C Communication added v2.0
  Wire.begin();

  //Temp DS18B20 setup
  sensors.begin();

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

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

 //PWM setup
  pinMode(pwmout, OUTPUT); // Variable dutycycle port
  pinMode(freqout, OUTPUT); // 2/F 50% dutycycle port
  //TCCR2A = _BV(COM2A0) | _BV(COM2B1) | _BV(WGM21) | _BV(WGM20); //Fast PWM
  TCCR2A = _BV(COM2A0) | _BV(COM2B1) | _BV(WGM20); // Phase Correct PWM
  TCCR2B = _BV(WGM22) | _BV(CS22);

  //Key-In Setup
  pinMode(kmode, INPUT_PULLUP); // LO= Local PWM selected
  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 Local PWM
  freqread();
  prescaleread();
  pot2pwm();

}
/// 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); nTT1 = TT1;
      //sensors.requestTemperaturesByAddress(Tsensor2);
      TT2 = sensors.getTempC(Tsensor2); nTT2 = TT2;
      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); // Counter F/D Display
      if (kmodeset > 0) lcd2.print("<EDM System PWM>"); else lcd2.print("<EDM= Local PWM>");
      lcd2.setCursor(0,1); 
      if (kmodeset > 0) dispFD(frequency, Htime); else dispFD(pwmfrequency, pwmHt);
      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;

    case pwmF:
      lcd2.setCursor(0,0); // Local PWM Freq Display
      //ocrab();
      lcd2.print("<Local PWM Freq>");
      lcd2.setCursor(0,1); dispFD(pwmfrequency, pwmHt);
      break;

    case pwmT:
      lcd2.setCursor(0,0); // Local PWM H/L Display
      lcd2.print("<Local PWM Time>");
      lcd2.setCursor(0,1); dispHL(pwmfrequency, pwmHt);
      break;

    case pwmS: 
      if (msNow-msLastscreen > msScreen) { msLastscreen = msNow; screen = pwmF; break; }
      lcd2.setCursor(0,0); // Local PWM Prescaler Display
      lcd2.print("<Local PWM Range");
      lcd2.setCursor(0,1); lcd2.print(scalerPWM[pwmprescale]);
      break;

    case pwmTF:
      lcd2.setCursor(0,0); dispHL(pwmfrequency, pwmHt);
      lcd2.setCursor(0,1); dispFD(pwmfrequency, pwmHt);
      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

  // check kmode SW
  if (digitalRead(kmode)==LOW) { kmodeset = 0; } else { kmodeset = 1; } //0=Local 1=System
  // kmode toggle display
  if (kmodelast != kmodeset) {
    backlightON();
    kmodelast = kmodeset;
    lcd2.setCursor(0,0); lcd2.print (" < EDM Driver > "); // kmode toggle display
    lcd2.setCursor(0,1); 
    if (kmodeset > 0) {
      lcd2.print ("= SYSTEM EXP-PWM");
    } else {
      lcd2.print ("= LOCAL PWM Gen ");
    }
    delay(1000);
    msLastscreen = msNow;
  }

  // PWM POT set
  freqread();
  if ((potfreq>lastpotfreq+1) || (potfreq<lastpotfreq-1) || (potduty>lastpotduty+1) || (potduty<lastpotduty-1)) {
    pot2pwm();
    screen = pwmTF; msLastscreen = msNow; backlightON();
  }
  prescaleread();
  if ((potprescale!=lastpotprescale)) {
    pot2pwm(); 
    screen = pwmS; msLastscreen = msNow; backlightON();
  }

  // PWM Output
  switch(pwmprescale) { 
    case 1: TCCR2B = TCCR2B & B11111000 | B00000001; break; // T2 divisor = 1   INOP
    case 2: TCCR2B = TCCR2B & B11111000 | B00000010; break; // T2 divisor = 8   3.9KHz ~ 50KHz (H)
    case 3: TCCR2B = TCCR2B & B11111000 | B00000011; break; // T2 divisor = 32  980Hz ~ 12.2KHz
    case 4: TCCR2B = TCCR2B & B11111000 | B00000100; break; // T2 divisor = 64  247Hz ~ 6.2KHz (M)
    case 5: TCCR2B = TCCR2B & B11111000 | B00000101; break; // T2 divisor = 128 491Hz ~ 3.15KHz
    case 6: TCCR2B = TCCR2B & B11111000 | B00000110; break; // T2 divisor = 256 121Hz ~ 1.56KHz (L)
    case 7: TCCR2B = TCCR2B & B11111000 | B00000111; break; // T2 divisor = 1024 31Hz ~ 390Hz
  }
  
  OCR2A = ocra;  OCR2B = ocrb;

  // 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
  }

  // Anykey set LCD Backligh
  
  // UP Key Inputs
  if (digitalRead(kselup)==LOW) {
    backlightON();
    if (dispscan>0) {
      lcd2.clear(); lcd2.print (" - Clear Scan   ");
      lcd2.begin(16,2); 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));
      lcd2.begin(16,2);
    }
    delay(250);
  } else { keyuphold=0; }

  //DN Key Input
  if (digitalRead(kseldn)==LOW) {
    backlightON();
    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-msLastDCOMM > msDCOMM) { 
    msLastDCOMM = msNow; 
    I2Csend();  // send DCOMM via I2C
  }
  if (msNow-msLastLCD > msLCD) { 
    msLastLCD = msNow; 
    lcd2.noBacklight();   // Turn-OFF LCD Backlight
  }
  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
/* ------------------------------------------------------------------------*/

/* ---- I2C DCOM --------------------------------------------------*/
void I2Csend() {
  Wire.beginTransmission(I2Cslave); //Check Slave-Address
  if (Wire.endTransmission () == 0) {
    Wire.endTransmission();
    lcd2.setCursor(0,0); lcd2.print("S");
    Wire.beginTransmission(I2Cslave); //OK to Send 
      I2C_writeAnything( pwmprescale );
      I2C_writeAnything( ocra );
      I2C_writeAnything( ocrb );
      I2C_writeAnything( nTT1 );
      I2C_writeAnything( nTT2 );
  }
  Wire.endTransmission();    // stop transmitting
}

/* ---- DS18B20 Temperature Sensor -------------------------------------------*/

/// 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 -----------------------------------------------------------------*/

/// 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);
}
/// 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;
  }
}

/* PWM ------------------------------------------------------------------------*/

/// Timer Register Display "RxA=xxx  RxB=xxx" 16-chr
void ocrab() {
    mfg = "RxA=";
    if (ocra<10) { mfg=mfg+"  "; } else if (ocra<100) { mfg=mfg+" "; }
    mfg=mfg + String(ocra) + "  RxB=";
   if (ocrb<10) { mfg=mfg+"  "; } else if (ocrb<100) { mfg=mfg+" "; }
    mfg=mfg + String(ocrb);
    lcd2.print(mfg);
}

///  Frequency/Duty Display "xxx.xxxKHz D:xx%"
void dispFD(float freq, float Ht) {
    mfg = "";
    if (ocrb==0) { mfg=mfg+"  -- PWM OFF -- "; } else {
      float Tt = 1000000 / freq; // in uS
      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 // 16 chr
void dispHL(float freq, float Ht) {
    float Lt = 1000000 / freq - Ht; // in uS
    mfg = " H"; tDisp(Ht);
    mfg += " L"; tDisp (Lt);
    lcd2.print(mfg);
}

/// H/L Data output
/// " Hxx.xuS Lx.xxuS" 
/// " Hxx.xuS Lxx.xuS" 
/// " H xxxuS L xxxuS" 
/// " Hx.xxmS Lx.xxmS" 
/// " Hxx.xmS Lxx.xmS"
/// " H xxxmS L xxxmS"
void tDisp (float T) {
    if ((T)>1000) {  //mS Range
      if ((T/1000)<10) { 
        mfg += String(T/1000,2); 
      } else if ((T/1000)<100) {
        mfg += String(T/1000,1);
      } else { mfg += "="; mfg += String(T/1000,0); }
      mfg += "mS";
    } else {
      if ((T)<10) { 
        mfg += String(T,2); 
      } else if ((T)<100) { 
        mfg += String(T,1); 
      } else { mfg += "="; mfg += String(T,0); }
      mfg += "uS";
    }
}

/// Local Freq/Duty POT read
void freqread() {
  int j;
  j = 2; if (j != 0) { potfreq = analogRead(sFreq)/4; j--; }
  j = 2; if (j != 0) { potduty = analogRead(sDutycycle)/4; j--; }
  potduty = 255 - potduty;  //swap H/L
  if (potfreq < 6) { potfreq = 6; }
  if (potduty > 240) { potduty = 240; } //Limit MAX dutycycle to ~90%
}

/// Local Prescaller POT read
void prescaleread() {
  int j;
  j = 2; if (j != 0) { potprescale = analogRead(sPrescaler)/147; j--; }
}

/// PWM Set Output
void pot2pwm() {  
  lastpotfreq = potfreq;
  lastpotduty = potduty;
  lastpotprescale = potprescale;
  ocra = potfreq;
  ocrb = potduty * ocra / 255;
  pwmprescale = potprescale +1; //skip 0
  pwmfrequency = sysclk / divider2[pwmprescale] / (ocra) / 2;  //Phase Corrected
  pwmHt = (float)ocrb / (float)ocra * (1000000/pwmfrequency); // in uS
}

/* SYSTEM ------------------------------------------------------------------------*/

/// LCD Backlight ON
void backlightON () {
  msLastLCD = millis();
  lcd2.backlight();
}

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

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