/*
 * Sleep.c
 *
 * Suspend and hibernation functions
 *
 *  Created on: Jan 24, 2014
 *      Author: rob
 *  Modified Apr 2018, Thom Maughan
 */

#include "main.h"
#include "system.h"
#include "sleep.h"
#include "user_io.h"
//#include "uartstdio.h"	// User local version with larger RX buffer
#include "microsd.h"
#include "init.h"
#include "board_util.h"
#include "uartstdio.h"
#include "i2c_fram.h"
#include "crc/crc-32c.h"
#include "inc/hw_sysctl.h"
#include "apf_init.h"

const uint32_t MENU_TIMEOUT_SEC        =  30;
const uint32_t TIMEOUT_EXEC_MAIN_H2M_SEC   = 100;  //100
const uint32_t TIMEOUT_EXEC_MAIN_M2M_SEC   = 10;
const uint32_t DEPLOY_DELAY_SEC        =  30;
const uint32_t CONFIG_MENU_TIMEOUT_SEC = 300;

extern int dbg_flag;  // main.c

void sleep_debug(void);

void print_sleep(void)
{
    uprintf("*"); prn_nl();     //added line terminator after * for APF
    wait_consoleTx();
}

uint32_t read_hib_rtcc_unix(void)
{
    return read_hib_rtcc() - TI_CCS_UNIX_EPOCH_OFFSET;
}

uint32_t read_hib_rtcc(void)
{
    uint32_t rtcc;
#if defined(TARGET_IS_TM4C129_RA0) || defined(TARGET_IS_TM4C129_RA1) || defined(TARGET_IS_TM4C129_RA2)
    rtcc = HWREG(HIB_RTCC);
#elif defined(TARGET_IS_TM4C123_RA1) || defined(TARGET_IS_TM4C123_RA3) || defined(TARGET_IS_TM4C123_RB1) || defined(TARGET_IS_TM4C123_RB2)
    // Work around TM4C123x errata HIB #02
    // reads to HIBRTCC and HIBRTCSS may be corrupt
    // this function used in place of HibernateRTCGet / MAP_HibernateRTCGet / MAP_HibernateRTCGet

    bool isr_already_disabled = MAP_IntMasterDisable();
    _dsb();
    _isb();

    do
    {
        rtcc = HWREG(HIB_RTCC);
    } while( rtcc != HWREG(HIB_RTCC) );

    if( ! isr_already_disabled )
    {
        MAP_IntMasterEnable();
    }
#else
    #error "Unknown target"
#endif

    return rtcc;
}

void read_hib_rtcc_rtcss(uint32_t* const out_hib_rtcc, uint32_t* const out_hib_rtccss)
{
    uint32_t rtcc1;
    uint32_t rtcc2;
    uint32_t rtcss1;

#if defined(TARGET_IS_TM4C129_RA0) || defined(TARGET_IS_TM4C129_RA1) || defined(TARGET_IS_TM4C129_RA2)

    // 1290 manual 7.3.5.1 says to reread until rtccc1 and rtcc2 match to avoid race
    do
    {
        rtcc1  = HWREG(HIB_RTCC);
        rtcss1 = HWREG(HIB_RTCSS);
        rtcc2  = HWREG(HIB_RTCC);
    } while(rtcc1 != rtcc2);

#elif defined(TARGET_IS_TM4C123_RA1) || defined(TARGET_IS_TM4C123_RA3) || defined(TARGET_IS_TM4C123_RB1) || defined(TARGET_IS_TM4C123_RB2)
    // Work around TM4C123x errata HIB #02
    // reads to HIBRTCC and HIBRTCSS may be corrupt
    // this function used in place of HibernateRTCGet / MAP_HibernateRTCGet / MAP_HibernateRTCGet
    // this function used in place of HibernateRTCSSGet / MAP_HibernateRTCSSGet / MAP_HibernateRTCSSGet
    //uint32_t rtcc2;
    uint32_t rtcss2;
    bool isr_already_disabled = MAP_IntMasterDisable();

    do
    {
        rtcc1  = HWREG(HIB_RTCC);
        rtcss1 = HWREG(HIB_RTCSS);
        rtcss2 = HWREG(HIB_RTCSS);
        rtcc2  = HWREG(HIB_RTCC);
    } while( (rtcc1 != rtcc2) || (rtcss1 != rtcss2) );

    if( ! isr_already_disabled )
    {
        MAP_IntMasterEnable();
    }
#else
    #error "Unknown target"
#endif

    if(out_hib_rtcc)
    {
        *out_hib_rtcc = rtcc1;
    }
    if(out_hib_rtccss)
    {
        *out_hib_rtccss = rtcss1;
    }
}

void wait_for_hib_wrc(void)
{
    while(!(HWREG(HIB_CTL) & HIB_CTL_WRC))
    {

    }
}

void hib_set_wake_source(const uint32_t wake_flags)
{
    uint32_t wake_mask = 0;
    uint32_t temp = 0;
#if defined(TARGET_IS_TM4C129_RA0) || defined(TARGET_IS_TM4C129_RA1) || defined(TARGET_IS_TM4C129_RA2)
    wake_mask = HIB_CTL_RTCWEN | HIB_CTL_PINWEN | HIB_CTL_BATWKEN;
#elif defined(TARGET_IS_TM4C123_RA1) || defined(TARGET_IS_TM4C123_RA3) || defined(TARGET_IS_TM4C123_RB1) || defined(TARGET_IS_TM4C123_RB2)
    wake_mask = HIB_CTL_RTCWEN | HIB_CTL_PINWEN | HIB_CTL_BATWKEN;
#else
    #error "Unknown target"
#endif

    temp = HWREG(HIB_CTL);
    temp &= (~wake_mask);
    temp |= (wake_flags & wake_mask);

    HWREG(HIB_CTL) = temp;

    wait_for_hib_wrc();
}

// MCU internal low speed osc
bool set_hib_LFIOSC()
{
    if( ! wait_for_hib_ready() )
    {
        return false;
    }

    // If using HIBERNATE_OSC_LFIOSC, this must be called before MAP_HibernateEnableExpClk
    HWREG(HIB_CTL) |= (HIB_CTL_OSCSEL | HIB_CTL_CLK32EN);

    if( ! wait_for_hib_ready() )
    {
        return false;
    }

    // errata says sometimes CTLWRC will go high but write will fail
    // check our osc bits are set
    if( ! ( HWREG(HIB_CTL) & (HIB_CTL_OSCSEL | HIB_CTL_CLK32EN)) )
    {
        return false;
    }

    return true;
}

// External 32k768 clock - not a xtal
bool set_hib_extclk()
{
    uint32_t temp_ctl;
    if( ! wait_for_hib_ready() )
    {
        return false;
    }

    // Configure hib for external osc
    temp_ctl = HWREG(HIB_CTL);
    temp_ctl &= ~(HIB_CTL_WRC | HIB_CTL_OSCSEL);
    temp_ctl |= (HIB_CTL_CLK32EN | HIB_CTL_OSCBYP);
    HWREG(HIB_CTL) = temp_ctl;

    if( ! wait_for_hib_ready() )
    {
        return false;
    }

    // errata says sometimes CTLWRC will go high but write will fail
    // check our osc bits are set correctly
    if( ! ( HWREG(HIB_CTL) & (HIB_CTL_CLK32EN | HIB_CTL_OSCBYP)) )
    {
        return false;
    }
    if( ( HWREG(HIB_CTL) & (HIB_CTL_OSCSEL)) )
    {
        return false;
    }

    return true;
}

bool wait_for_hib_ready()
{
    // TODO: lfiosc and ext clock probably do not need 1500ms to init

    int i = 0;
    bool hib_ok = false;

    // Wait for hib module
    // Errata HIB#19 says first hib write may not succeed, which shows up as hib WRC not getting set
    // Max osc init time is somewhere around a second, wait 1500ms
    for(i = 0; i < 1500; i++)
    {
        if(HWREG(HIB_CTL) & HIB_CTL_WRC)
        {
            hib_ok = true;
            break;
        }
        delay_msec(1);
    }

    return hib_ok;
}

bool is_hib_data_valid()
{
    crc32c_t crc_val = crc32c_init();

    // read the hibernate persistent data and compute crc
    for(int i = 0; i < 15; i++)
    {
        const uint32_t val = HWREG(HIB_DATA + (i * 4));
        crc_val = crc32c_update(crc_val, &val, sizeof(val));
    }
    crc_val = crc32c_finalize(crc_val);

    // verify crc in last HIB_DATA word
    return crc_val == HWREG(HIB_DATA + (15 * 4));
}

void clear_hib_data()
{
    uint32_t data[15] = {};

    set_hib_data(data);
}

void set_hib_data(const uint32_t data[15])
{
    crc32c_t crc_val = crc32c_init();

    // wait for ready
    wait_for_hib_wrc();

    // Clear the hibernate persistent data and write a crc to word 16
    for(int i = 0; i < 15; i++)
    {
        const uint32_t val = data[i];

        // Write to hib and wait
        HWREG(HIB_DATA + (i * 4)) = val;
        wait_for_hib_wrc();

        crc_val = crc32c_update(crc_val, &val, sizeof(val));
    }
    // store crc in last HIB_DATA word
    crc_val = crc32c_finalize(crc_val);
    HWREG(HIB_DATA + (15 * 4)) = crc_val;
    wait_for_hib_wrc();

    _dsb();
    _isb();
}

bool get_hib_data(uint32_t data[15])
{
    crc32c_t crc_val = crc32c_init();

    for(int i = 0; i < 15; i++)
    {
        const uint32_t val = HWREG(HIB_DATA + (i * 4));

        data[i] = val;
        crc_val = crc32c_update(crc_val, &val, sizeof(val));
    }

    crc_val = crc32c_finalize(crc_val);
    return crc_val == HWREG(HIB_DATA + (15 * 4));
}

bool init_hib_module(bool* out_was_por)
{
    uint32_t hib_reg;
    int dbgFlg = 0;

    // Need to enable the Hibernation peripheral after wake/reset, before using it.
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_HIBERNATE);

    // Wait for hib module
    while( ! MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_HIBERNATE) )
    {

    }

    // If clock is configured, do not re-configure hib
    if( MAP_HibernateIsActive() )
    {
        if(out_was_por)
        {
            *out_was_por = false;
        }

        hib_reg = HWREG(HIB_CTL);

        // Handle HIB#01 on TM4C123x case #2
        if( (hib_reg & HIB_CTL_CLK32EN) )
        {
            if( (hib_reg & (HIB_CTL_RTCEN | HIB_CTL_PINWEN)) == 0 )
            {
                // these bits don't care
                // HWREG(HIB_RTCLD);
                // HWREG(HIB_RTCM0);
                // HWREG(HIB_RTCSS);
                wait_for_hib_wrc();

                MAP_HibernateRTCTrimSet (0x00007FFFU);
                MAP_HibernateIntDisable (HIBERNATE_INT_WR_COMPLETE | HIBERNATE_INT_PIN_WAKE | HIBERNATE_INT_LOW_BAT | HIBERNATE_INT_RTC_MATCH_0);
            }
        }

        // check if the hib data is valid, and clear it if it is not
        if( ! is_hib_data_valid() )
        {
            clear_hib_data();
        }

        return true;
    }
    else
    {
        // The clock was not enabled, so the HIB had a POR
        if(out_was_por)
        {
            *out_was_por = true;
        }
    }

    // Power on reset, start up the HIB
    // Try to handle errata HIB#19 on TM4C129 by allowing 1 start up failure
    // This is for an extenral 32k768hz clock, not a xtal
    // Need to add code for external xtal if used with different init delays
    if( ! set_hib_extclk() )
    {
        //try one more time
        MAP_SysCtlPeripheralReset(SYSCTL_PERIPH_HIBERNATE);
        _dsb();
        _isb();

        while( ! MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_HIBERNATE) )
        {

        }

        MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_HIBERNATE);

        // Wait for hib module
        while( ! MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_HIBERNATE) )
        {

        }

        if( ! set_hib_extclk() )
        {
            return false;
        }
    }

    // HIB is now on, finish configuring hibernation module
    {
        //uprintf("\r\nHey Man, 200msec delay in Sleep.c in sleep_handler\r\n\r\n");

        if(dbgFlg)
        {
            // {IDLE, START, DEPLOYED, COMMAND}
            if(sys_samp.state == IDLE) uprintf("sys_samp.state = IDLE\r\n");
            //if(sys_samp.state == START) uprintf("sys_samp.state = START\r\n");
            if(sys_samp.state == DEPLOYED) uprintf("sys_samp.state = DEPLOYED\r\n");
            //if(sys_samp.state == COMMAND) uprintf("sys_samp.state = COMMAND\r\n");
        }

        // Next two lines prevent hibernate lockup (http://e2e.ti.com/support/microcontrollers/tiva_arm/f/908/t/275336.aspx)
        // Handle HIB#01 on TM4C123x case #1
        // We don't use the tiva api here as the tiva api often does a RMW cycle which we are not allowed to do after reset on TM4C123 per HIB#01
        // HWREG(HIB_RTCLD) = 0; // we don't care and writing will corrupt RTC
        // wait_for_hib_wrc();

        HWREG(HIB_RTCM0) = 0;
        wait_for_hib_wrc();

        HWREG(HIB_RTCSS) = 0; // RTCSSC is read-only, so this will zero RTCSSM
        wait_for_hib_wrc();

        HWREG(HIB_RTCT) = 0x00007FFFU; // ie MAP_HibernateRTCTrimSet (0x00007FFFU);
        wait_for_hib_wrc();

        HWREG(HIB_IM) = 0; // ie MAP_HibernateIntDisable (HIBERNATE_INT_WR_COMPLETE | HIBERNATE_INT_PIN_WAKE | HIBERNATE_INT_LOW_BAT | HIBERNATE_INT_RTC_MATCH_0);
        wait_for_hib_wrc();

        _dsb();
        _isb();

        MAP_HibernateRTCEnable();   // Enable Real Time Clock

        // clear the hib data since this is a hib POR
        clear_hib_data();

        // configure tamper module
        // we could have checked HIBPP bit 1 to see if we have tamper, but hilariously the TM4C123 does not have the HIBPP register...
        #if defined(TARGET_IS_TM4C129_RA0) || defined(TARGET_IS_TM4C129_RA1) || defined(TARGET_IS_TM4C129_RA2)
            // Disable tamper module, so we do not wake on tamper events
            MAP_HibernateTamperEventsConfig(HIBERNATE_TAMPER_EVENTS_NO_HIB_WAKE | HIBERNATE_TAMPER_EVENTS_NO_ERASE_HIB_MEM);
            MAP_HibernateTamperIODisable(0);
            MAP_HibernateTamperIODisable(1);
            MAP_HibernateTamperIODisable(2);
            MAP_HibernateTamperIODisable(3);
            MAP_HibernateTamperEventsClear();
            MAP_HibernateTamperDisable();
        #elif defined(TARGET_IS_TM4C123_RA1) || defined(TARGET_IS_TM4C123_RA3) || defined(TARGET_IS_TM4C123_RB1) || defined(TARGET_IS_TM4C123_RB2)
            // nothing to do, no tamper module
        #else
            #error "Unknown target"
        #endif

        if(dbgFlg) uprintf("\r\nPower On Reset\r\n");
    }

    return true;
}


/*
 * It is desired to catch the BOR1 or BOR0 interrupt
 * PBORCTL has a bit that enables an interrupt or a reset for BOR1 (2.88) and BOR0 (3.02)
 *
 * SysCtlResetCauseGet
 *
 * Configure the Brownout reset
 * SysCtlBrownOutConfigSet(SYSCTL_INT_BOR,0);
 * SysCtlBrownOutConfigSet(SYSCTL_INT_BOR0,0);
 * SysCtlBrownOutConfigSet(SYSCTL_INT_BOR1,0);
 * Enable the Brownout interrupt in sysctl
 * SysCtlIntEnable(SYSCTL_INT_BOR1)
 *
 * What is the ISR vector??
 */

//
// The following are values that can be passed to the SysCtlBrownOutConfigSet()
// API as the ui32Config parameter.
//
//
//#define SYSCTL_BOR_RESET        0x00000002  // Reset instead of interrupting
//#define SYSCTL_BOR_RESAMPLE     0x00000001  // Resample BOR before asserting

/*
 * sleep() - application calls this function to go into low power hibernate mode.   Wakeup is same as coming out of reset.
 * Puts controller in hibernate mode. Controller hardware will wake by either keystroke, wake pin or real-time clock
 * alarm match.
 *
 * if in RTCwake mode, reprogram the time for next wakeup (and handle even seconds/minutes alignment, aka, align to hours)
 * if in Sleep mode, wait for serial comm
 *
 */
void sleep(deploy_state state, uint32_t wake_time)
{
    uint32_t ulStatus;
    time_t current_time;
    bool isr_already_disabled;

    IOPwrDown();        //APFTODO, verify this is in the correct place for SYS RTS clear new 18Apr2025

    sys_samp.state = state;     // Save the current state for when we wakeup

    // THOM DEBUG
    //uprintf( "\r\ncurrent time: %u", read_hib_rtcc() );
    //uprintf("\r\nwakeup: %u, fptr: %u", sys_data.nextWakeUp, sys_data.next_gdata_fptr);
    //MAP_SysCtlDelay(MILLISECOND*100);

    // Save our sys_data variables before hibernating!  EEPROM has endurance of 500K Program/Erase cycles.
    // 500,000 seconds is 5.8 days => 8 second sampling interval is 46 days and the EEPROM is at it's limit
    // Copy the sys_data struct into EEPROM.  Last argument ensures # of bytes is multiple of 4

    // TODO, check side effects of not storing sys_data
    // Need utilities to dump sys_data, compare, etc.
    if(fram_sys_samp_store())
    {

    }
    fram_apf_store_all();   // defd in i2c_fram

    if(state == DEPLOYED)
    {
        if(wake_time > 0)   // Polled Mode is wake_time=0
        {
            // Check if wake time is in past to prevent lockup
            current_time = read_hib_rtcc();

            //if(wake_time <=  current_time + 2)    // Wake time too soon or in the past (corrupt)  // 15 Aug 2022: Wirewalker use case might need if((wake_time <=  current_time + 2) || (wake_time > current_time + 'a day or so'))
            // Check for corrupt wakeup.     // 15 Aug 2022: Wirewalker samples at 2 seconds, power gets turned off.   Bug, it stopped sampling after a week.   Hypothesis is wakeup time was corrupted into the future.
            if((wake_time <= current_time + MIN_SAMPLING_PERIOD) || (wake_time > current_time + MAX_SAMPLING_PERIOD))
            {
                // THOM DEBUG
                //uprintf("\r\n\r\nWake time %u is <= current time %u\r\n", wake_time, current_time);
                //MAP_SysCtlDelay(MILLISECOND*25);
                wake_time = current_time + 2;   // Add two seconds, results in a wakeup in 2 seconds which then will take a sample, then re compute wakeup to fix.
            }

            // Set wake time
            MAP_HibernateRTCMatchSet(0, wake_time);
            MAP_HibernateRTCSSMatchSet(0, 0);

            //Set wake condition on wake pin
            hib_set_wake_source(HIB_CTL_RTCWEN | HIB_CTL_PINWEN);

            //uprintf("\r\n\r\nDebug in sleep.c line 70, Sleeping until ");
            //print_time_t_Time(wake_time);

            if(sys_data.test_mode == 1 || sys_data.output == VERBOSE)
            {
                prn_nl(); prn_nl(); uprintf("Sleeping until ");
                print_time_t_Time(wake_time);
            }
        } // if wake_time >0
        else
        {
            // Polled mode (RTC is not used to wake)
            hib_set_wake_source(HIB_CTL_PINWEN);
            prn_nl(); prn_nl(); uprintf("Sleeping in polled mode.."); prn_nl(); prn_nl(); prn_nl(); 
        }
    }

    //else if(state == IDLE)
    else // state IDLE or COMMAND           THOM 8 May 2018  THOM Polled Mode
    {
        hib_set_wake_source(HIB_CTL_PINWEN);

        if(state == IDLE)
        {
            if(sys_data.output == VERBOSE)
            {
                prn_nl(); prn_nl(); uprintf("Sleeping...*");
            }
            else
            {
                print_sleep();  // prints *
            }
        }

        if(sys_data.output == VERBOSE)
        {
            uprintf("hit any key to wake"); prn_nl(); prn_nl(); prn_nl(); 
        }

        MAP_SysCtlDelay(MILLISECOND*25);
    }

    UARTFlushTx(0);
#ifdef MOVEDUP
    // Save our sys_data variables before hibernating!  EEPROM has endurance of 500K Program/Erase cycles.
    // 500,000 seconds is 5.8 days => 8 second sampling interval is 46 days and the EEPROM is at it's limit
    // Copy the sys_data struct into EEPROM.  Last argument ensures # of bytes is multiple of 4

    // TODO, check side effects of not storing sys_data
    // Need utilities to dump sys_data, compare, etc.
    if(fram_sys_samp_store())
    {

    }
    fram_apf_store_all();   // defd in i2c_fram
#endif
#ifdef THISWILLWEAROUTEEPROM
    if(storeSysDataVariables())     //if(EEPROMProgram((uint32_t*) &sys_data, 0x400, (sizeof(sys_data) + 3) & ~3))
    {
        uprintf("Error storing system data (sleep.c).\r\n");   // NOTE: this wont print due to console_off() above
        wait_consoleTx();
        error_store("Error storing system data (sleep.c).");
        return;
    }
#endif

    sys_rts(1);  // deassert CF2 RTS output (CTS input to APF, etc)
    console_off();  // THOM new location 24 Sep 2019

//  sleep_debug();      // THOM DEBUG - THIS SHOWS WR_COMPLETE interrupt is active

    // Clear any pending interrupts
    ulStatus = MAP_HibernateIntStatus(0);
    MAP_HibernateIntClear(ulStatus);

    MAP_HibernateRTCTrimSet (0x7FFF);   // Make sure trim is set to default to prevent lockup (see errata)

//    MAP_HibernateWakeSet(HIBERNATE_WAKE_RTC);

    // Mask ISR, Sync
    isr_already_disabled = MAP_IntMasterDisable();
    _dsb();
    _isb();

    // Tell hibernation module we want to sleep
    MAP_HibernateRequest();

#if defined(TARGET_IS_TM4C123_RB1) || defined(TARGET_IS_TM4C123_RB2)
    // Handle TM4C123x HIB#03 - Device fails to wake
    // Wait till the isolation has been applied, then trigger reset
    // The reset handler will detect this case and spin the part until the supplies decay
    while ((HWREG(HIB_CTL) & HIB_CTL_CLK32EN) == HIB_CTL_CLK32EN)
    {

    }
    MAP_SysCtlReset();
#endif

    MAP_SysCtlDelay(100*MILLISECOND);    // Give time to hibernate.

    if( ! isr_already_disabled )
    {
        MAP_IntMasterEnable();
    }

    // NOTE: code should never get here....
    console_on();  // THOM new 5 Aug 2020 - debugging brds that dont sleep

    // Shouldn't get to this point, something went wrong - Typically it is due to running MFET compiled code on the SEAPHOX
#if BOARD_MFET >= 2 || BOARD_MPHOX >= 1  || BOARD_MSC == 2 || BOARD_NANOFET >= 1
    prn_nl(); prn_nl(); prn_nl(); uprintf("Hibernation error!  Possible cause: remove JP1 on MFET board "); prn_nl(); prn_nl(); prn_nl(); 
    error_store("Hibernation error.  Possible cause: remove JP1 on MFET board.  \r\n");

    prn_nl(); prn_nl(); prn_nl(); uprintf("Calling SysCtrlReset..."); prn_nl(); prn_nl(); prn_nl(); 
    MAP_SysCtlDelay(100*MILLISECOND);
#endif
    // Code should never get here, but just in case, reset
    MAP_SysCtlReset();
}

void sleep_debug(void)
{
    uint32_t uiStatus;

    uiStatus = MAP_HibernateIntStatus(false);   // Read the status to determine cause of wake.
    MAP_HibernateIntClear(uiStatus);            // Clear the hibernate interrupt

    // Wake pin
    if(uiStatus & HIBERNATE_INT_PIN_WAKE)           // 0x00000008
    {
        //uprintf("\r\nWake by pin");       // THOM DEBUG (comment this line out)
        if(sys_samp.state == DEPLOYED)  // User hit key during sleep while deployed, enter command mode.
        {
            //uprintf(" - state = DEPLOYED ");       // THOM DEBUG (comment this line out)
            //sys_samp.state = COMMAND;
        }

    }
    else if(uiStatus & HIBERNATE_INT_RTC_MATCH_0)   // 0x00000001  // RTC match, Take a sample
    {
        //uprintf("\r\nWake by RTC match");     // THOM DEBUG (comment this line out)
        sys_samp.state = DEPLOYED;
    }
    else if(uiStatus & HIBERNATE_INT_VDDFAIL)       // 0x00000080
    {
        //uprintf("\r\nWake by HIB INT VDDFAIL");     // THOM DEBUG (comment this line out)
        sys_samp.state = IDLE;
    }

    else if(uiStatus & HIBERNATE_INT_RESET_WAKE)        // 0x00000040
    {
        //uprintf("\r\nWake by HIB INT RESET WAKE");     // THOM DEBUG (comment this line out)
        sys_samp.state = IDLE;
    }
    else if(uiStatus & HIBERNATE_INT_GPIO_WAKE)         // 0x00000020
    {
        //uprintf("\r\nWake by HIB INT GPIO WAKE");     // THOM DEBUG (comment this line out)
        sys_samp.state = IDLE;
    }
    else if(uiStatus & HIBERNATE_INT_WR_COMPLETE)       // 0x00000010
    {
        //uprintf("\r\nWake by HIB INT WR COMPLETE");     // THOM DEBUG (comment this line out)
        sys_samp.state = IDLE;
    }
    else if(uiStatus & HIBERNATE_INT_PIN_WAKE)          // 0x00000008
    {
        //uprintf("\r\nWake by HIB INT PIN WAKE");     // THOM DEBUG (comment this line out)
        sys_samp.state = IDLE;
    }
    else if(uiStatus & HIBERNATE_INT_LOW_BAT)           // 0x00000004
    {
        //uprintf("\r\nWake by HIB INT LOW BAT");     // THOM DEBUG (comment this line out)
        sys_samp.state = IDLE;
    }
    // Reset button
    else
    {
        //uprintf("\r\nWake by Reset Button");      // THOM DEBUG (comment this line out)
        sys_samp.state = IDLE;
    }
}

/*
 * sleep_handler()
 * Determines what woke the module (wake pin, RTC match, cold boot).
 * Drops through to Main Menu if woke by keystroke and status is IDLE.
 * Sets status as DEPLOYED if woke by RTC match (status should already be DEPLOYED).
 * Sets status to COMMAND if woke by keystroke and status is DEPLOYED.
 * Anything else is assumed to be a power-on-reset.
 * RCG 4/14
 * TM 16 Apr 2018 - MFET_BOARD sleep issues
 *
 *
 * v5 - rework sleep and wake.   sleep_handler name changed to wake_handler
 *
 *  Two states
 *   - RTCwake for datalogging
 *   - Console UART for polled operation and m2m command
 *      - treat wake pin the same as wake for polled operation
 *
 */
//uint32_t sleep_handler(void)
uint32_t wake_handler(void)
{
    uint32_t uiIntStatus;

    uint32_t wakeSource = WAKE_NOTSET;

    int dbgFlg = 0;

    bool was_por_start = true;

    // Do first time init of hib if needed, and indicate if this was probably a POR
    if( ! init_hib_module(&was_por_start) )
    {
        // wait for WD  reset   APFTODO: log this event
        crash_phfetsos();
    }

    // Check and clear the system non-hib reset cause register, it can tell us about SOC WD resets
    {
        const uint32_t sysctl_resc = MAP_SysCtlResetCauseGet();
        MAP_SysCtlResetCauseClear(sysctl_resc);

        if(sysctl_resc & SYSCTL_RESC_MOSCFAIL)
        {

        }
        if(sysctl_resc & SYSCTL_CAUSE_HSRVREQ)
        {

        }
        if(sysctl_resc & SYSCTL_CAUSE_WDOG1)
        {

        }
        if(sysctl_resc & SYSCTL_CAUSE_SW)
        {

        }
        if(sysctl_resc & SYSCTL_CAUSE_WDOG0)
        {

        }
        if(sysctl_resc & SYSCTL_CAUSE_BOR)
        {

        }
        if(sysctl_resc & SYSCTL_CAUSE_POR)
        {

        }
        if(sysctl_resc & SYSCTL_CAUSE_EXT)
        {

        }
    }

    if(dbgFlg) uprintf("\r\nPOR: %d\r\n", (int)was_por_start);

    // Check if we are having a cold HIB start, eg dead hib battery
    if( ! was_por_start )
    {
        // HIB has valid wake info
        uiIntStatus = MAP_HibernateIntStatus(false);   // Read the status to determine cause of wake.

        if(uiIntStatus)
        {
            MAP_HibernateIntClear(uiIntStatus);            // Clear the hibernate interrupt
            _dsb();
            _isb();
        }

        // ignore HIBERNATE_INT_WR_COMPLETE, it will be set by most writes to HIB completing
        uiIntStatus &= ~(HIBERNATE_INT_WR_COMPLETE);

        // Wake pin
        if(uiIntStatus & HIBERNATE_INT_PIN_WAKE)
        {
            if(dbgFlg) uprintf("\r\nWake by pin\r\n");              // serial console activity circuit, or WAKE switch
            wakeSource = WAKE_CONSOLE;
        }
        // RTC match
        else if(uiIntStatus & HIBERNATE_INT_RTC_MATCH_0)   // Take a sample
        {
            if(dbgFlg) uprintf("\r\nWake by RTC match\r\n");
            wakeSource = WAKE_RTC;
        }
        else if(uiIntStatus & HIBERNATE_INT_VDDFAIL)
        {
            //This can mean power was lost when we were not hibernating
            if(dbgFlg) uprintf("\r\nWake by HIB INT VDDFAIL\r\n");
            sys_samp.state = IDLE;      // Drop through to main menu
        }

        else if(uiIntStatus & HIBERNATE_INT_RESET_WAKE)
        {
            if(dbgFlg) uprintf("\r\nWake by HIB INT RESET WAKE\r\n");
            //wakeSource = WAKE_RESET;      // THOM NEW 2 Mar 2022
            sys_samp.state = IDLE;      // Drop through to main menu
        }
        else if(uiIntStatus & HIBERNATE_INT_GPIO_WAKE)
        {
            if(dbgFlg) uprintf("\r\nWake by HIB INT GPIO WAKE\r\n");
            //wakeSource = WAKE_GPIO;
            sys_samp.state = IDLE;      // Drop through to main menu
        }
        else if(uiIntStatus & HIBERNATE_INT_LOW_BAT)
        {
            if(dbgFlg) uprintf("\r\nWake by HIB INT LOW BAT\r\n");
            sys_samp.state = IDLE;      // Drop through to main menu
        }
        // Reset button
        else
        {
            if(dbgFlg) uprintf("\r\nWake by Reset Button\r\n");
            sys_samp.state = IDLE;      // Drop through to main menu
        }

        // THOM - need to check VDD3ON usage from MFET (TODO)
        MAP_HibernateGPIORetentionDisable();    // Return control of GPIO pins to CPU (clears VDD3ON bit)
    }
    else
    {
        //HIB was dead, we do not know why we are awake
        //Power On Reset

        if(dbgFlg) uprintf("\r\nWake by POR\r\n");      // this signal is active when RESET switch is pressed...
        //sys_samp.state = IDLE;      // Drop through to main menu  // commented out 21 Jul 2021
        // 21 Jul 2021 Working to fix a bug for nsFOCE, if asleep, power cycle no problem.  if awake, power cycle causes main menu (drops out of deploy)
        //wakeSource = WAKE_RESET;

        // NOTE:
        // if power is cycled when in DEPLOY and RTC sampling, the desired behavior is to resume sampling....
        if(sys_samp.state == DEPLOYED)
        {
            // THOM DEBUG
            if(dbgFlg) uprintf("Pretending that RTC wake event happened even tho it was a power cycle - keep on sampling...\r\n");
            wakeSource = WAKE_RTC;
        }
    }

    return(wakeSource);

}
