testing/drivertest: add pwm driver test
Signed-off-by: cuiziwei <cuiziwei@xiaomi.com>
This commit is contained in:
parent
220a5a2ce6
commit
7394b4584d
@ -39,5 +39,9 @@ MAINSRC += drivertest_timer.c
|
||||
PROGNAME += cmocka_driver_timer
|
||||
endif
|
||||
|
||||
ifneq ($(CONFIG_PWM),)
|
||||
MAINSRC += drivertest_pwm.c
|
||||
PROGNAME += cmocka_driver_pwm
|
||||
endif
|
||||
|
||||
include $(APPDIR)/Application.mk
|
||||
|
316
testing/drivertest/drivertest_pwm.c
Normal file
316
testing/drivertest/drivertest_pwm.c
Normal file
@ -0,0 +1,316 @@
|
||||
/****************************************************************************
|
||||
* apps/testing/drivertest/drivertest_pwm.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 <nuttx/config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <debug.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <setjmp.h>
|
||||
#include <stdint.h>
|
||||
#include <cmocka.h>
|
||||
|
||||
#include <nuttx/timers/pwm.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#define PWM_DEFAULT_COUNT 0
|
||||
#define PWM_DEFAULT_DURATION 5
|
||||
#define PWM_DEFAULT_DUTY 50
|
||||
#define PWM_DEFAULT_FREQUENCY 100
|
||||
#define PWM_DEFAULT_DEVPATH "/dev/pwm0"
|
||||
|
||||
#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); \
|
||||
pwm_help(argv[0], pwm_state, EXIT_FAILURE); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
struct pwm_state_s
|
||||
{
|
||||
char devpath[PATH_MAX];
|
||||
uint8_t duty;
|
||||
uint32_t freq;
|
||||
#ifdef CONFIG_PWM_PULSECOUNT
|
||||
uint32_t count;
|
||||
#endif
|
||||
int duration;
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: pwm_help
|
||||
****************************************************************************/
|
||||
|
||||
static void pwm_help(FAR const char *progname,
|
||||
FAR struct pwm_state_s *pwm_state, int exitcode)
|
||||
{
|
||||
printf("Usage: %s"
|
||||
" -p <devpath> -f <frequency> -d <duty> -n <count> -t <duration>\n",
|
||||
progname);
|
||||
printf("\nArguments are \"sticky\". "
|
||||
"For example, once the PWM frequency is\n");
|
||||
printf("specified, that frequency will be re-used until it is changed.\n");
|
||||
printf("\n\"sticky\" OPTIONS include:\n");
|
||||
printf(" [-p devpath] selects the PWM device. "
|
||||
"Default: %s Current: %s\n", PWM_DEFAULT_DEVPATH,
|
||||
pwm_state->devpath);
|
||||
printf(" [-f frequency] selects the pulse frequency. "
|
||||
"Default: %d Hz Current: %" PRIu32 " Hz\n",
|
||||
PWM_DEFAULT_FREQUENCY, pwm_state->freq);
|
||||
printf(" [-d duty] selects the pulse duty as a percentage. "
|
||||
"Default: %d %% Current: %d %%\n",
|
||||
PWM_DEFAULT_DUTY, pwm_state->duty);
|
||||
|
||||
#ifdef CONFIG_PWM_PULSECOUNT
|
||||
printf(" [-n count] selects the pulse count. "
|
||||
"Default: %d Current: %" PRIx32 "\n",
|
||||
PWM_DEFAULT_COUNT, pwm_state->count);
|
||||
#endif
|
||||
printf(" [-t duration] is the duration of the pulse train in seconds. "
|
||||
"Default: %d Current: %d\n",
|
||||
PWM_DEFAULT_DURATION, pwm_state->duration);
|
||||
printf(" [-h] shows this message and exits\n");
|
||||
|
||||
exit(exitcode);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: parse_commandline
|
||||
****************************************************************************/
|
||||
|
||||
static void parse_commandline(FAR struct pwm_state_s *pwm_state, int argc,
|
||||
FAR char **argv)
|
||||
{
|
||||
int ch;
|
||||
int converted;
|
||||
|
||||
while ((ch = getopt(argc, argv, "p:d:n:f:t:h")) != ERROR)
|
||||
{
|
||||
switch (ch)
|
||||
{
|
||||
case 'p':
|
||||
strncpy(pwm_state->devpath, optarg, sizeof(pwm_state->devpath));
|
||||
pwm_state->devpath[sizeof(pwm_state->devpath) - 1] = '\0';
|
||||
break;
|
||||
case 'd':
|
||||
OPTARG_TO_VALUE(converted, uint8_t, 10);
|
||||
if (converted < 0 || converted > 100)
|
||||
{
|
||||
printf("Duty out of range: %d\n", converted);
|
||||
pwm_help(argv[0], pwm_state, EXIT_FAILURE);
|
||||
}
|
||||
|
||||
pwm_state->duty = (uint8_t)converted;
|
||||
break;
|
||||
#ifdef CONFIG_PWM_PULSECOUNT
|
||||
case 'n':
|
||||
OPTARG_TO_VALUE(converted, uint32_t, 10);
|
||||
if (converted < 0)
|
||||
{
|
||||
printf("Count must be non-negative: %ld\n", converted);
|
||||
pwm_help(argv[0], pwm_state, EXIT_FAILURE);
|
||||
}
|
||||
|
||||
pwm_state->count = (uint32_t)value;
|
||||
break;
|
||||
#endif
|
||||
case 'f':
|
||||
OPTARG_TO_VALUE(converted, uint32_t, 10);
|
||||
if (converted < 0)
|
||||
{
|
||||
printf("Frequency out of range: %d\n", converted);
|
||||
pwm_help(argv[0], pwm_state, EXIT_FAILURE);
|
||||
}
|
||||
|
||||
pwm_state->freq = (uint32_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);
|
||||
pwm_help(argv[0], pwm_state, EXIT_FAILURE);
|
||||
}
|
||||
|
||||
pwm_state->duration = (int)converted;
|
||||
break;
|
||||
case 'h':
|
||||
pwm_help(argv[0], pwm_state, EXIT_FAILURE);
|
||||
break;
|
||||
case '?':
|
||||
printf("Unsupported option: %s\n", optarg);
|
||||
pwm_help(argv[0], pwm_state, EXIT_FAILURE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
printf("devname = %s\n"
|
||||
"duty = %d\n"
|
||||
"frenquency = %" PRIu32 "\n"
|
||||
"duration = %d\n",
|
||||
pwm_state->devpath,
|
||||
pwm_state->duty,
|
||||
pwm_state->freq,
|
||||
pwm_state->duration);
|
||||
|
||||
#ifdef CONFIG_PWM_PULSECOUNT
|
||||
printf("count = %" PRIu32 "\n", pwm_state->count);
|
||||
#endif
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: test_case_pwm
|
||||
****************************************************************************/
|
||||
|
||||
static void test_case_pwm(FAR void **state)
|
||||
{
|
||||
int fd;
|
||||
int ret;
|
||||
struct pwm_info_s info;
|
||||
FAR struct pwm_state_s *pwm_state;
|
||||
pwm_state = (FAR struct pwm_state_s *)*state;
|
||||
|
||||
/* Open the PWM device for reading */
|
||||
|
||||
fd = open(pwm_state->devpath, O_RDONLY);
|
||||
assert_true(fd > 0);
|
||||
|
||||
/* Configure the characteristics of the pulse train */
|
||||
|
||||
memset(&info, 0, sizeof(info));
|
||||
|
||||
info.frequency = pwm_state->freq;
|
||||
info.duty = b16divi(uitoub16(pwm_state->duty), 100);
|
||||
|
||||
#ifdef CONFIG_PWM_MULTICHAN
|
||||
for (i = 0; i < CONFIG_PWM_NCHANNELS; i++)
|
||||
{
|
||||
info.channels[i].channel = i + 1;
|
||||
info.channels[i].duty = info.duty;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PWM_PULSECOUNT
|
||||
info.count = pwm_state.count;
|
||||
#endif
|
||||
|
||||
ret = ioctl(fd, PWMIOC_SETCHARACTERISTICS,
|
||||
(unsigned long)((uintptr_t)&info));
|
||||
assert_return_code(ret, OK);
|
||||
|
||||
/* Then start the pulse train. Since the driver was opened in blocking
|
||||
* mode, this call will block if the count value is greater than zero.
|
||||
*/
|
||||
|
||||
ret = ioctl(fd, PWMIOC_START, 0);
|
||||
assert_return_code(ret, OK);
|
||||
|
||||
/* It a non-zero count was not specified, then wait for the selected
|
||||
* duration, then stop the PWM output.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_PWM_PULSECOUNT
|
||||
if (info.count == 0)
|
||||
#endif
|
||||
{
|
||||
/* Wait for the specified duration */
|
||||
|
||||
sleep(pwm_state->duration);
|
||||
|
||||
/* Then stop the pulse train */
|
||||
|
||||
ret = ioctl(fd, PWMIOC_STOP, 0);
|
||||
assert_return_code(ret, OK);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: main
|
||||
****************************************************************************/
|
||||
|
||||
int main(int argc, FAR char *argv[])
|
||||
{
|
||||
/* Initialize the state data */
|
||||
|
||||
struct pwm_state_s pwm_state =
|
||||
{
|
||||
.devpath = PWM_DEFAULT_DEVPATH,
|
||||
.duty = PWM_DEFAULT_DUTY,
|
||||
.freq = PWM_DEFAULT_FREQUENCY,
|
||||
.duration = PWM_DEFAULT_DURATION,
|
||||
#ifdef CONFIG_PWM_PULSECOUNT
|
||||
.count = PWM_DEFAULT_COUNT,
|
||||
#endif
|
||||
};
|
||||
|
||||
parse_commandline(&pwm_state, argc, argv);
|
||||
|
||||
const struct CMUnitTest tests[] =
|
||||
{
|
||||
cmocka_unit_test_prestate(test_case_pwm, &pwm_state)
|
||||
};
|
||||
|
||||
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||
}
|
Loading…
Reference in New Issue
Block a user