/* kw2asc.src   10/1/98

   This file contains the source code for the program KW2ASC.EXE. It
   is written in 'C' and was compiled with the Borland C++ DOS compiler,
   Version 4.52, using command line:

   bcc -mm -1 kw2asc.c kwhd1.c kwhd2.c util.c globals.c

   The program creates a formatted ascii file for both the K2 and
   Mt. Whitney file headers.  The data is demultiplexed into separate
   channel files in %12.9f floating point ascii.


   The program in this source file are:

   kw2asc.h          Header compiler includes, defines, externals
                     and function prototypes.

   kwhdrs.h          Structure definitions for K2 & Mt. Whitney file
                     headers, tags and frameheaders.

   globals.c         Variables.

   kw2asc.c          Main function.

   kwhd1.c           1st part of sub-function to write formatted header.
   kwhd2.c           2nd part of sub-function to write header.

   util.c            Other sub-functions for time decode and Motorola
                     to Intel byte swaping.

*/


/*--------------------------------------------------*/
/* kw2asc.h */
/*--------------------------------------------------*/

/* 3/27/95 kw2asc.h  for kw2asc.c */

/* 6/4/96  add CRYEAD */
/* 3/30/97  1.80   ADD: 1.40 K2 & 1/50 MTW */
/*                 ADD: Seismological Parms & Serial Data Stream Parms */
/* 5/12/98  1.90   FIX: message:from 'frame 1583 data read failure'
                                 to  'Premature end of file @ scan.... */

/* 9/22/97  1.92 SCR 296  Fix gpsStatus decode, using '&&', s/b using '&' */
/*               SCR 287  Fix limit on voterinfo array.  ADD maxvoters */
/*               SCR 272  FIX-CHANGE reporting of timing.local Offset */


#include <stdio.h>
#include <string.h>
#include <math.h>
#include <ctype.h>
#include <stdlib.h>
#include <io.h>
#include <dos.h>
#include <errno.h>
#include <dir.h>

#include "kwhdrs.h"  // combined headers definitions -- K2 & Mt. Whitney

#define HEADER TRUE     // for kwhd1/2.c  6/11/96

#define VERSION "1.92"
#define DATE    "22 Sept 1998"
#define CRYEAR  "1995..1998"

#define TRUE 1
#define FALSE 0
#define DWORD unsigned long
#define WORD unsigned short
#define BYTE unsigned char
#define BOOL int

// header versions
#define K2100 100          //  K2 - 12 channel
#define K2110 110          //  K2 - 12 channel
#define MTW120 120         //  Mt. Whitney - 18 channel
#define K2130 130          //  K2 - 12 channel
//  add new .H declarations for 1.40/1.50 headers
#define K2130 130          //  K2 - 12 channel
#define K2140 140          //  K2 - 4-12 channel seismo
#define MTW150 150         //  MT. Whitnew seismo

// header type
#define K2  10
#define MTW 20

// end new declarations for 1.40/1.50 headers

#define MAX_CHANNELS 18      // header defined channels

#define FIRST_LIMIT 11     // # channels that takes two passes

#define FRAME_DATA3    5400    //  1350 - 18ch * 25scans * 3bytes
#define FRAME_DATA4    7200    //  1800 - 18ch * 25scans * 4bytes
#define FRAME_SAMPLES  1800    //   450 - 18ch * 25scans * 1sample

#define NAME_LEN 80              // length of filename strings

//.........................................
//
//    variables
//
//.........................................

extern KFF_TAG tag;

extern FRAME_HEADER frmhdr;

extern K2_HEADER k2head;
extern MW_HEADER mwhead;

extern int headver;
extern int headtype;       //  head vers 1.40/1.50

extern FILE * infile;
extern FILE * hdrfile;
extern FILE * chfile[MAX_CHANNELS];
extern FILE * overfile;
extern FILE * hfp;
extern char infname[NAME_LEN];
extern char hdrname[NAME_LEN];
extern char chname[MAX_CHANNELS][NAME_LEN];
extern char overname[NAME_LEN];
extern char hfpname[NAME_LEN];

extern int fmhdflag;
extern int chanavail[MAX_CHANNELS];
extern unsigned int tagheadlen;
extern unsigned int tagdatalen;

extern char tempstr[90];
extern unsigned short us;
extern long lw,lwa,lwb;
extern float hr,gs,fileseconds;
extern BYTE hb;
extern char string1[80],string2[80];
extern int hi1,hi2,row;
extern unsigned int hw;
extern short bat;
extern float x,si;
extern char chidx[MAX_CHANNELS];

extern int chanavailbitmap,chanmask,tempint,chanct;

extern unsigned short usedchans;
extern int sps;
extern unsigned int framestat;

extern float fsample;

extern char  starttime[40];        // start time string
extern char  trigtime[40];          // trigger time string

extern long  temptime;             // place for swapped header time
									 // seconds2time() expects header time here
extern int   tempmsec;             // temp place for milliseconds, ver 1.10 only


// used by CK2time functions
extern unsigned long m_nRawTime;
extern int m_nYear;
extern int m_nMonth;
extern int m_nDayOfMonth;
extern int m_nDayOfYear;
extern int m_nHour;
extern int m_nMin;
extern int m_nSec;



//.........................................
//
//  prototypes
//
//.........................................

void CK2Time(unsigned long rawTime);

int  IsLeapYear(int year);
void Seconds2Time(unsigned long time, int *iyear, int *iday_of_year, int *ihour,
            	       int *imin, int *isec);
void Day2Month(int year, int day_of_year, int *month, int *day_of_month);

int swap2(int);
long swap4i(long);
float swap4r(float);

void decodeheader1(void);
void decodeheader2(void);

float ad_val(long);


/*--  end  kw2asc.h   ------------------------------------------------------*/

/*--------------------------------------------------------------------------*/
/* kwhdrs.h */
/*--------------------------------------------------------------------------*/
/* kwhdrs.h   Combined K2 & Mt. Whitney header definition
              also Tag definition & Frame header definition  */

/**************************************************************

REVISION HISTORY:

Version 1.00 (July 5, 1994)
-------------------------
Initial release with support for 12 channels.

Version 1.10 (August 25, 1994)
----------------------------
NOTE: all structure sizes and previous parameter offsets remain the same.

Used expansion space in CHANNEL_RW_PARMS to add the following:
   unsigned short sensorSerialNumberExt;  (high word of sensor serial number)
   float resp1,resp2,resp3,resp4,resp5,resp6; (sensor response)

Used expansion space in MISC_RW_PARMS to add the following:
   unsigned char minBatteryVoltage; (minimum battery voltage x 10)

Added new sensor code definitions for FBA 4g, 2g, 1g, 0.5g, 0.25g and 0.1g
for parameter CHANNEL_RW_PARMS.sensorType.  The code definitions are
   #define SENSOR_FBA_4G 11
   #define SENSOR_FBA_2G 12
		etc.

Changed MISC_RO_PARMS.batteryVoltage type from unsigned short to signed
short.  MISC_RO_PARMS.batteryVoltage has negative value if charging.
(For example, MISC_RO_PARMS.batteryVoltage = -130 indicates 13.0 V
and charging).

Redefined the meaning of STREAM_RW_PARMS.filterFlag.
Redefined the meaning of MODEM_RW_PARMS.flags.
Changed TIMING_RW_PARMS.gpsTurnOnInterval from hours to minutes.

New parameters:
   MISC_RO_PARMS.temperature
   MISC_RO_PARMS.restartSource
   MISC_RW_PARMS.networkFlag
   FRAME_HEADER.msec
   STREAM_RO_PARMS.nscans
   STREAM_RO_PARMS.startTimeMsec
   STREAM_RO_PARMS.triggerTimeMsec
   CHANNEL_RO_PARMS.aqOffset

   Added on 8/26/94:
   TIMING_RO_PARMS.gpsLongitude
   TIMING_RO_PARMS.gpsLatitude
   TIMING_RO_PARMS.gpsAltitude

   Added 9/9/94:
   MODEM_RW_PARMS.flags: added more definitions for bit fields

   Added 10/11/94:
   TIMING_RO_PARMS.dacCount


// 10/20/94 make note to CORRECT name:
//  STREAM_RW_PARMS.triggerThreshold & .detriggerThreshold ACTUALLY 'VOTES TO TRIGGER' !!!!!

//  11/18/94   make header 24 channels -- to check arrays --  OK!
//
//  Version 1.20 (28 November 1994)
//---------------------------------------
//  11/29/94  make header 18 channels - Mt.Whitney -- for now
//               MAX_CHANNELS 18
//               FRAME_HEADER_TYPE:  FHT16 3   one 16-bit channel bit map
//                                   FHT24 4     "        "                + byte bit map
//               PARAMETER_VERSION 120
//---------------------------------------------------------



Version 1.20 Mt Whit / 1.30 K2 (January 30, 1995) (March 3, 1995)
----------------------------
	Moved MTWHITNEY define here from mt.h to allow preprocessing
	for different headers for K2 and Mt Whit
		Mt Whit:	MAX_CHANNELS			12 -> 18
					PARAMETER_VERSION		110 -> 120
					FRAME_HEADER_TYPE		3 (16 ch) -> 4 (24 ch)

	FRAME_HEADER:  Renamed 'unsigned char pad4' to 'uc channelBitMap1' to
	support chan 17-24 (chan 1-16 are in channelBitMap)

	MISC_RW_PARMS: added ul channel_bitmap, ul cutler_bitmap,
	uc cutler_decimation, uc cutler_irig_type, uc cutler_protocol;
	uc cutlerCode now just sets the baudrate;
	reduced 'char bpad[14]' & 'int wpad[7]
	to [10] & [3] to keep structure the same size

	MISC_RO_PARMS: add us installedChan so QT can see how many
	channels are installed; decreased char bytepad[5] -> [3] to
	keep struct the same size

	K2_ALARM: changed ui channelBitMap to ulong

*********************************************

//  8/25/94
//  3/03/95   Ver 1.20/1.30
//           remove K2 File System(K2-Directory) definitions. not used
//           remove EVT_SUMMARY, not used
//           remove STATUS_INFO, not used
//           add from another .H: K2_TAG

/*-----------------03-05-95 06:23pm-----------------
 3/05/95  update with 1.20/1.30 header
          make final header, frame & tag structures = typedefs
--------------------------------------------------*/

/*-----------------03-16-95 01:05pm-----------------
 3/16/95  combined version K2 & MW headers - 12/18 channels
--------------------------------------------------*/

/* ----------------------------------------------
 5/21/96  add Parameters to Mt. Whitney (& K2)
          NO CHANGE IN VERSION NUMBER - REDEFINITION OF EXISTING PADS

          STREAM_RO_PARAMS: pad[2] -> triggerBitMap, pad[1]
          MISC_RW_PARMS: bpad[11],wpad[3] -> char siteID[17]
          MODEM_RW_PARMS:

            char pauseBetweenCalls   '' define '0'= random delay 5-30sec

            from:  char bytepad[17]
            to:    char cellShare;  '' K2 only, =0 for 1 Hz output, =1 for cell phone ''
                   char cellOnTime;       '' in minutes ''
                   unsigned char cellWarmupTime;  '' in seconds ''
                   int cellStartTime[2];  '' minutes since midnight ''
                   char bytepad[10];

            from:  unsigned short wordpad[7];
                   unsigned long dwordpad[8];
            to:    char calloutMsg[46];

------------------------------------------------- */


/* ----------------------------------------------
  5/31/96  add SRT & TRIG DATA bits to  ' roParms.stream.flags'
------------------------------------------------- */

/* ----------------------------------------------
  6/10/96  change  modem-rw:
                       int  cellStartTime[] from 2 to 5
                       char bytepad[] from 10 to 4

------------------------------------------------- */

/* 7/2/96  noted for CHANNEL_RO_PARAMETERS:
            'recorded channels entered consecutively' */

/* 9/18/96  new k2defs.h from MERGED MCU - no changes that effect
             kwhd1.c
            QLCA's vhf1/2.c merged into kwhd1/2.c
            cellShare -- NOT USED
            REMOVE:  from formatted files: Sensor Response -- not used
            kwhdrs.h NOT redistributed over all files */
/****************************************************************/

/*  ---------------------

 3/28/97

File Version 1.50: 1.40(K2) & 1.50(MW) 12/18-channel header (February 1997)
------------------------------------------------------

  Change the following:

  CHANNEL_RW_PARAMETERS:

  after 'gain':

  OUT -- 8 bytes :

   float resp1; * sensor response; poles and zeroes *
   float resp2;

  IN  -- 8 bytes :

   unsigned char triggertype;       * Type of trigger calculation  *
                                    default = 0 = Threshold

                                 valid: code 0h  threshold
                                             1   sta/lta

   unsigned char iirtrigfilter;     * coefficients for iir trigger filter *
                                    default = 1 = B  0.1Hz to 12.5 Hz @ 200sps

                  valid: code 0h  A
                              1   B
                              2   C
                              3   D

   unsigned char stasecondsTten;    * STA seconds * ten *
                                     default = code 7 = 1.0 seconds

                    valid: code 0h  0.1  store 1     Ah  1.6 store 16
                                1   0.2   as   2     B   1.8  as   18
                                2   0.3        3     C   2.0       20
                                3   0.4        4     D   2.5       25
                                4   0.5        5     E   3.0       30
                                5   0.6        6     F   5.0       50
                                6   0.8        8    10  10.0      100
                                7   1.0       10
                                8   1.2       12
                                9   1.4       14

   unsigned char ltaseconds;         * LTA seconds *
                                      default = code 4 = 60 seconds

                                 valid: code 0h  20
                                             1   30
                                             2   40
                                             3   50
                                             4   60
                                             5   80
                                             6  100
                                             7  120

   unsigned short sta/ltaratio;    * STA/LTA trigger ratio * ten *
                                   default = code 3 = 4

                    valid: code 0h  1.5  store 15   7h  15 store 150
                                1   2     as   20   8h  20  as   200
                                2   3          30   9   30       300
                                3   4          40   A   40       400
                                4   6          60   B   60       600
                                5   8          80   C  100      1000
                                6  10         100

   unsigned char sta/ltapercent;  * STA/LTA detrigger percent of trigger ratio *
                                   default = code 3 = 40%

                    valid: code 0h  10%  store 10
                                1   15    as   15
                                2   20         20
                                3   40         40
                                4   60         60
                                5  100        100

   char bytepad1[1];        * reserved *



  after 'alarmTriggerThreshold':

  OUT - 16 bytes :

   float resp3;
   float resp4;
   float resp5;
   float resp6;

  IN  - 16 bytes:

   char bytepad[16];     * reserved *

/* ------------

 STREAM_RW_PARMS:

 OUT -- 24 bytes:

   short wordpad[4]; * for expansion *

   long dwordpad[4]; * for expansion *

 IN -- 24 bytes:

   char bytepada;
   unsigned char FilterType;        * FirB: 0 regular, 1 causal *
   unsigned char DataFmt;           * Serial Data Stream: 0=uncompressed
                                                     1=compressed  *
   char Reserved;
   short Timeout;                   * Serial Data Stream Mode:        *
                                    *    mode 1 - 0   default    *
                                    *         2 - 6..32767       *
                                    *             send 'continue cmd' *
                                    *         3 -  -1  cmd for each block *

   unsigned short TxBlkSize;        * Serial Data Stream :           *
                                    *  fixed @ 100 samples per block *
   unsigned short BufferSize;       * Serial Data Stream:            *
                                    *  size of #SSTRBUF.BIN file in disk *
                                    *  number of 16,384 byte blocks *
                                    *  default= 64  - 1Meg *
   unsigned short SampleRate;       * Serial Data Stream:            *
                                    *  fixed at 100 sps *
   unsigned long TxChanMap;         * Serial Data Stream:            *
                                    *  select up to 6 channels *

   long dwordpad[2]; * for expansion *

 ---------------- */









/****************************************************************/

/* Type Definitions:
	  char: 1 byte integer
	  short: 2 byte integer
	  float: 4 byte floating point (IEEE format)
	  long: 4 byte integer

   All structures are 16-bit aligned
*/
#define MAX_MW_CHANNELS 18
#define VERSION_MW 150 /* =1.20 & 1.50; header version number x 100 */

#define MAX_K2_CHANNELS 12
#define VERSION_K2 140 /* = 1.00, 1.10, 1.30 & 1.40; header version number x 100 */

#define DFS_MAX_CHANNELS 3  /* =3 orig, eventually = 6 */

#define MAX_STREAMS 1
#define INSTRUMENT_CODE 9 /* for K2 */

/* SENSOR TYPE CODES */
#define SENSOR_UNKNOWN 0
#define SENSOR_ACCELERATION 1
#define SENSOR_VELOCITY 2
#define SENSOR_FBA11 10
#define SENSOR_FBA_4G 11		/* 4g FBA */
#define SENSOR_FBA_2G 12		/* 2g FBA */
#define SENSOR_FBA_1G 13		/* 1g FBA */
#define SENSOR_FBA_0_5G 14		/* 0.5g FBA */
#define SENSOR_FBA_0_25G 15	/* 0.25g FBA */
#define SENSOR_FBA_0_1G 16		/* 0.1g FBA */
#define SENSOR_FBA23 20
#define SENSOR_WR1 30

/* Voter type codes */
#define VOTER_UNDEFINED		0
#define VOTER_CHANNEL		'C'
#define VOTER_STREAM		'S'
#define VOTER_NETWORK		'N'
#define VOTER_KEYBOARD		'K'
#define VOTER_EXTERNAL		'E'
#define STREAM_K2_MAX_VOTERS (MAX_K2_CHANNELS+3) /* channels+network+keyboard+ext */
#define STREAM_MW_MAX_VOTERS (MAX_MW_CHANNELS+3) /* channels+network+keyboard+ext */

/* Restart sources for use with MISC_RO_PARMS.restartSource */
#define RESTART_UNKNOWN 0
#define RESTART_FROM_POWERSWITCH 1 /* someone flipped the power switch */
#define RESTART_FROM_COMMAND 2 /* user command to reset */
#define RESTART_FROM_WATCHDOG 3 /* watchdog caught a system crash */
#define RESTART_FROM_DSPFAILURE 4 /* DSP failure caused reset */
#define RESTART_FROM_BATTERYFAILURE 5 /* battery failure caused reset */
#define RESTART_FROM_MEMORYERROR 6 /* memory error caused reset */

/*---------------------------------------------------*/

/* Voting information */
struct VOTER_INFO {
   unsigned char type; /* voter type code */
   unsigned char number; /* channel number, stream number, etc. */
   short weight; /* voting weight: range is -100 to 100 */
};

/*---------------------------------------------------*/

/* Channel read/write parameters */
struct CHANNEL_RW_PARMS {
#define CHANNEL_ID_LENGTH 5
   char id[CHANNEL_ID_LENGTH]; /* NULL terminated */
   char bytepad; /* for expansion */
   unsigned short sensorSerialNumberExt; /* high word of serial number */
   short north; /* displacement */
   short east; /* displacement */
   short up; /* displacement */
   short altitude;
   short azimuth;
   unsigned short sensorType;
   unsigned short sensorSerialNumber; /* low word of serial number */
   unsigned short gain;  // only '1' defined as gain of 1 5/31/95

/* begin  added 3/29/97 1.40 K2 & 1.50 MTW */
   unsigned char triggerType;  /* Type of trigger calculation  added headver 1.50
                                  default = 0 = Threshold

                                  valid: code 0h  threshold
                                              1   sta/lta    */

   unsigned char iirTriggerFilter;  /* coefficients for iir trigger filter  ver 1.50
                                    default = 1 = B  0.1Hz to 12.5 Hz @ 200sps

                                    valid: code 0h  A
                                                1   B
                                                2   C  */



   unsigned char StaSeconds;  /* STA seconds * ten   ver 1.50
                                     default = code 7 = 1.0 seconds

                    valid: code 0h  0.1  store 1     Ah  1.6 store 16
                                1   0.2   as   2     B   1.8  as   18
                                2   0.3        3     C   2.0       20
                                3   0.4        4     D   2.5       25
                                4   0.5        5     E   3.0       30
                                5   0.6        6     F   5.0       50
                                6   0.8        8    10  10.0      100
                                7   1.0       10
                                8   1.2       12
                                9   1.4       14   */

   unsigned char LtaSeconds;    /* LTA seconds     ver 1.50
                                   default = code 4 = 60 seconds

                                 valid: code 0h  20
                                             1   30
                                             2   40
                                             3   50
                                             4   60
                                             5   80
                                             6  100
                                             7  120  */

   unsigned short StaLtaRatio;  /* STA/LTA trigger ratio * ten  ver 1.50
                                    default = code 3 = 4

                    valid: code 0h  1.5  store 15   7h  15 store 150
                                1   2     as   20   8h  20  as   200
                                2   3          30   9   30       300
                                3   4          40   A   40       400
                                4   6          60   B   60       600
                                5   8          80   C  100      1000
                                6  10         100      */

   unsigned char StaLtaPercent;  /* STA/LTA detrigger percent of trigger ratio
                                     default = code 3 = 40%         ver 1.50

                    valid: code 0h  10%  store 10
                                1   15    as   15
                                2   20         20
                                3   40         40
                                4   60         60
                                5  100        100   */

   char bytepada;
/* end 1.40 & 1./50 additions */

   float fullscale; /* volts */
   float sensitivity; /* in volts per unit (e.g., g's) */
   float damping; /* fraction of critical */
   float naturalFrequency; /* hz */
   float triggerThreshold; /* fraction of fullscale */
   float detriggerThreshold; /* fraction of fullscale */
   float alarmTriggerThreshold; /* fraction of fullscale */

/* begin change 3/29/97  1.40 & 1.50 */
   char bytepad2[16];
/* end change 1.40 & 1.50 */


};


/*---------------------------------------------------*/
/* Read only parameters */
/* recorded channels entered consecutivly */
struct CHANNEL_RO_PARMS {
   long maxPeak; /* raw sample counts */
   unsigned long maxPeakOffset; /* offset from start of file */
   long minPeak;
   unsigned long minPeakOffset; /* offset from start of file */
   long mean; /* raw sample counts */
   long aqOffset;
   long dwordpad[3]; /* for expansion */
};

/*---------------------------------------------------*/

/* Stream read/write information */
struct STREAM_K2_RW_PARMS {
   unsigned char filterFlag; /* BIT0 = 1 if filtered data;  NOT USED
                                BIT1 = 1 if auto FT after Event
                                BIT2 = 1 if compressed - NOT USED */
   unsigned char primaryStorage; /* = 0 for drive A: ,etc. */
   unsigned char secondaryStorage; /* = 1 for drive B:, etc. */
   unsigned char bytepad[5]; /* for expansion */
   unsigned short eventNumber; /* *NOT USED* */
   unsigned short sps; /* sampling rate */
   unsigned short apw; /* array propagation window, in seconds */
   unsigned short preEvent; /* in seconds */
   unsigned short postEvent; /* in seconds */
   unsigned short minRunTime; /* in seconds */
   short VotesToTrigger; /* signed number */
   short VotesToDetrigger;

/* begin change 3/29/97 1.40 & 1.50 */
   char bytepada;
   unsigned char FilterType;        /* 0 regular, 1 causal */
   unsigned char DataFmt;
   char Reserved;
   short Timeout;
   unsigned short TxBlkSize;
   unsigned short BufferSize;
   unsigned short SampleRate;
   unsigned long TxChanMap;
   long dwordpad[2]; /* for expansion */
/* end change 3/29/97 1.40 & 1.50 */

   /* Voter info: one entry for each channel, network, user command */
   /* Use functions IsStreamVoter() and GetStreamVoterWeight() in
	  STRMPAR.C to access the members.
   */
   struct VOTER_INFO voterInfo[STREAM_K2_MAX_VOTERS];
};


/* Stream read/write information */
struct STREAM_MW_RW_PARMS {
   unsigned char filterFlag; /* BIT0 = 1 if filtered data;
                                BIT1 = 1 if auto FT after Event
                                BIT2 = 1 if compressed */
   unsigned char primaryStorage; /* = 0 for drive A: ,etc. */
   unsigned char secondaryStorage; /* = 1 for drive B:, etc. */
   unsigned char bytepad[5]; /* for expansion */
   unsigned short eventNumber; /* *NOT USED* */
   unsigned short sps; /* sampling rate */
   unsigned short apw; /* array propagation window, in seconds */
   unsigned short preEvent; /* in seconds */
   unsigned short postEvent; /* in seconds */
   unsigned short minRunTime; /* in seconds */
   short VotesToTrigger; /* signed number */
   short VotesToDetrigger;

/* begin change 3/29/97 1.40 & 1.50 */
   char bytepada;
   unsigned char FilterType;        /* 0 regular, 1 causal */
   unsigned char DataFmt;
   char Reserved;
   short Timeout;
   unsigned short TxBlkSize;
   unsigned short BufferSize;
   unsigned short SampleRate;
   unsigned long TxChanMap;
   long dwordpad[2]; /* for expansion */
/* end change 3/29/97 1.40 & 1.50 */

   /* Voter info: one entry for each channel, network, user command */
   /* Use functions IsStreamVoter() and GetStreamVoterWeight() in
	  STRMPAR.C to access the members.
   */
   struct VOTER_INFO voterInfo[STREAM_MW_MAX_VOTERS];
};


/*---------------------------------------------------*/

/* Stream read only parameters */
struct STREAM_RO_PARMS {
   unsigned long startTime; /* first sample time, includes PEM */
   unsigned long triggerTime;
   unsigned long duration; /* in # of frames; note: frames may have different sizes */
   unsigned int errors;
   unsigned int flags; /* Bit 0 = 1 if functional test */
                       /* bit 1 = 1 if Sensor Response Test, SRT (& 0x03 = 0x03) */
                       /* bit 2 = 1 if recorded data = trigger data (& 0x04 = 0x04) */
   unsigned int startTimeMsec;
   unsigned int triggerTimeMsec;
   unsigned long nscans; /* # of scans in the event */
   unsigned long triggerBitMap; /* indicates first channel to trigger 5/96 */
   unsigned long pad; /* for expansion */
};

/*---------------------------------------------------*/

/* Miscellaneous read/write parameters: 92 bytes */
struct MISC_RW_PARMS {
   unsigned short serialNumber;
   unsigned short nchannels;		/* number of channels used */
#define STN_ID_LENGTH 5
   char stnID[STN_ID_LENGTH]; /* null terminated */
#define COMMENT_LENGTH 33
   char comment[COMMENT_LENGTH]; /* NULL terminated */
   short elevation; /* meters above sea level */
   float latitude; /*  degrees North */
   float longitude; /* degrees East */
   short userCodes[4];                             /* 60 bytes to here */

   /* Cutler grabber */
   unsigned char cutlerCode; /* 0: Cutler Off
								1: 4800 baud
								2: 9600 baud
								3: 19200 baud
								4: 38400 baud   // added 1.20-1.30
								5: 57600 baud   // added 1.20-1.30
							  */

   unsigned char minBatteryVoltage; /* minimum alarm battery voltage x 10 */

   // added 5 following parameters 3/3/95 for 1.20 MW & 1.30 K2 headers
   unsigned char cutler_decimation;	/* Cutler grabber decimation factor */
									/* valid 0=1:1(raw), 1= 1:2, 2= 1:4, 3= 1:5, 4= 1:10, 5= 1:20 */
									/* restrictions on 1:4 @ 250 sps? */
   unsigned char cutler_irig_type;  /* 0:B   1:E (default)   2:H */
   unsigned long cutler_bitmap;		/* Digital Field Station bit map - channels to output */
   unsigned long channel_bitmap;	/* channels selected for acq storage */
   unsigned char cutler_protocol; /* 0:CRLF - USGS DFS, 1:KMI/Agbabian */

   char siteID[17];    /* added 5/21/96 */

   /* Network */
   unsigned char externalTrigger; /* either 1 (on) or 0 (off) */
   unsigned char networkFlag; /* BIT0 = 0 (Master) or = 1 (Slave) */

};

/*---------------------------------------------------*/

/* Miscellaneous read only parameters */
struct MISC_RO_PARMS {
   unsigned char a2dBits; /* A/D bits per sample; = A2DBITS */
   unsigned char sampleBytes; /* bytes per sample; = 3 */
   unsigned char restartSource; /* code of restart source:
                                   0 = unknown
                                   1 = power switch;
                                   2 = user command,
                                   3 = software watchdog,
                                   4 = DSP failure,
                                   5 = battery failure
                                   6 = memory error */
   char bytepad[3]; /* for expansion */

   unsigned short installedChan; /* number of channels in system
                                    = (# dsp brds) * (chan per brd) */
   unsigned short maxChannels; /* physical number of channels */
   unsigned short sysBlkVersion; /* sys block version * 100 */
   unsigned short bootBlkVersion; /* boot block version * 100 */
   unsigned short appBlkVersion;  /* application block version * 100 */
   unsigned short dspBlkVersion; /* DSP version * 100 */

   /* System Status */
   short batteryVoltage; /* voltage * 10; negative value indicates charging */

   unsigned short crc; /* 16-bit CRC of entire file, with this word set to 0xffff */
					   /* NOTE: this parameter is not used at the moment.
              For integrity checking, the header and each frame are preceeded
              by a structure tag which contains a checksum */
   unsigned short flags; /* bit 0 = 1 if DSP system error */
   short temperature; /* degrees C x 10 */
   short wordpad[3]; /* for expansion */

   long dwordpad[4]; /* for expansion */
};

/*---------------------------------------------------*/
struct TIMING_RW_PARMS
{
   unsigned char gpsTurnOnInterval; /* minutes between GPS update checking */
   unsigned char gpsMaxTurnOnTime; /* max time in minutes GPS tries to lock before giving up */
   unsigned char bytepad[6];
   short localOffset; /* hours ahead of UTC; if this parameter is non-zero
						 then all times are in UTC time. If this parameter
						 is zero, then all times are based on local time.
					  */
   short wordpad[3];
   long dwordpad[4];
};

/*---------------------------------------------------*/

struct TIMING_RO_PARMS
{
   unsigned char clockSource; /* 0 = RTC from cold start
                                 1 = keyboard
                                 2 = Sync w/ ext. ref. pulse
                                 3 = Internal GPS
                                 */

   unsigned char gpsStatus; /* Bit 0=1 if currently checking for presence
                                          of GPS board
                               Bit 1=1 if GPS board present
                               Bit 2=1 if error communicating with GPS
                               Bit 3=1 if failed to lock within an
                                          allotted time (gpsMaxTurnOnTime)
                               Bit 4=1 if not locked
                               Bit 5=1 when GPS power is ON
                               Bits 6,7=undefined
                             */

   unsigned char gpsSOH; /* Current state of health; same as Acutime SOH code */
   unsigned char bytepad[5]; /* for expansion */

   unsigned short gpsLockFailCount; /* # of times GPS failed to locked within gpsMaxTurnOnTime */
   unsigned short gpsUpdateRTCCount; /* # of times GPS actually updated the RTC */
   short acqDelay; /* time in msec between actual A/D conversion and DSP output */
   short gpsLatitude; /* latitude x 100 , degrees North */
   short gpsLongitude; /* longitude x 100, degrees East */
   short gpsAltitude; /* altitude in meters */
   unsigned short dacCount; /* dac counts */
   short wordpad; /* for expansion */
   short gpsLastDrift[2]; /* in msec.; e.g. 5 = RTC was 5 msec faster than GPS */

   unsigned long gpsLastTurnOnTime[2]; /* time when GPS was last turned on */
   unsigned long gpsLastUpdateTime[2]; /* time of last RTC update */
   unsigned long gpsLastLockTime[2]; /* time of last GPS lock */
   long dwordpad[4]; /* for expansion */
};

/*---------------------------------------------------*/
#define MODEM_INITCMD_LENGTH 64
#define MODEM_DIALPREFIX_LENGTH 16
#define MODEM_DIALSUFFIX_LENGTH 16
#define MODEM_HANGUPCMD_LENGTH 16
#define MODEM_AUTOANSWERON_LENGTH 16
#define MODEM_AUTOANSWEROFF_LENGTH 16
#define MODEM_PHONES 4
#define MODEM_PHONENUMBER_LENGTH 24

struct MODEM_RW_PARMS {
   /* reserved space for modems */
   char initCmd[MODEM_INITCMD_LENGTH]; /* initialization string */
   char dialingPrefix[MODEM_DIALPREFIX_LENGTH]; /* dialing prefix */
   char dialingSuffix[MODEM_DIALSUFFIX_LENGTH];
   char hangupCmd[MODEM_HANGUPCMD_LENGTH];
   char autoAnswerOnCmd[MODEM_AUTOANSWERON_LENGTH];
   char autoAnswerOffCmd[MODEM_AUTOANSWEROFF_LENGTH];
   char phoneNumber[MODEM_PHONES][MODEM_PHONENUMBER_LENGTH]; /* 4 phone numbers */

   unsigned char waitForConnection; /* secs */
   unsigned char pauseBetweenCalls; /* secs, 5/21/96 define '0' */
   unsigned char maxDialAttempts;

   // added 5/21/96
   char cellShare;  /* K2 only, =0 for 1 Hz output, =1 for cell phone */
                    /* @ MERGE 9/18/96 -- NOT USED */
   char cellOnTime;       /* in minutes */
   unsigned char cellWarmupTime;  /* in seconds */
   int cellStartTime[5];  /* minutes since midnight, 2->5, 6/10/96 */
   char bytepad[4];       /* 10->4, 6/10/96 */

   unsigned short flags; /* BIT0 = 1 to enable auto call out
                            BIT1 = 1 to call out on battery < 12 V
                            BIT2 = 1 to call out on battery charge failed
                            BIT3 = 1 to call out on extreme temperature
                            BIT4 = 1 to call out on event
                            BIT5 = 1 to call out on GPS lock failure
                         */
   char calloutMsg[46];   // added 5/21/96
};

/*---------------------------------------------------*/

/* Group read/write parms into one structure */

struct RW_K2_PARMS {
   struct MISC_RW_PARMS misc;
   struct TIMING_RW_PARMS timing;
   struct CHANNEL_RW_PARMS channel[MAX_K2_CHANNELS];
   struct STREAM_K2_RW_PARMS stream;
   struct MODEM_RW_PARMS modem;
};


/*---------------------------------------------------*/

/* Group read/write parms into one structure */
struct RW_MW_PARMS {
   struct MISC_RW_PARMS misc;
   struct TIMING_RW_PARMS timing;
   struct CHANNEL_RW_PARMS channel[MAX_MW_CHANNELS];
   struct STREAM_MW_RW_PARMS stream;
   struct MODEM_RW_PARMS modem;
};


/*---------------------------------------------------*/

#define FILE_DESCRIPTOR_SIZE 8 /* size of file descriptor */

//  K2
/* Group read only parms into one structure */
struct RO_K2_PARMS {
   /* first 8 bytes is a common file descriptor */
   char id[3]; /* = 'KMI' to denote a Kinemetrics file */
   unsigned char instrumentCode; /* = '9' for K2 */
   unsigned short headerVersion; /* header version * 100 */
   unsigned short headerBytes; /* size of header following (includes RW_PARMS) */

   /* actual header follows */
   struct MISC_RO_PARMS misc;
   struct TIMING_RO_PARMS timing;
   struct CHANNEL_RO_PARMS channel[MAX_K2_CHANNELS];
   struct STREAM_RO_PARMS stream;
};


/*---------------------------------------------------*/

/* Group read only parms into one structure */
struct RO_MW_PARMS {
   /* first 8 bytes is a common file descriptor */
   char id[3]; /* = 'KMI' to denote a Kinemetrics file */
   unsigned char instrumentCode; /* = '9' for K2 */
   unsigned short headerVersion; /* header version * 100 */
   unsigned short headerBytes; /* size of header following (includes RW_PARMS) */

   /* actual header follows */
   struct MISC_RO_PARMS misc;
   struct TIMING_RO_PARMS timing;
   struct CHANNEL_RO_PARMS channel[MAX_MW_CHANNELS];
   struct STREAM_RO_PARMS stream;
};


/* This is what the K2 header looks like */
typedef struct {
   struct RO_K2_PARMS roParms;
   struct RW_K2_PARMS rwParms;
} K2_HEADER;

/* This is what the MtWhitney header looks like */
typedef struct {
   struct RO_MW_PARMS roParms;
   struct RW_MW_PARMS rwParms;
} MW_HEADER;

/*---------------------------------------------------*/
/*---------------------------------------------------*/


/*---------------------------------------------------*/
/* K2 Event Frame Structure */
/*---------------------------------------------------*/

#define FRAME_HEADER_SIZE 32 /* bytes */
#define MW_FRAME_HEADER_TYPE 4  /* 4 for 24 ch */
#define K2_FRAME_HEADER_TYPE 3  /* 3 for 16 ch */
#define TIMECODE_BYTES 13

typedef struct { /* 32 bytes */
   unsigned char frameType; /* like a version #, = FRAME_HEADER_TYPE */
   unsigned char instrumentCode; /* instrument code */
   unsigned short recorderID;
   unsigned short frameSize; /* # of frame bytes, includes 32 byte header */
   unsigned long blockTime; /* block time */
   unsigned short channelBitMap; /* 1 bit for each ch. in use. Ch. 1 is bit 0 */
   unsigned short streamPar; /* see comments below */
   unsigned char frameStatus; /* see comments below */
   unsigned char frameStatus2; /* see comments below */
   unsigned short msec; /* 0..999 */
	unsigned char channelBitMap1; /* extended chan bit map, ch17-24 */
   unsigned char timeCode[TIMECODE_BYTES]; /* time code, see comment below */
} FRAME_HEADER;

/* FRAME_HEADER Description:
   frameStatus:
	  Bits 0-3 = frame sequence number 0..9
	  Bit 4    = stream triggered flag. Set if frame exceeds stream trigger level.
	  Bit 5    = Compressed flag. Set if compressed frame.
	  Bits 6-7 = Sample size. 1=16 bits (2 bytes), 2=24 bits (3 bytes)
							  3=32 bits (4 bytes)
				 Samples are expressed as a signed integer of digital counts.
   frameStatus2:
	  Bit 0 = set if issued the ADD SCAN command
	  Bits 1-7: currently unused.

   streamPar:
	  Bits 0-11 = Stream sampling rate, 1..4095
	  Bits 12-15 = Stream number 0..15

   timeCode[]:
	  Time code sampled every millisecond.
	  Bits 4-7 of timeCode[0] = time code type (TBD)
	  Bit 3 of timeCode[0] = time code bit sampled at first msec of frame (0=low, 1=high)
	  Bit 2 of timeCode[0] = time code bit at 2nd msec.
	  Bit 0 of timeCode[12] = last (100th msec) bit of time code
*/

/*----------------------------------------------------*/
/*----------------------------------------------------*/


/*----------------------------------------------------*/
/*    K2 TAG FRAME HEADER */
/*----------------------------------------------------*/
/* STRUCTURE TYPE CODES */
#define KFF_K2_HDR 1 /* K2 header */
#define KFF_K2_FRAME 2 /* K2 FRAME; frame data follows */
#define KFF_BYTE_ORDER 1/* 0=INTEL (LSB first) , 1 = MOTOROLA (MSB first) */
#define KFF_VERSION 1
#define KFF_SYNC_CHAR 'K'


/* TAG. Separates and identifies structures */
typedef struct {
   unsigned char sync; /* sync character 'K' */
   unsigned char byteOrder; /* = 0 for LSB first (INTEL), 1 for MSB first (MOTOROLA) */
   unsigned char version; /* File format version; KFF_VERSION */
   unsigned char instrumentType; /* instrument type code */
   unsigned long type; /* structure type code */
   unsigned short length; /* structure size in bytes */
   unsigned short dataLength; /* # of data bytes following the structure */
   unsigned short id; /* unique instrument id (e.g. serial number); used for multi-instrument files */
   unsigned short checksum; /* 16 bit checksum of structure + data */
} KFF_TAG;

/*---------------------------------------------------*/
/*---------------------------------------------------*/


/*--  end  kwhdrs.h   ------------------------------------------------------*/

/*--------------------------------------------------------------------------*/
/* globals.c */
/*--------------------------------------------------------------------------*/

/* globals.c for kw2asc.c

	 3/27/95 ver 1.00	 write kw2asc for both k2 & Mt.Whitney files */

/* 6/4/96  1.70 CRYEAR & incorporate master header from kwsup\heads */
/* 3/30/97 1.80    ADD: 1.40 K2 & 1/50 MTW */
/*                 ADD: Seismological Parms & Serial Data Stream Parms */


#include "kw2asc.h"

KFF_TAG tag;

FRAME_HEADER frmhdr;

K2_HEADER k2head;
MW_HEADER mwhead;

int headver;
int headtype;        // k2 or mtw     headers 1.40/1.50

FILE * infile;                // event file .EVt
FILE * hdrfile;               // short header file .SHD
FILE * chfile[MAX_CHANNELS];  // channel data files .001 -- .018
FILE * overfile;              // temp file for channels > 12
FILE * hfp;              // formatted header file .HDR
char infname[NAME_LEN];
char hdrname[NAME_LEN];
char chname[MAX_CHANNELS][NAME_LEN];
char overname[NAME_LEN];
char hfpname[NAME_LEN];

int fmhdflag;                 // TRUE = write formatted header file to disk.
int chanavail[MAX_CHANNELS];  // formatter uses this

unsigned int tagheadlen;
unsigned int tagdatalen;

char tempstr[90];
unsigned short us;
long lw,lwa,lwb;
float hr,gs,fileseconds;
BYTE hb;
char string1[80],string2[80];
int hi1,hi2,row;
unsigned int hw;
short bat;
float x,si;
char chidx[MAX_CHANNELS];

int chanavailbitmap,chanmask,tempint,chanct;

unsigned short usedchans;
int sps;
unsigned int framestat;

float fsample;

char  starttime[40];        // start time string
char  trigtime[40];          // trigger time string

long  temptime;             // place for swapped header time
									 // seconds2time() expects header time here
int   tempmsec;             // temp place for milliseconds, ver 1.10 only


// used by CK2time functions
unsigned long m_nRawTime;
int m_nYear;
int m_nMonth;
int m_nDayOfMonth;
int m_nDayOfYear;
int m_nHour;
int m_nMin;
int m_nSec;






/*---  end  globals.c   ----------------------------------------------------*/

/*--------------------------------------------------------------------------*/
/* kw2asc.c */
/*--------------------------------------------------------------------------*/
/* 3/27/95  kw2asc.c  converts to K2 or Mt. Whitney file
                      to an event.HDR formatted ascii header
                      and for each channel an ascii file event.###
                      of %11.9f floating fraction of Full Scale
                      # / TWO223 == sample.0 / 8388608.0 */
/*  3/29/95  1.00   add option '-h' write formatted header file to disk */
/*  5/23/95  1.10   fix bug in chanavail, need to shift mask even if
							 channel not selected */
/*  5/31/95  1.20   compile with Turbo C== 4.0J to fix emulation problem*/
/*  6/ 1/95  1.30   compile with Borland C++ 4.5 8086/emulate/medium model
                    used bcc dcompiler -- dobcc.bat */
/*  6/5/95   1.30   fixed frame error message, needed frameCounter+1, to
                     report correct frame # starting @ 1*/
/*  6/15/95  1.40   fix bug when xmodem padds end of file with 0x00 */
/*  7/12/95  1.50   fix bug - mscans counter was inside channel loop
										 ended file short by #chans factor */
/*  5/20/96  1.60   verify works @ 1000 sps for CDMG
                    add default to bytesPerSample
    5/21/96  1.60   add new parameters */

/*  6/ 4/96  1.70   add CRYEAR and master header\formatters from kwsup\heads */
/*  6/10/96         add [.EVT] option*/
/*  6/11/96         add HEADER == TRUE for kwhd1/2.c
                     cellStartTime[] changed 2->5 */
/*  6/14/96         fix spacing in formatted header, fix adding .EVT */
/*  6/20/96         fix adding .EVT,
                    add program title, fullpathname & file date */
/*                  make data %12.9 */
/*  6/24/96         fix indexing bug in r0.channels: max @, min @, mean, aqoffset */
/*  7/01/96         fix case of invalid frameSize  */
/*  7/01/96         limit bytesPerSample 2-3-4, default 3 */
/*  9/19/96  1.71   kwhd1/2.c remove sensor response 1-6, FIX phone numbers */
/* 10/ 3/96  1.72   Fix framesize minimum from 20 to 2 */
/* 03/15/97  1.80   ADD: process to output file frames that are not 1/10 sec */
/*                       report frame error to .SHD & screen */
/* 3/30/97          ADD: 1.40 K2 & 1/50 MTW */
/*                  ADD: Seismological Parms & Serial Data Stream Parms */
/* 7/17/97   ----   Correction @ get samples,
                      counts translated to Volts, not FullScale */
/*  5/12/98  1.90   FIX: message:from 'frame 1583 data read failure'
                                 to  'Premature end of file @ scan.... */

/* 9/22/97  1.92 SCR 296  Fix gpsStatus decode, using '&&', s/b using '&' */
/*               SCR 287  Fix limit on voterinfo array.  ADD maxvoters */
/*               SCR 272  FIX-CHANGE reporting of timing.local Offset */
/*               Used Boaland 4.52 command line compiler */


#include "kw2asc.h"

static BYTE idata[FRAME_DATA3];        // 18ch * 25scans * 3bytes -- read data from file here

static union
{
  BYTE b[FRAME_DATA4];              // 18ch * 25scans * 4bytes -- expand data to here
  long l[FRAME_SAMPLES];            // 18ch * 25scans * 1long -- read long from here to heap
} far ixdata;




void main(int argc, char *argv[])
{

int scansPerFrame,bytesPerSample,bytesPerScan,frameSize;
long frameCounter, scans,mscans;
int i,j,k,p,q;

char sbuf[_MAX_PATH];
char cx1,cx2,cx3,cx4;
int  testi;

struct ffblk ffblk;
unsigned int d1,d2,d3,t1,t2,t3;


	if ( argc < 2 )
	{
    printf("Altus K2 & Mt. Whitney ASCII File Converter\n");
    printf("  Version %s  %s\n",VERSION,DATE);
    printf("  Copyright (c) %s Kinemetrics, Inc., Pasadena, CA\n\n",CRYEAR);
    printf("Usage:  KW2ASC filename[.EVT] [-H]\n");
		printf("\n");
		printf("  Option:  -H Write formatted header, filename.HDR, to disk.\n");
		printf("\n");
		printf("  Output: Separate file, filename.###, for each channel.\n");
		printf("          Format: xx.xxxxxxxxx V, max +/- 2.5V\n");
		printf("\n");
		printf("          Short Header File, filename.SHD, with pertinent\n");
		printf("          information about the event file.\n");
		return;
	} // if no filename

	fmhdflag = FALSE;

	strcpy(infname,argv[1]);

  tempint = strlen(infname);

  //  add default extension, if necessary
  cx1 = infname[tempint -4];
  cx2 = infname[tempint -3];
  cx3 = infname[tempint -2];
  cx4 = infname[tempint -1];
  if ( (cx1 != '.') &&
       (cx2 != '.') &&
       (cx3 != '.') &&
       (cx4 != '.') )
    strcat(infname,".EVT");         // ASSUME K2 '.EVT' FOR NOW

  // expand name to full pathname
  if (_fullpath(sbuf,infname,_MAX_PATH) != NULL)
  {
    strcpy(infname,sbuf);

    for (i = 0; i < strlen(infname); i++)        // set path & filename to uppercase
      infname[i] = toupper(infname[i]);

    tempint = access(infname,0);

    if (tempint == -1)
    {
      sound(150);                  // file not exist
      delay(400);
        nosound();
      if (errno == EACCES)
        printf("KW2ASC  %s permission denied\n",infname);
      if (errno == ENOENT)
        printf("KW2ASC   %s path or filename not found\n",infname);
      return;
    }  // if file exists
  }
  else
  {
    printf("KW2ASC   %s - unable to build full path name\n",infname);
    return;
  }

	infile = fopen(infname,"rb");
	if ( infile == NULL )
	{
    printf("KW2ASC   Unable to open %s\n",infname);
		return;
	}


	// GOT GOOD INFILE

	// create name of short header file
	strncpy(hdrname,infname,(strlen(infname) -3));
	strcat(hdrname,"SHD");

	for (i=2; i < argc; i++)
	{
	  if (argv[i][0] == '-' )
	  {
		 switch (toupper(argv[i][1]))
		 {
			case 'H':
        strncpy(hfpname,infname,(strlen(infname) -3));
        strcat(hfpname,"HDR");

				fmhdflag = TRUE;

				break;
		 }
	  } // if option code
	} // for arguments over 1



	// START READING INFILE
	fread(&tag,sizeof(tag),1,infile);

	tagheadlen = (unsigned int) swap2(tag.length);
	tagdatalen = (unsigned int) swap2(tag.dataLength);

	if ( (tagdatalen !=0) ||
		  ((tagheadlen != sizeof(k2head)) && (tagheadlen != sizeof(mwhead))) )
	{
		printf("KW2ASC   Invalid file header tag.\n");
		return;
	}

	// determine which header
	fread(&k2head,10,1,infile);
	fclose(infile);

    findfirst(infname,&ffblk,0);
		d1 = (unsigned int)ffblk.ff_fdate & 0x001f;   // day
		d2 = (unsigned int)ffblk.ff_fdate & 0x01e0;
		d2 = d2 >> 5;                   // month
		d3 = (unsigned int)ffblk.ff_fdate & 0xfe00;
		d3 = 1980 + (d3 >> 9);          // year
		t1 = (unsigned int)ffblk.ff_ftime & 0x001f;
		t1 = t1 << 1;                   // seconds -- not used
		t2 = (unsigned int)ffblk.ff_ftime & 0x07e0;
		t2 = t2 >> 5;                   // minutes
		t3 = (unsigned int)ffblk.ff_ftime & 0xf800;
    t3 = t3 >> 11;                  // hours

	headver = swap2(k2head.roParms.headerVersion);

//  add new .C declarations for 1.40/1.50 headers

  if ((headver == K2100) || (headver == K2110) ||
      (headver == K2130) || (headver == K2140))
  {
    headtype = K2;
  }
	else
  {
    if ((headver == MTW120) || (headver == MTW150))
    {
      headtype = MTW;
    }
    else
    {
      printf("KW2ASC  Header Version %d not recognized, %s\n",headver,infname);
      fcloseall();
      return;
    }
  } // headvers -> headtype

// end new declarations for 1.40/1.50 headers

  if ( headtype == MTW )
	{
		infile = fopen(infname,"rb");
    hdrfile = fopen(hdrname,"wt");
		fread(&tag,sizeof(tag),1,infile);  // toss tag
		fread(&mwhead,sizeof(mwhead),1,infile);

    printf("KW2ASC: %s   %02d/%02d/%d %02d:%02d \n",infname,d2,d1,d3,t3,t2);
    printf("Mt. Whitney Header Version %0.2f\n",(float)headver*0.01);
    fprintf(hdrfile,"KW2ASC: %s   %02d/%02d/%d %02d:%02d \n",infname,d2,d1,d3,t3,t2);
    fprintf(hdrfile,"Mt. Whitney Header Version %0.2f\n",(float)headver*0.01);
	}
	else
	{
		infile = fopen(infname,"rb");
		hdrfile = fopen(hdrname,"wt");
		fread(&tag,sizeof(tag),1,infile);  // toss tag
		fread(&k2head,sizeof(k2head),1,infile);

    printf("KW2ASC: %s   %02d/%02d/%d %02d:%02d \n",infname,d2,d1,d3,t3,t2);
    printf("K2 Header Version %0.2f\n",(float)headver*0.01);
    fprintf(hdrfile,"KW2ASC: %s   %02d/%02d/%d %02d:%02d \n",infname,d2,d1,d3,t3,t2);
    fprintf(hdrfile,"K2 Header Version %0.2f\n",(float)headver*0.01);
	}

  if ( headtype == MTW )
	 strcpy(tempstr,mwhead.rwParms.misc.stnID);
	else
	 strcpy(tempstr,k2head.rwParms.misc.stnID);
	printf("Station ID: %s",tempstr);
	fprintf(hdrfile,"Station ID: %s",tempstr);

  if ( headtype == MTW )                     // added 5/21/96
    strcpy(tempstr,mwhead.rwParms.misc.siteID);
  else
    strcpy(tempstr,k2head.rwParms.misc.siteID);
  printf(" Site: %s",tempstr);
  fprintf(hdrfile," Site: %s",tempstr);


  if ( headtype == MTW )
		us = swap2(mwhead.rwParms.misc.serialNumber);
	else
		us = swap2(k2head.rwParms.misc.serialNumber);
	printf("  Serial number: %d",us);
	fprintf(hdrfile,"  Serial number: %d",us);

  if ( headtype == MTW )
		usedchans = swap2(mwhead.rwParms.misc.nchannels);
	else
		usedchans = swap2(k2head.rwParms.misc.nchannels);
  printf("  Channels: %d\n",usedchans);
  fprintf(hdrfile,"  Channels: %d\n",usedchans);

  if ( headtype == MTW )
	 sps = swap2(mwhead.rwParms.stream.sps);            // samples per second
	else
    sps = swap2(k2head.rwParms.stream.sps);            // samples per second
	printf("Sampling rate: %d",sps);
	fprintf(hdrfile,"Sampling rate: %d",sps);

  if ( headtype == MTW )
    us = swap2(mwhead.rwParms.stream.preEvent);
	else
    us = swap2(k2head.rwParms.stream.preEvent);
  printf("   Pre-event:  %d seconds.",us);
  fprintf(hdrfile,"   Pre-event:  %d seconds.",us);

  if ( headtype == MTW )
	 us = swap2(mwhead.rwParms.stream.postEvent);
	else
	 us = swap2(k2head.rwParms.stream.postEvent);
  printf("   Post-event: %d seconds.\n",us);
  fprintf(hdrfile,"   Post-event: %d seconds.\n",us);


  if ( headtype == MTW )
	  temptime = swap4i(mwhead.roParms.stream.startTime);
	else
	  temptime = swap4i(k2head.roParms.stream.startTime);

	CK2Time(temptime);

  if (headver >= K2110)
  {
   if ( headtype == MTW)
		tempmsec = swap2(mwhead.roParms.stream.startTimeMsec);
	 else
		tempmsec = swap2(k2head.roParms.stream.startTimeMsec);
	 sprintf(starttime,"%d/%d/%d (%d) %d:%02d:%02d.%03d",
	  m_nMonth,m_nDayOfMonth,m_nYear,m_nDayOfYear,m_nHour,m_nMin,m_nSec,tempmsec);
  }
  else
	 sprintf(starttime,"%d/%d/%d (%d) %d:%02d:%02d",m_nMonth,m_nDayOfMonth,m_nYear,
				  m_nDayOfYear,m_nHour,m_nMin,m_nSec);

	printf("Start time:  %s\n",starttime);
	fprintf(hdrfile,"Start time:  %s\n",starttime);

  if ( headtype == MTW )
	{
	  temptime = swap4i(mwhead.roParms.stream.triggerTime);
	}
	else
	{
	  temptime = swap4i(k2head.roParms.stream.triggerTime);
	}

	CK2Time(temptime);

  if (headver >= K2110)
  {
   if (headtype == MTW)
		tempmsec = swap2(mwhead.roParms.stream.triggerTimeMsec);
	 else
		tempmsec = swap2(k2head.roParms.stream.triggerTimeMsec);
	 sprintf(trigtime,"%d/%d/%d (%d) %d:%02d:%02d.%03d",
	  m_nMonth,m_nDayOfMonth,m_nYear,m_nDayOfYear,m_nHour,m_nMin,m_nSec,tempmsec);
  }
  else
	 sprintf(trigtime,"%d/%d/%d (%d) %d:%02d:%02d",m_nMonth,m_nDayOfMonth,m_nYear,
				  m_nDayOfYear,m_nHour,m_nMin,m_nSec);

	printf("Trigger time:  %s\n",trigtime);
	fprintf(hdrfile,"Trigger time:  %s\n",trigtime);

  if (headver == K2100)
  {
	 lw = swap4i(k2head.roParms.stream.duration);  // 1/10 second frames
		lwa = lw * 20;
	 hr = (float)((float)lw * 0.1);
	 printf("Duration:  %6.3f seconds, %ld frames, %ld scans.\n", hr,lw,lwa);
	 fprintf(hdrfile,"Duration:  %6.3f seconds, %ld frames, %ld scans.\n", hr,lw,lwa);
	 scans = lwa;
  }
  if ((headver == K2110) || (headver == K2130) || (headver == K2140))
  {
	 lwa = swap4i(k2head.roParms.stream.duration); // frame count
	 lwb = swap4i(k2head.roParms.stream.nscans);
	 hr = (float)((float)lwb * ((float)1/sps));  // 1/sps
	 printf("Duration:  %6.3f seconds, %ld frames, %ld scans.\n",hr,lwa,lwb);
	 fprintf(hdrfile,"Duration:  %6.3f seconds, %ld frames, %ld scans.\n",hr,lwa,lwb);
	 scans = lwb;
  }
  if (headtype == MTW)
  {
	 lwa = swap4i(mwhead.roParms.stream.duration); // frame count
	 lwb = swap4i(mwhead.roParms.stream.nscans);
	 hr = (float)((float)lwb * ((float)1/sps));  // 1/sps
	 printf("Duration:  %6.3f seconds, %ld frames, %ld scans.\n",hr,lwa,lwb);
	 fprintf(hdrfile,"Duration:  %6.3f seconds, %ld frames, %ld scans.\n",hr,lwa,lwb);
	 scans = lwb;
  }

  if ( headtype == MTW )
	 hw = swap2(mwhead.roParms.stream.flags);
	else
	 hw = swap2(k2head.roParms.stream.flags);
  if ((hw & 0x0003) == 1)
	{
	 printf(" Functional Test\n");
	 fprintf(hdrfile," Functional Test\n");
	}
  if ((hw & 0x0003) == 3)
	{
   printf(" Sensor Response Test\n");
   fprintf(hdrfile," Sensor Response Test\n");
	}
  if ((hw & 0x0004) == 4)
	{
   printf(" Trigger Data\n");
   fprintf(hdrfile," Trigger Data\n");
	}

	// GPS stuff

  printf("GPS Status byte decoded:\n");
  if ( headtype == MTW )
	 hb = mwhead.roParms.timing.gpsStatus;
	else
	 hb = k2head.roParms.timing.gpsStatus;
  if ((0x01 && hb) == 0x01)
	{
	 printf("   Currently checking for presence of GPS.\n");
	 fprintf(hdrfile,"   Currently checking for presence of GPS.\n");
	}
  if ((0x02 && hb) == 0x02)
	{
	 printf("   GPS present.\n");
	 fprintf(hdrfile,"   GPS present.\n");
	}
  if ((0x04 && hb) == 0x04)
	{
	 printf("   Error communicating with GPS.\n");
	 fprintf(hdrfile,"   Error communicating with GPS.\n");
	}
  if ((0x08 && hb) == 0x08)
	{
	 printf("   GPS failed to lock with gpsMaxTurnOnTime.\n");
	 fprintf(hdrfile,"   GPS failed to lock with gpsMaxTurnOnTime.\n");
	}
  if ((0x10 && hb) == 0x10)
	{
	 printf("   GPS not locked.\n");
	 fprintf(hdrfile,"   GPS not locked.\n");
	}
  if ((0x20 && hb) == 0x20)
	{
    printf("   GPS power is ON.\n");
    fprintf(hdrfile,"   GPS power is ON.\n");
	}

  if ( headtype == MTW )
    hw = swap2(mwhead.roParms.timing.gpsUpdateRTCCount);
	else
    hw = swap2(k2head.roParms.timing.gpsUpdateRTCCount);
  printf("GPS updated the RTC %d times since last reset.\n",hw);
  fprintf(hdrfile,"GPS updated the RTC %d times since last reset.\n",hw);

  if ( headtype == MTW )
	{
	  hi1 = swap2(mwhead.roParms.timing.gpsLastDrift[0]);
	  hi2 = swap2(mwhead.roParms.timing.gpsLastDrift[1]);
	}
	else
	{
	  hi1 = swap2(k2head.roParms.timing.gpsLastDrift[0]);
	  hi2 = swap2(k2head.roParms.timing.gpsLastDrift[1]);
	}
  printf("Drift Rate at last two RTC updates to UTC: %d & %d msec.\n",hi1,hi2);
  fprintf(hdrfile,"Drift Rate at last two RTC updates to UTC: %d & %d msec.\n",hi1,hi2);

  if ( headtype == MTW )
    temptime = swap4i(mwhead.roParms.timing.gpsLastUpdateTime[0]);
	else
    temptime = swap4i(k2head.roParms.timing.gpsLastUpdateTime[0]);
  CK2Time(temptime);
  sprintf(string1,"%d/%d/%d (%d) %02d:%02d:%02d",m_nMonth,m_nDayOfMonth,m_nYear,
                                        m_nDayOfYear,m_nHour, m_nMin, m_nSec);
  if ( headtype == MTW )
    temptime = swap4i(mwhead.roParms.timing.gpsLastUpdateTime[1]);
	else
    temptime = swap4i(k2head.roParms.timing.gpsLastUpdateTime[1]);
  CK2Time(temptime);
  sprintf(string2,"%d/%d/%d (%d) %02d:%02d:%02d",m_nMonth,m_nDayOfMonth,m_nYear,
                                        m_nDayOfYear,m_nHour, m_nMin, m_nSec);
  printf("Last GPS Update times were:\n");
  fprintf(hdrfile,"Last GPS Update times were:\n");
  printf("  %s & %s.\n",string1,string2);
  fprintf(hdrfile,"  %s & %s.\n",string1,string2);

  if ( headtype == MTW )
    temptime = swap4i(mwhead.roParms.timing.gpsLastTurnOnTime[0]);
	else
    temptime = swap4i(k2head.roParms.timing.gpsLastTurnOnTime[0]);
  CK2Time(temptime);
  sprintf(string1,"%d/%d/%d (%d) %02d:%02d:%02d",m_nMonth,m_nDayOfMonth,m_nYear,
                                        m_nDayOfYear,m_nHour, m_nMin, m_nSec);
  if ( headtype == MTW )
    temptime = swap4i(mwhead.roParms.timing.gpsLastTurnOnTime[1]);
	else
    temptime = swap4i(k2head.roParms.timing.gpsLastTurnOnTime[1]);
  CK2Time(temptime);
  sprintf(string2,"%d/%d/%d (%d) %02d:%02d:%02d",m_nMonth,m_nDayOfMonth,m_nYear,
                                        m_nDayOfYear,m_nHour, m_nMin, m_nSec);
  printf("Last GPS TurnOn times were:\n");
  fprintf(hdrfile,"Last GPS TurnOn times were:\n");
  printf("  %s & %s.\n",string1,string2);
  fprintf(hdrfile,"  %s & %s.\n",string1,string2);

  if ( headtype == MTW )
    temptime = swap4i(mwhead.roParms.timing.gpsLastLockTime[0]);
		else
    temptime = swap4i(k2head.roParms.timing.gpsLastLockTime[0]);
  CK2Time(temptime);
  sprintf(string1,"%d/%d/%d (%d) %02d:%02d:%02d",m_nMonth,m_nDayOfMonth,m_nYear,
                                        m_nDayOfYear,m_nHour, m_nMin, m_nSec);
  if ( headtype == MTW )
    temptime = swap4i(mwhead.roParms.timing.gpsLastLockTime[1]);
	else
    temptime = swap4i(k2head.roParms.timing.gpsLastLockTime[1]);
  CK2Time(temptime);
  sprintf(string2,"%d/%d/%d (%d) %02d:%02d:%02d",m_nMonth,m_nDayOfMonth,m_nYear,
                                        m_nDayOfYear,m_nHour, m_nMin, m_nSec);
  printf("Last GPS Lock times were:\n");
  fprintf(hdrfile,"Last GPS Lock times were:\n");
  printf("   %s & %s.\n",string1,string2);
  fprintf(hdrfile,"   %s & %s.\n",string1,string2);

  if ( headtype == MTW )
    hw = swap2(mwhead.roParms.timing.gpsLockFailCount);
	else
    hw = swap2(k2head.roParms.timing.gpsLockFailCount);
  printf("Count of times GPS failed to lock\n");
  fprintf(hdrfile,"Count of times GPS failed to lock\n");
  printf("    within gpsMaxTurnOnTime: %d\n",hw);
  fprintf(hdrfile,"    within gpsMaxTurnOnTime: %d\n",hw);

	// Battery stuff
  if ( headtype == MTW )
		bat = swap2(mwhead.roParms.misc.batteryVoltage);  // short, voltage * 10
	else
		bat = swap2(k2head.roParms.misc.batteryVoltage);  // short, voltage * 10
	x = bat * 1.0;
  x = x / 10.0;

	if (headver == K2100)
	{
    printf("Main battery: %3.2fV",x);
    fprintf(hdrfile,"Main battery: %3.2fV",x);
	}

  if ((headver == K2110) || (headver == K2130) || (headver == K2140))
  {

    hb = k2head.rwParms.misc.minBatteryVoltage;
    hr = ((float) hb) * 0.1;
    if (x < 0.0)
    {
      x = x * -1.0;  // make positive
      printf("Main battery: %3.2fV, charging, minimum alarm voltage: %3.1fV",x,hr);
      fprintf(hdrfile,"Main battery: %3.2fV, charging, minimum alarm voltage: %3.1fV",x,hr);
    }
    else
		{
      printf("Main battery: %3.2fV, minimum alarm voltage: %3.1fV",x,hr);
      fprintf(hdrfile,"Main battery: %3.2fV, Not charging, minimum alarm voltage: %3.1fV",x,hr);
		}
  }  // if headver K2

  if (headtype == MTW)
  {

    hb = mwhead.rwParms.misc.minBatteryVoltage;
    hr = ((float) hb) * 0.1;
    if (x < 0.0)
    {
      x = x * -1.0;  // make positive
      printf("Main battery: %3.2fV, charging, minimum alarm voltage: %3.1fV",x,hr);
      fprintf(hdrfile,"Main battery: %3.2fV, charging, minimum alarm voltage: %3.1fV",x,hr);
    }
    else
		{
		printf("Main battery: %3.2fV, minimum alarm voltage: %3.1fV",x,hr);
      fprintf(hdrfile,"Main battery: %3.2fV, Not charging, minimum alarm voltage: %3.1fV",x,hr);
		}
  }  // if headver MTW
  printf("\n\n");     fprintf(hdrfile,"\n\n");


  // determine which channels are in file, check map in 1st frame
	//   channel bitmap in frame only place used since beginning

	// READ FIRST FRAME HEADER HERE
	fread(&tag,sizeof(tag),1,infile);         // toss tag
	fread(&frmhdr,sizeof(frmhdr),1,infile);

  if (tag.sync != 'K')
  {
    printf("%s is a Header Only file. No data to write.\n",infname);
    fprintf(hdrfile,"%s is a Header Only file. No data to write.\n",infname);
    fcloseall();
    return;
  }


	// read channels in frame from channelbitmap
	chanavailbitmap = swap2(frmhdr.channelBitMap);
	chanmask = 0x0001;     // chan 1 is in bit 0
	tempint = 0;
	chanct = 0;            // counts channels in initial display

	// setup list of used channels

	for (j = 0; j < MAX_CHANNELS; j++)  // initialize
	  chanavail[j] = FALSE;

	k = 0;
	for (j = 0; j < MAX_CHANNELS; j++)  // 3/17/95 make work for 18
	{
    if (headtype == MTW)
	  {
		 if (j == 16)      // channel 17
		 {
			chanavailbitmap = (int)frmhdr.channelBitMap1;   // only 1 byte
			chanmask = 0x0001;       // reset mask
		 }
	  }
	  else
	  {
		 if (j == MAX_K2_CHANNELS)
			break;                     // stop testing - not legal
	  }

	  tempint = chanavailbitmap & chanmask;

	  chidx[j] = 0;                  // zero 1st then make some 'channel number'
	  if (tempint != 0)
	  {
		 chidx[k] = j +1;             //      2,          = 3  etc.
		 k ++;

		 chanavail[j] = TRUE;
		 chanct = chanct +1;            // increment channel counter
	  }  //  if tempint != 0

    chanmask = chanmask << 1;      // shift mask left 1 bit
	}  // for j = 0 < max-chans

	if ( chanct != usedchans )
	{
		printf("# channels do not match: header %d  1st frame %d\n",usedchans,chanct);
		fprintf(hdrfile,"# channels do not match: header %d  1st frame %d\n",usedchans,chanct);
		fcloseall();
		return;
	}


	// WRITE HEADER FILE HERE ...
	if (fmhdflag == TRUE)
	{
    printf("\nWriting formatted header, %s, to disk.\n",hfpname);
    fprintf(hdrfile,"\nWriting formatted header, %s, to disk.\n",hfpname);

    hfp = fopen(hfpname,"wt");
	  decodeheader1();
	  decodeheader2();
    fclose(hfp);

	}  // fmhdflag == TRUE




	// OPEN CHANNEL FILES

  // BC limit of 20 files open at once,  when run 18 channel file
  //    only get files .001 thru .012, rest have NULL/VOID pointers

  if (chanct > (FIRST_LIMIT+1))
  {
	 printf("\nChannel Count > %d, demultiplex data in two passes.\n",FIRST_LIMIT +1);

	 // FIRST PASS
	  for ( i = 0; i < FIRST_LIMIT; i++ )
	  {
		 strncpy(chname[i],infname,(strlen(infname) -3));
		  sprintf(string1,"%03d",chidx[i]);
		 strcat(chname[i],string1);
		  chfile[i] = fopen(chname[i],"wt");
		  i = i;
	 }

	 //OPEN OVERFLOW TEMPORARY FILE
	 strcpy(overname,"OVER.BIN");      // text file for
	 overfile = fopen(overname,"wt");  //  overflow data channels

	  //........................
	  //
	  // LOOP TO DO FRAMES  --  FIRST PASS
	  //
	  //........................

	  scansPerFrame = 0;
	  bytesPerSample = 0;
	  bytesPerScan = 0;
	  frameSize = 0;

    frameCounter = 0L;
    mscans = 0L;

//    for ( frameCounter = 0;; )
    do
	  {
		  //read tag structure
		  if ( frameCounter != 0 )   // already have 0th tag
		  {
			  i= fread(&tag,sizeof(tag),1,infile);
			  if ( i!= 1 )
			  {
				  break;
			  }
			  i= fread(&frmhdr,sizeof(frmhdr),1,infile);
			  if ( i!= 1 )
			  {
				  break;
			  }
		  } // if frameCounter != 0 .. already have 0th tag & frameheader

		  framestat = frmhdr.frameStatus & 0xC0;
		  switch ( framestat )
		  {
			  case 0x40: bytesPerSample = 2; break;
			  case 0x80: bytesPerSample = 3; break;
        case 0xC0: bytesPerSample = 4; break;
        default:   bytesPerSample = 3;         // added 5/20/96
		  }

		  bytesPerScan = bytesPerSample * chanct;
		  frameSize = swap2(frmhdr.frameSize) -32;  // # data bytes following frame head
		  scansPerFrame = frameSize / bytesPerScan;

		  if ( scansPerFrame != (sps/10) )
		  {
        printf("\nFrame %ld, %d bytes, %d scans, not 0.1 sec\n",
              frameCounter+1,frameSize,scansPerFrame);
              // needs '\n' at beginning to end field of '.....'

        fprintf(hdrfile,"Frame %ld, %d bytes, %d scans, not 0.1 sec\n",
                   frameCounter+1,frameSize,scansPerFrame);
		  }

      if ( (frameSize < 2)         //  1 ch *  1scans * 2 bytes - minimum  100sps
                                   // 10/3/96  1.72,  was 20
          || (frameSize > 7200) )   // 18 ch * 100scans * 4 bytes - maximum 1000sps
        {
					printf("\nInvalid frame Size = %d. Terminating Program.\n",frameSize);
					fprintf(hdrfile,"Invalid frame Size = %d. Terminating Program.\n",frameSize);
          fcloseall();
          for ( i = 0; i < FIRST_LIMIT; i++ )
          {
            remove(chname[i]);
          }
          remove(overname);
          return;
        }


      i = fread(&idata,frameSize,1,infile);  // read frame's data samples

      if (i == 0)
      {
        fileseconds = mscans * ((float)1/sps);
        printf("\nPremature end of %s at frame %d.\n", infname,frameCounter);
        printf(" %ld scans found (%5.1f seconds)\n",mscans,fileseconds);
        fprintf(hdrfile,"Premature end of %s at frame %d.\n", infname,frameCounter);
        fprintf(hdrfile," %ld scans found (%5.1f seconds)\n",mscans,fileseconds);

// beg debug
//          printf("FrameSize= %d  scans= %ld   mscans=  %ld  i= %d\n",frameSize,scans,mscans, i);
// end debug

        scans = mscans;
        break;
      }
      else
      {
        if (i != 1)
        {
          printf("\nFrame %d data read failure.\n",frameCounter+1);

// beg debug
          printf("FrameSize= %d  scans= %ld   mscans=  %ld  i= %d\n",frameSize,scans,mscans, i);
// end debug

          fprintf(hdrfile,"Frame %d data read failure.\n",frameCounter+1);
          fcloseall();
          return;
        }
      }



      p = 0;  //  index for idata,  3 byte sample
      q = 0;  //  index for ixdata, 4 byte as byte
      k = 0;  //  index for ixdata, 4 bytes as 1 long

      for (i = 0; i < scansPerFrame; i++)      // # of scans in this frame
      {
        for (j = 0; j < chanct; j++)     // actual # of channels
        {
          if (bytesPerSample == 4)        // sambyte
          {
            ixdata.b[q]   = idata[p+3];      // low  - translate from
            ixdata.b[q+1] = idata[p+2];      // mid  - motorola 3 byte to
            ixdata.b[q+2] = idata[p+1];        // high - intel 4 byte
            ixdata.b[q+3] = idata[p];
          }
          else
          {
            if (bytesPerSample == 3)     // sambyte
              ixdata.b[q]   = idata[p+2];      // low  - translate from
            else
              ixdata.b[q] = 0x00;
            ixdata.b[q+1] = idata[p+1];      // mid  - motorola 3 byte to
            ixdata.b[q+2] = idata[p];        // high - intel 4 byte

            if ((ixdata.b[q+2] & 0x80) != 0)
              ixdata.b[q+3] = 0xFF;
            else
              ixdata.b[q+3] = 0x00;
          }

          // put data sample in file as float - Volts
          fsample = ((float)ixdata.l[k] * 2.5) / 8388608.0;

          if (fsample > 2.5)
            fsample = 2.5;
          if (fsample < -2.5)
            fsample = -2.5;

          if (j < FIRST_LIMIT)
            fprintf(chfile[j],"%12.9f\n",fsample);
          else
            fprintf(overfile,"%12.9f\n",fsample);  // multiplexed ascii samples

            // increment pointers
          if (bytesPerSample == 4)       // sambyte
            p = p +4;
          if (bytesPerSample == 3)
            p = p +3;
          if (bytesPerSample == 2)
            p = p +2;
            q = q +4;
            k ++;
        }  //  for j = 0 < max_chans

       mscans++;
      }  // for i = 0 < framescans

      frameCounter++;
      printf(".");
      if ( (frameCounter % 50) == 0 )
        printf("\n");
      else
      {
        if ( (frameCounter % 10) == 0 )
          printf("  ");
        else
        {
          if ( (frameCounter % 5) == 0 )
            printf(" ");
        }  // not 10
       } // not 50
      //   }  // for frameCounter .. until fread fails
    } while(mscans < scans);

	 for (i = 0; i < FIRST_LIMIT; i++)
	 {
		if (chfile[i] != NULL)
		  fclose(chfile[i]);
	 }
	 fclose(overfile);


	 // SECOND PASS
	 printf("\nStarting Second Pass ...\n");

	 for ( i = FIRST_LIMIT; i < chanct; i++ )
	 {
		strncpy(chname[i],infname,(strlen(infname) -3));
		sprintf(string1,"%03d",chidx[i]);
		strcat(chname[i],string1);
		chfile[i] = fopen(chname[i],"wt");
		i = i;
	 }

	 overfile = fopen(overname,"rt");

	 for (frameCounter = 0;frameCounter < scans; frameCounter++)
				// frameCounter used here as scan counter
	 {
		 for ( i = FIRST_LIMIT; i < chanct; i++ )
		 {
		  fgets(string1,20,overfile);

		  j = strlen(string1);

		  if (j == NULL)  break;

		  fprintf(chfile[i],"%s",string1);

		}  // for channels over

		if ( (frameCounter % scansPerFrame) == 0 )
		  printf(".");
		if ( (frameCounter % (50 * scansPerFrame )) == 0 )
		  printf("\n");
		else
		{
		  if ( (frameCounter % (10 * scansPerFrame)) == 0 )
			 printf("  ");
		  else
		  {
			 if ( (frameCounter % (5 * scansPerFrame)) == 0 )
				printf(" ");
		  }  // not 10
		} // not 50

		if (j == NULL) break;

	 }  // for frameCounter until fscanf fails

	 fclose(overfile);
	 remove(overname);

  }  // if chanct > FIRST_LIMIT
  else
  {

	 printf("\nChannel Count <= %d, demultiplex data in one pass.\n",FIRST_LIMIT +1);

	  for ( i = 0; i < chanct; i++ )
	  {
		 strncpy(chname[i],infname,(strlen(infname) -3));
		  sprintf(string1,"%03d",chidx[i]);
		 strcat(chname[i],string1);
		  chfile[i] = fopen(chname[i],"wt");
		  i = i;
	 }

	  //........................
	  //
	  // LOOP TO DO FRAMES
	  //
	  //........................

	  scansPerFrame = 0;
	  bytesPerSample = 0;
	  bytesPerScan = 0;
	  frameSize = 0;

    frameCounter = 0L;
    mscans = 0L;

//    for ( frameCounter = 0;; )
    do
	  {
		  //read tag structure
		  if ( frameCounter != 0 )   // already have 0th tag
		  {
			  i= fread(&tag,sizeof(tag),1,infile);
			  if ( i!= 1 )
			  {
				  break;
			  }
			  i= fread(&frmhdr,sizeof(frmhdr),1,infile);
			  if ( i!= 1 )
			  {
				  break;
			  }
		  } // if frameCounter != 0 .. already have 0th tag & frameheader

		  framestat = frmhdr.frameStatus & 0xC0;
		  switch ( framestat )
		  {
			  case 0x40: bytesPerSample = 2; break;
			  case 0x80: bytesPerSample = 3; break;
        case 0xC0: bytesPerSample = 4;
		  }

      if ( (bytesPerSample < 2) || (bytesPerSample > 4) )
        bytesPerSample = 3;

      bytesPerScan = bytesPerSample * chanct;
		  frameSize = swap2(frmhdr.frameSize) -32;  // # data bytes following frame head
		  scansPerFrame = frameSize / bytesPerScan;

		  if ( scansPerFrame != (sps/10) )
		  {
        printf("\nFrame %ld, %d bytes, %d scans, not 0.1 sec\n",
                    frameCounter+1,frameSize,scansPerFrame);
        fprintf(hdrfile,"Frame %ld, %d bytes, %d scans, not 0.1 sec\n",
                    frameCounter+1,frameSize,scansPerFrame);
		  }

			if ( (frameSize < 2)         //  1 ch *  10scans * 2 bytes - minimum  100sps
																	 // 1.80 was 20
					|| (frameSize > 7200) )   // 18 ch * 100scans * 4 bytes - maximum 1000sps
				{
					printf("\nInvalid frame Size = %d. Terminating Program.\n",frameSize);
					fprintf(hdrfile,"Invalid frame Size = %d. Terminating Program.\n",frameSize);
          fcloseall();
          for ( i = 0; i < FIRST_LIMIT; i++ )
            remove(chname[i]);
          return;
        }

	    i = fread(&idata,frameSize,1,infile);  // read frame's data samples

	    if (i != 1)
	    {
        printf("\nFrame %d data read failure.\n",frameCounter+1);
        fprintf(hdrfile,"Frame %d data read failure.\n",frameCounter+1);
			  fcloseall();
        for ( i = 0; i < FIRST_LIMIT; i++ )
          remove(chname[i]);
			  return;
	    }

	    p = 0;  //  index for idata,  3 byte sample
	    q = 0;  //  index for ixdata, 4 byte as byte
	    k = 0;  //  index for ixdata, 4 bytes as 1 long

	    for (i = 0; i < scansPerFrame; i++)      // # of scans in this frame
	    {
		   for (j = 0; j < chanct; j++)     // actual # of channels
		   {

          if (bytesPerSample == 4)        // sambyte
          {
            ixdata.b[q]   = idata[p+3];      // low  - translate from
            ixdata.b[q+1] = idata[p+2];      // mid  - motorola 3 byte to
            ixdata.b[q+2] = idata[p+1];        // high - intel 4 byte
            ixdata.b[q+3] = idata[p];
          }
          else
          {
            if (bytesPerSample == 3)     // sambyte
              ixdata.b[q]   = idata[p+2];      // low  - translate from
            else
              ixdata.b[q] = 0x00;
            ixdata.b[q+1] = idata[p+1];      // mid  - motorola 3 byte to
            ixdata.b[q+2] = idata[p];        // high - intel 4 byte

            if ((ixdata.b[q+2] & 0x80) != 0)
              ixdata.b[q+3] = 0xFF;
            else
              ixdata.b[q+3] = 0x00;
          }

			     // put data sample in file as float - fraction of Full Scale
				  fsample = ((float)ixdata.l[k] * 2.5) / 8388608.0;

				  if (fsample > 2.5)
				    fsample = 2.5;
				  if (fsample < -2.5)
				    fsample = -2.5;

          fprintf(chfile[j],"%12.9f\n",fsample);

			    // increment pointers
			    p = p +3;
			    q = q +4;
			    k ++;
       }  //  for j = 0 < max_chans

				mscans++;
			}  // for i = 0 < framescans

		  frameCounter++;
		  printf(".");
		  if ( (frameCounter % 50) == 0 )
			  printf("\n");
		  else
		  {
			  if ( (frameCounter % 10) == 0 )
			  {
				  printf("  ");
			  }
			  else
			  {
			   if ( (frameCounter % 5) == 0 )
				   printf(" ");
			  }
		  }
//    }  // for frameCounter .. until fread fails
      } while (mscans < scans);

  }  //  if chanct <= 12

	printf("\nFiles Created: %s, \n", hdrname);
	for (i = 0; i < chanct;i++)
	{
	  printf("  %s\n",chname[i]);
	}

	fprintf(hdrfile,"\nFiles Created: %s, \n", hdrname);
	for (i = 0; i < chanct;i++)
	{
	  fprintf(hdrfile,"  %s\n",chname[i]);
	}

	fcloseall();

	printf("\nKW2ASC completed.\n");



}  // main


/*---  end kw2asc.c   ------------------------------------------------------*/

/*--------------------------------------------------------------------------*/
/* kwhd1.c */
/*--------------------------------------------------------------------------*/
/*  kwhd1.c    1st half: master header formatter file for DOS programs */

/*  6/10/86  1.00  change #include to proper .H file;
                   before call to decodeheader1() do
                      hfp = fopen(hfpname,"wt");
                   after return from decodeheader2() do
                      fclose(hfp); */
/*                 for KWPARD - edit out all 'ro' items
                     #define HEADER == FALSE in kwpard.h */

/*  6/11/96        change modem_rw.cellStartTime[] from 2 to 5   (kwhd2.c)
                   make selected channels condition on HEADER or PARMS */

/* used by kwpard, kw2asc, kwrc, kwphf  */
/* HEADER == FALSE, TRUE,  TRUE, TRUE */
/* not used by kwtc, kwtrig, kwntp, kwsum, kw2cnts, or kw2suds, kw2v1 */
/* 6/18/96         battery: added 'Not Charging' */
/* 6/19/96         make all formatted headers the same, master in \kwsup\heads */
/* 6/24/96         fix bug in ro.channels: maxpeak, @, minpeak, @, mean, aqoffset */
/*                  not treated as physical (pixed place) items,
                    stored as logical, ie. if
                     recording ch 3,5,7, info in index 0,1,2, not 2,4,6 */
/* 7/2/96          add default 'Unknown(%d)' to sensor type */
/* 7/10/96         expand stream.filterflag when !HEADER (for kwpard only) */
/*                 add array propagation window - stream_rw_parms.apw */
/*                 add show sps when !HEADER */
/*                 add primary/secondary storage */
/* 9/19/96         merged vhf1/2.c into kwhd1/2.c */
/* 3/17/97         FIX: MAX & MIN peak time offsets hard coded to 0.005 */
/* 3/29/97         ADD: 1.40 K2 & 1/50 MTW */
/* 3/30/97         ADD: Seismological Parms & Serial Data Stream Parms */

#include "kw2asc.h"   /* kw2asc.h, kwphf.h, kwpard.h, kwrc.h, qlca.h */

#include <dos.h>
#include <dir.h>

//  Decode and write K2 header file to disk
//  Header-Write command


void decodeheader1(void)
{
int i,j,k;  // indexii

char tempstr[90];
char string1[80];
char by,by1,hb;
short wd;
int hi,hi1,hi2,hi3;
short bat;
unsigned int hw1,hw2;
unsigned short us;
long lw,lwa,lwb;
unsigned long ul,templ,chanmask;
unsigned long ulmask, ulsave;
float x,gs;
float hr;
float si;
unsigned char uc;
int code[MAX_CHANNELS],cd;

struct ffblk ffblk;
unsigned int d1,d2,d3,t1,t2,t3;

// already have this!
//  headver = swap2(head.roParms.headerVersion);
//      ver = K2100, K2110, k2130, k2140 or MTW120, MTW150
//  file, hfp, already open
//  headtype = K2 or MTW

  // setup control for loops

  k = chanct;

  si = (float)k;
  si = si/3.0;  // want 0 , 1, 2 or 3
  row = 0;
  if (si > 1.0) row = 1;  if (si > 2.0) row = 2;  if (si > 3.0) row = 3;
  if (si > 4.0) row = 4;  if (si > 5.0) row = 5;  if (si > 6.0) row = 6;

  fprintf(hfp,"\n");
    findfirst(infname,&ffblk,0);
		d1 = (unsigned int)ffblk.ff_fdate & 0x001f;   // day
		d2 = (unsigned int)ffblk.ff_fdate & 0x01e0;
		d2 = d2 >> 5;                   // month
		d3 = (unsigned int)ffblk.ff_fdate & 0xfe00;
		d3 = 1980 + (d3 >> 9);          // year
		t1 = (unsigned int)ffblk.ff_ftime & 0x001f;
		t1 = t1 << 1;                   // seconds -- not used
		t2 = (unsigned int)ffblk.ff_ftime & 0x07e0;
		t2 = t2 >> 5;                   // minutes
		t3 = (unsigned int)ffblk.ff_ftime & 0xf800;
		t3 = t3 >> 11;                  // hours
   fprintf(hfp,"KW2ASC: %s   %02d/%02d/%d %02d:%02d \n",infname,d2,d1,d3,t3,t2);
          /* KW2ASC, KWPHF, KWPARD, KWRC, QLCA */

    if ( headtype == MTW )
		  us = swap2(mwhead.rwParms.misc.serialNumber);
		else
		  us = swap2(k2head.rwParms.misc.serialNumber);

    if (headtype == MTW)
      fprintf(hfp,"Altus Mt.Whitney ");
		else
      fprintf(hfp,"Altus K2 ");
   fprintf(hfp,"Header, Version. %3.2f,  S/N %d",(float)headver*0.01,us);
   fprintf(hfp,"\n");

    if ( headtype == MTW )
      strcpy(tempstr,mwhead.rwParms.misc.stnID);
		else
      strcpy(tempstr,k2head.rwParms.misc.stnID);
    fprintf(hfp," Stn: %s",tempstr);

    if ( headtype == MTW )                     // added 5/21/96
      strcpy(tempstr,mwhead.rwParms.misc.siteID);
		else
      strcpy(tempstr,k2head.rwParms.misc.siteID);
    fprintf(hfp,"  Site: %s",tempstr);


#if HEADER      // not used for kwpard
    if ( headtype == MTW )
      wd = swap2(mwhead.roParms.stream.flags);
		else
      wd = swap2(k2head.roParms.stream.flags);
    if ((wd & 0x0003) == 1)
      fprintf(hfp,"   Functional Test");
    if ((wd & 0x0003) == 3)
      fprintf(hfp,"   Sensor Response Test");   // added 5/21/96
    if ((wd & 0x0004) == 4)
      fprintf(hfp,"   Trigger Data File");      // added 5/30/96
#endif
  fprintf(hfp,"\n");

#if HEADER      // not used for kwpard
    if ( headtype == MTW )
      us = swap2(mwhead.roParms.misc.maxChannels);
		else
      us = swap2(k2head.roParms.misc.maxChannels);
   fprintf(hfp," %d  channel unit,",us);
#endif

    if ( headtype == MTW )
		  us = swap2(mwhead.rwParms.misc.nchannels);
		else
		  us = swap2(k2head.rwParms.misc.nchannels);
   fprintf(hfp," %d channel(s) selected: ",us);

#if HEADER
    for (i = 0; i <MAX_CHANNELS; i++)
    {
      if (chanavail[i] == TRUE)
      fprintf(hfp," %d",i+1);   // channels start at 1, array at 0
    }
#else
    if ( headtype == MTW )
      ul = swap4i(mwhead.rwParms.misc.channel_bitmap);
		else
      ul = swap4i(k2head.rwParms.misc.channel_bitmap);

    chanmask = 0x00000001;     // chan 1 is in bit 0

    for (i = 0; i <MAX_CHANNELS; i++)
    {

      templ = ul & chanmask;

      if (templ != 0)
      {
        fprintf(hfp," %d",i+1);   // channels start at 1, array at 0
      }  //  if templ != 0

      chanmask = chanmask << 1;      // shift mask left 1 bit
    }
#endif
  fprintf(hfp,"\n");


#if HEADER      // not used for kwpard
    if ( headtype == MTW )      // added 5/21/96
      ul = swap4i(mwhead.roParms.stream.triggerBitMap);
		else
      ul = swap4i(k2head.roParms.stream.triggerBitMap);
    fprintf(hfp," Channel(s) triggered: ",ul);

    for (i = 0; i <MAX_CHANNELS; i++)
    {
      if ((ul & 0x00000001) == 1)    // unsigned long = 4 bytes
        fprintf(hfp," %d",i+1);   // channels start at 1, array at 02
      ul = ul >> 1;
    }
  fprintf(hfp,"\n");
#endif

   fprintf(hfp,"Comment: ");
    if ( headtype == MTW )
		  strcpy(tempstr,mwhead.rwParms.misc.comment);
		else
		  strcpy(tempstr,k2head.rwParms.misc.comment);
    fprintf(hfp,tempstr);

  fprintf(hfp,"\n");

    fprintf(hfp,"UserCodes: ");   // added 5/21/96

    for (i = 0; i < 4; i++)
    {
      if ( headtype == MTW )
        wd = mwhead.rwParms.misc.userCodes[i];
      else
        wd = k2head.rwParms.misc.userCodes[i];
      fprintf(hfp,"  %d",wd);
    }

  fprintf(hfp,"\n");
  fprintf(hfp,"\n");

#if HEADER      // not used for kwpard
    if ( headtype == MTW )
		  bat = swap2(mwhead.roParms.misc.batteryVoltage);  // short, voltage * 10
		else
		  bat = swap2(k2head.roParms.misc.batteryVoltage);  // short, voltage * 10
		x = bat * 1.0;
    x = x / 10.0;

    if (headver == K2100)
      fprintf(hfp,"Main battery: %3.2fV",x);

    if ((headver == K2110) || (headver == K2130) || (headver == K2140))
    {
      hb = k2head.rwParms.misc.minBatteryVoltage;
      hr = ((float) hb) * 0.1;
      if (x < 0.0)
      {
        x = x * -1.0;  // make positive
        fprintf(hfp,"Main battery: %3.2fV, charging, minimum alarm voltage: %3.1fV",x,hr);
      }
      else       // mtw
        fprintf (hfp,"Main battery: %3.2fV, Not Charging, minimum alarm voltage: %3.1fV",x,hr);
    }  // if headver K2110

    if (headtype == MTW)
    {
      hb = mwhead.rwParms.misc.minBatteryVoltage;
      hr = ((float) hb) * 0.1;
      if (x < 0.0)
      {
        x = x * -1.0;  // make positive
        fprintf(hfp,"Main battery: %3.2fV, charging, minimum alarm voltage: %3.1fV",x,hr);
      }
      else
        fprintf (hfp,"Main battery: %3.2fV, Not Charging, minimum alarm voltage: %3.1fV",x,hr);
    }  // if headver mtw
  fprintf(hfp,"\n");
#else
    if ((headver == K2110) || (headver == K2130) || (headver == K2140))
    {
      hb = k2head.rwParms.misc.minBatteryVoltage;
      hr = ((float) hb) * 0.1;
      fprintf(hfp,"Minimum alarm voltage: %3.1fV",hr);
    }  // if headver K2


    if (headtype == MTW)
    {
      hb = mwhead.rwParms.misc.minBatteryVoltage;
      hr = ((float) hb) * 0.1;
      fprintf(hfp,"Minimum alarm voltage: %3.1fV",hr);
    }  // if headver mtwxxx
  fprintf(hfp,"\n");

#endif



#if HEADER      // not used for kwpard
    if ( headtype == MTW )
		{
     fprintf(hfp,"   %d bit A/D",mwhead.roParms.misc.a2dBits);
	    wd = swap2(mwhead.roParms.timing.acqDelay);
		}
		else
		{
     fprintf(hfp,"   %d bit A/D",k2head.roParms.misc.a2dBits);
	    wd = swap2(k2head.roParms.timing.acqDelay);
		}
   fprintf(hfp," with group delay: %d msec",wd);
  fprintf(hfp,"\n");

  if ((headver == K2110) || (headver == K2130) || (headver == K2140))
  {
    wd = swap2(k2head.roParms.misc.temperature);
    hr = (float)wd * 0.1;
   fprintf(hfp,"Temperature:  %4.1f deg.C",hr);
  fprintf(hfp,"\n");
  }
  if (headtype == MTW)
  {
    wd = swap2(mwhead.roParms.misc.temperature);
    hr = (float)wd * 0.1;
   fprintf(hfp,"Temperature:  %4.1f deg.C",hr);
  fprintf(hfp,"\n");
  }
  fprintf(hfp,"\n");

  if ((headver == K2110) || (headver == K2130) || (headver == K2140))
  {
    hb = k2head.roParms.misc.restartSource;
   fprintf(hfp,"Restart Source(s):\n");
    if ((hb& 0xFF) == 0x00)
    fprintf(hfp,"  None Known.\n");
    if ((hb& 0x01) == 0x01)
    fprintf(hfp,"  Power switch.\n");
    if ((hb& 0x02) == 0x02)
    fprintf(hfp,"  User command.\n");
    if ((hb& 0x04) == 0x04)
    fprintf(hfp,"  Software watchdog.\n");
    if ((hb& 0x08) == 0x08)
    fprintf(hfp,"  DSP failure.\n");
    if ((hb& 0x10) == 0x10)
    fprintf(hfp,"  Battery failure.\n");
    if ((hb& 0x20) == 0x20)
    fprintf(hfp,"  Memory failure.\n");
  fprintf(hfp,"\n");

    hb = k2head.roParms.misc.flags;
   fprintf(hfp,"System Error(s):\n");
    if ((hb& 0xFF) == 0x00)
    fprintf(hfp,"  None Known.\n");
    if ((hb& 0x01) == 0x01)
    fprintf(hfp,"  DSP system error.\n");
  fprintf(hfp,"\n");
  }  // if headver == K2
  if (headtype == MTW)
  {
    hb = mwhead.roParms.misc.restartSource;
   fprintf(hfp,"Restart Source(s):\n");
    if ((hb& 0xFF) == 0x00)
    fprintf(hfp,"  None Known.\n");
    if ((hb& 0x01) == 0x01)
    fprintf(hfp,"  Power switch.\n");
    if ((hb& 0x02) == 0x02)
    fprintf(hfp,"  User command.\n");
    if ((hb& 0x04) == 0x04)
    fprintf(hfp,"  Software watchdog.\n");
    if ((hb& 0x08) == 0x08)
    fprintf(hfp,"  DSP failure.\n");
    if ((hb& 0x10) == 0x10)
    fprintf(hfp,"  Battery failure.\n");
    if ((hb& 0x20) == 0x20)
    fprintf(hfp,"  Memory failure.\n");
  fprintf(hfp,"\n");

    hb = mwhead.roParms.misc.flags;
   fprintf(hfp,"System Error(s):\n");
    if ((hb& 0xFF) == 0x00)
    fprintf(hfp,"  None Known.\n");
    if ((hb& 0x01) == 0x01)
    fprintf(hfp,"  DSP system error.\n");
  fprintf(hfp,"\n");
  }  // if headtype == MTW

   fprintf(hfp,"Altus Time Source: ");
    if ( headtype == MTW )
		  uc = mwhead.roParms.timing.clockSource;
		else
		  uc = k2head.roParms.timing.clockSource;
    if (uc == 0)
    fprintf(hfp,"RTC from cold start.");
    if (uc == 1)
    fprintf(hfp,"Keyboard.");
    if (uc == 2)
    fprintf(hfp,"Synchronized with external reference pulse.");
    if (uc == 3)
    fprintf(hfp,"Internal GPS Receiver.");
  fprintf(hfp,"\n");

//  ver 1.10 Msec taken care of when time first decoded.
   fprintf(hfp,"Event Start Time: %s",starttime);
  fprintf(hfp,"\n");

   fprintf(hfp,"Event Trigger Time: %s",trigtime);
  fprintf(hfp,"\n");
  fprintf(hfp,"\n");

   fprintf(hfp,"Samples per second:  %d",sps);
  fprintf(hfp,"\n");

    if (headver == K2100)
    {
      lw = swap4i(k2head.roParms.stream.duration);  // 1/10 second frames
      hr = (float)((float)lw * 0.1);
    fprintf(hfp,"Duration:  %6.3f seconds, %d frames.", hr, lw);
    }

    if ((headver == K2110) || (headver == K2130) || (headver == K2140))
    {
      lwa = swap4i(k2head.roParms.stream.duration); // variable time frames
      lwb = swap4i(k2head.roParms.stream.nscans);
      hr = (float)((float)lwb * ((float)1/sps));  // 1/sps
    fprintf(hfp,"Duration:  %6.3f seconds, %d frames",hr,lwa);

	    hb = k2head.rwParms.stream.filterFlag;
      if ((hb & 0x01) == 0x01)
        fprintf(hfp,"   Filtered Data");
      if ((hb & 0x02) == 0x02)
        fprintf(hfp,"   Auto FT after event");
      if ((hb & 0x04) == 0x04)
        fprintf(hfp,"   Data compressed");
    }

    if (headtype == MTW)
    {
      lwa = swap4i(mwhead.roParms.stream.duration); // variable time frames
      lwb = swap4i(mwhead.roParms.stream.nscans);
      hr = (float)((float)lwb * ((float)1/sps));  // 1/sps
    fprintf(hfp,"Duration:  %6.3f seconds, %d frames",hr,lwa);

      hb = mwhead.rwParms.stream.filterFlag;
      if ((hb & 0x01) == 0x01)
        fprintf(hfp,"   Filtered Data");
      if ((hb & 0x02) == 0x02)
        fprintf(hfp,"   Auto FT after event");
      if ((hb & 0x04) == 0x04)
        fprintf(hfp,"   Data compressed");
    }
  fprintf(hfp,"\n");

#else    // ! HEADER
    fprintf(hfp,"Samples per second:  %d",sps);
    fprintf(hfp,"\n");

    if ((headver == K2110) || (headver == K2130) || (headver == K2140))
    {
	    hb = k2head.rwParms.stream.filterFlag;
      if ((hb & 0x01) == 0x01)
        fprintf(hfp,"   Filtered Data");
      if ((hb & 0x02) == 0x02)
        fprintf(hfp,"   Auto FT after event");
      else
        fprintf(hfp,"   No Auto FT after event");
      if ((hb & 0x04) == 0x04)
        fprintf(hfp,"   Data compressed");
    }

    if (headtype == MTW)
    {
      hb = mwhead.rwParms.stream.filterFlag;
      if ((hb & 0x01) == 0x01)
        fprintf(hfp,"   Filtered Data");
      if ((hb & 0x02) == 0x02)
        fprintf(hfp,"   Auto FT after event");
      else
        fprintf(hfp,"   No Auto FT after event");
      if ((hb & 0x04) == 0x04)
        fprintf(hfp,"   Data compressed");
    }
  fprintf(hfp,"\n");
#endif


   fprintf(hfp,"Pre-event: ");
    if ( headtype == MTW )
      us = swap2(mwhead.rwParms.stream.preEvent);
		else
      us = swap2(k2head.rwParms.stream.preEvent);
   fprintf(hfp," %d seconds.",us);
  fprintf(hfp,"\n");

   fprintf(hfp,"Minimum runtime: ");
    if ( headtype == MTW )
      us = swap2(mwhead.rwParms.stream.minRunTime);
		else
      us = swap2(k2head.rwParms.stream.minRunTime);
   fprintf(hfp," %d seconds.",us);
  fprintf(hfp,"\n");

   fprintf(hfp,"Post event: ");
    if ( headtype == MTW )
      us = swap2(mwhead.rwParms.stream.postEvent);
		else
      us = swap2(k2head.rwParms.stream.postEvent);
   fprintf(hfp," %d seconds.",us);
   fprintf(hfp,"\n");

   fprintf(hfp,"Array Propagation Window: ");   // added 7/10/96
    if ( headtype == MTW )
      us = swap2(mwhead.rwParms.stream.apw);
		else
      us = swap2(k2head.rwParms.stream.apw);
   fprintf(hfp," %d seconds.",us);
  fprintf(hfp,"\n");

   fprintf(hfp,"Storage: Primary ");   // added 7/10/96
    if ( headtype == MTW )
      uc = (mwhead.rwParms.stream.primaryStorage);
		else
      uc = (k2head.rwParms.stream.primaryStorage);
    uc = uc + 0x41;            // 0 = A, 1 = B
   fprintf(hfp," %c:, ",uc);

   fprintf(hfp,"Secondary ");   // added 7/10/96
    if ( headtype == MTW )
      uc = (mwhead.rwParms.stream.secondaryStorage);
		else
      uc = (k2head.rwParms.stream.secondaryStorage);
    uc = uc + 0x41;            // 0 = A, 1 = B
   fprintf(hfp," %c: ",uc);
  fprintf(hfp,"\n");

   fprintf(hfp,"\n");


    if ( headtype == MTW )
      by = mwhead.rwParms.misc.cutlerCode;
		else
      by = k2head.rwParms.misc.cutlerCode;

    if (headver >= MTW120)
    {
      if ( headtype == MTW )
        by1 = mwhead.rwParms.misc.cutler_protocol;
			else
        by1 = k2head.rwParms.misc.cutler_protocol;

			if (by1 == 0)                             // USGS DFS protocol
      {
        if (by == 0)
          fprintf(hfp,"Digital Field Station OFF.");

        if ((by == 1) || (by == 2) || (by == 3))
          fprintf(hfp,"Digital Field Station ON: ");
        if (by == 1) fprintf(hfp," 4800 baud, 100 sps.");
        if (by == 2) fprintf(hfp," 9600 baud, 100 sps.");
        if (by == 3) fprintf(hfp," 19200 baud, 100 sps.");

        if ((by < 0) || (by > 3))
          fprintf(hfp,"Digital Field Station not defined");

      }  // USGS DFS
      else
      {
        if (by1 == 1)                           // KMI DFS protocol
        {
          if (by == 0)
            fprintf(hfp,"KMI Digital Port OFF.");
          else
          {
            fprintf(hfp,"KMI Digital Port ON: ");

            if (by == 1) fprintf(hfp," 4800 baud\n");
            if (by == 2) fprintf(hfp," 9600 baud\n");
            if (by == 3) fprintf(hfp," 19200 baud\n");
            if (by == 4) fprintf(hfp," 38400 baud\n");
            if (by == 5) fprintf(hfp," 57600 baud\n");
            if ((by <=0) || (by > 5))
              fprintf(hfp," baud rate undefined\n");

            if ( headtype == MTW )
              by = mwhead.rwParms.misc.cutler_irig_type;
            else
              by = k2head.rwParms.misc.cutler_irig_type;
            switch (by)
            {
              case 0: fprintf(hfp,"  DFS IRIG B\n"); break;
              case 1: fprintf(hfp,"  DFS IRIG E\n"); break;
              case 2: fprintf(hfp,"  DFS IRIG H\n"); break;
              default: fprintf(hfp,"  DFS IRIG undefined\n"); break;
            }  // switch: by= irig type

            if ( headtype == MTW )
              by = mwhead.rwParms.misc.cutler_decimation;
            else
              by = k2head.rwParms.misc.cutler_decimation;
            if ((by==0) || (by==1) || (by==2) || (by==3) || (by==4) || (by==5))
            {
              fprintf(hfp,"  Decimation = ");
              if (by==0) fprintf(hfp," 1:1\n");
              if (by==1) fprintf(hfp," 2:1\n");
              if (by==2) fprintf(hfp," 4:1\n");
              if (by==3) fprintf(hfp," 5:1\n");
              if (by==4) fprintf(hfp," 10:1\n");
              if (by==5) fprintf(hfp," 20:1\n");
            }
            else
              fprintf(hfp,"  Decimation = undefined\n",by);

            if ( headtype == MTW )
              ul = swap4i(mwhead.rwParms.misc.cutler_bitmap);
            else
              ul = swap4i(k2head.rwParms.misc.cutler_bitmap);

            if (ul != 0)
            {
              fprintf(hfp,"  DFS channels: ");

              ulmask = 0x00000001;        // mask for channels
              ulsave = ul;

              for (i= 0; i < MAX_CHANNELS; i++)
              {
               ul = ul & ulmask;
               if (ul != 0)
                 fprintf(hfp," %d", i +1);
               ulmask = ulmask << 1;
               ul = ulsave;
              }
              fprintf(hfp,"\n");

            }  // if cutler_bitmap != 0
            else
              fprintf(hfp,"  DFS channel bitmap undefined\n");

          } // kmi dfs ON
        }
        else
          fprintf(hfp,"Digital Field Station undefined");
      }  //  KMI DFS
    }
    else
    {                                     // header 1.00 or 1.10
      if (by == 0)
        fprintf(hfp,"Digital Field Station OFF.");
      if ((by == 1) || (by == 2) || (by == 3))
        fprintf(hfp,"Digital Field Station ON, decimation ");
      if (by == 1) fprintf(hfp,"4, 4800 baud, 50 sps.");
      if (by == 2) fprintf(hfp,"2, 9600 baud, 100 sps.");
      if (by == 3) fprintf(hfp,"1, 19200 baud, 200 sps.");
    }  // header < 120
  fprintf(hfp,"\n");
  fprintf(hfp,"\n");

#if HEADER      // not used for kwpard
   fprintf(hfp,"Program versions: ");
    if ( headtype == MTW )
      hi = swap2(mwhead.roParms.misc.sysBlkVersion);
		else
      hi = swap2(k2head.roParms.misc.sysBlkVersion);
    hr = (float)hi * 0.01;
   fprintf(hfp,"  sysBlk %3.2f",hr);
    if ( headtype == MTW )
      hi = swap2(mwhead.roParms.misc.bootBlkVersion);
		else
      hi = swap2(k2head.roParms.misc.bootBlkVersion);
    hr = (float)hi * 0.01;
   fprintf(hfp,", bootBlk  %3.2f,",hr);
  fprintf(hfp,"\n");

    if ( headtype == MTW )
      hi = swap2(mwhead.roParms.misc.appBlkVersion);
		else
      hi = swap2(k2head.roParms.misc.appBlkVersion);
    hr = (float)hi * 0.01;
   fprintf(hfp,"                    appBlk %3.2f",hr);
    if ( headtype == MTW )
      hi = swap2(mwhead.roParms.misc.dspBlkVersion);
		else
      hi = swap2(k2head.roParms.misc.dspBlkVersion);
    hr = (float)hi * 0.01;
   fprintf(hfp,",  dspBlk  %3.2f",hr);
  fprintf(hfp,"\n");
  fprintf(hfp,"\n");
#endif

    if ( headtype == MTW )
      hr = swap4r(mwhead.rwParms.misc.latitude);
		else
      hr = swap4r(k2head.rwParms.misc.latitude);
   fprintf(hfp,"Instrument latitude: %f Degrees North",hr);
  fprintf(hfp,"\n");

    if ( headtype == MTW )
      hr = swap4r(mwhead.rwParms.misc.longitude);
		else
      hr = swap4r(k2head.rwParms.misc.longitude);
   fprintf(hfp,"Instrument longitude: %f Degrees East",hr);
  fprintf(hfp,"\n");

    if ( headtype == MTW )
      wd = swap2(mwhead.rwParms.misc.elevation);   // short
		else
      wd = swap2(k2head.rwParms.misc.elevation);   // short
   fprintf(hfp,"Instrument elevation: %d Meters relative sea level.",wd);
  fprintf(hfp,"\n");
  fprintf(hfp,"\n");


#if HEADER      // not used for kwpard
  if ((headver == K2110) || (headver == K2130) || (headver ==  K2140))
  {
    hi = swap2(k2head.roParms.timing.gpsLatitude);  // short * 100
    hr = (float) (hi * 0.01);
   fprintf(hfp,"GPS latitude: %5.2f Degrees North", hr);
  fprintf(hfp,"\n");

    hi = swap2(k2head.roParms.timing.gpsLongitude);  // short * 100
    hr = (float) (hi * 0.01);
   fprintf(hfp,"GPS longitude: %5.2f Degrees East", hr);
  fprintf(hfp,"\n");

    wd = swap2(k2head.roParms.timing.gpsAltitude);   // short
   fprintf(hfp,"GPS altitude: %d Meters relative sea level.",wd);
  fprintf(hfp,"\n");
  }  // if K2
  if (headtype == MTW)
  {
    hi = swap2(mwhead.roParms.timing.gpsLatitude);  // short * 100
    hr = (float) (hi * 0.01);
   fprintf(hfp,"GPS latitude: %5.2f Degrees North", hr);
  fprintf(hfp,"\n");

    hi = swap2(mwhead.roParms.timing.gpsLongitude);  // short * 100
    hr = (float) (hi * 0.01);
   fprintf(hfp,"GPS longitude: %5.2f Degrees East", hr);
  fprintf(hfp,"\n");

    wd = swap2(mwhead.roParms.timing.gpsAltitude);   // short
   fprintf(hfp,"GPS altitude: %d Meters relative sea level.",wd);
  fprintf(hfp,"\n");
  }  // if K2110
  fprintf(hfp,"\n");
#endif

#if HEADER      // not used for kwpard

  // ro.channel stuff in logical order, ie. ch 3 5 7 @ index 0,1,2 not 2,4,6
  //  start of channel stuff that uses loops
    for (j = 0; j <= row; j++)  // ROWS
    {
      fprintf(hfp,"Ch                   ");
      for (k = 0; k < 3; k ++)  // COLUMNS
      {
        if (chidx[(j*3)+k] != 0)  // valid channel
        {
       fprintf(hfp,"%2d",chidx[(j*3)+k]);
          if ((k == 0) || (k == 1))
          {
//            if ((chidx[(j*3)+k+1] >=1) && (chidx[(j*3)+k+1] <=9))
          fprintf(hfp,"              ");  // 14 spaces
//            else
//          fprintf(hfp,"              ");  // 14 spaces
          }  // k == 0,1
        }  // if chidx active
      }  // for k
      fprintf(hfp,"\n");

      fprintf(hfp,"  MaxPeak:      ");
      for (k = 0; k < 3; k++)
      {
        if (chidx[(j*3)+k] != 0)
        {
          if (headtype == MTW)
            lw = swap4i(mwhead.roParms.channel[(j*3)+k].maxPeak);
          else
            lw = swap4i(k2head.roParms.channel[(j*3)+k].maxPeak);
          gs = ad_val(lw);
          if ((gs < -3.0) || (gs > 3.0))
            gs = 0.0;
          fprintf(hfp,"%11.7fV",gs);
          if ( (k == 0) || (k == 1 ))
            fprintf(hfp,"    ");  // 4 spaces
        }  // if channel
      }
      fprintf(hfp,"\n");

    fprintf(hfp,"   at seconds:  ");
		for (k = 0; k < 3; k++)
		{
		  if (chidx[(j*3)+k] != 0)
      {
        if (headtype == MTW)
         lw = swap4i(mwhead.roParms.channel[(j*3)+k].maxPeakOffset);
        else
         lw = swap4i(k2head.roParms.channel[(j*3)+k].maxPeakOffset);

        hr = lw * (float)(1.0/sps);   // fixed 3/17/97  was 0.005

        fprintf(hfp," %11.3f",hr);
        if ( (k == 0) || (k == 1) )
          fprintf(hfp,"    ");  // 4 spaces
		  }  // if have chan
		}
    fprintf(hfp,"\n");

    fprintf(hfp,"  MinPeak:      ");
		for (k = 0; k < 3; k++)
		{
		  if (chidx[(j*3)+k] != 0)
		  {
        if (headtype == MTW)
          lw = swap4i(mwhead.roParms.channel[(j*3)+k].minPeak);
			  else
          lw = swap4i(k2head.roParms.channel[(j*3)+k].minPeak);
			  gs = ad_val(lw);
			  if ((gs < -3.0) || (gs > 3.0))
          gs = 0.0;
        fprintf(hfp,"%11.7fV",gs);
			  if ( (k == 0) || (k == 1) )
          fprintf(hfp,"    ");  // 4 spaces
			}  // if have chan
		}
    fprintf(hfp,"\n");

    fprintf(hfp,"   at seconds:  ");
		for (k = 0; k < 3; k++)
		{
		  if (chidx[(j*3)+k] != 0)
      {
        if (headtype == MTW)
         lw = swap4i(mwhead.roParms.channel[(j*3)+k].minPeakOffset);
        else
         lw = swap4i(k2head.roParms.channel[(j*3)+k].minPeakOffset);

        hr = lw * (float)(1.0/sps);     // fixed 3/17/97  was 0.005

        fprintf(hfp," %11.3f",hr);
        if ( (k==0) || (k ==1) )
        fprintf(hfp,"    ");  // 4 spaces
		  }  // if have chan
		}
    fprintf(hfp,"\n");

    fprintf(hfp,"  Mean:          ");
		for (k = 0; k < 3; k++)
		{
		  if (chidx[(j*3)+k] != 0)
			{
        if (headtype == MTW)
          lw = swap4i(mwhead.roParms.channel[(j*3)+k].mean);
			  else
          lw = swap4i(k2head.roParms.channel[(j*3)+k].mean);
			  gs = ad_val(lw);
        fprintf(hfp,"%10.7fV",gs);
        if ( (k==0) || (k==1) )
         fprintf(hfp,"     ");  // 5 spaces
		  }  // if have chan
		}
    fprintf(hfp,"\n");

    if (headver >= K2110)
		{
      fprintf(hfp,"  AcqOffset:   ");
		  for (k = 0; k < 3; k++)
		  {
        if (chidx[(j*3)+k] != 0)
        {

          if (headtype == MTW)
            lw = swap4i(mwhead.roParms.channel[(j*3)+k].aqOffset);
          else
            lw = swap4i(k2head.roParms.channel[(j*3)+k].aqOffset);
          gs = ad_val(lw);
          if ((gs < -3.0) || (gs > 3.0))
            gs = 0.0;
          fprintf(hfp,"%12.7fV",gs);
          if ( (k==0) || (k==1) )
            fprintf(hfp,"   ");  // 3 spaces
        }  // if have chan
      }  // for
       fprintf(hfp,"\n");
    }  // if headver >= K2110
    fprintf(hfp,"\n");  // blank line  end of set
	 } // for j
#endif

   for (j = 0; j <= row; j++)   // ROWS
	 {
    fprintf(hfp,"Ch                   ");
		for (k = 0; k < 3; k++)     //  COLUMNS
		{
		  if (chidx[(j*3)+k] !=0)
		  {
       fprintf(hfp,"%2d",chidx[(j*3)+k]);
			 if ((k==0) || (k==1))
			 {
//        if ((chidx[(j*3)+k+1] >= 1) && (chidx[(j*3)+k+1] <= 9))
          fprintf(hfp,"               ");  // 15 spaces
//        else
//          fprintf(hfp,"               ");  // 15 spaces
			 }
		  }  // for chidx
		}  // for k
    fprintf(hfp,"\n");

    fprintf(hfp,"  Chan ID:           ");   // 16 chars
		for (k = 0;k < 3; k ++)
		{
		  if (chidx[(j*3)+k] != 0)
	{
    if (headtype == MTW)
		 strcpy(tempstr,mwhead.rwParms.channel[chidx[(j*3)+k]-1].id);
	  else
		 strcpy(tempstr,k2head.rwParms.channel[chidx[(j*3)+k]-1].id);
			 if (strlen(tempstr) == 3)
			 {
				strcpy(string1," ");   // 1 space
				strcat(string1,tempstr);
				strcpy(tempstr,string1);
			 }
			 if (strlen(tempstr) == 2)
			 {
				strcpy(string1,"  ");   // 2 spaces
				strcat(string1,tempstr);
				strcpy(tempstr,string1);
			 }
			 if (strlen(tempstr) == 1)
			 {
				strcpy(string1,"   ");   // 3 spaces
				strcat(string1,tempstr);
				strcpy(tempstr,string1);
          }
          if (strlen(tempstr) == NULL)
            strcpy(tempstr,"----");
       fprintf(hfp,"%s,",tempstr);
          if ( (k==0) || (k==1) )
        fprintf(hfp,"            ");  // 12 spaces
        }  // if have chan
      } // for k
    fprintf(hfp,"\n");

    fprintf(hfp,"  Sensors:     ");  // 16 chars
      for (k=0; k < 3; k++)
      {
        if (chidx[(j*3)+k] != 0)
        {
           if ( headtype == MTW )
               hi1 = swap2(mwhead.rwParms.channel[chidx[(j*3)+k]-1].sensorType);
           else
               hi1 = swap2(k2head.rwParms.channel[chidx[(j*3)+k]-1].sensorType);

           code[(j*3)+k] = hi1;   // save for Sensitivity below

           switch (hi1) // 17 spaces
           {
             case SENSOR_UNKNOWN:                 // 0
               fprintf(hfp,"   Unknown (0)   ");
                break;

             case SENSOR_ACCELERATION:            // 1
               fprintf(hfp," Acceleration(1) ");
                break;

             case SENSOR_VELOCITY:                // 2
               fprintf(hfp,"   Velocity(2)   ");
                break;

             case SENSOR_FBA11:                   // 10
               fprintf(hfp,"   FBA_11 (10)   ");
                break;

             case SENSOR_FBA_4G:                  // 11  4g FBA
               fprintf(hfp,"   4g FBA (11)   ");
                break;

             case SENSOR_FBA_2G:                  // 12  2g FBA
               fprintf(hfp,"   2g FBA (12)   ");
                break;

             case SENSOR_FBA_1G:                  // 13	1g FBA
               fprintf(hfp,"   1g FBA (13)   ");
                break;

             case SENSOR_FBA_0_5G:                // 14	0.5g FBA
               fprintf(hfp,"  0.5g FBA (14)  ");
                break;

             case SENSOR_FBA_0_25G:               // 15	0.25g FBA
               fprintf(hfp,"  0.25g FBA (15) ");
                break;

             case SENSOR_FBA_0_1G:                // 16	0.1g FBA
               fprintf(hfp,"  0.1g FBA (15)  ");
                break;

             case SENSOR_FBA23:                   // 20
               fprintf(hfp,"   FBA-23 (20)   ");
                break;

             case SENSOR_WR1:                     // 30
               fprintf(hfp,"    WR-1 (30)    ");
                break;
             default:
               fprintf(hfp,"   Unknown (%d)   ",hi1);
                break;

           }  // switch (hi1)

        }  // if have chan
      }
    fprintf(hfp,"\n");


      fprintf(hfp,"                   ");  // 16 chars Sensor S/N
      for (k=0; k < 3; k++)
      {
        if (chidx[(j*3)+k] != 0)
        {
          if ( headtype == MTW )
          {
            hw1 = swap2(mwhead.rwParms.channel[chidx[(j*3)+k]-1].sensorSerialNumber); // low word 8/27/94
            hw2 = swap2(mwhead.rwParms.channel[chidx[(j*3)+k]-1].sensorSerialNumberExt); // high word
          }
          else
          {
            hw1 = swap2(k2head.rwParms.channel[chidx[(j*3)+k]-1].sensorSerialNumber); // low word 8/27/94
            hw2 = swap2(k2head.rwParms.channel[chidx[(j*3)+k]-1].sensorSerialNumberExt); // high word
          }
          ul = (hw2 * 65536) + hw1;

          fprintf(hfp,"s/n%6u",ul);
          if ((k==0) || (k==1))
            fprintf(hfp,"        ");  // 8 spaces
        }  // if have chan
      }
    fprintf(hfp,"\n");


    fprintf(hfp,"  Displace, N:       ");
      for (k = 0; k < 3; k++)
      {
        if (chidx[(j*3)+k] != 0)
        {
          if ( headtype == MTW )
	    hi1 = swap2(mwhead.rwParms.channel[chidx[(j*3)+k]-1].north);
					else
	    hi1 = swap2(k2head.rwParms.channel[chidx[(j*3)+k]-1].north);
       fprintf(hfp,"%04d,",hi1);
          if ( (k==0) || (k==1))
        fprintf(hfp,"            ");  // 12 spaces
        }  // if have chan
      }
    fprintf(hfp,"\n");

    fprintf(hfp,"  Displace, E:       ");
      for (k=0; k<3; k++)
      {
        if (chidx[(j*3)+k] != 0)
        {
          if ( headtype == MTW )
	    hi2 = swap2(mwhead.rwParms.channel[chidx[(j*3)+k]-1].east);
					else
	    hi2 = swap2(k2head.rwParms.channel[chidx[(j*3)+k]-1].east);
       fprintf(hfp,"%04d,",hi2);
          if ( (k==0) || (k==1) )
        fprintf(hfp,"            ");  // 12 spaces
        }  // if have chan
      }
    fprintf(hfp,"\n");

    fprintf(hfp,"  Displace, U:       ");
      for (k=0; k <3; k++)
      {
        if (chidx[(j*3)+k] != 0)
        {
          if ( headtype == MTW )
	    hi3 = swap2(mwhead.rwParms.channel[chidx[(j*3)+k]-1].up);
					else
	    hi3 = swap2(k2head.rwParms.channel[chidx[(j*3)+k]-1].up);
       fprintf(hfp,"%04d,",hi3);
          if ( (k ==0) || (k==1) )
        fprintf(hfp,"            ");  // 12 spaces
        }  // if have chan
      }
    fprintf(hfp,"\n");

    fprintf(hfp,"  Alt,Azi(deg): ");
      for (k=0;k<3; k++)
      {
        if (chidx[(j*3)+k] != 0)
        {
          if ( headtype == MTW )
					{
		  hi1 = swap2(mwhead.rwParms.channel[chidx[(j*3)+k]-1].altitude);
		  hi2 = swap2(mwhead.rwParms.channel[chidx[(j*3)+k]-1].azimuth);
					}
					else
					{
		  hi1 = swap2(k2head.rwParms.channel[chidx[(j*3)+k]-1].altitude);
		  hi2 = swap2(k2head.rwParms.channel[chidx[(j*3)+k]-1].azimuth);
					}
          fprintf(hfp,"%6d, %6d", hi1,hi2);
          if ( (k==0) || (k==1))
            fprintf(hfp,"   ");  // 3 spaces
        }  // if have chan
      }
      fprintf(hfp,"\n");
      fprintf(hfp,"\n");  // blank line between sets
    }  //  for j

    for (j = 0; j <= row; j++)
    {
    fprintf(hfp,"Ch                   ");
      for (k = 0; k < 3; k++)
      {
        if (chidx[(j*3)+k] !=0)
        {
       fprintf(hfp,"%2d",chidx[(j*3)+k]);
          if ((k==0) || (k==1))
          {
//            if ((chidx[(j*3)+k+1] >= 1) && (chidx[(j*3)+k+1] <= 9))
          fprintf(hfp,"               ");  // 15 spaces
//            else
//          fprintf(hfp,"               ");  // 15 spaces
          }
        }  // for chidx
      }  // for k
    fprintf(hfp,"\n");

    fprintf(hfp,"  Gain:               ");   // 15 chars
      for (k = 0; k < 3;k ++)
      {
        if (chidx[(j*3)+k] != 0)
        {
          if ( headtype == MTW )
	    hi1 = swap2(mwhead.rwParms.channel[chidx[(j*3)+k]-1].gain);
					else
	    hi1 = swap2(k2head.rwParms.channel[chidx[(j*3)+k]-1].gain);
       fprintf(hfp,"%d",hi1);
          if ( (k==0) || (k==1) )
        fprintf(hfp,"                ");  // 16 spaces
        }  // if have chan
      }
    fprintf(hfp,"\n");

    fprintf(hfp,"  Fullscale         ");
      for (k = 0; k < 3; k++)
      {
        if (chidx[(j*3)+k] != 0)
        {
        if ( headtype == MTW )
	         hr = swap4r(mwhead.rwParms.channel[chidx[(j*3)+k]-1].fullscale);
			 else
	         hr = swap4r(k2head.rwParms.channel[chidx[(j*3)+k]-1].fullscale);
       fprintf(hfp,"%4.2fV",hr);
          if ( (k==0) || (k==1) )
        fprintf(hfp,"            ");  // 12 spaces
        }  // if have chan
      }
    fprintf(hfp,"\n");

    fprintf(hfp,"  Sensitivity:      ");
      for (k = 0; k < 3; k++)
      {
        if (chidx[(j*3)+k] != 0)
        {
          if ( headtype == MTW )
              hr = swap4r(mwhead.rwParms.channel[chidx[(j*3)+k]-1].sensitivity);
          else
              hr = swap4r(k2head.rwParms.channel[chidx[(j*3)+k]-1].sensitivity);
          fprintf(hfp,"%5.3f",hr);   // 11/3/94 was %4.1g
                                          // 3/29/95 was %5.2f
          cd = code[(j*3)+k];
          // label acceleration
          if ((cd==1)  || (cd==10) || (cd==11) || (cd==12) ||
              (cd==13) || (cd==14) || (cd==15) || (cd==16) ||
              (cd==20)  )
          {
            if ( (k==0) || (k==1))
              fprintf(hfp,"V/g         ");  // 12 spaces
            if (k==2)
              fprintf(hfp,"V/g");
          }
          else
          {
            if ( (k==0) || (k==1))
           fprintf(hfp,"            ");  // 12 spaces
          }

        }  // if have chan
      }
    fprintf(hfp,"\n");

    fprintf(hfp,"  Damping:         ");
      for (k =0; k < 3; k ++)
      {
        if (chidx[(j*3)+k] != 0)
        {
          if ( headtype == MTW )
            hr = swap4r(mwhead.rwParms.channel[chidx[(j*3)+k]-1].damping);
					else
            hr = swap4r(k2head.rwParms.channel[chidx[(j*3)+k]-1].damping);
          fprintf(hfp,"%5.2f",hr);  // 3/29/95 was %4.1f
          if ( (k==0) || (k==1))
            fprintf(hfp,"            ");  // 12 spaces
        }  // if have chan
      }
    fprintf(hfp,"\n");

    fprintf(hfp,"  NatFreq:         ");
      for (k=0; k <3; k++)
      {
        if (chidx[(j*3)+k] != 0)
        {
          if ( headtype == MTW )
	    hr = swap4r(mwhead.rwParms.channel[chidx[(j*3)+k]-1].naturalFrequency);
					else
	    hr = swap4r(k2head.rwParms.channel[chidx[(j*3)+k]-1].naturalFrequency);
       fprintf(hfp,"%5.2fHz",hr);
          if ( (k==0) || (k==1) )
        fprintf(hfp,"          ");  // 10 spaces
        }  // if have chan
      }
    fprintf(hfp,"\n");
    fprintf(hfp,"\n");  // blank line
    } // for j


    /* -----------------------------------------------  */
    /*    THE BALANCE OF THE FORMATTED HEADER CODE IS   */
    /*       IN KWHD2.C                                 */
    /* -----------------------------------------------  */


}  // decodeheader1()

/*---  end  kwhd1.c   ---------------------------------------------------*/

/*--------------------------------------------------------------------------*/
/* kwhd2.c */
/*--------------------------------------------------------------------------*/
/*  kwhd2.c    2nd half: master header formatter file for DOS programs */

/*  6/10/86  1.00  change #include to proper .H file
                   before call to decodeheader1() do
                      hfp = fopen(hfpname,"wt");
                   after return from decodheader2() do
                      fclose(hfp); */
/*                 for KWPARD - edit out all 'ro' items
                     define HEADER == FALSE in kwpard.h */

/* used by kwpard, kw2asc, kwrc, kwphf  */
/* HEADER == FALSE, TRUE,  TRUE, TRUE */
/* not used by kwtc, kwtrig, kwntp, kwsum, kw2cnts, or kw2suds, kw2v1 */

/* 6/19/96   make all formatted headers the same, master in \kwsup\heads */

/* 7/10/96   add 'autocallout disabled for xx.rwParms.modem.flags, bit 0
              and callout conditions if enabled  */
/* 7/11/96   remove modem.rw.autoanswerON/OFF -- not used */
/*           move cellular callout mdg to modem callout msg
             remove phone numbers 3: & 4: */
/*           make autoanswer/autocall smarter */
/* 7/12/96   add 'off' to cellular_on_times */
/* 9/18/96   FIX: K2 cell variables not changed from copy from mwhead !
             REMOVE: Sensor Response - not used */
/* 9/19/96   merged vhf1/2.c into kwhd1/2.c */
/* 3/29/97   ADD: 1.40 K2 & 1/50 MTW */
/* 3/30/97   ADD: Seismological Parms & Serial Data Stream Parms */

/* 9/22/97  H2.50 SCR 296  Fix gpsStatus decode, using '&&', s/b using '&' */
/*               SCR 287  Fix limit on voterinfo array.  ADD maxvoters */
/*               SCR 272  FIX-CHANGE reporting of timing.local Offset */

#include "kw2asc.h"   /* kw2asc.h, kwphf.h, kwpard.h, kwrc.h, qlca.h */


void decodeheader2(void)
{
char hb,by,by1;
BYTE uby, trigtype;
char string1[80],string2[80];
int i,j,k,m,hi,hi1,hi2,maxvoters;
unsigned int hw,us;
float hr,si;
unsigned long ul;



    /* -----------------------------------------------  */
    /*    THE PREVIOUS CODE FOR THE FORMATTED HEADER    */
    /*       IS IN KWHD1.C                              */
    /* ------------------------------------------------ */

/* sensor response 1-6 removed 9/19/96 -- not used */

    for (j = 0; j <= row; j++)
    {
    fprintf(hfp,"Ch                         ");   // 27
      for (k = 0; k < 3; k++)
      {
        if (chidx[(j*3)+k] !=0)
        {
       fprintf(hfp,"%2d",chidx[(j*3)+k]);
          if ((k==0) || (k==1))
          {
//            if ((chidx[(j*3)+k+1] >= 1) && (chidx[(j*3)+k+1] <= 9))
          fprintf(hfp,"               ");  // 15 spaces
//            else
//          fprintf(hfp,"               ");  // 15 spaces
          }
        }  // for chidx
      }  // for k
    fprintf(hfp,"\n");


//--- begin add 3/29/97  1.40/1.50  --------------------------------

    if (headver >= 140)
    {
      fprintf(hfp,"Trigger Filter:        ");        // 23
      for (k =0; k<3; k ++)
      {
        if (chidx[(j*3)+k] != 0)
        {
          if ( headtype == MTW )
            uby = mwhead.rwParms.channel[chidx[(j*3)+k]-1].iirTriggerFilter;
          else
            uby = k2head.rwParms.channel[chidx[(j*3)+k]-1].iirTriggerFilter;

          if (uby == 0)
          {
            fprintf(hfp,"   IIR A  ");   // 10
            if ( (k==0) || (k==1) )
              fprintf(hfp,"       ");    // 7 spaces
          }
          if (uby == 1)
          {
            fprintf(hfp,"Classic SM");   // 10
            if ( (k==0) || (k==1) )
              fprintf(hfp,"       ");    // 7 spaces
          }
          if (uby == 2)
          {
            fprintf(hfp,"   IIR B  ");   // 10
            if ( (k==0) || (k==1) )
              fprintf(hfp,"       ");    // 7 spaces
          }
        }  // if have chan
      } // for columns
      fprintf(hfp,"\n");

      fprintf(hfp,"Trigger Type:           ");   // 24
      for (k =0; k<3; k ++)
      {
        if (chidx[(j*3)+k] != 0)
        {
          if ( headtype == MTW )
            uby = mwhead.rwParms.channel[chidx[(j*3)+k]-1].triggerType;
          else
            uby = k2head.rwParms.channel[chidx[(j*3)+k]-1].triggerType;

          if (uby == 0)
          {
            fprintf(hfp,"Threshold");   //  9
            if ( (k==0) || (k==1) )
              fprintf(hfp,"        ");  //  8 spaces
          }
          if (uby == 1)
          {
            fprintf(hfp," STA/LTA ");   //  9
            if ( (k==0) || (k==1) )
              fprintf(hfp,"        ");  //  8 spaces
          }
        }  // if have chan
      } // for columns
      fprintf(hfp,"\n");

      fprintf(hfp,"Threshold:\n");

      fprintf(hfp," Trigger Threshold:    ");  // 23
      for (k =0; k<3; k ++)
      {
        if (chidx[(j*3)+k] != 0)
        {
#if HEADER     // not used by kwpard
          if ( headtype == MTW )
            trigtype = mwhead.rwParms.channel[chidx[(j*3)+k]-1].triggerType;
          else
            trigtype = k2head.rwParms.channel[chidx[(j*3)+k]-1].triggerType;

          if (trigtype == 0)
          {
#endif
            if ( headtype == MTW )
              si = swap4r(mwhead.rwParms.channel[chidx[(j*3)+k]-1].triggerThreshold);
            else
              si = swap4r(k2head.rwParms.channel[chidx[(j*3)+k]-1].triggerThreshold);
            fprintf(hfp,"%7.3f%%FS",si*100.0);  // 10
            if ( (k==0) || (k==1) )
              fprintf(hfp,"       ");          // 7 spaces
#if HEADER     // not used by kwpard
          }
          else
          {
            fprintf(hfp,"    ----  ");  // 10
            if ( (k==0) || (k==1) )
              fprintf(hfp,"       ");   // 7 spaces
          }
#endif
        }  // if have chan
      } // for columns
      fprintf(hfp,"\n");

      fprintf(hfp," Detrigger Threshold:  ");  // 23
      for (k=0; k<3; k ++)
      {
        if (chidx[(j*3)+k] != 0)
        {
#if HEADER     // not used by kwpard
          if ( headtype == MTW )
            trigtype = mwhead.rwParms.channel[chidx[(j*3)+k]-1].triggerType;
          else
            trigtype = k2head.rwParms.channel[chidx[(j*3)+k]-1].triggerType;

          if (trigtype == 0)
          {
#endif
            if ( headtype == MTW )
              si = swap4r(mwhead.rwParms.channel[chidx[(j*3)+k]-1].detriggerThreshold);
            else
              si = swap4r(k2head.rwParms.channel[chidx[(j*3)+k]-1].detriggerThreshold);
            fprintf(hfp,"%7.3f%%FS",si*100.0);  // 10
            if ( (k==0) || (k==1) )
              fprintf(hfp,"       ");           // 7 spaces
#if HEADER     // not used by kwpard
          }
          else
          {
            fprintf(hfp,"    ----  ");  // 10
            if ( (k==0) || (k==1) )
              fprintf(hfp,"       ");   // 7 spaces
          }  // if threshold trigtype == 0
#endif
        }  // if have chan
      } // for columns
		  fprintf(hfp,"\n");

		  fprintf(hfp,"STA/LTA:\n");

      fprintf(hfp," STA Length(sec):          ");  // 27
      for (k =0; k<3; k ++)
      {
        if (chidx[(j*3)+k] != 0)
        {
#if HEADER     // not used by kwpard
          if ( headtype == MTW )
            trigtype = mwhead.rwParms.channel[chidx[(j*3)+k]-1].triggerType;
          else
            trigtype = k2head.rwParms.channel[chidx[(j*3)+k]-1].triggerType;

          if (trigtype == 1)
          {
#endif
            if ( headtype == MTW )
              uby = mwhead.rwParms.channel[chidx[(j*3)+k]-1].StaSeconds;
            else
              uby = k2head.rwParms.channel[chidx[(j*3)+k]-1].StaSeconds;

            fprintf(hfp,"%4.1f",uby * 0.1);      //  4
            if ( (k==0) || (k==1) )
              fprintf(hfp,"             ");      // 13 spaces
#if HEADER     // not used by kwpard
          }
          else
          {
            fprintf(hfp,"----");                 //  4
            if ( (k==0) || (k==1) )
              fprintf(hfp,"             ");      // 13 spaces
          }
#endif
        }  // if have chan
      }  // for columns
      fprintf(hfp,"\n");

      fprintf(hfp," LTA Length(sec):          ");  // 27
      for (k =0; k<3; k ++)
      {
        if (chidx[(j*3)+k] != 0)
        {
#if HEADER     // not used by kwpard
          if ( headtype == MTW )
            trigtype = mwhead.rwParms.channel[chidx[(j*3)+k]-1].triggerType;
          else
            trigtype = k2head.rwParms.channel[chidx[(j*3)+k]-1].triggerType;

          if (trigtype == 1)
          {
#endif
            if ( headtype == MTW )
              uby = mwhead.rwParms.channel[chidx[(j*3)+k]-1].LtaSeconds;
            else
              uby = k2head.rwParms.channel[chidx[(j*3)+k]-1].LtaSeconds;

            fprintf(hfp,"%3d ",uby);         //  4
            if ( (k==0) || (k==1) )
              fprintf(hfp,"             ");  // 13 spaces
#if HEADER     // not used by kwpard
          }
          else
          {
            fprintf(hfp,"----");             //  4
            if ( (k==0) || (k==1) )
              fprintf(hfp,"             ");  // 13 spaces
          } // if trigtype == 1
#endif
        }  // if have chan
      }  // for columns
      fprintf(hfp,"\n");

      fprintf(hfp," Trigger Ratio:           "); // 26
      for (k =0; k<3; k ++)
      {
        if (chidx[(j*3)+k] != 0)
        {
#if HEADER     // not used by kwpard
          if ( headtype == MTW )
            trigtype = mwhead.rwParms.channel[chidx[(j*3)+k]-1].triggerType;
          else
            trigtype = k2head.rwParms.channel[chidx[(j*3)+k]-1].triggerType;

          if (trigtype == 1)
          {
#endif
            if ( headtype == MTW )
              us = swap2(mwhead.rwParms.channel[chidx[(j*3)+k]-1].StaLtaRatio);
            else
              us = swap2(k2head.rwParms.channel[chidx[(j*3)+k]-1].StaLtaRatio);

            fprintf(hfp,"%5.1f",us*0.1);    //  5
            if ( (k==0) || (k==1) )
              fprintf(hfp,"            ");  // 12 spaces
#if HEADER     // not used by kwpard
          }
          else
          {
            fprintf(hfp," ----");           //  5
            if ( (k==0) || (k==1) )
              fprintf(hfp,"            ");  // 12 spaces
          }  // if trigtype == 1
#endif

        }  // if have chan
      }  // for columns
      fprintf(hfp,"\n");

      fprintf(hfp," Detrigger %% of Trigger   ");  // 26
      for (k =0; k<3; k ++)
      {
        if (chidx[(j*3)+k] != 0)
        {

#if HEADER     // not used by kwpard
          if ( headtype == MTW )
            trigtype = mwhead.rwParms.channel[chidx[(j*3)+k]-1].triggerType;
          else
            trigtype = k2head.rwParms.channel[chidx[(j*3)+k]-1].triggerType;

          if (trigtype == 1)
          {
#endif
            if ( headtype == MTW )
              uby = mwhead.rwParms.channel[chidx[(j*3)+k]-1].StaLtaPercent;
            else
              uby = k2head.rwParms.channel[chidx[(j*3)+k]-1].StaLtaPercent;

            fprintf(hfp," %3d%%",uby); // 5
            if ( (k==0) || (k==1) )
              fprintf(hfp,"            ");  // 12 spaces
#if HEADER     // not used by kwpard
          }
          else
          {
            fprintf(hfp," ----"); // 5
            if ( (k==0) || (k==1) )
              fprintf(hfp,"            ");  // 12 spaces
          }
#endif
        }  // if have chan
      }  // for columns
      fprintf(hfp,"\n");
    }  // headerver >= 1.40
    else
    {
      fprintf(hfp,"Trigger Threshold:    ");
      for (k =0; k<3; k ++)
      {
        if (chidx[(j*3)+k] != 0)
        {
          if ( headtype == MTW )
            si = swap4r(mwhead.rwParms.channel[chidx[(j*3)+k]-1].triggerThreshold);
          else
            si = swap4r(k2head.rwParms.channel[chidx[(j*3)+k]-1].triggerThreshold);
          fprintf(hfp,"%6.3f%FS",si*100.0);
          if ( (k==0) || (k==1) )
            fprintf(hfp,"       ");  // 7 spaces
        }  // if have chan
      }
      fprintf(hfp,"\n");

      fprintf(hfp," Detrigger Threshold:  ");  //
      for (k=0; k<3; k ++)
      {
        if (chidx[(j*3)+k] != 0)
        {
            if ( headtype == MTW )
           si = swap4r(mwhead.rwParms.channel[chidx[(j*3)+k]-1].detriggerThreshold);
            else
           si = swap4r(k2head.rwParms.channel[chidx[(j*3)+k]-1].detriggerThreshold);
         fprintf(hfp,"%6.3f%FS",si*100.0);
         if ( (k==0) || (k==1) )
          fprintf(hfp,"       ");  // 7 spaces
        }  // if have chan
      }
      fprintf(hfp,"\n");

    }  // if else headver >= 140

//--- end add 3/29/97  1.40/1.50  --------------------------------

    fprintf(hfp,"Alarm Trig Threshold:  ");  // 23
		for (k=0; k<3; k++)
		{
		  if (chidx[(j*3)+k] != 0)
		  {
          if ( headtype == MTW )
				 si = swap4r(mwhead.rwParms.channel[chidx[(j*3)+k]-1].alarmTriggerThreshold);
					else
				 si = swap4r(k2head.rwParms.channel[chidx[(j*3)+k]-1].alarmTriggerThreshold);
       fprintf(hfp,"%7.3f%%FS",si*100.0);
			 if ( (k==0) || (k==1) )
        fprintf(hfp,"       ");  // 7 spaces
		  }  // if have chan
		}
    fprintf(hfp,"\n");

		// channel vote weights
    if ( headtype == MTW )   // limit checking with in allowed array size
      maxvoters = 21;        // 18 + 3
    else
      maxvoters = 15;        // 12 + 3

    fprintf(hfp,"               Votes:    ");
		for (k=0; k<3; k ++)
      {
        if (chidx[(j*3)+k] != 0)
        {
          for (m = 0; m < maxvoters; m++)
          {
            if ( headtype == MTW )
						{
							by = mwhead.rwParms.stream.voterInfo[m].type;
							by1 = mwhead.rwParms.stream.voterInfo[m].number;
						}
						else
						{
							by = k2head.rwParms.stream.voterInfo[m].type;
							by1 = k2head.rwParms.stream.voterInfo[m].number;
						}
            if ( (by == 'C') &&
                 (by1 == ((j*3)+k)) )
            {
              if ( headtype == MTW )
		            hi1 = swap2(mwhead.rwParms.stream.voterInfo[m].weight);
							else
		            hi1 = swap2(k2head.rwParms.stream.voterInfo[m].weight);
              fprintf(hfp,"%5d",hi1);
              break;     // found the right voter_info
            }
            else
              if (m == (maxvoters -1))  // checked last possible place, didn't find it
           fprintf(hfp,"undef");
          }  // for m = 0 to < maxvoters

          if ( (k==0) || (k==1) )
        fprintf(hfp,"            ");  // 12 spaces
        }  // if have chan
      }
    fprintf(hfp,"\n");
    fprintf(hfp,"\n");  // blank line between
    }  // for j

//--- begin add 3/29/97  1.40/1.50  --------------------------------

    if (headver >= K2140)
    {
      fprintf(hfp,"Anti-alias Filter:");

      if ( headtype == MTW )
        uby = mwhead.rwParms.stream.FilterType;
      else
        uby = k2head.rwParms.stream.FilterType;

      if (uby == 0)
      {
        fprintf(hfp,"  Non-causal");
        if ( (k==0) || (k==1) )
          fprintf(hfp,"   ");  // 3 spaces
      }
      if (uby == 1)
      {
        fprintf(hfp,"  Causal");
        if ( (k==0) || (k==1) )
          fprintf(hfp,"       ");  // 7 spaces
      }
      fprintf(hfp,"\n");
    }  // headver >= K2140


//--- end add 3/29/97  1.40/1.50  --------------------------------

    if (headver >= K2110)  // do network
    {
      if ( headtype == MTW )
	      hb = mwhead.rwParms.misc.networkFlag;
			else
	      hb = k2head.rwParms.misc.networkFlag;
      hb = hb & 0x01;   // bit0: 0 = master, 1 = slave
      if (hb == 0)
      fprintf(hfp,"Network Master.");
      else
      fprintf(hfp,"Network Slave.");

      for (m = 0; m < (maxvoters); m++)
      {
        if ( headtype == MTW )
					by = mwhead.rwParms.stream.voterInfo[m].type;
				else
					by = k2head.rwParms.stream.voterInfo[m].type;
        if (by == 'N')   // network votes
        {
          if ( headtype == MTW )
	    hi1 = swap2(mwhead.rwParms.stream.voterInfo[m].weight);
					else
	    hi1 = swap2(k2head.rwParms.stream.voterInfo[m].weight);
       fprintf(hfp,"   Votes: %d",hi1);
          break;     // found the right voter_info
        }
        else
          if (m == (maxvoters -1))  // checked last possible place, didn't find it
        fprintf(hfp,"   Votes: undefined");
      }  // for m = 0 to < maxvoters
    fprintf(hfp,"\n");
    } // if headver == K2110 do network

   fprintf(hfp,"External Trigger:");
    if ( headtype == MTW )
      hb = mwhead.rwParms.misc.externalTrigger;
		else
      hb = k2head.rwParms.misc.externalTrigger;
    if (hb == 1)
    fprintf(hfp,"  ON, ");
    else
    fprintf(hfp,"  OFF, ");

    for (m = 0; m < (maxvoters); m++)
    {
      if ( headtype == MTW )
			  by = mwhead.rwParms.stream.voterInfo[m].type;
			else
			  by = k2head.rwParms.stream.voterInfo[m].type;
      if (by  == 'E')   // external
      {
        if ( headtype == MTW )
	        hi1 = swap2(mwhead.rwParms.stream.voterInfo[m].weight);
				else
	        hi1 = swap2(k2head.rwParms.stream.voterInfo[m].weight);
      fprintf(hfp,"  Votes: %d",hi1);
        break;     // found the right voter_info
      }
      else
        if (m == (maxvoters -1))  // checked last possible place, didn't find it
       fprintf(hfp,"  Votes: undefined");
    }  // for m = 0 to < maxvoters
  fprintf(hfp,"\n");

    for (m = 0; m < (maxvoters); m++)
    {
      if ( headtype == MTW )
				by = mwhead.rwParms.stream.voterInfo[m].type;
			else
				by = k2head.rwParms.stream.voterInfo[m].type;
      if (by == 'K')   // keyboard if defined
      {
        if ( headtype == MTW )
	        hi1 = swap2(mwhead.rwParms.stream.voterInfo[m].weight);
				else
	        hi1 = swap2(k2head.rwParms.stream.voterInfo[m].weight);
      fprintf(hfp,"Keyboard Trigger Votes: %d",hi1);
        break;     // found the right voter_info
      }
      else
        if (m == (maxvoters -1))  // checked last possible place, didn't find it
       fprintf(hfp,"Keyboard Trigger Votes: undefined");
    }  // for m = 0 to < maxvoters
  fprintf(hfp,"\n");

    if ( headtype == MTW )
		{
      hi1 = swap2(mwhead.rwParms.stream.VotesToTrigger);
      hi2 = swap2(mwhead.rwParms.stream.VotesToDetrigger);
		}
		else
		{
      hi1 = swap2(k2head.rwParms.stream.VotesToTrigger);
      hi2 = swap2(k2head.rwParms.stream.VotesToDetrigger);
		}
   fprintf(hfp,"Stream:   Votes to trigger: %d,   Votes to detrigger: %d\n",hi1,hi2);

//.........................................

  fprintf(hfp,"\n");
    if ( headtype == MTW )
      hb = mwhead.rwParms.timing.gpsTurnOnInterval;
		else
      hb = k2head.rwParms.timing.gpsTurnOnInterval;
   fprintf(hfp,"GPS turn On interval:  %d minutes(s).\n",hb);

    if ( headtype == MTW )
      hb = mwhead.rwParms.timing.gpsMaxTurnOnTime;
		else
      hb = k2head.rwParms.timing.gpsMaxTurnOnTime;
   fprintf(hfp,"GPS maximum On time:  %d minute(s)\n",hb);

    if ( headtype == MTW )
      hi = swap2(mwhead.rwParms.timing.localOffset);  // swap2() added 10/5/94
		else
      hi = swap2(k2head.rwParms.timing.localOffset);  // swap2() added 10/5/94
    fprintf(hfp,"All times as set manually, or %d hour(s) from UTC if from GPS",hi);

#if 0         /// out 9/22/98, not correct, localOffset only subtracted from GPS
    if (hi == 0)
    fprintf(hfp,"All event times are in local time.");
    else
    fprintf(hfp,"All times in UTC, local time is %d hour(s) to UTC.",hi);
#endif

   fprintf(hfp,"\n");

#if HEADER      // not used for kwpard
    if ( headtype == MTW )
      hb = mwhead.roParms.timing.clockSource;
		else
      hb = k2head.roParms.timing.clockSource;
    switch (hb)
    {
    case 0 : fprintf(hfp,"Clock Source: RTC from cold start."); break;
    case 1 : fprintf(hfp,"Clock Source: Keyboard."); break;
    case 2 : fprintf(hfp,"Clock Source: External Reference Pulse."); break;
    case 3 : fprintf(hfp,"Clock Source: Internal GPS"); break;
    default: fprintf(hfp,"Clock Source unknown.");
    }
   fprintf(hfp,"\n");

   fprintf(hfp,"GPS Status byte decoded:\n");
    if ( headtype == MTW )
      hb = mwhead.roParms.timing.gpsStatus;
		else
      hb = k2head.roParms.timing.gpsStatus;
    if ((0x01 & hb) == 0x01)                  // bit 0
      fprintf(hfp,"   Currently checking for presence of GPS.\n");
    if ((0x02 & hb) == 0x02)                  // bit 1
      fprintf(hfp,"   GPS present.\n");
    if ((0x03 & hb) == 0x00)
      fprintf(hfp,"   GPS not present.\n");
    if ((0x04 & hb) == 0x04)                  // bit 2
      fprintf(hfp,"   Error communicating with GPS.\n");
    if ((0x08 & hb) == 0x08)                  // bit 3
      fprintf(hfp,"   GPS failed to lock with gpsMaxTurnOnTime.\n");
    if ((0x10 & hb) == 0x10)                  // bit 4
      fprintf(hfp,"   GPS not locked.\n");
    if ((0x20 & hb) == 0x20)                  // bit 5
      fprintf(hfp,"   GPS power is ON.\n");
  // imbedded \n

   fprintf(hfp,"GPS state of health byte [same as Acutime SOH byte]:\n");
    if ( headtype == MTW )
      hb = mwhead.roParms.timing.gpsSOH;
		else
      hb = k2head.roParms.timing.gpsSOH;
    if (hb == 0x00)
    fprintf(hfp,"  Doing position fixes.\n");
    if (hb == 0x01)
    fprintf(hfp,"  Don't have GPS time yet.\n");
    if (hb == 0x03)
    fprintf(hfp,"  PDOP is too high.\n");
    if (hb == 0x08)
    fprintf(hfp,"  No usable satellites.\n");
    if (hb == 0x09)
    fprintf(hfp,"  Only 1 usable satellite.\n");
    if (hb == 0x0A)
    fprintf(hfp,"  Only 2 usable satellites.\n");
    if (hb == 0x0B)
    fprintf(hfp,"  Only 3 usable satellites.\n");
    if (hb == 0x0C)
    fprintf(hfp,"  The chosen satellite is unusable.\n");
  // imbedded \n

    if ( headtype == MTW )
      hw = swap2(mwhead.roParms.timing.gpsUpdateRTCCount);
		else
      hw = swap2(k2head.roParms.timing.gpsUpdateRTCCount);
   fprintf(hfp,"GPS updated the RTC %d times since last reset.\n",hw);

    if ( headtype == MTW )
		{
	    hi1 = swap2(mwhead.roParms.timing.gpsLastDrift[0]);
	    hi2 = swap2(mwhead.roParms.timing.gpsLastDrift[1]);
		}
		else
		{
	    hi1 = swap2(k2head.roParms.timing.gpsLastDrift[0]);
	    hi2 = swap2(k2head.roParms.timing.gpsLastDrift[1]);
		}
   fprintf(hfp,"Drift Rate at last two RTC updates to UTC: %d & %d msec.",hi1,hi2);
  fprintf(hfp,"\n");

    if ( headtype == MTW )
      temptime = swap4i(mwhead.roParms.timing.gpsLastUpdateTime[0]);
		else
      temptime = swap4i(k2head.roParms.timing.gpsLastUpdateTime[0]);
    CK2Time(temptime);
    sprintf(string1,"%d/%d/%d (%d) %02d:%02d:%02d",m_nMonth,m_nDayOfMonth,m_nYear,
                                         m_nDayOfYear,m_nHour, m_nMin, m_nSec);
    if ( headtype == MTW )
      temptime = swap4i(mwhead.roParms.timing.gpsLastUpdateTime[1]);
		else
      temptime = swap4i(k2head.roParms.timing.gpsLastUpdateTime[1]);
    CK2Time(temptime);
    sprintf(string2,"%d/%d/%d (%d) %02d:%02d:%02d",m_nMonth,m_nDayOfMonth,m_nYear,
                                         m_nDayOfYear,m_nHour, m_nMin, m_nSec);
   fprintf(hfp,"Last GPS Update times were:\n");
   fprintf(hfp,"  %s & %s.",string1,string2);
  fprintf(hfp,"\n");

    if ( headtype == MTW )
      temptime = swap4i(mwhead.roParms.timing.gpsLastTurnOnTime[0]);
		else
      temptime = swap4i(k2head.roParms.timing.gpsLastTurnOnTime[0]);
    CK2Time(temptime);
    sprintf(string1,"%d/%d/%d (%d) %02d:%02d:%02d",m_nMonth,m_nDayOfMonth,m_nYear,
                                         m_nDayOfYear,m_nHour, m_nMin, m_nSec);
    if ( headtype == MTW )
      temptime = swap4i(mwhead.roParms.timing.gpsLastTurnOnTime[1]);
		else
      temptime = swap4i(k2head.roParms.timing.gpsLastTurnOnTime[1]);
    CK2Time(temptime);
    sprintf(string2,"%d/%d/%d (%d) %02d:%02d:%02d",m_nMonth,m_nDayOfMonth,m_nYear,
                                         m_nDayOfYear,m_nHour, m_nMin, m_nSec);
   fprintf(hfp,"Last GPS TurnOn times were:\n");
   fprintf(hfp,"  %s & %s.",string1,string2);
  fprintf(hfp,"\n");

    if ( headtype == MTW )
      temptime = swap4i(mwhead.roParms.timing.gpsLastLockTime[0]);
			else
      temptime = swap4i(k2head.roParms.timing.gpsLastLockTime[0]);
    CK2Time(temptime);
    sprintf(string1,"%d/%d/%d (%d) %02d:%02d:%02d",m_nMonth,m_nDayOfMonth,m_nYear,
                                         m_nDayOfYear,m_nHour, m_nMin, m_nSec);
    if ( headtype == MTW )
      temptime = swap4i(mwhead.roParms.timing.gpsLastLockTime[1]);
		else
      temptime = swap4i(k2head.roParms.timing.gpsLastLockTime[1]);
    CK2Time(temptime);
    sprintf(string2,"%d/%d/%d (%d) %02d:%02d:%02d",m_nMonth,m_nDayOfMonth,m_nYear,
                                         m_nDayOfYear,m_nHour, m_nMin, m_nSec);
   fprintf(hfp,"Last GPS Lock times were:\n");
   fprintf(hfp,"   %s & %s.",string1,string2);
  fprintf(hfp,"\n");

    if ( headtype == MTW )
      hw = swap2(mwhead.roParms.timing.gpsLockFailCount);
			else
      hw = swap2(k2head.roParms.timing.gpsLockFailCount);
   fprintf(hfp,"Count of times GPS failed to lock\n");
   fprintf(hfp,"    within gpsMaxTurnOnTime: %d\n",hw);
#endif

    //...................................................................
  fprintf(hfp,"\n");
  fprintf(hfp,"\n");

    fprintf(hfp,"Modem strings [ NULL TERMINATED ] from event header...\n");

    if ( headtype == MTW )
    fprintf(hfp," Initialization: %s\n",mwhead.rwParms.modem.initCmd);
    else
    fprintf(hfp," Initialization: %s\n",k2head.rwParms.modem.initCmd);

    if ( headtype == MTW )
    fprintf(hfp," Dialing Prefix: %s\n",mwhead.rwParms.modem.dialingPrefix);
    else
    fprintf(hfp," Dialing Prefix: %s\n",k2head.rwParms.modem.dialingPrefix);

    if ( headtype == MTW )
    fprintf(hfp," Dialing Suffix: %s\n",mwhead.rwParms.modem.dialingSuffix);
    else
    fprintf(hfp," Dialing Suffix: %s\n",k2head.rwParms.modem.dialingSuffix);

    if ( headtype == MTW )
    fprintf(hfp," Hangup command: %s\n",mwhead.rwParms.modem.hangupCmd);
    else
    fprintf(hfp," Hangup command: %s\n",k2head.rwParms.modem.hangupCmd);

    if ( headtype == MTW )
    fprintf(hfp," Callout message: %s\n",mwhead.rwParms.modem.calloutMsg);
    else
    fprintf(hfp," Callout message: %s\n",k2head.rwParms.modem.calloutMsg);

    // added 5/21/96
    fprintf(hfp,"Cellular Phone Parameters:\n");

    if ( headtype == MTW )
    by = mwhead.rwParms.modem.cellOnTime;
    else
    by = k2head.rwParms.modem.cellOnTime;

    if (by == -1)
      fprintf(hfp,"  Power control always ON.\n");
    else
    {
      if (by == 0)
        fprintf(hfp,"  Power control OFF.\n");
      else
        fprintf(hfp,"  Power ON time: %d minutes.\n",by);
    }

    if ( headtype == MTW )
      fprintf(hfp,"  WarmupTime %d seconds\n",mwhead.rwParms.modem.cellWarmupTime);
    else
      fprintf(hfp,"  WarmupTime %d seconds\n",k2head.rwParms.modem.cellWarmupTime);

    fprintf(hfp,"  Call-In Times: ");

    for (j = 0; j < 5; j++)          // changed 2->5 6/10/96
    {
      if ( headtype == MTW )
        hi = swap2(mwhead.rwParms.modem.cellStartTime[j]);
      else
        hi = swap2(k2head.rwParms.modem.cellStartTime[j]);

      if (hi < 0)
        fprintf(hfp," OFF ");
      else
      {
        hi1 = hi /60;    // get hours
        hi2 = hi % 60;   // get minutes
        fprintf(hfp," %02d:%02d",hi1,hi2);
      }
    } // for j
  fprintf(hfp,"\n");

    //  end cell stuff added 5/21/96

    fprintf(hfp," Phone Numbers: \n");       // remove 3 & 4 7/11/96

    if ( headtype == MTW )
    {
      fprintf(hfp,"   1: %s ",mwhead.rwParms.modem.phoneNumber[0]);
      fprintf(hfp,"   2:% s\n",mwhead.rwParms.modem.phoneNumber[1]);
//      fprintf(hfp,"   3: %s",mwhead.rwParms.modem.phoneNumber[2]);
//      fprintf(hfp,"   4: %s\n",mwhead.rwParms.modem.phoneNumber[3]);
    }
    else
    {
      fprintf(hfp,"   1: %s",k2head.rwParms.modem.phoneNumber[0]);
      fprintf(hfp,"   2: %s\n",k2head.rwParms.modem.phoneNumber[1]);
//      fprintf(hfp,"   3: %s",k2head.rwParms.modem.phoneNumber[2]);
//      fprintf(hfp,"   4: %s\n",k2head.rwParms.modem.phoneNumber[3]);
    }

    if (headver >= K2110)     // k2 110, mw 120, k2 130, k2 140, mtw 150
    {
      if ( headtype == MTW )
        hi = swap2(mwhead.rwParms.modem.flags);
      else
        hi = swap2(k2head.rwParms.modem.flags);

      if ((hi & 0x0001) == 0x0001)
      {
        if (((hi & 0x0002) != 0x0000) || ((hi & 0x0004) != 0x0000) ||
            ((hi & 0x0008) != 0x0000) || ((hi & 0x0010) != 0x0000) ||
            ((hi & 0x0020) != 0x0000))
        {
          fprintf(hfp,"Automatic callout ON.\n");
          if ((hi & 0x0002) != 0x0000)
            fprintf(hfp,"  Call out on low battery voltage\n");
          else
            fprintf(hfp,"   Ignore battery voltage\n");
          if ((hi & 0x0004) != 0x0000)
            fprintf(hfp,"  Call out on battery charge failed\n");
          else
            fprintf(hfp,"   Ignore battery charge\n");
          if ((hi & 0x0008) != 0x0000)
            fprintf(hfp,"  Call out on extreme temperature\n");
          else
            fprintf(hfp,"   Ignore temperature\n");
          if ((hi & 0x0010) != 0x0000)
            fprintf(hfp,"  Call out on event\n");
          else
            fprintf(hfp,"   Ignore event\n");
          if ((hi & 0x0020) != 0x0000)
            fprintf(hfp,"  Call out on GPS lock failure\n");
          else
            fprintf(hfp,"   Ignore GPS lock failure\n");
        }
        else
          fprintf(hfp,"Automatic answer ON.\n");
      }
      else
        fprintf(hfp,"Automatic answer/callout OFF.\n");
    }


    if ( headtype == MTW )
      hb = mwhead.rwParms.modem.waitForConnection;
		else
      hb = k2head.rwParms.modem.waitForConnection;
    fprintf(hfp," Wait for connection %d seconds.\n",hb);

    if ( headtype == MTW )
      hb = mwhead.rwParms.modem.pauseBetweenCalls;
		else
      hb = k2head.rwParms.modem.pauseBetweenCalls;
    if (hb == 0)                                             // added 5/21/96
      fprintf(hfp," Pause random delay, 5-30 seconds, between calls.\n",hb);
    else
      fprintf(hfp," Pause %d seconds between calls.\n",hb);

    if ( headtype == MTW )
      hb = mwhead.rwParms.modem.maxDialAttempts;
		else
      hb = k2head.rwParms.modem.maxDialAttempts;
    fprintf(hfp," Max dial attempts: %d.\n",hb);
    fprintf(hfp,"\n");

// -------- begin  1.40/1.50  -------------------

    if (headver >= 140)   // Seismo & SDS parameters added
    {
      fprintf(hfp,"Serial Data Stream Parameters:\n");

      if ( headtype == MTW )
        hi = swap2(mwhead.rwParms.stream.Timeout);
      else
        hi = swap2(k2head.rwParms.stream.Timeout);

      fprintf(hfp," Mode:  ");

      if (hi == 0)
      {
        fprintf(hfp," One \n",hi);
      }

      if ((hi >= 6) && (hi <= 32766))
      {
        fprintf(hfp," Two, Send 'Continue' every %d blocks\n",hi);
      }
      if (hi == -1)
      {
        fprintf(hfp," Three \n",hi);
      }

      if ( headtype == MTW )
        uby = mwhead.rwParms.stream.DataFmt;
      else
        uby = k2head.rwParms.stream.DataFmt;

      fprintf(hfp," Data Format:  ");

      if (uby == 0)
      {
        fprintf(hfp," Uncompressed\n");
      }

      if (uby == 1)
      {
        fprintf(hfp," Compressed\n");
      }

      if ( headtype == MTW )
        hw = swap2(mwhead.rwParms.stream.BufferSize);
      else
        hw = swap2(k2head.rwParms.stream.BufferSize);

      fprintf(hfp," Disk Buffer Size (16K blocks): %u \n",hw);

      if ( headtype == MTW )
        hw = swap2(mwhead.rwParms.stream.SampleRate);
      else
        hw = swap2(k2head.rwParms.stream.SampleRate);

      if (hw == 0)
      {
        fprintf(hfp," Transmission Sample Rate:  OFF \n",hw);
      }
      else
      {
        fprintf(hfp," Transmission Sample Rate: %u \n",hw,hw);
      }  // if samrate = 0

      if ( headtype == MTW )
        hw = swap2(mwhead.rwParms.stream.TxBlkSize);
      else
        hw = swap2(k2head.rwParms.stream.TxBlkSize);

      fprintf(hfp," Samples per Block: %u \n",hw);

      if ( headtype == MTW )
        ul = swap4i(mwhead.rwParms.stream.TxChanMap);
      else
        ul = swap4i(k2head.rwParms.stream.TxChanMap);

      fprintf(hfp," Channel(s) transmitted: ",ul);
      for (i = 0; i < MAX_CHANNELS; i++)
      {
        if ((ul & 0x00000001) == 1)
          fprintf(hfp," %d",i+1);
        ul = ul >> 1;
      }
      fprintf(hfp,"\n");
      fprintf(hfp,"\n");

    }  // if headver >= 140

// ---------   end  1.40/1.50  -----------------------

    if ( headtype == MTW )
      us = swap2(mwhead.rwParms.misc.serialNumber);
		else
      us = swap2(k2head.rwParms.misc.serialNumber);

    fprintf(hfp,"End Altus ");
    if (headtype == K2)
    fprintf(hfp,"K2 ");
		else
    fprintf(hfp,"Mt. Whitney ");
    fprintf(hfp,"Header S/N %d, %s\n\n\n",us,infname);

//
//  file, hfp, will be closed after return
//

}

// end kwhd2.c


/*---  end  kwhd2.c   ---------------------------------------------------*/

/*--------------------------------------------------------------------------*/
/* util.c */
/*--------------------------------------------------------------------------*/

/* 3/27/95  util.c  sub-routines for kw2asc.c */

#include "kw2asc.h"

//.......................

//  index

//  void CK2Time(unsigned long rawTime)

//  int  IsLeapYear(int year)
//  void Seconds2Time(unsigned long time, int *iyear, int *iday_of_year, int *ihour,
//            	       int *imin, int *isec)
//  void Day2Month(int year, int day_of_year, int *month, int *day_of_month)

//  int swap2(int);
//  long swap4i(long);
//  float swap4r(float);

//  float ad_val(long);

//.......................


/*---------------------------------------------------------*/

void CK2Time(unsigned long rawTime)
{

	Seconds2Time(rawTime, &m_nYear, &m_nDayOfYear, &m_nHour,
		&m_nMin, &m_nSec);
	Day2Month(m_nYear, m_nDayOfYear, &m_nMonth, &m_nDayOfMonth);
}

/*---------------------------------------------------------*/
// Algorithms below were taken from K2 code, file TIME.C
/*---------------------------------------------------------*/

static const int mon[] =
	{0,31,28,31,30,31,30,31,31,30,31,30,31}; /* January = 1, take out __far */


int IsLeapYear(int year)
{
	/* Returns 1 if year is a leap year
		Leap years are year divisible by 4 except century years.
		Leap years are century years divisible by 400.
	 */
	return (((year%100 == 0) && (year%400 == 0)) ||   // century & /400
				((year%100 != 0) && (year%4 == 0)));     // not century & /4
}

/*---------------------------------------------------------*/

void Seconds2Time(unsigned long time, int *iyear, int *iday_of_year, int *ihour,
	int *imin, int *isec)
{
	/* Converts seconds since Jan. 1, 1980 to
		calendar date and time
		This algorithm is good for years between 1980 and 2100.
		(Year 2100 is not a leap year and requires special handling.)
	*/
	*isec = (int)(time % 60L);
	time /= 60L; /* time in minutes */
	*imin = (int)(time % 60L);
	time /= 60L; /* time in hours */
	*ihour = (int)(time % 24L);
	time /= 24L; /* time in days */
	*iyear = 1980 + (int)((time/1461L) << 2); /* 1461 days in 4 years */
	time %= 1461L;
	if (time >= 366)
	{
		time -= 366;
		(*iyear)++;
		*iyear += (int)(time / 365L);
		time %= 365L;
	}
	*iday_of_year = (int)(time+1); /* add 1 since day 1 == Jan. 1 */
}

/*---------------------------------------------------------*/

void Day2Month(int year, int day_of_year, int *month, int *day_of_month)
{
	 /*
	  * Given year and day of year, calculates month and day of month
	  * day_of_year = 1 for January 1
	  * *month = 1, *day_of_month = 1 for January 1
	  */
	 int i;

	 for ( ; ; (year)++)
	 {
		  if (IsLeapYear(year))
		  {
				if (day_of_year > 60)
					day_of_year--;
				else if (day_of_year == 60)
				{
					*month = 2;
					*day_of_month = 29;
					return;
				}
		  }

		  for (i=1; i <= 12; i++)
		  {
				if (day_of_year <= mon[i])
				{
					 *day_of_month = day_of_year;
					 *month = i;
					 return;
				}
				day_of_year -= mon[i];
		  }
	 }
}

/*-----------------------------------------*/



//  ...................................
//
//  int swap2(int w)
//
//  swaps order of bytes: 12 -> 21
//
//  ...................................
int swap2(int w)
{
union {
  unsigned char t[2];
  int w;
} tempi;
unsigned char tempb;

  tempi.w = w;
  tempb = tempi.t[0];
  tempi.t[0] = tempi.t[1];
  tempi.t[1] = tempb;
  return tempi.w;
}  //  swap2()

/*------------------------------------*/


//  ...................................
//
//  long swap4i(long li)
//
//  swaps order of 4 byte long  1234 -> 4321
//
//  ...................................
long swap4i(long li)
{
union {
  unsigned char t[4];
  long l;
} templ;
unsigned char tempb;

  templ.l = li;
  tempb = templ.t[0];
  templ.t[0] = templ.t[3];
  templ.t[3] = tempb;
  tempb = templ.t[1];
  templ.t[1] = templ.t[2];
  templ.t[2] = tempb;
  return templ.l;
}  //  swap4i()

/*--------------------------------------*/


//  ...................................
//
//  float swap4r(float re)
//
//  swaps order of 4 byte float 1234 -> 4321
//
//  ...................................
float swap4r(float re)
{
union {
  unsigned char t[4];
  float f;
}  tempf;
unsigned char tempb;

  tempf.f = re;
  tempb = tempf.t[0];
  tempf.t[0] = tempf.t[3];
  tempf.t[3] = tempb;
  tempb = tempf.t[1];
  tempf.t[1] = tempf.t[2];
  tempf.t[2] = tempb;
 return tempf.f;
}  //  swap4r()

/*-------------------------------------*/


//  .....................................
//
//  float ad_val(long)
//
//  converts sample to voltage
//
//.......................................

float ad_val(long data)
{
float x;
	x = ((data*1.0)/8388608.0) * 2.5;  // fullscale = +/- 2.5V
   return x;
}  // ad_val()                        // 2^23 = 8388608.0


/*--------------------------------------*/

/*---  end  util.c   -------------------------------------------------------*/


/*---  end  kw2asc.src   ---------------------------------------------------*/




