234 lines
7.0 KiB
C
234 lines
7.0 KiB
C
|
/****************************************************************************
|
||
|
* apps/testing/drivertest/drivertest_adc.c
|
||
|
*
|
||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||
|
* contributor license agreements. See the NOTICE file distributed with
|
||
|
* this work for additional information regarding copyright ownership. The
|
||
|
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||
|
* "License"); you may not use this file except in compliance with the
|
||
|
* License. You may obtain a copy of the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||
|
* License for the specific language governing permissions and limitations
|
||
|
* under the License.
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
|
||
|
/****************************************************************************
|
||
|
* Included Files
|
||
|
****************************************************************************/
|
||
|
|
||
|
#include <fcntl.h>
|
||
|
#include <unistd.h>
|
||
|
#include <stdarg.h>
|
||
|
#include <stddef.h>
|
||
|
#include <stdint.h>
|
||
|
#include <setjmp.h>
|
||
|
#include <stdio.h>
|
||
|
#include <sys/ioctl.h>
|
||
|
#include <sys/stat.h>
|
||
|
#include <sys/types.h>
|
||
|
#include <syslog.h>
|
||
|
#include <sys/time.h>
|
||
|
#include <stdlib.h>
|
||
|
|
||
|
#include <cmocka.h>
|
||
|
#include <nuttx/analog/adc.h>
|
||
|
#include <nuttx/analog/ioctl.h>
|
||
|
|
||
|
/****************************************************************************
|
||
|
* Pre-processor Definitions
|
||
|
****************************************************************************/
|
||
|
|
||
|
#define OPTARG_TO_VALUE(value, type, base) \
|
||
|
do { \
|
||
|
FAR char* ptr; \
|
||
|
value = (type)strtoul(optarg, &ptr, base); \
|
||
|
if (*ptr != '\0') { \
|
||
|
printf("Parameter error: -%c %s\n", ch, optarg); \
|
||
|
adc_help(argv[0]); \
|
||
|
} \
|
||
|
} while (0)
|
||
|
|
||
|
/****************************************************************************
|
||
|
* Private Function Prototypes
|
||
|
****************************************************************************/
|
||
|
|
||
|
struct adc_state_s
|
||
|
{
|
||
|
char devpath[PATH_MAX]; /* device to adc device path */
|
||
|
int adc_diff; /* adc value difference */
|
||
|
int duration; /* duration of sampling adc in seconds */
|
||
|
bool soft_trigger; /* soft trigger : true or false */
|
||
|
};
|
||
|
|
||
|
/****************************************************************************
|
||
|
* Private Functions
|
||
|
****************************************************************************/
|
||
|
|
||
|
static void adc_help(FAR char *process_name)
|
||
|
{
|
||
|
printf("Usage: %s [OPTIONS]\n", process_name);
|
||
|
printf(" -p adc device path , default : /dev/adc0\n");
|
||
|
printf(" -d sample adc changes over set-up value. default : 200\n");
|
||
|
printf(" -t duration of adc test [second] , default: 10s\n");
|
||
|
printf(" -m adc conversion method, 1 -- soft trigger, "
|
||
|
"0 -- interrupt , default: 1\n");
|
||
|
exit(-1);
|
||
|
}
|
||
|
|
||
|
/****************************************************************************
|
||
|
* Name: parse_commandline
|
||
|
****************************************************************************/
|
||
|
|
||
|
static void parse_commandline(FAR struct adc_state_s *adc_state, int argc,
|
||
|
FAR char **argv)
|
||
|
{
|
||
|
int ch;
|
||
|
int converted;
|
||
|
|
||
|
while ((ch = getopt(argc, argv, "p:d:m:t:h")) != ERROR)
|
||
|
{
|
||
|
switch (ch)
|
||
|
{
|
||
|
case 'p':
|
||
|
strlcpy(adc_state->devpath, optarg, sizeof(adc_state->devpath));
|
||
|
adc_state->devpath[sizeof(adc_state->devpath) - 1] = '\0';
|
||
|
break;
|
||
|
case 'd':
|
||
|
OPTARG_TO_VALUE(converted, int, 10);
|
||
|
if (converted < 0 || converted > 5000)
|
||
|
{
|
||
|
printf("sample adc value changes over: %d\n", converted);
|
||
|
adc_help(argv[0]);
|
||
|
}
|
||
|
|
||
|
adc_state->adc_diff = (uint8_t)converted;
|
||
|
break;
|
||
|
case 't':
|
||
|
OPTARG_TO_VALUE(converted, int, 10);
|
||
|
if (converted < 1 || converted > INT_MAX)
|
||
|
{
|
||
|
printf("Duty out of range: %d\n", converted);
|
||
|
adc_help(argv[0]);
|
||
|
}
|
||
|
|
||
|
adc_state->duration = (int)converted;
|
||
|
break;
|
||
|
case 'm':
|
||
|
OPTARG_TO_VALUE(converted, uint8_t, 10);
|
||
|
adc_state->soft_trigger = converted ? true : false;
|
||
|
break;
|
||
|
case '?':
|
||
|
printf("Unsupported option: %s\n", optarg);
|
||
|
|
||
|
case 'h':
|
||
|
adc_help(argv[0]);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int32_t adc_read_one_sample(int fd, bool soft_trigger)
|
||
|
{
|
||
|
struct adc_msg_s sample;
|
||
|
int ret;
|
||
|
int nbytes;
|
||
|
|
||
|
/* software trigger to start one ADC conversion */
|
||
|
|
||
|
if (soft_trigger)
|
||
|
{
|
||
|
ret = ioctl(fd, ANIOC_TRIGGER, 0);
|
||
|
assert_return_code(ret, OK);
|
||
|
}
|
||
|
|
||
|
/* Read one samples */
|
||
|
|
||
|
nbytes = read(fd, &sample, sizeof(struct adc_msg_s));
|
||
|
|
||
|
/* Handle unexpected return values */
|
||
|
|
||
|
assert_true(nbytes == sizeof(struct adc_msg_s));
|
||
|
|
||
|
return sample.am_data;
|
||
|
}
|
||
|
|
||
|
/****************************************************************************
|
||
|
* Name: test_case_adc
|
||
|
****************************************************************************/
|
||
|
|
||
|
static void test_case_adc(FAR void** state)
|
||
|
{
|
||
|
int fd;
|
||
|
bool succ = false;
|
||
|
int32_t value1;
|
||
|
int32_t value2;
|
||
|
struct timeval tv1;
|
||
|
struct timeval tv2;
|
||
|
struct timeval res;
|
||
|
FAR struct adc_state_s *adc_state;
|
||
|
adc_state = (FAR struct adc_state_s *)*state;
|
||
|
|
||
|
/* Open the ADC device for reading */
|
||
|
|
||
|
fd = open(adc_state->devpath, O_RDONLY);
|
||
|
assert_true(fd > 0);
|
||
|
|
||
|
value1 = adc_read_one_sample(fd, adc_state->soft_trigger);
|
||
|
|
||
|
/* ADC sample value should be changed in duration [seconds] */
|
||
|
|
||
|
gettimeofday(&tv1, NULL);
|
||
|
while (true)
|
||
|
{
|
||
|
value2 = adc_read_one_sample(fd, adc_state->soft_trigger);
|
||
|
if (abs(value2 - value1) > adc_state->adc_diff)
|
||
|
{
|
||
|
succ = true;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
gettimeofday(&tv2, NULL);
|
||
|
timersub(&tv2, &tv1, &res);
|
||
|
if (res.tv_sec >= adc_state->duration)
|
||
|
{
|
||
|
printf("adc test timed out\n");
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
usleep(adc_state->soft_trigger ? 1000000 : 200000);
|
||
|
}
|
||
|
|
||
|
close(fd);
|
||
|
assert_true(succ);
|
||
|
}
|
||
|
|
||
|
/****************************************************************************
|
||
|
* drivertest_adc_main
|
||
|
****************************************************************************/
|
||
|
|
||
|
int main(int argc, FAR char *argv[])
|
||
|
{
|
||
|
/* Initialize the state data */
|
||
|
|
||
|
struct adc_state_s adc_state = {
|
||
|
.devpath = "/dev/adc0",
|
||
|
.adc_diff = 200,
|
||
|
.duration = 10,
|
||
|
.soft_trigger = true,
|
||
|
};
|
||
|
|
||
|
parse_commandline(&adc_state, argc, argv);
|
||
|
|
||
|
const struct CMUnitTest tests[] = {
|
||
|
cmocka_unit_test_prestate(test_case_adc, &adc_state),
|
||
|
};
|
||
|
|
||
|
return cmocka_run_group_tests(tests, NULL, NULL);
|
||
|
}
|