/*
 * sample.c
 *
 *  Created on: Jun 8, 2021
 *      Author: thomm
 */


#include "system.h"

#include "user_io.h"
#include "ads1248_iso.h"
#include "ads1248_noniso.h"

#include "board_util.h"
#include "ctd_base.h"
#include "ctd_sbe37_microcat.h"
#include "optode.h"
#include "ocr.h"
#include "sleep.h"
#include "microsd.h"
#include "fatfs/src/ff.h"
#include "uartstdio.h"  // User local version with larger RX buffer
#include "pwm.h"
#include "sample.h"
#include "config.h"


extern struct systemSamplingData sys_samp;

extern int microSD_flg;
extern int ctd_stateMachine(int ctdState);
extern int optode_stateMachine(int optodeState);
extern int ocr_stateMachine(int ocrState);
extern struct optodeDriver optode;
extern struct microCatDriver microCat;
extern struct ctdDriver ctd;   // struct defd in ctd_base.h
extern struct ocrDriver ocr;

extern void         adc_onchip_init(void);
extern uint32_t *   read_all_adc(void);
extern void         fram_store(void);
extern void         fram_retrieve(void);
extern void         ADS1248_gpio3(uint32_t state);


extern uint32_t     adc_data[];
extern int          dbg_flag;
extern int          ads1248noniso_flg;


float fBiasPos = 0.0;  // used for read_bias_bat();
float fBiasNeg = 0.0;

uint32_t gPumpTimeout;      // used in pump_sequencer

unsigned char prnBuf[SIZEOF_PRNBUF+4];      // size is defd in system.h

#define SIZEOF_PUMPBUF  32
unsigned char pumpBuf[SIZEOF_PUMPBUF+4];

void test_get_sample_timing(void)
{
    print_config_data_fields();
    print_data_header();     // defd in system.c
    // call get sample without timing
    get_sample(1,0);

    // call get_sample with timing
    sys_data.app_cfg[APPCFG_SAMPLING_DIAG] = 1;
    uprintf("\r\r\n ---  Sample Timing ---\r\r\n");
    get_sample(1,0);
    sys_data.app_cfg[APPCFG_SAMPLING_DIAG] = 0;
}



void test_get_sample_loop(void)
{
    char input;

    print_config_data_fields();
#ifdef MOVEDTOPp
    if(sys_data.pump1_ontime > 0)
        uprintf("\r\r\nHit Ctrl-X to terminate pump cycle followed by any key to terminate sample loop\r\r\n");
    else
        uprintf("\r\r\nHit any key to terminate sample loop\r\r\n");
#endif

    print_data_header();     // defd in system.c
    //sys_samp.pump_seq_state = 1;   // initialize pump sequence variable
    while(1)
    {
        if( UARTRxBytesAvail() )
        {
            input = get_key();
            break;    // break from while(1)
        }
        get_sample(1,0);
    }
}

void test_pump_and_sample_timing(void)
{
    uprintf("Feature not available in this release (test_pump_and_sample_timing)\r\n");
}



void test_pump_and_sample_loop(void)
{
    char input;

    print_config_data_fields();
    print_data_header();     // defd in system.c


    if(sys_data.pump1_ontime > 0)
        uprintf("\r\r\nHit Ctrl-X to terminate pump cycle followed by any key to terminate sample loop\r\r\n");
    else
        uprintf("\r\r\nHit any key to terminate sample loop\r\r\n");

    pump_and_sample(1,0);           // print to console, don't write to uSD

//#ifdef NOCODE
    //sys_samp.pump_seq_state = 1;   // initialize pump sequence variable
    while(1)
    {
        if( UARTRxBytesAvail() )
        {
            input = get_key();
            break;    // break from while(1)
        }
        pump_and_sample(1,0);           // print to console, don't write to uSD  was   get_sample(1,0);
    }
//#endif
}

// init global vars used for pump sequencer and get_sampling
void pump_var_init(void)
{
    // initialize pumpBuf -  "P1 %02d/%02d\t" fixes garbage print of pumpBuf in Test and Config (D/d) get_sample test routines 10Apr2022
    sprintf((char *)pumpBuf, "PumpSeq=%02d\t", sys_data.pump_seq_type);
}


void pump_and_sample_start(void)
{
    sys_samp.pump_seq_state = ST_SEQ_START;
}

// pump_and_sample()
//
// pass in printFlg and writeFlg to support pass thru call to get_sample(printFlg, writeFlg).  pump_and sample is also called for boards that don't have pumps (yet)
// return 0 when complete
// handle deploy to first sample delay, pump sequencing prior to sampling and later pump sequencing with sampling during pumping
// replaces most calls to get_sample in the pHFET-SOS application
//
int pump_and_sample(int printFlg, int writeFlg)
{

#if BOARD_MFET >= 2 || BOARD_NANOFET >= 1
    get_sample(printFlg, writeFlg);         // ts command both prints and writes, ss command writes
    return(0);
#endif

#if BOARD_MPHOX >= 1
    int pump_seq_state;

    //pump_seq_state = ST_SEQ_START;      // trying to fix broken statemachine 10 Apr 2022
//    pump_seq_state = 1;
    pump_seq_state = sys_samp.pump_seq_state;       // sys_samp.pump_seq_state requires careful initialization to handle board sleep and wake for delayed sampling THOM todo 10Apr2022


    //uprintf("pss: %d\r\n", pump_seq_state);
    while(1)
    {
        pump_seq_state = pump_sequencer(pump_seq_state, printFlg, writeFlg);

        ROM_SysCtlDelay(250 * MILLISECOND);                 // slow the loop checking for diagnostic prints...  why??
        //uprintf("pss: %d\r\n", pump_seq_state);
        if(pump_seq_state == 0)
        {
            if(sys_data.test_mode == 1) uprintf("\r\nPump is finished\r\n");
            return(0);
        }


        if(pump_seq_state == ST_SEQ_WAIT_TO_START)
        {
            uprintf("\r\nST_SEQ_WAIT_TO_START\r\n");      // DEBUG
            return(ST_SEQ_WAIT_TO_START);                   // board will sleep on return
        }
    }
#endif
}




void pump_sequencer_init(void)
{
    sys_samp.pump_seq_state = ST_SEQ_NADA;
}





// pass in a 1 to start the state machine, call pump_sequencer in a loop until it returns 0 or <0 (error)
// this approach enables calls to get_sample in loop.
// pump_sequencer calls get_sample
int pump_sequencer(int pump_seq_state, int printFlg, int writeFlg)
{
    char inChar;
    uint32_t timeout;
    char timeStamp[TIMESTAMPLENGTH];
    struct tm *time_struct;
    uint32_t ticks;

#if BOARD_MPHOX >= 1

    // handle the case of NO PUMPing required
    // TESTED, WORKS
    if(sys_data.pump1_ontime == 0)
    {
        //uprintf(" got here 1, no pump time, so just call get_sample ");

        get_sample(printFlg, writeFlg);

        sys_samp.pump_seq_state = ST_SEQ_NADA;
        return(ST_SEQ_NADA);
    }


    // TESTED, WORKS
    //start_pump_time  // Wakeup on sampling interval (and sample), but check the 'start deployment time' before actual using pumps when sampling 16 Feb 2022
    //sys_samp.pump_seq_state  // TODO: THIS VAR should not be stored in flash since the board does not sleep during pumping
    //---------------------------- Legacy Single Pump ---------------------------------------------------------------
    if((sys_data.pump1_ontime > 0) && (sys_data.pump_seq_type == TYPE_PUMP_SINGLE))
    {
        // Pump on time
        if(sys_data.test_mode == 1)
            uprintf("\r\nPump on (test mode)\r\n");     // Don't want the pump to run in test deployment, FUTURE, do this in pump1_on routine?
        else
            pump1_on();
        led_sampling_on();      // red_led

        timeout = Timer_1ms(false) + sys_data.pump1_ontime*1000;     // timeout is in msec

        do
        {
            ROM_SysCtlDelay(100 * MILLISECOND);

            if( UARTRxBytesAvail() )
            {
                //inChar = get_key();  // replace with getchar  THOM todo
                inChar = getChar();
                if( (inChar == 24) || (inChar == 0x0d) )    //Ctrl_X or KEY_ENTER
                {
                    //uprintf("Pump cycle ended early by %u sec, due to 0x%02x / %u key\r\n", (timeout - Timer_1ms(false))/1000, inChar, (unsigned int)inChar);
                    uprintf("Pump cycle ended early due to 0x%02x / %u key\r\n", inChar, (unsigned int)inChar);
                    break;
                }
                else
                {
                    uprintf("Pump cycle active, hit Ctrl-X then <Enter> to terminate cycle\r\n");
                }
                if( sys_data.output == VERBOSE)
                    uprintf("\r\nPumping before sample, please wait...");
            }

        //} while( ROM_HibernateRTCGet() < timeout );
        } while( Timer_1ms(false) < timeout );

        if(sys_data.test_mode == 1)
            uprintf("\r\nPump off (test mode)\r\n");     //
        else
            pump1_off();

        if(sys_data.test_mode == 1) uprintf("Pump off\r\n");
        //led_red_off();

        // DEBUG uprintf("\r\ncalling get_sample...\r\n");
        get_sample(printFlg, writeFlg);

        sys_samp.pump_seq_state = ST_SEQ_NADA;
        return(ST_SEQ_NADA);
    }


    //--------------------------------------------------------------------------------------------------
    // The first state machine implementation will be in get_sample, later this may be moved up the call chain
    if(sys_data.pump_seq_type == TYPE_2PUMP_BEAMSV1)
    {
        switch(pump_seq_state)      //switch(sys_samp.pump_seq_state)
        {
        case ST_SEQ_NADA:
            return(ST_SEQ_NADA);

        case ST_SEQ_START:
            //uprintf("ST_SEQ_START\r\n");
            // initialize state vars
            sys_samp.pump1_cnt = 0;
            sys_samp.pump2_cnt = 0;


            //char timeStamp[TIMESTAMPLENGTH];

#ifdef BROKENPUMPDELAYSTART
            if(sys_data.start_pump_time == 0)           // if there is not a time set, start the pump
                sys_samp.pump_seq_state = ST_SEQ_PUMP1;
#endif

            sys_samp.pump_seq_state = ST_SEQ_PUMP1;

            //get the time from the from the RTC so we can print it (to debug delayed start)
            ticks = ROM_HibernateRTCGet();
            // DEBUG
            //time_struct = localtime((const time_t*)&ticks);
            //strftime(timeStamp, sizeof(timeStamp),"%m/%d/%y %H:%M:%S", time_struct);
            //uprintf("DBG %s  ticks: %u\r\n", timeStamp, ticks);

            if ((ticks >= sys_data.start_pump_time) && (sys_data.start_pump_time > 0))
            {
                time_struct = localtime((const time_t*)&ticks);
                strftime(timeStamp, sizeof(timeStamp),"%m/%d/%y %H:%M:%S", time_struct);
                uprintf("%s  ticks: %u\r\n", timeStamp, ticks);

                sys_samp.pump_seq_state = ST_SEQ_PUMP1;
            }

#ifdef BROKENPUMPDELAYSTART
            // DOUBLE CHECK the countdown - which to use?  time or countdown?
            if(sys_samp.start_pump_cntdown > 0)
            {
                sys_samp.pump_seq_state = ST_SEQ_WAIT_TO_START;
            }
            else
            {
                sys_samp.pump_seq_state = ST_SEQ_PUMP1;     // pump_seq_state is either ST_SEQ_PUMP1 or ST_SEQ_PUMP2
            }

#endif
           // sys_samp.pump_seq_state = ST_SEQ_PUMP1;     // pump_seq_state is either ST_SEQ_PUMP1 or ST_SEQ_PUMP2

            sys_samp.pump_seq_state = ST_SEQ_PUMP1;     // fix for broken Delayed pump start

            return(sys_samp.pump_seq_state);

        case ST_SEQ_WAIT_TO_START:          // Needs to Sleep and wake on the sample_period
            // Need BOARD_SLEEP for this to work

            if(sys_samp.start_pump_cntdown > sys_data.sampling_period)
            {
                sys_samp.start_pump_cntdown -= sys_data.sampling_period;
                uprintf("%5d\b\b\b\b\b", sys_samp.start_pump_cntdown);

                if(sys_samp.start_pump_cntdown < sys_data.sampling_period)
                {
                    ticks = ROM_HibernateRTCGet();


                    //strftime(timeStamp, sizeof(timeStamp),"%m/%d/%y %H:%M:%S", time_struct);

                    if(sys_data.test_mode == 1)
                    {
                        uprintf("\r\nPump Start: ");      // DEBUG
                        print_time_t_Time(ticks);       // print NOW
                    }

                    sys_samp.pump_seq_state = ST_SEQ_PUMP1;
                }
                else
                {
                    // go back to sleep (return to pump_and_sample and exit from there)
                    sys_samp.pump_seq_state = ST_SEQ_WAIT_TO_START;

                }
            }
            else
            {
                // count down has expired, time to move to next state
                sys_samp.pump_seq_state = ST_SEQ_PUMP1;
            }
            return(sys_samp.pump_seq_state);

        case ST_SEQ_PUMP1:
            //uprintf("ST_SEQ_PUMP1, pump on\r\n");
            // count the number of times PUMP1 is turned on
            // when time expires, turn pump off, check if the cycle count means it's time to switch to PUMP2

            if(sys_data.test_mode == 1)
                uprintf("\r\nPump1 on (test mode)\r\n");     // Don't want the pump to run in test deployment
            else
                pump1_on();
            led_sampling_on();
            gPumpTimeout = Timer_1ms(false) + sys_data.pump1_ontime*1000;     // timeout is in msec
            sys_samp.pump_seq_state = ST_SEQ_PUMP1;
            return(ST_SEQ_PUMP1_ONTIME);

        case ST_SEQ_PUMP1_ONTIME:

            if( UARTRxBytesAvail() )
            {
                inChar = get_key();
                if( (inChar == 24) || (inChar == 0x0d) )    //Ctrl_X (CTRL-X) or KEY_ENTER
                {
                    //uprintf("Pump cycle ended early by %u sec, due to 0x%02x / %u key\r\n", (timeout - Timer_1ms(false))/1000, inChar, (unsigned int)inChar);
                    uprintf("Pump1 cycle ended early due to 0x%02x / %u key\r\n", inChar, (unsigned int)inChar);
                    //break;
                    gPumpTimeout = Timer_1ms(false) - 2;        // force the timeout
                }
                if( sys_data.output == VERBOSE)
                    uprintf("\r\nPumping before sample, please wait...");
            }


            if(Timer_1ms(false) > gPumpTimeout)     // timed out?
            {
                //uprintf("ST_SEQ_PUMP1, pump off\r\n");
                //uprintf("ST_SEQ_PUMP1, %d runtime, pump off, cycle %d/%d\r\n", sys_data.pump1_ontime, sys_samp.pump1_cnt, sys_data.pump1_cycles);
                sys_samp.pump1_cnt++;
                //sprintf(pumpBuf, "P1 %d/%d\tP2 %d/%d\t", sys_samp.pump1_cnt, sys_data.pump1_cycles, sys_samp.pump2_cnt, sys_data.pump2_cycles);
                sprintf((char *)pumpBuf, "P1 %02d/%02d\t", sys_samp.pump1_cnt, sys_data.pump1_cycles);
                if(sys_data.test_mode == 1)
                    uprintf("\r\nPump off (test mode)\r\n");     //
                else
                    pump1_off();


                get_sample(printFlg, writeFlg);

                if(sys_samp.pump1_cnt >= sys_data.pump1_cycles)
                {
                    sys_samp.pump2_cnt = 0;
                    sys_samp.pump1_cnt = 0;
                    // switch to pump2
                    sys_samp.pump_seq_state = ST_SEQ_PUMP2;     // next is pump2

                }
                else
                {
                    sys_samp.pump_seq_state = ST_SEQ_PUMP1;    // stay with pump1
                }

                return(ST_SEQ_NADA);        // pumping is done
            }
            return(ST_SEQ_PUMP1_ONTIME);

        case ST_SEQ_PUMP2:
            //uprintf("ST_SEQ_PUMP2, pump2 on\r\n");
            // count the number of times PUMP1 is turned on
            // when time expires, turn pump off, check if the cycle count means it's time to switch to PUMP2

            if(sys_data.test_mode == 1)
                uprintf("\r\nPump2 on (test mode)\r\n");     // Don't want the pump to run in test deployment
            else
            {
                pump2_on();     // PORTD-3 is hanging in the breeze on MFET   ROM_GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_3, 0xff);
                //pump4_on();  // solenoid as a backup for Barry Octopus Respirometer
            }
            led_sampling_on();
            gPumpTimeout = Timer_1ms(false) + sys_data.pump2_ontime*1000;     // timeout is in msec
            sys_samp.pump_seq_state = ST_SEQ_PUMP2;
            return(ST_SEQ_PUMP2_ONTIME);

        case ST_SEQ_PUMP2_ONTIME:
            if( UARTRxBytesAvail() )
            {
                inChar = get_key();
                if( (inChar == 24) || (inChar == 0x0d) )    //Ctrl_X (CTRL-X) or KEY_ENTER
                {
                    //uprintf("Pump cycle ended early by %u sec, due to 0x%02x / %u key\r\n", (timeout - Timer_1ms(false))/1000, inChar, (unsigned int)inChar);
                    uprintf("Pump2 cycle ended early due to 0x%02x / %u key\r\n", inChar, (unsigned int)inChar);
                    //break;
                    gPumpTimeout = Timer_1ms(false) - 2;        // force the timeout
                }
                if( sys_data.output == VERBOSE)
                    uprintf("\r\nPumping before sample, please wait...");
            }

            if(Timer_1ms(false) > gPumpTimeout)     // Timed out
            {
                //uprintf("ST_SEQ_PUMP2, %d runtime, pump off, cycle %d/%d\r\n", sys_data.pump2_ontime, sys_samp.pump2_cnt, sys_data.pump2_cycles);
                sys_samp.pump2_cnt++;       // increment prior to print
                //sprintf(pumpBuf, "P1 %d/%d\tP2 %d/%d\t", sys_samp.pump1_cnt, sys_data.pump1_cycles, sys_samp.pump2_cnt, sys_data.pump2_cycles);
                sprintf((char *)pumpBuf, "P2 %02d/%02d\t", sys_samp.pump2_cnt, sys_data.pump2_cycles);

                pump2_off();
                //pump4_off();  // solenoid as a backup for Barry Octopus Respirometer

                get_sample(printFlg, writeFlg);

                // switch the stored state, return 0 to exit the calling loop

                if(sys_samp.pump2_cnt >= sys_data.pump2_cycles)
                {
                    sys_samp.pump2_cnt = 0;
                    sys_samp.pump1_cnt = 0;
                    // switch to pump1
                    sys_samp.pump_seq_state = ST_SEQ_PUMP1;
                }
                else
                {
                    sys_samp.pump_seq_state = ST_SEQ_PUMP2;
                }

                return(ST_SEQ_NADA);
            }
            return(ST_SEQ_PUMP2_ONTIME);

        default:
            uprintf("ERROR: ST_SEQ hit the default switch statement");
            return(ST_SEQ_NADA);

        }
    }
// how does the pump sequencer work?
// pump_sequencer runs before ADC24 sampling.  Pumps are off when sampling.
// pump_seq_type = 0 = pump before sample if pump1_ontime > 0 (legacy mode).
// pump_seq_type = 1 = dual alternating pumps, BEAMSv1 / Barry lab
// pump_seq_type = 2 =

//#define TYPE_PUMP_SINGLE        0
//#define TYPE_2PUMP_BEAMSV1      1
//#define TYPE_2PUMP_BEAMSV2      2


#endif
    return(ST_SEQ_NADA);
}







#if BOARD_MFET >= 1 || BOARD_MPHOX >= 1 || BOARD_NANOFET >= 1
/*
 * fast sample()
 * Take measurements and write them to SD card.
 * sys_data.diag = 1 turns on timing diagnostics
 *
     *  SampNum        VbatMain        VbiasPos        VbiasNeg          Vtherm        VthrmStd         TC_Dfet            Vrsi        Vrsi_std            Vrse        Vrse_std          Vrsi_B              Vk          Vk_std              Ik       Ib                Opt_PN  Opt_SN  Moxy    O2satper        TC_opt  Dphase  Bphase  Rphase  Bamp    Bpot    Ramp    Opt_rawtemp     TempC   Cond    Salt    Unk1    Date    Time            Cond_PN Cond_SN Cond    Temp     Unk1    Unk2    Unk3
    #0000004           11.95            3.64           -3.61        0.997208        0.000003          24.714        -0.055249       0.000004        -0.799259       0.000009        0.674751        -0.500849       0.000007        18222.69 -399.597        4831    856     220.421 93.265  29.895  26.032  28.323  36.656  8.333   527.3   600.9   -128.9  5860    29      -0.011  30.508  0.016   995.506 1510.343

     ---  Sample Timing ---

    Pump         =  2008,    2008
    Pwr on, init =    24,    2032
    Bias Bat     =    70,    2102
    Ib Substrate =    62,    2164
    Ik Cntr E    =    61,    2225
    Vk Cntr E    =   260,    2485
    Vtherm       =   250,    2735
    Vrsi_B       =   509,    3244
    Vrsi         =   509,    3753
    Vrse         =   509,    4262
    Optode St8Ma =     2,    4264
    Condo  St8Ma =    20,    4284
    Onchip ADC   =     0,    4284
    Calc TempC   =     2,    4286
    Optode       =  2119,    6405
    CTD          =   572,    6977
    format data  =     2,    6979
    #0000005           11.95            3.64           -3.61        0.997401        0.000004          24.708        -0.055247       0.000005        -0.799254       0.000008        0.674756        -0.500856       0.000005        18219.66 -399.600        4831    856     220.417 93.276  29.903  26.029  28.320  36.655  8.335   527.2   600.5   -129.2  5860    29      -0.011  30.515  0.016   995.504 1510.358        (6979 msec)

    uSD writes   =     9,    6988
    wait TX      =    22,    7010
 *
 */
void get_sample(int printFlg, int writeFlg)
{
    char timestamp[TIMESTAMPLENGTH];
    uint32_t timeout;
    uint32_t tickStart, ticks, tickDelta, tickEnd, tick_onchip;
    struct tm *time_struct;
    unsigned long long posixtime_ms;        // tried uint64_t
    uint32_t subsec;

    float fVtherm;           // DuraFET raw temperature voltage
    float fVtherm_std;       // Std Dev for Durafet Thermistor
    float fTempC;            // Calculated DuraFET temperature
    //float fExtTemp;

    float fVrsi;             // DuraFET internal reference voltage   (Vint)
    float fVrsi_std;         // Std Dev for Durafet Internal Voltage
    float pHint;             // Calculated pH using internal reference

    float fVrse;             // External (AUX) reference voltage  (Vrs)
    float fVrse_std;         // Std Dev for Durafet External Voltage
    float pHext;             // Calculated pH using external reference

    float SBE_sal;           // MicroCAT salinity

    float fVrse_B;
    float fVrse_B_std;
    float fVrsi_B;
    float fVrsi_B_std;

    float fIk;              // (Ik) CounterElectrodeCurrent
    float fIk_std;
    float fVk;              // (Vk) CounterElectrodeVoltage
    float fVk_std;
    float fIb;              // (Ib) SubstrateCurrent
                            // float SubstrateVoltage;  //float SubstrateVoltage_std;
    float fVbat_main;
    float fBias_bat_lowest;

    float fHumidity;
    float fBrdTempC;
    uint32_t  uiHumidity;
    uint32_t  uiWater;

    uint32_t indx;
    int optodeState;
    int ctdState;
    int ocrState;

    FIL fileObject;
    FRESULT fresult;
    INT bw;

    optodeState = 0;
    ctdState = 0;

    tickStart = Timer_1ms(true);
    tickDelta = tickStart;
    char inChar;
    int     pump_seq_state;

    if(sys_data.test_mode == 1)
        uprintf("\r\nSampling...");

    //led_green_on();

    tickDelta = Timer_1ms(false) - tickDelta;
    ticks = (Timer_1ms(false) - tickStart);
    if(sys_data.app_cfg[APPCFG_SAMPLING_DIAG] == 1) uprintf("\r\nPump         = %5u,   %5u", tickDelta, ticks);
    tickDelta = ticks;

    if(sys_data.data_cfg[CFG_TIMESTAMP] == TYPE_EPOCH_MSEC)
    {

        //1648165197 - 12365360
        // = 1,635,799,837
        // 1648165439000

        posixtime_ms = ROM_HibernateRTCGet();   // cast to unsigned long long ?

        posixtime_ms += (1635799837);      // hacked offset  https://www.epoch101.com/  subtract what rtc is displaying in teraterm
        posixtime_ms *= 1000LL;      // make it msec
        sprintf(timestamp, "%13llu", posixtime_ms);
    }
    if(sys_data.data_cfg[CFG_TIMESTAMP] == TYPE_US_DATETIME)
    {
        time_struct = get_RTC_time();
        strftime(timestamp, sizeof(timestamp), "%m/%d/%Y %H:%M:%S", time_struct);        // change format of date/time per Yui  7 jun 2018

    }




    openADS1248_iso();              // turn on isolated power to 24bit A/D converter, init SPI3 port

#if BOARD_MFET >= 2 || BOARD_MPHOX >= 1 // BOARD_NANOFET has adc always on...
    ROM_SysCtlDelay(100*MILLISECOND);         // new, 3 Aug 2021 - BUG fix (Crash), let power supply settle.
#endif

    //THOM tbd, does NANOFET require ADS1248_gpio?? No with latest nanofet
    ADS1248_gpio_init();            // defd in ADS1248_iso.c  (CRASH HAPPENS HERE - first call to fast_sampling is good, next call crashes.   25 Aug 2022, Irene found a problem in gpio_init (data[0] declaration, gold star for Irene!)
    // turn on sensor and battery monitoring circuit - needs at least 150msec to settle (use iso sampling as delay
    pwr_env_mon_on();    // Turn on Load switch for ENV monitoring

#if BOARD_MFET >= 2 || BOARD_MPHOX >= 1
    pwr_vbat_mon_on();  //ROM_GPIOPinWrite(GPIO_PORTM_BASE, GPIO_PIN_6, 0xFF);   // Turn on VBat monitoring

    ROM_SysCtlDelay(1*MILLISECOND);         // fast sampling (was 800msec)

    adc_onchip_init();
    // read_adc_all was moved below as there is 100msec recommended for battery voltage to settle to within 1%
#endif

    tickDelta = Timer_1ms(false) - tickDelta;
    ticks = (Timer_1ms(false) - tickStart);
    if(sys_data.app_cfg[APPCFG_SAMPLING_DIAG] == 1) uprintf("\r\nPwr on, init = %5u,   %5u", tickDelta, ticks);
    tickDelta = ticks;
    tick_onchip = Timer_1ms(false) ;        // for insuring 100msec settling reading input battery voltage.

    //Future: add a config parameter for sampling CTD before pH voltages or after.   Sampling CTD before pH voltages provides a
    // salinity reading for calculating pH based on that salinity reading.

    // ---- Start optode and ctd statemachines, these need to finish and be shutdown prior to pH voltage readings  -----------------
    if(sys_data.data_cfg[CFG_OPTODE] > 0)
    {
        //start the optode driver by passing 1, when complete, the statemachine returns 0
        optodeState = 1;
        optodeState = optode_stateMachine(optodeState);     //pass in 1 to start the state machine, hereafter pass retVal

        tickDelta = Timer_1ms(false) - tickDelta;
        ticks = (Timer_1ms(false) - tickStart);
        if(sys_data.app_cfg[APPCFG_SAMPLING_DIAG] == 1) uprintf("\r\nOptode St8Ma = %5u,   %5u", tickDelta, ticks);
        tickDelta = ticks;
    }

    if(sys_data.data_cfg[CFG_CTD] > 0)
    {
        //start the ctd driver by passing 1, when complete, the statemachine returns 0
        ctdState = 1;
        ctdState = ctd_stateMachine(ctdState);     //pass in 1 to start the state machine, hereafter pass retVal

        tickDelta = Timer_1ms(false) - tickDelta;
        ticks = (Timer_1ms(false) - tickStart);
        if(sys_data.app_cfg[APPCFG_SAMPLING_DIAG] == 1) uprintf("\r\nCTD    St8Ma = %5u,   %5u", tickDelta, ticks);
        tickDelta = ticks;
    }

    if(sys_data.data_cfg[CFG_OCR] > 0)
    {
        //start the ocr driver by passing 1, when complete, the statemachine returns 0
        ocrState = 1;
        ocrState = ocr_stateMachine(ocrState);      //pass in 1 to start the state machine, hereafter pass retVal
        if((Timer_1ms(false) - tickDelta) > 1)
        {
            tickDelta = Timer_1ms(false) - tickDelta;
            ticks = (Timer_1ms(false) - tickStart);
            if(sys_data.app_cfg[APPCFG_SAMPLING_DIAG] == 1) uprintf("\r\nOCR    St8Ma = %5u,   %5u", tickDelta, ticks);
            tickDelta = ticks;
        }
    }

    // ---------- Read the isolated domain 24 bit ADC -----------------

    // Sampling ideas.   Read each channel fast to equalize the ADC front end
    // read 'diagnostic' channels first to buy time for stabilizing.   Bias bat, Ik, Ib, Vbias
    // read pH related channels  Vtherm, Vrsi, Vrse

    //---------------------------- diagnostic voltages --------------------------------------
    // NOT on nanoFET, config prevents
    if(sys_data.data_cfg[CFG_BIAS_BAT_NEG] > 0)
    {
        ADS1248_gpio3(0);
        ROM_SysCtlDelay(MILLISECOND * 10);
          fBiasNeg = pollADS1248_iso(7, 6, sys_data.Vbias_trials, 1, sys_data.Vbias_sps);     // Mux 01, Chan +7 -6, trials = 1, gain = 1, sps = 40 Hz

        fBiasNeg = fBiasNeg*2.0;                        // global var
    }

    if(sys_data.data_cfg[CFG_OPTODE] > 0)
    {
        optodeState = optode_stateMachine(optodeState);
        if((Timer_1ms(false) - tickDelta) > 1)
        {
            tickDelta = Timer_1ms(false) - tickDelta;
            ticks = (Timer_1ms(false) - tickStart);
            if(sys_data.app_cfg[APPCFG_SAMPLING_DIAG] == 1) uprintf("\r\nOptode St8Ma = %5u,   %5u", tickDelta, ticks);
            tickDelta = ticks;
        }
    }
    if(sys_data.data_cfg[CFG_CTD] > 0)
    {
        ctdState = ctd_stateMachine(ctdState);
        if((Timer_1ms(false) - tickDelta) > 1)
        {
            tickDelta = Timer_1ms(false) - tickDelta;
            ticks = (Timer_1ms(false) - tickStart);
            if(sys_data.app_cfg[APPCFG_SAMPLING_DIAG] == 1) uprintf("\r\nCTD    St8Ma = %5u,   %5u", tickDelta, ticks);
            tickDelta = ticks;
        }
    }
    if(sys_data.data_cfg[CFG_OCR] > 0)
    {
        ocrState = ocr_stateMachine(ocrState);
        if((Timer_1ms(false) - tickDelta) > 1)
        {
            tickDelta = Timer_1ms(false) - tickDelta;
            ticks = (Timer_1ms(false) - tickStart);
            if(sys_data.app_cfg[APPCFG_SAMPLING_DIAG] == 1) uprintf("\r\nOCR    St8Ma = %5u,   %5u", tickDelta, ticks);
            tickDelta = ticks;
        }
    }

    if(sys_data.data_cfg[CFG_BIAS_BAT_POS] > 0)
    {

#if BOARD_NANOFET >= 1
        //nanofet has no mux
        //no ground on this rev (6 is bias, 7 is hack gnd)
        fBiasPos = pollADS1248_iso(6, 7, sys_data.Vbias_trials, 1, sys_data.Vbias_sps);
#endif
#if BOARD_MFET >= 1 || BOARD_MPHOX >= 1
        ADS1248_gpio3(1);
        ROM_SysCtlDelay(MILLISECOND * 10);
        fBiasPos = pollADS1248_iso(7, 6, sys_data.Vbias_trials, 1, sys_data.Vbias_sps);
#endif

        fBiasPos = fBiasPos*2.0;                        // global var
    }

    if(sys_data.data_cfg[CFG_OPTODE] > 0)
    {
        optodeState = optode_stateMachine(optodeState);
        if((Timer_1ms(false) - tickDelta) > 1)
        {
            tickDelta = Timer_1ms(false) - tickDelta;
            ticks = (Timer_1ms(false) - tickStart);
            if(sys_data.app_cfg[APPCFG_SAMPLING_DIAG] == 1) uprintf("\r\nOptode St8Ma = %5u,   %5u", tickDelta, ticks);
            tickDelta = ticks;
        }
    }
    if(sys_data.data_cfg[CFG_CTD] > 0)
    {
        ctdState = ctd_stateMachine(ctdState);
        if((Timer_1ms(false) - tickDelta) > 1)
        {
            tickDelta = Timer_1ms(false) - tickDelta;
            ticks = (Timer_1ms(false) - tickStart);
            if(sys_data.app_cfg[APPCFG_SAMPLING_DIAG] == 1) uprintf("\r\nCTD    St8Ma = %5u,   %5u", tickDelta, ticks);
            tickDelta = ticks;
        }
    }
    if(sys_data.data_cfg[CFG_OCR] > 0)
    {
        ocrState = ocr_stateMachine(ocrState);
        if((Timer_1ms(false) - tickDelta) > 1)
        {
            tickDelta = Timer_1ms(false) - tickDelta;
            ticks = (Timer_1ms(false) - tickStart);
            if(sys_data.app_cfg[APPCFG_SAMPLING_DIAG] == 1) uprintf("\r\nOCR    St8Ma = %5u,   %5u", tickDelta, ticks);
            tickDelta = ticks;
        }
    }

    if((sys_data.data_cfg[CFG_BIAS_BAT_POS] > 0) || (sys_data.data_cfg[CFG_BIAS_BAT_NEG] > 0))
    if((Timer_1ms(false) - tickDelta) > 1)
    {
        tickDelta = Timer_1ms(false) - tickDelta;
        ticks = (Timer_1ms(false) - tickStart);
        if(sys_data.app_cfg[APPCFG_SAMPLING_DIAG] == 1) uprintf("\r\nBias Bat     = %5u,   %5u", tickDelta, ticks);
        tickDelta = ticks;
    }


    // --- Finish sampling and turn off external instruments (CTD / Optode) before reading pH voltages ------
    if(sys_data.data_cfg[CFG_OPTODE] > 0)
    {

        while(1)
        {
            if(optodeState == 0)            // makes sure optode statemachine is finished
                break;
            optodeState = optode_stateMachine(optodeState);

        }
        tickDelta = Timer_1ms(false) - tickDelta;
        ticks = (Timer_1ms(false) - tickStart);
        if(sys_data.app_cfg[APPCFG_SAMPLING_DIAG] == 1) uprintf("\r\nOptode       = %5u,   %5u", tickDelta, ticks);
        tickDelta = ticks;
    }

    if(sys_data.data_cfg[CFG_CTD] > 0)
    {

        while(1)
        {
            if(ctdState == 0)            // makes sure ctd statemachine is finished
                break;
            ctdState = ctd_stateMachine(ctdState);

        }
        tickDelta = Timer_1ms(false) - tickDelta;
        ticks = (Timer_1ms(false) - tickStart);
        if(sys_data.app_cfg[APPCFG_SAMPLING_DIAG] == 1) uprintf("\r\nCTD          = %5u,   %5u", tickDelta, ticks);
        tickDelta = ticks;
    }

    if(sys_data.data_cfg[CFG_OCR] > 0)
    {
        while(1)
        {
            if(ocrState == 0)            // makes sure ctd statemachine is finished
                break;
            ocrState = ocr_stateMachine(ocrState);

        }
        ocrState = ocr_stateMachine(ocrState);
        tickDelta = Timer_1ms(false) - tickDelta;
        ticks = (Timer_1ms(false) - tickStart);
        if(sys_data.app_cfg[APPCFG_SAMPLING_DIAG] == 1) uprintf("\r\nOCR    St8Ma = %5u,   %5u", tickDelta, ticks);
        tickDelta = ticks;
    }
    // OCR, CTD and Optode state machines when finished turn off the instrument power.

    //---------------------------- engineering data for isfet --------------------------------------

    // ----------- Ib Subst Cur, (Diagnostic) ------------------
    if(sys_data.data_cfg[CFG_I_SUBSTRATE] > 0)
    {
#if BOARD_NANOFET >= 1
        // is there a scaling change?  no
        fIb = pollADS1248_iso(2, 0, sys_data.Ib_trials, 1, sys_data.Ib_sps);
#endif
#if BOARD_MFET >= 1 || BOARD_MPHOX >= 1
        ADS1248_gpio_ADG1609_mux(2);
        ROM_SysCtlDelay(MILLISECOND * 10);      // 10msec settling for MUX analog
        fIb = pollADS1248_iso(1, 6, sys_data.Ib_trials, 1, sys_data.Ib_sps);       // GLIDER 1 sample, 20 hz
#endif
        fIb *= SUBSTRATECURRENT_IB_SCALING;   // convert to nanoAmps (multiply by 1000)         // new 2 Apr 2021

        tickDelta = Timer_1ms(false) - tickDelta;
        ticks = (Timer_1ms(false) - tickStart);
        if(sys_data.app_cfg[APPCFG_SAMPLING_DIAG] == 1) uprintf("\r\nIb Substrate = %5u,   %5u", tickDelta, ticks);
        tickDelta = ticks;
    }

    // ------------ Ik, CntrE Cur, (GLIDER)  Counter Electrode Current -------------
    if(sys_data.data_cfg[CFG_I_COUNTER] > 0)
    {
#if BOARD_NANOFET >= 1
        fIk = pollADS1248_iso(3, 4, sys_data.Ik_trials, 1, sys_data.Ik_sps);
#endif
#if BOARD_MFET >= 1 || BOARD_MPHOX >= 1
        ADS1248_gpio_ADG1609_mux(1);
        ROM_SysCtlDelay(MILLISECOND * 10);      // 10msec settling for MUX analog

        fIk = pollADS1248_iso(1, 5, sys_data.Ik_trials, 1, sys_data.Ik_sps);  // 3*25ms=75msec Chan +5 -1, trials = 1, gain = 1, sps = 20 Hz  //   GLIDER 40Hz
#endif
        // 15uV/nA for Ik - assuming Ik is counter electrode current.
        // V=IR  15uV = 1nA * R (15Kohm)
        fIk -= sys_data.offset_Ik;   // subtract opamp input offet voltage
        fIk *= COUNTERELECTRODE_IK_SCALE;

        fIk_std = sys_samp.AD24_std;        // Std dev does not apply with trials = 1
        fIk_std *= COUNTERELECTRODE_IK_SCALE;      // new 2 Apr 2021

        tickDelta = Timer_1ms(false) - tickDelta;
        ticks = (Timer_1ms(false) - tickStart);
        if(sys_data.app_cfg[APPCFG_SAMPLING_DIAG] == 1) uprintf("\r\nIk Cntr E    = %5u,   %5u", tickDelta, ticks);
        tickDelta = ticks;
    }


    // Vk, Counter Electrode Voltage, CntrE Volt, (Diagnostic)
    if(sys_data.data_cfg[CFG_V_COUNTER_ELECT] > 0)
    {
#if BOARD_NANOFET >= 1
        fVk = pollADS1248_iso(3, 0, sys_data.Vk_trials, 1, sys_data.Vk_sps);
#endif
#if BOARD_MFET >= 1 || BOARD_MPHOX >= 1
        ADS1248_gpio_ADG1609_mux(1);
        ROM_SysCtlDelay(MILLISECOND * 10);      // 10msec settling for MUX analog

        fVk = pollADS1248_iso(1, 6, sys_data.Vk_trials, 1, sys_data.Vk_sps);   // Mux 01, Chan +1 -6, trials = 5, gain = 1, sps = 20 Hz
#endif
        fVk_std = sys_samp.AD24_std;

        tickDelta = Timer_1ms(false) - tickDelta;
        ticks = (Timer_1ms(false) - tickStart);
        if(sys_data.app_cfg[APPCFG_SAMPLING_DIAG] == 1) uprintf("\r\nVk Cntr E    = %5u,   %5u", tickDelta, ticks);
        tickDelta = ticks;
    }


    //---------------------------- pH related voltages --------------------------------------

    //------------ Vtherm, Thermistor Voltage ----------------
    if(sys_data.data_cfg[CFG_V_THERMISTOR] > 0)
    {
#if BOARD_NANOFET >= 1
        fVtherm = pollADS1248_iso(5, 7, sys_data.Vtherm_trials, 1, sys_data.Vtherm_sps);
#endif
#if BOARD_MFET >= 1 || BOARD_MPHOX >= 1
        fVtherm = pollADS1248_iso(0, 6, sys_data.Vtherm_trials, 1, sys_data.Vtherm_sps);       // Chan +0 -6, trials = 5, gain = 1, sps = 20 Hz (per Yui 5May2021)
        fVtherm_std = sys_samp.AD24_std;
#endif
        tickDelta = Timer_1ms(false) - tickDelta;
        ticks = (Timer_1ms(false) - tickStart);
        if(sys_data.app_cfg[APPCFG_SAMPLING_DIAG] == 1) uprintf("\r\nVtherm       = %5u,   %5u", tickDelta, ticks);
        tickDelta = ticks;
    }

// THOM TODO: don't allow the config of unsupported data products

    //-------------- Vrsi_B, Int Ref Off, ------------------------
    if(sys_data.data_cfg[CFG_VRSI_BIASED] > 0)     // Not valid on nanoFET
    {
#if BOARD_MFET >= 1 || BOARD_MPHOX >= 1
        //dbg_printf("\r\nno intref on glider\r\n");
        ADS1248_gpio_ADG1609_mux(3);
        ROM_SysCtlDelay(MILLISECOND * 10);      // 10msec settling for MUX analog

        fVrsi_B = pollADS1248_iso(1, 5, sys_data.Vrsi_trials, 1, sys_data.Vrsi_sps);  // 200msec Chan +1 -5, trials = 10, gain = user, sps = 20 Hz
        fVrsi_B_std = sys_samp.AD24_std;

#endif
#if BOARD_NANOFET >= 1
        // Int Ref with offset not applicable on nanoFET per Scott
        fVrsi_B = 0.0;
        fVrsi_B_std = 0.0;
#endif
        tickDelta = Timer_1ms(false) - tickDelta;
        ticks = (Timer_1ms(false) - tickStart);
        if(sys_data.app_cfg[APPCFG_SAMPLING_DIAG] == 1) uprintf("\r\nVrsi_B       = %5u,   %5u", tickDelta, ticks);
        tickDelta = ticks;
    }



    // ----------- Vrsi (aka Vint) --------------
    if(sys_data.data_cfg[CFG_VRSI] > 0)        // Not valid on nanoFET
    {
#if BOARD_MFET >= 1 || BOARD_MPHOX >= 1
        //dbg_printf("\r\nno Vrsi on glider, not valid on nanoFET\r\n");
        ADS1248_gpio_ADG1609_mux(3);
        ROM_SysCtlDelay(MILLISECOND * 10);      // 10msec settling for MUX analog
        fVrsi = pollADS1248_iso(1, 6, sys_data.Vrsi_trials, 1, sys_data.Vrsi_sps);       // Chan +1 -6, trials = 10, gain = 1, sps = 20 Hz (10*50ms = 500ms)
        fVrsi_std = sys_samp.AD24_std;

#endif
#if BOARD_NANOFET >= 1
        fVrsi = 0.0;
        fVrsi_std = 0.0;
#endif

        tickDelta = Timer_1ms(false) - tickDelta;
        ticks = (Timer_1ms(false) - tickStart);
        if(sys_data.app_cfg[APPCFG_SAMPLING_DIAG] == 1) uprintf("\r\nVrsi         = %5u,   %5u", tickDelta, ticks);
        tickDelta = ticks;
    }



    // --------- Vrse_B, Ext Ref Offset, -------------
    if(sys_data.data_cfg[CFG_VRSE_BIASED] > 0)     // Not valid on nanoFET
    {
#if BOARD_NANOFET >= 1
        fVrse_B = 0.0;
        fVrse_B_std = 0.0;
#endif
#if BOARD_MFET >= 1 || BOARD_MPHOX >= 1
        //dbg_printf("\r\nno extref on glider\r\n");
        ADS1248_gpio_ADG1609_mux(0);
        ROM_SysCtlDelay(MILLISECOND * 10);      // 10msec settling for MUX analog
        fVrse_B = pollADS1248_iso(1, 5, sys_data.Vrse_trials, 1, sys_data.Vrse_sps);       // 200msec Chan +1 -5, trials = 10, gain = user, sps = 20 Hz
        fVrse_B_std = sys_samp.AD24_std;

#endif
#if BOARD_NANOFET >= 1
        fVrse_B = 0.0;
        fVrse_B_std = 0.0;
#endif
        tickDelta = Timer_1ms(false) - tickDelta;
        ticks = (Timer_1ms(false) - tickStart);
        if(sys_data.app_cfg[APPCFG_SAMPLING_DIAG] == 1) uprintf("\r\nVrse_B       = %5u,   %5u", tickDelta, ticks);
        tickDelta = ticks;
    }




    // ----------- fVrse ----------------------
    if(sys_data.data_cfg[CFG_VRSE] > 0)
    {
        fVrse = 0.0;         // new 30 Mar 2021
#if BOARD_NANOFET >= 1
        fVrse = pollADS1248_iso(1, 0, sys_data.Vrse_trials, 1, sys_data.Vrse_sps);
#endif


#if BOARD_MFET >= 1 || BOARD_MPHOX >= 1     //6 (gnd) NOT available on nanoFET
        ADS1248_gpio_ADG1609_mux(0);
        ROM_SysCtlDelay(MILLISECOND * 10);      // 10msec settling for MUX analog
        fVrse = pollADS1248_iso(1, 6, sys_data.Vrse_trials, 1, sys_data.Vrse_sps);  // 10x50msec= 500msec  trials=10, gain=1, sps=20
#endif
#if BOARD_NANOFET >= 1
            // 6 (GND) is not connected on nanoFET
        fVrse = pollADS1248_iso(1, 5, sys_data.Vrse_trials, 1, sys_data.Vrse_sps);  // 10x50msec= 500msec  trials=10, gain=1, sps=20
#endif
        fVrse_std = sys_samp.AD24_std;

        tickDelta = Timer_1ms(false) - tickDelta;
        ticks = (Timer_1ms(false) - tickStart);
        if(sys_data.app_cfg[APPCFG_SAMPLING_DIAG] == 1) uprintf("\r\nVrse         = %5u,   %5u", tickDelta, ticks);
        tickDelta = ticks;
    }


    // ------------- read internal adc (battery, etc), -----------------------
    // requires  adc_onchip_init(); is called and settled for 100msec or so prior to read_all_adc

    // fix for low reading of battery voltage when few fields are config'd 21 Jul 2021.   When no fields are config'd we have a crash
    while(1)
    {
        if((Timer_1ms(false) - tick_onchip) > 150)      // at least 150msec for proper vbat reading
            break;
        ROM_SysCtlDelay(MILLISECOND * 5);
    }

#if BOARD_NANOFET >= 1
    fVbat_main = 0.0;
#endif
#if BOARD_MFET >= 1 || BOARD_MPHOX >= 1
    read_all_adc();
    read_all_adc();     // read a second time for better fidelity

    // battery voltage must be read for 'too low' check at bottom
    fVbat_main = (float)(adc_data[0]*100);
    fVbat_main /= 18193.77;      // 30 Sep 2019  11.75v is measured with Agilent meter as 12.069v
                               // must compute battery voltage as it is checked for 'too low' below

    // onchip temperature (formulae from TI example code) (NOT NEEDED)
    //fOnChipTemp = (147.5 - ((75.0*3.3 *(float)adc_data[7])) / 4096.0);

    // LM60 temp
    if(sys_data.data_cfg[CFG_BRD_TEMP] > 0)
    {
        fBrdTempC = ((((float)adc_data[4])*0.80566) - 424) / 6.25;   //VOut= (+6.25 mV/°C × T °C) + 424 mV  // LM60 temperature sensor - formula from datasheet / schematic (good job Scott)
    }

    // Humidity
    if(sys_data.data_cfg[CFG_BRD_HUMIDITY] > 0)
    {
        // Water sensor - convert to percent
        uiWater = (adc_data[3] * 100) / 2596;    // NOTE: Water voltage adc cnts is 2622 when pulled to 3.3v  (measured at 2.1092v on test point with agilent u1272a meter)
        if(uiWater > 100)
            uiWater = 100;

        fHumidity = (float)( (adc_data[2] * 100) );  // VOUT=(VSUPPLY)(0.00636(sensor RH) + 0.1515), typical at 25C
        fHumidity /= 3284;
        uiHumidity = (adc_data[2] * 100) / 3284;
    }
#endif


#if BOARD_NANOFET >= 1
    //read_bme280();
#endif

    tickDelta = Timer_1ms(false) - tickDelta;
    ticks = (Timer_1ms(false) - tickStart);
    if(sys_data.app_cfg[APPCFG_SAMPLING_DIAG] == 1) uprintf("\r\nOnchip ADC   = %5u,   %5u", tickDelta, ticks);
    tickDelta = ticks;

    int stopFlg;
    stopFlg = 0;

#if BOARD_MFET >= 1 || BOARD_MPHOX >= 1
    // Check for low battery voltage. Exit and sleep if too low.
    if( fVbat_main < (sys_data.low_batt_volt + 0.005) )
    {
        pwr_vbat_mon_on();
        ROM_SysCtlDelay(MILLISECOND * 10);
        adc_onchip_init();
        ROM_SysCtlDelay(MILLISECOND * 100);
        for(indx=0; indx<5; indx++)
        {
            if(indx < 4)
                uprintf("\r\nLow battery voltage (%.2f < %.2f) !\r\n", fVbat_main, sys_data.low_batt_volt );
            else
                uprintf("\r\nLow battery voltage (%.2f < %.2f) ! Exiting deploy mode...\r\n", fVbat_main, sys_data.low_batt_volt );
            wait_consoleTx();

            ROM_SysCtlDelay(MILLISECOND * 150);

            read_all_adc();
            read_all_adc();     // read a second time for better fidelity

            // battery voltage must be read for 'too low' check at bottom
            fVbat_main = (float)(adc_data[0]*100);
            fVbat_main /= 18193.77;

            // if the input voltage is above the low batt threshold, then go ahead with the sample.   If after 5 checks, then SLEEP in IDLE and stop sampling to prevent uSD card failure
            if(fVbat_main > sys_data.low_batt_volt)
            {

                // any reading in 5 tries above the threshold is OK to write the sample.   Looking for 5 readings below threshold to end deployment.
                stopFlg = 0;
                break;
            }
            else
            {
                // if DIAG instrumented loop, don't halt  Fix 6 Aug 2021
                if(sys_data.app_cfg[APPCFG_SAMPLING_DIAG] == 0)
                {
                    stopFlg = 1;
                }
            }

            led_red_on();
            led_green_off();
            delay_msec(500);

            led_red_off();
            led_green_on();
            delay_msec(500);
        }

        if(stopFlg == 1)
        {
            error_store("Low battery! Exiting deploy mode");
            sleep(IDLE, 0);     // Sleep until woken by user, halt rtc wakeup by changing state to IDLE
        }
    } // Low voltage handler


#endif

    // poweroff monitoring circuitry
    pwr_vbat_mon_off();   // Turn off VBat monitoring
    pwr_env_mon_off();    // Turn off Load switch for ENV monitoring

    // Shutdown sensor power supply
    closeADS1248_iso();


    // ---------- Calculate the external and internal pH values -------------------------

    if(sys_data.data_cfg[CFG_CALC_TEMP] > 0)
    {
        fTempC = DuraFET_temp(fVtherm, sys_data.TCOffset);

        tickDelta = Timer_1ms(false) - tickDelta;
        ticks = (Timer_1ms(false) - tickStart);
        if(sys_data.app_cfg[APPCFG_SAMPLING_DIAG] == 1) uprintf("\r\nCalc TempC   = %5u,   %5u", tickDelta, ticks);
        tickDelta = ticks;
    }

    if(sys_data.data_cfg[CFG_CALC_PH_VRSE] > 0)
    {
        if(sys_data.data_cfg[CFG_CTD] == 0)
            SBE_sal = sys_data.default_sal;       // for pH_ext calc  (init'd to 35.0)
        else
            SBE_sal = sys_samp.sensor_sal;
        // Todo sys_data.sensor_sal;
        pHext = calc_pHext(fVrse, fTempC, SBE_sal);  // NOTE: this might be Vrse_B that is needed....   5 May 2021

        tickDelta = Timer_1ms(false) - tickDelta;
        ticks = (Timer_1ms(false) - tickStart);
        if(sys_data.app_cfg[APPCFG_SAMPLING_DIAG] == 1) uprintf("\r\nCalc pH Ext  = %5u,   %5u", tickDelta, ticks);
        tickDelta = ticks;
    }



    if(sys_data.data_cfg[CFG_CALC_PH_VRSI] > 0)
    {
        // requires TC and fVrsi_B
        //pHint = calc_pHint(fVrsi_B, fTempC);   // per YUI  7 Jun 2018
        pHint = calc_pHint(fVrsi, fTempC);   // per YUI  28 Dec 2021

        tickDelta = Timer_1ms(false) - tickDelta;
        ticks = (Timer_1ms(false) - tickStart);
        if(sys_data.app_cfg[APPCFG_SAMPLING_DIAG] == 1) uprintf("\r\nCalc pH Int  = %5u,   %5u", tickDelta, ticks);
        tickDelta = ticks;
    }



    //#000000    12.03           -3.59        0.997431        0.674842        -0.055235       0.000005        -0.799272       0.000004        -0.500569       0.000005        18178.39        -399.644        24.707  18.18122

    indx = 0;
    // for column alignment between data and header, 8 chars per field  - note, a negative sign throws off the print format

    if(sys_data.data_cfg[CFG_SAMPLE_NUM] > 0)       { indx += sprintf((char *)&prnBuf[indx], "#%07u\t", sys_samp.current_sample);   } //0  // was %07d
    if(sys_data.data_cfg[CFG_TIMESTAMP] > 0)         { indx += sprintf((char *)&prnBuf[indx], "%s\t", timestamp);               } //1    //was     if(sys_data.data_cfg[CFG_TIMESTAMP] > 0)         { indx += sprintf(&prnBuf[indx], "     %s\t", timestamp);               } //1

    if(sys_data.data_cfg[CFG_VIN_BAT_VOLT] > 0)     { indx += sprintf((char *)&prnBuf[indx], "%8.2f\t", fVbat_main);                } //2  // was %5.2f
    if(sys_data.data_cfg[CFG_BIAS_BAT_POS] > 0)     { indx += sprintf((char *)&prnBuf[indx], "%8.2f\t", fBiasPos);                  } //5  5.2
    if(sys_data.data_cfg[CFG_BIAS_BAT_NEG] > 0)     { indx += sprintf((char *)&prnBuf[indx], "%8.2f\t", fBiasNeg);                  } //5  5.2
    if(sys_data.data_cfg[CFG_BRD_TEMP] > 0)         { indx += sprintf((char *)&prnBuf[indx], "%8.2f\t", fBrdTempC);                     } //3  // was %5.2f
    if(sys_data.data_cfg[CFG_BRD_HUMIDITY] > 0)     { indx += sprintf((char *)&prnBuf[indx], "%8u\t", uiHumidity);                  } //4  // was %3u

    if(sys_data.data_cfg[CFG_V_THERMISTOR] > 0)     { indx += sprintf((char *)&prnBuf[indx], "%8.6f\t", fVtherm);                   } //6
    if(sys_data.data_cfg[CFG_V_THERMISTOR_STD] > 0) { indx += sprintf((char *)&prnBuf[indx], "%8.6f\t", fVtherm_std);               } //7
    if(sys_data.data_cfg[CFG_CALC_TEMP] > 0)        { indx += sprintf((char *)&prnBuf[indx], "%8.3f\t", fTempC);                    } //20

    if(sys_data.data_cfg[CFG_VRSI] > 0)             { indx += sprintf((char *)&prnBuf[indx], "%8.6f\t", fVrsi);                     } //12
    if(sys_data.data_cfg[CFG_VRSI_STD] > 0)         { indx += sprintf((char *)&prnBuf[indx], "%8.6f\t", fVrsi_std);                 } //13
    if(sys_data.data_cfg[CFG_CALC_PH_VRSI] > 0)     { indx += sprintf((char *)&prnBuf[indx], "%8.3f\t", pHint);                     } //21

    if(sys_data.data_cfg[CFG_VRSE] > 0)             { indx += sprintf((char *)&prnBuf[indx], "%8.6f\t", fVrse);                     } //14
    if(sys_data.data_cfg[CFG_VRSE_STD] > 0)         { indx += sprintf((char *)&prnBuf[indx], "%8.6f\t", fVrse_std);                 } //15
    if(sys_data.data_cfg[CFG_CALC_PH_VRSE] > 0)     { indx += sprintf((char *)&prnBuf[indx], "%8.3f\t", pHext);                     } //22

    if(sys_data.data_cfg[CFG_VRSI_BIASED] > 0)      { indx += sprintf((char *)&prnBuf[indx], "%8.6f\t", fVrsi_B);                   } //8
    if(sys_data.data_cfg[CFG_VRSI_BIASED_STD] > 0)  { indx += sprintf((char *)&prnBuf[indx], "%8.6f\t", fVrsi_B_std);               } //9
    if(sys_data.data_cfg[CFG_VRSE_BIASED] > 0)      { indx += sprintf((char *)&prnBuf[indx], "%8.6f\t", fVrse_B);                   } //10
    if(sys_data.data_cfg[CFG_VRSE_BIASED_STD] > 0)  { indx += sprintf((char *)&prnBuf[indx], "%8.6f\t", fVrse_B_std);               } //11

    if(sys_data.data_cfg[CFG_V_COUNTER_ELECT] > 0)  { indx += sprintf((char *)&prnBuf[indx], "%8.6f\t", fVk);                       } //16
    if(sys_data.data_cfg[CFG_V_COUNTER_ELECT_STD] > 0)  { indx += sprintf((char *)&prnBuf[indx], "%8.6f\t", fVk_std);               } //17
    if(sys_data.data_cfg[CFG_I_COUNTER] > 0)        { indx += sprintf((char *)&prnBuf[indx], "%8.2f\t", fIk);                       } //18
    if(sys_data.data_cfg[CFG_I_SUBSTRATE] > 0)      { indx += sprintf((char *)&prnBuf[indx], "%8.3f\t", fIb);                       } //19

    if(sys_data.data_cfg[CFG_OPTODE] > 0)           { indx += sprintf((char *)&prnBuf[indx], "%s\t", optode.buf);                   } //23
    if(sys_data.data_cfg[CFG_CTD] > 0)              { indx += sprintf((char *)&prnBuf[indx], "%s\t", ctd.buf);                      } //23
    if(sys_data.data_cfg[CFG_OCR] > 0)              { indx += sprintf((char *)&prnBuf[indx], "%s\t", ocr.buf);                      } //24

    if(sys_data.pump_seq_type == 2)                 { indx += sprintf((char *)&prnBuf[indx], "%s\t", pumpBuf);                      } //24

    tickDelta = Timer_1ms(false) - tickDelta;
    ticks = (Timer_1ms(false) - tickStart);
    if(sys_data.app_cfg[APPCFG_SAMPLING_DIAG] == 1) uprintf("\r\nformat data  = %5u,   %5u\r\n", tickDelta, ticks);
    tickDelta = ticks;

    tickEnd = Timer_1ms(false);
    ticks = (tickEnd - tickStart);
    //uprintf("(Time: %u msec)", ticks );
    if(sys_data.app_cfg[APPCFG_SAMPLING_DIAG] == 1)  indx += sprintf((char *)&prnBuf[indx], "(%u msec)\t", ticks);

    // terminate.
    indx--;     // delete the trailing tab
    prnBuf[indx] = '\r';
    indx++;
    prnBuf[indx] = '\n';
    indx++;
    prnBuf[indx] = 0;

    //if(txFlg == 1) uprintf("%s", prnBuf);      // uprint maximum is 255 sample to console, leaving this line for other developers...
    if(printFlg == 1) UARTwrite((char *)prnBuf, strlen((char *)prnBuf));


    if( (sys_data.app_cfg[APPCFG_MICROSD_ENABLE] == 1) && (writeFlg == 1) )  // fix 6 Aug 2021
    {
         //FA_OPEN_APPEND is not supported in this fatfs version
         // Open a file
        fresult = f_open(&fileObject, sys_data.fileName, FA_READ | FA_WRITE | FA_OPEN_ALWAYS);
         if(fresult != FR_OK)
         {
             // != FR_OK
             uprintf("f_open error: %s\r\n", StringFromFresult(fresult));
             error_store("f_open error");

         }
         else  // FILE is open
         {
             //uprintf("\r\nSampling... f_open is good\r\n"); // THOM DEBUG

             // Seek to the end, to append our file
             fresult = f_lseek(&fileObject, fileObject.fsize);
             if(fresult != FR_OK)
             {
                 uprintf("f_lseek error: %s\r\n", StringFromFresult(fresult));
             }
             else
             {
                 //uprintf("\r\nSampling... f_lseek is good\r\n"); // THOM DEBUG

                 // Write the formatted data string in the prnBuf buffer to the SD card
                  fresult = f_write( &fileObject, prnBuf, strlen((char *)prnBuf), (UINT*)&bw);
                  if(fresult != FR_OK)
                  {
                      uprintf("f_write error: %s\r\n", StringFromFresult(fresult));
                  }
                  else
                  {
                      //uprintf("\r\nSampling... f_write is good\r\n"); // THOM DEBUG
                  }

             }


             // Close the file
             fresult = f_close( &fileObject );
             if(fresult != FR_OK)
             {
                 uprintf("f_close error: %s\r\n", StringFromFresult(fresult));
                 error_store("f_close error");
             }
             else
             {
                 //uprintf("\r\nSampling... f_close is good\r\n"); // THOM DEBUG
             }

         }

    } // if sys_data.app_cfg[APPCFG_MICROSD_ENABLE]

    tickDelta = Timer_1ms(false) - tickDelta;
    ticks = (Timer_1ms(false) - tickStart);
    if(sys_data.app_cfg[APPCFG_SAMPLING_DIAG] == 1) uprintf("\r\nuSD writes   = %5u,   %5u", tickDelta, ticks);
    tickDelta = ticks;

    wait_consoleTx();

    tickDelta = Timer_1ms(false) - tickDelta;
    ticks = (Timer_1ms(false) - tickStart);
    if(sys_data.app_cfg[APPCFG_SAMPLING_DIAG] == 1) uprintf("\r\nwait TX      = %5u,   %5u", tickDelta, ticks);
    tickDelta = ticks;

    sys_samp.current_sample++;  // Increment the sample counter, this is stored to FRAM in sleep() routine

    led_sampling_off();      // red_led
    //led_green_off();

    // Low voltage check was here, moved up before uSD write

// .diag is gone

}


void exercise_iso(void)
{
    float fVtherm, fVtherm_std;

    openADS1248_iso();              // turn on isolated power to 24bit A/D converter
    ADS1248_gpio_init();            // defd in ADS1248_iso.c

    // turn on sensor and battery monitoring circuit - needs at least 150msec to settle (use iso sampling as delay
    pwr_env_mon_on();    // Turn on Load switch for ENV monitoring
    pwr_vbat_mon_on();  //ROM_GPIOPinWrite(GPIO_PORTM_BASE, GPIO_PIN_6, 0xFF);   // Turn on VBat monitoring

    ROM_SysCtlDelay(1*MILLISECOND);         // fast sampling (was 800msec)

    adc_onchip_init();

    ROM_SysCtlDelay(100*MILLISECOND);

    fVtherm = pollADS1248_iso(0, 6, sys_data.Vtherm_trials, 1, sys_data.Vtherm_sps);       // Chan +0 -6, trials = 5, gain = 1, sps = 20 Hz (per Yui 5May2021)
    fVtherm_std = sys_samp.AD24_std;

    uprintf("\r\nThermistor = %.6f\r\n", fVtherm);

    ROM_SysCtlDelay(900*MILLISECOND);


    // poweroff monitoring circuitry
    pwr_vbat_mon_off();   // Turn off VBat monitoring
    pwr_env_mon_off();    // Turn off Load switch for ENV monitoring

    // Shutdown sensor power supply
    closeADS1248_iso();

}

#endif




/*
 * batt_volt()
 * Returns main battery voltage on controller side of isolation diodes
 * RCG 4/14
 * TM 4/18  Added support for new MFET board
 *
 */
float batt_volt(void)
{
    float batt_volt;

#if BOARD_MFET >= 1 || BOARD_MPHOX == 1
    batt_volt = read_env_sensors();
#endif

    return batt_volt;
}

/*
 * batt_volt_iso()
 * Returns isolated battery voltage
 * RCG 4/14
 * TM  8/2019 added support for MFET v2 (revB)
 * assumes that iso power is on
 */
float batt_volt_iso(void)
{
    float ADC_volts, batt_volt;

#if BOARD_MFET == 1
    batt_volt = 0.0;
#endif

#if BOARD_MFET == 2  || BOARD_MPHOX == 1
    // GPIO3 on ADS1248
    //    float is gnd
    //    0 = bias-
    //    1 = bias+
    ADS1248_gpio3(1);
    ADC_volts = pollADS1248_iso(7, 6, 5, 1, 20);
    batt_volt = ADC_volts*2.0;
#endif
    return(batt_volt);
}

// NOT TESTED YET 14 Apr 2021 - issue with iso power turn on and init should be resolved
void read_bias_bat(void)
{
    float biasplus, biasneg, ADC_volts;
    //unsigned int indx;

    // GPIO3 on ADS1248
    //    float is gnd
    //    0 = bias-
    //    1 = bias+


    openADS1248_iso();
    ROM_SysCtlDelay(MILLISECOND * 100);
    ADS1248_gpio_init();

    ADS1248_gpio3(0);
    ROM_SysCtlDelay(MILLISECOND * 10);
    ADC_volts = pollADS1248_iso(7, 6, 5, 1, 20);    // throw away first reading
    ROM_SysCtlDelay(MILLISECOND * 100);
    ADC_volts = pollADS1248_iso(7, 6, 5, 1, 20);
    biasneg = ADC_volts*2.0;

    ADS1248_gpio3(1);
    ROM_SysCtlDelay(MILLISECOND * 10);
    ADC_volts = pollADS1248_iso(7, 6, 5, 1, 20);    // throw away first reading
    ROM_SysCtlDelay(MILLISECOND * 100);
    ADC_volts = pollADS1248_iso(7, 6, 5, 1, 20);
    biasplus = ADC_volts*2.0;

    fBiasPos = biasplus;   // update global var
    fBiasNeg = biasneg;     // update global var

    //uprintf("Iso Bat Bias- %7.3F,  Bias+ %7.3F\r\n", biasneg, biasplus);
    //ROM_SysCtlDelay(MILLISECOND * 500);


    closeADS1248_iso();
}

void print_bias_volt_iso(void)
{
    float biasplus, biasneg, ADC_volts;
    unsigned int indx;

    // GPIO3 on ADS1248
    //    float is gnd
    //    0 = bias-
    //    1 = bias+


    openADS1248_iso();
    ROM_SysCtlDelay(MILLISECOND * 100);
    ADS1248_gpio_init();

    for(indx=0; indx<5; indx++)
    {
        ADS1248_gpio3(0);
        ROM_SysCtlDelay(MILLISECOND * 10);
        ADC_volts = pollADS1248_iso(7, 6, 5, 1, 20);
        biasneg = ADC_volts*2.0;

        ADS1248_gpio3(1);
        ROM_SysCtlDelay(MILLISECOND * 10);
        ADC_volts = pollADS1248_iso(7, 6, 5, 1, 20);
        biasplus = ADC_volts*2.0;

        uprintf("Iso Bat Bias- %7.3F,  Bias+ %7.3F\r\n", biasneg, biasplus);
        ROM_SysCtlDelay(MILLISECOND * 500);
    }

    closeADS1248_iso();
}

/*
 * temp_int()
 * Returns internal temperature
 * RCG 4/14
 */
float controller_temp(void)
{
    float ADC_volts, temp;

    ADC_volts = pollADS1248_noniso(2, 7, 1); // Chan 2-7, 1 trial
    temp = (ADC_volts * 1000 - 480) / 15.6;
    return temp;
}


/*
 * depth()
 * Returns depth in meters from Honeywell MLH100PGB 100 psi pressure sensor
 * RCG 4/14
 */
float pressure(void)
{
#ifdef GETRIDOFPRESSURE_7May2019
    float ADCvolts, pressure;


    ADCvolts = pollADS1248_noniso(3, 7, 1); // Result in volts

    pressure = ((ADCvolts * 3.2) - 0.5) * (100 / 4 / 1.45); // 3.2-to-1 divider, 0.5-4.5 V span, 1.45 dBar/psi
    return pressure;    // Pressure in dBar
#endif
    return(0.0);
}

#if BOARD_MFET >= 1  || BOARD_MPHOX == 1


float read_vbat(void)
{
    float fVbat, fOnChipTemp, fExtTemp;
    uint32_t  uiHumidity, uiWater;
    uint32_t indx = 0;

    pwr_env_mon_on();       // Turn on Load switch for ENV monitoring
    pwr_vbat_mon_on();      //   ROM_GPIOPinWrite(GPIO_PORTM_BASE, GPIO_PIN_6, 0xFF);   // Turn on VBat monitoring

    adc_onchip_init();

    // delay to allow voltage divider circuit to charge up
    ROM_SysCtlDelay(MILLISECOND*150);    // 150msec reads 12.26, s100 works (12.31 reads 12.18), 25 does not (12.31 reads 8.99, 9.09, 9.20, 9.29)v), 50msec is weak (11.28, 11.31, 11.35, 11.37)

    read_all_adc();

    fVbat = (float)(adc_data[0]*100);
    //fVbat /= 18687.707;  // Thom 30 Sep 2019 reading 11.75 when actual is 12.069v
    fVbat /= 18193.77;

    // onchip temperature (formulae from TI example code)
    //TempValueC = (uint32_t)(147.5 - ((75.0*3.3 *(float)adc_data[7])) / 4096.0);
    fOnChipTemp = (147.5 - ((75.0*3.3 *(float)adc_data[7])) / 4096.0);

    // LM60 temperature sensor - formula from datasheet / schematic (good job Scott)
    // Vout = (+6.25 mV/C * T) + 424mV   =>  T = ((ADCcnt * 0.80566) - 424) / 6.25
    fExtTemp = ((((float)adc_data[4])*0.80566) - 424) / 6.25;

    // Water sensor - convert to percent
    uiWater = (adc_data[3] * 100) / 2596;    // NOTE: Water voltage adc cnts is 2622 when pulled to 3.3v  (measured at 2.1092v on test point with agilent u1272a meter)
    if(uiWater > 100)
        uiWater = 100;

    // Humidity
    uiHumidity = (adc_data[2] * 100) / 3284;

    // Pressure

    //uprintf("Bat = %6.2fV VBAT=%u VPRESS=%3u  VHUM=%3u  VWATER=%3u   VXTEMP=%3u   VBAT=%3u, VBAT=%u, VTEMP=%u  i=%u\r", fVbat, adc_data[0], adc_data[1], adc_data[2], adc_data[3], adc_data[4], adc_data[5], adc_data[6], TempValueC, indx++);
    //dbg_printf("Bat = %6.2fV Pressure = %4u  Humidity = %3u  Water = %3u  Temperature = %5.1fC (%4u)   ChipTemp = %5.1fC  i=%u\r\n\r", fVbat, adc_data[1], uiHumidity, uiWater, fExtTemp, adc_data[4], fOnChipTemp, indx++);

    pwr_vbat_mon_off();   // Turn off VBat monitoring

    return(fVbat);
 }

// This function applies only to the MFET/MPHOX
float read_env_sensors(void)
{
    float fVbat, fOnChipTemp, fExtTemp;
    uint32_t  uiHumidity, uiWater;
    uint32_t indx = 0;

    pwr_env_mon_on();       // Turn on Load switch for ENV monitoring
    pwr_vbat_mon_on();      //ROM_GPIOPinWrite(GPIO_PORTM_BASE, GPIO_PIN_6, 0xFF);   // Turn on VBat monitoring

    pwr_iso_on();        // Iso-power On
    dbg_printf("iso power on\r\n");

    adc_onchip_init();

    // delay to allow voltage divider circuit to charge up
    ROM_SysCtlDelay(MILLISECOND*150);    // 150msec reads 12.26, s100 works (12.31 reads 12.18), 25 does not (12.31 reads 8.99, 9.09, 9.20, 9.29)v), 50msec is weak (11.28, 11.31, 11.35, 11.37)

    read_all_adc();

    fVbat = (float)(adc_data[0]*100);
    //fVbat /= 18687.707;  // Thom 30 Sep 2019 reading 11.75 when actual is 12.069v
    fVbat /= 18193.77;

    // onchip temperature (formulae from TI example code)
    //TempValueC = (uint32_t)(147.5 - ((75.0*3.3 *(float)adc_data[7])) / 4096.0);
    fOnChipTemp = (147.5 - ((75.0*3.3 *(float)adc_data[7])) / 4096.0);

    // LM60 temperature sensor - formula from datasheet / schematic (good job Scott)
    // Vout = (+6.25 mV/C * T) + 424mV   =>  T = ((ADCcnt * 0.80566) - 424) / 6.25
    fExtTemp = ((((float)adc_data[4])*0.80566) - 424) / 6.25;

    // Water sensor - convert to percent
    uiWater = (adc_data[3] * 100) / 2596;    // NOTE: Water voltage adc cnts is 2622 when pulled to 3.3v  (measured at 2.1092v on test point with agilent u1272a meter)
    if(uiWater > 100)
        uiWater = 100;

    // Humidity
    uiHumidity = (adc_data[2] * 100) / 3284;

    // Pressure

    //uprintf("Bat = %6.2fV VBAT=%u VPRESS=%3u  VHUM=%3u  VWATER=%3u   VXTEMP=%3u   VBAT=%3u, VBAT=%u, VTEMP=%u  i=%u\r", fVbat, adc_data[0], adc_data[1], adc_data[2], adc_data[3], adc_data[4], adc_data[5], adc_data[6], TempValueC, indx++);
    dbg_printf("Bat = %6.2fV Pressure = %4u  Humidity = %3u  Water = %3u  Temperature = %5.1fC (%4u)   ChipTemp = %5.1fC  i=%u\n\r", fVbat, adc_data[1], uiHumidity, uiWater, fExtTemp, adc_data[4], fOnChipTemp, indx++);


    pwr_vbat_mon_off();   // Turn off VBat monitoring
    pwr_iso_off();        // Iso-power Off
    dbg_printf("iso power off, vbat monitoring off\r\n");

    return(fVbat);
 }
#endif





#ifdef TIMINGINFO
SampNum             MM/DD/YYYY HH:MM:SS          Vtherm        VthrmStd         TC_Dfet            Vrsi        Vrsi_std        pHintEst            Vrse        Vrse_std        pHextEst          Vrsi_B        VrsiBstd          Vrse_B VrseBstd              Vk          Vk_std              Ik              Ib        VbatMain        VbiasPos        VbiasNeg         TC_cont        Humidity

Pump         = 2002,   2002
Pwr on, init =   24,   2026
CTD Optode   =    0,   2026
Bias Bat     =   71,  2097
Ib Substrate =   61,   2158
Ik Cntr E    =   60,   2218
Vk Cntr E    =  260,   2478
Vtherm       =  249,   2727
Vrsi         =  508,   3235
Vrse         =  508,   3743
Vrse_B       =  507,   4250
Vrsi_B       =  508,   4758
Onchip ADC   =    0,   4758
Calc TempC   =    1,   4759
Calc pH Ext  =    2,   4761
Calc pH Int  =    0,   4761
Optode       =    0,   4761
CTD          =    0,   4761
format data  =    2,   4763
#0000492             05/17/2021 04:26:32        0.997514        0.000002          24.704        -0.055202       0.000009          18.182        -0.799227       0.000005           7.826        0.674909        0.000008        -0.069118        0.000006        -0.500551       0.000003        18197.15        -399.608           12.00            3.61           -3.60           18.01              59        (4763 msec)

uSD writes   =   12,   4775
wait TX      =   27,   4802



A -- Sample Num               = 1
B -- MM/DD/YYYY HH:MM:SS      = 1

C -- Vthermistor              = 1
     Vtermistor Std           = 1
D -- Temperature Calc         = 1
E -- Vrsi (Int Ref pH volt)   = 1
     Vrsi Std                 = 1
F -- pH Vrsi Calc             = 1
G -- Vrse (Ext Ref pH volt)   = 1
     Vrse Std                 = 1
H -- pH Vrse Calc             = 1
I -- Vrsi Biased (7pH=0v)     = 1
J -- Vrsi Biased Std          = 1
K -- Vrse Biased (7pH=0v)     = 1
L -- Vrse Biased Std          = 1

M -- Counter Electrode Vk     = 1
N -- Counter Electrode Vk Std = 1
O -- Counter Electrode Cur Ik = 1
P -- Substrate Current        = 1

Q -- Battery Volt             = 1
R -- Bias Battery Pos         = 1
S -- Bias Battery Neg         = 1
T -- Board Temperature        = 1
U -- Board Humidity           = 1

U -- Optode                   = 1
V -- Conductivity             = 1


 SampNum             MM/DD/YYYY HH:MM:SS          Vtherm        VthrmStd         TC_Dfet            Vrsi        Vrsi_std        pHintEst            Vrse        Vrse_std        pHextEst          Vrsi_B        VrsiBstd          Vrse_B VrseBstd              Vk          Vk_std              Ik              Ib        VbatMain        VbiasPos        VbiasNeg         TC_cont        Humidity                Opt_PN  Opt_SN  Moxy    O2satper        TC_opt  Dphase   Bphase  Rphase  Bamp    Bpot    Ramp    Opt_rawtemp     TempC   Cond    Salt    Unk1    Date    Time            Cond_PN Cond_SN Cond    Temp    Unk1    Unk2    Unk3

Pump         = 2002,   2002
Pwr on, init =   23,   2025
CTD Optode   =   22,   2047
Bias Bat     =   70,  2117
Ib Substrate =   61,   2178
Ik Cntr E    =   61,   2239
Vk Cntr E    =  989,   3228
Vtherm       =  250,   3478
Vrsi         =  508,   3986
Vrse         =  507,   4493
Vrse_B       =  508,   5001
Vrsi_B       =  508,   5509
Onchip ADC   =    0,   5509
Calc TempC   =    1,   5510
Calc pH Ext  =    1,   5511
Calc pH Int  =    1,   5512
Optode       =    0,   5512
CTD          =    0,   5512
format data  =    2,   5514
#0000491             05/17/2021 04:21:05        0.997609        0.000002          24.701        -0.055199       0.000011          18.183        -0.799234       0.000007           7.826        0.674919        0.000005        -0.069120        0.000007        -0.500557       0.000005        18197.77        -399.623           11.99            3.61           -3.60           17.50              60        4831    856     273.940 92.968  18.159  28.090  30.381   38.298  7.917   599.9   704.4   252.7   5860    29      -0.004  17.101  0.010   998.766 1473.130        (5514 msec)

uSD writes   =   14,   5528
wait TX      =   35,   5563





Pump         = 1900
Pwr on, init = 1920
CTD Optode   = 1920
Bias Bat     = 1920
Ib Substrate = 1980
Ik Cntr E    = 2040
Vk Cntr E    = 2300
Vtherm       = 2300
Vrsi         = 2300
Vrse         = 2810
Vrse_B       = 2810
Vrsi_B       = 2810
Onchip ADC   = 2810
Calc TempC   = 2810
Calc pH Ext  = 2810
Calc pH Int  = 2810
Optode       = 2810
CTD          = 2810
format data  = 2810
 SampNum             MM/DD/YYYY HH:MM:SS            Vrse        Vrse_std              Vk          Vk_std              Ik              Ib        VbatMain
#0000003             05/15/2021 09:36:42        -0.799235       0.000009        -0.500556       0.000003        18197.32        -399.593           12.00        (2810 msec)

uSD writes   = 2980
wait TX      = 2980





#endif

