/* SigLib Costas Loop Example */

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <siglib.h>
#include "GraphFunctions.h"

/* Define constants */
#define	PER_SAMPLE						0				/* Set to '1' to use SDS_CostasLoop, '0' to use SDA_CostasLoop */

#define	SAMPLE_LENGTH					512L

#define SAMPLE_RATE						((SLData_t)48000.0)		/* Sample rate */
#define CARRIER_FREQUENCY				((SLData_t)300.0)		/* Carrier frequency */

#define FEEDBACK_MODE	SIGLIB_COSTAS_LOOP_MULTIPLY_LOOP		/* Feedback mode */
//#define FEEDBACK_MODE	SIGLIB_COSTAS_LOOP_POLARITY_LOOP
//#define FEEDBACK_MODE	SIGLIB_COSTAS_LOOP_HARD_LIMITED_LOOP	/* Very sensitive so may need to reduce modulation index */

						/* Note : Costas loop LPFs - lengths are chosen so that there
						are at least two full cycles and an odd number - for an integer group delay */
#define	COSTAS_LP_LPF_LENGTH			(((SLFixData_t)((SAMPLE_RATE / CARRIER_FREQUENCY) * SIGLIB_TWO)) | 0x1)						/* Costas loop LP LPF FIR filter length */
#define COSTAS_LP_LPF_CUTOFF_FREQUENCY	100.0					/* LPF cut-off frequency */
#define	COSTAS_LP_VCO_MODULATION_INDEX	((SLData_t)0.005) 		/* Modulation index */
#define COSTAS_LP_LOOP_FILTER_ALPHA		((SLData_t)0.9)			/* Feedback coeff for one-pole loop filter */
#define	COSTAS_LP_VCO_SINE_TABLE_SIZE	((SLArrayIndex_t)1024)	/* Look up table for fast sine calculation */

SLData_t		*pData;
SLData_t		*pCostasLpLPFCoeffs, *pCostasLpLPF1State, *pCostasLpLPF2State;	/* Costas loop loop filter coefficient pointer */

SLArrayIndex_t	CostasLpLPF1Index;					/* Costas loop inphase LPF filter index */
SLArrayIndex_t	CostasLpLPF2Index;					/* Costas loop quadrature phase LPF filter index */
SLData_t		CostasLpState;						/* Costas loop feedback state for next iteration */

SLData_t		CostasLpLoopFilterState;			/* Costas loop loop filter feedback coeff */
SLData_t		*pCostasLpVCOLookUpTable;			/* VCO cosine look-up-table pointer */
SLData_t		CostasLpVCOPhase;					/* Costas loop VCO phase */

SLData_t		SinePhase;


void main (void);

void   main(void)

{
	GraphObject *h2DGraph;							/* Declare graph object */

#if PER_SAMPLE
		SLArrayIndex_t i;
#endif

	printf ("\n\nSigLib Costas Loop Example\n");

	pData = SUF_VectorArrayAllocate (SAMPLE_LENGTH);
	pCostasLpLPFCoeffs = SUF_VectorArrayAllocate (COSTAS_LP_LPF_LENGTH);
	pCostasLpLPF1State = SUF_VectorArrayAllocate (COSTAS_LP_LPF_LENGTH);
	pCostasLpLPF2State = SUF_VectorArrayAllocate (COSTAS_LP_LPF_LENGTH);
	pCostasLpVCOLookUpTable = SUF_CostasLoopVCOArrayAllocate (COSTAS_LP_VCO_SINE_TABLE_SIZE);

	SIF_CostasLoop (&CostasLpVCOPhase,								/* VCO phase */
					pCostasLpVCOLookUpTable,						/* VCO look up table */
					COSTAS_LP_VCO_SINE_TABLE_SIZE,					/* VCO look up table size */
					COSTAS_LP_LPF_CUTOFF_FREQUENCY / SAMPLE_RATE,	/* Low-pass filter cut-off frequency */
					pCostasLpLPF1State,								/* Pointer to loop filter 1 state */
					&CostasLpLPF1Index,								/* Pointer to loop filter 1 index */
					pCostasLpLPF2State,								/* Pointer to loop filter 2 state */
					&CostasLpLPF2Index,								/* Pointer to loop filter 2 index */
					pCostasLpLPFCoeffs,								/* Pointer to loop filter coefficients */
					COSTAS_LP_LPF_LENGTH,							/* Loop filter length */
					&CostasLpLoopFilterState,						/* Pointer to loop filter state */
					&CostasLpState);								/* Pointer to delayed sample */

	SinePhase = ((SLData_t)2.0);									/* Arbitrary phase - radians */

	h2DGraph =										/* Initialize graph */
		Create2DGraph ("Costas Loop",				/* Graph title */
					   "Time",						/* X-Axis label */
					   "Magnitude",					/* Y-Axis label */
					   SV_AUTO_SCALE,				/* Scaling mode */
					   SV_SIGNED,					/* Sign mode */
					   SV_GRAPH_LINE,				/* Graph type */
					   "localhost");				/* Graph server */
	if (h2DGraph == NULL)							/* Graph creation failed - e.g is server running ? */
	{
		printf ("\nGraph creation failure. Please check that the server is running\n");
		exit (1);
	}

	do
	{
		SDA_SignalGenerate (pData,								/* Pointer to destination array */
							SIGLIB_SINE_WAVE,					/* Signal type - Sine wave */
							SIGLIB_ONE,							/* Signal peak level */
							SIGLIB_FILL,						/* Fill (overwrite) or add to existing array contents */
							CARRIER_FREQUENCY / SAMPLE_RATE,	/* Signal frequency */
							SIGLIB_ZERO,						/* D.C. Offset */
							SIGLIB_ZERO,						/* Unused */
							SIGLIB_ZERO,						/* Signal end value - Unused */
							&SinePhase,							/* Signal phase - maintained across array boundaries */
							SIGLIB_NULL_DATA_PTR,				/* Unused */
							SAMPLE_LENGTH);						/* Output array length */

		Display2DGraph (h2DGraph,					/* Graph handle */
					    "Original Sine Wave",		/* Title of the dataset */
					    pData,						/* Array of Double dataset */
					    SAMPLE_LENGTH,				/* Number of data points */
						SV_GRAPH_LINE,				/* Graph type */
					    SV_MAGENTA,					/* Colour */
						SV_HIDE_MARKERS,			/* Marker enable / disable */
						SV_GRAPH_NEW);				/* New graph */


#if PER_SAMPLE
		for (i = 0; i < SAMPLE_LENGTH; i++)
		{
			*(pData +i) =
				SDS_CostasLoop (*(pData +i),						/* Source data sample */
								&CostasLpVCOPhase,					/* VCO phase */
								COSTAS_LP_VCO_MODULATION_INDEX,		/* VCO modulation index */
								pCostasLpVCOLookUpTable,			/* VCO look up table */
								COSTAS_LP_VCO_SINE_TABLE_SIZE,		/* VCO look up table size */
								CARRIER_FREQUENCY / SAMPLE_RATE,	/* Carrier frequency */
								pCostasLpLPF1State,					/* Pointer to loop filter 1 state */
								&CostasLpLPF1Index,					/* Pointer to loop filter 1 index */
								pCostasLpLPF2State,					/* Pointer to loop filter 2 state */
								&CostasLpLPF2Index,					/* Pointer to loop filter 2 index */
								pCostasLpLPFCoeffs,					/* Pointer to loop filter coefficients */
								COSTAS_LP_LPF_LENGTH,				/* Loop filter length */
								&CostasLpLoopFilterState,			/* Pointer to loop filter state */
								COSTAS_LP_LOOP_FILTER_ALPHA,		/* Loop filter coefficient */
								FEEDBACK_MODE,						/* Loop feedback mode */
								&CostasLpState);					/* Pointer to delayed sample */
		}
#else
		SDA_CostasLoop (pData,								/* Source data pointer */
						pData,								/* Destination data pointer */
						&CostasLpVCOPhase,					/* VCO phase */
						COSTAS_LP_VCO_MODULATION_INDEX,		/* VCO modulation index */
						pCostasLpVCOLookUpTable,			/* VCO look up table */
						COSTAS_LP_VCO_SINE_TABLE_SIZE,		/* VCO look up table size */
						CARRIER_FREQUENCY / SAMPLE_RATE,	/* Carrier frequency */
						pCostasLpLPF1State,					/* Pointer to loop filter 1 state */
						&CostasLpLPF1Index,					/* Pointer to loop filter 1 index */
						pCostasLpLPF2State,					/* Pointer to loop filter 2 state */
						&CostasLpLPF2Index,					/* Pointer to loop filter 2 index */
						pCostasLpLPFCoeffs,					/* Pointer to loop filter coefficients */
						COSTAS_LP_LPF_LENGTH,				/* Loop filter length */
						&CostasLpLoopFilterState,			/* Pointer to loop filter state */
						COSTAS_LP_LOOP_FILTER_ALPHA,		/* Loop filter coefficient */
						FEEDBACK_MODE,						/* Loop feedback mode */
						&CostasLpState,						/* Pointer to delayed sample */
						SAMPLE_LENGTH);						/* Length of input array */
#endif

		Display2DGraph (h2DGraph,					/* Graph handle */
					    "Costas Loop Output",		/* Title of the dataset */
					    pData,						/* Array of Double dataset */
					    SAMPLE_LENGTH,				/* Number of data points */
						SV_GRAPH_LINE,				/* Graph type */
					    SV_BLUE,					/* Colour */
						SV_HIDE_MARKERS,			/* Marker enable / disable */
						SV_GRAPH_ADD);				/* New graph */

		printf ("Hit 'x' to exit or <CR> to continue\n");

	} while (tolower (getchar ()) != 'x');


	SUF_MemoryFree (pData);							/* Free memory */
	SUF_MemoryFree (pCostasLpLPFCoeffs);
	SUF_MemoryFree (pCostasLpLPF1State);
	SUF_MemoryFree (pCostasLpLPF2State);
	SUF_MemoryFree (pCostasLpVCOLookUpTable);
}



