/****************************************************************************
adc4smp2.c
	Sample program to read data from an XP8500/ADC4 board on the PLCBUS. Each
	of the first four channels of the XP8500/ADC4 board is read for 20 times
	at ~ 1ms	intervals. The average readings and their voltage equivalents are
	displayed in the STDIO window.
	
	Calibration constants to convert A/D reading to voltages are stored in
	the last 66 bytes ( 6 bytes/channel) of the eeprom of the XP8500/ADC4 board. 

	adc4smp3.c shows how to recalibrate a chan of an XP8500/ADC4 board and how
	to store the calibration constants to the eeprom.
****************************************************************************/

#if (BOARD_TYPE == CPLC_BOARD) || (BOARD_TYPE==L_STAR)
#use cplc.lib
#endif

int get_average(int *buf, int count);
float get_stddev(int *buf, int count);
main()
{
	struct adc4coeff adc4conv0;
	struct adc4coeff adc4conv1;
	struct adc4coeff adc4conv2;
	struct adc4coeff adc4conv3;

	int data0, data1, data2, data3;
	float sig0, sig1, sig2, sig3;
	unsigned int adc4_board;
	unsigned int divider;
		
	int data[20];
	
	int i;      
#if (BOARD_TYPE == CPLC_BOARD) || (BOARD_TYPE==L_STAR)
	uplc_init();
#endif

	reset_pbus();           // reset the plcbus
	reset_pbus_wait();      // wait for reset to end   

	if(sysclock() > 0x1e00)
		reset_pbus_wait();   // for boards faster than 9 Mhz
									// double wait.
									
	// find the first available XP8500/ADC4 Board on the PLCBUS
	for(i=0;i<4;i++)
	{
		if(adc4_init(0x0c0+i))
		{
			adc4_board = 0x0c0 + i;
			break;
		}
	}

	if( i >= 4)
	{
		printf("\nNo XP8500/ADC4 Board is detected !!!\n");
		while(1) runwatch();    // stop here if no board is found.
	}

	printf("\nXP8500/ADC4 board %x has been detected !!!\n", adc4_board);
	printf("\nReading XP8500/ADC4 board calibration constants ...\n");
	
	adc4_readcoeff(adc4_board, 0, &adc4conv0);   // read calibration for chan0
	adc4_readcoeff(adc4_board, 1, &adc4conv1);   // read calibration for chan1
	adc4_readcoeff(adc4_board, 2, &adc4conv2);   // read calibration for chan2
	adc4_readcoeff(adc4_board, 3, &adc4conv3);   // read calibration for chan3

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

	hitwd();
	printf("\nToggle F4 (DOS only) to make keyboard input active as STDIO.\n");
	printf("\nHit any key to read A/D data from XP8500/ADC4 board.\n");

	// get ~1ms sampling period 
	divider = (unsigned int)((0.001 * sysclock() * 1200)/ 20);

	for(;;)
	{
		hitwd();
		while(!kbhit()) {
			runwatch();               // wait for key from the PC
			hitwd();
		}
		getchar();                                // get the key
		adc4_sample(adc4_board, 0, 20, data, divider);  // read chan 0 for 20 samples
		data0 = get_average(data, 20);            // get the average
		sig0  = get_stddev(data, 20);
		adc4_sample(adc4_board, 1, 20, data, divider);  // read chan 1 for 20 samples
		data1 = get_average(data, 20);             // get the average
		sig1 	= get_stddev(data, 20);
		adc4_sample(adc4_board, 2, 20, data, divider);  // read chan 2 for 20 samples
		data2 = get_average(data, 20);            // get the average
		sig2 	= get_stddev(data, 20);
		adc4_sample(adc4_board, 3, 20, data, divider);  // read chan 3 for 20 samples
		data3 = get_average(data, 20);            // get the average
		sig3 	= get_stddev(data, 20);
		// Note: function adc4_sample(...) turns off the interrupt for the whole
		//       duration of data sampling.

		hitwd();
		printf("\nXP8500/ADC4 Channels 0-3.\n");
		printf("Average data, standard deviations, and converted voltages\n");
		printf("chan 0 >> %6d, %6.3f, %8.3f volts\n",
					data0, sig0, adc4_convert(data0, &adc4conv0));
		hitwd();
		printf("chan 1 >> %6d, %6.3f, %8.3f volts\n",
					data1, sig1, adc4_convert(data1, &adc4conv1));
		printf("chan 2 >> %6d, %6.3f, %8.3f volts\n",
					data2, sig2, adc4_convert(data2, &adc4conv2));
		printf("chan 3 >> %6d, %6.3f, %8.3f volts\n",
					data3, sig3, adc4_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)
{
	long sum;
	int i;

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

	if(count == 0) return 0;
	hitwd();	
	return (int) (sum/count);
}
	
		
//float get_stddev(int *data, int count)
//Computes the standard deviation of "count" number of readings for data array.
float get_stddev( int *data, int count)
{
	long	sum;
	long	sigsqr;
	int i;

	sum = sigsqr = 0L;

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

	sum = sum / count;
	
	for(i=0;i<count;i++)
	{
		sigsqr = sigsqr + ( (long)data[i] - sum)*((long)data[i] - sum);
	}
	hitwd();
	if( count == 0) return 0.0;
	return sqrt((float) sigsqr/count);
}
 