
/***************************************************************************
 *                                                                         *
 *                               -----------                               *
 *                                ssmt2list                                *
 *                               -----------                               *
 *                                                                         *
 *     List SSM/T-2 file, optionally showing raw counts instead of         *
 *     antenna temperatures.                                               *
 *                                                                         *
 ***************************************************************************
 *                                                                         *
 *     Usage:  ssmt2list [-raw] file                                       *
 *                                                                         *
 ***************************************************************************
 *                                                                         *
 *     Written 5/95 by Don Moss, University of Alabama in Huntsville       *
 *                                                                         *
 *     Revision 1    8/1/95   Don Moss   DPR95-172     Release 1.1         *
 *        Make buffer unsigned char.                                       *
 *                                                                         *
 ***************************************************************************/

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

#define TRUE  1
#define FALSE 0
#define ERROUT stderr
#define HDRSIZE  692
#define DATSIZE  692

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

/*-----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
 * SLOPE extracts and unscales calibration slope
 * OFFSET extracts and unscales calibration offset
 */
#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 SLOPE(p) ((double) SV2(p) / 10000.0)
/* The scaling factor has been changed to 20 */
/*#define OFFSET(p) ((double) SV2(p) / 100.0)*/
#define OFFSET(p) ((double) SV2(p) / 20.0)

/*-----define bool 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[] = "ssmt2list";
const char rel[] = "1.1";

/*-----record structures-----*/
struct hdr_rec {		 /* ----- header record ----- */
    char dsname[45];		 /* data set name */
    int nscan;			 /* number of scans */
    int ngap;			 /* number of data gaps */
    char precal[108];		 /* preflight calibration (not used) */
    float apc[28][5];		 /* antenna pattern correction */
    int qc_earth;		 /* QC summary of earth locations */
    int qc_scene;		 /* QC summary of scene data */
    int qc_cal[5];		 /* QC summary of calibration */
};
struct dat_rec {		 /* ----- data record ----- */
    int32 orbit;		 /* orbit number */
    int scan;			 /* scan number */
    int t1x;			 /* scan index to SSM/T1 */
    int32 yyddd;		 /* year of century and day of year */
    int32 ols;			 /* OLS time in seconds */
    int32 ts;			 /* TS (not used) */
    float lat[28];		 /* latitudes (-90..90) North > 0 */
    float lon[28];		 /* longitudes (-180..180) East > 0 */
    int time[28];		 /* time at beam positions 1-28 */
    int count[28][5];		 /* raw counts */
    char rawcal[172];		 /* raw calibration data (not used) */
    float slope[5];		 /* slopes */
    float offset[5];		 /* intercepts */
    int qc_earth;		 /* earth locations QC flag */
    int qc_scene;		 /* scene data QC flag */
    int qc_cal[5];		 /* calibration QC flag */
};

/*-----functions-----*/
void UsageExit(void);		 /* show usage and exit */
FILE *OpenIn(char *fn);		 /* open file */
void GetHdr(FILE *fp, struct hdr_rec *rec);	/* read header record */
int GetRec(FILE *fp, struct dat_rec *rec);	/* read data record */



/*================================== main ===================================*/
main(int argc, char *argv[])
{
    FILE *infp;			 /* file pointer */
    char *infn;			 /* file name pointer */
    struct hdr_rec hdr;		 /* header record */
    struct dat_rec rec;		 /* data record */
    int chan, pos;		 /* channel and position */
    char stars[]  = "**************************************************\
***********************************";
    char dashes[] = "--------------------------------------------------\
-----------------------------------";
    bool raw;			 /* true if raw counts are desired */
    float temp;			 /* temperature */
    int tm = time(0);

    /*-----check command-line arguments-----*/
    if (argc == 2) {
	raw = FALSE;
	infn = argv[1];
    } else if (argc == 3 && !strcmp(argv[1], "-raw")) {
	raw = TRUE;
	infn = argv[2];
    } else {
	UsageExit();
    }

    /*-----open file-----*/
    infp = OpenIn(infn);

    /*-----read and list header record-----*/
    GetHdr(infp, &hdr);
    printf("\n\n\n%s\n", stars);
    printf("     SSM/T2 input file:  %s\n", infn);
    printf("     File header contains the following:\n");
    printf("%s\n", stars);
    printf("\nDSName:  %s\n", hdr.dsname);
    printf(  "Scans:   %d     Gaps:  %d\n", hdr.nscan, hdr.ngap);
    printf("\nAntenna pattern correction:\n");
    printf("\n Spot      Ch 1       Ch 2       Ch 3       Ch 4       Ch 5\n");    
    printf("------------------------------------------------------------\n");
    for (pos = 0; pos < 28; pos++) {
	printf("%4d", pos + 1);
	for (chan = 0; chan < 5; chan++)
	    printf(" %10.2f", hdr.apc[pos][chan]);
	printf("\n");
    }
    printf("------------------------------------------------------------\n");
    printf("\nOrbit-level QC summary:\n");
    printf("     Earth locations:  %10d\n", hdr.qc_earth);
    printf("     Scene data:       %10d\n", hdr.qc_scene);
    printf("     Calibration data: %10d %10d %10d %10d %10d\n",
      hdr.qc_cal[0], hdr.qc_cal[1], hdr.qc_cal[2],
      hdr.qc_cal[3], hdr.qc_cal[4]);
    printf("\n\n\n%s\n", stars);
    printf("     Data records:\n");
    printf("%s\n", stars);

    /*-----read and list data records-----*/
    while (!GetRec(infp, &rec)) {

	printf("\nOrbit:  %d     Scan:  %d     ", rec.orbit, rec.scan);
	printf("T1 index:  %d     Date:  %d     OLS time:  %d\n\n",
	  rec.t1x, rec.yyddd, rec.ols);

	printf("QC flags:\n");
	printf("     Earth:  %d     Scene:  %d     Cal:  %d  %d  %d  %d  %d\n\n",
	  rec.qc_earth, rec.qc_scene, rec.qc_cal[0], rec.qc_cal[1],
	  rec.qc_cal[2], rec.qc_cal[3], rec.qc_cal[4]);

	printf("Slope:  %9.4f %9.4f %9.4f %9.4f %9.4f\n",
	  rec.slope[0], rec.slope[1], rec.slope[2], rec.slope[3], rec.slope[4]);
	printf("Offset: %9.2f %9.2f %9.2f %9.2f %9.2f\n\n",
	  rec.offset[0], rec.offset[1], rec.offset[2],
	  rec.offset[3], rec.offset[4]);

	printf("Position: ");
	for (pos = 1; pos <= 28; pos++)
	    printf("      %2d", pos);
	printf("\n");

	printf("Latitude:   ");
	for (pos = 0; pos < 28; pos++)
	    printf("%8.2f", rec.lat[pos]);
	printf("\n");

	printf("Longitude:  ");
	for (pos = 0; pos < 28; pos++)
	    printf("%8.2f", rec.lon[pos]);
	printf("\n");

	printf("Time:       ");
	for (pos = 0; pos < 28; pos++)
	    printf("%8d", rec.time[pos]);
	printf("\n");

	if (raw) {
	    for (chan = 0; chan < 5; chan++) {
		printf("Ch %d count: ", chan + 1);
		for (pos = 0; pos < 28; pos++)
		    printf("%8d", rec.count[pos][chan]);
		printf("\n");
	    }
	} else {
	    for (chan = 0; chan < 5; chan++) {
		printf("Ch %d temp:  ", chan + 1);
		for (pos = 0; pos < 28; pos++) {
		    temp = (float) rec.count[pos][chan]
		      * rec.slope[chan]
		      + rec.offset[chan];
		    printf("%8.2f", temp);
		}
		printf("\n");
	    }
	}

	printf("\n\n%s\n", dashes);
    }
	printf("\nTime Taken : %d\n", (time(0)-tm));
    /*-----return-----*/
    return OK;
}



/*================================ UsageExit ================================*/
void UsageExit(void)
{
    fprintf(ERROUT, "%s %s\n", pgm, rel);
    fprintf(ERROUT, "Usage:  %s [-raw] <SSM/T-2 file>\n", pgm);
    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;
}



/*================================= GetHdr ==================================*/
void GetHdr(FILE *fp, struct hdr_rec *rec)
{
    uchar buf[HDRSIZE];		 /* record buffer */
    int chan, pos;		 /* channel and position */
    int p;			 /* offset into buffer */
    char ebcdic_ascii[256] = {
	'?','?','?','?','?','?','?','?','?','?','?','?','?','?','?','?',
	'?','?','?','?','?','?','?','?','?','?','?','?','?','?','?','?',
	'?','?','?','?','?','?','?','?','?','?','?','?','?','?','?','?',
	'?','?','?','?','?','?','?','?','?','?','?','?','?','?','?','?',
	' ','?','?','?','?','?','?','?','?','?','?','.','?','?','+','?',
	'?','?','?','?','?','?','?','?','?','?','?','?','?','?','?','?',
	'-','?','?','?','?','?','?','?','?','?','?','?','?','_','?','?',
	'?','?','?','?','?','?','?','?','?','?',':','#','@','?','=','?',
	'?','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','?','?','?','?','?','?'
    };
    char *ptr;

    /*-----read record-----*/
    if (fread(buf, HDRSIZE, 1, fp) != 1) {
	fprintf(ERROUT, "%s:  error reading header record\n", pgm);
	exit(READ_ERR);
    }

    /*-----translate internal data set name from EBCDIC-----*/
    memcpy(rec->dsname, buf, 44);
    rec->dsname[44] = '\0';
    ptr = rec->dsname;
    while (*ptr)
	*ptr = ebcdic_ascii[*(ptr++)];

    /*-----get number of scans and data gaps-----*/
    rec->nscan = V2(44);
    rec->ngap  = V2(46);

    /*-----get preflight calibration data (not used)-----*/
    memcpy(rec->precal, buf + 48, 108);

    /*-----get antenna pattern correction coefficients-----*/
    p = 156;			 /* point to beginning of apc data */
    for (pos = 0; pos < 28; pos++)
	for (chan = 0; chan < 5; chan++) {
	    rec->apc[pos][chan] = (double) V2(p) / 100.0;
	    p += 2;
	}

    /*-----get QC summary of earth locations and scene data-----*/
    rec->qc_earth = V2(436);
    rec->qc_scene = V2(438);

    /*-----get calibration QC summary-----*/
    p = 440;			 /* beginning of qc summary data */
    for (chan = 0; chan < 5; chan++) {
	rec->qc_cal[chan] = V2(p);
	p += 2;
    }
}



/*================================= GetRec ==================================*/
int GetRec(FILE *fp, struct dat_rec *rec)
{
    uchar buf[DATSIZE];		 /* record buffer */
    int chan, pos;		 /* channel and position */
    int p;			 /* offset into buffer */

    /*-----read record-----*/
    if (fread(buf, DATSIZE, 1, fp) != 1) {
	if (ferror(fp)) {
	    fprintf(ERROUT, "%s:  error reading data record\n", pgm);
	    exit(READ_ERR);
	} else
	    return END_FILE;
    }

    /*-----get scan information-----*/
    rec->orbit = V4( 0);
    rec->scan  = V2( 4);
    rec->t1x   = V2( 6);
    rec->yyddd = V4( 8);
    rec->ols   = V4(12);
    rec->ts    = V4(16);

    /*-----get earth locations-----*/
    p = 20;			 /* first latitude field */
    for (pos = 0; pos < 28; pos++) {
	rec->lat[pos] = (float) SV2(p    ) / 128.0;
	rec->lon[pos] = (float) SV2(p + 2) / 128.0;
	p += 4;
    }

    /*-----get scene data-----*/
    p = 132;			 /* beginning of time/count data */
    for (pos = 0; pos < 28; pos++) {
	rec->time[pos] = V2(p);
	p += 2;
	for (chan = 0; chan < 5; chan++) {
	    rec->count[pos][chan] = V2(p);
	    p += 2;
	}
    }

    /*-----get raw calibration data (not used)-----*/
    memcpy(rec->rawcal, buf + 468, 172);

    /*-----get slopes-----*/
    p = 640;			 /* slopes */
    for (chan = 0; chan < 5; chan++) {
	rec->slope[chan] = SLOPE(p);
	p += 2;
    }

    /*-----get intercepts-----*/
    p = 650;			 /* intercepts */
    for (chan = 0; chan < 5; chan++) {
	rec->offset[chan] = OFFSET(p);
	p += 2;
    }

    /*-----get earth locations and scene data QC flags-----*/
    rec->qc_earth = V2(660);
    rec->qc_scene = V2(662);

    /*-----get calibration QC flags-----*/
    p = 664;			 /* calibration QC flags */
    for (chan = 0; chan < 5; chan++) {
	rec->qc_cal[chan] = V2(p);
	p += 2;
    }

    /*-----if orbit number is 0, assume we've read past EOF-----*/
    if (rec->orbit == 0)
	return END_FILE;

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