/*
 * David Muller; Germán Alfaro
 * davehmuller@gmail.com; alfaro.germanevera@gmail.com
 *
 * 2/2014 Robert Glatts
 * rglatts@ucsd.edu
 *
 * 4/2018 Thom Maughan, tm@mbari.org
 */


/*
 * System.c contains a variety of functions related to sensors and basic system utilities.
 */

#include "System.h"

#include "IO.h"
#include "ADS1248_iso.h"
#include "ADS1248_noniso.h"
#include "MicroCAT.h"
#include "Optode.h"
#include "Sleep.h"
#include "SDCard.h"

#include "uartstdio.h"	// User local version with larger RX buffer


extern void adc_onchip_init(void);
extern uint32_t * read_all_adc(void);
extern void fram_store(void);
extern void ADS1248_gpio3(uint32_t state);

void fram_retrieve(void);

void get_header(void);

void print_header(void);

void profile_on(int target);
void profile_off(int target);
void profile2_on(int target);
void profile2_off(int target);
void profile2_toggle(int target);

// Global variables
extern char Optode_buff[];

uint32_t sys_data_chksum32;

#define SIZEOF_SAMPBUF  160
char sampBuf[SIZEOF_SAMPBUF+4];

unsigned long timer_10ms;

unsigned int ledGreenState = 0;
unsigned int ledRedState = 0;

extern uint32_t adc_data[];
extern int dbg_flag;
extern int profileTarget;
extern int profile2Target;
extern int ads1248noniso_flg;



#define TIME_TXSAMPLE_MSEC      30      // was 50

/*****************************************************************************
*
* System tick interrupt handler. Provides 10 ms tick for various timing requirements.
* FatFs requires a timer tick every 10 ms for internal timing purposes.
*
*****************************************************************************/
void SysTickHandler(void)
{
	disk_timerproc();	// FatFs
	timer_10ms++;			// For Timer_10ms()
}

/****************************************************************************
 * Timer_10ms()
 *
 * Returns value of 10 ms system tick variable. Can be used for general
 * purpose timing where a simple delay is not workable.
 * Call with "reset" true to reset timer to zero.
 * RCG 4/14
 ***************************************************************************/
unsigned long Timer_10ms(bool reset)
{
	if(reset) timer_10ms = 0L;
	return timer_10ms;
}


uint32_t compute_sys_data_chksum(void)
{
    int indx;
    uint8_t *bytePtr;
    uint32_t chkSum32 = 0;

    bytePtr = (uint8_t *)&sys_data;

    for(indx=0; indx<sizeof(sys_data); indx++)
    {
        chkSum32 += *bytePtr;     // add byte at a time, sum into 32 bit checksum (later use a more bulletproof alg)
        bytePtr++;
    }
    return(chkSum32);
}


void initSysDataVolatileVariables(void)
{
    uprintf("\nWarning: Initialized volatile sys data variables\n");

    sys_data.state = IDLE;
    sys_data.nextWakeUp = ROM_HibernateRTCGet()+sys_data.sampling_period;
    sys_data.next_gdata_fptr = 0L;      // deprecated (not used, need to confirm)
    sys_data.current_sample = 0;
    sys_data.AD24_std = 0.0;

    sys_data_vol.state = sys_data.state;                // NOTE TO THOM - might not want to restore state - this one should not change
    sys_data_vol.nextWakeUp = sys_data.nextWakeUp;
    sys_data_vol.next_gdata_fptr = sys_data.next_gdata_fptr;
    sys_data_vol.current_sample = sys_data.current_sample;
    sys_data_vol.AD24_std = sys_data.AD24_std;


    sys_data_chg.state = sys_data.state;                // NOTE TO THOM - this changes in deploy(), a complicated routine that needs rework
    sys_data_chg.nextWakeUp = sys_data.nextWakeUp;
    sys_data_chg.next_gdata_fptr = sys_data.next_gdata_fptr;
    sys_data_chg.current_sample = sys_data.current_sample;
    sys_data_chg.AD24_std = sys_data.AD24_std;


#if HIB_REG_STORE==1
    // for MFET, write to internal memory
    sys_data_chg.state = sys_data.state;                // NOTE TO THOM - this changes in deploy(), a complicated routine that needs rework
    sys_data_chg.nextWakeUp = sys_data.nextWakeUp;
    sys_data_chg.next_gdata_fptr = sys_data.next_gdata_fptr;
    sys_data_chg.current_sample = sys_data.current_sample;
    sys_data_chg.AD24_std = sys_data.AD24_std;
    sys_data_chg.chksum = 0x55AA55AA;

    write_nonvol_ram();         // _chg stored to hib reg file

    // restore values that were read at init.c time
    sys_data.state = sys_data_vol.state;                // NOTE TO THOM - might not want to restore state - this one should not change
    sys_data.nextWakeUp = sys_data_vol.nextWakeUp;
    sys_data.next_gdata_fptr = sys_data_vol.next_gdata_fptr;
    sys_data.current_sample = sys_data_vol.current_sample;
    sys_data.AD24_std = sys_data_vol.AD24_std;

    // read sys_data
    // if checksum changes from Init() to sleep(), then store new config
    // this is implemented to alleviate 500K write cycle limit.  Limit hit in 57 days if sampling once every 10 seconds
    if(compute_sys_data_chksum() != sys_data_chksum32)
    {
        //profile_on(1);  // THOM debug
        return(EEPROMProgram((uint32_t*) &sys_data, 0x400, (sizeof(sys_data) + 3) & ~3));
        //profile_off(1);
    }
    else
    {
        return 0;
    }
#endif

#if FRAM_REG_STORE==1
    sys_data_chg.state = sys_data.state;                // NOTE TO THOM - this changes in deploy(), a complicated routine that needs rework
    sys_data_chg.nextWakeUp = sys_data.nextWakeUp;
    sys_data_chg.next_gdata_fptr = sys_data.next_gdata_fptr;
    sys_data_chg.current_sample = sys_data.current_sample;
    sys_data_chg.AD24_std = sys_data.AD24_std;
    sys_data_chg.chksum = 0x55AA55AA;   //sys_data_chg.state + sys_data_chg.nextWakeUp + sys_data_chg.current_sample;

    fram_store();           // store _chg in FRAM

    // restore values that were read at init.c time
    sys_data.state = sys_data_vol.state;                // NOTE TO THOM - might not want to restore state - this one should not change
    sys_data.nextWakeUp = sys_data_vol.nextWakeUp;
    sys_data.next_gdata_fptr = sys_data_vol.next_gdata_fptr;
    sys_data.current_sample = sys_data_vol.current_sample;
    sys_data.AD24_std = sys_data_vol.AD24_std;
#endif

#if EEPROM_REG_STORE==1
    return(EEPROMProgram((uint32_t*) &sys_data, 0x400, (sizeof(sys_data) + 3) & ~3));
#endif
}




/*
 * Retrieves the saved sys_data variables from their storage
 * location in EEPROM (when the device hibernates, sys_data variables
 * are stored in EEPROM if there is a change - 500K write cycle limit).
 * If no value has been assigned to a sys_data variable, a default
 * value is assigned.
 */
void retrieveSysDataVariables()
{
	uint32_t ulStatus;

	//enable the EEPROM
	ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_EEPROM0);

	ulStatus = EEPROMInit();
	if( ulStatus != EEPROM_INIT_OK)
	{
		uprintf("EEPROM Initialization error.\n");
	}

	//read the sys_data struct out of EEPROM.  Last argument ensures # of bytes is multiple of 4
	EEPROMRead((uint32_t*) &sys_data, 0x400, (sizeof(sys_data) + 3) & ~3);


#if HIB_REG_STORE==1
	sys_data_chksum32 = compute_sys_data_chksum();      // global variable

	// store a copy of the volatile data that is in the eeprom struct, on MFET these volatiles will be stored in battery backed internal memory
	sys_data_vol.state = sys_data.state;
	sys_data_vol.nextWakeUp = sys_data.nextWakeUp;
	sys_data_vol.next_gdata_fptr = sys_data.next_gdata_fptr;
	sys_data_vol.current_sample = sys_data.current_sample;
	sys_data_vol.AD24_std = sys_data.AD24_std;

	read_nonvol_ram();      // retrieve and store in _chg, in this case read from hib->_chg
    if(sys_data_chg.chksum != 0x55AA55AA)
    {
        uprintf("HIB sys_data_chg.chksum is not 0x55AA55AA\n");
        initSysDataVolatileVariables();
    }

    sys_data.state = sys_data_chg.state;
    sys_data.nextWakeUp = sys_data_chg.nextWakeUp;
    sys_data.next_gdata_fptr = sys_data_chg.next_gdata_fptr;
    sys_data.current_sample = sys_data_chg.current_sample;
    sys_data.AD24_std = sys_data_chg.AD24_std;
#endif

#if FRAM_REG_STORE==1

    sys_data_chksum32 = compute_sys_data_chksum();      // global variable

    // store a copy of the volatile data that is in the eeprom struct,
    // on MFET these volatiles will be stored in battery backed internal memory, MFET v2 in FRAM

    sys_data_vol.state = sys_data.state;
    sys_data_vol.nextWakeUp = sys_data.nextWakeUp;
    sys_data_vol.next_gdata_fptr = sys_data.next_gdata_fptr;
    sys_data_vol.current_sample = sys_data.current_sample;
    sys_data_vol.AD24_std = sys_data.AD24_std;

    fram_retrieve();      // retrieve and store in _chg
    if(sys_data_chg.chksum != 0x55AA55AA)
    {
        uprintf("FRAM sys_data_chg.chksum is not 0x55AA55AA\n");
        initSysDataVolatileVariables();
    }

    sys_data.state = sys_data_chg.state;
    sys_data.nextWakeUp = sys_data_chg.nextWakeUp;
    sys_data.next_gdata_fptr = sys_data_chg.next_gdata_fptr;
    sys_data.current_sample = sys_data_chg.current_sample;
    sys_data.AD24_std = sys_data_chg.AD24_std;

#endif


}



void write_nonvol_ram(void)         // system.c
{
    //int indx;

    // Need to enable the Hibernation peripheral after wake/reset, before using it.
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_HIBERNATE);

        // EnableExpClk should always be called, even if the module was already enabled,
        // because this function also initializes some timing parameters.
    ROM_HibernateEnableExpClk(ROM_SysCtlClockGet());

    // store volatile config data
    HibernateDataSet((uint32_t *)&sys_data_chg, SYSDATACHG_NUMWORDS);
    //uprintf("\nwrite_nonvol_ram() st=%u, nwup=%u, ngfptr=%u, cursam=%u, std=%u\n");
}

void read_nonvol_ram(void)         // system.c
{
    // Need to enable the Hibernation peripheral after wake/reset, before using it.
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_HIBERNATE);

        // EnableExpClk should always be called, even if the module was already enabled,
        // because this function also initializes some timing parameters.
    ROM_HibernateEnableExpClk(ROM_SysCtlClockGet());

    HibernateDataGet((uint32_t *)&sys_data_chg, SYSDATACHG_NUMWORDS);     // last parm is number of 4byte words

    //uprintf("\nread_nonvol_ram() st=%u, nwup=%u, ngfptr=%u, cursam=%u, std=%u\n");
}

uint32_t storeSysDataVariables(void)
{
#if HIB_REG_STORE==1
    // for MFET, write to internal memory
    sys_data_chg.state = sys_data.state;                // NOTE TO THOM - this changes in deploy(), a complicated routine that needs rework
    sys_data_chg.nextWakeUp = sys_data.nextWakeUp;
    sys_data_chg.next_gdata_fptr = sys_data.next_gdata_fptr;
    sys_data_chg.current_sample = sys_data.current_sample;
    sys_data_chg.AD24_std = sys_data.AD24_std;

    write_nonvol_ram();         // _chg stored to hib reg file

    // restore values that were read at init.c time
    sys_data.state = sys_data_vol.state;                // NOTE TO THOM - might not want to restore state - this one should not change
    sys_data.nextWakeUp = sys_data_vol.nextWakeUp;
    sys_data.next_gdata_fptr = sys_data_vol.next_gdata_fptr;
    sys_data.current_sample = sys_data_vol.current_sample;
    sys_data.AD24_std = sys_data_vol.AD24_std;

    // read sys_data
    // if checksum changes from Init() to sleep(), then store new config in EEPROM
    // this is implemented to alleviate 500K write cycle limit.  Limit hit in 57 days if sampling once every 10 seconds
    if(compute_sys_data_chksum() != sys_data_chksum32)
    {
        //profile_on(1);  // THOM debug
        return(EEPROMProgram((uint32_t*) &sys_data, 0x400, (sizeof(sys_data) + 3) & ~3));
        //profile_off(1);
    }
    else
    {
        return 0;
    }
#endif

#if FRAM_REG_STORE==1
    sys_data_chg.state = sys_data.state;                // NOTE TO THOM - this changes in deploy(), a complicated routine that needs rework
    sys_data_chg.nextWakeUp = sys_data.nextWakeUp;
    sys_data_chg.next_gdata_fptr = sys_data.next_gdata_fptr;
    sys_data_chg.current_sample = sys_data.current_sample;
    sys_data_chg.AD24_std = sys_data.AD24_std;
    fram_store();           // store in FRAM

    // restore values that were read at init.c time
    sys_data.state = sys_data_vol.state;                // NOTE TO THOM - might not want to restore state - this one should not change
    sys_data.nextWakeUp = sys_data_vol.nextWakeUp;
    sys_data.next_gdata_fptr = sys_data_vol.next_gdata_fptr;
    sys_data.current_sample = sys_data_vol.current_sample;
    sys_data.AD24_std = sys_data_vol.AD24_std;
    //return(0);
#endif

    // store the sys_data structure (_vol is used to prevent changes in eeprom - this needs to be improved when we drop support for older hardware)
    return(EEPROMProgram((uint32_t*) &sys_data, 0x400, (sizeof(sys_data) + 3) & ~3));

}


// console fxns are a routine (MFET_BOARD)  THOM
void console_off(void)
{
#if BOARD_SEAPHOX == 1
    ROM_GPIOPinWrite(GPIO_PORTL_BASE, GPIO_PIN_0, 0x00);        // LTC2801 PS
#endif

#if BOARD_MFET == 1
    ROM_GPIOPinWrite(GPIO_PORTL_BASE, GPIO_PIN_0, 0x00);        // LTC2801 PS
    ROM_GPIOPinWrite(GPIO_PORTL_BASE, GPIO_PIN_1, 0x00);        // LTC2801 MODE
#endif

#if BOARD_MFET == 2
    // MFET revB has MAX3222EETP+
    ROM_GPIOPinWrite(GPIO_PORTL_BASE, GPIO_PIN_0, 0xff);    // Set pin to turn console driver off // PL0, pin 108
    ROM_GPIOPinWrite(GPIO_PORTL_BASE, GPIO_PIN_1, 0x00);    // Clear to ensable shutdown  // PL0, pin 107
#endif

}

void console_on(void)
{

#if BOARD_SEAPHOX == 1
    ROM_GPIOPinWrite(GPIO_PORTL_BASE, GPIO_PIN_0, 0xff);        // LTC2801 PS
#endif

#if BOARD_MFET == 1
    ROM_GPIOPinWrite(GPIO_PORTL_BASE, GPIO_PIN_0, 0xff);        // LTC2801 PS
    ROM_GPIOPinWrite(GPIO_PORTL_BASE, GPIO_PIN_1, 0xff);        // LTC2801 MODE
#endif


#if BOARD_MFET == 2
    // MFET revB has MAX3222EETP+
    ROM_GPIOPinWrite(GPIO_PORTL_BASE, GPIO_PIN_0, 0x00);    // Clear pin to turn console driver on // PL0, pin 108
    ROM_GPIOPinWrite(GPIO_PORTL_BASE, GPIO_PIN_1, 0xff);    // Set to disable shutdown (part is enabled) // PL0, pin 107
#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()
{
	float batt_volt;

#if BOARD_SEAPHOX==1
	float ADC_volts;
	ADC_volts = pollADS1248_noniso(0, 7, 1);
	batt_volt = ADC_volts * 11;  	// 11-to-1 divider
#endif
#if BOARD_MFET >= 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)
 */
float batt_volt_iso()
{
	float ADC_volts, batt_volt;
#if BOARD_SEAPHOX==1
	ADC_volts = pollADS1248_iso(5, 6, 1, 1, 20);		// Chan 5-6, 1 trial, gain = 1, sps = 5 Hz  (was 5, now 20) THOM 7 May 2019
	batt_volt = ADC_volts * 11;  	// 11-to-1 divider
#endif

#if BOARD_MFET==1
	batt_volt = 0.0;
#endif

#if BOARD_MFET==2
	// 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;

}

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\n", biasneg, biasplus);
        ROM_SysCtlDelay(MILLISECOND * 500);
    }

    closeADS1248_iso();
}

/*
 * temp_int()
 * Returns internal temperature
 * RCG 4/14
 */
float controller_temp()
{
	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
// This function applies only to the MFET
float read_env_sensors(void)
{
    float fVbat, fOnChipTemp, fExtTemp;
    uint32_t  uiHumidity, uiWater;
    uint32_t indx = 0;

    ROM_GPIOPinWrite(GPIO_PORTM_BASE, GPIO_PIN_7, 0xFF);    // Turn on Load switch for ENV monitoring
    ROM_GPIOPinWrite(GPIO_PORTM_BASE, GPIO_PIN_6, 0xFF);   // Turn on VBat monitoring

    ROM_GPIOPinWrite(GPIO_PORTK_BASE, GPIO_PIN_2, 0xFF);        // Iso-power On
    dbg_printf("iso power on\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;

    // 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++);


    ROM_GPIOPinWrite(GPIO_PORTM_BASE, GPIO_PIN_6, 0x00);   // Turn off VBat monitoring
    ROM_GPIOPinWrite(GPIO_PORTK_BASE, GPIO_PIN_2, 0x00);        // Iso-power Off
    dbg_printf("iso power off, vbat monitoring off\n");

    return(fVbat);
 }
#endif

// Calculates temperature from Durafet's thermistor. V_therm is the voltage from thermistor, measured using isolated 24-bit ADC.
// TCOffset is an user input, to correct thermistor to be more accurate.
float DuraFET_temp(float V_therm, float TCOffset)
{
	// Declare variables
	float Rtherm;
	float TC;

	// Thermistor coefficients
	float c0 = 340.9819863;
	float c1 = -9.10257E-05;
	float c2 = -95.08806667;
	float c3 = 0.965370274;


	// Calculate TC
	Rtherm = 20000 / ((3.3 / V_therm) - 1);
	TC = c0 + c1*Rtherm + c2*(log10(Rtherm)) + c3*(pow(log10(Rtherm), 3));

	// Apply offset to TC; TCOffset is an user input,
	// or derived during pH calibration process.
	TC = TC + TCOffset;
	return TC;
}

/*
* Calculate pH using external reference.
* Eext refers to the voltage from the external reference, measured using isolated 24-bit ADC.
* TC should be calculated using fucntion getDurafettemp.
* Salt refers to salinity, extracted from SBE 37.
* RCG 5/14
*/
float calc_pHext(float Eext, float TC, float salt)
{
	float TK;				// Temperature in Kelvin
	float S_T;				// Nernst Slope
	float Eoext;			// Calibration coefficient corrected to in situ temperature
	float Z; 				// Ionic Strength; Dickson 2007
	float SO4_tot; 			// Total sulfate concentration; Dickson 2007
	float mCl; 				// Molality of Chloride; Dickson 2007;
	float K_HSO4; 			// Bisulfate acidity constant; Dickson 1990.
	float DHconst;			// Debye-Huckel; Khoo et al. 1997
	float log10gamma_HCl;	// log10 of mean activity coefficient of HCl in seawater
	float pHext_free;		// pH on free scale calculated from external reference
	float pHext_tot;		// pH on total scale calculated from external reference

	// Start calculations
	TK = TC + 273.15;
	S_T = (R_ * TK) / F_ * LN10;
	Eoext = sys_data.Eo_ext_25C + dEoEXT_dt * (TC - 25);
	Z = 19.924 * salt / (1000 - 1.005 * salt); // Ionic strength
	SO4_tot = (0.14 / 96.062) * (salt / 1.80655); // molality sulfate from conservative relationship.
	mCl = 0.99889 / 35.453 * salt / 1.80655; // moallity chloride from conservative relationship.
	K_HSO4 =  exp(-4276.1/(TK)+141.328-23.093*log(TK)+(-13856/(TK)+324.57-47.986*log(TK))*sqrt(Z)+(35474/(TK)-771.54+114.723*log(TK))*Z-2698/(TK)*pow(sqrt(Z), 3)+1776/(TK)*pow(Z, 2)+log(1-0.001005*salt));
	DHconst = 0.00000343 * (pow(TC, 2)) + 0.00067524 * TC + 0.49172143; //Debye-Huckel
	log10gamma_HCl = 2*(-DHconst * sqrt(Z) / (1 + 1.394 * sqrt(Z)) + (0.08885 - 0.000111 * TC) * Z);

	pHext_free =  -( (Eoext - Eext) - S_T * (log10(mCl) + log10gamma_HCl) ) / S_T;
	pHext_tot = pHext_free - log10(1 + SO4_tot / K_HSO4); // pH from external reference electrode on total scale.
	return pHext_tot;

}

/*
* calc_pHint()
* Function to calculate pH using internal reference.
* Eint refers to the voltage from the internal reference, measured using the isolated 24-bit ADC.
* TC should be calculated using function getDurafettemp.
* RCG 5/14
*/
float calc_pHint(float Eint, float TC)
{
	float TK; 		// Temperature in Kelvin
	float S_T; 		// Nernest Slope
	float Eoint;  	// Calibration coefficient corrected to in situ temperature.
	float pHint;

	TK = TC + 273.15;
	S_T = (R_ * TK) / F_ * LN10;

	Eoint = sys_data.Eo_int_25C + dEoINT_dt * (TC - 25);
	pHint = (Eint - Eoint) / S_T;

	return pHint;
}

/*
 * ph_calib()
 * Calculates DuraFET pH sensorcalibration values
 * using either user entered values, or automatic
 * calibration using temperature and salinity derived
 * from a MicroCAT CTD.
 * RCG 5/14
 */
void ph_calib(void)
{
	int response, i, j, samp, lines;
	char buff[20];
	static float Vint=0, Vext=0, pHcalpt=0, tempC, salt;
	float ftemp, tempK, E0int, S_T, Z, SO4_tot, mCl, K_HSO4, pHint_free, dummy, Vtherm, TCOffset;
	float DHconst, log10gamma_HCl, mHfree, aHfree_aCl, E0ext, sqrt_Z, E0int25, E0ext25;	// beta_SO4,
	float StdDev[SD_VALUES][SD_DIFF_SQ+1], diff, sum;
	float Vint_SD, Vext_SD, Vtherm_SD, tempC_SD, salt_SD;


	// pH Calibration point
	while(1)
	{
		sprintf(buff, "\n\nEnter pH calibration point [%f]: ", pHcalpt);
		uprintf("%s", buff);
		if(getUserInput(buff, 20))
		{
			if(sscanf(buff, "%f", &ftemp) == 1)
			{
				if(ftemp >= 0 && ftemp <= 14)
				{
					pHcalpt = ftemp;
					break;
				}
				else uprintf("\nEnter between 0 and 14");
				continue;
			}
			else break;
		}
		else break;
	}

	// Automatic or manual calibration?
	response = yesOrNoMenuChoice("\n\nPerform automatic DuraFET calibration (Y/N) [N]? ", NO);

	// Manual calibration
	if(response == NO)
	{
		// Vint
		while(1)
		{
			sprintf(buff, "\n\nEnter Vint [%f]: ", Vint);
			uprintf("%s", buff);
			if(getUserInput(buff, 20))
			{
				if(sscanf(buff, "%f", &ftemp) == 1)
				{
					if(ftemp >= (-2) && ftemp <= 2)
					{
						Vint = ftemp;
						break;
					}
					else uprintf("Enter number between -2 and 2\n\n");
					continue;
				}
				else break;
			}
			else break;
		}

		// Vext
		while(1)
		{
			sprintf(buff, "\n\nEnter Vext [%f]: ", Vext);
			uprintf("%s", buff);
			if(getUserInput(buff, 20))
			{
				if(sscanf(buff, "%f", &ftemp) == 1)
				{
					if(ftemp >= (-2) && ftemp <= 2)
					{
						Vext = ftemp;
						break;
					}
					else uprintf("Enter number between -2 and 2\n\n");
					continue;
				}
				else break;
			}
			else break;
		}

		// Temperature
		while(1)
		{
			sprintf(buff, "\nEnter bath temperature [%f]: ", tempC);
			uprintf("%s", buff);
			if(getUserInput(buff, 20))
			{
				if(sscanf(buff, "%f", &ftemp) == 1)
				{
					if(ftemp >= 0 && ftemp <= 100)
					{
						tempC = ftemp;
						break;
					}
					else uprintf("\nEnter between 0 and 100");
					continue;
				}
				else break;
			}
			else break;
		}

		// Salinity
		while(1)
		{
			sprintf(buff, "\nEnter bath salinity [%f]: ", salt);
			uprintf("%s", buff);
			if(getUserInput(buff, 20))
			{
				if(sscanf(buff, "%f", &ftemp) == 1)
				{
					if(ftemp >= 0 && ftemp <= 100)
					{
						salt = ftemp;
						break;
					}
					else uprintf("\nEnter between 0 and 100");
					continue;
				}
				else break;
			}
			else break;
		}
	}

	// Automatic calibration
	else
	{
		// Clear standard deviation array
		for(j=0; j<SD_AVG; j++)
		{
			for(i=0; i<5; i++) StdDev[i][j] = 0;
		}

		j = 0;				// Reset standard deviation array counter
		lines = 20; 		// Force program to write column labels before first data line

		openMicroCAT();
		openADS1248_iso();
		ROM_SysCtlDelay(ONESEC);	// Let instruments and sensors settle
		uprintf("\n\nPlace DuraFET and MicroCAT in calibration bath.");
		uprintf("\nHit any key when values have stabilized...");
		UARTFlushRx();

		while(1)
		{
			Vint = pollADS1248_iso(1, 6, sys_data.sample_average, sys_data.Vint_gain, sys_data.Vint_sps);
			Vext = pollADS1248_iso(4, 6, sys_data.sample_average, 1, 5);
			Vtherm = pollADS1248_iso(0, 6, sys_data.sample_average, 1, 5);	// Chan 0-6, trials = user, gain = 1, sps = 5 Hz
//			TC = DuraFET_temp(Vtherm, sys_data.TCOffset);

			pollMicroCAT();
			ROM_SysCtlDelay(5*ONESEC);	// Wait for instruments to respond
			parseMicroCATData();	// Extract the data from response strings

			// Update salinity from MicroCAT data
			if( sscanf( MicroCAT_buff, "%f %f %f %s %s", &tempC, &dummy, &salt, buff, buff) != 5)
			{
				tempC = salt = 0;
			}

			// Store current sample values
			if(samp < SD_AVG) samp++;
			else samp = 0;
			StdDev[0][samp] = Vint;
			StdDev[1][samp] = Vext;
			StdDev[2][samp] = Vtherm;
			StdDev[3][samp] = tempC;
			StdDev[4][samp] = salt;


			// Find the mean of the last SD_AVG samples for each sensor
			for(i=0; i<SD_VALUES; i++)
			{
				sum = 0;

				for(j=0; j<SD_AVG; j++)
				{
					sum += StdDev[i][j];
				}

				StdDev[i][SD_MEAN] = sum / SD_AVG;	// Current mean for each sensor
			}

			// Find the difference squared for each of the last SD_AVG samples
			// Then find the sum of the squared differences
			for(i=0; i<SD_VALUES; i++)
			{
				sum = 0;

				for(j=0; j<SD_AVG; j++)
				{
					 diff = (StdDev[i][j] - StdDev[i][SD_MEAN]) ;	// Difference for each sample
					 sum += diff * diff;							// Sum of differences squared
				}

				StdDev[i][SD_DIFF_SQ] = sum;
			}

			// Take square root for each sensor
			Vint_SD = sqrt(StdDev[0][SD_DIFF_SQ]);
			Vext_SD = sqrt(StdDev[1][SD_DIFF_SQ]);
			Vtherm_SD = sqrt(StdDev[2][SD_DIFF_SQ]);
			tempC_SD = sqrt(StdDev[3][SD_DIFF_SQ]);
			salt_SD = sqrt(StdDev[4][SD_DIFF_SQ]);

			// Write column headers every 20 lines
			if(lines >= 20)
			{
				uprintf("\n\nVint\t\tVint-SD\t"
						"Vext\t\tVext-SD\t"
						"Vtherm\tVtherm-SD\t"
						"Temp\t\tTemp-SD\t"
						"Salinity\tSal-SD");

				lines = 1;		// Reset line counter
			}
			else lines++;

			// Write data line
			uprintf("\n%8.5f\t%8.5f\t"
					"%8.5f\t%8.5f\t"
					"%8.5f\t%8.5f\t"
					"%8.5f\t%8.5f\t"
					"%8.5f\t%8.5f",
					Vint, Vint_SD,
					Vext, Vext_SD,
					Vtherm, Vtherm_SD,
					tempC, tempC_SD,
					salt, salt_SD);

			// Key hit, so display current averaged values
			if(kbhit())
			{
				uprintf("\n\nAverage of last %d values", SD_AVG);

				Vint = StdDev[0][SD_MEAN];
				uprintf("\nVint = %f V  SD = %f", Vint, Vint_SD);

				Vext = StdDev[1][SD_MEAN];
				uprintf("\nVext = %f V  SD = %f", Vext, Vext_SD);

				Vtherm = StdDev[2][SD_MEAN];
				uprintf("\nVtherm = %f C  SD = %f", Vtherm, Vtherm_SD);

				tempC = StdDev[3][SD_MEAN];
				uprintf("\nMicroCAT Temperature = %f C  SD = %f", tempC, tempC_SD);

				salt = StdDev[4][SD_MEAN];
				uprintf("\nMicroCAT Salinity = %f  SD = %f", salt, salt_SD);

				response = yesOrNoMenuChoice("\n\nValues acceptable (Y/N) [N]? ", NO);
				if(response == NO) continue;
				else break;
			}
		}

		closeADS1248_iso();
		closeMicroCAT();
	}

	// Calculate E0int25 and E0ext25 using either manual or automatic values
	tempK = tempC + 273.15;  					// Convert temp from C to K
	S_T = (R_ * tempK) / F_ * log(10); 			// Nernst temp dependence
	E0int = Vint - S_T * pHcalpt; 				// Calc E0int from Nernst & pH @ calibration point
	E0int25 = E0int + dEoINT_dt * (25 - tempC);

	Z = 19.924 * salt / (1000 - 1.005 * salt); 			// Ionic strength, Dickson et al. 2007
	sqrt_Z = sqrt(Z);

	SO4_tot = (0.14 / 96.062) * (salt / 1.80655);  	// Total conservative sulfate
	mCl = 0.99889/35.453*salt/1.80655; 				// Conservative chloride

	// Bisulfate equilibrium const., Dickson et al. 2007
	K_HSO4 = exp( -4276.1 / tempK + 141.328 - 23.093 * log(tempK) \
	          + ( -13856 / tempK + 324.57 - 47.986 * log(tempK) ) * sqrt_Z \
	          + ( 35474 / tempK - 771.54 + 114.723 * log(tempK) ) * Z - 2698 / tempK * pow(Z, 1.5) \
	          + 1776 / tempK * Z * Z + log(1 - 0.001005 * salt) );

	pHint_free = pHcalpt + log10( 1 + SO4_tot / K_HSO4);
	DHconst = 0.00000343 * tempC * tempC + 0.00067524 * tempC + 0.49172143; //Debye-Huckel, Khoo et al. 1977
	log10gamma_HCl = 2 * (-DHconst * sqrt_Z / ( 1 + 1.394 * sqrt_Z ) + (0.08885 - 0.000111 * tempC) * Z);
	mHfree = pow(10, (-pHint_free) );
	aHfree_aCl = mHfree * mCl * pow( 10, (log10gamma_HCl) );
	E0ext = Vext + S_T * log10(aHfree_aCl);
	E0ext25 = E0ext + dEoEXT_dt * (25-tempC);

	TCOffset =  tempC - DuraFET_temp(Vtherm, 0);

	uprintf("\n\nEo Int @ 25C = %f", E0int25);
	uprintf("\nEo Ext @ 25C = %f", E0ext25);
	uprintf("\nTCOffset = %f", sys_data.TCOffset);

	response = yesOrNoMenuChoice("\n\nAccept and store calibration values(Y/N) [N]? ", NO);
	if(response == YES)
	{
		sys_data.Eo_int_25C = E0int25;
		sys_data.Eo_ext_25C = E0ext25;
		sys_data.TCOffset = TCOffset;

		uprintf("\nCalibration values stored");
	}

}

/*
 * Store the deployment parameters to the beginning of a new deployment.
 * Returns non-zero if there is a file error. Usually because user forgot to
 * install a SD card.
 * Modified RCG 5/14
 */
int writeDeploymentInformationHeader(const time_t currentTime, const time_t firstSample, int txFlg)
{
	struct tm *time_struct;
	char buff[TIMESTAMPLENGTH];
	FIL fileObject;		// File object
	FRESULT fresult;
	UINT bw;

	// Open a file
	fresult = f_open(&fileObject, sys_data.fileName, FA_READ |FA_WRITE |FA_OPEN_ALWAYS);
	if(fresult != FR_OK)
	{
		uprintf("f_open error: %s\n", StringFromFresult(fresult));
		return 1;
	}

	// Seek to the end, to append our file
	fresult = f_lseek(&fileObject, fileObject.fsize);
	if(fresult != FR_OK)
	{
		uprintf("f_lseek error: %s\n", StringFromFresult(fresult));
		return 1;
	}

	// Store current time
	time_struct = localtime(&currentTime);
	strftime(buff, sizeof(buff),"\"Current time\"\t\t\t%Y/%m/%d %H:%M:%S", time_struct);
	fresult = f_write(&fileObject, buff, strlen(buff), &bw);
	if(txFlg)  uprintf("%s", buff);       // THOM new 2 Jul 2019
	if(fresult != FR_OK)
	{
		uprintf("Current time f_write error: %s\n", StringFromFresult(fresult));
		return 1;
	}

#ifdef NOCODE       // THOM - this calc is broken by edits made pre-2017
	// Store first sample time
	time_struct = localtime(&firstSample);
	strftime(buff, sizeof(buff),"\n\"First sample\"\t\t\t%Y/%m/%d %H:%M:%S", time_struct);
	fresult = f_write(&fileObject, buff, strlen(buff), &bw);
	if(txFlg)  uprintf("%s", buff);       // THOM new 2 Jul 2019
	if(fresult != FR_OK)
	{
		uprintf("First sample time f_write error: %s\n", StringFromFresult(fresult));
		return 1;
	}
#endif
	// Store timezone
	if(sys_data.GMT)
	{
	    sd_fprintf(&fileObject, "\n\"Time zone\"\t\t\tGMT");
	    if(txFlg)  uprintf("\n\"Time zone\"\t\t\tGMT");         // THOM new 2 Jul 2019
	}
	else
	{
	    sd_fprintf(&fileObject, "\n\"Time zone\"\t\t\tLocal");
	    if(txFlg)  uprintf("\n\"Time zone\"\t\t\tLocal");
	}

	// THOM new 23Apr2019
#if BOARD_MFET >= 1
    sd_fprintf(&fileObject, "\n\"MFET version\"\t\t\t%s", VERSION);     if(txFlg)  uprintf("\n\"MFET version\"\t\t\t%s", VERSION);         // THOM new 2 Jul 2019
#endif
#if BOARD_SEAPHOX==1
    sd_fprintf(&fileObject, "\n\"SEAPHOX version\"\t%s", VERSION);
    if(txFlg)  uprintf("\n\"SEAPHOX version\"\t%s", VERSION);         // THOM new 2 Jul 2019
#endif


	// Store the tab delimited deployment header. (Excel treats quoted string as text)
	sd_fprintf(&fileObject, "\n\"File name\"\t%s", sys_data.fileName);                  if(txFlg) uprintf("\n\"File name\"\t\t\t%s", sys_data.fileName);
	sd_fprintf(&fileObject, "\n\"User initials\"\t%s", sys_data.user);                  if(txFlg) uprintf("\n\"User initials\"\t\t\t%s", sys_data.user);
	sd_fprintf(&fileObject, "\n\"Sampling period (s)\"\t%u", sys_data.sampling_period); if(txFlg) uprintf("\n\"Sampling period (s)\"\t\t%u", sys_data.sampling_period);
	sd_fprintf(&fileObject, "\n\"pH Sample average\"\t%u", sys_data.sample_average);    if(txFlg) uprintf("\n\"pH Sample average\"\t\t%u", sys_data.sample_average);
	sd_fprintf(&fileObject, "\n\"Pump on time (s)\"\t%u", sys_data.pumpon_time);        if(txFlg) uprintf("\n\"Pump on time (s)\"\t\t%u", sys_data.pumpon_time);
	sd_fprintf(&fileObject, "\n\"Low battery voltage (V)\"\t%f", sys_data.low_batt_volt);   if(txFlg) uprintf("\n\"Low battery voltage (V)\"\t%f", sys_data.low_batt_volt);
	sd_fprintf(&fileObject, "\n\"TCOffset\"\t%f", sys_data.TCOffset);                       if(txFlg) uprintf("\n\"TCOffset\"\t\t\t%f", sys_data.TCOffset);
	sd_fprintf(&fileObject, "\n\"Eo_int_25C\"\t%f", sys_data.Eo_int_25C);               if(txFlg) uprintf("\n\"Eo_int_25C\"\t\t\t%f", sys_data.Eo_int_25C);
	sd_fprintf(&fileObject, "\n\"Eo_ext_25C\"\t%f", sys_data.Eo_ext_25C);               if(txFlg) uprintf("\n\"Eo_ext_25C\"\t\t\t%f", sys_data.Eo_ext_25C);
	sd_fprintf(&fileObject, "\n\"Default salinity (ppt)\"\t%f", sys_data.default_sal);  if(txFlg) uprintf("\n\"Default salinity (ppt)\"\t%f", sys_data.default_sal);
	sd_fprintf(&fileObject, "\n\"Sensor name\"\t%s", sys_data.sensor_name);             if(txFlg) uprintf("\n\"Sensor name\"\t\t\t%s", sys_data.sensor_name);
	sd_fprintf(&fileObject, "\n\"DuraFET SN\"\t%s", sys_data.durafet_SN);               if(txFlg) uprintf("\n\"DuraFET SN\"\t\t\t%s", sys_data.durafet_SN);
	sd_fprintf(&fileObject, "\n\"CAP adapter SN\"\t%s", sys_data.capadap_SN);           if(txFlg) uprintf("\n\"CAP adapter SN\"\t\t%s", sys_data.capadap_SN);
	sd_fprintf(&fileObject, "\n\"ISE SN\"\t%s", sys_data.ISE_SN);                       if(txFlg) uprintf("\n\"ISE SN\"\t\t\t%s", sys_data.ISE_SN);
	sd_fprintf(&fileObject, "\n\"MicroCAT SN\"\t%s", sys_data.microcat_SN);             if(txFlg) uprintf("\n\"MicroCAT SN\"\t\t\t%s", sys_data.microcat_SN);
	sd_fprintf(&fileObject, "\n\"Pump SN\"\t%s", sys_data.pump_SN);                     if(txFlg) uprintf("\n\"Pump SN\"\t\t\t%s", sys_data.pump_SN);
	sd_fprintf(&fileObject, "\n\"Pressure sensor max (psi)\"\t%d", sys_data.press_full_scale);   if(txFlg) uprintf("\n\"Pressure sensor max (psi)\"\t%d", sys_data.press_full_scale);
	sd_fprintf(&fileObject, "\n\"Vint gain\"\t%d", sys_data.Vint_gain);                 if(txFlg) uprintf("\n\"Vint gain\"\t\t\t%d", sys_data.Vint_gain);
	sd_fprintf(&fileObject, "\n\"Vint sample rate (sps)\"\t%d", sys_data.Vint_sps);     if(txFlg) uprintf("\n\"Vint sample rate (sps)\"\t%d", sys_data.Vint_sps);

	if(sys_data.test_mode)
	{
	    sd_fprintf(&fileObject, "\n\"Test mode (pump off)\"");
	    if(txFlg) uprintf("\n\"Test mode (pump off)\"");
	}
	else
	{
	    sd_fprintf(&fileObject, "\n\"Deploy mode (pump on)\"");
	    if(txFlg) uprintf("\n\"Deploy mode (pump on)\"");
	}

	// THOM DEBUG
	sd_fprintf(&fileObject, "\n\"Fast mode\"\t\t\t%u", sys_data.fast_mode);     if(txFlg) uprintf("\n\"Fast mode\"\t\t\t%u", sys_data.fast_mode);


	// Store the tab delimited column headers
    if(sys_data.data_cfg[CFG_SAMPLE_NUM] > 0)       { sd_fprintf(&fileObject, "\n\n\"Sample #\"\t");    }  //0
    if(sys_data.data_cfg[CFG_TIMEDATE] > 0)         { sd_fprintf(&fileObject, "\"Sample Time\"\t");     }  //1
    if(sys_data.data_cfg[CFG_ENV_BAT_VOLT] > 0)     { sd_fprintf(&fileObject, "\"Main Batt\"\t");       }  //2
    if(sys_data.data_cfg[CFG_ENV_BRD_TEMP] > 0)     { sd_fprintf(&fileObject, "\"Env Temp\"\t");        }  //3
    if(sys_data.data_cfg[CFG_ENV_HUMIDITY] > 0)     { sd_fprintf(&fileObject, "\"Env Humidity\"\t");    }  //4
    if(sys_data.data_cfg[CFG_INT_PRESSURE] > 0)     { sd_fprintf(&fileObject, "\"Env Pressure\"\t");    }  //5
    if(sys_data.data_cfg[CFG_V_THERMISTOR] > 0)     { sd_fprintf(&fileObject, "\"Vtherm\"\t");          }  //6
    if(sys_data.data_cfg[CFG_V_THERMISTOR_STD] > 0) { sd_fprintf(&fileObject, "\"Vtherm std\"\t");      }  //7
    if(sys_data.data_cfg[CFG_V_INT_OFFSET] > 0)     { sd_fprintf(&fileObject, "\"Vint Offset\"\t");     }  //8
    if(sys_data.data_cfg[CFG_V_INT_OFFSET_STD] > 0) { sd_fprintf(&fileObject, "\"Vint Offset Std\"\t"); }  //9
    if(sys_data.data_cfg[CFG_V_EXT_OFFSET] > 0)     { sd_fprintf(&fileObject, "\"Vext Offset\"\t");     }  //10
    if(sys_data.data_cfg[CFG_V_EXT_OFFSET_STD] > 0) { sd_fprintf(&fileObject, "\"Vext Offset Std\"\t"); }  //11

    if(sys_data.data_cfg[CFG_V_INT] > 0)            { sd_fprintf(&fileObject, "\"Vint\"\t");            }  //12
    if(sys_data.data_cfg[CFG_V_INT_STD] > 0)        { sd_fprintf(&fileObject, "\"Vint Std\"\t");        }  //13
    if(sys_data.data_cfg[CFG_V_EXT] > 0)            { sd_fprintf(&fileObject, "\"Vext\"\t");            }  //14
    if(sys_data.data_cfg[CFG_V_EXT_STD] > 0)        { sd_fprintf(&fileObject, "\"Vext Std\"\t");        }  //15
    if(sys_data.data_cfg[CFG_V_COUNTER_ELECT] > 0)  { sd_fprintf(&fileObject, "\"Vcntr E\"\t");         }  //16
    if(sys_data.data_cfg[CFG_V_COUNTER_ELECT_STD] > 0)  { sd_fprintf(&fileObject, "\"Vcntr E Std\"\t"); }  //17
    if(sys_data.data_cfg[CFG_I_COUNTER] > 0)        { sd_fprintf(&fileObject, "\"Icntr Elec\"\t");      }  //18
    if(sys_data.data_cfg[CFG_I_SUBSTRATE] > 0)      { sd_fprintf(&fileObject, "\"Substrate Leak\"\t");  }  //19
    if(sys_data.data_cfg[CFG_CALC_TEMP] > 0)        { sd_fprintf(&fileObject, "\"pH Temp\"\t");         }  //20
    if(sys_data.data_cfg[CFG_EST_PH_INT] > 0)       { sd_fprintf(&fileObject, "\"pH Int\"\t");          }  //21
    sd_fprintf(&fileObject, "\n");

	sys_data.next_gdata_fptr = fileObject.fptr;		// Store the file pointer for the first sample (for gdata)

	// Close the file
	fresult = f_close( &fileObject);
	if(fresult != FR_OK)
	{
		uprintf("f_close error: %s\n", StringFromFresult(fresult));
		return 1;
	}

	return 0;
}

// write deployment header to SD card, if txFlg is set then print to terminal output
void write_deployment_header(int txFlg)
{

}


void print_header(void)
{
//#SampNum        MM/DD/YYYY HH:MM:SS     Bat V   Vtherm  VthrStd VextRef VextRStd        VcntElec        VceStd  Ik      Ib
//#SampNum        MM/DD/YYYY HH:MM:SS     Bat V    Vtherm         VthermStd       VextRef VextRStd        VcntElec        VceStd  Ik      Ib
//#0000030        05/29/2019 16:41:59     12.03   -0.047092       0.000766        -0.040439       0.000090        -2.048000       0.000000        0.001311        0.000385

    if(sys_data.data_cfg[CFG_SAMPLE_NUM] > 0)       { uprintf("#SampNum\t");                  } //0
    if(sys_data.data_cfg[CFG_TIMEDATE] > 0)         { uprintf("MM/DD/YYYY HH:MM:SS\t");         } //1
    if(sys_data.data_cfg[CFG_ENV_BAT_VOLT] > 0)     { uprintf("Bat V\t");                } //2
    if(sys_data.data_cfg[CFG_ENV_BRD_TEMP] > 0)     { uprintf("BrdTmp\t");                  } //3
    if(sys_data.data_cfg[CFG_ENV_HUMIDITY] > 0)     { uprintf("Humid\t");                    } //4
    if(sys_data.data_cfg[CFG_INT_PRESSURE] > 0)     { uprintf("Press\t");                    } //5
    if(sys_data.data_cfg[CFG_V_THERMISTOR] > 0)     { uprintf(" Vtherm  \t");                 } //6
    if(sys_data.data_cfg[CFG_V_THERMISTOR_STD] > 0) { uprintf("VthermStd\t");              } //7
    if(sys_data.data_cfg[CFG_V_INT_OFFSET] > 0)     { uprintf("VintOff\t");                 } //8
    if(sys_data.data_cfg[CFG_V_INT_OFFSET_STD] > 0) { uprintf("VintOStd\t");             } //9
    if(sys_data.data_cfg[CFG_V_EXT_OFFSET] > 0)     { uprintf("VextOff\t");                 } //10
    if(sys_data.data_cfg[CFG_V_EXT_OFFSET_STD] > 0) { uprintf("VextOStd\t");             } //11

    if(sys_data.data_cfg[CFG_V_INT] > 0)            { uprintf("Vint\t");                        } //12
    if(sys_data.data_cfg[CFG_V_INT_STD] > 0)        { uprintf("VintStd\t");                    } //13
    if(sys_data.data_cfg[CFG_V_EXT] > 0)            { uprintf(" VextRef \t");                    } //14
    if(sys_data.data_cfg[CFG_V_EXT_STD] > 0)        { uprintf("VextRStd\t");                } //15
    if(sys_data.data_cfg[CFG_V_COUNTER_ELECT] > 0)  { uprintf("VcntElec\t");          } //16
    if(sys_data.data_cfg[CFG_V_COUNTER_ELECT_STD] > 0) { uprintf("VcntEStd\t");   } //17
    if(sys_data.data_cfg[CFG_I_COUNTER] > 0)        { uprintf("  Ik   \t");   } //18
    if(sys_data.data_cfg[CFG_I_SUBSTRATE] > 0)      { uprintf("  Ib  \t");           } //19
    if(sys_data.data_cfg[CFG_CALC_TEMP] > 0)        { uprintf("CalcT\t");            } //20
    if(sys_data.data_cfg[CFG_EST_PH_INT] > 0)       { uprintf("Est pH");              } //21
    uprintf("\r\n");
}

void get_header(void)
{

    if(sys_data.data_cfg[CFG_SAMPLE_NUM] > 0)       { uprintf("Sample Num\t");                  } //0
    if(sys_data.data_cfg[CFG_TIMEDATE] > 0)         { uprintf("MM/DD/YYYY HH:MM:SS\t");         } //1
    if(sys_data.data_cfg[CFG_ENV_BAT_VOLT] > 0)     { uprintf("Battery Volt\t");                } //2
    if(sys_data.data_cfg[CFG_ENV_BRD_TEMP] > 0)     { uprintf("Board Temp\t");                  } //3
    if(sys_data.data_cfg[CFG_ENV_HUMIDITY] > 0)     { uprintf("Humidity\t");                    } //4
    if(sys_data.data_cfg[CFG_INT_PRESSURE] > 0)     { uprintf("Pressure\t");                    } //5
    if(sys_data.data_cfg[CFG_V_THERMISTOR] > 0)     { uprintf("Vthermistor\t");                 } //6
    if(sys_data.data_cfg[CFG_V_THERMISTOR_STD] > 0) { uprintf("Vtermistor Std\t");              } //7
    if(sys_data.data_cfg[CFG_V_INT_OFFSET] > 0)     { uprintf("Vint Offset\t");                 } //8
    if(sys_data.data_cfg[CFG_V_INT_OFFSET_STD] > 0) { uprintf("Vint Offset Std\t");             } //9
    if(sys_data.data_cfg[CFG_V_EXT_OFFSET] > 0)     { uprintf("Vext Offset\t");                 } //10
    if(sys_data.data_cfg[CFG_V_EXT_OFFSET_STD] > 0) { uprintf("Vext Offset Std\t");             } //11

    if(sys_data.data_cfg[CFG_V_INT] > 0)            { uprintf("Vint\t");                        } //12
    if(sys_data.data_cfg[CFG_V_INT_STD] > 0)        { uprintf("Vint Std\t");                    } //13
    if(sys_data.data_cfg[CFG_V_EXT] > 0)            { uprintf("Vext Ref\t");                    } //14
    if(sys_data.data_cfg[CFG_V_EXT_STD] > 0)        { uprintf("Vext Ref Std\t");                } //15
    if(sys_data.data_cfg[CFG_V_COUNTER_ELECT] > 0)  { uprintf("Vcounter Electrode\t");          } //16
    if(sys_data.data_cfg[CFG_V_COUNTER_ELECT_STD] > 0) { uprintf("Vcounter Electrode Std\t");   } //17
    if(sys_data.data_cfg[CFG_I_COUNTER] > 0)        { uprintf("Counter Electrode Current\t");   } //18
    if(sys_data.data_cfg[CFG_I_SUBSTRATE] > 0)      { uprintf("Substrate Current\t");           } //19
    if(sys_data.data_cfg[CFG_CALC_TEMP] > 0)        { uprintf("Calc Temperature\t");            } //20
    if(sys_data.data_cfg[CFG_EST_PH_INT] > 0)       { uprintf("Estimated pH");              } //21
    uprintf("\r\n");
    ROM_SysCtlDelay(MILLISECOND*50);        // time to send string

}

/*
 *  send last sample, then take new sample and store to SD card
 * Take measurements and write them to SD card.
 */
void sendlast_takesample(void)
{
    FIL fileObject;
    FRESULT fresult;
#define MAX_DATASAMPSIZE    240     // this is oversized by over 20 bytes
    unsigned char buf[MAX_DATASAMPSIZE];
    unsigned int readSize;

    // open snapshot.txt, send all until /n
    fresult = f_open(&fileObject, "snapshot.txt", FA_READ);  // Creates a new file. If the file is existing, it will be truncated and overwritten.
    if(fresult != FR_OK)
    {
        // file does not exist, first time reading so previous data not available
        get_sample(0);      // arg=0 says 'dont tx the result', this will create the snapshot.txt file (after a delay)
        fresult = f_open(&fileObject, "snapshot.txt", FA_READ);  // Creates a new file. If the file is existing, it will be truncated and overwritten.
        if(fresult != FR_OK)
        {
            uprintf("f_open error snapshot.txt: %s\n", StringFromFresult(fresult));
            error_store("f_open error on snapshot.txt");
            return;
        }

    }

    fresult = f_read(&fileObject, &buf[0], MAX_DATASAMPSIZE-1, &readSize);
    if(fresult != FR_OK)
    {
        uprintf("f_read error snapshot.txt\n");
    }
    else
    {

        if(readSize > 4)
        {
            if(readSize >= MAX_DATASAMPSIZE)        // in the odd chance of an error
                readSize = MAX_DATASAMPSIZE-1;
            buf[readSize] = 0x00;       // null terminate

            uprintf("%s", buf);       //uprintf("%s\n", buf); print the sample

        }
        else
        {
            uprintf("bad read size (less than 5)\n");
        }
    }

    // Close the file
    fresult = f_close( &fileObject );
    if(fresult != FR_OK)
    {
        //uprintf("8\n");
        uprintf("f_close error snapshot.txt: %s\n", StringFromFresult(fresult));
        error_store("f_close error");
    }

    get_sample(0);          // get sample for reading with next 'sl'
}



/****************************************************************
 * Get the current time according to the RTC.
 * returns in time-strcut
 ****************************************************************/
struct tm *get_RTC_time(void)
{
    //char timeStamp[TIMESTAMPLENGTH];
    uint32_t ticks;
    struct tm *time_struct;

    //get the time from the from the RTC so we can print it
    ticks = ROM_HibernateRTCGet();

    time_struct = localtime((const time_t*)&ticks);

    // DEBUG to print the time
    //strftime(timeStamp, sizeof(timeStamp),"%m/%d/%y %H:%M:%S", time_struct);
    //uprintf("%s", timeStamp);

    return(time_struct);
}



#if BOARD_MFET >= 1
/*
 * sample()
 * Take measurements and write them to SD card.
 * RCG 5/14
 */
void get_sample(int txFlg)
{
	char timestamp[TIMESTAMPLENGTH];
	struct tm *time_struct;
    float main_batt_volt, con_temp;
	float Vtherm;			// DuraFET raw temperature voltage
	float Vtherm_std; 		// Std Dev for Durafet Thermistor
	float Vint;				// DuraFET internal reference voltage   (Vint)
	float Vint_std; 		// Std Dev for Durafet Internal Voltage
	float TC;				// Calculated DuraFET temperature
	float Vext_ref;			// External (AUX) reference voltage  (Vrs)
	float Vext_std; 		// Std Dev for Durafet External Voltage
	float pHint;			// Calculated pH using internal reference
	float pHext;            // Calculated pH using external reference
	float SBE_sal;          // MicroCat or estimated salinity

	float ExtRef_WithOffset;
	float ExtRef_WithOffset_std;
	float IntRef_WithOffset;
	float IntRef_WithOffset_std;
	float CounterElectrodeCurrent;          // (Ik)
	float CounterElectrodeVoltage;          // (Vk)
	float CounterElectrodeVoltage_std;
	float SubstrateCurrent;                 // (Ib)
	float CounterElectrodeCurrent_std;
	float SubstrateVoltage;
	float SubstrateVoltage_std;

	float fHumidity, fPressure;
    float fVbat, fExtTemp;
	uint32_t  uiPressure, uiHumidity, uiWater;

	FIL fileObject;
	FRESULT fresult;


	if(sys_data.test_mode == 1)
	    uprintf("\nSampling...");

	// Pump on time
//	if(sys_data.test_mode == 1)
//	    uprintf("\nPump on (test mode)\n");		// Don't want the pump to run in test deployment
//	else
//	    pump_on();     // PORTD-3 is hanging in the breeze on MFET   ROM_GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_3, 0xff);

	//timeout = ROM_HibernateRTCGet() + sys_data.pumpon_time;       // THOM 7 May 2019  no pump on MFET

	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
	ADS1248_gpio_init();            // defd in ADS1248_iso.c

	// turn on sensor and battery monitoring circuit - needs at least 150msec to settle
	ROM_GPIOPinWrite(GPIO_PORTM_BASE, GPIO_PIN_7, 0xFF);    // Turn on Load switch for ENV monitoring
    ROM_GPIOPinWrite(GPIO_PORTM_BASE, GPIO_PIN_6, 0xFF);   // Turn on VBat monitoring

	ROM_SysCtlDelay(800*MILLISECOND);	// Let instruments and sensors settle

    ROM_GPIOPinWrite(GPIO_PORTM_BASE, GPIO_PIN_7, 0xFF);    // Turn on Load switch for ENV monitoring
    ROM_GPIOPinWrite(GPIO_PORTM_BASE, GPIO_PIN_6, 0xFF);   // Turn on VBat monitoring

    adc_onchip_init();
    ROM_SysCtlDelay(120*MILLISECOND);            // needs at least 100msec for battery voltage to settle within 1%

    read_all_adc();


    fVbat = (float)(adc_data[0]*100);
    fVbat /= 18687.707;
    main_batt_volt = fVbat;         // 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_ENV_BRD_TEMP] > 0)
    {
        fExtTemp = ((((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)
        con_temp = fExtTemp;
    }

    // Humidity
    if(sys_data.data_cfg[CFG_ENV_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;
    }


    ROM_GPIOPinWrite(GPIO_PORTM_BASE, GPIO_PIN_6, 0x00);   // Turn off VBat monitoring
    ROM_GPIOPinWrite(GPIO_PORTM_BASE, GPIO_PIN_7, 0x00);    // Turn off Load switch for ENV monitoring

	// ---------- Read the isolated domain 24 bit ADC -----------------

    // Thermistor Voltage is Vtherm
    if(sys_data.data_cfg[CFG_V_THERMISTOR] > 0)
    {
        Vtherm = pollADS1248_iso(0, 6, sys_data.sample_average, 1, sys_data.Vint_sps);       // Chan +0 -6, trials = user, gain = 1, sps = 20 Hz
	    Vtherm_std = sys_data.AD24_std;
    }

	// Vint
    if(sys_data.data_cfg[CFG_V_INT] > 0)
    {
        ADS1248_gpio_ADG1609_mux(3);
        ROM_SysCtlDelay(MILLISECOND * 10);      // 10msec settling for MUX analog
        Vint = pollADS1248_iso(1, 6, sys_data.sample_average, 1, sys_data.Vint_sps);       // Chan +1 -6, trials = user, gain = user, sps = 20 Hz
	    Vint_std = sys_data.AD24_std;
    }

	//Vext_ref (GLIDER)
    if(sys_data.data_cfg[CFG_V_EXT] > 0)
    {
        ADS1248_gpio_ADG1609_mux(0);
        ROM_SysCtlDelay(MILLISECOND * 10);      // 10msec settling for MUX analog
        //Vext_ref = pollADS1248_iso(1, 6, 1, 1, sys_data.Vint_sps);       // Chan +1 -6, trials = user, gain = user, sps = 20 Hz //YT changed average to 1
        Vext_ref = pollADS1248_iso(1, 6, sys_data.sample_average, 1, sys_data.Vint_sps);       // Chan +1 -6, trials = user, gain = user, sps = 20 Hz //YT changed average to 1
        //Vext_ref = pollADS1248_iso(1, 6, 10, 1, 20);  // 500msec
        Vext_std = sys_data.AD24_std;
    }

    //Ext Ref Offset,
    if(sys_data.data_cfg[CFG_V_EXT_OFFSET] > 0)
    {
        ADS1248_gpio_ADG1609_mux(0);
        ROM_SysCtlDelay(MILLISECOND * 10);      // 10msec settling for MUX analog
        //ExtRef_WithOffset = pollADS1248_iso(1, 5, 1, 1, sys_data.Vint_sps);       // Chan +1 -5, trials = 1, gain = user, sps = 5 Hz
        ExtRef_WithOffset = pollADS1248_iso(1, 5, sys_data.sample_average, sys_data.Vint_gain, sys_data.Vint_sps);       // Chan +1 -5, trials = 1, gain = user, sps = 5 Hz
        ExtRef_WithOffset_std = sys_data.AD24_std;
    }


    //Int Ref Off,
    if(sys_data.data_cfg[CFG_V_INT_OFFSET] > 0)
    {
        ADS1248_gpio_ADG1609_mux(3);
        ROM_SysCtlDelay(MILLISECOND * 10);      // 10msec settling for MUX analog
        //IntRef_WithOffset = pollADS1248_iso(1, 5, sys_data.sample_average, 1, sys_data.Vint_sps);       // Chan +1 -5, trials = 1, gain = user, sps = 5 Hz
        IntRef_WithOffset = pollADS1248_iso(1, 5, sys_data.sample_average, sys_data.Vint_gain, sys_data.Vint_sps);
        IntRef_WithOffset_std = sys_data.AD24_std;
    }

    //CntrE Cur, (GLIDER)
    if(sys_data.data_cfg[CFG_I_COUNTER] > 0)
    {
        ADS1248_gpio_ADG1609_mux(1);
        ROM_SysCtlDelay(MILLISECOND * 10);      // 10msec settling for MUX analog
        CounterElectrodeCurrent = pollADS1248_iso(1, 5, 3, 1, sys_data.Vint_sps);       // Chan +5 -1, trials = 1, gain = user, sps = 5 Hz
        //CounterElectrodeCurrent = pollADS1248_iso(1, 5, 1, 1, 20);  // (could be 40hz)  GLIDER
        CounterElectrodeCurrent_std = sys_data.AD24_std;
    }

    // CntrE Volt, (GLIDER)
    if(sys_data.data_cfg[CFG_V_COUNTER_ELECT] > 0)
    {
        ADS1248_gpio_ADG1609_mux(1);
        ROM_SysCtlDelay(MILLISECOND * 10);      // 10msec settling for MUX analog
        CounterElectrodeVoltage = pollADS1248_iso(1, 6, sys_data.sample_average, 1, sys_data.Vint_sps);       // Chan +5 -1, trials = 1, gain = user, sps = 5 Hz
        //CounterElectrodeVoltage = pollADS1248_iso(1, 6, 5, 1, 20);  // GLIDER
        CounterElectrodeVoltage_std = sys_data.AD24_std;
    }

    // Subst Cur, (GLIDER Ib)
    if(sys_data.data_cfg[CFG_I_SUBSTRATE] > 0)
    {
        ADS1248_gpio_ADG1609_mux(2);
        ROM_SysCtlDelay(MILLISECOND * 10);      // 10msec settling for MUX analog
        SubstrateCurrent = pollADS1248_iso(1, 6, 3, 1, sys_data.Vint_sps);       // Chan +1 -6, trials = 1, gain = user, sps = 5 Hz
        //SubstrateCurrent = pollADS1248_iso(1, 6, 1, 1, 20);       // GLIDER 1 sample, 20 hz
    }

#ifdef NOTNEEDED_COMMENTOUTPERYUI_7May2019
    // Subst Vol,
    ADS1248_gpio_ADG1609_mux(2);
    ROM_SysCtlDelay(MILLISECOND * 10);      // 10msec settling for MUX analog
    SubstrateVoltage = pollADS1248_iso(5, 6, 1, 1, sys_data.Vint_sps);       // Chan +5 -6, trials = 1, gain = user, sps = 5 Hz
    SubstrateVoltage_std = sys_data.AD24_std;
#endif

	// Shutdown sensor power supply
	closeADS1248_iso();   // MFET turns off 5mA (no ph attached to MCAP)

	// Calculate the external and internal pH values

	if(sys_data.data_cfg[CFG_CALC_TEMP] > 0)
	{
	    TC = DuraFET_temp(Vtherm, 0);   //sys_data.TCOffset);
	}

	if(sys_data.data_cfg[CFG_EST_PH_EXT] > 0)
	{
	    pHext = calc_pHext(Vext_ref, TC, SBE_sal);
	}

	if(sys_data.data_cfg[CFG_EST_PH_INT] > 0)
	{
	    //pHint = calc_pHint(Vint, TC);
	    pHint = calc_pHint(IntRef_WithOffset, TC);   // NEW THOM per YUI  7 Jun 2018
	}

	// Open a file
	fresult = f_open(&fileObject, sys_data.fileName, FA_READ |FA_WRITE |FA_OPEN_ALWAYS);
	if(fresult != FR_OK)
	{
		uprintf("f_open error: %s\n", StringFromFresult(fresult));
		error_store("f_open error");
	}

	// Seek to the end, to append our file
	fresult = f_lseek(&fileObject, fileObject.fsize);
	if(fresult != FR_OK)
	{
		uprintf("f_lseek error: %s\n", StringFromFresult(fresult));
		error_store("f_lseek error");
	}

	// Data Format request from Yui 6 Jun 2018
	//Sample_Number\tMM/DD/YYYY HH:MM:SS\tBattery_Voltage\tBoard_Temperature\tHumidity_sensor\tInternal_Pressure\tVthermistor\tVthermistor_std\tVint_offset\tVint_offset_std\tVext_offset\tVext_offset_std\tVint\tVint_std\tVext\tVext_std\tVcounter_electrode\tVcounter_electrode_std\tCounter_current\tSubstrate_current\tcalculated_temperature_Vthermistor\testimated_pH_int\r\n

    //+ Sample_Number\t
	//+ MM/DD/YYYY HH:MM:SS\t
	//+ Battery_Voltage\t
	//+ Board_Temperature\t
	//+ Humidity_sensor\t
	//+ Internal_Pressure\t
	//+ Vthermistor\t
	//+ Vthermistor_std\t
	//- Vint_offset\t
	//- Vint_offset_std\t
	//- Vext_offset\t
	//- Vext_offset_std\t
	//+ Vint\t
	//+ Vint_std\t
	//- Vext\t
	//- Vext_std\t

	// Vcounter_electrode\t
	// Vcounter_electrode_std\t
	// Counter_current\t
	// Substrate_current\t
	// calculated_temperature_Vthermistor\t
	// estimated_pH_int\r\n


    // Store sample to SD card file (field is turned off when 0, on when 1 or 255)
    if(sys_data.data_cfg[CFG_SAMPLE_NUM] > 0)       { sd_fprintf(&fileObject, "#%07d\t", sys_data.current_sample);  } //0
    if(sys_data.data_cfg[CFG_TIMEDATE] > 0)         { sd_fprintf(&fileObject, "%s\t", timestamp);                   } //1
    if(sys_data.data_cfg[CFG_ENV_BAT_VOLT] > 0)     { sd_fprintf(&fileObject, "%5.2f\t", main_batt_volt);           } //2
    if(sys_data.data_cfg[CFG_ENV_BRD_TEMP] > 0)     { sd_fprintf(&fileObject, "%5.2f\t", con_temp);                 } //3
    if(sys_data.data_cfg[CFG_ENV_HUMIDITY] > 0)     { sd_fprintf(&fileObject, "%3u\t", uiHumidity);                 } //4
    if(sys_data.data_cfg[CFG_INT_PRESSURE] > 0)     { sd_fprintf(&fileObject, "%5.2f\t", fPressure);                } //5
    if(sys_data.data_cfg[CFG_V_THERMISTOR] > 0)     { sd_fprintf(&fileObject, "%8.6f\t", Vtherm);                   } //6
    if(sys_data.data_cfg[CFG_V_THERMISTOR_STD] > 0) { sd_fprintf(&fileObject, "%8.6f\t", Vtherm_std);               } //7
    if(sys_data.data_cfg[CFG_V_INT_OFFSET] > 0)     { sd_fprintf(&fileObject, "%8.6f\t", IntRef_WithOffset);        } //8
    if(sys_data.data_cfg[CFG_V_INT_OFFSET_STD] > 0) { sd_fprintf(&fileObject, "%8.6f\t", IntRef_WithOffset_std);    } //9
    if(sys_data.data_cfg[CFG_V_EXT_OFFSET] > 0)     { sd_fprintf(&fileObject, "%8.6f\t", ExtRef_WithOffset);        } //10
    if(sys_data.data_cfg[CFG_V_EXT_OFFSET_STD] > 0) { sd_fprintf(&fileObject, "%8.6f\t", ExtRef_WithOffset_std);    } //11

    if(sys_data.data_cfg[CFG_V_INT] > 0)            { sd_fprintf(&fileObject, "%8.6f\t", Vint);                     } //12
    if(sys_data.data_cfg[CFG_V_INT_STD] > 0)        { sd_fprintf(&fileObject, "%8.6f\t", Vint_std);                 } //13
    if(sys_data.data_cfg[CFG_V_EXT] > 0)            { sd_fprintf(&fileObject, "%8.6f\t", Vext_ref);                 } //14
    if(sys_data.data_cfg[CFG_V_EXT_STD] > 0)        { sd_fprintf(&fileObject, "%8.6f\t", Vext_std);                 } //15
    if(sys_data.data_cfg[CFG_V_COUNTER_ELECT] > 0)  { sd_fprintf(&fileObject, "%8.6f\t", CounterElectrodeVoltage);  } //16
    if(sys_data.data_cfg[CFG_V_COUNTER_ELECT_STD] > 0)  { sd_fprintf(&fileObject, "%8.6f\t", CounterElectrodeVoltage_std);  }  //17
    if(sys_data.data_cfg[CFG_I_COUNTER] > 0)        { sd_fprintf(&fileObject, "%8.6f\t", CounterElectrodeCurrent);  } //18
    if(sys_data.data_cfg[CFG_I_SUBSTRATE] > 0)      { sd_fprintf(&fileObject, "%8.6f\t", SubstrateCurrent);         } //19
    if(sys_data.data_cfg[CFG_CALC_TEMP] > 0)        { sd_fprintf(&fileObject, "%6.3f\t", TC);                       } //20
    if(sys_data.data_cfg[CFG_EST_PH_INT] > 0)       { sd_fprintf(&fileObject, "%7.6f\t", pHint);                    } //21
    sd_fprintf(&fileObject, "get_sample");    // THOM DEBUG
    sd_fprintf(&fileObject, "\n");

	// Close the file
	fresult = f_close( &fileObject );
	if(fresult != FR_OK)
	{
		uprintf("f_close error: %s\n", StringFromFresult(fresult));
		error_store("f_close error");
	}

    if((txFlg == 1) || (sys_data.test_mode == 1))
    {
        //#0000405       06/07/2018 14:16:12
        // bat 8.67   temp 24.20   humidity 25.61    pressure 6.80  vtherm 1.023693        vtherm_std 4.884770
        // -0.090986       0.434246        -0.019936       0.095250
        //-1.120937       5.349794        -1.050123       5.012120        -1.049656       6.796905        0.000644        0.022814        23.863  -12.254394

        if(sys_data.data_cfg[CFG_SAMPLE_NUM] > 0)       { uprintf("#%07d\t", sys_data.current_sample);   } //0
        if(sys_data.data_cfg[CFG_TIMEDATE] > 0)         { uprintf("%s\t", timestamp);                    } //1
        if(sys_data.data_cfg[CFG_ENV_BAT_VOLT] > 0)     { uprintf("%5.2f\t", main_batt_volt);            } //2
        if(sys_data.data_cfg[CFG_ENV_BRD_TEMP] > 0)     { uprintf("%5.2f\t", con_temp);                  } //3
        if(sys_data.data_cfg[CFG_ENV_HUMIDITY] > 0)     { uprintf("%3u\t", uiHumidity);                  } //4
        if(sys_data.data_cfg[CFG_INT_PRESSURE] > 0)     { uprintf("%5.2f\t", fPressure);                 } //5
        if(sys_data.data_cfg[CFG_V_THERMISTOR] > 0)     { uprintf("%8.6f\t", Vtherm);                    } //6
        if(sys_data.data_cfg[CFG_V_THERMISTOR_STD] > 0) { uprintf("%8.6f\t", Vtherm_std);                } //7
        if(sys_data.data_cfg[CFG_V_INT_OFFSET] > 0)     { uprintf("%8.6f\t", IntRef_WithOffset);         } //8
        if(sys_data.data_cfg[CFG_V_INT_OFFSET_STD] > 0) { uprintf("%8.6f\t", IntRef_WithOffset_std);     } //9
        if(sys_data.data_cfg[CFG_V_EXT_OFFSET] > 0)     { uprintf("%8.6f\t", ExtRef_WithOffset);        } //10
        if(sys_data.data_cfg[CFG_V_EXT_OFFSET_STD] > 0) { uprintf("%8.6f\t", ExtRef_WithOffset_std);    } //11

        if(sys_data.data_cfg[CFG_V_INT] > 0)            { uprintf("%8.6f\t", Vint);                      } //12
        if(sys_data.data_cfg[CFG_V_INT_STD] > 0)        { uprintf("%8.6f\t", Vint_std);                  } //13
        if(sys_data.data_cfg[CFG_V_EXT] > 0)            { uprintf("%8.6f\t", Vext_ref);                  } //14
        if(sys_data.data_cfg[CFG_V_EXT_STD] > 0)        { uprintf("%8.6f\t", Vext_std);                  } //15
        if(sys_data.data_cfg[CFG_V_COUNTER_ELECT] > 0)  { uprintf("%8.6f\t", CounterElectrodeVoltage);   } //16
        if(sys_data.data_cfg[CFG_V_COUNTER_ELECT_STD] > 0)  { uprintf("%8.6f\t", CounterElectrodeVoltage_std); } //17
        if(sys_data.data_cfg[CFG_I_COUNTER] > 0)        { uprintf("%8.6f\t", CounterElectrodeCurrent);   } //18
        if(sys_data.data_cfg[CFG_I_SUBSTRATE] > 0)      { uprintf("%8.6f\t", SubstrateCurrent);          } //19
        if(sys_data.data_cfg[CFG_CALC_TEMP] > 0)        { uprintf("%6.3f\t", TC);                        } //20
        if(sys_data.data_cfg[CFG_EST_PH_INT] > 0)       { uprintf("%7.6f\t", pHint);                   } //21
        uprintf("get_sample");      // THOM DEBUG
        uprintf("\r\n");

        ROM_SysCtlDelay(MILLISECOND*TIME_TXSAMPLE_MSEC);        // time for transmit
    }

	sys_data.current_sample++;  // Increment the sample counter

	// Check for low battery voltage. Exit and sleep if too low.
	if( main_batt_volt < sys_data.low_batt_volt )
	{
	    uprintf("\nLow battery voltage (%.2f < %.2f) ! Exiting deploy mode...\n", main_batt_volt, sys_data.low_batt_volt );
		error_store("Low battery! Exited deploy mode");
		sleep(IDLE, 0);		// Sleep until woken by user
	}
}

#endif

#if BOARD_MFET >= 1
/*
 * fast sample()
 * Take measurements and write them to SD card.
 *
 */
void fast_sample(int txFlg)
{
    char timestamp[TIMESTAMPLENGTH];
    uint32_t timeout;
    struct tm *time_struct;
    float main_batt_volt, con_temp;
    float Vtherm;           // DuraFET raw temperature voltage
    float Vtherm_std;       // Std Dev for Durafet Thermistor
    float Vint;             // DuraFET internal reference voltage   (Vint)
    float Vint_std;         // Std Dev for Durafet Internal Voltage
    float TC;               // Calculated DuraFET temperature
    float Vext_ref;         // External (AUX) reference voltage  (Vrs)
    float Vext_std;         // Std Dev for Durafet External Voltage
    float pHint;            // Calculated pH using internal reference
    float pHext;            // Calculated pH using external reference
    float SBE_sal;          // MicroCAT salinity

    float ExtRef_WithOffset;
    float ExtRef_WithOffset_std;
    float IntRef_WithOffset;
    float IntRef_WithOffset_std;
    float CounterElectrodeCurrent;          // (Ik)
    float CounterElectrodeVoltage;          // (Vk)
    float CounterElectrodeVoltage_std;
    float SubstrateCurrent;                 // (Ib)
    float CounterElectrodeCurrent_std;
    float SubstrateVoltage;
    float SubstrateVoltage_std;

    float fHumidity, fPressure;
    float fVbat, fExtTemp;
    uint32_t  uiPressure, uiHumidity, uiWater;
    uint32_t indx;

    FIL fileObject;
    FRESULT fresult;

    //uprintf("\nfast mode = %u\n", (unsigned int)sys_data.fast_mode); // THOM DEBUG

    fPressure = 0.0;        // pressure transducer removed per Yui

    if(sys_data.test_mode == 1)
        uprintf("\nSampling...");

    // Open and poll the microCat and Optode
    if(sys_data.data_cfg[CFG_OPTODE] > 0)
    {
        //set up the optode
        openOptode();       // power on the optode

        ROM_SysCtlDelay(MILLISECOND*300);       //100 does not work, 500 works

        Optode_UARTwrite("do sample\n",11);        // this function auto appends \r (not a good idea)
        //ROM_SysCtlDelay(MILLISECOND*1000);

        //parseOptodeData();

       // int bytesRead;
       // bytesRead = Optode_UARTRxBytesAvail();          // This is a hack to workaround a ring buffer bug - might be an init problem?  not sure.  First call with data in buffer results in bytesRead=0,  reads do not clear the buffer
        //Optode_UARTgets(Optode_buff, bytesRead);

        //parseOptodeData();
        // DEBUG code
        //uprintf("optode bytesRead = %d\n", bytesRead);
        //uprintf("%s", Optode_buff);

        //uprintf("boo: %s\n\n", Optode_buff);

        //pollOptode();       // send do_sample
    }


    SBE_sal = 35;       // for pH_ext calc

    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
    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
    ROM_GPIOPinWrite(GPIO_PORTM_BASE, GPIO_PIN_7, 0xFF);    // Turn on Load switch for ENV monitoring
    ROM_GPIOPinWrite(GPIO_PORTM_BASE, GPIO_PIN_6, 0xFF);   // Turn on VBat monitoring

    //ROM_SysCtlDelay(800*MILLISECOND);   // Let instruments and sensors settle
    ROM_SysCtlDelay(1*MILLISECOND);         // fast sampling

    adc_onchip_init();
    // read_adc_all was moved below as there is 100msec required for battery voltage to settle to within 1%


    // ---------- Read the isolated domain 24 bit ADC -----------------

    profile2_toggle(1);

    // Thermistor Voltage is Vtherm
    if(sys_data.data_cfg[CFG_V_THERMISTOR] > 0)
    {
        Vtherm = pollADS1248_iso(0, 6, sys_data.sample_average, 1, sys_data.Vint_sps);       // Chan +0 -6, trials = user, gain = 1, sps = 20 Hz
        Vtherm_std = sys_data.AD24_std;
    }
    profile2_toggle(1);
    // Vint
    if(sys_data.data_cfg[CFG_V_INT] > 0)
    {
        dbg_printf("\nno vint on glider\n");
        ADS1248_gpio_ADG1609_mux(3);
        ROM_SysCtlDelay(MILLISECOND * 10);      // 10msec settling for MUX analog
        Vint = pollADS1248_iso(1, 6, sys_data.sample_average, 1, sys_data.Vint_sps);       // Chan +1 -6, trials = user, gain = user, sps = 20 Hz
        Vint_std = sys_data.AD24_std;
    }
    profile2_toggle(1);
    //Vext_ref (GLIDER)
    if(sys_data.data_cfg[CFG_V_EXT] > 0)
    {
        ADS1248_gpio_ADG1609_mux(0);
        ROM_SysCtlDelay(MILLISECOND * 10);      // 10msec settling for MUX analog
        ////Vext_ref = pollADS1248_iso(1, 6, 1, 1, sys_data.Vint_sps);       // Chan +1 -6, trials = user, gain = user, sps = 20 Hz //YT changed average to 1
        //Vext_ref = pollADS1248_iso(1, 6, sys_data.sample_average, 1, sys_data.Vint_sps);       // Chan +1 -6, trials = user, gain = user, sps = 20 Hz //YT changed average to 1

        if(sys_data.fast_mode == 1)
        {
            //#ifdef TRIEDANDTRUEFASTSAMP
            Vext_ref = pollADS1248_iso(1, 6, 10, 1, 20);  // 10x50msec= 500msec  trials=10, gain=1, sps=20  THOM note: suggest using 1,6,5,1,10 to allow adc to do better filtering
            //#endif
            // saves 100msec - noise looks close to same with 100msec less sampling time - needs more testing
            //uprintf("\nfast mode = 2\n");
            //Vext_ref = pollADS1248_iso(1, 6, 2, 1, 5);  // 4*100msec = 400msec  trials=4, gain=1, sps=10

        }
        else if(sys_data.fast_mode == 2)
        {
            // saves 100msec - noise looks close to same with 100msec less sampling time - needs more testing
            //uprintf("\nfast mode = 2\n");
            Vext_ref = pollADS1248_iso(1, 6, 4, 1, 10);  // 400msec  trials=4, gain=1, sps=10
        }
        else if(sys_data.fast_mode == 3)
        {
            // saves 100msec - noise looks close to same with 100msec less sampling time - needs more testing
            //uprintf("\nfast mode = 2\n");
            Vext_ref = pollADS1248_iso(1, 6, 2, 1, 5);  // 2*200msec = 400msec  trials=2, gain=1, sps=5
        }
        else
        {
            Vext_ref = pollADS1248_iso(1, 6, sys_data.sample_average, 1, sys_data.Vint_sps);       // Chan +1 -6, trials = user, gain = user, sps = 20 Hz //YT changed average to 1
        }
        Vext_std = sys_data.AD24_std;
    }
    profile2_toggle(1);
    //Ext Ref Offset,
    if(sys_data.data_cfg[CFG_V_EXT_OFFSET] > 0)
    {
        dbg_printf("\nno extref on glider\n");
        ADS1248_gpio_ADG1609_mux(0);
        ROM_SysCtlDelay(MILLISECOND * 10);      // 10msec settling for MUX analog
        //ExtRef_WithOffset = pollADS1248_iso(1, 5, 1, 1, sys_data.Vint_sps);       // Chan +1 -5, trials = 1, gain = user, sps = 5 Hz
        ExtRef_WithOffset = pollADS1248_iso(1, 5, sys_data.sample_average, sys_data.Vint_gain, sys_data.Vint_sps);       // Chan +1 -5, trials = 1, gain = user, sps = 5 Hz
        ExtRef_WithOffset_std = sys_data.AD24_std;
    }
    profile2_toggle(1);

    //Int Ref Off,
    if(sys_data.data_cfg[CFG_V_INT_OFFSET] > 0)
    {
        dbg_printf("\nno intref on glider\n");
        ADS1248_gpio_ADG1609_mux(3);
        ROM_SysCtlDelay(MILLISECOND * 10);      // 10msec settling for MUX analog
        //IntRef_WithOffset = pollADS1248_iso(1, 5, sys_data.sample_average, 1, sys_data.Vint_sps);       // Chan +1 -5, trials = 1, gain = user, sps = 5 Hz
        IntRef_WithOffset = pollADS1248_iso(1, 5, sys_data.sample_average, sys_data.Vint_gain, sys_data.Vint_sps);
        IntRef_WithOffset_std = sys_data.AD24_std;
    }
    profile2_toggle(1);
    //CntrE Cur, (GLIDER)
    if(sys_data.data_cfg[CFG_I_COUNTER] > 0)
    {
        ADS1248_gpio_ADG1609_mux(1);
        ROM_SysCtlDelay(MILLISECOND * 10);      // 10msec settling for MUX analog
        //CounterElectrodeCurrent = pollADS1248_iso(1, 5, 3, 1, sys_data.Vint_sps);       // Chan +5 -1, trials = 1, gain = user, sps = 5 Hz
        //CounterElectrodeCurrent = pollADS1248_iso(1, 5, 1, 1, 20);  // (could be 40hz)  GLIDER
        if(sys_data.fast_mode >= 1)
        {
            CounterElectrodeCurrent = pollADS1248_iso(1, 5, 1, 1, 20);  // (could be 40hz)  GLIDER
        }
        else
        {
            CounterElectrodeCurrent = pollADS1248_iso(1, 5, 3, 1, sys_data.Vint_sps);       // Chan +5 -1, trials = 3, gain = 1, sps = 5 Hz
        }
        CounterElectrodeCurrent_std = sys_data.AD24_std;
    }
    profile2_toggle(1);
    // CntrE Volt, (GLIDER)
    if(sys_data.data_cfg[CFG_V_COUNTER_ELECT] > 0)
    {
        ADS1248_gpio_ADG1609_mux(1);
        ROM_SysCtlDelay(MILLISECOND * 10);      // 10msec settling for MUX analog
        //CounterElectrodeVoltage = pollADS1248_iso(1, 6, sys_data.sample_average, 1, sys_data.Vint_sps);       // Chan +5 -1, trials = 1, gain = user, sps = 5 Hz
        //CounterElectrodeVoltage = pollADS1248_iso(1, 6, 5, 1, 20);  // GLIDER
        if(sys_data.fast_mode >= 1)
        {
            CounterElectrodeVoltage = pollADS1248_iso(1, 6, 5, 1, 20);  // GLIDER
        }
        else
        {
            CounterElectrodeVoltage = pollADS1248_iso(1, 6, sys_data.sample_average, 1, sys_data.Vint_sps);
        }
        CounterElectrodeVoltage_std = sys_data.AD24_std;
    }
    profile2_toggle(1);
    // Subst Cur, (GLIDER Ib)
    if(sys_data.data_cfg[CFG_I_SUBSTRATE] > 0)
    {
        ADS1248_gpio_ADG1609_mux(2);
        ROM_SysCtlDelay(MILLISECOND * 10);      // 10msec settling for MUX analog
        //SubstrateCurrent = pollADS1248_iso(1, 6, 3, 1, sys_data.Vint_sps);       // Chan +1 -6, trials = 1, gain = user, sps = 5 Hz
        //SubstrateCurrent = pollADS1248_iso(1, 6, 1, 1, 20);       // GLIDER 1 sample, 20 hz
        if(sys_data.fast_mode >= 1)
        {
            SubstrateCurrent = pollADS1248_iso(1, 6, 1, 1, 20);       // GLIDER 1 sample, 20 hz
        }
        else
        {
            SubstrateCurrent = pollADS1248_iso(1, 6, 3, 1, sys_data.Vint_sps);       // Chan +1 -6, trials = 1, gain = user, sps = 5 Hz
        }
    }

    profile2_toggle(1);
    // read internal adc (battery, etc)
    read_all_adc();
    read_all_adc();     // read a second time just for fun

    // battery voltage must be read for 'too low' check at bottom
    fVbat = (float)(adc_data[0]*100);
    fVbat /= 18687.707;
    main_batt_volt = fVbat;         // 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_ENV_BRD_TEMP] > 0)
    {
        fExtTemp = ((((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)
        con_temp = fExtTemp;
    }

    // Humidity
    if(sys_data.data_cfg[CFG_ENV_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;
    }
    profile2_toggle(1);

    // poweroff monitoring circuitry
    ROM_GPIOPinWrite(GPIO_PORTM_BASE, GPIO_PIN_6, 0x00);   // Turn off VBat monitoring
    ROM_GPIOPinWrite(GPIO_PORTM_BASE, GPIO_PIN_7, 0x00);    // 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)
    {
        TC = DuraFET_temp(Vtherm, 0);   //sys_data.TCOffset);
    }

    if(sys_data.data_cfg[CFG_EST_PH_EXT] > 0)
    {
        pHext = calc_pHext(Vext_ref, TC, SBE_sal);
    }

    if(sys_data.data_cfg[CFG_EST_PH_INT] > 0)
    {
        //pHint = calc_pHint(Vint, TC);
        pHint = calc_pHint(IntRef_WithOffset, TC);   // NEW THOM per YUI  7 Jun 2018
    }
    profile2_toggle(1);



    if(sys_data.data_cfg[CFG_OPTODE] > 0)
    {
        ROM_SysCtlDelay(MILLISECOND*1000);      // 1000 works, 500 does not, 700 does not, 900 causes a hang

        int bytesRead;
        bytesRead = Optode_UARTRxBytesAvail();          // This is a hack to workaround a ring buffer bug - might be an init problem?  not sure.  First call with data in buffer results in bytesRead=0,  reads do not clear the buffer


        //ROM_SysCtlDelay(ONESEC);    // Wait for instruments to respond // changed from 2*ONESEC 4/27/2017 -TW
        closeOptode();

        parseOptodeData();      // returns data in global optode_buff
    }

    //uprintf("\nOptode response\t%s", Optode_buff);


    // Open a file
    fresult = f_open(&fileObject, sys_data.fileName, FA_READ |FA_WRITE |FA_OPEN_ALWAYS);
    if(fresult != FR_OK)
    {
        uprintf("f_open error: %s\n", StringFromFresult(fresult));
        error_store("f_open error");
    }

    // Seek to the end, to append our file
    fresult = f_lseek(&fileObject, fileObject.fsize);
    if(fresult != FR_OK)
    {
        uprintf("f_lseek error: %s\n", StringFromFresult(fresult));
        error_store("f_lseek error");
    }


    // Store sample to SD card file (field is turned off when 0, on when 1 or 255)
    if(sys_data.data_cfg[CFG_SAMPLE_NUM] > 0)       { sd_fprintf(&fileObject, "#%07d\t", sys_data.current_sample);  } //0
    if(sys_data.data_cfg[CFG_TIMEDATE] > 0)         { sd_fprintf(&fileObject, "%s\t", timestamp);                   } //1
    if(sys_data.data_cfg[CFG_ENV_BAT_VOLT] > 0)     { sd_fprintf(&fileObject, "%5.2f\t", main_batt_volt);           } //2
    if(sys_data.data_cfg[CFG_ENV_BRD_TEMP] > 0)     { sd_fprintf(&fileObject, "%5.2f\t", con_temp);                 } //3
    if(sys_data.data_cfg[CFG_ENV_HUMIDITY] > 0)     { sd_fprintf(&fileObject, "%3u\t", uiHumidity);                 } //4
    if(sys_data.data_cfg[CFG_INT_PRESSURE] > 0)     { sd_fprintf(&fileObject, "%5.2f\t", fPressure);                } //5
    if(sys_data.data_cfg[CFG_V_THERMISTOR] > 0)     { sd_fprintf(&fileObject, "%8.6f\t", Vtherm);                   } //6
    if(sys_data.data_cfg[CFG_V_THERMISTOR_STD] > 0) { sd_fprintf(&fileObject, "%8.6f\t", Vtherm_std);               } //7
    if(sys_data.data_cfg[CFG_V_INT_OFFSET] > 0)     { sd_fprintf(&fileObject, "%8.6f\t", IntRef_WithOffset);        } //8
    if(sys_data.data_cfg[CFG_V_INT_OFFSET_STD] > 0) { sd_fprintf(&fileObject, "%8.6f\t", IntRef_WithOffset_std);    } //9
    if(sys_data.data_cfg[CFG_V_EXT_OFFSET] > 0)     { sd_fprintf(&fileObject, "%8.6f\t", ExtRef_WithOffset);        } //10
    if(sys_data.data_cfg[CFG_V_EXT_OFFSET_STD] > 0) { sd_fprintf(&fileObject, "%8.6f\t", ExtRef_WithOffset_std);    } //11

    if(sys_data.data_cfg[CFG_V_INT] > 0)            { sd_fprintf(&fileObject, "%8.6f\t", Vint);                     } //12
    if(sys_data.data_cfg[CFG_V_INT_STD] > 0)        { sd_fprintf(&fileObject, "%8.6f\t", Vint_std);                 } //13
    if(sys_data.data_cfg[CFG_V_EXT] > 0)            { sd_fprintf(&fileObject, "%8.6f\t", Vext_ref);                 } //14
    if(sys_data.data_cfg[CFG_V_EXT_STD] > 0)        { sd_fprintf(&fileObject, "%8.6f\t", Vext_std);                 } //15
    if(sys_data.data_cfg[CFG_V_COUNTER_ELECT] > 0)  { sd_fprintf(&fileObject, "%8.6f\t", CounterElectrodeVoltage);  } //16
    if(sys_data.data_cfg[CFG_V_COUNTER_ELECT_STD] > 0)  { sd_fprintf(&fileObject, "%8.6f\t", CounterElectrodeVoltage_std);  }  //17
    if(sys_data.data_cfg[CFG_I_COUNTER] > 0)        { sd_fprintf(&fileObject, "%8.6f\t", CounterElectrodeCurrent);  } //18
    if(sys_data.data_cfg[CFG_I_SUBSTRATE] > 0)      { sd_fprintf(&fileObject, "%8.6f\t", SubstrateCurrent);         } //19
    if(sys_data.data_cfg[CFG_CALC_TEMP] > 0)        { sd_fprintf(&fileObject, "%6.3f\t", TC);                       } //20
    if(sys_data.data_cfg[CFG_EST_PH_INT] > 0)       { sd_fprintf(&fileObject, "%7.6f\t", pHint);                    } //21
    if(sys_data.data_cfg[CFG_OPTODE] > 0)           { sd_fprintf(&fileObject, "%s\t", Optode_buff);                 } //22

    //sd_fprintf(&fileObject, "fast_sample");
    sd_fprintf(&fileObject, "\n");


    // Close the file
    fresult = f_close( &fileObject );
    if(fresult != FR_OK)
    {
        uprintf("f_close error: %s\n", StringFromFresult(fresult));
        error_store("f_close error");
    }
    profile2_toggle(1);

    if(txFlg == 1) // added to support 'sl' command when txFlg=0
    {
        //#0000405       06/07/2018 14:16:12
        // bat 8.67   temp 24.20   humidity 25.61    pressure 6.80  vtherm 1.023693        vtherm_std 4.884770
        // -0.090986       0.434246        -0.019936       0.095250
        //-1.120937       5.349794        -1.050123       5.012120        -1.049656       6.796905        0.000644        0.022814        23.863  -12.254394

        for(indx=0; indx<SIZEOF_SAMPBUF; indx++)
            sampBuf[indx] = ' ';
        indx = 0;
        if(sys_data.data_cfg[CFG_SAMPLE_NUM] > 0)       { uprintf("#%07d\t", sys_data.current_sample);   } //0
        if(sys_data.data_cfg[CFG_TIMEDATE] > 0)         { uprintf("%s\t", timestamp);                    } //1
        if(sys_data.data_cfg[CFG_ENV_BAT_VOLT] > 0)     { uprintf("%5.2f\t", main_batt_volt);            } //2
        if(sys_data.data_cfg[CFG_ENV_BRD_TEMP] > 0)     { uprintf("%5.2f\t", con_temp);                  } //3
        if(sys_data.data_cfg[CFG_ENV_HUMIDITY] > 0)     { uprintf("%3u\t", uiHumidity);                  } //4
        if(sys_data.data_cfg[CFG_INT_PRESSURE] > 0)     { uprintf("%5.2f\t", fPressure);                 } //5
        if(sys_data.data_cfg[CFG_V_THERMISTOR] > 0)     { uprintf("%8.6f\t", Vtherm);                    } //6
        if(sys_data.data_cfg[CFG_V_THERMISTOR_STD] > 0) { uprintf("%8.6f\t", Vtherm_std);                } //7
        if(sys_data.data_cfg[CFG_V_INT_OFFSET] > 0)     { uprintf("%8.6f\t", IntRef_WithOffset);         } //8
        if(sys_data.data_cfg[CFG_V_INT_OFFSET_STD] > 0) { uprintf("%8.6f\t", IntRef_WithOffset_std);     } //9
        if(sys_data.data_cfg[CFG_V_EXT_OFFSET] > 0)     { uprintf("%8.6f\t", ExtRef_WithOffset);         } //10
        if(sys_data.data_cfg[CFG_V_EXT_OFFSET_STD] > 0) { uprintf("%8.6f\t", ExtRef_WithOffset_std);     } //11

        if(sys_data.data_cfg[CFG_V_INT] > 0)            { uprintf("%8.6f\t", Vint);                      } //12
        if(sys_data.data_cfg[CFG_V_INT_STD] > 0)        { uprintf("%8.6f\t", Vint_std);                  } //13
        if(sys_data.data_cfg[CFG_V_EXT] > 0)            { uprintf("%8.6f\t", Vext_ref);                  } //14
        if(sys_data.data_cfg[CFG_V_EXT_STD] > 0)        { uprintf("%8.6f\t", Vext_std);                  } //15
        if(sys_data.data_cfg[CFG_V_COUNTER_ELECT] > 0)  { uprintf("%8.6f\t", CounterElectrodeVoltage);   } //16
        if(sys_data.data_cfg[CFG_V_COUNTER_ELECT_STD] > 0)  { uprintf("%8.6f\t", CounterElectrodeVoltage_std); } //17
        if(sys_data.data_cfg[CFG_I_COUNTER] > 0)        { uprintf("%8.6f\t", CounterElectrodeCurrent);   } //18
        if(sys_data.data_cfg[CFG_I_SUBSTRATE] > 0)      { uprintf("%8.6f\t", SubstrateCurrent);          } //19
        if(sys_data.data_cfg[CFG_CALC_TEMP] > 0)        { uprintf("%6.3f\t", TC);                        } //20
        if(sys_data.data_cfg[CFG_EST_PH_INT] > 0)       { uprintf("%7.6f\t", pHint);                     } //21
        if(sys_data.data_cfg[CFG_OPTODE] > 0)           { uprintf("%s\t", Optode_buff);                  } //22
        //uprintf("fast_sample");         // THOM DEBUG
        uprintf("\r\n");

        ROM_SysCtlDelay(MILLISECOND*TIME_TXSAMPLE_MSEC);        // time for transmit
    }   // if txFlg
    else
    {
        indx = 0;
        if(sys_data.data_cfg[CFG_SAMPLE_NUM] > 0)       { indx += sprintf(&sampBuf[indx], "#%07d\t", sys_data.current_sample);  } //0
        if(sys_data.data_cfg[CFG_TIMEDATE] > 0)         { indx += sprintf(&sampBuf[indx], "%s\t", timestamp);                    } //1
        if(sys_data.data_cfg[CFG_ENV_BAT_VOLT] > 0)     { indx += sprintf(&sampBuf[indx], "%5.2f\t", main_batt_volt);            } //2
        if(sys_data.data_cfg[CFG_ENV_BRD_TEMP] > 0)     { indx += sprintf(&sampBuf[indx], "%5.2f\t", con_temp);                  } //3
        if(sys_data.data_cfg[CFG_ENV_HUMIDITY] > 0)     { indx += sprintf(&sampBuf[indx], "%3u\t", uiHumidity);                  } //4
        if(sys_data.data_cfg[CFG_INT_PRESSURE] > 0)     { indx += sprintf(&sampBuf[indx], "%5.2f\t", fPressure);                 } //5
        if(sys_data.data_cfg[CFG_V_THERMISTOR] > 0)     { indx += sprintf(&sampBuf[indx], "%8.6f\t", Vtherm);                    } //6
        if(sys_data.data_cfg[CFG_V_THERMISTOR_STD] > 0) { indx += sprintf(&sampBuf[indx], "%8.6f\t", Vtherm_std);                } //7
        if(sys_data.data_cfg[CFG_V_INT_OFFSET] > 0)     { indx += sprintf(&sampBuf[indx], "%8.6f\t", IntRef_WithOffset);         } //8
        if(sys_data.data_cfg[CFG_V_INT_OFFSET_STD] > 0) { indx += sprintf(&sampBuf[indx], "%8.6f\t", IntRef_WithOffset_std);     } //9
        if(sys_data.data_cfg[CFG_V_EXT_OFFSET] > 0)     { indx += sprintf(&sampBuf[indx], "%8.6f\t", ExtRef_WithOffset);        } //10
        if(sys_data.data_cfg[CFG_V_EXT_OFFSET_STD] > 0) { indx += sprintf(&sampBuf[indx], "%8.6f\t", ExtRef_WithOffset_std);    } //11

        if(sys_data.data_cfg[CFG_V_INT] > 0)            { indx += sprintf(&sampBuf[indx], "%8.6f\t", Vint);                      } //12
        if(sys_data.data_cfg[CFG_V_INT_STD] > 0)        { indx += sprintf(&sampBuf[indx], "%8.6f\t", Vint_std);                  } //13
        if(sys_data.data_cfg[CFG_V_EXT] > 0)            { indx += sprintf(&sampBuf[indx], "%8.6f\t", Vext_ref);                  } //14
        if(sys_data.data_cfg[CFG_V_EXT_STD] > 0)        { indx += sprintf(&sampBuf[indx], "%8.6f\t", Vext_std);                  } //15
        if(sys_data.data_cfg[CFG_V_COUNTER_ELECT] > 0)  { indx += sprintf(&sampBuf[indx], "%8.6f\t", CounterElectrodeVoltage);   } //16
        if(sys_data.data_cfg[CFG_V_COUNTER_ELECT_STD] > 0)  { indx += sprintf(&sampBuf[indx], "%8.6f\t", CounterElectrodeVoltage_std);  } //17
        if(sys_data.data_cfg[CFG_I_COUNTER] > 0)        { indx += sprintf(&sampBuf[indx], "%8.6f\t", CounterElectrodeCurrent);   } //18
        if(sys_data.data_cfg[CFG_I_SUBSTRATE] > 0)      { indx += sprintf(&sampBuf[indx], "%8.6f\t", SubstrateCurrent);          } //19
        if(sys_data.data_cfg[CFG_CALC_TEMP] > 0)        { indx += sprintf(&sampBuf[indx], "%6.3f\t", TC);                        } //20
        if(sys_data.data_cfg[CFG_EST_PH_INT] > 0)       { indx += sprintf(&sampBuf[indx], "%7.6f\t", pHint);                     } //21
        if(sys_data.data_cfg[CFG_OPTODE] > 0)           { indx += sprintf(&sampBuf[indx], "%s\t", Optode_buff);                  } //22
        sprintf(&sampBuf[indx], "\r\n");

        for(indx=0; indx<SIZEOF_SAMPBUF; indx++)
        {
            if(sampBuf[indx] == 0)
                sampBuf[indx] = 'x';      // DEBUG - make this a space
            if(sampBuf[indx] == 0x0a || sampBuf[indx] == 0x0d)
                break;
        }

        //uprintf("%s", sampBuf);      // debug
    }

    profile2_toggle(1);

    sys_data.current_sample++;  // Increment the sample counter

    // Check for low battery voltage. Exit and sleep if too low.
    if( main_batt_volt < sys_data.low_batt_volt )
    {
        uprintf("\nLow battery voltage (%.2f < %.2f) ! Exiting deploy mode...\n", main_batt_volt, sys_data.low_batt_volt );

        //error_store("Low battery! Exited deploy mode");
        //sleep(IDLE, 0);     // Sleep until woken by user
    }

}

#endif

int print_sampBuf(void)
{
    return(uprintf("%s", sampBuf));
}



#if BOARD_SEAPHOX==1
void get_sample(int txFlg)
{
    char timestamp[TIMESTAMPLENGTH], buff[80];
    uint32_t timeout;
    //uint32_t ticks;
    struct tm *time_struct;
    //float dummy;
    //float main_batt_volt, iso_batt_volt, temp_press, con_temp;
    float main_batt_volt, iso_batt_volt, con_temp;
    float SBE_sal;          // MicroCAT salinity
    //float SBE_temp;           // MicroCAT temperature
    float Vtherm;           // DuraFET raw temperature voltage
    float Vtherm_std;       // Std Dev for Durafet Thermistor
    float Vint;             // DuraFET internal reference voltage
    float Vint_std;         // Std Dev for Durafet Internal Voltage
    float TC;               // Calculated DuraFET temperature
    float Vext_ref;         // External (AUX) reference voltage
    float Vext_std;         // Std Dev for Durafet External Voltage
    float pHext;            // Calculated pH using external reference
    float pHint;            // Calculated pH using internal reference
    float CounterElecrodeCurrent;       // (was counter_leak) DuraFET counter leakage current
    float SubstrateCurrent; // (was substrate_leak) DuraFET substrate leakage current

    // counter_leak is now CounterElectrodeCurrent
    // substrate_leak is now SubstrateCurrent


    FIL fileObject;
    FRESULT fresult;

    if(sys_data.test_mode == 1) uprintf("\nSampling...");

    // Pump on time
    if(sys_data.test_mode == 1) uprintf("\nPump on (test mode)\n");     // Don't want the pump to run in test deployment
    else pump_on();

    timeout = ROM_HibernateRTCGet() + sys_data.pumpon_time;

#ifdef MINIMIZEDELAY
    do
    {
        ROM_SysCtlDelay(100 * MILLISECOND);
        if( kbhit() && sys_data.output == VERBOSE) uprintf("\nSampling, please wait...");

    } while( ROM_HibernateRTCGet() < timeout );
#endif
    while(1)
    {
        if( ROM_HibernateRTCGet() >= timeout )      // re-write pump on time check to save 100msec if pumpon_time = 0
            break;

        ROM_SysCtlDelay(100 * MILLISECOND);
        if( kbhit() && sys_data.output == VERBOSE) uprintf("\nSampling, please wait...");

    }

    pump_off();
    if(sys_data.test_mode == 1) uprintf("Pump off\n");

    //get the time from the RTC
//  ticks = ROM_HibernateRTCGet();
    time_struct = localtime(&sys_data.nextWakeUp);
    strftime(timestamp, sizeof(timestamp),"%Y/%m/%d %H:%M:%S", time_struct);

    // Open and poll the microCat and Optode
    /*openMicroCAT();
    openOptode();
    pressureOn();*/
    openADS1248_noniso();
    openADS1248_iso();

    ROM_SysCtlDelay(800*MILLISECOND);   // Let instruments and sensors settle


    SBE_sal = 35;   // Thom added 7May2019 since SBE_sal is commented out and pHext (below) relies on it
    /*PollMicroCAT();
    pollOptode();

    ROM_SysCtlDelay(ONESEC);    // Wait for instruments to respond // changed from 2*ONESEC 4/27/2017 -TW

    closeMicroCAT();
    closeOptode();

    parseMicroCATData();    // Extract the data from response strings
    parseOptodeData();

    // Update salinity from MicroCAT data
    if( sscanf( MicroCAT_buff, "%f %f %f %s %s", &SBE_temp, &dummy, &SBE_sal, buff, buff) != 5)
    {
        if(sys_data.test_mode == 1) uprintf("\n\nMicroCAT read error! Setting salinity to default\n");
        SBE_sal = sys_data.default_sal;
        error_store("MicroCAT read error");
    }

    // Read the non-isolated sensors
    temp_press = pressure();*/

#ifdef TEMPCODE
    if(sys_data.data_cfg[CFG_SAMPLE_NUM] > 0)       { sd_fprintf(&fileObject, "#%07d\t", sys_data.current_sample);  } //0
    if(sys_data.data_cfg[CFG_TIMEDATE] > 0)         { sd_fprintf(&fileObject, "%s\t", timestamp);                   } //1
    if(sys_data.data_cfg[CFG_ENV_BAT_VOLT] > 0)     { sd_fprintf(&fileObject, "%5.2f\t", main_batt_volt);           } //2
    if(sys_data.data_cfg[CFG_ENV_BRD_TEMP] > 0)     { sd_fprintf(&fileObject, "%5.2f\t", con_temp);                 } //3
    if(sys_data.data_cfg[CFG_ENV_HUMIDITY] > 0)     { sd_fprintf(&fileObject, "%3u\t", uiHumidity);                 } //4
    if(sys_data.data_cfg[CFG_INT_PRESSURE] > 0)     { sd_fprintf(&fileObject, "%5.2f\t", fPressure);                } //5
    if(sys_data.data_cfg[CFG_V_THERMISTOR] > 0)     { sd_fprintf(&fileObject, "%8.6f\t", Vtherm);                   } //6
    if(sys_data.data_cfg[CFG_V_THERMISTOR_STD] > 0) { sd_fprintf(&fileObject, "%8.6f\t", Vtherm_std);               } //7
    if(sys_data.data_cfg[CFG_V_INT_OFFSET] > 0)     { sd_fprintf(&fileObject, "%8.6f\t", IntRef_WithOffset);        } //8
    if(sys_data.data_cfg[CFG_V_INT_OFFSET_STD] > 0) { sd_fprintf(&fileObject, "%8.6f\t", IntRef_WithOffset_std);    } //9
    if(sys_data.data_cfg[CFG_V_EXT_OFFSET] > 0)     { sd_fprintf(&fileObject, "%8.6f\t", ExtRef_WithOffset);        } //10
    if(sys_data.data_cfg[CFG_V_EXT_OFFSET_STD] > 0) { sd_fprintf(&fileObject, "%8.6f\t", ExtRef_WithOffset_std);    } //11

    if(sys_data.data_cfg[CFG_V_INT] > 0)            { sd_fprintf(&fileObject, "%8.6f\t", Vint);                     } //12
    if(sys_data.data_cfg[CFG_V_INT_STD] > 0)        { sd_fprintf(&fileObject, "%8.6f\t", Vint_std);                 } //13
    if(sys_data.data_cfg[CFG_V_EXT] > 0)            { sd_fprintf(&fileObject, "%8.6f\t", Vext_ref);                 } //14
    if(sys_data.data_cfg[CFG_V_EXT_STD] > 0)        { sd_fprintf(&fileObject, "%8.6f\t", Vext_std);                 } //15
    if(sys_data.data_cfg[CFG_V_COUNTER_ELECT] > 0)  { sd_fprintf(&fileObject, "%8.6f\t", CounterElectrodeVoltage);  } //16
    if(sys_data.data_cfg[CFG_V_COUNTER_ELECT_STD] > 0)  { sd_fprintf(&fileObject, "%8.6f\t", CounterElectrodeVoltage_std);  }  //17
    if(sys_data.data_cfg[CFG_I_COUNTER] > 0)        { sd_fprintf(&fileObject, "%8.6f\t", CounterElectrodeCurrent);  } //18
    if(sys_data.data_cfg[CFG_I_SUBSTRATE] > 0)      { sd_fprintf(&fileObject, "%8.6f\t", SubstrateCurrent);         } //19
    if(sys_data.data_cfg[CFG_CALC_TEMP] > 0)        { sd_fprintf(&fileObject, "%6.3f\t", TC);                       } //20
    if(sys_data.data_cfg[CFG_EST_PH_INT] > 0)       { sd_fprintf(&fileObject, "%7.6f\n", pHint);                    } //21
#endif


    if(sys_data.data_cfg[CFG_ENV_BRD_TEMP] > 0)
        con_temp = controller_temp();
    //if(sys_data.data_cfg[CFG_ENV_BAT_VOLT] > 0)   //MUST read battery voltage as it is checked for too low
        main_batt_volt = batt_volt();

    //------------- Read the isolated sensors -----------------------

    if(sys_data.data_cfg[CFG_V_THERMISTOR] > 0)
    {
        Vtherm = pollADS1248_iso(0, 6, sys_data.sample_average, 1, 20);
        Vtherm_std = sys_data.AD24_std;
    }

    if(sys_data.data_cfg[CFG_V_INT] > 0)
    {
        Vint = pollADS1248_iso(1, 6, sys_data.sample_average, sys_data.Vint_gain, 20); // sps used to be sys_data.Vint_sps YT
        Vint_std = sys_data.AD24_std;
    }

    if(sys_data.data_cfg[CFG_V_EXT] > 0)
    {
        Vext_ref = pollADS1248_iso(4, 6, sys_data.sample_average, 1, 20);
        Vext_std = sys_data.AD24_std;
    }


// THOM - TODO there is no config for iso batt
    iso_batt_volt = batt_volt_iso();
    //CounterElecrodeCurrent = pollADS1248_iso(3, 2, 1, 1, 5);        // Chan 3-2, 1 trial, gain = 1, sps = 5 Hz
    //SubstrateCurrent = pollADS1248_iso(7, 6, 1, 1, 5);  // Chan 7-6, 1 trial, gain = 1, sps = 5 Hz
    CounterElecrodeCurrent = 0.0;  // added 25 Apr 2019
    SubstrateCurrent = 0.0; // added 25 Apr 2019


    // Shutdown sensors
    /* pressureOff();  */  //pressureOn was commented out above, commenting this out 7May2019
    closeADS1248_noniso();
    closeADS1248_iso();

    // Calculate the external and internal pH values

    if(sys_data.data_cfg[CFG_CALC_TEMP] > 0)
    {
        TC = DuraFET_temp(Vtherm, 0);   //sys_data.TCOffset);

        pHext = calc_pHext(Vext_ref, TC, SBE_sal);      // SBE_sal is set or sampled above
        pHint = calc_pHint(Vint, TC);
    }

    // Open a file
    fresult = f_open(&fileObject, sys_data.fileName, FA_READ |FA_WRITE |FA_OPEN_ALWAYS);
    if(fresult != FR_OK)
    {
        uprintf("f_open error: %s\n", StringFromFresult(fresult));
        error_store("f_open error");
    }

    // Seek to the end, to append our file
    fresult = f_lseek(&fileObject, fileObject.fsize);
    if(fresult != FR_OK)
    {
        uprintf("f_lseek error: %s\n", StringFromFresult(fresult));
        error_store("f_lseek error");
    }


    // Store sample to SD card file (field is turned off when 0, on when 1 or 255)
    if(sys_data.data_cfg[CFG_SAMPLE_NUM] > 0)       { sd_fprintf(&fileObject, "#%07d\t", sys_data.current_sample);  } //0
    if(sys_data.data_cfg[CFG_TIMEDATE] > 0)         { sd_fprintf(&fileObject, "%s\t", timestamp);                   } //1
    if(sys_data.data_cfg[CFG_ENV_BAT_VOLT] > 0)     { sd_fprintf(&fileObject, "%5.2f\t", main_batt_volt);           } //2
    if(sys_data.data_cfg[CFG_ENV_BRD_TEMP] > 0)     { sd_fprintf(&fileObject, "%5.2f\t", con_temp);                 } //3
    if(sys_data.data_cfg[CFG_ENV_HUMIDITY] > 0)     { sd_fprintf(&fileObject, "NotSup\t");                          } //4  HUMIDITY NOT SUPPORTED
    if(sys_data.data_cfg[CFG_INT_PRESSURE] > 0)     { sd_fprintf(&fileObject, "NotSup\t");                          } //5   PRESSURE NOT SUPPORTED
    if(sys_data.data_cfg[CFG_V_THERMISTOR] > 0)     { sd_fprintf(&fileObject, "%8.6f\t", Vtherm);                   } //6
    if(sys_data.data_cfg[CFG_V_THERMISTOR_STD] > 0) { sd_fprintf(&fileObject, "%8.6f\t", Vtherm_std);               } //7
    if(sys_data.data_cfg[CFG_V_INT_OFFSET] > 0)     { sd_fprintf(&fileObject, "NotSup\t");                          } //8   IntRef_WithOffset Not Supported
    if(sys_data.data_cfg[CFG_V_INT_OFFSET_STD] > 0) { sd_fprintf(&fileObject, "NotSup\t");                          } //9   IntRef_WithOffset_std
    if(sys_data.data_cfg[CFG_V_EXT_OFFSET] > 0)     { sd_fprintf(&fileObject, "NotSup\t");                          } //10  ExtRef_WithOffset
    if(sys_data.data_cfg[CFG_V_EXT_OFFSET_STD] > 0) { sd_fprintf(&fileObject, "NotSup\t");                          } //11  ExtRef_WithOffset_std

    if(sys_data.data_cfg[CFG_V_INT] > 0)            { sd_fprintf(&fileObject, "%8.6f\t", Vint);                     } //12
    if(sys_data.data_cfg[CFG_V_INT_STD] > 0)        { sd_fprintf(&fileObject, "%8.6f\t", Vint_std);                 } //13
    if(sys_data.data_cfg[CFG_V_EXT] > 0)            { sd_fprintf(&fileObject, "%8.6f\t", Vext_ref);                 } //14
    if(sys_data.data_cfg[CFG_V_EXT_STD] > 0)        { sd_fprintf(&fileObject, "%8.6f\t", Vext_std);                 } //15
    if(sys_data.data_cfg[CFG_V_COUNTER_ELECT] > 0)  { sd_fprintf(&fileObject, "NotSup\t");                          }      //16   CounterElectrodeVoltage
    if(sys_data.data_cfg[CFG_V_COUNTER_ELECT_STD] > 0)  { sd_fprintf(&fileObject, "NotSup\t");                      }  //17  CounterElectrodeVoltage_std
    if(sys_data.data_cfg[CFG_I_COUNTER] > 0)        { sd_fprintf(&fileObject, "%8.6f\t", CounterElecrodeCurrent);             } //18   counter_leak = CounterElectrodeCurrent
    if(sys_data.data_cfg[CFG_I_SUBSTRATE] > 0)      { sd_fprintf(&fileObject, "%8.6f\t", SubstrateCurrent);           } //19    = SubstrateCurrent
    if(sys_data.data_cfg[CFG_CALC_TEMP] > 0)        { sd_fprintf(&fileObject, "%6.3f\t", TC);                       } //20
    if(sys_data.data_cfg[CFG_EST_PH_INT] > 0)       { sd_fprintf(&fileObject, "%7.6f", pHint);                    } //21
    sd_fprintf(&fileObject, "\n");


    // Close the file
    fresult = f_close( &fileObject );
    if(fresult != FR_OK)
    {
        uprintf("f_close error: %s\n", StringFromFresult(fresult));
        error_store("f_close error");
    }

    if(txFlg == 1)
    {
        // Print test mode data to screen
        if(sys_data.test_mode == 1)
        {
            // THOM Todo - need to test the test_mode = 1
            uprintf("\n\nSample # \t\t%u", sys_data.current_sample);
            uprintf("\nTimestamp \t\t%s", timestamp);
            //uprintf("\nSBE response\t%s", MicroCAT_buff);
            //uprintf("\nSBE salinity \t%.4f", SBE_sal);
            //uprintf("\nSBE temperature \t%.4f", SBE_temp);
            //uprintf("\nOptode response\t%s", Optode_buff);
            uprintf("\nVtherm \t\t%.6f V", Vtherm);
            uprintf("\nVtherm std \t\t%.6f V", Vtherm_std);
            uprintf("\nVint \t\t\t%.6f V", Vint);
            uprintf("\nVint std \t\t\t%.6f V", Vint_std);
            uprintf("\nVext \t\t%.6f V", Vext_ref);
            uprintf("\nVext std \t\t%.6f V", Vext_std);
            uprintf("\npH internal \t%.6f", pHint);
            uprintf("\npH external \t%.6f", pHext);
            uprintf("\npH temperature\t%.4f C", TC);
            //uprintf("\nCounter leak. \t%.4f", CounterElecrodeCurrent);
            //uprintf("\nSubstrate leak. \t%.4f", SubstrateCurrent);
            //uprintf("\nPressure \t\t%.3f dbar", temp_press);
            uprintf("\nController temp \t%.3f C", con_temp);
            uprintf("\nMain Battery \t%.3f V", main_batt_volt);
            uprintf("\nIsolated battery \t%.3f V", iso_batt_volt);
            uprintf("\nFile name \t\t%s\n", sys_data.fileName);
        }

        else    // Print the data in normal or verbose mode
        {
            // console output
            if(sys_data.data_cfg[CFG_SAMPLE_NUM] > 0)       { uprintf("#%07d\t", sys_data.current_sample);  } //0
            if(sys_data.data_cfg[CFG_TIMEDATE] > 0)         { uprintf("%s\t", timestamp);                   } //1
            if(sys_data.data_cfg[CFG_ENV_BAT_VOLT] > 0)     { uprintf("%5.2f\t", main_batt_volt);           } //2
            if(sys_data.data_cfg[CFG_ENV_BRD_TEMP] > 0)     { uprintf("%5.2f\t", con_temp);                 } //3
            if(sys_data.data_cfg[CFG_ENV_HUMIDITY] > 0)     { uprintf("NotSup\t");                          } //4
            if(sys_data.data_cfg[CFG_INT_PRESSURE] > 0)     { uprintf("NotSup\t");                          } //5
            if(sys_data.data_cfg[CFG_V_THERMISTOR] > 0)     { uprintf("%8.6f\t", Vtherm);                   } //6
            if(sys_data.data_cfg[CFG_V_THERMISTOR_STD] > 0) { uprintf("%8.6f\t", Vtherm_std);               } //7
            if(sys_data.data_cfg[CFG_V_INT_OFFSET] > 0)     { uprintf("NotSup\t");                          } //8
            if(sys_data.data_cfg[CFG_V_INT_OFFSET_STD] > 0) { uprintf("NotSup\t");                          } //9
            if(sys_data.data_cfg[CFG_V_EXT_OFFSET] > 0)     { uprintf("NotSup\t");                          } //10
            if(sys_data.data_cfg[CFG_V_EXT_OFFSET_STD] > 0) { uprintf("NotSup\t");                          } //11

            if(sys_data.data_cfg[CFG_V_INT] > 0)            { uprintf("%8.6f\t", Vint);                     } //12
            if(sys_data.data_cfg[CFG_V_INT_STD] > 0)        { uprintf("%8.6f\t", Vint_std);                 } //13
            if(sys_data.data_cfg[CFG_V_EXT] > 0)            { uprintf("%8.6f\t", Vext_ref);                 } //14
            if(sys_data.data_cfg[CFG_V_EXT_STD] > 0)        { uprintf("%8.6f\t", Vext_std);                 } //15
            if(sys_data.data_cfg[CFG_V_COUNTER_ELECT] > 0)  { uprintf("NotSup\t");                          } //16
            if(sys_data.data_cfg[CFG_V_COUNTER_ELECT_STD] > 0)  { uprintf("NotSup\t");                      } //17
            if(sys_data.data_cfg[CFG_I_COUNTER] > 0)        { uprintf("%8.6f\t", CounterElecrodeCurrent);             } //18
            if(sys_data.data_cfg[CFG_I_SUBSTRATE] > 0)      { uprintf("%8.6f\t", SubstrateCurrent);           } //19
            if(sys_data.data_cfg[CFG_CALC_TEMP] > 0)        { uprintf("%6.3f\t", TC);                       } //20
            if(sys_data.data_cfg[CFG_EST_PH_INT] > 0)       { uprintf("%7.6f", pHint);                      } //21
            uprintf("\r\n");
        }
    }
    else
    { // this is the case of txFlg = 0 (use snapshot.txt)

        // store sample in 'last sample file' snapshot.txt
        // Open a file
        fresult = f_open(&fileObject, "snapshot.txt",   FA_CREATE_ALWAYS | FA_WRITE);  // Creates a new file. If the file is existing, it will be truncated and overwritten.
        if(fresult != FR_OK)
        {
            uprintf("f_open error: %s\n", StringFromFresult(fresult));
            error_store("f_open error on snapshot.txt");
        }

        // Store sample to SD card file snapshot.txt (field is turned off when 0, on when 1 or 255)
        if(sys_data.data_cfg[CFG_SAMPLE_NUM] > 0)       { sd_fprintf(&fileObject, "#%07d\t", sys_data.current_sample);  } //0
        if(sys_data.data_cfg[CFG_TIMEDATE] > 0)         { sd_fprintf(&fileObject, "%s\t", timestamp);                   } //1
        if(sys_data.data_cfg[CFG_ENV_BAT_VOLT] > 0)     { sd_fprintf(&fileObject, "%5.2f\t", main_batt_volt);           } //2
        if(sys_data.data_cfg[CFG_ENV_BRD_TEMP] > 0)     { sd_fprintf(&fileObject, "%5.2f\t", con_temp);                 } //3
        if(sys_data.data_cfg[CFG_ENV_HUMIDITY] > 0)     { sd_fprintf(&fileObject, "NotSup\t");                          } //4  HUMIDITY NOT SUPPORTED
        if(sys_data.data_cfg[CFG_INT_PRESSURE] > 0)     { sd_fprintf(&fileObject, "NotSup\t");                          } //5   PRESSURE NOT SUPPORTED
        if(sys_data.data_cfg[CFG_V_THERMISTOR] > 0)     { sd_fprintf(&fileObject, "%8.6f\t", Vtherm);                   } //6
        if(sys_data.data_cfg[CFG_V_THERMISTOR_STD] > 0) { sd_fprintf(&fileObject, "%8.6f\t", Vtherm_std);               } //7
        if(sys_data.data_cfg[CFG_V_INT_OFFSET] > 0)     { sd_fprintf(&fileObject, "NotSup\t");                          } //8   IntRef_WithOffset Not Supported
        if(sys_data.data_cfg[CFG_V_INT_OFFSET_STD] > 0) { sd_fprintf(&fileObject, "NotSup\t");                          } //9   IntRef_WithOffset_std
        if(sys_data.data_cfg[CFG_V_EXT_OFFSET] > 0)     { sd_fprintf(&fileObject, "NotSup\t");                          } //10  ExtRef_WithOffset
        if(sys_data.data_cfg[CFG_V_EXT_OFFSET_STD] > 0) { sd_fprintf(&fileObject, "NotSup\t");                          } //11  ExtRef_WithOffset_std

        if(sys_data.data_cfg[CFG_V_INT] > 0)            { sd_fprintf(&fileObject, "%8.6f\t", Vint);                     } //12
        if(sys_data.data_cfg[CFG_V_INT_STD] > 0)        { sd_fprintf(&fileObject, "%8.6f\t", Vint_std);                 } //13
        if(sys_data.data_cfg[CFG_V_EXT] > 0)            { sd_fprintf(&fileObject, "%8.6f\t", Vext_ref);                 } //14
        if(sys_data.data_cfg[CFG_V_EXT_STD] > 0)        { sd_fprintf(&fileObject, "%8.6f\t", Vext_std);                 } //15
        if(sys_data.data_cfg[CFG_V_COUNTER_ELECT] > 0)  { sd_fprintf(&fileObject, "NotSup\t");                          }      //16   CounterElectrodeVoltage
        if(sys_data.data_cfg[CFG_V_COUNTER_ELECT_STD] > 0)  { sd_fprintf(&fileObject, "NotSup\t");                      }  //17  CounterElectrodeVoltage_std
        if(sys_data.data_cfg[CFG_I_COUNTER] > 0)        { sd_fprintf(&fileObject, "%8.6f\t", CounterElecrodeCurrent);             } //18   counter_leak = CounterElectrodeCurrent
        if(sys_data.data_cfg[CFG_I_SUBSTRATE] > 0)      { sd_fprintf(&fileObject, "%8.6f\t", SubstrateCurrent);           } //19    = SubstrateCurrent
        if(sys_data.data_cfg[CFG_CALC_TEMP] > 0)        { sd_fprintf(&fileObject, "%6.3f\t", TC);                       } //20
        if(sys_data.data_cfg[CFG_EST_PH_INT] > 0)       { sd_fprintf(&fileObject, "%7.6f", pHint);                    } //21
        sd_fprintf(&fileObject, "\n");


        // Close the file
        fresult = f_close( &fileObject );
        if(fresult != FR_OK)
        {
            uprintf("f_close error snapshot.txt: %s\n", StringFromFresult(fresult));
            error_store("f_close error");
        }


    }
    sys_data.current_sample++;  // Increment the sample counter

    // Check for low battery voltage. Exit and sleep if too low.
    if( main_batt_volt < sys_data.low_batt_volt )
    {
        uprintf("\nLow battery voltage (%.2f < %.2f) ! Exiting deploy mode...\n", main_batt_volt, sys_data.low_batt_volt );
        error_store("Low battery! Exited deploy mode");
        sleep(IDLE, 0);     // Sleep until woken by user
    }
}
#endif

#if BOARD_SEAPHOX==1
void fast_sample(int txFlg)
{
    char timestamp[TIMESTAMPLENGTH], buff[80];
    uint32_t timeout;
    struct tm *time_struct;
    float main_batt_volt, iso_batt_volt, con_temp;
    float SBE_sal;          // MicroCAT salinity
    float Vtherm;           // DuraFET raw temperature voltage
    float Vtherm_std;       // Std Dev for Durafet Thermistor
    float Vint;             // DuraFET internal reference voltage
    float Vint_std;         // Std Dev for Durafet Internal Voltage
    float TC;               // Calculated DuraFET temperature
    float Vext_ref;         // External (AUX) reference voltage
    float Vext_std;         // Std Dev for Durafet External Voltage
    float pHext;            // Calculated pH using external reference
    float pHint;            // Calculated pH using internal reference
    float CounterElecrodeCurrent;       // (was counter_leak) DuraFET counter leakage current
    float SubstrateCurrent; // (was substrate_leak) DuraFET substrate leakage current

    // counter_leak is now CounterElectrodeCurrent
    // substrate_leak is now SubstrateCurrent

    FIL fileObject;
    FRESULT fresult;

    // pump is removed from fast sample

//#ifdef NOPUMP
    if(sys_data.test_mode == 1)
        uprintf("\nSampling...");

    // Pump on time
    if(sys_data.test_mode == 1)
        uprintf("\nPump on (test mode)\n");     // Don't want the pump to run in test deployment
    else
        pump_on();

    timeout = ROM_HibernateRTCGet() + sys_data.pumpon_time;

    while(1)
    {
        if( ROM_HibernateRTCGet() <= timeout )
            break;

        ROM_SysCtlDelay(100 * MILLISECOND);
        if( kbhit() && sys_data.output == VERBOSE) uprintf("\nSampling, please wait...");

    }

    pump_off();
    if(sys_data.test_mode == 1) uprintf("Pump off\n");
//#endif


    profile_on(2);          // ----- 800 msec
    //get the time from the RTC
//  ticks = ROM_HibernateRTCGet();
    time_struct = localtime(&sys_data.nextWakeUp);
    strftime(timestamp, sizeof(timestamp),"%Y/%m/%d %H:%M:%S", time_struct);

    profile_on(9);          // ---- 450 msec
    if(ads1248noniso_flg == 1)
        openADS1248_noniso();   // 450 msec - odd, when 400msec delay is changed to 300 msec, profile stays the same at 450msec
    profile_off(9);         // ----

    // NOTE: there is a bug, when the openADS1248_noniso is NOT opened, the thermistor voltage is not read correctly

    profile_on(0);
    openADS1248_iso();      // 52msec    Note: weird that this has the same reset chip and it's not at least 200msec???
    profile_off(0);

    ROM_SysCtlDelay(200 * MILLISECOND);

    ROM_SysCtlDelay(100*MILLISECOND);   // Let instruments and sensors settle (was 800msec)


    SBE_sal = 35;   // Thom added 7May2019 since SBE_sal is commented out and pHext (below) relies on it

    main_batt_volt = 12.0;
    if(ads1248noniso_flg == 1)
    {
        if(sys_data.data_cfg[CFG_ENV_BRD_TEMP] > 0)
            con_temp = controller_temp();       // 200 msec
        //if(sys_data.data_cfg[CFG_ENV_BAT_VOLT] > 0)  // MUST sample battery voltage for check if too low below
        main_batt_volt = batt_volt();       // 200 msec
    }

    profile_off(2);         // -----------

    //------------- Read the isolated sensors -----------------------


    if(sys_data.data_cfg[CFG_V_THERMISTOR] > 0)
    {
        profile_on(3);          // --- 100 msec
        Vtherm = pollADS1248_iso(0, 6, sys_data.sample_average, 1, 20);
        Vtherm_std = sys_data.AD24_std;
        profile_off(3);         // ----
    }

    if(sys_data.data_cfg[CFG_V_INT] > 0)
    {
        profile_on(4);          // --- 100 msec
        Vint = pollADS1248_iso(1, 6, sys_data.sample_average, sys_data.Vint_gain, 20); // sps used to be sys_data.Vint_sps YT
        Vint_std = sys_data.AD24_std;
        profile_off(4);         // ---
    }

    if(sys_data.data_cfg[CFG_V_EXT] > 0)
    {
        profile_on(5);          // --- 100 msec
        Vext_ref = pollADS1248_iso(4, 6, sys_data.sample_average, 1, 20);
        Vext_std = sys_data.AD24_std;
        profile_off(5);         // -----
    }


// THOM - TODO there is no config for iso batt
    profile_on(6);              // ---- 50 msec
    iso_batt_volt = batt_volt_iso();
    profile_off(6);             // ----
    //CounterElecrodeCurrent = pollADS1248_iso(3, 2, 1, 1, 5);        // Chan 3-2, 1 trial, gain = 1, sps = 5 Hz
    //SubstrateCurrent = pollADS1248_iso(7, 6, 1, 1, 5);  // Chan 7-6, 1 trial, gain = 1, sps = 5 Hz
    CounterElecrodeCurrent = 0.0;  // added 25 Apr 2019
    SubstrateCurrent = 0.0; // added 25 Apr 2019


    // Shutdown sensors
    //profile_on(7);          // ---- 14 usec
    closeADS1248_noniso();  // ----- 14 usec for the two fxn
    closeADS1248_iso();     // -----
    //profile_off(7);         // ----

    // Calculate the external and internal pH values

    if(sys_data.data_cfg[CFG_CALC_TEMP] > 0)
    {
        TC = DuraFET_temp(Vtherm, 0);   //sys_data.TCOffset);

        pHext = calc_pHext(Vext_ref, TC, SBE_sal);      // SBE_sal is set or sampled above
        pHint = calc_pHint(Vint, TC);
    }

    //profile_on(8);         // --- 12 msec to 17 msec
    // Open a file
    fresult = f_open(&fileObject, sys_data.fileName, FA_READ |FA_WRITE |FA_OPEN_ALWAYS);
    if(fresult != FR_OK)
    {
        uprintf("f_open error: %s\n", StringFromFresult(fresult));
        error_store("f_open error");
    }

    // Seek to the end, to append our file
    fresult = f_lseek(&fileObject, fileObject.fsize);
    if(fresult != FR_OK)
    {
        uprintf("f_lseek error: %s\n", StringFromFresult(fresult));
        error_store("f_lseek error");
    }


    // Store sample to SD card file (field is turned off when 0, on when 1 or 255)
    if(sys_data.data_cfg[CFG_SAMPLE_NUM] > 0)       { sd_fprintf(&fileObject, "#%07d\t", sys_data.current_sample);  } //0
    if(sys_data.data_cfg[CFG_TIMEDATE] > 0)         { sd_fprintf(&fileObject, "%s\t", timestamp);                   } //1
    if(sys_data.data_cfg[CFG_ENV_BAT_VOLT] > 0)     { sd_fprintf(&fileObject, "%5.2f\t", main_batt_volt);           } //2
    if(sys_data.data_cfg[CFG_ENV_BRD_TEMP] > 0)     { sd_fprintf(&fileObject, "%5.2f\t", con_temp);                 } //3
    if(sys_data.data_cfg[CFG_ENV_HUMIDITY] > 0)     { sd_fprintf(&fileObject, "NotSup\t");                          } //4  HUMIDITY NOT SUPPORTED
    if(sys_data.data_cfg[CFG_INT_PRESSURE] > 0)     { sd_fprintf(&fileObject, "NotSup\t");                          } //5   PRESSURE NOT SUPPORTED
    if(sys_data.data_cfg[CFG_V_THERMISTOR] > 0)     { sd_fprintf(&fileObject, "%8.6f\t", Vtherm);                   } //6
    if(sys_data.data_cfg[CFG_V_THERMISTOR_STD] > 0) { sd_fprintf(&fileObject, "%8.6f\t", Vtherm_std);               } //7
    if(sys_data.data_cfg[CFG_V_INT_OFFSET] > 0)     { sd_fprintf(&fileObject, "NotSup\t");                          } //8   IntRef_WithOffset Not Supported
    if(sys_data.data_cfg[CFG_V_INT_OFFSET_STD] > 0) { sd_fprintf(&fileObject, "NotSup\t");                          } //9   IntRef_WithOffset_std
    if(sys_data.data_cfg[CFG_V_EXT_OFFSET] > 0)     { sd_fprintf(&fileObject, "NotSup\t");                          } //10  ExtRef_WithOffset
    if(sys_data.data_cfg[CFG_V_EXT_OFFSET_STD] > 0) { sd_fprintf(&fileObject, "NotSup\t");                          } //11  ExtRef_WithOffset_std

    if(sys_data.data_cfg[CFG_V_INT] > 0)            { sd_fprintf(&fileObject, "%8.6f\t", Vint);                     } //12
    if(sys_data.data_cfg[CFG_V_INT_STD] > 0)        { sd_fprintf(&fileObject, "%8.6f\t", Vint_std);                 } //13
    if(sys_data.data_cfg[CFG_V_EXT] > 0)            { sd_fprintf(&fileObject, "%8.6f\t", Vext_ref);                 } //14
    if(sys_data.data_cfg[CFG_V_EXT_STD] > 0)        { sd_fprintf(&fileObject, "%8.6f\t", Vext_std);                 } //15
    if(sys_data.data_cfg[CFG_V_COUNTER_ELECT] > 0)  { sd_fprintf(&fileObject, "NotSup\t");                          }      //16   CounterElectrodeVoltage
    if(sys_data.data_cfg[CFG_V_COUNTER_ELECT_STD] > 0)  { sd_fprintf(&fileObject, "NotSup\t");                      }  //17  CounterElectrodeVoltage_std
    if(sys_data.data_cfg[CFG_I_COUNTER] > 0)        { sd_fprintf(&fileObject, "%8.6f\t", CounterElecrodeCurrent);             } //18   counter_leak = CounterElectrodeCurrent
    if(sys_data.data_cfg[CFG_I_SUBSTRATE] > 0)      { sd_fprintf(&fileObject, "%8.6f\t", SubstrateCurrent);           } //19    = SubstrateCurrent
    if(sys_data.data_cfg[CFG_CALC_TEMP] > 0)        { sd_fprintf(&fileObject, "%6.3f\t", TC);                       } //20
    if(sys_data.data_cfg[CFG_EST_PH_INT] > 0)       { sd_fprintf(&fileObject, "%7.6f", pHint);                    } //21
    sd_fprintf(&fileObject, "\n");


    // Close the file
    fresult = f_close( &fileObject );
    if(fresult != FR_OK)
    {
        uprintf("f_close error: %s\n", StringFromFresult(fresult));
        error_store("f_close error");
    }
    //profile_off(8);

    //profile_on(9);          // ---- 1 msec
    if(txFlg == 1)
    {
        // Print the configured sample

        // console output
        if(sys_data.data_cfg[CFG_SAMPLE_NUM] > 0)       { uprintf("#%07d\t", sys_data.current_sample);  } //0
        if(sys_data.data_cfg[CFG_TIMEDATE] > 0)         { uprintf("%s\t", timestamp);                   } //1
        if(sys_data.data_cfg[CFG_ENV_BAT_VOLT] > 0)     { uprintf("%5.2f\t", main_batt_volt);           } //2
        if(sys_data.data_cfg[CFG_ENV_BRD_TEMP] > 0)     { uprintf("%5.2f\t", con_temp);                 } //3
        if(sys_data.data_cfg[CFG_ENV_HUMIDITY] > 0)     { uprintf("NotSup\t");                          } //4
        if(sys_data.data_cfg[CFG_INT_PRESSURE] > 0)     { uprintf("NotSup\t");                          } //5
        if(sys_data.data_cfg[CFG_V_THERMISTOR] > 0)     { uprintf("%8.6f\t", Vtherm);                   } //6
        if(sys_data.data_cfg[CFG_V_THERMISTOR_STD] > 0) { uprintf("%8.6f\t", Vtherm_std);               } //7
        if(sys_data.data_cfg[CFG_V_INT_OFFSET] > 0)     { uprintf("NotSup\t");                          } //8
        if(sys_data.data_cfg[CFG_V_INT_OFFSET_STD] > 0) { uprintf("NotSup\t");                          } //9
        if(sys_data.data_cfg[CFG_V_EXT_OFFSET] > 0)     { uprintf("NotSup\t");                          } //10
        if(sys_data.data_cfg[CFG_V_EXT_OFFSET_STD] > 0) { uprintf("NotSup\t");                          } //11

        if(sys_data.data_cfg[CFG_V_INT] > 0)            { uprintf("%8.6f\t", Vint);                     } //12
        if(sys_data.data_cfg[CFG_V_INT_STD] > 0)        { uprintf("%8.6f\t", Vint_std);                 } //13
        if(sys_data.data_cfg[CFG_V_EXT] > 0)            { uprintf("%8.6f\t", Vext_ref);                 } //14
        if(sys_data.data_cfg[CFG_V_EXT_STD] > 0)        { uprintf("%8.6f\t", Vext_std);                 } //15
        if(sys_data.data_cfg[CFG_V_COUNTER_ELECT] > 0)  { uprintf("NotSup\t");                          } //16
        if(sys_data.data_cfg[CFG_V_COUNTER_ELECT_STD] > 0)  { uprintf("NotSup\t");                      } //17
        if(sys_data.data_cfg[CFG_I_COUNTER] > 0)        { uprintf("%8.6f\t", CounterElecrodeCurrent);             } //18
        if(sys_data.data_cfg[CFG_I_SUBSTRATE] > 0)      { uprintf("%8.6f\t", SubstrateCurrent);           } //19
        if(sys_data.data_cfg[CFG_CALC_TEMP] > 0)        { uprintf("%6.3f\t", TC);                       } //20
        if(sys_data.data_cfg[CFG_EST_PH_INT] > 0)       { uprintf("%7.6f", pHint);                      } //21
        uprintf("\r\n");

    }
    //profile_off(9);

    sys_data.current_sample++;  // Increment the sample counter

    // Check for low battery voltage. Exit and sleep if too low.
    if( main_batt_volt < sys_data.low_batt_volt )
    {
        uprintf("\nLow battery voltage (%.2f < %.2f) ! Exiting deploy mode...\n", main_batt_volt, sys_data.low_batt_volt );
        error_store("Low battery! Exited deploy mode");
        sleep(IDLE, 0);     // Sleep until woken by user
    }

    //profile_off(8);

}
#endif

/*
 * error_store()
 * Stores error messages with timestamp.
 * Appends a newline character to message.
 * Function is useful during deployment when console is disconnected
 * RCG 5/14
 */
void error_store(const char *error_buff)
{
	char timestamp[TIMESTAMPLENGTH];
	uint32_t ticks;
	struct tm *time_struct;
	FIL fil;		// File object
	FRESULT fresult;
	UINT bw;

	// Open a file
	fresult = f_open(&fil, "Error.txt", FA_WRITE |FA_OPEN_ALWAYS);
	if(fresult != FR_OK)
	{
		uprintf("Error.txt f_open error: %s\n", StringFromFresult(fresult));
	}

	// Seek to the end, to append our file
	fresult = f_lseek(&fil, fil.fsize);
	if(fresult != FR_OK)
	{
		uprintf("Error.txt f_lseek error: %s\n", StringFromFresult(fresult));
	}

	// Write timestamp to file
	ticks = ROM_HibernateRTCGet();
	time_struct = localtime(&ticks);
	strftime(timestamp, sizeof(timestamp),"\n%Y/%m/%d %H:%M:%S ", time_struct);

	fresult = f_write( &fil, timestamp, strlen(timestamp), &bw );
	if(fresult != FR_OK)
	{
		uprintf("Error.txt f_write error: %s\n", StringFromFresult(fresult));
	}

	// Write error message to file
	fresult = f_write( &fil, error_buff, strlen(error_buff), &bw );
	if(fresult != FR_OK)
	{
		uprintf("Error.txt f_write error: %s\n", StringFromFresult(fresult));
	}

	// Close the file
	fresult = f_close( &fil );
	if(fresult != FR_OK)
	{
		uprintf("Error.txt f_close error: %s\n", StringFromFresult(fresult));
	}

}



// profileTarget is a global variable set programmatically
void profile_toggle(int target)
{
    if(target == profileTarget)
    {
        if(ledRedState == 0)
            led_red_on();
        else
            led_red_off();
    }
}


void profile_off(int target)
{
    if(target == profileTarget)
    {
        led_red_off();
    }
}


void profile_on(int target)
{
    if(target == profileTarget)
    {
        led_red_on();
    }
}

void led_red(int state)
{
    if(state == 0)
        led_red_off();
    else
        led_red_on();
}

void led_red_toggle(void)
{
    if(ledRedState == 0)
        led_red_on();
    else
        led_red_off();
}

void led_red_off(void)
{
    ROM_GPIOPinWrite(GPIO_PORTP_BASE, GPIO_PIN_2, 0x00);    // Red LED off
    ledRedState = 0;
}

void led_red_on(void)
{
    ROM_GPIOPinWrite(GPIO_PORTP_BASE, GPIO_PIN_2, 0xFF);    // Red LED off
    ledRedState = 1;
}

// PORTE.3

void profile2_toggle(int target)
{
    if(target == profile2Target)
    {
        if(ledGreenState == 0)
            led_green_on();
        else
            led_green_off();
    }
}


void profile2_off(int target)
{
    if(target == profile2Target)
    {
        led_green_off();
    }
}


void profile2_on(int target)
{
    if(target == profile2Target)
    {
        led_green_on();
    }
}


void led_green(int state)
{
    if(state == 0)
        led_green_off();
    else
        led_green_on();
}

void led_green_toggle(void)
{
    if(ledGreenState == 0)
        led_green_on();
    else
        led_green_off();
}

void led_green_off(void)
{
    ROM_GPIOPinWrite(GPIO_PORTE_BASE, GPIO_PIN_3, 0x00);    // LED off
    ledGreenState = 0;
}

void led_green_on(void)
{
    ROM_GPIOPinWrite(GPIO_PORTE_BASE, GPIO_PIN_3, 0xFF);    // LED on
    ledGreenState = 1;
}


//*****************************************************************************
//
// The error routine that is called if the driver library encounters an error.
//
//*****************************************************************************
#ifdef DEBUG
void
__error__(char *pcFilename, uint32_t ui32Line)
{
}
#endif









