meta-digi/meta-digi-dey/recipes-digi/dey-examples/files/adc_test/adc_test.c

346 lines
9.1 KiB
C

/*
* adc_test.c
*
* Copyright (C) 2009-2013 by Digi International Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* Description: ADC test application
*
*/
#include <fcntl.h>
#include <getopt.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#if defined(CCIMX51JS) || defined(CCIMX53JS)
#include <linux/pmic_adc.h>
#include <sys/ioctl.h>
#elif defined(CCARDIMX28JS)
#include <linux/mxs-lradc.h>
#include <sys/ioctl.h>
#endif
#define PROGRAM "adc_test"
#define VERSION "2.0"
#if defined(CCIMX53JS)
# define ADC_MAX_CHANNELS 10
#elif defined(CCIMX51JS)
# define ADC_MAX_CHANNELS 8
#endif
#if defined(CCIMX51JS) || defined(CCIMX53JS)
# define ADC_CONVERT_IOCTL PMIC_ADC_CONVERT
# define ADC_CHARDEV "/dev/pmic_adc"
#elif defined(CCARDIMX28JS)
# define ADC_MAX_CHANNELS 7
# define ADC_CONVERT_IOCTL LRADC_CONVERT
# define ADC_CHARDEV "/dev/mxs_lradc"
#endif
#define ADC_MAX_SAMPLE_BUFFER 10000
#define adc_test_usage \
"[-i ms] [-n samples] [-v verbosity] -c chnum[,chnum]\n"
#define adc_test_full_usage \
"adc_test [options] channel list\n\n" \
"Tests the ADC channels\n" \
"Options:\n" \
" -n --numsamples numsamples Number of samples to display (default 100)\n" \
" -v --verbosity level Verbosity level (0-display only statistics, 1-display all samples)\n" \
" -c --channels ch_num[,ch_num] (comma separated without spaces)\n" \
" -i --isms num_of_ms Intersample number of ms (default 100)\n" \
" -h --help Usage information\n" \
" --version Show version\n"
typedef struct adc_channel {
int fd;
int channel;
unsigned short int *samples;
unsigned int samplecount;
unsigned int avg;
unsigned int variance;
unsigned short maxval;
unsigned short minval;
} adc_channel_t;
static char *chlist = NULL;
/*
* Function: adc_test_banner
* Description: print banner
*/
static void adc_test_banner(void)
{
fprintf(stdout, "%s %s Copyright 2010 Digi International Inc.\n"
"ADC test/demo application\n\n", PROGRAM, VERSION);
}
/*
* Function: exit_error
* Description: print error message and exit
*/
static void exit_error(char *error_msg, int exit_val)
{
if (error_msg != NULL)
fprintf(stderr, "%s", error_msg);
exit(exit_val);
}
/*
* Function: show_usage_exit
* Description: print usage information and exit
*/
static void show_usage_exit(int exit_val, int full)
{
if (full) {
adc_test_banner();
fprintf(stdout, "%s", adc_test_full_usage);
} else {
fprintf(stdout, "%s", adc_test_usage);
}
exit_error(NULL, exit_val);
}
/*
* Function: compute_ch_statistics
* Description: compute some statistics over the stored samples
*/
static void compute_ch_statistics(adc_channel_t *adcch)
{
int i;
unsigned int avg = 0;
unsigned int variance = 0;
/* Compute the average */
for (i = 0; i < adcch->samplecount; i++) {
avg += adcch->samples[i];
if (adcch->samples[i] > adcch->maxval)
adcch->maxval = adcch->samples[i];
if (adcch->samples[i] < adcch->minval)
adcch->minval = adcch->samples[i];
}
/* compute average first so we can compute the variance */
avg /= adcch->samplecount;
/* compute the variance with a new loop to avoid rounding errors when
* computing the average */
for (i = 0; i < adcch->samplecount; i++)
variance += ((adcch->samples[i] - avg) * (adcch->samples[i] - avg));
adcch->variance = variance / adcch->samplecount;
adcch->avg = avg;
}
/*
* Function: print_ch_statistics
* Description: print channel statistic information
*/
static void print_ch_statistics(adc_channel_t *adcch)
{
fprintf(stdout, "Channel %d Statistics (samples %d)\n", adcch->channel,
adcch->samplecount);
fprintf(stdout, "----------------------------------------------\n");
fprintf(stdout, " Average = %d\n", adcch->avg);
fprintf(stdout, " Variance = %d\n", adcch->variance);
fprintf(stdout, " Std deviation = %d\n", (int)sqrt(adcch->variance));
fprintf(stdout, " max val = %d\n", adcch->maxval);
fprintf(stdout, " min val = %d\n\n", adcch->minval);
}
/*
* Function: main
* Description: main function
*/
int main(int argc, char *argv[])
{
adc_channel_t channel[ADC_MAX_CHANNELS];
char device_name[30], *var;
int ret, i, j, k, numsamples = 100;
int verbose = 0;
int intersample_us = 100000;
static int version = 0;
static int opt_index, opt, optcount = 0;
static const char *short_options = "hi:c:n:v:";
static const struct option long_options[] = {
{"help", no_argument, NULL, 'h'},
{"isms", required_argument, NULL, 'i'},
{"channels", required_argument, NULL, 'c'},
{"samples", required_argument, NULL, 'n'},
{"verbose", required_argument, NULL, 'v'},
{"version", no_argument, &version, 1 },
{0, 0, 0, 0},
};
#if defined(CCIMX51JS) || defined(CCIMX53JS) || defined(CCARDIMX28JS)
t_adc_convert_param adc_convert_param;
#else
unsigned short int adcval;
#endif
for (opt_index = 0;;) {
opt = getopt_long(argc, argv, short_options, long_options, &opt_index);
if (opt == EOF)
break;
switch (opt) {
case 0:
if (version) {
printf("%s %s, compiled on %s, %s\n", PROGRAM, VERSION,
__DATE__, __TIME__);
exit(EXIT_SUCCESS);
}
break;
case 'n':
numsamples = atoi(optarg);
break;
case 'i':
intersample_us = atoi(optarg) * 1000;
break;
case 'c':
chlist = optarg;
break;
case 'v':
verbose = atoi(optarg);
break;
case 'h':
case '?':
show_usage_exit((opt == 'h') ? EXIT_SUCCESS : EXIT_FAILURE, 1);
break;
}
optcount++;
}
if (optcount == 0)
show_usage_exit(EXIT_FAILURE, 1);
/* Check options */
if (chlist == NULL)
show_usage_exit(EXIT_FAILURE, 1);
/* Initialize some variables */
for (i = 0; i < ADC_MAX_CHANNELS; i++) {
channel[i].fd = -1;
channel[i].avg = 0;
channel[i].samplecount = 0;
channel[i].maxval = 0;
channel[i].minval = 4095;
}
var = strtok(chlist, ",");
while (var != NULL) {
char *end;
int chnr = strtol(var, &end, 10);
if ((chnr >= 0) && (chnr < ADC_MAX_CHANNELS) && (var != end)) {
#if defined(CCIMX51JS) || defined(CCIMX53JS) || defined(CCARDIMX28JS)
sprintf(device_name, ADC_CHARDEV);
#else
snprintf(device_name, 30, "%s%d", ADC_CHARDEV, chnr);
#endif
channel[chnr].channel = chnr;
channel[chnr].fd = open(device_name, O_RDONLY);
if (channel[chnr].fd < 0) {
fprintf(stderr,
"Unable to open adc channel %d (device file %s)\n",
chnr, device_name);
}
channel[chnr].samples = malloc((numsamples > ADC_MAX_SAMPLE_BUFFER) ?
ADC_MAX_SAMPLE_BUFFER *
sizeof(unsigned short int) : numsamples *
sizeof(unsigned short int));
}
var = strtok(NULL, ",");
}
adc_test_banner();
/* Check if any channel is available */
int any_channel = 0;
for (i = 0; i < ADC_MAX_CHANNELS; i++)
any_channel |= (channel[i].fd >= 0);
if (!any_channel)
exit_error("No adc channel available (verify command line arguments)\n",
EXIT_FAILURE);
for (j = 0; j < numsamples; j++) {
k = j % ADC_MAX_SAMPLE_BUFFER;
for (i = 0; i < ADC_MAX_CHANNELS; i++) {
if (channel[i].fd >= 0) {
#if defined(CCIMX51JS) || defined(CCIMX53JS) || defined(CCARDIMX28JS)
memset(&adc_convert_param,0,sizeof(adc_convert_param));
adc_convert_param.channel = channel[i].channel;
#if defined(CCIMX51JS)
/* The PMIC ADC driver maps GEN_PURPOSE_AD5,GEN_PURPOSE_AD6 and
* GEN_PURPOSE_AD7 to channels 10,11,12*/
if( adc_convert_param.channel > 4 )
adc_convert_param.channel = adc_convert_param.channel + 5;
#endif
fflush(stdout);
if ((ret = ioctl(channel[i].fd, ADC_CONVERT_IOCTL, &adc_convert_param)) != 0) {
fprintf(stderr,
"Unable to read adc channel %d (device file %s)\n",
i, device_name);
continue;
}
channel[i].samples[k] = adc_convert_param.result[0];
if (verbose > 0)
fprintf(stdout, "CH %d (%03d): %04d [0x%3x]\n", i, k,
adc_convert_param.result[0], adc_convert_param.result[0]);
#else
ret = read(channel[i].fd, &adcval, sizeof(unsigned short int));
if (ret < 0) {
fprintf(stderr,
"Unable to read adc channel %d (device file %s)\n",
i, device_name);
continue;
}
channel[i].samples[k] = adcval;
if (verbose > 0)
fprintf(stdout, "CH %d (%03d): %04d [0x%3x]\n", i, k,
adcval, adcval);
#endif
channel[i].samplecount++;
if ((k + 1) == ADC_MAX_SAMPLE_BUFFER) {
if (verbose > 0)
fprintf(stdout, "\n");
compute_ch_statistics(&channel[i]);
print_ch_statistics(&channel[i]);
channel[i].samplecount = 0;
}
}
}
usleep(intersample_us);
}
if (numsamples % ADC_MAX_SAMPLE_BUFFER) {
if (verbose > 0)
fprintf(stdout, "\n");
for (i = 0; i < ADC_MAX_CHANNELS; i++) {
if (channel[i].fd >= 0) {
compute_ch_statistics(&channel[i]);
print_ch_statistics(&channel[i]);
}
}
}
for (i = 0; i < ADC_MAX_CHANNELS; i++) {
if (channel[i].fd >= 0) {
close(channel[i].fd);
free(channel[i].samples);
}
}
return EXIT_SUCCESS;
}