/***************************************************************************
mgadc43.c
	Sample program that shows step by step process to calibrate the first four
channels of an ADC4 board. 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
mgadc4_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 to convert A/D reading to voltages are stored in
the last 66 bytes ( 6 bytes/channel) of the eeprom of the ADC4 board. 
******************************************************************************/

int get_average(int *buf, int count);
main()
{
	char key;
	int ercode;
	float volt1, volt2;
	
	struct adc4coeff adc4conv0;
	struct adc4coeff adc4conv1;
	struct adc4coeff adc4conv2;
	struct adc4coeff adc4conv3;

	int datav10, datav20;
	int datav11, datav21;
	int datav12, datav22;
	int datav13, datav23;
	int data0, data1, data2, data3;
		
	unsigned int adc4_board;
	unsigned int divider;
			
	int dataset[20];
	
	int i,j,k;     

	volt1 = 0.2;								
	volt2 = 2.3;
	hitwd();
	mgreset_pbus();           // reset the plcbus
	hitwd();

	// identify the first ADC4 board on the PLCBUS
	for(i=0;i<4;i++)
	{
		if(mgadc4_init(0x0c0+i))
		{
			adc4_board = 0x0c0 + i;
			break;
		}
	}

	if( i >= 4)
	{
		printf("No ADC4 Board is detected !!!\n");
		while(1)
		{
			hitwd();	runwatch();
		}
	}

	hitwd();
	printf("ADC4 board %x has been detected !!!\n", adc4_board);
	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 = (unsigned int)((0.0025 * sysclock() * 1200)/ 20);


	for(;;)
	{
		while(!kbhit())
		{
			hitwd();	runwatch();
		}
		getchar();
		printf("Input volt1 reference to chans 0 - 3 of the ADC4 board.\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();
		
		hitwd();
		mgadc4_sample(adc4_board, 0, 20, dataset, divider);  // data for chan0
		datav10 = get_average(dataset,20);                 
		hitwd();
		mgadc4_sample(adc4_board, 1, 20, dataset, divider);  // data for chan1
		datav11 = get_average(dataset,20);
		hitwd();
		mgadc4_sample(adc4_board, 2, 20, dataset, divider);  // data for chan2
		datav12 = get_average(dataset,20);
		hitwd();
		mgadc4_sample(adc4_board, 3, 20, dataset, divider);  // data for chan3
		datav13 = get_average(dataset,20);

		printf("Input volt2 reference to chans 0 - 3 of the ADC4 board.\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();

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

		mgadc4_compute(&adc4conv0, datav10, volt1, datav20, volt2);
		mgadc4_compute(&adc4conv1, datav11, volt1, datav21, volt2);
		mgadc4_compute(&adc4conv2, datav12, volt1, datav22, volt2);
		mgadc4_compute(&adc4conv3, datav13, volt1, datav23, volt2);

		hitwd();
		printf("New Calibration, zero_offset = %d, invgain = %f\n",
					adc4conv0.zero_offset, adc4conv0.invgain);
		printf("New Calibration, zero_offset = %d, invgain = %f\n",
					adc4conv1.zero_offset, adc4conv1.invgain);
		hitwd();
		printf("New Calibration, zero_offset = %d, invgain = %f\n",
					adc4conv2.zero_offset, adc4conv2.invgain);
		printf("New Calibration, zero_offset = %d, invgain = %f\n",
					adc4conv3.zero_offset, adc4conv3.invgain);

		printf("\nHit 's' to store the new calibration constant\n");
		printf("or any key to continue.\n");
		printf("Make sure eeprom is not protected.\n\n");

		while(!kbhit())
		{
			hitwd(); runwatch();
		}

		key = getchar();
		if(key == 's')
		{
			printf("Storing new calibration constants to chans 0 - 3.\n");
			ercode = mgadc4_writecoef(adc4_board, 0, &adc4conv0);
			show_msg(ercode);
			ercode = mgadc4_writecoef(adc4_board, 1, &adc4conv1);
			show_msg(ercode);
			ercode = mgadc4_writecoef(adc4_board, 2, &adc4conv2);
			show_msg(ercode);
			ercode = mgadc4_writecoef(adc4_board, 3, &adc4conv3);
			show_msg(ercode);
		}

		printf("\nReading calibration from ADC4 board's eeprom !!!\n\n");
		hitwd();
		mgadc4_readcoef(adc4_board, 0, &adc4conv0);	// read calibration for chan 0
		mgadc4_readcoef(adc4_board, 1, &adc4conv1);	// read calibration for chan 1
		mgadc4_readcoef(adc4_board, 2, &adc4conv2);	// read calibration for chan 2
		mgadc4_readcoef(adc4_board, 3, &adc4conv3);	// read calibration for chan 3
		
		printf("Hit key to read ADC4 chans 0 - 3 !!!!\n\n");
		for(;;)
		{
			while(!kbhit())			// wait for key from STDIO
			{
				hitwd();	runwatch();         	
			}
			getchar();      			// get the key 
	
			data0 = mgadc4_read(adc4_board,0);   // read A/D channel 0
			data1 = mgadc4_read(adc4_board,1);   // read A/D channel 1
			data2 = mgadc4_read(adc4_board,2);   // read A/D channel 2
			data3 = mgadc4_read(adc4_board,3);   // read A/D channel 3   

			hitwd();
			printf("\nData for the ADC4 channels 0-3 !!!\n");
			printf("chan 0 >> %6d, %8.3f\n", data0, mgadc4_convert(data0, &adc4conv0));
			printf("chan 1 >> %6d, %8.3f\n", data1, mgadc4_convert(data1, &adc4conv1));
			printf("chan 2 >> %6d, %8.3f\n", data2, mgadc4_convert(data2, &adc4conv2));
			printf("chan 3 >> %6d, %8.3f\n", data3, mgadc4_convert(data3, &adc4conv3));
		}
	}  
}

// int get_average(int *data, int count)
// Computes 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);
}

// Decode error code 
int show_msg(int ercode)
{
	switch(ercode)
	{
		case 0:
				printf("Calibration stored to eeprom.\n");
				break;
		case -1:
				printf("ADC4 board not found.\n");
				break;
		case -2:
				printf("Eeprom access failure.\n");
				break;
		case -3:
				printf("Eeprom is write protected.\n");
				break;
	}
}
