/***************************************************************************************************
  Filename:       cav_main.c
  Revised:        $Date: $
  Revision:       $Revision: $

   Description:    Cavalier App main() function

**************************************************************************************************/

/***************************************************************************************************
*                                             INCLUDES
***************************************************************************************************/

#include <msp430.h> 
#include <stdio.h>
#include "ComTypeDefs.h"
//#include BOARD_HEADER
#include "cavalier_board_cfg_rev2.h"
#include "sys_tick.h"
#include "ucs.h"
#include "Monitor.h"
#include "radio_api.h"
#include "pixl_sensor.h"
#include "magaccel.h"
#include "analog_sensors.h"
#include "sample_mngr.h"
#include "hal_nv_ti.h"
#include "sys_utils.h"

/***************************************************************************************************
*                                             ENUMS
***************************************************************************************************/
// SYSRSTIV Reset sources
typedef enum
{
	RESET_BROWNOUT,			//Brownout (BOR) (highest priority)
	RESET_RST_NMI, 			//RST/NMI (BOR)
	RESET_PMMSWBOR, 		//PMMSWBOR (BOR)
	RESET_WAKE_LPMx_5, 		//Wakeup from LPMx.5 (BOR)
	RESET_SEC_VOIL, 		//Security violation (BOR)
	RESET_SVSL, 			//SVSL (POR)
	RESET_SVSH, 			//SVSH (POR)
	RESET_SVML_OVP, 		//SVML_OVP (POR)
	RESET_SVMH_OVP, 		//SVMH_OVP (POR)
	RESET_PMMSWPOR, 		//PMMSWPOR (POR)
	RESET_WDT_TO, 			//WDT time out (PUC)
	RESET_WDT_PWD, 			//WDT password violation (PUC)
	RESET_FLASH_PWD, 		//Flash password violation (PUC)
	RESET_RES, 				//Reserved
	RESET_PERF, 			//PERF peripheral/configuration area fetch (PUC)
	RESET_PMM_PWD, 			//PMM password violation (PUC)

	TOTAL_RESETS,
	NUM_RESET_SOURCES
} reset_source_t;


//***
//***    NV (noinit) RAM    ***
//***
#define NO_INIT_COOKIE	(0x39AD)

#pragma DATA_SECTION(noinit_key, ".TI.noinit")
uint16_t noinit_key;
#pragma DATA_SECTION(reset_sources, ".TI.noinit")
uint16_t reset_sources[NUM_RESET_SOURCES];

#define SYSTATE_WAKEY		0
#define SYSTATE_SLEEPY		1


uint8_t	sys_state;
uint16_t no_tx_interrupt;
uint16_t sleep_cycle_sec = 0;
uint16_t wake_cycle_sec = 0;
uint16_t radio_awake_sec = 0;
uint16_t xbee_hang_alive_counter;
uint16_t radio_awake_max = 10; //DEBUG - pass in through nvram or readback from xbee OW




/***************************************************************************************************
*                                             PROTOTYPES
***************************************************************************************************/

static void _reset_counter_init(void);
static void _waitForPowerup(void);

/**********************************************************************************************//**
* @brief   You da main()!
*
* @param   none
*
*
* @return  - DOES NOT RETURN
**************************************************************************************************/
int main( void )
{
	uint8_t	i;

    // Initialization for board related stuff
	HAL_BOARD_INIT();
	__disable_interrupt();

    _reset_counter_init();

    sys_state = SYSTATE_WAKEY;

    for(i=0;i<3;i++)
    {
    	// Show uC is awake
    	HAL_TURN_ON_DBGLED1();
		milli_wait(20);
    	HAL_TURN_OFF_DBGLED1();
		milli_wait(100);
    }

    _waitForPowerup();

    // Initialize Stuff
    if (Usart_Init())
        {
        debug_printf("Uart initialized!\n"); // Initialize at PUP for DAFE
        }
    else
    {
        debug_printf('Uart initialization failed!!\n');
    }
    Monitor_init();
    tick_Init();
    sampmgr_init();
    pixlN_init();
    pixl_init();
    ana_init();
    xbee_hang_alive_counter =0;

#ifndef REV3_DAFE
    debug_printf("REV3 DAFE not present!\n");
#else
    debug_printf("REV3 DAFE present!\n");
#endif
    // let 'er rip
    __enable_interrupt();

    radio_init();
    // manage power to rs422 interface
#ifndef REV3_DAFE // exclude for rev3.2 and later , only turn on when power is enabled

    debug_printf("not rev3.2+ specific init of rs422 ctls!!\n");
    SET_RS422_DE_PIN();			// transmit enable
    CLR_RS422_nRE_PIN();		// receiver enable
#else //rev3.2

    debug_printf("rev3.2+ specific init of rs422 ctls!!\n");
    CLR_RS422_DE_PIN();         // transmit disable
    SET_RS422_nRE_PIN();        // receiver disable
#endif

#ifndef REV3_DAFE  //rev4 or non-Dafe cavalier
    if( !Usart_Present() && (nv_sleep_mode == 1) )  // Don't start Sleep automatically if monitor connected
#else  //DAFE connected sensors
        if( nv_sleep_mode == 1) 	// with DAFE - monitor/cable detection can not block entering sleep mode
#endif
    {
    	radio_enableSleepMode( TRUE );  // now set by nv setting
    }

    //-----------------------------------------------------------------------------
    //   Das Meister Schleife!
    //-----------------------------------------------------------------------------
    while( TRUE )
    {
    	bool_t	stay_awake;

    	if( sys_state == SYSTATE_WAKEY )
    	{
    		if( radio_isAwake() )
    		{
    			radio_tick();
    		}
			pixl_update();
            pixlN_update();
#ifndef REV3_DAFE // exclude for dafe/rev3+, include otherwise
            Monitor_update();
#endif
			if( timerTickEvent.tick_100ms )
			{
				timerTickEvent.tick_100ms = 0;

				HAL_TOGGLE_DBGLED1();			// blink fast when awake
				ana_tick();
				stay_awake = sampmgr_100ms_tick();
				if (!radio_isAwake())
				{
				    radio_awake_sec =0; // reset this counter
				}
				if (!stay_awake){
				    debug_printf("stay_awake flag is FALSE\n");
				}
#ifdef REV3_DAFE // include if rev3/rev3.2
				if( !stay_awake && !radio_isAwake()) // && !Monitor_isPresent() )
#else // rev4 or non-DAFE
	            if( !stay_awake && !radio_isAwake() && !Monitor_isPresent() )
#endif
				{
					// go to sleep my child
					tick_SpeedUp( FALSE );
					// REMOVE turn off RS422 transceiver
				    //CLR_RS422_DE_PIN();			// transmit disable
				    //SET_RS422_nRE_PIN();		// receiver disable

					debug_printf("go to sleep\n");
					debug_printf("wake_cycle_sec 0x%02x \n", wake_cycle_sec);
                    debug_printf("sleep_cycle_sec 0x%02x \n", sleep_cycle_sec);
					sys_state = SYSTATE_SLEEPY;
					no_tx_interrupt = 0;  //start the tx interrupt counter
				}
			}

			if( timerTickEvent.tick_1s )      // check 1s tick bit & clear
			{
				timerTickEvent.tick_1s = 0;
				wake_cycle_sec++;
				debug_printf("cavalier is awake 0x%02x \n", wake_cycle_sec);
				debug_printf("stay_awake: 0x%02x, radio_isAwake  0x%02x\n",
				                    stay_awake, radio_isAwake());
				RESET_WATCHDOG();            // Reset watchdog counter here
	    		if( radio_isAwake() )
	    		{
	    		    radio_awake_sec++;
	    			radio_1s_tick();
	    		    debug_printf("cavalier is wake 0x%02x, xbee is awake 0x%02x \n",
	    		                                wake_cycle_sec, radio_awake_sec);
	    		    if (radio_awake_sec > radio_awake_max)
	    		    {
	    		        uint16_t radio_passthru_mode_save = radio_getMode();
	    		        bool_t radio_sleep_mode_save = radio_getSleepMode();
	    		        radio_init();
	    		        radio_setMode(radio_passthru_mode_save);
	    		        if (radio_sleep_mode_save)
	    		         {
	    		            // if synchro sleep mode set -
	    		            radio_enableSleepMode(radio_sleep_mode_save);
	    		         }
	    		         xbee_hang_alive_counter++;
	    		         xbee_reset_counter++;
	    		         debug_printf( "Radio is hung awake above %i - xbee reset count: %i\n",
	    		                                        radio_awake_sec, xbee_reset_counter);
	    		         radio_awake_sec =0;
	    		    }
	    		}

				//pixl_1s_tick(); REMOVE - this function has been gutted
				Monitor_1s_tick();		// primarily for monitor connection detection
				sampmgr_1s_sleepy_tick();
			}
    	}
    	else	// systate == SYSTATE_SLEEPY
    	{
    		HAL_TURN_ON_DBGLED1();

			if( timerTickEvent.tick_1s )      		// check 1s tick bit & clear
			{
			    //DEBUG
			    no_tx_interrupt++;
			    sleep_cycle_sec++;
			    debug_printf("sleep radio state is %d, stay_awake %d, 0x%04x\n", timerTickEvent.radio_woke_up,
			            stay_awake,no_tx_interrupt);

				timerTickEvent.tick_1s = 0;

				RESET_WATCHDOG();            		// Reset watchdog counter here

				if( sampmgr_1s_sleepy_tick() )		// returns TRUE if it's time to take a sample
				{
					tick_SpeedUp( TRUE );
					sys_state = SYSTATE_WAKEY;
					debug_printf("wake up and sample\n");
				}
			}

			if( timerTickEvent.radio_woke_up )
			{
				// Radio's awake
                no_tx_interrupt =0; // reset counter
				timerTickEvent.radio_woke_up = 0;
				if (radio_isAwake())
				{
				    debug_printf(" wakeup cav: Xbee radio is actually awake!\n");
	                tick_SpeedUp( TRUE );
	                sys_state = SYSTATE_WAKEY;

				}else {
                    debug_printf("cav in LPM: Xbee radio is not currently awake!\n");

				}
                //tick_SpeedUp( TRUE );
				//sys_state = SYSTATE_WAKEY;
				//debug_printf("wake up - radio's up\n");
			}

    		HAL_TURN_OFF_DBGLED1();
			if( sys_state == SYSTATE_SLEEPY )
			{
				// Snooze fest
				LPM3;
				_nop();
			}
    	}
    }	// while(TRUE)

    // Shouldn't never not no not get here.
}

/*!*************************************************************************************************
 * @brief  Reset Counter Initialization
 *
 * @param none
 *
 * @
 *
 **************************************************************************************************/
static void _reset_counter_init(void)
{
	uint8_t i;
	uint16_t source;

	if( noinit_key != NO_INIT_COOKIE )
	{
		// first-time run, so initialize the values.
		noinit_key = NO_INIT_COOKIE;
		//adc_crc_fail_count = 0;
		//i2c_num_crc_failures = 0;
		//sys_error_flags = 0;
		for( i=0; i<NUM_RESET_SOURCES; i++ )
		{
			reset_sources[i] = 0;
		}
	}
	else
	{
		// reset due to error or RESET command
		reset_sources[TOTAL_RESETS]++;
		while( (source=SYSRSTIV) != 0 )
		{
			reset_sources[ (source/2)-1 ]++;
		}
	}
}

#define POWERUP_TIMEOUT 60		// seconds
#define POWERUP_VCC_THRESH	 2800

/*!*************************************************************************************************
 * @brief  Wait until VCC reaches operational threshold
 *
 * @param none
 *
 **************************************************************************************************/
static void _waitForPowerup(void)
{
	uint16_t	i;
	uint16_t	batv;

	for( i=0; i<POWERUP_TIMEOUT*4; i++ )
	{
		batv = ana_readVdd();
		debug_printf("pup: %d: %dmV\n", i, batv);
		if( batv >= POWERUP_VCC_THRESH )
		{
			break;
		}
		milli_wait(250);
	}

}

