/*
 * Calculate the samples required for a sine wave for the Arbitary Function
 * Generator.
 * Written by Ben Low, Copyright 1996. Permission is granted to reproduce this
 * algorithm and/or code in full or part, provided acknowldegment is given.
 */

#include <stdio.h>
#include <math.h>

/* output file name */
#define OUTFILENAME "sine.out"

/* memory size */
#define RAMSIZE 32768

double clocks[] = {7812.5, 250e3, 2e6};	/* clocks derived from main clock */
int nclocks = sizeof(clocks) / sizeof(clocks[0]);

main(int argc, char *argv[])
{
	double N, f, fout, df;
	long k, L;
	int i, n;
	FILE *fileout;

	if ( (argc != 2) || (sscanf(argv[1], "%lf", &f) != 1) )
	{	/* no argument, or argument is not a number */
		fprintf(stderr, "Usage: %s [frequency]\n", argv[0]);
		exit(1);
	}

	if (f <= 0.0)
		exit(1);	/* can't generate DC !*/

	/* Now decide which clock to use. The optimum changeover point for the
	   clock is the frequency at which the next higher clock 'cuts in'.
	   (Optimum in terms of maximum sampling rate). e.g. the 2 MHz clock
	   cuts out at (2x10^6/32768) Hz = 61.0... Hz, this corresponds to the
	   maximum waveform length of 32768 samples at 0.5 us per sample.
	 */
	i = 0;
	while ((i < nclocks-1) && (f > clocks[i+1]/(double)RAMSIZE) )
	{
		i++;
	};

	N = clocks[i] / f;			/* exact no. of samples (real #) */
	k = floor(RAMSIZE / N);		/* no. of repetitions */

	/* check f isn't too small or in excess of Nyquist limit */
	if ((k < 1) || (k > RAMSIZE/2))
	{
		fprintf(stderr, "Frequency is out of range: %lg to %lg Hz\n",
			clocks[0] / RAMSIZE,
			clocks[nclocks-1]/2 );
		exit(1);
	}

	L = floor(N * k);			/* total waveform length */
	fout = clocks[i] * k / L;	/* output freq. */

	df = (fout - f) / f;

	fprintf(stdout, "Clock = %lg Hz\n", clocks[i]);
	fprintf(stdout, "Desired frequency   = %lg Hz\n", f);
	fprintf(stdout, "Generated frequency = %lg Hz\n", fout);
	fprintf(stdout, "Percentage error = %lg %%\n", df * 100);

	if ((fileout = fopen(OUTFILENAME, "w")) == NULL)
	{
		fprintf(stderr, "Could not open file %s\n", OUTFILENAME);
		exit(1);
	}

	/* now calculate the sinusoid. Length L, "period" N */
	/* Note that the samples range in value from 0 to 254 (0h to FEh).
	   255d, (FFh) is used to flag "end of recording". Also note that
	   if the waveform length is *exactly* RAMSIZE, we don't need to use
	   this flag as the RAM address counter will wrap around by itself */
	for (n = 0; n < L; n++)
	{
		fprintf(fileout, "%u\n",
			(unsigned char) (254 * (0.5 * cos((2 * M_PI / N) * n) + 0.5)) );
	}

	if (L < RAMSIZE)	/* need to attach EOR marker */
	{
		fprintf(fileout, "255\n");
	}

	fclose(fileout);

	exit (0);
}
