/**************************************************************************** * * Copyright (c) 2015, 2016 Airmind 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 Airmind 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 test_ppm.cpp * * @author sudragon */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define TEST_PPM_PIN (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_2MHz|GPIO_OUTPUT_SET|GPIO_PORTE|GPIO_PIN15) class TEST_PPM { public: TEST_PPM(unsigned channels); virtual ~TEST_PPM(void); virtual int init(); unsigned _values[20]; unsigned _gaps[20]; unsigned _channels; unsigned _plus_width; protected: private: struct hrt_call _call; unsigned _call_times; void start(); void stop(); void do_out(); static void loops(void *arg); }; /** driver 'main' command */ extern "C" { __EXPORT int test_ppm_main(int argc, char *argv[]); } TEST_PPM::TEST_PPM(unsigned channels) : _channels(channels), _plus_width(400), _call{}, _call_times(0) { memset(&_call, 0, sizeof(_call)); for (int i = 0; i < 20; i++) { _values[i] = 1500; } _values[0] = 5000; } TEST_PPM::~TEST_PPM() { /* make sure we are truly inactive */ stop(); } int TEST_PPM::init() { px4_arch_configgpio(TEST_PPM_PIN); start(); return OK; } void TEST_PPM::start() { stop(); _call_times = 0; hrt_call_after(&_call, 1000, (hrt_callout)&TEST_PPM::loops, this); } void TEST_PPM::stop() { hrt_cancel(&_call); } void TEST_PPM::loops(void *arg) { TEST_PPM *dev = static_cast(arg); dev->do_out(); } void TEST_PPM::do_out(void) { if ((_call_times % 2) == 0) { px4_arch_gpiowrite(TEST_PPM_PIN, false); hrt_call_after(&_call, _values[_call_times / 2] - _plus_width, (hrt_callout)&TEST_PPM::loops, this); } else { px4_arch_gpiowrite(TEST_PPM_PIN, true); hrt_call_after(&_call, _plus_width, (hrt_callout)&TEST_PPM::loops, this); } if ((_call_times / 2) < _channels + 1) { _call_times++; } else { _call_times = 0; } } namespace test_ppm { TEST_PPM *g_test = nullptr; void start(unsigned channels); void stop(); void usage(); void set(unsigned ch, unsigned value); /** * Start the driver. * * This function only returns if the driver is up and running * or failed to detect the sensor. */ void start(unsigned channels) { if (g_test != nullptr) /* if already started, the still command succeeded */ { errx(1, "already started"); } g_test = new TEST_PPM(channels); if (g_test == nullptr) { goto fail; } if (OK != g_test->init()) { goto fail; } exit(0); fail: if (g_test != nullptr) { delete (g_test); g_test = nullptr; } errx(1, "test_ppm start failed"); } void stop() { if (g_test != nullptr) { delete g_test; g_test = nullptr; } else { /* warn, but not an error */ warnx("test_ppm already stopped."); } exit(0); } void set(unsigned ch, unsigned value) { if (ch > 18 || ch < 1) {warnx("channel is not valid.");} if (value > 2500 || value < 1) { warnx("value is not valid.");} g_test->_values[ch] = value; g_test->_gaps[ch] = 2500 - value; if (ch == g_test->_channels) { g_test->_gaps[ch] = 5000; } return; } void usage() { warnx("missing command: try 'start', 'stop', 'set'\n"); } } // namespace int test_ppm_main(int argc, char *argv[]) { if (argc < 2) { test_ppm::usage(); return -1; } const char *verb = argv[1]; unsigned channels = 7; /* * Start/load the driver. */ if (!strcmp(verb, "start")) { test_ppm::start(channels); return 0; } if (!strcmp(verb, "stop")) { test_ppm::stop(); return 0; } /* * Test the driver/device. */ if (!strcmp(verb, "set")) { if (argc < 4) { errx(1, "Usage: test_ppm set "); } unsigned channel = strtol(argv[2], NULL, 0); unsigned value = strtol(argv[3], NULL, 0); test_ppm::set(channel, value); return 0; } test_ppm::usage(); return -1; }