Neptune_170620

Dependencies:   mbed

Revision:
0:20b4b057fa7f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Functions.cpp	Wed Jun 17 10:11:19 2020 +0000
@@ -0,0 +1,1030 @@
+#include <string> 
+#include "main.h"
+#include "Functions.h"
+#include "Definitions.h"
+#include "Boolean.h"
+#include "NextionLCD.h"
+#include "mbed_debug.h"
+#include "mbed.h"
+#include "Languages.h"
+#include "Ser25lcxxx.h"
+#include "NVM.h"
+#include "Watchdog.h"
+#include "NextionPages.h"
+#include "Controls.h"
+#include "Threads.h"
+#include "ISR.h"
+#include "FastPWM.h"
+
+///////////////////////////////////////////////////////////////////////////////
+// MBED OBJECTS
+///////////////////////////////////////////////////////////////////////////////
+extern NextionLCD lcd;//Tx, Rx, Nextion Port
+
+Thread thread;
+volatile uint16_t loopTime = 0; 
+volatile bool loopTimeFlag = false;
+volatile bool readFlag = false;
+
+///////////////////////////////////////////////////////////////////////////////
+// VARIABLES
+///////////////////////////////////////////////////////////////////////////////
+bool incFlag = false;
+bool decFlag = false;
+bool okFlag =  false;
+bool manFlag = false;
+
+uint8_t pumpType = QDOS_30;
+uint8_t calState = ZERO;
+
+///////////////////////////////////////////////////////////////////////////////
+// THREADS
+///////////////////////////////////////////////////////////////////////////////
+void loopTime_thread(){
+
+    while(1){
+        #ifdef LOOP_TIME        
+            if(readFlag){
+                pc.printf("\r\n\r\n Loop Time \t=  %d us",loopTime);
+                readFlag = false;
+                loopTimeFlag = true;                
+            }
+        #endif
+    }
+}
+
+void loopTimeMeasure(void){
+
+    #ifdef LOOP_TIME                                          
+        if(!loopTimeFlag){
+            //wait_us(20);//add a known time to verify the accuracy of the loop timer
+            tSec.stop();    
+            loopTime  = tSec.read_us();
+            //run_stat_out_oc = 1;
+            readFlag = true;         
+        }
+        else{
+            tSec.reset();
+            tSec.start(); 
+            loopTimeFlag = false;   
+            //run_stat_out_oc = 0;          
+        }
+    #endif    
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// ARRAYS
+///////////////////////////////////////////////////////////////////////////////
+char buffer[20];
+
+const uint8_t uOutPut1_ID[7] = {
+    OUT1_GENERAL_ALARM,
+    OUT1_RUN_STATUS,         
+    OUT1_MANUAL_MODE,        
+    OUT1_ANALOGUE_MODE,      
+    OUT1_CONTACT_MODE,       
+    OUT1_FLUID_LEVEL,        
+    OUT1_LEAK_DETECT        
+};
+
+const uint8_t uOutPut2_ID[7] = {
+    OUT2_GENERAL_ALARM,
+    OUT2_RUN_STATUS,         
+    OUT2_MANUAL_MODE,        
+    OUT2_ANALOGUE_MODE,      
+    OUT2_CONTACT_MODE,       
+    OUT2_FLUID_LEVEL,        
+    OUT2_LEAK_DETECT        
+};
+
+const uint8_t uFlowUnitID[10] = {
+    PERCENT,
+    GPD,
+    GPH,
+    ML_HR,                 
+    ML_MIN,
+    L_DAY,                  
+    L_HR,                
+    L_MIN,
+    OZ_MIN,            
+    RPM 
+};
+
+const string menuStringArray[3][10] = {//[Group][Item], 2 groups, 10 items in each group i.e menuItems[1][6]= "Leak Detect"
+     "%\0",       //0x10
+     "gpd\0",     //0x11
+     "gph\0",     //0x12
+     "ml/hr\0",   //0x13
+     "ml/min\0",  //0x14
+     "l/day\0",   //0x15
+     "l/hr\0",    //0x16
+     "l/min\0",   //0x17   
+     "oz/min\0",  //0x18
+     "RPM\0",     //0x19 
+
+    "General Alarm\0",
+    "Run Status\0",
+    "Manual Mode\0",
+    "Analogue Mode\0",
+    "Contact Mode\0",
+    "Fluid Level\0",
+    "Leak Detect\0",
+    "A1\0",
+    "B1\0",
+    "C1\0",
+
+    "General Alarm\0",
+    "Run Status\0",
+    "Manual Mode\0",
+    "Analogue Mode\0",
+    "Contact Mode\0",
+    "Fluid Level\0",
+    "Leak Detect\0",
+    "A2\0",
+    "B2\0",
+    "C2\0"   
+};
+
+const float fMaxFlowUnits[5][10] = {
+
+      //QDOS 30          
+      100.0,//%
+      190.2,//gpd
+      7.925,//gph
+      30.00,//l/hr
+      500.0,//ml/min
+      720.0,//l/day
+      30.00,//l/hr
+      0.500,//l/min        
+      17.6,//oz
+      125.0,//rpm
+
+      //VDOS 20          
+      100.0,
+      131.06,
+      5.46,
+      20670.00,
+      344.50,
+      496.08,
+      20.67,
+      0.34,        
+      12.15,
+      65.0,
+
+      //VDOS 30  
+      100.0,
+      191.56,
+      7.98,
+      30210.00,
+      503.50,
+      725.04,
+      30.21,
+      0.50,        
+      17.76,
+      95.00,
+
+      //VDOS 60  
+      100.0,
+      380.83,
+      15.87,
+      60060.00,
+      1001.00,
+      1441.44,
+      60.06,
+      1.00,        
+      35.31,
+      110.00,    
+
+      //VDOS 120  
+      100.0,
+      765.62,
+      31.90,
+      120744.00,
+      2012.40,
+      2897.86,
+      120.74,
+      2.01,        
+      70.98,
+      129.00        
+};      
+
+const float fMinFlowUnits[5][10] = {
+
+      //QDOS 30          
+      0.1,//%
+      0.1,//gpd
+      0.001,//gph
+      1.0,//ml/hr
+      0.1,//ml/min
+      0.1,//l/day
+      0.01,//l/hr
+      0.001,//l/min        
+      0.1,//oz
+      0.1,//rpm
+
+      //VDOS 20          
+      0.2,
+      0.26,
+      0.01,
+      41.34,
+      0.87,
+      0.99,
+      0.04,
+      0.00,        
+      0.02,
+      5.0,
+
+      //VDOS 30  
+      0.2,
+      0.38,
+      0.02,
+      60.42,
+      1.01,
+      1.45,
+      0.06,
+      0.00,        
+      0.04,
+      5.0,
+
+      //VDOS 60  
+      0.2,
+      0.76,
+      0.03,
+      120.12,
+      2.0,
+      2.88,
+      0.16,
+      0.00,        
+      0.07,
+      5.0,    
+
+      //VDOS 120  
+      0.2,
+      1.53,
+      0.06,
+      241.49,
+      4.02,
+      5.80,
+      0.24,
+      0.00,        
+      0.14,
+      5.0        
+};  
+
+
+///////////////////////////////////////////////////////////////////////////////
+// FUNCTIONS
+///////////////////////////////////////////////////////////////////////////////
+void sysInit(void){
+
+    wait(0.250);//settle time
+
+    pc.baud(MED_BAUD);//Debug Port
+    usart6.baud(MED_BAUD);//Motor Controller Port
+
+    led1=ON; 
+    led2=ON; 
+    led3=ON; 
+    wait(2.00);
+    led1=OFF; 
+    led2=OFF; 
+    led3=OFF; 
+
+    nexInit(MED_BAUD);       
+    reset();
+
+    //4-20mA Control Outputs
+    alarmOut1 = OFF;
+    alarmOut2 = OFF;
+
+    initNVM();//Initialise the NVM memory       
+    loadNVM(&nvm,0);//loads EEPROM content to nvm data structure
+
+    nvm.pumpOnOff = PUMP_OFF;
+    writeNVMByte(PUMP_ON_OFF,nvm.pumpOnOff);
+
+    nvm.speedLimit = 125.0;
+    writeNVMfloat(NVM_SPEED_LIMIT,nvm.speedLimit); 
+
+    #ifdef DEBUG_NVM
+            
+        pc.printf("\r\n\r\n HARDWARE \t\t=  %s", HARDWARE.c_str());
+        pc.printf("\r\n\r\n SOFTWARE \t\t=  %s",SOFTWARE.c_str());
+        pc.printf("\r\n\r\n AUTHOR \t\t=  %s",AUTHOR.c_str());
+        pc.printf("\r\n\r\n DATE \t\t\t=  %s",__DATE__);        
+        pc.printf("\r\n\r\n TIME \t\t\t=  %s",__TIME__);   
+        pc.printf("\r\n\r\n ADC Samples \t\t=  %d", ADC_SAMPLES);   
+        pc.printf("\r\n\r\n SPI Freq \t\t=  %d(Hz)", SPI_FREQ);  
+        pc.printf("\r\n\r\n Watchdog  \t\t=  %.1f(Seconds)", WDT);                  
+        pc.printf("\r\n\r\n Flow Unit\t\t=  0x%X", nvm.flowUnits);
+        pc.printf("\r\n\r\n Run Mode\t\t=  0x%X", nvm.runMode);
+        pc.printf("\r\n\r\n Auto Restart\t\t=  0x%X", nvm.autoRestart);                                
+        pc.printf("\r\n\r\n Pump Head\t\t=  0x%X", nvm.pumpHeadStatus);
+        pc.printf("\r\n\r\n Alarm\t\t\t=  0x%X", nvm.alarm);
+        pc.printf("\r\n\r\n Head Side\t\t=  0x%X", nvm.headSide);
+        pc.printf("\r\n\r\n Pump On/Off\t\t=  0x%X", nvm.pumpOnOff);                                                              
+        pc.printf("\r\n\r\n Speed Limit Val\t=  %.2f", nvm.speedLimit);        
+        pc.printf("\r\n\r\n Flow Unit Val\t\t=  %.2f", nvm.flowUnitVal);
+        pc.printf("\r\n\r\n Analogue Cal mA Low\t=  %.2f(mA)", nvm.mA_low);                                
+        pc.printf("\r\n\r\n Analogue Cal mA High\t=  %.2f(mA)", nvm.mA_high);     
+        pc.printf("\r\n\r\n Analogue Cal Flow Low\t=  %.2f(%%)", nvm.flow_low);                                     
+        pc.printf("\r\n\r\n Analogue Cal Flow High\t=  %.2f(%%)", nvm.flow_high);    
+        pc.printf("\r\n\r\n ADC min V\t\t=  %.2f(V)", nvm.adc_min_v);   
+        pc.printf("\r\n\r\n ADC max V\t\t=  %.2f(V)", nvm.adc_max_v);  
+        pc.printf("\r\n\r\n DAC V low factor\t=  %f", nvm.dac_v_low);     
+        pc.printf("\r\n\r\n DAC V high factor\t=  %f", nvm.dac_v_high);      
+        pc.printf("\r\n\r\n DAC V low \t\t=  %.2f(V)", nvm.dac_v_low*VDD);     
+        pc.printf("\r\n\r\n DAC V high \t\t=  %.2f(V)", nvm.dac_v_high*VDD);        
+        pc.printf("\r\n\r\n Remote Stop Pump Input =  0x%X", nvm.rmtStopPump);           
+        pc.printf("\r\n\r\n Output 1\t\t=  0x%X", nvm.outPut1);   
+        pc.printf("\r\n\r\n Output 1 Logic \t=  0x%X", nvm.outPut1Logic);          
+        pc.printf("\r\n\r\n Output 2\t\t=  0x%X", nvm.outPut2);   
+        pc.printf("\r\n\r\n Output 2 Logic \t=  0x%X", nvm.outPut2Logic);                    
+        pc.printf("\r\n\r\n 4-20mA Output\t\t=  0x%X", nvm._4_20mAoutPut);     
+
+        usart6.printf("\r\n\r\n Motor Controller Active");
+                                                                                                                                                                             
+    #endif
+    
+    //pumpType = VDOS_120;
+    pumpType = QDOS_30;    
+
+    //tachoIn.rise(&isr1);
+
+    motor(MOTOR_RPM_MIN, CW, BRAKE_OFF, MOTOR_DISABLE, 100);     
+
+    anaOut_mA(I_3MA);//analogue output forced to 3mA   
+
+    wd.Configure(WDT);       // sets the timeout 
+    
+    thread.start(callback(loopTime_thread));
+}
+
+void nexInit(uint32_t baud){
+
+    /* Set the baudrate which is for debug and communicate with Nextion screen. */
+
+    nexPwrCont = ON;//Nextion power is on    
+    wait(0.25);     
+    lcd.nexSetBaud(baud);//Set Nextion baud        
+    lcd.nexSetBckLite(100);//program backlight to be off at power up      
+}
+
+float motorRPM(void){
+    static float rpm = 0.1;
+    //static float flowUnits = 0.1;
+
+    rpm = mapF(nvm.flowUnitVal, minScale, maxScale, 0, fMaxFlowUnits[pumpType][9]);
+          
+    //flowUnits = mapF(rpm,0.1,125.0,minScale,maxScale);
+
+    //return(flowUnits);      
+    return(rpm);          
+}
+
+float incDecControl(float *val, float precision, float min, float max, float speedLimit){
+
+    static bool incMode = false;
+    static bool decMode = false;
+    static float speed = SLOW_SPEED;
+
+    if(motorRPM() < speedLimit){
+
+        if(*val < max){
+            if((tPush.read() > START_DELAY)&&(incMode)){//INC button pressed > 0.5 seconds, speed set to fast update
+
+                if(tSpeed.read() > speed){//fast and then slow after 4 seconds
+                    tSpeed.reset();
+                
+                    if(tPush.read() > DELAY_LONG){//INC button pressed > 4 seconds, now set speed to slow update                        
+                        tPush.stop();
+                        speed = FAST_SPEED;                    
+                    }            
+                    *val+=flowUnitPrec(precision-1);                                                                                                                                 
+                }    
+            }
+            else//INC button released
+                if(incFlag){
+                    incFlag = false;
+                    incMode = true;
+                    decMode = false;
+                    speed = SLOW_SPEED;    
+                    *val+=flowUnitPrec(precision);//Inc 0.1            
+                }
+                if(*val > max)
+                    *val = max;                     
+        }
+    }
+    else
+        if(motorRPM() > speedLimit)
+            *val-=0.1;
+
+    if(*val > min){
+
+        if((tPush.read() > START_DELAY)&&(decMode)){
+
+            if(tSpeed.read() > speed){//fast and then slow after 4 seconds
+                tSpeed.reset();
+            
+                if(tPush.read() > DELAY_LONG){//INC button pressed > 4 seconds, now set speed to slow update                        
+                    tPush.stop();
+                    speed = FAST_SPEED;                    
+                }
+                *val-=flowUnitPrec(precision-1);                                                                                                                                 
+            }                                                                                     
+        }
+        else
+            if(decFlag){
+                decFlag = false;
+                decMode = true;
+                incMode = false;
+                speed = SLOW_SPEED;                         
+                *val-=flowUnitPrec(precision);//Dec 0.1    
+            }
+            if(*val < min)//catch fix
+                *val = min;   
+
+    }                
+    return(mapF(*val, 0.0, max, 0.0, 100.0));//return percentage multiplier
+}   
+
+long mapI(long x, long in_min, long in_max, long out_min, long out_max){
+  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
+}
+
+float mapF(float in, float inMin, float inMax, float outMin, float outMax) {
+  // check it's within the range
+  if (inMin<inMax) { 
+    if (in <= inMin) 
+      return outMin;
+    if (in >= inMax)
+      return outMax;
+  } else {  // cope with input range being backwards.
+    if (in >= inMin) 
+      return outMin;
+    if (in <= inMax)
+      return outMax;
+  }
+  // calculate how far into the range we are
+  float scale = (in-inMin)/(inMax-inMin);
+  // calculate the output.
+  return outMin + scale*(outMax-outMin);
+}
+
+void diags(void){
+    pc.printf("////////////////////////////////////////////////////////////////////////////////\r\n");
+    pc.printf("//Neptune Diagnostics\r\n");
+    pc.printf("////////////////////////////////////////////////////////////////////////////////\r\n");
+}
+ 
+uint8_t decodeByteNVM(uint8_t nvmByte, uint8_t *prec){
+/*
+    Decode Byte from NVM
+
+    Function decodes nvm byte and displays and:-    
+    * Displays the approriate string for the passed nvm byte
+    * Sets the flow unit precision when nvm byte is a flow unit
+    * Sets the min and max scale when nvm bytes is a flow unit
+ */
+    uint8_t list = 0;
+    uint8_t i = ZERO;
+    bool error = false;
+
+    switch(nvmByte){     
+
+        case OUT1_GENERAL_ALARM:      
+        case OUT1_RUN_STATUS:        
+        case OUT1_MANUAL_MODE:        
+        case OUT1_ANALOGUE_MODE:     
+        case OUT1_CONTACT_MODE:       
+        case OUT1_FLUID_LEVEL:       
+        case OUT1_LEAK_DETECT:  list = OUTPUT1_LIST; break;     
+
+        case OUT2_GENERAL_ALARM:      
+        case OUT2_RUN_STATUS:         
+        case OUT2_MANUAL_MODE:        
+        case OUT2_ANALOGUE_MODE:      
+        case OUT2_CONTACT_MODE:       
+        case OUT2_FLUID_LEVEL:        
+        case OUT2_LEAK_DETECT:  list = OUTPUT2_LIST; break;         
+
+        case PERCENT:   
+        case GPD:          
+        case ML_MIN:                   
+        case L_DAY:                
+        case OZ_MIN:                
+        case RPM:       *prec = 1;  break;                                               
+                        
+        case ML_HR:                    
+        case L_HR:      *prec = 2;  break;     
+
+        case GPH:    
+        case L_MIN:     *prec = 3;  break;        
+
+        default:        pc.printf("Error flowUnitsNVM : Last case %d", nvmByte);  
+                        error = true;    
+    }  
+
+    if(!error){
+        i = ReadListIndexNVM(nvmByte);        
+
+        minScale = fMinFlowUnits[pumpType][i];    
+        maxScale = fMaxFlowUnits[pumpType][i];//float, max flow unit range
+
+        lcd.nexSendFloat("p1right",maxScale, 2);//page 1 right text box          
+        lcd.nexSendTxt("units", menuStringArray[list][i]);
+    }
+
+    return(i);
+}
+
+uint8_t ReadListIndexNVM(uint8_t nvm){
+/*
+    return the list item index
+*/
+    return(0x0f&nvm);
+}
+
+float flowUnitPrec(int8_t precision){
+/*
+precision = number of decimal places, 1, 2 & 3
+returns a float used to Inc/Dec flow units
+
+      100.0,
+      139.6,
+      5.815,
+      22.01,
+      366.9,
+      528.2,
+      22.01,
+      0.367,        
+      12.9,
+      55.0,
+*/
+
+    float precisionVal;
+
+    switch(precision){
+        case -1:    precisionVal = 10; break; 
+        case 0:     precisionVal = 1; break; 
+        case 1:     precisionVal = 0.1; break; 
+        case 2:     precisionVal = 0.01; break;       
+        case 3:     precisionVal = 0.001; break;                              
+        default:pc.printf("Error incDec : Last case %d",precision);  
+    }
+    return(precisionVal);
+}
+
+float low_pass_filterF(float x) {
+
+   //https://www.eevblog.com/forum/beginners/averaging-or-smoothing-adc-values/
+
+   static float samples[ADC_SAMPLES];
+   static int i = ZERO;
+   static float total = ZERO;
+
+   /* Update the moving average */  
+   total += x - samples[i];
+   samples[i] = x;
+
+   /* Update the index */
+   i = (i==(ADC_SAMPLES-1) ? 0 : i+1);
+
+   return total/ADC_SAMPLES;
+}
+
+uint8_t runModeNVM(uint8_t settingIndex){
+    uint8_t task;
+/*
+    Converts EEPROM setting to state machine case setting
+
+ */
+    switch(settingIndex)
+    {
+        case MANUAL:        task = MANUAL_SET; break;
+        case ANALOGUE:      task = ANALOGUE_SET; break;
+        case CONTACT:       task = CONTACT_SET; break;
+        case FLUID_REC:     task = FLUIDREC_SET; break;
+        case FLOW_CAL:      task = FLOW_CAL_SET;  break;
+        default:            pc.printf("Error runModeNVM : Last case %d",settingIndex);  
+    }    
+    return(task);
+}
+
+void dbgStates(uint8_t state){
+    
+    #ifdef DEBUG_STATES
+
+        static uint8_t lastState = INITIALISE;
+        
+        if(state != lastState){
+            switch(state){
+                case INITIALISE:    pc.printf("\r\nSTATE = INITIALISE");  break;
+                case START:         pc.printf("\r\nSTATE = START");  break;
+                case STOP:          pc.printf("\r\nSTATE = STOP");  break;
+                case STOP_SCRN:     pc.printf("\r\nSTATE = STOP_SCRN");  break;
+                case RUNNING:       pc.printf("\r\nSTATE = RUNNING");  break;
+                case ANALOGUE_SET:  pc.printf("\r\nSTATE = ANALOGUE_SET");  break;
+                case DOSE:          pc.printf("\r\nSTATE = DOSE");  break;
+                case MANUAL_SET:    pc.printf("\r\nSTATE = MANUAL_SET");  break;
+                case PROFIBUS:      pc.printf("\r\nSTATE = PROFIBUS");  break;
+                case STALL:         pc.printf("\r\nSTATE = STALL");  break;
+                case DEBUG:         pc.printf("\r\nSTATE = DEBUG");  break;
+                case DIAGS:         pc.printf("\r\nSTATE = DIAGS");  break;
+                case ALARM:         pc.printf("\r\nSTATE = ALARM");  break;
+                case FAULT:         pc.printf("\r\nSTATE = FAULT");  break;
+                case READ_KEYS:     pc.printf("\r\nSTATE = READ_KEYS");  break;
+                case MANUAL_MODE:   pc.printf("\r\nSTATE = MANUAL_MODE");  break;
+                case ANALOGUE_MODE: pc.printf("\r\nSTATE = ANALOGUE_MODE");  break;
+                case PROFIBUS_MODE: pc.printf("\r\nSTATE = PROFIBUS_MODE");  break;
+                case CONTACT_SET:   pc.printf("\r\nSTATE = CONTACT_SET");  break;
+                case FLUIDREC_SET:  pc.printf("\r\nSTATE = FLUIDREC_SET");  break;
+                case READ_NVM:      pc.printf("\r\nSTATE = READ_NVM");  break;
+                case RESET_VARS:    pc.printf("\r\nSTATE = RESET_VARS");  break;
+                case ANA_CAL:       pc.printf("\r\nSTATE = ANA_CAL");  break;
+                case REMOTE_IN:     pc.printf("\r\nSTATE = REMOTE_IN");  break;                
+
+                default:            pc.printf("\r\nSTATE = UNDEFINED");
+            }
+    
+            lastState = state;
+        }
+
+    #endif
+}
+ 
+uint8_t touchBtn(uint8_t nexPage, uint8_t nexBtn, uint8_t nexPushPop){
+    /*
+        Function returns true if the button matches input parameters
+    */
+ 
+    uint8_t state = false;
+    
+    if((page == nexPage)&&(id == nexBtn)&&(pushPop == nexPushPop))
+        state = true;
+
+    return(state);
+}
+
+uint8_t anaCal(void){
+
+    char* buffer;
+    float tmp;
+    bool drawCompleted = false;
+    uint8_t task = ANA_CAL;
+
+    switch(calState){
+    
+            case CAL1_SCRN:                                   
+                                if(scrnUpdate){
+                                    scrnUpdate = false;
+
+                                    lcd.nexSendTxt("title","4-20mA Calibration 1/4");   
+                                    lcd.nexSendTxt("info2","signal");                                              
+                                    lcd.nexSendTxt("sigName","Signal High");                                                                                               
+                                    lcd.nexSendTxt("t1","mA");                                
+
+                                    if(manFlag){                                                   
+                                        lcd.nexSendTxt("info1","Enter HIGH");       
+                                        lcd.nexSendTxt("info2","signal");      
+                                        lcd.nexSendTxt("info3","using +/- keys");                                                                                                                                                                                                                         
+                                    }                                        
+                                    else                     
+                                    {                                                                                   
+                                        lcd.nexSendTxt("info1","Apply HIGH");                                                 
+                                        lcd.nexSendTxt("info2","signal");    
+                                    }                                        
+                                
+                                    lcd.nexSendTxt("info4","then press OK");             
+                                    lcd.nexSendTxt("info5",""); 
+                                }
+
+                                if(manFlag)
+                                    incDecControl(&nvm.mA_high, 2, LOW_CAL_MIN, HIGH_CAL_MAX, nvm.speedLimit);//2 decimal places for mA                                                        
+                                else                                                           
+                                    nvm.mA_high = anaIn_mA();                                                                                                         
+                                        
+                                lcd.nexSendFloat("anaVal", nvm.mA_high, 2);                                                                                                                           
+                                tmp = nvm.mA_high;//make a copy of the data to be 
+
+                                drawCompleted = drawCalGraph(X1,Y1,mapF(nvm.mA_high, I_0MA, I_21MA,X1,X2),Y2,DRAW);//wait for graph to complete
+
+                                if(okFlag && drawCompleted){
+                                    drawCompleted = okFlag = false;                                    
+                                    scrnUpdate = true;  
+                                    calState++;
+                                    
+                                    if(writeNVMfloat(NVM_ANA_MA_CAL_HIGH, nvm.mA_high))
+                                        lcd.nexSendTxt("info5","Data Varified"); 
+                                    else
+                                    {
+                                            lcd.nexSendTxt("info5","Varify Failed");                                     
+                                            while(1);
+                                    }
+
+                                    wait(1.0);
+                                    lcd.nexSendTxt("info5",""); 
+                                }
+                                break;
+
+            case CAL2_SCRN:                 
+                                if(scrnUpdate){
+                                    scrnUpdate = false;
+
+                                    lcd.nexSendTxt("title","4-20mA Calibration 2/4");   
+                                    lcd.nexSendTxt("info1","Enter MAX");     
+                                    lcd.nexSendTxt("info2","flow signal");  
+                                    lcd.nexSendTxt("info3","using +/- keys");  
+                                    lcd.nexSendTxt("info4","then press OK");                                                                                                                               
+                                    lcd.nexSendTxt("flowName","Flow High");                                                                                            
+                                    lcd.nexSendTxt("t0","%");       
+                                    drawCalGraph(X1,Y1,mapF(nvm.mA_high, I_0MA, I_21MA,X1,X2),Y2,ERASE);//mA high, now erase the line read for next cal screen                                                                                                                                                                                                          
+                                }
+                                            
+                                incDecControl(&nvm.flow_high, 1, 0.0, 100.0, nvm.speedLimit);//2 decimal places for mA                                                                                              
+                                lcd.nexSendFloat("flowVal", nvm.flow_high, 1);   
+                                drawCompleted = drawCalGraph(X1,Y1,mapF(nvm.mA_high, I_0MA, I_21MA,X1,X2),mapF(nvm.flow_high, 0.0, 100.0,Y1,Y2),DRAW);//%, draw the line  
+
+                                if(okFlag && drawCompleted){
+                                    drawCompleted = okFlag = false;                                 
+                                    scrnUpdate = true;  
+                                    calState++;
+
+                                    if(writeNVMfloat(NVM_ANA_FLOW_CAL_HIGH, nvm.flow_high))                
+                                        lcd.nexSendTxt("info5","Data Varified"); 
+                                    else
+                                    {
+                                            lcd.nexSendTxt("info5","Varify Failed");                                     
+                                            while(1);
+                                    }                           
+                                    
+                                    wait(1.0);
+                                    lcd.nexSendTxt("info5","");                                   
+                                }                                                          
+                                break;
+
+            case CAL3_SCRN:                                                                                                                                                                                                                      
+                                if(scrnUpdate){
+                                    scrnUpdate = false;
+
+                                    lcd.nexSendTxt("title","4-20mA Calibration 3/4");              
+                                    lcd.nexSendTxt("info2","signal");                                  
+                                    lcd.nexSendTxt("sigName","Signal Low");        
+                    
+                                    lcd.nexSendTxt("flowName","");//Clear these displays                                                                                            
+                                    lcd.nexSendTxt("flowVal","");                                                   
+                                    lcd.nexSendTxt("t0","");                                                                                                                                                               
+
+                                    if(manFlag){                                                   
+                                        lcd.nexSendTxt("info1","Enter LOW");        
+                                        lcd.nexSendTxt("info2","signal");                                                                                         
+                                        lcd.nexSendTxt("info3","using +/- keys");                                                                                                 
+                                    }
+                                    else
+                                    {                                       
+                                        lcd.nexSendTxt("info1","Apply LOW");    
+                                        lcd.nexSendTxt("info2","signal");                                                                                 
+                                    }
+
+                                    lcd.nexSendTxt("info4","then press OK");                                         
+                                    
+                                    drawCalGraph(X1,Y1,mapF(nvm.mA_high, I_0MA, I_21MA,X1,X2),mapF(nvm.flow_high, 0.0, 100.0,Y1,Y2),ERASE);//%, now erase the line read for next cal screen  
+                                }
+                        
+                                if(manFlag)
+                                    incDecControl(&nvm.mA_low, 2, LOW_CAL_MIN, HIGH_CAL_MAX, nvm.speedLimit);//2 decimal places for mA                                                    
+                                else                                
+                                    nvm.mA_low = anaIn_mA();
+                            
+                                lcd.nexSendFloat("anaVal", nvm.mA_low, 2);                     
+                                drawCompleted = drawCalGraph(X1,Y1,mapF(nvm.mA_low, I_0MA, I_21MA,X1,X2),Y2,DRAW);//mA low, draw the line                                              
+
+                                if(okFlag && drawCompleted){
+                                    drawCompleted = okFlag = false;                                        
+                                    scrnUpdate = true;  
+                                    calState++;
+                                                    
+                                    if(writeNVMfloat(NVM_ANA_MA_CAL_LOW, nvm.mA_low))
+                                        lcd.nexSendTxt("info5","Data Varified"); 
+                                    else
+                                    {
+                                            lcd.nexSendTxt("info5","Varify Failed");                                     
+                                            while(1);
+                                    }                           
+                                    
+                                    wait(1.0);
+                                    lcd.nexSendTxt("info5","");                           
+                                }                              
+                                break;
+
+            case CAL4_SCRN:                                                                                                                                   
+                                if(scrnUpdate){
+                                    scrnUpdate = false;
+                                                                        
+                                    lcd.nexSendTxt("title","4-20mA Calibration 4/4");   
+                                    lcd.nexSendTxt("info1","Enter MIN");     
+                                    lcd.nexSendTxt("info2","flow signal");  
+                                    lcd.nexSendTxt("info3","using +/- keys");  
+                                    lcd.nexSendTxt("info4","then press OK");                                                                                                                                           
+                                    lcd.nexSendTxt("flowName","Flow Low");    
+                                    lcd.nexSendTxt("t0","%");   
+                                    drawCalGraph(X1,Y1,mapF(nvm.mA_low, I_0MA, I_21MA,X1,X2),Y2,ERASE);//mA low, now erase the line read for next cal screen                                                                                                                                                                                                                                                                                                                                                                             
+                                }
+                                        
+                                incDecControl(&nvm.flow_low, 1, 0.0, 100.0, nvm.speedLimit);//2 decimal places for mA                                                                                         
+                                lcd.nexSendFloat("flowVal", nvm.flow_low, 1);   
+                                drawCompleted = drawCalGraph(X1,Y1,mapF(nvm.mA_low, I_0MA, I_21MA,X1,X2),mapF(nvm.flow_low, 0.0, 100.0,Y1,Y2),DRAW);//%, draw the line                                              
+
+                                if(okFlag && drawCompleted){
+                                    drawCompleted = okFlag = false;                                                              
+                                    scrnUpdate = true;  
+                                    calState++;                  
+
+                                    if(writeNVMfloat(NVM_ANA_FLOW_CAL_LOW, nvm.flow_low))                                    
+                                        lcd.nexSendTxt("info5","Data Varified");                                         
+                                    else
+                                    {
+                                            lcd.nexSendTxt("info5","Varify Failed");                                     
+                                            while(1);
+                                    }
+  
+                                    wait(1.0);
+                                    lcd.nexSendTxt("info5",""); 
+                                }                                                              
+                                break;                                    
+
+            case COMPLETE_SCRN:                                                                                     
+                                if(scrnUpdate){
+                                    scrnUpdate = false;
+
+                                    calComplete = true;                                    
+
+                                    lcd.nexChgPage(PAGE_18_ANA_CAL_MODE);  
+                                    //lcd.nexSendTxt("title","4 - 20mA Calibration completed");   
+                                    //lcd.nexSendTxt("info2","Analogue = Starts in 4-20mA mode");   
+                                    //lcd.nexSendTxt("info4","Manual = Starts in Manual mode");                                                                                             
+                                    //lcd.nexSendTxt("btnRight","Manual");  
+                                    //lcd.nexSendTxt("btnLeft","Analogue");   
+
+                                    stopLED = 0;//turn off the stop LED                         
+                                    drawCalGraph(X1,Y1,mapF(nvm.mA_low, I_0MA, I_21MA,X1,X2),mapF(nvm.flow_low, 0.0, 100.0,Y1,Y2),ERASE);//%, now erase the line read for next cal screen                                 
+                                }                                
+                                break;
+                                                                                         
+    }
+
+    return(task);
+}
+
+bool drawCalGraph(float x1, float y1, float x2, float y2,bool draw){
+    
+    static uint16_t cntr = ZERO;    
+    static float lastX1 = X1;
+    static float lastY1 = Y1;
+    static float lastX2 = X2;
+    static float lastY2 = Y2;
+    bool updated = false;
+
+    if(draw){
+
+        if(cntr < DRAW_SPEED){
+            cntr++; 
+            updated = false;    
+        }
+        else   
+        {
+            cntr=ZERO;
+
+            stopLED = !stopLED;               
+
+            lcd.nexDrawLine (lastX1, lastY1, lastX2, lastY2, WHITE);//Erase the previous red line calibration posotion   
+            wait(0.001); 
+            lcd.nexDrawLine (x1, y1, x2, y2, RED);//draw the new red line calibration position   
+
+            lastX1 = x1; 
+            lastY1 = y1; 
+            lastX2 = x2; 
+            lastY2 = y2; 
+            updated = true;
+        }                
+    }
+    else    
+        lcd.nexDrawLine (x1, y1, x2, y2, WHITE);//erase the new red line calibration position   
+    
+    return(updated);                    
+}
+
+uint8_t retLastStoredTask(uint8_t storedTask){
+/*
+    Returns to the last stored task
+*/
+
+    uint8_t task;
+
+    switch(storedTask){
+        case STOP_SCRN:         task = STOP_SCRN;//refresh stop screen 
+                                break;
+
+        case ANALOGUE_SET:      task = ANALOGUE_SET;//refresh 
+                                break;
+
+        case MANUAL_SET:        task = MANUAL_SET;//refresh  
+                                break;
+        default:;
+    }
+    return(task);
+}
+ 
+void flowUnitInc(uint8_t *fUx, uint8_t *fUy, uint8_t *fUz){
+
+    if(*fUx > ZERO) 
+        *fUx-=1;
+    else
+        *fUx = P8_MENU_ITEMS;                                                                    
+
+    if(*fUy > ZERO) 
+        *fUy-=1;
+    else
+        *fUy = P8_MENU_ITEMS;    
+
+    if(*fUz > ZERO) 
+        *fUz-=1;
+    else
+        *fUz = P8_MENU_ITEMS;                                                                        
+
+    lcd.nexSendTxt("top", menuStringArray[0][*fUx]);                                                                                                                                                                                                        
+    lcd.nexSendTxt("data", menuStringArray[0][*fUy]);    
+    lcd.nexSendTxt("bot", menuStringArray[0][*fUz]);     
+
+    nvm.flowUnits = uFlowUnitID[*fUy];    
+}
+
+void flowUnitDec(uint8_t *fUx, uint8_t *fUy, uint8_t *fUz){
+
+    if(*fUx < P8_MENU_ITEMS)         
+        *fUx+=1;                        
+    else 
+        *fUx = ZERO;
+
+    if(*fUy < P8_MENU_ITEMS)           
+        *fUy+=1;                        
+    else 
+        *fUy = ZERO;
+
+    if(*fUz < P8_MENU_ITEMS)           
+        *fUz+=1;                        
+    else 
+        *fUz = ZERO;
+
+    lcd.nexSendTxt("top", menuStringArray[0][*fUx]);                                                                                                                                                                                                        
+    lcd.nexSendTxt("data", menuStringArray[0][*fUy]);    
+    lcd.nexSendTxt("bot", menuStringArray[0][*fUz]);     
+
+    nvm.flowUnits = uFlowUnitID[*fUy]; 
+} 
+
+void dispList(uint8_t i[3], uint8_t incDec, uint8_t stringList, const string sArray[2][10], uint8_t maxListStrings){    
+    
+    const uint8_t x=0,y=1,z=2;
+
+    if(incDec){
+        if(i[x] < maxListStrings)         
+            i[x]+=1;                        
+        else 
+            i[x] = ZERO;
+
+        if(i[y] < maxListStrings)           
+            i[y]+=1;                        
+        else 
+            i[y] = ZERO;
+
+        if(i[z] < maxListStrings)           
+            i[z]+=1;                        
+        else 
+            i[z] = ZERO;        
+    }else{
+        if(i[x] > ZERO)         
+            i[x]-=1;                        
+        else 
+            i[x] = maxListStrings;
+
+        if(i[y] > ZERO)           
+            i[y]-=1;                        
+        else 
+            i[y] = maxListStrings;
+
+        if(i[z] > ZERO)           
+            i[z]-=1;                        
+        else 
+            i[z] = maxListStrings;
+    }
+    
+    lcd.nexSetFontCol("data", RED);
+    lcd.nexSendTxt("top", sArray[stringList][i[x]]);                                                                                                                                                                                                        
+    lcd.nexSendTxt("data", sArray[stringList][i[y]]);    
+    lcd.nexSendTxt("bot", sArray[stringList][i[z]]);          
+}
+
+
+
+