/***********************************************************************
 *                                                                     *
 * Program to control LORAN-C radio                                    *
 *                                                                     *
 * Header file used by all programs                                    *
 *                                                                     *
 * Note on units: (ms) milliseconds, (us) microseconds, (cycle) 10-us  *
 * carrier cycles, (clock) 200-ns master clock cycles                  *
 *                                                                     *
 ***********************************************************************
 */

#include <stdio.h>
#include <ctype.h>
#include <bios.h>
#include <math.h>
#include <conio.h>
#include <string.h>

#define DEBUG					/* define for simulation */

/*
 * Sizes of things. The pulse-group filter is a shift register with one
 * stage for each 100-us bin in a 900-us sample window plus one stage
 * for a noise gate for a total of 10 stages. The envelope filters
 * consist of one stage for each 10-us cycle in the 400-us envelope
 * gate, for a total of 40 stages.
 */
#define NSTA 6					/* max number of stations */
#define NRMS 10					/* size of pulse-group filter */
#define NENV 40					/* size of envelope filter */
#define RMAX 20					/* size of rank vector */
#define NLMS 9					/* size of LMS filter (not used) */

/*
 * Incidental constants. These establish the master clock period, LORAN-
 * C carrier cycle period, the velocity of light and other trivia.
 */
#define CLOCK 50				/* clock period (clock) */
#define CYCLE 10				/* carrier period (us) */
#define GRI 800					/* pulse-group gate (cycle) */
#define PCX (NENV * CLOCK)		/* envelope gate (clock) */
#define STROBE 50				/* strobe gate (clock) */
#define PI 3.141592653589		/* the real thing */
#define PIH (PI / 2)			/* half the real thing */
#define PID (2 * PI)			/* twice the real thing */
#define D2R (PI / 180)			/* convert degrees to radians */
#define R2D (180 / PI)			/* convert radians to degrees */
#define VOFL 2.9979250e8		/* velocity of light */
#define R 6371.2				/* radius of the Earth (km) */
#define LORSTA "loran.dat"		/* name of LORAN-C data file  */

/*
 * The program and display guard times bound the maximum latency for the
 * program to process samples at the end of a gri and for the output
 * routines to display a line, respectively. The LORAN-C signal
 * specification requires a minimum guard time of 9900 microseconds or
 * 990 cycles, which is less than the value here (1100). The reason for
 * this is that the 386/387 is not quite fast enough to meet the spec;
 * however, this has not been a problem in the prototype system. If the
 * time to the next gri is less than either of these, the next frame is
 * skipped. The watchdog timeout is the maximum number of frames before
 * the program abandons cycle search and reverts to pulse-group search.
 */
#define PGUARD 1100				/* program guard time (cycle) (990!) */
#define DGUARD 8000				/* display guard time (cycle) */
#define WATCHDOG 2000			/* watchdog timeout (frame) */

/*
 * The i-channel and q-channel median filters are characterized by the
 * shift-register size (mcnt). The minimum value of this variable
 * (PMIN) is established at the conclusion of the pulse-group search and
 * must be at least 3. As the time constant of integration is increased
 * during the subsequent synchronization process, mcnt can be increased
 * to improve the efficience of the filter. However, its size (sample
 * delay) must remain small compared with the time constant of
 * integration in order to preserve the transient response of the
 * feedback loop. The maximum value of mcnt (MMAX) controls the high-
 * frequency response (boxcar effect) of the filter and is
 * experimentally determined. The boxcar affect is mitigated somewhat by
 * the use of a trimmed-mean statistic, where the output of the filter
 * is actually the average of the three samples near the median of the
 * (sorted) samples in the filter.
 */
#define MMIN 3					/* min median filter size */
#define MMAX 7					/* max median filter size */

/*
 * The amplitude and phase feedback loops are characterized by the time
 * constant of integration (pfac). The minimum value of this variable
 * (PMIN) establishes the bandwidth of the phase loop and thus the pull-
 * in range. There is a tradeoff between pull-in range and sensitivity;
 * the larger the pull-in range, and thus the larger the master
 * oscillator intrinsic frequency tolerance, the greater the minimum
 * signal required for synchronization and vice versa. The value
 * selected for PMIN is appropriate for an oscillator tolerance of 0.1
 * ppm, pretty tight for a cold rock, but about right for a hot one. The
 * maximum value of pfac (PMAX) establishes the tracking range, which
 * depends on the intrinsic short-term stability (wander) of the master
 * oscillator. If this is made too large, the phase loop can break lock
 * if the wander is too large. The value selected seems adequate for the
 * hot rock now used (Isotemp); however, the wander of this unit has not
 * been precisely determined. The speed of adaptation of the amplitude
 * and phase loops is established by the PFAC parameter, which has been
 * experimentally determined by simulation and watching many
 * sunchronization episodes under varying conditions.
 */
#define PMIN 8					/* min pll time constant */
#define PMAX 1000				/* max pll time constant */
#define PFAC 1.2				/* time-constant adjustment factor */

/*
 * The agc adjustment factor controls the gain of the amplitude feedback
 * loop. There is some hocus-pocus here, since the transfer function of
 * the gain-control loop has not been precisely determined. The value is
 * selected so that the agc action is smooth and free of obvious
 * hunting.
 */
#define AFAC 4					/* agc adjustment factor */

/*
 * The OFFSET parameter represents the delay of the matched filter and
 * noise gate to position the pulse group in the middle of the pulse-
 * group gate. The delay from the peak of the matched filter to the
 * current sample is 550 microseconds (55 cycles). To this is added the
 * delay necessary to position the pulse group at the center of the 400-
 * us pulse-group gate at the conclusion of pulse-group search, or 200
 * us (20 cycles). Experimentally, for whatever reason, the optimum
 * value is found to be 12 instead of 20. Note that the pulse-group gate
 * and phase decoder are implemented between the first and second rf
 * stages and operate with a relatively wide passband, while the strobe
 * is implemented as part of the synchronous detector and operates with
 * a relatively narrow passband. The additional delay due to bandwidth
 * reduction is specified by the RCVDELAY parameter. From SPICE
 * simulation this value is found to be between 20 and 40 us; but, in
 * practice, it must be experimentally determined relative to a
 * precision timing source, such as a GPS receiver.
 */
#define OFFSET (55 + 12)		/* pulse-group offset (cycle) */
#define RCVDELAY 30				/* receiver strobe delay (us) */

/*
 * The VCO parameter represents the initial value of the vco dac and is
 * set at the midpoint of its full-scale range. A vernier pot on the
 * master oscillator unit is then adjusted for zero nominal frequency
 * offset as much less than 0.1 ppm as possible (for the Istemp rock,
 * down in the 1e-10 range). The AGC parameter represents the initial
 * value of the agc dac and thus the gain of the system during pulse-
 * group search. It is set with the antenna connected using the operator
 * commands to increment or decrement the agc until the peak of the
 * maximum amplitude pulses observed with an oscilloscope connected to
 * the output of the last rf stage preceeding the detector is nominally
 * 800 mV p-p. The ADCOFS parameter represents the initial coarse
 * offsets of the adc channels and is chosen to match the reference
 * voltage of the integrators. The working offsets are refined by the
 * program.
 */
#define VCO 2048				/* initial vco dac (0 V)*/
#define AGC 1440				/* initial agc dac (3.51 V) */
#define ADCOFS (256 * 3 / 5)	/* adc offset for 3V Zener */

/*
 * The XGATE parameter establishs the error/false-alarm rate during the
 * pulse-group search mode. A noise gate nips ambient pulse-type
 * electrical noise and isolated pulses from other loran chains during
 * the pulse-group search. The value is experimentally determined as a
 * tradeoff between clipping wanted pulses, thus possibly failing to
 * synchronize, and allowing unwanted pulses, thus possibly synchonizing
 * in error. The value selected does reasonably well in simulations
 * using Gaussian noise; however, it is likely the optimum value under
 * actual LORAN-C conditions may be considerably different and open to
 * experimental refinement.
 */
#define XGATE 4.				/* cross-rate noise gate */

/*
 * The following parameters establish the error/false-alarm rate during
 * the cycle-search and tracking modes and are determined experimentally
 * during simulation and refined during actual operation. The values
 * selected were established using an initial frequency offset of 0.1
 * ppm and a received peak-signal/Gaussian-noise ratio (snr) of 0 dB
 * (with no coding gain), which is comfortably heroic. The envelope-
 * cycle-difference (ecd) snr gate EGATE and strobe noise gate SGATE
 * control entry to the tracking mode from the cycle-search mode. The
 * EGATE parameter establishes the minimum snr acceptable for tracking
 * mode. If set too low the system may synchronize to casual pulses or
 * random noise; if set too high the system may never track a legitimate
 * station. The SGATE parameter represents the maximum acceptable span
 * between the maximim cycle number and minimum cycle number of the
 * strobe (reference) cycle determined in the last several envelope
 * scans. It is chosen to minimize the frequency of 10-us strobe slips
 * due to noise excursions. If set too low this frequency may be
 * unneccessarily high; if set too high the "boxcar" effect of large
 * noise excursions may unneccessarily extend the period of incorrect
 * synchronization. The phase error gate PGATE controls the adjustment
 * of the time constant of integration (pfac) during the initial cycle-
 * search and tracking phases. With high noise levels at initial entry
 * to the cycle-search mode, the phase and amplitude loops are quite
 * loose and bounce around a lot. However, once reliable phase lock has
 * been achieved and the reference cycle has been found, the time
 * constant of integration must be increased by two orders of magnitude
 * in order to achieve the ultimate stability and accuracy. In order to
 * quickly reach this condition, PGATE needs to be set as high as
 * possible; however, this may inhibit and even defeat the initial
 * adjustments necessary to compensate for the master oscillator
 * intrinsic frequency tolerance. The value selected allows some 90% of
 * the initial adjustment to be completed before the time constant is
 * incremented, yet provides reliable adaptation under the simulated
 * conditions.
 */ 
#define EGATE .7				/* ecd snr gate */
#define SGATE 2					/* strobe noise gate */
#define PGATE 150				/* phase error gate */

/*
 * Phase-lock loop (pll) parameters (the trickiest of all). The receiver
 * agc is controlled to produce a max envelope-cycle amplitude of 100,
 * which represents a phase-detector constant Kd = 100 * 2 * PI = 628.
 * This is an upper bound; since, when locked only the third carrier
 * cycle is used and its anplitude is only about 50. The vco has a
 * measured sensitivity Ko = 2.25e-10 per Hz or 2.25e-5 at the 100-kHz
 * phase-detector frequency. The overall pll gain is the product Kd *
 * Ko. The digital loop gain is found experimentally to control slave-
 * loop dynamics.
 */
#define Kd 628.					/* phase detector constant */
#define Ko 2.25e-5 				/* vco constant (Hz/dac unit) */
#define VGAIN (Kd * Ko)			/* overall analog loop gain */
#define DGAIN 15				/* digital loop threshold */

/*
 * The following represent works in progress.
 */
#define LMS 1e-5				/* LMS step size (not used) */
#define AGCFAC 16				/* agc time constant (not used) */

/*
 * Define program modes
 */
#define MODE_MIN 1				/* set min gain */
#define MODE_MAX 2				/* set max gain */
#define MODE_AGC 3				/* set agc */
#define MODE_PSRCH 4			/* pulse-group search */
#define MODE_CSRCH 5			/* cycle search */
#define MODE_TRACK 6			/* phase track */

/*
 * Timing generator definitions and master oscillator source
 */
#define PORT 0x0300				/* controller port address */
#define TGC PORT+0				/* stc control port (r/w) */
#define TGD PORT+1				/* stc data port (r/w) */
	#define OSC 0x0500			/* oscillator: 0x0100 int/0x0500 ext */

/*
 * Analog/digital converter (ADC) hardware definitions
 */
#define ADC PORT+2				/* adc buffer (r)/address (w) */
#define ADCGO PORT+3			/* adc status (r)/adc start (w) */
	#define START 0x01			/* converter start bit (w) */
	#define BUSY 0x01			/* converter busy bit (r) */
	#define DONE 0x80			/* converter done bit (r) */
	#define I 0					/* i channel (phase) */
	#define Q 1					/* q channel (amplitude) */
	#define S 2					/* s channel (agc) */

/*
 * Digital/analog converter (DAC) hardware definitions
 * Note: output voltage increases with value programmed; the buffer
 * is loaded in two 8-bit bytes, the lsb 8 bits with the MSB bit off in
 * the PAR register, the msb 4 bits with the MSB on.
 */
#define DACA PORT+4				/* vco (dac a) buffer (w) */
#define DACB PORT+5				/* agc (dac b) buffer (w) */

/*
 * Pulse-code generator (CODE) hardware definitions
 * Note: bits are shifted out from the lsb first
 */
#define CODE PORT+6				/* pulse-code buffer (w) */
	#define MPCA 0xCA			/* LORAN-C master pulse code group a */
	#define MPCB 0x9F			/* LORAN-C master pulse code group b */
	#define SPCA 0xF9			/* LORAN-C slave pulse code group a */
	#define SPCB 0xAC			/* LORAN-C slave pulse code group b */

/*
 * Mode register (PAR) hardware definitions
 */
#define PAR PORT+7				/* parameter buffer (w) */
	#define INTEG 0x03			/* integrator mask */
	/*
	 * time constant values
	 *
	 * 0	1.000 ms
	 * 1	0.264 ms
	 * 2	0.036 ms
	 * 3	short caps
	 */
	#define GATE 0x0C			/* gate source mask */
	/*
	 * gate source values
	 *
	 * 4	always open
	 * 8	group repeition interval (GRI)
	 * c	puldse code interval (PCI)
	 * f	strobe (STB)
	 */
	#define MSB 0x10			/* load dac high-order bits */
	#define IEN 0x20			/* enable interrupt bit */
	#define EN5 0x40			/* enable counter 5 bit */
	#define ENG 0x80			/* enable gri bit */

/*
 * Timing generator (STC) hardware commands
 */
/* argument sssss = counter numbers 5-1 */
#define LOADDP 0x00				/* load data pointer */
	/* argument ee = element (all groups except ggg = 000 or 111) */
	#define MODEREG 0x00		/* mode register */
	#define LOADREG 0x08		/* load register */
	#define HOLDREG 0x10		/* hold register */
	#define HOLDINC 0x18		/* hold register (hold cycle increm) */
	/* argument ee = element (group ggg = 111) */
	#define ALARM1 0x07			/* alarm register 1 */
	#define ALARM2 0x0F			/* alarm register 2 */
	#define MASTER 0x17			/* master mode register */
	#define STATUS 0x1F			/* status register */
#define ARM 0x20				/* arm counters */
#define LOAD 0x40				/* load counters */
#define LOADARM 0x60			/* load and arm counters */
#define DISSAVE 0x80			/* disarm and save counters */
#define SAVE 0xA0				/* save counters */
#define DISARM 0xC0				/* disarm counters */
/* argument nnn = counter number */
#define SETTOG 0xE8				/* set toggle output HIGH for counter */
#define CLRTOG 0xE0				/* set toggle output LOW for counter */
#define STEP 0xF0				/* step counter */
/* argument eeggg, where ee = element, ggg - counter group */
/* no arguments */
#define ENABDPS 0xE0			/* enable data pointer sequencing */
#define ENABFOUT 0xE6			/* enable fout */
#define ENAB8 0xE7				/* enable 8-bit data bus */
#define DSABDPS 0xE8			/* disable data pointer sequencing */
#define ENAB16 0xEF				/* enable 16-bit data bus */
#define DSABFOUT 0xEE			/* disable fout */
#define ENABPFW 0xF8			/* enable prefetch for write */
#define DSABPFW 0xF9			/* disable prefetch for write */
#define RESET 0xFF				/* master reset */

/*
 * The station structure is the main data structure used by the program.
 * There is one of these for every station in the chain up to five. It
 * contains raw and processed signal samples plus signals used for
 * acquisition, tracking and control of the program.
 */
struct station {

	/*
	 * Identification and control information
	 */
	char type;					/* type (m, w, x, y, z) */
	int mode;					/* operating mode (1-6) */
	int codesw;					/* gri a/b switch */
	int index;					/* index (1-5) */

	/*
	 * Cycle-adjustment counters and related riffraff
	 */
	long phase;					/* station phase offset (cycle) */
	int mindex;					/* index of max pulse-group signal */
	int maxdex;					/* index of max cycle in envelope */
	int cycle;					/* cycle counter */
	int strobe;					/* offset to reference cycle (cycle) */
	int env;					/* envelope scan pointer */
	int envbot;					/* first cycle in envelope scan */
	int envtop;					/* last cycle in envelope scan */
	int ptrenv;					/* display cycle */
	int sgate;					/* strobe noise (max-min) */
	int count;					/* utility counter */
	int icnt;					/* integration cycle counter */
	int mcnt;					/* median counter */
	int ecnt;					/* envelope counter */

	/*
	 * Received signal samples and time constants
	 */
	int isig;					/* i-signal (a+b) (adc chan 0) */
	int qsig;					/* q-signal (a+b) (adc chan 1) */
	double fmax;				/* max signal */
	double fmin;				/* min signal */
	double level;				/* gain control */
	double pfac;				/* integration time constant */

	/*
	 * Phase-lock loop variables
	 */
	double vphase;				/* pll phase adjustment */
	double vfreq;				/* pll frequency adjustment */
	double update;				/* time of last pll update (us) */
	int	slew;					/* digital pll adjustment (clock) */
	int borrow;					/* slew overflow (clock) */

	/*
	 * Median filters, shift registers and cycle accumulators
	 */
	int stb[MMAX];				/* strobe median filter */
	double rms[NRMS];			/* pulse-group shift register */
	double pmed[NENV][MMAX];	/* phase median filter */
	double emed[NENV][MMAX];	/* envelope median filter */
	double pcyc[NENV];			/* cycle phase (i channel) */
	double ecyc[NENV];			/* cycle amplitude (q channel) */
	double qcyc[NENV];			/* cycle energy (q channel) */
	double erms[NENV];			/* cycle rms error */
	double lms[NENV];			/* output signal for LMS algorithm */
	double weight[NLMS];		/* weight vector for LMS algorithm */

	/*
	 * Signal quality indicators
	 */
	double esnr;				/* estimated ecd snr */
	double rsnr;				/* estimated reference cycle snr */
	double psnr;				/* estimated phase error */

	/*
	 * Debugging data and status-message area
	 */
	int cscnt;					/* cycle-slip events */
	int sscnt;					/* strobe-slip events */
	int pncnt;					/* cross-rate noise events */
	char kbd;					/* last keyboard twink */
	char msg[80];				/* status message */
	char report[80];			/* report string for display */

	/*
	 * LORAN-C station data (from data file)
	 */
	double lat;					/* north latitude (rad) */
	double lon;					/* west longitude (rad) */
	double rad_power;			/* radiated power (kw) */
	char name[40];				/* station location name */
	double rcvr_azim;			/* receiver azimuth (rad) */
	double xmtr_azim;			/* transmitter azimuth (rad) */
	double ems_delay;			/* emission delay (us) */
	double path_delay;			/* path delay (us) */
	double system_delay;		/* computed loran system delay (us) */
	};

/* end header */
