/*
	MG2ADC3.C
	
	BL15xx/MicroG2.

	Sample program that shows step by step process to calibrate the first four
	channels of the ADC. The calibration points are assumed to be at two known
	voltages specified by the user before or while running the program. Z-World
	recommends calibrating at points inside the computed range of the ADC
	channels.

	For example, if the full range is 0.00 - 10.00 v, it is suggested to
	calibrate with voltages 1.00 and 9.00 volts. Twenty readings are taken for
	each voltage position at ~ 2.5 ms interval. The calibration function
	mg2adc_compute(...) uses two sets of A/D data and known voltage to compute
	the constants zero_offset and invgain such that:

			voltage = invgain * (zero_offset - A/D data).
			
	The user will be prompted by the STDIO to reply before the reading are
	taken at a prescribed voltage.

	At the end of the calibration process, the program will ask the user if 
	the constants are to be stored to eeprom or not.

	Calibration constants are stored to the simulated eeprom at the following
	locations:

	address  10 - 15  for chan 0
	address	16 - 21  for chan 1
	address	22 - 27  for chan 2
	address  28 - 33  for chan 3
*/

int get_average(int *buf, int count);
extern char OPMODE;

main()
{
char key;
int ercode;

struct mg2adccoeff adcconv0;
struct mg2adccoeff adcconv1;
struct mg2adccoeff adcconv2;
struct mg2adccoeff adcconv3;

int datav10, datav20;
int datav11, datav21;
int datav12, datav22;
int datav13, datav23;

int data0, data1, data2, data3;
unsigned int divider;
float volt1, volt2;			
int dataset[20];
	
int i,j,k;     

	volt1 = 0.2;
	volt2 = 2.3;		
	printf("Toggle F4 (DOS only) to make keyboard input active as STDIO.\n");
	printf("Hit any key to start the calibration process.\n\n");
	
	// get ~2.5 ms sampling period 
	divider = (0.0025 * sysclock() * 1200)/ 20;

	for(;;)
	{
		while(!kbhit())
		{
			hitwd();	runwatch();
		}
		getchar();  
		printf("Input volt1 reference to chans 0 - 3 of the ADC.\n");
		printf("Set actual value of volt1 thru the watch window.\n");
		printf("Hit any key when ready !!!\n\n");
		while(!kbhit())
		{
			hitwd(); runwatch();
		}
		getchar();
		mg2adc_sample(0, 20, dataset, divider);  // data for chan0
		datav10 = get_average(dataset,20);                 
		mg2adc_sample(1, 20, dataset, divider);  // data for chan1
		datav11 = get_average(dataset,20);
		mg2adc_sample(2, 20, dataset, divider);  // data for chan2
		datav12 = get_average(dataset,20);
		mg2adc_sample(3, 20, dataset, divider);  // data for chan3
		datav13 = get_average(dataset,20);
		hitwd();

		printf("Input volt2 reference to chans 0 - 3 of the ADC.\n");
		printf("Set actual value of volt2 thru the watch window.\n");
		printf("Hit any key when ready !!!\n\n");
		while(!kbhit())
		{
			hitwd(); runwatch();
		}
		getchar();

		mg2adc_sample(0, 20, dataset, divider);  // data for chan0
		datav20 = get_average(dataset,20);
		mg2adc_sample(1, 20, dataset, divider);  // data for chan1
		datav21 = get_average(dataset,20);
		mg2adc_sample(2, 20, dataset, divider);  // data for chan2
		datav22 = get_average(dataset,20);
		mg2adc_sample(3, 20, dataset, divider);  // data for chan3
		datav23 = get_average(dataset,20);

		mg2adc_compute(&adcconv0, datav10, volt1, datav20, volt2);
		mg2adc_compute(&adcconv1, datav11, volt1, datav21, volt2);
		mg2adc_compute(&adcconv2, datav12, volt1, datav22, volt2);
		mg2adc_compute(&adcconv3, datav13, volt1, datav23, volt2);

		hitwd();
		printf("New Calibration, zero_offset = %d, invgain = %f\n",
					adcconv0.zero_offset, adcconv0.invgain);
		printf("New Calibration, zero_offset = %d, invgain = %f\n",
					adcconv1.zero_offset, adcconv1.invgain);
		printf("New Calibration, zero_offset = %d, invgain = %f\n",
					adcconv2.zero_offset, adcconv2.invgain);
		printf("New Calibration, zero_offset = %d, invgain = %f\n",
					adcconv3.zero_offset, adcconv3.invgain);

		hitwd();
		printf("Hit 's' to store the new calibration constant\n");
		printf("or any key to continue.\n\n");

		while(!kbhit())
		{
			hitwd(); runwatch();
		}
		key = getchar();
		if(key == 's')
		{
			if(OPMODE & 0x80)
			{
				printf("Storing new calibration constants for chans 0 - 3.\n\n");
				hitwd();
			 	mg2adc_writecoef(10, &adcconv0);
				hitwd();
			 	mg2adc_writecoef(16, &adcconv1);
				hitwd();
				mg2adc_writecoef(22, &adcconv2);
				hitwd();
				mg2adc_writecoef(28, &adcconv3);
			}
			else
			{
				printf("Non-flash eprom, cannot store data !!!\n\n");
			}
		}

		if(OPMODE & 0x80)
		{
			printf("Reading calibration from flash eprom !!!\n\n");
			hitwd();
			mg2adc_readcoef(10, &adcconv0);	// read calibration for chan 0
			mg2adc_readcoef(16, &adcconv1);	// read calibration for chan 1
			mg2adc_readcoef(22, &adcconv2);	// read calibration for chan 2
			mg2adc_readcoef(28, &adcconv3);	// read calibration for chan 3
		}

		printf("Hit key to read ADC chans 0 - 3 !!!!\n");
		for(;;)
		{
			while(!kbhit())			// wait for key from STDIO
			{
				hitwd();	runwatch();         	
			}
			getchar();      			// get the key 
	
			data0 = mg2adc_read(0);   // read A/D channel 0
			data1 = mg2adc_read(1);   // read A/D channel 1
			data2 = mg2adc_read(2);   // read A/D channel 2
			data3 = mg2adc_read(3);   // read A/D channel 3   

			hitwd();
			printf("\nData for the ADC channels 0-3 !!!\n");
			printf("chan 0 >> %6d, %8.3f\n", data0, mg2adc_convert(data0, &adcconv0));
			printf("chan 1 >> %6d, %8.3f\n", data1, mg2adc_convert(data1, &adcconv1));
			printf("chan 2 >> %6d, %8.3f\n", data2, mg2adc_convert(data2, &adcconv2));
			printf("chan 3 >> %6d, %8.3f\n", data3, mg2adc_convert(data3, &adcconv3));
		}
	}  
}

// Compute the average of "count" number of readings for data array.

int get_average( int *data, int count)
{
unsigned long sum;
int i;

	sum = 0L;
	for(i=0;i<count;i++)
	{
		sum = sum + (long) data[i];
	}

	if(count == 0) return 0;
	
	return (int) (sum/count);
}

