/*  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        <dio332.h>              /* 68332 Digital I/O Port Pin Definitions */
#include        <tt8lib.h>              /* definitions and prototypes for Model 8 library */

/*  general C includes  */
#include        <stdio.h>
#include        <stdlib.h>
#include		<string.h>
#include		<ctype.h>
#include		<userio.h>

//  includes related to the data logger
#include		"ASSERT.h"
#include		"commands.h"
#include		"science.h"
#include		"engineer.h"
#include		"eeprom.h"
#include		"logtime.h"
#include		"logdisk.h"
#include		"logger.h"
#include		"text_log.h"
#include		"misc.h"
#include		"MacTrimp.h"
#include		"power.h"
#include		"lpsleep.h"

#include		"AD7716.h"	//  delete this include in final version

//  includes related to the disk drive
#include		<pcdisk.h>

//  defined in main.c.  Sets the minimum clock freqeuncy required
//  for a sync time set or read.
extern const long MIN_TIME_SET_FREQ;

//  The working directory always contains at least a partition letter,
//  the : and the \.  The default partition is A.
//  Remember that the path must be all upper case.
char wd[EMAXPATH] = "A:\\";


//  structure used to parse a command string
struct commands  {
	char name[32];		//  character string used to invoke the command
	int code;			//  integer code used to reference the command
	int (*func) (char* string);
						//  function used to implement the command.  All
						//  functions return an integer to indicates success
						//  or failure.  All functions take a pointer to the
						//  remainder of the command string which may contain
						//  additional arguments
	char help[48];		//  character string to print when user asks for
						//  help on allowed arguments
};



const struct commands cmd_ref[] = {
	"QUIT",
	CMD_QUIT,
	cmd_quit,
	" [no argument - debug only]",

//	"HELP",
//	CMD_HELP,
//	cmd_help,
//	"[no arguments]",
//	
	"?",
	CMD_HELP,
	cmd_help,
	"[no arguments]",
	
	"SUSPEND LOGGER",
	CMD_SUSPEND_LOGGER,
	cmd_suspend_logger,
	"[number of seconds to suspend]",
	
	"START LOGGER",
	CMD_START_LOGGER,
	cmd_start_logger,
	"[no arguments]",
	
	"SENSOR POWER",
	CMD_SENSOR_POWER,
	cmd_sensor_power,
	"ON or OFF",
	
	"SET SCIENCE CHANNELS",	//  Sets which science channels are recorded
	CMD_SET_SCIENCE_CHANNELS,
	cmd_set_science_channels,
	"[channel #][,channel #]...",
	
	"SET SCIENCE GAIN",		//  Sets gain of a science channel
	CMD_SET_SCIENCE_GAIN,   //  Arguments: channel number, gain
	cmd_set_science_gain,
	"[channel #, gain], where gain is 2.5 or 25",
	
	"SET SCIENCE RATE",		//  Sets conversion rate for all science channels
	CMD_SET_SCIENCE_RATE,   //  Arguments: rate
	cmd_set_science_rate,
	"[rate], where rate = 129 or 257",
	
	"SET SCIENCE AVERAGING",	//  Sets the number of science samples which
								//  are averaged together
	CMD_SET_SCIENCE_AVERAGING,
	cmd_set_science_averaging,
	"[#], where # is 1, 2, 3, or 4",
	
	"SET STA TIME",			//  Sets length of short term average
	CMD_SET_STA_TIME,		//  Arguments: length of STA in seconds
	cmd_set_STA_time,
	"[length in seconds]",

	"SET LTA TIME",			//  Sets length of short term average
	CMD_SET_LTA_TIME,		//  Arguments: length of STA in seconds
	cmd_set_LTA_time,
	"[length in seconds]",
	
	"SET TRIGGER LEVEL",	//  Sets the trigger level for all channels
	CMD_SET_TRIGGER_LEVEL,
	cmd_set_trigger_level,
	"[channel or ALL] [value of STA/LTA]",
	
	"SET PRE-EVENT TIME",	//  Sets length of the pre-event data
	CMD_SET_PRE_EVENT_TIME,	//  Arguments: length of pre-event in seconds
	cmd_set_pre_event_time,
	"[length in seconds]",
	
	"SET POST-EVENT TIME",	//  Sets length of the post-event data
	CMD_SET_POST_EVENT_TIME,//  Arguments: length of post-event in seconds
	cmd_set_post_event_time,
	"[length in seconds]",
	
	"SET ENGINEERING RATE",	//  Sets the sample time for engineering channels
	CMD_SET_ENGINEERING_RATE,
	cmd_set_eng_rate,
	"[channel #, rate], rate is seconds/sample",
	
	"READ ENGINEERING", 	//  Reads an engineering channel
	CMD_READ_ENGINEERING,
	cmd_read_eng,
	"[channel #]",

	"READ SCIENCE",
	CMD_READ_SCIENCE,
	cmd_read_science,
	"[channel #]",
	
	//  commands which start with a "!" are intended for use by the graphical interface.
	//  They are not displayed by the help screen.  They are kept short to minimize
	//  transmission times.  They need not be particularly mneumonic since general users
	//  don't have to remember them.
	"!RBS",
	CMD_READ_BINARY_SCIENCE,
	cmd_read_binary_science,
	"",
	
	"SET TIME",				//  Sets time when carriage return is hit
	CMD_SET_TIME,
	cmd_set_time,
	"[no arguments]",
	
	"PRINT TIME",			//  Gets time when carriage return is hit
	CMD_PRINT_TIME,
	cmd_print_time,
	"[no arguments]",
	
	"SYNC SET TIME",		//  Sets time on leading edge of input pulse
	CMD_SYNC_SET_TIME,
	cmd_sync_set_time,
	"[no arguments]",

	"SAVE SETUP",			//  Saves setup data to EEPROM
	CMD_SAVE_SETUP,
	cmd_save_setup,
	"[no arguments]",
	
	"SYNC PRINT TIME ERROR",		//  Gets time on leading edge of input pulse
	CMD_SYNC_PRINT_TIME_ERROR,      //  This routine MUST be in the structure before
	cmd_sync_print_time_error,      //  the next in order for the parse routines to
	"[no arguments]",               //  work properly.  If not, they will think this
									//  is the "sync print time" command with an argument
									//  of "error"
	
	"SYNC PRINT TIME",		//  Gets time on leading edge of input pulse
	CMD_SYNC_PRINT_TIME,
	cmd_sync_print_time,
	"[no arguments]",
	
	"SHOW SETUP DATA",
	CMD_SHOW_SETUP_DATA,
	cmd_show_setup_data,
	"[no arguments]",
	
	"SHOW STATUS",
	CMD_SHOW_STATUS,
	cmd_show_status,
	"[no arguments]",
	
	"CD",
	CMD_DISK_CD,
	cmd_disk_cd,
	"[DOS path to use as working directory]",
	
	"PWD",
	CMD_DISK_PWD,
	cmd_disk_pwd,
	"[no arguments]",

	"DIR",
	CMD_DISK_DIR,
	cmd_disk_dir,
	"[optional path]",
	
	//  note that this command must follow the 'print setup' command
	//  in this array, or it will be interpreted as print the file named
	//  setup
	"PRINT",
	CMD_DISK_PRINT,
	cmd_disk_print,
	"[filename]",
	
	"TEST",					//  general purpose test routine adjusts as desired
	CMD_TEST,               //  not for general user usage
	cmd_test,
	"[no argument]",
/*	
	"",						//  last command is empty
	NOOP,
	NULL,
	""
*/	
	"SET CLOCK",
	CMD_SET_CLOCK,
	cmd_set_clock,
	"[new clock rate]",

	"VERSION",
	CMD_PRINT_VERSION,
	cmd_print_version,
	"[no argument]"
};
const short n_commands = sizeof (cmd_ref) / sizeof (struct commands);


//  array of error messages available to describe failed commands
const char* cmd_error_msgs[] = {
	"Command executed",
	"Illegal channel number",
	"Illegal value for gain",
	"Bad command syntax",
	"Times must be non-negative",
	"Conversion rate is unavailable",
	"Out of memory - shouldn't happen",
	"Illegal value for trigger level",
	"Illegal number of samples to average",
	NULL
};




//  command_parse (char* string)
//
//  This subroutine takes a pointer to a character string which the user
//  has typed, parses the string, executes the command, and prints an error
//  message if the command failed.
//
//	Returns: non-negative on success; -1 on command failure;
//		positive returns may indicate the specific command processed
//
int command_parse (char* string)  {
	int n, result;
	char* cp;

	//  convert to all upper case for ease of processing
	strupr (string);
	
	//  skip any leading spaces
	while (isspace (*string))
		string++;
		
	//  if there isn't anything left, just return	
	if (*string == '\0')
		return 0;	
	
	//  otherwise, parse the input
	for (n = 0; n < n_commands;  n++)  {
		ASSERT (n < 40);
		
        if (strncmp (cmd_ref[n].name, string, strlen(cmd_ref[n].name)) != 0)
        	continue;
        	
        cp = &string [strlen(cmd_ref[n].name)];
        while (isspace (*cp))
        	cp++;
        if (*cp == '?')  {
        	printf ("Command syntax: %s %s\n\n", cmd_ref[n].name, cmd_ref[n].help);
	        return cmd_ref[n].code;
        }		
        
        //  if we get here we have a match; call the processing routine
        //
        //  Allowed returns from the processing routine are:
        //		negative -> error, but the message is already printed
        //		0 -> OK
        //		positive -> error, print an error message using the error
        //					number as an index into a message array
        result = cmd_ref[n].func (cp);
        if (result != 0)  {
        	if (result < 0)
        		return -1;
        	ASSERT (result < (sizeof(cmd_error_msgs)/sizeof (char*)));
        	ASSERT (cmd_error_msgs[result] != NULL);
        	printf ("Error executing '%s': %s\n", string, cmd_error_msgs[result]);
        	printf ("Command syntax: %s %s\n\n", cmd_ref[n].name, cmd_ref[n].help);
        	return -1;
        }
        printf ("\n");
        return cmd_ref[n].code;
      }
      
      printf ("Unknown command: %s\n\n", string);
      return -1;
}


//  cmd_quit
//
//	
//
int cmd_quit (char* args)  {
	uchar answer;

	printf ("If you quit you will return to the TOM8 monitor.\n");
	printf ("The data logger program will be completely disabled,\n");
	printf ("and will not be able to restart itself.\n");
	printf ("Do you really want to quit? [N] ");
	fflush (stdout);
	answer = SerGetByte ();
	printf ("%c\n", answer);
	if ((answer == 'y') || (answer == 'Y'))  {
		printf ("Quitting\n");
		return 0;
	}	
		
	//  a negative return prevents the implementation of this command
	return -1;
}	





//  cmd_set_science_gain (char* arguments)
//
//  Sets the gain of a particular science channel
//
//	Arguments: pointer to a character string consisting of an integer
//		which is the channel number and a float which is the gain.  The
//		gain must match a known value available with this hardware
//	Returns: 0 if successful; non-zero on failure.  On failure the number
//		returned may be used as an index into the array cmd_error_msgs[]
//		to print an error message for the user.
//	Failures: fails if the channel number is out of range or if the
//		gain is an unrecognized value
//
int cmd_set_science_gain (char* args)  {
	float gain;
	int channel;
	char* cp;

	//  first number should be a channel number
	cp = args;
	channel = atoi (cp);
	//  channels numbers start at 0 and are less than N_SCI_CHANNELS
	if ((channel < 0) || (channel >= N_SCI_CHANNELS))
		return ILLEGAL_CHANNEL_NUMBER;
	
	//  skip the channel number and the following white space
	while (isdigit (*cp))
		cp++;
	while (isspace (*cp))
		cp++;
	
	//  get the gain and ask the science logger to set it
	gain = (float)atof (cp);
	if (sci_logger_set_gain (channel, gain) < 0)
		return ILLEGAL_GAIN;
		
	//  set the initialization array - note that we don't set the array
	//  unless the science logger verified that the gain was a known
	//  value.  It must do this properly even if it is not open.	
	setup_data.science_gain[channel] = gain;
	
	printf ("Science channel %d set to gain %f\n", channel, gain);
	return 0;
}	
	
	
//  cmd_set_science_rate ()
//
//	Sets the conversion rate to use for the science channels.  All
//  channels are converted at the same rate.
//
//	Returns: 0 on success; non-zero for illegal conversion rate
//
int cmd_set_science_rate (char* args)  {
	float rate;
	
	//  The science logger will stop the data logger and flush
	//  all previous data from the internal buffers
	printf ("All data buffers were emptied of data acquired at the original rate.\n");

	rate = (float)atof (args);
	rate = sci_logger_set_conversion_rate (rate);
	if (rate < 0)
		return ILLEGAL_RATE;

	//  set the initialization array	
	setup_data.science_rate = rate;
	printf ("Conversion rate set to %.2f\n", rate);
	return 0;
}





//  cmd_set_science_averaging
//
//  Sets the number of science samples which are averaged together
//  before the data is used.  Can be 1 (no averaging), 2, 3, or 4.
//  
//	Returns: 0 on success; non-zero for illegal averaging number
//
int cmd_set_science_averaging (char* args)  {
	short n_average;
	short result;
	
	//  The science logger will stop the logger and flush all
	//  previous data from the internal buffers
	printf ("All data buffers were emptied of data acquired at the original rate.\n");
	
	n_average = atoi (args);
	result = sci_logger_set_averaging (n_average);
	if (result < 0)
		return ILLEGAL_AVERAGING;
		
	setup_data.science_n_to_average = n_average;
	printf ("Now averaging %d samples together.\n", n_average);
	printf ("The effective science data rate is %.3lf\n", sci_logger_get_conversion_rate ());
	return 0;
}
	
		




//  cmd_read_science
//
//	sets a particular channel for real-time data dump so the user
//	can preview the data.  Arguments must be a legal channel number
//  or the word "OFF"
//
int cmd_read_science (char* args)  {
	int channel;
	
	if (!isdigit (*args))
		return ILLEGAL_CHANNEL_NUMBER;
	
	channel = atoi (args);
	if ((channel < 0) || (channel >= N_SCI_CHANNELS))
		return ILLEGAL_CHANNEL_NUMBER;
	
	if (sci_logger_is_open () == 0)
		printf ("Science channels cannot be read unless the logger is started.\n");
	else  {	
		sci_logger_set_ASCII_preview (channel);
		if ((0x01 << channel)&setup_data.science_chans)
			printf ("Data preview for channel %d turned on.\n", channel);
		else
			printf ("Channel %d is not active and cannot be read.\n", channel);	
	}	
	return 0;
}	
 
 
 

//  cmd_read_binary_science
//
//	Sets a particular channel for real-time binary data dump so the
//	user can preview the data.  Arguments must be a legal channel
//  number.
//
int cmd_read_binary_science (char* args)  {
	int channel;
	
	if (!isdigit (*args))
		return BAD_SYNTAX;
	
	channel = atoi (args);
	if ((channel < 0) || (channel >= N_SCI_CHANNELS))
		return ILLEGAL_CHANNEL_NUMBER;
	if (sci_logger_is_open () == 0)
		printf ("Science channels cannot be read unless the logger is started.\n");
	else
		sci_logger_set_binary_preview (channel);
	return 0;
}	
 
 
 

int cmd_set_STA_time (char* args)  {
	float t;
	
	t = (float)atof (args);
	if (t < 0)
		return ILLEGAL_TIME;
	if (sci_logger_set_STA_time (t) != 0)  {
		printf ("Previous pre-event length error remains:\n");
		printf ("The pre-event time is longer than the data buffer length allows\n");
		printf ("and has been truncated.  A reduction in sampling rate may bring\n");
		printf ("it back within range.  If so, it will be adjusted automatically.\n");
	}
	setup_data.t_STA = t;
	
	printf ("The short term average has been set to %.2f seconds.\n", t);
	return 0;
}

	
int cmd_set_LTA_time (char* args)  {
	float t;
	
	t = (float)atof (args);
	if (t < 0)
		return ILLEGAL_TIME;
	if (sci_logger_set_LTA_time (t) != 0)  {
		printf ("Previous pre-event length error remains:\n");
		printf ("The pre-event time is longer than the data buffer length allows\n");
		printf ("and has been truncated.  A reduction in sampling rate may bring\n");
		printf ("it back within range.  If so, it will be adjusted automatically.\n");
	}
	setup_data.t_LTA = t;

	printf ("The long term average has been set to %.2f seconds.\n", t);
	return 0;
}




//  cmd_set_trigger_level ()
//
//	Sets the value of STA/LTA which causes the system to trigger.
//
int cmd_set_trigger_level (char* args)  {
	float level;
	char *cp;
	int channel, n;
	
	//  first number should be a channel number or the word ALL
	cp = args;
	if (strncmp (args, "ALL", 3) == 0)  {
		cp +=3;
		channel = -1;
	}  else  {
		channel = atoi (args);
		if ((channel < 0) || (channel >= N_SCI_CHANNELS))
			return ILLEGAL_CHANNEL_NUMBER;

		//  skip the channel number
		while (isdigit (*cp))
			cp++;
	}		
	//  skip any white space
	while (isspace (*cp))
		cp++;
	
	//  convert the trigger level
	level = (float)atof (cp);
	if (level < 0)
		return ILLEGAL_TRIGGER;
		
	//  set it and assign to the initialization struct
	sci_logger_set_trigger_level (channel, level);
	if (channel == -1)  {
		printf ("All channels now trigger when the STA/LTA exceeds %.2f.\n", level);
		for (n = 0;  n < N_SCI_CHANNELS;  n++)
			setup_data.trigger_level[n] = level;
	}  else  {
		printf ("Channel %d now triggers when the STA/LTA exceeds %.2f.\n",
																channel, level);
		if (((0x01 << channel) & (setup_data.science_chans)) == 0)
			printf ("This channel is not yet active!\n");
		setup_data.trigger_level[channel] = level;		
	}
	
	printf ("New code to change triggering\n");
		
	return 0;
}
			


	


//  cmd_set_pre_event_time ()
//
//	Sets the pre-event time.  The argument is the length in seconds.  This
//  number must be positive.  If the length requested is longer than the
//  buffer length than the science logger routines will reduce it to the
//  maximum available length.
//
int cmd_set_pre_event_time (char* args)  {
	float t;
	
	t = (float)atof (args);
	if (t < 0)
		return ILLEGAL_TIME;
	if (sci_logger_set_pre_event (t) != 0)  {
		printf ("The pre-event time is longer than the current buffer length\n");
		printf ("and has been truncated.  A reduction in sampling rate may bring\n");
		printf ("it back within range.  If so, it will be adjusted automatically.\n");
	}
	
	setup_data.pre_event_time = t;
	printf ("The pre-event time is now %.2f seconds.\n", t);
	return 0;
}	




int cmd_set_post_event_time (char* args)  {
	float t;
	
	t = (float)atof (args);
	if (t < 0)
		return ILLEGAL_TIME;
	if (sci_logger_set_post_event (t) != 0)  {
		printf ("Previous pre-event time error remains:\n");
		printf ("The pre-event time is longer than the current buffer length\n");
		printf ("and has been truncated.  A reduction in sampling rate may bring\n");
		printf ("it back within range.  If so, it will be adjusted automatically.\n");
	}
	
	setup_data.post_event_time = t;
	printf ("The post-event time is now %.2f seconds.\n", t);
	return 0;
}
	



//  cmd_set_science_channels ()
//
//  Sets which science channels are considered for recording
//
int cmd_set_science_channels (char* args)  {
	char* cp;
	int channel_bits;
	int n;
	int print_flag;
	
	//  need a channel number; don't let a null look like channel 0
	if (!isdigit (*args))
		return ILLEGAL_CHANNEL_NUMBER;
	
	
	if (strcmp (args, "OFF") == 0)  {
		//  turn all science channels off
		setup_data.science_chans = 0x0;
		if (sci_logger_activate_chans (setup_data.science_chans) != 0)  {
			printf ("Could not disable the science data logger channels.\n");
			return -1;
		}
		printf ("All science data channels turned off.\n");
		return 0;
	}

	channel_bits = 0;
	cp = args;
	do  {
		n = atoi (cp);
		if ((n < 0) || (n >= N_SCI_CHANNELS))
			return ILLEGAL_CHANNEL_NUMBER;
		channel_bits |= (0x01 << n);
		
		while (isdigit (*cp))
			cp++;
		while (isspace (*cp))
			cp++;
			
		if (*cp == ',')
			cp++;
		while (isspace (*cp))
			cp++;
	}  while (isdigit (*cp));
	//  a channel number must be followed by a "," or the end of the
	//  command line.  Any other character is illegal.	
	if ((*cp != '\0') || (channel_bits == 0))
		return BAD_SYNTAX;
	

	//  REVIEW - we may want to change this at a later data
	//  For now, all recorded channels are used for triggering		
	setup_data.science_chans = channel_bits;
	setup_data.trigger_chans = channel_bits;

	//  The next few lines don't do anything unless the logger is open
	if (sci_logger_activate_chans (setup_data.science_chans) != 0)  {
		printf ("Could not activate science data logger channels.\n");
		return -1;
	}
	
	printf ("Science channel");
	print_flag = 0;
	for (n = 0;  n < N_SCI_CHANNELS;  n++)  {
		if ((0x01 << n) & channel_bits)
			print_flag++;
	}
	if (print_flag > 1)
		printf ("s ");
	else
		printf (" ");
	print_flag = 0;		
	for (n = 0;  n < N_SCI_CHANNELS;  n++)  {
		if ((0x01 << n) & channel_bits)  {
			if (print_flag++ != 0)
				printf (", ");
			printf ("%d", n);
		}	
	}
	if (print_flag > 1)
		printf (" are");
	else
		printf (" is");	
	printf (" now marked for processing.\n");

	//  Need to restart the data flow after changing the channels
	//  This has no affect if the logger is suspended
	sci_logger_start_data ();
	return 0;
}




//  cmd_set_eng_rate (char* arguments)
//
//  Sets the delay between engineering channel samples
//
//	Returns: 0 if successful; non-zero on failure.  On failure the number
//		returned may be used as an index into the array cmd_error_msgs[]
//		to print an error message for the user.
//	Failures: fails if the channel number is out of range or if the
//		gain is an unrecognized value
//
int cmd_set_eng_rate (char* args)  {
	long delay;
	int channel;
	char* cp;

	//  first number should be a channel number
	cp = args;
	//  channels numbers must lie within range
	channel = atoi (cp);
	if ((channel < 0) || (channel >= N_ENG_CHANNELS))
		return ILLEGAL_CHANNEL_NUMBER;
	
	//  skip the channel number and the following white space
	while (isdigit (*cp))
		cp++;
	while (isspace (*cp))
		cp++;
	if (*cp != ',')  {
		printf ("Time must be separated from the channel number with a ','.\n");
		return 0;
	}
	cp++;
	while (isspace (*cp))
		cp++;
	
	//  get the rate
	if (strcmp (cp, "OFF") == 0)  {
		delay = 0;
		printf ("Channel %d will be turned off.\n", channel);
	}  else  {
		delay = (long)(atof (cp) + 0.5F);
		if (delay <= 0)  {
			printf ("A time between samples of %f is unacceptable.\n", delay);
			printf ("The time between samples must be a positive number.\n");
			printf ("Use OFF to disable a channel.\n");
			return 0;
		}
	}

	//  set the initialization array	
	setup_data.eng_rate[channel] = delay;

	//  set the logger if active
	if (eng_logger_channel_setup (channel, delay) < 0)  {
		printf ("Out of memory.  Contact GEOSense.\n");
		return OUT_OF_MEMORY;
	}
	
	if (delay > 0)
		printf ("Engineering channel %d will now be collected every %ld seconds.\n",
																		channel, delay);
	return 0;
}	




//	cmd_read_eng ()
//
//	Reads and prints an engineering channel
//
int cmd_read_eng (char* arg)  {
	int channel, value;
	float mVolts;
	
	channel = atoi (arg);
	if ((channel < 0) || (channel >= N_ENG_CHANNELS))
		return ILLEGAL_CHANNEL_NUMBER;
/*
switch (channel)  {
  case 0:
	printf ("power cycle and restart of bus\n");
	PConfInp (F, 4);
	Max186PowerUp ();
	Max186PowerDown ();
	printf ("power down\n");
	AD7716_SPI_interface_init ();
	printf ("int init\n");
	PConfBus (F, 4);
	printf ("bus\n");
	return 0;

  case 1:
	printf ("power cycle; no restart of bus\n");
	PConfInp (F, 4);
	Max186PowerUp ();
	Max186PowerDown ();
	printf ("power down\n");
	AD7716_SPI_interface_init ();
	printf ("int init\n");
	return 0;
  	
  case 2:	
	printf ("power off\n");
	Max186PowerDown ();
	return 0;

  case 3:
  	printf ("read chan 0; power down\n");
	Max186PowerUp ();
	value = eng_logger_read_channel (0, 20);
	if (value == 0x8000)  {
		printf ("Unknown error while reading channel %d\n", channel);
	}  else  {
		mVolts = AtoDtoMilliVolts (value);
		printf ("Channel %d reads %f mVolts\n", channel, mVolts);
	}	
	printf ("QPAR = 0x%02X\n", (short)(*QPAR));
	printf ("QDDR = 0x%02X\n", (short)(*QDDR));
	printf ("QPDR = 0x%02X\n", (short)(*QPDR));

	Max186PowerDown ();
	return 0;
}

*/	
	//  REVIEW - this will not work if the logger is not active because the
	//  power will not be turned on to the analog sections
	value = eng_logger_read_channel (channel, 10);
	if (value == 0x8000)  {
		printf ("Unknown error while reading channel %d\n", channel);
	}  else  {
		mVolts = AtoDtoMilliVolts (value);
		printf ("Channel %d input is at %.0f mVolts\n", channel, mVolts);
	}	
	return 0;
}
	



//  cmd_set_time ()
//
//	Queries user for a data and time, then sets the logger time immediately
//
int cmd_set_time (char* args)  {
	struct tm tp;
	int result;
	long suspend_time;
	
	//  out how much time is left on our suspension, and save it so we
	//  can restart the suspension after changing the time.  Otherwise
	//  the system will automatically come out of suspension if we change
	//  the time by a large number
	suspend_time = logger_get_seconds_to_start ();
	
	//  REVIEW - we should also investigate how changing the time affects
	//  the engineering logger if it is running when the time is changed
	
	//	tp.tm_sec = tp.tm_min = tp.tm_hour = tp.tm_year = tp.tm_mon = tp.tm_mday = -1;
	result = logger_time_query_time (&tp);	
	if (result != 0)
		return 0;
		
	//  REVIEW
	//  why is this here?
	if (tp.tm_sec < 0)
		return 0;
	logger_time_set_time (&tp);
	printf ("Time now set to:\n");
	cmd_print_time (args);
	
	if (suspend_time > 0)
		logger_suspend (suspend_time);
	return 0;
}




//  cmd_sync_set_time ()
//
//	Queries user for a data and time, then sets the logger time on the
//  falling edge of TPU input 15
//
int cmd_sync_set_time (char* args)  {
	struct tm tp;
	int result;
	long freq, baud, suspend_time;

	printf ("The time will be set on the falling edge of the sync pulse.\n");
	suspend_time = logger_get_seconds_to_start ();
	
	//  Make sure the clock rate is set at some minimum before we
	//  wait for the interrupt.  The query time routine will print,
	//  so we also adjust the baud rate.  If the current clock
	//  exceed the min, don't bother changing
	freq = SimGetFSys ();
	if (freq < MIN_TIME_SET_FREQ)  {
		baud = SerGetBaud (0, 0);
		SimSetFSys (MIN_TIME_SET_FREQ);
		SerSetBaud (baud, 0);
	}  else
		baud = -1;	
	
	result = logger_time_query_time (&tp);	
	if (result != 0)
		return 0;
	logger_time_sync_set_time (&tp);
	
	if (baud > 0)  {
		SimSetFSys (freq);
		SerSetBaud (baud, 0);
	}
	printf ("Time now set to:\n");
	cmd_print_time (args);
	if (suspend_time > 0)
		logger_suspend (suspend_time);
	return 0;
}	


		

int cmd_print_time (char* args)  {
	time_tt now;        
	
	now = logger_time_get_time ();
	printf ("%s", logger_time_get_string (&now));
	return 0;
}
	


	
	
int cmd_sync_print_time (char* args)  {
	time_tt now;
	long freq;
	short freq_set;
	
	//  Make sure the clock rate is set at some minimum before we
	//  wait for the interrupt.  The query time routine will print,
	//  so we also adjust the baud rate.  If the current clock
	//  exceed the min, don't bother changing
	freq = SimGetFSys ();
	if (freq < MIN_TIME_SET_FREQ)  {
		SimSetFSys (MIN_TIME_SET_FREQ);
		freq_set = 1;
	}  else
		freq_set = 0;	
	now = logger_time_sync_get_time ();

	//  and reset the freq back to the original	if necessary
	if (freq_set)
		SimSetFSys (freq);
	printf ("%s", logger_time_get_string (&now));
	return 0;
}
	



int cmd_sync_print_time_error (char* args)  {
	time_tt from_logger, from_user;
	struct tm tm;
	long delta;
	float dt;
	long freq, baud;
	short sign;
	
	//  Make sure the clock rate is set at some minimum before we
	//  wait for the interrupt.  The query time routine will print,
	//  so we also adjust the baud rate.  If the current clock
	//  exceed the min, don't bother changing
	freq = SimGetFSys ();
	if (freq < MIN_TIME_SET_FREQ)  {
		baud = SerGetBaud (0, 0);
		SimSetFSys (MIN_TIME_SET_FREQ);
		SerSetBaud (baud, 0);
	}  else
		baud = -1;	

	if (logger_time_query_time (&tm) != 0)
		return 0;
		
	from_logger = logger_time_sync_get_time ();
	
	//  reset the clock as quickly as possible to minimize power usage
	if (baud > 0)  {
		SimSetFSys (freq);
		SerSetBaud (baud, 0);
	}

	from_user.secs = mktime (&tm);
	from_user.ticks = 0;

	delta = ttmcmp (from_logger, from_user);
	if (delta < 0)
		sign = -1;
	else
		sign = 1;	

	//  complex crap is necessary to handle negative numbers properly
	dt = labs(delta) / GetTickRate();
	dt += (labs(delta)%GetTickRate()) / ((float)GetTickRate());
	dt *= sign;
	
	printf ("Difference is %.3f seconds\n", dt);
	if (sign > 0)
		printf ("The logger is fast by this amount.\n");
	else
		printf ("The logger is slow by this amount.\n");	
	return 0;
}
	



int cmd_help (char* args)  {
	int n;
	
	printf ("The following commands are available:\n");
	for (n = 0;  n < n_commands; n++)  {
		//  don't print help message for commands which start
		//  with a "!", because these are commands which are
		//  not intended for use by the user with an ASCII
		//  interface
		if (cmd_ref[n].name[0] != '!')
			printf (" %s %s\n", cmd_ref[n].name, cmd_ref[n].help);
	}	
	return 0;
}



//  This command is used to show any interesting status information that the user might
//  want.  Add freely to it.
//
int cmd_show_status (char* args)  {
	extern const float SOFTWARE_VERSION;
	
	printf ("This is software version %.2f\n", SOFTWARE_VERSION);
	#ifdef DEBUG
		printf ("This code was compiled in debug mode, and is NOT appropriate for deployment.\n");
	#endif
	#ifdef SIMULATE_DATA
		printf ("This code simulates data, and is NOT appropriate for deployment.\n");
	#endif
	#if !defined(SIMULATE_DATA) && !defined(DEBUG)
		printf ("This code was NOT compiled for debugging or simulation, and is suitable for deployment.\n");	
	#endif	

	if (sci_logger_is_open())  {
		printf ("The logger is running.\n");
	}  else  {
		printf ("The logger is NOT running.\n");
	}
	printf ("The clock rate is currently set to %.3f MHz\n", (SimGetFSys ()/1.0e6));
	logger_disk_show_status ();
	sci_logger_show_status ();
	return 0;
}

	


int cmd_disk_cd (char* args)  {
	ASSERT (args != NULL);

	//  A full path starting with a '\' is treated as an absolute path on
	//  the current partition.  A path starting with a letter and a ':' is
	//  treated as a full path including the partition.  Anything else is
	//  treated as an additional path to add to the current working directory.
	if ((args[0] != '\0') && (args[1] == ':'))  {
		//  user has provided a complete path including a partition letter
		strcpy (wd, args);
	}  else  {
		if (args[0] == '\\')  {
			//  User specified a complete path from the root, but no partition
			//  Keep the current partition
			strcpy (&wd[2], args);
		}  else  {
			//  User specified a relative path
			//  Add this directory name to our current path
			if (strcmp (args, "..") == 0)
				printf ("The .. convention is not yet implemented.\n");
			else
				strcat (wd, args);
		}
	}	
	//  make sure our current working directory always ends with a '\'
	if (wd[strlen(wd)-1] != '\\')
		strcat (wd, "\\");
	printf ("The working directory is now '%s'\n", wd);	
	return 0;	
}	




int cmd_disk_pwd (char* args)  {
	printf ("Current working directory: %s\n", wd);
	return 0;
}	



int cmd_disk_dir (char* args)  {
	char path[128];
	int pc_seedir(char *);
	ASSERT (args != NULL);
	
	//  print time stamp; args not used
	cmd_print_time (args);
	
//	printf ("dos show dir\n");	
	//  if user provides a full path, including the partition, use it
	if ((args[0] != '\0') && (args[1] == ':'))
		strcpy (path, args);
	else  {
		//  If the user hasn't provided a full path, then we will use
		//  at least some part of the current working directory.
 		//  If user has provided no path, use default
		strcpy (path, wd);
		if (args[0] == '\\')
			//  if user provides part of a path, but no partition, use current
			//  partition and the users path
			strcpy (&path[2], args);
		else  {
			//  This takes care of the case where the user has provided a partial
			//  path.  It also must take care of the case where the user has
			//  provided no argument at all.  This code relies on the fact that
			//  the argument passed to this subroutine has had all white space
			//  eliminated before the argument was passed.
			strcat (path, args);	
		}
	}		
	if (path[strlen(path)-1] != '\\')
		strcat (path, "\\");
	strcat (path, "*");
	printf ("Directory of %s:\n", path);	
	
	#ifdef DEBUG
//	printf ("Calling disk power on (dir '%s')\n", path);
	#endif
	disk_power_on (path);
	

	/* Now do the dir */
	pc_seedir(&path[0]);

	//  Release all resources used by the disk the disk
//	pc_dskclose(&path[0]);
//	ide_close((int)(path[0]-'A'));									/*__fn__*/
//	pc_memory_close();

	#ifdef DEBUG
//	printf ("Calling disk power off (dir '%s')\n", path);
	#endif
	disk_power_off (path);

	return 0;
}	




//  List directory, and return number of matching file
int pc_seedir(char *path)                                          /*__fn__*/
{
    char *dirstr;
    int fcount = 0;
    DSTAT statobj;
    int year;
	unsigned long blocks_free, blocks_total;
	unsigned long nfree, Mbytes, kbytes, fraction;;

    /* Get the first match   */
//	printf ("pc_gfirst\n");    
    if (pc_gfirst(&statobj, path))
    {
//	printf ("outside while true\n");    
        while (TRUE)
        {
//	printf ("inside while true\n");        
            fcount++;
            if (statobj.fattribute & AVOLUME)
                 dirstr = "<VOL>";
            else if (statobj.fattribute & ADIRENT)
                 dirstr = "<DIR>";
            else
                 dirstr = "     ";

            printf("%-8s.%-3s", &(statobj.fname[0]), &(statobj.fext[0]));
            printf(" %7ld %5s", statobj.fsize, dirstr);
            printf(" %02d",(statobj.fdate >> 5 ) & 0xf); /* Month */
            printf("-%02d",(statobj.fdate & 0x1f));      /* Day */
            year = 80 +(statobj.fdate >> 9) & 0xff;
            if (year >= 100)
            	year -= 100;
            printf("-%02d", year); /* Year */
            printf(" %02d",(statobj.ftime >> 11) & 0x1f);    /* Hour */
            printf(":%02d",(statobj.ftime >> 5) & 0x3f);    /* Minute */
#if (VFAT)
            printf(" - %s\n", statobj.lfname);
#else
            printf("  \n");
#endif
             /* Get the next   */
             if (!pc_gnext(&statobj))
                 break;
        }
        /* Call gdone to free up internal resources used by statobj   */
        pc_gdone(&statobj);
    }

	//  And print the bytes remaining */
//	printf ("pc_free\n");	
	blocks_total = blocks_free = -1;
	nfree = pc_free (&path[0], &blocks_total, &blocks_free);
	if (blocks_total != -1)  {
		ASSERT (blocks_total > 0);
		//  Nfree is wrong for large drives because a long isn't enough to hold the number
		//  of bytes.  Report in k instead
		kbytes = (blocks_free /2);
		Mbytes = kbytes / 1024;
		kbytes = (kbytes % 1024L);
		fraction = (1000*kbytes)/1024L;
		printf ("       %-6d File(s)   %lu.%03lu MBytes free\n", fcount, Mbytes, fraction);
	}  else
		printf ("The disk did not respond\n");	

    return(fcount);
}





int cmd_disk_print (char* args)  {
	char filename[EMAXPATH];
	char* cp;
	PCFD fd;
	int n, nread, word_length;
	char buffer[512];
	
	if ((args == NULL) || (*args == '\0'))  {
		printf ("Need the name of the file to print.\n");
		return 0;
	}
	
	//  if user provides a full path, including the partition, use it
	if ((args[0] != '\0') && (args[1] == ':'))
		strcpy (filename, args);
	else  {
		//  If the user hasn't provided a full path, then we will use
		//  at least some part of the current working directory.
		//  If user has provided no path, use default
		strcpy (filename, wd);
		if (args[0] == '\\')
			//  if user provides part of a path, but no partition, use current
			//  partition and the users path
			strcpy (&filename[2], args);
		else  {
			//  This takes care of the case where the user has provided a partial
			//  path.  It also must take care of the case where the user has
			//  provided no argument at all.  This code relies on the fact that
			//  the argument passed to this subroutine has had all white space
			//  eliminated before the argument was passed.
			strcat (filename, args);	
		}
	}		
//	printf ("Printing file %s:\n", filename);	

	disk_power_on (filename);

	//  open the file
	fd = po_open (filename, (unsigned int)(PO_BINARY|PO_RDONLY), PS_IREAD);
	if (fd < 0)  {
		printf ("Cannot open '%s': %s\n\n", filename, get_errno_string (-1));
	    // Release all resources used by the disk the disk
 		disk_power_off (filename);
		return -1;
	}
	
	//  Files are assumed to be either science data files, ending with ".SCI" or
	//	engineering data files, ending with "ENG", or they are treated as normal
	//  text files.  The individual loggers are called to print their own
	//  files rather than having the command program make an assumption regarding
	//  the format.
	cp = filename;
	while ((*cp != '.') && (*cp != '\0'))
		cp++;
	if ((*cp != '\0') && (strcmp (cp+1, "SCI") == 0))  {
		sci_logger_print_file (fd);
	}  else  {
		if ((*cp != '\0') && (strcmp (cp+1, "ENG") == 0))  {
			eng_logger_print_file (fd);
		}  else  {
			//  normal text file
			printf ("Printing text file '%s':\n", filename);
			while ((nread = po_read(fd,(byte*)buffer, sizeof(buffer))) > 0)  {
				for (n = 0;  n < nread;  n++)
					putchar (buffer[n]);
				if (SerByteAvail ())  {
					printf ("\n\nPrint command interrupted.\n");	
					break;
				}	
			}
			printf ("\n");
			if (nread < 0)  {
				printf ("cmd_disk_print: Error while reading file (%s)\n", get_errno_string (-1));
				printf ("Aborting file print.\n");
			}	
		}	
	}	
	
	//  close out file descriptor
	po_close(fd);

    // Release all resources used by the disk the disk
 	disk_power_off (filename);
 	return 0;
}





//  cmd_show_setup_data ()
//
//  Prints the current setup data
//
int cmd_show_setup_data (char* args)  {
	eeprom_print_setup_data ();
	return 0;
}
	



//  cmd_suspend_logger ()
//
//  Shuts down the logger function for the specified length of
//  time, if the length is valid.  This routine seems a little
//  odd in that it accesses routines in the file main.c, which
//  is nominally a level above this, not below
//
int cmd_suspend_logger (char* args)  {
	long length;

	if (args[0] == '\0')  {
		printf ("You must specify how long to suspend for.\n");
		return 0;
	}

	length = atol (args);
	if (length <= 0)  {
		printf ("Suspension times must be greater than zero.\n");
		return 0;
	}	
	
	if (logger_suspend (length) < 0)  {
		printf ("Suspend logger command NOT executed.\n");
		printf ("The logger can be suspended for at most %ld seconds\n",
															MAX_SUSPENSION_TIME);
		return 0;
	}

	printf ("The logger has been suspended for %ld seconds.\n", length);
	return 0;
}




//  cmd_start_logger ()
//
//	Restarts the logger
//  Equivalent to suspend_logger (0)
//
int cmd_start_logger (char* args)  {
	if (logger_start () < 0)  {
		log_printf ("Could not start the logger.\n");
		return -1;
	}
	
	printf ("The data logger is now processing data.\n");
	return 0;
}



int cmd_save_setup (char* args)  {
	setup_data.tick_offset = logger_time_get_tick_offset ();
	if (eeprom_write_setup_data (0) != 0)  {
		printf ("Error: write of setup data failed.\n");
		return -1;
	}  else
		printf ("Setup data saved to EEPROM.\n");
	return 0;
}	



int cmd_sensor_power (char* args)  {
	ASSERT (args != NULL);
	
	if (strcmp (args, "ON") == 0)  {
		SensorPowerON ();
		printf ("The sensor power is now on.\n");
		return 0;
	}

	if (strcmp (args, "OFF") == 0)  {
		SensorPowerOFF();
		printf ("The sensor power is now off.\n");
		printf ("You MUST turn it back on manually before final deployment.\n");
		printf ("The software will NOT do this automatically!\n");
		return 0;
	}
	
	printf ("Must specify whether power is to be turned ON or OFF.\n\n");
	return -1;
}



int cmd_print_version (char* args)  {
    extern const float SOFTWARE_VERSION;
    
    printf ("This is software version %.3f\n", SOFTWARE_VERSION);
 	printf("Compiled on %s at %s\n", __DATE__, __TIME__);
	return 0;
}	    




int cmd_set_clock (char* args)  {
	long freq;
	long baud;
	
	printf ("Current frequency is %ld\n", SimGetFSys ());

	freq = atol (args);
	if ((freq > 16e6) ||
		(freq < 1e6 )   )  {
		printf ("Unacceptable frequency %ld\n", freq);
		printf ("Limits are 1 and 16 MHz\n");
		return 0;
	}
	logger_set_clock_rate (freq);
	printf ("New frequency is %.3f MHz\n", SimGetFSys()/1e6);
	printf ("Baud rate is %ld\n", (long)SerGetBaud (0, 0));
	return 0;
}	



	
	
int cmd_test (char* args)  {
    int a, b, c;
    long test, baud;

	pc_file_system_reset ();
	printf ("%ld memory available\n", mem_find_max_malloc());
	return 0;
	
	
	sci_logger_setup_partition ();
	return 0;

	printf ("There are %ld points waiting.\n", AD7716_get_n_waiting ());
	printf ("Elapsed time = %.3f\n", (float)((float)StopWatchTime()/1.0e6));
	StopWatchStart ();
	AD7716_icount_print ();
//	printf ("cmd_test: entering low power sleep mode\n");
//	low_power_start_sleep ();
    return 0;
    
//	printf ("Hit any key to quit reading time.\n");
//  while (SerByteAvail () == 0)  {
//    	cmd_sync_print_time (NULL);
//	}
    return 0;
}	
		