/*
 * Sleep.c
 *
 * Suspend and hybernation functions
 *
 *  Created on: Jan 24, 2014
 *      Author: rob
 */

#include "System.h"
#include "Sleep.h"
#include "IO.h"
#include "uartstdio.h"	// User local version with larger RX buffer
#include "SDCard.h"
#include "Init.h"

/*
 * sleep()
 * Puts controller in hibernate mode. Controller will wake by either keystroke or real-time clock
 * alarm match. Action after wake determined by state argument (IDLE or DEPLOYED). IDLE state returns
 * to main menu. DEPLOYED state returns to sample loop.
 * RCG 4/14
 */
void sleep(deploy_state state, uint32_t wake_time)
{
	uint32_t ulStatus;
	time_t current_time;

	sys_data.state = state;		// Save the current state for when we wakeup

//	uprintf( "\ncurrent time: %u",ROM_HibernateRTCGet() );
//	uprintf("\nwakeup: %u", sys_data.nextWakeUp);

	if(state == DEPLOYED)
	{
		// Check if wake time is in past to prevent lockup
		current_time = ROM_HibernateRTCGet();

		if(wake_time <=  current_time + 2)	// Wake time too soon
		{
			wake_time = current_time + 2;	// Add a couple seconds
		}

		// Set wake time
		HibernateRTCMatchSet(0, wake_time);

		//Set wake condition on wake pin
		ROM_HibernateWakeSet(HIBERNATE_WAKE_PIN | HIBERNATE_WAKE_RTC);

		if(sys_data.test_mode == 1 || sys_data.output == VERBOSE)
		{
			uprintf("\n\nSleeping until ");
			print_time_t_Time(wake_time);
		}
	}

	else if(state == IDLE)
	{
		ROM_HibernateWakeSet(HIBERNATE_WAKE_PIN);
		uprintf("\n\nSleeping...hit any key to wake\n\n\n");
	}

	// Let message print out
	UARTFlushTx(0);
	ROM_SysCtlDelay(MILLISECOND*250);
	console_off();

	// Save our sys_data variables before hibernating!
	// Copy the sys_data struct into EEPROM.  Last argument ensures # of bytes is multiple of 4
	if(EEPROMProgram((uint32_t*) &sys_data, 0x400, (sizeof(sys_data) + 3) & ~3))
	{
		uprintf("Error storing system data.\n");
		error_store("Error storing system data.");
		return;
	}

	// Clear any pending interrupts
	ulStatus = ROM_HibernateIntStatus(0);
	ROM_HibernateIntClear(ulStatus);

	ROM_HibernateRTCTrimSet (0x7FFF);	// Make sure trim is set to default to prevent lockup (see errata)

	// Disable CPU control of GPIO pins (sets VDD3ON bit)
	HibernateGPIORetentionEnable();

	// Tell hibernation module we want to sleep
	ROM_HibernateRequest();

	ROM_SysCtlDelay(MILLISECOND);	// Give time to hibernate.

	// Shouldn't get to this point, something went wrong
	uprintf("\n\n\nHybernation error!\n\n\n");
	error_store("Hybernation error.");

}

/*
 * 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
 */
void sleep_handler(void)
{
	uint32_t uiStatus;

	// 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());

	// Check if we just came out of hibernate mode
	if(ROM_HibernateIsActive())
	{
		uiStatus = ROM_HibernateIntStatus(false);	// Read the status to determine cause of wake.
		ROM_HibernateIntClear(uiStatus);			// Clear the hibernate interrupt

		// Wake pin
		if(uiStatus & HIBERNATE_INT_PIN_WAKE)
		{
//			uprintf("\nWake by pin");

			if(sys_data.state == DEPLOYED)	// User hit key during sleep while deployed, enter command mode.
			{
				sys_data.state = COMMAND;
			}
		}

		// RTC match
		else if(uiStatus & HIBERNATE_INT_RTC_MATCH_0)	// Take a sample
		{
//			uprintf("\nWake by RTC match");
			sys_data.state = DEPLOYED;
		}

		// Reset button
		else
		{
			sys_data.state = IDLE;		// Drop through to main menu
		}

		HibernateGPIORetentionDisable();	// Return control of GPIO pins to CPU (clears VDD3ON bit)
	}

//	uprintf( "\n\nRTC Trim: %X", HibernateRTCTrimGet() );

	// Otherwise, power on reset, finish configuring hibernation module
	if(!(uiStatus & (HIBERNATE_INT_PIN_WAKE | HIBERNATE_INT_RTC_MATCH_0)))
	{
		HibernateClockConfig(HIBERNATE_OSC_LOWDRIVE);

		// Next two lines prevent hibernate lockup (http://e2e.ti.com/support/microcontrollers/tiva_arm/f/908/t/275336.aspx)
		ROM_HibernateRTCTrimSet (0x7FFF);
		HibernateIntDisable (HIBERNATE_INT_PIN_WAKE | HIBERNATE_INT_LOW_BAT | HIBERNATE_INT_RTC_MATCH_0 | HIBERNATE_INT_WR_COMPLETE);

		// Let 32 kHz crystal stabilize
		ROM_SysCtlDelay(MILLISECOND*200);
		ROM_HibernateRTCEnable();	// Enable Real Time Clock

		sys_data.state = IDLE;		// Drop through to main menu
//		uprintf("\nPower On Reset");
	}

}

