/****************************************************************************/
/* Summary  : Test Routines for Dallas DS3234 accurate clock chip	    */
/* Filename : adTest.c                                                      */
/* Author   : Robert Herlien (rah)					    */
/* Project  : BEDS (Benthic Event Detection System)			    */
/* Revision : 1.0							    */
/* Created  : 1/29/2013							    */
/****************************************************************************/
/* Modification History:						    */
/* 29jan2013 rah - created						    */
/****************************************************************************/

#include <mbariTypes.h>
#include <mbariConst.h>
#include <cfxpico.h>			/* Persistor PicoDOS definitions    */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <cfxad.h>			/* Generic SPI A-D QPB Driver for CFx*/
#include <ADS8344.h>			/* Support for ADS8344 A/D chip	    */
#include <adc.h>

#define ADSLOT		NMPCS3		/* SPI slot for ADC		    */
#define AVG_DELAY	1000

#define NumberOf(arr)		((sizeof(arr) / sizeof(arr[0])))


/********************************/
/*	Global Data		*/
/********************************/

const char * const	signon = "Analog test program for BEDS board\n\n";

MLocal MBool	sensorPwr = TRUE;
MLocal ushort	avg = 1;

static CFxAD	adbuf, *ad;

void		readAnalog(ushort);
void		repeatReadAnalog(void);
void		readAllAnalog(void);
void		readAnalogN(void);


/************************************************************************/
/* Function    : main							*/
/* Purpose     : Main entry point					*/
/* Inputs      : None							*/
/* Outputs     : None							*/
/* Comments    : Never returns						*/
/************************************************************************/
int main( void )
{
    ushort	c;

	// Identify the progam and build
    printf("\nProgram: %s: %s %s \n", __FILE__, __DATE__, __TIME__);
	// Identify the device and its firmware
    cprintf("Persistor CF%d SN:%ld   BIOS:%d.%d   PicoDOS:%d.%d\n", CFX,
	    BIOSGVT.CFxSerNum, BIOSGVT.BIOSVersion, BIOSGVT.BIOSRelease, 
	    BIOSGVT.PICOVersion, BIOSGVT.PICORelease);

    TMGSetSpeed(16000);

    cprintf("Delay loop constants - 1us %u, 10us %u, 1ms %u\n",
	    BIOSGVT.LoopDelay1us, BIOSGVT.LoopDelay10us,
	    BIOSGVT.LoopDelay1ms);

    cprintf(signon);

    PIOSet(TPU1);			// ADC /ShDn
    PIOSet(TPU2);			// MPU power
    PIOSet(TPU3);			// Sensor power
    PIOClear(TPU4);			// Modem power
    PIORead(TPU6);			// MPU IRQ
    PIOClear(TPU8);			// Turn off Aux Tx
    PIOSet(TPU9);			// Disable Aux Rx
    PIORead(TPU12);			// Aux Rx
    
    if ((ad = CFxADInit(&adbuf, ADSLOT, ADS8344Init)) == NULL)
	    cprintf("Warning!! - Failed to initialize A/D converter!!!\n");

    CFxADSample(ad, 0, TRUE, TRUE, FALSE);

    while(TRUE)
    {
	printf("\n");
	printf("\nType 0-7 to read A/D channel 0-7\n");
	printf("       8 to read all A/D channels via sampleBlock\n");
	printf("       C to continuously sample an A/D channel\n");
	printf("       N to read one A/D channel multiple times\n");
	printf("       P to turn %s power to the sensors\n", sensorPwr ? "OFF" : "ON");
	printf("       A to set number of samples to average (currently %hu)\n", avg);
	printf("       X to exit program\n");

	c = cgetc();

	if ((c >= '0') && (c <= '7'))
	    readAnalog(c - '0');
	else switch(c)
	{
	  case '8':
	      readAllAnalog();
	      break;

	  case 'c':
	  case 'C':
	      repeatReadAnalog();
	      break;

	  case 'n':
	  case 'N':
	      readAnalogN();
	      break;

	  case 'p':
	  case 'P':
	      sensorPwr = ! sensorPwr;
	      if (sensorPwr)
		  PIOSet(TPU3);
	      else
		  PIOClear(TPU3);
	      break;

	  case 'a':
	  case 'A':
	      QRshort("\nSamples to average (1 - 1000)):  ", "%hu",
		      FALSE, &avg, 1, 1000);
	      break;

	  case 'x':
	  case 'X':
	      return(0);
	}

    }

    return(0);
			      
} /* main() */


/************************************************************************/
/* Function    : readAnalog						*/
/* Purpose     : Read an analog channel					*/
/* Inputs      : Channel number						*/
/* Outputs     : None							*/
/************************************************************************/
void readAnalog(ushort chan)
{
    ushort	i, ival;
    ulong	accum = 0L;
    Flt32	fval;
    char	*units;

    for (i = 0; i < avg; i++)
    {
	accum += CFxADSample(ad, chan, TRUE, TRUE, FALSE);
	RTCDelayMicroSeconds(AVG_DELAY);
    }

    ival = accum/avg;
    fval = adcEngValue(chan, ival, &units);

    printf("\nChannel %hd  %hu counts  %5.3f VDC  %5.3f %s\n", chan, ival,
	   RAW_TO_VOLTS(ival), fval, units);

    printf("\n");
    
}   /* readAnalog() */


/************************************************************************/
/* Function    : readAllAnalog						*/
/* Purpose     : Read an analog channel					*/
/* Inputs      : None							*/
/* Outputs     : None							*/
/************************************************************************/
void readAllAnalog(void)
{
    ushort	i, j, ival;
    ushort	*result;
    Flt32	fval;
    ulong	accum[8];
    char	*units;

    for (i = 0; i < 8; i++)
	accum[i] = 0;

    for (i = 0; i < avg; i++)
    {
	result = CFxADSampleBlock(ad, 0, 8, NULL, TRUE, TRUE, FALSE);
	for (j = 0; j < 8; j++)
	    accum[j] += result[j];
	RTCDelayMicroSeconds(AVG_DELAY);
    }

    printf("\n");

    for (i = 0; i < 8; i++)
    {
	ival = accum[i]/avg;
	fval = adcEngValue(i, ival, &units);

	printf("\nChannel %hd  %5hu counts  %5.3f VDC  %5.3f %s\n", i, ival,
	       RAW_TO_VOLTS(ival), fval, units);
    }

}   /* readAllAnalog() */


/************************************************************************/
/* Function    : repeatReadAnalog					*/
/* Purpose     : Continuously read analog channel			*/
/* Inputs      : None							*/
/* Outputs     : None							*/
/************************************************************************/
void repeatReadAnalog(Void)
{
    short	chan;

    if (!QRshort("\nAnalog channel to read (0 to 7):  ", "%hd", FALSE, &chan, 0, 7))
	return;

    printf("\n\nContinuously reading channel %hd.  Type any key to stop\n", chan);

    while (!kbhit())
    {
	CFxADSample(ad, chan, TRUE, TRUE, FALSE);
	RTCDelayMicroSeconds(AVG_DELAY);
    }

}   /* repeatReadAnalog() */


/************************************************************************/
/* Function    : readAnalogN						*/
/* Purpose     : Read one analog channel N times			*/
/* Inputs      : None							*/
/* Outputs     : None							*/
/************************************************************************/
void readAnalogN(Void)
{
    ushort	chan, nReads, i;
    Nat16	*buf, *p, min, max;
    Nat32	accum;
    Flt32	fval;
    double	avg, stdaccum, diff;
    char	*units;

    if (!QRshort("\nAnalog channel to read (0 to 7):  ", "%hu", FALSE, &chan, 0, 7))
	return;

    if (!QRshort("\nNumber of samples to read(1 to 10000):  ", "%hu",
		 FALSE, &nReads, 1, 10000))
	return;

    CFxADSample(ad, chan, TRUE, TRUE, FALSE);

    if ((buf = malloc(nReads * sizeof(Nat16))) == NULL)
    {
	printf("Could not malloc read buffer.\n");
	return;
    }

    printf("\n");
    min = NAT16_MAX;
    max = 0;
    accum = 0;

    for (i = 0, p = buf; i < nReads; i++, p++)
    {
	*p = CFxADSample(ad, chan, TRUE, TRUE, FALSE);
	accum += *p;
	if (*p < min)
	    min = *p;
	if (*p > max)
	    max = *p;
	RTCDelayMicroSeconds(AVG_DELAY);
    }

    if (nReads <= 100)
	for (i = 0, p = buf; i < nReads; i++, p++)
	{
	    fval = adcEngValue(chan, *p, &units);
	    printf("\n%5hu counts  %5.3f VDC  %5.3f %s\n",
		   *p, RAW_TO_VOLTS(*p), fval, units);
	}

    avg = (double)accum / (double)nReads;
    fval = adcEngValue(chan, avg, &units);
    stdaccum = 0.0;

    for (i = 0, p = buf; i < nReads; i++, p++)
    {
	diff = (double)(*p) - avg;
	stdaccum += (diff * diff);
    }

    if (nReads > 1)
	printf("\nAvg %.2f (%.2f VDC, %.2f %s)  Min %hu  Max %hu  Std Dev %.2f counts\n",
	       avg, RAW_TO_VOLTS(avg), fval, units, min, max,	
	       sqrt(stdaccum / (double)(nReads-1)));

    free(buf);

}   /* repeatReadAnalog() */
