#define info0  "F/W: ZDRV3_v0.28.4  "  // for 20 chr Display
#define info1  "Released: 02/22/2018"
#define info2  "PCB Assy#  CES171107"
#define info3  "Job End at BOT-Sense"

/* ZDRV3_
 *  Simplified 1st Built EDMP3 v0.28 Lawrence CHu 2/20/18~
 *    RUN as Default (Ended at BSense)
 *    Speed up RUN 
 *      Disabled all realtime MSG dispolay
 *    Override UP if ProbeERR  (inop)
 *    Shut EDM to Check BSense 
 *    !!! relocation truncated to fit: R_AVR_13_PCREL against `no symbol'??? fails on both 1.8.3 and 1.8.5
 *      Reducing LOOP to see if works
 *      
 *  Initial 1st Built EDMP3 v0.2 Lawrence CHu 2/16/18~
 *    Swapped ZDRV Direction Bit (New 60mm A/B Wiring Swaps)
 *    RealTime Z Speed per A7 (Remove ZDRV Page)
 *    Add iSTOP ALL
 *    INFO pagfe U/D Works
 *    CAL Probe DIA change to Zero. Setup CAL Gap = 1-in + Probe-DIA
 *    Machine coordinate CAL using TOP only (Fixed Range)
 *    Remove Prox, GAP in Setup (Fixed Prox, Gap)
 *    Bypass RANGE/CAL. Self RangeCheck when entering SET
 *    Remove PARK, Use RUN start position
 *    SETUP End Position only
 *    Change PARK=0.1 below TOP
 *    After water Contaminated, Psense triggered. 
 *      Add 3.9K 10W Resistor from PS+ to Probe as solution
 *    Job Finised unespectly ?    
 *      Redo RUN using "IF" instead of "WHILE"
 *  
 *  Initial Built Release v0.12 Lawrence Chu 1/9/18
 *    Use TB6506 w/ 12V Stepper 60mm Z-Axis
 *    50% ZClk 150/1ms Max Speed
 *  Initial Built Release v0.11 Lawrence Chu 1/9/18
 *    Use TB6506 w/ 12V Stepper 60mm Z-Axis
 *    50% ZClk 150/150us Max Speed
 *  Initial Test Release v0.10 Lawrence Chu 12/14/17
 *  --------------------------------------------------------
 *  Release as v0.10
 *  v0.30.8 Cleanup for Initial Release
 *    Code: 79% 
 *    DRAM: 73% Local has (545)
 *  v0.30.7 <RANGE>ok, <CAL>ok, <SETUP>ok, <RUN>ok
 *    Code: 79% 
 *    DRAM: 75% Local has (503)
 *  v0.30.6 <RANGE>ok, <CAL>ok, <SETUP>ok, <RUN>?
 *    Code: 79% 
 *    DRAM: 75% Local has (503) 
 *  v0.30.5 <RANGE>ok, <CAL>ok, <SETUP>ok, <RUN>?
 *    Code: 79% 
 *    DRAM: 74% Local has (517)
 *  v0.30.4 Update SET OK
 *    Code: 76% 
 *    DRAM: 75%
 *  v0.30.2 Reducing Step's Msg (Not Test)
 *    Code: 72% 
 *    DRAM: 76%
 *  v0.30.1 Working on Reduce Dynamic Memory
 *    Code: 74% 
 *    DRAM: 84%
 *  v0.30 as REF
 *    Code: 71% 
 *    DRAM: 85%
 *  v0.2.5p5 Test on Sketch ver 1.8.2 OK   
 *    Save Keep as v.0.2.5, v0.30
 * --------------------------------------------------------
 * LCD 2004 I2C (5V)
 *    A5 = SCL
 *    A4 = SDA
 * --------------------------------------------------------
 * TB6560 Stepper Driver
 *    A+ (Red)
 *    A- (Blue)
 *    B+ (Green)
 *    B- (Black)
 * --------------------------------------------------------
 * --------------------------------------------------------
 *    Pro Mini (TN168) PORT Assignments
 *      A7  WORK Zclk Setting
 *      A6  
 *      A5  I2C-SCL
 *      A4  I2C-SDA
 * -----------------------     
 *      A3/D17  iRESET Input (cold boot)
 *      A2/D16  iSTOP Input (disable all)
 *      A1/D15  BSense Input (Bottom Sense)  
 *      A0/D14  TSense Input (Top Sense)
 *      D13 Output Zdir ZDRV-DIR (IDE Reserved Output Only)
 *      D12 Output Zclk ZDRV-CLK
 *      D11 Output Zen ZDRV-EN 
 *      D10 Output EDM Enable
 *      D9  Key Zdn Input
 *      D8  Key Zup Input
 *      D7  Key Zrun Input
 *      D6  Key Zset Input
 *      D5  Key PageDN Input
 *      D4  Key PageUP Input
 *      D3  ISense Input
 *      D2  PSense Input
 * -----------------------     
 *      D1  RXD to HC-05 TXD
 *      D0  TXD to HC-05 RXD w/ K/15K Divider
 * === Pro Mini w/ 5x2 Extended Header =========================
 *  (D9)(D8)(D7)(D6)(D5)(D4)(D3)(D2)(GND)(RES)(RXD)(TXD) < DTR >
 *      (GND) * * (RES)                                  < RX >
 * (MOSI/D11) * * (SCK/D13)                              < TX >
 *     VCC+5V * * (MISO/D12)                             < VCC >
 *         A4 * * A6 (ADC Input only)                    < CTS >
 *         A5 * * A7 (ADC Input only)                    < GND >
 *  (D10)(D11)(D12)(D13)(A0)(A1)(A2)(A3)(VCC)(RES)(GND)(RAW) 
 *  
 * === Pro Mini w/ 5x1 Extended Header CES171107) ==============
 *  (D9)(D8)(D7)(D6)(D5)(D4)(D3)(D2)(GND)(RES)(RXD)(TXD) < DTR >
 *      (GND) *                                          < RX >
 *         A4 *                                          < TX >
 *         A5 *                                          < VCC >
 *         A6 *                                          < CTS >
 *         A7 *                                          < GND >
 *  (D10)(D11)(D12)(D13)(A0)(A1)(A2)(A3)(VCC)(RES)(GND)(RAW) 
 *
 * === TB6560 SW Settings ======================================
 *  --- Running Current --- (1.5A*)
 *  sw1 OFF OFF OFF OFF OFF ON  OFF ON*  ON  ON  ON  ON  ON  ON
 *  sw2 OFF OFF ON  ON  ON  OFF ON  OFF* OFF ON  OFF ON  ON  ON
 *  sw3 ON  ON  OFF OFF ON  OFF ON  ON*  OFF OFF ON  ON  OFF ON
 *  S1  OO  OFF ON  OFF ON  ON  OFF ON*v  OFF ON  OFF ON  OFF OFF
 *      0.3 0.5.0.8  1*  1.1 1.2 1.4 1.5 1.6 1.9  2  2.2 2.6 3.0
 *  --- Stop Current --- (50%)
 *  S2  OFF*  ON
 *      50%*  20%
 *  --- Excitation Mode --- (Mode 16)
 *  S3  OFF OFF ON*  ON
 *  S4  OFF ON  OFF* ON
 *       1  2   8*   16
 *  --- Decay Setting ---
 *  S5  OFF* OFF ON  ON
 *  S6  OFF* ON  OFF ON
 *      0%*  25% 50% 100%
 *  ZScale per Inch Excitation Mode Note: 
 *  Mode.1 3off 4off = No Good
 *  Mode.2 3on 4off = Default = 2526
 *  Mode.8 3on 4on = fine = 10090
 *  Mode.16 3off 4on = Ultra = 20190
 * =============================================================
 */

// LCD 2004A 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(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); // 2004A LCD
  
// Z-drive Stepper Output Port
  #define Zclk 12 //ZDRV Clock output
    #define ZclkH HIGH
    #define ZclkL LOW
  #define Zdir 13 //ZDRV Direction output 
    #define ZdirUP LOW
    #define ZdirDN HIGH
  #define Zen 11 //ZDRV Enable output
    #define Zon LOW
    #define Zoff HIGH
  #define EDM 10 //EMD Enable output
    #define EDMon HIGH
    #define EDMoff LOW

// Z-drive I/O Port
  #define TSense 14 //Z-Drive TOP Limit     
  #define BSense 15 //Z-Drive BOT Limit
  #define iRESET 17 //Input Emergency KILL Reset  
  #define iSTOP 16 //Input Emergency KILL Stop
  #define PSense 2 //Sense Probe input  
  #define ISense 3 //Sense Probe input  

// Z-drive control Keys
  #define Zdn 9 //Z Down Key
  #define Zup 8 //Z up Key
  #define Zrun 7 //Z Run Key
  #define Zset 6 //Z Set Key

// System control Keys
  #define PageDN 5  //Page DN
  #define PageUP 4  //Page UP 
  
// Z-Drive Pulse 10KHz=100uS 20KHz=50uS
  #define A7pulse A7  //POT Speed Adj
  //long pulsewidth = 200; // ON Pulse in uS
  //long pulsegap = 200; // OFF Gap in uS
  #define pulseMin 150 // Maximum Speed
  long Ain7; //Read A7 Input 0-255 for WORK Zclk
  
  // Z-Drive working variable
  int ZupHold = 0; //UP Speed Test Count
  int ZdnHold = 0; //DN Speed Test Count
  long Zcount; //Current Step Count (from Work Zero)
  long ZcountSet; //Target Step Count (from Work Zero)
  long ZcountSave; //+UP -DN Temp Display Counts (from Work Zero)
  long ZcountEnd; //Finish Depth (from Work Zero)
  long ZcountPark;  //Part in Counts (from Work Zero)
  long ZcountProx;  //Prox in Counts (from Work Zero)
  long ZcountGap;  //Gap in Counts (from Work Zero)
  long ZcountMax; //Top Limit Counts (from Work Zero)
  long ZcountMin; //Bottom Limit Counts (from Work Zero)
  long ZcountZero; //Z Machine Work Zero offset  
  long ZcountMMax; //Z Machine Top Limit TSense
  long ZcountMMin; //Z Machine Bot Limit BSense (BOT = Machine-Zero)

// Z-Drive Default Value from Work Zero
  //long ZscaleDefault = 2526;  //steps counts per Inch (TB6560 Mode2 ) 150mm
  //long ZscaleDefault = 10142;  //steps counts per Inch (TB6560 Mode8 Default) 150mm
  //long ZscaleDefault = 20272;  //steps counts per Inch (TB6560 Mode16 ) 150mm
  long ZscaleDefault = 2542;  //steps counts per Inch (TB6560 Mode8 Default) 60mm
  long Zscale;  //steps counts per Inch
  float ZmaxDefault = 2.1; //Z Top 2.1 Inch (60mm Axis) - Justify Sensing Block Thk.
  float Zmax; // Z Top in Inch
  float Zmin = 0; // Machine Zero Default = 0
  float Zpark = 0.2; //Park in Inch from Zero
  float Zprox = 0.1; //Prox Zone in Inch from Zero
  float Zend = -1; //Job Finish Depth in Inch from Zero (initial value)
  float Zgap = 0.05; //Max gap prior Prox Clearing in Inch from Zero
  float Zzero;  // Zero in Inch
  #define ZcalProde 0 //CAL Prode DIA or Thickness

// Z-Drive Operating Range Limits
  #define ZscaleMin 800 //counts
  #define ZscaleMax 30000 //counts

// Processing Steps Index
  byte Srng;  //Range Finder process steps
  byte Scal;  //Calibration process steps 
  byte Sset; //Setup process steps
  byte Srun; //Run process steps

  byte Zready;  //Ready Check 0=notready, 1=ScaleOK, 2=RangeOK, 3=SetupOK 
  byte Zclear;  //Test if Not Clear Discharging Gap
  byte Zstop; // 0=RUN

// Position Label
  #define mZERO 0
  #define mPARK 1
  #define mPROX 2
  #define mGAP 3
  #define mEND 4
  #define mSEEK 5
char* Zposmsg[]={ //
  "ZERO", //0
  "PARK", //1
  "PROX", //2
  "GAP ", //3
  "END ", //4
  "SEEK"};  //5

// Zpage Page MSG 2004 20 chr
  byte Zpage = 0; //default
  #define SETUP 0
  #define RUN 1
  #define INF 2
  #define TEST 3
  #define RNG 4
  #define CAL 5
  char* Zpagemsg[]={  //6-chr
    "<SET> ", //0
    "<RUN> ", //1
    "INFO> ", //2
    "TEST> ", //3
    "RANGE ", //4
    "<CAL> "}; //5

// Zmode MSG 2004 20 chr
  byte Zmode = 0; //Mode state
    #define mUP 1
    #define mDN 2
    #define mPause 3
    //#define mError 4
  char* Zmodemsg[]={  // 7-chr
    " ----- ",  //0 
    " (zUP) ", //1 Zdir
    " (zDN) ", //2
    " PAUSE "};  //3

// System I/O & Variable
  #define disptime 2000 //Delay for Display in mS
  #define hiSpeed 25  // count before switch to high speed 
  byte pagemsg = 0; //Init Display MSG once
  String mfg; // Long MSG
  byte Next;  // Next Index
  unsigned long msNow; //Current Wait Timer
  unsigned long msLast; //Last Wait Timer
  unsigned long msWait = 2000; //default 2-second Wait
  float calc; //Share for Caculations
    
/* ------------------------------------------------------------------------*/
/// Setup Start Here
void setup() {
  //Stepper Drive Output
  pinMode(EDM,OUTPUT); digitalWrite(EDM,EDMoff);
  pinMode(Zen,OUTPUT); digitalWrite(Zen,Zoff);
  pinMode(Zdir,OUTPUT); digitalWrite(Zdir,ZdirUP);
  pinMode(Zclk,OUTPUT); digitalWrite(Zclk,ZclkL);

  //ZDRV Sensing input
  pinMode(TSense,INPUT_PULLUP);
  pinMode(BSense,INPUT_PULLUP);
  pinMode(iRESET,INPUT_PULLUP);
  pinMode(iSTOP,INPUT_PULLUP);
  pinMode(PSense,INPUT_PULLUP);
  pinMode(ISense,INPUT_PULLUP);

  //ZDRV Key Input
  pinMode(Zdn,INPUT_PULLUP);
  pinMode(Zup,INPUT_PULLUP);
  pinMode(Zrun,INPUT_PULLUP);
  pinMode(Zset,INPUT_PULLUP);
  
  // System Key Input
  pinMode(PageUP,INPUT_PULLUP);
  pinMode(PageDN,INPUT_PULLUP);
  
  // StartUp Page
  Zpage = RUN;

  // Load Z Setup Default
  Zdefault();
  
  // Display Info
  lcd2.begin(20,4);

  //display info
  lcd2.setCursor(0,0); lcd2.print(info0);
  lcd2.setCursor(0,1); lcd2.print(info1);
  lcd2.setCursor(0,2); lcd2.print(info2);
  lcd2.setCursor(0,3); lcd2.print(info3);
  delay(2000);
  lcd2.clear();

  // Read A7 Zclk Setting
  Zin7();
  
  // Enable Z-Drive
  digitalWrite(Zen,Zon);

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

  // Check Zstop Status
  //if (Zstop = 3) Zmode = mPause;
  //if (Zstop = 4) Zmode = mError;

  // Move Z if not in RUN process
  if ((Srun == 0) && (Zstop == 0)) Z2countSet();  

  // Reset Process Index
  if (Zpage!=RUN) Srun=0;
  if (Zpage!=SETUP) Sset=0;
  if (Zpage!=CAL) Scal=0;
  if (Zpage!=RNG) Srng=0;
  
  // iRESET Key Check --------------
  if (digitalRead(iRESET)==LOW) {
    resetBoot();
  }

  // iSTOP Key Check --------------
  if (digitalRead(iSTOP)==LOW) {
    if (Zstop > 0) { Zstop = 0; Zmode = 0; }
    else {
      Zstop=1; Zmode = mPause;
      digitalWrite(EDM,EDMoff);
    }
    ZstatusLine();
    delay(250); // debounce
  }

  // PageUP Key Check --------------
  if (digitalRead(PageUP)==LOW) {
    //if (Zmode==mPause) Zmode=mError;
    //Zpage++;
    //if (Zpage <INF) Zpage=INF;
    //if (Zpage >CAL) Zpage=INF;
    if (Zpage==TEST) { Zpage=RUN; } else { Zpage = TEST; }
    delay(250); // debounce
  }

  // PageDN Key Check --------------
  if (digitalRead(PageDN)==LOW) {
    //if (Zmode==mPause) Zmode=mError;
    //Zpage++;
    //if (Zpage>RUN) Zpage=SETUP;
    Zpage=RUN;
    delay(250); // debounce
  }

  // Zup Key Check --------------
  if ((digitalRead(Zup)==LOW) && (Zstop==0)) {
    do { ZmoveUP1(); } while ((digitalRead(TSense)==HIGH) && (digitalRead(PSense)==LOW) && (digitalRead(iSTOP)==LOW));
    if ((digitalRead(TSense)==HIGH)) {
      ZcountSet++; ZupHold++;
      if (ZupHold>hiSpeed) {
        do { ZmoveUP1(); ZcountSet=Zcount; } while ((digitalRead(TSense)==HIGH) && (digitalRead(PSense)==HIGH) && (digitalRead(Zup)==LOW));
      }
    } else { 
      do {} while ((digitalRead(Zup)==LOW));
    }
  }  else {  ZupHold = 0; }
    
  // Zdn Key Check --------------
  if ((digitalRead(Zdn)==LOW) && (Zstop==0)) {
    if ((digitalRead(PSense)==HIGH) && (digitalRead(BSense)==HIGH) || (Zpage==CAL)) {
      ZcountSet--; ZdnHold++;
      if (ZdnHold>hiSpeed) {
          do { ZmoveDN1(); ZcountSet=Zcount; } while ((digitalRead(PSense)==HIGH) && (digitalRead(BSense)==HIGH) && (digitalRead(Zdn)==LOW));
      }
    } else {
      do {} while (digitalRead(Zdn)==LOW);
    } 
  } else {  ZdnHold = 0; }
    
  // Zrun Key Check --------------
  if (digitalRead(Zrun)==LOW) {
    switch (Zpage) {
      case CAL:
        //Zstop=0;
        Scal++;
        break;
      case RNG:
        //Zstop=0;
        Srng++;
        break;
      case SETUP:
        //Zstop=0;
        
        Sset++;
        break;
      case RUN:
        if (Srun > 4) Srun = 1; //resume RUN
        break; 
    }
    delay(250); // debounce
  }
  
  // Zpage Switching (Main)
  switch(Zpage) {
    
    case TEST:  // I/O Test Panel display, PageUP to Exit
      while (digitalRead(PageUP)==HIGH) {
        /// Z I/O Monitor Page " xxx  ---  ***  +++ "
        lcd2.setCursor(0,0); mfg="TEST ";
          if (digitalRead(PageDN)==LOW) mfg+= " PgD "; else mfg+=" ... ";
          if (digitalRead(Zdn)==LOW) mfg+= " Zdn "; else mfg+=" ... ";
          if (digitalRead(Zup)==LOW) mfg+= " Zup "; else mfg+=" ... ";
          lcd2.print(mfg);
        lcd2.setCursor(0,1); mfg="";
          if (digitalRead(Zrun)==LOW) mfg+= " Run "; else mfg+=" ... ";
          if (digitalRead(Zset)==LOW) mfg+= " Set "; else mfg+=" ... ";
          if (digitalRead(PSense)==LOW) mfg+= " [P] "; else mfg+=" +++ ";
          if (digitalRead(ISense)==LOW) mfg+= " [I] "; else mfg+=" +++ ";
          lcd2.print(mfg);
        lcd2.setCursor(0,2); mfg="";
          if (digitalRead(Zdir)==ZdirDN) mfg+= " ZDN "; else mfg+=" ZUP ";
          if (digitalRead(Zclk)==ZclkL) mfg+= " --- "; else mfg+=" CLK ";
          if (digitalRead(Zen)==Zon) mfg+= " Zon "; else mfg+=" Z-- ";
          if (digitalRead(EDM)==EDMon) mfg+= " Eon "; else mfg+=" E-- ";
          lcd2.print(mfg);
        lcd2.setCursor(0,3); mfg="";
          if (digitalRead(TSense)==LOW) mfg+= " [T] "; else mfg+=" +++ ";
          if (digitalRead(BSense)==LOW) mfg+= " [B] "; else mfg+=" +++ ";
          if (digitalRead(iRESET)==LOW) mfg+= " iRS "; else mfg+=" +++ ";
          if (digitalRead(iSTOP)==LOW) mfg+= " iST "; else mfg+=" +++ ";
          lcd2.print(mfg);
      }
      break;
/*
    case INF:   //Z Info scanning Display, iSTOP=Pause
      msNow = millis();
      //while ((digitalRead(PageUP)==HIGH) && (digitalRead(PageDN)==HIGH) && (digitalRead(iRESET)==HIGH) && (digitalRead(iSTOP)==HIGH)) {
      while ((digitalRead(PageUP)==HIGH) && (digitalRead(PageDN)==HIGH) && (digitalRead(Zrun)==HIGH) && (digitalRead(Zset)==HIGH) && (digitalRead(Zup)==HIGH) && (digitalRead(Zdn)==HIGH) && (digitalRead(iSTOP)==HIGH) && (digitalRead(iRESET)==HIGH)) {
        if (Zmode<3) nextMfg(11); // Next Scanner
        ZstatusLine();
        switch(Next) {
          case 0: break;
          case 1: Zinfor(1); Zshowr(2); Zcntr(3); break; // Range
          case 2: Zinfot(1); Zshowt(2); Zcntt(3); break;
          case 3: Zinfob(1); Zshowb(2); Zcntb(3); break;
          case 4: Zinfoz(1); Zshowz(2); Zcntz(3); break;
          case 5: Zinfop(1); Zshowp(2); Zcntp(3); break;
          case 6: ZinfoP(1); ZshowP(2); ZcntP(3); break;
          case 7: ZinfoX(1); ZshowX(2); ZcntX(3); break;
          case 8: ZinfoG(1); ZshowG(2); ZcntG(3); break;
          case 9: ZinfoC(1); ZshowC(2); ZcntC(3); break;
          case 10: ZinfoE(1); ZshowE(2); ZcntE(3); break;
          case 11: Zinfoe(1); Zshowe(2); Zcnte(3); break;
        }
      }
      break;

    case RNG: // Srange Z Limit Range Finder (Tested v0.30.5)
      digitalWrite(EDM,EDMoff);
      ZstatusLine();
      Zshowr(1);
      Zcntr(2);
      switch(Srng) {
        case 0:
          ZreadyChk(Srng);
          break; 
        case 1: 
          Zready=0; //clear ready flag
          if (digitalRead(PSense)==LOW) { ZprobeErr(Srng); Srng=0; break; }
          Next = 5; showmfg(Srng,mSEEK); //print Top-Limit
          Zmode=mUP; ZstatusLine();
          do { ZmoveUP1(); } while ((digitalRead(TSense)==HIGH) && (digitalRead(PSense)==HIGH) && (digitalRead(iSTOP)==HIGH));
          if (digitalRead(TSense)==HIGH) { Srng = 5; break; }
          Zcount = 0; ZcountSet = Zcount;
          Srng++;
          break;
        case 2: 
          Next = 9; showmfg(Srng,mSEEK); //print Bot-Limit
          Zmode=mDN; ZstatusLine();
          do { ZmoveDN1(); } while ((digitalRead(PSense)==HIGH) && (digitalRead(iSTOP)==HIGH) && (digitalRead(BSense)==HIGH));
          if (digitalRead(BSense)==HIGH) { Srng = 5; break; }
          // Calculation here
          Zcount = -Zcount;
          Zmax = (float)Zcount / Zscale; //new Range
          Zzero = (float)Zmax / 2;  //new MID Zero
          Zupdate(); //update with new data
          Zcount = 0;
          ZcountSet = ZcountZero;
          Next = 6; showmfg(Srng,mSEEK); //print MID Pos
          Srng++; 
          break;
        case 3:
          do { ZmoveUP1(); } while (Zcount < ZcountSet);
          Srng++; 
          break;
        case 4:
          Zinfor(1); Zshowr(2);
          lcd2.setCursor(0,3); lcd2.print(Srng); lcd2.print(" Range Setup DONE  ");
          delay(disptime);
          Zcount = 0; ZcountSet = 0;
          Zready = 3;
          Srng = 0;
          Zpage=INF;
          break;
        case 5: // error, Reload Defalult
        ZcountSet = Zcount;
        ZerrReload();
        Srng=0;
        break;
      }      
      break;

    case CAL:   // Z Scale Calibration
      digitalWrite(EDM,EDMoff);
      ZstatusLine();
      Zinfor(1);
      Zshowr(2);
      // Z-CAL Move Auto Calibration 1-Inch (+Probe Thickness) using PSense as TOP/BOT boundery
      if (Zstop != 0) break; 
      switch(Scal) {
        case 0:
          ZreadyChk(Scal);
          break;
        case 1:
          Zready=0;
          if (digitalRead(PSense)==LOW) {
            ZprobeErr(Scal);
            Scal=0; break; 
          }
          lcd2.setCursor(0,3); lcd2.print(Scal); lcd2.print(" seek DN BaseREF...");
          Zmode=mDN; ZstatusLine();
          do { ZmoveDN1(); } while ((digitalRead(PSense)==HIGH) && (digitalRead(iSTOP)==HIGH) && (digitalRead(BSense)==HIGH));
          if (digitalRead(PSense)==HIGH) { Scal=4; break; }
//lcd2.setCursor(0,3); lcd2.print(Srng); lcd2.print(" BaseREF Found!    ");
          Zcount=0;
          ZcountSet = Zcount + ZcountProx;
          do { ZmoveUP1(); } while ((Zcount < ZcountSet));
          ZstatusLine();
          Scal++; 
          break;
        case 2:
          lcd2.setCursor(0,3); lcd2.print(Scal); lcd2.print(" seek UP to 1-inch ");
          Zmode=mUP; ZstatusLine(); 
          do { ZmoveUP1(); } while ((digitalRead(PSense)==HIGH) && (digitalRead(iSTOP)==HIGH) && (digitalRead(TSense)==HIGH));
          if (digitalRead(PSense)==HIGH) { Scal=4; break; }
//lcd2.setCursor(0,3); lcd2.print(Srng); lcd2.print(" 1-inch Mark Found ");
          if ((Zcount < ZscaleMin) || (Zcount > ZscaleMax)) { Scal=4; break; }
          //Zscale = Zcount;
          Zscale = Zcount + (Zcount * ZcalProde);
          Zmax = (float)(ZcountMMin + ZcountMMax) / Zscale;
          Zupdate();
          ZstatusLine(); 
          lcd2.setCursor(0,1); showInMM((ZcountSet),"P");
//lcd2.setCursor(0,3); lcd2.print(Scal); lcd2.print(" To MID position   ");
          ZcountSet = (long)Zcount - (0.5 * Zscale);
          Zmode=mDN; ZstatusLine(); 
          do { ZmoveDN1(); } while ((Zcount > ZcountSet));
          Scal++; 
          break; 
        case 3:
          lcd2.setCursor(0,3); lcd2.print(Scal); lcd2.print(" Calibration DONE  ");
          delay(disptime);
          Zready=2;
          Scal=0;
          break;
        case 4: // error, Reload Defalult
          ZcountSet = Zcount;
          ZerrReload();
          Scal=0;
          break;
      } 
      break;

    case SETUP:   // Z SETUP Zero > Park > Prox > Gap > End >  
      digitalWrite(EDM,EDMoff);
      ZstatusLine();
      switch(Sset) {
        if (Zstop != 0) break;
        //ZcountCheck();
        case 0:
          ZshowP(1);
          ZshowE(2);
          ZreadyChk(Sset);
          break;
        case 1: // Top > Work-Zero > ReCal
          ZshowT(1);
          ZshowC(2);
// RUN Cycle start here, Error if Psensed
          if ((digitalRead(PSense)==LOW) || (digitalRead(TSense)==LOW)) {
            ZprobeErr(Sset);
            Sset=0; break; 
          }
          Next = 5; showmfg(Sset,mSEEK); //print Top-Limit
          Zmode=mUP; ZstatusLine();
          do { ZmoveUP1(); } while ((digitalRead(PSense)==HIGH) && (digitalRead(TSense)==HIGH) && (digitalRead(iRESET)==HIGH) && (digitalRead(iSTOP)==HIGH));
// Error if not stop by Tsense
          if (digitalRead(TSense)==HIGH) { Sset=0; ZerrReload(); break; }
          Zcount=0; // Set Top Reference
          Next = 10; showmfg(Sset,mSEEK); //print Work-Zero
          Zmode=mDN; ZstatusLine();
          do { ZmoveDN1(); } while ((digitalRead(PSense)==HIGH) && (digitalRead(BSense)==HIGH) && (digitalRead(iRESET)==HIGH) && (digitalRead(iSTOP)==HIGH));
// Error if not stop by Psense
          if (digitalRead(PSense)==HIGH) { Sset=0; ZerrReload(); break; }      
          //Next = 11; showmfg(Sset,mSEEK); //print FineTune Work-Zero
          //ZcountSet = Zcount + 250;
          //ZcountSet = Zcount + 100;
          //do { ZmoveUP1(); } while (( Zcount < ZcountSet) && (digitalRead(BSense)==HIGH));
          //do { ZmoveDN1(); ZstatusLine(); } while ((digitalRead(PSense)==HIGH) && (digitalRead(BSense)==HIGH));
          //if (digitalRead(BSense)==LOW) { Sset=0; ZerrReload(); break; }

// Work Zero found
          ZcountMax = -Zcount;
          ZcountZero = (float)Zmax * Zscale - ZcountMax;
          ZcountMin = -ZcountZero;
          Zzero = ZcountZero / Zscale;
          Zcount = 0; 
          
          ZcountSet = ZcountPark; //next POS
          Zmode=mUP; ZstatusLine(); 
          do { ZmoveUP1(); } while (Zcount < ZcountSet);
          Sset++;
          break;
        case 2: //PARK Adjust w/ normal UP/DN
          ZshowP(1);
          lcd2.setCursor(0,2); showInMM(ZcountSet,"p");
          nextMfg(2); showmfg(Sset,mPARK); //print Edit
          if (ZcountSet < 0 ) { ZcountSet = 0; ZdnHold=0; }
          if (digitalRead(Zset) == LOW) { 
            Next = 3; showmfg(Sset,mPARK); //print saved
            ZcountPark = Zcount; Zpark = (float)Zcount / Zscale; ZcountSet = Zcount;
            delay(500); Sset++;
          } else {
            if (digitalRead(Zrun) == LOW) {
            Next = 4; showmfg(Sset,mPARK); //print skip
            ZcountSet = ZcountPark;
            delay(500); Sset++;
            }
          }
          break;
        case 3: //move to current Prox
          Sset++; //not used
          //ZcountSet = ZcountProx; //next POS
          //do { ZmoveDN1(); } while (Zcount > ZcountSet);
          //ZstatusLine();
          //if (Zcount == ZcountSet) { Zstop=1; Zmode = mPause; ZcountSet = ZcountProx; Sset++; }  // check POS before lockdown
          break; 
        case 4: // work on END Position
          Zstop=1;  // ensure lockdown
          ZshowE(1);
          do {
            nextMfg(2); showmfg(Sset,mEND); //print Edit
            lcd2.setCursor(0,2); showInMM(ZcountSet,"e");
            Zvirtual(); ZstatusLine();
            if (ZcountSet>0) ZcountSet=0;
            if (ZcountSet<ZcountMin) ZcountSet=ZcountMin;
          } while ((digitalRead(Zset) == HIGH) && (digitalRead(Zrun) == HIGH));
          if (digitalRead(Zset) == LOW) { 
            Next = 3; showmfg(Sset,mEND); //print saved
            ZcountEnd = ZcountSet; 
            Zend = (float)ZcountSet / Zscale; ZcountSet = Zcount;
            delay(500); Sset++; break; 
          } else {
            if (digitalRead(Zrun) == LOW) {
              Next = 4; showmfg(Sset,mEND); //print skip
              ZcountSet = ZcountEnd;
              lcd2.setCursor(0,2); showInMM(ZcountSet,"e");      
              delay(500); Sset++; break; 
            }
          }
          Zupdate(); ZcountCheck();
          break;
        case 5:
          do {
            nextMfg(2);
            switch(Next) {
              case 0: Zinfot(1); ZinfoP(2); break;
              case 1: ZinfoX(1); ZinfoG(2); break;
              case 2: ZinfoE(1); Zinfob(2); break; 
            }
            Next = 2; dispmfg(Sset); //print S to keep, R to redo
            ZcountSet = ZcountPark;
            Zstop=0;
            do {} while (digitalRead(iSTOP)==LOW);
          } while ((digitalRead(Zset)==HIGH) && (digitalRead(Zrun)==HIGH));
          if (digitalRead(Zset)==LOW) { Sset=0; Srun=0; Zready=4; Zpage=RUN; } else { Sset=1; }
          break;
      } 
      break;
*/
    case RUN:   // Z RUN
      ZstatusLine();
      switch(Srun) {
        case 0:
          //ZshowE(1);
          //ZshowC(2);
          Z2Bmsg();     
          ZreadyChk(Srun);
          if (digitalRead(Zrun)==LOW) { Zstop=0; Srun++; }
          break;
        
        case 1: //RUN start, define Work-Zero
          ZshowT(1); ZshowC(2);
          Next = 10; showmfg(Srun,mSEEK); //print Work-Zero
          Zmode=mDN; ZstatusLine();
          do { ZmoveDN1(); } while ((digitalRead(PSense)==HIGH) && (digitalRead(BSense)==HIGH) && (digitalRead(iSTOP)==HIGH));
          if (digitalRead(PSense)==HIGH) { Srun=0; ZerrReload(); break; }      
          Zcount = 0;
          Next = 4; dispmfg(Srun); //print to Start Position
          ZcountSet = ZcountProx;
          do { ZmoveUP1(); } while ((Zcount < ZcountSet) );
          //Zmode=mDN; ZstatusLine();
          //ZshowX(1); ZshowC(2);
          //((digitalRead(iSTOP)==LOW) || (digitalRead(PSense)==LOW) || (digitalRead(ISense)==LOW))  { Srun=0; break; } //error checking
          Srun++; 
          break;

// <Run> Start Srun = 2; at ZcountProx
// <iSTOP> Move to Park
///***        
        case 2: // Looping until Finish or iSTOP or Bsense hit
          //ZshowE(1);
          Z2Bmsg();
          Next = 5; dispmfg(Srun); //print Job in Progress

// Loop Start here
          while ((digitalRead(BSense)==HIGH)) {
          //while ((Zcount > ZcountEnd) ) {
              //ZshowC(2);
//Goto Start Gap Position fast
              do { ZmoveDN1(); } while ((Zcount > ZcountGap) && (digitalRead(PSense)==HIGH) && (digitalRead(ISense)==HIGH) && (digitalRead(BSense)==HIGH)) ;
              //do { ZmoveDN1(); } while ((Zcount > ZcountGap));
// EDM Start
              digitalWrite(EDM,EDMon);
              //ZstatusLine();           
              do { ZmoveDN1(); } while ((digitalRead(PSense)==HIGH) && (digitalRead(ISense)==HIGH));

// Spark Gap Controls
              while (digitalRead(ISense)==LOW) { ZmoveUP1();}
              //if (digitalRead(ISense)==LOW) { Zclear++; }
              while (digitalRead(PSense)==LOW) { ZmoveUP1(); }
/*              
              if (Zclear > 1000) { // cleaning, move to Gap
                Zclear=0; Zstop=0; 
                Next = 9; dispmfg(Srun); //print Cleaning
                do { ZmoveUP1(); } while (Zcount < ZcountGap); 
                ZshowC(2);
                break; 
              }
*/
// Z-Botom Reached
              if (digitalRead(BSense)==LOW) { // BSense Z-Bottom 
// Check again with EDM OFF
                digitalWrite(EDM,EDMoff);
                delay (250);
                if (digitalRead(BSense)==LOW) { // BSense Z-Bottom Reached, Exit Job
                  Next = 8; dispmfg(Srun); //print Z-Bottom Reach
                  do { ZmoveUP1(); } while ((digitalRead(TSense)==HIGH));  // Move to Park
                  anyKey(); 
                  Srun=0;
                  break;
                } else { 
                    do { ZmoveUP1(); } while ((digitalRead(PSense)==LOW));
                    Srun=2; 
                    break; }
              }
// Zup
              if (digitalRead(Zup)==LOW) { //UP interruping to Prox than resume
                digitalWrite(EDM,EDMoff); 
                //Zclear=0; Zstop=0; 
                do { ZmoveUP1(); } while ((digitalRead(Zup)==LOW) && (digitalRead(TSense)==HIGH)); // Move UP
                Srun=2;
                break; 
              } 

// iSTOP PAUSE
              if (digitalRead(iSTOP)==LOW) { // Job Pause
// Check again with EDM OFF
                digitalWrite(EDM,EDMoff);
                delay (250);
                if (digitalRead(iSTOP)==LOW) { // Confirmed
                  Zstop=0; 
                  do { ZmoveUP1(); } while ((digitalRead(TSense)==HIGH));  // Move to Top
                  Srun=4; 
                  break; 
                } else {
                    do { ZmoveUP1(); } while ((digitalRead(PSense)==LOW));
                    Srun=2; 
                    break; 
                    }
                }

// iRESET Key Check --------------
              if (digitalRead(iRESET)==LOW) {
// Check again with EDM OFF
                digitalWrite(EDM,EDMoff);
                delay (250);
                if (digitalRead(iRESET)==LOW) { // Confirmed
                  Zstop=0; 
                  do { ZmoveUP1(); } while ((digitalRead(TSense)==HIGH));  // Move to Top
                  resetBoot(); break; 
                } else {
                    do { ZmoveUP1(); } while ((digitalRead(PSense)==LOW));
                    Srun=2; 
                    break;
                    }
                }

// cont
          }
/*
// PSense Check
          do { ZmoveUP1(); } while ((digitalRead(PSense)==LOW) && (digitalRead(TSense)==HIGH));  // Move to Top
          digitalWrite(EDM,EDMoff);
          Srun=0;
*/
          break;
// Exiting Job Loop check 
/*
// End of RUN, End has reached 
          if (ZcountEnd < Zcount) {
            break;
          } else {
            Next = 3; dispmfg(Srun); //print JOB Done. R next 
            Srun = 6; // goto Job Finish
            break;
          }
*/
        case 3: // Job Cont
          Next = 9; dispmfg(Srun); //print Cleaning
          Srun=2;
          break;

        case 4: //Pause at ZcountPark Position, RUN to resume
          ZshowC(2);
          Next = 6; dispmfg(Srun); //print Job Pause R to resume
          if (digitalRead(Zrun)==LOW) { Srun=2; break; }  //Job Resume
          if (digitalRead(iSTOP)==LOW) { Srun=5; break; } //Job Cancel
          anyKey(); 
          Srun=2;
          break;    
/*          
          msLast = millis();
          do {
            msNow = millis();
            if (digitalRead(Zrun)==LOW) { Srun=2; break; }  //Job Resume
            if (digitalRead(iSTOP)==LOW) { Srun=5; break; } //Job Cancel
          } while (msNow-msLast > 5000);
          Srun=2;
          break;        
*/        
        case 5: // Job Cancel, Exit
          ZshowC(2);
          Next = 7; dispmfg(Srun); //print Job Cancel, move to Park
          digitalWrite(EDM,EDMoff);
          Zstop=0;
          //do { ZmoveUP1(); } while ((Zcount < ZcountPark) && (digitalRead(TSense)==HIGH));  // Move to Park
          do { ZmoveUP1(); } while ((digitalRead(TSense)==HIGH));  // Move to Top
          //anyKey(); 
          Srun=0;
          break;

        case 6: // Job Finish
          digitalWrite(EDM,EDMoff);
          Zstop=0;
          //do { ZmoveUP1(); } while ((Zcount < ZcountPark) && (digitalRead(TSense)==HIGH));  // Move to Park
          do { ZmoveUP1(); } while ((digitalRead(TSense)==HIGH));  // Move to Top
          //anyKey(); 
          Srun=0;
          break;
        }
  }
}
/// Program End Here
/* Condition Check ------------------------------------------------------------------------*/
/// Check AnyKey Press
void anyKey() {
  do {} while ((digitalRead(PageUP)==HIGH) && (digitalRead(PageDN)==HIGH) && (digitalRead(Zrun)==HIGH) && (digitalRead(Zset)==HIGH) && (digitalRead(Zup)==HIGH) && (digitalRead(Zdn)==HIGH) && (digitalRead(iSTOP)==HIGH) && (digitalRead(iRESET)==HIGH));
}

///Set ZCLK Speed
void Zin7() {
//  Next = 0; do { Ain7 = analogRead(A7pulse); Next++; } while (Next < 3);  //Read 3 times
  Ain7 = analogRead(A7pulse); //Read once
  Ain7 = pulseMin + (Ain7 * 2); 
  //calc = 1000000 / (Ain7 * 2);
}

/// Z Default Reload Works Setup Default
void Zdefault() {
  Zscale = ZscaleDefault;
  Zmax = ZmaxDefault;
  Zzero = Zmax /2;  //Default MID Pos as Work Zero
  Zready=1;
  Zupdate();
}

/// Z Scale Update and Check
void Zupdate() {
  ZcountZero = (float)Zzero * Zscale; //machine offset counts
  ZcountMMax = ((float)Zmax * Zscale); //machine Z range counts
  ZcountMax = ZcountMMax - ZcountZero; //work Top-Limit
  ZcountMin = -ZcountZero;  //work Bot-Limit
  ZcountPark = ((float)Zpark * Zscale); //Delta from wZero
  ZcountProx = ((float)Zprox * Zscale); //Delta from wZero
  ZcountEnd = ((float)Zend * Zscale); //Delta from wZero
  ZcountGap = ((float)Zgap * Zscale); //Delta from wZero
}

/// Z Parameter Check  Max > Park > Prox > Gap > Zero > End > Min
void ZcountCheck() {
  if ((Zscale < ZscaleMin) || (Zscale > ZscaleMax)) ZerrStop(); //chk against #defind
  if ((ZcountPark < ZcountProx) || (ZcountProx < ZcountGap) || (ZcountGap < 0) || (0 < ZcountEnd) || (ZcountEnd < ZcountMin)) ZerrStop();
  if ((ZcountMax < (ZcountZero + ZcountPark)) || (ZcountZero < 0)) ZerrStop();
}

/// Z Error Stop
void ZerrStop() {
  Zstop=1;
  ZerrReload();
}

/// Z-Drive ERR Reload Default
void ZerrReload() {
  lcd2.clear();
  mfg = ("Reload Default");
  lcd2.setCursor(3,1); lcd2.print(mfg);
  Zdefault();
  delay (disptime);
}

/// Z-Drive Probe Error print
void ZprobeErr(int j) {
  mfg = ("  ! Probe ERROR !  ");
  lcd2.setCursor(0,3); lcd2.print(mfg); 
  delay(disptime);
}

/* Z-MOVEMENT >>------------------------------------------------------------------------*/
/// Z Direction UP setup
void ZsetUP() {
  Zmode = mUP;
  digitalWrite(Zdir, ZdirUP);
}

/// Z Direction DN setup
void ZsetDN() {
  Zmode = mDN;
  digitalWrite(Zdir, ZdirDN);
}

/// Z Clock for Normal ---------------------------------------------------------------
void Zclock() {
  //digitalWrite(Zclk, ZclkH); delayMicroseconds(pulsewidth); digitalWrite(Zclk, ZclkL); delayMicroseconds(pulsegap);
  Zin7();
  digitalWrite(Zclk, ZclkH); delayMicroseconds(Ain7); digitalWrite(Zclk, ZclkL); delayMicroseconds(Ain7);
}

/// Z move to Prox Absolute POS
void Zmove2prox() {
  ZcountSet = ZcountProx;
  do { Z2countSet(); } while (Zcount != ZcountSet );
}

/// Z move to Park
void Zmove2park() {
  ZcountSet = ZcountPark;
  do { Z2countSet(); } while (Zcount != ZcountSet );
}

/// Z move to GAP
void Zmove2gap() {
  ZcountSet = ZcountGap;
  do { Z2countSet(); } while (Zcount != ZcountSet );
}
 
/// Z move to Set Position
void Z2countSet() {
  if ((Zstop!=0) || (Zcount == ZcountSet)) return;
  if (Zcount < ZcountSet) { 
    do { ZmoveUP1(); } while ((Zcount < ZcountSet) && (digitalRead(PSense)==HIGH) && (digitalRead(iRESET)==HIGH) && (digitalRead(iSTOP)==HIGH) && digitalRead(TSense)==HIGH);
    if (digitalRead(PSense)==LOW || digitalRead(TSense)==LOW) ZcountSet = Zcount;
  } else {
    do { ZmoveDN1(); } while ((Zcount > ZcountSet) && (digitalRead(PSense)==HIGH) && (digitalRead(iRESET)==HIGH) && (digitalRead(iSTOP)==HIGH) && digitalRead(BSense)==HIGH);
    if (digitalRead(PSense)==LOW || digitalRead(BSense)==LOW) ZcountSet=Zcount;
  }
}

/// Z Move UP 1
void ZmoveUP1() {
  if (Zstop!=0) return;
  ZsetUP(); Zclock();
  Zcount++;  
}

/// Z Move DN 1
void ZmoveDN1() {
  if (Zstop!=0) return;
  ZsetDN(); Zclock();
  Zcount--;  
}

/// Z Virtual Movement
void Zvirtual() {
  if (digitalRead(Zup)==LOW) {
    ZcountSet++; ZupHold++;
    if (ZupHold>10) ZcountSet += ZupHold; 
  } else ZupHold=0;
  if (digitalRead(Zdn)==LOW) {
    ZcountSet--; ZdnHold++;
    if (ZdnHold>10) ZcountSet -= ZdnHold; 
  } else ZdnHold=0;
}

/* DISPLAY >>------------------------------------------------------------------------*/
/// RUN to BSense DIsplay
void Z2Bmsg() {
  lcd2.setCursor(0,1); lcd2.print("  [RUN] to Start    ");
  lcd2.setCursor(0,2); lcd2.print(" End at BOT-Sense.  ");
}

/// Z Status Display in Line0
void ZstatusLine() {
  lcd2.setCursor(0,0);
  lcd2.print(Zpagemsg[Zpage]); lcd2.print(Zmodemsg[Zmode]); 
  if (Zcount==ZcountSet) { lcd2.print("#       "); lcd2.setCursor(14,0); lcd2.print(Zscale); }
  else {
    lcd2.print("        "); lcd2.setCursor(13,0); 
    if (Zcount > -1) lcd2.print("+");
    lcd2.print(Zcount); 
  } 
}

/// Z Info Display in Line(j) Lowwer-case =Mechine, Upper-case = from Work Zero
void Zinfor(byte j) { lcd2.setCursor(0,j); showInfo((Zmax*Zscale), "r =Z-Range "); }
void Zinfot(byte j) { lcd2.setCursor(0,j); showInfo((ZcountMax), "t wTop Max "); }
void Zinfob(byte j) { lcd2.setCursor(0,j); showInfo((ZcountMin), "b wBot Min "); }
void Zinfoz(byte j) { lcd2.setCursor(0,j); showInfo((ZcountZero), "z =Zero Ref"); }
void Zinfop(byte j) { lcd2.setCursor(0,j); showInfo((ZcountPark+ZcountZero),"p =Park-POS"); }
void ZinfoP(byte j) { lcd2.setCursor(0,j); showInfo((ZcountPark),"P wPark-POS"); }
void Zinfox(byte j) { lcd2.setCursor(0,j); showInfo((ZcountProx+ZcountZero),"x =Prox-POS"); }
void ZinfoX(byte j) { lcd2.setCursor(0,j); showInfo((ZcountProx),"X wProx-POS"); }
void ZinfoC(byte j) { lcd2.setCursor(0,j); showInfo((Zcount),    "C wCurrent "); }
void ZinfoT(byte j) { lcd2.setCursor(0,j); showInfo((ZcountSet), "T wTarget  "); }
void Zinfoe(byte j) { lcd2.setCursor(0,j); showInfo((ZcountEnd+ZcountZero), "e =End-POS "); }
void ZinfoE(byte j) { lcd2.setCursor(0,j); showInfo((ZcountEnd), "E wEnd-POS "); }
void ZinfoG(byte j) { lcd2.setCursor(0,j); showInfo((ZcountGap), "G wGap-val "); }

void Zshowr(byte j) { lcd2.setCursor(0,j); showInMM((Zmax*Zscale), "r"); }
void Zshowt(byte j) { lcd2.setCursor(0,j); showInMM((ZcountMax), "t"); }
void Zshowb(byte j) { lcd2.setCursor(0,j); showInMM((ZcountMin), "b"); }
void Zshowz(byte j) { lcd2.setCursor(0,j); showInMM((ZcountZero),"z"); }
void Zshowp(byte j) { lcd2.setCursor(0,j); showInMM((ZcountPark+ZcountZero),"p"); }
void ZshowP(byte j) { lcd2.setCursor(0,j); showInMM((ZcountPark),"P"); }
void Zshowx(byte j) { lcd2.setCursor(0,j); showInMM((ZcountProx+ZcountZero),"x"); }
void ZshowX(byte j) { lcd2.setCursor(0,j); showInMM((ZcountProx),"X"); }
void ZshowC(byte j) { lcd2.setCursor(0,j); showInMM((Zcount),    "C"); }
void ZshowT(byte j) { lcd2.setCursor(0,j); showInMM((ZcountSet), "T"); }
void Zshowe(byte j) { lcd2.setCursor(0,j); showInMM((ZcountEnd+ZcountZero), "e"); }
void ZshowE(byte j) { lcd2.setCursor(0,j); showInMM((ZcountEnd), "E"); }
void ZshowG(byte j) { lcd2.setCursor(0,j); showInMM((ZcountGap), "G"); }

void Zcntr(byte j) { lcd2.setCursor(0,j); showInCNT((Zmax*Zscale), "r"); }
void Zcntt(byte j) { lcd2.setCursor(0,j); showInCNT((ZcountMax), "t"); }
void Zcntb(byte j) { lcd2.setCursor(0,j); showInCNT((ZcountMin), "b"); }
void Zcntz(byte j) { lcd2.setCursor(0,j); showInCNT((ZcountZero),"z"); }
void Zcntp(byte j) { lcd2.setCursor(0,j); showInCNT((ZcountPark+ZcountZero),"p"); }
void ZcntP(byte j) { lcd2.setCursor(0,j); showInCNT((ZcountPark),"P"); }
void Zcntx(byte j) { lcd2.setCursor(0,j); showInCNT((ZcountProx+ZcountZero),"x"); }
void ZcntX(byte j) { lcd2.setCursor(0,j); showInCNT((ZcountProx),"X"); }
void ZcntC(byte j) { lcd2.setCursor(0,j); showInCNT((Zcount),    "C"); }
void ZcntT(byte j) { lcd2.setCursor(0,j); showInCNT((ZcountSet), "T"); }
void Zcnte(byte j) { lcd2.setCursor(0,j); showInCNT((ZcountEnd+ZcountZero), "e"); }
void ZcntE(byte j) { lcd2.setCursor(0,j); showInCNT((ZcountEnd), "E"); }
void ZcntG(byte j) { lcd2.setCursor(0,j); showInCNT((ZcountGap), "G"); }

void ZreadyDisp(byte j) {
  lcd2.setCursor(0,j); 
  mfg = ("Sys-Status: "); //12-chr
  switch (Zready) {
    case 0: mfg+=("NotReady"); break;
    case 1: mfg+=("Default "); break;
    case 2: mfg+=("ZscaleOK"); break;
    case 3: mfg+=("Range OK"); break;
    case 4: mfg+=("Setup OK"); break;
  }
  lcd2.print(mfg);
}

/// Display in Line 0, ReadCheck prior RUN m=Sxxx value
void ZreadyChk(byte m) {
  mfg = (m);
  if (Zmode < mPause) { 
    mfg += (" [RUN] w/"); // 10-chr
    switch(Zready) {
      case 0: mfg += ("Not Ready "); break;
      case 1: mfg += ("Default   "); break;
      case 2: mfg += ("ZScale Chk"); break;
      case 3: mfg += ("ZRange Chk"); break;
      case 4: mfg += ("ZSetup Chk"); break;
    }
  } else {
    if (Zmode==mPause) { 
      mfg += (" ! System PAUSE !  "); 
    } else {
      mfg += (" ! System ERROR !  ");
    }
  }
  lcd2.setCursor(0,3); lcd2.print(mfg);  
}

/// Display Setting Info j=Step m=Label display=Next
void showmfg(byte j, byte m) {
  mfg = (j); mfg += Zposmsg[m]; mfg += " "; //6-chr
  switch (Next) {
    case 0: mfg += ("[Up/Dn] to Adj"); break;
    case 1: mfg += ("[SET] to Save "); break;
    case 2: mfg += ("[RUN] to Skip "); break;
    case 3: mfg += ("Position Saved"); break;
    case 4: mfg += ("No Change,Skip"); break;
    case 5: mfg += ("goto TOP-Limit"); break;
    case 6: mfg += ("goto MID Pos. "); break;
    case 7: mfg += ("goto PARK Pos."); break;
    case 8: mfg += ("goto PROX Pos."); break;
    case 9: mfg += ("goto BOT-Limit"); break;
    case 10: mfg += ("goto Work-Zero"); break;
    case 11: mfg += ("tune Work-Zero"); break;
  }
  lcd2.setCursor(0,3); lcd2.print(mfg);  
}

// Display Progress Info j=Step
void dispmfg(int j) {
  mfg = (j); mfg += " "; //2-chr
  switch (Next) {
    case 0: mfg += ("[RUN] key to Start"); break;
    case 1: mfg += ("[RUN] to Continue "); break;
    case 2: mfg += ("[S]keep [RUN]redo "); break;
    case 3: mfg += ("JOB Finished.     "); break;
    case 4: mfg += ("to Start Position "); break;
    case 5: mfg += ("Job in Progress..."); break;
    case 6: mfg += ("PAUSE [RUN]resume "); break;
    case 7: mfg += ("Job Cancel...     "); break;
    case 8: mfg += ("Z-Bottom Reached. "); break;
    case 9: mfg += ("Cleaning...       "); break;
  }
  lcd2.setCursor(0,3); lcd2.print(mfg);  
}

/// Display Next mfg, J=loopback
void nextMfg(int j) {
  msNow = millis();
  if (msNow-msLast > msWait) {
    msLast = msNow;
    Next++; 
    if ((Next < 0) || (Next > j)) { Next = 0; }
  }  
}

/// Display Timer Clear
void msClear() {
  msNow=0; msLast=0;
}


/// Display Inch + Count "+xx.xxx" T +xxxxxcnt"
void showInCNT(float Zdata, String m) {
 float Zcnt = Zdata;
  Zdata = Zdata / Zscale;
  mfg = ""; 
  if (Zdata < 0) { 
    if (Zdata >-10) { mfg += " "; } 
  } else {
    if (Zdata < 10) { mfg += " "; } 
    mfg += "+";
  }
  mfg += String(Zdata,3); mfg += char(34); mfg += " ";
  // Print m
  mfg += m; 
  // Print (mm)
  mfg += " ";
  if (Zcnt < 0) {
    if (Zcnt>-10000) mfg += " ";
    if (Zcnt>-1000) mfg += " ";
    if (Zcnt>-100) mfg += " ";
    if (Zcnt>-10) mfg += " ";
  } else {
    if (Zcnt<10000) mfg += " ";
    if (Zcnt<1000) mfg += " ";
    if (Zcnt<100) mfg += " ";
    //if (Zcnt<10) mfg += " ";
    mfg += "+";
  }
  mfg += String(Zcnt,0); mfg += "cnt";
  lcd2.print (mfg);  
}

/// Display Inch + MM "+xx.xxx" T +xxx.xxmm" from Count
void showInMM(float Zdata, String m) {
  Zdata = Zdata / Zscale;
  mfg = ""; 
  if (Zdata < 0) { 
    if (Zdata >-10) { mfg += " "; } 
  } else {
    if (Zdata < 10) { mfg += " "; } 
      mfg += "+";
  }
  mfg += String(Zdata,3); mfg += char(34); mfg += " ";
  // Print m
  mfg += m; 
  // Print (mm)
  mfg += " ";
  Zdata = Zdata * 25.4;
  if (Zdata < 0) { 
    if (Zdata >-10) { mfg += "  "; } 
    else { if (Zdata >-100) { mfg += " "; } 
    }
  } else {
    if (Zdata < 10) { mfg += "  "; } 
    else { if (Zdata < 100) { mfg += " "; } 
    }
    mfg += "+";
  }
  mfg += String(Zdata,2); mfg += "mm";
  lcd2.print (mfg);  
}

/// Display Inch + Info Text (11-chr) from Count
void showInfo(float Zdata, String m) {
  Zdata = Zdata / Zscale;
  mfg = ""; 
  if (Zdata < 0) { 
    if (Zdata >-10) { mfg += " "; } 
  } else {
    if (Zdata < 10) { mfg += " "; } 
    mfg += "+";
  }
  mfg += String(Zdata,3); mfg += char(34); mfg += " ";
  mfg += m; 
  lcd2.print (mfg);  
}

/// RESET BOOT -----------------------------------------------------------------------
void resetBoot() {
  asm volatile ("  jmp 0");
}

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