diff --git a/testing/drivertest/Makefile b/testing/drivertest/Makefile index 631329e635..3bccede604 100644 --- a/testing/drivertest/Makefile +++ b/testing/drivertest/Makefile @@ -75,6 +75,11 @@ MAINSRC += drivertest_watchdog.c PROGNAME += cmocka_driver_watchdog endif +ifneq ($(CONFIG_ADC),) +MAINSRC += drivertest_adc.c +PROGNAME += cmocka_driver_adc +endif + ifneq ($(CONFIG_I2C)$(CONFIG_SPI),) ifneq ($(CONFIG_SENSORS_BMI160),) MAINSRC += drivertest_i2c_spi.c diff --git a/testing/drivertest/drivertest_adc.c b/testing/drivertest/drivertest_adc.c new file mode 100644 index 0000000000..0a9bd6d582 --- /dev/null +++ b/testing/drivertest/drivertest_adc.c @@ -0,0 +1,233 @@ +/**************************************************************************** + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/**************************************************************************** + * 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); +}