diff --git a/boards/airmind/mindpx-v2/src/board_config.h b/boards/airmind/mindpx-v2/src/board_config.h index 3d0fe95891..c02d24ca93 100644 --- a/boards/airmind/mindpx-v2/src/board_config.h +++ b/boards/airmind/mindpx-v2/src/board_config.h @@ -271,7 +271,7 @@ // #define GPIO_RSSI_IN (GPIO_INPUT|GPIO_PULLUP|GPIO_PORTC|GPIO_PIN1) #define GPIO_SBUS_INV (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_2MHz|GPIO_OUTPUT_SET|GPIO_PORTA|GPIO_PIN10) -#define BOARD_INVERT_RC_INPUT(_invert_true, _na) px4_arch_gpiowrite(GPIO_SBUS_INV, _invert_true); +#define RC_INVERT_INPUT(_invert_true) px4_arch_gpiowrite(GPIO_SBUS_INV, _invert_true); #define GPIO_FRSKY_INV (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_2MHz|GPIO_OUTPUT_SET|GPIO_PORTB|GPIO_PIN12) #define INVERT_FRSKY(_invert_true) px4_arch_gpiowrite(GPIO_FRSKY_INV, _invert_true); diff --git a/boards/av/x-v1/nuttx-config/nsh/defconfig b/boards/av/x-v1/nuttx-config/nsh/defconfig index f62f764623..be76a44adc 100644 --- a/boards/av/x-v1/nuttx-config/nsh/defconfig +++ b/boards/av/x-v1/nuttx-config/nsh/defconfig @@ -226,6 +226,9 @@ CONFIG_STM32F7_USART2=y CONFIG_STM32F7_USART3=y CONFIG_STM32F7_USART6=y CONFIG_STM32F7_USART_BREAKS=y +CONFIG_STM32F7_USART_INVERT=y +CONFIG_STM32F7_USART_SINGLEWIRE=y +CONFIG_STM32F7_USART_SWAP=y CONFIG_STM32F7_WWDG=y CONFIG_SYSTEM_NSH=y CONFIG_SYSTEM_PING=y diff --git a/boards/av/x-v1/src/CMakeLists.txt b/boards/av/x-v1/src/CMakeLists.txt index 85968ef8f1..7e0ef44d31 100644 --- a/boards/av/x-v1/src/CMakeLists.txt +++ b/boards/av/x-v1/src/CMakeLists.txt @@ -33,7 +33,6 @@ add_library(drivers_board init.c - manifest.c sdio.c spi.cpp timer_config.c diff --git a/boards/av/x-v1/src/board_config.h b/boards/av/x-v1/src/board_config.h index f56f6bd904..c3626213fc 100644 --- a/boards/av/x-v1/src/board_config.h +++ b/boards/av/x-v1/src/board_config.h @@ -268,12 +268,7 @@ /* RC Serial port */ -#define RC_UXART_BASE STM32_UART5_BASE #define RC_SERIAL_PORT "/dev/ttyS4" -#define BOARD_HAS_SINGLE_WIRE 0 /* HW is capable of Single Wire */ -#define BOARD_HAS_SINGLE_WIRE_ON_TX 0 /* HW default is wired as Single Wire On TX pin */ -#define BOARD_HAS_RX_TX_SWAP 0 /* HW Can swap TX and RX */ -#define RC_SERIAL_PORT_IS_SWAPED 0 /* Board wired with RC's TX is on cpu RX */ /* Power switch controls ******************************************************/ diff --git a/boards/av/x-v1/src/init.c b/boards/av/x-v1/src/init.c index 64afae4836..9877f87516 100644 --- a/boards/av/x-v1/src/init.c +++ b/boards/av/x-v1/src/init.c @@ -75,51 +75,6 @@ static int configure_switch(void); -/************************************************************************************ - * Name: board_rc_input - * - * Description: - * All boards my optionally provide this API to invert the Serial RC input. - * This is needed on SoCs that support the notion RXINV or TXINV as apposed to - * and external XOR controlled by a GPIO - * - ************************************************************************************/ - -__EXPORT void board_rc_input(bool invert_on, uint32_t uxart_base) -{ - - irqstate_t irqstate = px4_enter_critical_section(); - - uint32_t cr1 = getreg32(STM32_USART_CR1_OFFSET + uxart_base); - uint32_t cr2 = getreg32(STM32_USART_CR2_OFFSET + uxart_base); - uint32_t regval = cr1; - - /* {R|T}XINV bit fields can only be written when the USART is disabled (UE=0). */ - - regval &= ~USART_CR1_UE; - - putreg32(regval, STM32_USART_CR1_OFFSET + uxart_base); - - if (invert_on) { -#if defined(BOARD_HAS_RX_TX_SWAP) && RC_SERIAL_PORT_IS_SWAPED == 1 - - /* This is only ever turned on */ - - cr2 |= (USART_CR2_RXINV | USART_CR2_TXINV | USART_CR2_SWAP); -#else - cr2 |= (USART_CR2_RXINV | USART_CR2_TXINV); -#endif - - } else { - cr2 &= ~(USART_CR2_RXINV | USART_CR2_TXINV); - } - - putreg32(cr2, STM32_USART_CR2_OFFSET + uxart_base); - putreg32(cr1, STM32_USART_CR1_OFFSET + uxart_base); - - leave_critical_section(irqstate); -} - /************************************************************************************ * Name: board_on_reset * diff --git a/boards/av/x-v1/src/manifest.c b/boards/av/x-v1/src/manifest.c deleted file mode 100644 index a9e5898d8d..0000000000 --- a/boards/av/x-v1/src/manifest.c +++ /dev/null @@ -1,67 +0,0 @@ -/**************************************************************************** - * - * Copyright (c) 2018 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 manifest.c - * - * This module supplies the interface to the manifest of hardware that is - * optional and dependent on the HW REV and HW VER IDs - * - * The manifest allows the system to know whether a hardware option - * say for example the PX4IO is an no-pop option vs it is broken. - * - */ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include -#include - -#include -#include "systemlib/px4_macros.h" - -/************************************************************************************ - * Name: board_rc_input - * - * Description: - * All boards my optionally provide this API to invert the Serial RC input. - * This is needed on SoCs that support the notion RXINV or TXINV as opposed to - * and external XOR controlled by a GPIO - * - ************************************************************************************/ -__EXPORT bool board_supports_single_wire(uint32_t uxart_base) -{ - return uxart_base == RC_UXART_BASE; -} diff --git a/boards/nxp/fmuk66-v3/nuttx-config/nsh/defconfig b/boards/nxp/fmuk66-v3/nuttx-config/nsh/defconfig index 9e1c7707bf..e1bf4c51ef 100644 --- a/boards/nxp/fmuk66-v3/nuttx-config/nsh/defconfig +++ b/boards/nxp/fmuk66-v3/nuttx-config/nsh/defconfig @@ -89,6 +89,7 @@ CONFIG_KINETIS_UART4_RXDMA=y CONFIG_KINETIS_UARTFIFOS=y CONFIG_KINETIS_UART_BREAKS=y CONFIG_KINETIS_UART_EXTEDED_BREAK=y +CONFIG_KINETIS_UART_INVERT=y CONFIG_KINETIS_USBDCD=y CONFIG_KINETS_LPUART_LOWEST=y CONFIG_LIBC_FLOATINGPOINT=y diff --git a/boards/nxp/fmuk66-v3/src/board_config.h b/boards/nxp/fmuk66-v3/src/board_config.h index 0c50ba58ca..64a44ad638 100644 --- a/boards/nxp/fmuk66-v3/src/board_config.h +++ b/boards/nxp/fmuk66-v3/src/board_config.h @@ -130,7 +130,6 @@ __BEGIN_DECLS /* RC input */ -#define RC_UXART_BASE KINETIS_UART1_BASE #define RC_SERIAL_PORT "/dev/ttyS2" /* UART1 */ #define GPIO_RSSI_IN PIN_ADC1_SE13 diff --git a/boards/nxp/fmuk66-v3/src/init.c b/boards/nxp/fmuk66-v3/src/init.c index 87e28b6f52..fd49478bc2 100644 --- a/boards/nxp/fmuk66-v3/src/init.c +++ b/boards/nxp/fmuk66-v3/src/init.c @@ -140,41 +140,6 @@ int board_read_VBUS_state(void) return BOARD_ADC_USB_CONNECTED ? 0 : 1; } -/************************************************************************************ - * Name: board_rc_input - * - * Description: - * All boards my optionally provide this API to invert the Serial RC input. - * This is needed on SoCs that support the notion RXINV or TXINV as opposed to - * and external XOR controlled by a GPIO - * - ************************************************************************************/ - -__EXPORT void board_rc_input(bool invert_on, uint32_t uxart_base) -{ - - irqstate_t irqstate = px4_enter_critical_section(); - - uint8_t s2 = getreg8(KINETIS_UART_S2_OFFSET + uxart_base); - uint8_t c3 = getreg8(KINETIS_UART_C3_OFFSET + uxart_base); - - /* {R|T}XINV bit fields can written any time */ - - if (invert_on) { - s2 |= (UART_S2_RXINV); - c3 |= (UART_C3_TXINV); - - } else { - s2 &= ~(UART_S2_RXINV); - c3 &= ~(UART_C3_TXINV); - } - - putreg8(s2, KINETIS_UART_S2_OFFSET + uxart_base); - putreg8(c3, KINETIS_UART_C3_OFFSET + uxart_base); - - leave_critical_section(irqstate); -} - /************************************************************************************ * Name: board_peripheral_reset * diff --git a/boards/px4/fmu-v4/src/board_config.h b/boards/px4/fmu-v4/src/board_config.h index c712feb262..86faaeca8c 100644 --- a/boards/px4/fmu-v4/src/board_config.h +++ b/boards/px4/fmu-v4/src/board_config.h @@ -306,7 +306,7 @@ /* For R12, this signal is active high. */ #define GPIO_SBUS_INV (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_2MHz|GPIO_OUTPUT_SET|GPIO_PORTC|GPIO_PIN13) -#define BOARD_INVERT_RC_INPUT(_invert_true, _na) px4_arch_gpiowrite(GPIO_SBUS_INV, _invert_true) +#define RC_INVERT_INPUT(_invert_true) px4_arch_gpiowrite(GPIO_SBUS_INV, _invert_true) #define GPIO_SPEKTRUM_PWR_EN (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_2MHz|GPIO_OUTPUT_CLEAR|GPIO_PORTE|GPIO_PIN4) diff --git a/boards/px4/fmu-v4pro/src/board_config.h b/boards/px4/fmu-v4pro/src/board_config.h index 0814327a65..e8b35d326b 100644 --- a/boards/px4/fmu-v4pro/src/board_config.h +++ b/boards/px4/fmu-v4pro/src/board_config.h @@ -306,7 +306,6 @@ */ #define GPIO_BTN_SAFETY_FMU (GPIO_INPUT|GPIO_FLOAT|GPIO_PORTC|GPIO_PIN4) #define GPIO_SBUS_INV (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_2MHz|GPIO_OUTPUT_SET|GPIO_PORTC|GPIO_PIN13) -#define BOARD_INVERT_RC_INPUT(_invert_true, _na) px4_arch_gpiowrite(GPIO_SBUS_INV, _invert_true) #define GPIO_8266_GPIO0 (GPIO_INPUT|GPIO_PULLUP|GPIO_PORTE|GPIO_PIN2) //TODO: fo not see on schematic #define GPIO_SPEKTRUM_PWR_EN (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_2MHz|GPIO_OUTPUT_CLEAR|GPIO_PORTE|GPIO_PIN4) diff --git a/boards/px4/fmu-v5/nuttx-config/nsh/defconfig b/boards/px4/fmu-v5/nuttx-config/nsh/defconfig index 170ad21c90..27bb01918d 100644 --- a/boards/px4/fmu-v5/nuttx-config/nsh/defconfig +++ b/boards/px4/fmu-v5/nuttx-config/nsh/defconfig @@ -205,7 +205,9 @@ CONFIG_STM32F7_USART2=y CONFIG_STM32F7_USART3=y CONFIG_STM32F7_USART6=y CONFIG_STM32F7_USART_BREAKS=y +CONFIG_STM32F7_USART_INVERT=y CONFIG_STM32F7_USART_SINGLEWIRE=y +CONFIG_STM32F7_USART_SWAP=y CONFIG_STM32F7_WWDG=y CONFIG_SYSTEM_CDCACM=y CONFIG_SYSTEM_NSH=y diff --git a/boards/px4/fmu-v5/src/board_config.h b/boards/px4/fmu-v5/src/board_config.h index 18c7bca782..1e6fd32f2a 100644 --- a/boards/px4/fmu-v5/src/board_config.h +++ b/boards/px4/fmu-v5/src/board_config.h @@ -496,12 +496,8 @@ /* RC Serial port */ -#define RC_UXART_BASE STM32_USART6_BASE #define RC_SERIAL_PORT "/dev/ttyS4" -#define BOARD_HAS_SINGLE_WIRE 1 /* HW is capable of Single Wire */ -#define BOARD_HAS_SINGLE_WIRE_ON_TX 1 /* HW default is wired as Single Wire On TX pin */ -#define BOARD_HAS_RX_TX_SWAP 1 /* HW Can swap TX and RX */ -#define RC_SERIAL_PORT_IS_SWAPED 0 /* Board wired with RC's TX is on cpu RX */ +#define RC_SERIAL_SINGLEWIRE /* Input Capture Channels. */ #define INPUT_CAP1_TIMER 2 diff --git a/boards/px4/fmu-v5/src/init.c b/boards/px4/fmu-v5/src/init.c index 8c37ee36d8..8f4c3bced4 100644 --- a/boards/px4/fmu-v5/src/init.c +++ b/boards/px4/fmu-v5/src/init.c @@ -91,51 +91,6 @@ extern void led_off(int led); __END_DECLS -/************************************************************************************ - * Name: board_rc_input - * - * Description: - * All boards my optionally provide this API to invert the Serial RC input. - * This is needed on SoCs that support the notion RXINV or TXINV as apposed to - * and external XOR controlled by a GPIO - * - ************************************************************************************/ - -__EXPORT void board_rc_input(bool invert_on, uint32_t uxart_base) -{ - - irqstate_t irqstate = px4_enter_critical_section(); - - uint32_t cr1 = getreg32(STM32_USART_CR1_OFFSET + uxart_base); - uint32_t cr2 = getreg32(STM32_USART_CR2_OFFSET + uxart_base); - uint32_t regval = cr1; - - /* {R|T}XINV bit fields can only be written when the USART is disabled (UE=0). */ - - regval &= ~USART_CR1_UE; - - putreg32(regval, STM32_USART_CR1_OFFSET + uxart_base); - - if (invert_on) { -#if defined(BOARD_HAS_RX_TX_SWAP) && RC_SERIAL_PORT_IS_SWAPED == 1 - - /* This is only ever turned on */ - - cr2 |= (USART_CR2_RXINV | USART_CR2_TXINV | USART_CR2_SWAP); -#else - cr2 |= (USART_CR2_RXINV | USART_CR2_TXINV); -#endif - - } else { - cr2 &= ~(USART_CR2_RXINV | USART_CR2_TXINV); - } - - putreg32(cr2, STM32_USART_CR2_OFFSET + uxart_base); - putreg32(cr1, STM32_USART_CR1_OFFSET + uxart_base); - - leave_critical_section(irqstate); -} - /************************************************************************************ * Name: board_peripheral_reset * diff --git a/boards/px4/fmu-v5/src/manifest.c b/boards/px4/fmu-v5/src/manifest.c index c733fe971e..eed9104a66 100644 --- a/boards/px4/fmu-v5/src/manifest.c +++ b/boards/px4/fmu-v5/src/manifest.c @@ -96,20 +96,6 @@ static px4_hw_mft_list_entry_t mft_lists[] = { }; -/************************************************************************************ - * Name: board_rc_input - * - * Description: - * All boards my optionally provide this API to invert the Serial RC input. - * This is needed on SoCs that support the notion RXINV or TXINV as opposed to - * and external XOR controlled by a GPIO - * - ************************************************************************************/ -__EXPORT bool board_supports_single_wire(uint32_t uxart_base) -{ - return uxart_base == RC_UXART_BASE; -} - /************************************************************************************ * Name: board_query_manifest * diff --git a/src/drivers/boards/common/board_common.h b/src/drivers/boards/common/board_common.h index 9784edd494..9dad6e913a 100644 --- a/src/drivers/boards/common/board_common.h +++ b/src/drivers/boards/common/board_common.h @@ -46,6 +46,7 @@ #include #include #include +#include /************************************************************************************ * Definitions ************************************************************************************/ @@ -453,32 +454,78 @@ typedef uint8_t px4_guid_t[PX4_GUID_BYTE_LENGTH]; ************************************************************************************/ __BEGIN_DECLS -/* Provide an interface for determining if a board supports single wire */ /************************************************************************************ - * Name: board_supports_single_wire + * Name: board_rc_singlewire * * Description: - * A board may provide serial ports that supports single wire. - * This interface will call into the board support code to determine - * if the interface is available at runtime, on this version of the - * hardware. + * A board may define RC_SERIAL_SINGLEWIRE, so that RC_SERIAL_PORT is configured + * as singlewire UART. * * Input Parameters: - * uxart_base - the base address of the UxART. + * device: serial device, e.g. "/dev/ttyS0" * * Returned Value: - * true the hardware supports this interface. + * true singlewire should be enabled. * false if not. * ************************************************************************************/ -#if !defined(BOARD_HAS_SINGLE_WIRE) -# define board_supports_single_wire(_uxart_base) false +#if defined(RC_SERIAL_SINGLEWIRE) +static inline bool board_rc_singlewire(const char *device) { return strcmp(device, RC_SERIAL_PORT) == 0; } #else -__EXPORT bool board_supports_single_wire(uint32_t uxart_base); +static inline bool board_rc_singlewire(const char *device) { return false; } #endif +/************************************************************************************ + * Name: board_rc_swap_rxtx + * + * Description: + * A board may define RC_SERIAL_SWAP_RXTX, so that RC_SERIAL_PORT is configured + * as UART with RX/TX swapped. + * + * Input Parameters: + * device: serial device, e.g. "/dev/ttyS0" + * + * Returned Value: + * true RX/RX should be swapped. + * false if not. + * + ************************************************************************************/ + +#if defined(RC_SERIAL_SWAP_RXTX) +static inline bool board_rc_swap_rxtx(const char *device) { return strcmp(device, RC_SERIAL_PORT) == 0; } +#else +static inline bool board_rc_swap_rxtx(const char *device) { return false; } +#endif + +/************************************************************************************ + * Name: board_rc_invert_input + * + * Description: + * All boards may optionally define RC_INVERT_INPUT(bool invert) that is + * used to invert the RC_SERIAL_PORT RC port (e.g. to toggle an external XOR via + * GPIO). + * + * Input Parameters: + * invert_on - A positive logic value, that when true (on) will set the HW in + * inverted NRZ mode where a MARK will be 0 and SPACE will be a 1. + * + * Returned Value: + * true the UART inversion got set. + * + ************************************************************************************/ + +#ifdef RC_INVERT_INPUT +static inline bool board_rc_invert_input(const char *device, bool invert) +{ + if (strcmp(device, RC_SERIAL_PORT) == 0) { RC_INVERT_INPUT(invert); return true; } + + return false; +} +#else +static inline bool board_rc_invert_input(const char *device, bool invert) { return false; } +#endif /* Provide an interface for reading the connected state of VBUS */ @@ -504,52 +551,6 @@ __EXPORT bool board_supports_single_wire(uint32_t uxart_base); int board_read_VBUS_state(void); #endif -/************************************************************************************ - * Name: board_rc_input - * - * Description: - * All boards my optionally provide this API to invert the Serial RC input. - * This is needed on SoCs that support the notion RXINV or TXINV as opposed to - * and external XOR controlled by a GPIO - * - * Input Parameters: - * invert_on - A positive logic value, that when true (on) will set the HW in - * inverted NRZ mode where a MARK will be 0 and SPACE will be a 1. - * - * Returned Value: - * None - * - ************************************************************************************/ - -/* Provide an interface for Inversion of serial data - * - * Case 1:Board does provide UxART based inversion - * Use it, and it will define RC_UXART_BASE - * - * Case 1:Board does provide GPIO inversion - * Use it and let board determine active state - * Define RC_UXART_BASE as empty - * - * Case 3:Board does not provide any inversions - * Default to nop - * Define RC_UXART_BASE as empty - */ - -#if defined(RC_UXART_BASE) -__EXPORT void board_rc_input(bool invert_on, uint32_t uxart_base); -# define INVERT_RC_INPUT(_invert_true, _rc_uxart) board_rc_input((_invert_true), (_rc_uxart)); -#endif - -#if defined(BOARD_INVERT_RC_INPUT) -# define INVERT_RC_INPUT BOARD_INVERT_RC_INPUT -# define RC_UXART_BASE 0 -#endif - -#if !defined(INVERT_RC_INPUT) -# define INVERT_RC_INPUT(_invert_true, _na) while(0) -# define RC_UXART_BASE 0 -#endif - /************************************************************************************ * Name: board_on_reset * diff --git a/src/drivers/rc_input/RCInput.cpp b/src/drivers/rc_input/RCInput.cpp index 94c654369a..58fe8002d8 100644 --- a/src/drivers/rc_input/RCInput.cpp +++ b/src/drivers/rc_input/RCInput.cpp @@ -44,7 +44,7 @@ static bool bind_spektrum(int arg); work_s RCInput::_work = {}; constexpr char const *RCInput::RC_SCAN_STRING[]; -RCInput::RCInput(bool run_as_task) : +RCInput::RCInput(bool run_as_task, char *device) : _cycle_perf(perf_alloc(PC_ELAPSED, "rc_input cycle time")), _publish_interval_perf(perf_alloc(PC_INTERVAL, "rc_input publish interval")) { @@ -58,6 +58,15 @@ RCInput::RCInput(bool run_as_task) : for (unsigned i = 0; i < input_rc_s::RC_INPUT_MAX_CHANNELS; i++) { _raw_rc_values[i] = UINT16_MAX; } + +#ifdef RC_SERIAL_PORT + + if (device) { + strncpy(_device, device, sizeof(_device)); + _device[sizeof(_device) - 1] = '\0'; + } + +#endif } RCInput::~RCInput() @@ -87,11 +96,20 @@ RCInput::init() # endif // dsm_init sets some file static variables and returns a file descriptor - _rcs_fd = dsm_init(RC_SERIAL_PORT); + _rcs_fd = dsm_init(_device); + + if (_rcs_fd < 0) { + return -errno; + } + + if (board_rc_swap_rxtx(_device)) { + ioctl(_rcs_fd, TIOCSSWAP, SER_SWAP_ENABLED); + } + // assume SBUS input and immediately switch it to // so that if Single wire mode on TX there will be only // a short contention - sbus_config(_rcs_fd, board_supports_single_wire(RC_UXART_BASE)); + sbus_config(_rcs_fd, board_rc_singlewire(_device)); # ifdef GPIO_PPM_IN // disable CPPM input by mapping it away from the timer capture input px4_arch_unconfiggpio(GPIO_PPM_IN); @@ -110,13 +128,18 @@ RCInput::task_spawn(int argc, char *argv[]) int myoptind = 1; int ch; const char *myoptarg = nullptr; + const char *device = RC_SERIAL_PORT; - while ((ch = px4_getopt(argc, argv, "t", &myoptind, &myoptarg)) != EOF) { + while ((ch = px4_getopt(argc, argv, "td:", &myoptind, &myoptarg)) != EOF) { switch (ch) { case 't': run_as_task = true; break; + case 'd': + device = myoptarg; + break; + case '?': error_flag = true; break; @@ -136,24 +159,28 @@ RCInput::task_spawn(int argc, char *argv[]) if (!run_as_task) { /* schedule a cycle to start things */ - int ret = work_queue(HPWORK, &_work, (worker_t)&RCInput::cycle_trampoline, nullptr, 0); + int ret = work_queue(HPWORK, &_work, (worker_t)&RCInput::cycle_trampoline_init, (void *)device, 0); if (ret < 0) { return ret; } + // we need to wait, otherwise 'device' could go out of scope while still being accessed + wait_until_running(); + _task_id = task_id_is_work_queue; } else { /* start the IO interface task */ + const char *const args[] = { device, nullptr }; _task_id = px4_task_spawn_cmd("rc_input", SCHED_DEFAULT, SCHED_PRIORITY_SLOW_DRIVER, 1000, (px4_main_t)&run_trampoline, - nullptr); + (char *const *)args); if (_task_id < 0) { _task_id = -1; @@ -164,29 +191,32 @@ RCInput::task_spawn(int argc, char *argv[]) return PX4_OK; } +void +RCInput::cycle_trampoline_init(void *arg) +{ + RCInput *dev = new RCInput(false, (char *)arg); + + if (!dev) { + PX4_ERR("alloc failed"); + return; + } + + int ret = dev->init(); + + if (ret != 0) { + PX4_ERR("init failed (%i)", ret); + delete dev; + return; + } + + _object.store(dev); + + dev->cycle(); +} void RCInput::cycle_trampoline(void *arg) { RCInput *dev = reinterpret_cast(arg); - - // check if the trampoline is called for the first time - if (!dev) { - dev = new RCInput(false); - - if (!dev) { - PX4_ERR("alloc failed"); - return; - } - - if (dev->init() != 0) { - PX4_ERR("init failed"); - delete dev; - return; - } - - _object.store(dev); - } - dev->cycle(); } @@ -263,17 +293,23 @@ void RCInput::set_rc_scan_state(RC_SCAN newState) _rc_scan_state = newState; } -void RCInput::rc_io_invert(bool invert, uint32_t uxart_base) +void RCInput::rc_io_invert(bool invert) { - INVERT_RC_INPUT(invert, uxart_base); + // First check if the board provides a board-specific inversion method (e.g. via GPIO), + // and if not use an IOCTL + if (!board_rc_invert_input(_device, invert)) { + ioctl(_rcs_fd, TIOCSINVERT, invert ? (SER_INVERT_ENABLED_RX | SER_INVERT_ENABLED_TX) : 0); + } } #endif void RCInput::run() { - if (init() != 0) { - PX4_ERR("init failed"); + int ret = init(); + + if (ret != 0) { + PX4_ERR("init failed (%i)", ret); exit_and_cleanup(); return; } @@ -386,8 +422,8 @@ RCInput::cycle() if (_rc_scan_begin == 0) { _rc_scan_begin = cycle_timestamp; // Configure serial port for SBUS - sbus_config(_rcs_fd, board_supports_single_wire(RC_UXART_BASE)); - rc_io_invert(true, RC_UXART_BASE); + sbus_config(_rcs_fd, board_rc_singlewire(_device)); + rc_io_invert(true); } else if (_rc_scan_locked || cycle_timestamp - _rc_scan_begin < rc_scan_max) { @@ -418,7 +454,7 @@ RCInput::cycle() _rc_scan_begin = cycle_timestamp; // // Configure serial port for DSM dsm_config(_rcs_fd); - rc_io_invert(false, RC_UXART_BASE); + rc_io_invert(false); } else if (_rc_scan_locked || cycle_timestamp - _rc_scan_begin < rc_scan_max) { @@ -451,7 +487,7 @@ RCInput::cycle() _rc_scan_begin = cycle_timestamp; // Configure serial port for DSM dsm_config(_rcs_fd); - rc_io_invert(false, RC_UXART_BASE); + rc_io_invert(false); } else if (_rc_scan_locked || cycle_timestamp - _rc_scan_begin < rc_scan_max) { @@ -499,7 +535,7 @@ RCInput::cycle() _rc_scan_begin = cycle_timestamp; // Configure serial port for DSM dsm_config(_rcs_fd); - rc_io_invert(false, RC_UXART_BASE); + rc_io_invert(false); } else if (_rc_scan_locked || cycle_timestamp - _rc_scan_begin < rc_scan_max) { @@ -541,7 +577,8 @@ RCInput::cycle() _rc_scan_begin = cycle_timestamp; // Configure timer input pin for CPPM px4_arch_configgpio(GPIO_PPM_IN); - rc_io_invert(false, RC_UXART_BASE); + rc_io_invert(false); + ioctl(_rcs_fd, TIOCSINVERT, 0); } else if (_rc_scan_locked || cycle_timestamp - _rc_scan_begin < rc_scan_max) { @@ -575,7 +612,7 @@ RCInput::cycle() _rc_scan_begin = cycle_timestamp; // Configure serial port for CRSF crsf_config(_rcs_fd); - rc_io_invert(false, RC_UXART_BASE); + rc_io_invert(false); } else if (_rc_scan_locked || cycle_timestamp - _rc_scan_begin < rc_scan_max) { @@ -707,7 +744,7 @@ bool bind_spektrum(int arg) RCInput *RCInput::instantiate(int argc, char *argv[]) { // No arguments to parse. We also know that we should run as task - return new RCInput(true); + return new RCInput(true, argv[0]); } int RCInput::custom_command(int argc, char *argv[]) @@ -760,6 +797,7 @@ When running on the work queue, it schedules at a fixed frequency. PRINT_MODULE_USAGE_NAME("rc_input", "driver"); PRINT_MODULE_USAGE_COMMAND_DESCR("start", "Start the task (without any mode set, use any of the mode_* cmds)"); PRINT_MODULE_USAGE_PARAM_FLAG('t', "Run as separate task instead of the work queue", true); + PRINT_MODULE_USAGE_PARAM_STRING('d', "/dev/ttyS3", "", "RC device", true); #if defined(SPEKTRUM_POWER) PRINT_MODULE_USAGE_COMMAND_DESCR("bind", "Send a DSM bind command (module must be running)"); @@ -777,6 +815,9 @@ int RCInput::print_status() if (!_run_as_task) { PX4_INFO("Max update rate: %i Hz", 1000000 / _current_update_interval); } + if (_device[0] != '\0') { + PX4_INFO("Serial device: %s", _device); + } PX4_INFO("RC scan state: %s, locked: %s", RC_SCAN_STRING[_rc_scan_state], _rc_scan_locked ? "yes" : "no"); PX4_INFO("CRSF Telemetry: %s", _crsf_telemetry ? "yes" : "no"); diff --git a/src/drivers/rc_input/RCInput.hpp b/src/drivers/rc_input/RCInput.hpp index 12c7632bd9..d8e62d0d50 100644 --- a/src/drivers/rc_input/RCInput.hpp +++ b/src/drivers/rc_input/RCInput.hpp @@ -63,7 +63,7 @@ class RCInput : public ModuleBase { public: - RCInput(bool run_as_task); + RCInput(bool run_as_task, char *device); virtual ~RCInput(); /** @see ModuleBase */ @@ -132,6 +132,7 @@ private: orb_advert_t _to_input_rc{nullptr}; int _rcs_fd{-1}; + char _device[20] {}; ///< device / serial port path uint8_t _rcs_buf[SBUS_BUFFER_SIZE] {}; @@ -144,6 +145,7 @@ private: perf_counter_t _publish_interval_perf; static void cycle_trampoline(void *arg); + static void cycle_trampoline_init(void *arg); int start(); void fill_rc_in(uint16_t raw_rc_count_local, @@ -153,6 +155,6 @@ private: void set_rc_scan_state(RC_SCAN _rc_scan_state); - void rc_io_invert(bool invert, uint32_t uxart_base); + void rc_io_invert(bool invert); };