/***************************************************************************
 *                                                                         *
 *                               ----------                                *
 *                                ssmt1rdc                                 *
 *                               ----------                                *
 *                                                                         *
 *     Read SSM/T-1 file, output FORTRAN-readable values.                  *
 *                                                                         *
 ***************************************************************************
 *                                                                         *
 *     Usage:  ssmt1rdc <SSM/T-1 file> { <output file> | - }               *
 *     Example:  ssmt1rdc S4.D95101.S0135.* S0135.rdc                      *
 *                                                                         *
 ***************************************************************************
 *                                                                         *
 *     Written 7/95 by Don Moss, University of Alabama in Huntsville       *
 *                                                                         *
 ***************************************************************************
 *                                                                         *
 *     This program is intended to be used with its companion program,     *
 *     ssmt1rdf.  Run this program to produce an intermediate file, then   *
 *     run the FORTRAN program ssmt1rdf to read the file into arrays.      *
 *     Add additional code to ssmt1rdf to use the arrays as you wish.      *
 *                                                                         *
 ***************************************************************************/

#include <stdio.h>
#include <string.h>

#define ERROUT stderr
#define HDRSIZE 500
#define RECSIZE 500

/*-----return codes-----*/
#define OK         0
#define SYNTAX_ERR 1
#define FOPEN_ERR  2
#define READ_ERR   3
#define END_FILE   4
#define WRITE_ERR  5

/*-----macros-----*/
/*
 * V1 evaluates a 1-byte binary value as an unsigned number
 * V2 evaluates a 2-byte binary value as an unsigned number
 * V4 evaluates a 4-byte binary value as an unsigned number
 * SV2 evaluates a 2-byte binary value as a signed number
 */
#define V1(p) ((long) *(buf+p))
#define V2(p) (256L * (long) *(buf+p) + (long) *(buf+p+1))
#define V4(p) (256L * (256L * (256L * (long) *(buf+p) + (long) *(buf+p+1))\
 + (long) *(buf+p+2)) + (long) *(buf+p+3))
#define SV2(p) (((long) *(buf+p) <= 127L) ? V2(p) : (V2(p) - 65536L))
#define GET2I(v, n, p) \
    {for (zI = 0, zP = (p); zI < (n); zI++, zP+=2) v[zI] = V2(zP);}
#define FPRINTI(v, n) \
    {for (zI = 0; zI < (n); zI++) fprintf(fp,"%6d", v[zI]); fprintf(fp,"\n");}
#define FPRINTJ(v, n) \
    {for (zI = 0; zI < (n); zI++) fprintf(fp,"%6d", v[zI]);}

/*-----global variables needed for macros-----*/
int zI, zP;

/*-----define bool and uchar and int32 types-----*/
typedef char bool;
typedef unsigned char uchar;
#if INT_MAX < 0x7FFFFFFF
    typedef long int32;
#else
    typedef int int32;
#endif

/*-----program name and release level-----*/
const char pgm[] = "ssmt1rdc";
const char rls[] = "1.0";

/*-----SSM/T data structure-----*/
struct t_dat {
    uchar ols_sync[6];		 /* OLS sync code (constant 0x05717D78BE) */
    int32 ols_time;		 /* OLS time code (sec/1024) */
    int32 ch[7];		 /* data for 7 channels */
    int32 mux[3];		 /* housekeeping parameters */
    int32 sagc;			 /* stepped automatic gain control */
    int32 pos;			 /* beam position */
};

/*-----record structures-----*/
struct hdr_rec {		 /* ----- header record ----- */
    int32 scid;			 /* spacecraft ID */
    int32 instr;		 /* instrument code */
    int32 stream;		 /* ingest data stream */
    int32 start_year;		 /* start year */
    int32 start_day;		 /* start day of year */
    int32 start_time;		 /* start time of day in milliseconds */
    int32 num_scan;		 /* number of scans in data set */
    int32 end_year;		 /* end year */
    int32 end_day;		 /* end day of year */
    int32 end_time;		 /* end time of day in milliseconds */
    int32 num_gap;		 /* number of data gaps */
    uchar pbid[9];		 /* processing block ID */
				 /* -pre-flight calibration- */
    int32 precal_count[11];      /*     counts               */
    int32 precal_temp[11];       /*     temperatures         */
    int32 precal_hot[7];	 /*     hot reference temps  */
    int32 precal_cold[7];        /*     cold reference temps */
    int32 scan_bias[7][7];       /* scan bias correction values [ch][FOV] */
    int32 apc[7][7];		 /* antenna pattern correction [ch][FOV] */
    int32 manual_coeff[7];       /* manual coefficients */
    int32 cnt_lim_lo[7];	 /* raw counts lower limits */
    int32 cnt_lim_up[7];	 /* raw counts upper limits */
};

struct dat_rec {		 /* ----- data record ----- */
    int32 scan_num;		 /* scan number */
    int32 orient_vect[3];        /* X, Y, Z unit orientation vectors */
    int32 altitude;		 /* satellite altitude */
    int32 angle;		 /* satellite angle */
    int32 year;			 /* scan year */
    int32 day;			 /* scan day of year */
    int32 time;			 /* scan time (milliseconds of day) */
    int32 orbit;		 /* orbit number */
    int32 latitude[7];		 /* latitudes */
    int32 longitude[7];		 /* longitudes */
    struct t_dat data[9];        /* SSM/T FOV and data (9 beam positions) */
    int32 warm_load;		 /* warm load temperature */
    int32 slope[7];		 /* slopes */
    int32 warm_mean[7];		 /* warm calibration means */
    int32 cold_mean[7];		 /* cold calibration means */
    uchar qual_flag[25];	 /* scan quality flags */
};

/*-----functions-----*/
void UsageExit(void);		 /* show usage and exit */
FILE *OpenIn(char *fn);		 /* open input file */
FILE *OpenOut(char *fn);	 /* open output file */
int ReadHdr(FILE *fp, struct hdr_rec *rec);	/* read header record */
int ReadDat(FILE *fp, struct dat_rec *rec);	/* read data record */
int WriteHdr(FILE *fp, struct hdr_rec *rec);	/* write header record */
int WriteDat(FILE *fp, struct dat_rec *rec);	/* write data record */



/*================================== main ==================================*/
int main(int argc, char *argv[])
{
    FILE *infp;			 /* input file pointer */
    FILE *outfp;		 /* input file pointer */
    char *infn;			 /* output file name pointer */
    char *outfn;		 /* output file name pointer */
    struct hdr_rec hdr;		 /* header record */
    struct dat_rec dat;		 /* data record */
    int rc;			 /* function return code */
    int irec;			 /* record index */
    int tm = time(0);	         /* time taken for this program*/

    /*-----check command-line arguments-----*/
    if (argc != 3) {
	UsageExit();
    }

    /*-----get input and output file names-----*/
    infn  = argv[1];
    outfn = argv[2];

    /*-----open input and output files-----*/
    infp  = OpenIn(infn);
    outfp = OpenOut(outfn);

    /*-----read header record-----*/
    if (rc = ReadHdr(infp, &hdr)) {
	fprintf(ERROUT, "%s:  error reading file header\n", pgm);
	return rc;
    }

    /*-----write header record-----*/
    if (rc = WriteHdr(outfp, &hdr)) {
	fprintf(ERROUT, "%s:  error writing file header\n", pgm);
	return rc;
    }

    /*-----loop through data records-----*/
    for (irec = 1; irec <= hdr.num_scan; irec++) {

	/*-----read record-----*/
	if (rc = ReadDat(infp, &dat)) {
	    fprintf(ERROUT, "%s:  error reading data record %d\n", pgm, irec);
	    return rc;
	}

	/*-----write record-----*/
	if (rc = WriteDat(outfp, &dat)) {
	    fprintf(ERROUT, "%s:  error writing data record %d\n", pgm, irec);
	    return rc;
	}
    }
	printf("\n Time Taken : %d \n", (time(0)-tm));
    /*-----return-----*/
    return OK;
}



/*=============================== UsageExit ================================*/
void UsageExit(void)
{
    fprintf(ERROUT, "%s %s\n", pgm, rls);
    fprintf(ERROUT, "Usage:  %s <SSM/T-1 file> <output file>\n", pgm);
    fprintf(ERROUT, "For stdout, use \"-\" as output file name\n");
    fprintf(ERROUT,
	"Reads the file and prints all fields in a FORTRAN-readable format.\n");
    exit(SYNTAX_ERR);
}



/*================================= OpenIn =================================*/
FILE *OpenIn(char *fn)
{
    FILE *fp;

    if (!(fp = fopen(fn, "rb"))) {
	fprintf(ERROUT, "%s:  error opening input file %s\n", pgm, fn);
	exit(FOPEN_ERR);
    }

    return fp;
}



/*================================ OpenOut =================================*/
FILE *OpenOut(char *fn)
{
    FILE *fp;

    if (!strcmp(fn, "-"))
	return stdout;

    if (!(fp = fopen(fn, "w"))) {
	fprintf(ERROUT, "%s:  error opening output file %s\n", pgm, fn);
	exit(FOPEN_ERR);
    }

    return fp;
}



/*================================ ReadHdr =================================*/
int ReadHdr(FILE *fp, struct hdr_rec *rec)
{
    uchar buf[HDRSIZE];		 /* record buffer */
    uchar ebcdic_ascii[256] = {  /* partial translation table */
	'?','?','?','?','?','?','?','?','?','?','?','?','?','?','?','?',
	'?','?','?','?','?','?','?','?','?','?','?','?','?','?','?','?',
	'?','?','?','?','?','?','?','?','?','?','?','?','?','?','?','?',
	'?','?','?','?','?','?','?','?','?','?','?','?','?','?','?','?',
	' ','?','?','?','?','?','?','?','?','?','?','.','?','?','+','?',
	'?','?','?','?','?','?','?','?','?','?','?','?','?','?','?','?',
	'-','?','?','?','?','?','?','?','?','?','?','?','?','_','?','?',
	'?','?','?','?','?','?','?','?','?','?',':','#','@','?','=','?',
	'?','a','b','c','d','e','f','g','h','i','?','?','?','?','?','?',
	'?','j','k','l','m','n','o','p','q','r','?','?','?','?','?','?',
	'?','?','s','t','u','v','w','x','y','z','?','?','?','?','?','?',
	'?','?','?','?','?','?','?','?','?','?','?','?','?','?','?','?',
	'?','A','B','C','D','E','F','G','H','I','?','?','?','?','?','?',
	'?','J','K','L','M','N','O','P','Q','R','?','?','?','?','?','?',
	'?','?','S','T','U','V','W','X','Y','Z','?','?','?','?','?','?',
	'0','1','2','3','4','5','6','7','8','9','?','?','?','?','?','?'
    };
    uchar *ptr;			 /* intermediate variable */
    int32 z;			 /* intermediate variable */
    int chan;			 /* channel index (0-6) */

    /*-----read record-----*/
    if (fread(buf, HDRSIZE, 1, fp) != 1)
	return READ_ERR;

    /*-----get spacecraft ID-----*/
    rec->scid = V2(0);

    /*-----get data type-----*/
    z = V1(3);
    rec->instr  = z >> 4;
    rec->stream = z & 0xF;

    /*-----get start time-----*/
    rec->start_year = V2(4);
    rec->start_day  = V2(6);
    rec->start_time = V4(8);

    /*-----get number of scans-----*/
    rec->num_scan = V4(12);

    /*-----get end time-----*/
    rec->end_year = V2(16);
    rec->end_day  = V2(18);
    rec->end_time = V4(20);

    /*-----get number of gaps-----*/
    rec->num_gap = V4(24);

    /*-----translate processing block ID from EBCDIC-----*/
    memcpy(rec->pbid, buf + 28, 8);
    rec->pbid[8] = 0;
    ptr = rec->pbid;
    while (*ptr)
	*ptr = ebcdic_ascii[*(ptr++)];

    /*-----get pre-flight calibration-----*/
    GET2I(rec->precal_count, 11, 36);
    GET2I(rec->precal_temp,  11, 58);
    GET2I(rec->precal_hot,    7, 80);
    GET2I(rec->precal_cold,   7, 94);

    /*-----get scan bias correction-----*/
    for (chan = 0; chan < 7; chan++)
	GET2I(rec->scan_bias[chan], 7, 108 + 14 * chan);

    /*-----get antenna pattern correction-----*/
    for (chan = 0; chan < 7; chan++)
	GET2I(rec->apc[chan], 7, 206 + 14 * chan);

    /*-----get manual coefficients-----*/
    GET2I(rec->manual_coeff,  7, 304);

    /*-----get raw counts limits-----*/
    GET2I(rec->cnt_lim_lo,    7, 318);
    GET2I(rec->cnt_lim_up,    7, 332);

    /*-----return-----*/
    return OK;
}



/*================================ WriteHdr ================================*/
int WriteHdr(FILE *fp, struct hdr_rec *rec)
{
    int chan;			 /* channel index (0-6) */

    /*-----write spacecraft ID, data type codes, and processing block ID-----*/
    fprintf(fp, "%5d %4d %6d  %8s\n",
	rec->scid, rec->instr, rec->stream, rec->pbid);

    /*-----write start date/time and number of scans-----*/
    fprintf(fp, "%5d %4d %9d %6d\n",
	rec->start_year, rec->start_day, rec->start_time, rec->num_scan);

    /*-----write end date/time and number of data gaps-----*/
    fprintf(fp, "%5d %4d %9d %6d\n",
	rec->end_year, rec->end_day, rec->end_time, rec->num_gap);

    /*-----write pre-flight calibration-----*/
    FPRINTI(rec->precal_count, 11);	/*     counts               */
    FPRINTI(rec->precal_temp,  11);	/*     temperatures         */
    FPRINTI(rec->precal_hot,    7);	/*     hot reference temps  */
    FPRINTI(rec->precal_cold,   7);	/*     cold reference temps */

    /*-----write scan bias correction values-----*/
    for (chan = 0; chan < 7; chan++)
	FPRINTI(rec->scan_bias[chan], 7);

    /*-----write antenna pattern correction-----*/
    for (chan = 0; chan < 7; chan++)
	FPRINTI(rec->apc[chan], 7);

    /*-----write manual coefficients-----*/
    FPRINTI(rec->manual_coeff, 7);

    /*-----write raw counts limits-----*/
    FPRINTI(rec->cnt_lim_lo, 7);
    FPRINTI(rec->cnt_lim_up, 7);

    /*-----return-----*/
    return OK;
}



/*================================ ReadDat =================================*/
int ReadDat(FILE *fp, struct dat_rec *rec)
{
    uchar buf[HDRSIZE];		 /* record buffer */
    int i;			 /* loop index */
    int i36;			 /* intermediate variable */

    /*-----read record-----*/
    if (fread(buf, RECSIZE, 1, fp) != 1)
	return READ_ERR;

    /*-----get scan number-----*/
    rec->scan_num = V2(0);

    /*-----get orientation vectors-----*/
    GET2I(rec->orient_vect, 3, 2);

    /*-----get satellite altitude and angle-----*/
    rec->altitude = V2( 8);
    rec->angle    = V2(10);

    /*-----get time code-----*/
    rec->year  = V2(12);
    rec->day   = V2(14);
    rec->time  = V4(16);

    /*-----get orbit number-----*/
    rec->orbit = V4(20);

    /*-----get earth locations-----*/
    GET2I(rec->latitude,  7, 24);
    GET2I(rec->longitude, 7, 38);

    /*-----get FOV & telemetry data-----*/
    for (i = 0; i < 9; i++) {
	i36 = i * 36;
	memcpy(rec->data[i].ols_sync, buf + i36 + 54, 6);
	rec->data[i].ols_time = V4(i36 + 60);
	GET2I(rec->data[i].ch,  7, i36 + 64);
	GET2I(rec->data[i].mux, 3, i36 + 78);
	rec->data[i].sagc = V2(i36 + 84);
	rec->data[i].pos  = V2(i36 + 86);
    }

    /*-----get calibration coefficients-----*/
    rec->warm_load = V2(376);
    GET2I(rec->slope, 7, 378);
    GET2I(rec->warm_mean, 7, 392);
    GET2I(rec->cold_mean, 7, 406);

    /*-----get quality flags-----*/
    memcpy(rec->qual_flag, buf + 420, 25);

    /*-----return-----*/
    return OK;
}



/*================================ WriteDat ================================*/
int WriteDat(FILE *fp, struct dat_rec *rec)
{
    int i, j;			 /* loop indices */
    int v;			 /* intermediate variable */

    /*-----write scan number, orientation vectors, altitude, and angle-----*/
    fprintf(fp, "%6d", rec->scan_num);
    fprintf(fp, "%6d%6d%6d",
	rec->orient_vect[0], rec->orient_vect[1], rec->orient_vect[2]);
    fprintf(fp, "%6d%6d", rec->altitude, rec->angle);

    /*-----write date code and orbit number-----*/
    fprintf(fp, "%6d%6d%12d%12d\n",
	rec->year, rec->day, rec->time, rec->orbit);

    /*-----write latitudes and longitudes-----*/
    FPRINTJ(rec->latitude,  7);
    FPRINTI(rec->longitude, 7);

    /*-----loop through 9 beam positions-----*/
    for (i = 0; i < 9; i++) {

	/*-----write OLS sync code and OLS time code-----*/
	for (j = 0; j < 6; j++)
	    fprintf(fp, "%02X", rec->data[i].ols_sync[j]);
	fprintf(fp, "%12d", rec->data[i].ols_time);

	/*-----write channel data-----*/
	FPRINTJ(rec->data[i].ch,  7);

	/*-----write housekeeping parameters-----*/
	FPRINTJ(rec->data[i].mux, 3);

	/*-----write stepped agc and beam position-----*/
	fprintf(fp, "%6d%6d\n",
	    rec->data[i].sagc, rec->data[i].pos);
    }

    /*-----write warm load temperature and slopes-----*/
    fprintf(fp, "%6d", rec->warm_load);
    FPRINTI(rec->slope, 7);

    /*-----write warm and cold calibration means-----*/
    FPRINTJ(rec->warm_mean, 7);
    FPRINTI(rec->cold_mean, 7);

    /*-----write quality flags-----*/
    for (i = 0; i < 25; i++) {
	v = rec->qual_flag[i];
	if (v > 127) v -= 256;   /* make compatible with FORTRAN I*1 */
	fprintf(fp, "%4d", v);
    }
    fprintf(fp, "\n");

    /*-----return-----*/
    return OK;
}
