/**************************************************************************** * * Copyright (C) 2013 PX4 Development Team. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * 3. Neither the name PX4 nor the names of its contributors may be * used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************/ /** * @file pwm.c * * PWM servo output configuration and monitoring tool. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "systemlib/systemlib.h" #include "systemlib/err.h" #include "drivers/drv_pwm_output.h" static void usage(const char *reason); __EXPORT int pwm_main(int argc, char *argv[]); static void usage(const char *reason) { if (reason != NULL) warnx("%s", reason); errx(1, "usage:\n" "pwm arm|disarm|rate|failsafe|disarmed|min|max|test|info ...\n" "\n" " arm Arm output\n" " disarm Disarm output\n" "\n" " rate ... Configure PWM rates\n" " [-g ] Channel group that should update at the alternate rate\n" " [-m ] Directly supply channel mask\n" " [-a] Configure all outputs\n" " -r PWM rate (50 to 400 Hz)\n" "\n" " failsafe ... Configure failsafe PWM values\n" " disarmed ... Configure disarmed PWM values\n" " min ... Configure minimum PWM values\n" " max ... Configure maximum PWM values\n" " [-c ] Supply channels (e.g. 1234)\n" " [-m ] Directly supply channel mask (e.g. 0xF)\n" " [-a] Configure all outputs\n" " -p PWM value\n" "\n" " test ... Directly set PWM values\n" " [-c ] Supply channels (e.g. 1234)\n" " [-m ] Directly supply channel mask (e.g. 0xF)\n" " [-a] Configure all outputs\n" " -p PWM value\n" "\n" " info Print information about the PWM device\n" "\n" " -v Print verbose information\n" " -d PWM output device (defaults to " PWM_OUTPUT_DEVICE_PATH ")\n" ); } int pwm_main(int argc, char *argv[]) { const char *dev = PWM_OUTPUT_DEVICE_PATH; unsigned alt_rate = 0; uint32_t alt_channel_groups = 0; bool alt_channels_set = false; bool print_verbose = false; int ch; int ret; char *ep; uint32_t set_mask = 0; unsigned group; unsigned long channels; unsigned single_ch = 0; unsigned pwm_value = 0; if (argc < 1) usage(NULL); while ((ch = getopt(argc-1, &argv[1], "d:vc:g:m:ap:r:")) != EOF) { switch (ch) { case 'd': if (NULL == strstr(optarg, "/dev/")) { warnx("device %s not valid", optarg); usage(NULL); } dev = optarg; break; case 'v': print_verbose = true; break; case 'c': /* Read in channels supplied as one int and convert to mask: 1234 -> 0xF */ channels = strtoul(optarg, &ep, 0); while ((single_ch = channels % 10)) { set_mask |= 1<<(single_ch-1); channels /= 10; } break; case 'g': group = strtoul(optarg, &ep, 0); if ((*ep != '\0') || (group >= 32)) usage("bad channel_group value"); alt_channel_groups |= (1 << group); alt_channels_set = true; warnx("alt channels set, group: %d", group); break; case 'm': /* Read in mask directly */ set_mask = strtoul(optarg, &ep, 0); if (*ep != '\0') usage("bad set_mask value"); break; case 'a': for (unsigned i = 0; i 0) { warnx("Chose channels: "); printf(" "); for (unsigned i = 0; i 0) { ret = ioctl(fd, PWM_SERVO_SET_UPDATE_RATE, alt_rate); if (ret != OK) err(1, "PWM_SERVO_SET_UPDATE_RATE (check rate for sanity)"); } /* directly supplied channel mask */ if (set_mask > 0) { ret = ioctl(fd, PWM_SERVO_SET_SELECT_UPDATE_RATE, set_mask); if (ret != OK) err(1, "PWM_SERVO_SET_SELECT_UPDATE_RATE"); } /* assign alternate rate to channel groups */ if (alt_channels_set) { uint32_t mask = 0; for (group = 0; group < 32; group++) { if ((1 << group) & alt_channel_groups) { uint32_t group_mask; ret = ioctl(fd, PWM_SERVO_GET_RATEGROUP(group), (unsigned long)&group_mask); if (ret != OK) err(1, "PWM_SERVO_GET_RATEGROUP(%u)", group); mask |= group_mask; } } ret = ioctl(fd, PWM_SERVO_SET_SELECT_UPDATE_RATE, mask); if (ret != OK) err(1, "PWM_SERVO_SET_SELECT_UPDATE_RATE"); } exit(0); } else if (!strcmp(argv[1], "min")) { if (set_mask == 0) { usage("no channels set"); } if (pwm_value == 0) usage("no PWM value provided"); struct pwm_output_values pwm_values = {.values = {0}, .channel_count = 0}; for (unsigned i = 0; i < servo_count; i++) { if (set_mask & 1< 0) { read(0, &c, 1); if (c == 0x03 || c == 0x63 || c == 'q') { /* reset output to the last value */ for (unsigned i = 0; i < servo_count; i++) { if (set_mask & 1<