/**************************************************************************** * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /**************************************************************************** * 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 -f -d -n -t \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': strlcpy(pwm_state->devpath, optarg, sizeof(pwm_state->devpath)); 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); }