/******************************************************************************\
**	cfxmain.c		Persistor and PicoDOS starter C file
**						Main routine for Accelerometer Logger Project		  
**	
*****************************************************************************
**	
**	
*****************************************************************************
**	
**	
\******************************************************************************/

#include	<cfxbios.h>		// Persistor BIOS and I/O Definitions
#include	<cfxpico.h>		// Persistor PicoDOS Definitions

#include	<assert.h>
#include	<ctype.h>
#include	<errno.h>
#include	<float.h>
#include	<limits.h>
#include	<locale.h>
#include	<math.h>
#include	<setjmp.h>
#include	<signal.h>
#include	<stdarg.h>
#include	<stddef.h>
#include	<stdio.h>
#include	<stdlib.h>
#include	<string.h>
#include	<time.h>

#include	<dirent.h>		// PicoDOS POSIX-like Directory Access Defines
#include	<dosdrive.h>	// PicoDOS DOS Drive and Directory Definitions
#include	<fcntl.h>		// PicoDOS POSIX-like File Access Definitions
#include	<stat.h>		// PicoDOS POSIX-like File Status Definitions
#include	<termios.h>		// PicoDOS POSIX-like Terminal I/O Definitions
#include	<unistd.h>		// PicoDOS POSIX-like UNIX Function Definitions

#include "pta.h"
#include "accel.h"

#define MAX_STR 256

#define MAX_MEAS_FREQ 10000.0  // Hz
#define MIN_MEAS_FREQ 0.077  // Hz
#define MICROSECOND_TIMER_RESOLUTION 100.0  // 100 microseconds
#define MILLISECOND_TIMER_RESOLUTION 51.0   // 51 milliseconds
#define MAX_MICROSECOND_TIMER_PERIOD 0.0255  // Seconds

#define DUTYCYCLE_PERIODS 10

#define MEAS_BLOCK_SIZE 512  //Resulting data files will be multiples of this size.

#define BYTES_PER_SAMPLE 2  // Stored as Unsigned Short Integer (16bit)
#define NUM_ACCEL_CHANNELS 3 // Three axis logger


typedef struct 
{
 int samp_per;  // 7200 second sample period default
 int samp_dur; //  600 second sample duration default
 int meas_freq; // Nominal 10 Hz measurement frequency default
 time_t start_time;
 time_t stop_time;
} schedule_parameters;

typedef struct 
{
 bool ms_timer;  // if true, use 51ms timer.
 int meas_period_ticks;
 float timer_period;
 float meas_freq_hz;
 long samp_blocks;
 float actual_sample_dur;
 ulong num_of_samples;
 long mem_req;
} logging_parameters;


typedef struct 
{
 time_t start_time; 
 float meas_freq; 
 ulong number_of_measurements;
 double calibration_bias1;    // accel = duty_cycle*bias + offset  (duty_cycle = (-1.0:1.0);
 double calibration_offset1;
 double calibration_bias2;    // accel = duty_cycle*bias + offset  (duty_cycle = (-1.0:1.0);
 double calibration_offset2;
 double calibration_bias3;    // accel = duty_cycle*bias + offset  (duty_cycle = (-1.0:1.0);
 double calibration_offset3;
} data_header;

typedef struct
{
int data_tpu_chan;
double calibration_bias;    // accel = duty_cycle*bias + offset  (duty_cycle = (-1.0:1.0);
double calibration_offset;

IEVCWrapper *tpu_isr;

volatile ulong pulse_counts;
ulong dataptnum;

ulong *databuf;

} accelerometer_axis;

schedule_parameters user_sched_parms = {3600,600,10}; //{7200,600,10};
logging_parameters log_parms;

accelerometer_axis axis[4];


IEV_C_FUNCT(TPU2_ISR)
{
axis[0].pulse_counts = 65536*TPU.PRAM[2][4] + TPU.PRAM[2][5];

TPU.PRAM[2][4] = 0;

// Disable Chan 2 PTA to make one-shot
/* Disable the channel by clearing the two channel priority bits */
TPU.CPR1 &= (short int) ~(0x3 << 4);
  
/* Clear outstandinf interrupt (if any). */
TPU.CISR &= ~(1 << 2);
return;
}



IEV_C_FUNCT(TPU3_ISR)
{
axis[2].pulse_counts = 65536*TPU.PRAM[3][4] + TPU.PRAM[3][5];

TPU.PRAM[3][4] = 0;

// Disable Chan 3 PTA to make one-shot
/* Disable the channel by clearing the two channel priority bits */
TPU.CPR1 &= (short int) ~(0x3 << 6);
  
/* Clear outstandinf interrupt (if any). */
TPU.CISR &= ~(1 << 3);
return;
}



IEV_C_FUNCT(TPU5_ISR)
{
axis[1].pulse_counts = 65536*TPU.PRAM[5][4] + TPU.PRAM[5][5];

TPU.PRAM[5][4] = 0;

// Disable Chan 3 PTA to make one-shot
/* Disable the channel by clearing the two channel priority bits */
TPU.CPR1 &= (short int) ~(0x3 << 10);
  
/* Clear outstandinf interrupt (if any). */
TPU.CISR &= ~(1 << 5);
return;
}


IEV_C_FUNCT(TPU6_ISR)
{
axis[3].pulse_counts = 65536*TPU.PRAM[6][4] + TPU.PRAM[6][5];

TPU.PRAM[6][4] = 0;

// Disable Chan 3 PTA to make one-shot
/* Disable the channel by clearing the two channel priority bits */
TPU.CPR1 &= (short int) ~(0x3 << 12);
  
/* Clear outstandinf interrupt (if any). */
TPU.CISR &= ~(1 << 6);
return;
}




double round(double f);
double round(double f) {
 	return floor(f + 0.5);
 }




void MyChore(void);
void MyChore(void)
{
// Enable TPU/PTA to measure on time
axis[1].pulse_counts = 0; 
axis[2].pulse_counts = 0;
axis[3].pulse_counts = 0;

pta_start(axis[1].data_tpu_chan,DUTYCYCLE_PERIODS,axis[1].tpu_isr,PTA_TCR1 | PTA_HIGH_WIDTH); //TPU Channel 2
//while(!axis[1].pulse_counts);
pta_start(axis[2].data_tpu_chan,DUTYCYCLE_PERIODS,axis[2].tpu_isr,PTA_TCR1 | PTA_HIGH_WIDTH); //TPU Channel 3
//while(!axis[2].pulse_counts);
pta_start(axis[3].data_tpu_chan,DUTYCYCLE_PERIODS,axis[3].tpu_isr,PTA_TCR1 | PTA_HIGH_WIDTH); //TPU Channel 5
  //while(!axis[3].pulse_counts);


// Wait for all axes to update.  //Need to add time-out here.
while(!axis[1].pulse_counts || !axis[2].pulse_counts || !axis[3].pulse_counts);
//printf("dptnum %ld %ld %ld \n",axis[1].dataptnum,axis[2].dataptnum,axis[3].dataptnum);
//printf("cts = %d-%ld  %d-%ld %d-%ld \n",1,axis[1].pulse_counts,2,axis[2].pulse_counts,3,axis[3].pulse_counts);


// Convert and Store data
axis[1].databuf[axis[1].dataptnum] = axis[1].pulse_counts;
axis[2].databuf[axis[2].dataptnum] = axis[2].pulse_counts;
axis[3].databuf[axis[3].dataptnum] = axis[3].pulse_counts;

axis[1].dataptnum++;
axis[2].dataptnum++;
axis[3].dataptnum++;
} 




/****************************************************************************	
**  Set date and time:
**  This method is a little suspect, hitting return on the time 'cause
**  it looks right actually delays the RTC, cause it sets the clock to the
**  shown default, which is the time when the call was made.
*****************************************************************************/
int set_time();
int set_time()
{
	int i;
	struct tm *time_ptr;
	time_t current_time;
	
	
	time(&current_time);
	printf("\nCurrent date and time: %s\n",asctime(gmtime(&current_time)));

	if(QRconfirm("Reset date and time? ",false,true))
	{
	  time(&current_time);	 
	  time_ptr = gmtime(&current_time);
	  QRdate("\nEnter Date: ",true,true,MMDDYY,time_ptr);
	  QRtime("\nEnter Time: ",true,time_ptr);

	  RTCSetTime(mktime(time_ptr),0);
	}
	for(i = 0;i<5;i++)
	  {
	  	RTCDelayMicroSeconds(500000);
	  	time(&current_time);
	  	printf("\nCurrent date and time: %s\n",asctime(gmtime(&current_time)));
	  	RTCDelayMicroSeconds(500000);
	  }
	if(QRconfirm("Is time Correct?",true,true)) return 1;
	else return 0;
}	

int file_actions();
int file_actions()
{
return 1;
}


void print_log_parms();
void print_log_parms()
{
	if(log_parms.ms_timer)  printf("using 51ms Timer \n");
	else printf("using microsecond timer \n");
	printf("Actual Measurement Frequency = %f Hz\n",log_parms.meas_freq_hz);
	printf("Actual Sample Duration = %f Seconds\n",log_parms.actual_sample_dur);
	printf("Memory Requirements per Sample = %ld bytes \n",log_parms.mem_req);
}	


	
/****************************************************************************	
**  Compute measurement parameter details
*****************************************************************************/
void compute_measurement_parameters();
void compute_measurement_parameters()
{
float meas_per;

	meas_per = 1.0/user_sched_parms.meas_freq; // Desired period in seconds
	if(meas_per < MAX_MICROSECOND_TIMER_PERIOD)  //Use microsecond PIT Timer as millisecond timer is 51ms minimum
	{
	log_parms.ms_timer = false;
	log_parms.meas_period_ticks = round(meas_per/(MICROSECOND_TIMER_RESOLUTION/1000000.0));
	log_parms.timer_period = log_parms.meas_period_ticks*MICROSECOND_TIMER_RESOLUTION/1000000.0;
	log_parms.meas_freq_hz = 1000000.0/(MICROSECOND_TIMER_RESOLUTION*log_parms.meas_period_ticks);
	}
	else			   //Use millisecond PIT Timer
	{
	log_parms.ms_timer = true;
	log_parms.meas_period_ticks = round(meas_per/(MILLISECOND_TIMER_RESOLUTION/1000.0));
	if(log_parms.meas_period_ticks <= 0) log_parms.meas_period_ticks = 1;
	log_parms.timer_period = log_parms.meas_period_ticks*MILLISECOND_TIMER_RESOLUTION/1000.0;
	log_parms.meas_freq_hz = 1000.0/(MILLISECOND_TIMER_RESOLUTION*log_parms.meas_period_ticks);
	}
	
	//log_parms.samp_blocks = ceil(user_sched_parms.samp_dur/(MEAS_BLOCK_SIZE*log_parms.timer_period));
	//log_parms.actual_sample_dur = MEAS_BLOCK_SIZE*log_parms.samp_blocks*log_parms.timer_period;
	
	//log_parms.mem_req = log_parms.samp_blocks*(NUM_ACCEL_CHANNELS*BYTES_PER_SAMPLE*MEAS_BLOCK_SIZE);

	log_parms.samp_blocks = round((NUM_ACCEL_CHANNELS*BYTES_PER_SAMPLE*user_sched_parms.samp_dur*log_parms.meas_freq_hz+sizeof(data_header))/MEAS_BLOCK_SIZE);
	log_parms.num_of_samples = floor((log_parms.samp_blocks*MEAS_BLOCK_SIZE-sizeof(data_header))/(NUM_ACCEL_CHANNELS*BYTES_PER_SAMPLE));
	log_parms.actual_sample_dur = log_parms.num_of_samples/log_parms.meas_freq_hz;
	
	log_parms.mem_req = log_parms.samp_blocks*MEAS_BLOCK_SIZE;


}


void print_user_parms();
void print_user_parms()
{
	printf("Sample Period = %d seconds \n",user_sched_parms.samp_per);
	printf("Sample Duration = %d seconds \n",user_sched_parms.samp_dur);
 	printf("Measurement Frequency = %d Hz \n",user_sched_parms.meas_freq);

	printf("\nThe first measurements will be made at %s \n",asctime(gmtime(&(user_sched_parms.start_time))));
	printf("\nThe last measurements will be made at %s \n",asctime(gmtime(&(user_sched_parms.stop_time))));

}	
/****************************************************************************	
**  Prompt user for measurement parameters
*****************************************************************************/
int get_user_schedule_parameters();
int get_user_schedule_parameters()
{
struct tm *time_ptr;
	
	printf("\n");
	printf("\n  <--------------------Sample Period------------------->      ");
	printf("\n   ___________________                                   _____");
	printf("\n  |                   |                                 |     ");
	printf("\n  |                   |                                 |     ");
	printf("\n  |                   |                                 |     ");
	printf("\n__|                   |_________________________________|     ");
	printf("\n  <--Sample Duration-->                                       ");
	printf("\n\n\n");
	
	QRshort("\nEnter sample period (seconds): ","%d", true,&(user_sched_parms.samp_per),0,0);	
	QRshort("\nEnter sample duration (seconds): ","%d",true,&(user_sched_parms.samp_dur),0,0);
	QRshort("\nEnter measurement frequency (Hz): ","%d",true,&(user_sched_parms.meas_freq),MIN_MEAS_FREQ,MAX_MEAS_FREQ);

 	 printf("\n\nEnter date and time to take first measurement\n");
	 time(&(user_sched_parms.start_time));	 
	 user_sched_parms.start_time += user_sched_parms.samp_per;
	 time_ptr = gmtime(&(user_sched_parms.start_time));
	 QRdate("\nEnter Date: ",true,true,MMDDYY,time_ptr);
	 QRtime("\nEnter Time: ",true,time_ptr);
	 
	 user_sched_parms.start_time = mktime(time_ptr);

	 printf("\n\nEnter date and time to take final measurement\n");
	 user_sched_parms.stop_time = user_sched_parms.start_time+31536000L;
	 time_ptr = gmtime(&(user_sched_parms.stop_time));
	 QRdate("\nEnter Date: ",true,true,MMDDYY,time_ptr);
	 QRtime("\nEnter Time: ",true,time_ptr);
	 
	 user_sched_parms.stop_time = mktime(time_ptr);
	
	print_user_parms();
	 
	if(QRconfirm("Is this correct?",true,true)) return 1;
		else return 0;

}

int calibrate_axis(int axis_num);
int calibrate_axis(int axis_num)
{
ulong cal_plus_cnts;
ulong cal_minus_cnts;
ulong cal_period_cnts;
double cal_plus,cal_minus;

printf("Position axis %d to positive one g (point upwards)\n",axis_num);
printf("Hit space bar when positioned\n");
SCIRxFlush();
while(SCIRxGetChar() != 32);

//Enable TPU/PTA to measure PWM one time
	axis[axis_num].pulse_counts = 0;
	pta_start(axis[axis_num].data_tpu_chan,100,axis[axis_num].tpu_isr,PTA_TCR1 | PTA_HIGH_WIDTH); //TPU Channel 2
	
	printf("TCR1 Clock = %ld Hz \n",TPUGetTCR1Clock());
	
while(!axis[axis_num].pulse_counts);



cal_plus_cnts = axis[axis_num].pulse_counts;
printf("positive g on time = %ld counts \n",cal_plus_cnts);


printf("Position axis %d to negative one g (point downwards)\n",axis_num);
printf("Hit space bar when positioned\n");
SCIRxFlush();
while(SCIRxGetChar() != 32);

//Enable TPU/PTA to measure PWM one time
	axis[axis_num].pulse_counts = 0;
	pta_start(axis[axis_num].data_tpu_chan,100,axis[axis_num].tpu_isr,PTA_TCR1 | PTA_HIGH_WIDTH); //TPU Channel 2
	
while(!axis[axis_num].pulse_counts);

cal_minus_cnts = axis[axis_num].pulse_counts;
printf("negative g on time = %ld counts \n",cal_minus_cnts);




//Enable TPU/PTA to measure PWM Period
	axis[axis_num].pulse_counts = 0;
	pta_start(axis[axis_num].data_tpu_chan,100,axis[axis_num].tpu_isr,PTA_TCR1 | PTA_PERIOD_RISING); //TPU Channel 2
	
while(!axis[axis_num].pulse_counts);

cal_period_cnts = axis[axis_num].pulse_counts;

	printf("period length = %ld counts \n",cal_period_cnts);

cal_plus  = ((double) cal_plus_cnts)/cal_period_cnts; 
cal_minus = ((double) cal_minus_cnts)/cal_period_cnts; 

axis[axis_num].calibration_bias = 2.0/(cal_plus-cal_minus);
axis[axis_num].calibration_offset = -1.0 - axis[axis_num].calibration_bias * cal_minus;


printf("Calibration of axis %d complete \n",axis_num);
printf("bias = %g offset = %g \n\n",axis[axis_num].calibration_bias,axis[axis_num].calibration_offset);
}

int main_menu();
int main_menu()
{
int main_selection;
int what_woke;
int ready_to_deploy = 0;
int fd;

do
{

printf("\n");
printf("1) Set Date and Time        \n");
printf("2) File Actions             \n");
printf("3) Set Deploy Parameters    \n");
printf("4) Calibrate Accelerometers \n");
printf("5) Verify and Deploy        \n");
printf("6) Data Offload             \n");
printf("7) Exit to PicoDos          \n");
printf("8) Sleep                    \n");
printf("\n");

QRshort("Enter Selection: ","%d",false,&main_selection,1,8);

printf("\n");


switch(main_selection)
{
case 1:
	while(!set_time());
	break;
case 2:
	printf("File Actions Selected \n");
	break;
case 3:
	printf("Set Deploy Parameters selected\n");
	while(!get_user_schedule_parameters());
	break;
case 4:
	printf("Calibrate Accelerometers selected \n");
	
// Turn on Accelerometers
	PinSet(22);
	PinSet(25);
	
	calibrate_axis(1);
	calibrate_axis(2);
	calibrate_axis(3);
	
// Turn on Accelerometers
	PinClear(22);
	PinClear(25);
	
	break;	
case 5:
	printf("Verify and Deploy selected\n");
	compute_measurement_parameters();
	print_log_parms();
	if(QRconfirm("Is this correct?",true,true))
	{
	   //Store state.
	   fd = open("deploy.dat",O_WRONLY | O_CREAT | O_TRUNC);
		if (fd <= 0)
		    {
			printf("Error opening deploy.dat \n");
			printf("Continuing with deployment but setup won't be saved \n");
			}
		else
		{
		   printf("Storing setup in deploy.dat\n");
		   write(fd,&user_sched_parms,sizeof(schedule_parameters));
		   write(fd,&log_parms,sizeof(logging_parameters));
		   write(fd,&(axis[1].calibration_bias),sizeof(double));
		   write(fd,&(axis[1].calibration_offset),sizeof(double));
		   write(fd,&(axis[2].calibration_bias),sizeof(double));
		   write(fd,&(axis[2].calibration_offset),sizeof(double));
		   write(fd,&(axis[3].calibration_bias),sizeof(double));
		   write(fd,&(axis[3].calibration_offset),sizeof(double));
		   write(fd,&(axis[0].calibration_bias),sizeof(double));
		   write(fd,&(axis[0].calibration_offset),sizeof(double));



		   //write(fd,&(axis[1]),sizeof(accelerometer_axis));
		   //write(fd,&(axis[2]),sizeof(accelerometer_axis));
		   //write(fd,&(axis[3]),sizeof(accelerometer_axis));

		   close(fd);
		}
	   ready_to_deploy = 1;
	}
	break;
case 6:
	printf("Data Offload selected\n");
	break;
case 7:
	printf("Exit to PicoDos selected\n");
	BIOSResetToPicoDOS();	// full reset, but jump to 0xE10000 (PicoDOS)
	break;	
case 8:
	printf("Sleep until WAKE button pressed\n");
	PWRSuspendSecs(LONG_MAX, false, WakeTmtOrWAKEFall);   //Wake to Reset on Wake pin.
	
	break;
default:
	printf("ruh-row, shouldn't be here \n");

} 

} while(!ready_to_deploy);

return 1;

}


/******************************************************************************\
**	main
\******************************************************************************/
int main()
	{
	
	short key;
	
	short	i;
	
	short what;
	
	struct tm *time_ptr;
	time_t wake_time;

	ulong sample_num;
	
	ulong measurements;
	
	char *data_image;
	ushort *datastore1;
	ushort *datastore2;
	ushort *datastore3;


	char dirname[MAX_STR/2];
	char filename[MAX_STR];
	char month_name[MAX_STR];
	int fd;

	time_t current_time; 
	long delay_seconds;
	
	data_header header;

	TMGSetSpeed(640);  
	//printf("Speed = %d kHz \n",TMGGetSpeed());

	
	PinClear(28);
	PinClear(29);
	PinClear(30);
	PinClear(31);
	PinClear(32);
	PinClear(33);
	PinClear(34);
	PinClear(35);
	PinClear(37);


/*
	// Identify the progam and build
	printf("\nProgram: %s: %s %s \n", __FILE__, __DATE__, __TIME__);
	// Identify the device and its firmware
	printf("Persistor CF%d SN:%ld   BIOS:%d.%d   PicoDOS:%d.%d\n", CFX,
		BIOSGVT.CFxSerNum, BIOSGVT.BIOSVersion, BIOSGVT.BIOSRelease, 
		BIOSGVT.PICOVersion, BIOSGVT.PICORelease);
*/
	
	   //Store state.
	   fd = open("deploy.dat",O_RDONLY);
		if (fd <= 0)
		    {
			printf("deploy.dat does not exist. \n");
			printf("Continuing with deployment with  default schedule. \n");
			printf("This can be modified by hitting Ctrl-X below and entering menu \n");
			time(&(user_sched_parms.start_time));
			}
		else
		{
		   printf("Retrieving Deployment schedule and status from flash\n");
		   read(fd,&user_sched_parms,sizeof(schedule_parameters));
		   read(fd,&log_parms,sizeof(logging_parameters));
		   read(fd,&(axis[1].calibration_bias),sizeof(double));
		   read(fd,&(axis[1].calibration_offset),sizeof(double));
		   read(fd,&(axis[2].calibration_bias),sizeof(double));
		   read(fd,&(axis[2].calibration_offset),sizeof(double));
		   read(fd,&(axis[3].calibration_bias),sizeof(double));
		   read(fd,&(axis[3].calibration_offset),sizeof(double));
		   read(fd,&(axis[0].calibration_bias),sizeof(double));
		   read(fd,&(axis[0].calibration_offset),sizeof(double));

		   close(fd);
		   
		   time(&current_time);

		   if(current_time > user_sched_parms.stop_time)
			 PWRSuspendUntil(current_time+7*24*3600,false,WakeTmtOrWAKEFall); // Sleep for a week and check again

		}
		
		
compute_measurement_parameters();
	
//Init axis structures;	

	axis[1].data_tpu_chan = 5;
	axis[1].tpu_isr = &TPU5_ISR;

	axis[2].data_tpu_chan = 3;
	axis[2].tpu_isr = &TPU3_ISR;
		
	axis[3].data_tpu_chan = 6;
	axis[3].tpu_isr = &TPU6_ISR;
	
	axis[0].data_tpu_chan = 2;//Redundant Axis
	axis[0].tpu_isr = &TPU2_ISR;
	
	
//Run TPU once to work around "bug" related with first sample	
	PinSet(22);
	PinSet(25);
	
	axis[1].pulse_counts = 0; 
	axis[2].pulse_counts = 0;
	axis[3].pulse_counts = 0;

pta_start(axis[1].data_tpu_chan,1,axis[1].tpu_isr,PTA_TCR1 | PTA_HIGH_WIDTH); //TPU Channel 2
while(!axis[1].pulse_counts);
pta_start(axis[2].data_tpu_chan,1,axis[2].tpu_isr,PTA_TCR1 | PTA_HIGH_WIDTH); //TPU Channel 3
while(!axis[2].pulse_counts);
pta_start(axis[3].data_tpu_chan,1,axis[3].tpu_isr,PTA_TCR1 | PTA_HIGH_WIDTH); //TPU Channel 5
while(!axis[3].pulse_counts);
	PinClear(22);
	PinClear(25);
	
	
	
//	printf("Current Deployment Schedule\n");
//	print_user_parms();
//	print_log_parms();
//	printf("\n\n");
	
	i = 3;  // Give the user 3 seconds to hit Ctrl-C before moving on to measurement phase 
	printf("Hit Ctrl-X within 3 seconds to enter set-up\n");
	fflush(stdout);
	
	while(i>0)
	{
	printf("%d..",i--);  fflush(stdout);
	key = SCIRxGetCharWithTimeout(1000);
	if (key != -1)  break;
	}
	
	
	if (key == 24)
	{
		printf("\n\nEnter M to Enter Main Menu \n");
		key = SCIRxGetCharWithTimeout(10000);
		if(key == 'M' || key == 'm')
			main_menu();
	}
	
	
	/*
	QSMStop();
	EIAForceOff(true);
	*/

	
	
	

/****************************************************************************	
**  Make measurements
*****************************************************************************/

	measurements = log_parms.num_of_samples;
	
	axis[1].databuf = calloc(measurements,sizeof(ulong));
	axis[2].databuf = calloc(measurements,sizeof(ulong));
	axis[3].databuf = calloc(measurements,sizeof(ulong));
	
	data_image = (char *) malloc(log_parms.mem_req);
	
	datastore1 = (ushort *) (data_image+sizeof(data_header));
	datastore2 = (ushort *) ((char *) datastore1 + measurements*sizeof(short));
	datastore3 = (ushort *) ((char *) datastore2 + measurements*sizeof(short));
	
	
	sample_num = 0;
	while(sample_num < LONG_MAX)  // Outer loop for samples
	{
	  do					//This algorithm advances the sample number if neccessary
	  {						//to ensure wake_time is after current time, but still on schedule.
	    time(&current_time);
	    wake_time = user_sched_parms.start_time+sample_num*user_sched_parms.samp_per;
	    delay_seconds = wake_time-current_time;
	    sample_num++;
	  } while (delay_seconds < 0L);
	  
	  printf("Sleeping until %s \n",asctime(gmtime(&wake_time)));
	  


	if(delay_seconds < 20)
	  RTCDelayMicroSeconds(1000000*delay_seconds); //This is temporarily here until suspend problems are fixed.
	else
	  what = PWRSuspendUntil(wake_time-20,false,WakeTmtOrWAKEFall);  //Sleep until next scheduled sample period

/*
    what = PWRSuspendUntil(wake_time,true,WakeTmtOrWAKEFall);  //Sleep until next scheduled sample period
	PinBus(23);
	PinBus(24);
	PinBus(26);
	PinBus(27);
*/
  
//      printf("Woken by %d \n",what);
//		TPUInit();
	

// Turn on Accelerometers
	PinSet(22);
	PinSet(25);

	
	  printf("Making %ld measurements at %f Hz\n",measurements,log_parms.meas_freq_hz);
	  axis[1].dataptnum = 0L;
	  axis[2].dataptnum = 0L;
	  axis[3].dataptnum = 0L;


	  PITInit(5);
	  if(log_parms.ms_timer)
	  	PITSet51msPeriod(log_parms.meas_period_ticks);
	  else
		PITSet100usPeriod(log_parms.meas_period_ticks);
		 
	  PITAddChore(MyChore,6);
	  

	
	  
	  while(axis[1].dataptnum < measurements)
	  {
	   	LPStopCSE(CPUStop);     // LPStop sleep until PIT wakes things up.  I still
	   							 //	don't know why FullStop and FastStop screw up the
	   							 // serial coms.
	  };
	  


	  if(log_parms.ms_timer)
	  	PITSet51msPeriod(PITOff);
	  else
	  	PITSet100usPeriod(PITOff);
	  	
	  PITRemoveChore(MyChore);	




/* * * * * * * * * * * * * * * *
** Measure Period
* * * * * * * * * * * * * * * */


//Enable TPU/PTA to measure PWM Period
	axis[1].pulse_counts = 0;
	axis[2].pulse_counts = 0;
	axis[3].pulse_counts = 0;

	pta_start(axis[1].data_tpu_chan,DUTYCYCLE_PERIODS,axis[1].tpu_isr,PTA_TCR1 | PTA_PERIOD_RISING); //TPU Channel 1
	pta_start(axis[2].data_tpu_chan,DUTYCYCLE_PERIODS,axis[2].tpu_isr,PTA_TCR1 | PTA_PERIOD_RISING); //TPU Channel 1
	pta_start(axis[3].data_tpu_chan,DUTYCYCLE_PERIODS,axis[3].tpu_isr,PTA_TCR1 | PTA_PERIOD_RISING); //TPU Channel 1
	
	while(!axis[1].pulse_counts || !axis[2].pulse_counts || !axis[3].pulse_counts);

//printf("cts: %d-%ld  %d-%ld %d-%ld \n",1,axis[1].pulse_counts,2,axis[2].pulse_counts,3,axis[3].pulse_counts);



// Turn off Accelerometers
	PinClear(22);
	PinClear(25);


/* * * * * * * * * * * * * * * *
** Store Results 
* * * * * * * * * * * * * * * */
	
	
	header.start_time = wake_time;
	header.meas_freq = log_parms.meas_freq_hz;
	header.number_of_measurements = measurements;
	header.calibration_bias1 = axis[1].calibration_bias;	
	header.calibration_offset1 = axis[1].calibration_offset;
	header.calibration_bias2 = axis[2].calibration_bias;
	header.calibration_offset2 = axis[2].calibration_offset;
	header.calibration_bias3 = axis[3].calibration_bias;
	header.calibration_offset3 = axis[3].calibration_offset;
	
	memcpy(data_image,&header,sizeof(data_header));
		
	  for(i = 0;i<measurements;i++)
	  {
	    datastore1[i] = (axis[1].databuf[i] * 0xffff)/axis[1].pulse_counts;
	 	datastore2[i] = (axis[2].databuf[i] * 0xffff)/axis[2].pulse_counts;
 	    datastore3[i] = (axis[3].databuf[i] * 0xffff)/axis[3].pulse_counts;
	  }
	
	  time_ptr = gmtime(&wake_time);
	  
	  strftime(month_name, 4, "%b", time_ptr);
	  
	  sprintf(dirname,"C:\\%s%d",month_name,1900+time_ptr->tm_year);
	
	
	   CFEnable(true);
	
		//printf("%s\n",dirname);
		mkdir(dirname,S_IFDIR);
		//printf("mkdir returns %d ",mkdir(dirname,S_IFDIR));
	    //printf("errno = %d\n",errno);
		
	
		sprintf(filename,"%s\\%8.8lX.dat",dirname,wake_time);

		fd = open(filename,O_WRONLY | O_CREAT | O_TRUNC);

		
		printf("fd = %d\n",fd);
		if (fd <= 0)
		    {
			printf("Error opening %s \n",filename);
			BIOSReset();			// full hardware reset
			}
		else
		{
		   printf("Writing data to  %s\n",filename);
		   write(fd,data_image,log_parms.mem_req);
		   close(fd);
		}
	
		CFEnable(false);

	 }

	free(axis[1].databuf);	 
	free(axis[2].databuf);	 
	free(axis[3].databuf);	 

	  
// Various exit strategies
//	BIOSReset();			// full hardware reset
//	BIOSResetToPBM();		// full reset, but stay in Pesistor Boot Monitor
//	BIOSResetToPicoDOS();	// full reset, but jump to 0xE10000 (PicoDOS)
	return 1;

	}	//____ main() ____//

