/*  TT8 specific includes  */

#include        <TT8.h>                 /* Tattletale Model 8 Definitions */
#include        <tat332.h>              /* 68332 Tattletale (7,8) Hardware Definitions */
#include        <sim332.h>              /* 68332 System Integration Module Definitions */
#include        <qsm332.h>              /* 68332 Queued Serial Module Definitions */
#include        <tpu332.h>              /* 68332 Time Processing Unit Definitions */
#include        <dio332.h>              /* 68332 Digital I/O Port Pin Definitions */
#include        <tt8pic.h>              /* Model 8 PIC Parallel Slave Port Definitions */
#include        <tt8lib.h>              /* definitions and prototypes for Model 8 library */

/*  general C includes  */
#include        <stdio.h>
#include        <stdlib.h>
#include		<math.h>

//  includes for the data logger
#include		"assert.h"
#include		"memcheck.h"
#include		"logger.h"
#include		"science.h"
#include		"engineer.h"
#include		"logtime.h"
#include		"text_log.h"
#include		"eeprom.h"
#include		"misc.h"


struct logger  {
	time_tt logger_suspension_over;		//  tracks the time at which the logger
										//  will be restarted from suspension
} logger;



//  logger_suspend 
//
//  Suspends the logger for the given length of time
//
int logger_suspend (long length)  {
	time_tt now;

	ASSERT (length > 0);
/*	
	if (length <= 0)  {
		if (logger.logger_suspension_over.secs == 0)
			printf ("The logger is already running.\n\n");
			return -1;
		}
	
		//  REVIEW - how do we convey an error if we can't restart
		//  the logger?
		//  restart the logger - but are we really stopped?
		log_printf ("Restarted logger from logger_suspend()\n");
		return logger_start ();
	}
*/	
	if (length > MAX_SUSPENSION_TIME)
		return -1;
	
	now = logger_time_get_time ();
	log_printf ("Suspending logger for %ld seconds @ %s", length, logger_time_get_string (&now));

	logger_shutdown ();
	logger.logger_suspension_over = logger_time_get_time ();
	logger.logger_suspension_over.secs += length;
	
	printf ("There are %ld bytes of RAM available for data buffers\n", mem_find_max_malloc());
	return 0;
}																





//  logger_start ()
//
//	Reads the initialization table and sets the logger up as specified
//  before calling the main data collection loop
//
int logger_start (void)  {
	time_tt now;
	
	if (sci_logger_is_open())  {
		//  REVIEW - should verify that the engineering logger is open
		printf ("The logger is already running.\n");
		return 0;
	}

	now = logger_time_get_time ();
	log_printf ("Starting logger at %s", logger_time_get_string (&now));
	log_printf ("There are %ld bytes of memory available\n", mem_find_max_malloc());
	printf ("There are %ld bytes of memory available\n", mem_find_max_malloc());

	if (logger_start_engineering () != 0)  {
		printf ("Logger NOT started\n");
		return -1;
	}	
		
	if (logger_start_science () != 0)  {
		logger_shutdown_engineering ();
		printf ("Logger NOT started\n");
		return -1;
	}
		
	//  when the logger is temporarily shutdown, then logger_suspension_over is
	//  set to the new time at which the logger should be started.  If
	//  logger_suspension_over.secs is 0, then the logger is already running
	logger.logger_suspension_over.secs = 0;
	return 0;
}




//  logger_get_seconds_to_start
//
//	Returns non-zero if the logger is currently suspended
//
long logger_get_seconds_to_start (void)  {
	time_tt now;

	if (logger.logger_suspension_over.secs == 0)  {
		//  logger is not suspended, so it should be open
		ASSERT (sci_logger_is_open () != 0);
		return 0;
	}  else  {
		//  logger is suspended, so it shouldn't be open
		ASSERT (sci_logger_is_open () == 0);

		now = logger_time_get_time ();
		//  REVIEW
		//  REVIEW
		//  REVIEW
		//  There appears to be a compiler bug which hurts the ASSERT that follows
		//  Or else my brain isn't working.  The printf can print 600, and the
		//  ASSERT can fail.  		
		//  Follow this up later.  Check the assembly.
//		printf ("Delta is %ld\n", (logger.logger_suspension_over.secs - now.secs));
//		ASSERT ((logger.logger_suspension_over.secs - now.secs) > -1000L);
		return (logger.logger_suspension_over.secs - now.secs);
	}	
}
			



//  logger_verify_suspension
//
//	Checks the suspension to determine if it has expired.  Restarts
//  the logger if it has.  Also verifies that the expiration time is
//  reasonable, defined as being within the maximum suspension time
//  of the current time.  If it isn't reasonable, then this routine
//  immediately restarts the logger
//
void logger_verify_suspension (void)  {
	time_tt now;
	long delta;
	
	now = logger_time_get_time ();
	delta = now.secs - logger.logger_suspension_over.secs;
	//  if the delay is a legal length and unexpired, just return
	if ((delta < 0) && (-1*delta <= MAX_SUSPENSION_TIME))
		return;

	//  if the delay is an unreasonable value, log it and override it.
	if (labs (delta) > MAX_SUSPENSION_TIME)  {
		log_printf ("Unreasonable large suspension time - overrode!\n");
	}

	log_printf ("Restarting logger at %s", logger_time_get_string (&now));
	//  if we get here then either the inhibit expired, or the length is
	//  unreasonable, and we should force its expiration
	logger_start ();
	return;
}



//  logger_shutdown ()
//
//  Ensures that everything is shut down and powered off before quitting
//  the logger completely
//
void logger_shutdown (void)  {
	
	//  if non-zero, we are already shut down, so do nothing.  The user
	//  may adjust the wake up time.
	if (logger.logger_suspension_over.secs != 0)
		return;

	//  a normal sequence of events would allow us to call the close
	//  routines when the logger was already closed.  Make sure they
	//  properly handle this
	sci_logger_close ();
	eng_logger_close ();
	
	//  when the logger is temporarily shutdown, then logger_suspension_over is
	//  set to the new time at which the logger should be started.  It is 
	//  the job of the routine which shut the logger down to set this variable
	//  AFTER calling this shutdown routine.  This routine sets the seconds
	//  non-zero so the rest of the program will know the logger is off, and
	//  sets the seconds to a nonsensical value so that the fail safe routines
	//  will restart the logger if the user doesn't properly init this variable
	logger.logger_suspension_over.secs = 1;
}




//  logger_start_engineering
//
//  Starts up and inits the engineering data logger
//
int logger_start_engineering (void)  {
	int n;
	
	//  open the engineering logger; can't fail
	eng_logger_open ();

	//  initialize the engineering channels as needed
	for (n = 0;  n < N_ENG_CHANNELS;  n++)  {
		ASSERT (setup_data.eng_rate[n] >= 0);
		ASSERT (setup_data.eng_rate[n] < 1e6);
		if (eng_logger_channel_setup (n, setup_data.eng_rate[n]) < 0)  {
			log_printf ("logger_start_engineering failed on channel %d.\n", n);
			printf ("Could not start engineering logger, channel %d.\n", n);
			return -1;
		}
		if (setup_data.eng_rate[n] > 0)
			printf ("Engineering channel %d will be recorded every %ld seconds.\n",
													1+n, setup_data.eng_rate[n]);
	}
	log_printf ("Engineering logger started.\n");
	return 0;
}



void logger_shutdown_engineering (void)  {
	eng_logger_close ();
}




//  logger_start_science
//
//  Starts up and inits the science data logger
//
int logger_start_science (void)  {
	int n;

//	//  don't open science logger unless at least one channel is active
//	if (setup_data.science_chans != 0)  {
		if (sci_logger_open ())  {
			log_printf ("Could not open the science data logger.\n");
			return -1;
		}
		if (sci_logger_set_conversion_rate (setup_data.science_rate) < 0)  {
			printf ("Illegal conversion rate; it MUST be reset before collecting any data.\n");
			printf ("Default value currently in use.\n");
			log_printf ("Illegal conversion rate; it MUST be reset before collecting any data.\n");
		}
		if (sci_logger_set_averaging (setup_data.science_n_to_average) != 0)  {
			printf ("Illegal value for science data averaging.  Please reset.\n");
			printf ("Default value currently in use.\n");
			log_printf ("Illegal value for science data averaging.  Please reset.\n");
		}
		if (sci_logger_activate_chans (setup_data.science_chans) != 0)  {
			printf ("Could not activate channels 0x%02X.\n", setup_data.science_chans);
			log_printf ("Could not activate channels 0x%02X.\n", setup_data.science_chans);
			sci_logger_close ();
			return -1;
		}
		sci_logger_set_STA_time (setup_data.t_STA);
		sci_logger_set_LTA_time (setup_data.t_LTA);
		sci_logger_set_pre_event (setup_data.pre_event_time);
		sci_logger_set_post_event (setup_data.post_event_time);
		for (n = 0;  n < N_SCI_CHANNELS;  n++)  {
			//  somewhat confusing in that the channel numbers are offset
			//  from 0, while the index is not
			sci_logger_set_gain (n, setup_data.science_gain[n]);
			sci_logger_set_trigger_level (n, setup_data.trigger_level[n]);
		}	
//	}  else
//		log_printf ("There are no science channels active.\n");
#ifdef CREATE_DIRS
	sci_logger_setup_partition ();
	logger_disk_power_disk_off ();
#endif	
	sci_logger_start_data ();
	log_printf ("Science logger started.\n");
	return 0;
}



void logger_shutdown_science (void)  {
	sci_logger_close ();
}
	


void logger_set_clock_rate (long clock_rate)  {
	long baud, temp, delta_clock;
	float sci_rate;

	//  find out what the current baud rate is
	baud = SerGetBaud (0, 0);
	baud = 1200 * (int)((baud/1200.0) + 0.5);

	//  Clock speed necessary is determined mainly by the rate at which
	//  science data comes in.  In debug mode, always use 16 MHz
	if (clock_rate < 0)  {
#if defined(DEBUG) || defined (SIMULATE_DATA)
		clock_rate = (long)16e6;
#else
		sci_rate = sci_logger_get_conversion_rate ();
		if (sci_rate < 65)
			clock_rate = (long)2.5E6;
		else  {
			if (sci_rate < 129)
				clock_rate = (long)2.5e6;
			else
				clock_rate = (long)4.0e6;
		}
#endif	
	}	
	//  twiddle the clock rate as necessary to maintain the current baud rate
	delta_clock = 1e5;
	for (;;)  {
		SimSetFSys (clock_rate);
		temp = SerSetBaud (baud, 0);
		if (fabs ((temp/(float)baud) - 1.0) < 0.045)
			break;
		if (clock_rate >= 16e6)
			delta_clock *= -1;
		if (clock_rate < 1e6)  {
			SimSetFSys (2.5e6);
			SerSetBaud (baud, 0);
			break;
		}	
		clock_rate += delta_clock;	
	}
	return;
}	
		
		
