AD7124 Development

From HiveTool
Revision as of 03:49, 29 January 2018 by Paul (talk | contribs)
Jump to: navigation, search
/*
 * Hivetool AD7124 driver
 * 
 * To compile with the PIGPIO libraries
 *  gcc  -pthread -o AD7124 ad7124PIGPIO.c  -lpigpiod_if2 -lrt
 * 
 *
 * AD7124 --pm=LOW  --fs=120 --verbose=9 --aip=1 --aim=2 --gain=7
 * 
 * 
 */

#include <stdio.h>
#include <time.h>
#include <unistd.h>                    // usleep
#include <getopt.h>
#include <string.h>                    // strcasecmp
#include <stdlib.h>                    // strtol
#include <pigpiod_if2.h>               // PIGPIO libraries
#include <errno.h>                     // PIGPIO 

/**************************** printf byte to binary converter *************************************
 * https://stackoverflow.com/questions/111928/is-there-a-printf-converter-to-print-in-binary-format
 * ***********************************************************************************************/

#define BYTE_TO_BINARY_PATTERN "%c%c%c%c%c%c%c%c"
#define BYTE_TO_BINARY(byte)  \
  (byte & 0x80 ? '1' : '0'), \
  (byte & 0x40 ? '1' : '0'), \
  (byte & 0x20 ? '1' : '0'), \
  (byte & 0x10 ? '1' : '0'), \
  (byte & 0x08 ? '1' : '0'), \
  (byte & 0x04 ? '1' : '0'), \
  (byte & 0x02 ? '1' : '0'), \
  (byte & 0x01 ? '1' : '0') 

int  initialize( void );                     /* set BCM2835 SPI parameters, reset the AD7124, read ID and Status registers */
void setup( void );                          /* setup the AD7124 configuration registers */
void read_registers(void);                   /* read and dump the AD7124 registers */
char wait_for_ready(void);                   /* wait for conversion by polling the AD7124 Status register */
int  median_select(int arr[], int n);        /* select the median from the data array */
int  get_options(int argc, char **argv);     /* read the command line options */
int  convert_options(void);                  /* convert the command line option integers to hex bytes */
void print_help(void);                       /* display usage when invoked with the --help argument */

enum { LOW_POWER=0x00, MEDIUM_POWER=0x40, HIGH_POWER=0x80 } power_mode = HIGH_POWER;

int pi = 0;
int spi_handle = 0;
int number_active_channels = 1;
int number_of_filtered_samples = 0;

int data_array[64];

/* command line argument defaults */
int  number_of_samples = 64;                        /*  Number of data reads to average */
int  verbose = 0;
char FS[2] = { 0x01, 0x40 };                        /*  Filter Select (FS) default: 320 */
char PGA   = 0x07;                                  /*  PGA default: 128                */
char AINM  = 0x06;                                  /*  Negative analog input: 6 */
char AINP  = 0x07;                                  /*  Positive analog input: 7 */


int main(int argc, char **argv)
{
int i = 0; 
int j = 0;
int sum = 0;
int sample_counter = 0;
int read_counter = 0;

int data_register=0;
int return_code = 0;

char wrBuf[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
char rdBuf[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
time_t t;

/* Read the command line arguments */
get_options(argc, argv);    

/* connect to the local PIGPIO daemon  */
pi = pigpio_start(NULL, NULL);                        
if (pi < 0) {
  fprintf (stderr, "Unable to connect to pigpiod: %s\n", strerror (errno));
  return 1;
  }

spi_handle = spi_open( pi, 0, 4194304, 0x000003 );

if (spi_handle < 0) {
  fprintf (stderr, "Unable to open SPI device: %s\n", strerror (errno));
  fprintf (stderr, "Unable to open SPI device: %x\n", spi_handle);
  return 2;
  }

/* Initialize the SPI interface and reset the AD7124 */
return_code = initialize();
if ( verbose > 7 ) printf("initialize routine return value: %d\n",return_code);
  
if ( return_code )
   {
   printf("ERROR! Initialization failed code %d. Is the AD7124 connected and powered?\n", return_code);
   return return_code;
   }
   
/* Set up the registers on the AD7124  */
setup();

/* turn on load cell excitation using PDSW Power Down Switch  */
wrBuf[0]= 0x03; wrBuf[1]= 0x00; wrBuf[2]= 0x80; wrBuf[3]= 0x00;
spi_xfer(pi, spi_handle, wrBuf, rdBuf, 4);

  
/* start data conversion, Continuous conversion mode 00 0084  ADC Control  High power, Mode 0*/
wrBuf[0]= 0x01; wrBuf[1]= 0x06; wrBuf[2]= power_mode;    
spi_xfer(pi, spi_handle, wrBuf, rdBuf, 3);

if ( verbose > 6 )
  {
  printf("Write ADC Control: %02x %02x "BYTE_TO_BINARY_PATTERN"  "BYTE_TO_BINARY_PATTERN"\n", wrBuf[1],wrBuf[2],BYTE_TO_BINARY(wrBuf[1]),BYTE_TO_BINARY(wrBuf[2]));
  }
  
wrBuf[0]= 0x41; wrBuf[1]= 0x00; wrBuf[2]= 0x00;  
spi_xfer(pi, spi_handle, wrBuf, rdBuf, 3);

if ( verbose > 6 )
  {
  printf("Read ADC Control:  %02x %02x "BYTE_TO_BINARY_PATTERN"  "BYTE_TO_BINARY_PATTERN"\nBeginning continuous conversions\n", rdBuf[1],rdBuf[2],BYTE_TO_BINARY(rdBuf[1]),BYTE_TO_BINARY(rdBuf[2]));
  }


    time(&t);
//    printf(" %s",ctime(&t));

sum=0;
sample_counter=0;
read_counter = 0;

while ( read_counter < 128 && sample_counter < number_of_samples )
  {  
  for ( i=0; i< number_active_channels; i++ ) 
    {  
    if ( !wait_for_ready() )
       {
	/* Read the data register  */
        wrBuf[0]= 0x42; 
        spi_xfer(pi, spi_handle, wrBuf, rdBuf, 5);
     
        data_register = (rdBuf[1] << 16) | (rdBuf[2] << 8) | (rdBuf[3]); 
    
        if ( verbose > 8 ) { printf("Data: %d %02x%02x%02x  Status: %02X ",data_register, rdBuf[1],rdBuf[2],rdBuf[3],rdBuf[4]); }

        /* Read the error register */
        wrBuf[0]= 0x46;
        spi_xfer(pi, spi_handle, wrBuf, rdBuf, 4);

        if ( verbose > 8 )
	   { 
           time(&t);	    
	   printf(" Error: %02X %02X %02X "BYTE_TO_BINARY_PATTERN"  "BYTE_TO_BINARY_PATTERN"  "BYTE_TO_BINARY_PATTERN"  %s", rdBuf[1],rdBuf[2],rdBuf[3],BYTE_TO_BINARY(rdBuf[1]),BYTE_TO_BINARY(rdBuf[2]),BYTE_TO_BINARY(rdBuf[3]) ,ctime(&t));
           } 

	/* Check for errors  */

if ( (rdBuf[1] | rdBuf[2] | rdBuf[3]) == 0 ) /* if no errors, use data to calculate average */

          {
	   data_array[sample_counter] = data_register;
          sum += data_register;
          sample_counter++;
          }
       }
   } 
// read_registers();  
  read_counter++;
  }

/* turn off load cell excitation using PDSW Power Down Switch  */
wrBuf[0]= 0x03; wrBuf[1]= 0x00; wrBuf[2]= 0x00; wrBuf[3]= 0x00;
spi_xfer(pi, spi_handle, wrBuf, rdBuf, 4);

if (sample_counter == 0)  return 5;
number_of_filtered_samples = sample_counter;

if (sample_counter > 1 )
   {
   /* calculate raw average */ 
   int raw_average = sum/sample_counter;

   /* calculate median */
   int median = median_select( data_array, sample_counter );

   printf("AD7124test Raw Average: %10d Median: %10d  Number of samples: %4d  Number of errors:  %3d  %s", raw_average, median,sample_counter, (read_counter - sample_counter), ctime(&t) );
   //     printf(" %s",ctime(&t));

   sum = 0;
   number_of_filtered_samples = 0;

   /* set limits for outliers  */
//   int high_limit = median * 1.00002;
//   int low_limit = median * .99998;
   int high_limit = median * 1.0002;
   int low_limit = median * .9998;

// printf("high_limit:  %10d low_limit: %10d\n", high_limit, low_limit );


/* Test for outliers and throw them away */

   for ( j=0; j<sample_counter; j++ )
       {
       if ( data_array[j] < high_limit && data_array[j] > low_limit ) 
         {
         number_of_filtered_samples++;
        sum += data_array[j]; 
        //    printf ("data_array: %d less median: %d\n", data_array[j], data_array[j] - median);
        }
 //  else 
 //    printf ("OUTLIER     %d less median: %d\n", data_array[j], data_array[j] - median);
      }

  if (number_of_filtered_samples == 0)  return 6;

  /* calculate raw average */ 
  int filtered_average = sum/number_of_filtered_samples;

  printf("AD7124test Filtered Avg:%10d Median: %10d  Number of samples: %4d  Number  Outliers:  %3d  %s", filtered_average, median, number_of_filtered_samples, (sample_counter - number_of_filtered_samples),  ctime(&t) );
  //     printf(" %s",ctime(&t));
  }
//printf("Weight: %7.3f\n",  0.000536331066441 * ( ( (sum/number_of_filtered_samples)/10 ) - 855362)  );
//printf("Weight: %7.3f\n",  0.00000868891 * ( ( (sum/number_of_filtered_samples) ) - 73.10472780232)  );
printf("Weight: %7.3f\n",  (0.0003438388 *  (sum/number_of_filtered_samples))  - 2892.912  );
spi_close(pi, spi_handle);

return 0;
}

/* *********************** initialize **********************************
 * 
 * set the BCM2835 SPi parameters
 * Reset AD7124
 * check for AD7124 by reading ID register 5 (ID 14)
 * Read Status Register
 * 
 * 
 ***********************************************************************/

int initialize ( void )
 {
 char wrBuf[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
 char rdBuf[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
 
/* Reset the AD7124 by sending 64 ones */
 spi_write(pi, spi_handle,wrBuf, 8);                   
//   printf("Sent 64 ones to reset\n");
 usleep(1000);                                         /* Wait for the reset to complete */

 wrBuf[0]= 0x45;                        /* check for AD7124 by reading ID register 5 (ID 14) */
 spi_xfer(pi, spi_handle, wrBuf, rdBuf, 2);   

 if (verbose > 6)  printf("initialize()  ID register: %02X\n",rdBuf[1]);
 if ( rdBuf[1] != 0x14 ) 
    { 
    printf("AD7124 reset failed. Bad ID: %02X\n", rdBuf[1]);
    return 3;
    }
    
 /* Read Status Register */
 wrBuf[0]= 0x40;                       
 spi_xfer(pi, spi_handle, wrBuf, rdBuf, 2);

if (verbose > 6)    printf("initialize() Status register: %02X\n",rdBuf[1]);

/* Read Status Register again to clear Power reset bit */
  wrBuf[0]= 0x40; 
  spi_xfer(pi, spi_handle, wrBuf, rdBuf, 2);

  if (verbose > 6)  printf("initialize() Status register: %02X\n",rdBuf[1]);
 
  if ( rdBuf[1] != 0x80 ) 
     {  
     printf("AD7124 reset failed. Bad Status: %02X \n", rdBuf[1]);
     return 4;
     }
     
 return 0;
 }
 
 
/* ************************** setup ************************************
 * 
 * Maybe add an external conf file that sets up the ADC registers?
 * 
 ***********************************************************************/
 
void setup ( void )
 {

char wrBuf[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
char rdBuf[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

wrBuf[0]= 0x09; wrBuf[1]= 0x00; wrBuf[2]= 0x01;                        /* Turn off channel_0 (on by default) */
spi_xfer(pi, spi_handle, wrBuf, rdBuf, 3);
//wrBuf[1] = ( AIMP & 0x18 ) >> 3 ;
wrBuf[0]= 0x0a;
wrBuf[1] = (( AINP >> 3) & 0x07 ) | 0x80;
wrBuf[2] = (( AINP & 0x07 ) << 5) | ( AINM & 0x1F );

spi_xfer(pi, spi_handle, wrBuf, rdBuf, 3);

wrBuf[0]= 0x19; wrBuf[1]= 0x08; wrBuf[2]= 0x7F;
spi_xfer(pi, spi_handle, wrBuf, rdBuf, 3);

wrBuf[0]= 0x21; wrBuf[1]= 0x06; wrBuf[2]= FS[0]; wrBuf[3]= FS[1];       /* Set the Filter Select bits             */
spi_xfer(pi, spi_handle, wrBuf, rdBuf, 4);

wrBuf[0]= 0x07; wrBuf[1]= 0x03; wrBuf[2]= 0xF0; wrBuf[3]= 0x38;
spi_xfer(pi, spi_handle, wrBuf, rdBuf, 4);
if ( verbose > 6 )
  {
  read_registers();                // This sets the number_active_channels (default = 1)
  }
}
 
/* ************************ read_registers *****************************
 * 
 * Read and dump most of the AD7124-8 registers
 * 
 ***********************************************************************/

void read_registers(void)
{
 int i;
 char wrBuf[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
 char rdBuf[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

      wrBuf[0]= 0x46;
      spi_xfer(pi, spi_handle, wrBuf, rdBuf, 4);
      printf("%02X Error     : %02X %02X %02X "BYTE_TO_BINARY_PATTERN"  "BYTE_TO_BINARY_PATTERN"  "BYTE_TO_BINARY_PATTERN"\n", 0x06,rdBuf[1],rdBuf[2],rdBuf[3],BYTE_TO_BINARY(rdBuf[1]),BYTE_TO_BINARY(rdBuf[2]),BYTE_TO_BINARY(rdBuf[3]));

      wrBuf[0]= 0x47;
      spi_xfer(pi, spi_handle, wrBuf, rdBuf, 4);
      printf("%02X Error Enab: %02X %02X %02X "BYTE_TO_BINARY_PATTERN"  "BYTE_TO_BINARY_PATTERN"  "BYTE_TO_BINARY_PATTERN"\n", 0x07,rdBuf[1],rdBuf[2],rdBuf[3],BYTE_TO_BINARY(rdBuf[1]),BYTE_TO_BINARY(rdBuf[2]),BYTE_TO_BINARY(rdBuf[3]));
 
  number_active_channels=0;
  for ( i = 0x49; i< 0x59; i++ )                                   /* Read Channel Registers */
      {
      wrBuf[0]= i;
      spi_xfer(pi, spi_handle, wrBuf, rdBuf, 3);
  
      /* Test for active channels and count them */  
      if ( rdBuf[1] & 0x80 )  { number_active_channels++; }        
      printf("%02X Channel %2d: %02x %02x "BYTE_TO_BINARY_PATTERN"  "BYTE_TO_BINARY_PATTERN"\n",i-0x40, (i-0x49),rdBuf[1],rdBuf[2],BYTE_TO_BINARY(rdBuf[1]),BYTE_TO_BINARY(rdBuf[2]));
      }
  printf("Number of active channels: %d\n", number_active_channels);
   
 for ( i = 0x59; i< 0x61; i++ )                                   /* Read Configuration Registers */
     {
     wrBuf[0]= i;
     spi_xfer(pi, spi_handle, wrBuf, rdBuf, 3);
     printf("%02X Config  %2d: %02X %02X "BYTE_TO_BINARY_PATTERN"  "BYTE_TO_BINARY_PATTERN"\n", i-0x40, (i-0x59),rdBuf[1],rdBuf[2],BYTE_TO_BINARY(rdBuf[1]),BYTE_TO_BINARY(rdBuf[2]));
     }
 for ( i = 0x61; i< 0x69; i++ )                                   /* Read Configuration Registers */
     {
     wrBuf[0]= i;
     spi_xfer(pi, spi_handle, wrBuf, rdBuf, 4);
     printf("%02X Filter  %2d: %02X %02X %02X "BYTE_TO_BINARY_PATTERN"  "BYTE_TO_BINARY_PATTERN"  "BYTE_TO_BINARY_PATTERN"\n", i-0x40, (i-0x61),rdBuf[1],rdBuf[2],rdBuf[3],BYTE_TO_BINARY(rdBuf[1]),BYTE_TO_BINARY(rdBuf[2]),BYTE_TO_BINARY(rdBuf[3]));
     }  

}

/************************* wait_for_ready  *********************************
 *
 *   This routine spins in a loop waiting until either:
 *   1, The conversion is complete ~RDY bit goes low (data is written to the Data Register)
 *   2. We time out and give up
 * 
 *   WARNING: This routine is senstive to the SPI clock speed.
 *   Low clock speeds can cause delays much greater than 0.1 miliseconds each pass.
 * 
 ***************************************************************************/


char wait_for_ready(void)
{
char wrBuf[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
char rdBuf[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
unsigned int waiting=10000;
char busy = 1;

while( busy && waiting )
  {
  /* Read the Status Register */
  wrBuf[0]= 0x40;
  spi_xfer(pi, spi_handle, wrBuf, rdBuf, 2);  
  busy = rdBuf[1] & 0x80 ;                      /* Test the Not Ready bit */
//  printf("Busy: %X  timeout: %d\n", busy, (1000-timeout) );
  
  usleep(100);                                /* wait 0.1 msec */
  waiting--;
  }
  return busy;
}




/************************* median_select  *********************************
 *
 *      from http://ndevilla.free.fr/median/median/
 *  This Quickselect routine is based on the algorithm described in
 *  "Numerical recipes in C", Second Edition,
 *  Cambridge University Press, 1992, Section 8.5, ISBN 0-521-43108-5
 *  This code by Nicolas Devillard - 1998. Public domain.
 *
 ***************************************************************************/

#define ELEM_SWAP(a,b) { register int t=(a);(a)=(b);(b)=t; }

int median_select(int arr[], int n) 
{
    int low, high;
    int median;
    int middle, ll, hh;

    low = 0 ; high = n-1 ; median = (low + high) / 2;
    
    for (;;) {
        if (high <= low) /* One element only */
            return arr[median];

        if (high == low + 1) {  /* Two elements only */
            if (arr[low] > arr[high]) ELEM_SWAP(arr[low], arr[high]);
            return arr[median];
            }

    /* Find median of low, middle and high items; swap into position low */
    middle = (low + high) / 2;
    if (arr[middle] > arr[high])    ELEM_SWAP(arr[middle], arr[high]);
    if (arr[low] > arr[high])       ELEM_SWAP(arr[low], arr[high]);
    if (arr[middle] > arr[low])     ELEM_SWAP(arr[middle], arr[low]);

    /* Swap low item (now in position middle) into position (low+1) */
    ELEM_SWAP(arr[middle], arr[low+1]);

    /* Nibble from each end towards middle, swapping items when stuck */
    ll = low + 1;
    hh = high;
    for (;;) {
        do ll++; while (arr[low] > arr[ll]);
        do hh--; while (arr[hh]  > arr[low]);

        if (hh < ll)
        break;

        ELEM_SWAP(arr[ll], arr[hh]);
        }

   /* Swap middle item (in position low) back into correct position */
   ELEM_SWAP(arr[low], arr[hh]);

   /* Re-set active partition */
   if (hh <= median) low = ll;
   if (hh >= median) high = hh - 1;
   }
}

#undef ELEM_SWAP


/****************************** get_options *********************************************************************
 * 
 * https://www.gnu.org/software/libc/manual/html_node/Getopt-Long-Option-Example.html#Getopt-Long-Option-Example
 * https://stackoverflow.com/questions/3792663/atol-v-s-strtol
 * 
 ***************************************************************************************************************/

int get_options (int argc, char **argv)
{
  int short_option;
  char* end;
  
  int  filter_select = 0;
  int  positive_analog_input = 0;
  int  negative_analog_input = 0;
  int  programable_gain = 0;
  
  while (1)
    {
      static struct option long_options[] =
        {
          /* These options set a flag. */
//          {"brief",   no_argument,       &verbose_flag, 0},
          /* These options don?t set a flag.
             We distinguish them by their indices. */
          {"aip",     required_argument, 0, 'p'},
          {"aim",     required_argument, 0, 'm'},
          {"fs",      required_argument, 0, 'f'},
          {"gain",    required_argument, 0, 'g'},
          {"help",    no_argument,       0, 'h'},
          {"samples", required_argument, 0, 'n'},
          {"power",   required_argument, 0, 'w'},
          {"verbose", required_argument, 0, 'v'},
          {0, 0, 0, 0}
        };
      /* getopt_long stores the option index here. */
     int option_index = 0;

     short_option = getopt_long (argc, argv, "n:p:m:f:g:hw:v:",
                      long_options, &option_index);

     /* Detect the end of the options. */
     if (short_option == -1)
       break;

     switch (short_option)
       {
       case 0:
         /* If this option set a flag, do nothing else now. */
         if (long_options[option_index].flag != 0)
           break;
         printf ("option %s", long_options[option_index].name);
         if (optarg)
           printf (" with arg %s", optarg);
         printf ("\n");
         break;

       case 'f':
	  filter_select = strtol(optarg, &end, 10);
	  if (*end)
	     {
	     printf ("ERROR! Filter Select (FS) argument numeric conversion failed, non-numeric part: %s\n", end);
	     exit(-3);  
	     }
	  if ( filter_select > 2047 || filter_select < 1 ) 
	     {
	     printf ("ERROR! Filter Select (FS) argument out of range (1-2047): %d\n", filter_select);	     
	     exit(-1);
	     }
	  FS[0] = filter_select & 0xFF;
	  FS[1] = (filter_select >> 8 ) & 0xFF;
	 
         if ( verbose > 4 ) printf ("Command line option Filter Select (--fs or -f) has value %d converted to %02X %02X \n", filter_select, FS[1], FS[0]);
	  
	  
         break;

	case 'g':
	  programable_gain = strtol(optarg, &end, 10);
	  if (*end)
	     {
	     printf ("ERROR! Programable Gain Amplifier (PGA) argument numeric conversion failed, non-numeric part: %s\n", end);
	     exit(-3);  
	     }
	  if ( programable_gain > 7 || programable_gain < 0 ) 
	     {
	     printf ("ERROR! Programable Gain Amplifier (PGA) argument out of range (0-7): %d\n", programable_gain);	     
	     exit(-1);
	     }
	  PGA = programable_gain & 0x07;
	  
         if ( verbose > 4 ) printf ("Command line option Programable Gain Amplifer (--gain or -g) has value %d converted to %02X\n", programable_gain, PGA);
         break;

//	case '?':
	case 'h':
         print_help();
	  exit(0);
	  break;

	  
       case 'm':
	  negative_analog_input = strtol(optarg, &end, 10);
	  if (*end)
	     {
	     printf ("ERROR! Analog INput Minus (AINM) argument numeric conversion failed, non-numeric part: %s\n", end);
	     exit(-3);  
	     }
	  if ( negative_analog_input > 31 || negative_analog_input < 0 ) 
	     {
	     printf ("ERROR! Analog INput Minus (AINM) argument out of range (0-31): %d\n", negative_analog_input);	     
	     exit(-1);
	     }
	  AINM = 0x1F & negative_analog_input;
	  
         if ( verbose > 4 ) printf ("Command line option Analog INput Minus (AINM) (--aim or -m) has value %d converted to %02X\n", negative_analog_input, AINM);
         break;

       case 'n':
	  number_of_samples = strtol(optarg, &end, 10);
	  if (*end)
	     {
	     printf ("ERROR! Analog INput Minus (AINM) argument numeric conversion failed, non-numeric part: %s\n", end);
	     exit(-3);  
	     }
	  if ( number_of_samples > 64 || number_of_samples < 1 ) 
	     {
	     printf ("ERROR! Number of samples argument out of range (0-31): %d\n", number_of_samples);	     
	     exit(-1);
	     }
	  	  
          if ( verbose > 4 ) printf ("Command line option Number of samples (--samples or -n) has value %d\n", number_of_samples);
          break; 

	  
       case 'p':
	  positive_analog_input = strtol(optarg, &end, 10);
	  if (*end)
	     {
	     printf ("ERROR! Analog INput Plus (AINP) argument numeric conversion failed, non-numeric part: %s\n", end);
	     exit(-3);  
	     }
	  if ( positive_analog_input > 31 || positive_analog_input < 0 ) 
	     {
	     printf ("ERROR! Analog INput Plus (AINP) argument out of range (0-31): %d\n", positive_analog_input);	     
	     exit(-1);
	     }
	  AINP = 0x1F & positive_analog_input;
	     
         if ( verbose > 4 ) printf ("Command line option Analog INput Plus (AINP) (--aip or -p) has value %d converted to %02X\n", positive_analog_input, AINP);
         break;
	  
	case 'w':
	  if ( strcasecmp( optarg, "LOW") == 0 ) { power_mode = LOW_POWER; }
	  else if ( strcasecmp( optarg, "MEDIUM") == 0 ) { power_mode = MEDIUM_POWER; }
	  else if ( strcasecmp( optarg, "HIGH") == 0 ) { power_mode = HIGH_POWER; }
	  else { printf ("ERROR! Expecting --power(-w) [low|LOW|medium|MEDIUM|high|HIGH] found %s\n", optarg); 
	         exit(-2);
	       }
	  break;

       case 'v':
//	  verbose = 1;
//	  if ( optarg )
//	  {
	  verbose = strtol(optarg, &end, 10);
	  if (*end)
	     {
	     printf ("ERROR! Verbose argument numeric conversion failed, non-numeric part: %s\n", end);
	     exit(-3);  
	     }
	  if ( verbose > 9 || verbose < 0 ) 
	     {
	     printf ("ERROR! Verbose argument out of range (0-9): %d\n", verbose);	     
	     exit(-1);
	     }
//	  }   
         if ( verbose > 4 ) printf ("Command line option Verbose (--verbose or -v) with value %d\n", verbose);
         break;

       case '?':
         /* getopt_long already printed an error message. */
	  exit(-5);
         break;

       default:
         abort ();
       }
       
       
       
       
   }

 /* Instead of reporting ?--verbose?
    and ?--brief? as they are encountered,
    we report the final status resulting from them. */
//  if (verbose_flag)
//    puts ("verbose flag is set");

 /* Print any remaining command line arguments (not options). */
 if (optind < argc)
   {
     printf ("non-option ARGV-elements: ");
     while (optind < argc)
       printf ("%s ", argv[optind++]);
     putchar ('\n');
   }

 return (0);
}

/* *********************** print_help **********************************
 * 
 * Prints usage information - some of this could go in a man page
 * 
 ***********************************************************************/

void print_help(void)
{
 printf (
  "Usage: ad7124 [OPTION...]\n\n"
  "  -f, --fs=FS   0 < FS < 2048\n"
  "       Sets the output data rate of the sinc3, sinc4 and fast settling filters, affects the\n"
  "       position of the first notch, the cutoff frequency of the sinc filter, the output noise\n"
  "       and effective resolution\n"
  "\n"
  "  -g, --gain=GAIN\n"
  "       Sets PGA stage gain:\n"
  "       GAIN gain Input Voltage Range\n"
  "        0    1    +/-2.5 V\n"
  "        1    2    +/-1.25 V\n"
  "        2    4    +/-625 mV\n"
  "        3    8    +/-312.5 mV\n"
  "        4    16   +/-156.25 mV\n"
  "        5    32   +/-78.125 mV\n"
  "        6    64   +/-39.06 mV\n"
  "        7    128  +/-19.53 mV\n"
  "\n"
  "  -m, --aim=AIM\n"
  "       AIM selects which input is multiplexed to the ADC negative input where:\n"
  "       AIM  AINM\n"
  "        0   AIN0\n"
  "        1   AIN1\n"
  "        2   AIN2\n"
  "        3   AIN3\n"
  "        4   AIN4\n"
  "        5   AIN5\n"
  "        6   AIN6\n"
  "        7   AIN7\n"
  "        8   AIN8\n"
  "        9   AIN9\n"
  "        10  AIN10\n"
  "        11  AIN11\n"
  "        12  AIN12\n"
  "        13  AIN13\n"
  "        14  AIN14\n"
  "        15  AIN15\n"
  "        16  temperature sensor\n"
  "        17  AVSS\n"
  "        18  internal reference\n"
  "        19  DGND\n"
  "\n"	    
  "  -n, --samples=N\n"
  "        N sets the number of samples that are read and averaged.  0 < N < 65\n"
  "        If N > 1, the samples are read as quickly as possible with no delay between samples.\n"
  "\n"	    
  "  -p, --aip=AIP\n"
  "       AIP selects which input is multiplexed to the ADC positive input. AIP is the same as\n"
  "        AIM in the -m,--aim option.\n"
  "\n"
  "Examples:\n\n"
  "\n"
  "\n"
  "Application Notes:\n"
  "\n"
  "This program is designed to run on the Raspberry Pi and interface to the Analog Devices AD7124-8 Evaluation Board\n"
  "EVAL-AD7124-8SDZ via the 4 wire SPI interface.  No other MCU, including the EVAL-SDP-CB1Z System Demonstration Platform\n" 
  "(SDP) board, is necessary.  The Pi is operated as the Master, the AD7124 is the Slave.\n"
  "\n"  
  "Wiring:\n"
  "Connect:\n"
  "   Raspberry Pi Header J8                       EVAL-AD7124-8SDZ\n"  
  "     Signal        Pin Number                Signal       Pin Number\n"
  " GPIO 12 SPI0 MOSI   19                       DI         TDIN  or TDIN1\n"
  " GPIO 13 SPI0 MISO   21                       DO         TDOUT or TDOU1\n"
  " GPIO 14 SPI0 SCLK   23                       SCLK       TSCLK or TSCLK1\n"
  " GPIO 10 SPI0_CE0    24                       ~CS        TCS   or TCS1\n"
  "\n"
  
 );
}