/* ROVFILE.C, ROVER FILE SYSTEM */

#include <TT7.h>
#include "rovfile.h"
#include "rovsys.h"
#include "rovlib.h"
#include <psram.h>
#include <time.h>
#include <stdio.h>
#include <timing.h>
#include <string.h>
#include <math.h>

#ifdef AZTEC_C
#include <offload.h>
#include <drive.h>
#include <pario.h>
#include <datafile.h>
#include <serio.h>
#include <userio.h>

#else                    /* Turbo C */
#include "tt7pclib.h"
#endif


/* Global Variables */

short df_count, record_count;
short g_curr_dir, g_curr_speed, g_heading;
long mem_size;
void *mem_start, *rov_data_start, *inst_mem_start, *inst_data_start;
unsigned char *inst_data_ptr;
unsigned long max_inst_bytes, max_rov_records;

struct file_header{
  unsigned long record_count;
} *file_head_ptr;

struct inst_file_header{
  ulong byte_count;
  ulong inst_start_time[4];
} *inst_head_ptr;

struct rov_data{
  short record_type;
  time_t caltime;
  short analog[8];
  short heading;
  short curr_speed;
  short curr_dir;
} *rov_data_ptr;

union {
  LongSample 		sample_struct;
  unsigned char		sample_buf[33];
} sample_union;

unsigned g_num_samples = 0;

/*******************************************************
	      Datafiles Function
********************************************************/

int datafiles(void){
  char menukey;
  short i, chan;
  unsigned long dfnum = 0;
  XmdmErr xerr;
  DriveErr derr;

  while(1){
    SerInFlush();
    printf("\n\n\nRover Datafiles Menu");
    printf("\n\n  1 -- Display File Status");
    printf("\n  2 -- Load Disk File to Memory");
    printf("\n  3 -- Offload Data Memory");
    printf("\n  4 -- Load Instrument Data");
    printf("\n  5 -- Store Memory to Disk");
    printf("\n  6 -- Display Rover Data");
    printf("\n  7 -- Display Inst. Data");
    printf("\n  8 -- Fill Memory with Test Data");
    printf("\n  9 -- Exit");
    QueryChar("\nEnter Selection: ",'9',"123456789a",&menukey);

    switch(menukey){

      case '1':  /*Datafile Status*/
	printf("\n\nMaximum Rover Data Records = %lu", max_rov_records);
	printf("\nMaximum Inst. Data Bytes = %lu", max_inst_bytes);
	printf("\nRover Data Records in Memory = %lu", file_head_ptr->record_count);
	printf("\nInst. Data Bytes in Memory = %lu", inst_head_ptr->byte_count);
	printf("\nDisk Files Written = %hd", df_count);
	break;

      case '2':  /* Load Disk Files */
	if( QueryNum("\nEnter disk file number to load: ","%lu", "%lu", &dfnum) ){
	  derr = DFRead(mem_start, (short)dfnum);
	  if(derr) printf("\nDisk file error: %d", derr);
	  else printf("\nDisk file loaded");
	}
	break;

      case '3':  /* Offload Data */
	offload();
	break;

      case '4':  /* Load Instrument Data */
	clear_inst_files();
	stbd_bc_pwr_on();
	delaysecs(1);
	port_bc_pwr_on();
	delaysecs(5);

	inst_transfer_data(STBD_BENCHAM);
	inst_transfer_data(PORT_BENCHAM);

	stbd_bc_pwr_off();
	port_bc_pwr_off();
	break;

      case '5':  /* Store Memory to Disk */
	if(QueryYesNo("\n\nStore memory to disk?", FALSE)){
	  mem_to_disk();
	}
	break;
	

      case '6':  /* Display Rover Data */
	display_data();
	break;

      case '7':  /* Display Inst. Data */
	inst_data_ptr = inst_mem_start;
	printf("\n");
	for(i = 0; i < inst_head_ptr->byte_count; i++){
	  SerPutByte(*inst_data_ptr);
	  inst_data_ptr++;
	}
	break;

      case '8':  /* Test Data */
	clear_rov_files();

	for(i = 1; i <= 100; i++){
	  rov_data_ptr->record_type = TRANSIT;
	  rov_data_ptr->caltime = time(0);
	  for(chan = 0; chan <= 7; chan++) rov_data_ptr->analog[chan] = 16380;
	  rov_data_ptr->heading = 359;
	  rov_data_ptr->curr_speed = 10;
	  rov_data_ptr->curr_dir = 359;

	  rov_data_ptr++;
	  file_head_ptr->record_count++;
	}

	printf("\n%lu test data files stored", file_head_ptr->record_count);
	break;

      case '9':  /* Exit */
	DriveOff();
	DisableParIO();
	return 0;

      case 'a':
	stbd_bc_pwr_on();
	delaysecs(1);
	port_bc_pwr_on();
	delaysecs(5);

	if(inst_start(STBD_BENCHAM)) printf("\nStbd benthic chamber not responding");
	else printf("\nStbd benthic chamber running");
	if(inst_start(PORT_BENCHAM)) printf("\nPort benthic chamber not responding");
	else printf("\nPort benthic chamber running");
	break;

    }  /* Switch ends */

  }  /* End of WHILE loop */

}


/****************************************************
	    File Functions
****************************************************/

int file_init(void){

  PSMemFreeAll();

  mem_start = PSMemAlloc(ROV_FILE_BLKS);   /* Allocate all free memory to file system */
  if(!mem_start){
    printf("\nRov. Data memory request failure");
    return -1;
  }

  file_head_ptr = mem_start;
  rov_data_start = file_head_ptr + 1;  /* Pointer arithmetic adds 4 */
  rov_data_ptr = rov_data_start;       /* Void pointer keeps compiler happy */
  max_rov_records = ROV_FILE_BLKS;
  max_rov_records *= (16384/sizeof(struct rov_data));
  file_head_ptr->record_count = 0;

  inst_mem_start = PSMemAlloc(INST_FILE_BLKS);
  if(!inst_mem_start){
    printf("\nInst. Data memory request failure");
    return -1;
  }

  inst_head_ptr = inst_mem_start;
  inst_data_start = inst_head_ptr + 1;
  inst_data_ptr = inst_data_start;
  max_inst_bytes =  INST_FILE_BLKS;
  max_inst_bytes *= 16384;
  inst_head_ptr->byte_count = 0;

  printf("\nFile system initialized");

  return 0;
}


/***********************************************/

int store_data(short type){
  short chan;

  rov_data_ptr->record_type = type;
  rov_data_ptr->caltime = time(0);
  for(chan = 0; chan <=7; chan++) rov_data_ptr->analog[chan] = get_ad_counts(chan);
  rov_data_ptr->heading = g_heading;
  if(type == CURRMET_DATA){
    rov_data_ptr->curr_speed = g_curr_speed;
    rov_data_ptr->curr_dir = g_curr_dir;
  }
  else{
    rov_data_ptr->curr_speed = -1;
    rov_data_ptr->curr_dir = -1;
  }
  rov_data_ptr++;
  file_head_ptr->record_count++;
  return 0;
}
/***********************************************/

void clear_rov_files(void){

  rov_data_ptr = rov_data_start;
  file_head_ptr->record_count = 0;
  return;
}

/***********************************************/

void clear_inst_files(void){

  inst_data_ptr = inst_data_start;
  inst_head_ptr->byte_count = 0;

  return;
}

/***********************************************/
int inst_start(int instrument){
  int x;
  char inbuf[80];

    setcomchan(instrument);
    delaysecs(1);
    TSerInFlush(13);
    TPuts("3");            /* Start data cycle */
    delaysecs(1);          /* Benthic chamber contoller is slow */
    TPuts("\n");
    for(x=0; x<5; x++){
      TGetsTimed(1000, inbuf);
      printf("\n%s", inbuf);
      if( !strcmp(inbuf, "Running...") ){     /* Check for confirmation string */
	inst_head_ptr->inst_start_time[instrument] = time(NOW);
	return 0;
      }
    }
    inst_head_ptr->inst_start_time[instrument] = 0;
    return -1;
}

/***********************************************/

int inst_transfer_data(int instrument){    /* Transfers data from rack instruments */
  setcomchan(instrument);
  delaysecs(1);
  TSerInFlush(13);
  TPuts("4");
  delaysecs(1);     /* Benthic chamber controller is slow */
  TPuts("\n");
  inst_store_data();

  return 0;
}

/***********************************************/

void inst_store_data(void){    /* Stores data from rack instruments */
  int inbyte;

  while(1){
    inbyte = TSerGetByteTimed(1000);
    if( inbyte == (-1) ) break;
    else{
      *inst_data_ptr++ = inbyte;    /* Store the data in hex form */
      inst_head_ptr->byte_count++;
    }
  }
  return;
}

/***********************************************/

void offload(void){
  char menukey;
  XmdmErr xerr;
  long length;

  while(1){
    SerInFlush();

    printf("\n\n\nOffload Menu");
    printf("\n\n1 -- Rover Data");
    printf("\n2 -- Instrument Data");
    printf("\n9 -- Exit");

    QueryChar("\nEnter Selection: ",'9',"12345789",&menukey);

    switch(menukey){
      case '1':
	printf("\n\nStarting XMODEM-1K transfer ... ");
	length = sizeof(struct file_header)
		 + file_head_ptr->record_count * sizeof(struct rov_data);
	xerr = XmodemSendMem(mem_start, length, 30);
	if(xerr) printf("\nXmodem error: %d", xerr);
	else printf("\nTransfer complete");
	break;

      case '2':
	printf("\n\nStarting XMODEM-1K transfer ... ");
	length = inst_head_ptr->byte_count;
	xerr = XmodemSendMem(inst_data_start, length, 30);
	if(xerr) printf("\nXmodem error: %d", xerr);
	else printf("\nTransfer complete");
	break;

      case '9':
	return;
    }
  }
}

/*****************************************************/

int display_data(void){
  int chan;
  unsigned long i;
  time_t rovtime;

  rov_data_ptr = rov_data_start;
  SerInFlush();

  for(i = 1; i <= file_head_ptr->record_count; i++){
      if( kbhit() ) break;

      printf("\n\n%hd ", rov_data_ptr->record_type);
      rovtime = rov_data_ptr->caltime;
      printf("   %s", ctime(&rovtime));
      printf("%6.2f ", ((float)rov_data_ptr->analog[0]/BATTCAL));
      printf("%6.2f ", (float)rov_data_ptr->analog[1]/HPCURRCAL);
      printf("%6.2f ", (float)rov_data_ptr->analog[2]/LPCURRCAL);
      printf("%6.2f ", (float)rov_data_ptr->analog[3]/GFVOLTCAL);
      printf("%5.1f ", (float)rov_data_ptr->analog[4]/TILTX_CAL-TILTX_OFFSET);
      printf("%5.1f ", (float)rov_data_ptr->analog[5]/TILTY_CAL-TILTY_OFFSET);
      printf("%5.1f ", (float)rov_data_ptr->analog[6]);
      printf("%5.1f ", (float)rov_data_ptr->analog[7]/AUXANACAL);
      printf(" %hd ", rov_data_ptr->heading);
      printf("%5.1f ", (float)rov_data_ptr->curr_speed);
      printf("%5.1f ", (float)rov_data_ptr->curr_dir);

      rov_data_ptr++;
  }

  printf("\nEnd of data, press any key to continue");
  while( !kbhit() );
  return 0;
}

/***********************************************************/

int mem_to_disk(void){
  DriveErr derr;

  derr = DFWrite( mem_start, df_count);
  if(derr) printf("\nDisk error: %d ", derr);
  else{
    printf("\nMemory to written to disk file %hd", df_count);
    df_count++;
  }
  DriveOff();
  DisableParIO();

  file_init();
  printf("\nDisk drive off");
  return(0);
}

/****************************************************/

void clear_disk_files(void){

  df_count = 0;
}


/************************************************
	 CURRENT METER FUNCTIONS
************************************************/

/***********************************************************************

   cm_data assumes the Argonaut current meter is running in deploy
   mode with OutMode set to AUTO and Outformat set to BINARY. It waits
   for a sync character and then puts the binary data into a union.

   Input: maximum time (seconds) to wait for a data string.
   Return: 0 for success, -1 for error.

************************************************************************/

int cm_data(time_t wait_time)
{
  unsigned char 	byte;
  unsigned 		x;
  time_t		over_time;
  double 		east, north, double_speed;
  float			float_speed;
  int 			angle;

  over_time = time(0) + wait_time;
  setcomchan(CURRMET);	// Set the comm. channel to current meter
  SerInFlush();
  TSerInFlush(13);

  while(1){                  //Search for the sync character
    byte = TSerGetByteTimed(1000);
    if(byte == 0xB0){
      sample_union.sample_buf[0] = byte;
      for(x=1;x<33;x++) sample_union.sample_buf[x] = TSerGetByteTimed(1000);

      printf("\n");
      for(x=0;x<33;x++) printf("%02X ", sample_union.sample_buf[x]);

      east =  (double)sample_union.sample_struct.Vel[0];
      north = (double)sample_union.sample_struct.Vel[1];
      double_speed = sqrt( east*east + north*north );
      if (double_speed == 0) double_speed = 1;      		// Avoid divde by zero error
      float_speed = (float)double_speed;  		// Must convert to float first
      g_curr_speed = (short)float_speed;

      printf("\nSize of sample_struct = %d", sizeof(LongSample));
      printf("\nVel0 = %hd", sample_union.sample_struct.Vel[0]);
      printf("\nVel1 = %hd", sample_union.sample_struct.Vel[1]);
      printf("\nEast = %f", east);
      printf("\nNorth = %f", north);
      printf("\ndouble_speed = %f", double_speed);
      printf("\nCurrent speed(mm/s): %hd", g_curr_speed);

      angle = (acos(north/double_speed)/3.1415)*180;
      if(east < 0){
	angle += 180;
	angle %= 360;
      }
      g_curr_dir = (short)angle;
      printf("\nCurrent direction(deg true): %hd", g_curr_dir);
      break;
    }

    if(time(0) > over_time) return -1;	// No working overtime
    if(kbhit()) return -1;		// Exit from test
  }
  return 0;
}
