/* ROVCONV.C  Rover data file conversion routine */

#include "rovsys.h"
#include <stdio.h>
#include <time.h>
#include <string.h>

/* Function Prototypes */
int c_file(void);
int i_file(void);
short rotate_short(short inbuf);
unsigned long rotate_ulong(unsigned long inbuf);
void get_string(char *outstr, char *instr, short pos, short length);


/* Definitions */
#define BATT_CAL		1841
#define	CURR_CAL		32.76
#define ISO_PLUS_CAL            -3591     /* Corrects error in benthic chamber software */
#define ISO_MINUS_CAL           3591



main(void){
  char menukey;

  while(1){

    printf("\n\n\nRover Data Conversion Utility");
    printf("\n\n1 -- Convert central controller data file");
    printf("\n2 -- Convert instrument data file");
    printf("\n9 -- Exit");
    printf("\n\nEnter Selection: ");

    menukey = getch();

    switch(menukey){
      case '1':
	c_file();
	break;

      case '2':
	i_file();
	break;

      case '9':
	exit(0);
    }
  }
}

/****************************************************/

int c_file(void){
  short  filetype;
  unsigned long record_count, record_num;
  unsigned long thistime, time_correct;
  float battvolt, hpcurr, lpcurr, gfvolt, tiltx, tilty, cmvane, auxana;
  float heading, curr_speed, curr_dir;
  char filein[80], fileout[80];
  FILE *in, *out;

  struct file_header{
    unsigned long record_count;
  } file_head;

  struct datafile{
    short filetype;
    time_t caltime;
    short analog[8];
    short heading;
    short curr_speed;
    short curr_dir;
  } datain;

  printf("\n\nEnter central controller data file name: ");
  gets(filein);

  printf("\nEnter Output file name: ");
  gets(fileout);

  if((in=fopen(filein, "rb")) == NULL) {
    printf("Cannot open source file\n");
    return(1);
  }

  if((out=fopen(fileout, "w")) == NULL) {
    printf("Cannot open destination file\n");
    return(1);
  }

  if(fread(&file_head, sizeof(struct file_header), 1, in) != 1){
    printf("\n file read error");
    return(1);
  }

  fprintf(out, "\nVolt HPcurr LPCurr gfvolt Tilt-x Tilt-y Vane Aux Heading CM-Spd CM-Dir\n\n");

  time_correct = 66*365+17;  /* Days between 1904 and 1970 */
  time_correct *= 24;        /* Hours   "      "   "    "  */
  time_correct *= 3600;      /* Seconds "      "   "    "  */

  record_count = rotate_ulong(file_head.record_count);

  for(record_num = 1; record_num <= record_count; record_num++){
    fread(&datain, sizeof(struct datafile), 1, in);

    filetype = rotate_short(datain.filetype);
    thistime = rotate_ulong(datain.caltime);
    battvolt = (float)rotate_short(datain.analog[0])/BATTCAL;
    hpcurr = (float)rotate_short(datain.analog[1])/HPCURRCAL;
    lpcurr = (float)rotate_short(datain.analog[2])/LPCURRCAL;
    gfvolt = (float)rotate_short(datain.analog[3])/GFVOLTCAL;
    tiltx = (float)rotate_short(datain.analog[4])/TILTX_CAL-TILTX_OFFSET;
    tilty = (float)rotate_short(datain.analog[5])/TILTY_CAL-TILTY_OFFSET;
    cmvane = (float)rotate_short(datain.analog[6])/CMVANECAL;
    auxana = (float)rotate_short(datain.analog[7])/AUXANACAL;
    heading = (float)rotate_short(datain.heading);
    curr_speed = (float)rotate_short(datain.curr_speed);
    curr_dir = (float)rotate_short(datain.curr_dir);

    thistime -= time_correct;  /* Correct for Mac/DOS time difference 1904/1970 */

    switch(filetype){
      case 0:
	fprintf(out, "\nNo Errors");
	break;
      case 1:
	fprintf(out, "\nTransit");
	break;
      case 2:
	fprintf(out, "\nTurn Right");
	break;
      case 3:
	fprintf(out, "\nTurn Left");
	break;
      case 10:
	fprintf(out, "\nRack Down");
	break;
      case 11:
	fprintf(out, "\nRack Up");
	break;
      case 20:
	fprintf(out, "\nCurrent Meter Up");
	break;
      case 21:
	fprintf(out, "\nCurrent Meter Down");
	break;
      case 22:
	fprintf(out, "\nCurrent Meter Data");
	break;
      case 1000:
	fprintf(out, "\nError: Transit Timeout");
	break;
      case 1010:
	fprintf(out, "\nError: Turn Timeout");
	break;
      case 1020:
	fprintf(out, "\nError: Rack Limit Up");
	break;
      case 1021:
	fprintf(out, "\nError: Rack Limit Down");
	break;
      case 1022:
	fprintf(out, "\nError: Rack Leadscrew");
	break;
      case 1023:
	fprintf(out, "\nError: Rack Timeout");
	break;
      case 1024:
	fprintf(out, "\nError: Rack Jam");
	break;
      case 1025:
	fprintf(out, "\nError: CM Motor Timeout");
	break;
      case 1026:
	fprintf(out, "\nError: CM Motor Jam");
	break;
      default:
	fprintf(out, "\nUnrecognized Activity Code");
    }

    fprintf(out, "  %s %6.2f %6.2f %6.2f %6.2f %5.1f %5.1f %5.1f %6.2f %5.1f %5.1f %5.1f\n",
	    asctime(gmtime(&(time_t)thistime)), battvolt, hpcurr, lpcurr,
	    gfvolt, tiltx, tilty, cmvane, auxana, heading, curr_speed,
	    curr_dir);
  }

  if(fclose(in)) printf("\nfile close error");
  if(fclose(out)) printf("\nfile close error");
  printf("\n%lu records converted\n", record_count);

  return 0;
}

/*************** Instrument Data Files ****************************/

int i_file(void){
  char 	filein[80], fileout[80], instr[80], tempstr[10];
  FILE 	*in, *out;

  static time_t caltime;
  static short record_type, batvolt, current, o2a, o2b, isopwr_plus, isopwr_minus;
  static short stir_ticks;
  float f_batvolt, f_current, f_isopwr_plus, f_isopwr_minus;
  unsigned long inchar;


  printf("\n\nEnter instrument data file name: ");
  gets(filein);

  printf("\nEnter Output file name: ");
  gets(fileout);

  if((in=fopen(filein, "rb")) == NULL) {
    printf("Cannot open source file\n");
    return(1);
  }

  if((out=fopen(fileout, "w")) == NULL) {
    printf("Cannot open destination file\n");
    return(1);
  }

  while(1){                               /* Look for file start string */
    if( fscanf(in, "%s", instr) == EOF ){
      printf("\nSTART not found");
      return(1);
    }
    if( !strcmp( instr, "START" ) ) break;
  }

  fprintf(out, "\nFunction  Time(sec)  Volt  Curr  O2(Sayles)  O2(Head)  Iso. V+  Iso. V-  Turns\n\n");

  while( fscanf(in, "%s", instr) != EOF ){   /* Parse the hex strings */
    if( !strcmp( instr, "START" ) ) fprintf(out, "\n\n");
    else{
    get_string(tempstr, instr, 0, 4);
    sscanf(tempstr, "%X", &record_type);
    get_string(tempstr, instr, 4, 8);
    sscanf(tempstr, "%X", &caltime);
    get_string(tempstr, instr, 12, 4);
    sscanf(tempstr, "%X", &batvolt);
    get_string(tempstr, instr, 16, 4);
    sscanf(tempstr, "%X", &current);
    get_string(tempstr, instr, 20, 4);
    sscanf(tempstr, "%X", &o2a);
    get_string(tempstr, instr, 24, 4);
    sscanf(tempstr, "%X", &o2b);
    get_string(tempstr, instr, 28, 4);
    sscanf(tempstr, "%X", &isopwr_plus);
    get_string(tempstr, instr, 32, 4);
    sscanf(tempstr, "%X", &isopwr_minus);
    get_string(tempstr, instr, 36, 4);
    sscanf(tempstr, "%X", &stir_ticks);


    f_batvolt = (float)batvolt/BATT_CAL;
    f_current = (float)current/CURR_CAL;
    f_isopwr_plus = (float)isopwr_plus/ISO_PLUS_CAL;
    f_isopwr_minus = (float)isopwr_minus/ISO_MINUS_CAL;
    o2a *= (-1);
    o2b *= (-1);

    switch(record_type){
      case 100:
	fprintf(out, "\nAmbient");
	break;
      case 110:
	fprintf(out, "\nChamber");
	break;
      case 1000:
	fprintf(out, "\nError: Purge Jam");
	break;
      case 1001:
	fprintf(out, "\nError: Purge Timeout");
	break;
      case 1010:
	fprintf(out, "\nError: Slide Jam");
	break;
      case 1011:
	fprintf(out, "\nError: Slide Timeout");
	break;
    }

    fprintf(out, "%12ld %6.2f %6.2f %6hd %6hd %6.2f %6.2f %6hd", caltime,
	f_batvolt, f_current, o2a, o2b, f_isopwr_plus, f_isopwr_minus, stir_ticks);
    }
  }

  if(fclose(in)) printf("\nInput file close error");
  if(fclose(out)) printf("\nOutput file close error");

  return 0;
}

/**************************************************/

short rotate_short(short inbuf){
  unsigned short leftbuf, rightbuf;
  short outbuf;

  leftbuf = (unsigned short)inbuf;
  rightbuf = (unsigned short)inbuf;

  rightbuf = rightbuf >> 8;
  leftbuf = leftbuf << 8;
  outbuf = (short)(leftbuf | rightbuf);
  return outbuf;
}

/**************************************************/


unsigned long rotate_ulong(unsigned long inbuf){
  union ulong_buf{
    unsigned long word;
    unsigned char byte[4];
  } tempbuf1, tempbuf2;

  tempbuf1.word = inbuf;
  tempbuf2.byte[0] = tempbuf1.byte[3];
  tempbuf2.byte[1] = tempbuf1.byte[2];
  tempbuf2.byte[2] = tempbuf1.byte[1];
  tempbuf2.byte[3] = tempbuf1.byte[0];

  return tempbuf2.word;
}

/*****************************************************/

void get_string(char *outstr, char *instr, short pos, short length){
  char nullstr[10] = {0};

  strncpy(nullstr, &instr[pos], length);
  strcpy(outstr, nullstr);
  return;
}