/*
 * MBARI software for MFET, MpHOx and NanoFET boards, derived from Scripps Institute
 *     SeapHOx software for Rev-E PC board Version 2.0
 *
 * David Muller, davehmuller@gmail.com
 * Germán Alfaro, alfaro.germanevera@gmail.com
 * Rob Glatts, rglatts@ucsd.edu (from 4/2014)
 * Taylor Wirth, twirth@ucsd.edu (from 4/2015)
 *
 * Thom Maughan (TM), MBARI, tm@mbari.org (from 2/2018)
 *
 * v3.1.2:  deployment for Ischia
 * v3.1.3:  interim version, decided to roll to v3.1.4 for Glider and Cleanup
 * v3.1.4:  added configuration of data fields in get_sample, added get_header (gh) command  14 Aug 2018
 * v3.1.5:  glider deployment  Nov 2018  added 'sl' command and 'ts'   sl (send last) uses uSD to cache sample.  This makes the glider code simpler.
 * v3.1.6   glider deployment with mods to workaround power glitching (if sample period is 0, and power cycled, start in deployed mode)
 * v3.1.7:  Update fatfs to fix 'debug' build crash.  8 Feb 2019, Fix in ff.c (uninitialized FatFs[0] pointer in Debug Build.  Release relies on linker init of pointer
 * v3.2.0:  Bug fixes (spurious serial wakeup, aligned to hour default, var headers data cfg), bring SEAPHOX up to the same state as MFET.  29 Apr 2019 TM
 * v3.2.1:  Interim build tag, reduction of delays to improve sample request-response time and to reduce power.  Identified eeprom writecycle (500K) bug - eeprom being written on each sample
 * v3.2.2:  Project named changed from SeaFET_SeapHOx to SeapHOx_MFET.   Using register file in hibernate module to store volatile data in config struct to prevent eeprom burn out
 * v3.3.0:  Adding support for MFETrevB/MCAPrevC  1) different rs232 xcvr (MAX2333) so EN# and SHUTD#,  2) i2c_fram.c basic driver, 3) optode (has bug in ring buffer)
 * v3.3.1:  fram support for nonvolatile data (sequence number, etc) tested on MFET v2.  Sep 2019
 * v3.4:    restructuring code, removing SEAPHOX support, supporting MFET,MPHOX and starting support for nanoFET, added conductivity sensor to AUX1
 * refactored uart support, split main.c into main.c, test.c config.c (4500+ lines to managable)
 */
// NOTE: // VERSION is defd in system.h

// BUGS in v3.3.1
//  1) ring buffer for optode - is ok during datalogging as it does not wrap the buffer
//  2) battery voltage reading in fast_sample reads low, 5.8v reads as 5.05v - likely due to too little settling time after switching on battery voltage.  12.11v reads as 12.11v so it's something that happens with lower voltages.


// mA-Hr * Volts * 3.6 = Joules
// pH sampling  12.0v @ 14.5mA for 1.2seconds => 0.2 Joules

#include "System.h"
#include "Init.h"
#include "test.h"
#include "config.h"

#include "user_IO.h"
#include "SDCard.h"
#include "fatfs/src/ff.h"
#include "ADS1248_iso.h"
#include "ADS1248_noniso.h"
#include "Sleep.h"
#include "AUX1.h"
#include "AUX2.h"
#include "uartstdio.h"

// Force a compile error if more than one board is =1
//#if (BOARD_NANOFET==1 && BOARD_MFET>=1 && BOARD_MPHOX==1) || (BOARD_NANOFET==0 && BOARD_MFET==0)
//    PROBLEM  Right click project->properties, Build->Compiler->Predefine Symbols and define only one BOARD_XXX=1
//#endif

// move to test.c



//extern unsigned long Timer_10ms(bool reset);

//extern void print_bias_volt_iso(void);
//extern uint32_t storeSysDataVariables(void);

//int test_sampling_mcap(float extRefOff, float intRefOff, float extRefV, float intRefV, float cntrC, float cntrV, float substCur, float substV, float thermistor);

void exec_main_menu(void);
void print_main_menu(void);

//void adc_onchip_init(void);
//uint16_t * read_all_adc(void);
void state_dump(void);


void deploy(deploy_state state);


void print_help(void);

//void display_ph_ref_therm_volts(void);


/*
 * Global System variables.
 */
extern uint32_t adc_data[];
extern char Optode_buff[];
extern float fBiasPos;  // used for read_bias_bat();
extern float fBiasNeg;

struct systemData sys_data;
struct systemDataVolatile sys_data_vol;
struct systemDataVolatile sys_data_chg;         // used to write to hibernate module battery backed register file


int dbg_flag = 0;                 // global var used for dbg_printf
//int profileTarget = 0;
//int profile2Target = 0;
int ads1248noniso_flg = 0;

int microSD_flg = 1;            // 0 or 1, quick hack for nsFOCE added 20 Jan 2021, enable/disable logging to microSD.   Move this to Config later.

unsigned int deployDelay = 30;      // 30 sec timeout

extern char sampBuf[];     // for sl command

/*
 * main.c
 */

int main(void)
{

	init();		// Initialize pins and ports  // 425 usec  (removed 400 msec delay)

	// Symbols for board builds are define in Project Properties (right click project, Select properties,
	// then select Build->ARM Compiler->Predefined Symbols.  Edit the BOARD_XXX and define = 1.  Only 1 board
	// should be =1, the deselected board is =0
#if BOARD_SEAPHOX == 1
    dbg_printf("\n***** BOARD_SEAPHOX = 1 *****\n");        // 100usec
#endif
#if BOARD_MFET == 1
    dbg_printf("\n***** BOARD_MFET = 1 *****\n");
#endif
#if BOARD_MFET == 2
    dbg_printf("\n***** BOARD_MFET = 2 *****\n");
#endif
#if BOARD_MPHOX == 1
    dbg_printf("\n***** BOARD_MpHOx = 1 *****\n");
#endif
#if BOARD_NANOFET == 1
    dbg_printf("\n***** BOARD_NANOFET = 1 *****\n");
#endif

    /*  Thoms notes on top level statemachine:  the code needs refactoring as it is too challenging to make changes
     *
     * Re-write of the top level state machine as it is layered with quick fixes and is getting difficult to implement changes
     * without side effects
     *
     * SLEEP/IDLE - state for a pre-deployment system
     *    - woke up by serial or reset switch
     * DEPLOY - after configuration of sampling parameters, this is the lower power state woke by
     *     A) real time clock based on sampling period
     *     B) when sampling period = 0, it is in polled mode and responds to 'ts' or 'sl'   STOP to get it out of sampling mode
     *
     * Use Cases:
     *    LABINSTRUMENT - wired, power cycled at times, typically polled. does not need to log to uSD.
     *    DATALOGGER - battery powered, self timed RTC based logging to uSD, insure the battery does not get too low to prevent uSD corruption
     *    'GLIDER" - power is being cycled.  power on, polled get_sample, save to uSD, respond to ts, sleep.  When the glider is on a down cast, power is turned off
     *
     *
     * MENU - state for setup and testing with user interface provided through the console port
     *    - times out and returns to previous state (SLEEP or DEPLOY).
     *    - Test is part of the menu state
     *    - MENU is not a state that is stored in sys_dataq
     *
     *    The question is, when a key is hit, the app wakes up,
     *      if nothing is commanded,
     *      then it should go back to the state it was in (SLEEP or DEPLOY) within a few seconds
     *
     *    if the menu key is hit (m, M, h, H, or <ENTER>) then the menu is displayed and the return to state it was in time should be 30 seconds (maybe even a minute)
     *      if the user changes the state in the menu, then this state gets stored in sys_data.state and off the app goes in that mode
     *
     *    Polled mode is achieved by a sample_period of 0, this could also be what makes it 'sleep'.   Deploy would then ask - polled or timed?
     *
     */

    //sys_data.state = IDLE;  /// FUCKING SHIT
    while(1)        // this while(1) handles state change in exec_main_menu
    {
        switch(sys_data.state)
        {
            case DEPLOYED:      // RTC wakeup sampling period
                dbg_printf("\ncalling deploy(DEPLOYED)\n");
                deploy(DEPLOYED);
                //state_dump();       // DEBUG
                // deploy(DEPLOYED) should not return, pwrOff/sleep is called
                break;

            case COMMAND:       // serial command sampling (period=0)
                dbg_printf("\ncalling deploy(COMMAND)\n");
                deploy(COMMAND);
                // deploy(COMMAND) should not return, pwrOff/sleep is called
                break;

            case IDLE:
                dbg_printf("\nstate = IDLE\n");
            default:
                if(sys_data.state != IDLE)
                    uprintf("ERROR in sys_data.state = %u", sys_data.state);
                sys_data.state = IDLE;
                exec_main_menu();
                break;
        }

    }

}


void exec_main_menu(void)
{
    char input;
    time_t timer;

   // while(1) //added while loop for user to choose command or enter deployment automatically --1/24/2017 -TW
   //     {
        //uprintf("\n*****Press enter to bring up main menu*****\n");
        //print_main_menu();


    while(1)
    {
        print_main_menu();

        // Get user's selection with a 30 sec timeout - enter deployment mode --1/24/2017 -TW
        UARTFlushRx();

        timer = deployDelay + ROM_HibernateRTCGet(); // 30 second delay | timer = 300 + ROM_HibernateRTCGet();

        while(1)
        {
            if( UARTRxBytesAvail() )
            {
                input = get_key();
                break;    // break from while(1)
            }

            if( timer <= ROM_HibernateRTCGet() )
            {
                // THOM 23Apr2019 - timeout on menu is resulting in a big when SP is in sleep and a spurious character wakes it up, this results in 'deploy'
                 //deploy(START); //enter deployment mode | if( timer <= ROM_HibernateRTCGet() ) sleep(IDLE, 0);
                switch(sys_data.state)
                {
                    case DEPLOYED:      // RTC wakeup sampling period
                        // if woke up by spurious character and was deployed, got back to sleep
                        dbg_printf("\n***** D E P L O Y (was deployed, stay deployed) *****\n");  // THOM DEBUG
                        deploy(DEPLOYED);  // THOM new 7May2019
                        break;

                    case COMMAND:       // serial command sampling (period=0)
                        deploy(COMMAND);  // THOM new 12Apr2021
                        break;

                    case START:         // This state should never happen (I hope). 12Apr2021
                        deploy(START);
                        break;

                    case IDLE:
                    default:
                        dbg_printf("\n***** SLEEP *****\n");  // THOM DEBUG
                        sleep(IDLE, 0);
                        break;
                }
#ifdef NOCODE
                if(sys_data.state == IDLE)
                {
                    dbg_printf("\n***** SLEEP *****\n");  // THOM DEBUG
                    sleep(IDLE, 0);
                }
                if (sys_data.state == DEPLOYED)
                {
                    // if woke up by spurious character and was deployed, got back to sleep
                    dbg_printf("\n***** D E P L O Y (was deployed, stay deployed) *****\n");  // THOM DEBUG
                    deploy(DEPLOYED);  // THOM new 7May2019
                }
                else            // if (sys_data.state == DEPLOY)
                {
                    // THOM TODO - what about COMMAND???   START seems wrong

                    dbg_printf("\n***** D E P L O Y  (and write header) *****\n");  // THOM DEBUG
                    deploy(START);      // THOM this causes the header to be written
                }
#endif
            }  // end of if(timeout)

        } // end of while(1) looking for key and timeout


        switch(input)
        {
            case '1':
                configuration_menu();
                break;

            case '2':
                deploy(START);
                break;

            case '3':
                test_menu();
                break;

            case '4':
                sleep(IDLE, 0);
                break;

            case '5':
                viewFiles();
                break;

            case 'h':
            case 'H':
                print_help();
#ifdef NOCODE
                uprintf("\n\nVersion -- %s, %s \n ", VERSION, NONVOLATILEMEM);      // VERSION is defd in system.h
#if BOARD_MFET >= 1
                uprintf("\nMFET Power Consumption per Sample = ~0.2 Joules per sample:  12v, 1.2sec, ~14.5mA => 12 * 14.5 * (1.2 / 3600) * 3.6 = ~0.2 Joules\n\n");
#endif
#if BOARD_MPHOX == 1
                uprintf("\nMPHOX Power Consumption per Sample = TBD\n\n");
#endif
#if BOARD_NANOFET >= 1
                uprintf("\nNANOFET Power Consumption per Sample = TBD\n\n");
#endif
                uprintf("\n\n--------- Configuration --------------\n");
                uprintf("\nConfiguration checklist: (use Main Menu 1--Configure)\n");
                uprintf("\n1 -- Set Clock");
                uprintf("\n2 -- Change File Name");
                uprintf("\n3 -- Set Deployment Parameters");
                uprintf("\n        - Sample aligned to hour? (Y/N) [Y]?");
                uprintf("\n        - Enter sample period [20] sec:   Polled Mode: configure with a period of 0 seconds");
                //uprintf("\n       Enter pH sample average [5] samples:");
                uprintf("\n        - Enter pump on time [0] sec:");
                uprintf("\n        - Enter low battery_voltage (10.5 V for SeapHOx, 5.5 V for MFET) [5.5 V]:");
                uprintf("\n4 -- Enter pH Sensor Calibration Coefficients");
                uprintf("\n7 -- Config Data Fields");
                uprintf("\n");
                ROM_SysCtlDelay(MILLISECOND*300);  // tx buffer before filling with more
                uprintf("\n\n------ Deployment Mode commands ------\n");
                uprintf("\nany character to wake, then issue command:\n");
                uprintf("\nstop  -- stop sampling, exit deployment mode");
                uprintf("\ngdata -- get data since last command");
                uprintf("\nts    -- take sample with 1.2 sec response time");
                uprintf("\nss    -- start sample followed by 'sl' command to send last sample, times out after 8 sec");
                uprintf("\ngh    -- get header");
                uprintf("\n");
                uprintf("\n");
#endif
                break;

            default:
                // if an invalid char is received, then
                break;
        }  // end of switch


    }
    //} // while(1)

}

void print_main_menu(void)
{
    // Print out the menu:
    uprintf("\n\n\nMain Menu -- %s -- Will sleep in %u seconds", VERSION, deployDelay);      // VERSION is defd in system.h

    uprintf("\n1 -- Configure");
    uprintf("\n2 -- Deploy");
    uprintf("\n3 -- Test");
    uprintf("\n4 -- Sleep");
    uprintf("\n5 -- Files");
    uprintf("\nH -- Help");
    uprintf("\nEnter Selection: ");
}


void print_help(void)
{

    uprintf("\n\nVersion -- %s, %s \n ", VERSION, NONVOLATILEMEM);      // VERSION is defd in system.h
#if BOARD_MFET >= 1
    uprintf("\nMFET Power Consumption per Sample = ~0.2 Joules per sample:  12v, 1.2sec, ~14.5mA => 12 * 14.5 * (1.2 / 3600) * 3.6 = ~0.2 Joules\n\n");
#endif
#if BOARD_MPHOX == 1
    uprintf("\nMPHOX Power Consumption per Sample = TBD\n\n");
#endif
#if BOARD_NANOFET >= 1
    uprintf("\nNANOFET Power Consumption per Sample = TBD\n\n");
#endif
    uprintf("\n\n--------- Configuration --------------\n");
    uprintf("\nConfiguration checklist: (use Main Menu 1--Configure)\n");
    uprintf("\n1 -- Set Clock");
    uprintf("\n2 -- Change File Name");
    uprintf("\n3 -- Set Deployment Parameters");
    uprintf("\n        - Sample aligned to hour? (Y/N) [Y]?");
    uprintf("\n        - Enter sample period [20] sec:   Polled Mode: configure with a period of 0 seconds");
    //uprintf("\n       Enter pH sample average [5] samples:");
    uprintf("\n        - Enter pump on time [0] sec:");
    uprintf("\n        - Enter low battery_voltage (10.5 V for SeapHOx, 5.5 V for MFET) [5.5 V]:");
    uprintf("\n4 -- Enter pH Sensor Calibration Coefficients");
    uprintf("\n7 -- Config Data Fields");
    uprintf("\n");
    ROM_SysCtlDelay(MILLISECOND*300);  // tx buffer before filling with more
    uprintf("\n\n------ Deployment Mode commands ------\n");
    uprintf("\nany character to wake, then issue command:\n");
    uprintf("\nstop  -- stop sampling, exit deployment mode");
    uprintf("\ngdata -- get data since last command");
    uprintf("\nts    -- take sample with 1.2 sec response time");
    uprintf("\nss    -- start sample followed by 'sl' command to send last sample, times out after 8 sec");
    uprintf("\ngh    -- get header");
    uprintf("\n");
    uprintf("\n");
    ROM_SysCtlDelay(MILLISECOND*300);  // tx buffer before filling with more

    uprintf("\n\n------ DuraFET Voltage Wisdom ------\n");
    uprintf("\nVtherm:        ~1.1V at 20C");
    uprintf("\nVrsi:          Internal reference pH in seawater: ~-0.9V. In original buffer solution: ~-1.1V");
    uprintf("\nVrsi Offset:   Electrical bias so that 7pH is 0V");
    uprintf("\nVrsi std:      Standard deviation should be < 50uV, typical is ~20uV");
    ROM_SysCtlDelay(MILLISECOND*300);  // tx buffer before filling with more
    uprintf("\nVrse:          External reference pH in seawater: TBD (DeepSea Durafet only) ");
    uprintf("\nVk:            Between -1.5 and -0.7, expected to move around");
    uprintf("\nIk:            15uV/nA + amplifier offset (~800uV).  Should be < ~20uA");
    uprintf("\nIb:            1mV/nA.   Should be < 10uA");
    uprintf("\n");
    uprintf("\n");

    ROM_SysCtlDelay(MILLISECOND*1000);  // tx buffer before filling with more

}


// Thom TODO this is used for sl command, need to fix this hack
int print_sampBuf(void)
{
    return(uprintf("%s", sampBuf));
}


/*
 * exec_command() is the execution loop for serial command processing
 */

void exec_command(void)
{
    //time_t start_time;
    int charCount, gdata, ts, stop, dump, samp_byte, gh, gm, sl, ss;  //, to, tc;   // to, tc added for Dale Graves nsFOCE Jan 2020 Thom
    char buff[81];
    FIL fileObject;
    FRESULT fresult;
    UINT br;
    bool line_end;
    time_t current_time;        // new

    while(1)    // Command loop
    {
        if(sys_data.output == VERBOSE || sys_data.test_mode) uprintf("\nEnter command (ts, ss, gh, gdata, stop): ");

        //flush the receive and transmit buffers
        UARTFlushRx();

        // Wait for command for 10 seconds
        charCount = getUserInputTimeLimit(buff, sizeof(buff), 10);

        // If the time limit passed...
        if(charCount == TIMELIMITPASSED)
        {
            if(sys_data.output == VERBOSE) uprintf("\n\nNo command, resuming deployment...");
            break;
        }
        else
        {
            // Parse command
            gdata = strncmp(buff, "gdata", 5);      // get data
            ts = strncmp(buff, "ts", 2);            // take sample
            ss = strncmp(buff, "ss", 2);            // start sample, needs to have sl
            //sl = strncmp(buff, "sl", 2);            // send last sample, must have sent ss first
            gh = strncmp(buff, "gh", 2);            // get data header
            gm = strncmp(buff, "gm", 2);            // get metadata header
            stop = strncmp(buff, "stop", 4);        // stop deployment (sampling)
            dump = strncmp(buff, "dump", 4);        // dump
            //to = strncmp(buff, "to", 2);   //#0000000    08/29/2019 15:14:17  8.55   25.75    59 1.025509    0.000062    -1.212960   0.000011    -1.000950   0.000011    0.000832    -0.000842   23.805  5730    1565    218.137 99.939  24.118  29.860  29.860  37.342  7.482   751.9   780.1   108.4
            //tc = strncmp(buff, "tc", 2);


            if( (gdata == 0) && (microSD_flg == 1) )    // Display samples since last gdata command
            {
                UARTEchoSet(false);     // Turn off console echo so key hit doesn't mess up screen output


                // Open a file
                fresult = f_open(&fileObject, sys_data.fileName, FA_READ|FA_OPEN_ALWAYS);
                if(fresult != FR_OK)
                {
                    uprintf("Error.txt f_open error: %s\n", StringFromFresult(fresult));
                }

                // Seek to the next byte in data file since last gdata
                fresult = f_lseek(&fileObject, sys_data.next_gdata_fptr);
                if(fresult != FR_OK)
                {
                    uprintf("Error.txt f_lseek error: %s\n", StringFromFresult(fresult));
                }

                // Print out the records
                line_end = false;

                do
                {
                    fresult = f_read(&fileObject, buff, 80, &br);
                    if(fresult != FR_OK)
                    {
                        uprintf("Error.txt f_read error: %s\n", StringFromFresult(fresult));
                    }

                    buff[br] = '\0';

                    // Wait till there is room in tx buffer, then print the buffer
                    while( UARTTxBytesFree() <= 80 );
                    uprintf("%s", buff);

                    // Stop reading and printing if user hits key
                    if(kbhit())
                    {
                        // Print out any remaining characters of the last sample
                        do
                        {
                            fresult = f_read(&fileObject, buff, 80, &br);
                            {
                                uprintf("Error.txt f_read error: %s\n", StringFromFresult(fresult));
                            }

                            for(samp_byte = 0; samp_byte < br; samp_byte++)
                            {
                                uprintf("%c", buff[samp_byte]);

                                if( buff[samp_byte] == '\n' )   // Look for the end of the line
                                {
                                    line_end = true;
                                    break;
                                }
                            }
                        } while(br == 80 && !line_end);

                        break;
                    }

                } while (br == 80 && !line_end);        // Keep doing this until the end of the file

                sys_data.next_gdata_fptr = fileObject.fptr;     // Store the current file position for next gdata command
                UARTEchoSet(true);                              // Turn console echo back on
            }

            // Take a sample and continue with deployment
            else if( ts == 0 )
            {
                //profile_on(8);
#ifdef NOCODE
                sys_data.state = DEPLOYED;
                if(sys_data.sampling_period == 0)   // THOM Polled Mode
                    sys_data.state = COMMAND;      // THOM NEW - use command mode to stop RTC wakeup (polled mode)
#endif


                //get_sample(1);
                fast_sample(1);     // new fast sampling - replaced get_sample per Yui Jun 2019
                if(sys_data.state == IDLE)
                    sleep(IDLE, 0);
                if(sys_data.state == COMMAND)
                    sleep(COMMAND, 0);
                //sleep(sys_data.state, 0);  // for COMMAND and IDLE   THOM TODO - resolve enum arg
                break;
            }
            else if( ss == 0 )
            {
#ifdef NOCODE
                //profile_on(8);
                sys_data.state = DEPLOYED;
                if(sys_data.sampling_period == 0)   // THOM Polled Mode
                    sys_data.state = COMMAND;      // THOM NEW - use command mode to stop RTC wakeup (polled mode)
#endif
                //flush the receive and transmit buffers
                UARTFlushRx();

                //get_sample(1);
                profile_on(1);
                fast_sample(0);     // new fast sampling - replaced get_sample per Yui Jun 2019
                profile_off(1);

                // Wait for command for 6 seconds
                charCount = getUserInputTimeLimit(buff, sizeof(buff), 6);

                if(charCount == TIMELIMITPASSED)
                {
                    if(sys_data.output == VERBOSE) uprintf("\n\nNo command, resuming deployment...");
                    if(sys_data.state == IDLE)
                        sleep(IDLE, 0);
                    if(sys_data.state == COMMAND)
                        sleep(COMMAND, 0);
                    uprintf("\nSomething is wrong, sleep state should have been IDLE or COMMAND, call Thom\n\n");
                    //sleep(sys_data.state, 0);  // for COMMAND and IDLE  THOM TODO - resolve enum arg
                    break;
                }
                else
                {
                    // Parse command
                    sl = strncmp(buff, "sl", 2);            // send last sample, must have sent ss first
                    if( sl == 0 )
                    {
                        print_sampBuf();
                        ROM_SysCtlDelay(MILLISECOND*30);        // time to send string
                        if(sys_data.state == IDLE)
                            sleep(IDLE, 0);
                        if(sys_data.state == COMMAND)
                            sleep(COMMAND, 0);
                        //sleep(sys_data.state, 0);  // for COMMAND and IDLE   THOM TODO - resolve enum arg
                        uprintf("\nSomething is wrong, sleep state should have been IDLE or COMMAND, call Thom\n\n");
                        break;

                    }
                    else
                    {
                        uprintf("\nexpected sl, received %s\n", buff);
                    }
                }

                //break;
            }
            // Get header info and dump to terminal
            else if( gh == 0 )
            {
#ifdef NOCODE
                sys_data.state = DEPLOYED;
                if(sys_data.sampling_period == 0)   // THOM Polled Mode
                    sys_data.state = COMMAND;      // THOM NEW - use command mode to stop RTC wakeup (polled mode)
#endif

                // THOM TODO:  Bug, sending gh while in DEPLOYED mode stops the sampling
                get_header();
                if(sys_data.state == IDLE)
                    sleep(IDLE, 0);
                if(sys_data.state == COMMAND)
                    sleep(COMMAND, 0);
                //sleep(sys_data.state, 0);  // for COMMAND and IDLE   THOM TODO - resolve enum arg
                uprintf("\nSomething is wrong, sleep state should have been IDLE or COMMAND, call Thom\n\n");
                break;
            }
            // Get header info and dump to terminal
            else if( gm == 0 )
            {
                // THOM TODO:  Bug, sending gm while in DEPLOYED mode stops the sampling
                current_time = ROM_HibernateRTCGet();       // THOM TODO: add var called sys_data.deployment_time 20 Apr 2021
                print_metadata_header(current_time);
                //sleep(sys_data.state, 0);  // for COMMAND and IDLE
                if(sys_data.state == IDLE)
                    sleep(IDLE, 0);
                if(sys_data.state == COMMAND)
                    sleep(COMMAND, 0);
                //sleep(sys_data.state, 0);  // for COMMAND and IDLE   THOM TODO - resolve enum arg
                uprintf("\nSomething is wrong, sleep state should have been IDLE or COMMAND, call Thom\n\n");
                break;
            }
            // Exit deployment and return to main menu
            else if( stop == 0 )
            {
                sys_data.state = IDLE;
                return;
            }
            else if( dump == 0)
            {
                state_dump();
                // no break here - means another command can be entered, break leads to sleep
            }
            // Invalid command
            else
            {
                if(sys_data.output == VERBOSE) uprintf("\nInvalid command");    // Goes back to top of command loop
                uprintf("NAK\n");
            }
        }
        dbg_printf("\nbottom of command loop\n");   // THOM debug
    }   // End of command loop


}



/**************************************************************************************
 * deploy()
 * Accepts a deployment state argument that determines whether to start the deployment,
 * take a sample, or enter the command mode.
 ***************************************************************************************/
void deploy(deploy_state state)
{
	//int response;
	time_t start_time;
	time_t current_time;
	//int charCount, gdata, ts, stop, dump, samp_byte, gh, sl, ss, to, tc;   // to, tc added for Dale Graves nsFOCE Jan 2020 Thom
	//char buff[81];
	//FIL fileObject;
	//FRESULT fresult;
	//UINT br;
	//bool line_end;


	switch(state)
	{
        case START:
            //print_metadata_header();       // defd in main.c

            sys_data.test_mode = 0;         // SBE pump will run if not in test mode

            // Set custom start time, test mode, removed before 2018...

            // Start immediately
            current_time = ROM_HibernateRTCGet();
            sys_data.nextWakeUp = current_time;
            sys_data.deploy_time = current_time;

            if(sys_data.pumpon_time > 0)
            {
                uprintf("\nSBE pump will run and must be immersed at start time!");
            }

            //
            get_deployment_note();



            // Begin deployment...
            sys_data.current_sample = 0;    // Reset sample number

            sys_data.state = DEPLOYED;          // assume RTC periodic wakeup sample period, unless period=0
            if(sys_data.sampling_period == 0)
            {
                uprintf("\n\nDeployed in polled mode, space to wake, then ts ...\n\n");        // THOM, polled mode  7 May 2018  (COMMAND)
                sys_data.state = COMMAND;
            }

//            if( writeDeploymentInformationHeader(current_time, start_time, 1) )  // Write deployment header to data file  THOM TODO, BUG need to define start_time 17 Apr 2021

            // THOM TODO call write_metadata_descriptors();
            //                write_metadata_sampling();
            // THOM TODO write_deployment_header(currentTime); // write to uSD card
            //if( writeDeploymentInformationHeader(current_time) )  // Write deployment header to data file  THOM TODO, BUG need to define start_time 17 Apr 2021
            print_metadata_header(current_time);       // defd in main.c //++   --//
            if( write_metadata_header(current_time) )
            {
                // Error
                sys_data.state = IDLE;      // New 12 Apr 2021
                uprintf("\n\nFile system error, check SD Card, sleeping in IDLE state\r\n");
                ROM_SysCtlDelay(MILLISECOND*100);
                sleep(IDLE, 0);
                return;     // File access error, abort deployment
            }


            print_data_header();
            uprintf("\n\nStarting deployment...\r\n");       // THOM New 07 Jun 2018 - added crlf
            ROM_SysCtlDelay(MILLISECOND*100);        // allow 100msec time to send string

            if(sys_data.state == COMMAND)
            {
                //profile_off(8);
                sleep(COMMAND, 0);   // Sleep until woken by UART (keystroke at serial terminal)   THOM New 8 May 2018
            }
            else
            {
                sleep(DEPLOYED, sys_data.nextWakeUp);   // Sleep until woken by RTC or keystroke
            }

            break;

        case COMMAND:
            exec_command();     // look for command characters, will sleep as needed, or return.
            //sleep(COMMAND, 0);   // Sleep until woken by UART (keystroke at serial terminal)
            //sleep(sys_data.state, 0);  // handles COMMAND and IDLE
            break;

        case DEPLOYED:
            // RTC wakeup, take sample, compute next wakeup
            fast_sample(1);

            // Calculate the next sample time
            if(sys_data.sample_aligned)     // Sample time hour aligned?
            {
                current_time = ROM_HibernateRTCGet();
                sys_data.deploy_time = current_time;        // new 20 Apr 2021
                sys_data.nextWakeUp = (current_time / 3600) * 3600;         // Find last hour

                // THOM TODO: 2 Jul ??? this code needs an error check to insure time is not whacked - have seen a hang here
                do
                {
                    sys_data.nextWakeUp += sys_data.sampling_period;
                } while(sys_data.nextWakeUp < current_time);
            }
            else
            {
                sys_data.nextWakeUp += sys_data.sampling_period;   // Not hour aligned
            }
            sleep(DEPLOYED, sys_data.nextWakeUp);   // Sleep until woken by RTC or keystroke
            break;

        case IDLE:      // should NOT ever need to handle IDLE being passed to DEPLOY 12 Apr 2021   Case not handled in old code
        default:
            uprintf("\n\nDeploy() Should NOT be IDLE, check arg error\n\n");
            ROM_SysCtlDelay(MILLISECOND*100);
            sleep(IDLE, 0);
            break;

	}

}



void state_dump(void)
{
    time_t current_time;

    dbg_flag = 1;

    dbg_printf("\n\n");

    if(sys_data.state == DEPLOYED)
    {
        dbg_printf("DEPLOYED\n");
    }
    if( sys_data.state == COMMAND)
    {
        dbg_printf("COMMAND\n");
    }
    if( sys_data.state == IDLE)
    {
        dbg_printf("IDLE\n");
    }

    current_time = ROM_HibernateRTCGet();

    dbg_printf("now %lu, next wake %lu, sampling period %lu\n", (unsigned int)current_time, sys_data.nextWakeUp, sys_data.sampling_period);

}



