/****************************************************************************/
/* Copyright (c) 2013 MBARI                                                 */
/* MBARI Proprietary Information. All rights reserved.                      */
/****************************************************************************/
/* Summary  : Convert 83P file to simple ascii matlab file.                 */
/* Filename : 83p2mat.c                                                     */
/* Author   :                                                               */
/* Project  :                                                               */
/* Version  : 1.0                                                           */
/* Created  : 02/17/2013                                                    */
/* Modified :                                                               */
/* Archived :                                                               */
/****************************************************************************/
/* Modification History:                                                    */
/****************************************************************************/
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/stat.h>
#include <string.h>
#include <fcntl.h>
#include <time.h>
#include <errno.h>


#define TO_UINT(upper,lower) ((upper)<<8 | (lower))
#define DT_83P  1
#define DT_83B  2
#define MAX_REC_SIZE 2176
#define HDR_SIZE     256

static FILE *f_83p;
static FILE *f_target;
static unsigned char read_buf[MAX_REC_SIZE];

struct dt_record {
  float beam_ranges[480];
  int   beam_intensities[480];
  int   nbeams;
  float range;
  long  epoch_seconds;
  int   millis;
};

static char mat_header[2000];


/////////////////////////////////////////////////////////////////////////////
// Read a 83P record from the source file
//
int read83PRecord()
{
  int nb;
  unsigned int nbytes = TO_UINT(read_buf[4], read_buf[5]);

  nb = fread(read_buf, sizeof(char), HDR_SIZE, f_83p);
  if (nb != HDR_SIZE) {
    printf("\nDone.\n");
    return -1;
  }

  nbytes = TO_UINT(read_buf[4], read_buf[5]);
  if (0 != strncmp(read_buf, "83P", 3)) {
    printf("Not 83P data in source file\n");
    return -1;
  }

  nb = fread(read_buf+nb, sizeof(char), nbytes-HDR_SIZE, f_83p);
  
  return 0;
}

//////////////////////////////////////////////////////////////////////////////
// Process 83P data packets from the beam former
//
int process83PRecord(unsigned char *buf, struct dt_record *dt)
{
  int i;
  struct tm d_tm;
  time_t epoch_seconds;
  float millis;
  char month[5];

  // Process 83P data packet
  //
  unsigned int nsamples = TO_UINT(buf[72], buf[73]);
  unsigned int resolution = TO_UINT(buf[85], buf[86]);

  unsigned int nbeams = TO_UINT(buf[70], buf[71]);
  unsigned int interval = TO_UINT(buf[91], buf[92]);

  unsigned char *ranges = buf+256;
  unsigned char *intens = buf+256+(2*nbeams);

  // Extract timestamp
  buf[10] = buf[14] = '\0';
  d_tm.tm_mday = atoi(buf+8);
  strcpy(month, buf+11);
  d_tm.tm_year = atoi(buf+15) - 1900;

  if (0 == strcmp("JAN", month))
    d_tm.tm_mon = 0;
  else if (0 == strcmp("FEB", month))
    d_tm.tm_mon = 1;
  else if (0 == strcmp("MAR", month))
    d_tm.tm_mon = 2;
  else if (0 == strcmp("APR", month))
    d_tm.tm_mon = 3;
  else if (0 == strcmp("MAY", month))
    d_tm.tm_mon = 4;
  else if (0 == strcmp("JUN", month))
    d_tm.tm_mon = 5;
  else if (0 == strcmp("JUL", month))
    d_tm.tm_mon = 6;
  else if (0 == strcmp("AUG", month))
    d_tm.tm_mon = 7;
  else if (0 == strcmp("SEP", month))
    d_tm.tm_mon = 8;
  else if (0 == strcmp("OCT", month))
    d_tm.tm_mon = 9;
  else if (0 == strcmp("NOV", month))
    d_tm.tm_mon = 10;
  else if (0 == strcmp("DEC", month))
    d_tm.tm_mon = 11;
  else
    printf("Unknown month spec: %s\n", month);

  buf[22] = buf[25] = '\0';
  d_tm.tm_hour = atoi(buf+20);
  d_tm.tm_min = atoi(buf+23);
  d_tm.tm_sec = atoi(buf+26);
  d_tm.tm_isdst = -1;
  epoch_seconds = mktime(&d_tm);

  millis = atof(buf+113);
  dt->epoch_seconds = epoch_seconds;
  dt->millis = millis;
  dt->nbeams = nbeams;
  // Individual beam ranges
  //
  for (i = 0; i < nbeams; i++) {
    dt->beam_ranges[i] = TO_UINT(ranges[i*2],ranges[i*2+1]) * resolution/1000.;
    dt->beam_intensities[i] = TO_UINT(intens[i*2],intens[i*2+1]);
  }

  // DeltaT bottom pick
  memcpy((void*)&dt->range,
	 (const void*)&buf[133], sizeof(float));

  return 0;
}

//////////////////////////////////////////////////////////////////////////////
// Write dt_struct data to the target file
//
void writeToMat(struct dt_record dt)
{
  int i;
  struct tm d_tm;

  // Write the timestamp
  //
  fprintf(f_target, "%ld.%03d", dt.epoch_seconds, dt.millis);

  // Write the beam ranges
  //
  for (i = 0; i < dt.nbeams; i++) {
    fprintf(f_target, "  %.5f", dt.beam_ranges[i]);
  }
  fprintf(f_target, "\n");
}

//////////////////////////////////////////////////////////////////////////////
// Initialize - open file, etc
int initialize(const char *src_filename)
{
  int i;
  char *p;
  char mat_filename[250];

  printf("initializing...\n");

  // Create mat filename from source filename
  //
  strcpy(mat_filename, src_filename);
  if ((p = strrchr(mat_filename, '.'))) {
    *(++p) = '\0';
  }
  else
  strcat(mat_filename, ".");

  strcat(mat_filename, "mat");
  printf("%s -> %s\n", src_filename, mat_filename);

  if (!(f_83p = fopen(src_filename, "rb"))) {
    printf("Unable to open 83P file: %s\n", src_filename);
    return -1;
  }

  if (!(f_target = fopen(mat_filename, "w"))) {
    printf("Unable to open target MAT file: %s\n", mat_filename);
    return -1;
  }

  fprintf(f_target, "%s  %s  %s %s",
	  "%\n  %%%%%", "Log File", "%%%%%\n\n", "Signal Names:\n\n");
  fprintf(f_target, "time = 1;\n");
  for (i = 0; i < 120; i++) {
    fprintf(f_target, "P83.Range-%03d = %d;\n", i+1, i+2);
  }
  fprintf(f_target, "\n\n P83.data=[\n");


  return 0;
} 

int main(int argc, char **argv)
{
  struct dt_record dt;
  int nrecords = 0;

  if (argc < 2) {
    printf("Usage: 83p2mat sourcefile.83P\n");
    exit(1);
  }

  if (initialize(argv[1]) < 0) {
    return -1;
  }

  while(read83PRecord() == 0) {
    printf("%d records\r", ++nrecords);
    process83PRecord(read_buf, &dt);
    writeToMat(dt);
    //usleep(5000L);
  }
  fprintf(f_target, "\n\n];\n");

  fclose(f_83p);
  fclose(f_target);

  return 0;
}


