From 72193eda8260767b61c2945da353a503345bdaee Mon Sep 17 00:00:00 2001 From: Raphael Coeffic Date: Thu, 9 Feb 2023 10:44:32 +0100 Subject: [PATCH] chore: New module/serial API (#3055) * WiP: new module interface * WiP: softserial timer DMA * WiP: setup() and send() in one step and remove methods specific to internal or external module * fixes and extra port config * horus targets * module ports have moved * T8 support (only internal module) * fix nv14 * stupid GCC.... * disable BT * remove nv14 telem driver * remove old aux serial driver * Move module buffers out of pulses.h * Soft serial fixes and PXX1 support * Fixed PPM module output * Fixed CLI * compilation fixes * Ported bluetooth and flysky gimbal to new serial driver * Re-enable soft-serial RX * fixes and cleanup * nv14 fixes * Fix flysky gimbals * Ghost module * 16 bytes of RAM * Remove getByte from module API * Ghost cleanup * fix: _half_duplex_input() must be called after usart init * WiP * more cleanup * Remove board specific settings from PXX1 / PXX2 drivers * A bit of PXX2 header cleanup * Add support for OVER8 and ONEBIT * Add some support for inverters (NV14 / EL18) * Support NV14 power fixes in generic board * Fix polarity handling * Fix RX DMA * Fix mixer not running * Add soft-serial polarity control * Quick fix for telemetry polling while module port is changed * Fix bootloader DEBUG * Fix MPM telemetry * Fix pulse start * DSM2 soft-serial fallback * DSMP async module restart * Fix CRSF LUA upstream * Remove global variable telemetryProtocol * Use HAL/LL constants * Fix various issue with AFHDS3 and NV14/EL18 internal module * Fixed S.PORT unit tests * fix: update widx after writing at current index * fix: init error condition * Fix: possible infinite loop in _find_port() * Add support for bidir S.PORT init * Add support for "getLastByte" in HW serial driver * PXX1: Add support for S.PORT based on IDLE callback * Fix rebase error * Fix softserial _rx_fifo_push() * Add softserial support for waitForTxCompleted() * Fix MPM flashing (internal / external) * Fixed external MPM * Activate RX DMA on internal module Seems to work with serial passthrough without issues, at least on the L3R PRO. * Fix softserial DMA on stdlcd F4 targets * Add softserial support for 32bit timers (mostly TIM2) * More precise soft-serial * Fix MPM update using inverters & HW uart * Raise S.PORT DMA/USART IRQ prio to achieve faster switching to input * Remove useless delays * Fix flashing external ELRS module * Added a retry mechanism for FrSky S.PORT update * Remove useless enableRx() * External FrSky modules are all flashed via S.PORT * Remove power management unit update This was only used on the first batch of X-lite. --- radio/src/CMakeLists.txt | 2 + radio/src/bluetooth.cpp | 48 +- radio/src/boards/generic_stm32/aux_ports.cpp | 148 ++++ .../generic_stm32/intmodule_heartbeat.cpp | 63 ++ .../generic_stm32/intmodule_heartbeat.h} | 13 +- .../src/boards/generic_stm32/module_ports.cpp | 484 ++++++++++++ radio/src/boards/generic_stm32/module_ports.h | 24 + .../src/boards/generic_stm32/sport_update.cpp | 57 ++ radio/src/boards/generic_stm32/sport_update.h | 26 + radio/src/cli.cpp | 86 +-- radio/src/dataconstants.h | 26 +- radio/src/debug.cpp | 59 -- radio/src/dmafifo.h | 83 -- radio/src/gui/128x64/model_setup.cpp | 37 +- radio/src/gui/128x64/model_telemetry.cpp | 11 +- .../src/gui/128x64/model_telemetry_sensor.cpp | 37 +- radio/src/gui/128x64/radio_setup.cpp | 5 +- radio/src/gui/128x64/view_statistics.cpp | 15 +- radio/src/gui/212x64/model_setup.cpp | 26 +- radio/src/gui/212x64/model_telemetry.cpp | 10 +- .../src/gui/212x64/model_telemetry_sensor.cpp | 33 +- radio/src/gui/212x64/radio_setup.cpp | 5 +- radio/src/gui/212x64/view_statistics.cpp | 13 +- radio/src/gui/colorlcd/crossfire_settings.cpp | 5 +- radio/src/gui/colorlcd/draw_functions.cpp | 61 +- radio/src/gui/colorlcd/hw_intmodule.cpp | 2 +- radio/src/gui/colorlcd/model_inputs.cpp | 13 +- radio/src/gui/colorlcd/model_mixes.cpp | 18 +- radio/src/gui/colorlcd/model_telemetry.cpp | 51 +- radio/src/gui/colorlcd/module_setup.cpp | 2 +- radio/src/gui/colorlcd/radio_diaganas.cpp | 2 +- radio/src/gui/colorlcd/radio_hardware.cpp | 2 +- radio/src/gui/colorlcd/radio_sdmanager.cpp | 35 +- radio/src/gui/colorlcd/radio_setup.cpp | 6 +- .../gui/colorlcd/radio_spectrum_analyser.cpp | 8 +- radio/src/gui/colorlcd/radio_tools.cpp | 5 +- radio/src/gui/colorlcd/radio_version.cpp | 20 +- radio/src/gui/colorlcd/view_statistics.cpp | 3 + .../src/gui/common/stdlcd/draw_functions.cpp | 85 +-- radio/src/gui/common/stdlcd/model_inputs.cpp | 17 +- radio/src/gui/common/stdlcd/model_mixes.cpp | 17 +- .../gui/common/stdlcd/radio_ghost_menu.cpp | 8 +- .../src/gui/common/stdlcd/radio_hardware.cpp | 24 +- .../src/gui/common/stdlcd/radio_sdmanager.cpp | 76 +- .../common/stdlcd/radio_spectrum_analyser.cpp | 2 + radio/src/gui/common/stdlcd/radio_tools.cpp | 22 +- radio/src/gui/common/stdlcd/radio_version.cpp | 36 +- radio/src/gui/gui_common.cpp | 27 +- radio/src/hal/module_driver.h | 23 +- radio/src/hal/module_port.cpp | 254 +++++++ radio/src/hal/module_port.h | 158 ++++ radio/src/hal/serial_driver.h | 66 +- radio/src/hal/serial_port.h | 1 + radio/src/hal/timer_driver.h | 41 + radio/src/io/bootloader_flash.cpp | 4 +- radio/src/io/frsky_firmware_update.cpp | 675 +++++------------ radio/src/io/frsky_firmware_update.h | 26 +- radio/src/io/multi_firmware_update.cpp | 371 ++++----- radio/src/io/multi_firmware_update.h | 8 +- radio/src/io/multi_protolist.cpp | 2 +- radio/src/logs.cpp | 4 +- radio/src/lua/api_general.cpp | 47 +- radio/src/lua/api_model.cpp | 4 + radio/src/mixer.cpp | 158 +++- radio/src/mixer_scheduler.cpp | 6 + radio/src/mixer_scheduler.h | 4 + radio/src/opentx.cpp | 266 +------ radio/src/opentx.h | 33 +- radio/src/pulses/afhds2.cpp | 64 +- radio/src/pulses/afhds2.h | 13 +- radio/src/pulses/afhds3.cpp | 148 ++-- radio/src/pulses/afhds3.h | 6 +- radio/src/pulses/afhds3_transport.cpp | 162 +--- radio/src/pulses/afhds3_transport.h | 29 +- radio/src/pulses/crossfire.cpp | 189 ++--- radio/src/pulses/crossfire.h | 3 +- radio/src/pulses/dsm2.cpp | 221 ++++-- radio/src/pulses/dsm2.h | 30 + radio/src/pulses/flysky.cpp | 321 +++----- radio/src/pulses/flysky.h | 2 +- radio/src/pulses/ghost.cpp | 159 +++- .../ghost.h} | 7 +- radio/src/pulses/modules_helpers.h | 23 +- radio/src/pulses/multi.cpp | 309 ++++---- radio/src/pulses/multi.h | 8 +- radio/src/pulses/ppm.cpp | 107 ++- radio/src/pulses/ppm.h | 26 + radio/src/pulses/pulses.cpp | 711 ++++++------------ radio/src/pulses/pulses.h | 190 ++--- radio/src/pulses/pxx.h | 110 +-- radio/src/pulses/pxx1.cpp | 281 ++++--- radio/src/pulses/pxx1.h | 157 +--- radio/src/pulses/pxx1_transport.h | 212 ++++++ radio/src/pulses/pxx2.cpp | 482 +++++------- radio/src/pulses/pxx2.h | 344 +-------- radio/src/pulses/pxx2_ota.cpp | 160 ++++ radio/src/pulses/pxx2_ota.h | 53 ++ radio/src/pulses/pxx2_transport.h | 156 ++++ radio/src/pulses/sbus.cpp | 165 ++-- radio/src/pulses/sbus.h | 26 + radio/src/rtos.h | 12 +- radio/src/serial.cpp | 105 +-- radio/src/spacemouse.cpp | 5 +- radio/src/storage/storage_common.cpp | 30 +- .../storage/yaml/yaml_datastructs_funcs.cpp | 10 +- radio/src/strhelpers.cpp | 49 +- radio/src/switches.cpp | 4 +- radio/src/targets/common/arm/CMakeLists.txt | 3 +- .../targets/common/arm/stm32/CMakeLists.txt | 9 +- .../common/arm/stm32/aux_serial_driver.cpp | 292 ------- .../common/arm/stm32/bluetooth_driver.cpp | 175 ++--- .../common/arm/stm32/bluetooth_driver.h | 52 ++ .../targets/common/arm/stm32/board_common.h | 2 - .../arm/stm32/bootloader/CMakeLists.txt | 12 +- .../common/arm/stm32/bootloader/boot.cpp | 22 +- .../common/arm/stm32/extmodule_driver.cpp | 131 +--- .../common/arm/stm32/extmodule_driver.h | 21 +- .../arm/stm32/extmodule_serial_driver.cpp | 210 ------ .../common/arm/stm32/f2/CMakeLists.txt | 1 - .../common/arm/stm32/f4/CMakeLists.txt | 1 - .../common/arm/stm32/flysky_gimbal_driver.cpp | 190 +++++ .../arm/stm32/flysky_gimbal_driver.h} | 4 + .../common/arm/stm32/heartbeat_driver.h | 1 - .../arm/stm32/intmodule_serial_driver.cpp | 220 ------ .../common/arm/stm32/module_timer_driver.cpp | 64 ++ ..._serial_driver.h => module_timer_driver.h} | 11 +- .../src/targets/common/arm/stm32/stm32_dma.h | 49 ++ .../common/arm/stm32/stm32_exti_driver.cpp | 2 +- .../common/arm/stm32/stm32_exti_driver.h | 2 +- .../targets/common/arm/stm32/stm32_hal_ll.h | 2 + .../common/arm/stm32/stm32_pulse_driver.cpp | 101 ++- .../common/arm/stm32/stm32_pulse_driver.h | 17 +- .../common/arm/stm32/stm32_serial_driver.cpp | 497 ++++++++++++ .../common/arm/stm32/stm32_serial_driver.h | 59 ++ .../arm/stm32/stm32_softserial_driver.cpp | 510 +++++++++++++ .../arm/stm32/stm32_softserial_driver.h | 107 +++ .../common/arm/stm32/stm32_usart_driver.cpp | 356 +++++++-- .../common/arm/stm32/stm32_usart_driver.h | 19 +- .../common/arm/stm32/timers_driver.cpp | 37 +- .../targets/common/arm/stm32/timers_driver.h | 4 +- .../common/arm/stm32/trainer_driver.cpp | 77 +- .../src/targets/common/arm/stm32/usbd_cdc.cpp | 9 +- radio/src/targets/horus/CMakeLists.txt | 11 +- radio/src/targets/horus/board.cpp | 163 +--- radio/src/targets/horus/board.h | 20 - .../targets/horus/flyskyHallStick_driver.cpp | 378 ---------- radio/src/targets/horus/hal.h | 61 +- radio/src/targets/horus/telemetry_driver.cpp | 434 ----------- radio/src/targets/nv14/CMakeLists.txt | 7 +- radio/src/targets/nv14/board.cpp | 28 +- radio/src/targets/nv14/board.h | 33 +- radio/src/targets/nv14/extmodule_helper.cpp | 68 -- radio/src/targets/nv14/hal.h | 28 +- radio/src/targets/nv14/telemetry_driver.cpp | 238 ------ radio/src/targets/simu/bt_driver.cpp | 10 +- radio/src/targets/simu/module_drivers.cpp | 171 ++++- radio/src/targets/simu/opentxsimulator.cpp | 4 +- radio/src/targets/simu/simpgmspace.cpp | 77 +- radio/src/targets/taranis/CMakeLists.txt | 12 +- radio/src/targets/taranis/board.cpp | 90 +-- radio/src/targets/taranis/board.h | 90 +-- radio/src/targets/taranis/hal.h | 56 +- .../taranis/intmodule_pulses_driver.cpp | 35 +- .../targets/taranis/intmodule_pulses_driver.h | 13 +- .../src/targets/taranis/telemetry_driver.cpp | 375 --------- radio/src/tasks.cpp | 151 +--- radio/src/tasks.h | 8 - radio/src/tasks/mixer_task.cpp | 243 ++++++ radio/src/tasks/mixer_task.h | 76 ++ radio/src/telemetry/crossfire.cpp | 13 +- radio/src/telemetry/crossfire.h | 23 +- radio/src/telemetry/flysky_nv14.cpp | 1 + radio/src/telemetry/frsky.cpp | 55 +- radio/src/telemetry/frsky.h | 15 +- radio/src/telemetry/frsky_d.cpp | 36 +- radio/src/telemetry/frsky_pxx2.cpp | 92 ++- radio/src/telemetry/frsky_sport.cpp | 155 +++- radio/src/telemetry/ghost.cpp | 147 ++-- radio/src/telemetry/ghost.h | 7 +- radio/src/telemetry/multi.cpp | 38 +- radio/src/telemetry/spektrum.cpp | 6 +- radio/src/telemetry/telemetry.cpp | 253 +++---- radio/src/telemetry/telemetry.h | 41 +- radio/src/telemetry/telemetry_sensors.cpp | 52 +- radio/src/tests/frsky.cpp | 132 ++-- radio/src/trainer.cpp | 1 - radio/src/translations.cpp | 3 +- radio/src/translations.h | 3 +- radio/src/translations/untranslated.h | 4 +- 189 files changed, 7960 insertions(+), 8364 deletions(-) create mode 100644 radio/src/boards/generic_stm32/aux_ports.cpp create mode 100644 radio/src/boards/generic_stm32/intmodule_heartbeat.cpp rename radio/src/{targets/common/arm/stm32/aux_serial_driver.h => boards/generic_stm32/intmodule_heartbeat.h} (77%) create mode 100644 radio/src/boards/generic_stm32/module_ports.cpp create mode 100644 radio/src/boards/generic_stm32/module_ports.h create mode 100644 radio/src/boards/generic_stm32/sport_update.cpp create mode 100644 radio/src/boards/generic_stm32/sport_update.h delete mode 100644 radio/src/dmafifo.h create mode 100644 radio/src/hal/module_port.cpp create mode 100644 radio/src/hal/module_port.h create mode 100644 radio/src/hal/timer_driver.h create mode 100644 radio/src/pulses/dsm2.h rename radio/src/{targets/common/arm/stm32/intmodule_serial_driver.h => pulses/ghost.h} (83%) create mode 100644 radio/src/pulses/ppm.h create mode 100644 radio/src/pulses/pxx1_transport.h create mode 100644 radio/src/pulses/pxx2_ota.cpp create mode 100644 radio/src/pulses/pxx2_ota.h create mode 100644 radio/src/pulses/pxx2_transport.h create mode 100644 radio/src/pulses/sbus.h delete mode 100644 radio/src/targets/common/arm/stm32/aux_serial_driver.cpp create mode 100644 radio/src/targets/common/arm/stm32/bluetooth_driver.h delete mode 100644 radio/src/targets/common/arm/stm32/extmodule_serial_driver.cpp create mode 100644 radio/src/targets/common/arm/stm32/flysky_gimbal_driver.cpp rename radio/src/targets/{horus/flyskyHallStick_driver.h => common/arm/stm32/flysky_gimbal_driver.h} (96%) delete mode 100755 radio/src/targets/common/arm/stm32/intmodule_serial_driver.cpp create mode 100644 radio/src/targets/common/arm/stm32/module_timer_driver.cpp rename radio/src/targets/common/arm/stm32/{extmodule_serial_driver.h => module_timer_driver.h} (70%) create mode 100644 radio/src/targets/common/arm/stm32/stm32_dma.h create mode 100644 radio/src/targets/common/arm/stm32/stm32_serial_driver.cpp create mode 100644 radio/src/targets/common/arm/stm32/stm32_serial_driver.h create mode 100644 radio/src/targets/common/arm/stm32/stm32_softserial_driver.cpp create mode 100644 radio/src/targets/common/arm/stm32/stm32_softserial_driver.h delete mode 100644 radio/src/targets/horus/flyskyHallStick_driver.cpp delete mode 100644 radio/src/targets/horus/telemetry_driver.cpp delete mode 100644 radio/src/targets/nv14/extmodule_helper.cpp delete mode 100644 radio/src/targets/nv14/telemetry_driver.cpp delete mode 100644 radio/src/targets/taranis/telemetry_driver.cpp create mode 100644 radio/src/tasks/mixer_task.cpp create mode 100644 radio/src/tasks/mixer_task.h diff --git a/radio/src/CMakeLists.txt b/radio/src/CMakeLists.txt index fa10f2b6c..a896d482d 100644 --- a/radio/src/CMakeLists.txt +++ b/radio/src/CMakeLists.txt @@ -472,6 +472,8 @@ set(SRC model_init.cpp serial.cpp sbus.cpp + hal/module_port.cpp + tasks/mixer_task.cpp ) if(GUI) diff --git a/radio/src/bluetooth.cpp b/radio/src/bluetooth.cpp index bb617671e..cab649403 100644 --- a/radio/src/bluetooth.cpp +++ b/radio/src/bluetooth.cpp @@ -22,6 +22,7 @@ #include #include "opentx.h" #include "io/frsky_firmware_update.h" +#include "bluetooth_driver.h" #if defined(LIBOPENUI) #include "libopenui.h" @@ -49,37 +50,25 @@ extern FIL g_bluetoothFile; #define SWAP32(val) (__builtin_bswap32(val)) #endif -extern Fifo btTxFifo; -extern Fifo btRxFifo; - Bluetooth bluetooth; void Bluetooth::write(const uint8_t * data, uint8_t length) { - if (btTxFifo.hasSpace(length)) { - BLUETOOTH_TRACE_VERBOSE("BT>"); - for (int i = 0; i < length; i++) { - BLUETOOTH_TRACE_VERBOSE(" %02X", data[i]); - btTxFifo.push(data[i]); - } - BLUETOOTH_TRACE_VERBOSE(CRLF); + BLUETOOTH_TRACE_VERBOSE("BT>"); + for (int i = 0; i < length; i++) { + BLUETOOTH_TRACE_VERBOSE(" %02X", data[i]); } - else { - BLUETOOTH_TRACE("[BT] TX fifo full!" CRLF); - } - - bluetoothWriteWakeup(); + BLUETOOTH_TRACE_VERBOSE(CRLF); + bluetoothWrite(data, length); } +static const char _bt_crlf[] = "\r\n"; + void Bluetooth::writeString(const char * str) { BLUETOOTH_TRACE("BT> %s" CRLF, str); - while (*str != 0) { - btTxFifo.push(*str++); - } - btTxFifo.push('\r'); - btTxFifo.push('\n'); - bluetoothWriteWakeup(); + bluetoothWrite(str, strlen(str)); + bluetoothWrite(_bt_crlf, sizeof(_bt_crlf) - 1); } char * Bluetooth::readline(bool error_reset) @@ -87,7 +76,7 @@ char * Bluetooth::readline(bool error_reset) uint8_t byte; while (true) { - if (!btRxFifo.pop(byte)) { + if (!bluetoothRead(&byte)) { #if defined(PCBX9E) // X9E BT module can get unresponsive BLUETOOTH_TRACE("NO RESPONSE FROM BT MODULE" CRLF); @@ -327,7 +316,7 @@ void Bluetooth::receiveTrainer() uint8_t byte; while (true) { - if (!btRxFifo.pop(byte)) { + if (!bluetoothRead(&byte)) { return; } @@ -398,7 +387,6 @@ void Bluetooth::wakeup(void) } else if (IS_BLUETOOTH_TRAINER()){ state = BLUETOOTH_STATE_CONNECTED; - bluetoothWriteWakeup(); sendTrainer(); } } @@ -408,7 +396,6 @@ void Bluetooth::wakeup(void) void Bluetooth::wakeup() { if (state != BLUETOOTH_STATE_OFF) { - bluetoothWriteWakeup(); if (bluetoothIsWriting()) { return; } @@ -425,7 +412,10 @@ void Bluetooth::wakeup() return; } - if (g_eeGeneral.bluetoothMode == BLUETOOTH_OFF || (g_eeGeneral.bluetoothMode == BLUETOOTH_TRAINER && !IS_BLUETOOTH_TRAINER())) { + if (g_eeGeneral.bluetoothMode == BLUETOOTH_OFF || + (g_eeGeneral.bluetoothMode == BLUETOOTH_TRAINER && + !IS_BLUETOOTH_TRAINER())) { + if (state != BLUETOOTH_STATE_OFF) { bluetoothDisable(); state = BLUETOOTH_STATE_OFF; @@ -567,7 +557,7 @@ uint8_t Bluetooth::read(uint8_t * data, uint8_t size, uint32_t timeout) while (len < size) { uint32_t elapsed = 0; uint8_t byte; - while (!btRxFifo.pop(byte)) { + while (!bluetoothRead(&byte)) { if (elapsed++ >= timeout) { return len; } @@ -825,7 +815,7 @@ const char * Bluetooth::flashFirmware(const char * filename, ProgressHandler pro state = BLUETOOTH_STATE_FLASH_FIRMWARE; - pausePulses(); + pulsesStop(); bluetoothInit(BLUETOOTH_BOOTLOADER_BAUDRATE, true); // normal mode watchdogSuspend(500 /*5s*/); @@ -854,7 +844,7 @@ const char * Bluetooth::flashFirmware(const char * filename, ProgressHandler pro RTOS_WAIT_MS(1000); state = BLUETOOTH_STATE_OFF; - resumePulses(); + pulsesStart(); return result; } diff --git a/radio/src/boards/generic_stm32/aux_ports.cpp b/radio/src/boards/generic_stm32/aux_ports.cpp new file mode 100644 index 000000000..a006334fa --- /dev/null +++ b/radio/src/boards/generic_stm32/aux_ports.cpp @@ -0,0 +1,148 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "hal/serial_port.h" +#include "stm32_serial_driver.h" + +#include "board.h" +#include "dataconstants.h" + +#define AUX_SERIAL_TX_BUFFER 512 +#if defined(SDRAM) + #define AUX_SERIAL_RX_BUFFER 512 +#else + #define AUX_SERIAL_RX_BUFFER 32 +#endif + +#if defined(AUX_SERIAL_PWR_GPIO) || defined(AUX2_SERIAL_PWR_GPIO) +static void _aux_pwr(GPIO_TypeDef *GPIOx, uint32_t pin, uint8_t on) +{ + LL_GPIO_InitTypeDef pinInit; + LL_GPIO_StructInit(&pinInit); + pinInit.Pin = pin; + pinInit.Mode = LL_GPIO_MODE_OUTPUT; + pinInit.Pull = LL_GPIO_PULL_UP; + LL_GPIO_Init(GPIOx, &pinInit); + + if (on) { + LL_GPIO_SetOutputPin(GPIOx, pin); + } else { + LL_GPIO_ResetOutputPin(GPIOx, pin); + } +} +#endif + +#if defined(AUX_SERIAL) + +#if !defined(AUX_SERIAL_DMA_TX) + #define AUX_SERIAL_DMA_TX nullptr + #define AUX_SERIAL_DMA_Stream_TX nullptr + #define AUX_SERIAL_DMA_Stream_TX_LL 0 + #define AUX_SERIAL_DMA_Channel_TX 0 +#endif + +static const stm32_usart_t auxUSART = { + .USARTx = AUX_SERIAL_USART, + .GPIOx = AUX_SERIAL_GPIO, + .GPIO_Pin = AUX_SERIAL_GPIO_PIN_TX | AUX_SERIAL_GPIO_PIN_RX, + .IRQn = AUX_SERIAL_USART_IRQn, + .IRQ_Prio = 7, // TODO: define constant + .txDMA = AUX_SERIAL_DMA_TX, + .txDMA_Stream = AUX_SERIAL_DMA_Stream_TX_LL, + .txDMA_Channel = AUX_SERIAL_DMA_Channel_TX, + .rxDMA = AUX_SERIAL_DMA_RX, + .rxDMA_Stream = AUX_SERIAL_DMA_Stream_RX_LL, + .rxDMA_Channel = AUX_SERIAL_DMA_Channel_RX, +}; + +DEFINE_STM32_SERIAL_PORT(Aux, auxUSART, AUX_SERIAL_RX_BUFFER, AUX_SERIAL_TX_BUFFER); + +#if defined(AUX_SERIAL_PWR_GPIO) +void set_aux_pwr(uint8_t on) +{ + _aux_pwr(AUX_SERIAL_PWR_GPIO, AUX_SERIAL_PWR_GPIO_PIN, on); +} +#define AUX_PWR_FCT set_aux_pwr +#else +#define AUX_PWR_FCT nullptr +#endif + +const etx_serial_port_t auxSerialPort = { + .name = "AUX1", + .uart = &STM32SerialDriver, + .hw_def = REF_STM32_SERIAL_PORT(Aux), + AUX_PWR_FCT +}; +#define AUX_SERIAL_PORT &auxSerialPort +#else +#define AUX_SERIAL_PORT nullptr +#endif + +#if defined(AUX2_SERIAL) + +static const stm32_usart_t aux2USART = { + .USARTx = AUX2_SERIAL_USART, + .GPIOx = AUX2_SERIAL_GPIO, + .GPIO_Pin = AUX2_SERIAL_GPIO_PIN_TX | AUX2_SERIAL_GPIO_PIN_RX, + .IRQn = AUX2_SERIAL_USART_IRQn, + .IRQ_Prio = 7, // TODO: define constant + .txDMA = nullptr, + .txDMA_Stream = 0, + .txDMA_Channel = 0, + .rxDMA = AUX2_SERIAL_DMA_RX, + .rxDMA_Stream = AUX2_SERIAL_DMA_Stream_RX_LL, + .rxDMA_Channel = AUX2_SERIAL_DMA_Channel_RX, +}; + +DEFINE_STM32_SERIAL_PORT(Aux2, aux2USART, AUX_SERIAL_RX_BUFFER, AUX_SERIAL_TX_BUFFER); + +#if defined(AUX2_SERIAL_PWR_GPIO) +void set_aux2_pwr(uint8_t on) +{ + _aux_pwr(AUX2_SERIAL_PWR_GPIO, AUX2_SERIAL_PWR_GPIO_PIN, on); +} +#define AUX2_PWR_FCT set_aux2_pwr +#else +#define AUX2_PWR_FCT nullptr +#endif + +const etx_serial_port_t aux2SerialPort = { + .name = "AUX2", + .uart = &STM32SerialDriver, + .hw_def = REF_STM32_SERIAL_PORT(Aux2), + AUX2_PWR_FCT +}; +#define AUX2_SERIAL_PORT &aux2SerialPort +#else +#define AUX2_SERIAL_PORT nullptr +#endif + +static const etx_serial_port_t* serialPorts[MAX_AUX_SERIAL] = { + AUX_SERIAL_PORT, + AUX2_SERIAL_PORT, +}; + +const etx_serial_port_t* auxSerialGetPort(int port_nr) +{ + if (port_nr >= MAX_AUX_SERIAL) return nullptr; + return serialPorts[port_nr]; +} + diff --git a/radio/src/boards/generic_stm32/intmodule_heartbeat.cpp b/radio/src/boards/generic_stm32/intmodule_heartbeat.cpp new file mode 100644 index 000000000..3def287cb --- /dev/null +++ b/radio/src/boards/generic_stm32/intmodule_heartbeat.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "intmodule_heartbeat.h" + +#include "heartbeat_driver.h" +#include "mixer_scheduler.h" +#include "dataconstants.h" +#include "pulses/pxx.h" + +#if defined(PXX1) + #include "pulses/pxx1.h" + #define isPxx1Driver(drv) (drv == &Pxx1Driver) +#else + #define isPxx1Driver(drv) (false) +#endif + +#if defined(PXX2) + #include "pulses/pxx2.h" + #define isPxx2Driver(drv) (drv == &Pxx2Driver) +#else + #define isPxx2Driver(drv) (false) +#endif + +void _intmodule_heartbeat_init(uint8_t module, const etx_proto_driver_t* drv) +{ + if (module == INTERNAL_MODULE && (isPxx1Driver(drv) || isPxx2Driver(drv))) { + init_intmodule_heartbeat(); + if (isPxx1Driver(drv)) { + // XJT / iXJT + auto period = mixerSchedulerGetPeriod(module); + mixerSchedulerSetPeriod(module, period + 1000/*us*/); + } else if (isPxx2Driver(drv)) { + // ISRM + mixerSchedulerSetPeriod(module, PXX2_MAX_HEARTBEAT_PERIOD); + } + } +} + +void _intmodule_heartbeat_deinit(uint8_t module, const etx_proto_driver_t* drv) +{ + if (module == INTERNAL_MODULE) { + stop_intmodule_heartbeat(); + } +} diff --git a/radio/src/targets/common/arm/stm32/aux_serial_driver.h b/radio/src/boards/generic_stm32/intmodule_heartbeat.h similarity index 77% rename from radio/src/targets/common/arm/stm32/aux_serial_driver.h rename to radio/src/boards/generic_stm32/intmodule_heartbeat.h index 2e8625354..b2f1ef911 100644 --- a/radio/src/targets/common/arm/stm32/aux_serial_driver.h +++ b/radio/src/boards/generic_stm32/intmodule_heartbeat.h @@ -19,15 +19,10 @@ * GNU General Public License for more details. */ -#include +#pragma once -#include "hal/serial_driver.h" +#include "hal/module_driver.h" -#if defined(AUX_SERIAL) -extern const etx_serial_driver_t AuxSerialDriver; -#endif - -#if defined(AUX2_SERIAL) -extern const etx_serial_driver_t Aux2SerialDriver; -#endif +void _intmodule_heartbeat_init(uint8_t module, const etx_proto_driver_t* drv); +void _intmodule_heartbeat_deinit(uint8_t module, const etx_proto_driver_t* drv); diff --git a/radio/src/boards/generic_stm32/module_ports.cpp b/radio/src/boards/generic_stm32/module_ports.cpp new file mode 100644 index 000000000..915a67be3 --- /dev/null +++ b/radio/src/boards/generic_stm32/module_ports.cpp @@ -0,0 +1,484 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "hal/module_port.h" +#include "stm32_serial_driver.h" +#include "stm32_softserial_driver.h" + +#include "module_ports.h" +#include "board.h" +#include "dataconstants.h" + +#if defined(INTMODULE_USART) + +#define INTMODULE_USART_IRQ_PRIORITY 6 + +static const stm32_usart_t intmoduleUSART = { + .USARTx = INTMODULE_USART, + .GPIOx = INTMODULE_GPIO, + .GPIO_Pin = INTMODULE_TX_GPIO_PIN | INTMODULE_RX_GPIO_PIN, + .IRQn = INTMODULE_USART_IRQn, + .IRQ_Prio = INTMODULE_USART_IRQ_PRIORITY, +#if defined(INTMODULE_DMA) + .txDMA = INTMODULE_DMA, + .txDMA_Stream = INTMODULE_DMA_STREAM, + .txDMA_Channel = INTMODULE_DMA_CHANNEL, +#else + .txDMA = nullptr, + .txDMA_Stream = 0, + .txDMA_Channel = 0, +#endif +#if defined(INTMODULE_RX_DMA) + .rxDMA = INTMODULE_RX_DMA, + .rxDMA_Stream = INTMODULE_RX_DMA_STREAM, + .rxDMA_Channel = INTMODULE_RX_DMA_CHANNEL, +#else + .rxDMA = nullptr, + .rxDMA_Stream = 0, + .rxDMA_Channel = 0, +#endif +}; + +DEFINE_STM32_SERIAL_PORT(InternalModule, intmoduleUSART, INTMODULE_FIFO_SIZE, 0); + +#else // INTMODULE_USART + +#include "stm32_pulse_driver.h" +#include "timers_driver.h" + +extern const stm32_pulse_timer_t intmoduleTimer; +DEFINE_STM32_SOFTSERIAL_PORT(InternalModule, intmoduleTimer); + +#endif + +#include "module_timer_driver.h" +#include "extmodule_driver.h" + +#if defined(HARDWARE_EXTERNAL_MODULE) +#if defined(EXTMODULE_USART) + +#define EXTMODULE_USART_IRQ_PRIORITY 6 + +#if defined(EXTMODULE_TX_INVERT_GPIO) && defined(EXTMODULE_RX_INVERT_GPIO) +static void _extmod_set_inverted(uint8_t enable) +{ + // In EdgeTX the external module is normally always + // inverted, so invert the logic here + if (!enable) { + LL_GPIO_SetOutputPin(EXTMODULE_TX_INVERT_GPIO, + EXTMODULE_TX_INVERT_GPIO_PIN); + LL_GPIO_SetOutputPin(EXTMODULE_RX_INVERT_GPIO, + EXTMODULE_RX_INVERT_GPIO_PIN); + } else { + LL_GPIO_ResetOutputPin(EXTMODULE_TX_INVERT_GPIO, + EXTMODULE_TX_INVERT_GPIO_PIN); + LL_GPIO_ResetOutputPin(EXTMODULE_RX_INVERT_GPIO, + EXTMODULE_RX_INVERT_GPIO_PIN); + } +} + +static void _extmod_init_inverter() +{ + LL_GPIO_InitTypeDef pinInit; + LL_GPIO_StructInit(&pinInit); + + pinInit.Mode = LL_GPIO_MODE_OUTPUT; + pinInit.Pin = EXTMODULE_TX_INVERT_GPIO_PIN; + LL_GPIO_Init(EXTMODULE_TX_INVERT_GPIO, &pinInit); + + pinInit.Pin = EXTMODULE_RX_INVERT_GPIO_PIN; + LL_GPIO_Init(EXTMODULE_RX_INVERT_GPIO, &pinInit); + + // this sets the output to idle-low as is + // the default in EdgeTX on external module + // (historically, most radios work this way) + _extmod_set_inverted(false); +} +#endif + +static const stm32_usart_t extmoduleUSART = { + .USARTx = EXTMODULE_USART, + .GPIOx = EXTMODULE_TX_GPIO, + .GPIO_Pin = EXTMODULE_TX_GPIO_PIN | EXTMODULE_RX_GPIO_PIN, + .IRQn = EXTMODULE_USART_IRQn, + .IRQ_Prio = EXTMODULE_USART_IRQ_PRIORITY, + .txDMA = EXTMODULE_USART_TX_DMA, + .txDMA_Stream = EXTMODULE_USART_TX_DMA_STREAM_LL, + .txDMA_Channel = EXTMODULE_USART_TX_DMA_CHANNEL, + .rxDMA = EXTMODULE_USART_TX_DMA, + .rxDMA_Stream = EXTMODULE_USART_RX_DMA_STREAM_LL, + .rxDMA_Channel = EXTMODULE_USART_RX_DMA_CHANNEL, + .set_input = nullptr, + .txDMA_IRQn = (IRQn_Type)0, + .txDMA_IRQ_Prio = 0, +}; + +DEFINE_STM32_SERIAL_PORT(ExternalModule, extmoduleUSART, INTMODULE_FIFO_SIZE, 0); + +#endif + +DEFINE_STM32_SOFTSERIAL_PORT(ExternalModule, extmoduleTimer); +#endif + +#define TELEMETRY_USART_IRQ_PRIORITY 5 +#define TELEMETRY_DMA_IRQ_PRIORITY 0 + +static void _set_sport_input(uint8_t enable) +{ + if (TELEMETRY_SET_INPUT) { + if (enable) { + LL_GPIO_SetOutputPin(TELEMETRY_DIR_GPIO, TELEMETRY_DIR_GPIO_PIN); + } else { + LL_GPIO_ResetOutputPin(TELEMETRY_DIR_GPIO, TELEMETRY_DIR_GPIO_PIN); + } + } else { + if (enable) { + LL_GPIO_ResetOutputPin(TELEMETRY_DIR_GPIO, TELEMETRY_DIR_GPIO_PIN); + } else { + LL_GPIO_SetOutputPin(TELEMETRY_DIR_GPIO, TELEMETRY_DIR_GPIO_PIN); + } + } +} + +#if defined(TELEMETRY_REV_GPIO) +static void _sport_set_inverted(uint8_t enable) +{ + uint32_t pins = TELEMETRY_TX_REV_GPIO_PIN | TELEMETRY_RX_REV_GPIO_PIN; + if (!enable) { + LL_GPIO_SetOutputPin(TELEMETRY_REV_GPIO, pins); + } else { + LL_GPIO_ResetOutputPin(TELEMETRY_REV_GPIO, pins); + } +} + +static void _sport_init_inverter() +{ + LL_GPIO_InitTypeDef pinInit; + LL_GPIO_StructInit(&pinInit); + + pinInit.Pin = TELEMETRY_TX_REV_GPIO_PIN | TELEMETRY_RX_REV_GPIO_PIN; + pinInit.Mode = LL_GPIO_MODE_OUTPUT; + LL_GPIO_Init(TELEMETRY_REV_GPIO, &pinInit); + _sport_set_inverted(false); +} +#endif + +static const stm32_usart_t sportUSART = { + .USARTx = TELEMETRY_USART, + .GPIOx = TELEMETRY_GPIO, + .GPIO_Pin = TELEMETRY_TX_GPIO_PIN | TELEMETRY_RX_GPIO_PIN, + .IRQn = TELEMETRY_USART_IRQn, + .IRQ_Prio = TELEMETRY_USART_IRQ_PRIORITY, + .txDMA = TELEMETRY_DMA, + .txDMA_Stream = TELEMETRY_DMA_Stream_TX, + .txDMA_Channel = TELEMETRY_DMA_Channel_TX, + .rxDMA = nullptr, + .rxDMA_Stream = 0, + .rxDMA_Channel = 0, + .set_input = _set_sport_input, + .txDMA_IRQn = TELEMETRY_DMA_TX_Stream_IRQ, + .txDMA_IRQ_Prio = TELEMETRY_DMA_IRQ_PRIORITY, +}; + +extern "C" void TELEMETRY_DMA_TX_IRQHandler(void) +{ + stm32_usart_tx_dma_isr(&sportUSART); +} + +DEFINE_STM32_SERIAL_PORT(SportModule, sportUSART, TELEMETRY_FIFO_SIZE, 0); + +static void _sport_direction_init() +{ + LL_GPIO_InitTypeDef dirPinInit; + LL_GPIO_StructInit(&dirPinInit); + + dirPinInit.Pin = TELEMETRY_DIR_GPIO_PIN; + dirPinInit.Mode = LL_GPIO_MODE_OUTPUT; + LL_GPIO_Init(TELEMETRY_DIR_GPIO, &dirPinInit); +} + +#if defined(TELEMETRY_TIMER) +static const stm32_softserial_rx_port sportSoftRX = { + .GPIOx = TELEMETRY_GPIO, + .GPIO_Pin = TELEMETRY_RX_GPIO_PIN, + .TIMx = TELEMETRY_TIMER, + .TIM_Freq = PERI2_FREQUENCY * TIMER_MULT_APB2, + .TIM_IRQn = TELEMETRY_TIMER_IRQn, + .EXTI_Port = TELEMETRY_EXTI_PORT, + .EXTI_SysLine = TELEMETRY_EXTI_SYS_LINE, + .EXTI_Line = TELEMETRY_EXTI_LINE, + .dir_GPIOx = TELEMETRY_DIR_GPIO, + .dir_Pin = TELEMETRY_DIR_GPIO_PIN, + .dir_Input = TELEMETRY_SET_INPUT, + // re-use S.PORT serial RX buffer + .buffer = { SportModule_RXBuffer, TELEMETRY_FIFO_SIZE }, +}; + +extern "C" void TELEMETRY_TIMER_IRQHandler() +{ + stm32_softserial_rx_timer_isr(&sportSoftRX); +} +#endif + +#if defined(HARDWARE_INTERNAL_MODULE) + +static void _internal_module_set_pwr(uint8_t enable) +{ + if (enable) { + INTERNAL_MODULE_ON(); + } else { + INTERNAL_MODULE_OFF(); + } +} + +#if defined(INTMODULE_BOOTCMD_GPIO) +static void _internal_module_set_bootcmd(uint8_t enable) +{ + // If default state is SET, invert the logic + if (INTMODULE_BOOTCMD_DEFAULT) { + enable = !enable; + } + + if (enable) { + LL_GPIO_SetOutputPin(INTMODULE_BOOTCMD_GPIO, INTMODULE_BOOTCMD_GPIO_PIN); + } else { + LL_GPIO_ResetOutputPin(INTMODULE_BOOTCMD_GPIO, INTMODULE_BOOTCMD_GPIO_PIN); + } +} +#endif + +static const etx_module_port_t _internal_ports[] = { +#if defined(INTMODULE_USART) + { + .port = ETX_MOD_PORT_UART, + .type = ETX_MOD_TYPE_SERIAL, + .dir_flags = ETX_MOD_DIR_TX_RX | ETX_MOD_FULL_DUPLEX, + .drv = { .serial = &STM32SerialDriver }, + .hw_def = REF_STM32_SERIAL_PORT(InternalModule), + }, +#else // INTMODULE_USART + { + .port = ETX_MOD_PORT_SOFT_INV, + .type = ETX_MOD_TYPE_SERIAL, + .dir_flags = ETX_MOD_DIR_TX, + .drv = { .serial = &STM32SoftSerialTxDriver }, + .hw_def = REF_STM32_SOFTSERIAL_PORT(InternalModule), + }, +#endif +#if defined(INTERNAL_MODULE_PXX1) + { + .port = ETX_MOD_PORT_SPORT, + .type = ETX_MOD_TYPE_SERIAL, + .dir_flags = ETX_MOD_DIR_TX | ETX_MOD_DIR_RX, + .drv = { .serial = &STM32SerialDriver }, + .hw_def = REF_STM32_SERIAL_PORT(SportModule), + }, +#endif +}; + +static const etx_module_t _internal_module = { + .ports = _internal_ports, + .set_pwr = _internal_module_set_pwr, +#if defined(INTMODULE_BOOTCMD_GPIO) + .set_bootcmd = _internal_module_set_bootcmd, +#else + .set_bootcmd = nullptr, +#endif + .n_ports = DIM(_internal_ports), +}; +#endif + +#if defined(HARDWARE_EXTERNAL_MODULE) + +static void _external_module_set_pwr(uint8_t enable) +{ + if (enable) { + EXTERNAL_MODULE_ON(); +#if defined(PCBNV14) + if (hardwareOptions.pcbrev == PCBREV_NV14) { + LL_GPIO_ResetOutputPin(EXTMODULE_PWR_FIX_GPIO, EXTMODULE_PWR_FIX_GPIO_PIN); + } +#endif + } else { + EXTERNAL_MODULE_OFF(); +#if defined(PCBNV14) + if (hardwareOptions.pcbrev == PCBREV_NV14) { + LL_GPIO_SetOutputPin(EXTMODULE_PWR_FIX_GPIO, EXTMODULE_PWR_FIX_GPIO_PIN); + } +#endif + } +} + +static const etx_module_port_t _external_ports[] = { +#if defined(EXTMODULE_USART) + // TX on PPM, RX on HEARTBEAT + { + .port = ETX_MOD_PORT_UART, + .type = ETX_MOD_TYPE_SERIAL, + .dir_flags = ETX_MOD_DIR_TX_RX | ETX_MOD_FULL_DUPLEX, + .drv = { .serial = &STM32SerialDriver }, + .hw_def = REF_STM32_SERIAL_PORT(ExternalModule), +#if defined(EXTMODULE_TX_INVERT_GPIO) && defined(EXTMODULE_RX_INVERT_GPIO) + .set_inverted = _extmod_set_inverted, +#else + .set_inverted = nullptr, +#endif + }, +#endif + // Timer output on PPM + { + .port = ETX_MOD_PORT_TIMER, + .type = ETX_MOD_TYPE_TIMER, + .dir_flags = ETX_MOD_DIR_TX, + .drv = { .timer = &STM32ModuleTimerDriver }, + .hw_def = (void*)&extmoduleTimer, +#if defined(EXTMODULE_TX_INVERT_GPIO) && defined(EXTMODULE_RX_INVERT_GPIO) + .set_inverted = _extmod_set_inverted, +#else + .set_inverted = nullptr, +#endif + }, + // TX inverted DMA pulse train on PPM + { + .port = ETX_MOD_PORT_SOFT_INV, + .type = ETX_MOD_TYPE_SERIAL, + .dir_flags = ETX_MOD_DIR_TX, + .drv = { .serial = &STM32SoftSerialTxDriver }, + .hw_def = REF_STM32_SOFTSERIAL_PORT(ExternalModule), +#if defined(EXTMODULE_TX_INVERT_GPIO) && defined(EXTMODULE_RX_INVERT_GPIO) + .set_inverted = _extmod_set_inverted, +#else + .set_inverted = nullptr, +#endif + }, + // TX/RX half-duplex on S.PORT + { + .port = ETX_MOD_PORT_SPORT, + .type = ETX_MOD_TYPE_SERIAL, + .dir_flags = ETX_MOD_DIR_TX | ETX_MOD_DIR_RX, + .drv = { .serial = &STM32SerialDriver }, + .hw_def = REF_STM32_SERIAL_PORT(SportModule), +#if defined(TELEMETRY_REV_GPIO) + .set_inverted = _sport_set_inverted, +#else + .set_inverted = nullptr, +#endif + }, +#if defined(TELEMETRY_TIMER) + // RX soft-serial sampled bit-by-bit via timer IRQ on S.PORT + { + .port = ETX_MOD_PORT_SPORT_INV, + .type = ETX_MOD_TYPE_SERIAL, + .dir_flags = ETX_MOD_DIR_RX, + .drv = { .serial = &STM32SoftSerialRxDriver }, + .hw_def = (void*)&sportSoftRX, + }, +#endif +}; + +static const etx_module_t _external_module = { + .ports = _external_ports, + .set_pwr = _external_module_set_pwr, + .set_bootcmd = nullptr, + .n_ports = DIM(_external_ports), +}; +#endif + +#if defined(SPORT_UPDATE_PWR_GPIO) +#include "sport_update.h" + +// Not declared 'static' to be accessible +// from board.cpp +void _sport_set_pwr(uint8_t enabled) +{ + if (enabled) { + LL_GPIO_SetOutputPin(SPORT_UPDATE_PWR_GPIO, SPORT_UPDATE_PWR_GPIO_PIN); + } else { + LL_GPIO_ResetOutputPin(SPORT_UPDATE_PWR_GPIO, SPORT_UPDATE_PWR_GPIO_PIN); + } +} + +#if defined(RADIO_X7) +// set_pwr is set at runtime once +// the PCB has been identified +etx_module_t _sport_module = { + .ports = nullptr, + .set_pwr = nullptr, + .set_bootcmd = nullptr, + .n_ports = 0, +}; +#else +const etx_module_t _sport_module = { + .ports = nullptr, + .set_pwr = _sport_set_pwr, + .set_bootcmd = nullptr, + .n_ports = 0, +}; +#endif // RADIO_X7 + +#endif // SPORT_UPDATE_PWR_GPIO + +void boardInitModulePorts() +{ + _sport_direction_init(); +#if defined(SPORT_UPDATE_PWR_GPIO) + sportUpdateInit(); +#endif + +#if defined(TELEMETRY_REV_GPIO) + _sport_init_inverter(); +#endif +#if defined(EXTMODULE_TX_INVERT_GPIO) && defined(EXTMODULE_RX_INVERT_GPIO) + _extmod_init_inverter(); +#endif + +#if defined(PCBNV14) + if (hardwareOptions.pcbrev == PCBREV_NV14) { + LL_GPIO_InitTypeDef pinInit; + LL_GPIO_StructInit(&pinInit); + pinInit.Pin = EXTMODULE_PWR_FIX_GPIO_PIN; + pinInit.Mode = LL_GPIO_MODE_OUTPUT; + + // pin must be pulled to V+ (voltage of board - VCC is not enough to fully close transistor) + // for additional transistor to ensuring module is completely disabled + pinInit.OutputType = LL_GPIO_OUTPUT_OPENDRAIN; + + LL_GPIO_SetOutputPin(EXTMODULE_PWR_FIX_GPIO, EXTMODULE_PWR_FIX_GPIO_PIN); + LL_GPIO_Init(EXTMODULE_PWR_FIX_GPIO, &pinInit); + } +#endif +} + +BEGIN_MODULES() +#if defined(HARDWARE_INTERNAL_MODULE) + &_internal_module, +#else + nullptr, +#endif +#if defined(HARDWARE_EXTERNAL_MODULE) + &_external_module, +#else + nullptr, +#endif +#if defined(SPORT_UPDATE_PWR_GPIO) + &_sport_module, +#endif +END_MODULES() diff --git a/radio/src/boards/generic_stm32/module_ports.h b/radio/src/boards/generic_stm32/module_ports.h new file mode 100644 index 000000000..43e41e3ab --- /dev/null +++ b/radio/src/boards/generic_stm32/module_ports.h @@ -0,0 +1,24 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#pragma once + +void boardInitModulePorts(); diff --git a/radio/src/boards/generic_stm32/sport_update.cpp b/radio/src/boards/generic_stm32/sport_update.cpp new file mode 100644 index 000000000..1b5617400 --- /dev/null +++ b/radio/src/boards/generic_stm32/sport_update.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "hal.h" +#include "stm32_hal_ll.h" + +#include "hal/module_port.h" +#include "opentx.h" // g_eeGeneral + +void sportUpdateInit() +{ +#if defined(SPORT_UPDATE_PWR_GPIO) + +#if defined(RADIO_X7) + // QX7 has a external S.PORT connector + // with switchable power from revision 40 on + if (hardwareOptions.pcbrev == PCBREV_X7_40) { + extern etx_module_t _sport_module; + extern void _sport_set_pwr(uint8_t); + _sport_module.set_pwr = _sport_set_pwr; + } else { + return; + } +#endif + + GPIO_InitTypeDef GPIO_InitStructure; + GPIO_InitStructure.GPIO_Pin = SPORT_UPDATE_PWR_GPIO_PIN; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; + GPIO_Init(SPORT_UPDATE_PWR_GPIO, &GPIO_InitStructure); +#endif +} + +void sportUpdatePowerInit() +{ + modulePortSetPower(SPORT_MODULE, g_eeGeneral.sportUpdatePower); +} diff --git a/radio/src/boards/generic_stm32/sport_update.h b/radio/src/boards/generic_stm32/sport_update.h new file mode 100644 index 000000000..8730d08bb --- /dev/null +++ b/radio/src/boards/generic_stm32/sport_update.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +// init S.PORT power pin +void sportUpdateInit(); + +// Set S.PORT power ON/OFF on start as configured +void sportUpdatePowerInit(); diff --git a/radio/src/cli.cpp b/radio/src/cli.cpp index 4d65d4720..1461db602 100644 --- a/radio/src/cli.cpp +++ b/radio/src/cli.cpp @@ -25,6 +25,10 @@ #include "opentx.h" #include "diskio.h" #include "timers_driver.h" +#include "hal/module_port.h" + +#include "tasks.h" +#include "tasks/mixer_task.h" #include "cli.h" @@ -34,10 +38,6 @@ #include -#if defined(INTMODULE_USART) -#include "intmodule_serial_driver.h" -#endif - #define CLI_COMMAND_MAX_ARGS 8 #define CLI_COMMAND_MAX_LEN 256 @@ -581,7 +581,7 @@ int cliTestGraphics() if (pulsesStarted()) { pausePulses(); } - pauseMixerCalculations(); + mixerTaskStop(); perMainEnabled = false; float result = 0; @@ -607,7 +607,7 @@ int cliTestGraphics() if (pulsesStarted()) { resumePulses(); } - resumeMixerCalculations(); + mixerTaskStart(); watchdogSuspend(0); return 0; @@ -714,7 +714,7 @@ int cliTestMemorySpeed() if (pulsesStarted()) { pausePulses(); } - pauseMixerCalculations(); + mixerTaskStop(); perMainEnabled = false; float result = 0; @@ -749,7 +749,7 @@ int cliTestMemorySpeed() if (pulsesStarted()) { resumePulses(); } - resumeMixerCalculations(); + mixerTaskStart(); watchdogSuspend(0); return 0; @@ -906,7 +906,7 @@ int cliReboot(const char ** argv) #if !defined(SIMU) if (!strcmp(argv[1], "wdt")) { // do a user requested watchdog test by pausing mixer thread - pausePulses(); + pulsesStop(); } else { NVIC_SystemReset(); @@ -973,17 +973,9 @@ int cliSet(const char **argv) } if (!strcmp(argv[3], "power")) { if (!strcmp("on", argv[4])) { - if (module == 0) { - INTERNAL_MODULE_ON(); - } else { - EXTERNAL_MODULE_ON(); - } + modulePortSetPower(module, true); } else if (!strcmp("off", argv[4])) { - if (module == 0) { - INTERNAL_MODULE_OFF(); - } else { - EXTERNAL_MODULE_OFF(); - } + modulePortSetPower(module, false); } else { cliSerialPrint("%s: invalid power argument '%s'", argv[0], argv[4]); return -1; @@ -1026,10 +1018,10 @@ int cliSet(const char **argv) if (level) { cliSerialPrint("%s: pulses start", argv[0]); - startPulses(); + pulsesStart(); } else { cliSerialPrint("%s: pulses stop", argv[0]); - stopPulses(); + pulsesStop(); } } @@ -1037,21 +1029,24 @@ int cliSet(const char **argv) } #if defined(ENABLE_SERIAL_PASSTHROUGH) -static void *spInternalModuleCTX = nullptr; +static etx_module_state_t *spInternalModuleState = nullptr; + static void spInternalModuleTx(uint8_t* buf, uint32_t len) { + auto drv = modulePortGetSerialDrv(spInternalModuleState->tx); + auto ctx = modulePortGetCtx(spInternalModuleState->tx); + while (len > 0) { - IntmoduleSerialDriver.sendByte(spInternalModuleCTX, *(buf++)); + drv->sendByte(ctx, *(buf++)); len--; } } static const etx_serial_init spIntmoduleSerialInitParams = { .baudrate = 0, - .parity = ETX_Parity_None, - .stop_bits = ETX_StopBits_One, - .word_length = ETX_WordLength_8, - .rx_enable = true, + .encoding = ETX_Encoding_8N1, + .direction = ETX_Dir_TX_RX, + .polarity = ETX_Pol_Normal, }; // TODO: use proper method instead @@ -1100,7 +1095,7 @@ int cliSerialPassthrough(const char **argv) // stop pulses watchdogSuspend(200/*2s*/); - stopPulses(); + pulsesStop(); // suspend RTOS scheduler vTaskSuspendAll(); @@ -1114,30 +1109,27 @@ int cliSerialPassthrough(const char **argv) etx_serial_init params(spIntmoduleSerialInitParams); params.baudrate = baudrate; - void* uart_ctx = IntmoduleSerialDriver.init(¶ms); - spInternalModuleCTX = uart_ctx; + spInternalModuleState = modulePortInitSerial(port_n, ETX_MOD_PORT_UART, + ¶ms); + + auto drv = modulePortGetSerialDrv(spInternalModuleState->rx); + auto ctx = modulePortGetCtx(spInternalModuleState->rx); // backup and swap CLI input auto backupCB = cliReceiveCallBack; cliReceiveCallBack = spInternalModuleTx; - // loop until cable disconnected while (cdcConnected) { uint32_t cli_br = cliGetBaudRate(); if (cli_br && (cli_br != (uint32_t)baudrate)) { baudrate = cli_br; - - etx_serial_init params(spIntmoduleSerialInitParams); - params.baudrate = baudrate; - - // re-configure serial port - spInternalModuleCTX = IntmoduleSerialDriver.init(¶ms); + drv->setBaudrate(ctx, baudrate); } uint8_t data; - if (IntmoduleSerialDriver.getByte(uart_ctx, &data) > 0) { + if (drv->getByte(ctx, &data) > 0) { uint8_t timeout = 10; // 10 ms while(!usbSerialFreeSpace() && (timeout > 0)) { @@ -1154,13 +1146,13 @@ int cliSerialPassthrough(const char **argv) // restore callsbacks cliReceiveCallBack = backupCB; - spInternalModuleCTX = nullptr; // and stop module - IntmoduleSerialDriver.deinit(uart_ctx); + modulePortDeInit(spInternalModuleState); + spInternalModuleState = nullptr; // power off the module and wait for a bit - INTERNAL_MODULE_OFF(); + modulePortSetPower(port_n, false); delay_ms(200); } #endif @@ -1169,7 +1161,7 @@ int cliSerialPassthrough(const char **argv) // - external module (S.PORT?) watchdogSuspend(200/*2s*/); - startPulses(); + pulsesStart(); // suspend RTOS scheduler xTaskResumeAll(); @@ -1549,7 +1541,7 @@ int cliCrypt(const char ** argv) if (pulsesStarted()) { pausePulses(); } - pauseMixerCalculations(); + mixerTaskStop(); perMainEnabled = false; uint32_t startMs = RTOS_GET_MS(); @@ -1564,7 +1556,7 @@ int cliCrypt(const char ** argv) if (pulsesStarted()) { resumePulses(); } - resumeMixerCalculations(); + mixerTaskStart(); watchdogSuspend(0); return 0; @@ -1587,7 +1579,7 @@ int cliResetGT911(const char** argv) // stop pulses & suspend RTOS scheduler watchdogSuspend(200/*2s*/); - stopPulses(); + pulsesStop(); vTaskSuspendAll(); // reset touch controller @@ -1598,7 +1590,7 @@ int cliResetGT911(const char** argv) cliSerialPrintf("GT911: new config version is %u\n", tp_gt911_cfgVer); // restart pulses & RTOS scheduler - startPulses(); + pulsesStart(); xTaskResumeAll(); return 0; @@ -1719,7 +1711,7 @@ void cliTask(void * pdata) const TickType_t xTimeout = 100 / RTOS_MS_PER_TICK; size_t xReceivedBytes = xStreamBufferReceive(cliRxBuffer, &c, 1, xTimeout); - if (s_pulses_paused) { + if (!mixerTaskRunning()) { WDG_RESET(); } diff --git a/radio/src/dataconstants.h b/radio/src/dataconstants.h index 95505ce79..67d67d9a3 100644 --- a/radio/src/dataconstants.h +++ b/radio/src/dataconstants.h @@ -136,6 +136,7 @@ enum CurveType { #define MAX_CURVE_POINTS 512 #endif +// TODO: remove this #if defined(PCBFRSKY) || defined(PCBNV14) #define NUM_MODULES 2 #else @@ -183,7 +184,13 @@ enum BeeperMode { enum ModuleIndex { INTERNAL_MODULE, EXTERNAL_MODULE, - SPORT_MODULE + // end of "normal" modules + + MAX_MODULES, + + // only used for power control + // and firmware updates + SPORT_MODULE = MAX_MODULES }; enum TrainerMode { @@ -215,19 +222,22 @@ enum SerialPort { #define PILOTPOS_MIN_HDOP 500 #if defined(HARDWARE_INTERNAL_MODULE) - #define IS_INTERNAL_MODULE_ENABLED() (g_model.moduleData[INTERNAL_MODULE].type != MODULE_TYPE_NONE) +#define IS_INTERNAL_MODULE_ENABLED() \ + (g_model.moduleData[INTERNAL_MODULE].type != MODULE_TYPE_NONE) #else - #define IS_INTERNAL_MODULE_ENABLED() (false) +#define IS_INTERNAL_MODULE_ENABLED() (false) #endif -#define IS_EXTERNAL_MODULE_ENABLED() (g_model.moduleData[EXTERNAL_MODULE].type != MODULE_TYPE_NONE) - -#if defined(HARDWARE_INTERNAL_MODULE) - #define IS_MODULE_ENABLED(moduleIdx) (moduleIdx==INTERNAL_MODULE ? IS_INTERNAL_MODULE_ENABLED() : moduleIdx==EXTERNAL_MODULE ? IS_EXTERNAL_MODULE_ENABLED() : false) +#if defined(HARDWARE_EXTERNAL_MODULE) +#define IS_EXTERNAL_MODULE_ENABLED() \ + (g_model.moduleData[EXTERNAL_MODULE].type != MODULE_TYPE_NONE) #else - #define IS_MODULE_ENABLED(moduleIdx) (moduleIdx==EXTERNAL_MODULE ? IS_EXTERNAL_MODULE_ENABLED() : false) +#define IS_EXTERNAL_MODULE_ENABLED() false #endif +#define IS_MODULE_ENABLED(moduleIdx) \ + (g_model.moduleData[moduleIdx].type != MODULE_TYPE_NONE) + enum UartModes { UART_MODE_NONE, UART_MODE_TELEMETRY_MIRROR, diff --git a/radio/src/debug.cpp b/radio/src/debug.cpp index 478c80e3b..94df3b665 100644 --- a/radio/src/debug.cpp +++ b/radio/src/debug.cpp @@ -45,65 +45,6 @@ void debugPrintf(const char * format, ...) } #endif -#if defined(DEBUG_TRACE_BUFFER) -static struct TraceElement traceBuffer[TRACE_BUFFER_LEN]; -static uint8_t traceBufferPos; -extern Fifo auxSerialTxFifo; -gtime_t filltm(const gtime_t *t, struct gtm *tp); - -void trace_event(enum TraceEvent event, uint32_t data) -{ - if (traceBufferPos >= TRACE_BUFFER_LEN) return; - __disable_irq(); - struct TraceElement * p = &traceBuffer[traceBufferPos++]; - __enable_irq(); - p->time = g_rtcTime; - p->time_ms = g_ms100; - p->event = event; - p->data = data; -} - -void trace_event_i(enum TraceEvent event, uint32_t data) -{ - if (traceBufferPos >= TRACE_BUFFER_LEN) return; - struct TraceElement * p = &traceBuffer[traceBufferPos++]; - p->time = g_rtcTime; - p->time_ms = g_ms100; - p->event = event; - p->data = data; -} - - -const struct TraceElement * getTraceElement(uint16_t idx) -{ - if (idx < TRACE_BUFFER_LEN) return &traceBuffer[idx]; - return 0; -} - - -void dumpTraceBuffer() -{ - TRACE("Dump of Trace Buffer (%s " DATE " " TIME "):", vers_stamp); - TRACE("# Time Event Data"); - for(int n = 0; n < TRACE_BUFFER_LEN; ++n) { - struct gtm tp; - filltm(&traceBuffer[n].time, &tp); - TRACE_NOCRLF("%02d ", n); - TRACE_NOCRLF("%4d-%02d-%02d,%02d:%02d:%02d.%02d0", tp.tm_year+TM_YEAR_BASE, tp.tm_mon+1, tp.tm_mday, tp.tm_hour, tp.tm_min, tp.tm_sec, traceBuffer[n].time_ms); - TRACE(" %03d 0x%08x", traceBuffer[n].event, traceBuffer[n].data); - if (traceBuffer[n].time == 0 && traceBuffer[n].time_ms == 0) break; -#if !defined(SIMU) - if ((n % 5) == 0) { - while (!auxSerialTxFifo.isEmpty()) { - RTOS_WAIT_TICKS(1); - } - } -#endif - } - TRACE("End of Trace Buffer dump"); -} -#endif - #if defined(DEBUG_INTERRUPTS) #if defined(PCBHORUS) diff --git a/radio/src/dmafifo.h b/radio/src/dmafifo.h deleted file mode 100644 index bf19fb935..000000000 --- a/radio/src/dmafifo.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (C) EdgeTX - * - * Based on code named - * opentx - https://github.com/opentx/opentx - * th9x - http://code.google.com/p/th9x - * er9x - http://code.google.com/p/er9x - * gruvin9x - http://code.google.com/p/gruvin9x - * - * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef _DMA_FIFO_H_ -#define _DMA_FIFO_H_ - -#include "definitions.h" - -template -class DMAFifo -{ - public: - explicit DMAFifo(DMA_Stream_TypeDef * stream): - stream(stream), - ridx(0) - { - } - - void clear() - { - ridx = N - stream->NDTR; - } - - uint32_t size() - { - return N; - } - - uint8_t last(int index) - { - return fifo[(2*N - stream->NDTR - index) & (N-1)]; - } - - bool isEmpty() - { -#if defined(SIMU) - return true; -#endif - return !(stream->CR & DMA_SxCR_EN) || (ridx == N - stream->NDTR); - } - - bool pop(uint8_t & element) - { - if (isEmpty()) { - return false; - } - else { - element = fifo[ridx]; - ridx = (ridx+1) & (N-1); - return true; - } - } - - uint8_t * buffer() - { - return fifo; - } - - protected: - uint8_t fifo[N]; - DMA_Stream_TypeDef * stream; - volatile uint32_t ridx; -}; - -#endif // _DMA_FIFO_H_ diff --git a/radio/src/gui/128x64/model_setup.cpp b/radio/src/gui/128x64/model_setup.cpp index 708c9d5dd..2e4a2ae89 100644 --- a/radio/src/gui/128x64/model_setup.cpp +++ b/radio/src/gui/128x64/model_setup.cpp @@ -500,9 +500,13 @@ void menuModelSetup(event_t event) if (event == EVT_ENTRY || event == EVT_ENTRY_UP) { memclear(&reusableBuffer.moduleSetup, sizeof(reusableBuffer.moduleSetup)); + +#if defined(HARDWARE_EXTERNAL_MODULE) reusableBuffer.moduleSetup.r9mPower = g_model.moduleData[EXTERNAL_MODULE].pxx.power; reusableBuffer.moduleSetup.previousType = g_model.moduleData[EXTERNAL_MODULE].type; reusableBuffer.moduleSetup.newType = g_model.moduleData[EXTERNAL_MODULE].type; +#endif + #if defined(INTERNAL_MODULE_PXX1) && defined(EXTERNAL_ANTENNA) reusableBuffer.moduleSetup.antennaMode = g_model.moduleData[INTERNAL_MODULE].pxx.antennaMode; #endif @@ -1004,10 +1008,11 @@ void menuModelSetup(event_t event) lcdDrawTextAlignedLeft(y, INDENT TR_MODE); lcdDrawTextAtIndex( MODEL_SETUP_2ND_COLUMN, y, - moduleIdx == EXTERNAL_MODULE ? STR_EXTERNAL_MODULE_PROTOCOLS - : STR_INTERNAL_MODULE_PROTOCOLS, - moduleIdx == EXTERNAL_MODULE ? reusableBuffer.moduleSetup.newType - : g_model.moduleData[moduleIdx].type, + STR_MODULE_PROTOCOLS, +#if defined(HARDWARE_EXTERNAL_MODULE) + moduleIdx == EXTERNAL_MODULE ? reusableBuffer.moduleSetup.newType : +#endif + g_model.moduleData[moduleIdx].type, menuHorizontalPosition == 0 ? attr : 0); if (isModuleXJT(moduleIdx)) lcdDrawTextAtIndex(lcdNextPos + 3, y, STR_XJT_ACCST_RF_PROTOCOLS, @@ -1031,6 +1036,7 @@ void menuModelSetup(event_t event) lcdNextPos + 3, y, STR_CRSF_BAUDRATE, CROSSFIRE_STORE_TO_INDEX(g_eeGeneral.internalModuleBaudrate), 0); +#if defined(HARDWARE_EXTERNAL_MODULE) if (attr && menuHorizontalPosition == 0 && moduleIdx == EXTERNAL_MODULE) { if (s_editMode > 0) { @@ -1048,6 +1054,7 @@ void menuModelSetup(event_t event) reusableBuffer.moduleSetup.newType; } } +#endif if (attr) { if (s_editMode > 0) { switch (menuHorizontalPosition) { @@ -1177,17 +1184,17 @@ void menuModelSetup(event_t event) lcdDrawText(INDENT_WIDTH, y, STR_STATUS); lcdDrawNumber(MODEL_SETUP_2ND_COLUMN, y, 1000000 / getMixerSchedulerPeriod(), LEFT | attr); lcdDrawText(lcdNextPos, y, "Hz ", attr); - lcdDrawNumber(lcdNextPos, y, telemetryErrors, attr); - lcdDrawText(lcdNextPos + 1, y, "Err", attr); - if (attr) { - s_editMode = 0; - if (event == EVT_KEY_LONG(KEY_ENTER)) { - START_NO_HIGHLIGHT(); - telemetryErrors = 0; - AUDIO_WARNING1(); - killEvents(event); - } - } + // lcdDrawNumber(lcdNextPos, y, telemetryErrors, attr); + // lcdDrawText(lcdNextPos + 1, y, "Err", attr); + // if (attr) { + // s_editMode = 0; + // if (event == EVT_KEY_LONG(KEY_ENTER)) { + // START_NO_HIGHLIGHT(); + // telemetryErrors = 0; + // AUDIO_WARNING1(); + // killEvents(event); + // } + // } break; #endif diff --git a/radio/src/gui/128x64/model_telemetry.cpp b/radio/src/gui/128x64/model_telemetry.cpp index f179c55dd..69a184949 100644 --- a/radio/src/gui/128x64/model_telemetry.cpp +++ b/radio/src/gui/128x64/model_telemetry.cpp @@ -61,10 +61,10 @@ enum MenuModelTelemetryFrskyItems { #define VARIO_ROWS #endif -#if defined(PCBTARANIS) +#if defined(HARDWARE_EXTERNAL_MODULE) #define TELEMETRY_TYPE_ROW (!IS_INTERNAL_MODULE_ENABLED() && g_model.moduleData[EXTERNAL_MODULE].type == MODULE_TYPE_PPM) ? (uint8_t)0 : HIDDEN_ROW #else - #define TELEMETRY_TYPE_ROW (g_model.moduleData[EXTERNAL_MODULE].type == MODULE_TYPE_PPM) ? (uint8_t)0 : HIDDEN_ROW + #define TELEMETRY_TYPE_ROW HIDDEN_ROW #endif #define TELEMETRY_TYPE_ROWS TELEMETRY_TYPE_ROW, @@ -174,9 +174,12 @@ void menuModelTelemetry(event_t event) switch (k) { case ITEM_TELEMETRY_PROTOCOL_TYPE: lcdDrawTextAlignedLeft(y, STR_TELEMETRY_TYPE); - lcdDrawTextAtIndex(TELEM_COL2, y, STR_TELEMETRY_PROTOCOLS, g_model.telemetryProtocol, attr); + lcdDrawTextAtIndex(TELEM_COL2, y, STR_TELEMETRY_PROTOCOLS, + g_model.telemetryProtocol, attr); if (attr) { - g_model.telemetryProtocol = checkIncDec(event, g_model.telemetryProtocol, PROTOCOL_TELEMETRY_FIRST, PROTOCOL_TELEMETRY_LAST, EE_MODEL, isTelemetryProtocolAvailable); + g_model.telemetryProtocol = checkIncDec( + event, g_model.telemetryProtocol, PROTOCOL_TELEMETRY_FIRST, + PROTOCOL_TELEMETRY_LAST, EE_MODEL, isTelemetryProtocolAvailable); } break; diff --git a/radio/src/gui/128x64/model_telemetry_sensor.cpp b/radio/src/gui/128x64/model_telemetry_sensor.cpp index 925a0940f..095a2f040 100644 --- a/radio/src/gui/128x64/model_telemetry_sensor.cpp +++ b/radio/src/gui/128x64/model_telemetry_sensor.cpp @@ -26,7 +26,7 @@ enum SensorFields { SENSOR_FIELD_TYPE, SENSOR_FIELD_ID, SENSOR_FIELD_FORMULA = SENSOR_FIELD_ID, - SENSOR_FILED_RECEIVER_NAME, + // SENSOR_FIELD_RECEIVER_NAME, SENSOR_FIELD_UNIT, SENSOR_FIELD_PRECISION, SENSOR_FIELD_PARAM1, @@ -54,7 +54,7 @@ void menuModelSensor(event_t event) 0, // Name 0, // Type sensor->type == TELEM_TYPE_CALCULATED ? (uint8_t)0 : (uint8_t)1, // ID / Formula - sensor->type == TELEM_TYPE_CALCULATED ? HIDDEN_ROW : READONLY_ROW, // Receiver name + // sensor->type == TELEM_TYPE_CALCULATED ? HIDDEN_ROW : READONLY_ROW, // Receiver name ((sensor->type == TELEM_TYPE_CALCULATED && (sensor->formula == TELEM_FORMULA_DIST)) || sensor->isConfigurable() ? (uint8_t)0 : HIDDEN_ROW), // Unit (sensor->isPrecConfigurable() && sensor->unit != UNIT_FAHRENHEIT ? (uint8_t)0 : HIDDEN_ROW), // Precision (sensor->unit >= UNIT_FIRST_VIRTUAL ? HIDDEN_ROW : (uint8_t)0), // Param1 @@ -145,21 +145,24 @@ void menuModelSensor(event_t event) } break; - case SENSOR_FILED_RECEIVER_NAME: - lcdDrawTextAlignedLeft(y, STR_SOURCE); - if (telemetryProtocol == PROTOCOL_TELEMETRY_FRSKY_SPORT && sensor->frskyInstance.rxIndex != TELEMETRY_ENDPOINT_SPORT) { - drawReceiverName(SENSOR_2ND_COLUMN, y, sensor->frskyInstance.rxIndex >> 2, sensor->frskyInstance.rxIndex & 0x03, 0); - } -#if defined(HARDWARE_INTERNAL_MODULE) - else if (isModuleUsingSport(INTERNAL_MODULE, g_model.moduleData[INTERNAL_MODULE].type)) { - // far from perfect - lcdDrawText(SENSOR_2ND_COLUMN, y, STR_INTERNAL_MODULE); - } -#endif - else { - lcdDrawText(SENSOR_2ND_COLUMN, y, STR_EXTERNAL_MODULE); - } - break; + // TODO: this needs to be known from the sensor data alone! +// case SENSOR_FIELD_RECEIVER_NAME: +// lcdDrawTextAlignedLeft(y, STR_SOURCE); +// if (telemetryProtocol == PROTOCOL_TELEMETRY_FRSKY_SPORT && +// sensor->frskyInstance.rxIndex != TELEMETRY_ENDPOINT_SPORT) { +// drawReceiverName(SENSOR_2ND_COLUMN, y, sensor->frskyInstance.rxIndex >> 2, +// sensor->frskyInstance.rxIndex & 0x03, 0); +// } +// #if defined(HARDWARE_INTERNAL_MODULE) +// else if (isModuleUsingSport(INTERNAL_MODULE, g_model.moduleData[INTERNAL_MODULE].type)) { +// // far from perfect +// lcdDrawText(SENSOR_2ND_COLUMN, y, STR_INTERNAL_MODULE); +// } +// #endif +// else { +// lcdDrawText(SENSOR_2ND_COLUMN, y, STR_EXTERNAL_MODULE); +// } +// break; case SENSOR_FIELD_UNIT: lcdDrawTextAlignedLeft(y, STR_UNIT); diff --git a/radio/src/gui/128x64/radio_setup.cpp b/radio/src/gui/128x64/radio_setup.cpp index 892ebc84a..57da3de7a 100644 --- a/radio/src/gui/128x64/radio_setup.cpp +++ b/radio/src/gui/128x64/radio_setup.cpp @@ -22,6 +22,7 @@ #define LANGUAGE_PACKS_DEFINITION #include "opentx.h" +#include "tasks/mixer_task.h" const unsigned char sticks[] = { #include "sticks.lbm" @@ -693,10 +694,10 @@ void menuRadioSetup(event_t event) CHECK_INCDEC_GENVAR(event, reusableBuffer.generalSettings.stickMode, 0, 3); } else if (reusableBuffer.generalSettings.stickMode != g_eeGeneral.stickMode) { - pausePulses(); + mixerTaskStop(); g_eeGeneral.stickMode = reusableBuffer.generalSettings.stickMode; checkThrottleStick(); - resumePulses(); + mixerTaskStart(); waitKeysReleased(); } break; diff --git a/radio/src/gui/128x64/view_statistics.cpp b/radio/src/gui/128x64/view_statistics.cpp index 891c32902..a7dfca94c 100644 --- a/radio/src/gui/128x64/view_statistics.cpp +++ b/radio/src/gui/128x64/view_statistics.cpp @@ -20,6 +20,11 @@ */ #include "opentx.h" +#include "tasks.h" + +#if defined(BLUETOOTH) + #include "bluetooth_driver.h" +#endif #define STATS_1ST_COLUMN 1 #define STATS_2ND_COLUMN 7*FW+FW/2 @@ -228,9 +233,9 @@ void menuStatisticsDebug2(event_t event) title(STR_MENUDEBUG); switch(event) { - case EVT_KEY_FIRST(KEY_ENTER): - telemetryErrors = 0; - break; + // case EVT_KEY_FIRST(KEY_ENTER): + // telemetryErrors = 0; + // break; case EVT_KEY_FIRST(KEY_UP): #if defined(KEYS_GPIO_REG_PAGEDN) @@ -258,8 +263,8 @@ void menuStatisticsDebug2(event_t event) uint8_t y = FH + 1; - lcdDrawTextAlignedLeft(y, "Tlm RX Err"); - lcdDrawNumber(MENU_DEBUG_COL1_OFS, y, telemetryErrors, RIGHT); + // lcdDrawTextAlignedLeft(y, "Tlm RX Err"); + // lcdDrawNumber(MENU_DEBUG_COL1_OFS, y, telemetryErrors, RIGHT); y += FH; #if defined(BLUETOOTH) diff --git a/radio/src/gui/212x64/model_setup.cpp b/radio/src/gui/212x64/model_setup.cpp index 190fd79b2..8e9c3d8dc 100644 --- a/radio/src/gui/212x64/model_setup.cpp +++ b/radio/src/gui/212x64/model_setup.cpp @@ -923,7 +923,7 @@ void menuModelSetup(event_t event) { lcdDrawTextAlignedLeft(y, INDENT TR_MODE); lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, - STR_INTERNAL_MODULE_PROTOCOLS, + STR_MODULE_PROTOCOLS, g_model.moduleData[INTERNAL_MODULE].type, menuHorizontalPosition == 0 ? attr : 0); if (isModuleXJT(INTERNAL_MODULE)) @@ -977,7 +977,7 @@ void menuModelSetup(event_t event) case ITEM_MODEL_SETUP_EXTERNAL_MODULE_TYPE: lcdDrawTextAlignedLeft(y, INDENT TR_MODE); - lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_EXTERNAL_MODULE_PROTOCOLS, reusableBuffer.moduleSetup.newType, menuHorizontalPosition==0 ? attr : 0); + lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_MODULE_PROTOCOLS, reusableBuffer.moduleSetup.newType, menuHorizontalPosition==0 ? attr : 0); if (isModuleXJT(EXTERNAL_MODULE)) lcdDrawTextAtIndex(lcdNextPos + 3, y, STR_XJT_ACCST_RF_PROTOCOLS, g_model.moduleData[EXTERNAL_MODULE].subType, menuHorizontalPosition==1 ? attr : 0); else if (isModuleDSM2(EXTERNAL_MODULE)) @@ -1110,17 +1110,17 @@ void menuModelSetup(event_t event) lcdDrawText(INDENT_WIDTH, y, STR_STATUS); lcdDrawNumber(MODEL_SETUP_2ND_COLUMN, y, 1000000 / getMixerSchedulerPeriod(), LEFT | attr); lcdDrawText(lcdNextPos, y, "Hz ", attr); - lcdDrawNumber(lcdNextPos, y, telemetryErrors, attr); - lcdDrawText(lcdNextPos + 1, y, "Err", attr); - if (attr) { - s_editMode = 0; - if (event == EVT_KEY_LONG(KEY_ENTER)) { - START_NO_HIGHLIGHT(); - telemetryErrors = 0; - AUDIO_WARNING1(); - killEvents(event); - } - } + // lcdDrawNumber(lcdNextPos, y, telemetryErrors, attr); + // lcdDrawText(lcdNextPos + 1, y, "Err", attr); + // if (attr) { + // s_editMode = 0; + // if (event == EVT_KEY_LONG(KEY_ENTER)) { + // START_NO_HIGHLIGHT(); + // telemetryErrors = 0; + // AUDIO_WARNING1(); + // killEvents(event); + // } + // } break; #endif diff --git a/radio/src/gui/212x64/model_telemetry.cpp b/radio/src/gui/212x64/model_telemetry.cpp index 6e996dfd1..b3de4e891 100644 --- a/radio/src/gui/212x64/model_telemetry.cpp +++ b/radio/src/gui/212x64/model_telemetry.cpp @@ -143,14 +143,6 @@ void menuModelTelemetry(event_t event) lcdDrawText(TELEM_COL2, y, "---", 0); // TODO shortcut } TelemetrySensor * sensor = & g_model.telemetrySensors[index]; -#if defined(MULTIMODULE) - if (IS_SPEKTRUM_PROTOCOL()) { - // Spektrum does not (yet?) really support multiple sensor of the same type. But a lot of - // different sensor display the same information (e.g. voltage, capacity). Show the id - // of the sensor in the overview to ease figuring out what sensors belong together - lcdDrawHexNumber(TELEM_COL3, y, sensor->id, LEFT); - } else -#endif if (sensor->type == TELEM_TYPE_CUSTOM && !g_model.ignoreSensorIds) { lcdDrawNumber(TELEM_COL3, y, sensor->instance, LEFT); } @@ -183,7 +175,7 @@ void menuModelTelemetry(event_t event) case ITEM_TELEMETRY_SENSORS_LABEL: lcdDrawTextAlignedLeft(y, STR_TELEMETRY_SENSORS); lcdDrawText(TELEM_COL2, y, STR_VALUE, 0); - if (!g_model.ignoreSensorIds && !IS_SPEKTRUM_PROTOCOL()) { + if (!g_model.ignoreSensorIds /*&& !IS_SPEKTRUM_PROTOCOL()*/) { lcdDrawText(TELEM_COL3, y, STR_ID, 0); } break; diff --git a/radio/src/gui/212x64/model_telemetry_sensor.cpp b/radio/src/gui/212x64/model_telemetry_sensor.cpp index b1e9b4f17..1902191d8 100644 --- a/radio/src/gui/212x64/model_telemetry_sensor.cpp +++ b/radio/src/gui/212x64/model_telemetry_sensor.cpp @@ -26,7 +26,7 @@ enum SensorFields { SENSOR_FIELD_TYPE, SENSOR_FIELD_ID, SENSOR_FIELD_FORMULA=SENSOR_FIELD_ID, - SENSOR_FILED_RECEIVER_NAME, + // SENSOR_FIELD_RECEIVER_NAME, SENSOR_FIELD_UNIT, SENSOR_FIELD_PRECISION, SENSOR_FIELD_PARAM1, @@ -69,7 +69,7 @@ void menuModelSensor(event_t event) 0, //Name 0, // Type sensor->type == TELEM_TYPE_CALCULATED ? (uint8_t)0 : (uint8_t)1, // ID / Formula - sensor->type == TELEM_TYPE_CALCULATED ? HIDDEN_ROW : READONLY_ROW, // Receiver name + // sensor->type == TELEM_TYPE_CALCULATED ? HIDDEN_ROW : READONLY_ROW, // Receiver name SENSOR_UNIT_ROWS, SENSOR_PREC_ROWS, SENSOR_PARAM1_ROWS, @@ -151,19 +151,22 @@ void menuModelSensor(event_t event) } break; - case SENSOR_FILED_RECEIVER_NAME: - lcdDrawTextAlignedLeft(y, STR_SOURCE); - if (telemetryProtocol == PROTOCOL_TELEMETRY_FRSKY_SPORT && sensor->frskyInstance.rxIndex != TELEMETRY_ENDPOINT_SPORT) { - drawReceiverName(SENSOR_2ND_COLUMN, y, sensor->frskyInstance.rxIndex >> 2, sensor->frskyInstance.rxIndex & 0x03, 0); - } - else if (isModuleUsingSport(INTERNAL_MODULE, g_model.moduleData[INTERNAL_MODULE].type)) { - // far from perfect - lcdDrawText(SENSOR_2ND_COLUMN, y, STR_INTERNAL_MODULE); - } - else { - lcdDrawText(SENSOR_2ND_COLUMN, y, STR_EXTERNAL_MODULE); - } - break; + // case SENSOR_FIELD_RECEIVER_NAME: + // lcdDrawTextAlignedLeft(y, STR_SOURCE); + // // TODO: this needs to be known from the sensor data alone! + // if (telemetryProtocol == PROTOCOL_TELEMETRY_FRSKY_SPORT && + // sensor->frskyInstance.rxIndex != TELEMETRY_ENDPOINT_SPORT) { + // drawReceiverName(SENSOR_2ND_COLUMN, y, sensor->frskyInstance.rxIndex >> 2, + // sensor->frskyInstance.rxIndex & 0x03, 0); + // } + // else if (isModuleUsingSport(INTERNAL_MODULE, g_model.moduleData[INTERNAL_MODULE].type)) { + // // far from perfect + // lcdDrawText(SENSOR_2ND_COLUMN, y, STR_INTERNAL_MODULE); + // } + // else { + // lcdDrawText(SENSOR_2ND_COLUMN, y, STR_EXTERNAL_MODULE); + // } + // break; case SENSOR_FIELD_UNIT: lcdDrawTextAlignedLeft(y, STR_UNIT); diff --git a/radio/src/gui/212x64/radio_setup.cpp b/radio/src/gui/212x64/radio_setup.cpp index 6c5dfb657..2bfc8bc8b 100644 --- a/radio/src/gui/212x64/radio_setup.cpp +++ b/radio/src/gui/212x64/radio_setup.cpp @@ -22,6 +22,7 @@ #define LANGUAGE_PACKS_DEFINITION #include "opentx.h" +#include "tasks/mixer_task.h" const unsigned char sticks[] = { #include "sticks.lbm" @@ -623,10 +624,10 @@ void menuRadioSetup(event_t event) CHECK_INCDEC_GENVAR(event, reusableBuffer.generalSettings.stickMode, 0, 3); } else if (reusableBuffer.generalSettings.stickMode != g_eeGeneral.stickMode) { - pausePulses(); + mixerTaskStop(); g_eeGeneral.stickMode = reusableBuffer.generalSettings.stickMode; checkThrottleStick(); - resumePulses(); + mixerTaskStart(); waitKeysReleased(); } break; diff --git a/radio/src/gui/212x64/view_statistics.cpp b/radio/src/gui/212x64/view_statistics.cpp index 759f9dc4f..87a5cb4a4 100644 --- a/radio/src/gui/212x64/view_statistics.cpp +++ b/radio/src/gui/212x64/view_statistics.cpp @@ -20,6 +20,7 @@ */ #include "opentx.h" +#include "tasks.h" #define STATS_1ST_COLUMN FW/2 #define STATS_2ND_COLUMN 12*FW+FW/2 @@ -112,7 +113,7 @@ void menuStatisticsDebug(event_t event) warningResult = 0; // do a user requested watchdog test TRACE("Performing watchdog test"); - pausePulses(); + pulsesStop(); } #endif @@ -232,14 +233,14 @@ void menuStatisticsDebug2(event_t event) chainMenu(menuMainView); break; - case EVT_KEY_LONG(KEY_ENTER): - telemetryErrors = 0; - break; + // case EVT_KEY_LONG(KEY_ENTER): + // telemetryErrors = 0; + // break; } // UART statistics - lcdDrawTextAlignedLeft(MENU_DEBUG_ROW1, "Tlm RX Err"); - lcdDrawNumber(MENU_DEBUG_COL1_OFS, MENU_DEBUG_ROW1, telemetryErrors, RIGHT); + // lcdDrawTextAlignedLeft(MENU_DEBUG_ROW1, "Tlm RX Err"); + // lcdDrawNumber(MENU_DEBUG_COL1_OFS, MENU_DEBUG_ROW1, telemetryErrors, RIGHT); lcdDrawText(LCD_W/2, 7*FH+1, STR_MENUTORESET, CENTERED); diff --git a/radio/src/gui/colorlcd/crossfire_settings.cpp b/radio/src/gui/colorlcd/crossfire_settings.cpp index 482623dba..b7c3a64ab 100644 --- a/radio/src/gui/colorlcd/crossfire_settings.cpp +++ b/radio/src/gui/colorlcd/crossfire_settings.cpp @@ -61,8 +61,9 @@ CrossfireSettings::CrossfireSettings(Window* parent, const FlexGridLayout& g, new StaticText(line, rect_t{}, STR_STATUS, 0, COLOR_THEME_PRIMARY1); new DynamicText(line, rect_t{}, [=] { char msg[64] = ""; - sprintf(msg, "%d Hz %" PRIu32 " Err", 1000000 / getMixerSchedulerPeriod(), - telemetryErrors); + // sprintf(msg, "%d Hz %" PRIu32 " Err", 1000000 / getMixerSchedulerPeriod(), + // telemetryErrors); + sprintf(msg, "%d Hz", 1000000 / getMixerSchedulerPeriod()); return std::string(msg); }); } diff --git a/radio/src/gui/colorlcd/draw_functions.cpp b/radio/src/gui/colorlcd/draw_functions.cpp index d814c366e..631802c34 100644 --- a/radio/src/gui/colorlcd/draw_functions.cpp +++ b/radio/src/gui/colorlcd/draw_functions.cpp @@ -376,7 +376,8 @@ void drawGPSSensorValue(BitmapBuffer * dc, coord_t x, coord_t y, TelemetryItem & drawGPSPosition(dc, x, y, telemetryItem.gps.longitude, telemetryItem.gps.latitude, flags); } -void drawSensorCustomValue(BitmapBuffer * dc, coord_t x, coord_t y, uint8_t sensor, int32_t value, LcdFlags flags) +void drawSensorCustomValue(BitmapBuffer* dc, coord_t x, coord_t y, + uint8_t sensor, int32_t value, LcdFlags flags) { if (sensor >= MAX_TELEMETRY_SENSORS) { // Lua luaLcdDrawChannel() can call us with a bad value @@ -392,65 +393,19 @@ void drawSensorCustomValue(BitmapBuffer * dc, coord_t x, coord_t y, uint8_t sens else if (telemetrySensor.unit == UNIT_GPS) { drawGPSSensorValue(dc, x, y, telemetryItem, flags); } - else if (telemetrySensor.unit == UNIT_BITFIELD) { - if (IS_FRSKY_SPORT_PROTOCOL()) { - if (telemetrySensor.id >= RBOX_STATE_FIRST_ID && telemetrySensor.id <= RBOX_STATE_LAST_ID) { - if (telemetrySensor.subId == 0) { - if (value == 0) { - dc->drawText(x, y, "OK", flags); - } - else { - for (uint8_t i=0; i<16; i++) { - if (value & (1 << i)) { - char s[] = "CH__ KO"; - strAppendUnsigned(&s[2], i+1, 2); - dc->drawText(x, flags & FONT(XL) ? y+1 : y, s, flags & ~FONT(XL)); - break; - } - } - } - } - else { - if (value == 0) { - dc->drawText(x, flags & FONT(XL) ? y+1 : y, "Rx OK", flags & ~FONT(XL)); - } - else { - static const char * const RXS_STATUS[] = { - "Rx1 Ovl", - "Rx2 Ovl", - "SBUS Ovl", - "Rx1 FS", - "Rx1 LF", - "Rx2 FS", - "Rx2 LF", - "Rx1 Lost", - "Rx2 Lost", - "Rx1 NS", - "Rx2 NS", - }; - for (uint8_t i=0; idrawText(x, flags & FONT(XL) ? y+1 : y, RXS_STATUS[i], flags & ~FONT(XL)); - break; - } - } - } - } - } - } - } else if (telemetrySensor.unit == UNIT_TEXT) { - dc->drawSizedText(x, flags & FONT(XL) ? y+1 : y, telemetryItem.text, sizeof(telemetryItem.text), flags & ~FONT(XL)); - } - else { + dc->drawSizedText(x, flags & FONT(XL) ? y + 1 : y, telemetryItem.text, + sizeof(telemetryItem.text), flags & ~FONT(XL)); + } else { if (telemetrySensor.prec > 0) { flags |= (telemetrySensor.prec==1 ? PREC1 : PREC2); } - drawValueWithUnit(dc, x, y, value, telemetrySensor.unit == UNIT_CELLS ? UNIT_VOLTS : telemetrySensor.unit, flags); + drawValueWithUnit(dc, x, y, value, + telemetrySensor.unit == UNIT_CELLS ? UNIT_VOLTS : telemetrySensor.unit, + flags); } } - void drawTimer(BitmapBuffer * dc, coord_t x, coord_t y, int32_t tme, LcdFlags flags) { char str[LEN_TIMER_STRING]; diff --git a/radio/src/gui/colorlcd/hw_intmodule.cpp b/radio/src/gui/colorlcd/hw_intmodule.cpp index 9a09767c6..f2fc740d6 100644 --- a/radio/src/gui/colorlcd/hw_intmodule.cpp +++ b/radio/src/gui/colorlcd/hw_intmodule.cpp @@ -47,7 +47,7 @@ InternalModuleWindow::InternalModuleWindow(Window *parent) : lv_obj_set_style_grid_cell_x_align(box->getLvObj(), LV_GRID_ALIGN_STRETCH, 0); auto internalModule = new Choice( - box, rect_t{}, STR_INTERNAL_MODULE_PROTOCOLS, MODULE_TYPE_NONE, + box, rect_t{}, STR_MODULE_PROTOCOLS, MODULE_TYPE_NONE, MODULE_TYPE_COUNT - 1, GET_DEFAULT(g_eeGeneral.internalModule), [=](int type) { return setModuleType(type); }); diff --git a/radio/src/gui/colorlcd/model_inputs.cpp b/radio/src/gui/colorlcd/model_inputs.cpp index 9fe32cc13..1e6922e14 100644 --- a/radio/src/gui/colorlcd/model_inputs.cpp +++ b/radio/src/gui/colorlcd/model_inputs.cpp @@ -29,6 +29,7 @@ #include "input_mix_group.h" #include "input_mix_button.h" +#include "tasks/mixer_task.h" #include #define SET_DIRTY() storageDirty(EE_MODEL) @@ -52,7 +53,7 @@ uint8_t getExposCount() // void copyExpo(uint8_t source, uint8_t dest, uint8_t input) { - pauseMixerCalculations(); + mixerTaskStop(); ExpoData sourceExpo; memcpy(&sourceExpo, expoAddress(source), sizeof(ExpoData)); ExpoData *expo = expoAddress(dest); @@ -60,13 +61,13 @@ void copyExpo(uint8_t source, uint8_t dest, uint8_t input) memmove(expo + 1, expo, trailingExpos * sizeof(ExpoData)); memcpy(expo, &sourceExpo, sizeof(ExpoData)); expo->chn = input; - resumeMixerCalculations(); + mixerTaskStart(); storageDirty(EE_MODEL); } void deleteExpo(uint8_t idx) { - pauseMixerCalculations(); + mixerTaskStop(); ExpoData * expo = expoAddress(idx); int input = expo->chn; memmove(expo, expo+1, (MAX_EXPOS-(idx+1))*sizeof(ExpoData)); @@ -74,7 +75,7 @@ void deleteExpo(uint8_t idx) if (!isInputAvailable(input)) { memclear(&g_model.inputNames[input], LEN_INPUT_NAME); } - resumeMixerCalculations(); + mixerTaskStart(); storageDirty(EE_MODEL); } @@ -85,7 +86,7 @@ int8_t s_copySrcRow; void insertExpo(uint8_t idx, uint8_t input) { - pauseMixerCalculations(); + mixerTaskStop(); ExpoData * expo = expoAddress(idx); memmove(expo+1, expo, (MAX_EXPOS-(idx+1))*sizeof(ExpoData)); memclear(expo, sizeof(ExpoData)); @@ -94,7 +95,7 @@ void insertExpo(uint8_t idx, uint8_t input) expo->mode = 3; // pos+neg expo->chn = input; expo->weight = 100; - resumeMixerCalculations(); + mixerTaskStart(); storageDirty(EE_MODEL); } diff --git a/radio/src/gui/colorlcd/model_mixes.cpp b/radio/src/gui/colorlcd/model_mixes.cpp index ca13fa59e..d561ce414 100644 --- a/radio/src/gui/colorlcd/model_mixes.cpp +++ b/radio/src/gui/colorlcd/model_mixes.cpp @@ -31,6 +31,8 @@ #include "input_mix_button.h" #include "mixer_edit.h" +#include "tasks/mixer_task.h" + #define SET_DIRTY() storageDirty(EE_MODEL) #define PASTE_BEFORE -2 #define PASTE_AFTER -1 @@ -66,7 +68,7 @@ uint8_t getMixesCount() void insertMix(uint8_t idx, uint8_t channel) { - pauseMixerCalculations(); + mixerTaskStop(); MixData *mix = mixAddress(idx); memmove(mix + 1, mix, (MAX_MIXERS - (idx + 1)) * sizeof(MixData)); memclear(mix, sizeof(MixData)); @@ -80,17 +82,17 @@ void insertMix(uint8_t idx, uint8_t channel) } } mix->weight = 100; - resumeMixerCalculations(); + mixerTaskStart(); storageDirty(EE_MODEL); } void deleteMix(uint8_t idx) { - pauseMixerCalculations(); + mixerTaskStop(); MixData * mix = mixAddress(idx); memmove(mix, mix + 1, (MAX_MIXERS - (idx + 1)) * sizeof(MixData)); memclear(&g_model.mixData[MAX_MIXERS - 1], sizeof(MixData)); - resumeMixerCalculations(); + mixerTaskStart(); storageDirty(EE_MODEL); } @@ -106,7 +108,7 @@ void insertMix(uint8_t idx) void copyMix(uint8_t source, uint8_t dest, int8_t ch) { - pauseMixerCalculations(); + mixerTaskStop(); MixData sourceMix; memcpy(&sourceMix, mixAddress(source), sizeof(MixData)); MixData *mix = mixAddress(dest); @@ -114,7 +116,7 @@ void copyMix(uint8_t source, uint8_t dest, int8_t ch) memmove(mix + 1, mix, trailingMixes * sizeof(MixData)); memcpy(mix, &sourceMix, sizeof(MixData)); mix->destCh = ch; - resumeMixerCalculations(); + mixerTaskStart(); storageDirty(EE_MODEL); } @@ -153,9 +155,9 @@ bool swapMixes(uint8_t &idx, uint8_t up) return true; } - pauseMixerCalculations(); + mixerTaskStop(); memswap(x, y, sizeof(MixData)); - resumeMixerCalculations(); + mixerTaskStart(); idx = tgt_idx; return true; diff --git a/radio/src/gui/colorlcd/model_telemetry.cpp b/radio/src/gui/colorlcd/model_telemetry.cpp index 59a18cd25..b17bd4d1e 100644 --- a/radio/src/gui/colorlcd/model_telemetry.cpp +++ b/radio/src/gui/colorlcd/model_telemetry.cpp @@ -187,9 +187,7 @@ class SensorButton : public Button { lv_obj_set_grid_cell(v->getLvObj(), LV_GRID_ALIGN_STRETCH, 2, 2, LV_GRID_ALIGN_CENTER, 0, 1); TelemetrySensor * sensor = & g_model.telemetrySensors[index]; - if (IS_SPEKTRUM_PROTOCOL()) { - sprintf(s, "%x", sensor->id); - } else if (sensor->type == TELEM_TYPE_CUSTOM && !g_model.ignoreSensorIds) { + if (sensor->type == TELEM_TYPE_CUSTOM && !g_model.ignoreSensorIds) { sprintf(s, "%d", sensor->instance); } @@ -589,7 +587,7 @@ void ModelTelemetryPage::build(FormWindow * window, int8_t focusSensorIndex) new StaticText(line, rect_t{}, STR_NAME, 0, FONT(XS) | COLOR_THEME_PRIMARY1); grid2.nextCell(); new StaticText(line, rect_t{}, STR_VALUE, 0, FONT(XS) | COLOR_THEME_PRIMARY1); - if (!g_model.ignoreSensorIds && !IS_SPEKTRUM_PROTOCOL()) { + if (!g_model.ignoreSensorIds) { new StaticText(line, rect_t{}, STR_ID, 0, FONT(XS) | COLOR_THEME_PRIMARY1); } } @@ -821,51 +819,6 @@ std::string getSensorCustomValue(uint8_t sensor, int32_t value, LcdFlags flags) else if (telemetrySensor.unit == UNIT_GPS) { return getGPSSensorValue(telemetryItem, flags); } - else if (telemetrySensor.unit == UNIT_BITFIELD) { - if (IS_FRSKY_SPORT_PROTOCOL()) { - if (telemetrySensor.id >= RBOX_STATE_FIRST_ID && telemetrySensor.id <= RBOX_STATE_LAST_ID) { - if (telemetrySensor.subId == 0) { - if (value == 0) { - return std::string("OK"); - } - else { - for (uint8_t i=0; i<16; i++) { - if (value & (1 << i)) { - char s[] = "CH__ KO"; - strAppendUnsigned(&s[2], i+1, 2); - return std::string(s); - } - } - } - } - else { - if (value == 0) { - return std::string("Rx OK"); - } - else { - static const char * const RXS_STATUS[] = { - "Rx1 Ovl", - "Rx2 Ovl", - "SBUS Ovl", - "Rx1 FS", - "Rx1 LF", - "Rx2 FS", - "Rx2 LF", - "Rx1 Lost", - "Rx2 Lost", - "Rx1 NS", - "Rx2 NS", - }; - for (uint8_t i=0; igetLvObj(), LV_SIZE_CONTENT); ModuleData* md = &g_model.moduleData[moduleIdx]; - auto moduleChoice = new Choice(box, rect_t{}, STR_INTERNAL_MODULE_PROTOCOLS, + auto moduleChoice = new Choice(box, rect_t{}, STR_MODULE_PROTOCOLS, MODULE_TYPE_NONE, MODULE_TYPE_COUNT - 1, GET_DEFAULT(md->type)); diff --git a/radio/src/gui/colorlcd/radio_diaganas.cpp b/radio/src/gui/colorlcd/radio_diaganas.cpp index a88572a7e..824c8df5c 100644 --- a/radio/src/gui/colorlcd/radio_diaganas.cpp +++ b/radio/src/gui/colorlcd/radio_diaganas.cpp @@ -29,7 +29,7 @@ // #endif #if defined(RADIO_FAMILY_T16) || defined(PCBNV14) -#include "../../targets/horus/flyskyHallStick_driver.h" + #include "flysky_gimbal_driver.h" #endif #define STATSDEPTH 8 // ideally a value of power of 2 diff --git a/radio/src/gui/colorlcd/radio_hardware.cpp b/radio/src/gui/colorlcd/radio_hardware.cpp index 16b3775e6..de173cc59 100644 --- a/radio/src/gui/colorlcd/radio_hardware.cpp +++ b/radio/src/gui/colorlcd/radio_hardware.cpp @@ -26,7 +26,7 @@ #include "opentx.h" #include "libopenui.h" #include "hal/adc_driver.h" -#include "aux_serial_driver.h" + #include "hw_intmodule.h" #include "hw_extmodule.h" #include "hw_serial.h" diff --git a/radio/src/gui/colorlcd/radio_sdmanager.cpp b/radio/src/gui/colorlcd/radio_sdmanager.cpp index a6306abd9..6dbc74caf 100644 --- a/radio/src/gui/colorlcd/radio_sdmanager.cpp +++ b/radio/src/gui/colorlcd/radio_sdmanager.cpp @@ -255,10 +255,11 @@ void RadioSdManagerPage::fileAction(const char* path, const char* name, [=]() { BootloaderUpdate(fullpath); }); } } else if (!READ_ONLY() && !strcasecmp(ext, SPORT_FIRMWARE_EXT)) { - if (HAS_SPORT_UPDATE_CONNECTOR()) { - menu->addLine(STR_FLASH_EXTERNAL_DEVICE, - [=]() { FrSkyFirmwareUpdate(fullpath, SPORT_MODULE); }); - } + // TODO + // if (HAS_SPORT_UPDATE_CONNECTOR()) { + // menu->addLine(STR_FLASH_EXTERNAL_DEVICE, + // [=]() { FrSkyFirmwareUpdate(fullpath, SPORT_MODULE); }); + // } menu->addLine(STR_FLASH_INTERNAL_MODULE, [=]() { FrSkyFirmwareUpdate(fullpath, INTERNAL_MODULE); }); menu->addLine(STR_FLASH_EXTERNAL_MODULE, @@ -279,15 +280,15 @@ void RadioSdManagerPage::fileAction(const char* path, const char* name, } if (information.productFamily == FIRMWARE_FAMILY_RECEIVER || information.productFamily == FIRMWARE_FAMILY_SENSOR) { - if (HAS_SPORT_UPDATE_CONNECTOR()) { - menu->addLine(STR_FLASH_EXTERNAL_DEVICE, [=]() { - FrSkyFirmwareUpdate(fullpath, SPORT_MODULE); - }); - } else { - menu->addLine(STR_FLASH_EXTERNAL_MODULE, [=]() { - FrSkyFirmwareUpdate(fullpath, EXTERNAL_MODULE); - }); - } + // if (HAS_SPORT_UPDATE_CONNECTOR()) { + // menu->addLine(STR_FLASH_EXTERNAL_DEVICE, [=]() { + // FrSkyFirmwareUpdate(fullpath, SPORT_MODULE); + // }); + // } else { + menu->addLine(STR_FLASH_EXTERNAL_MODULE, [=]() { + FrSkyFirmwareUpdate(fullpath, EXTERNAL_MODULE); + }); + // } } #if _NYI_ // Not yet implemented #if defined(PXX2) @@ -325,14 +326,6 @@ void RadioSdManagerPage::fileAction(const char* path, const char* name, }); } #endif -#if defined(HARDWARE_POWER_MANAGEMENT_UNIT) - if (information.productFamily == - FIRMWARE_FAMILY_POWER_MANAGEMENT_UNIT) { - menu->addLine(STR_FLASH_POWER_MANAGEMENT_UNIT, [=]() { - FrSkyFirmwareUpdate(fullpath, STR_FLASH_POWER_MANAGEMENT_UNIT); - }); - } -#endif #endif // _NYI_ } } diff --git a/radio/src/gui/colorlcd/radio_setup.cpp b/radio/src/gui/colorlcd/radio_setup.cpp index d5d0f55d6..e59efe670 100644 --- a/radio/src/gui/colorlcd/radio_setup.cpp +++ b/radio/src/gui/colorlcd/radio_setup.cpp @@ -25,6 +25,8 @@ #include "opentx.h" #include "libopenui.h" +#include "tasks/mixer_task.h" + #define SET_DIRTY() storageDirty(EE_GENERAL) static const lv_coord_t col_two_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1), @@ -777,11 +779,11 @@ void RadioSetupPage::build(FormWindow * window) grid.setColSpan(2); choice = new Choice(line, rect_t{}, 0, 3, GET_DEFAULT(g_eeGeneral.stickMode), [=](uint8_t newValue) { - pausePulses(); + mixerTaskStop(); g_eeGeneral.stickMode = newValue; SET_DIRTY(); checkThrottleStick(); - resumePulses(); + mixerTaskStart(); }); choice->setTextHandler([](uint8_t value) { return std::to_string(1 + value) + ": " + STR_LEFT_STICK + " = " + diff --git a/radio/src/gui/colorlcd/radio_spectrum_analyser.cpp b/radio/src/gui/colorlcd/radio_spectrum_analyser.cpp index 13326205d..e131849c7 100644 --- a/radio/src/gui/colorlcd/radio_spectrum_analyser.cpp +++ b/radio/src/gui/colorlcd/radio_spectrum_analyser.cpp @@ -281,15 +281,21 @@ void RadioSpectrumAnalyser::start() void RadioSpectrumAnalyser::stop() { +#if defined(PXX2) if (isModulePXX2(moduleIdx)) { moduleState[moduleIdx].readModuleInformation( &reusableBuffer.moduleSetup.pxx2.moduleInformation, PXX2_HW_INFO_TX_ID, PXX2_HW_INFO_TX_ID); - } else if (isModuleMultimodule(moduleIdx)) { + } +#endif + +#if defined(MULTIMODULE) + if (isModuleMultimodule(moduleIdx)) { moduleState[moduleIdx].mode = MODULE_MODE_NORMAL; if (reusableBuffer.spectrumAnalyser.moduleOFF) setModuleType(INTERNAL_MODULE, MODULE_TYPE_NONE); } +#endif /* wait 1s to resume normal operation before leaving */ // watchdogSuspend(1000); // RTOS_WAIT_MS(1000); diff --git a/radio/src/gui/colorlcd/radio_tools.cpp b/radio/src/gui/colorlcd/radio_tools.cpp index adfd47f74..397c42dfb 100644 --- a/radio/src/gui/colorlcd/radio_tools.cpp +++ b/radio/src/gui/colorlcd/radio_tools.cpp @@ -27,6 +27,7 @@ #include "libopenui.h" #include "lua/lua_api.h" #include "standalone_lua.h" +#include "hal/module_port.h" extern uint8_t g_moduleIdx; @@ -44,7 +45,7 @@ void RadioToolsPage::build(FormWindow * window) #if defined(PXX2) for (uint8_t module = 0; module < NUM_MODULES; module++) { - if (isModulePXX2(module) && (module == INTERNAL_MODULE ? IS_INTERNAL_MODULE_ON() : IS_EXTERNAL_MODULE_ON())) { + if (isModulePXX2(module) && (module == INTERNAL_MODULE ? modulePortPowered(INTERNAL_MODULE) : modulePortPowered(EXTERNAL_MODULE))) { waiting |= (1 << module); moduleState[module].readModuleInformation(&reusableBuffer.radioTools.modules[module], PXX2_HW_INFO_TX_ID, PXX2_HW_INFO_TX_ID); } @@ -56,6 +57,7 @@ void RadioToolsPage::build(FormWindow * window) void RadioToolsPage::checkEvents() { +#if defined(PXX2) bool refresh = false; for (uint8_t module = 0; module < NUM_MODULES; module++) { @@ -68,6 +70,7 @@ void RadioToolsPage::checkEvents() if (refresh) { rebuild(window); } +#endif PageTab::checkEvents(); } diff --git a/radio/src/gui/colorlcd/radio_version.cpp b/radio/src/gui/colorlcd/radio_version.cpp index f47a74545..6c5f23c1d 100644 --- a/radio/src/gui/colorlcd/radio_version.cpp +++ b/radio/src/gui/colorlcd/radio_version.cpp @@ -24,11 +24,13 @@ #include "options.h" #include "libopenui.h" #include "fw_version.h" +#include "hal/module_port.h" #if defined(CROSSFIRE) #include "mixer_scheduler.h" #endif +#if defined(PXX2) char *getVersion(char *str, PXX2Version version) { if (version.major == 0xFF && version.minor == 0x0F && @@ -40,6 +42,7 @@ char *getVersion(char *str, PXX2Version version) return str; } } +#endif static const lv_coord_t col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(2), LV_GRID_TEMPLATE_LAST}; static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST}; @@ -70,22 +73,24 @@ class VersionDialog : public Dialog VersionDialog(Window *parent) : Dialog(parent, STR_MODULES_RX_VERSION, rect_t{ 0, 0, 200, 100 }) { +#if defined(PXX2) memclear(&reusableBuffer.hardwareAndSettings.modules, sizeof(reusableBuffer.hardwareAndSettings.modules)); reusableBuffer.hardwareAndSettings.updateTime = get_tmr10ms(); // Query modules - if (isModulePXX2(INTERNAL_MODULE) && IS_INTERNAL_MODULE_ON()) { + if (isModulePXX2(INTERNAL_MODULE) && modulePortPowered(INTERNAL_MODULE)) { moduleState[INTERNAL_MODULE].readModuleInformation( &reusableBuffer.hardwareAndSettings.modules[INTERNAL_MODULE], PXX2_HW_INFO_TX_ID, PXX2_MAX_RECEIVERS_PER_MODULE - 1); } - if (isModulePXX2(EXTERNAL_MODULE) && IS_EXTERNAL_MODULE_ON()) { + if (isModulePXX2(EXTERNAL_MODULE) && modulePortPowered(EXTERNAL_MODULE)) { moduleState[EXTERNAL_MODULE].readModuleInformation( &reusableBuffer.hardwareAndSettings.modules[EXTERNAL_MODULE], PXX2_HW_INFO_TX_ID, PXX2_MAX_RECEIVERS_PER_MODULE - 1); } +#endif setCloseWhenClickOutside(true); @@ -176,7 +181,7 @@ class VersionDialog : public Dialog // initialize to module does not provide status // PXX2 will overwrite name // CRSF, MPM, NV14 and PXX2 will overwrite status - name->setText(STR_INTERNAL_MODULE_PROTOCOLS[g_model.moduleData[module].type]); + name->setText(STR_MODULE_PROTOCOLS[g_model.moduleData[module].type]); lv_obj_add_flag(module_status_w->getLvObj(), LV_OBJ_FLAG_HIDDEN); #if defined(CROSSFIRE) @@ -185,7 +190,8 @@ class VersionDialog : public Dialog char statusText[64]; auto hz = 1000000 / getMixerSchedulerPeriod(); - snprintf(statusText, 64, "%d Hz %" PRIu32 " Err", hz, telemetryErrors); + // snprintf(statusText, 64, "%d Hz %" PRIu32 " Err", hz, telemetryErrors); + snprintf(statusText, 64, "%d Hz", hz); status->setText(statusText); lv_obj_clear_flag(module_status_w->getLvObj(), LV_OBJ_FLAG_HIDDEN); } @@ -292,16 +298,17 @@ class VersionDialog : public Dialog #endif } +#if defined(PXX2) void checkEvents() override { if (get_tmr10ms() >= reusableBuffer.hardwareAndSettings.updateTime) { // Query modules - if (isModulePXX2(INTERNAL_MODULE) && IS_INTERNAL_MODULE_ON()) { + if (isModulePXX2(INTERNAL_MODULE) && modulePortPowered(INTERNAL_MODULE)) { moduleState[INTERNAL_MODULE].readModuleInformation( &reusableBuffer.hardwareAndSettings.modules[INTERNAL_MODULE], PXX2_HW_INFO_TX_ID, PXX2_MAX_RECEIVERS_PER_MODULE - 1); } - if (isModulePXX2(EXTERNAL_MODULE) && IS_EXTERNAL_MODULE_ON()) { + if (isModulePXX2(EXTERNAL_MODULE) && modulePortPowered(EXTERNAL_MODULE)) { moduleState[EXTERNAL_MODULE].readModuleInformation( &reusableBuffer.hardwareAndSettings.modules[EXTERNAL_MODULE], PXX2_HW_INFO_TX_ID, PXX2_MAX_RECEIVERS_PER_MODULE - 1); @@ -311,6 +318,7 @@ class VersionDialog : public Dialog update(); Dialog::checkEvents(); } +#endif }; RadioVersionPage::RadioVersionPage(): diff --git a/radio/src/gui/colorlcd/view_statistics.cpp b/radio/src/gui/colorlcd/view_statistics.cpp index 49614524a..cd1aed77f 100644 --- a/radio/src/gui/colorlcd/view_statistics.cpp +++ b/radio/src/gui/colorlcd/view_statistics.cpp @@ -24,6 +24,9 @@ #include "opentx.h" #include "draw_functions.h" +#include "tasks.h" +#include "tasks/mixer_task.h" + static const lv_coord_t col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_TEMPLATE_LAST}; diff --git a/radio/src/gui/common/stdlcd/draw_functions.cpp b/radio/src/gui/common/stdlcd/draw_functions.cpp index 047a61513..943d0c01a 100644 --- a/radio/src/gui/common/stdlcd/draw_functions.cpp +++ b/radio/src/gui/common/stdlcd/draw_functions.cpp @@ -440,89 +440,16 @@ void drawSensorCustomValue(coord_t x, coord_t y, uint8_t sensor, int32_t value, else if (telemetrySensor.unit == UNIT_GPS) { drawGPSSensorValue(x, y, telemetryItem, flags); } - else if (telemetrySensor.unit == UNIT_BITFIELD) { - if (IS_FRSKY_SPORT_PROTOCOL()) { - if (telemetrySensor.id >= RBOX_STATE_FIRST_ID && telemetrySensor.id <= RBOX_STATE_LAST_ID) { - if (telemetrySensor.subId == 0) { - if (value == 0) { - lcdDrawText(x, y, "OK", flags); - } - else { - for (uint8_t i = 0; i < 16; i++) { - if (value & (1u << i)) { - char s[] = "CH__ KO"; - strAppendUnsigned(&s[2], i + 1, 2); - lcdDrawText(x, flags & DBLSIZE ? y + 1 : y, s, flags & ~DBLSIZE); - break; - } - } - } - } - else { - if (value == 0) { - lcdDrawText(x, flags & DBLSIZE ? y + 1 : y, "Rx OK", flags & ~DBLSIZE); - } - else { - static const char * const RXS_STATUS[] = { - "Rx1 Ovl", - "Rx2 Ovl", - "SBUS Ovl", - "Rx1 FS", - "Rx1 LF", - "Rx2 FS", - "Rx2 LF", - "Rx1 Lost", - "Rx2 Lost", - "Rx1 NS", - "Rx2 NS", - "Rx3 FS", - "Rx3 LF", - "Rx3 Lost", - "Rx3 NS" - }; - for (uint8_t i = 0; i < DIM(RXS_STATUS); i++) { - if (value & (1u << i)) { - lcdDrawText(x, flags & DBLSIZE ? y + 1 : y, RXS_STATUS[i], flags & ~DBLSIZE); - break; - } - } - } - } - } - else if (telemetrySensor.id >= RB3040_OUTPUT_FIRST_ID && telemetrySensor.id <= RB3040_OUTPUT_LAST_ID) { - if (telemetrySensor.subId == 0) { - if (value == 0) { - lcdDrawText(x, y, "OK", flags); - } - else { - for (uint8_t i = 0; i < 9; i++) { - if (value & (1u << i)) { - if (i < 8) { - char s[] = "CH__ KO"; - strAppendUnsigned(&s[2], i + 17, 2); - lcdDrawText(x, flags & DBLSIZE ? y + 1 : y, s, flags & ~DBLSIZE); - break; - } - else { - char s[] = "S.P Ovl"; - lcdDrawText(x, flags & DBLSIZE ? y + 1 : y, s, flags & ~DBLSIZE); - break; - } - } - } - } - } - } - } - } else if (telemetrySensor.unit == UNIT_TEXT) { - lcdDrawSizedText(x, flags & DBLSIZE ? y + 1 : y, telemetryItem.text, sizeof(telemetryItem.text), flags & ~DBLSIZE); - } - else { + lcdDrawSizedText(x, flags & DBLSIZE ? y + 1 : y, telemetryItem.text, + sizeof(telemetryItem.text), flags & ~DBLSIZE); + } else { if (telemetrySensor.prec > 0) { flags |= (telemetrySensor.prec == 1 ? PREC1 : PREC2); } - drawValueWithUnit(x, y, value, telemetrySensor.unit == UNIT_CELLS ? UNIT_VOLTS : telemetrySensor.unit, flags); + drawValueWithUnit(x, y, value, + telemetrySensor.unit == UNIT_CELLS ? UNIT_VOLTS : telemetrySensor.unit, + flags); } } diff --git a/radio/src/gui/common/stdlcd/model_inputs.cpp b/radio/src/gui/common/stdlcd/model_inputs.cpp index 95b4b6d02..023c6b909 100644 --- a/radio/src/gui/common/stdlcd/model_inputs.cpp +++ b/radio/src/gui/common/stdlcd/model_inputs.cpp @@ -20,6 +20,7 @@ */ #include "opentx.h" +#include "tasks/mixer_task.h" #define _STR_MAX(x) "/" #x #define STR_MAX(x) _STR_MAX(x) @@ -51,7 +52,7 @@ bool reachExposLimit() int8_t s_currCh; void insertExpo(uint8_t idx) { - pauseMixerCalculations(); + mixerTaskStop(); ExpoData * expo = expoAddress(idx); memmove(expo+1, expo, (MAX_EXPOS-(idx+1))*sizeof(ExpoData)); memclear(expo, sizeof(ExpoData)); @@ -65,16 +66,16 @@ void insertExpo(uint8_t idx) expo->mode = 3; // pos+neg expo->chn = s_currCh - 1; expo->weight = 100; - resumeMixerCalculations(); + mixerTaskStart(); storageDirty(EE_MODEL); } void copyExpo(uint8_t idx) { - pauseMixerCalculations(); + mixerTaskStop(); ExpoData * expo = expoAddress(idx); memmove(expo+1, expo, (MAX_EXPOS-(idx+1))*sizeof(ExpoData)); - resumeMixerCalculations(); + mixerTaskStart(); storageDirty(EE_MODEL); } @@ -112,9 +113,9 @@ bool swapExpos(uint8_t & idx, uint8_t up) return true; } - pauseMixerCalculations(); + mixerTaskStop(); memswap(x, y, sizeof(ExpoData)); - resumeMixerCalculations(); + mixerTaskStart(); idx = tgt_idx; return true; @@ -122,7 +123,7 @@ bool swapExpos(uint8_t & idx, uint8_t up) void deleteExpo(uint8_t idx) { - pauseMixerCalculations(); + mixerTaskStop(); ExpoData * expo = expoAddress(idx); int input = expo->chn; memmove(expo, expo+1, (MAX_EXPOS-(idx+1))*sizeof(ExpoData)); @@ -130,7 +131,7 @@ void deleteExpo(uint8_t idx) if (!isInputAvailable(input)) { memclear(&g_model.inputNames[input], LEN_INPUT_NAME); } - resumeMixerCalculations(); + mixerTaskStart(); storageDirty(EE_MODEL); } diff --git a/radio/src/gui/common/stdlcd/model_mixes.cpp b/radio/src/gui/common/stdlcd/model_mixes.cpp index c96cbb315..8a16c5045 100644 --- a/radio/src/gui/common/stdlcd/model_mixes.cpp +++ b/radio/src/gui/common/stdlcd/model_mixes.cpp @@ -20,6 +20,7 @@ */ #include "opentx.h" +#include "tasks/mixer_task.h" #define _STR_MAX(x) "/" #x #define STR_MAX(x) _STR_MAX(x) @@ -49,17 +50,17 @@ bool reachMixesLimit() void deleteMix(uint8_t idx) { - pauseMixerCalculations(); + mixerTaskStop(); MixData * mix = mixAddress(idx); memmove(mix, mix+1, (MAX_MIXERS-(idx+1))*sizeof(MixData)); memclear(&g_model.mixData[MAX_MIXERS-1], sizeof(MixData)); - resumeMixerCalculations(); + mixerTaskStart(); storageDirty(EE_MODEL); } void insertMix(uint8_t idx) { - pauseMixerCalculations(); + mixerTaskStop(); MixData * mix = mixAddress(idx); memmove(mix+1, mix, (MAX_MIXERS-(idx+1))*sizeof(MixData)); memclear(mix, sizeof(MixData)); @@ -72,16 +73,16 @@ void insertMix(uint8_t idx) } } mix->weight = 100; - resumeMixerCalculations(); + mixerTaskStart(); storageDirty(EE_MODEL); } void copyMix(uint8_t idx) { - pauseMixerCalculations(); + mixerTaskStop(); MixData * mix = mixAddress(idx); memmove(mix+1, mix, (MAX_MIXERS-(idx+1))*sizeof(MixData)); - resumeMixerCalculations(); + mixerTaskStart(); storageDirty(EE_MODEL); } @@ -120,9 +121,9 @@ bool swapMixes(uint8_t & idx, uint8_t up) return true; } - pauseMixerCalculations(); + mixerTaskStop(); memswap(x, y, sizeof(MixData)); - resumeMixerCalculations(); + mixerTaskStart(); idx = tgt_idx; return true; diff --git a/radio/src/gui/common/stdlcd/radio_ghost_menu.cpp b/radio/src/gui/common/stdlcd/radio_ghost_menu.cpp index 8bf9cdf89..2821e86c5 100644 --- a/radio/src/gui/common/stdlcd/radio_ghost_menu.cpp +++ b/radio/src/gui/common/stdlcd/radio_ghost_menu.cpp @@ -21,9 +21,9 @@ #include "opentx.h" -#if defined(GHOST) - #include "telemetry/ghost.h" -#endif +#if defined(GHOST) && defined(HARDWARE_EXTERNAL_MODULE) + +#include "telemetry/ghost.h" void menuGhostModuleConfig(event_t event) { @@ -126,3 +126,5 @@ void menuGhostModuleConfig(event_t event) } } } + +#endif diff --git a/radio/src/gui/common/stdlcd/radio_hardware.cpp b/radio/src/gui/common/stdlcd/radio_hardware.cpp index 05c41cdd0..9a81ef476 100644 --- a/radio/src/gui/common/stdlcd/radio_hardware.cpp +++ b/radio/src/gui/common/stdlcd/radio_hardware.cpp @@ -21,12 +21,15 @@ #include #include "hal/adc_driver.h" -#include "aux_serial_driver.h" #if defined(CROSSFIRE) #include "telemetry/crossfire.h" #endif +#if defined(BLUETOOTH) + #include "bluetooth_driver.h" +#endif + #if defined(PCBTARANIS) enum { ITEM_RADIO_HARDWARE_LABEL_STICKS, @@ -532,7 +535,7 @@ void menuRadioHardware(event_t event) case ITEM_RADIO_HARDWARE_INTERNAL_MODULE_TYPE: { g_eeGeneral.internalModule = editChoice(HW_SETTINGS_COLUMN2, y, STR_TYPE, - STR_INTERNAL_MODULE_PROTOCOLS, + STR_MODULE_PROTOCOLS, g_eeGeneral.internalModule, MODULE_TYPE_NONE, MODULE_TYPE_MAX, attr, event, isInternalModuleSupported); if (g_model.moduleData[INTERNAL_MODULE].type != @@ -663,14 +666,15 @@ void menuRadioHardware(event_t event) lcdDrawText(lcdNextPos, y, "---"); break; -#if defined(SPORT_UPDATE_PWR_GPIO) - case ITEM_RADIO_HARDWARE_SPORT_UPDATE_POWER: - g_eeGeneral.sportUpdatePower = editChoice(HW_SETTINGS_COLUMN2, y, STR_SPORT_UPDATE_POWER_MODE, STR_SPORT_UPDATE_POWER_MODES, g_eeGeneral.sportUpdatePower, 0, 1, attr, event); - if (attr && checkIncDec_Ret) { - SPORT_UPDATE_POWER_INIT(); - } - break; -#endif +// TODO: this is board specific, do something about it! +// #if defined(SPORT_UPDATE_PWR_GPIO) +// case ITEM_RADIO_HARDWARE_SPORT_UPDATE_POWER: +// g_eeGeneral.sportUpdatePower = editChoice(HW_SETTINGS_COLUMN2, y, STR_SPORT_UPDATE_POWER_MODE, STR_SPORT_UPDATE_POWER_MODES, g_eeGeneral.sportUpdatePower, 0, 1, attr, event); +// if (attr && checkIncDec_Ret) { +// SPORT_UPDATE_POWER_INIT(); +// } +// break; +// #endif case ITEM_RADIO_HARDWARE_DEBUG: lcdDrawTextAlignedLeft(y, STR_DEBUG); diff --git a/radio/src/gui/common/stdlcd/radio_sdmanager.cpp b/radio/src/gui/common/stdlcd/radio_sdmanager.cpp index f2619d86a..ddf31860a 100644 --- a/radio/src/gui/common/stdlcd/radio_sdmanager.cpp +++ b/radio/src/gui/common/stdlcd/radio_sdmanager.cpp @@ -92,6 +92,9 @@ void onSdFormatConfirm(const char * result) } #if defined(PXX2) + +#include "pulses/pxx2_ota.h" + void onUpdateConfirmation(const char * result) { if (result == STR_OK) { @@ -108,26 +111,19 @@ void onUpdateStateChanged() { if (reusableBuffer.sdManager.otaUpdateInformation.step == BIND_INFO_REQUEST) { uint8_t modelId = reusableBuffer.sdManager.otaUpdateInformation.receiverInformation.modelID; - if (modelId > 0 && modelId < DIM(PXX2ReceiversNames)) { - if (isPXX2ReceiverOptionAvailable(modelId, RECEIVER_OPTION_OTA)) { - POPUP_CONFIRMATION(getPXX2ReceiverName(modelId), onUpdateConfirmation); - char *tmp = strAppend(reusableBuffer.sdManager.otaReceiverVersion, TR_CURRENT_VERSION); - tmp = strAppendUnsigned(tmp, 1 + reusableBuffer.sdManager.otaUpdateInformation.receiverInformation.swVersion.major); - *tmp++ = '.'; - tmp = strAppendUnsigned(tmp, reusableBuffer.sdManager.otaUpdateInformation.receiverInformation.swVersion.minor); - *tmp++ = '.'; - tmp = strAppendUnsigned(tmp, reusableBuffer.sdManager.otaUpdateInformation.receiverInformation.swVersion.revision); - SET_WARNING_INFO(reusableBuffer.sdManager.otaReceiverVersion, tmp - reusableBuffer.sdManager.otaReceiverVersion, 0); - } - else { - POPUP_WARNING(STR_OTA_UPDATE_ERROR); - SET_WARNING_INFO(STR_UNSUPPORTED_RX, sizeof(TR_UNSUPPORTED_RX) - 1, 0); - moduleState[reusableBuffer.sdManager.otaUpdateInformation.module].mode = MODULE_MODE_NORMAL; - } + if (isPXX2ReceiverOptionAvailable(modelId, RECEIVER_OPTION_OTA)) { + POPUP_CONFIRMATION(getPXX2ReceiverName(modelId), onUpdateConfirmation); + char *tmp = strAppend(reusableBuffer.sdManager.otaReceiverVersion, TR_CURRENT_VERSION); + tmp = strAppendUnsigned(tmp, 1 + reusableBuffer.sdManager.otaUpdateInformation.receiverInformation.swVersion.major); + *tmp++ = '.'; + tmp = strAppendUnsigned(tmp, reusableBuffer.sdManager.otaUpdateInformation.receiverInformation.swVersion.minor); + *tmp++ = '.'; + tmp = strAppendUnsigned(tmp, reusableBuffer.sdManager.otaUpdateInformation.receiverInformation.swVersion.revision); + SET_WARNING_INFO(reusableBuffer.sdManager.otaReceiverVersion, tmp - reusableBuffer.sdManager.otaReceiverVersion, 0); } else { POPUP_WARNING(STR_OTA_UPDATE_ERROR); - SET_WARNING_INFO(STR_UNKNOWN_RX, sizeof(TR_UNKNOWN_RX) - 1, 0); + SET_WARNING_INFO(STR_UNSUPPORTED_RX, sizeof(TR_UNSUPPORTED_RX) - 1, 0); moduleState[reusableBuffer.sdManager.otaUpdateInformation.module].mode = MODULE_MODE_NORMAL; } } @@ -220,12 +216,14 @@ void onSdManagerMenu(const char * result) FrskyDeviceFirmwareUpdate device(INTERNAL_MODULE); device.flashFirmware(lfn, drawProgressScreen); } +#if defined(HARDWARE_EXTERNAL_MODULE) else if (result == STR_FLASH_EXTERNAL_MODULE) { // needed on X-Lite (as the R9M needs 2S while the external device flashing port only provides 5V) getSelectionFullPath(lfn); FrskyDeviceFirmwareUpdate device(EXTERNAL_MODULE); device.flashFirmware(lfn, drawProgressScreen); } +#endif else if (result == STR_FLASH_EXTERNAL_DEVICE) { getSelectionFullPath(lfn); FrskyDeviceFirmwareUpdate device(SPORT_MODULE); @@ -239,6 +237,7 @@ void onSdManagerMenu(const char * result) device.flashFirmware(lfn, drawProgressScreen); } #endif +#if defined(HARDWARE_EXTERNAL_MODULE) else if (result == STR_FLASH_EXTERNAL_MULTI) { getSelectionFullPath(lfn); MultiDeviceFirmwareUpdate device(EXTERNAL_MODULE, MULTI_TYPE_MULTIMODULE); @@ -250,20 +249,14 @@ void onSdManagerMenu(const char * result) device.flashFirmware(lfn, drawProgressScreen); } #endif +#endif #if defined(BLUETOOTH) else if (result == STR_FLASH_BLUETOOTH_MODULE) { getSelectionFullPath(lfn); bluetooth.flashFirmware(lfn, drawProgressScreen); } #endif -#if defined(HARDWARE_POWER_MANAGEMENT_UNIT) - else if (result == STR_FLASH_POWER_MANAGEMENT_UNIT) { - getSelectionFullPath(lfn); - FrskyChipFirmwareUpdate device; - device.flashFirmware(lfn, drawProgressScreen); - } -#endif -#if defined(PXX2) +#if defined(PXX2) && defined(HARDWARE_EXTERNAL_MODULE) else if (result == STR_FLASH_RECEIVER_BY_INTERNAL_MODULE_OTA || result == STR_FLASH_RECEIVER_BY_EXTERNAL_MODULE_OTA) { memclear(&reusableBuffer.sdManager.otaUpdateInformation, sizeof(OtaUpdateInformation)); getSelectionFullPath(reusableBuffer.sdManager.otaUpdateInformation.filename); @@ -432,29 +425,38 @@ void menuRadioSdManager(event_t _event) } } else if (!READ_ONLY() && !strcasecmp(ext, SPORT_FIRMWARE_EXT)) { - if (HAS_SPORT_UPDATE_CONNECTOR()) + auto mod_desc = modulePortGetModuleDescription(SPORT_MODULE); + if (mod_desc && mod_desc->set_pwr) POPUP_MENU_ADD_ITEM(STR_FLASH_EXTERNAL_DEVICE); -#if defined(INTERNAL_MODULE_PXX1) || defined(INTERNAL_MODULE_PXX2) - POPUP_MENU_ADD_ITEM(STR_FLASH_INTERNAL_MODULE); -#endif + + if (g_eeGeneral.internalModule == MODULE_TYPE_XJT_PXX1 || + g_eeGeneral.internalModule == MODULE_TYPE_ISRM_PXX2) + POPUP_MENU_ADD_ITEM(STR_FLASH_INTERNAL_MODULE); + POPUP_MENU_ADD_ITEM(STR_FLASH_EXTERNAL_MODULE); } else if (!READ_ONLY() && !strcasecmp(ext, FRSKY_FIRMWARE_EXT)) { FrSkyFirmwareInformation information; if (readFrSkyFirmwareInformation(line, information) == nullptr) { -#if defined(INTERNAL_MODULE_PXX1) || defined(INTERNAL_MODULE_PXX2) - if (information.productFamily == FIRMWARE_FAMILY_INTERNAL_MODULE) + + if (information.productFamily == FIRMWARE_FAMILY_INTERNAL_MODULE && + (g_eeGeneral.internalModule == MODULE_TYPE_XJT_PXX1 || + g_eeGeneral.internalModule == MODULE_TYPE_ISRM_PXX2)) POPUP_MENU_ADD_ITEM(STR_FLASH_INTERNAL_MODULE); -#endif + if (information.productFamily == FIRMWARE_FAMILY_EXTERNAL_MODULE) POPUP_MENU_ADD_ITEM(STR_FLASH_EXTERNAL_MODULE); - if (information.productFamily == FIRMWARE_FAMILY_RECEIVER || information.productFamily == FIRMWARE_FAMILY_SENSOR) { - if (HAS_SPORT_UPDATE_CONNECTOR()) + + if (information.productFamily == FIRMWARE_FAMILY_RECEIVER || + information.productFamily == FIRMWARE_FAMILY_SENSOR) { + + auto mod_desc = modulePortGetModuleDescription(SPORT_MODULE); + if (mod_desc && mod_desc->set_pwr) POPUP_MENU_ADD_ITEM(STR_FLASH_EXTERNAL_DEVICE); else POPUP_MENU_ADD_ITEM(STR_FLASH_EXTERNAL_MODULE); } -#if defined(PXX2) +#if defined(PXX2) && defined(HARDWARE_EXTERNAL_MODULE) if (information.productFamily == FIRMWARE_FAMILY_RECEIVER) { if (isReceiverOTAEnabledFromModule(INTERNAL_MODULE, information.productId)) POPUP_MENU_ADD_ITEM(STR_FLASH_RECEIVER_BY_INTERNAL_MODULE_OTA); @@ -469,10 +471,6 @@ void menuRadioSdManager(event_t _event) #if defined(BLUETOOTH) if (information.productFamily == FIRMWARE_FAMILY_BLUETOOTH_CHIP) POPUP_MENU_ADD_ITEM(STR_FLASH_BLUETOOTH_MODULE); -#endif -#if defined(HARDWARE_POWER_MANAGEMENT_UNIT) - if (information.productFamily == FIRMWARE_FAMILY_POWER_MANAGEMENT_UNIT) - POPUP_MENU_ADD_ITEM(STR_FLASH_POWER_MANAGEMENT_UNIT); #endif } } diff --git a/radio/src/gui/common/stdlcd/radio_spectrum_analyser.cpp b/radio/src/gui/common/stdlcd/radio_spectrum_analyser.cpp index 9a1a023be..451f44cc1 100644 --- a/radio/src/gui/common/stdlcd/radio_spectrum_analyser.cpp +++ b/radio/src/gui/common/stdlcd/radio_spectrum_analyser.cpp @@ -44,7 +44,9 @@ void menuRadioSpectrumAnalyser(event_t event) if (menuEvent) { lcdDrawCenteredText(LCD_H/2, STR_STOPPING); lcdRefresh(); +#if defined(PXX2) moduleState[g_moduleIdx].readModuleInformation(&reusableBuffer.moduleSetup.pxx2.moduleInformation, PXX2_HW_INFO_TX_ID, PXX2_HW_INFO_TX_ID); +#endif /* wait 1s to resume normal operation before leaving */ watchdogSuspend(500 /*5s*/); RTOS_WAIT_MS(1000); diff --git a/radio/src/gui/common/stdlcd/radio_tools.cpp b/radio/src/gui/common/stdlcd/radio_tools.cpp index bc35ca8dc..c47e40ceb 100644 --- a/radio/src/gui/common/stdlcd/radio_tools.cpp +++ b/radio/src/gui/common/stdlcd/radio_tools.cpp @@ -22,6 +22,7 @@ #include #include #include "opentx.h" +#include "hal/module_port.h" extern uint8_t g_moduleIdx; @@ -104,7 +105,7 @@ void menuRadioTools(event_t event) memclear(&reusableBuffer.radioTools, sizeof(reusableBuffer.radioTools)); #if defined(PXX2) for (uint8_t module = 0; module < NUM_MODULES; module++) { - if (isModulePXX2(module) && (module == INTERNAL_MODULE ? IS_INTERNAL_MODULE_ON() : IS_EXTERNAL_MODULE_ON())) { + if (isModulePXX2(module) && (module == INTERNAL_MODULE ? modulePortPowered(INTERNAL_MODULE) : modulePortPowered(EXTERNAL_MODULE))) { moduleState[module].readModuleInformation(&reusableBuffer.radioTools.modules[module], PXX2_HW_INFO_TX_ID, PXX2_HW_INFO_TX_ID); } } @@ -161,12 +162,25 @@ void menuRadioTools(event_t event) if (isPXX2ModuleOptionAvailable(reusableBuffer.radioTools.modules[INTERNAL_MODULE].information.modelID, MODULE_OPTION_POWER_METER)) addRadioModuleTool(index++, STR_POWER_METER_INT, menuRadioPowerMeter, INTERNAL_MODULE); #endif + #if defined(HARDWARE_INTERNAL_MODULE) && defined(MULTIMODULE) if (g_eeGeneral.internalModule == MODULE_TYPE_MULTIMODULE) addRadioModuleTool(index++, STR_SPECTRUM_ANALYSER_INT, menuRadioSpectrumAnalyser, INTERNAL_MODULE); #endif -#if defined(PXX2) || defined(MULTIMODULE) - if (isPXX2ModuleOptionAvailable(reusableBuffer.radioTools.modules[EXTERNAL_MODULE].information.modelID, MODULE_OPTION_SPECTRUM_ANALYSER) || isModuleMultimodule(EXTERNAL_MODULE)) + +#if defined(HARDWARE_EXTERNAL_MODULE) + +#if (defined(PXX2) || defined(MULTIMODULE)) + bool has_spectrum_analyser = false; +#if defined(PXX2) + if (isPXX2ModuleOptionAvailable(reusableBuffer.radioTools.modules[EXTERNAL_MODULE].information.modelID, MODULE_OPTION_SPECTRUM_ANALYSER)) + has_spectrum_analyser = true; +#endif +#if defined(MULTIMODULE) + if (isModuleMultimodule(EXTERNAL_MODULE)) + has_spectrum_analyser = true; +#endif + if (has_spectrum_analyser) addRadioModuleTool(index++, STR_SPECTRUM_ANALYSER_EXT, menuRadioSpectrumAnalyser, EXTERNAL_MODULE); #endif #if defined(PXX2) @@ -177,6 +191,8 @@ void menuRadioTools(event_t event) #if defined(GHOST) if (isModuleGhost(EXTERNAL_MODULE)) addRadioModuleTool(index++, "Ghost Menu", menuGhostModuleConfig, EXTERNAL_MODULE); +#endif + #endif if (index == 0) { diff --git a/radio/src/gui/common/stdlcd/radio_version.cpp b/radio/src/gui/common/stdlcd/radio_version.cpp index 429dc41cf..f3761abf1 100644 --- a/radio/src/gui/common/stdlcd/radio_version.cpp +++ b/radio/src/gui/common/stdlcd/radio_version.cpp @@ -21,6 +21,8 @@ #include "opentx.h" #include "options.h" +#include "hal/module_port.h" + #if defined(CROSSFIRE) #include "mixer_scheduler.h" #endif @@ -95,8 +97,9 @@ void drawPXX2FullVersion(coord_t x, coord_t y, PXX2Version hwVersion, PXX2Versio void menuRadioModulesVersion(event_t event) { if (menuEvent) { - moduleState[INTERNAL_MODULE].mode = MODULE_MODE_NORMAL; - moduleState[EXTERNAL_MODULE].mode = MODULE_MODE_NORMAL; + for (uint8_t i = 0; i < MAX_MODULES; i++) { + moduleState[i].mode = MODULE_MODE_NORMAL; + } return; } @@ -107,13 +110,18 @@ void menuRadioModulesVersion(event_t event) } if (event == EVT_ENTRY || get_tmr10ms() >= reusableBuffer.hardwareAndSettings.updateTime) { - if (isModulePXX2(INTERNAL_MODULE) && IS_INTERNAL_MODULE_ON()) { + +#if defined(HARDWARE_INTERNAL_MODULE) + if (isModulePXX2(INTERNAL_MODULE) && modulePortPowered(INTERNAL_MODULE)) { moduleState[INTERNAL_MODULE].readModuleInformation(&reusableBuffer.hardwareAndSettings.modules[INTERNAL_MODULE], PXX2_HW_INFO_TX_ID, PXX2_MAX_RECEIVERS_PER_MODULE - 1); } +#endif - if (isModulePXX2(EXTERNAL_MODULE) && IS_EXTERNAL_MODULE_ON()) { +#if defined(HARDWARE_EXTERNAL_MODULE) + if (isModulePXX2(EXTERNAL_MODULE) && modulePortPowered(EXTERNAL_MODULE)) { moduleState[EXTERNAL_MODULE].readModuleInformation(&reusableBuffer.hardwareAndSettings.modules[EXTERNAL_MODULE], PXX2_HW_INFO_TX_ID, PXX2_MAX_RECEIVERS_PER_MODULE - 1); } +#endif reusableBuffer.hardwareAndSettings.updateTime = get_tmr10ms() + 1000 /* 10s*/; } @@ -123,18 +131,30 @@ void menuRadioModulesVersion(event_t event) for (uint8_t module=0; module= MENU_BODY_TOP && y < MENU_BODY_BOTTOM) { +#if defined(HARDWARE_INTERNAL_MODULE) if (module == INTERNAL_MODULE) lcdDrawTextAlignedLeft(y, STR_INTERNAL_MODULE); - else if (module == EXTERNAL_MODULE) +#endif +#if defined(HARDWARE_EXTERNAL_MODULE) + if (module == EXTERNAL_MODULE) lcdDrawTextAlignedLeft(y, STR_EXTERNAL_MODULE); +#endif } y += FH; // Module model if (y >= MENU_BODY_TOP && y < MENU_BODY_BOTTOM) { lcdDrawText(INDENT_WIDTH, y, STR_MODULE); - if ((module == INTERNAL_MODULE && !IS_INTERNAL_MODULE_ON()) || - (module == EXTERNAL_MODULE && !IS_EXTERNAL_MODULE_ON())) { + bool module_off = true; +#if defined(HARDWARE_INTERNAL_MODULE) + if (module == INTERNAL_MODULE && modulePortPowered(INTERNAL_MODULE)) + module_off = false; +#endif +#if defined(HARDWARE_EXTERNAL_MODULE) + if (module == EXTERNAL_MODULE && modulePortPowered(EXTERNAL_MODULE)) + module_off = false; +#endif + if (module_off) { lcdDrawText(COLUMN2_X, y, STR_OFF); y += FH; continue; @@ -152,7 +172,7 @@ void menuRadioModulesVersion(event_t event) if (isModuleCrossfire(module)) { char statusText[64] = ""; sprintf(statusText, "%d Hz %zu Err", - 1000000 / getMixerSchedulerPeriod(), (size_t)telemetryErrors); + 1000000 / getMixerSchedulerPeriod(), (size_t)0/*telemetryErrors*/); lcdDrawText(COLUMN2_X, y, statusText); y += FH; continue; diff --git a/radio/src/gui/gui_common.cpp b/radio/src/gui/gui_common.cpp index bd5c3bbab..f5071b768 100644 --- a/radio/src/gui/gui_common.cpp +++ b/radio/src/gui/gui_common.cpp @@ -20,10 +20,7 @@ */ #include "opentx.h" - -#if defined(PXX2) - #include "extmodule_serial_driver.h" -#endif +#include "hal/module_port.h" #if defined(PCBFRSKY) || defined(PCBFLYSKY) uint8_t switchToMix(uint8_t source) @@ -726,12 +723,16 @@ bool isModuleUsingSport(uint8_t moduleBay, uint8_t moduleType) // External XJT has a physical switch to disable S.PORT case MODULE_TYPE_R9M_PXX1: // R9M telemetry is disabled by pulses (pxx1.cpp) +#if defined(HARDWARE_EXTERNAL_MODULE) if (moduleBay == EXTERNAL_MODULE) return false; +#endif case MODULE_TYPE_CROSSFIRE: +#if defined(HARDWARE_INTERNAL_MODULE) if (moduleBay == INTERNAL_MODULE) return false; +#endif default: return true; @@ -785,7 +786,7 @@ bool isInternalModuleAvailable(int moduleType) if (g_eeGeneral.internalModule != moduleType) return false; -#if defined(INTERNAL_MODULE_PXX1) +#if defined(INTERNAL_MODULE_PXX1) && defined(HARDWARE_EXTERNAL_MODULE) if ((moduleType == MODULE_TYPE_XJT_PXX1) && isModuleUsingSport(EXTERNAL_MODULE, g_model.moduleData[EXTERNAL_MODULE].type)) { @@ -793,7 +794,7 @@ bool isInternalModuleAvailable(int moduleType) } #endif -#if defined(INTERNAL_MODULE_PXX2) +#if defined(INTERNAL_MODULE_PXX2) && defined(HARDWARE_EXTERNAL_MODULE) if ((moduleType == MODULE_TYPE_ISRM_PXX2) && areModulesConflicting(moduleType, g_model.moduleData[EXTERNAL_MODULE].type)) { @@ -854,7 +855,8 @@ bool isExternalModuleAvailable(int moduleType) moduleType == MODULE_TYPE_R9M_LITE_PRO_PXX2) { #if defined(PXX2) - return extmoduleGetSerialPort() != nullptr; + return modulePortFind(EXTERNAL_MODULE, ETX_MOD_TYPE_SERIAL, + ETX_MOD_PORT_UART, ETX_Pol_Normal); #else return false; #endif @@ -916,22 +918,25 @@ bool isExternalModuleAvailable(int moduleType) bool isRfProtocolAvailable(int protocol) { -#if defined(CROSSFIRE) +#if defined(CROSSFIRE) && defined(HARDWARE_EXTERNAL_MODULE) if (protocol != MODULE_SUBTYPE_PXX1_OFF && g_model.moduleData[EXTERNAL_MODULE].type == MODULE_TYPE_CROSSFIRE) { return false; } #endif -#if defined(GHOST) + +#if defined(GHOST) && defined(HARDWARE_EXTERNAL_MODULE) if (protocol != MODULE_SUBTYPE_PXX1_OFF && g_model.moduleData[EXTERNAL_MODULE].type == MODULE_TYPE_GHOST) { return false; } #endif + #if !defined(MODULE_PROTOCOL_D8) if (protocol == MODULE_SUBTYPE_PXX1_ACCST_D8) { return false; } #endif -#if defined(PCBTARANIS) || defined(PCBHORUS) + +#if (defined(PCBTARANIS) || defined(PCBHORUS)) && defined(HARDWARE_EXTERNAL_MODULE) if (protocol != MODULE_SUBTYPE_PXX1_OFF && g_model.moduleData[EXTERNAL_MODULE].type == MODULE_TYPE_R9M_PXX1) { return false; } @@ -1029,7 +1034,7 @@ bool isTrainerModeAvailable(int mode) return false; #endif -#if !defined(MULTIMODULE) +#if !defined(MULTIMODULE) || !defined(HARDWARE_INTERNAL_MODULE) || !defined(HARDWARE_EXTERNAL_MODULE) if (mode == TRAINER_MODE_MULTI) return false; #else diff --git a/radio/src/hal/module_driver.h b/radio/src/hal/module_driver.h index fddcb9ec2..11c04023c 100644 --- a/radio/src/hal/module_driver.h +++ b/radio/src/hal/module_driver.h @@ -27,23 +27,21 @@ enum ChannelsProtocols { PROTOCOL_CHANNELS_UNINITIALIZED, PROTOCOL_CHANNELS_NONE, PROTOCOL_CHANNELS_PPM, - PROTOCOL_CHANNELS_PXX1_PULSES, - PROTOCOL_CHANNELS_PXX1_SERIAL, + PROTOCOL_CHANNELS_PXX1, PROTOCOL_CHANNELS_DSM2_LP45, PROTOCOL_CHANNELS_DSM2_DSM2, PROTOCOL_CHANNELS_DSM2_DSMX, PROTOCOL_CHANNELS_CROSSFIRE, PROTOCOL_CHANNELS_MULTIMODULE, PROTOCOL_CHANNELS_SBUS, - PROTOCOL_CHANNELS_PXX2_LOWSPEED, - PROTOCOL_CHANNELS_PXX2_HIGHSPEED, + PROTOCOL_CHANNELS_PXX2, PROTOCOL_CHANNELS_AFHDS2A, PROTOCOL_CHANNELS_AFHDS3, PROTOCOL_CHANNELS_GHOST, PROTOCOL_CHANNELS_DSMP }; -struct etx_module_driver_t { +struct etx_proto_driver_t { // Protocol implemented by this module driver ChannelsProtocols protocol; @@ -51,20 +49,11 @@ struct etx_module_driver_t { // Init module communication void* (*init)(uint8_t module); - // // Default pulse period in microseconds - // uint16_t (*get_default_period)(uint8_t module); - // De-Init module communication - void (*deinit)(void* context); + void (*deinit)(void* ctx); - // Prepare the pulses to be sent - void (*setupPulses)(void* context, int16_t* channels, uint8_t nChannels); - - // Send the pulses - void (*sendPulses)(void* context); - - // Fetch telemetry byte - int (*getByte)(void* context, uint8_t* data); + // Send the next pulse frame + void (*sendPulses)(void* ctx, uint8_t* buffer, int16_t* channels, uint8_t nChannels); // Process input data byte (telemetry) void (*processData)(void* context, uint8_t data, uint8_t* buffer, uint8_t* len); diff --git a/radio/src/hal/module_port.cpp b/radio/src/hal/module_port.cpp new file mode 100644 index 000000000..c54b67746 --- /dev/null +++ b/radio/src/hal/module_port.cpp @@ -0,0 +1,254 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "module_port.h" +#include "dataconstants.h" // MAX_MODULES +#include "myeeprom.h" // g_eeGeneral + +#include + +extern const etx_module_t* const _modules[]; +extern const uint8_t _n_modules; + +static etx_module_state_t _module_states[MAX_MODULES]; +static uint8_t _module_power; + +void modulePortInit() +{ + memset(_module_states, 0, sizeof(_module_states)); + _module_power = 0; + +#if defined(CONFIGURABLE_MODULE_PORT) + memset(&_extra_module_port, 0, sizeof(_extra_module_port)); + _extra_module_port.type = 0xFF; // some invalid type +#endif +} + +#if defined(CONFIGURABLE_MODULE_PORT) +// supplemental configurable port +static etx_module_port_t _extra_module_port; + +void modulePortConfigExtra(const etx_module_port_t* port) +{ + memcpy(&_extra_module_port, port, sizeof(_extra_module_port)); +} +#endif + +static void modulePortClear(etx_module_state_t* st) +{ + memset(st, 0, sizeof(etx_module_state_t)); +} + +static void _init_serial_driver(etx_module_driver_t* d, const etx_module_port_t* port, + const etx_serial_init* params) +{ + auto drv = port->drv.serial; + d->ctx = drv->init(port->hw_def, params); + d->port = port; + + // S.PORT specific HW settings + if (port->port == ETX_MOD_PORT_SPORT && params->baudrate >= 400000) { + + // enable over-sampling by 8 + if (drv->setHWOption) drv->setHWOption(d->ctx, ETX_HWOption_OVER8); + + // one-bit + if (g_eeGeneral.uartSampleMode == UART_SAMPLE_MODE_ONEBIT) { + if (drv->setHWOption) drv->setHWOption(d->ctx, ETX_HWOption_ONEBIT); + } + } + + // setup polarity + if (port->set_inverted) { + port->set_inverted(params->polarity == ETX_Pol_Inverted); + } +} + +static void _init_timer_driver(etx_module_driver_t* d, const etx_module_port_t* port, + const etx_timer_config_t* cfg) +{ + auto drv = port->drv.timer; + d->ctx = drv->init(port->hw_def, cfg); + d->port = port; + + // setup polarity + if (port->set_inverted) { + port->set_inverted(false); + } +} + +static const etx_module_port_t* _find_port(uint8_t module, uint8_t type, + uint8_t port, uint8_t polarity) +{ + if (module >= MAX_MODULES || module >= _n_modules || !_modules[module]) + return nullptr; + + uint8_t n_ports = _modules[module]->n_ports; + const etx_module_port_t* p = _modules[module]->ports; + const etx_module_port_t* found_port = nullptr; + + while(n_ports > 0) { + + if (p->type == type && p->port == port) { + + // skip the port if polarity does not match + // and cannot be set + if (polarity != ETX_Pol_Inverted || + p->set_inverted || + port == ETX_MOD_PORT_SOFT_INV || + port == ETX_MOD_PORT_SPORT_INV) { + + found_port = p; + break; + } + } + + ++p; --n_ports; + } + +#if defined(CONFIGURABLE_MODULE_PORT) + if (!found_port && + polarity == ETX_Pol_Normal && + module == EXTERNAL_MODULE && + _extra_module_port.type == type && + _extra_module_port.port == port) { + found_port = &_extra_module_port; + } +#endif + + return found_port; +} + +const etx_module_t* modulePortGetModuleDescription(uint8_t module) +{ + if (module >= _n_modules) return nullptr; + return _modules[module]; +} + +const etx_module_port_t* modulePortFind(uint8_t module, uint8_t type, + uint8_t port, uint8_t polarity) +{ + return _find_port(module, type, port, polarity); +} + +void modulePortSetPower(uint8_t module, uint8_t enable) +{ + if (module >= _n_modules) return; + auto mod = _modules[module]; + if (mod && mod->set_pwr) { + mod->set_pwr(enable); + if (enable) { + _module_power |= (1 << module); + } else { + _module_power &= ~(1 << module); + } + } +} + +bool modulePortPowered(uint8_t module) +{ + if (module >= _n_modules) return false; + return _module_power & (1 << module); +} + +etx_module_state_t* modulePortInitSerial(uint8_t module, uint8_t port, + const etx_serial_init* params) +{ + // TODO: match capabilities (1. USART -> 2. SOFT-SERIAL) + const etx_module_port_t* found_port = _find_port(module, ETX_MOD_TYPE_SERIAL, + port, params->polarity); + if (!found_port) return nullptr; + + auto state = &(_module_states[module]); + + const uint8_t duplex = ETX_Dir_TX_RX; + uint8_t dir = params->direction & duplex; + + if (dir == duplex) { + + // init RX first, in case TX was already done previously + _init_serial_driver(&state->rx, found_port, params); + + // do not overwrite TX state if it has already been set: + // -> support using S.PORT in bidir mode + if (!state->tx.port) { + state->tx.port = state->rx.port; + state->tx.ctx = state->rx.ctx; + } + } else if (dir == ETX_Dir_TX) { + _init_serial_driver(&state->tx, found_port, params); + } else if (dir == ETX_Dir_RX) { + _init_serial_driver(&state->rx, found_port, params); + } + + return state; +} + +etx_module_state_t* modulePortInitTimer(uint8_t module, uint8_t port, + const etx_timer_config_t* cfg) +{ + const etx_module_port_t* found_port = _find_port(module, ETX_MOD_TYPE_TIMER, + port, ETX_Pol_Normal); + if (!found_port) return nullptr; + + auto state = &(_module_states[module]); + _init_timer_driver(&state->tx, found_port, cfg); + + return state; +} + +static void _deinit_driver(etx_module_driver_t* d) +{ + auto p = d->port; + auto ctx = d->ctx; + + if (p->type == ETX_MOD_TYPE_SERIAL) { + auto drv = p->drv.serial; + drv->deinit(ctx); + } else if (p->type == ETX_MOD_TYPE_TIMER) { + auto drv = p->drv.timer; + drv->deinit(ctx); + } +} + +void modulePortDeInit(etx_module_state_t* st) +{ + if (st->tx.port != nullptr) { + _deinit_driver(&st->tx); + } + + if (st->rx.port != nullptr && st->rx.port != st->tx.port) { + _deinit_driver(&st->rx); + } + + modulePortClear(st); +} + +etx_module_state_t* modulePortGetState(uint8_t module) +{ + if (module >= MAX_MODULES) return nullptr; + return &(_module_states[module]); +} + +uint8_t modulePortGetModule(etx_module_state_t* st) +{ + return st - _module_states; +} diff --git a/radio/src/hal/module_port.h b/radio/src/hal/module_port.h new file mode 100644 index 000000000..80597179b --- /dev/null +++ b/radio/src/hal/module_port.h @@ -0,0 +1,158 @@ +/* + * Copyright (C) EdgeTx + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#pragma once + +#include +#include "serial_driver.h" +#include "timer_driver.h" +#include "definitions.h" + +// +// Module ports +// + +// flags +#define ETX_MOD_DIR_TX (1 << 0) +#define ETX_MOD_DIR_RX (1 << 1) +#define ETX_MOD_DIR_TX_RX (ETX_MOD_DIR_TX | ETX_MOD_DIR_RX) +#define ETX_MOD_FULL_DUPLEX (1 << 2) + +#define ETX_MOD_TYPE_NONE 0 +#define ETX_MOD_TYPE_TIMER (1 << 0) +#define ETX_MOD_TYPE_SERIAL (1 << 1) + +enum ModulePort : uint8_t { + ETX_MOD_PORT_UART, + ETX_MOD_PORT_TIMER, + ETX_MOD_PORT_SOFT_INV, + ETX_MOD_PORT_SPORT, + ETX_MOD_PORT_SPORT_INV, + ETX_MOD_PORT_MAX +}; + +// +// A module port is a pin (single UART RX or TX; PPM pin) +// or pin pair (UART RX/TX) +// +typedef struct { + + // enum ModulePort + uint8_t port; + + // ETX_MOD_TYPE_xx + uint8_t type; + + // flags bitfield ETX_MOD_DIR_xx + uint8_t dir_flags; + + union { + const etx_timer_driver_t *timer; + const etx_serial_driver_t *serial; + } drv; + + // this is specific to the driver above + void* hw_def; + + // inverter support: only works on the following ports + // - ETX_MOD_PORT_UART / ETX_MOD_PORT_SPORT + void (*set_inverted)(uint8_t enable); + +} etx_module_port_t; + +typedef struct { + const etx_module_port_t* const ports; + void (*set_pwr)(uint8_t on); + void (*set_bootcmd)(uint8_t on); + const uint8_t n_ports; +} etx_module_t; + +#define BEGIN_MODULES() \ + extern const etx_module_t* const _modules[]; \ + const etx_module_t* const _modules[] = { + +#define END_MODULES() }; \ + extern const uint8_t _n_modules; \ + const uint8_t _n_modules = DIM(_modules); + +typedef struct { + const etx_module_port_t* port; + void* ctx; +} etx_module_driver_t; + +typedef struct { + + etx_module_driver_t tx; + etx_module_driver_t rx; + + void* user_data; + +} etx_module_state_t; + +// Init the internal module port data +void modulePortInit(); + +#if defined(CONFIGURABLE_MODULE_PORT) +// Configure an extra port +void modulePortConfigExtra(const etx_module_port_t* port); +#endif + +const etx_module_t* modulePortGetModuleDescription(uint8_t module); + +const etx_module_port_t* modulePortFind(uint8_t module, uint8_t type, + uint8_t port, uint8_t polarity); + +void modulePortSetPower(uint8_t module, uint8_t enabled); + +bool modulePortPowered(uint8_t module); + +// Init module port with params (driver & context stored locally) +etx_module_state_t* modulePortInitSerial(uint8_t module, uint8_t port, + const etx_serial_init* params); + +// Init module port with params (driver & context stored locally) +etx_module_state_t* modulePortInitTimer(uint8_t module, uint8_t port, + const etx_timer_config_t* cfg); + +// De-init port and clear data +void modulePortDeInit(etx_module_state_t* st); + +// Once initialized, retrieve module serial driver and context +etx_module_state_t* modulePortGetState(uint8_t module); + +uint8_t modulePortGetModule(etx_module_state_t* st); + +inline uint8_t modulePortGetType(const etx_module_driver_t& d) { + return d.port->type; +} + +inline const etx_serial_driver_t* modulePortGetSerialDrv(const etx_module_driver_t& d) { + return d.port->drv.serial; +} + +inline const etx_timer_driver_t* modulePortGetTimerDrv(const etx_module_driver_t& d) { + return d.port->drv.timer; +} + +inline void* modulePortGetCtx(const etx_module_driver_t& d) { + return d.ctx; +} + diff --git a/radio/src/hal/serial_driver.h b/radio/src/hal/serial_driver.h index a27f0405c..a37df45c5 100644 --- a/radio/src/hal/serial_driver.h +++ b/radio/src/hal/serial_driver.h @@ -23,42 +23,49 @@ #include -enum SerialParity { - ETX_Parity_None, - ETX_Parity_Even, - ETX_Parity_Odd, + +enum SerialEncoding { + ETX_Encoding_8N1, + ETX_Encoding_8E2, + ETX_Encoding_PXX1_PWM, }; -enum SerialStopBits { - ETX_StopBits_One, - ETX_StopBits_OneAndHalf, - ETX_StopBits_Two, +enum SerialDirection { + ETX_Dir_None = 0, + ETX_Dir_RX = 1, + ETX_Dir_TX = 2, + ETX_Dir_TX_RX = 3, }; -enum SerialWordLength { - ETX_WordLength_8, - ETX_WordLength_9, +enum SerialPolarity { + ETX_Pol_Normal, + ETX_Pol_Inverted, }; typedef struct { uint32_t baudrate; // = 0; - uint8_t parity; // = ETX_Parity_None; - uint8_t stop_bits; // = ETX_StopBits_One; - uint8_t word_length; // = ETX_WordLength_8; - uint8_t rx_enable; // = false; - + uint8_t encoding; // = ETX_Encoding_8N1; + uint8_t direction; // = ETX_Dir_None; + uint8_t polarity; // = ETX_Pol_Normal; } etx_serial_init; +// TODO: move somewhere else struct etx_serial_callbacks_t { uint8_t (*on_send)(uint8_t* data); void (*on_receive)(uint8_t data); + void (*on_idle)(); void (*on_error)(); }; +enum SerialHWOption { + ETX_HWOption_OVER8, // oversampling by 8 + ETX_HWOption_ONEBIT, // one-bit sampling +}; + typedef struct { // Init serial communication - void* (*init)(const etx_serial_init* params); + void* (*init)(void* hw_def, const etx_serial_init* params); // De-Init serial communication void (*deinit)(void* ctx); @@ -67,22 +74,41 @@ typedef struct { void (*sendByte)(void* ctx, uint8_t byte); // Send a buffer - void (*sendBuffer)(void* ctx, const uint8_t* data, uint8_t size); + void (*sendBuffer)(void* ctx, const uint8_t* data, uint32_t size); + // Is TX phase completed + uint8_t (*txCompleted)(void* ctx); + // Wait for last send operation to complete void (*waitForTxCompleted)(void* ctx); - - // Fetch byte from internal buffer + + // 2-wire half-duplex + void (*enableRx)(void* ctx); + + // Fetch next available byte from internal buffer int (*getByte)(void* ctx, uint8_t* data); + // Fetch a byte by its index from the end of the buffer + int (*getLastByte)(void* ctx, uint32_t idx, uint8_t* data); + // Clear internal buffer void (*clearRxBuffer)(void* ctx); // Get current baudrate uint32_t (*getBaudrate)(void*); + + // Set baudrate + void (*setBaudrate)(void*, uint32_t baudrate); + + // Configure inverter + void (*setPolarity)(void*, uint8_t polarity); + + // Set a HW specific option (SerialHWOption; possibly unsupported by the driver) + void (*setHWOption)(void*, uint32_t option); // Callbacks void (*setReceiveCb)(void* ctx, void (*on_receive)(uint8_t*, uint32_t)); + void (*setIdleCb)(void* ctx, void (*on_idle)()); void (*setBaudrateCb)(void* ctx, void (*on_set_baudrate)(uint32_t)); } etx_serial_driver_t; diff --git a/radio/src/hal/serial_port.h b/radio/src/hal/serial_port.h index 8e89aeb39..4621ec486 100644 --- a/radio/src/hal/serial_port.h +++ b/radio/src/hal/serial_port.h @@ -26,5 +26,6 @@ typedef struct { const char* name; const etx_serial_driver_t* uart; + void* hw_def; void (*set_pwr)(uint8_t on); } etx_serial_port_t; diff --git a/radio/src/hal/timer_driver.h b/radio/src/hal/timer_driver.h new file mode 100644 index 000000000..2f516eeeb --- /dev/null +++ b/radio/src/hal/timer_driver.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) EdgeTx + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#pragma once + +#include + +enum PulseGenerationType { + ETX_PWM=0, + ETX_TOGGLE +}; + +typedef struct { + uint8_t type; + uint8_t polarity; + uint16_t cmp_val; +} etx_timer_config_t; + +typedef struct { + void* (*init)(void* hw_def, const etx_timer_config_t* cfg); + void (*deinit)(void* ctx); + void (*send)(void* ctx, const etx_timer_config_t* cfg, const void* pulses, uint16_t length); +} etx_timer_driver_t; diff --git a/radio/src/io/bootloader_flash.cpp b/radio/src/io/bootloader_flash.cpp index b81845e02..be45400c3 100644 --- a/radio/src/io/bootloader_flash.cpp +++ b/radio/src/io/bootloader_flash.cpp @@ -50,7 +50,7 @@ void BootloaderFirmwareUpdate::flashFirmware(const char * filename, ProgressHand uint8_t buffer[1024]; UINT count; - pausePulses(); + pulsesStop(); f_open(&file, filename, FA_READ); @@ -110,5 +110,5 @@ void BootloaderFirmwareUpdate::flashFirmware(const char * filename, ProgressHand f_close(&file); - resumePulses(); + pulsesStart(); } diff --git a/radio/src/io/frsky_firmware_update.cpp b/radio/src/io/frsky_firmware_update.cpp index b54e93e55..86a66ac4e 100644 --- a/radio/src/io/frsky_firmware_update.cpp +++ b/radio/src/io/frsky_firmware_update.cpp @@ -24,6 +24,7 @@ #include "frsky_firmware_update.h" #include "debug.h" #include "timers_driver.h" +#include "tasks/mixer_task.h" #if defined(LIBOPENUI) #include "libopenui.h" @@ -31,9 +32,7 @@ #include "libopenui/src/libopenui_file.h" #endif -#if defined(INTMODULE_USART) -#include "intmodule_serial_driver.h" -#endif +#include "hal/module_port.h" #define PRIM_REQ_POWERUP 0 #define PRIM_REQ_VERSION 1 @@ -110,97 +109,65 @@ void FrskyDeviceFirmwareUpdate::processFrame(const uint8_t * frame) } } -#if defined(PCBHORUS) bool FrskyDeviceFirmwareUpdate::readBuffer(uint8_t * buffer, uint8_t count, uint32_t timeout) { watchdogSuspend(timeout); - switch (module) { - case INTERNAL_MODULE: - { - uint32_t elapsed = 0; - uint8_t index = 0; - while (index < count && elapsed < timeout) { - if (IntmoduleSerialDriver.getByte(uart_ctx, &(buffer[index]))) { - ++index; - } - else { - RTOS_WAIT_MS(1); - if (++elapsed == timeout) - return false; - } - } - break; + uint32_t elapsed = 0; + uint8_t index = 0; + while (index < count && elapsed < timeout) { + if (uart_drv->getByte(uart_ctx, &(buffer[index]))) { + ++index; + } + else { + RTOS_WAIT_MS(1); + if (++elapsed == timeout) + return false; } - - default: - break; } return true; } -#endif - -const uint8_t * FrskyDeviceFirmwareUpdate::readFullDuplexFrame(uint32_t timeout) -{ -#if defined(INTMODULE_USART) - uint8_t len = 0; - bool bytestuff = false; - while (len < 10) { - uint32_t elapsed = 0; - uint8_t byte = 0; - while (IntmoduleSerialDriver.getByte(uart_ctx, &byte) == 0) { - RTOS_WAIT_MS(1); - if (elapsed++ >= timeout) { - return nullptr; - } - } - if (byte == 0x7D) { - bytestuff = true; - continue; - } - if (bytestuff) { - frame[len] = 0x20 ^ byte; - bytestuff = false; - } - else { - frame[len] = byte; - } - if (len > 0 || byte == 0x7E) { - ++len; - } - } - return &frame[1]; -#else - return nullptr; -#endif -} - -const uint8_t * FrskyDeviceFirmwareUpdate::readHalfDuplexFrame(uint32_t timeout) -{ - for (int i = timeout; i >= 0; i--) { - uint8_t byte ; - while (sportGetByte(&byte)) { - if (pushFrskyTelemetryData(byte)) { - return telemetryRxBuffer; - } - } - RTOS_WAIT_MS(1); - } - return nullptr; -} const uint8_t * FrskyDeviceFirmwareUpdate::readFrame(uint32_t timeout) { RTOS_WAIT_MS(1); -#if defined(INTERNAL_MODULE_PXX2) - if ((module == INTERNAL_MODULE) && - (g_eeGeneral.internalModule = MODULE_TYPE_ISRM_PXX2)) { - return readFullDuplexFrame(timeout); + uint8_t len = 0; + bool bytestuff = false; + + while (len <= FRSKY_SPORT_PACKET_SIZE) { + + uint32_t elapsed = 0; + uint8_t byte = 0; + + while (uart_drv->getByte(uart_ctx, &byte) == 0) { + RTOS_WAIT_MS(1); + if (elapsed++ >= timeout) { + TRACE("timeout in frame (len=%d)",len); + return nullptr; + } + } + + if (byte == BYTE_STUFF) { + bytestuff = true; + continue; + } + + if (bytestuff) { + frame[len] = STUFF_MASK ^ byte; + bytestuff = false; + } + else { + frame[len] = byte; + } + + if (len > 0 || byte == START_STOP) { + ++len; + } } -#endif - return readHalfDuplexFrame(timeout); + + return &frame[1]; } bool FrskyDeviceFirmwareUpdate::waitState(State newState, uint32_t timeout) @@ -238,29 +205,20 @@ void FrskyDeviceFirmwareUpdate::startFrame(uint8_t command) void FrskyDeviceFirmwareUpdate::sendFrame() { uint8_t * ptr = outputTelemetryBuffer.data; - *ptr++ = 0x7E; + *ptr++ = START_STOP; *ptr++ = 0xFF; frame[7] = crc16(CRC_1021, frame, 7); - for (int i=0; i<8; i++) { - if (frame[i] == 0x7E || frame[i] == 0x7D) { - *ptr++ = 0x7D; - *ptr++ = 0x20 ^ frame[i]; - } - else { + for (int i = 0; i < 8; i++) { + if (frame[i] == START_STOP || frame[i] == BYTE_STUFF) { + *ptr++ = BYTE_STUFF; + *ptr++ = STUFF_MASK ^ frame[i]; + } else { *ptr++ = frame[i]; } } -#if defined(INTERNAL_MODULE_PXX2) - if ((module == INTERNAL_MODULE) && - (g_eeGeneral.internalModule = MODULE_TYPE_ISRM_PXX2)) { - IntmoduleSerialDriver.sendBuffer(uart_ctx, outputTelemetryBuffer.data, - ptr - outputTelemetryBuffer.data); - return; - } -#endif - - sportSendBuffer(outputTelemetryBuffer.data, ptr - outputTelemetryBuffer.data); + uart_drv->sendBuffer(uart_ctx, outputTelemetryBuffer.data, + ptr - outputTelemetryBuffer.data); return; } @@ -269,7 +227,7 @@ const char * FrskyDeviceFirmwareUpdate::sendPowerOn() state = SPORT_POWERUP_REQ; RTOS_WAIT_MS(50); - telemetryClearFifo(); + uart_drv->clearRxBuffer(uart_ctx); for (int i=0; i<10; i++) { // max 10 attempts @@ -279,21 +237,13 @@ const char * FrskyDeviceFirmwareUpdate::sendPowerOn() return nullptr; } - if (telemetryProtocol != PROTOCOL_TELEMETRY_FRSKY_SPORT) { - return STR_DEVICE_NO_RESPONSE; - } - - if (!IS_FRSKY_SPORT_PROTOCOL()) { - return STR_DEVICE_NO_RESPONSE; - } - return STR_DEVICE_NO_RESPONSE; } const char * FrskyDeviceFirmwareUpdate::sendReqVersion() { RTOS_WAIT_MS(20); - telemetryClearFifo(); + uart_drv->clearRxBuffer(uart_ctx); state = SPORT_VERSION_REQ; for (int i=0; i<10; i++) { @@ -311,20 +261,18 @@ const char * FrskyDeviceFirmwareUpdate::sendReqVersion() // X9D / X9D+ / X9E / XLite IXJT = use S.PORT @ 57600 bauds // XLite PRO / X9Lite / X9D+ 2019 ISRM = use TX + RX @ 57600 bauds -#if defined(INTMODULE_USART) static const etx_serial_init serialInitParams = { .baudrate = 0, - .parity = ETX_Parity_None, - .stop_bits = ETX_StopBits_One, - .word_length = ETX_WordLength_8, - .rx_enable = true, + .encoding = ETX_Encoding_8N1, + .direction = ETX_Dir_TX_RX, + .polarity = ETX_Pol_Normal, }; -#endif -const char * FrskyDeviceFirmwareUpdate::doFlashFirmware(const char * filename, ProgressHandler progressHandler) +const char *FrskyDeviceFirmwareUpdate::doFlashFirmware( + const char *filename, ProgressHandler progressHandler) { FIL file; - const char * result; + const char *result; FrSkyFirmwareInformation information; UINT count; @@ -332,64 +280,99 @@ const char * FrskyDeviceFirmwareUpdate::doFlashFirmware(const char * filename, P return STR_NEEDS_FILE; } - const char * ext = getFileExtension(filename); + // Start with checking if we have a firmware description: + // this mainly covers "newer" modules (ISRM, ACCESS based) + + // default to S.PORT update... + uint8_t port = ETX_MOD_PORT_SPORT; + void (*set_pwr)(uint8_t) = nullptr; + void (*set_bootcmd)(uint8_t) = nullptr; + + // TODO: what about S.PORT update power control? (RX?) + auto mod_desc = modulePortGetModuleDescription(module); + set_pwr = mod_desc->set_pwr; + + // ... and 57600 bps + etx_serial_init cfg(serialInitParams); + cfg.baudrate = 57600; + + const char *ext = getFileExtension(filename); if (ext && !strcasecmp(ext, FRSKY_FIRMWARE_EXT)) { - auto ret = f_read(&file, &information, sizeof(FrSkyFirmwareInformation), &count); + auto ret = + f_read(&file, &information, sizeof(FrSkyFirmwareInformation), &count); if (ret != FR_OK || count != sizeof(FrSkyFirmwareInformation)) { f_close(&file); return STR_DEVICE_FILE_ERROR; + } + + // probably some ISRM or ACCESS module... + // TODO: what are we supposed to start with the firmware header file? + if ((information.productFamily == FIRMWARE_FAMILY_INTERNAL_MODULE && + module != INTERNAL_MODULE) || + (information.productFamily == FIRMWARE_FAMILY_EXTERNAL_MODULE && + module != EXTERNAL_MODULE)) { + + return STR_DEVICE_FILE_WRONG_SIG; + } + + if (information.productFamily == FIRMWARE_FAMILY_INTERNAL_MODULE && + information.productId == FIRMWARE_ID_MODULE_ISRM) { + port = ETX_MOD_PORT_UART; + } + + } else if (module == INTERNAL_MODULE) { + // For the older modules we need some guess work: + // + // - X12S / X10 IXJT = use TX + RX @ 38400 bauds with BOOTCMD pin + // -> internal USART + boot pin + // + // - X9D / X9D+ / X9E / XLite IXJT = use S.PORT @ 57600 bauds + // -> no internal USART OR no boot pin (XLite has an internal USART) + + // X12S / X10 iXJT: TX + RX @ 38400 bauds with BOOTCMD pin inverted + if (mod_desc->set_bootcmd) { + cfg.baudrate = 38400; + port = ETX_MOD_PORT_UART; + set_bootcmd = mod_desc->set_bootcmd; + } else { + // keep the above defaults (S.PORT @ 57600 bps) } - } else { -#if defined(PCBHORUS) - information.productId = FIRMWARE_ID_MODULE_XJT; -#endif } -#if defined(PCBHORUS) - if (module == INTERNAL_MODULE && information.productId == FIRMWARE_ID_MODULE_XJT) { - INTERNAL_MODULE_ON(); - RTOS_WAIT_MS(1); + // SPORT_MODULE is only defined for power control + // but has not ports declared on it. + // + uint8_t serial_module = module != SPORT_MODULE ? module : EXTERNAL_MODULE; - etx_serial_init params(serialInitParams); - params.baudrate = 38400; - uart_ctx = IntmoduleSerialDriver.init(¶ms); + mod_st = modulePortInitSerial(serial_module, port, &cfg); + if (!mod_st) return "Communication port error"; - GPIO_SetBits(INTMODULE_BOOTCMD_GPIO, INTMODULE_BOOTCMD_GPIO_PIN); + // assume RX port is the same as TX + uart_drv = modulePortGetSerialDrv(mod_st->tx); + uart_ctx = modulePortGetCtx(mod_st->tx); + + if (set_bootcmd) set_bootcmd(true); + if (set_pwr) set_pwr(true); + + // wait a bit for PWR to settle + RTOS_WAIT_MS(1); + + // Special update method for X12S / X10 iXJT + if (module == INTERNAL_MODULE && port == ETX_MOD_PORT_UART && set_bootcmd != nullptr) { result = uploadFileToHorusXJT(filename, &file, progressHandler); - GPIO_ResetBits(INTMODULE_BOOTCMD_GPIO, INTMODULE_BOOTCMD_GPIO_PIN); - - f_close(&file); - return result; - } -#endif - -#if defined(INTERNAL_MODULE_PXX2) - if ((module == INTERNAL_MODULE) && - (g_eeGeneral.internalModule = MODULE_TYPE_ISRM_PXX2)) { - etx_serial_init params(serialInitParams); - params.baudrate = 57600; - uart_ctx = IntmoduleSerialDriver.init(¶ms); - } - else -#endif - { - telemetryInit(PROTOCOL_TELEMETRY_FRSKY_SPORT); + } else { + result = uploadFileNormal(filename, &file, progressHandler); } - if (module == INTERNAL_MODULE) - INTERNAL_MODULE_ON(); - else if (module == EXTERNAL_MODULE) - EXTERNAL_MODULE_ON(); - else - SPORT_UPDATE_POWER_ON(); + if (set_pwr) set_pwr(false); + if (set_bootcmd) set_bootcmd(false); - result = uploadFileNormal(filename, &file, progressHandler); - f_close(&file); + modulePortDeInit(mod_st); return result; } -#if defined(PCBHORUS) -const char * FrskyDeviceFirmwareUpdate::uploadFileToHorusXJT(const char * filename, FIL * file, ProgressHandler progressHandler) +const char *FrskyDeviceFirmwareUpdate::uploadFileToHorusXJT( + const char *filename, FIL *file, ProgressHandler progressHandler) { uint32_t buffer[1024 / sizeof(uint32_t)]; UINT count; @@ -399,14 +382,14 @@ const char * FrskyDeviceFirmwareUpdate::uploadFileToHorusXJT(const char * filena return STR_DEVICE_NO_RESPONSE; } - IntmoduleSerialDriver.sendByte(uart_ctx, 0x81); + uart_drv->sendByte(uart_ctx, 0x81); readBuffer(frame, 1, 100); if (!readBuffer(frame, 8, 100) || frame[0] != 0x02) { return STR_DEVICE_NO_RESPONSE; } - IntmoduleSerialDriver.sendByte(uart_ctx, 0x82); + uart_drv->sendByte(uart_ctx, 0x82); readBuffer(frame, 1, 100); uint8_t index = 0; @@ -424,7 +407,7 @@ const char * FrskyDeviceFirmwareUpdate::uploadFileToHorusXJT(const char * filena return STR_DEVICE_WRONG_REQUEST; if (count == 0) { - IntmoduleSerialDriver.sendByte(uart_ctx, 0xA1); + uart_drv->sendByte(uart_ctx, 0xA1); RTOS_WAIT_MS(50); return nullptr; } @@ -432,22 +415,32 @@ const char * FrskyDeviceFirmwareUpdate::uploadFileToHorusXJT(const char * filena if (count < 1024) memset(((uint8_t *)buffer) + count, 0, 1024 - count); - IntmoduleSerialDriver.sendByte(uart_ctx, frame[0] + 0x80); - IntmoduleSerialDriver.sendByte(uart_ctx, frame[1]); + uart_drv->sendByte(uart_ctx, frame[0] + 0x80); + uart_drv->sendByte(uart_ctx, frame[1]); uint16_t crc_16 = crc16(CRC_1189, (uint8_t *)buffer, 1024, crc16(CRC_1189, &frame[1], 1)); for (size_t i = 0; i < sizeof(buffer); i++) { - IntmoduleSerialDriver.sendByte(uart_ctx, ((uint8_t *)buffer)[i]); + uart_drv->sendByte(uart_ctx, ((uint8_t *)buffer)[i]); } - IntmoduleSerialDriver.sendByte(uart_ctx, crc_16 >> 8); - IntmoduleSerialDriver.sendByte(uart_ctx, crc_16); + uart_drv->sendByte(uart_ctx, crc_16 >> 8); + uart_drv->sendByte(uart_ctx, crc_16); index++; } } -#endif -const char * FrskyDeviceFirmwareUpdate::uploadFileNormal(const char * filename, FIL * file, ProgressHandler progressHandler) +void FrskyDeviceFirmwareUpdate::sendDataTransfer(uint32_t* buffer) +{ + startFrame(PRIM_DATA_WORD); + uint32_t offset = (address & 1023) >> 2; // 32 bit word offset into buffer + *((uint32_t *)(frame + 2)) = buffer[offset]; + frame[6] = address & 0x000000FF; + state = SPORT_DATA_TRANSFER; + sendFrame(); +} + +const char *FrskyDeviceFirmwareUpdate::uploadFileNormal( + const char *filename, FIL *file, ProgressHandler progressHandler) { uint32_t buffer[1024 / sizeof(uint32_t)]; UINT count; @@ -461,12 +454,14 @@ const char * FrskyDeviceFirmwareUpdate::uploadFileNormal(const char * filename, return result; RTOS_WAIT_MS(200); - telemetryClearFifo(); + uart_drv->clearRxBuffer(uart_ctx); state = SPORT_DATA_TRANSFER; startFrame(PRIM_CMD_DOWNLOAD); sendFrame(); + uint8_t retries = 0; + while (true) { if (f_read(file, buffer, 1024, &count) != FR_OK) { return STR_DEVICE_FILE_ERROR; @@ -474,16 +469,19 @@ const char * FrskyDeviceFirmwareUpdate::uploadFileNormal(const char * filename, count >>= 2; - for (uint32_t i=0; i 0){ + --retries; + TRACE("retrying last transfer (address=0x%04X)", address); + } else { return STR_DEVICE_DATA_REFUSED; } - startFrame(PRIM_DATA_WORD); - uint32_t offset = (address & 1023) >> 2; // 32 bit word offset into buffer - *((uint32_t *)(frame + 2)) = buffer[offset]; - frame[6] = address & 0x000000FF; - state = SPORT_DATA_TRANSFER, - sendFrame(); + + sendDataTransfer(buffer); + if (i == 0) { progressHandler(getBasename(filename), STR_WRITING, file->fptr, file->obj.objsize); } @@ -509,23 +507,13 @@ const char * FrskyDeviceFirmwareUpdate::endTransfer() return nullptr; } -const char * FrskyDeviceFirmwareUpdate::flashFirmware(const char * filename, ProgressHandler progressHandler) +const char *FrskyDeviceFirmwareUpdate::flashFirmware( + const char *filename, ProgressHandler progressHandler) { - pauseMixerCalculations(); - pausePulses(); + pulsesStop(); -#if defined(HARDWARE_INTERNAL_MODULE) - stopPulsesInternalModule(); -#endif - -#if defined(HARDWARE_EXTERNAL_MODULE) - stopPulsesExternalModule(); -#endif - -#if defined(SPORT_UPDATE_PWR_GPIO) - uint8_t spuPwr = IS_SPORT_UPDATE_POWER_ON(); - SPORT_UPDATE_POWER_OFF(); -#endif + // switch S.PORT power OFF if supported + modulePortSetPower(SPORT_MODULE, false); progressHandler(getBasename(filename), STR_DEVICE_RESET, 0, 0); @@ -544,305 +532,18 @@ const char * FrskyDeviceFirmwareUpdate::flashFirmware(const char * filename, Pro POPUP_INFORMATION(STR_FIRMWARE_UPDATE_SUCCESS); } -#if defined(INTMODULE_USART) - if (uart_ctx) { - // If the UART is not deactivated, the module - // will not properly reset - IntmoduleSerialDriver.deinit(uart_ctx); - } -#endif - -#if defined(HARDWARE_INTERNAL_MODULE) - INTERNAL_MODULE_OFF(); -#endif - EXTERNAL_MODULE_OFF(); - SPORT_UPDATE_POWER_OFF(); + watchdogSuspend(50 /*500ms*/); + pulsesStart(); - /* wait 2s off */ - watchdogSuspend(500 /*5s*/); - RTOS_WAIT_MS(2000); - telemetryClearFifo(); - - resumePulses(); - resumeMixerCalculations(); - -#if defined(SPORT_UPDATE_PWR_GPIO) - if (spuPwr) { - SPORT_UPDATE_POWER_ON(); - } -#endif +// TODO: S.PORT power control +// -> where is it actually turned ON normally? +// +// #if defined(SPORT_UPDATE_PWR_GPIO) +// if (spuPwr) { +// SPORT_UPDATE_POWER_ON(); +// } +// #endif state = SPORT_IDLE; return result; } - -#define CHIP_FIRMWARE_UPDATE_TIMEOUT 20000 /* 20s */ - -const char * FrskyChipFirmwareUpdate::waitAnswer(uint8_t & status) -{ - watchdogSuspend(CHIP_FIRMWARE_UPDATE_TIMEOUT); - - telemetryPortSetDirectionInput(); - - uint8_t buffer[12]; - for (uint8_t i = 0; i < sizeof(buffer); i++) { - uint32_t retry = 0; - while (true) { - if (sportGetByte(&buffer[i])) { - if ((i == 0 && buffer[0] != 0x7F) || - (i == 1 && buffer[1] != 0xFE) || - (i == 10 && buffer[10] != 0x0D) || - (i == 11 && buffer[11] != 0x0A)) { - i = 0; - continue; - } - break; - } - if (++retry == CHIP_FIRMWARE_UPDATE_TIMEOUT) { - return STR_DEVICE_NO_RESPONSE; - } - RTOS_WAIT_MS(1); - } - } - status = buffer[8]; - return nullptr; -} - -const char * FrskyChipFirmwareUpdate::startBootloader() -{ - sportSendByte(0x03); - RTOS_WAIT_MS(20); - sportSendByte(0x02); - RTOS_WAIT_MS(20); - sportSendByte(0x01); - - for (uint8_t i = 0; i < 30; i++) - sportSendByte(0x7E); - - for (uint32_t i = 0; i < 100; i++) { - RTOS_WAIT_MS(20); - sportSendByte(0x7F); - } - - RTOS_WAIT_MS(20); - sportSendByte(0xFA); - - /*for (uint8_t i=0; i < 30; i++) - sportSendByte(0x7E); - for (uint8_t i=0; i < 50; i++) - sportSendByte(0x7F);*/ - - uint8_t status; - const char * result = waitAnswer(status); - if (result) - return result; - - return status == 0x08 ? nullptr : "Bootloader failed"; -} - -void FrskyChipFirmwareUpdate::sendByte(uint8_t byte, bool crcFlag) -{ - sportSendByte(byte); - if (crcFlag) { - crc ^= byte; - } -} - -const char * FrskyChipFirmwareUpdate::sendUpgradeCommand(char command, uint32_t packetsCount) -{ - crc = 0; - - // Head - sendByte(0x7F, false); - sendByte(0xFE, false); - - // Addr - sendByte(0xFA); - - // Cmd - sendByte(command); - - // Packets count - sendByte(packetsCount >> 8); - sendByte(packetsCount); - - // Len - sendByte('E' == command ? 0x00 : 0x0C); - sendByte(0x40); - - // Data - for (uint8_t i=0; i < 0x40; i++) - sendByte('E' == command ? 0xF7 : 0x7F); - - // Checksum - sendByte(crc, false); - - // Tail - sendByte(0x0D, false); - sendByte(0x0A, false); - - uint8_t status; - const char * result = waitAnswer(status); - if (result) - return result; - - return status == 0x00 ? nullptr : STR_FIRMWARE_UPDATE_ERROR; -} - -const char * FrskyChipFirmwareUpdate::sendUpgradeData(uint32_t index, uint8_t * data) -{ - crc = 0; - - // Head - sendByte(0x7F, false); - sendByte(0xFE, false); - - // Addr - sendByte(0xFA); - - // Cmd - sendByte('W'); - - // Packets count - sendByte(index >> 8); - sendByte(index); - - // Len - sendByte(0x00); - sendByte(0x40); - - // Data - for (uint8_t i = 0; i < 0x40; i++) - sendByte(*data++); - - // Checksum - sendByte(crc, false); - - // Tail - sendByte(0x0D, false); - sendByte(0x0A, false); - - uint8_t status; - const char * result = waitAnswer(status); - if (result) - return result; - - return status == 0x00 ? nullptr : STR_FIRMWARE_UPDATE_ERROR; -} - -const char * FrskyChipFirmwareUpdate::doFlashFirmware(const char * filename, ProgressHandler progressHandler) -{ - const char * result; - FIL file; - uint8_t buffer[64]; - UINT count; - - result = startBootloader(); - if (result) - return result; - - if (f_open(&file, filename, FA_READ) != FR_OK) { - return STR_NEEDS_FILE; - } - - FrSkyFirmwareInformation * information = (FrSkyFirmwareInformation *)buffer; - if (f_read(&file, buffer, sizeof(FrSkyFirmwareInformation), &count) != FR_OK || count != sizeof(FrSkyFirmwareInformation)) { - f_close(&file); - return STR_DEVICE_FILE_ERROR; - } - - uint32_t packetsCount = (information->size + sizeof(buffer) - 1) / sizeof(buffer); - progressHandler(getBasename(filename), STR_FLASH_WRITE, 0, packetsCount); - - result = sendUpgradeCommand('A', packetsCount); - if (result) - return result; - - uint32_t index = 0; - while (1) { - progressHandler(getBasename(filename), STR_FLASH_WRITE, index, packetsCount); - if (f_read(&file, buffer, sizeof(buffer), &count) != FR_OK) { - f_close(&file); - return STR_DEVICE_FILE_ERROR; - } - result = sendUpgradeData(index + 1, buffer); - if (result) - return result; - if (++index == packetsCount) - break; - } - - f_close(&file); - - return sendUpgradeCommand('E', packetsCount); -} - -const char * FrskyChipFirmwareUpdate::flashFirmware(const char * filename, ProgressHandler progressHandler, bool wait) -{ - progressHandler(getBasename(filename), STR_DEVICE_RESET, 0, 0); - - pausePulses(); - -#if defined(HARDWARE_INTERNAL_MODULE) - uint8_t intPwr = IS_INTERNAL_MODULE_ON(); - INTERNAL_MODULE_OFF(); -#endif - -#if defined(HARDWARE_EXTERNAL_MODULE) - uint8_t extPwr = IS_EXTERNAL_MODULE_ON(); - EXTERNAL_MODULE_OFF(); -#endif - -#if defined(SPORT_UPDATE_PWR_GPIO) - uint8_t spuPwr = IS_SPORT_UPDATE_POWER_ON(); - SPORT_UPDATE_POWER_OFF(); -#endif - - if (wait) { - /* wait 2s off */ - watchdogSuspend(1000 /*10s*/); - RTOS_WAIT_MS(2000); - } - - telemetryInit(PROTOCOL_TELEMETRY_FRSKY_SPORT); - - const char * result = doFlashFirmware(filename, progressHandler); - - AUDIO_PLAY(AU_SPECIAL_SOUND_BEEP1); - BACKLIGHT_ENABLE(); - - if (result) { - POPUP_WARNING(STR_FIRMWARE_UPDATE_ERROR, result); - } - else { - POPUP_INFORMATION(STR_FIRMWARE_UPDATE_SUCCESS); - } - - /* wait 2s off */ - watchdogSuspend(1000 /*10s*/); - RTOS_WAIT_MS(2000); - -#if defined(HARDWARE_INTERNAL_MODULE) - if (intPwr) { - INTERNAL_MODULE_ON(); - setupPulsesInternalModule(); - } -#endif - -#if defined(HARDWARE_EXTERNAL_MODULE) - if (extPwr) { - EXTERNAL_MODULE_ON(); - setupPulsesExternalModule(); - } -#endif - -#if defined(SPORT_UPDATE_PWR_GPIO) - if (spuPwr) { - SPORT_UPDATE_POWER_ON(); - } -#endif - - resumePulses(); - - return result; -} diff --git a/radio/src/io/frsky_firmware_update.h b/radio/src/io/frsky_firmware_update.h index 288811303..754e5fdbf 100644 --- a/radio/src/io/frsky_firmware_update.h +++ b/radio/src/io/frsky_firmware_update.h @@ -25,6 +25,8 @@ #include "dataconstants.h" #include "definitions.h" +#include "hal/module_port.h" + enum FrskyFirmwareProductFamily { FIRMWARE_FAMILY_INTERNAL_MODULE, FIRMWARE_FAMILY_EXTERNAL_MODULE, @@ -133,6 +135,9 @@ class FrskyDeviceFirmwareUpdate { uint32_t address = 0; ModuleIndex module; uint8_t frame[12]; + + etx_module_state_t* mod_st = nullptr; + const etx_serial_driver_t* uart_drv = nullptr; void* uart_ctx = nullptr; void startFrame(uint8_t command); @@ -144,6 +149,7 @@ class FrskyDeviceFirmwareUpdate { const uint8_t * readFrame(uint32_t timeout); bool waitState(State state, uint32_t timeout); void processFrame(const uint8_t * frame); + void sendDataTransfer(uint32_t* buffer); const char * doFlashFirmware(const char * filename, ProgressHandler progressHandler); const char * sendPowerOn(); @@ -153,24 +159,4 @@ class FrskyDeviceFirmwareUpdate { const char * endTransfer(); }; -class FrskyChipFirmwareUpdate { - public: - FrskyChipFirmwareUpdate() - { - } - - const char * flashFirmware(const char * filename, ProgressHandler progressHandler, bool wait = true); - - protected: - uint8_t crc; - - void sendByte(uint8_t byte, bool crc = true); - const char * waitAnswer(uint8_t & status); - const char * startBootloader(); - const char * sendUpgradeCommand(char command, uint32_t packetsCount); - const char * sendUpgradeData(uint32_t index, uint8_t * data); - - const char * doFlashFirmware(const char * filename, ProgressHandler progressHandler); -}; - #endif // _FRSKY_FIRMWARE_UPDATE_H_ diff --git a/radio/src/io/multi_firmware_update.cpp b/radio/src/io/multi_firmware_update.cpp index 312b5f01b..945fbed4e 100644 --- a/radio/src/io/multi_firmware_update.cpp +++ b/radio/src/io/multi_firmware_update.cpp @@ -21,6 +21,9 @@ #if !defined(DISABLE_MULTI_UPDATE) +#include "hal.h" +#include "hal/module_port.h" + #include #include "opentx.h" #include "multi_firmware_update.h" @@ -40,181 +43,121 @@ #include "io/multi_protolist.h" #endif -#if defined(INTMODULE_USART) -#include "intmodule_serial_driver.h" -#endif - -#include "extmodule_driver.h" - #define UPDATE_MULTI_EXT_BIN ".bin" class MultiFirmwareUpdateDriver { - public: - MultiFirmwareUpdateDriver() {} - virtual ~MultiFirmwareUpdateDriver() {} - const char* flashFirmware(FIL* file, const char* label, - ProgressHandler progressHandler); + ModuleIndex module; + MultiModuleType type; - protected: - virtual void moduleOn() const = 0; - virtual void init(bool inverted) = 0; - virtual bool getByte(uint8_t & byte) const = 0; - virtual void sendByte(uint8_t byte) const = 0; - virtual void clear() const = 0; - virtual void deinit(bool inverted) {} + etx_module_state_t* mod_st = nullptr; - private: - bool getRxByte(uint8_t & byte) const; - bool checkRxByte(uint8_t byte) const; - const char * waitForInitialSync(bool& inverted); - const char * getDeviceSignature(uint8_t * signature) const; - const char * loadAddress(uint32_t offset) const; - const char * progPage(uint8_t * buffer, uint16_t size) const; - void leaveProgMode(bool inverted); + bool init(); + bool getByte(uint8_t& byte) const; + void sendByte(uint8_t byte) const; + void sendBuffer(uint8_t* buffer, uint16_t size) const; + void clear() const; + void deinit(); + + bool getRxByte(uint8_t& byte) const; + bool checkRxByte(uint8_t byte) const; + const char* waitForInitialSync(); + const char* getDeviceSignature(uint8_t* signature) const; + const char* loadAddress(uint32_t offset) const; + const char* progPage(uint8_t* buffer, uint16_t size) const; + void leaveProgMode(); + + public: + MultiFirmwareUpdateDriver(ModuleIndex module, MultiModuleType type) : + module(module), type(type) + { + } + + const char* flashFirmware(FIL* file, const char* label, + ProgressHandler progressHandler); }; -#if defined(INTERNAL_MODULE_MULTI) - static const etx_serial_init serialInitParams = { - .baudrate = 0, - .parity = ETX_Parity_None, - .stop_bits = ETX_StopBits_One, - .word_length = ETX_WordLength_8, - .rx_enable = true, + .baudrate = 57600, + .encoding = ETX_Encoding_8N1, + .direction = ETX_Dir_TX_RX, + .polarity = ETX_Pol_Normal, }; -class MultiInternalUpdateDriver: public MultiFirmwareUpdateDriver +bool MultiFirmwareUpdateDriver::init() { - public: - MultiInternalUpdateDriver() {} - - protected: - void* uart_ctx = nullptr; - - void moduleOn() const override - { - INTERNAL_MODULE_ON(); + if (type == MULTI_TYPE_MULTIMODULE && module == INTERNAL_MODULE) { + // duplex internal USART + mod_st = modulePortInitSerial(INTERNAL_MODULE, ETX_MOD_PORT_UART, &serialInitParams); + } else if (type == MULTI_TYPE_MULTIMODULE && module == EXTERNAL_MODULE) { + // TX on PPM (inverted softserial) + etx_serial_init params(serialInitParams); + params.direction = ETX_Dir_TX; + params.polarity = ETX_Pol_Inverted; + mod_st = modulePortInitSerial(EXTERNAL_MODULE, ETX_MOD_PORT_UART, ¶ms); + if (!mod_st) { + params.polarity = ETX_Pol_Normal; + mod_st = modulePortInitSerial(EXTERNAL_MODULE, ETX_MOD_PORT_SOFT_INV, ¶ms); + if (!mod_st) return false; } - - void init(bool inverted) override - { - etx_serial_init params(serialInitParams); - params.baudrate = 57600; - uart_ctx = IntmoduleSerialDriver.init(¶ms); + // RX on S.PORT (inverted softserial) + params.direction = ETX_Dir_RX; + params.polarity = ETX_Pol_Inverted; + if (!modulePortInitSerial(EXTERNAL_MODULE, ETX_MOD_PORT_SPORT, ¶ms)) { + params.polarity = ETX_Pol_Normal; + if (!modulePortInitSerial(EXTERNAL_MODULE, ETX_MOD_PORT_SPORT_INV, ¶ms)) { + modulePortDeInit(mod_st); + return false; + } } + } else if (type == MULTI_TYPE_ELRS && module == EXTERNAL_MODULE) { + // half-duplex on S.PORT USART + mod_st = modulePortInitSerial(EXTERNAL_MODULE, ETX_MOD_PORT_SPORT, &serialInitParams); + } - bool getByte(uint8_t & byte) const override - { - return IntmoduleSerialDriver.getByte(uart_ctx, &byte) > 0; - } + if (!mod_st) return false; - void sendByte(uint8_t byte) const override - { - IntmoduleSerialDriver.sendByte(uart_ctx, byte); - } + modulePortSetPower(module, true); + return true; +} - void clear() const override - { - IntmoduleSerialDriver.clearRxBuffer(uart_ctx); - } - - void deinit(bool inverted) override - { - IntmoduleSerialDriver.deinit(uart_ctx); - clear(); - uart_ctx = nullptr; - } -}; -#endif - -#if defined(HARDWARE_EXTERNAL_MODULE) -class MultiExternalUpdateDriver: public MultiFirmwareUpdateDriver +bool MultiFirmwareUpdateDriver::getByte(uint8_t & byte) const { - public: - MultiExternalUpdateDriver() {} + auto drv = modulePortGetSerialDrv(mod_st->rx); + auto ctx = modulePortGetCtx(mod_st->rx); + return drv->getByte(ctx, &byte) > 0; +} - protected: - void moduleOn() const override - { - EXTERNAL_MODULE_ON(); - } - - void init(bool inverted) override - { - extmoduleInitTxPin(); - - if (inverted) - telemetryPortInvertedInit(57600); - else - telemetryPortInit(57600, TELEMETRY_SERIAL_WITHOUT_DMA); - } - - bool getByte(uint8_t & byte) const override - { - return sportGetByte(&byte); - } - - void sendByte(uint8_t byte) const override - { - extmoduleSendInvertedByte(byte); - } - - void clear() const override - { - telemetryClearFifo(); - } - - void deinit(bool inverted) override - { - if (inverted) - telemetryPortInvertedInit(0); - else - telemetryPortInit(0, 0); - - clear(); - } -}; -#endif - -class MultiExtSportUpdateDriver: public MultiFirmwareUpdateDriver +void MultiFirmwareUpdateDriver::sendByte(uint8_t byte) const { - public: - MultiExtSportUpdateDriver(): MultiFirmwareUpdateDriver() {} + auto drv = modulePortGetSerialDrv(mod_st->tx); + auto ctx = modulePortGetCtx(mod_st->tx); + drv->sendByte(ctx, byte); +} - protected: - void moduleOn() const override - { - EXTERNAL_MODULE_ON(); - } +void MultiFirmwareUpdateDriver::sendBuffer(uint8_t* buffer, uint16_t size) const +{ + auto drv = modulePortGetSerialDrv(mod_st->tx); + auto ctx = modulePortGetCtx(mod_st->tx); - void init(bool inverted) override - { - telemetryPortInit(57600, TELEMETRY_SERIAL_WITHOUT_DMA); - } + drv->waitForTxCompleted(ctx); + drv->sendBuffer(ctx, buffer, size); + drv->waitForTxCompleted(ctx); +} - bool getByte(uint8_t & byte) const override - { - return sportGetByte(&byte); - } +void MultiFirmwareUpdateDriver::clear() const +{ + auto drv = modulePortGetSerialDrv(mod_st->rx); + auto ctx = modulePortGetCtx(mod_st->rx); + drv->clearRxBuffer(ctx); +} - void sendByte(uint8_t byte) const override - { - sportSendByte(byte); - telemetryPortSetDirectionInput(); - } - - void clear() const override - { - telemetryClearFifo(); - } - - void deinit(bool inverted) override - { - telemetryPortInit(0, 0); - clear(); - } -}; +void MultiFirmwareUpdateDriver::deinit() +{ + clear(); + modulePortSetPower(module, false); + modulePortDeInit(mod_st); +} bool MultiFirmwareUpdateDriver::getRxByte(uint8_t & byte) const { @@ -241,7 +184,7 @@ bool MultiFirmwareUpdateDriver::checkRxByte(uint8_t byte) const return getRxByte(rxchar) ? rxchar == byte : false; } -const char * MultiFirmwareUpdateDriver::waitForInitialSync(bool & inverted) +const char * MultiFirmwareUpdateDriver::waitForInitialSync() { uint8_t byte; int retries = 200; @@ -253,13 +196,6 @@ const char * MultiFirmwareUpdateDriver::waitForInitialSync(bool & inverted) clear(); do { - // Invert at half-time - if (retries == 100) { - deinit(inverted); - inverted = !inverted; - init(inverted); - } - // Send sync request sendByte(STK_GET_SYNC); sendByte(CRC_EOP); @@ -300,7 +236,6 @@ const char * MultiFirmwareUpdateDriver::getDeviceSignature(uint8_t * signature) // Read signature sendByte(STK_READ_SIGN); sendByte(CRC_EOP); - clear(); if (!checkRxByte(STK_INSYNC)) return STR_DEVICE_NO_RESPONSE; @@ -343,9 +278,7 @@ const char * MultiFirmwareUpdateDriver::progPage(uint8_t * buffer, uint16_t size // flash/eeprom flag sendByte(0); - for (uint16_t i = 0; i < size; i++) { - sendByte(buffer[i]); - } + sendBuffer(buffer, size); sendByte(CRC_EOP); @@ -365,14 +298,14 @@ const char * MultiFirmwareUpdateDriver::progPage(uint8_t * buffer, uint16_t size return nullptr; } -void MultiFirmwareUpdateDriver::leaveProgMode(bool inverted) +void MultiFirmwareUpdateDriver::leaveProgMode() { sendByte(STK_LEAVE_PROGMODE); sendByte(CRC_EOP); // eat last sync byte checkRxByte(STK_INSYNC); - deinit(inverted); + deinit(); } const char* MultiFirmwareUpdateDriver::flashFirmware( @@ -388,25 +321,22 @@ const char* MultiFirmwareUpdateDriver::flashFirmware( #endif const char * result = nullptr; - moduleOn(); - - bool inverted = true; //false; // true - init(inverted); + if (!init()) return "Initialisation error"; /* wait 500ms for power on */ watchdogSuspend(500 /*5s*/); RTOS_WAIT_MS(500); - result = waitForInitialSync(inverted); + result = waitForInitialSync(); if (result) { - leaveProgMode(inverted); + leaveProgMode(); return result; } unsigned char signature[4]; // 3 bytes signature + STK_OK result = getDeviceSignature(signature); if (result) { - leaveProgMode(inverted); + leaveProgMode(); return result; } @@ -415,7 +345,7 @@ const char* MultiFirmwareUpdateDriver::flashFirmware( uint32_t writeOffset = 0; if (signature[0] != 0x1E) { - leaveProgMode(inverted); + leaveProgMode(); return STR_DEVICE_FILE_WRONG_SIG; } @@ -456,7 +386,7 @@ const char* MultiFirmwareUpdateDriver::flashFirmware( progressHandler(label, STR_WRITING, file->fptr, file->obj.objsize); } - leaveProgMode(inverted); + leaveProgMode(); return result; } @@ -591,6 +521,7 @@ bool MultiDeviceFirmwareUpdate::flashFirmware(const char * filename, ProgressHan } f_lseek(&file, 0); +#if defined(HARDWARE_EXTERNAL_MODULE) if (module == EXTERNAL_MODULE) { if (!firmwareFile.isMultiExternalFirmware()) { f_close(&file); @@ -598,43 +529,29 @@ bool MultiDeviceFirmwareUpdate::flashFirmware(const char * filename, ProgressHan return false; } } - else { +#endif + +#if defined(HARDWARE_INTERNAL_MODULE) + if (module == INTERNAL_MODULE) { if (!firmwareFile.isMultiInternalFirmware()) { f_close(&file); POPUP_WARNING(STR_NEEDS_FILE, STR_INT_MULTI_SPEC); return false; } } +#endif } - std::unique_ptr driver; -#if defined(INTERNAL_MODULE_MULTI) - if (type == MULTI_TYPE_MULTIMODULE && module == INTERNAL_MODULE) - driver.reset(new MultiInternalUpdateDriver()); -#endif -#if defined(HARDWARE_EXTERNAL_MODULE) - if (type == MULTI_TYPE_MULTIMODULE && module == EXTERNAL_MODULE) - driver.reset(new MultiExternalUpdateDriver()); - if (type == MULTI_TYPE_ELRS && module == EXTERNAL_MODULE) - driver.reset(new MultiExtSportUpdateDriver()); + pulsesStop(); + +#if defined(MULTI_PROTOLIST) + for (uint8_t i = 0; i < MAX_MODULES; i++) { + MultiRfProtocols::removeInstance(i); + } #endif - pausePulses(); - -#if defined(HARDWARE_INTERNAL_MODULE) - uint8_t intPwr = IS_INTERNAL_MODULE_ON(); - INTERNAL_MODULE_OFF(); -#endif - -#if defined(HARDWARE_EXTERNAL_MODULE) - uint8_t extPwr = IS_EXTERNAL_MODULE_ON(); - EXTERNAL_MODULE_OFF(); -#endif - -#if defined(SPORT_UPDATE_PWR_GPIO) - uint8_t spuPwr = IS_SPORT_UPDATE_POWER_ON(); - SPORT_UPDATE_POWER_OFF(); -#endif + // switch S.PORT power OFF if supported + modulePortSetPower(SPORT_MODULE, false); progressHandler(getBasename(filename), STR_DEVICE_RESET, 0, 0); @@ -642,22 +559,13 @@ bool MultiDeviceFirmwareUpdate::flashFirmware(const char * filename, ProgressHan watchdogSuspend(500 /*5s*/); RTOS_WAIT_MS(3000); - const char * result = driver->flashFirmware(&file, getBasename(filename), progressHandler); + MultiFirmwareUpdateDriver driver(module, type); + const char * result = driver.flashFirmware(&file, getBasename(filename), progressHandler); f_close(&file); AUDIO_PLAY(AU_SPECIAL_SOUND_BEEP1); BACKLIGHT_ENABLE(); -#if defined(HARDWARE_INTERNAL_MODULE) - INTERNAL_MODULE_OFF(); -#endif - EXTERNAL_MODULE_OFF(); - SPORT_UPDATE_POWER_OFF(); - - /* wait 2s off */ - watchdogSuspend(500 /*5s*/); - RTOS_WAIT_MS(2000); - if (result) { POPUP_WARNING(STR_FIRMWARE_UPDATE_ERROR, result); } @@ -665,36 +573,17 @@ bool MultiDeviceFirmwareUpdate::flashFirmware(const char * filename, ProgressHan POPUP_INFORMATION(STR_FIRMWARE_UPDATE_SUCCESS); } - // reset telemetry protocol - telemetryInit(255); + watchdogSuspend(50 /*500ms*/); + pulsesStart(); -#if defined(HARDWARE_INTERNAL_MODULE) - if (intPwr) { -#if defined(MULTI_PROTOLIST) - MultiRfProtocols::removeInstance(INTERNAL_MODULE); -#endif - INTERNAL_MODULE_ON(); - setupPulsesInternalModule(); - } -#endif - -#if defined(HARDWARE_EXTERNAL_MODULE) - if (extPwr) { -#if defined(MULTI_PROTOLIST) - MultiRfProtocols::removeInstance(EXTERNAL_MODULE); -#endif - EXTERNAL_MODULE_ON(); - setupPulsesExternalModule(); - } -#endif - -#if defined(SPORT_UPDATE_PWR_GPIO) - if (spuPwr) { - SPORT_UPDATE_POWER_ON(); - } -#endif - - resumePulses(); +// TODO: S.PORT power control +// -> where is it actually turned ON normally? +// +// #if defined(SPORT_UPDATE_PWR_GPIO) +// if (spuPwr) { +// SPORT_UPDATE_POWER_ON(); +// } +// #endif return result == nullptr; } diff --git a/radio/src/io/multi_firmware_update.h b/radio/src/io/multi_firmware_update.h index 16f96c40a..29a210818 100644 --- a/radio/src/io/multi_firmware_update.h +++ b/radio/src/io/multi_firmware_update.h @@ -74,12 +74,16 @@ class MultiFirmwareInformation bool isMultiInternalFirmware() const { - return (boardType == FIRMWARE_MULTI_STM && optibootSupport && bootloaderCheck && telemetryType == FIRMWARE_MULTI_TELEM_MULTI_TELEMETRY); + return (boardType == FIRMWARE_MULTI_STM && optibootSupport && + bootloaderCheck && + telemetryType == FIRMWARE_MULTI_TELEM_MULTI_TELEMETRY); } bool isMultiExternalFirmware() const { - return ((telemetryInversion || boardType == FIRMWARE_MULTI_STM ) && optibootSupport && bootloaderCheck && telemetryType == FIRMWARE_MULTI_TELEM_MULTI_TELEMETRY); + return ((telemetryInversion || boardType == FIRMWARE_MULTI_STM) && + optibootSupport && bootloaderCheck && + telemetryType == FIRMWARE_MULTI_TELEM_MULTI_TELEMETRY); } const char * readMultiFirmwareInformation(const char * filename); diff --git a/radio/src/io/multi_protolist.cpp b/radio/src/io/multi_protolist.cpp index 3abe4eb40..bca9381b9 100644 --- a/radio/src/io/multi_protolist.cpp +++ b/radio/src/io/multi_protolist.cpp @@ -54,7 +54,7 @@ void MultiRfProtocols::timerCb(TimerHandle_t xTimer) } #endif -MultiRfProtocols* MultiRfProtocols::_instance[NUM_MODULES] = {}; +MultiRfProtocols* MultiRfProtocols::_instance[MAX_MODULES] = {}; // MPM telemetry packet format type = MultiProtoDef (0x11) // diff --git a/radio/src/logs.cpp b/radio/src/logs.cpp index 23f32ab3f..8cadc0811 100644 --- a/radio/src/logs.cpp +++ b/radio/src/logs.cpp @@ -34,13 +34,15 @@ static tmr10ms_t lastLogTime = 0; #include #include +#include "tasks/mixer_task.h" + static TimerHandle_t loggingTimer = nullptr; static StaticTimer_t loggingTimerBuffer; static void loggingTimerCb(TimerHandle_t xTimer) { (void)xTimer; - if (!s_pulses_paused) { + if (!mixerTaskRunning()) { DEBUG_TIMER_START(debugTimerLoggingWakeup); logsWrite(); DEBUG_TIMER_STOP(debugTimerLoggingWakeup); diff --git a/radio/src/lua/api_general.cpp b/radio/src/lua/api_general.cpp index 9e63f1166..fc1e1d9a6 100644 --- a/radio/src/lua/api_general.cpp +++ b/radio/src/lua/api_general.cpp @@ -25,7 +25,7 @@ #include "stamp.h" #include "lua_api.h" #include "api_filesystem.h" -#include "aux_serial_driver.h" +#include "hal/module_port.h" #if defined(LIBOPENUI) #include "libopenui.h" @@ -915,10 +915,20 @@ When called without parameters, it will only return the status of the output buf @status current Introduced in 2.2.0, retval nil added in 2.3.4 */ +static bool _supports_sport(uint8_t module) +{ + return IS_NATIVE_FRSKY_PROTOCOL(module) || + (isModuleMultimodule(module) && + (IS_D16_MULTI(module) || IS_R9_MULTI(module))); +} + static int luaSportTelemetryPush(lua_State * L) { + bool extmod = _supports_sport(EXTERNAL_MODULE); + bool intmod = _supports_sport(INTERNAL_MODULE); + // dirty hack until 2 simultanous protocols are supported - if (isModuleCrossfire(INTERNAL_MODULE) || !IS_FRSKY_SPORT_PROTOCOL()) { + if (!extmod && !intmod) { lua_pushnil(L); return 1; } @@ -966,9 +976,11 @@ static int luaSportTelemetryPush(lua_State * L) packet.dataId = dataId; packet.value = luaL_checkunsigned(L, 4); outputTelemetryBuffer.pushSportPacketWithBytestuffing(packet); -#if defined(PXX2) - uint8_t destination = (IS_INTERNAL_MODULE_ON() ? INTERNAL_MODULE : EXTERNAL_MODULE); - outputTelemetryBuffer.setDestination(isModulePXX2(destination) ? (destination << 2) : TELEMETRY_ENDPOINT_SPORT); +#if defined(PXX2) && defined(HARDWARE_EXTERNAL_MODULE) + uint8_t destination = (intmod ? INTERNAL_MODULE : EXTERNAL_MODULE); + outputTelemetryBuffer.setDestination(isModulePXX2(destination) + ? (destination << 2) + : TELEMETRY_ENDPOINT_SPORT); #else outputTelemetryBuffer.setDestination(TELEMETRY_ENDPOINT_SPORT); #endif @@ -1120,10 +1132,10 @@ When called without parameters, it will only return the status of the output buf */ static int luaCrossfireTelemetryPush(lua_State * L) { - bool sport = (telemetryProtocol == PROTOCOL_TELEMETRY_CROSSFIRE); + bool external = (moduleState[EXTERNAL_MODULE].protocol == PROTOCOL_CHANNELS_CROSSFIRE); bool internal = (moduleState[INTERNAL_MODULE].protocol == PROTOCOL_CHANNELS_CROSSFIRE); - if (!internal && !sport) { + if (!internal && !external) { lua_pushnil(L); return 1; } @@ -1218,9 +1230,8 @@ When called without parameters, it will only return the status of the output buf */ static int luaGhostTelemetryPush(lua_State * L) { - bool sport = (telemetryProtocol == PROTOCOL_TELEMETRY_GHOST); - - if (!sport) { + bool extmod = (moduleState[EXTERNAL_MODULE].protocol == PROTOCOL_CHANNELS_GHOST); + if (!extmod) { lua_pushnil(L); return 1; } @@ -1242,18 +1253,20 @@ static int luaGhostTelemetryPush(lua_State * L) return 1; } - // Ghost frames are fixed 14B - outputTelemetryBuffer.pushByte(getGhostModuleAddr()); // addr (1B) - outputTelemetryBuffer.pushByte(12); // len = payload length(10B) + type(1B) + crc(1B) + // Ghost frames are fixed 14B: + // address(1B) + len (1B) + type(1B) + payload(10B) + crc(1B) + // -> address + len up-front are inserted later outputTelemetryBuffer.pushByte(type); // type (1B) - for (int i=0; i #endif +#if defined(MULTIMODULE) +#include "pulses/multi.h" +#endif + /*luadoc @function model.getInfo() diff --git a/radio/src/mixer.cpp b/radio/src/mixer.cpp index 7b0ed4504..6c4e314f9 100644 --- a/radio/src/mixer.cpp +++ b/radio/src/mixer.cpp @@ -23,6 +23,8 @@ #include "timers.h" #include "switches.h" +uint8_t s_mixer_first_run_done = false; + int8_t virtualInputsTrims[MAX_INPUTS]; int16_t anas [MAX_INPUTS] = {0}; int16_t trims[NUM_TRIMS] = {0}; @@ -34,7 +36,6 @@ SwOn swOn [MAX_MIXERS]; // TODO better name later... uint8_t mixWarning; - int16_t calibratedAnalogs[NUM_CALIBRATED_ANALOGS]; int16_t channelOutputs[MAX_OUTPUT_CHANNELS] = {0}; int16_t ex_chans[MAX_OUTPUT_CHANNELS] = {0}; // Outputs (before LIMITS) of the last perMain; @@ -455,6 +456,20 @@ getvalue_t getValue(mixsrc_t i, bool* valid) } } +void evalTrims() +{ + uint8_t phase = mixerCurrentFlightMode; + for (uint8_t i=0; i throttle trim if applicable + int16_t trim = getTrimValue(phase, i); + if (trimsCheckTimer > 0) { + trim = 0; + } + + trims[i] = trim*2; + } +} + void evalInputs(uint8_t mode) { BeepANACenter anaCenter = 0; @@ -524,7 +539,8 @@ void evalInputs(uint8_t mode) if (mode == e_perout_mode_normal) { if (tmp==0 || (tmp==1 && (bpanaCenter & mask))) { anaCenter |= mask; - if ((g_model.beepANACenter & mask) && !(bpanaCenter & mask) && s_mixer_first_run_done && !menuCalibrationState) { + if ((g_model.beepANACenter & mask) && !(bpanaCenter & mask) && + s_mixer_first_run_done && !menuCalibrationState) { if (!IS_POT(i) || IS_POT_SLIDER_AVAILABLE(i)) { AUDIO_POT_MIDDLE(i); } @@ -625,6 +641,7 @@ int getSourceTrimValue(int source, int stickValue=0) } uint8_t mixerCurrentFlightMode; + void evalFlightModeMixes(uint8_t mode, uint8_t tick10ms) { evalInputs(mode); @@ -1092,3 +1109,140 @@ void evalMixes(uint8_t tick10ms) } } } + +#if defined(THRTRACE) +uint8_t s_traceBuf[MAXTRACE]; +uint16_t s_traceWr; +uint8_t s_cnt_10s; +uint16_t s_cnt_samples_thr_10s; +uint16_t s_sum_samples_thr_10s; +#endif + +void doMixerPeriodicUpdates() +{ + static tmr10ms_t lastTMR = 0; + + tmr10ms_t tmr10ms = get_tmr10ms(); + + uint8_t tick10ms = (tmr10ms >= lastTMR ? tmr10ms - lastTMR : 1); + // handle tick10ms overrun + // correct overflow handling costs a lot of code; happens only each 11 min; + // therefore forget the exact calculation and use only 1 instead; good compromise + lastTMR = tmr10ms; + + DEBUG_TIMER_START(debugTimerMixes10ms); + if (tick10ms) { + /* Throttle trace */ + int16_t val; + + if (g_model.thrTraceSrc > NUM_POTS+NUM_SLIDERS) { + uint8_t ch = g_model.thrTraceSrc-NUM_POTS-NUM_SLIDERS-1; + val = channelOutputs[ch]; + + LimitData * lim = limitAddress(ch); + int16_t gModelMax = LIMIT_MAX_RESX(lim); + int16_t gModelMin = LIMIT_MIN_RESX(lim); + + if (lim->revert) + val = -val + gModelMax; + else + val = val - gModelMin; + +#if defined(PPM_LIMITS_SYMETRICAL) + if (lim->symetrical) { + val -= calc1000toRESX(lim->offset); + } +#endif + + gModelMax -= gModelMin; // we compare difference between Max and Mix for recaling needed; Max and Min are shifted to 0 by default + // usually max is 1024 min is -1024 --> max-min = 2048 full range + + if (gModelMax != 0 && gModelMax != 2048) + val = (int32_t) (val << 11) / (gModelMax); // rescaling only needed if Min, Max differs + + if (val < 0) + val=0; // prevent val be negative, which would corrupt throttle trace and timers; could occur if safetyswitch is smaller than limits + } + else { + val = RESX + calibratedAnalogs[g_model.thrTraceSrc == 0 ? THR_STICK : g_model.thrTraceSrc+NUM_STICKS-1]; + } + + val >>= (RESX_SHIFT-6); // calibrate it (resolution increased by factor 4) + + evalTimers(val, tick10ms); + + static uint8_t s_cnt_100ms; + static uint8_t s_cnt_1s; + static uint8_t s_cnt_samples_thr_1s; + static uint16_t s_sum_samples_thr_1s; + + s_cnt_samples_thr_1s++; + s_sum_samples_thr_1s+=val; + + if ((s_cnt_100ms += tick10ms) >= 10) { // 0.1sec + s_cnt_100ms -= 10; + s_cnt_1s += 1; + + logicalSwitchesTimerTick(); + checkTrainerSignalWarning(); + + if (s_cnt_1s >= 10) { // 1sec + s_cnt_1s -= 10; + sessionTimer += 1; + inactivity.counter++; + if ((((uint8_t)inactivity.counter) & 0x07) == 0x01 && g_eeGeneral.inactivityTimer && inactivity.counter > ((uint16_t)g_eeGeneral.inactivityTimer * 60)) + AUDIO_INACTIVITY(); + +#if defined(AUDIO) + if (mixWarning & 1) if ((sessionTimer&0x03)==0) AUDIO_MIX_WARNING(1); + if (mixWarning & 2) if ((sessionTimer&0x03)==1) AUDIO_MIX_WARNING(2); + if (mixWarning & 4) if ((sessionTimer&0x03)==2) AUDIO_MIX_WARNING(3); +#endif + + val = s_sum_samples_thr_1s / s_cnt_samples_thr_1s; + s_timeCum16ThrP += (val>>3); // s_timeCum16ThrP would overrun if we would store throttle value with higher accuracy; therefore stay with 16 steps + if (val) + s_timeCumThr += 1; + s_sum_samples_thr_1s >>= 2; // correct better accuracy now, because trace graph can show this information; in case thrtrace is not active, the compile should remove this + +#if defined(THRTRACE) + // throttle trace is done every 10 seconds; Tracebuffer is adjusted to screen size. + // in case buffer runs out, it wraps around + // resolution for y axis is only 32, therefore no higher value makes sense + s_cnt_samples_thr_10s += s_cnt_samples_thr_1s; + s_sum_samples_thr_10s += s_sum_samples_thr_1s; + + if (++s_cnt_10s >= 10) { // 10s + s_cnt_10s -= 10; + val = s_sum_samples_thr_10s / s_cnt_samples_thr_10s; + s_sum_samples_thr_10s = 0; + s_cnt_samples_thr_10s = 0; + s_traceBuf[s_traceWr % MAXTRACE] = val; + s_traceWr++; + } +#endif + + s_cnt_samples_thr_1s = 0; + s_sum_samples_thr_1s = 0; + } + } + +#if defined(PXX) || defined(DSM2) + static uint8_t countRangecheck = 0; + for (uint8_t i = 0; i < NUM_MODULES; ++i) { + if (isModuleBeeping(i)) { + if (++countRangecheck >= 250) { + countRangecheck = 0; + AUDIO_PLAY(AU_SPECIAL_SOUND_CHEEP); + } + } + } +#endif + + checkTrims(); + } + + DEBUG_TIMER_STOP(debugTimerMixes10ms); + + s_mixer_first_run_done = true; +} diff --git a/radio/src/mixer_scheduler.cpp b/radio/src/mixer_scheduler.cpp index e4ec76736..98da61da0 100644 --- a/radio/src/mixer_scheduler.cpp +++ b/radio/src/mixer_scheduler.cpp @@ -21,6 +21,7 @@ #include "opentx.h" #include "mixer_scheduler.h" +#include "tasks/mixer_task.h" bool mixerSchedulerWaitForTrigger(uint8_t timeoutMs) { @@ -98,6 +99,11 @@ void mixerSchedulerSetPeriod(uint8_t moduleIdx, uint16_t periodUs) mixerSchedules[moduleIdx].period = periodUs; } +uint16_t mixerSchedulerGetPeriod(uint8_t moduleIdx) +{ + return mixerSchedules[moduleIdx].period; +} + void mixerSchedulerISRTrigger() { BaseType_t xHigherPriorityTaskWoken = pdFALSE; diff --git a/radio/src/mixer_scheduler.h b/radio/src/mixer_scheduler.h index 07d4c979b..b79d7c7af 100644 --- a/radio/src/mixer_scheduler.h +++ b/radio/src/mixer_scheduler.h @@ -46,6 +46,9 @@ void mixerSchedulerResetTimer(); // Set the scheduling period for a given module void mixerSchedulerSetPeriod(uint8_t moduleIdx, uint16_t periodUs); +// Get the scheduling period for a given module +uint16_t mixerSchedulerGetPeriod(uint8_t moduleIdx); + // Enable the timer trigger void mixerSchedulerEnableTrigger(); @@ -65,6 +68,7 @@ void mixerSchedulerISRTrigger(); #define mixerSchedulerStop() #define mixerSchedulerResetTimer() #define mixerSchedulerSetPeriod(m,p) ((void)(p)) +#define mixerSchedulerGetPeriod(m) ((uint16_t)MIXER_SCHEDULER_DEFAULT_PERIOD_US) #define mixerSchedulerClearTrigger() #define mixerSchedulerEnableTrigger() diff --git a/radio/src/opentx.cpp b/radio/src/opentx.cpp index a05834320..1680bc02b 100644 --- a/radio/src/opentx.cpp +++ b/radio/src/opentx.cpp @@ -22,9 +22,11 @@ #include "opentx.h" #include "io/frsky_firmware_update.h" #include "hal/adc_driver.h" -#include "aux_serial_driver.h" #include "timers_driver.h" +#include "tasks.h" +#include "tasks/mixer_task.h" + #if defined(LIBOPENUI) #include "libopenui.h" // #include "shutdown_animation.h" @@ -675,21 +677,23 @@ void doSplash() #if defined(MULTIMODULE) void checkMultiLowPower() { - if (isModuleMultimodule(EXTERNAL_MODULE) && g_model.moduleData[EXTERNAL_MODULE].multi.lowPowerMode) { - ALERT("MULTI", STR_WARN_MULTI_LOWPOWER, AU_ERROR); - return; + bool low_power_warning = false; + for (uint8_t i = 0; i < MAX_MODULES; i++) { + if (isModuleMultimodule(i) && + g_model.moduleData[i].multi.lowPowerMode) { + low_power_warning = true; + } } -#if defined(INTERNAL_MODULE_MULTI) - if (isModuleMultimodule(INTERNAL_MODULE) && g_model.moduleData[INTERNAL_MODULE].multi.lowPowerMode) { + + if (low_power_warning) { ALERT("MULTI", STR_WARN_MULTI_LOWPOWER, AU_ERROR); } -#endif } #endif static void checkRTCBattery() { - GET_ADC_IF_MIXER_NOT_RUNNING(); + if (!mixerTaskRunning()) getADC(); if (getRTCBatteryVoltage() < 200) { ALERT(STR_BATTERY, STR_WARN_RTC_BATTERY_LOW, AU_ERROR); } @@ -815,7 +819,7 @@ bool isThrottleWarningAlertNeeded() // no other information available at the moment, and good enough to my option (otherwise too much exceptions...) uint8_t thrchn = ((g_model.thrTraceSrc==0) || (g_model.thrTraceSrc>NUM_POTS+NUM_SLIDERS)) ? THR_STICK : g_model.thrTraceSrc+NUM_STICKS-1; - GET_ADC_IF_MIXER_NOT_RUNNING(); + if (!mixerTaskRunning()) getADC(); evalInputs(e_perout_mode_notrainer); // let do evalInputs do the job int16_t v = calibratedAnalogs[thrchn]; @@ -1088,8 +1092,7 @@ uint16_t sessionTimer; uint16_t s_timeCumThr; // THR in 1/16 sec uint16_t s_timeCum16ThrP; // THR% in 1/16 sec -uint8_t trimsCheckTimer = 0; - +uint8_t trimsCheckTimer = 0; uint8_t trimsDisplayTimer = 0; uint8_t trimsDisplayMask = 0; @@ -1129,194 +1132,6 @@ void flightReset(uint8_t check) } } -#if defined(THRTRACE) -uint8_t s_traceBuf[MAXTRACE]; -uint16_t s_traceWr; -uint8_t s_cnt_10s; -uint16_t s_cnt_samples_thr_10s; -uint16_t s_sum_samples_thr_10s; -#endif - -void evalTrims() -{ - uint8_t phase = mixerCurrentFlightMode; - for (uint8_t i=0; i throttle trim if applicable - int16_t trim = getTrimValue(phase, i); - if (trimsCheckTimer > 0) { - trim = 0; - } - - trims[i] = trim*2; - } -} - -uint8_t s_mixer_first_run_done = false; - -void doMixerCalculations() -{ - static tmr10ms_t lastTMR = 0; - - tmr10ms_t tmr10ms = get_tmr10ms(); - -#if defined(DEBUG_LATENCY_MIXER_RF) || defined(DEBUG_LATENCY_RF_ONLY) - static tmr10ms_t lastLatencyToggle = 0; - if (tmr10ms - lastLatencyToggle >= 10) { - lastLatencyToggle = tmr10ms; - toggleLatencySwitch(); - } -#endif - - uint8_t tick10ms = (tmr10ms >= lastTMR ? tmr10ms - lastTMR : 1); - // handle tick10ms overrun - // correct overflow handling costs a lot of code; happens only each 11 min; - // therefore forget the exact calculation and use only 1 instead; good compromise - lastTMR = tmr10ms; - - DEBUG_TIMER_START(debugTimerGetAdc); - getADC(); - DEBUG_TIMER_STOP(debugTimerGetAdc); - - DEBUG_TIMER_START(debugTimerGetSwitches); - getSwitchesPosition(!s_mixer_first_run_done); - DEBUG_TIMER_STOP(debugTimerGetSwitches); - - - - DEBUG_TIMER_START(debugTimerEvalMixes); - evalMixes(tick10ms); - DEBUG_TIMER_STOP(debugTimerEvalMixes); -} - -void doMixerPeriodicUpdates() -{ - static tmr10ms_t lastTMR = 0; - - tmr10ms_t tmr10ms = get_tmr10ms(); - - uint8_t tick10ms = (tmr10ms >= lastTMR ? tmr10ms - lastTMR : 1); - // handle tick10ms overrun - // correct overflow handling costs a lot of code; happens only each 11 min; - // therefore forget the exact calculation and use only 1 instead; good compromise - lastTMR = tmr10ms; - - DEBUG_TIMER_START(debugTimerMixes10ms); - if (tick10ms) { - /* Throttle trace */ - int16_t val; - - if (g_model.thrTraceSrc > NUM_POTS+NUM_SLIDERS) { - uint8_t ch = g_model.thrTraceSrc-NUM_POTS-NUM_SLIDERS-1; - val = channelOutputs[ch]; - - LimitData * lim = limitAddress(ch); - int16_t gModelMax = LIMIT_MAX_RESX(lim); - int16_t gModelMin = LIMIT_MIN_RESX(lim); - - if (lim->revert) - val = -val + gModelMax; - else - val = val - gModelMin; - -#if defined(PPM_LIMITS_SYMETRICAL) - if (lim->symetrical) { - val -= calc1000toRESX(lim->offset); - } -#endif - - gModelMax -= gModelMin; // we compare difference between Max and Mix for recaling needed; Max and Min are shifted to 0 by default - // usually max is 1024 min is -1024 --> max-min = 2048 full range - - if (gModelMax != 0 && gModelMax != 2048) - val = (int32_t) (val << 11) / (gModelMax); // rescaling only needed if Min, Max differs - - if (val < 0) - val=0; // prevent val be negative, which would corrupt throttle trace and timers; could occur if safetyswitch is smaller than limits - } - else { - val = RESX + calibratedAnalogs[g_model.thrTraceSrc == 0 ? THR_STICK : g_model.thrTraceSrc+NUM_STICKS-1]; - } - - val >>= (RESX_SHIFT-6); // calibrate it (resolution increased by factor 4) - - evalTimers(val, tick10ms); - - static uint8_t s_cnt_100ms; - static uint8_t s_cnt_1s; - static uint8_t s_cnt_samples_thr_1s; - static uint16_t s_sum_samples_thr_1s; - - s_cnt_samples_thr_1s++; - s_sum_samples_thr_1s+=val; - - if ((s_cnt_100ms += tick10ms) >= 10) { // 0.1sec - s_cnt_100ms -= 10; - s_cnt_1s += 1; - - logicalSwitchesTimerTick(); - checkTrainerSignalWarning(); - - if (s_cnt_1s >= 10) { // 1sec - s_cnt_1s -= 10; - sessionTimer += 1; - inactivity.counter++; - if ((((uint8_t)inactivity.counter) & 0x07) == 0x01 && g_eeGeneral.inactivityTimer && inactivity.counter > ((uint16_t)g_eeGeneral.inactivityTimer * 60)) - AUDIO_INACTIVITY(); - -#if defined(AUDIO) - if (mixWarning & 1) if ((sessionTimer&0x03)==0) AUDIO_MIX_WARNING(1); - if (mixWarning & 2) if ((sessionTimer&0x03)==1) AUDIO_MIX_WARNING(2); - if (mixWarning & 4) if ((sessionTimer&0x03)==2) AUDIO_MIX_WARNING(3); -#endif - - val = s_sum_samples_thr_1s / s_cnt_samples_thr_1s; - s_timeCum16ThrP += (val>>3); // s_timeCum16ThrP would overrun if we would store throttle value with higher accuracy; therefore stay with 16 steps - if (val) - s_timeCumThr += 1; - s_sum_samples_thr_1s >>= 2; // correct better accuracy now, because trace graph can show this information; in case thrtrace is not active, the compile should remove this - -#if defined(THRTRACE) - // throttle trace is done every 10 seconds; Tracebuffer is adjusted to screen size. - // in case buffer runs out, it wraps around - // resolution for y axis is only 32, therefore no higher value makes sense - s_cnt_samples_thr_10s += s_cnt_samples_thr_1s; - s_sum_samples_thr_10s += s_sum_samples_thr_1s; - - if (++s_cnt_10s >= 10) { // 10s - s_cnt_10s -= 10; - val = s_sum_samples_thr_10s / s_cnt_samples_thr_10s; - s_sum_samples_thr_10s = 0; - s_cnt_samples_thr_10s = 0; - s_traceBuf[s_traceWr % MAXTRACE] = val; - s_traceWr++; - } -#endif - - s_cnt_samples_thr_1s = 0; - s_sum_samples_thr_1s = 0; - } - } - -#if defined(PXX) || defined(DSM2) - static uint8_t countRangecheck = 0; - for (uint8_t i = 0; i < NUM_MODULES; ++i) { - if (isModuleBeeping(i)) { - if (++countRangecheck >= 250) { - countRangecheck = 0; - AUDIO_PLAY(AU_SPECIAL_SOUND_CHEEP); - } - } - } -#endif - - checkTrims(); - } - - DEBUG_TIMER_STOP(debugTimerMixes10ms); - - s_mixer_first_run_done = true; -} - #if !defined(OPENTX_START_DEFAULT_ARGS) #define OPENTX_START_DEFAULT_ARGS 0 #endif @@ -1372,12 +1187,13 @@ void opentxClose(uint8_t shutdown) watchdogSuspend(2000/*20s*/); if (shutdown) { - pausePulses(); // stop mixer task to disable trims processing while in shutdown + pulsesStop(); AUDIO_BYE(); - // TODO needed? telemetryEnd(); + #if defined(LUA) luaClose(&lsScripts); #endif + #if defined(HAPTIC) hapticOff(); #endif @@ -1509,7 +1325,7 @@ void instantTrim() void copySticksToOffset(uint8_t ch) { - pauseMixerCalculations(); + mixerTaskStop(); int32_t zero = (int32_t)channelOutputs[ch]; evalFlightModeMixes(e_perout_mode_nosticks+e_perout_mode_notrainer, 0); @@ -1522,7 +1338,8 @@ void copySticksToOffset(uint8_t ch) } zero = (zero*256000 - val*lim) / (1024*256-val); ld->offset = (ld->revert ? -zero : zero); - resumeMixerCalculations(); + + mixerTaskStart(); storageDirty(EE_MODEL); } @@ -1530,7 +1347,7 @@ void copyTrimsToOffset(uint8_t ch) { int16_t zero; - pauseMixerCalculations(); + mixerTaskStop(); evalFlightModeMixes(e_perout_mode_noinput, 0); // do output loop - zero input sticks and trims zero = applyLimits(ch, chans[ch]); @@ -1544,7 +1361,7 @@ void copyTrimsToOffset(uint8_t ch) v += (output * 125) / 128; g_model.limitData[ch].offset = limit((int16_t)-1000, (int16_t)v, (int16_t)1000); // make sure the offset doesn't go haywire - resumeMixerCalculations(); + mixerTaskStart(); storageDirty(EE_MODEL); } @@ -1555,7 +1372,7 @@ void copyMinMaxToOutputs(uint8_t ch) int16_t max = ld->max; int16_t center = ld->ppmCenter; - pauseMixerCalculations(); + mixerTaskStop(); for (uint8_t chan = 0; chan < MAX_OUTPUT_CHANNELS; chan++) { ld = limitAddress(chan); @@ -1564,7 +1381,7 @@ void copyMinMaxToOutputs(uint8_t ch) ld->ppmCenter = center; } - resumeMixerCalculations(); + mixerTaskStart(); storageDirty(EE_MODEL); } @@ -1609,7 +1426,7 @@ void moveTrimsToOffsets() // copy state of 3 primary to subtrim { int16_t zeros[MAX_OUTPUT_CHANNELS]; - pauseMixerCalculations(); + mixerTaskStop(); evalFlightModeMixes(e_perout_mode_noinput, 0); // do output loop - zero input sticks and trims @@ -1642,7 +1459,7 @@ void moveTrimsToOffsets() // copy state of 3 primary to subtrim } } - resumeMixerCalculations(); + mixerTaskStart(); storageDirty(EE_MODEL); AUDIO_WARNING2(); @@ -1726,13 +1543,6 @@ void opentxInit() if (bluetooth.flashFirmware(AUTOUPDATE_FILENAME) == nullptr) f_unlink(AUTOUPDATE_FILENAME); } -#endif -#if defined(HARDWARE_POWER_MANAGEMENT_UNIT) - if (information.productFamily == FIRMWARE_FAMILY_POWER_MANAGEMENT_UNIT) { - FrskyChipFirmwareUpdate device; - if (device.flashFirmware(AUTOUPDATE_FILENAME, false) == nullptr) - f_unlink(AUTOUPDATE_FILENAME); - } #endif } } @@ -1771,6 +1581,11 @@ void opentxInit() #endif #endif // #if !defined(EEPROM) +// TODO: move to board on hook (onStorageReady()?) +// #if defined(SPORT_UPDATE_PWR_GPIO) +// SPORT_UPDATE_POWER_INIT(); +// #endif + initSerialPorts(); currentSpeakerVolume = requiredSpeakerVolume = g_eeGeneral.speakerVolume + VOLUME_LEVEL_DEF; @@ -1783,12 +1598,6 @@ void opentxInit() audioQueue.start(); BACKLIGHT_ENABLE(); - - -#if defined(SPORT_UPDATE_PWR_GPIO) - SPORT_UPDATE_POWER_INIT(); -#endif - #if defined(COLORLCD) loadTheme(); if (g_eeGeneral.backlightMode == e_backlight_mode_off) { @@ -1823,8 +1632,7 @@ void opentxInit() resetBacklightTimeout(); - startPulses(); - + pulsesStart(); WDG_ENABLE(WDG_DURATION); } @@ -1848,15 +1656,6 @@ int main() NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 ); #endif - TRACE("reusableBuffer: modelSel=%d, moduleSetup=%d, calib=%d, sdManager=%d, hardwareAndSettings=%d, spectrumAnalyser=%d, usb=%d", - sizeof(reusableBuffer.modelsel), - sizeof(reusableBuffer.moduleSetup), - sizeof(reusableBuffer.calib), - sizeof(reusableBuffer.sdManager), - sizeof(reusableBuffer.hardwareAndSettings), - sizeof(reusableBuffer.spectrumAnalyser), - sizeof(reusableBuffer.MSC_BOT_Data)); - // G: The WDT remains active after a WDT reset -- at maximum clock speed. So it's // important to disable it before commencing with system initialisation (or // we could put a bunch more WDG_RESET()s in. But I don't like that approach @@ -1866,6 +1665,7 @@ int main() #endif boardInit(); + pulsesInit(); #if defined(PCBHORUS) if (!IS_FIRMWARE_COMPATIBLE_WITH_BOARD()) { diff --git a/radio/src/opentx.h b/radio/src/opentx.h index d1ccbf509..308278771 100644 --- a/radio/src/opentx.h +++ b/radio/src/opentx.h @@ -569,12 +569,6 @@ void checkAlarm(); void checkAll(); void getADC(); -static inline void GET_ADC_IF_MIXER_NOT_RUNNING() -{ - if (s_pulses_paused) { - getADC(); - } -} #include "sbus.h" @@ -583,23 +577,6 @@ void checkBacklight(); uint16_t isqrt32(uint32_t n); -#if defined(BOOT) -#define pauseMixerCalculations() -#define resumeMixerCalculations() -#else -#include "tasks.h" -extern RTOS_MUTEX_HANDLE mixerMutex; -inline void pauseMixerCalculations() -{ - RTOS_LOCK_MUTEX(mixerMutex); -} - -inline void resumeMixerCalculations() -{ - RTOS_UNLOCK_MUTEX(mixerMutex); -} -#endif - void setDefaultOwnerId(); void generalDefault(); @@ -941,8 +918,10 @@ union ReusableBuffer int8_t antennaMode; uint8_t previousType; uint8_t newType; +#if defined(PXX2) BindInformation bindInformation; PXX2ModuleSetup pxx2; +#endif #if defined(BLUETOOTH) struct { char devices[MAX_BLUETOOTH_DISTANT_ADDR][LEN_BLUETOOTH_ADDR+1]; @@ -973,8 +952,10 @@ union ReusableBuffer uint16_t offset; uint16_t count; char originalName[SD_SCREEN_FILE_LENGTH+1]; +#if defined(PXX2) OtaUpdateInformation otaUpdateInformation; char otaReceiverVersion[sizeof(TR_CURRENT_VERSION) + 12]; +#endif } sdManager; #endif @@ -983,10 +964,14 @@ union ReusableBuffer char id[27]; } version; +#if defined(PXX2) PXX2HardwareAndSettings hardwareAndSettings; // radio_version +#endif struct { +#if defined(PXX2) ModuleInformation modules[NUM_MODULES]; +#endif char msg[64]; #if !defined(COLORLCD) uint8_t linesCount; @@ -1060,7 +1045,9 @@ union ReusableBuffer } modelFailsafe; struct { +#if defined(PXX2) ModuleInformation internalModule; +#endif } viewMain; // Data for the USB mass storage driver. If USB mass storage runs no menu is not allowed to be displayed diff --git a/radio/src/pulses/afhds2.cpp b/radio/src/pulses/afhds2.cpp index ac07d41ee..b84b89685 100644 --- a/radio/src/pulses/afhds2.cpp +++ b/radio/src/pulses/afhds2.cpp @@ -23,21 +23,18 @@ #include "afhds2.h" #include "flysky.h" -#include "intmodule_serial_driver.h" #include "mixer_scheduler.h" +#include "hal/module_port.h" #include "pulses/pulses.h" #include "telemetry/telemetry.h" - - const etx_serial_init afhds2SerialInitParams = { .baudrate = INTMODULE_USART_AFHDS2_BAUDRATE, - .parity = ETX_Parity_None, - .stop_bits = ETX_StopBits_One, - .word_length = ETX_WordLength_8, - .rx_enable = true, + .encoding = ETX_Encoding_8N1, + .direction = ETX_Dir_TX_RX, + .polarity = ETX_Pol_Normal, }; static void* afhds2Init(uint8_t module) @@ -46,50 +43,43 @@ static void* afhds2Init(uint8_t module) // serial port setup resetPulsesAFHDS2(); - void* ctx = IntmoduleSerialDriver.init(&afhds2SerialInitParams); + auto mod_st = modulePortInitSerial(module, ETX_MOD_PORT_UART, + &afhds2SerialInitParams); // mixer setup - mixerSchedulerSetPeriod(INTERNAL_MODULE, AFHDS2_PERIOD); - INTERNAL_MODULE_ON(); + mixerSchedulerSetPeriod(module, AFHDS2_PERIOD); - return ctx; + return (void*)mod_st; } -static void afhds2DeInit(void* context) +static void afhds2DeInit(void* ctx) { - INTERNAL_MODULE_OFF(); - IntmoduleSerialDriver.deinit(context); - - // mixer setup - mixerSchedulerSetPeriod(INTERNAL_MODULE, 0); + auto mod_st = (etx_module_state_t*)ctx; + modulePortDeInit(mod_st); } -static void afhds2SetupPulses(void* context, int16_t* channels, uint8_t nChannels) +static void afhds2SendPulses(void* ctx, uint8_t* buffer, int16_t* channels, uint8_t nChannels) { - (void)context; - // TODO: (void)channels; (void)nChannels; - ModuleSyncStatus& status = getModuleSyncStatus(INTERNAL_MODULE); - mixerSchedulerSetPeriod(INTERNAL_MODULE, status.isValid() - ? status.getAdjustedRefreshRate() - : AFHDS2_PERIOD); + auto mod_st = (etx_module_state_t*)ctx; + auto module = modulePortGetModule(mod_st); + + ModuleSyncStatus& status = getModuleSyncStatus(module); + mixerSchedulerSetPeriod(module, status.isValid() + ? status.getAdjustedRefreshRate() + : AFHDS2_PERIOD); status.invalidate(); - setupPulsesAFHDS2(); -} -static void afhds2SendPulses(void* context) -{ - uint8_t* data = (uint8_t*)intmodulePulsesData.flysky.pulses; - uint16_t size = intmodulePulsesData.flysky.ptr - data; - IntmoduleSerialDriver.sendBuffer(context, data, size); -} + auto p_data = buffer; + setupPulsesAFHDS2(p_data); -static int afhds2GetByte(void* context, uint8_t* data) -{ - return IntmoduleSerialDriver.getByte(context, data); + auto drv = modulePortGetSerialDrv(mod_st->tx); + auto drv_ctx = modulePortGetCtx(mod_st->tx); + + drv->sendBuffer(drv_ctx, buffer, p_data - buffer); } static void afhds2ProcessData(void*, uint8_t data, uint8_t* buffer, uint8_t* len) @@ -97,12 +87,10 @@ static void afhds2ProcessData(void*, uint8_t data, uint8_t* buffer, uint8_t* len processInternalFlySkyTelemetryData(data, buffer, len); } -const etx_module_driver_t Afhds2InternalDriver = { +const etx_proto_driver_t Afhds2InternalDriver = { .protocol = PROTOCOL_CHANNELS_AFHDS2A, .init = afhds2Init, .deinit = afhds2DeInit, - .setupPulses = afhds2SetupPulses, .sendPulses = afhds2SendPulses, - .getByte = afhds2GetByte, .processData = afhds2ProcessData, }; diff --git a/radio/src/pulses/afhds2.h b/radio/src/pulses/afhds2.h index 5d978e263..82dffa999 100644 --- a/radio/src/pulses/afhds2.h +++ b/radio/src/pulses/afhds2.h @@ -32,18 +32,7 @@ #define AFHDS2_PERIOD (2 * 1000) /* us */ -struct FlySkySerialPulsesData { - uint8_t pulses[64]; - uint8_t * ptr; - uint8_t frame_index; - uint8_t crc; - uint8_t state; - uint8_t timeout; - uint8_t esc_state; -} __attribute__((__packed__)); - - extern const etx_serial_init afhds2SerialInitParams; -extern const etx_module_driver_t Afhds2InternalDriver; +extern const etx_proto_driver_t Afhds2InternalDriver; #endif /* PULSES_AFHDS2_H_ */ diff --git a/radio/src/pulses/afhds3.cpp b/radio/src/pulses/afhds3.cpp index 00bc56a39..67da700e0 100644 --- a/radio/src/pulses/afhds3.cpp +++ b/radio/src/pulses/afhds3.cpp @@ -31,16 +31,7 @@ #include "telemetry/telemetry.h" #include "mixer_scheduler.h" #include "hal/module_driver.h" - -#if defined(INTMODULE_USART) -#include "intmodule_serial_driver.h" -#endif - -#if defined(AFHDS3_EXT_UART) -#include "extmodule_serial_driver.h" -#else -#include "extmodule_driver.h" -#endif +#include "hal/module_port.h" #define FAILSAFE_HOLD 1 #define FAILSAFE_CUSTOM 2 @@ -192,8 +183,7 @@ class ProtoState * @param moduleIndex index of module one of INTERNAL_MODULE, EXTERNAL_MODULE * @param resetFrameCount flag if current frame count should be reseted */ - void init(uint8_t moduleIndex, void* buffer, const etx_serial_driver_t* drv); - void deinit() { trsp.deinit(); } + void init(uint8_t moduleIndex, void* buffer, etx_module_state_t* mod_st); /** * Fills DMA buffers with frame to be send depending on actual state @@ -205,11 +195,6 @@ class ProtoState */ void sendFrame() { trsp.sendBuffer(); } - /** - * Fetch telemetry byte - */ - int getTelemetryByte(uint8_t* data) { return trsp.getTelemetryByte(data); } - /** * Gets actual module status into provided buffer * @param statusText target buffer for status @@ -320,7 +305,7 @@ static const COMMAND periodicRequestCommands[] = }; //Static collection of afhds3 object instances by module -static ProtoState protoState[NUM_MODULES]; +static ProtoState protoState[MAX_MODULES]; void getStatusString(uint8_t module, char* buffer) { @@ -330,7 +315,8 @@ void getStatusString(uint8_t module, char* buffer) //friends function that can access telemetry parsing method void processTelemetryData(void* ctx, uint8_t data, uint8_t* buffer, uint8_t* len) { - auto p_state = (ProtoState*)ctx; + auto mod_st = (etx_module_state_t*)ctx; + auto p_state = (ProtoState*)mod_st->user_data; p_state->processTelemetryData(data, buffer, len); } @@ -482,16 +468,10 @@ void ProtoState::setupFrame() } } -void ProtoState::init(uint8_t moduleIndex, void* buffer, const etx_serial_driver_t* drv) +void ProtoState::init(uint8_t moduleIndex, void* buffer, etx_module_state_t* mod_st) { module_index = moduleIndex; - - // TODO: move bit/byte transport to serial driver - if (drv) { - trsp.init(ByteTransport::Serial, buffer, drv); - } else { - trsp.init(ByteTransport::Pulses, buffer, nullptr); - } + trsp.init(buffer, mod_st); //clear local vars because it is member of union moduleData = &g_model.moduleData[module_index]; @@ -861,106 +841,70 @@ void applyModelConfig(uint8_t module) p_state->applyConfigFromModel(); } -static void* initExternal(uint8_t module) +static const etx_serial_init _uartParams = { + .baudrate = 0, //AFHDS3_UART_BAUDRATE, + .encoding = ETX_Encoding_8N1, + .direction = ETX_Dir_TX_RX, + .polarity = ETX_Pol_Normal, +}; + +static void* initModule(uint8_t module) { -#if defined(AFHDS3_EXT_UART) - auto drv = extmoduleGetSerialPort(); - if (!drv) return nullptr; + etx_module_state_t* mod_st = nullptr; + etx_serial_init params(_uartParams); + uint16_t period = AFHDS3_UART_COMMAND_TIMEOUT * 1000; - uint16_t period = AFHDS3_UART_COMMAND_TIMEOUT * 1000 /* us */; -#else - const etx_serial_driver_t* drv = nullptr; - uint16_t period = AFHDS3_SOFTSERIAL_COMMAND_TIMEOUT * 1000 /* us */; + params.baudrate = AFHDS3_UART_BAUDRATE; + params.polarity = + module == INTERNAL_MODULE ? ETX_Pol_Normal : ETX_Pol_Inverted; + mod_st = modulePortInitSerial(module, ETX_MOD_PORT_UART, ¶ms); - telemetryPortInvertedInit(AFHDS3_SOFTSERIAL_BAUDRATE); - telemetryPortSetDirectionInput(); -#endif + if (module == EXTERNAL_MODULE && !mod_st) { + // soft-serial fallback + params.baudrate = AFHDS3_SOFTSERIAL_BAUDRATE; + params.direction = ETX_Dir_RX; + period = AFHDS3_SOFTSERIAL_COMMAND_TIMEOUT * 1000 /* us */; + mod_st = modulePortInitSerial(module, ETX_MOD_PORT_SOFT_INV, ¶ms); + // TODO: telemetry RX ??? + } + + if (!mod_st) return nullptr; auto p_state = &protoState[module]; - p_state->init(module, &extmodulePulsesData.afhds3, drv); + p_state->init(module, pulsesGetModuleBuffer(module), mod_st); + mod_st->user_data = (void*)p_state; mixerSchedulerSetPeriod(module, period); - EXTERNAL_MODULE_ON(); - return p_state; + return mod_st; } -static void deinitExternal(void* context) +static void deinitModule(void* ctx) { - EXTERNAL_MODULE_OFF(); - mixerSchedulerSetPeriod(EXTERNAL_MODULE, 0); - - auto p_state = (ProtoState*)context; - p_state->deinit(); + auto mod_st = (etx_module_state_t*)ctx; + modulePortDeInit(mod_st); } -static void sendPulses(void* context) -{ - auto p_state = (ProtoState*)context; - p_state->sendFrame(); -} - -static void setupPulses(void* context, int16_t* channels, uint8_t nChannels) +static void sendPulses(void* ctx, uint8_t* buffer, int16_t* channels, uint8_t nChannels) { + (void)buffer; (void)channels; (void)nChannels; - auto p_state = (ProtoState*)context; + auto mod_st = (etx_module_state_t*)ctx; + auto p_state = (ProtoState*)mod_st->user_data; p_state->setupFrame(); + p_state->sendFrame(); } -etx_module_driver_t externalDriver = { +etx_proto_driver_t ProtoDriver = { .protocol = PROTOCOL_CHANNELS_AFHDS3, - .init = initExternal, - .deinit = deinitExternal, - .setupPulses = setupPulses, + .init = initModule, + .deinit = deinitModule, .sendPulses = sendPulses, - .getByte = nullptr, // TODO .processData = processTelemetryData, }; -#if defined(INTERNAL_MODULE_AFHDS3) - -static void* initInternal(uint8_t module) -{ - auto p_state = &protoState[module]; - p_state->init(module, &intmodulePulsesData, &IntmoduleSerialDriver); - - telemetryProtocol = PROTOCOL_TELEMETRY_AFHDS3; - mixerSchedulerSetPeriod(module, AFHDS3_UART_COMMAND_TIMEOUT * 1000 /* us */); - INTERNAL_MODULE_ON(); - - return p_state; -} - -static void deinitInternal(void* context) -{ - INTERNAL_MODULE_OFF(); - telemetryProtocol = 0xFF; - mixerSchedulerSetPeriod(INTERNAL_MODULE, 0); - - auto p_state = (ProtoState*)context; - p_state->deinit(); -} - -static int getByteInternal(void* context, uint8_t* data) -{ - auto p_state = (ProtoState*)context; - return p_state->getTelemetryByte(data); -} - -etx_module_driver_t internalDriver = { - .protocol = PROTOCOL_CHANNELS_AFHDS3, - .init = initInternal, - .deinit = deinitInternal, - .setupPulses = setupPulses, - .sendPulses = sendPulses, - .getByte = getByteInternal, - .processData = processTelemetryData, -}; - -#endif - } diff --git a/radio/src/pulses/afhds3.h b/radio/src/pulses/afhds3.h index 146477332..26f7f32ef 100644 --- a/radio/src/pulses/afhds3.h +++ b/radio/src/pulses/afhds3.h @@ -70,11 +70,7 @@ typedef PulsesData ExtmoduleData; typedef SerialData IntmoduleData; #endif -extern etx_module_driver_t externalDriver; - -#if defined(INTERNAL_MODULE_AFHDS3) -extern etx_module_driver_t internalDriver; -#endif +extern etx_proto_driver_t ProtoDriver; void getStatusString(uint8_t module, char* buffer); void processTelemetryData(uint8_t data, uint8_t module); diff --git a/radio/src/pulses/afhds3_transport.cpp b/radio/src/pulses/afhds3_transport.cpp index cedf36e5e..d23eb0b89 100644 --- a/radio/src/pulses/afhds3_transport.cpp +++ b/radio/src/pulses/afhds3_transport.cpp @@ -23,8 +23,9 @@ #include "opentx_helpers.h" #include "debug.h" -#include "extmodule_driver.h" #include "board.h" +#include "dataconstants.h" +#include "mixer_scheduler.h" // timer is 2 MHz #if defined(AFHDS3_SLOW) @@ -60,110 +61,16 @@ enum DeviceAddress //Address used in transmitted frames - it constrains of target address and source address const uint8_t FrameAddress = DeviceAddress::TRANSMITTER | (DeviceAddress::MODULE << 4); -static void _serial_reset(void* buffer) +void FrameTransport::init(void* buffer) { - auto data = (SerialData*)buffer; - data->ptr = data->pulses; -} - -static void _serial_sendByte(void* buffer, uint8_t b) -{ - auto data = (SerialData*)buffer; - *(data->ptr++) = b; -} - -static void _serial_flush(void*) {} - -uint32_t _serial_getSize(void* buffer) -{ - auto data = (SerialData*)buffer; - return data->ptr - data->pulses; -} - -static void _pulses_reset(void* buffer) -{ - auto data = (PulsesData*)buffer; - data->ptr = data->pulses; -} - -static inline void _pulses_send_level(PulsesData* data, uint16_t v) -{ - uint32_t size = data->ptr - data->pulses; - if (size >= AFHDS_MAX_PULSES_TRANSITIONS) return; - *(data->ptr)++ = v; -} - -static void _pulses_sendByte(void* buffer, uint8_t b) -{ - auto data = (PulsesData*)buffer; - uint32_t size = data->ptr - data->pulses; - if (size >= AFHDS_MAX_PULSES_TRANSITIONS) return; - - // use 8n1 - // parity: If the parity is enabled, then the MSB bit of the data to be - // transmitted is changed by the parity bit start is always 0 - bool level = 0; - uint16_t length = BITLEN_AFHDS; // start bit - for (uint8_t i = 0; i <= 8; i++) { // 8 data bits + Stop=1 - bool next_level = b & 1; - if (level == next_level) { - length += BITLEN_AFHDS; - } else { - _pulses_send_level(data, length); - length = BITLEN_AFHDS; - level = next_level; - } - b = (b >> 1) | 0x80; // shift left to get next bit, fill msb with stop - // bit - needed just once - } - _pulses_send_level(data, length); // last bit (stop) -} - -static void _pulses_flush(void* buffer) -{ - // TODO: use less, as the new driver can handle it - auto data = (PulsesData*)buffer; - *data->ptr = 60000; -} - -uint32_t _pulses_getSize(void* buffer) -{ - auto data = (PulsesData*)buffer; - return data->ptr - data->pulses; -} - -void ByteTransport::init(Type t) -{ - if (t == Serial) { - reset = _serial_reset; - sendByte = _serial_sendByte; - flush = _serial_flush; - getSize = _serial_getSize; - } else if (t == Pulses) { - reset = _pulses_reset; - sendByte = _pulses_sendByte; - flush = _pulses_flush; - getSize = _pulses_getSize; - } else { - reset = nullptr; - sendByte = nullptr; - flush = nullptr; - getSize = nullptr; - } -} - -void FrameTransport::init(ByteTransport::Type t, void* buffer) -{ - trsp.init(t); - trsp_buffer = buffer; - + trsp_buffer = (uint8_t*)buffer; clear(); } void FrameTransport::clear() { // reset send buffer - trsp.reset(trsp_buffer); + data_ptr = trsp_buffer; // reset parser esc_state = 0; @@ -171,7 +78,7 @@ void FrameTransport::clear() void FrameTransport::sendByte(uint8_t b) { - trsp.sendByte(trsp_buffer, b); + *(data_ptr++) = b; } void FrameTransport::putBytes(uint8_t* data, int length) @@ -197,7 +104,8 @@ void FrameTransport::putFrame(COMMAND command, FRAME_TYPE frameType, uint8_t* da uint8_t dataLength, uint8_t frameIndex) { //header - trsp.reset(trsp_buffer); + data_ptr = trsp_buffer; + crc = 0; sendByte(START); @@ -213,7 +121,11 @@ void FrameTransport::putFrame(COMMAND command, FRAME_TYPE frameType, uint8_t* da uint8_t crcValue = crc ^ 0xff; putBytes(&crcValue, 1); sendByte(END); - trsp.flush(trsp_buffer); +} + +uint32_t FrameTransport::getFrameSize() +{ + return data_ptr - trsp_buffer; } static bool _checkCRC(const uint8_t* data, uint8_t size) @@ -311,35 +223,10 @@ void CommandFifo::enqueue(COMMAND command, FRAME_TYPE frameType, bool useData, } } -static const etx_serial_init _uartParams = { - .baudrate = AFHDS3_UART_BAUDRATE, - .parity = ETX_Parity_None, - .stop_bits = ETX_StopBits_One, - .word_length = ETX_WordLength_8, - .rx_enable = true, -}; - -void Transport::init(ByteTransport::Type t, void* buffer, const etx_serial_driver_t* drv) +void Transport::init(void* buffer, etx_module_state_t* mod_st) { - trsp.init(t, buffer); - - if (drv) { - uart_drv = drv; - uart_ctx = drv->init(&_uartParams); - } else { - uart_drv = nullptr; - uart_ctx = nullptr; - extmoduleSerialStart(); - } -} - -void Transport::deinit() -{ - if (uart_drv) { - uart_drv->deinit(uart_ctx); - } else { - extmoduleStop(); - } + trsp.init(buffer); + this->mod_st = mod_st; } void Transport::clear() @@ -385,11 +272,9 @@ void Transport::enqueue(COMMAND command, FRAME_TYPE frameType, bool useData, void Transport::sendBuffer() { - if (uart_drv) { - uart_drv->sendBuffer(uart_ctx, (uint8_t*)trsp.trsp_buffer, trsp.getFrameSize()); - } else { - extmoduleSendNextFrameSoftSerial((uint8_t*)trsp.trsp_buffer, trsp.getFrameSize()); - } + auto drv = modulePortGetSerialDrv(mod_st->tx); + auto ctx = modulePortGetCtx(mod_st->tx); + drv->sendBuffer(ctx, (uint8_t*)trsp.trsp_buffer, trsp.getFrameSize()); } bool Transport::processQueue() @@ -474,15 +359,6 @@ bool Transport::handleReply(uint8_t* buffer, uint8_t len) return false; } -int Transport::getTelemetryByte(uint8_t* data) -{ - if (uart_drv) { - return uart_drv->getByte(uart_ctx, data); - } else { - return sportGetByte(data); - } -} - bool Transport::processTelemetryData(uint8_t byte, uint8_t* rxBuffer, uint8_t& rxBufferCount, uint8_t maxSize) { diff --git a/radio/src/pulses/afhds3_transport.h b/radio/src/pulses/afhds3_transport.h index 3103e55b9..e7a649016 100644 --- a/radio/src/pulses/afhds3_transport.h +++ b/radio/src/pulses/afhds3_transport.h @@ -24,22 +24,11 @@ #include "afhds3_module.h" #include "definitions.h" -#include "hal/serial_driver.h" +#include "hal/module_port.h" namespace afhds3 { -struct ByteTransport { - enum Type { Serial, Pulses }; - - void (*reset)(void* buffer); - void (*sendByte)(void* buffer, uint8_t b); - void (*flush)(void* buffer); - uint32_t (*getSize)(void* buffer); - - void init(Type t); -}; - enum FRAME_TYPE: uint8_t { REQUEST_GET_DATA = 0x01, //Get data response: ACK + DATA @@ -130,14 +119,14 @@ struct CommandFifo { struct FrameTransport { - ByteTransport trsp; - void* trsp_buffer; + uint8_t* trsp_buffer; + uint8_t* data_ptr; uint8_t crc; // uint8_t timeout; uint8_t esc_state; - void init(ByteTransport::Type t, void* buffer); + void init(void* buffer); void clear(); void sendByte(uint8_t b); @@ -146,7 +135,7 @@ struct FrameTransport void putFrame(COMMAND command, FRAME_TYPE frameType, uint8_t* data, uint8_t dataLength, uint8_t frameIndex); - uint32_t getFrameSize() { return trsp.getSize(trsp_buffer); } + uint32_t getFrameSize(); bool processTelemetryData(uint8_t byte, uint8_t* rxBuffer, uint8_t& rxBufferCount, uint8_t maxSize); @@ -161,8 +150,7 @@ class Transport IDLE }; - const etx_serial_driver_t* uart_drv; - void* uart_ctx; + etx_module_state_t* mod_st; FrameTransport trsp; CommandFifo fifo; @@ -187,8 +175,7 @@ class Transport bool handleReply(uint8_t* buffer, uint8_t len); public: - void init(ByteTransport::Type t, void* buffer, const etx_serial_driver_t* drv); - void deinit(); + void init(void* buffer, etx_module_state_t* mod_st); void clear(); @@ -213,8 +200,6 @@ class Transport */ bool processQueue(); - int getTelemetryByte(uint8_t* data); - bool processTelemetryData(uint8_t byte, uint8_t* rxBuffer, uint8_t& rxBufferCount, uint8_t maxSize); }; diff --git a/radio/src/pulses/crossfire.cpp b/radio/src/pulses/crossfire.cpp index 21b71e6cc..26ba69f2c 100644 --- a/radio/src/pulses/crossfire.cpp +++ b/radio/src/pulses/crossfire.cpp @@ -22,10 +22,7 @@ #include "opentx.h" #include "mixer_scheduler.h" #include "hal/module_driver.h" - -#if defined(INTMODULE_USART) -#include "intmodule_serial_driver.h" -#endif +#include "hal/module_port.h" #include "crossfire.h" #include "telemetry/crossfire.h" @@ -79,26 +76,25 @@ uint8_t createCrossfireChannelsFrame(uint8_t * frame, int16_t * pulses) return buf - frame; } -static void setupPulsesCrossfire(uint8_t idx, CrossfirePulsesData* p_data, +static void setupPulsesCrossfire(uint8_t module, uint8_t*& p_buf, uint8_t endpoint, int16_t* channels, uint8_t nChannels) { #if defined(LUA) if (outputTelemetryBuffer.destination == endpoint) { - memcpy(p_data->pulses, outputTelemetryBuffer.data, - outputTelemetryBuffer.size); - p_data->length = outputTelemetryBuffer.size; + auto len = outputTelemetryBuffer.size; + memcpy(p_buf, outputTelemetryBuffer.data, len); outputTelemetryBuffer.reset(); + p_buf += len; } else #endif { - if (moduleState[idx].counter == CRSF_FRAME_MODELID) { - p_data->length = createCrossfireModelIDFrame(idx, p_data->pulses); - moduleState[idx].counter = CRSF_FRAME_MODELID_SENT; + if (moduleState[module].counter == CRSF_FRAME_MODELID) { + p_buf += createCrossfireModelIDFrame(module, p_buf); + moduleState[module].counter = CRSF_FRAME_MODELID_SENT; } else { - p_data->length = createCrossfireChannelsFrame( - p_data->pulses, - channels /*TODO: nChannels*/); + /* TODO: nChannels */ + p_buf += createCrossfireChannelsFrame(p_buf, channels); } } } @@ -109,7 +105,7 @@ static void crossfireSetupMixerScheduler(uint8_t module) if (status.isValid()) { mixerSchedulerSetPeriod(module, status.getAdjustedRefreshRate()); } else { - mixerSchedulerSetPeriod(module, CROSSFIRE_PERIOD); + mixerSchedulerSetPeriod(module, CROSSFIRE_PERIOD(module)); } } @@ -120,59 +116,22 @@ static bool _checkFrameCRC(uint8_t* rxBuffer) return (crc == rxBuffer[len+1]); } -struct CrossfireState { - uint8_t module; - CrossfirePulsesData* data; - const etx_serial_driver_t* uart_drv; - void* uart_ctx; - uint8_t endpoint; - - void init(uint8_t _module, CrossfirePulsesData* _data, - const etx_serial_driver_t* _drv, void* _ctx, uint8_t _endpoint) - { - module = _module; - data = _data; - uart_drv = _drv; - uart_ctx = _ctx; - endpoint = _endpoint; - } - - void deinit() { uart_drv->deinit(uart_ctx); } -}; - -static CrossfireState crossfireState[NUM_MODULES]; - -static void crossfireSetupPulses(void* context, int16_t* channels, uint8_t nChannels) +static void crossfireSendPulses(void* ctx, uint8_t* buffer, int16_t* channels, uint8_t nChannels) { - auto state = (CrossfireState*)context; - crossfireSetupMixerScheduler(state->module); - setupPulsesCrossfire(state->module, state->data, state->endpoint, channels, nChannels); -} + auto mod_st = (etx_module_state_t*)ctx; + auto module = modulePortGetModule(mod_st); + crossfireSetupMixerScheduler(module); -static void crossfireSendPulses(void* context) -{ - auto state = (CrossfireState*)context; - auto data = state->data; + uint8_t endpoint = 0; +#if defined(HARDWARE_EXTERNAL_MODULE) + if (module == EXTERNAL_MODULE) endpoint = TELEMETRY_ENDPOINT_SPORT; +#endif + auto p_buf = buffer; + setupPulsesCrossfire(module, p_buf, endpoint, channels, nChannels); - if (state->uart_drv) { - auto drv = state->uart_drv; - auto ctx = state->uart_ctx; - drv->sendBuffer(ctx, data->pulses, data->length); - } else { - sportSendBuffer(data->pulses, data->length); - } -} - -static int crossfireGetByte(void* context, uint8_t* data) -{ - auto state = (CrossfireState*)context; - if (state->uart_drv) { - auto drv = state->uart_drv; - auto ctx = state->uart_ctx; - return drv->getByte(ctx, data); - } else { - return sportGetByte(data); - } + auto drv = modulePortGetSerialDrv(mod_st->tx); + auto drv_ctx = modulePortGetCtx(mod_st->tx); + drv->sendBuffer(drv_ctx, buffer, p_buf - buffer); } static bool _lenIsSane(uint8_t len) @@ -210,7 +169,7 @@ static void _seekStart(uint8_t* buffer, uint8_t* len) *len = 0; } -static void crossfireProcessData(void* context, uint8_t data, uint8_t* buffer, uint8_t* len) +static void crossfireProcessData(void* ctx, uint8_t data, uint8_t* buffer, uint8_t* len) { if (*len == 0 && data != RADIO_ADDRESS && data != UART_SYNC) { TRACE("[XF] address 0x%02X error", data); @@ -233,16 +192,15 @@ static void crossfireProcessData(void* context, uint8_t data, uint8_t* buffer, u // rxBuffer[1] holds the packet length-2, check if the whole packet was received while (*len > 4 && (buffer[1]+2) == *len) { - // TODO: module in context? if (_checkFrameCRC(buffer)) { -#if defined(BLUETOOTH) +#if defined(BLUETOOTH) // TODO: generic telemetry mirror to BT if (g_eeGeneral.bluetoothMode == BLUETOOTH_TELEMETRY && bluetooth.state == BLUETOOTH_STATE_CONNECTED) { bluetooth.write(buffer, *len); } #endif - auto state = (CrossfireState*)context; - processCrossfireTelemetryFrame(state->module); + auto mod_st = (etx_module_state_t*)ctx; + processCrossfireTelemetryFrame(modulePortGetModule(mod_st)); *len = 0; } else { @@ -252,84 +210,51 @@ static void crossfireProcessData(void* context, uint8_t data, uint8_t* buffer, u } } -#if defined(INTERNAL_MODULE_CRSF) -static const etx_serial_init intmoduleCrossfireInitParams = { +static const etx_serial_init crsfSerialParams = { .baudrate = 0, - .parity = ETX_Parity_None, - .stop_bits = ETX_StopBits_One, - .word_length = ETX_WordLength_8, - .rx_enable = true, + .encoding = ETX_Encoding_8N1, + .direction = ETX_Dir_TX_RX, + .polarity = ETX_Pol_Normal, }; -static void* crossfireInitInternal(uint8_t module) +static void* crossfireInit(uint8_t module) { - // serial port setup - etx_serial_init params(intmoduleCrossfireInitParams); - params.baudrate = INT_CROSSFIRE_BAUDRATE; - INTERNAL_MODULE_ON(); + etx_module_state_t* mod_st = nullptr; + etx_serial_init params(crsfSerialParams); - auto state = &crossfireState[module]; - state->init(module, &intmodulePulsesData.crossfire, - &IntmoduleSerialDriver, IntmoduleSerialDriver.init(¶ms), 0); +#if defined(INTERNAL_MODULE_CRSF) + if (module == INTERNAL_MODULE) { - return state; -} - -static void crossfireDeInitInternal(void* context) -{ - INTERNAL_MODULE_OFF(); - mixerSchedulerSetPeriod(INTERNAL_MODULE, 0); - - auto state = (CrossfireState*)context; - state->deinit(); -} - -const etx_module_driver_t CrossfireInternalDriver = { - .protocol = PROTOCOL_CHANNELS_CROSSFIRE, - .init = crossfireInitInternal, - .deinit = crossfireDeInitInternal, - .setupPulses = crossfireSetupPulses, - .sendPulses = crossfireSendPulses, - .getByte = crossfireGetByte, - .processData = crossfireProcessData, -}; + params.baudrate = INT_CROSSFIRE_BAUDRATE; + mod_st = modulePortInitSerial(module, ETX_MOD_PORT_UART, ¶ms); + } #endif -static void* crossfireInitExternal(uint8_t module) -{ - // telemetryInit(PROTOCOL_TELEMETRY_CROSSFIRE); - telemetryProtocol = PROTOCOL_TELEMETRY_CROSSFIRE; - telemetryPortInit(EXT_CROSSFIRE_BAUDRATE, TELEMETRY_SERIAL_DEFAULT); -#if defined(LUA) - outputTelemetryBuffer.reset(); +#if defined(HARDWARE_EXTERNAL_MODULE) + if (module == EXTERNAL_MODULE) { + + params.baudrate = EXT_CROSSFIRE_BAUDRATE; + mod_st = modulePortInitSerial(module, ETX_MOD_PORT_SPORT, ¶ms); + } #endif - telemetryPortSetDirectionOutput(); - mixerSchedulerSetPeriod(module, CROSSFIRE_PERIOD); - EXTERNAL_MODULE_ON(); - - auto state = &crossfireState[module]; - state->init(module, &extmodulePulsesData.crossfire, nullptr, nullptr, - TELEMETRY_ENDPOINT_SPORT); - - return state; + if (mod_st) { + mixerSchedulerSetPeriod(module, CROSSFIRE_PERIOD(module)); + } + + return (void*)mod_st; } -static void crossfireDeInitExternal(void* context) +static void crossfireDeInit(void* ctx) { - (void)context; - telemetryProtocol = 0xFF; - - EXTERNAL_MODULE_OFF(); - mixerSchedulerSetPeriod(EXTERNAL_MODULE, 0); + auto mod_st = (etx_module_state_t*)ctx; + modulePortDeInit(mod_st); } -const etx_module_driver_t CrossfireExternalDriver = { +const etx_proto_driver_t CrossfireDriver = { .protocol = PROTOCOL_CHANNELS_CROSSFIRE, - .init = crossfireInitExternal, - .deinit = crossfireDeInitExternal, - .setupPulses = crossfireSetupPulses, + .init = crossfireInit, + .deinit = crossfireDeInit, .sendPulses = crossfireSendPulses, - .getByte = crossfireGetByte, .processData = crossfireProcessData, }; diff --git a/radio/src/pulses/crossfire.h b/radio/src/pulses/crossfire.h index c0d85a841..95265471e 100644 --- a/radio/src/pulses/crossfire.h +++ b/radio/src/pulses/crossfire.h @@ -23,5 +23,4 @@ #include "hal/module_driver.h" -extern const etx_module_driver_t CrossfireInternalDriver; -extern const etx_module_driver_t CrossfireExternalDriver; +extern const etx_proto_driver_t CrossfireDriver; diff --git a/radio/src/pulses/dsm2.cpp b/radio/src/pulses/dsm2.cpp index 6a8a58d1b..e771c8750 100644 --- a/radio/src/pulses/dsm2.cpp +++ b/radio/src/pulses/dsm2.cpp @@ -19,7 +19,12 @@ * GNU General Public License for more details. */ +#include "dsm2.h" +#include "hal/module_port.h" +#include "mixer_scheduler.h" + #include "opentx.h" +#include "telemetry/spektrum.h" #define DSM2_SEND_BIND (1 << 7) #define DSM2_SEND_RANGECHECK (1 << 5) @@ -31,62 +36,18 @@ #define DSMX_BIT 0x08 #define BAD_DATA 0x47 -#define BITLEN_DSM2 (8*2) //125000 Baud => 8uS per bit +#define DSM2_BITRATE 125000 -static void reset_dsm2_buffer() +static inline void sendByte(uint8_t*& p_buf, uint8_t b) { - extmodulePulsesData.dsm2.index = 0; - extmodulePulsesData.dsm2.ptr = extmodulePulsesData.dsm2.pulses; + *p_buf++ = b; } -static void _send_1(uint8_t v) -{ - *extmodulePulsesData.dsm2.ptr++ = v - 1; - extmodulePulsesData.dsm2.index += 1; -} - -static void _sendByte(uint8_t b, uint8_t bit_len) // max 10 changes 0 10 10 10 10 1 -{ - bool lev = 0; - uint8_t len = bit_len; // max val: 9*16 < 256 - for (uint8_t i=0; i<=8; i++) { // 8Bits + Stop=1 - bool nlev = b & 1; // lsb first - if (lev == nlev) { - len += bit_len; - } - else { - _send_1(len); - len = bit_len; - lev = nlev; - } - b = (b>>1) | 0x80; // shift in stop bit - } - _send_1(len); // stop bit (len is already bit_len) -} - -static void sendByteDsm2(uint8_t b) -{ - _sendByte(b, BITLEN_DSM2); -} - -void putDsm2Flush() -{ - if (extmodulePulsesData.dsm2.index & 1) - *extmodulePulsesData.dsm2.ptr++ = 255; - else - *(extmodulePulsesData.dsm2.ptr - 1) = 255; -} - -// This is the data stream to send, prepare after 19.5 mS -// Send after 22.5 mS - -void setupPulsesDSM2() +static void setupPulsesDSM2(uint8_t module, uint8_t*& p_buf) { uint8_t dsmDat[14]; - reset_dsm2_buffer(); - - switch (moduleState[EXTERNAL_MODULE].protocol) { + switch (moduleState[module].protocol) { case PROTOCOL_CHANNELS_DSM2_LP45: dsmDat[0] = 0x00; break; @@ -98,17 +59,17 @@ void setupPulsesDSM2() break; } - if (moduleState[EXTERNAL_MODULE].mode == MODULE_MODE_BIND) { + if (moduleState[module].mode == MODULE_MODE_BIND) { dsmDat[0] |= DSM2_SEND_BIND; } - else if (moduleState[EXTERNAL_MODULE].mode == MODULE_MODE_RANGECHECK) { + else if (moduleState[module].mode == MODULE_MODE_RANGECHECK) { dsmDat[0] |= DSM2_SEND_RANGECHECK; } - dsmDat[1] = g_model.header.modelId[EXTERNAL_MODULE]; // DSM2 Header second byte for model match + dsmDat[1] = g_model.header.modelId[module]; // DSM2 Header second byte for model match for (int i=0; i>5)+512, 1023); dsmDat[2+2*i] = (i<<2) | ((pulse>>8)&0x03); @@ -116,36 +77,28 @@ void setupPulsesDSM2() } for (int i=0; i<14; i++) { - sendByteDsm2(dsmDat[i]); + sendByte(p_buf, dsmDat[i]); } - - putDsm2Flush(); } -#define BITLEN_DSMP (17) -static void sendByteDSMP(uint8_t b) -{ - _sendByte(b, BITLEN_DSMP); -} +#define DSMP_BITRATE 115200 -void setupPulsesLemonDSMP() +static void setupPulsesLemonDSMP(uint8_t module, uint8_t*& p_buf) { static uint8_t pass = 0; - reset_dsm2_buffer(); - - const auto& md = g_model.moduleData[EXTERNAL_MODULE]; + const auto& md = g_model.moduleData[module]; uint8_t start_channel = md.channelsStart; auto channels = md.getChannelsCount(); auto flags = md.dsmp.flags & 0x3F; // Force setup packet in Bind mode. - auto module_mode = getModuleMode(EXTERNAL_MODULE); + auto module_mode = getModuleMode(module); - sendByteDSMP( 0xAA ); - sendByteDSMP( pass ); + sendByte(p_buf, 0xAA); + sendByte(p_buf, pass); // Setup packet if (pass == 0) { @@ -154,17 +107,17 @@ void setupPulsesLemonDSMP() flags = DSM2_SEND_BIND | (1 << 6 /* AUTO */); channels = 12; } - sendByteDSMP( flags ); + sendByte(p_buf, flags); uint8_t pwr = 7; if (module_mode == MODULE_MODE_RANGECHECK) { pwr = 4; } - sendByteDSMP( pwr ); - sendByteDSMP( channels ); + sendByte(p_buf, pwr); + sendByte(p_buf, channels ); // Model number - sendByteDSMP( 1 ); + sendByte(p_buf, 1); // Send only 1 single Setup packet pass = 1; @@ -192,20 +145,18 @@ void setupPulsesLemonDSMP() pulse = limit(0, ((value*13)>>5)+512, 1023) | (current_channel << 10); } - sendByteDSMP( pulse >> 8 ); - sendByteDSMP( pulse & 0xFF ); + sendByte(p_buf, pulse >> 8); + sendByte(p_buf, pulse & 0xFF); } else { // Outside of announced number of channels: // -> send invalid value - sendByteDSMP( 0xFF ); - sendByteDSMP( 0xFF ); + sendByte(p_buf, 0xFF); + sendByte(p_buf, 0xFF); } current_channel++; } } - putDsm2Flush(); - if (++pass > 2) pass = 1; if (channels < 8) pass = 1; @@ -213,9 +164,119 @@ void setupPulsesLemonDSMP() // bind packet is setup pass = 0; } - else if (--moduleState[EXTERNAL_MODULE].counter == 0) { + else if (--moduleState[module].counter == 0) { // every 100th packet is setup pass = 0; - moduleState[EXTERNAL_MODULE].counter = 100; + moduleState[module].counter = 100; } } + +const etx_serial_init dsmUartParams = { + .baudrate = 0, + .encoding = ETX_Encoding_8N1, + .direction = ETX_Dir_TX, + .polarity = ETX_Pol_Inverted, +}; + +static void* dsmInit(uint8_t module, uint32_t baudrate, uint16_t period, bool telemetry) +{ + // only external module supported + if (module == INTERNAL_MODULE) return nullptr; + + etx_serial_init params(dsmUartParams); + params.baudrate = baudrate; + auto mod_st = modulePortInitSerial(module, ETX_MOD_PORT_UART, ¶ms); + if (!mod_st) { + // inverted soft-serial fallback + mod_st = modulePortInitSerial(module, ETX_MOD_PORT_SOFT_INV, ¶ms); + if (!mod_st) return nullptr; + } + + if (telemetry) { + params.direction = ETX_Dir_RX; + if (!modulePortInitSerial(module, ETX_MOD_PORT_SPORT, ¶ms)) { + // inverted soft-serial fallback + modulePortInitSerial(module, ETX_MOD_PORT_SPORT_INV, ¶ms); + } + } + + mixerSchedulerSetPeriod(module, period); + return (void*)mod_st; +} + +static void* dsm2Init(uint8_t module) +{ + return dsmInit(module, DSM2_BITRATE, DSM2_PERIOD, false); +} + +static void* dsmpInit(uint8_t module) +{ + return dsmInit(module, DSMP_BITRATE, 11 * 1000 /* 11ms in us */, true); +} + + +static void dsmDeInit(void* ctx) +{ + auto mod_st = (etx_module_state_t*)ctx; + modulePortDeInit(mod_st); +} + +static void _dsm_send(etx_module_state_t* st, uint8_t* buffer, uint32_t len) +{ + auto drv = modulePortGetSerialDrv(st->tx); + auto ctx = modulePortGetCtx(st->tx); + drv->sendBuffer(ctx, buffer, len); +} + +static void dsm2SendPulses(void* ctx, uint8_t* buffer, int16_t* channels, uint8_t nChannels) +{ + // TODO: + (void)channels; + (void)nChannels; + + auto mod_st = (etx_module_state_t*)ctx; + auto module = modulePortGetModule(mod_st); + + auto p_data = buffer; + setupPulsesDSM2(module, p_data); + _dsm_send(mod_st, buffer, p_data - buffer); +} + +static void dsmpSendPulses(void* ctx, uint8_t* buffer, int16_t* channels, uint8_t nChannels) +{ + // TODO: + (void)channels; + (void)nChannels; + + auto mod_st = (etx_module_state_t*)ctx; + auto module = modulePortGetModule(mod_st); + + auto p_data = buffer; + setupPulsesLemonDSMP(module, p_data); + _dsm_send(mod_st, buffer, p_data - buffer); +} + +static void dsmpProcessData(void* ctx, uint8_t data, uint8_t* buffer, uint8_t* len) +{ + auto mod_st = (etx_module_state_t*)ctx; + auto module = modulePortGetModule(mod_st); + + processSpektrumTelemetryData(module, data, buffer, *len); +} + +// No telemetry +const etx_proto_driver_t DSM2Driver = { + .protocol = PROTOCOL_CHANNELS_DSM2_LP45, + .init = dsm2Init, + .deinit = dsmDeInit, + .sendPulses = dsm2SendPulses, + .processData = nullptr, +}; + +const etx_proto_driver_t DSMPDriver = { + .protocol = PROTOCOL_CHANNELS_DSMP, + .init = dsmpInit, + .deinit = dsmDeInit, + .sendPulses = dsmpSendPulses, + .processData = dsmpProcessData, +}; diff --git a/radio/src/pulses/dsm2.h b/radio/src/pulses/dsm2.h new file mode 100644 index 000000000..ae8edf0c9 --- /dev/null +++ b/radio/src/pulses/dsm2.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) EdgeTx + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#pragma once + +#include "hal/module_driver.h" + +// DSM2/DSMX +extern const etx_proto_driver_t DSM2Driver; + +// Lemon RX DSMP +extern const etx_proto_driver_t DSMPDriver; diff --git a/radio/src/pulses/flysky.cpp b/radio/src/pulses/flysky.cpp index 49ac5ad49..6c99e3243 100644 --- a/radio/src/pulses/flysky.cpp +++ b/radio/src/pulses/flysky.cpp @@ -116,11 +116,15 @@ struct rf_info_t { uint8_t fw_state; }; -// static STRUCT_HALL rxBuffer = {0}; -static uint32_t rfRxCount = 0; static uint8_t lastState = STATE_IDLE; static uint32_t set_loop_cnt = 0; +static uint8_t _flysky_state; +static uint8_t _flysky_frame_index; +static uint8_t _flysky_crc; +static uint8_t _flysky_timeout; +static uint8_t _esc_state; + uint32_t NV14internalModuleFwVersion = 0; static rf_info_t rf_info = { @@ -153,11 +157,7 @@ uint8_t emptyRxID[] = {0, 0, 0, 0}; void setFlyskyState(uint8_t state); void onFlySkyBindReceiver(); void onFlySkyModuleSetPower(bool isPowerOn); -void afhds2Command(uint8_t type, uint8_t cmd); -void onFlySkyGetVersionInfoStart(uint8_t isRfTransfer); -// void usbDownloadTransmit(uint8_t *buffer, uint32_t size); - -// extern uint32_t NV14internalModuleFwVersion; +void afhds2Command(uint8_t*& p_buf, uint8_t type, uint8_t cmd); #define END 0xC0 #define ESC 0xDB @@ -190,146 +190,85 @@ enum FlySkyModuleCommandID { CMD_LAST }; -bool isFlySkyUsbDownload(void) { return rf_info.fw_state != 0; } - -// void usbSetFrameTransmit(uint8_t packetID, uint8_t *dataBuf, uint32_t nBytes) -// { -// // send to host via usb -// uint8_t *pt = (uint8_t*)&rxBuffer; -// // rxBuffer.head = HALL_PROTOLO_HEAD; -// rxBuffer.hallID.hall_Id.packetID = packetID;//0x08; -// rxBuffer.hallID.hall_Id.senderID = 0x03; -// rxBuffer.hallID.hall_Id.receiverID = 0x02; - -// if ( packetID == 0x08 ) { -// uint8_t fwVerision[40]; -// for(uint32_t idx = 40; idx > 0; idx--) -// { -// if ( idx <= nBytes ) { -// fwVerision[idx-1] = dataBuf[idx-1]; -// } -// else fwVerision[idx-1] = 0; -// } -// dataBuf = fwVerision; -// nBytes = 40; -// } - -// rxBuffer.length = nBytes; - -// TRACE_NOCRLF("\r\nToUSB: 55 %02X %02X ", rxBuffer.hallID.ID, nBytes); -// for ( uint32_t idx = 0; idx < nBytes; idx++ ) -// { -// rxBuffer.data[idx] = dataBuf[idx]; -// TRACE_NOCRLF("%02X ", rxBuffer.data[idx]); -// } -// #if !defined(SIMU) -// uint16_t checkSum = calc_crc16(pt, rxBuffer.length+3); -// TRACE(" CRC:%04X;", checkSum); - -// pt[rxBuffer.length + 3] = checkSum & 0xFF; -// pt[rxBuffer.length + 4] = checkSum >> 8; - -// usbDownloadTransmit(pt, rxBuffer.length + 5); -// #endif -// } - -void onFlySkyModuleSetPower(bool isPowerOn) +void setFlyskyState(uint8_t state) { - if (isPowerOn) { - INTERNAL_MODULE_ON(); - resetPulsesAFHDS2(); - } else { - moduleState[INTERNAL_MODULE].mode = MODULE_MODE_NORMAL; - INTERNAL_MODULE_OFF(); - } + _flysky_state = state; } -void setFlyskyState(uint8_t state) { intmodulePulsesData.flysky.state = state; } - -void onFlySkyUsbDownloadStart(uint8_t fw_state) { rf_info.fw_state = fw_state; } - -void onFlySkyGetVersionInfoStart(uint8_t isRfTransfer) +inline void initFlySkyCRC() { - lastState = intmodulePulsesData.flysky.state; - setFlyskyState(isRfTransfer ? STATE_GET_RF_VERSION_INFO - : STATE_GET_RX_VERSION_INFO); + _flysky_crc = 0; } -inline void initFlySkyArray() -{ - intmodulePulsesData.flysky.ptr = intmodulePulsesData.flysky.pulses; - intmodulePulsesData.flysky.crc = 0; -} - -inline void putFlySkyByte(uint8_t byte) +inline void putFlySkyByte(uint8_t*& p_buf, uint8_t byte) { if (END == byte) { - *intmodulePulsesData.flysky.ptr++ = ESC; - *intmodulePulsesData.flysky.ptr++ = ESC_END; + *p_buf++ = ESC; + *p_buf++ = ESC_END; } else if (ESC == byte) { - *intmodulePulsesData.flysky.ptr++ = ESC; - *intmodulePulsesData.flysky.ptr++ = ESC_ESC; + *p_buf++ = ESC; + *p_buf++ = ESC_ESC; } else { - *intmodulePulsesData.flysky.ptr++ = byte; + *p_buf++ = byte; } } -inline void putFlySkyFrameByte(uint8_t byte) +inline void putFlySkyFrameByte(uint8_t*& p_buf, uint8_t byte) { - intmodulePulsesData.flysky.crc += byte; - putFlySkyByte(byte); + _flysky_crc += byte; + putFlySkyByte(p_buf, byte); } -inline void putFlySkyFrameCmd(uint8_t type, uint8_t cmd) +inline void putFlySkyFrameCmd(uint8_t*& p_buf, uint8_t type, uint8_t cmd) { - intmodulePulsesData.flysky.crc += type + cmd; - putFlySkyByte(type); - putFlySkyByte(cmd); + _flysky_crc += type + cmd; + putFlySkyByte(p_buf, type); + putFlySkyByte(p_buf, cmd); } -inline void putFlySkyFrameBytes(uint8_t* data, int length) +inline void putFlySkyFrameBytes(uint8_t*& p_buf, uint8_t* data, int length) { for (int i = 0; i < length; i++) { - intmodulePulsesData.flysky.crc += data[i]; - putFlySkyByte(data[i]); + _flysky_crc += data[i]; + putFlySkyByte(p_buf, data[i]); } } -inline void putFlySkyFrameHeader() +inline void putFlySkyFrameHeader(uint8_t*& p_buf) { - initFlySkyArray(); - *intmodulePulsesData.flysky.ptr++ = END; - putFlySkyFrameByte(intmodulePulsesData.flysky.frame_index); + initFlySkyCRC(); + *p_buf++ = END; + putFlySkyFrameByte(p_buf, _flysky_frame_index); } -inline void putFlySkyFrameFooter() +inline void putFlySkyFrameFooter(uint8_t*& p_buf) { - if (++intmodulePulsesData.flysky.frame_index == 0) { - intmodulePulsesData.flysky.frame_index = 1; + if (++_flysky_frame_index == 0) { + _flysky_frame_index = 1; } - putFlySkyByte(intmodulePulsesData.flysky.crc ^ 0xff); - *intmodulePulsesData.flysky.ptr++ = END; + putFlySkyByte(p_buf, _flysky_crc ^ 0xff); + *p_buf++ = END; } -void afhds2Command(uint8_t type, uint8_t cmd) +void afhds2Command(uint8_t*& p_buf, uint8_t type, uint8_t cmd) { - putFlySkyFrameHeader(); - putFlySkyFrameCmd(type, cmd); - putFlySkyFrameFooter(); + putFlySkyFrameHeader(p_buf); + putFlySkyFrameCmd(p_buf, type, cmd); + putFlySkyFrameFooter(p_buf); } -inline void putFlySkySendChannelData() +inline void putFlySkySendChannelData(uint8_t*& p_buf) { uint16_t pulseValue = 0; uint8_t channels_start = g_model.moduleData[INTERNAL_MODULE].channelsStart; uint8_t channels_last = channels_start + 8 + g_model.moduleData[INTERNAL_MODULE].channelsCount; - putFlySkyFrameCmd(FRAME_TYPE_REQUEST_NACK, CMD_SEND_CHANNEL_DATA); + putFlySkyFrameCmd(p_buf, FRAME_TYPE_REQUEST_NACK, CMD_SEND_CHANNEL_DATA); if (moduleState[INTERNAL_MODULE].counter-- == 0) { moduleState[INTERNAL_MODULE].counter = FAILSAVE_SEND_COUNTER_MAX; - putFlySkyFrameByte(FLYSKY_CHANNEL_DATA_FAILSAFE); - putFlySkyFrameByte(channels_last - channels_start); + putFlySkyFrameByte(p_buf, FLYSKY_CHANNEL_DATA_FAILSAFE); + putFlySkyFrameByte(p_buf, channels_last - channels_start); for (uint8_t channel = channels_start; channel < channels_last; channel++) { if (g_model.moduleData[INTERNAL_MODULE].failsafeMode == FAILSAFE_CUSTOM) { int16_t failsafeValue = g_model.failsafeChannels[channel]; @@ -345,28 +284,28 @@ inline void putFlySkySendChannelData() pulseValue = limit(0, 988 + ((failsafeValue + 1024) / 2), 0xfff); } - putFlySkyFrameByte(pulseValue & 0xff); - putFlySkyFrameByte(pulseValue >> 8); + putFlySkyFrameByte(p_buf, pulseValue & 0xff); + putFlySkyFrameByte(p_buf, pulseValue >> 8); } if (DEBUG_RF_FRAME_PRINT & RF_FRAME_ONLY) { TRACE("------FAILSAFE------"); } } else { - putFlySkyFrameByte(FLYSKY_CHANNEL_DATA_NORMAL); - putFlySkyFrameByte(channels_last - channels_start); + putFlySkyFrameByte(p_buf, FLYSKY_CHANNEL_DATA_NORMAL); + putFlySkyFrameByte(p_buf, channels_last - channels_start); for (uint8_t channel = channels_start; channel < channels_last; channel++) { int channelValue = channelOutputs[channel] + 2 * PPM_CH_CENTER(channel) - 2 * PPM_CENTER; pulseValue = limit(0, 988 + ((channelValue + 1024) / 2), 0xfff); - putFlySkyFrameByte(pulseValue & 0xff); - putFlySkyFrameByte(pulseValue >> 8); + putFlySkyFrameByte(p_buf, pulseValue & 0xff); + putFlySkyFrameByte(p_buf, pulseValue >> 8); } } } -void putFlySkyUpdateFirmwareStart(uint8_t cmd) +void putFlySkyUpdateFirmwareStart(uint8_t*& p_buf, uint8_t cmd) { - putFlySkyFrameCmd(FRAME_TYPE_REQUEST_ACK, cmd); + putFlySkyFrameCmd(p_buf, FRAME_TYPE_REQUEST_ACK, cmd); } bool checkFlySkyFrameCrc(const uint8_t* ptr, uint8_t size) @@ -419,17 +358,17 @@ inline void parseResponse(uint8_t* buffer, uint8_t dataLen) if ((moduleState[INTERNAL_MODULE].mode != MODULE_MODE_BIND) && (resp->frame_type == FRAME_TYPE_ANSWER) && - ((intmodulePulsesData.flysky.frame_index - 1) != resp->frame_number)) { + ((_flysky_frame_index - 1) != resp->frame_number)) { return; } else if (resp->frame_type == FRAME_TYPE_REQUEST_ACK) { - intmodulePulsesData.flysky.frame_index = resp->frame_number; + _flysky_frame_index = resp->frame_number; } debugFrame(&resp->command_id, dataLen - 2); switch (resp->command_id) { default: if (moduleState[INTERNAL_MODULE].mode == MODULE_MODE_NORMAL && - intmodulePulsesData.flysky.state >= STATE_IDLE) { + _flysky_state >= STATE_IDLE) { setFlyskyState(STATE_SEND_CHANNELS); if (DEBUG_RF_FRAME_PRINT & RF_FRAME_ONLY) TRACE("State back to channel data"); @@ -467,12 +406,12 @@ inline void parseResponse(uint8_t* buffer, uint8_t dataLen) } case CMD_RF_GET_CONFIG: setFlyskyState(STATE_GET_RECEIVER_CONFIG); - intmodulePulsesData.flysky.timeout = FLYSKY_MODULE_TIMEOUT; + _flysky_timeout = FLYSKY_MODULE_TIMEOUT; break; case CMD_RX_SENSOR_DATA: flySkyNv14ProcessTelemetryPacket(&resp->value, dataLen - 3); if (moduleState[INTERNAL_MODULE].mode == MODULE_MODE_NORMAL && - intmodulePulsesData.flysky.state >= STATE_IDLE) { + _flysky_state >= STATE_IDLE) { setFlyskyState(STATE_SEND_CHANNELS); } break; @@ -510,7 +449,7 @@ inline void parseResponse(uint8_t* buffer, uint8_t dataLen) break; } case CMD_GET_VERSION_INFO: { - if (intmodulePulsesData.flysky.state == STATE_GET_FW_VERSION_INIT) { + if (_flysky_state == STATE_GET_FW_VERSION_INIT) { memcpy(&NV14internalModuleFwVersion, &resp->value + 1, sizeof(NV14internalModuleFwVersion)); setFlyskyState(STATE_SET_RECEIVER_ID); @@ -531,48 +470,17 @@ inline void parseResponse(uint8_t* buffer, uint8_t dataLen) } } -bool isrxBufferMsgOK(void) -{ - bool isMsgOK = (0 != rfRxCount); - rfRxCount = 0; - return isMsgOK && isFlySkyUsbDownload(); -} - void processInternalFlySkyTelemetryData(uint8_t byte, uint8_t* buffer, uint8_t* len) { - // #if !defined(SIMU) - // parseFlyskyData(&rxBuffer, byte); - // #endif - // if (rxBuffer.valid) { - // rfRxCount++; - // rxBuffer.valid = 0; - // uint8_t *pt = (uint8_t*)&rxBuffer; - // //rxBuffer.head = HALL_PROTOLO_HEAD; - // pt[rxBuffer.length + 3] = rxBuffer.checkSum & 0xFF; - // pt[rxBuffer.length + 4] = rxBuffer.checkSum >> 8; - - // if((DEBUG_RF_FRAME_PRINT & RF_FRAME_ONLY)) { - // TRACE("RF: %02X %02X %02X ...%04X; CRC:%04X", pt[0], pt[1], pt[2], - // rxBuffer.checkSum, calc_crc16(pt, rxBuffer.length+3)); - // } - - // //FW UPDATE done - // if (0x01 == rxBuffer.length && (0x05 == rxBuffer.data[0] || 0x06 == - // rxBuffer.data[0])) { - // setFlyskyState(STATE_INIT); - // rf_info.fw_state = 0; - // } - // usbDownloadTransmit(pt, rxBuffer.length + 5); - // } if (byte == END && *len > 0) { parseResponse(buffer, *len); *len = 0; } else { if (byte == ESC) { - intmodulePulsesData.flysky.esc_state = 1; + _esc_state = 1; } else { - if (intmodulePulsesData.flysky.esc_state) { - intmodulePulsesData.flysky.esc_state = 0; + if (_esc_state) { + _esc_state = 0; if (byte == ESC_END) byte = END; else if (byte == ESC_ESC) @@ -590,10 +498,10 @@ void processInternalFlySkyTelemetryData(uint8_t byte, uint8_t* buffer, uint8_t* void resetPulsesAFHDS2() { NV14internalModuleFwVersion = 0; - intmodulePulsesData.flysky.frame_index = 1; + _flysky_frame_index = 1; setFlyskyState(STATE_SET_TX_POWER); - intmodulePulsesData.flysky.timeout = 0; - intmodulePulsesData.flysky.esc_state = 0; + _flysky_timeout = 0; + _esc_state = 0; uint16_t rx_freq = gRomData.rx_freq[0]; rx_freq += (gRomData.rx_freq[1] * 256); if (50 > rx_freq || 400 < rx_freq) { @@ -601,41 +509,43 @@ void resetPulsesAFHDS2() } } -void setupPulsesAFHDS2() +void setupPulsesAFHDS2(uint8_t*& p_buf) { - putFlySkyFrameHeader(); - if (intmodulePulsesData.flysky.state == STATE_DISCONNECT) { + auto buffer_start = p_buf; + + putFlySkyFrameHeader(p_buf); + if (_flysky_state == STATE_DISCONNECT) { TRACE("STATE_DISCONNECT"); - putFlySkyFrameCmd(FRAME_TYPE_REQUEST_ACK, CMD_SET_RECEIVER_ID); - putFlySkyFrameBytes(emptyRxID, 4); - } else if (intmodulePulsesData.flysky.state < STATE_SEND_CHANNELS) { - if (++intmodulePulsesData.flysky.timeout >= + putFlySkyFrameCmd(p_buf, FRAME_TYPE_REQUEST_ACK, CMD_SET_RECEIVER_ID); + putFlySkyFrameBytes(p_buf, emptyRxID, 4); + } else if (_flysky_state < STATE_SEND_CHANNELS) { + if (++_flysky_timeout >= FLYSKY_MODULE_TIMEOUT / FLYSKY_PERIOD) { - intmodulePulsesData.flysky.timeout = 0; - switch (intmodulePulsesData.flysky.state) { + _flysky_timeout = 0; + switch (_flysky_state) { case STATE_INIT: { - putFlySkyFrameCmd(FRAME_TYPE_REQUEST_ACK, CMD_RF_INIT); + putFlySkyFrameCmd(p_buf, FRAME_TYPE_REQUEST_ACK, CMD_RF_INIT); } break; case STATE_BIND: { - putFlySkyFrameCmd(FRAME_TYPE_REQUEST_ACK, CMD_BIND); - putFlySkyFrameByte(rf_info.bind_power); + putFlySkyFrameCmd(p_buf, FRAME_TYPE_REQUEST_ACK, CMD_BIND); + putFlySkyFrameByte(p_buf, rf_info.bind_power); uint32_t txID = 0; // internal module firmware does not allow changing TX id - putFlySkyFrameBytes((uint8_t*)(&txID), 4); + putFlySkyFrameBytes(p_buf, (uint8_t*)(&txID), 4); } break; case STATE_SET_RECEIVER_ID: { - putFlySkyFrameCmd(FRAME_TYPE_REQUEST_ACK, CMD_SET_RECEIVER_ID); - putFlySkyFrameBytes(gRomData.rx_id, 4); + putFlySkyFrameCmd(p_buf, FRAME_TYPE_REQUEST_ACK, CMD_SET_RECEIVER_ID); + putFlySkyFrameBytes(p_buf, gRomData.rx_id, 4); } break; case STATE_GET_RECEIVER_CONFIG: { - putFlySkyFrameCmd(FRAME_TYPE_ANSWER, CMD_RF_GET_CONFIG); - putFlySkyFrameByte(AfhdsPwmMode); // 00:PWM, 01:PPM - putFlySkyFrameByte(AfhdsIbusMode); // 00:I-BUS, 01:S-BUS - putFlySkyFrameByte( + putFlySkyFrameCmd(p_buf, FRAME_TYPE_ANSWER, CMD_RF_GET_CONFIG); + putFlySkyFrameByte(p_buf, AfhdsPwmMode); // 00:PWM, 01:PPM + putFlySkyFrameByte(p_buf, AfhdsIbusMode); // 00:I-BUS, 01:S-BUS + putFlySkyFrameByte(p_buf, gRomData.rx_freq[0] < 50 ? 50 : gRomData.rx_freq[0]); // receiver servo freq bit[7:0] - putFlySkyFrameByte( + putFlySkyFrameByte(p_buf, gRomData.rx_freq[1]); // receiver servo freq bit[15:8] setFlyskyState(STATE_INIT); } break; @@ -644,12 +554,12 @@ void setupPulsesAFHDS2() moduleState[INTERNAL_MODULE].mode == MODULE_MODE_RANGECHECK ? 0 : gRomData.rfPower ? 170 : 90; - putFlySkyFrameCmd(FRAME_TYPE_REQUEST_ACK, CMD_SET_TX_POWER); - putFlySkyFrameByte(power); + putFlySkyFrameCmd(p_buf, FRAME_TYPE_REQUEST_ACK, CMD_SET_TX_POWER); + putFlySkyFrameByte(p_buf, power); } break; case STATE_SET_RANGE_TEST: { - putFlySkyFrameCmd(FRAME_TYPE_REQUEST_ACK, CMD_TEST_RANGE); - putFlySkyFrameByte(moduleState[INTERNAL_MODULE].mode == + putFlySkyFrameCmd(p_buf, FRAME_TYPE_REQUEST_ACK, CMD_TEST_RANGE); + putFlySkyFrameByte(p_buf, moduleState[INTERNAL_MODULE].mode == MODULE_MODE_RANGECHECK); } break; case STATE_RANGE_TEST_RUNNING: { @@ -659,71 +569,70 @@ void setupPulsesAFHDS2() } } break; case STATE_SET_RX_PWM_PPM: { - putFlySkyFrameCmd(FRAME_TYPE_REQUEST_ACK, CMD_SET_RX_PWM_PPM); - putFlySkyFrameByte(AfhdsPwmMode); // 00:PWM, 01:PPM + putFlySkyFrameCmd(p_buf, FRAME_TYPE_REQUEST_ACK, CMD_SET_RX_PWM_PPM); + putFlySkyFrameByte(p_buf, AfhdsPwmMode); // 00:PWM, 01:PPM } break; case STATE_SET_RX_IBUS_SBUS: { - putFlySkyFrameCmd(FRAME_TYPE_REQUEST_ACK, CMD_SET_RX_IBUS_SBUS); - putFlySkyFrameByte(AfhdsIbusMode); // 0x00:I-BUS, 0x01:S-BUS + putFlySkyFrameCmd(p_buf, FRAME_TYPE_REQUEST_ACK, CMD_SET_RX_IBUS_SBUS); + putFlySkyFrameByte(p_buf, AfhdsIbusMode); // 0x00:I-BUS, 0x01:S-BUS } break; case STATE_SET_RX_FREQUENCY: { - putFlySkyFrameCmd(FRAME_TYPE_REQUEST_ACK, CMD_SET_RX_SERVO_FREQ); - putFlySkyFrameBytes(gRomData.rx_freq, 2); + putFlySkyFrameCmd(p_buf, FRAME_TYPE_REQUEST_ACK, CMD_SET_RX_SERVO_FREQ); + putFlySkyFrameBytes(p_buf, gRomData.rx_freq, 2); } break; case STATE_UPDATE_RF_PROTOCOL: { - putFlySkyFrameCmd(FRAME_TYPE_REQUEST_ACK, CMD_SET_RF_PROTOCOL); - putFlySkyFrameByte( + putFlySkyFrameCmd(p_buf, FRAME_TYPE_REQUEST_ACK, CMD_SET_RF_PROTOCOL); + putFlySkyFrameByte(p_buf, rf_info.protocol); // 0x00:AFHDS1 0x01:AFHDS2 0x02:AFHDS2A } break; case STATE_UPDATE_RX_FIRMWARE: { - putFlySkyFrameCmd(FRAME_TYPE_REQUEST_ACK, CMD_UPDATE_RX_FIRMWARE); + putFlySkyFrameCmd(p_buf, FRAME_TYPE_REQUEST_ACK, CMD_UPDATE_RX_FIRMWARE); } break; case STATE_UPDATE_RF_FIRMWARE: { - putFlySkyFrameCmd(FRAME_TYPE_REQUEST_ACK, CMD_UPDATE_RF_FIRMWARE); + putFlySkyFrameCmd(p_buf, FRAME_TYPE_REQUEST_ACK, CMD_UPDATE_RF_FIRMWARE); } break; case STATE_GET_RX_VERSION_INFO: { - putFlySkyFrameCmd(FRAME_TYPE_REQUEST_ACK, CMD_GET_VERSION_INFO); - putFlySkyFrameByte(FLYSKY_RX_FIRMWARE); + putFlySkyFrameCmd(p_buf, FRAME_TYPE_REQUEST_ACK, CMD_GET_VERSION_INFO); + putFlySkyFrameByte(p_buf, FLYSKY_RX_FIRMWARE); } break; case STATE_GET_FW_VERSION_INIT: case STATE_GET_RF_VERSION_INFO: { - putFlySkyFrameCmd(FRAME_TYPE_REQUEST_ACK, CMD_GET_VERSION_INFO); - putFlySkyFrameByte(FLYSKY_RF_FIRMWARE); + putFlySkyFrameCmd(p_buf, FRAME_TYPE_REQUEST_ACK, CMD_GET_VERSION_INFO); + putFlySkyFrameByte(p_buf, FLYSKY_RF_FIRMWARE); } break; case STATE_IDLE: - initFlySkyArray(); + initFlySkyCRC(); break; default: setFlyskyState(STATE_INIT); - initFlySkyArray(); + initFlySkyCRC(); if ((DEBUG_RF_FRAME_PRINT & TX_FRAME_ONLY)) { TRACE("State back to INIT\r\n"); } return; } } else { - initFlySkyArray(); + initFlySkyCRC(); return; } } else { if (moduleState[INTERNAL_MODULE].mode == MODULE_MODE_BIND) moduleState[INTERNAL_MODULE].mode = MODULE_MODE_NORMAL; - putFlySkySendChannelData(); + putFlySkySendChannelData(p_buf); } - putFlySkyFrameFooter(); + putFlySkyFrameFooter(p_buf); - if (intmodulePulsesData.flysky.state < STATE_SEND_CHANNELS) { - // uint8_t size = intmodulePulsesData.flysky.ptr - - // intmodulePulsesData.flysky.pulses; - // debugFrame(intmodulePulsesData.flysky.pulses, size); + if (_flysky_state < STATE_SEND_CHANNELS) { + // uint8_t size = p_buf - buffer_start; + // debugFrame(buffer_start, size); } if ((DEBUG_RF_FRAME_PRINT & TX_FRAME_ONLY)) { /* print each command, except channel data by interval */ - uint8_t* data = intmodulePulsesData.flysky.pulses; + uint8_t* data = buffer_start; if (data[3] != CMD_SEND_CHANNEL_DATA || (set_loop_cnt++ % 100 == 0)) { - uint8_t size = intmodulePulsesData.flysky.ptr - data; - TRACE_NOCRLF("TX(State%0d)%0dB:", intmodulePulsesData.flysky.state, size); + uint8_t size = p_buf - data; + TRACE_NOCRLF("TX(State%0d)%0dB:", _flysky_state, size); for (int idx = 0; idx < size; idx++) { TRACE_NOCRLF(" %02X", data[idx]); } diff --git a/radio/src/pulses/flysky.h b/radio/src/pulses/flysky.h index 8683222b8..32cbacffe 100644 --- a/radio/src/pulses/flysky.h +++ b/radio/src/pulses/flysky.h @@ -23,7 +23,7 @@ #define INTMODULE_USART_AFHDS2_BAUDRATE 921600 -void setupPulsesAFHDS2(); +void setupPulsesAFHDS2(uint8_t*& p_buf); void resetPulsesAFHDS2(); void processInternalFlySkyTelemetryData(uint8_t byte, uint8_t* buffer, uint8_t* len); diff --git a/radio/src/pulses/ghost.cpp b/radio/src/pulses/ghost.cpp index bc8c5c228..56efac5f2 100755 --- a/radio/src/pulses/ghost.cpp +++ b/radio/src/pulses/ghost.cpp @@ -20,10 +20,28 @@ */ #include "opentx.h" +#include "ghost.h" #include "telemetry/ghost.h" #include "telemetry/ghost_menu.h" +#include "hal/module_port.h" +#include "mixer_scheduler.h" -uint8_t createGhostMenuControlFrame(uint8_t * frame, int16_t * pulses) +static uint8_t getGhostModuleAddr() +{ +// TODO: check if asymmetric baudrate is really needed +// as it introduces a lot of clutter +// +// #if SPORT_MAX_BAUDRATE < 400000 +// return g_model.moduleData[EXTERNAL_MODULE].ghost.telemetryBaudrate == +// GHST_TELEMETRY_RATE_400K +// ? GHST_ADDR_MODULE_SYM +// : GHST_ADDR_MODULE_ASYM; +// #else + return GHST_ADDR_MODULE_SYM; +// #endif +} + +static uint8_t createGhostMenuControlFrame(uint8_t * frame, int16_t * pulses) { uint8_t * buf = frame; @@ -46,7 +64,7 @@ uint8_t createGhostMenuControlFrame(uint8_t * frame, int16_t * pulses) } // Range for pulses (channels output) is [-1024:+1024] -uint8_t createGhostChannelsFrame(uint8_t * frame, int16_t * pulses, bool raw12bits) +static uint8_t createGhostChannelsFrame(uint8_t * frame, int16_t * pulses, bool raw12bits) { static uint8_t lastGhostFrameId = 0; uint8_t ghostUpper4Offset = 0; @@ -88,10 +106,16 @@ uint8_t createGhostChannelsFrame(uint8_t * frame, int16_t * pulses, bool raw12bi uint8_t bitsavailable = 0; for (int i = 0; i < 4; i++) { uint32_t value; - if(raw12bits) { - value = limit(0, (1024 + (pulses[i] + 2 * PPM_CH_CENTER(i) - 2 * PPM_CENTER)) << 1, 0xFFF); + if (raw12bits) { + value = limit( + 0, (1024 + (pulses[i] + 2 * PPM_CH_CENTER(i) - 2 * PPM_CENTER)) << 1, + 0xFFF); } else { - value = limit(0, GHST_RC_CTR_VAL_12BIT + (((pulses[i] + 2 * PPM_CH_CENTER(i) - 2 * PPM_CENTER) << 3) / 5), 2 * GHST_RC_CTR_VAL_12BIT); + value = limit( + 0, + GHST_RC_CTR_VAL_12BIT + + (((pulses[i] + 2 * PPM_CH_CENTER(i) - 2 * PPM_CENTER) << 3) / 5), + 2 * GHST_RC_CTR_VAL_12BIT); } bits |= value << bitsavailable; bitsavailable += GHST_CH_BITS_12; @@ -106,10 +130,20 @@ uint8_t createGhostChannelsFrame(uint8_t * frame, int16_t * pulses, bool raw12bi for (int i = 4; i < 8; ++i) { uint8_t channelIndex = i + ghostUpper4Offset; uint8_t value; - if(raw12bits) { - value = limit(0, 128 + ((pulses[channelIndex] + 2 * PPM_CH_CENTER(channelIndex) - 2 * PPM_CENTER) >> 3), 0xFF); + if (raw12bits) { + value = limit(0, + 128 + ((pulses[channelIndex] + + 2 * PPM_CH_CENTER(channelIndex) - 2 * PPM_CENTER) >> + 3), + 0xFF); } else { - value = limit(0, GHST_RC_CTR_VAL_8BIT + (((pulses[channelIndex] + 2 * PPM_CH_CENTER(channelIndex) - 2 * PPM_CENTER) >> 1) / 5), 2 * GHST_RC_CTR_VAL_8BIT); + value = limit(0, + GHST_RC_CTR_VAL_8BIT + + (((pulses[channelIndex] + + 2 * PPM_CH_CENTER(channelIndex) - 2 * PPM_CENTER) >> + 1) / + 5), + 2 * GHST_RC_CTR_VAL_8BIT); } *buf++ = value; } @@ -120,25 +154,102 @@ uint8_t createGhostChannelsFrame(uint8_t * frame, int16_t * pulses, bool raw12bi return buf - frame; } -void setupPulsesGhost() +static const etx_serial_init ghostSerialParams = { + .baudrate = GHOST_BAUDRATE, + .encoding = ETX_Encoding_8N1, + .direction = ETX_Dir_TX_RX, + .polarity = ETX_Pol_Normal, +}; + +static void* ghostInit(uint8_t module) { - if (telemetryProtocol == PROTOCOL_TELEMETRY_GHOST) { + auto mod_st = modulePortInitSerial(module, ETX_MOD_PORT_SPORT, &ghostSerialParams); + if (!mod_st) return nullptr; - auto &module = g_model.moduleData[EXTERNAL_MODULE]; - auto *p_data = &extmodulePulsesData.ghost; + mixerSchedulerSetPeriod(module, GHOST_PERIOD); + return mod_st; +} - #if defined(LUA) - if (outputTelemetryBuffer.destination == TELEMETRY_ENDPOINT_SPORT) { - memcpy(p_data->pulses, outputTelemetryBuffer.data, outputTelemetryBuffer.size); - p_data->length = outputTelemetryBuffer.size; - outputTelemetryBuffer.reset(); - } else - #endif - if (moduleState[EXTERNAL_MODULE].counter == GHST_MENU_CONTROL) { - p_data->length = createGhostMenuControlFrame(p_data->pulses, &channelOutputs[module.channelsStart]); - } else { - p_data->length = createGhostChannelsFrame(p_data->pulses, &channelOutputs[module.channelsStart], module.ghost.raw12bits); +static void ghostDeInit(void* ctx) +{ + auto mod_st = (etx_module_state_t*)ctx; + modulePortDeInit(mod_st); +} + +static void ghostSendPulses(void* ctx, uint8_t* buffer, int16_t* channels, uint8_t nChannels) +{ + auto mod_st = (etx_module_state_t*)ctx; + auto module = modulePortGetModule(mod_st); + + ModuleSyncStatus& status = getModuleSyncStatus(module); + if (status.isValid()) { + mixerSchedulerSetPeriod(module, status.getAdjustedRefreshRate()); + } else { + mixerSchedulerSetPeriod(module, GHOST_PERIOD); + } + + const auto& mod_cfg = g_model.moduleData[module].ghost; + auto p_data = buffer; + +#if defined(LUA) + if (outputTelemetryBuffer.destination == TELEMETRY_ENDPOINT_SPORT) { + auto len = outputTelemetryBuffer.size; + auto f_data = outputTelemetryBuffer.data; + while (len >= 12) { // type(1B) + payload(10B) + crc(1B) + // insert address byte + *p_data++ = getGhostModuleAddr(); + // and length + *p_data++ = 12; + memcpy(p_data, f_data, 12); + p_data += 12; f_data += 12; + len -= 12; + } + outputTelemetryBuffer.reset(); + } else +#endif + if (moduleState[module].counter == GHST_MENU_CONTROL) { + p_data += createGhostMenuControlFrame(p_data, channels); + } else { + p_data += createGhostChannelsFrame(p_data, channels, mod_cfg.raw12bits); + } + + moduleState[module].counter = GHST_FRAME_CHANNEL; + + auto drv = modulePortGetSerialDrv(mod_st->tx); + auto drv_ctx = modulePortGetCtx(mod_st->tx); + drv->sendBuffer(drv_ctx, buffer, p_data - buffer); +} + +static void ghostProcessData(void* ctx, uint8_t data, uint8_t* buffer, uint8_t* len) +{ + if (*len == 0 && data != GHST_ADDR_RADIO) { + TRACE("[GH] address 0x%02X error", data); + return; + } + + if (*len < TELEMETRY_RX_PACKET_SIZE) { + buffer[(*len)++] = data; + } + else { + TRACE("[GH] array size %d error", *len); + *len = 0; + } + + if (*len > 4) { + uint8_t length = buffer[1]; + if (length + 2 == *len) { + auto mod_st = (etx_module_state_t*)ctx; + auto module = modulePortGetModule(mod_st); + processGhostTelemetryFrame(module, buffer, *len); + *len = 0; } - moduleState[EXTERNAL_MODULE].counter = GHST_FRAME_CHANNEL; } } + +const etx_proto_driver_t GhostDriver = { + .protocol = PROTOCOL_CHANNELS_GHOST, + .init = ghostInit, + .deinit = ghostDeInit, + .sendPulses = ghostSendPulses, + .processData = ghostProcessData, +}; diff --git a/radio/src/targets/common/arm/stm32/intmodule_serial_driver.h b/radio/src/pulses/ghost.h similarity index 83% rename from radio/src/targets/common/arm/stm32/intmodule_serial_driver.h rename to radio/src/pulses/ghost.h index 4ee4a63f9..f5d2570ba 100644 --- a/radio/src/targets/common/arm/stm32/intmodule_serial_driver.h +++ b/radio/src/pulses/ghost.h @@ -21,9 +21,6 @@ #pragma once -#include -#include "hal/serial_driver.h" +#include "hal/module_driver.h" -#define INTMODULE_USART_IRQ_PRIORITY 6 - -extern const etx_serial_driver_t IntmoduleSerialDriver; +extern const etx_proto_driver_t GhostDriver; diff --git a/radio/src/pulses/modules_helpers.h b/radio/src/pulses/modules_helpers.h index 56afef957..237d1343b 100644 --- a/radio/src/pulses/modules_helpers.h +++ b/radio/src/pulses/modules_helpers.h @@ -43,6 +43,10 @@ extern uint32_t NV14internalModuleFwVersion; #define CROSSFIRE_CHANNELS_COUNT 16 #define GHOST_CHANNELS_COUNT 16 +#define IS_NATIVE_FRSKY_PROTOCOL(module) \ + ((moduleState[module].protocol == PROTOCOL_CHANNELS_PXX1) || \ + (moduleState[module].protocol == PROTOCOL_CHANNELS_PXX2)) + #if defined (MULTIMODULE) #define IS_D16_MULTI(module) \ ((g_model.moduleData[module].multi.rfProtocol == MODULE_SUBTYPE_MULTI_FRSKYX) || \ @@ -71,32 +75,15 @@ extern uint32_t NV14internalModuleFwVersion; (g_model.moduleData[module].multi.rfProtocol == \ MODULE_SUBTYPE_MULTI_DSM_RX)) -#if defined(HARDWARE_INTERNAL_MODULE) -#define IS_FRSKY_SPORT_PROTOCOL() \ - (telemetryProtocol == PROTOCOL_TELEMETRY_FRSKY_SPORT || \ - (telemetryProtocol == PROTOCOL_TELEMETRY_MULTIMODULE && \ - (IS_D16_MULTI(INTERNAL_MODULE) || IS_D16_MULTI(EXTERNAL_MODULE) || \ - IS_R9_MULTI(INTERNAL_MODULE) || IS_R9_MULTI(EXTERNAL_MODULE)))) -#else -#define IS_FRSKY_SPORT_PROTOCOL() \ - (telemetryProtocol == PROTOCOL_TELEMETRY_FRSKY_SPORT || \ - (telemetryProtocol == PROTOCOL_TELEMETRY_MULTIMODULE && \ - (IS_D16_MULTI(EXTERNAL_MODULE) || IS_R9_MULTI(EXTERNAL_MODULE)))) -#endif - #else #define IS_D16_MULTI(module) false #define IS_R9_MULTI(module) false #define IS_HOTT_MULTI(module) false #define IS_CONFIG_MULTI(module) false #define IS_DSM_MULTI(module) false - #define IS_FRSKY_SPORT_PROTOCOL() (telemetryProtocol == PROTOCOL_TELEMETRY_FRSKY_SPORT) #define IS_RX_MULTI(module) false #endif -#define IS_SPEKTRUM_PROTOCOL() (telemetryProtocol == PROTOCOL_TELEMETRY_SPEKTRUM) - - #if defined(MULTIMODULE) // When using packed, the pointer in here end up not being aligned, which clang and gcc complain about // Keep the order of the fields that the so that the size stays small @@ -726,6 +713,7 @@ inline bool isTelemAllowedOnBind(uint8_t moduleIndex) return false; #endif +#if defined(HARDWARE_EXTERNAL_MODULE) if (g_model.moduleData[EXTERNAL_MODULE].type == MODULE_TYPE_R9M_LITE_PXX1) { if (isModuleR9M_LBT(EXTERNAL_MODULE)) return g_model.moduleData[EXTERNAL_MODULE].pxx.power < R9M_LITE_LBT_POWER_100_16CH_NOTELEM; @@ -739,6 +727,7 @@ inline bool isTelemAllowedOnBind(uint8_t moduleIndex) else return true; } +#endif return true; } diff --git a/radio/src/pulses/multi.cpp b/radio/src/pulses/multi.cpp index 0bdfed313..2550f23e6 100644 --- a/radio/src/pulses/multi.cpp +++ b/radio/src/pulses/multi.cpp @@ -41,37 +41,28 @@ #define MULTI_FAILSAFE 0x01 #define MULTI_DATA 0x02 -static void sendFrameProtocolHeader(uint8_t moduleIdx, bool failsafe); -void sendChannels(uint8_t moduleIdx); -static void sendD16BindOption(uint8_t moduleIdx); +static void sendFrameProtocolHeader(uint8_t*& p_buf, uint8_t module, bool failsafe); +static void sendChannels(uint8_t*& p_buf, uint8_t module); +static void sendD16BindOption(uint8_t*& p_buf, uint8_t module); #if defined(LUA) -static void sendSport(uint8_t moduleIdx); -static void sendHott(uint8_t moduleIdx); -static void sendConfig(uint8_t moduleIdx); -static void sendDSM(uint8_t moduleIdx); +static void sendSport(uint8_t*& p_buf, uint8_t module); +static void sendHott(uint8_t*& p_buf, uint8_t module); +static void sendConfig(uint8_t*& p_buf, uint8_t module); +static void sendDSM(uint8_t*& p_buf, uint8_t module); #endif -#if defined(INTMODULE_USART) && defined(INTERNAL_MODULE_MULTI) -#include "intmodule_serial_driver.h" +#include "hal/module_port.h" etx_serial_init multiSerialInitParams = { .baudrate = MULTIMODULE_BAUDRATE, - .parity = ETX_Parity_Even, - .stop_bits = ETX_StopBits_Two, - .word_length = ETX_WordLength_9, - .rx_enable = true, + .encoding = ETX_Encoding_8E2, + .direction = ETX_Dir_TX, + .polarity = ETX_Pol_Normal, }; -#endif -static void sendMulti(uint8_t moduleIdx, uint8_t b) +static inline void sendMulti(uint8_t*& p_buf, uint8_t b) { -#if defined(INTERNAL_MODULE_MULTI) - if (moduleIdx == INTERNAL_MODULE) { - intmodulePulsesData.multi.sendByte(b); - } - else -#endif - sendByteSbus(b); + *p_buf++ = b; } static void updateMultiSync(uint8_t module) @@ -88,7 +79,7 @@ static void updateMultiSync(uint8_t module) } } -static void sendFailsafeChannels(uint8_t moduleIdx) +static void sendFailsafeChannels(uint8_t*& p_buf, uint8_t module) { uint32_t bits = 0; uint8_t bitsavailable = 0; @@ -97,16 +88,16 @@ static void sendFailsafeChannels(uint8_t moduleIdx) int16_t failsafeValue = g_model.failsafeChannels[i]; int pulseValue; - if (g_model.moduleData[moduleIdx].failsafeMode == FAILSAFE_HOLD || + if (g_model.moduleData[module].failsafeMode == FAILSAFE_HOLD || failsafeValue == FAILSAFE_CHANNEL_HOLD) { pulseValue = 2047; - } else if (g_model.moduleData[moduleIdx].failsafeMode == + } else if (g_model.moduleData[module].failsafeMode == FAILSAFE_NOPULSES || failsafeValue == FAILSAFE_CHANNEL_NOPULSE) { pulseValue = 0; } else { failsafeValue += - 2 * PPM_CH_CENTER(g_model.moduleData[moduleIdx].channelsStart + i) - + 2 * PPM_CH_CENTER(g_model.moduleData[module].channelsStart + i) - 2 * PPM_CENTER; pulseValue = limit(1, (failsafeValue * 800 / 1000) + 1024, 2046); } @@ -114,14 +105,14 @@ static void sendFailsafeChannels(uint8_t moduleIdx) bits |= pulseValue << bitsavailable; bitsavailable += MULTI_CHAN_BITS; while (bitsavailable >= 8) { - sendMulti(moduleIdx, (uint8_t) (bits & 0xff)); + sendMulti(p_buf, (uint8_t) (bits & 0xff)); bits >>= 8; bitsavailable -= 8; } } } -void setupPulsesMulti(uint8_t moduleIdx) +static void setupPulsesMulti(uint8_t*& p_buf, uint8_t module) { static int counter[2] = {0,0}; //TODO static uint8_t invert[2] = {0x00, //internal @@ -133,165 +124,177 @@ void setupPulsesMulti(uint8_t moduleIdx) }; uint8_t type=MULTI_NORMAL; - updateMultiSync(moduleIdx); + updateMultiSync(module); // not scanning protos && not spectrum analyser - if (getModuleMode(moduleIdx) == MODULE_MODE_NORMAL) { + if (getModuleMode(module) == MODULE_MODE_NORMAL) { // Failsafe packets - if (counter[moduleIdx] % 1000 == 0 && - g_model.moduleData[moduleIdx].failsafeMode != FAILSAFE_NOT_SET && - g_model.moduleData[moduleIdx].failsafeMode != FAILSAFE_RECEIVER) { + if (counter[module] % 1000 == 0 && + g_model.moduleData[module].failsafeMode != FAILSAFE_NOT_SET && + g_model.moduleData[module].failsafeMode != FAILSAFE_RECEIVER) { type |= MULTI_FAILSAFE; } - counter[moduleIdx]++; + counter[module]++; } // Invert telemetry if needed - if (invert[moduleIdx] & 0x80 && - !g_model.moduleData[moduleIdx].multi.disableTelemetry) { - if (getMultiModuleStatus(moduleIdx).isValid()) { - invert[moduleIdx] &= 0x08; // Telemetry received, stop searching - } else if (counter[moduleIdx] % 100 == 0) { - invert[moduleIdx] ^= 0x08; // Try inverting telemetry + if (invert[module] & 0x80 && + !g_model.moduleData[module].multi.disableTelemetry) { + if (getMultiModuleStatus(module).isValid()) { + invert[module] &= 0x08; // Telemetry received, stop searching + } else if (counter[module] % 100 == 0) { + invert[module] ^= 0x08; // Try inverting telemetry } } // Send header - sendFrameProtocolHeader(moduleIdx, type & MULTI_FAILSAFE); + sendFrameProtocolHeader(p_buf, module, type & MULTI_FAILSAFE); // Send channels if (type & MULTI_FAILSAFE) - sendFailsafeChannels(moduleIdx); + sendFailsafeChannels(p_buf, module); else - sendChannels(moduleIdx); + sendChannels(p_buf, module); // Multi V1.3.X.X -> Send byte 26, Protocol (bits 7 & 6), RX_Num (bits 5 & 4), invert, not used, disable telemetry, disable mapping - if ((moduleState[moduleIdx].mode == MODULE_MODE_SPECTRUM_ANALYSER) + if (moduleState[module].mode == MODULE_MODE_SPECTRUM_ANALYSER #if defined(MULTI_PROTOLIST) - || (moduleState[moduleIdx].mode == MODULE_MODE_GET_HARDWARE_INFO) + || moduleState[module].mode == MODULE_MODE_GET_HARDWARE_INFO #endif ) { - sendMulti(moduleIdx, invert[moduleIdx] & 0x08); + sendMulti(p_buf, invert[module] & 0x08); } else { - sendMulti(moduleIdx, (uint8_t) (((g_model.moduleData[moduleIdx].multi.rfProtocol + 3) & 0xC0) - | (g_model.header.modelId[moduleIdx] & 0x30) - | (invert[moduleIdx] & 0x08) - //| 0x04 // Future use - | (g_model.moduleData[moduleIdx].multi.disableTelemetry << 1) - | g_model.moduleData[moduleIdx].multi.disableMapping)); + sendMulti(p_buf, (uint8_t) (((g_model.moduleData[module].multi.rfProtocol + 3) & 0xC0) + | (g_model.header.modelId[module] & 0x30) + | (invert[module] & 0x08) + //| 0x04 // Future use + | (g_model.moduleData[module].multi.disableTelemetry << 1) + | g_model.moduleData[module].multi.disableMapping)); } // Multi V1.3.X.X -> Send protocol additional data: max 9 bytes - if (getMultiModuleStatus(moduleIdx).isValid()) { - MultiModuleStatus &status = getMultiModuleStatus(moduleIdx); + if (getMultiModuleStatus(module).isValid()) { + MultiModuleStatus &status = getMultiModuleStatus(module); if (status.minor >= 3 && !(status.flags & 0x80)) { //Version 1.3.x.x or more and Buffer not full - if ((IS_D16_MULTI(moduleIdx) || IS_R9_MULTI(moduleIdx)) && moduleState[moduleIdx].mode == MODULE_MODE_BIND) { - sendD16BindOption(moduleIdx);//1 byte of additional data + if ((IS_D16_MULTI(module) || IS_R9_MULTI(module)) && moduleState[module].mode == MODULE_MODE_BIND) { + sendD16BindOption(p_buf, module);//1 byte of additional data } #if defined(LUA) // SPort send - if (IS_D16_MULTI(moduleIdx) && outputTelemetryBuffer.destination == TELEMETRY_ENDPOINT_SPORT && outputTelemetryBuffer.size) { - sendSport(moduleIdx); //8 bytes of additional data + if (IS_D16_MULTI(module) && outputTelemetryBuffer.destination == TELEMETRY_ENDPOINT_SPORT && outputTelemetryBuffer.size) { + sendSport(p_buf, module); //8 bytes of additional data } - else if (IS_HOTT_MULTI(moduleIdx)) { - sendHott(moduleIdx); //1 byte of additional data + else if (IS_HOTT_MULTI(module)) { + sendHott(p_buf, module); //1 byte of additional data } - else if (IS_CONFIG_MULTI(moduleIdx)) { - sendConfig(moduleIdx); //7 bytes of additional data + else if (IS_CONFIG_MULTI(module)) { + sendConfig(p_buf, module); //7 bytes of additional data } - else if (IS_DSM_MULTI(moduleIdx)) { - sendDSM(moduleIdx); //7 bytes of additional data + else if (IS_DSM_MULTI(module)) { + sendDSM(p_buf, module); //7 bytes of additional data } #endif } } } -void setupPulsesMultiExternalModule() -{ - extmodulePulsesData.dsm2.index = 0; - extmodulePulsesData.dsm2.ptr = extmodulePulsesData.dsm2.pulses; - - setupPulsesMulti(EXTERNAL_MODULE); - putDsm2Flush(); -} - -#if defined(INTERNAL_MODULE_MULTI) static void* multiInit(uint8_t module) { - (void)module; - - // serial port setup - intmodulePulsesData.multi.initFrame(); - void* uart_ctx = IntmoduleSerialDriver.init(&multiSerialInitParams); + etx_module_state_t* mod_st = nullptr; + etx_serial_init cfg(multiSerialInitParams); +#if defined(INTERNAL_MODULE_MULTI) + if (module == INTERNAL_MODULE) { + // serial port setup + // TODO: error handling + cfg.direction = ETX_Dir_TX_RX; + mod_st = modulePortInitSerial(module, ETX_MOD_PORT_UART, &cfg); + } +#endif + +#if defined(HARDWARE_EXTERNAL_MODULE) + if (module == EXTERNAL_MODULE) { + // serial port setup + cfg.direction = ETX_Dir_TX; + cfg.polarity = ETX_Pol_Inverted; + mod_st = modulePortInitSerial(module, ETX_MOD_PORT_UART, &cfg); + + if (!mod_st) { + cfg.polarity = ETX_Pol_Normal; + mod_st = modulePortInitSerial(module, ETX_MOD_PORT_SOFT_INV, &cfg); + } + + // no TX port: bail out + if (!mod_st) return nullptr; + + // Init S.PORT RX channel + cfg.direction = ETX_Dir_RX; + cfg.polarity = ETX_Pol_Normal; + modulePortInitSerial(module, ETX_MOD_PORT_SPORT, &cfg); + } +#endif + + if (!mod_st) return nullptr; + // mixer setup - mixerSchedulerSetPeriod(INTERNAL_MODULE, MULTIMODULE_PERIOD); - INTERNAL_MODULE_ON(); + mixerSchedulerSetPeriod(module, MULTIMODULE_PERIOD); // reset status - getMultiModuleStatus(INTERNAL_MODULE).failsafeChecked = false; - getMultiModuleStatus(INTERNAL_MODULE).flags = 0; + getMultiModuleStatus(module).failsafeChecked = false; + getMultiModuleStatus(module).flags = 0; #if defined(MULTI_PROTOLIST) TRACE("enablePulsesInternalModule(): trigger scan"); - MultiRfProtocols::instance(INTERNAL_MODULE)->triggerScan(); - TRACE("counter = %d", moduleState[INTERNAL_MODULE].counter); + MultiRfProtocols::instance(module)->triggerScan(); #endif - return uart_ctx; + return mod_st; } -static void multiDeInit(void* context) +static void multiDeInit(void* ctx) { - INTERNAL_MODULE_OFF(); - mixerSchedulerSetPeriod(INTERNAL_MODULE, 0); - IntmoduleSerialDriver.deinit(context); + auto mod_st = (etx_module_state_t*)ctx; + modulePortDeInit(mod_st); } -static void multiSetupPulses(void* context, int16_t* channels, uint8_t nChannels) +static void multiSendPulses(void* ctx, uint8_t* buffer, int16_t* channels, uint8_t nChannels) { - (void)context; // TODO: (void)channels; (void)nChannels; - - intmodulePulsesData.multi.initFrame(); - setupPulsesMulti(INTERNAL_MODULE); + + auto mod_st = (etx_module_state_t*)ctx; + auto module = modulePortGetModule(mod_st); + + auto data = buffer; + setupPulsesMulti(data, module); + + auto drv = modulePortGetSerialDrv(mod_st->tx); + auto drv_ctx = modulePortGetCtx(mod_st->tx); + drv->sendBuffer(drv_ctx, buffer, data - buffer); } -static void multiSendPulses(void* context) +static void multiProcessData(void* ctx, uint8_t data, uint8_t* buffer, uint8_t* len) { - IntmoduleSerialDriver.sendBuffer(context, intmodulePulsesData.multi.getData(), - intmodulePulsesData.multi.getSize()); -} + auto mod_st = (etx_module_state_t*)ctx; + auto module = modulePortGetModule(mod_st); -static int multiGetByte(void* context, uint8_t* data) -{ - return IntmoduleSerialDriver.getByte(context, data); -} - -static void multiProcessData(void* context, uint8_t data, uint8_t* buffer, uint8_t* len) -{ - processMultiTelemetryData(data, INTERNAL_MODULE); + processMultiTelemetryData(data, module); } #include "hal/module_driver.h" -const etx_module_driver_t MultiInternalDriver = { +const etx_proto_driver_t MultiDriver = { .protocol = PROTOCOL_CHANNELS_MULTIMODULE, .init = multiInit, .deinit = multiDeInit, - .setupPulses = multiSetupPulses, .sendPulses = multiSendPulses, - .getByte = multiGetByte, .processData = multiProcessData, }; -#endif -void sendChannels(uint8_t moduleIdx) +static void sendChannels(uint8_t*& p_buf, uint8_t module) { uint32_t bits = 0; uint8_t bitsavailable = 0; @@ -300,7 +303,7 @@ void sendChannels(uint8_t moduleIdx) // Range for pulses (channelsOutputs) is [-1024:+1024] for [-100%;100%] // Multi uses [204;1843] as [-100%;100%] for (int i = 0; i < MULTI_CHANS; i++) { - int channel = g_model.moduleData[moduleIdx].channelsStart + i; + int channel = g_model.moduleData[module].channelsStart + i; int value = channelOutputs[channel] + 2 * PPM_CH_CENTER(channel) - 2 * PPM_CENTER; // Scale to 80% @@ -310,42 +313,42 @@ void sendChannels(uint8_t moduleIdx) bits |= value << bitsavailable; bitsavailable += MULTI_CHAN_BITS; while (bitsavailable >= 8) { - sendMulti(moduleIdx, (uint8_t) (bits & 0xff)); + sendMulti(p_buf, (uint8_t) (bits & 0xff)); bits >>= 8; bitsavailable -= 8; } } } -void sendFrameProtocolHeader(uint8_t moduleIdx, bool failsafe) +void sendFrameProtocolHeader(uint8_t*& p_buf, uint8_t module, bool failsafe) {// byte 1+2, protocol information // Our enumeration starts at 0 - int type = g_model.moduleData[moduleIdx].multi.rfProtocol + 1; - int subtype = g_model.moduleData[moduleIdx].subType; - int8_t optionValue = g_model.moduleData[moduleIdx].multi.optionValue; + int type = g_model.moduleData[module].multi.rfProtocol + 1; + int subtype = g_model.moduleData[module].subType; + int8_t optionValue = g_model.moduleData[module].multi.optionValue; uint8_t protoByte = 0; - uint8_t moduleMode = getModuleMode(moduleIdx); + uint8_t moduleMode = getModuleMode(module); if (moduleMode == MODULE_MODE_SPECTRUM_ANALYSER) { - sendMulti(moduleIdx, (uint8_t) 0x54); // Header byte - sendMulti(moduleIdx, (uint8_t) 54); // Spectrum custom protocol - sendMulti(moduleIdx, (uint8_t) 0); - sendMulti(moduleIdx, (uint8_t) 0); + sendMulti(p_buf, (uint8_t) 0x54); // Header byte + sendMulti(p_buf, (uint8_t) 54); // Spectrum custom protocol + sendMulti(p_buf, (uint8_t) 0); + sendMulti(p_buf, (uint8_t) 0); return; } #if defined(MULTI_PROTOLIST) if (moduleMode == MODULE_MODE_GET_HARDWARE_INFO) { - sendMulti(moduleIdx, (uint8_t) 0x55); // Header byte - sendMulti(moduleIdx, (uint8_t) 0); // PROTOLIST custom protocol - sendMulti(moduleIdx, (uint8_t) 0); + sendMulti(p_buf, (uint8_t) 0x55); // Header byte + sendMulti(p_buf, (uint8_t) 0); // PROTOLIST custom protocol + sendMulti(p_buf, (uint8_t) 0); // proto array item - uint8_t protoIdx = MultiRfProtocols::instance(moduleIdx)->getScanProto(); + uint8_t protoIdx = MultiRfProtocols::instance(module)->getScanProto(); TRACE("scan [%d]", protoIdx); - sendMulti(moduleIdx, protoIdx); + sendMulti(p_buf, protoIdx); return; } #endif @@ -362,19 +365,19 @@ void sendFrameProtocolHeader(uint8_t moduleIdx, bool failsafe) optionValue = 0x80; // Max throw else optionValue = 0x00; - if (g_model.moduleData[moduleIdx].multi.optionValue & 0x02) + if (g_model.moduleData[module].multi.optionValue & 0x02) optionValue |= 0x40; // 11ms servo refresh - optionValue |= sentModuleChannels(moduleIdx); //add number of channels + optionValue |= sentModuleChannels(module); //add number of channels } // Set the highest bit of option byte in AFHDS2A protocol to instruct MULTI to passthrough telemetry bytes instead // of sending Frsky D telemetry - if (g_model.moduleData[moduleIdx].multi.rfProtocol == MODULE_SUBTYPE_MULTI_FS_AFHDS2A) + if (g_model.moduleData[module].multi.rfProtocol == MODULE_SUBTYPE_MULTI_FS_AFHDS2A) optionValue = optionValue | 0x80; // For custom protocol send unmodified type byte - if (g_model.moduleData[moduleIdx].multi.rfProtocol == MM_RF_CUSTOM_SELECTED) - type = g_model.moduleData[moduleIdx].multi.rfProtocol; + if (g_model.moduleData[module].multi.rfProtocol == MM_RF_CUSTOM_SELECTED) + type = g_model.moduleData[module].multi.rfProtocol; uint8_t headerByte = 0x55; // header, byte 0, 0x55 for proto 0-31, 0x54 for proto 32-63 @@ -384,34 +387,34 @@ void sendFrameProtocolHeader(uint8_t moduleIdx, bool failsafe) if (failsafe) headerByte |= 0x02; - sendMulti(moduleIdx, headerByte); + sendMulti(p_buf, headerByte); // protocol byte protoByte |= (type & 0x1f); - if (g_model.moduleData[moduleIdx].multi.rfProtocol != MODULE_SUBTYPE_MULTI_DSM2) - protoByte |= (g_model.moduleData[moduleIdx].multi.autoBindMode << 6); + if (g_model.moduleData[module].multi.rfProtocol != MODULE_SUBTYPE_MULTI_DSM2) + protoByte |= (g_model.moduleData[module].multi.autoBindMode << 6); - sendMulti(moduleIdx, protoByte); + sendMulti(p_buf, protoByte); // byte 2, subtype, powermode, model id - sendMulti(moduleIdx, (uint8_t) ((g_model.header.modelId[moduleIdx] & 0x0f) + sendMulti(p_buf, (uint8_t) ((g_model.header.modelId[module] & 0x0f) | ((subtype & 0x7) << 4) - | (g_model.moduleData[moduleIdx].multi.lowPowerMode << 7)) + | (g_model.moduleData[module].multi.lowPowerMode << 7)) ); // byte 3 - sendMulti(moduleIdx, (uint8_t) optionValue); + sendMulti(p_buf, (uint8_t) optionValue); } -void sendD16BindOption(uint8_t moduleIdx) +void sendD16BindOption(uint8_t*& p_buf, uint8_t module) { - uint8_t bind_opt = g_model.moduleData[moduleIdx].multi.receiverTelemetryOff ? 1 : 0; - bind_opt |= g_model.moduleData[moduleIdx].multi.receiverHigherChannels ? 2 : 0; - sendMulti(moduleIdx, bind_opt); + uint8_t bind_opt = g_model.moduleData[module].multi.receiverTelemetryOff ? 1 : 0; + bind_opt |= g_model.moduleData[module].multi.receiverHigherChannels ? 2 : 0; + sendMulti(p_buf, bind_opt); } #if defined(LUA) -void sendSport(uint8_t moduleIdx) +void sendSport(uint8_t*& p_buf, uint8_t module) { // example: B7 30 30 0C 80 00 00 00 13 uint8_t j=0; @@ -420,25 +423,25 @@ void sendSport(uint8_t moduleIdx) for (uint8_t i = 0; i < outputTelemetryBuffer.size - 1 && j < 8; i++, j++) { if (outputTelemetryBuffer.data[i] == BYTE_STUFF) { i++; - sendMulti(moduleIdx, outputTelemetryBuffer.data[i] ^ STUFF_MASK); + sendMulti(p_buf, outputTelemetryBuffer.data[i] ^ STUFF_MASK); } else { - sendMulti(moduleIdx, outputTelemetryBuffer.data[i]); + sendMulti(p_buf, outputTelemetryBuffer.data[i]); } } outputTelemetryBuffer.reset(); // empty buffer } -void sendHott(uint8_t moduleIdx) +void sendHott(uint8_t*& p_buf, uint8_t module) { if (Multi_Buffer && memcmp(Multi_Buffer, "HoTT", 4) == 0 && (Multi_Buffer[5] & 0x80) && (Multi_Buffer[5] & 0x0F) >= 0x07) { // HoTT Lua script is running - sendMulti(moduleIdx, Multi_Buffer[5]); + sendMulti(p_buf, Multi_Buffer[5]); } } -void sendConfig(uint8_t moduleIdx) +void sendConfig(uint8_t*& p_buf, uint8_t module) { // Multi_Buffer[0..3]=="Conf" -> Lua script is running // Multi_Buffer[4]==0x01 -> TX to Module data ready to be sent @@ -449,13 +452,13 @@ void sendConfig(uint8_t moduleIdx) if (Multi_Buffer && memcmp(Multi_Buffer, "Conf", 4) == 0 && Multi_Buffer[4] == 0x01) { // Config Lua script is running and sending for (uint8_t i = 0; i < 7; i++) { - sendMulti(moduleIdx, Multi_Buffer[5 + i]); + sendMulti(p_buf, Multi_Buffer[5 + i]); } Multi_Buffer[4] = 0x00; // Send data only once } } -void sendDSM(uint8_t moduleIdx) +void sendDSM(uint8_t*& p_buf, uint8_t module) { // Multi_Buffer[0..2]=="DSM" -> Lua script is running // Multi_Buffer[3]==0x70 + len -> TX to RX data ready to be sent @@ -463,7 +466,7 @@ void sendDSM(uint8_t moduleIdx) // Multi_Buffer[10..25]=16 bytes of RX to TX data if (Multi_Buffer && memcmp(Multi_Buffer, "DSM", 3) == 0 && (Multi_Buffer[3] & 0xF8) == 0x70) { for(uint8_t i = 0; i < 7; i++) { - sendMulti(moduleIdx, Multi_Buffer[3+i]); + sendMulti(p_buf, Multi_Buffer[3+i]); } Multi_Buffer[3] = 0x00; // Data sent } diff --git a/radio/src/pulses/multi.h b/radio/src/pulses/multi.h index ada4cf03b..9bed85e9c 100644 --- a/radio/src/pulses/multi.h +++ b/radio/src/pulses/multi.h @@ -19,8 +19,7 @@ * GNU General Public License for more details. */ -#ifndef _MULTI_PULSES_H_ -#define _MULTI_PULSES_H_ +#pragma once #include "pulses_common.h" #include "hal/serial_driver.h" @@ -41,7 +40,4 @@ class UartMultiPulses: public DataBuffer } }; -extern etx_serial_init multiSerialInitParams; -extern const etx_module_driver_t MultiInternalDriver; - -#endif +extern const etx_proto_driver_t MultiDriver; diff --git a/radio/src/pulses/ppm.cpp b/radio/src/pulses/ppm.cpp index ea282bf2e..115404365 100644 --- a/radio/src/pulses/ppm.cpp +++ b/radio/src/pulses/ppm.cpp @@ -21,14 +21,17 @@ #include +#include "ppm.h" +#include "hal/module_port.h" +#include "mixer_scheduler.h" + #include "opentx.h" // Minimum space after the last PPM pulse in us #define PPM_SAFE_MARGIN 3000 // 3ms template -uint16_t setupPulsesPPM(PpmPulsesData* ppmPulsesData, uint8_t channelsStart, - int8_t channelsCount) +uint16_t setupPulsesPPM(T*& data, uint8_t channelsStart, int8_t channelsCount) { uint16_t total = 0; int16_t PPM_range = g_model.extendedLimits ? @@ -40,16 +43,13 @@ uint16_t setupPulsesPPM(PpmPulsesData* ppmPulsesData, uint8_t channelsStart, // The pulse ISR is 2mhz that's why everything is multiplied by 2 uint8_t firstCh = channelsStart; - uint8_t lastCh = - min(MAX_OUTPUT_CHANNELS, firstCh + 8 + channelsCount); - - ppmPulsesData->ptr = ppmPulsesData->pulses; + uint8_t lastCh = min(MAX_OUTPUT_CHANNELS, firstCh + 8 + channelsCount); for (uint32_t i = firstCh; i < lastCh; i++) { int16_t v = limit((int16_t)-PPM_range, channelOutputs[i], (int16_t)PPM_range) + 2 * PPM_CH_CENTER(i); - *ppmPulsesData->ptr++ = v; + *data++ = v; total += v; } @@ -58,8 +58,9 @@ uint16_t setupPulsesPPM(PpmPulsesData* ppmPulsesData, uint8_t channelsStart, void setupPulsesPPMTrainer() { + auto p_data = trainerPulsesData.ppm.pulses; uint16_t total = setupPulsesPPM( - &trainerPulsesData.ppm, g_model.trainerData.channelsStart, + p_data, g_model.trainerData.channelsStart, g_model.trainerData.channelsCount); uint32_t rest = PPM_TRAINER_PERIOD_HALF_US(); @@ -72,42 +73,88 @@ void setupPulsesPPMTrainer() if (rest >= USHRT_MAX - 1) rest = USHRT_MAX - 1; - *trainerPulsesData.ppm.ptr++ = (uint16_t)rest; + *p_data++ = (uint16_t)rest; // stop mark so that IRQ-based sending // knows when to stop - *trainerPulsesData.ppm.ptr = 0; + *p_data = 0; + + trainerPulsesData.ppm.ptr = p_data; } -static void setupPulsesPPMModule(uint8_t module) +static uint32_t setupPulsesPPMModule(uint8_t module, pulse_duration_t*& data) { - PpmPulsesData* data = nullptr; -#if defined(PCBTARANIS) && defined(INTERNAL_MODULE_PPM) - if (module == INTERNAL_MODULE) { - data = &intmodulePulsesData.ppm; - } else -#endif - { - data = &extmodulePulsesData.ppm; - } - - setupPulsesPPM(&extmodulePulsesData.ppm, + auto start = data; + setupPulsesPPM(data, g_model.moduleData[module].channelsStart, g_model.moduleData[module].channelsCount); // Set the final period to 1ms after which the // PPM will be switched OFF - *data->ptr++ = PPM_SAFE_MARGIN * 2; + *data++ = PPM_SAFE_MARGIN * 2; + + return data - start; } -#if defined(PCBTARANIS) && defined(INTERNAL_MODULE_PPM) -void setupPulsesPPMInternalModule() +static void* ppmInit(uint8_t module) { - setupPulsesPPMModule(INTERNAL_MODULE); -} +#if defined(HARDWARE_INTERNAL_MODULE) + // only external module supported + if (module == INTERNAL_MODULE) return nullptr; #endif -void setupPulsesPPMExternalModule() -{ - setupPulsesPPMModule(EXTERNAL_MODULE); + auto delay = GET_MODULE_PPM_DELAY(module) * 2; + etx_timer_config_t cfg = { + .type = ETX_PWM, + .polarity = GET_MODULE_PPM_POLARITY(module), + .cmp_val = (uint16_t)delay, + }; + + auto mod_st = modulePortInitTimer(module, ETX_MOD_PORT_TIMER, &cfg); + if (!mod_st) return nullptr; + + mixerSchedulerSetPeriod(module, PPM_PERIOD(module)); + return (void*)mod_st; } + +static void ppmDeInit(void* ctx) +{ + auto mod_st = (etx_module_state_t*)ctx; + modulePortDeInit(mod_st); +} + +static void ppmSendPulses(void* ctx, uint8_t* buffer, int16_t* channels, uint8_t nChannels) +{ + // TODO: + (void)channels; + (void)nChannels; + + auto mod_st = (etx_module_state_t*)ctx; + auto module = modulePortGetModule(mod_st); + + pulse_duration_t* pulses = (pulse_duration_t*)buffer; + auto length = setupPulsesPPMModule(module, pulses); + + auto drv = modulePortGetTimerDrv(mod_st->tx); + auto drv_ctx = modulePortGetCtx(mod_st->tx); + + auto delay = GET_MODULE_PPM_DELAY(module) * 2; + etx_timer_config_t cfg = { + .type = ETX_PWM, + .polarity = GET_MODULE_PPM_POLARITY(module), + .cmp_val = (uint16_t)delay, + }; + + drv->send(drv_ctx, &cfg, buffer, length); + + // PPM_PERIOD is not a constant! It can be set from UI + mixerSchedulerSetPeriod(module, PPM_PERIOD(module)); +} + +const etx_proto_driver_t PpmDriver = { + .protocol = PROTOCOL_CHANNELS_PPM, + .init = ppmInit, + .deinit = ppmDeInit, + .sendPulses = ppmSendPulses, + .processData = nullptr, +}; diff --git a/radio/src/pulses/ppm.h b/radio/src/pulses/ppm.h new file mode 100644 index 000000000..336ace47b --- /dev/null +++ b/radio/src/pulses/ppm.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) EdgeTx + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#pragma once + +#include "hal/module_driver.h" + +extern const etx_proto_driver_t PpmDriver; diff --git a/radio/src/pulses/pulses.cpp b/radio/src/pulses/pulses.cpp index f30ace1b9..c3b95db5e 100755 --- a/radio/src/pulses/pulses.cpp +++ b/radio/src/pulses/pulses.cpp @@ -19,28 +19,36 @@ * GNU General Public License for more details. */ +// #include "hal.h" #include "opentx.h" + #include "mixer_scheduler.h" #include "heartbeat_driver.h" +#include "hal/module_port.h" +#include "tasks/mixer_task.h" #include "pulses/pxx2.h" #include "pulses/flysky.h" +#include "pulses/dsm2.h" -#if defined(INTMODULE_USART) -#include "intmodule_serial_driver.h" -#else -#include "intmodule_pulses_driver.h" +#if defined(PPM) +#include "pulses/ppm.h" #endif -#include "extmodule_serial_driver.h" -#include "extmodule_driver.h" +#if defined(PXX1) +#include "pulses/pxx1.h" +#endif + +#if defined(SBUS) +#include "pulses/sbus.h" +#endif #if defined(CROSSFIRE) #include "pulses/crossfire.h" #endif #if defined(GHOST) -#include "telemetry/ghost.h" +#include "pulses/ghost.h" #endif #if defined(MULTIMODULE) @@ -56,63 +64,91 @@ #include "pulses/afhds3.h" #endif -uint8_t s_pulses_paused = 0; +static module_pulse_driver _module_drivers[MAX_MODULES]; +static module_pulse_buffer _module_buffers[MAX_MODULES] __DMA; + +void pulsesInit() +{ + memset(_module_drivers, 0, sizeof(_module_drivers)); +} + +module_pulse_driver* pulsesGetModuleDriver(uint8_t module) +{ + return &(_module_drivers[module]); +} + +uint8_t* pulsesGetModuleBuffer(uint8_t module) +{ + return _module_buffers[module]._buffer; +} + ModuleState moduleState[NUM_MODULES]; -InternalModulePulsesData intmodulePulsesData __DMA; -ExternalModulePulsesData extmodulePulsesData __DMA; TrainerPulsesData trainerPulsesData __DMA; -void startPulses() +void pulsesStart() { telemetryStart(); - s_pulses_paused = false; - -#if defined(HARDWARE_INTERNAL_MODULE) - setupPulsesInternalModule(); -#endif - -#if defined(HARDWARE_EXTERNAL_MODULE) - setupPulsesExternalModule(); -#endif - -#if defined(HARDWARE_EXTRA_MODULE) - extramodulePpmStart(); -#endif + mixerTaskStart(); } -void stopPulses() +void pulsesStop() { telemetryStop(); - s_pulses_paused = true; + mixerTaskStop(); - for (uint8_t i = 0; i < NUM_MODULES; i++) - moduleState[i].protocol = PROTOCOL_CHANNELS_UNINITIALIZED; + for (uint8_t i = 0; i < MAX_MODULES; i++) + pulsesStopModule(i); } -void restartModule(uint8_t idx) +void restartModule(uint8_t module) { - if (idx == INTERNAL_MODULE) { - if (!IS_INTERNAL_MODULE_ON()) return; - } else if (idx == EXTERNAL_MODULE){ - if (!IS_EXTERNAL_MODULE_ON()) return; - } else { + mixerTaskStop(); + + // wait for the power output to be drained + pulsesStopModule(module); + RTOS_WAIT_MS(200); + + mixerTaskStart(); +} + +#if !defined(SIMU) +#include +#include + +static void _setup_async_module_restart(void* p1, uint32_t p2) +{ + if (!mixerTaskTryLock()) { + // In case the mixer cannot be locked, try again later + // and make the same function pending again. + PendedFunction_t cb = _setup_async_module_restart; + xTimerPendFunctionCall(cb, p1, p2, 0/* do not wait */); return; } - pauseMixerCalculations(); - pausePulses(); + uint8_t module = (uint8_t)(uintptr_t)p1; + moduleState[module].forced_off = 1; - if (idx == INTERNAL_MODULE) stopPulsesInternalModule(); -#if defined(HARDWARE_EXTERNAL_MODULE) - else stopPulsesExternalModule(); + uint32_t timeout = p2; + moduleState[module].counter = timeout; + + mixerTaskUnlock(); +} #endif - RTOS_WAIT_MS(200); // 20ms so that the pulses interrupt will reinit the frame rate - - resumePulses(); - resumeMixerCalculations(); +// return true if the request could be posted to the timer queue +bool restartModuleAsync(uint8_t module, uint8_t cnt_delay) +{ +#if !defined(SIMU) + PendedFunction_t cb = _setup_async_module_restart; + return xTimerPendFunctionCall(cb, (void*)(uintptr_t)module, cnt_delay, + 0/* do not wait */) == pdPASS; +#else + return true; +#endif } +// TODO: this should be moved to PXX2 territory! +#if defined(PXX2) // use only for PXX void ModuleState::startBind(BindInformation* destination, ModuleCallback bindCallback) @@ -160,6 +196,7 @@ void ModuleState::writeReceiverSettings(ReceiverSettings* source) receiverSettings->timeout = 0; mode = MODULE_MODE_RECEIVER_SETTINGS; } +#endif void getModuleStatusString(uint8_t moduleIdx, char * statusText) { @@ -170,6 +207,7 @@ void getModuleStatusString(uint8_t moduleIdx, char * statusText) getMultiModuleStatus(moduleIdx).getStatusString(statusText); } #endif + #if defined(AFHDS3) if (isModuleAFHDS3(moduleIdx)) { afhds3::getStatusString(moduleIdx, statusText); @@ -216,6 +254,9 @@ uint8_t getModuleType(uint8_t module) return MODULE_TYPE_NONE; } +// TODO: replace with some mapping between +// module type and protocol driver. +// uint8_t getRequiredProtocol(uint8_t module) { uint8_t protocol = PROTOCOL_CHANNELS_UNINITIALIZED; @@ -226,36 +267,17 @@ uint8_t getRequiredProtocol(uint8_t module) break; case MODULE_TYPE_XJT_PXX1: -#if defined(INTMODULE_USART) - if (module == INTERNAL_MODULE) { - protocol = PROTOCOL_CHANNELS_PXX1_SERIAL; - break; - } -#endif - protocol = PROTOCOL_CHANNELS_PXX1_PULSES; - break; - case MODULE_TYPE_R9M_PXX1: - protocol = PROTOCOL_CHANNELS_PXX1_PULSES; - break; - -#if defined(HARDWARE_EXTERNAL_MODULE_SIZE_SML) case MODULE_TYPE_R9M_LITE_PXX1: - protocol = PROTOCOL_CHANNELS_PXX1_SERIAL; + protocol = PROTOCOL_CHANNELS_PXX1; break; - case MODULE_TYPE_R9M_LITE_PXX2: - protocol = PROTOCOL_CHANNELS_PXX2_LOWSPEED; - break; -#endif - case MODULE_TYPE_ISRM_PXX2: case MODULE_TYPE_R9M_PXX2: -#if defined(HARDWARE_EXTERNAL_MODULE_SIZE_SML) + case MODULE_TYPE_R9M_LITE_PXX2: case MODULE_TYPE_XJT_LITE_PXX2: case MODULE_TYPE_R9M_LITE_PRO_PXX2: -#endif - protocol = PROTOCOL_CHANNELS_PXX2_HIGHSPEED; + protocol = PROTOCOL_CHANNELS_PXX2; break; case MODULE_TYPE_SBUS: @@ -275,6 +297,7 @@ uint8_t getRequiredProtocol(uint8_t module) PROTOCOL_CHANNELS_DSM2_LP45 + g_model.moduleData[module].subType, PROTOCOL_CHANNELS_DSM2_DSMX); // The module is set to OFF during one second before BIND start + // TODO: move this to DSM2 driver... { static tmr10ms_t bindStartTime = 0; if (moduleState[module].mode == MODULE_MODE_BIND) { @@ -322,239 +345,78 @@ uint8_t getRequiredProtocol(uint8_t module) break; } - if (s_pulses_paused) { - protocol = PROTOCOL_CHANNELS_NONE; - } - -#if 0 - // will need an EEPROM conversion - if (moduleState[module].mode == MODULE_OFF) { - protocol = PROTOCOL_CHANNELS_NONE; - } -#endif - return protocol; } -#if defined(HARDWARE_INTERNAL_MODULE) -static void* internalModuleContext = nullptr; -static const etx_module_driver_t* internalModuleDriver = nullptr; +static module_init_cb_t _on_module_init = nullptr; +static module_deinit_cb_t _on_module_deinit = nullptr; -const etx_module_driver_t* getIntModuleDriver() +void pulsesSetModuleInitCb(module_init_cb_t cb) { - return internalModuleDriver; + _on_module_init = cb; } -void* getIntModuleCtx() +void pulsesSetModuleDeInitCb(module_deinit_cb_t cb) { - return internalModuleContext; + _on_module_deinit = cb; } -static void enablePulsesInternalModule(uint8_t protocol) +static void _init_module(uint8_t module, const etx_proto_driver_t* drv) { - // start new protocol hardware here - if (internalModuleDriver) { - internalModuleDriver->deinit(internalModuleContext); - internalModuleContext = nullptr; - internalModuleDriver = nullptr; - } else { - intmoduleStop(); - } + auto mod = &(_module_drivers[module]); + void* ctx = drv->init(module); - switch (protocol) { -#if defined(INTERNAL_MODULE_PXX1) && !defined(INTMODULE_USART) - case PROTOCOL_CHANNELS_PXX1_PULSES: - intmodulePxx1PulsesStart(); -#if defined(INTMODULE_HEARTBEAT) - init_intmodule_heartbeat(); -#endif - mixerSchedulerSetPeriod(INTERNAL_MODULE, INTMODULE_PXX1_SERIAL_PERIOD); - break; -#endif - -#if defined(INTERNAL_MODULE_PXX1) && defined(INTMODULE_USART) - case PROTOCOL_CHANNELS_PXX1_SERIAL: - internalModuleContext = Pxx1InternalSerialDriver.init(INTERNAL_MODULE); - internalModuleDriver = &Pxx1InternalSerialDriver; - break; -#endif - -#if defined(INTERNAL_MODULE_PXX2) - case PROTOCOL_CHANNELS_PXX2_HIGHSPEED: - internalModuleContext = Pxx2InternalDriver.init(INTERNAL_MODULE); - internalModuleDriver = &Pxx2InternalDriver; - break; -#endif - -#if defined(INTERNAL_MODULE_MULTI) && defined(MULTIMODULE) - case PROTOCOL_CHANNELS_MULTIMODULE: - internalModuleContext = MultiInternalDriver.init(INTERNAL_MODULE); - internalModuleDriver = &MultiInternalDriver; - break; -#endif - -#if defined(INTERNAL_MODULE_CRSF) && defined(CROSSFIRE) - case PROTOCOL_CHANNELS_CROSSFIRE: - internalModuleContext = CrossfireInternalDriver.init(INTERNAL_MODULE); - internalModuleDriver = &CrossfireInternalDriver; - break; -#endif - -#if defined(INTERNAL_MODULE_PPM) - case PROTOCOL_CHANNELS_PPM: - intmodulePpmStart(); - mixerSchedulerSetPeriod(INTERNAL_MODULE, PPM_PERIOD(INTERNAL_MODULE)); - break; -#endif - -#if defined(INTERNAL_MODULE_AFHDS2A) && defined(AFHDS2) - case PROTOCOL_CHANNELS_AFHDS2A: - internalModuleContext = Afhds2InternalDriver.init(INTERNAL_MODULE); - internalModuleDriver = &Afhds2InternalDriver; - break; -#endif - -#if defined(INTERNAL_MODULE_AFHDS3) - case PROTOCOL_CHANNELS_AFHDS3: - internalModuleContext = afhds3::internalDriver.init(INTERNAL_MODULE); - internalModuleDriver = &afhds3::internalDriver; - break; -#endif - - default: - // internal module stopped, use default mixer period - mixerSchedulerSetPeriod(INTERNAL_MODULE, 0); - break; - } -} - -bool setupPulsesInternalModule(uint8_t protocol) -{ - uint8_t channelStart = g_model.moduleData[INTERNAL_MODULE].channelsStart; - int16_t* channels = &channelOutputs[channelStart]; - uint8_t nChannels = 16; // TODO: MAX_CHANNELS - channelsStart - - if (internalModuleDriver) { - internalModuleDriver->setupPulses(internalModuleContext, - channels, nChannels); - return true; - } - - switch (protocol) { -#if defined(HARDWARE_INTERNAL_MODULE) && defined(PXX1) && !defined(INTMODULE_USART) - case PROTOCOL_CHANNELS_PXX1_PULSES: - intmodulePulsesData.pxx.setupFrame(INTERNAL_MODULE); - return true; -#endif - -#if defined(PCBTARANIS) && defined(INTERNAL_MODULE_PPM) - case PROTOCOL_CHANNELS_PPM: - setupPulsesPPMInternalModule(); - return true; -#endif - - default: - return false; - } -} - -void stopPulsesInternalModule() -{ - auto& proto = moduleState[INTERNAL_MODULE].protocol; - if (proto != PROTOCOL_CHANNELS_UNINITIALIZED && - proto != PROTOCOL_CHANNELS_NONE) { - if (internalModuleDriver) { - internalModuleDriver->deinit(internalModuleContext); - internalModuleDriver = nullptr; - internalModuleContext = nullptr; - } else { - mixerSchedulerSetPeriod(INTERNAL_MODULE, 0); - intmoduleStop(); - } - proto = PROTOCOL_CHANNELS_NONE; - } -} - -void intmoduleSendNextFrame() -{ - if (internalModuleDriver) { - internalModuleDriver->sendPulses(internalModuleContext); + // TODO: module init failed somehow, we should handle this better... + if (!ctx) { + TRACE("Module #%d init failed", module); return; } - switch (moduleState[INTERNAL_MODULE].protocol) { + mod->drv = drv; + mod->ctx = ctx; -#if defined(INTERNAL_MODULE_PPM) - case PROTOCOL_CHANNELS_PPM: - intmoduleSendNextFramePPM( - intmodulePulsesData.ppm.pulses, - intmodulePulsesData.ppm.ptr - intmodulePulsesData.ppm.pulses); - break; -#endif - -#if defined(PXX1) && !defined(INTMODULE_USART) - case PROTOCOL_CHANNELS_PXX1_PULSES: - intmoduleSendNextFramePxx1(intmodulePulsesData.pxx.getData(), - intmodulePulsesData.pxx.getSize()); - break; -#endif - } + // board specific hook + if (_on_module_init) + _on_module_init(module, drv); + + // power ON + modulePortSetPower(module, true); + TRACE("Module #%d init succeeded", module); } -bool setupPulsesInternalModule() +static void _deinit_module(uint8_t module) { - uint8_t protocol = getRequiredProtocol(INTERNAL_MODULE); + auto mod = &(_module_drivers[module]); + if (!mod->drv) return; - heartbeat |= (HEART_TIMER_PULSES << INTERNAL_MODULE); + // scheduling OFF + mixerSchedulerSetPeriod(module, 0); - if (moduleState[INTERNAL_MODULE].protocol != protocol) { - enablePulsesInternalModule(protocol); - moduleState[INTERNAL_MODULE].protocol = protocol; - return false; - } - else { - return setupPulsesInternalModule(protocol); - } -} -#endif + // board specific hook + auto drv = mod->drv; + if (_on_module_deinit) + _on_module_deinit(module, drv); + + // de-init + auto ctx = mod->ctx; + drv->deinit(ctx); -#if defined(HARDWARE_EXTERNAL_MODULE) -static void* externalModuleContext = nullptr; -static const etx_module_driver_t* externalModuleDriver = nullptr; + // power OFF + modulePortSetPower(module, false); -const etx_module_driver_t* getExtModuleDriver() -{ - return externalModuleDriver; + // clear + memset(mod, 0, sizeof(module_pulse_driver)); + TRACE("Module #%d de-init succeeded", module); } -void* getExtModuleCtx() +static void pulsesEnableModule(uint8_t module, uint8_t protocol) { - return externalModuleContext; -} - -void enablePulsesExternalModule(uint8_t protocol) -{ - // start new protocol hardware here - if (externalModuleDriver) { - externalModuleDriver->deinit(externalModuleContext); - externalModuleDriver = nullptr; - externalModuleContext = nullptr; - } else { - extmoduleStop(); - } + _deinit_module(module); switch (protocol) { #if defined(PXX1) - case PROTOCOL_CHANNELS_PXX1_PULSES: - extmodulePxx1PulsesStart(); - mixerSchedulerSetPeriod(EXTERNAL_MODULE, PXX_PULSES_PERIOD); - break; -#endif - -#if defined(PXX1) && defined(HARDWARE_EXTERNAL_MODULE_SIZE_SML) - case PROTOCOL_CHANNELS_PXX1_SERIAL: - externalModuleContext = Pxx1ExternalSerialDriver.init(EXTERNAL_MODULE); - externalModuleDriver = &Pxx1ExternalSerialDriver; + case PROTOCOL_CHANNELS_PXX1: + _init_module(module, &Pxx1Driver); break; #endif @@ -562,254 +424,155 @@ void enablePulsesExternalModule(uint8_t protocol) case PROTOCOL_CHANNELS_DSM2_LP45: case PROTOCOL_CHANNELS_DSM2_DSM2: case PROTOCOL_CHANNELS_DSM2_DSMX: - extmoduleSerialStart(); - mixerSchedulerSetPeriod(EXTERNAL_MODULE, DSM2_PERIOD); + _init_module(module, &DSM2Driver); + break; +#endif + +#if defined(SBUS) + case PROTOCOL_CHANNELS_SBUS: + _init_module(module, &SBusDriver); + break; +#endif + +#if defined(PXX2) + case PROTOCOL_CHANNELS_PXX2: + _init_module(module, &Pxx2Driver); + break; +#endif + +#if defined(MULTIMODULE) + case PROTOCOL_CHANNELS_MULTIMODULE: + _init_module(module, &MultiDriver); break; #endif #if defined(CROSSFIRE) case PROTOCOL_CHANNELS_CROSSFIRE: - externalModuleContext = CrossfireExternalDriver.init(EXTERNAL_MODULE); - externalModuleDriver = &CrossfireExternalDriver; + _init_module(module, &CrossfireDriver); break; #endif #if defined(GHOST) case PROTOCOL_CHANNELS_GHOST: - EXTERNAL_MODULE_ON(); - mixerSchedulerSetPeriod(EXTERNAL_MODULE, GHOST_PERIOD); - break; -#endif - -#if defined(PXX2) - case PROTOCOL_CHANNELS_PXX2_HIGHSPEED: - externalModuleContext = Pxx2ExternalDriver.init(EXTERNAL_MODULE); - externalModuleDriver = &Pxx2ExternalDriver; - break; - - case PROTOCOL_CHANNELS_PXX2_LOWSPEED: - externalModuleContext = Pxx2LowSpeedExternalDriver.init(EXTERNAL_MODULE); - externalModuleDriver = &Pxx2LowSpeedExternalDriver; - break; -#endif - -#if defined(MULTIMODULE) - case PROTOCOL_CHANNELS_MULTIMODULE: - extmoduleSerialStart(); - mixerSchedulerSetPeriod(EXTERNAL_MODULE, MULTIMODULE_PERIOD); - getMultiModuleStatus(EXTERNAL_MODULE).failsafeChecked = false; - getMultiModuleStatus(EXTERNAL_MODULE).flags = 0; -#if defined(MULTI_PROTOLIST) - MultiRfProtocols::instance(EXTERNAL_MODULE)->triggerScan(); -#endif - break; -#endif - -#if defined(SBUS) - case PROTOCOL_CHANNELS_SBUS: - extmoduleSerialStart(); - mixerSchedulerSetPeriod(EXTERNAL_MODULE, SBUS_PERIOD); + _init_module(module, &GhostDriver); break; #endif #if defined(PPM) - case PROTOCOL_CHANNELS_PPM: - extmodulePpmStart( - GET_MODULE_PPM_DELAY(EXTERNAL_MODULE), - GET_MODULE_PPM_POLARITY(EXTERNAL_MODULE)); - mixerSchedulerSetPeriod(EXTERNAL_MODULE, PPM_PERIOD(EXTERNAL_MODULE)); + case PROTOCOL_CHANNELS_PPM: + _init_module(module, &PpmDriver); break; #endif -#if defined(AFHDS3) +#if defined(INTERNAL_MODULE_AFHDS2A) && defined(AFHDS2) + case PROTOCOL_CHANNELS_AFHDS2A: + _init_module(module, &Afhds2InternalDriver); + break; +#endif + +#if defined(INTERNAL_MODULE_AFHDS3) case PROTOCOL_CHANNELS_AFHDS3: - externalModuleContext = afhds3::externalDriver.init(EXTERNAL_MODULE); - externalModuleDriver = &afhds3::externalDriver; + _init_module(module, &afhds3::ProtoDriver); break; #endif - case PROTOCOL_CHANNELS_DSMP: - extmoduleSerialStart(); - mixerSchedulerSetPeriod(EXTERNAL_MODULE, 11 * 1000 /* 11ms in us */); - break; - - default: - // external module stopped, use default mixer period - mixerSchedulerSetPeriod(EXTERNAL_MODULE, 0); - break; - } -} - -bool setupPulsesExternalModule(uint8_t protocol) -{ - uint8_t channelStart = g_model.moduleData[EXTERNAL_MODULE].channelsStart; - int16_t* channels = &channelOutputs[channelStart]; - uint8_t nChannels = 16; // TODO: MAX_CHANNELS - channelsStart - - if (externalModuleDriver) { - externalModuleDriver->setupPulses(externalModuleContext, - channels, nChannels); - return true; - } - - switch (protocol) { - -#if defined(PXX1) - case PROTOCOL_CHANNELS_PXX1_PULSES: - extmodulePulsesData.pxx.setupFrame(EXTERNAL_MODULE); - return true; -#endif - -#if defined(SBUS) - case PROTOCOL_CHANNELS_SBUS: - setupPulsesSbus(); - // SBUS_PERIOD is not a constant! It can be set from UI - mixerSchedulerSetPeriod(EXTERNAL_MODULE, SBUS_PERIOD); - return true; -#endif - #if defined(DSM2) - case PROTOCOL_CHANNELS_DSM2_LP45: - case PROTOCOL_CHANNELS_DSM2_DSM2: - case PROTOCOL_CHANNELS_DSM2_DSMX: - setupPulsesDSM2(); - return true; -#endif - -#if defined(GHOST) - case PROTOCOL_CHANNELS_GHOST: - { - ModuleSyncStatus& status = getModuleSyncStatus(EXTERNAL_MODULE); - if (status.isValid()) - mixerSchedulerSetPeriod(EXTERNAL_MODULE, status.getAdjustedRefreshRate()); - else - mixerSchedulerSetPeriod(EXTERNAL_MODULE, GHOST_PERIOD); - setupPulsesGhost(); - return true; - } -#endif - -#if defined(MULTIMODULE) - case PROTOCOL_CHANNELS_MULTIMODULE: - setupPulsesMultiExternalModule(); - return true; -#endif - -#if defined(PPM) - case PROTOCOL_CHANNELS_PPM: - setupPulsesPPMExternalModule(); - return true; -#endif - case PROTOCOL_CHANNELS_DSMP: - setupPulsesLemonDSMP(); - return true; + _init_module(module, &DSMPDriver); + break; +#endif default: - return false; + break; } } -void extmoduleSendNextFrame() +// TODO: declare a function in telemetry +extern volatile uint8_t _telemetryIsPolling; + +void pulsesStopModule(uint8_t module) { - if (externalModuleDriver) { - externalModuleDriver->sendPulses(externalModuleContext); + if (module >= MAX_MODULES) return; + + while(_telemetryIsPolling) { + // In case the telemetry timer is currently polling the port, + // we give the timer task a chance to run and finish the polling. + RTOS_WAIT_MS(1); + } + _deinit_module(module); + + auto& proto = moduleState[module].protocol; + proto = PROTOCOL_CHANNELS_NONE; +} + +static bool _handle_async_restart(uint8_t module) +{ + if (moduleState[module].forced_off) { + if (--moduleState[module].counter > 0) { + _deinit_module(module); + moduleState[module].protocol = PROTOCOL_CHANNELS_NONE; + return true; + } else { + moduleState[module].forced_off = 0; + } + } + return false; +} + +void pulsesSendNextFrame(uint8_t module) +{ + if (module >= MAX_MODULES) return; + + uint8_t protocol = getRequiredProtocol(module); + + if (moduleState[module].protocol != protocol || + moduleState[module].forced_off) { + // TODO: error checking! + + if (_telemetryIsPolling) { + // In case the telemetry timer is currently polling the port, + // we just yield in the hope it will be different next time. + return; + } + + if (_handle_async_restart(module)) + return; + + pulsesEnableModule(module, protocol); + moduleState[module].protocol = protocol; return; } - switch (moduleState[EXTERNAL_MODULE].protocol) { + auto mod = &(_module_drivers[module]); + if (mod->drv) { + uint8_t channelStart = g_model.moduleData[module].channelsStart; + int16_t* channels = &channelOutputs[channelStart]; + uint8_t nChannels = 16; // TODO: MAX_CHANNELS - channelsStart - case PROTOCOL_CHANNELS_PPM: - extmoduleSendNextFramePpm( - extmodulePulsesData.ppm.pulses, - extmodulePulsesData.ppm.ptr - extmodulePulsesData.ppm.pulses, - GET_MODULE_PPM_DELAY(EXTERNAL_MODULE), - GET_MODULE_PPM_POLARITY(EXTERNAL_MODULE)); - mixerSchedulerSetPeriod(EXTERNAL_MODULE, PPM_PERIOD(EXTERNAL_MODULE)); - break; - -#if defined(PXX1) - case PROTOCOL_CHANNELS_PXX1_PULSES: - extmoduleSendNextFramePxx1(extmodulePulsesData.pxx.getData(), - extmodulePulsesData.pxx.getSize()); - break; -#endif - -#if defined(SBUS) || defined(DSM2) || defined(MULTIMODULE) - case PROTOCOL_CHANNELS_SBUS: - extmoduleSendNextFrameSoftSerial( - extmodulePulsesData.dsm2.pulses, - extmodulePulsesData.dsm2.ptr - extmodulePulsesData.dsm2.pulses, - GET_SBUS_POLARITY(EXTERNAL_MODULE)); - break; - - case PROTOCOL_CHANNELS_DSM2_LP45: - case PROTOCOL_CHANNELS_DSM2_DSM2: - case PROTOCOL_CHANNELS_DSM2_DSMX: - case PROTOCOL_CHANNELS_MULTIMODULE: - extmoduleSendNextFrameSoftSerial( - extmodulePulsesData.dsm2.pulses, - extmodulePulsesData.dsm2.ptr - extmodulePulsesData.dsm2.pulses); - break; -#endif - case PROTOCOL_CHANNELS_DSMP: - extmoduleSendNextFrameSoftSerial( - extmodulePulsesData.dsm2.pulses, - extmodulePulsesData.dsm2.ptr - extmodulePulsesData.dsm2.pulses, - true); - break; - -#if defined(GHOST) - case PROTOCOL_CHANNELS_GHOST: - sportSendBuffer(extmodulePulsesData.ghost.pulses, - extmodulePulsesData.ghost.length); - break; -#endif + auto drv = mod->drv; + auto ctx = mod->ctx; + auto buffer = _module_buffers[module]._buffer; + drv->sendPulses(ctx, buffer, channels, nChannels); } } -void stopPulsesExternalModule() +void pulsesSendChannels() { - auto& proto = moduleState[EXTERNAL_MODULE].protocol; - if (proto != PROTOCOL_CHANNELS_UNINITIALIZED && - proto != PROTOCOL_CHANNELS_NONE) { - if (externalModuleDriver) { - externalModuleDriver->deinit(externalModuleContext); - externalModuleDriver = nullptr; - externalModuleContext = nullptr; - } else { - mixerSchedulerSetPeriod(EXTERNAL_MODULE, 0); - extmoduleStop(); - } - proto = PROTOCOL_CHANNELS_NONE; + for (uint8_t i = 0; i < MAX_MODULES; i++) { + pulsesSendNextFrame(i); } } -bool setupPulsesExternalModule() -{ - uint8_t protocol = getRequiredProtocol(EXTERNAL_MODULE); - - heartbeat |= (HEART_TIMER_PULSES << EXTERNAL_MODULE); - - if (moduleState[EXTERNAL_MODULE].protocol != protocol) { - enablePulsesExternalModule(protocol); - moduleState[EXTERNAL_MODULE].protocol = protocol; - return false; - } - else { - return setupPulsesExternalModule(protocol); - } -} -#endif - +// set the failsafe channel values to the current output values void setCustomFailsafe(uint8_t moduleIndex) { if (moduleIndex < NUM_MODULES) { - for (int ch=0; ch= sentModuleChannels(moduleIndex) + g_model.moduleData[moduleIndex].channelsStart) { + for (int ch = 0; ch < MAX_OUTPUT_CHANNELS; ch++) { + if (ch < g_model.moduleData[moduleIndex].channelsStart || + ch >= sentModuleChannels(moduleIndex) + + g_model.moduleData[moduleIndex].channelsStart) { g_model.failsafeChannels[ch] = 0; - } - else if (g_model.failsafeChannels[ch] < FAILSAFE_CHANNEL_HOLD) { + } else if (g_model.failsafeChannels[ch] < FAILSAFE_CHANNEL_HOLD) { g_model.failsafeChannels[ch] = channelOutputs[ch]; } } @@ -819,5 +582,5 @@ void setCustomFailsafe(uint8_t moduleIndex) int32_t getChannelValue(uint8_t channel) { - return channelOutputs[channel] + 2*PPM_CH_CENTER(channel) - 2*PPM_CENTER; + return channelOutputs[channel] + 2 * PPM_CH_CENTER(channel) - 2 * PPM_CENTER; } diff --git a/radio/src/pulses/pulses.h b/radio/src/pulses/pulses.h index 9587d3e62..54b722fdd 100644 --- a/radio/src/pulses/pulses.h +++ b/radio/src/pulses/pulses.h @@ -25,15 +25,13 @@ #include "definitions.h" #include "dataconstants.h" #include "pulses_common.h" -#include "pxx1.h" -#include "pxx2.h" -#include "multi.h" -#include "afhds2.h" -#include "afhds3_module.h" #include "modules_helpers.h" -#include "ff.h" #include "hal/module_driver.h" +#if defined(PXX2) +#include "pxx2.h" +#include "pxx2_ota.h" +#endif #if defined(DSM2) #define IS_DSM2_PROTOCOL(protocol) (protocol>=PROTOCOL_CHANNELS_DSM2_LP45 && protocol<=PROTOCOL_CHANNELS_DSM2_DSMX) @@ -62,17 +60,16 @@ #define IS_AFHDS3_PROTOCOL(protocol) (0) #endif -extern uint8_t s_pulses_paused; - typedef void (* ModuleCallback)(); PACK(struct ModuleState { uint8_t protocol; uint8_t mode:4; - uint8_t paused:1; + uint8_t forced_off:1; uint8_t spare:3; uint16_t counter; +#if defined(PXX2) // PXX specific items union { @@ -90,6 +87,7 @@ PACK(struct ModuleState { void writeModuleSettings(ModuleSettings * source); void readReceiverSettings(ReceiverSettings * destination); void writeReceiverSettings(ReceiverSettings * source); +#endif }); extern ModuleState moduleState[NUM_MODULES]; @@ -130,98 +128,13 @@ typedef Dsm2TimerPulsesData Dsm2PulsesData; #define SBUS_MAX_PERIOD 325 /*Overflows uint16_t if set higher*/ #define SBUS_DEF_PERIOD 225 #define SBUS_STEPSIZE 5 /* SBUS Step Size 0.5ms */ -#define SBUS_PERIOD_HALF_US ((g_model.moduleData[EXTERNAL_MODULE].sbus.refreshRate * SBUS_STEPSIZE + SBUS_DEF_PERIOD) * 200) /*half us*/ -#define SBUS_PERIOD (SBUS_PERIOD_HALF_US / 2) /*us*/ +#define SBUS_PERIOD_HALF_US(m) ((g_model.moduleData[m].sbus.refreshRate * SBUS_STEPSIZE + SBUS_DEF_PERIOD) * 200) /*half us*/ +#define SBUS_PERIOD(m) (SBUS_PERIOD_HALF_US(m) / 2) /*us*/ #define MULTIMODULE_BAUDRATE 100000 #define MULTIMODULE_PERIOD 7000 /*us*/ #define CROSSFIRE_FRAME_MAXLEN 64 -PACK(struct CrossfirePulsesData { - uint8_t pulses[CROSSFIRE_FRAME_MAXLEN]; - uint8_t length; -}); - #define GHOST_FRAME_MAXLEN 16 -PACK(struct GhostPulsesData { - uint8_t pulses[GHOST_FRAME_MAXLEN]; - uint8_t length; -}); - -union InternalModulePulsesData { -#if defined(INTERNAL_MODULE_PXX1) -#if defined(INTMODULE_USART) - UartPxx1Pulses pxx_uart; -#else - PwmPxx1Pulses pxx; -#endif -#endif - -#if defined(INTERNAL_MODULE_PXX2) - Pxx2Pulses pxx2; -#endif - -#if defined(INTERNAL_MODULE_AFHDS2A) - FlySkySerialPulsesData flysky; -#endif - -#if defined(INTERNAL_MODULE_MULTI) - UartMultiPulses multi; -#endif - -#if defined(INTERNAL_MODULE_CRSF) - CrossfirePulsesData crossfire; -#endif - -#if defined(INTERNAL_MODULE_AFHDS3) - afhds3::IntmoduleData afhds3; -#endif - -#if defined(INTERNAL_MODULE_PPM) - PpmPulsesData ppm; -#endif - -} __ALIGNED(4); - -union ExternalModulePulsesData { -#if defined(PXX1) -#if defined(HARDWARE_EXTERNAL_MODULE_SIZE_SML) - UartPxx1Pulses pxx_uart; -#endif - PwmPxx1Pulses pxx; -#endif - -#if defined(PXX2) - Pxx2Pulses pxx2; -#endif - -#if defined(DSM2) || defined(MULTIMODULE) || defined(SBUS) - Dsm2PulsesData dsm2; -#endif - -#if defined(AFHDS3) - afhds3::ExtmoduleData afhds3; -#endif - - PpmPulsesData ppm; - -#if defined(CROSSFIRE) - CrossfirePulsesData crossfire; -#endif - -#if defined(GHOST) - GhostPulsesData ghost; -#endif -} __ALIGNED(4); - -/* The __ALIGNED keyword is required to align the struct inside the modulePulsesData below, - * which is also defined to be __DMA (which includes __ALIGNED) aligned. - * Arrays in C/C++ are always defined to be *contiguously*. The first byte of the second element is therefore always - * sizeof(ModulePulsesData). __ALIGNED is required for sizeof(ModulePulsesData) to be a multiple of the alignment. - */ - - -extern InternalModulePulsesData intmodulePulsesData; -extern ExternalModulePulsesData extmodulePulsesData; union TrainerPulsesData { PpmPulsesData ppm; @@ -229,63 +142,50 @@ union TrainerPulsesData { extern TrainerPulsesData trainerPulsesData; -#if defined(HARDWARE_INTERNAL_MODULE) -bool setupPulsesInternalModule(); -void stopPulsesInternalModule(); -void intmoduleSendNextFrame(); -const etx_module_driver_t* getIntModuleDriver(); -void* getIntModuleCtx(); +#if !defined(AFHDS3) + #define MODULE_BUFFER_SIZE 64 +#else + #define MODULE_BUFFER_SIZE 128 #endif -#if defined(HARDWARE_EXTERNAL_MODULE) -bool setupPulsesExternalModule(); -void stopPulsesExternalModule(); -void extmoduleSendNextFrame(); -const etx_module_driver_t* getExtModuleDriver(); -void* getExtModuleCtx(); -#endif -void restartModule(uint8_t idx); -void setupPulsesDSM2(); -void setupPulsesLemonDSMP(); -void setupPulsesCrossfire(uint8_t idx); -void setupPulsesGhost(); -void setupPulsesMultiExternalModule(); -void setupPulsesSbus(); -void setupPulsesPPMInternalModule(); -void setupPulsesPPMExternalModule(); + +struct module_pulse_buffer { + uint8_t _buffer[MODULE_BUFFER_SIZE]; +}; + +struct module_pulse_driver { + module_pulse_buffer buffer; + const etx_proto_driver_t* drv; + void* ctx; +}; + +module_pulse_driver* pulsesGetModuleDriver(uint8_t module); +uint8_t* pulsesGetModuleBuffer(uint8_t module); + +void pulsesStopModule(uint8_t module); +void pulsesSendNextFrame(uint8_t module); +void pulsesSendChannels(); + +typedef void (*module_init_cb_t)(uint8_t, const etx_proto_driver_t*); +typedef void (*module_deinit_cb_t)(uint8_t, const etx_proto_driver_t*); + +void pulsesSetModuleInitCb(module_init_cb_t cb); +void pulsesSetModuleDeInitCb(module_deinit_cb_t cb); + +void restartModule(uint8_t module); +bool restartModuleAsync(uint8_t module, uint8_t cnt_delay); + void setupPulsesPPMTrainer(); -void putDsm2Flush(); -void sendByteSbus(uint8_t b); -void intmodulePpmStart(); -void intmodulePxx1PulsesStart(); -void intmodulePxx1SerialStart(); -void extmodulePxx1PulsesStart(); -void extmodulePpmStart(); -void intmoduleStop(); -void extmoduleStop(); + void getModuleStatusString(uint8_t moduleIdx, char * statusText); void getModuleSyncStatusString(uint8_t moduleIdx, char * statusText); + #if defined(AFHDS3) uint8_t actualAfhdsRunPower(int moduleIndex); #endif -void extramodulePpmStart(); -void startPulses(); -void stopPulses(); - -inline bool pulsesStarted() -{ - return moduleState[0].protocol != PROTOCOL_CHANNELS_UNINITIALIZED; -} - -inline void pausePulses() -{ - s_pulses_paused = true; -} - -inline void resumePulses() -{ - s_pulses_paused = false; -} +void pulsesInit(); +void pulsesStart(); +void pulsesStop(); inline void SEND_FAILSAFE_NOW(uint8_t idx) { diff --git a/radio/src/pulses/pxx.h b/radio/src/pulses/pxx.h index 14c2ae8a2..3e6aca2a0 100644 --- a/radio/src/pulses/pxx.h +++ b/radio/src/pulses/pxx.h @@ -19,10 +19,7 @@ * GNU General Public License for more details. */ -#ifndef _PULSES_PXX_H_ -#define _PULSES_PXX_H_ - -#include "pulses_common.h" +#pragma once #define PXX_SEND_BIND 0x01 #define PXX_SEND_FAILSAFE (1 << 4) @@ -30,100 +27,21 @@ #define PXX2_LOWSPEED_BAUDRATE 230400 #define PXX2_HIGHSPEED_BAUDRATE 450000 -#define PXX2_NO_HEARTBEAT_PERIOD 4000/*us*/ -#define PXX2_MAX_HEARTBEAT_PERIOD (9000 + 1000)/*us longest period (isrm/accst) + 1ms heartbeat backup*/ -#if defined(INTMODULE_HEARTBEAT) - #define PXX2_PERIOD PXX2_MAX_HEARTBEAT_PERIOD -#else - #define PXX2_PERIOD PXX2_NO_HEARTBEAT_PERIOD -#endif + +/* microseconds */ +#define PXX2_DEFAULT_PERIOD 4000 + +/* microseconds longest period (isrm/accst) + 1ms heartbeat backup*/ +#define PXX2_MAX_HEARTBEAT_PERIOD (9000 + 1000) + #define PXX2_TOOLS_PERIOD 1000/*us*/ #define PXX2_FRAME_MAXLENGTH 64 -#define PXX_PULSES_PERIOD 9000/*us*/ +#define PXX1_DEFAULT_PERIOD 9000/*us*/ +#define PXX1_DEFAULT_SERIAL_BAUDRATE 115200 + +#define PXX1_FAST_PERIOD 4000/*us*/ +#define PXX1_FAST_SERIAL_BAUDRATE 450000 + #define EXTMODULE_PXX1_SERIAL_PERIOD 4000/*us*/ #define EXTMODULE_PXX1_SERIAL_BAUDRATE 420000 - -#if defined(PXX_FREQUENCY_HIGH) - #define INTMODULE_PXX1_SERIAL_BAUDRATE 450000 - #if defined(INTMODULE_HEARTBEAT) - // use backup trigger (1 ms later) - #define INTMODULE_PXX1_SERIAL_PERIOD (4000 + 1000)/*us*/ - #else - #define INTMODULE_PXX1_SERIAL_PERIOD 4000/*us*/ - #endif -#else - #define INTMODULE_PXX1_SERIAL_BAUDRATE 115200 - #if defined(INTMODULE_HEARTBEAT) - // use backup trigger (1 ms later) - #define INTMODULE_PXX1_SERIAL_PERIOD (9000 + 1000)/*us*/ - #else - #define INTMODULE_PXX1_SERIAL_PERIOD 9000/*us*/ - #endif -#endif - -// Used by the Sky9x family boards -class SerialPxxBitTransport: public DataBuffer { - protected: - uint8_t byte; - uint8_t bits_count; - - void initFrame(uint32_t period) - { - initBuffer(); - byte = 0; - bits_count = 0; - } - - void addSerialBit(uint8_t bit) - { - byte >>= 1; - if (bit & 1) { - byte |= 0x80; - } - if (++bits_count >= 8) { - *ptr++ = byte; - bits_count = 0; - } - } - - // 8uS/bit 01 = 0, 001 = 1 - void addPart(uint8_t value) - { - addSerialBit(0); - if (value) { - addSerialBit(0); - } - addSerialBit(1); - } - - void addTail() - { - while (bits_count != 0) { - addSerialBit(1); - } - } -}; - -class PwmPxxBitTransport: public PulsesBuffer { - protected: - - void initFrame(uint32_t period) - { - initBuffer(); - } - - void addPart(uint8_t value) - { - pulse_duration_t duration = value ? 47 : 31; - *ptr++ = duration; - } - - void addTail() - { - // rest min value is 18000 - 200 * 48 = 8400 (4.2ms) - *(ptr - 1) = 255; - } -}; - -#endif diff --git a/radio/src/pulses/pxx1.cpp b/radio/src/pulses/pxx1.cpp index 7b4450fb6..7ea34ac92 100644 --- a/radio/src/pulses/pxx1.cpp +++ b/radio/src/pulses/pxx1.cpp @@ -19,10 +19,21 @@ * GNU General Public License for more details. */ -#include "opentx.h" -#include "pulses/pxx1.h" -#include "mixer_scheduler.h" +#include "hal/module_port.h" #include "heartbeat_driver.h" +#include "mixer_scheduler.h" + +#include "pxx1_transport.h" +#include "pxx1.h" + +#include "opentx.h" + +static uint32_t _pxx1_internal_baudrate = PXX1_DEFAULT_SERIAL_BAUDRATE; + +void pxx1SetInternalBaudrate(uint32_t baudrate) +{ + _pxx1_internal_baudrate = baudrate; +} template void Pxx1Pulses::addFlag1(uint8_t module, uint8_t sendFailsafe) @@ -63,10 +74,12 @@ void Pxx1Pulses::addExtraFlags(uint8_t module) extraFlags |= (1 << 6); } +#if defined(HARDWARE_EXTERNAL_MODULE) && defined(HARDWARE_INTERNAL_MODULE) // Disable S.PORT if internal module is active if (module == EXTERNAL_MODULE && isSportLineUsedByInternalModule()) { extraFlags |= (1 << 5); } +#endif PxxTransport::addByte(extraFlags); } @@ -175,17 +188,25 @@ void Pxx1Pulses::add8ChannelsFrame(uint8_t module, uint8_t sendUpp } template -void Pxx1Pulses::setupFrame(uint8_t module) +Pxx1Pulses::Pxx1Pulses(uint8_t* buffer) + : PxxTransport(buffer) +{ +} + +template +void Pxx1Pulses::setupFrame(uint8_t module, Pxx1Type type) { uint8_t sendUpperChannels = 0; uint8_t sendFailsafe = 0; - PxxTransport::initFrame(PXX_PULSES_PERIOD); -#if defined(PXX_FREQUENCY_HIGH) - if (moduleState[module].protocol == PROTOCOL_CHANNELS_PXX1_SERIAL) { + // Fast serial PXX1 (either X-lite internal or R9M-lite): + // - up to 16 channels sent in the same frame + // + if (type == Pxx1Type::FAST_SERIAL) { if (moduleState[module].counter-- == 0) { - sendFailsafe = (g_model.moduleData[module].failsafeMode != FAILSAFE_NOT_SET && g_model.moduleData[module].failsafeMode != FAILSAFE_RECEIVER); + sendFailsafe = (g_model.moduleData[module].failsafeMode != FAILSAFE_NOT_SET && + g_model.moduleData[module].failsafeMode != FAILSAFE_RECEIVER); moduleState[module].counter = 1000; } add8ChannelsFrame(module, 0, sendFailsafe); @@ -194,8 +215,11 @@ void Pxx1Pulses::setupFrame(uint8_t module) } return; } -#endif + // Slow PXX1: + // - if more than 8 channels shall be sent, it happens + // in alternating frames + // if (moduleState[module].counter & 0x01) { // channelsCount is shifted by 8 sendUpperChannels = g_model.moduleData[module].channelsCount; @@ -207,7 +231,8 @@ void Pxx1Pulses::setupFrame(uint8_t module) } } else { if (moduleState[module].counter == 0) { - sendFailsafe = (g_model.moduleData[module].failsafeMode != FAILSAFE_NOT_SET && g_model.moduleData[module].failsafeMode != FAILSAFE_RECEIVER); + sendFailsafe = (g_model.moduleData[module].failsafeMode != FAILSAFE_NOT_SET && + g_model.moduleData[module].failsafeMode != FAILSAFE_RECEIVER); } } @@ -218,129 +243,167 @@ void Pxx1Pulses::setupFrame(uint8_t module) } } -template class Pxx1Pulses >; -template class Pxx1Pulses >; +template class Pxx1Pulses; template class Pxx1Pulses; -#if defined(INTMODULE_USART) && defined(INTERNAL_MODULE_PXX1) -#include "intmodule_serial_driver.h" - -static const etx_serial_init pxx1SerialInit = { - .baudrate = INTMODULE_PXX1_SERIAL_BAUDRATE, - .parity = ETX_Parity_None, - .stop_bits = ETX_StopBits_One, - .word_length = ETX_WordLength_8, - .rx_enable = false, +static const etx_serial_init pxx1SerialCfg = { + .baudrate = 0, + .encoding = ETX_Encoding_8N1, + .direction = ETX_Dir_TX, + .polarity = ETX_Pol_Normal, }; -static void* pxx1InitInternal(uint8_t module) +static const etx_serial_driver_t* _sport_drv; +static void* _sport_ctx; + +static void pxx1SportSensorPolling() { - void* uart_ctx = IntmoduleSerialDriver.init(&pxx1SerialInit); + if (outputTelemetryBuffer.destination != TELEMETRY_ENDPOINT_SPORT) + return; -#if defined(INTMODULE_HEARTBEAT) - init_intmodule_heartbeat(); -#endif - mixerSchedulerSetPeriod(INTERNAL_MODULE, INTMODULE_PXX1_SERIAL_PERIOD); - INTERNAL_MODULE_ON(); + // Match sensor polling from the module + // -> detect <0x7E [Physical ID]> as the last sequence + uint8_t b; + if (_sport_drv->getLastByte(_sport_ctx, 2, &b) <= 0 || b != START_STOP) + return; + if (_sport_drv->getLastByte(_sport_ctx, 1, &b) <= 0 || + b != outputTelemetryBuffer.sport.physicalId) + return; - return uart_ctx; + _sport_drv->sendBuffer(_sport_ctx, + outputTelemetryBuffer.data + 1, + outputTelemetryBuffer.size - 1); + + outputTelemetryBuffer.reset(); } -static void pxx1DeInitInternal(void* context) +static void* pxx1Init(uint8_t module) { - INTERNAL_MODULE_OFF(); - mixerSchedulerSetPeriod(INTERNAL_MODULE, 0); -#if defined(INTMODULE_HEARTBEAT) - stop_intmodule_heartbeat(); -#endif - IntmoduleSerialDriver.deinit(context); + etx_module_state_t* mod_st = nullptr; + etx_serial_init txCfg(pxx1SerialCfg); + + if (module == INTERNAL_MODULE) { + + txCfg.baudrate = _pxx1_internal_baudrate; + mod_st = modulePortInitSerial(module, ETX_MOD_PORT_UART, &txCfg); + + if (!mod_st) { + // assume that radios that don't have an internal UART + // will have a module that uses legacy PXX1 (PWM) + txCfg.encoding = ETX_Encoding_PXX1_PWM; + mod_st = modulePortInitSerial(module, ETX_MOD_PORT_SOFT_INV, &txCfg); + } + + if (!mod_st) return nullptr; + } + + if (module == EXTERNAL_MODULE) { + + // Init driver (timer / serial) based on module type + uint8_t type = g_model.moduleData[module].type; + switch(type) { + + case MODULE_TYPE_R9M_LITE_PXX1: { + txCfg.baudrate = EXTMODULE_PXX1_SERIAL_BAUDRATE; + mod_st = modulePortInitSerial(module, ETX_MOD_PORT_UART, &txCfg); + if (!mod_st) return nullptr; + } break; + + case MODULE_TYPE_XJT_PXX1: + case MODULE_TYPE_R9M_PXX1: { + txCfg.encoding = ETX_Encoding_PXX1_PWM; + mod_st = modulePortInitSerial(module, ETX_MOD_PORT_SOFT_INV, &txCfg); + if (!mod_st) return nullptr; + } break; + + default: + // unknown module: bail out! + return nullptr; + } + } + + // Init telemetry RX + etx_serial_init rxCfg(pxx1SerialCfg); + rxCfg.baudrate = FRSKY_SPORT_BAUDRATE; + rxCfg.direction = ETX_Dir_TX_RX; + + // TODO: handle init errors properly + if (modulePortInitSerial(module, ETX_MOD_PORT_SPORT, &rxCfg) != nullptr) { + auto drv = modulePortGetSerialDrv(mod_st->rx); + auto ctx = modulePortGetCtx(mod_st->rx); + if (drv && ctx && drv->setIdleCb) { + _sport_drv = drv; + _sport_ctx = ctx; + drv->setIdleCb(ctx, pxx1SportSensorPolling); + } + } + + // Store PXX1 type in 'user_data' + if (txCfg.encoding == ETX_Encoding_PXX1_PWM || + txCfg.baudrate == PXX1_DEFAULT_SERIAL_BAUDRATE) { + + // Legacy / slow PXX1 + mixerSchedulerSetPeriod(module, PXX1_DEFAULT_PERIOD); + if (txCfg.encoding == ETX_Encoding_PXX1_PWM) { + mod_st->user_data = (void*)Pxx1Type::PWM; + } else { + mod_st->user_data = (void*)Pxx1Type::SLOW_SERIAL; + } + } else { + // Fast PXX1 + mixerSchedulerSetPeriod(module, PXX1_FAST_PERIOD); + mod_st->user_data = (void*)Pxx1Type::FAST_SERIAL; + } + + return mod_st; } -static void pxx1SetupPulsesInternal(void* context, int16_t* channels, uint8_t nChannels) +static void pxx1DeInit(void* ctx) { - (void)context; - - // TODO: - (void)channels; - (void)nChannels; - intmodulePulsesData.pxx_uart.setupFrame(INTERNAL_MODULE); + auto mod_st = (etx_module_state_t*)ctx; + modulePortDeInit(mod_st); } -static void pxx1SendPulsesInternal(void* context) +static void pxx1SendPulses(void* ctx, uint8_t* buffer, int16_t* channels, uint8_t nChannels) { - IntmoduleSerialDriver.sendBuffer(context, intmodulePulsesData.pxx_uart.getData(), - intmodulePulsesData.pxx_uart.getSize()); -} - -const etx_module_driver_t Pxx1InternalSerialDriver = { - .protocol = PROTOCOL_CHANNELS_PXX1_SERIAL, - .init = pxx1InitInternal, - .deinit = pxx1DeInitInternal, - .setupPulses = pxx1SetupPulsesInternal, - .sendPulses = pxx1SendPulsesInternal, -}; - -#endif - -#if defined(EXTMODULE_USART) && defined(HARDWARE_EXTERNAL_MODULE_SIZE_SML) -#include "extmodule_serial_driver.h" - -static const etx_serial_init pxx1ExtSerialInit = { - .baudrate = EXTMODULE_PXX1_SERIAL_BAUDRATE, - .parity = ETX_Parity_None, - .stop_bits = ETX_StopBits_One, - .word_length = ETX_WordLength_8, - .rx_enable = false, -}; - -static void* pxx1InitExternal(uint8_t module) -{ - auto drv = extmoduleGetSerialPort(); - if (!drv) return nullptr; - - void* uart_ctx = drv->init(&pxx1ExtSerialInit); - - mixerSchedulerSetPeriod(EXTERNAL_MODULE, EXTMODULE_PXX1_SERIAL_PERIOD); - EXTERNAL_MODULE_ON(); - - return uart_ctx; -} - -static void pxx1DeInitExternal(void* context) -{ - EXTERNAL_MODULE_OFF(); - mixerSchedulerSetPeriod(EXTERNAL_MODULE, 0); - - auto drv = extmoduleGetSerialPort(); - if (drv) drv->deinit(context); -} - -static void pxx1SetupPulsesExternal(void* context, int16_t* channels, uint8_t nChannels) -{ - (void)context; - // TODO: (void)channels; (void)nChannels; - extmodulePulsesData.pxx_uart.setupFrame(EXTERNAL_MODULE); + auto mod_st = (etx_module_state_t*)ctx; + auto module = modulePortGetModule(mod_st); + auto pxx1_type = (Pxx1Type)(uintptr_t)mod_st->user_data; + + uint32_t frame_len = 0; + if (pxx1_type == Pxx1Type::PWM) { + PwmPxx1Pulses frame(buffer); + frame.setupFrame(module, pxx1_type); + frame_len = frame.getSize(); + } else { + UartPxx1Pulses frame(buffer); + frame.setupFrame(module, pxx1_type); + frame_len = frame.getSize(); + } + + if (frame_len == 0) return; + + auto drv = modulePortGetSerialDrv(mod_st->tx); + auto drv_ctx = modulePortGetCtx(mod_st->tx); + drv->sendBuffer(drv_ctx, buffer, frame_len); } -static void pxx1SendPulsesExternal(void* context) +static void pxx1ProcessData(void* ctx, uint8_t data, uint8_t* buffer, uint8_t* len) { - auto drv = extmoduleGetSerialPort(); - if (!drv) return; + auto mod_st = (etx_module_state_t*)ctx; + auto module = modulePortGetModule(mod_st); - drv->sendBuffer(context, extmodulePulsesData.pxx_uart.getData(), - extmodulePulsesData.pxx_uart.getSize()); + processFrskySportTelemetryData(module, data, buffer, *len); } -const etx_module_driver_t Pxx1ExternalSerialDriver = { - .protocol = PROTOCOL_CHANNELS_PXX1_SERIAL, - .init = pxx1InitExternal, - .deinit = pxx1DeInitExternal, - .setupPulses = pxx1SetupPulsesExternal, - .sendPulses = pxx1SendPulsesExternal, +const etx_proto_driver_t Pxx1Driver = { + .protocol = PROTOCOL_CHANNELS_PXX1, + .init = pxx1Init, + .deinit = pxx1DeInit, + .sendPulses = pxx1SendPulses, + .processData = pxx1ProcessData, }; - -#endif diff --git a/radio/src/pulses/pxx1.h b/radio/src/pulses/pxx1.h index 1be0335ed..d21137d93 100644 --- a/radio/src/pulses/pxx1.h +++ b/radio/src/pulses/pxx1.h @@ -19,160 +19,11 @@ * GNU General Public License for more details. */ -#ifndef _PULSES_PXX1_H_ -#define _PULSES_PXX1_H_ - -#include "pxx.h" -#include "crc.h" +#pragma once #include "hal/module_driver.h" -class Pxx1CrcMixin { - protected: - void initCrc() - { - crc = 0; - } +// Set the board specific PXX1 baudrate (X-lite only?) +void pxx1SetInternalBaudrate(uint32_t baudrate); - void addToCrc(uint8_t byte) - { - crc = (crc << 8) ^ (crc16tab[CRC_1189][((crc >> 8) ^ byte) & 0xFF]); - } - - uint16_t crc; -}; - -template -class StandardPxx1Transport: public BitTransport, public Pxx1CrcMixin { - protected: - uint8_t ones_count; - - void initFrame(uint32_t period) - { - BitTransport::initFrame(period); - ones_count = 0; - } - - void addByte(uint8_t byte) - { - Pxx1CrcMixin::addToCrc(byte); - addByteWithoutCrc(byte); - }; - - void addRawByte(uint8_t byte) - { - for (uint8_t i = 0; i < 8; i++) { - if (byte & 0x80) - BitTransport::addPart(1); - else - BitTransport::addPart(0); - byte <<= 1; - } - } - - void addByteWithoutCrc(uint8_t byte) - { - for (uint8_t i = 0; i < 8; i++) { - addBit(byte & 0x80); - byte <<= 1; - } - } - - void addBit(uint8_t bit) - { - if (bit) { - BitTransport::addPart(1); - if (++ones_count == 5) { - ones_count = 0; - BitTransport::addPart(0); // Stuff a 0 bit in - } - } - else { - BitTransport::addPart(0); - ones_count = 0; - } - } -}; - -class UartPxx1Transport: public DataBuffer, public Pxx1CrcMixin { - protected: - void initFrame(uint32_t period) - { - initBuffer(); - } - - void addByte(uint8_t byte) - { - Pxx1CrcMixin::addToCrc(byte); - addWithByteStuffing(byte); - } - - void addRawByte(uint8_t byte) - { - *ptr++ = byte; - } - - void addByteWithoutCrc(uint8_t byte) - { - addWithByteStuffing(byte); - } - - void addWithByteStuffing(uint8_t byte) - { - if (0x7E == byte) { - addRawByte(0x7D); - addRawByte(0x5E); - } - else if (0x7D == byte) { - addRawByte(0x7D); - addRawByte(0x5D); - } - else { - addRawByte(byte); - } - } - - void addTail() - { - // nothing - } -}; - -template -class Pxx1Pulses: public PxxTransport -{ - public: - void setupFrame(uint8_t port); - - protected: - void addHead() - { - // send 7E, do not CRC - PxxTransport::addRawByte(0x7E); - } - - void addCrc() - { - PxxTransport::addByteWithoutCrc(Pxx1CrcMixin::crc >> 8); - PxxTransport::addByteWithoutCrc(Pxx1CrcMixin::crc); - } - - void addFlag1(uint8_t port, uint8_t sendFailsafe); - void addExtraFlags(uint8_t port); - void addChannels(uint8_t port, uint8_t sendFailsafe, uint8_t sendUpperChannels); - void add8ChannelsFrame(uint8_t port, uint8_t sendUpperChannels, uint8_t sendFailsafe); -}; - -typedef Pxx1Pulses UartPxx1Pulses; -typedef Pxx1Pulses> PwmPxx1Pulses; -typedef Pxx1Pulses> SerialPxx1Pulses; - -#if defined(INTMODULE_USART) -extern const etx_module_driver_t Pxx1InternalSerialDriver; -#endif - -#if defined(EXTMODULE_USART) -extern const etx_module_driver_t Pxx1ExternalSerialDriver; -#endif - -#endif +extern const etx_proto_driver_t Pxx1Driver; diff --git a/radio/src/pulses/pxx1_transport.h b/radio/src/pulses/pxx1_transport.h new file mode 100644 index 000000000..0a11c47ce --- /dev/null +++ b/radio/src/pulses/pxx1_transport.h @@ -0,0 +1,212 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#pragma once + +#include "pxx.h" +#include "crc.h" + +class Pxx1CrcMixin { + protected: + void initCrc() + { + crc = 0; + } + + void addToCrc(uint8_t byte) + { + crc = (crc << 8) ^ (crc16tab[CRC_1189][((crc >> 8) ^ byte) & 0xFF]); + } + + uint16_t crc; +}; + +class StandardPxx1Transport: public Pxx1CrcMixin { + protected: + const uint8_t* buffer; + uint8_t* ptr; + uint8_t byte = 0; + uint8_t bits_count = 0; + uint8_t ones_count = 0; + + StandardPxx1Transport(uint8_t* buffer) + : buffer(buffer), ptr(buffer) + { + } + + void addByte(uint8_t b) + { + Pxx1CrcMixin::addToCrc(b); + addByteWithoutCrc(b); + }; + + void addRawByte(uint8_t b) + { + for (uint8_t i = 0; i < 8; i++) { + // MSB first + if (b & 0x80) addPart(1); + else addPart(0); + b <<= 1; + } + } + + void addByteWithoutCrc(uint8_t b) + { + for (uint8_t i = 0; i < 8; i++) { + // MSB first + addBit(b & 0x80); + b <<= 1; + } + } + + void addBit(uint8_t bit) + { + if (bit) { + addPart(1); + if (++ones_count == 5) { + ones_count = 0; + addPart(0); // Stuff a 0 bit in + } + } + else { + addPart(0); + ones_count = 0; + } + } + + void addPart(uint8_t bit) + { + // MSB first + byte <<= 1; + if (bit & 1) { + byte |= 1; + } + if (++bits_count >= 8) { + *ptr++ = byte; + bits_count = 0; + } + } + + void addTail() + { + if (bits_count > 0) + *ptr++ = byte << (8 - bits_count); + } + + public: + uint32_t getSize() + { + uint32_t size = (ptr - buffer) * 8; + if (bits_count > 0) + size -= (8 - bits_count); + + return size; + } +}; + +class UartPxx1Transport: public Pxx1CrcMixin { + protected: + const uint8_t* buffer; + uint8_t* ptr; + + UartPxx1Transport(uint8_t* buffer) + : buffer(buffer), ptr(buffer) + { + } + + void addByte(uint8_t byte) + { + Pxx1CrcMixin::addToCrc(byte); + addWithByteStuffing(byte); + } + + void addRawByte(uint8_t byte) + { + *ptr++ = byte; + } + + void addByteWithoutCrc(uint8_t byte) + { + addWithByteStuffing(byte); + } + + void addWithByteStuffing(uint8_t byte) + { + if (0x7E == byte) { + addRawByte(0x7D); + addRawByte(0x5E); + } + else if (0x7D == byte) { + addRawByte(0x7D); + addRawByte(0x5D); + } + else { + addRawByte(byte); + } + } + + void addTail() + { + // nothing + } + + public: + uint32_t getSize() + { + return ptr - buffer; + } +}; + + +enum class Pxx1Type : uintptr_t { + PWM, + SLOW_SERIAL, + FAST_SERIAL, +}; + +template +class Pxx1Pulses: public PxxTransport +{ + public: + Pxx1Pulses(uint8_t* buffer); + void setupFrame(uint8_t module, Pxx1Type type); + + protected: + void addHead() + { + // send 7E, do not CRC + PxxTransport::addRawByte(0x7E); + } + + void addCrc() + { + PxxTransport::addByteWithoutCrc(Pxx1CrcMixin::crc >> 8); + PxxTransport::addByteWithoutCrc(Pxx1CrcMixin::crc); + } + + void addFlag1(uint8_t port, uint8_t sendFailsafe); + void addExtraFlags(uint8_t port); + void addChannels(uint8_t port, uint8_t sendFailsafe, uint8_t sendUpperChannels); + void add8ChannelsFrame(uint8_t port, uint8_t sendUpperChannels, uint8_t sendFailsafe); +}; + +typedef Pxx1Pulses UartPxx1Pulses; +typedef Pxx1Pulses PwmPxx1Pulses; diff --git a/radio/src/pulses/pxx2.cpp b/radio/src/pulses/pxx2.cpp index b6ca1572c..688d6c0dc 100644 --- a/radio/src/pulses/pxx2.cpp +++ b/radio/src/pulses/pxx2.cpp @@ -21,24 +21,117 @@ #include #include "opentx.h" -#include "pulses/pxx2.h" #include "io/frsky_firmware_update.h" #include "libopenui/src/libopenui_file.h" #include "mixer_scheduler.h" #include "heartbeat_driver.h" #include "timers_driver.h" -#if defined(INTMODULE_USART) -#include "intmodule_serial_driver.h" +#include "pxx2.h" +#include "pxx2_transport.h" -const etx_serial_init pxx2SerialInitParams = { +static const etx_serial_init pxx2SerialInitParams = { .baudrate = PXX2_HIGHSPEED_BAUDRATE, - .parity = ETX_Parity_None, - .stop_bits = ETX_StopBits_One, - .word_length = ETX_WordLength_8, - .rx_enable = true, + .encoding = ETX_Encoding_8N1, + .direction = ETX_Dir_TX_RX, + .polarity = ETX_Pol_Normal, }; + +#include "hal/module_port.h" + +/* Module options order: + * - External antenna (0x01) + * - Power (0x02) + * - Spektrum analyser (0x04) + * - Power meter (0x08) + */ +static const uint8_t PXX2ModuleOptions[] = { +#if defined(SIMU) + 0b11111111, // None = display all options on SIMU +#else + 0b00000000, // None = no option available on unknown modules #endif + 0b00000001, // XJT + 0b00000001, // ISRM + 0b00001101, // ISRM-PRO + 0b00000101, // ISRM-S + 0b00000010, // R9M + 0b00000010, // R9MLite + 0b00000110, // R9MLite-PRO + 0b00000100, // ISRM-N + 0b00000100, // ISRM-S-X9 + 0b00000101, // ISRM-S-X10E + 0b00000001, // XJT_LITE + 0b00000101, // ISRM-S-X10S + 0b00000100, // ISRM-X9LITES +}; + +uint8_t getPXX2ModuleOptions(uint8_t modelId) +{ + if (modelId < DIM(PXX2ModuleOptions)) + return PXX2ModuleOptions[modelId]; + else + return PXX2ModuleOptions[0]; +} + +bool isPXX2ModuleOptionAvailable(uint8_t modelId, uint8_t option) +{ + return getPXX2ModuleOptions(modelId) & (1 << option); +} + +/* Receiver options order: + * - OTA (0x01) + */ +static const uint8_t PXX2ReceiverOptions[] = { +#if defined(SIMU) + 0b11111111, // None = display all options on SIMU +#else + 0b00000000, // None = display all options on SIMU +#endif + 0b11111110, // X8R + 0b11111110, // RX8R + 0b11111110, // RX8R-PRO + 0b11111111, // RX6R + 0b11111111, // RX4R + 0b11111111, // G-RX8 + 0b11111111, // G-RX6 + 0b11111110, // X6R + 0b11111110, // X4R + 0b11111110, // X4R-SB + 0b11111110, // XSR + 0b11111110, // XSR-M + 0b11111111, // RXSR + 0b11111110, // S6R + 0b11111110, // S8R + 0b11111110, // XM + 0b11111110, // XM+ + 0b11111110, // XMR + 0b11111110, // R9 + 0b11111110, // R9-SLIM + 0b11111110, // R9-SLIM+ + 0b11111110, // R9-MINI + 0b11111110, // R9-MM + 0b11111111, // R9-STAB+OTA + 0b11111111, // R9-MINI+OTA + 0b11111111, // R9-MM+OTA + 0b11111111, // R9-SLIM+OTA + 0b11111111, // ARCHER-X + 0b11111111, // R9MX + 0b11111111, // R9SX +}; + +uint8_t getPXX2ReceiverOptions(uint8_t modelId) +{ + if (modelId < DIM(PXX2ReceiverOptions)) + return PXX2ReceiverOptions[modelId]; + else + return PXX2ReceiverOptions[0]; +} + +bool isPXX2ReceiverOptionAvailable(uint8_t modelId, uint8_t option) +{ + return getPXX2ReceiverOptions(modelId) & (1 << option); +} bool isPXX2PowerAvailable(const PXX2HardwareInformation& info, int value) { @@ -435,10 +528,12 @@ void Pxx2Pulses::setupShareMode(uint8_t module) Pxx2Transport::addByte(reusableBuffer.moduleSetup.pxx2.shareReceiverIndex); } -void Pxx2Pulses::sendOtaUpdate(uint8_t module, const char * rxName, uint32_t address, const char * data) -{ - initFrame(); +// TODO: move up +static void _send_frame(etx_module_state_t* mod_st, uint8_t* buffer, uint32_t len); +void Pxx2Pulses::sendOtaUpdate(uint8_t module, const char* rxName, + uint32_t address, const char* data) +{ addFrameType(PXX2_TYPE_C_OTA, PXX2_TYPE_ID_OTA); if (rxName) { @@ -459,22 +554,11 @@ void Pxx2Pulses::sendOtaUpdate(uint8_t module, const char * rxName, uint32_t add } endFrame(); - -#if defined(HARDWARE_INTERNAL_MODULE) - if (module == INTERNAL_MODULE) { - intmoduleSendNextFrame(); - } -#endif -#if defined(HARDWARE_EXTERNAL_MODULE) - if (module == EXTERNAL_MODULE) { - extmoduleSendNextFrame(); - } -#endif } void Pxx2Pulses::setupAuthenticationFrame(uint8_t module, uint8_t mode, const uint8_t * outputMessage) { - initFrame(); + // initFrame(); addFrameType(PXX2_TYPE_C_MODULE, PXX2_TYPE_ID_AUTHENTICATION); @@ -498,7 +582,7 @@ bool Pxx2Pulses::setupFrame(uint8_t module, int16_t* channels, uint8_t nChannels return false; } - initFrame(); + // initFrame(); switch (moduleState[module].mode) { case MODULE_MODE_GET_HARDWARE_INFO: @@ -548,216 +632,96 @@ bool Pxx2Pulses::setupFrame(uint8_t module, int16_t* channels, uint8_t nChannels return true; } -bool Pxx2OtaUpdate::waitStep(uint8_t step, uint8_t timeout) +static void* pxx2Init(uint8_t module) { - OtaUpdateInformation * destination = moduleState[module].otaUpdateInformation; - uint8_t elapsed = 0; + etx_module_state_t* mod_st = nullptr; + etx_serial_init params(pxx2SerialInitParams); - watchdogSuspend(100 /*1s*/); + if (module == INTERNAL_MODULE) { - while (step != destination->step) { - if (elapsed++ > timeout) { - return false; - } - RTOS_WAIT_MS(1); - telemetryWakeup(); + params.baudrate = PXX2_HIGHSPEED_BAUDRATE; + mod_st = modulePortInitSerial(module, ETX_MOD_PORT_UART, ¶ms); + if (!mod_st) return nullptr; + resetAccessAuthenticationCount(); } - return true; -} + if (module == EXTERNAL_MODULE) { -const char * Pxx2OtaUpdate::nextStep(uint8_t step, const char * rxName, uint32_t address, const uint8_t * buffer) -{ - OtaUpdateInformation * destination = moduleState[module].otaUpdateInformation; + uint8_t type = g_model.moduleData[module].type; + switch(type) { - destination->step = step; - destination->address = address; + case MODULE_TYPE_R9M_LITE_PXX2: + params.baudrate = PXX2_LOWSPEED_BAUDRATE; + break; - for (uint8_t retry = 0;; retry++) { - if (module == EXTERNAL_MODULE) { - extmodulePulsesData.pxx2.sendOtaUpdate(module, rxName, address, (const char *) buffer); - } - else if (module == INTERNAL_MODULE) { - intmodulePulsesData.pxx2.sendOtaUpdate(module, rxName, address, (const char *) buffer); - } - if (waitStep(step + 1, 20)) { + case MODULE_TYPE_ISRM_PXX2: + case MODULE_TYPE_R9M_PXX2: + case MODULE_TYPE_XJT_LITE_PXX2: + case MODULE_TYPE_R9M_LITE_PRO_PXX2: + params.baudrate = PXX2_HIGHSPEED_BAUDRATE; + break; + + default: return nullptr; } - else if (retry == 100) { - return "Transfer failed"; - } + + mod_st = modulePortInitSerial(module, ETX_MOD_PORT_UART, ¶ms); + if (!mod_st) return nullptr; } + + mixerSchedulerSetPeriod(module, PXX2_DEFAULT_PERIOD); + return mod_st; } -const char * Pxx2OtaUpdate::doFlashFirmware(const char * filename, ProgressHandler progressHandler) +static void pxx2DeInit(void* ctx) { - FIL file; - uint8_t buffer[32]; - UINT count; - const char * result; + auto mod_st = (etx_module_state_t*)ctx; + modulePortDeInit(mod_st); +} - result = nextStep(OTA_UPDATE_START, rxName, 0, nullptr); - if (result) { - return result; - } +static void _send_frame(etx_module_state_t* mod_st, uint8_t* buffer, uint32_t len) +{ + auto drv = modulePortGetSerialDrv(mod_st->tx); + auto ctx = modulePortGetCtx(mod_st->tx); + drv->sendBuffer(ctx, buffer, len); +} - if (f_open(&file, filename, FA_READ) != FR_OK) { - return "Open file failed"; - } +static void pxx2SendPulses(void* ctx, uint8_t* buffer, int16_t* channels, uint8_t nChannels) +{ + auto mod_st = (etx_module_state_t*)ctx; + auto module = modulePortGetModule(mod_st); - uint32_t size; - const char * ext = getFileExtension(filename); - if (ext && !strcasecmp(ext, FRSKY_FIRMWARE_EXT)) { - FrSkyFirmwareInformation * information = (FrSkyFirmwareInformation *) buffer; - if (f_read(&file, buffer, sizeof(FrSkyFirmwareInformation), &count) != FR_OK || count != sizeof(FrSkyFirmwareInformation)) { - f_close(&file); - return "Format error"; - } - size = information->size; - } - else { - size = f_size(&file); - } + if (module == INTERNAL_MODULE) { + Pxx2Pulses pxx2(buffer); + bool should_send = pxx2.setupFrame(module, channels, nChannels); - uint32_t done = 0; - while (1) { - progressHandler(getBasename(filename), STR_OTA_UPDATE, done, size); - if (f_read(&file, buffer, sizeof(buffer), &count) != FR_OK) { - f_close(&file); - return "Read file failed"; + if (moduleState[module].mode == MODULE_MODE_SPECTRUM_ANALYSER || + moduleState[module].mode == MODULE_MODE_POWER_METER) { + + // backup normal period into 'user_data' + if (!mod_st->user_data) { + mod_st->user_data = (void*)(uintptr_t)mixerSchedulerGetPeriod(module); + } + mixerSchedulerSetPeriod(module, PXX2_TOOLS_PERIOD); + } else if (mod_st->user_data) { + // restore old scheduling period + uintptr_t period = (uintptr_t)mod_st->user_data; + mixerSchedulerSetPeriod(module, period); + mod_st->user_data = nullptr; } - result = nextStep(OTA_UPDATE_TRANSFER, nullptr, done, buffer); - if (result) { - return result; - } - - if (count < sizeof(buffer)) { - f_close(&file); - break; - } - - done += count; + if (!should_send) return; + _send_frame(mod_st, buffer, pxx2.getSize()); } - return nextStep(OTA_UPDATE_EOF, nullptr, done, nullptr); -} - -void Pxx2OtaUpdate::flashFirmware(const char * filename, ProgressHandler progressHandler) -{ - pausePulses(); - - watchdogSuspend(100 /*1s*/); - RTOS_WAIT_MS(100); - - moduleState[module].mode = MODULE_MODE_OTA_UPDATE; - const char * result = doFlashFirmware(filename, progressHandler); - moduleState[module].mode = MODULE_MODE_NORMAL; - - AUDIO_PLAY(AU_SPECIAL_SOUND_BEEP1 ); - BACKLIGHT_ENABLE(); - - if (result) { - POPUP_WARNING(STR_FIRMWARE_UPDATE_ERROR, result); - } - else { - POPUP_INFORMATION(STR_FIRMWARE_UPDATE_SUCCESS); - } - - watchdogSuspend(100); - RTOS_WAIT_MS(100); - - resumePulses(); -} - -struct PXX2State { - uint8_t module; - Pxx2Pulses* pulses; - const etx_serial_driver_t* uart_drv; - void* uart_ctx; - - void init(uint8_t _module, Pxx2Pulses* _pulses, const etx_serial_driver_t* _drv, void* _ctx) - { - module = _module; - pulses = _pulses; - uart_drv = _drv; - uart_ctx = _ctx; - } - - void deinit() { uart_drv->deinit(uart_ctx); } -}; - -static PXX2State pxx2State[NUM_MODULES]; - -static void* pxx2InitInternal(uint8_t module) -{ -#if defined(INTMODULE_HEARTBEAT) - // use backup trigger (1 ms later) - init_intmodule_heartbeat(); -#endif - mixerSchedulerSetPeriod(module, PXX2_PERIOD); - INTERNAL_MODULE_ON(); - - resetAccessAuthenticationCount(); - - auto state = &pxx2State[module]; - state->init(module, &intmodulePulsesData.pxx2, &IntmoduleSerialDriver, - IntmoduleSerialDriver.init(&pxx2SerialInitParams)); - - return state; -} - -static void pxx2DeInitInternal(void* context) -{ - auto state = (PXX2State*)context; - state->deinit(); - - INTERNAL_MODULE_OFF(); -#if defined(INTMODULE_HEARTBEAT) - stop_intmodule_heartbeat(); -#endif - mixerSchedulerSetPeriod(state->module, 0); -} - -// TODO: move this to Pxx2Pulses -static bool pxx2InternalSendNextFrame = true; - -static void pxx2SetupPulsesInternal(void* context, int16_t* channels, uint8_t nChannels) -{ - auto state = (PXX2State*)context; - - auto pulses = state->pulses; - auto module = state->module; - pxx2InternalSendNextFrame = pulses->setupFrame(module, channels, nChannels); - - if (moduleState[module].mode == MODULE_MODE_SPECTRUM_ANALYSER || - moduleState[module].mode == MODULE_MODE_POWER_METER) { - mixerSchedulerSetPeriod(module, PXX2_TOOLS_PERIOD); - } else { - mixerSchedulerSetPeriod(module, PXX2_PERIOD); + if (module == EXTERNAL_MODULE) { + Pxx2Pulses pxx2(buffer); + pxx2.setupFrame(module, channels, nChannels); + _send_frame(mod_st, buffer, pxx2.getSize()); } } -static void pxx2SendPulsesInternal(void* context) -{ - if (pxx2InternalSendNextFrame) { - auto state = (PXX2State*)context; - auto drv = state->uart_drv; - auto ctx = state->uart_ctx; - auto pulses = state->pulses; - drv->sendBuffer(ctx, pulses->getData(), pulses->getSize()); - } -} - -static int pxx2GetByte(void* context, uint8_t* data) -{ - auto state = (PXX2State*)context; - auto drv = state->uart_drv; - auto ctx = state->uart_ctx; - return drv->getByte(ctx, data); -} - -static void pxx2ProcessData(void* context, uint8_t data, uint8_t* buffer, uint8_t* len) +static void pxx2ProcessData(void* ctx, uint8_t data, uint8_t* buffer, uint8_t* len) { if (*len == 0 && data != START_STOP) { return; @@ -802,99 +766,21 @@ static void pxx2ProcessData(void* context, uint8_t data, uint8_t* buffer, uint8_ return; } - auto state = (PXX2State*)context; - auto module = state->module; - auto drv = state->uart_drv; - auto ctx = state->uart_ctx; - processPXX2Frame(module, frame, drv, ctx); + auto mod_st = (etx_module_state_t*)ctx; + auto module = modulePortGetModule(mod_st); + auto drv = modulePortGetSerialDrv(mod_st->rx); + auto drv_ctx = modulePortGetCtx(mod_st->rx); + processPXX2Frame(module, frame, drv, drv_ctx); *len = 0; } - #include "hal/module_driver.h" -#include "extmodule_serial_driver.h" +// #include "extmodule_serial_driver.h" -const etx_module_driver_t Pxx2InternalDriver = { - .protocol = PROTOCOL_CHANNELS_PXX2_HIGHSPEED, - .init = pxx2InitInternal, - .deinit = pxx2DeInitInternal, - .setupPulses = pxx2SetupPulsesInternal, - .sendPulses = pxx2SendPulsesInternal, - .getByte = pxx2GetByte, - .processData = pxx2ProcessData, -}; - -static void* pxx2InitExternal(uint8_t module, uint32_t baudrate) -{ - etx_serial_init params(pxx2SerialInitParams); - params.baudrate = baudrate; - - mixerSchedulerSetPeriod(module, PXX2_NO_HEARTBEAT_PERIOD); - EXTERNAL_MODULE_ON(); - - telemetryProtocol = PROTOCOL_TELEMETRY_FRSKY_SPORT; - - auto state = &pxx2State[module]; - auto drv = extmoduleGetSerialPort(); - if (!drv) return nullptr; - - state->init(module, &extmodulePulsesData.pxx2, drv, drv->init(¶ms)); - return state; -} - -static void* pxx2InitExtLowSpeed(uint8_t module) -{ - return pxx2InitExternal(module, PXX2_LOWSPEED_BAUDRATE); -} - -static void* pxx2InitExtHighSpeed(uint8_t module) -{ - return pxx2InitExternal(module, PXX2_HIGHSPEED_BAUDRATE); -} - -static void pxx2DeInitExternal(void* context) -{ - auto state = (PXX2State*)context; - if (state) state->deinit(); - - EXTERNAL_MODULE_OFF(); - mixerSchedulerSetPeriod(EXTERNAL_MODULE, 0); - telemetryProtocol = 0xFF; -} - -static void pxx2SetupPulsesExternal(void* context, int16_t* channels, uint8_t nChannels) -{ - auto state = (PXX2State*)context; - auto pulses = state->pulses; - auto module = state->module; - pulses->setupFrame(module, channels, nChannels); -} - -static void pxx2SendPulsesExternal(void* context) -{ - auto state = (PXX2State*)context; - auto drv = state->uart_drv; - auto ctx = state->uart_ctx; - auto pulses = state->pulses; - drv->sendBuffer(ctx, pulses->getData(), pulses->getSize()); -} - -const etx_module_driver_t Pxx2ExternalDriver = { - .protocol = PROTOCOL_CHANNELS_PXX2_HIGHSPEED, - .init = pxx2InitExtHighSpeed, - .deinit = pxx2DeInitExternal, - .setupPulses = pxx2SetupPulsesExternal, - .sendPulses = pxx2SendPulsesExternal, - .getByte = pxx2GetByte, - .processData = pxx2ProcessData, -}; - -const etx_module_driver_t Pxx2LowSpeedExternalDriver = { - .protocol = PROTOCOL_CHANNELS_PXX2_LOWSPEED, - .init = pxx2InitExtLowSpeed, - .deinit = pxx2DeInitExternal, - .setupPulses = pxx2SetupPulsesExternal, - .sendPulses = pxx2SendPulsesExternal, - .getByte = pxx2GetByte, +const etx_proto_driver_t Pxx2Driver = { + .protocol = PROTOCOL_CHANNELS_PXX2, + .init = pxx2Init, + .deinit = pxx2DeInit, + .sendPulses = pxx2SendPulses, .processData = pxx2ProcessData, }; diff --git a/radio/src/pulses/pxx2.h b/radio/src/pulses/pxx2.h index a10144f4f..6235a2915 100644 --- a/radio/src/pulses/pxx2.h +++ b/radio/src/pulses/pxx2.h @@ -22,13 +22,12 @@ #ifndef _PULSES_PXX2_H_ #define _PULSES_PXX2_H_ -#include "fifo.h" -#include "popups.h" #include "pxx.h" - -#include "hal/serial_driver.h" #include "hal/module_driver.h" +#include "dataconstants.h" +#include "opentx_types.h" + #define PXX2_TYPE_C_MODULE 0x01 #define PXX2_TYPE_ID_REGISTER 0x01 #define PXX2_TYPE_ID_BIND 0x02 @@ -67,11 +66,7 @@ #define PXX2_HW_INFO_TX_ID 0xFF -#if defined(COLORLCD) - #define SPECTRUM_ANALYSER_POWER_FLOOR -120 /*dBm*/ -#else - #define SPECTRUM_ANALYSER_POWER_FLOOR -120 /*dBm*/ -#endif +#define SPECTRUM_ANALYSER_POWER_FLOOR -120 /*dBm*/ #define PXX2_AUTH_REFUSED_FLAG 0xA5 @@ -92,30 +87,7 @@ enum PXX2ModuleModelID { PXX2_MODULE_ISRM_X9LITES, }; -static const char * const PXX2ModulesNames[] = { - "---", - "XJT", - "ISRM", - "ISRM-PRO", - "ISRM-S", - "R9M", - "R9MLite", - "R9MLite-PRO", - "ISRM-N", - "ISRM-S-X9", - "ISRM-S-X10E", - "XJT Lite", - "ISRM-S-X10S", - "ISRM-X9LiteS" -}; - -inline const char * getPXX2ModuleName(uint8_t modelId) -{ - if (modelId < DIM(PXX2ModulesNames)) - return PXX2ModulesNames[modelId]; - else - return PXX2ModulesNames[0]; -} +const char * getPXX2ModuleName(uint8_t modelId); enum { MODULE_OPTION_EXTERNAL_ANTENNA, @@ -124,149 +96,21 @@ enum { MODULE_OPTION_POWER_METER, }; -/* Module options order: - * - External antenna (0x01) - * - Power (0x02) - * - Spektrum analyser (0x04) - * - Power meter (0x08) - */ -static const uint8_t PXX2ModuleOptions[] = { -#if defined(SIMU) - 0b11111111, // None = display all options on SIMU -#else - 0b00000000, // None = no option available on unknown modules -#endif - 0b00000001, // XJT - 0b00000001, // ISRM - 0b00001101, // ISRM-PRO - 0b00000101, // ISRM-S - 0b00000010, // R9M - 0b00000010, // R9MLite - 0b00000110, // R9MLite-PRO - 0b00000100, // ISRM-N - 0b00000100, // ISRM-S-X9 - 0b00000101, // ISRM-S-X10E - 0b00000001, // XJT_LITE - 0b00000101, // ISRM-S-X10S - 0b00000100, // ISRM-X9LITES -}; - -inline uint8_t getPXX2ModuleOptions(uint8_t modelId) -{ - if (modelId < DIM(PXX2ModuleOptions)) - return PXX2ModuleOptions[modelId]; - else - return PXX2ModuleOptions[0]; -} - -inline bool isPXX2ModuleOptionAvailable(uint8_t modelId, uint8_t option) -{ - return getPXX2ModuleOptions(modelId) & (1 << option); -} +uint8_t getPXX2ModuleOptions(uint8_t modelId); +bool isPXX2ModuleOptionAvailable(uint8_t modelId, uint8_t option); enum ModuleCapabilities { MODULE_CAPABILITY_COUNT }; -static const char * const PXX2ReceiversNames[] = { - "---", - "X8R", - "RX8R", - "RX8R-PRO", - "RX6R", - "RX4R", - "G-RX8", - "G-RX6", - "X6R", - "X4R", - "X4R-SB", - "XSR", - "XSR-M", - "RXSR", - "S6R", - "S8R", - "XM", - "XM+", - "XMR", - "R9", - "R9-SLIM", - "R9-SLIM+", - "R9-MINI", - "R9-MM", - "R9-STAB", // R9-STAB has OTA - "R9-MINI-OTA", // this one has OTA (different bootloader) - "R9-MM-OTA", // this one has OTA (different bootloader) - "R9-SLIM+-OTA", // this one has OTA (different bootloader) - "Archer-X", // this one has OTA (internal module) - "R9MX", // this one has OTA - "R9SX", // this one has OTA -}; - -inline const char * getPXX2ReceiverName(uint8_t modelId) -{ - if (modelId < DIM(PXX2ReceiversNames)) - return PXX2ReceiversNames[modelId]; - else - return PXX2ReceiversNames[0]; -} +const char * getPXX2ReceiverName(uint8_t modelId); enum { RECEIVER_OPTION_OTA, }; -/* Receiver options order: - * - OTA (0x01) - */ -static const uint8_t PXX2ReceiverOptions[] = { -#if defined(SIMU) - 0b11111111, // None = display all options on SIMU -#else - 0b00000000, // None = display all options on SIMU -#endif - 0b11111110, // X8R - 0b11111110, // RX8R - 0b11111110, // RX8R-PRO - 0b11111111, // RX6R - 0b11111111, // RX4R - 0b11111111, // G-RX8 - 0b11111111, // G-RX6 - 0b11111110, // X6R - 0b11111110, // X4R - 0b11111110, // X4R-SB - 0b11111110, // XSR - 0b11111110, // XSR-M - 0b11111111, // RXSR - 0b11111110, // S6R - 0b11111110, // S8R - 0b11111110, // XM - 0b11111110, // XM+ - 0b11111110, // XMR - 0b11111110, // R9 - 0b11111110, // R9-SLIM - 0b11111110, // R9-SLIM+ - 0b11111110, // R9-MINI - 0b11111110, // R9-MM - 0b11111111, // R9-STAB+OTA - 0b11111111, // R9-MINI+OTA - 0b11111111, // R9-MM+OTA - 0b11111111, // R9-SLIM+OTA - 0b11111111, // ARCHER-X - 0b11111111, // R9MX - 0b11111111, // R9SX -}; - -inline uint8_t getPXX2ReceiverOptions(uint8_t modelId) -{ - if (modelId < DIM(PXX2ReceiverOptions)) - return PXX2ReceiverOptions[modelId]; - else - return PXX2ReceiverOptions[0]; -} - -inline bool isPXX2ReceiverOptionAvailable(uint8_t modelId, uint8_t option) -{ - return getPXX2ReceiverOptions(modelId) & (1 << option); -} +uint8_t getPXX2ReceiverOptions(uint8_t modelId); +bool isPXX2ReceiverOptionAvailable(uint8_t modelId, uint8_t option); enum ReceiverCapabilities { RECEIVER_CAPABILITY_FPORT, @@ -403,15 +247,8 @@ class BindInformation { PXX2HardwareInformation receiverInformation; }; -class OtaUpdateInformation: public BindInformation { - public: - char filename[FF_MAX_LFN + 1]; - uint32_t address; - uint32_t module; -}; - struct PXX2HardwareAndSettings { - ModuleInformation modules[NUM_MODULES]; + ModuleInformation modules[MAX_MODULES]; uint32_t updateTime; ModuleSettings moduleSettings; ReceiverSettings receiverSettings; // when dealing with receiver settings, we @@ -423,163 +260,6 @@ PXX2ModuleSetup& getPXX2ModuleSetupBuffer(); BindInformation& getPXX2BindInformationBuffer(); PXX2HardwareAndSettings& getPXX2HardwareAndSettingsBuffer(); -class Pxx2CrcMixin { - protected: - void initCrc() - { - crc = 0xFFFF; - } - - void addToCrc(uint8_t byte) - { - crc -= byte; - } - - uint16_t crc; -}; - -class Pxx2Transport: public DataBuffer, public Pxx2CrcMixin { - protected: - void addWord(uint32_t word) - { - addByte(word); - addByte(word >> 8); - addByte(word >> 16); - addByte(word >> 24); - } - - void addByte(uint8_t byte) - { - Pxx2CrcMixin::addToCrc(byte); - addByteWithoutCrc(byte); - }; - - void addByteWithoutCrc(uint8_t byte) - { - *ptr++ = byte; - } -}; - -class Pxx2Pulses: public Pxx2Transport { - friend class Pxx2OtaUpdate; - - public: - bool setupFrame(uint8_t module, int16_t* channels, uint8_t nChannels); - void setupAuthenticationFrame(uint8_t module, uint8_t mode, const uint8_t * outputMessage); - - protected: - void setupHardwareInfoFrame(uint8_t module, int16_t* channels, uint8_t nChannels); - - void setupRegisterFrame(uint8_t module); - - void setupBindFrame(uint8_t module); - - void setupAccstBindFrame(uint8_t module); - - void setupAccessBindFrame(uint8_t module); - - void setupResetFrame(uint8_t module); - - void setupShareMode(uint8_t module); - - void setupModuleSettingsFrame(uint8_t module, int16_t* channels, uint8_t nChannels); - - void setupReceiverSettingsFrame(uint8_t module, int16_t* channels, uint8_t nChannels); - - void setupChannelsFrame(uint8_t module, int16_t* channels, uint8_t nChannels); - - void setupTelemetryFrame(uint8_t module); - - void setupSpectrumAnalyser(uint8_t module); - - void setupPowerMeter(uint8_t module); - - void sendOtaUpdate(uint8_t module, const char * rxName, uint32_t address, const char * data); - - void addHead() - { - // send 7E, do not CRC - Pxx2Transport::addByteWithoutCrc(0x7E); - - // reserve 1 byte for LEN - Pxx2Transport::addByteWithoutCrc(0x00); - } - - void addFrameType(uint8_t type_c, uint8_t type_id) - { - // TYPE_C + TYPE_ID - Pxx2Transport::addByte(type_c); - Pxx2Transport::addByte(type_id); - } - - uint8_t addFlag0(uint8_t module); - - void addFlag1(uint8_t module); - - void addPulsesValues(uint16_t low, uint16_t high); - - void addChannels(uint8_t module, int16_t* channels, uint8_t nChannels); - - void addFailsafe(uint8_t module); - - void addCrc() - { - Pxx2Transport::addByteWithoutCrc(Pxx2CrcMixin::crc >> 8); - Pxx2Transport::addByteWithoutCrc(Pxx2CrcMixin::crc); - } - - void initFrame() - { - // init the CRC counter - initCrc(); - - // reset the frame pointer - Pxx2Transport::initBuffer(); - - // add the frame head - addHead(); - } - - void endFrame() - { - uint8_t size = getSize() - 2; - - if (size > 0) { - // update the frame LEN = frame length minus the 2 first bytes - data[1] = getSize() - 2; - - // now add the CRC - addCrc(); - } - else { - Pxx2Transport::initBuffer(); - } - } -}; - -class Pxx2OtaUpdate { - public: - Pxx2OtaUpdate(uint8_t module, const char * rxName): - module(module), - rxName(rxName) - { - } - - void flashFirmware(const char * filename, ProgressHandler progressHandler); - - protected: - uint8_t module; - const char * rxName; - - const char * doFlashFirmware(const char * filename, ProgressHandler progressHandler); - bool waitStep(uint8_t step, uint8_t timeout); - const char * nextStep(uint8_t step, const char * rxName, uint32_t address, const uint8_t * buffer); -}; - -extern const etx_serial_init pxx2SerialInitParams; - -extern const etx_module_driver_t Pxx2InternalDriver; -extern const etx_module_driver_t Pxx2ExternalDriver; -extern const etx_module_driver_t Pxx2LowSpeedExternalDriver; +extern const etx_proto_driver_t Pxx2Driver; #endif diff --git a/radio/src/pulses/pxx2_ota.cpp b/radio/src/pulses/pxx2_ota.cpp new file mode 100644 index 000000000..74d81b0e7 --- /dev/null +++ b/radio/src/pulses/pxx2_ota.cpp @@ -0,0 +1,160 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "opentx.h" +#include "io/frsky_firmware_update.h" +#include "tasks/mixer_task.h" + +#include "pxx2_ota.h" +#include "pxx2_transport.h" + +bool Pxx2OtaUpdate::waitStep(uint8_t step, uint8_t timeout) +{ + OtaUpdateInformation * destination = moduleState[module].otaUpdateInformation; + uint8_t elapsed = 0; + + watchdogSuspend(100 /*1s*/); + + while (step != destination->step) { + if (elapsed++ > timeout) { + return false; + } + RTOS_WAIT_MS(1); + telemetryWakeup(); + } + + return true; +} + +const char* Pxx2OtaUpdate::nextStep(uint8_t step, const char* rxName, + uint32_t address, const uint8_t* buffer) +{ + OtaUpdateInformation * destination = moduleState[module].otaUpdateInformation; + + destination->step = step; + destination->address = address; + + for (uint8_t retry = 0;; retry++) { + uint8_t* module_buffer = pulsesGetModuleBuffer(module); + Pxx2Pulses pxx2(module_buffer); + pxx2.sendOtaUpdate(module, rxName, address, (const char *) buffer); + + // send the frame immediately + auto mod = pulsesGetModuleDriver(module); + auto mod_st = (etx_module_state_t*)mod->ctx; + + auto drv = modulePortGetSerialDrv(mod_st->tx); + auto ctx = modulePortGetCtx(mod_st->tx); + drv->sendBuffer(ctx, module_buffer, pxx2.getSize()); + + if (waitStep(step + 1, 20)) { + return nullptr; + } + else if (retry == 100) { + return "Transfer failed"; + } + } +} + +const char* Pxx2OtaUpdate::doFlashFirmware(const char* filename, + ProgressHandler progressHandler) +{ + FIL file; + uint8_t buffer[32]; + UINT count; + const char * result; + + result = nextStep(OTA_UPDATE_START, rxName, 0, nullptr); + if (result) { + return result; + } + + if (f_open(&file, filename, FA_READ) != FR_OK) { + return "Open file failed"; + } + + uint32_t size; + const char * ext = getFileExtension(filename); + if (ext && !strcasecmp(ext, FRSKY_FIRMWARE_EXT)) { + FrSkyFirmwareInformation * information = (FrSkyFirmwareInformation *) buffer; + if (f_read(&file, buffer, sizeof(FrSkyFirmwareInformation), &count) != FR_OK || + count != sizeof(FrSkyFirmwareInformation)) { + f_close(&file); + return "Format error"; + } + size = information->size; + } + else { + size = f_size(&file); + } + + uint32_t done = 0; + while (1) { + progressHandler(getBasename(filename), STR_OTA_UPDATE, done, size); + if (f_read(&file, buffer, sizeof(buffer), &count) != FR_OK) { + f_close(&file); + return "Read file failed"; + } + + result = nextStep(OTA_UPDATE_TRANSFER, nullptr, done, buffer); + if (result) { + return result; + } + + if (count < sizeof(buffer)) { + f_close(&file); + break; + } + + done += count; + } + + return nextStep(OTA_UPDATE_EOF, nullptr, done, nullptr); +} + +void Pxx2OtaUpdate::flashFirmware(const char * filename, ProgressHandler progressHandler) +{ + mixerTaskStop(); + + watchdogSuspend(100 /*1s*/); + RTOS_WAIT_MS(100); + + moduleState[module].mode = MODULE_MODE_OTA_UPDATE; + const char * result = doFlashFirmware(filename, progressHandler); + moduleState[module].mode = MODULE_MODE_NORMAL; + + AUDIO_PLAY(AU_SPECIAL_SOUND_BEEP1 ); + BACKLIGHT_ENABLE(); + + if (result) { + POPUP_WARNING(STR_FIRMWARE_UPDATE_ERROR, result); + } + else { + POPUP_INFORMATION(STR_FIRMWARE_UPDATE_SUCCESS); + } + + watchdogSuspend(100); + RTOS_WAIT_MS(100); + + mixerTaskStart(); +} + + diff --git a/radio/src/pulses/pxx2_ota.h b/radio/src/pulses/pxx2_ota.h new file mode 100644 index 000000000..4bb76585c --- /dev/null +++ b/radio/src/pulses/pxx2_ota.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#pragma once + +#include "pxx2.h" +#include "popups.h" + +class OtaUpdateInformation: public BindInformation { + public: + char filename[FF_MAX_LFN + 1]; + uint32_t address; + uint32_t module; +}; + +class Pxx2OtaUpdate { + public: + Pxx2OtaUpdate(uint8_t module, const char * rxName): + module(module), + rxName(rxName) + { + } + + void flashFirmware(const char * filename, ProgressHandler progressHandler); + + protected: + uint8_t module; + const char * rxName; + + const char * doFlashFirmware(const char * filename, ProgressHandler progressHandler); + bool waitStep(uint8_t step, uint8_t timeout); + const char* nextStep(uint8_t step, const char* rxName, uint32_t address, + const uint8_t* buffer); +}; + diff --git a/radio/src/pulses/pxx2_transport.h b/radio/src/pulses/pxx2_transport.h new file mode 100644 index 000000000..63987bd91 --- /dev/null +++ b/radio/src/pulses/pxx2_transport.h @@ -0,0 +1,156 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#pragma once + +#include + +class Pxx2CrcMixin { + protected: + uint16_t crc = 0xFFFF; + + void addToCrc(uint8_t byte) + { + crc -= byte; + } + +}; + +class Pxx2Transport: public Pxx2CrcMixin { + protected: + uint8_t* buffer; + uint8_t* ptr; + + Pxx2Transport(uint8_t* buffer) + : buffer(buffer), ptr(buffer) + {} + + void addWord(uint32_t word) + { + addByte(word); + addByte(word >> 8); + addByte(word >> 16); + addByte(word >> 24); + } + + void addByte(uint8_t byte) + { + Pxx2CrcMixin::addToCrc(byte); + addByteWithoutCrc(byte); + }; + + void addByteWithoutCrc(uint8_t byte) + { + *ptr++ = byte; + } + + public: + uint32_t getSize() + { + return ptr - buffer; + } +}; + +class Pxx2Pulses: public Pxx2Transport { + friend class Pxx2OtaUpdate; + + public: + Pxx2Pulses(uint8_t* buffer) + : Pxx2Transport(buffer) + { + addHead(); + } + + bool setupFrame(uint8_t module, int16_t* channels, uint8_t nChannels); + void setupAuthenticationFrame(uint8_t module, uint8_t mode, const uint8_t * outputMessage); + + protected: + void setupHardwareInfoFrame(uint8_t module, int16_t* channels, uint8_t nChannels); + + void setupRegisterFrame(uint8_t module); + + void setupBindFrame(uint8_t module); + + void setupAccstBindFrame(uint8_t module); + + void setupAccessBindFrame(uint8_t module); + + void setupResetFrame(uint8_t module); + + void setupShareMode(uint8_t module); + + void setupModuleSettingsFrame(uint8_t module, int16_t* channels, uint8_t nChannels); + + void setupReceiverSettingsFrame(uint8_t module, int16_t* channels, uint8_t nChannels); + + void setupChannelsFrame(uint8_t module, int16_t* channels, uint8_t nChannels); + + void setupTelemetryFrame(uint8_t module); + + void setupSpectrumAnalyser(uint8_t module); + + void setupPowerMeter(uint8_t module); + + void sendOtaUpdate(uint8_t module, const char * rxName, uint32_t address, const char * data); + + void addHead() + { + // send 7E, do not CRC + Pxx2Transport::addByteWithoutCrc(0x7E); + + // reserve 1 byte for LEN + Pxx2Transport::addByteWithoutCrc(0x00); + } + + void addFrameType(uint8_t type_c, uint8_t type_id) + { + // TYPE_C + TYPE_ID + Pxx2Transport::addByte(type_c); + Pxx2Transport::addByte(type_id); + } + + uint8_t addFlag0(uint8_t module); + + void addFlag1(uint8_t module); + + void addPulsesValues(uint16_t low, uint16_t high); + + void addChannels(uint8_t module, int16_t* channels, uint8_t nChannels); + + void addFailsafe(uint8_t module); + + void addCrc() + { + Pxx2Transport::addByteWithoutCrc(Pxx2CrcMixin::crc >> 8); + Pxx2Transport::addByteWithoutCrc(Pxx2CrcMixin::crc); + } + + void endFrame() + { + if (getSize() <= 2) return; + + // update the frame LEN = frame length minus the 2 first bytes + buffer[1] = getSize() - 2; + + // now add the CRC + addCrc(); + } +}; diff --git a/radio/src/pulses/sbus.cpp b/radio/src/pulses/sbus.cpp index a1e6535b7..76e1b5829 100644 --- a/radio/src/pulses/sbus.cpp +++ b/radio/src/pulses/sbus.cpp @@ -19,56 +19,14 @@ * GNU General Public License for more details. */ +#include "sbus.h" +#include "hal/module_port.h" +#include "mixer_scheduler.h" + #include "opentx.h" - -#define BITLEN_SBUS (10*2) // 100000 Baud => 10uS per bit - - -/* The protocol reuse some the DSM2 definitions where they are identical */ - - -static void _send_level(uint8_t v) -{ - /* Copied over from DSM, this looks doubious and in my logic analyzer - output the low->high is about 2 ns late */ - if (extmodulePulsesData.dsm2.index & 1) - v += 2; - else - v -= 2; - - *extmodulePulsesData.dsm2.ptr++ = v - 1; - extmodulePulsesData.dsm2.index+=1; -} - -void sendByteSbus(uint8_t b) // max 11 changes 0 10 10 10 10 P 1 -{ - bool lev = 0; - uint8_t parity = 1; - - uint8_t len = BITLEN_SBUS; //max val: 10*20 < 256 - for (uint8_t i=0; i<=9; i++) { //8Bits + 1Parity + Stop=1 - bool nlev = b & 1; //lsb first - parity = parity ^ (uint8_t)nlev; - if (lev == nlev) { - len += BITLEN_SBUS; - } - else { - _send_level(len); - len = BITLEN_SBUS; - lev = nlev; - } - b = (b>>1) | 0x80; //shift in ones for stop bit and parity - if (i==7) - b = b ^ parity; // lowest bit is one from previous line - } - _send_level(len+ BITLEN_SBUS); // enlarge the last bit to be two stop bits long -} - - -#define SBUS_NORMAL_CHANS 16 -#define SBUS_CHAN_BITS 11 - +#define SBUS_NORMAL_CHANS 16 +#define SBUS_CHAN_BITS 11 /* Definitions from CleanFlight/BetaFlight */ @@ -80,44 +38,39 @@ void sendByteSbus(uint8_t b) // max 11 changes 0 10 10 10 10 P 1 #define SBUS_CHAN_CENTER 992 -inline int getChannelValue(uint8_t port, int channel) +static inline void sendByte(uint8_t*& p_buf, uint8_t b) { - int ch = g_model.moduleData[port].channelsStart+channel; + *p_buf++ = b; +} + +static inline int getChannelValue(uint8_t port, int channel) +{ + int ch = g_model.moduleData[port].channelsStart + channel; // We will ignore 17 and 18th if that brings us over the limit - if (ch > 31) - return 0; - return channelOutputs[ch] + 2 * PPM_CH_CENTER(ch) - 2*PPM_CENTER; + if (ch > 31) return 0; + return channelOutputs[ch] + 2 * PPM_CH_CENTER(ch) - 2 * PPM_CENTER; } -static void sbusFlush() +static void setupPulsesSbus(uint8_t module, uint8_t*& p_buf) { - if (extmodulePulsesData.dsm2.index & 1) - *extmodulePulsesData.dsm2.ptr++ = 255; - else - *(extmodulePulsesData.dsm2.ptr - 1) = 255; -} - -void setupPulsesSbus() -{ - extmodulePulsesData.dsm2.index = 0; - - extmodulePulsesData.dsm2.ptr = extmodulePulsesData.dsm2.pulses; + // extmodulePulsesData.dsm2.index = 0; + // extmodulePulsesData.dsm2.ptr = extmodulePulsesData.dsm2.pulses; // Sync Byte - sendByteSbus(SBUS_FRAME_BEGIN_BYTE); + sendByte(p_buf, SBUS_FRAME_BEGIN_BYTE); uint32_t bits = 0; uint8_t bitsavailable = 0; // byte 1-22, channels 0..2047, limits not really clear (B for (int i=0; i= 8) { - sendByteSbus((uint8_t) (bits & 0xff)); + sendByte(p_buf, (uint8_t) (bits & 0xff)); bits >>= 8; bitsavailable -= 8; } @@ -125,15 +78,79 @@ void setupPulsesSbus() // flags uint8_t flags=0; - if (getChannelValue(EXTERNAL_MODULE, 16) > 0) + if (getChannelValue(module, 16) > 0) flags |= SBUS_FLAG_CHANNEL_17; - if (getChannelValue(EXTERNAL_MODULE, 17) > 0) + if (getChannelValue(module, 17) > 0) flags |= SBUS_FLAG_CHANNEL_18; - sendByteSbus(flags); + sendByte(p_buf, flags); // last byte, always 0x0 - sendByteSbus(0x00); - - sbusFlush(); + sendByte(p_buf, 0x00); } + + +#define SBUS_BAUDRATE 100000 + +const etx_serial_init sbusUartParams = { + .baudrate = SBUS_BAUDRATE, + .encoding = ETX_Encoding_8E2, + .direction = ETX_Dir_TX, + .polarity = ETX_Pol_Normal, +}; + +static void* sbusInit(uint8_t module) +{ +#if defined(HARDWARE_INTERNAL_MODULE) + // only external module supported + if (module == INTERNAL_MODULE) return nullptr; +#endif + + // auto mod_st = modulePortInitSerial(module, ETX_MOD_PORT_UART, &sbusUartParams); + // TODO: check if inverter is there, or mandate it somehow... + // if (!mod_st) { + // -> SOFT_INV has 'setPolarity' + auto mod_st = modulePortInitSerial(module, ETX_MOD_PORT_SOFT_INV, &sbusUartParams); + if (!mod_st) return nullptr; + // } + + mixerSchedulerSetPeriod(module, SBUS_PERIOD(module)); + return (void*)mod_st; +} + +static void sbusDeInit(void* ctx) +{ + auto mod_st = (etx_module_state_t*)ctx; + modulePortDeInit(mod_st); +} + +static void sbusSendPulses(void* ctx, uint8_t* buffer, int16_t* channels, uint8_t nChannels) +{ + // TODO: + (void)channels; + (void)nChannels; + + auto mod_st = (etx_module_state_t*)ctx; + auto module = modulePortGetModule(mod_st); + + auto p_data = buffer; + setupPulsesSbus(module, p_data); + + auto drv = modulePortGetSerialDrv(mod_st->tx); + auto drv_ctx = modulePortGetCtx(mod_st->tx); + + // TODO: check if the port has an inverter and use it instead + drv->setPolarity(drv_ctx, GET_SBUS_POLARITY(module)); + drv->sendBuffer(drv_ctx, buffer, p_data - buffer); + + // SBUS_PERIOD is not a constant! It can be set from UI + mixerSchedulerSetPeriod(module, SBUS_PERIOD(module)); +} + +const etx_proto_driver_t SBusDriver = { + .protocol = PROTOCOL_CHANNELS_SBUS, + .init = sbusInit, + .deinit = sbusDeInit, + .sendPulses = sbusSendPulses, + .processData = nullptr, +}; diff --git a/radio/src/pulses/sbus.h b/radio/src/pulses/sbus.h new file mode 100644 index 000000000..5a2ae4596 --- /dev/null +++ b/radio/src/pulses/sbus.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) EdgeTx + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#pragma once + +#include "hal/module_driver.h" + +extern const etx_proto_driver_t SBusDriver; diff --git a/radio/src/rtos.h b/radio/src/rtos.h index e29b9b0c6..96a61cc0c 100644 --- a/radio/src/rtos.h +++ b/radio/src/rtos.h @@ -70,6 +70,11 @@ extern "C++" { pthread_mutex_lock(&mutex); } + static inline bool RTOS_TRYLOCK_MUTEX(pthread_mutex_t &mutex) + { + return pthread_mutex_trylock(&mutex) == 0; + } + static inline void RTOS_UNLOCK_MUTEX(pthread_mutex_t &mutex) { pthread_mutex_unlock(&mutex); @@ -204,12 +209,13 @@ inline void RTOS_CREATE_TASK(pthread_t &taskId, void * (*task)(void *), const ch #define RTOS_CREATE_MUTEX(handle) _RTOS_CREATE_MUTEX(&handle) - static inline void _RTOS_LOCK_MUTEX(RTOS_MUTEX_HANDLE* h) + static inline bool _RTOS_LOCK_MUTEX(RTOS_MUTEX_HANDLE* h, TickType_t xTickToWait) { - xSemaphoreTake(h->rtos_handle, portMAX_DELAY); + return xSemaphoreTake(h->rtos_handle, xTickToWait) == pdTRUE; } - #define RTOS_LOCK_MUTEX(handle) _RTOS_LOCK_MUTEX(&handle) + #define RTOS_LOCK_MUTEX(handle) _RTOS_LOCK_MUTEX(&handle, portMAX_DELAY) + #define RTOS_TRYLOCK_MUTEX(handle) _RTOS_LOCK_MUTEX(&handle, (TickType_t)0) static inline void _RTOS_UNLOCK_MUTEX(RTOS_MUTEX_HANDLE* h) { diff --git a/radio/src/serial.cpp b/radio/src/serial.cpp index e008daa99..e1f708075 100644 --- a/radio/src/serial.cpp +++ b/radio/src/serial.cpp @@ -27,7 +27,6 @@ #include #include -#include "aux_serial_driver.h" #include "hal/serial_port.h" #if !defined(BOOT) @@ -41,10 +40,6 @@ #include "telemetry/crossfire.h" #endif -#if defined(AUX_SERIAL_DMA_TX) && !defined(EXTMODULE_USART) - #include "extmodule_serial_driver.h" -#endif - #if defined(DEBUG_SEGGER_RTT) #include "thirdparty/Segger_RTT/RTT/SEGGER_RTT.h" #endif @@ -182,7 +177,7 @@ static void serialSetCallBacks(int mode, void* ctx, const etx_serial_port_t* por void (*setRxCb)(void*, void (*)(uint8_t*, uint32_t)) = nullptr; const etx_serial_driver_t* drv = nullptr; - if (port) { + if (port && ctx) { drv = port->uart; if (drv) { sendByte = drv->sendByte; @@ -227,7 +222,8 @@ static void serialSetCallBacks(int mode, void* ctx, const etx_serial_port_t* por #endif case UART_MODE_TELEMETRY: - telemetrySetGetByte(ctx, getByte); + // telemetrySetGetByte(ctx, getByte); + // TODO: setRxCb (see MODE_LUA) // de we really need telemetry // input over USB VCP? @@ -255,9 +251,24 @@ static void serialSetCallBacks(int mode, void* ctx, const etx_serial_port_t* por break; #endif -#if defined(AUX_SERIAL_DMA_TX) && !defined(EXTMODULE_USART) +#if defined(CONFIGURABLE_MODULE_PORT) case UART_MODE_EXT_MODULE: - extmoduleSetSerialPort(drv); + if (port && !ctx) { // de-init + etx_module_port_t mod_port; + memset(&mod_port, 0, sizeof(mod_port)); + auto mod_st = modulePortGetState(EXTERNAL_MODULE); + if (mod_st && mod_st->tx.hw_def == port->hw_def) { + // port is in use, let's stop it + mixerTaskStop(); + pausePulses(); + pulsesStopModule(EXTERNAL_MODULE); + modulePortConfigExtra(&mod_port); + resumePulses(); + mixerTaskStart(); + } else { + modulePortConfigExtra(&mod_port); + } + } break; #endif @@ -291,45 +302,38 @@ static void serialSetupPort(int mode, etx_serial_init& params) case UART_MODE_TELEMETRY: if (modelTelemetryProtocol() == PROTOCOL_TELEMETRY_FRSKY_D_SECONDARY) { params.baudrate = FRSKY_D_BAUDRATE; - params.rx_enable = true; + params.direction = ETX_Dir_RX; } break; case UART_MODE_SBUS_TRAINER: params.baudrate = SBUS_BAUDRATE; - params.word_length = ETX_WordLength_9; - params.parity = ETX_Parity_Even; - params.stop_bits = ETX_StopBits_Two; - params.rx_enable = true; + params.encoding = ETX_Encoding_8E2, + params.direction = ETX_Dir_RX; break; #if defined(LUA) case UART_MODE_LUA: params.baudrate = LUA_DEFAULT_BAUDRATE; - params.rx_enable = true; + params.direction = ETX_Dir_TX_RX; break; #endif #if defined(INTERNAL_GPS) case UART_MODE_GPS: params.baudrate = GPS_USART_BAUDRATE; - params.rx_enable = true; + params.direction = ETX_Dir_TX_RX; break; #endif #if defined(SPACEMOUSE) case UART_MODE_SPACEMOUSE: params.baudrate = SPACEMOUSE_BAUDRATE; - params.rx_enable = true; + params.direction = ETX_Dir_TX_RX; break; #endif -#if defined(AUX_SERIAL_DMA_TX) && !defined(EXTMODULE_USART) - case UART_MODE_EXT_MODULE: - params.rx_enable = true; - break; -#endif -#endif +#endif // BOOT } } @@ -385,40 +389,57 @@ void serialInit(uint8_t port_nr, int mode) } if (state->mode != UART_MODE_NONE) { // Clear callbacks - serialSetCallBacks(state->mode, nullptr, nullptr); + serialSetCallBacks(state->mode, nullptr, state->port); } memset(state, 0, sizeof(SerialPortState)); } +#if defined(CONFIGURABLE_MODULE_PORT) + if (mode == UART_MODE_EXT_MODULE) { + etx_module_port_t mod_port = { + .port = ETX_MOD_PORT_EXTERNAL_UART, + .type = ETX_MOD_TYPE_SERIAL, + .dir_flags = ETX_MOD_DIR_TX_RX, + .drv = { .serial = port->uart }, + }; + modulePortConfigExtra(&mod_port); + state->mode = mode; + state->port = port; + return; + } +#endif + etx_serial_init params = { .baudrate = 0, - .parity = ETX_Parity_None, - .stop_bits = ETX_StopBits_One, - .word_length = ETX_WordLength_8, - .rx_enable = false, + .encoding = ETX_Encoding_8N1, + .direction = ETX_Dir_TX, + .polarity = ETX_Pol_Normal, }; serialSetupPort(mode, params); + if (mode == UART_MODE_NONE || + !port || params.baudrate == 0 || + !port->uart || !port->uart->init) + return; + + auto hw_def = port->hw_def; + state->usart_ctx = port->uart->init(hw_def, ¶ms); + + // init failed + if (!state->usart_ctx) return; + + state->mode = mode; + state->port = port; + + // Update callbacks once the port is setup + serialSetCallBacks(mode, state->usart_ctx, state->port); + #if defined(SWSERIALPOWER) // Set power on/off if (port_nr < SP_VCP) serialSetPowerState(port_nr); #endif - - state->mode = mode; - - if (mode != UART_MODE_NONE) { - state->port = port; - - if (port && params.baudrate != 0) { - if (port->uart && port->uart->init) - state->usart_ctx = port->uart->init(¶ms); - } - - // Update callbacks once the port is setup - serialSetCallBacks(mode, state->usart_ctx, state->port); - } } void initSerialPorts() diff --git a/radio/src/spacemouse.cpp b/radio/src/spacemouse.cpp index dc11f15c3..269ec1c9a 100644 --- a/radio/src/spacemouse.cpp +++ b/radio/src/spacemouse.cpp @@ -20,7 +20,8 @@ */ #include "opentx.h" -#include +// #include +#include "tasks/mixer_task.h" #if !defined(SIMU) #include @@ -62,7 +63,7 @@ static StaticTimer_t spacemouseTimerBuffer; static void spacemouseTimerCb(TimerHandle_t xTimer) { - if (!s_pulses_paused) { + if (!mixerTaskRunning()) { DEBUG_TIMER_START(debugTimerSpacemouseWakeup); spacemousePoll(); spacemouseWakeup(); diff --git a/radio/src/storage/storage_common.cpp b/radio/src/storage/storage_common.cpp index d3bb8f834..9523cb80e 100644 --- a/radio/src/storage/storage_common.cpp +++ b/radio/src/storage/storage_common.cpp @@ -56,24 +56,13 @@ void preModelLoad() logsClose(); #endif - if (pulsesStarted()) { - pausePulses(); - } - pauseMixerCalculations(); - -#if defined(HARDWARE_INTERNAL_MODULE) - stopPulsesInternalModule(); -#endif -#if defined(HARDWARE_EXTERNAL_MODULE) - stopPulsesExternalModule(); - RTOS_WAIT_MS(200); -#endif - + pulsesStop(); stopTrainer(); - #if defined(COLORLCD) deleteCustomScreens(); #endif + + RTOS_WAIT_MS(200); } void postRadioSettingsLoad() @@ -138,16 +127,13 @@ void postModelLoad(bool alarms) loadCurves(); - resumeMixerCalculations(); - if (pulsesStarted()) { #if defined(GUI) - if (alarms) { - checkAll(); - PLAY_MODEL_NAME(); - } -#endif - resumePulses(); + if (alarms) { + checkAll(); + PLAY_MODEL_NAME(); } +#endif + pulsesStart(); #if defined(SDCARD) referenceModelAudioFiles(); diff --git a/radio/src/storage/yaml/yaml_datastructs_funcs.cpp b/radio/src/storage/yaml/yaml_datastructs_funcs.cpp index 032ea3189..a4304ae3e 100644 --- a/radio/src/storage/yaml/yaml_datastructs_funcs.cpp +++ b/radio/src/storage/yaml/yaml_datastructs_funcs.cpp @@ -1133,7 +1133,7 @@ static bool w_trainerMode(const YamlNode* node, uint32_t val, #if !defined(COLORLCD) -const char* _tele_screen_type_lookup[] = { +const char* const _tele_screen_type_lookup[] = { "NONE", "VALUES", "BARS", @@ -1236,21 +1236,21 @@ static bool w_flightModes(const YamlNode* node, uint32_t val, return true; } -static const char* _func_reset_param_lookup[] = { +static const char* const _func_reset_param_lookup[] = { "Tmr1","Tmr2","Tmr3","All","Tele" }; -static const char* _func_failsafe_lookup[] = { +static const char* const _func_failsafe_lookup[] = { "Int","Ext" }; -static const char* _func_sound_lookup[] = { +static const char* const _func_sound_lookup[] = { "Bp1","Bp2","Bp3","Wrn1","Wrn2", "Chee","Rata","Tick","Sirn","Ring", "SciF","Robt","Chrp","Tada","Crck","Alrm" }; -static const char* _adjust_gvar_mode_lookup[] = { +static const char* const _adjust_gvar_mode_lookup[] = { "Cst", "Src", "GVar", "IncDec" }; diff --git a/radio/src/strhelpers.cpp b/radio/src/strhelpers.cpp index 4d48920d9..886ec0be6 100644 --- a/radio/src/strhelpers.cpp +++ b/radio/src/strhelpers.cpp @@ -770,61 +770,20 @@ char *getSensorCustomValueString(char (&dest)[L], uint8_t sensor, int32_t val, { if (sensor >= MAX_TELEMETRY_SENSORS) { return dest; } - // TelemetryItem & telemetryItem = telemetryItems[sensor]; TelemetrySensor & telemetrySensor = g_model.telemetrySensors[sensor]; size_t len = L - 1; + // TODO: display TEXT sensors? if (telemetrySensor.unit == UNIT_DATETIME || telemetrySensor.unit == UNIT_GPS || telemetrySensor.unit == UNIT_TEXT) { strAppend(dest, "N/A", len); return dest; } - if (telemetrySensor.unit == UNIT_BITFIELD) { - if (IS_FRSKY_SPORT_PROTOCOL()) { - if (telemetrySensor.id >= RBOX_STATE_FIRST_ID && - telemetrySensor.id <= RBOX_STATE_LAST_ID) { - if (telemetrySensor.subId == 0) { - if (val == 0) { - strAppend(dest, "OK", len); - return dest; - } - for (uint8_t i = 0; i < 16; i++) { - if (val & (1 << i)) { - if (len < 8) return dest; - auto pos = strAppend(dest, "CH", len); - len -= 2; - pos = strAppendUnsigned(pos, i + 1, 2); - len -= 2; - strAppend(pos, " KO", len); - return dest; - } - } - } else { - if (val == 0) { - strAppend(dest, "Rx OK", len); - return dest; - } - - static const char *const RXS_STATUS[] = { - "Rx1 Ovl", "Rx2 Ovl", "SBUS Ovl", "Rx1 FS", "Rx1 LF", "Rx2 FS", - "Rx2 LF", "Rx1 Lost", "Rx2 Lost", "Rx1 NS", "Rx2 NS", - }; - for (uint8_t i = 0; i < DIM(RXS_STATUS); i++) { - if (val & (1 << i)) { - strAppend(dest, RXS_STATUS[i], len); - return dest; - } - } - } - } - } - } else { - if (telemetrySensor.prec > 0) { - flags |= (telemetrySensor.prec == 1 ? PREC1 : PREC2); - } - getValueWithUnit(dest, len, val, telemetrySensor.unit, flags); + if (telemetrySensor.prec > 0) { + flags |= (telemetrySensor.prec == 1 ? PREC1 : PREC2); } + getValueWithUnit(dest, len, val, telemetrySensor.unit, flags); return dest; } diff --git a/radio/src/switches.cpp b/radio/src/switches.cpp index ae33c01c9..037d0afd0 100644 --- a/radio/src/switches.cpp +++ b/radio/src/switches.cpp @@ -22,6 +22,8 @@ #include "opentx.h" #include "switches.h" +#include "tasks/mixer_task.h" + #define CS_LAST_VALUE_INIT -32768 #if defined(COLORLCD) @@ -704,7 +706,7 @@ bool isSwitchWarningRequired(uint16_t &bad_pots) { swarnstate_t states = g_model.switchWarningState; - GET_ADC_IF_MIXER_NOT_RUNNING(); + if (!mixerTaskRunning()) getADC(); getMovedSwitch(); bool warn = false; diff --git a/radio/src/targets/common/arm/CMakeLists.txt b/radio/src/targets/common/arm/CMakeLists.txt index 431734857..9b4140e87 100644 --- a/radio/src/targets/common/arm/CMakeLists.txt +++ b/radio/src/targets/common/arm/CMakeLists.txt @@ -204,6 +204,7 @@ if(PXX2) set(PULSES_SRC ${PULSES_SRC} pxx2.cpp + pxx2_ota.cpp ) endif() @@ -302,7 +303,7 @@ set(FIRMWARE_TARGET_SRC ${FIRMWARE_TARGET_SRC} keys_driver.cpp diskio.cpp - telemetry_driver.cpp + # telemetry_driver.cpp ) set(PULSES_SRC diff --git a/radio/src/targets/common/arm/stm32/CMakeLists.txt b/radio/src/targets/common/arm/stm32/CMakeLists.txt index fa03900a1..01628c2c2 100644 --- a/radio/src/targets/common/arm/stm32/CMakeLists.txt +++ b/radio/src/targets/common/arm/stm32/CMakeLists.txt @@ -38,6 +38,9 @@ set(FIRMWARE_TARGET_SRC ${FIRMWARE_TARGET_SRC} ../common/arm/stm32/usbd_hid_joystick.c ../common/arm/stm32/stm32_hal.cpp ../common/arm/stm32/stm32_i2c_driver.cpp + ../common/arm/stm32/stm32_serial_driver.cpp + ../common/arm/stm32/stm32_softserial_driver.cpp + ../common/arm/stm32/module_timer_driver.cpp ) if(IMU) @@ -49,9 +52,9 @@ if(IMU) endif() if(AUX_SERIAL OR AUX2_SERIAL) - set(FIRMWARE_TARGET_SRC ${FIRMWARE_TARGET_SRC} - ../common/arm/stm32/aux_serial_driver.cpp - ) + # set(FIRMWARE_TARGET_SRC ${FIRMWARE_TARGET_SRC} + # ../common/arm/stm32/aux_serial_driver.cpp + # ) if(AUX_SERIAL) add_definitions(-DAUX_SERIAL) endif() diff --git a/radio/src/targets/common/arm/stm32/aux_serial_driver.cpp b/radio/src/targets/common/arm/stm32/aux_serial_driver.cpp deleted file mode 100644 index e42e941f5..000000000 --- a/radio/src/targets/common/arm/stm32/aux_serial_driver.cpp +++ /dev/null @@ -1,292 +0,0 @@ -/* - * Copyright (C) EdgeTX - * - * Based on code named - * opentx - https://github.com/opentx/opentx - * th9x - http://code.google.com/p/th9x - * er9x - http://code.google.com/p/er9x - * gruvin9x - http://code.google.com/p/gruvin9x - * - * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "stm32_hal_ll.h" -#include "stm32_usart_driver.h" -#include "aux_serial_driver.h" - -#include "board.h" - -#include "fifo.h" -#include "dmafifo.h" -#include "debug.h" - -#define AUX_SERIAL_TX_BUFFER 512 - -#if defined(SDRAM) - #define AUX_SERIAL_RX_BUFFER 512 -#else - #define AUX_SERIAL_RX_BUFFER 32 -#endif - -typedef Fifo TxFifo; -typedef DMAFifo RxFifo; - -struct SerialState -{ - TxFifo* txFifo; - RxFifo* rxFifo; - - const stm32_usart_t* usart; -}; - -static void* aux_serial_init(const SerialState* st, const etx_serial_init* params) -{ - stm32_usart_init(st->usart, params); - - if (params->rx_enable && st->usart->rxDMA) { - stm32_usart_init_rx_dma(st->usart, st->rxFifo->buffer(), st->rxFifo->size()); - st->rxFifo->clear(); - } - - return (void*)st; -} - -static void aux_serial_putc(void* ctx, uint8_t c) -{ - // When sending single bytes, - // send is based on IRQ, so that this - // only enables the corresponding IRQ - - auto st = (const SerialState*)ctx; - if (st->txFifo->isFull()) return; - st->txFifo->push(c); - - stm32_usart_enable_tx_irq(st->usart); -} - -static void aux_serial_send_buffer(void* ctx, const uint8_t* data, uint8_t size) -{ - auto st = (const SerialState*)ctx; - if (st->usart->txDMA) { - stm32_usart_send_buffer(st->usart, data, size); - return; - } - - while(size > 0) { - aux_serial_putc(ctx, *data++); - size--; - } -} - -static void aux_wait_tx_completed(void* ctx) -{ - // TODO - (void)ctx; -} - -static int aux_get_byte(void* ctx, uint8_t* data) -{ - auto st = (const SerialState*)ctx; - if (!st->rxFifo) return -1; - return st->rxFifo->pop(*data); -} - -void aux_serial_deinit(void* ctx) -{ - auto st = (const SerialState*)ctx; - stm32_usart_deinit(st->usart); -} - -#if defined(AUX_SERIAL) - -static TxFifo auxSerialTxFifo; -static RxFifo auxSerialRxFifo __DMA (AUX_SERIAL_DMA_Stream_RX); - -static const LL_GPIO_InitTypeDef auxUSARTPinInit = { - .Pin = AUX_SERIAL_GPIO_PIN_TX | AUX_SERIAL_GPIO_PIN_RX, - .Mode = LL_GPIO_MODE_ALTERNATE, - .Speed = LL_GPIO_SPEED_FREQ_LOW, - .OutputType = LL_GPIO_OUTPUT_PUSHPULL, - .Pull = LL_GPIO_PULL_UP, - .Alternate = AUX_SERIAL_GPIO_AF_LL, -}; - -#if !defined(AUX_SERIAL_DMA_TX) - #define AUX_SERIAL_DMA_TX nullptr - #define AUX_SERIAL_DMA_Stream_TX nullptr - #define AUX_SERIAL_DMA_Stream_TX_LL 0 - #define AUX_SERIAL_DMA_Channel_TX 0 -#endif - -static const stm32_usart_t auxUSART = { - .USARTx = AUX_SERIAL_USART, - .GPIOx = AUX_SERIAL_GPIO, - .pinInit = &auxUSARTPinInit, - .IRQn = AUX_SERIAL_USART_IRQn, - .IRQ_Prio = 7, // TODO: define constant - .txDMA = AUX_SERIAL_DMA_TX, - .txDMA_Stream = AUX_SERIAL_DMA_Stream_TX_LL, - .txDMA_Channel = AUX_SERIAL_DMA_Channel_TX, - .rxDMA = AUX_SERIAL_DMA_RX, - .rxDMA_Stream = AUX_SERIAL_DMA_Stream_RX_LL, - .rxDMA_Channel = AUX_SERIAL_DMA_Channel_RX, -}; - -static const SerialState auxSerialState = { - .txFifo = &auxSerialTxFifo, - .rxFifo = &auxSerialRxFifo, - .usart = &auxUSART, -}; - -// TODO: grab context to get buffer -static uint8_t auxSerialOnSend(uint8_t* data) -{ - return auxSerialTxFifo.pop(*data); -} - -// TODO: add to state -static etx_serial_callbacks_t auxSerialCb = { - .on_send = auxSerialOnSend, - .on_receive = nullptr, - .on_error = nullptr, -}; - -static void* auxSerialInit(const etx_serial_init* params) -{ - return aux_serial_init(&auxSerialState, params); -} - -static void (*aux1RxCb)(uint8_t*, uint32_t); - -static void aux1_on_rx_byte(uint8_t data) -{ - if (aux1RxCb) aux1RxCb(&data, 1); -} - -static void aux1SetRxCb(void*, void (*cb)(uint8_t*, uint32_t)) -{ - aux1RxCb = cb; - if (aux1RxCb) { - auxSerialCb.on_receive = aux1_on_rx_byte; - stm32_usart_deinit_rx_dma(&auxUSART); - } else { - auxSerialCb.on_receive = nullptr; - } -} - -const etx_serial_driver_t AuxSerialDriver = { - .init = auxSerialInit, - .deinit = aux_serial_deinit, - .sendByte = aux_serial_putc, - .sendBuffer = aux_serial_send_buffer, - .waitForTxCompleted = aux_wait_tx_completed, - .getByte = aux_get_byte, - .getBaudrate = nullptr, - .setReceiveCb = aux1SetRxCb, - .setBaudrateCb = nullptr, -}; - -extern "C" void AUX_SERIAL_USART_IRQHandler(void) -{ - DEBUG_INTERRUPT(INT_SER2); - stm32_usart_isr(&auxUSART, &auxSerialCb); -} - -#endif // AUX_SERIAL - -#if defined(AUX2_SERIAL) - -static TxFifo aux2SerialTxFifo; -static RxFifo aux2SerialRxFifo __DMA (AUX2_SERIAL_DMA_Stream_RX); - -static const LL_GPIO_InitTypeDef aux2USARTPinInit = { - .Pin = AUX2_SERIAL_GPIO_PIN_TX | AUX2_SERIAL_GPIO_PIN_RX, - .Mode = LL_GPIO_MODE_ALTERNATE, - .Speed = LL_GPIO_SPEED_FREQ_LOW, - .OutputType = LL_GPIO_OUTPUT_PUSHPULL, - .Pull = LL_GPIO_PULL_UP, - .Alternate = AUX2_SERIAL_GPIO_AF_LL, -}; - -static const stm32_usart_t aux2USART = { - .USARTx = AUX2_SERIAL_USART, - .GPIOx = AUX2_SERIAL_GPIO, - .pinInit = &aux2USARTPinInit, - .IRQn = AUX2_SERIAL_USART_IRQn, - .IRQ_Prio = 7, // TODO: define constant - .txDMA = nullptr, - .txDMA_Stream = 0, - .txDMA_Channel = 0, - .rxDMA = AUX2_SERIAL_DMA_RX, - .rxDMA_Stream = AUX2_SERIAL_DMA_Stream_RX_LL, - .rxDMA_Channel = AUX2_SERIAL_DMA_Channel_RX, -}; - -static const SerialState aux2SerialState = { - .txFifo = &aux2SerialTxFifo, - .rxFifo = &aux2SerialRxFifo, - .usart = &aux2USART, -}; - -static uint8_t aux2SerialOnSend(uint8_t* data) -{ - return aux2SerialTxFifo.pop(*data); -} - -static etx_serial_callbacks_t aux2SerialCb = { - .on_send = aux2SerialOnSend, - .on_receive = nullptr, - .on_error = nullptr, -}; - -static void* aux2SerialInit(const etx_serial_init* params) -{ - return aux_serial_init(&aux2SerialState, params); -} - -static void (*aux2RxCb)(uint8_t*, uint32_t); - -static void aux2_on_rx_byte(uint8_t data) -{ - if (aux2RxCb) aux2RxCb(&data, 1); -} - -static void aux2SetRxCb(void*, void (*cb)(uint8_t*, uint32_t)) -{ - aux2RxCb = cb; - if (aux2RxCb) { - aux2SerialCb.on_receive = aux2_on_rx_byte; - stm32_usart_deinit_rx_dma(&aux2USART); - } else { - aux2SerialCb.on_receive = nullptr; - } -} - -extern "C" void AUX2_SERIAL_USART_IRQHandler(void) -{ - DEBUG_INTERRUPT(INT_SER2); - stm32_usart_isr(&aux2USART, &aux2SerialCb); -} - -const etx_serial_driver_t Aux2SerialDriver = { - .init = aux2SerialInit, - .deinit = aux_serial_deinit, - .sendByte = aux_serial_putc, - .sendBuffer = aux_serial_send_buffer, - .waitForTxCompleted = aux_wait_tx_completed, - .getByte = aux_get_byte, - .getBaudrate = nullptr, - .setReceiveCb = aux2SetRxCb, - .setBaudrateCb = nullptr, -}; - -#endif // AUX2_SERIAL diff --git a/radio/src/targets/common/arm/stm32/bluetooth_driver.cpp b/radio/src/targets/common/arm/stm32/bluetooth_driver.cpp index 56f28e0e9..8500d5142 100644 --- a/radio/src/targets/common/arm/stm32/bluetooth_driver.cpp +++ b/radio/src/targets/common/arm/stm32/bluetooth_driver.cpp @@ -19,107 +19,100 @@ * GNU General Public License for more details. */ +#include "bluetooth_driver.h" +#include "stm32_hal_ll.h" + #include "board.h" #include "debug.h" #if !defined(BOOT) -#include "fifo.h" +#include "stm32_serial_driver.h" -Fifo btTxFifo; -Fifo btRxFifo; +#define BT_USART_IRQ_PRIORITY 6 + +static const stm32_usart_t btUSART = { + .USARTx = BT_USART, + .GPIOx = BT_USART_GPIO, + .GPIO_Pin = BT_TX_GPIO_PIN | BT_RX_GPIO_PIN, + .IRQn = BT_USART_IRQn, + .IRQ_Prio = BT_USART_IRQ_PRIORITY, + .txDMA = nullptr, + .txDMA_Stream = 0, + .txDMA_Channel = 0, + .rxDMA = nullptr, + .rxDMA_Stream = 0, + .rxDMA_Channel = 0, +}; + +DEFINE_STM32_SERIAL_PORT(BTModule, btUSART, BT_RX_FIFO_SIZE, BT_TX_FIFO_SIZE); #if defined(BLUETOOTH_PROBE) volatile uint8_t btChipPresent = 0; #endif -enum BluetoothWriteState -{ - BLUETOOTH_WRITE_IDLE, -#if defined(BT_BRTS_GPIO_PIN) - BLUETOOTH_WRITE_INIT, -#endif - BLUETOOTH_WRITING, -#if defined(BT_BRTS_GPIO_PIN) - BLUETOOTH_WRITE_DONE -#else - BLUETOOTH_WRITE_DONE = BLUETOOTH_WRITE_IDLE -#endif -}; - -volatile uint8_t bluetoothWriteState = BLUETOOTH_WRITE_IDLE; +// const etx_serial_driver_t* _bt_usart_drv = nullptr; +void* _bt_usart_ctx = nullptr; #endif void bluetoothInit(uint32_t baudrate, bool enable) { - GPIO_InitTypeDef GPIO_InitStructure; - GPIO_InitStructure.GPIO_Pin = BT_EN_GPIO_PIN; - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; - GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; - GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; - GPIO_Init(BT_EN_GPIO, &GPIO_InitStructure); + LL_GPIO_InitTypeDef pinInit; + LL_GPIO_StructInit(&pinInit); -#if defined(BT_BRTS_GPIO_PIN) - GPIO_InitStructure.GPIO_Pin = BT_BRTS_GPIO_PIN; - GPIO_Init(BT_BRTS_GPIO, &GPIO_InitStructure); - GPIO_SetBits(BT_BRTS_GPIO, BT_BRTS_GPIO_PIN); -#endif + pinInit.Pin = BT_EN_GPIO_PIN; + pinInit.Mode = LL_GPIO_MODE_OUTPUT; + pinInit.OutputType = LL_GPIO_OUTPUT_PUSHPULL; + pinInit.Pull = LL_GPIO_PULL_NO; -#if defined(BT_BCTS_GPIO_PIN) - GPIO_InitStructure.GPIO_Pin = BT_BCTS_GPIO_PIN; - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; - GPIO_Init(BT_BCTS_GPIO, &GPIO_InitStructure); -#endif + LL_GPIO_Init(BT_EN_GPIO, &pinInit); #if !defined(BOOT) - GPIO_PinAFConfig(BT_USART_GPIO, BT_TX_GPIO_PinSource, BT_GPIO_AF); - GPIO_PinAFConfig(BT_USART_GPIO, BT_RX_GPIO_PinSource, BT_GPIO_AF); + etx_serial_init cfg = { + .baudrate = baudrate, + .encoding = ETX_Encoding_8N1, + .direction = ETX_Dir_TX_RX, + .polarity = ETX_Pol_Normal, + }; - GPIO_InitStructure.GPIO_Pin = BT_TX_GPIO_PIN | BT_RX_GPIO_PIN; - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; - GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; - GPIO_Init(BT_USART_GPIO, &GPIO_InitStructure); - - USART_DeInit(BT_USART); - USART_InitTypeDef USART_InitStructure; - USART_InitStructure.USART_BaudRate = baudrate; - USART_InitStructure.USART_Parity = USART_Parity_No; - USART_InitStructure.USART_StopBits = USART_StopBits_1; - USART_InitStructure.USART_WordLength = USART_WordLength_8b; - USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; - USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; - USART_Init(BT_USART, &USART_InitStructure); - USART_Cmd(BT_USART, ENABLE); - - USART_ITConfig(BT_USART, USART_IT_RXNE, ENABLE); - NVIC_SetPriority(BT_USART_IRQn, 6); - NVIC_EnableIRQ(BT_USART_IRQn); - - bluetoothWriteState = BLUETOOTH_WRITE_IDLE; - - btRxFifo.clear(); - btTxFifo.clear(); + if (!_bt_usart_ctx) { + auto hw_def = REF_STM32_SERIAL_PORT(BTModule); + _bt_usart_ctx = STM32SerialDriver.init(hw_def, &cfg); + } else { + STM32SerialDriver.setBaudrate(_bt_usart_ctx, baudrate); + } #endif - if (enable) - GPIO_ResetBits(BT_EN_GPIO, BT_EN_GPIO_PIN); - else - GPIO_SetBits(BT_EN_GPIO, BT_EN_GPIO_PIN); + if (enable) { + LL_GPIO_ResetOutputPin(BT_EN_GPIO, BT_EN_GPIO_PIN); + } else { + LL_GPIO_SetOutputPin(BT_EN_GPIO, BT_EN_GPIO_PIN); + } } #if !defined(BOOT) void bluetoothDisable() { - GPIO_SetBits(BT_EN_GPIO, BT_EN_GPIO_PIN); // close bluetooth (recent modules will go to bootloader mode) - USART_ITConfig(BT_USART, USART_IT_RXNE, DISABLE); - GPIO_InitTypeDef GPIO_InitStructure; - GPIO_InitStructure.GPIO_Pin = BT_RX_GPIO_PIN; - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; - GPIO_Init(BT_USART_GPIO, &GPIO_InitStructure); - USART_DeInit(BT_USART); + // close bluetooth (recent modules will go to bootloader mode) + LL_GPIO_SetOutputPin(BT_EN_GPIO, BT_EN_GPIO_PIN); + if (_bt_usart_ctx) { + STM32SerialDriver.deinit(_bt_usart_ctx); + } } +// @Cliff +// ISR is handled by the serial driver, +// however, it is unclear at this point +// how the detection should be implemented. +// Maybe setting a temporary callback on +// the interface, or trying to pull some data. +// +// Also, it is quite unclear why we would need +// to disable sending when the TX buffer is exahausted. +// The serial driver does take care of that but does not +// set any particular piece of state that could be queried +// to deduct the state of this TX buffer. +#if _OBSOLETE_ extern "C" void BT_USART_IRQHandler(void) { DEBUG_INTERRUPT(INT_BLUETOOTH); @@ -144,38 +137,30 @@ extern "C" void BT_USART_IRQHandler(void) } else { USART_ITConfig(BT_USART, USART_IT_TXE, DISABLE); + // => BLUETOOTH_WRITE_IDLE bluetoothWriteState = BLUETOOTH_WRITE_DONE; } } } +#endif -void bluetoothWriteWakeup() +void bluetoothWrite(const void* buffer, uint32_t len) { - if (bluetoothWriteState == BLUETOOTH_WRITE_IDLE) { - if (!btTxFifo.isEmpty()) { -#if defined(BT_BRTS_GPIO_PIN) - bluetoothWriteState = BLUETOOTH_WRITE_INIT; - GPIO_ResetBits(BT_BRTS_GPIO, BT_BRTS_GPIO_PIN); -#else - bluetoothWriteState = BLUETOOTH_WRITING; - USART_ITConfig(BT_USART, USART_IT_TXE, ENABLE); -#endif - } - } -#if defined(BT_BRTS_GPIO_PIN) - else if (bluetoothWriteState == BLUETOOTH_WRITE_INIT) { - bluetoothWriteState = BLUETOOTH_WRITING; - USART_ITConfig(BT_USART, USART_IT_TXE, ENABLE); - } - else if (bluetoothWriteState == BLUETOOTH_WRITE_DONE) { - bluetoothWriteState = BLUETOOTH_WRITE_IDLE; - GPIO_SetBits(BT_BRTS_GPIO, BT_BRTS_GPIO_PIN); - } -#endif + if (!_bt_usart_ctx) return; + STM32SerialDriver.sendBuffer(_bt_usart_ctx, (const uint8_t*)buffer, len); +} + +int bluetoothRead(uint8_t* data) +{ + if (!_bt_usart_ctx) return 0; + return STM32SerialDriver.getByte(_bt_usart_ctx, data); } uint8_t bluetoothIsWriting(void) { - return bluetoothWriteState != BLUETOOTH_WRITE_IDLE; + if (!_bt_usart_ctx) + return false; + + return STM32SerialDriver.txCompleted(_bt_usart_ctx); } #endif // !BOOT diff --git a/radio/src/targets/common/arm/stm32/bluetooth_driver.h b/radio/src/targets/common/arm/stm32/bluetooth_driver.h new file mode 100644 index 000000000..783e42002 --- /dev/null +++ b/radio/src/targets/common/arm/stm32/bluetooth_driver.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#pragma once + +#include "hal/serial_driver.h" + +// BT driver +#define BLUETOOTH_BOOTLOADER_BAUDRATE 230400 +#define BLUETOOTH_DEFAULT_BAUDRATE 115200 +#if defined(PCBX9E) +#define BLUETOOTH_FACTORY_BAUDRATE 9600 +#else +#define BLUETOOTH_FACTORY_BAUDRATE 57600 +#endif +#define BT_TX_FIFO_SIZE 64 +#define BT_RX_FIFO_SIZE 256 + +void bluetoothInit(uint32_t baudrate, bool enable); +void bluetoothWrite(const void* buffer, uint32_t length); +int bluetoothRead(uint8_t* data); +uint8_t bluetoothIsWriting(); +void bluetoothDisable(); + +#if defined(PCBX9LITES) || defined(PCBX7ACCESS) + #define IS_BLUETOOTH_CHIP_PRESENT() (true) +#elif defined(PCBX9LITE) + #define IS_BLUETOOTH_CHIP_PRESENT() (false) +#elif defined(BLUETOOTH_PROBE) && !defined(SIMU) + extern volatile uint8_t btChipPresent; + #define IS_BLUETOOTH_CHIP_PRESENT() (btChipPresent) +#else + #define IS_BLUETOOTH_CHIP_PRESENT() (true) +#endif diff --git a/radio/src/targets/common/arm/stm32/board_common.h b/radio/src/targets/common/arm/stm32/board_common.h index 0f9d7b4b9..9c93fc101 100644 --- a/radio/src/targets/common/arm/stm32/board_common.h +++ b/radio/src/targets/common/arm/stm32/board_common.h @@ -47,7 +47,6 @@ #include "stm32f4xx_spi.h" #include "stm32f4xx_pwr.h" #include "stm32f4xx_dma.h" - #include "stm32f4xx_usart.h" #include "stm32f4xx_flash.h" #include "stm32f4xx_dbgmcu.h" #include "misc.h" @@ -62,7 +61,6 @@ #include "stm32f2xx_spi.h" #include "stm32f2xx_pwr.h" #include "stm32f2xx_dma.h" - #include "stm32f2xx_usart.h" #include "stm32f2xx_flash.h" #include "stm32f2xx_dbgmcu.h" #include "misc.h" diff --git a/radio/src/targets/common/arm/stm32/bootloader/CMakeLists.txt b/radio/src/targets/common/arm/stm32/bootloader/CMakeLists.txt index 3a1857c29..2046ac809 100644 --- a/radio/src/targets/common/arm/stm32/bootloader/CMakeLists.txt +++ b/radio/src/targets/common/arm/stm32/bootloader/CMakeLists.txt @@ -35,6 +35,8 @@ set(BOOTLOADER_SRC ../usb_driver.cpp ../flash_driver.cpp ../stm32_exti_driver.cpp + ../stm32_serial_driver.cpp + ../stm32_usart_driver.cpp init.c boot.cpp bin_files.cpp @@ -89,18 +91,12 @@ if(PCB STREQUAL X10 OR PCB STREQUAL X12S OR PCB STREQUAL NV14) ) endif() - if(PCB STREQUAL NV14) - set(BOOTLOADER_SRC - ${BOOTLOADER_SRC} - ../../../../../targets/${TARGET_DIR}/extmodule_helper.cpp - ) - endif() - if(DEBUG) set(BOOTLOADER_SRC ${BOOTLOADER_SRC} ../../../../../serial.cpp - ../../../../../targets/common/arm/stm32/aux_serial_driver.cpp + ../../../../../boards/generic_stm32/aux_ports.cpp + ../../../../../targets/common/arm/stm32/stm32_serial_driver.cpp ../../../../../targets/common/arm/stm32/stm32_usart_driver.cpp ) endif() diff --git a/radio/src/targets/common/arm/stm32/bootloader/boot.cpp b/radio/src/targets/common/arm/stm32/bootloader/boot.cpp index 8ba0fba9c..c5c16525e 100644 --- a/radio/src/targets/common/arm/stm32/bootloader/boot.cpp +++ b/radio/src/targets/common/arm/stm32/bootloader/boot.cpp @@ -19,6 +19,11 @@ * GNU General Public License for more details. */ +#if defined(BLUETOOTH) + #include "bluetooth_driver.h" + #include "stm32_serial_driver.h" +#endif + #include "board.h" #include "boot.h" #include "bin_files.h" @@ -240,14 +245,15 @@ void bootloaderInitApp() keysInit(); #if defined(SWSERIALPOWER) - #if defined(AUX_SERIAL) - void set_aux_pwr(uint8_t on); - set_aux_pwr(0); - #endif - #if defined(AUX2_SERIAL) - void set_aux2_pwr(uint8_t on); - set_aux2_pwr(0); - #endif + // TODO: replace with proper serial port query... + // #if defined(AUX_SERIAL) + // void set_aux_pwr(uint8_t on); + // set_aux_pwr(0); + // #endif + // #if defined(AUX2_SERIAL) + // void set_aux2_pwr(uint8_t on); + // set_aux2_pwr(0); + // #endif #endif // wait a bit for the inputs to stabilize... diff --git a/radio/src/targets/common/arm/stm32/extmodule_driver.cpp b/radio/src/targets/common/arm/stm32/extmodule_driver.cpp index 001fb1cd8..c70c336fb 100644 --- a/radio/src/targets/common/arm/stm32/extmodule_driver.cpp +++ b/radio/src/targets/common/arm/stm32/extmodule_driver.cpp @@ -20,24 +20,26 @@ */ #include "extmodule_driver.h" -#include "stm32_pulse_driver.h" #include "hal.h" #include "board.h" #include "timers_driver.h" -static const stm32_pulse_timer_t extmoduleTimer = { +static stm32_pulse_dma_tc_cb_t _ext_timer_DMA_TC_Callback; + +const stm32_pulse_timer_t extmoduleTimer = { .GPIOx = EXTMODULE_TX_GPIO, .GPIO_Pin = EXTMODULE_TX_GPIO_PIN, .GPIO_Alternate = EXTMODULE_TIMER_TX_GPIO_AF, .TIMx = EXTMODULE_TIMER, - .TIM_Prescaler = __LL_TIM_CALC_PSC(EXTMODULE_TIMER_FREQ, 2000000), + .TIM_Freq = EXTMODULE_TIMER_FREQ, .TIM_Channel = EXTMODULE_TIMER_Channel, .TIM_IRQn = EXTMODULE_TIMER_IRQn, .DMAx = EXTMODULE_TIMER_DMA, .DMA_Stream = EXTMODULE_TIMER_DMA_STREAM_LL, .DMA_Channel = EXTMODULE_TIMER_DMA_CHANNEL, .DMA_IRQn = EXTMODULE_TIMER_DMA_STREAM_IRQn, + .DMA_TC_CallbackPtr = &_ext_timer_DMA_TC_Callback, }; // Make sure the timer channel is supported @@ -65,126 +67,3 @@ extern "C" void EXTMODULE_TIMER_IRQHandler() { stm32_pulse_tim_update_isr(&extmoduleTimer); } - -void extmoduleStop() -{ - EXTERNAL_MODULE_OFF(); - stm32_pulse_deinit(&extmoduleTimer); -} - -static void config_ppm_output(uint16_t ppm_delay, bool polarity) -{ - // PPM generation principle: - // - // Hardware timer in PWM mode is used for PPM generation - // Output is OFF if CNT>= 1 ; - while ((uint16_t) (getTmr2MHz() - time) < 35) { - // wait - } - time += 35 ; - } - LL_GPIO_ResetOutputPin(EXTMODULE_TX_GPIO, EXTMODULE_TX_GPIO_PIN); - __enable_irq(); // No need to wait for the stop bit to complete - while ((uint16_t) (getTmr2MHz() - time) < 34) { - // wait - } -} diff --git a/radio/src/targets/common/arm/stm32/extmodule_driver.h b/radio/src/targets/common/arm/stm32/extmodule_driver.h index 581c8dd4e..89383228b 100644 --- a/radio/src/targets/common/arm/stm32/extmodule_driver.h +++ b/radio/src/targets/common/arm/stm32/extmodule_driver.h @@ -23,23 +23,6 @@ #include -void extmoduleStop(); -void extmodulePpmStart(uint16_t ppm_delay, bool polarity); +#include "stm32_pulse_driver.h" -#if defined(PXX1) -void extmodulePxx1PulsesStart(); -void extmoduleSendNextFramePxx1(const void* pulses, uint16_t length); -#endif - -// Soft serial on PPM pin -void extmoduleSerialStart(); - -void extmoduleSendNextFramePpm(void* pulses, uint16_t length, - uint16_t ppm_delay, bool polarity); - -void extmoduleSendNextFrameSoftSerial(const void* pulses, uint16_t length, - bool polarity = true); - -// Bitbang serial -void extmoduleInitTxPin(); -void extmoduleSendInvertedByte(uint8_t byte); +extern const stm32_pulse_timer_t extmoduleTimer; diff --git a/radio/src/targets/common/arm/stm32/extmodule_serial_driver.cpp b/radio/src/targets/common/arm/stm32/extmodule_serial_driver.cpp deleted file mode 100644 index 40d735412..000000000 --- a/radio/src/targets/common/arm/stm32/extmodule_serial_driver.cpp +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright (C) EdgeTX - * - * Based on code named - * opentx - https://github.com/opentx/opentx - * th9x - http://code.google.com/p/th9x - * er9x - http://code.google.com/p/er9x - * gruvin9x - http://code.google.com/p/gruvin9x - * - * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "stm32_hal_ll.h" -#include "stm32_usart_driver.h" -#include "extmodule_serial_driver.h" - -#include "board.h" - -#if defined(EXTMODULE_USART) - -struct RxFifo { - uint8_t* buf; - uint16_t size; - uint16_t widx; - uint16_t ridx; -}; - -struct ExtmoduleCtx { - RxFifo rxFifo; - const stm32_usart_t* usart; -}; - -static etx_serial_callbacks_t extmodule_callbacks = { - nullptr, nullptr, nullptr -}; - -static void _fifo_clear(const stm32_usart_t* usart, RxFifo& fifo) -{ - if (usart->rxDMA) { - auto dma_len = LL_DMA_GetDataLength(usart->rxDMA, usart->rxDMA_Stream); - fifo.ridx = fifo.size - dma_len; - } else { - fifo.widx = fifo.ridx = 0; - } -} - -static int _fifo_get_byte(const stm32_usart_t* usart, RxFifo& fifo, uint8_t* data) -{ - if (usart->rxDMA) { - auto DMAx = usart->rxDMA; - auto stream = usart->rxDMA_Stream; - - // DMA stream enabled? - if (!LL_DMA_IsEnabledStream(DMAx, stream)) return 0; - - // Anything to read? - auto dma_len = LL_DMA_GetDataLength(DMAx, stream); - if (fifo.size - dma_len == fifo.ridx) return 0; - } else { - if (fifo.ridx == fifo.widx) return 0; - } - - *data = fifo.buf[fifo.ridx]; - fifo.ridx = (fifo.ridx + 1) & (fifo.size - 1); - - return 1; -} - -static const LL_GPIO_InitTypeDef extmoduleUSART_PinDef = { - .Pin = EXTMODULE_TX_GPIO_PIN | EXTMODULE_RX_GPIO_PIN, - .Mode = LL_GPIO_MODE_ALTERNATE, - .Speed = LL_GPIO_SPEED_FREQ_LOW, - .OutputType = LL_GPIO_OUTPUT_PUSHPULL, - .Pull = LL_GPIO_PULL_UP, - .Alternate = EXTMODULE_USART_GPIO_AF_LL, -}; - -static const stm32_usart_t extmoduleUSART = { - .USARTx = EXTMODULE_USART, - .GPIOx = EXTMODULE_TX_GPIO, - .pinInit = &extmoduleUSART_PinDef, - .IRQn = EXTMODULE_USART_IRQn, - .IRQ_Prio = EXTMODULE_USART_IRQ_PRIORITY, - .txDMA = EXTMODULE_USART_TX_DMA, - .txDMA_Stream = EXTMODULE_USART_TX_DMA_STREAM_LL, - .txDMA_Channel = EXTMODULE_USART_TX_DMA_CHANNEL, - .rxDMA = EXTMODULE_USART_TX_DMA, - .rxDMA_Stream = EXTMODULE_USART_RX_DMA_STREAM_LL, - .rxDMA_Channel = EXTMODULE_USART_RX_DMA_CHANNEL, -}; - -static uint8_t _rx_buffer[INTMODULE_FIFO_SIZE] __DMA; - -static ExtmoduleCtx extmoduleCtx = { - .rxFifo = { _rx_buffer, sizeof(_rx_buffer), 0, 0 }, - .usart = &extmoduleUSART, -}; - -static void* extmoduleSerialInit(const etx_serial_init* params) -{ - if (!params) return nullptr; - - extmodule_callbacks.on_receive = nullptr; - extmodule_callbacks.on_error = nullptr; - - // UART config - auto usart = extmoduleCtx.usart; - stm32_usart_init(usart, params); - - auto& fifo = extmoduleCtx.rxFifo; - if (params->rx_enable && usart->rxDMA) { - stm32_usart_init_rx_dma(usart, fifo.buf, fifo.size); - } - _fifo_clear(usart, fifo); - - return (void*)&extmoduleCtx; -} - -void extmoduleSerialStop(void* ctx) -{ - auto modCtx = (ExtmoduleCtx*)ctx; - stm32_usart_deinit(modCtx->usart); - - // reset callbacks - extmodule_callbacks.on_receive = nullptr; - extmodule_callbacks.on_error = nullptr; -} - -static void extmoduleSerialSendByte(void* ctx, uint8_t byte) -{ - auto modCtx = (ExtmoduleCtx*)ctx; - stm32_usart_send_byte(modCtx->usart, byte); -} - -static void extmoduleSerialSendBuffer(void* ctx, const uint8_t * data, uint8_t size) -{ - auto modCtx = (ExtmoduleCtx*)ctx; - if (size == 0) return; - stm32_usart_send_buffer(modCtx->usart, data, size); -} - -static void extmoduleSerialWaitForTxCompleted(void* ctx) -{ - auto modCtx = (ExtmoduleCtx*)ctx; - stm32_usart_wait_for_tx_dma(modCtx->usart); -} - -static int extmoduleSerialGetByte(void* ctx, uint8_t* data) -{ - auto modCtx = (ExtmoduleCtx*)ctx; - return _fifo_get_byte(modCtx->usart, modCtx->rxFifo, data); -} - -static void extmoduleSerialClearRxBuffer(void* ctx) -{ - auto modCtx = (ExtmoduleCtx*)ctx; - _fifo_clear(modCtx->usart, modCtx->rxFifo); -} - -static const etx_serial_driver_t extmoduleSerialDriver = { - .init = extmoduleSerialInit, - .deinit = extmoduleSerialStop, - .sendByte = extmoduleSerialSendByte, - .sendBuffer = extmoduleSerialSendBuffer, - .waitForTxCompleted = extmoduleSerialWaitForTxCompleted, - .getByte = extmoduleSerialGetByte, - .clearRxBuffer = extmoduleSerialClearRxBuffer, - .getBaudrate = nullptr, - .setReceiveCb = nullptr, - .setBaudrateCb = nullptr, -}; - -constexpr const etx_serial_driver_t* _default_driver = &extmoduleSerialDriver; - -// IRQ based RX/TX: probably obsolete now -extern "C" void EXTMODULE_USART_IRQHandler(void) -{ - stm32_usart_isr(extmoduleCtx.usart, &extmodule_callbacks); -} - -#else - -constexpr const etx_serial_driver_t* _default_driver = nullptr; - -#endif // defined(EXTMODULE_USART) - -const etx_serial_driver_t* _extmodule_driver = _default_driver; - -void extmoduleSetSerialPort(const etx_serial_driver_t* drv) -{ - if (drv) { - _extmodule_driver = drv; - } else { - _extmodule_driver = _default_driver; - } -} - -const etx_serial_driver_t* extmoduleGetSerialPort() -{ - return _extmodule_driver; -} diff --git a/radio/src/targets/common/arm/stm32/f2/CMakeLists.txt b/radio/src/targets/common/arm/stm32/f2/CMakeLists.txt index 3557d96a5..232ab41e1 100644 --- a/radio/src/targets/common/arm/stm32/f2/CMakeLists.txt +++ b/radio/src/targets/common/arm/stm32/f2/CMakeLists.txt @@ -54,7 +54,6 @@ add_library(stm32_stdperiph OBJECT EXCLUDE_FROM_ALL ${STM32_STDPERIPH_DIR}/src/stm32f2xx_spi.c ${STM32_STDPERIPH_DIR}/src/stm32f2xx_dma.c ${STM32_STDPERIPH_DIR}/src/stm32f2xx_pwr.c - ${STM32_STDPERIPH_DIR}/src/stm32f2xx_usart.c ${STM32_STDPERIPH_DIR}/src/stm32f2xx_adc.c ) diff --git a/radio/src/targets/common/arm/stm32/f4/CMakeLists.txt b/radio/src/targets/common/arm/stm32/f4/CMakeLists.txt index 14a1c14ed..c92006d71 100644 --- a/radio/src/targets/common/arm/stm32/f4/CMakeLists.txt +++ b/radio/src/targets/common/arm/stm32/f4/CMakeLists.txt @@ -53,7 +53,6 @@ set(STM32_STDPERIPH_SRC ${STM32_STDPERIPH_DIR}/src/stm32f4xx_spi.c ${STM32_STDPERIPH_DIR}/src/stm32f4xx_dma.c ${STM32_STDPERIPH_DIR}/src/stm32f4xx_pwr.c - ${STM32_STDPERIPH_DIR}/src/stm32f4xx_usart.c ${STM32_STDPERIPH_DIR}/src/stm32f4xx_adc.c ${STM32_STDPERIPH_DIR}/src/stm32f4xx_flash.c ) diff --git a/radio/src/targets/common/arm/stm32/flysky_gimbal_driver.cpp b/radio/src/targets/common/arm/stm32/flysky_gimbal_driver.cpp new file mode 100644 index 000000000..31b5d19e8 --- /dev/null +++ b/radio/src/targets/common/arm/stm32/flysky_gimbal_driver.cpp @@ -0,0 +1,190 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "flysky_gimbal_driver.h" +#include "stm32_serial_driver.h" +#include "delays_driver.h" + +#include "hal.h" +#include "crc.h" + +#include + +static const stm32_usart_t fsUSART = { + .USARTx = FLYSKY_HALL_SERIAL_USART, + .GPIOx = FLYSKY_HALL_SERIAL_GPIO, + .GPIO_Pin = FLYSKY_HALL_SERIAL_RX_GPIO_PIN, + .IRQn = FLYSKY_HALL_SERIAL_USART_IRQn, + .IRQ_Prio = 6, + .txDMA = nullptr, + .txDMA_Stream = 0, + .txDMA_Channel = 0, + .rxDMA = FLYSKY_HALL_SERIAL_DMA, + .rxDMA_Stream = FLYSKY_HALL_DMA_Stream_RX, + .rxDMA_Channel = FLYSKY_HALL_DMA_Channel, +}; + +DEFINE_STM32_SERIAL_PORT(FSGimbal, fsUSART, HALLSTICK_BUFF_SIZE, 0); + +static STRUCT_HALL HallProtocol = { 0 }; + +signed short hall_raw_values[FLYSKY_HALL_CHANNEL_COUNT]; +unsigned short hall_adc_values[FLYSKY_HALL_CHANNEL_COUNT]; + +static void* _fs_usart_ctx = nullptr; + +uint16_t get_flysky_hall_adc_value(uint8_t ch) +{ + if (ch >= FLYSKY_HALL_CHANNEL_COUNT) { + return 0; + } + + return 2 * FLYSKY_OFFSET_VALUE - hall_adc_values[ch]; +} + +static int _fs_get_byte(uint8_t* data) +{ + return STM32SerialDriver.getByte(_fs_usart_ctx, data); +} + +static void _fs_parse(STRUCT_HALL *hallBuffer, unsigned char ch) +{ + switch (hallBuffer->status) { + case GET_START: + if (FLYSKY_HALL_PROTOLO_HEAD == ch) { + hallBuffer->head = FLYSKY_HALL_PROTOLO_HEAD; + hallBuffer->status = GET_ID; + hallBuffer->msg_OK = 0; + } + break; + + case GET_ID: + hallBuffer->hallID.ID = ch; + hallBuffer->status = GET_LENGTH; + break; + + case GET_LENGTH: + hallBuffer->length = ch; + hallBuffer->dataIndex = 0; + hallBuffer->status = GET_DATA; + if (0 == hallBuffer->length) { + hallBuffer->status = GET_CHECKSUM; + hallBuffer->checkSum = 0; + } + break; + + case GET_DATA: + hallBuffer->data[hallBuffer->dataIndex++] = ch; + if (hallBuffer->dataIndex >= hallBuffer->length) { + hallBuffer->checkSum = 0; + hallBuffer->dataIndex = 0; + hallBuffer->status = GET_STATE; + } + break; + + case GET_STATE: + hallBuffer->checkSum = 0; + hallBuffer->dataIndex = 0; + hallBuffer->status = GET_CHECKSUM; + // fall through! + + case GET_CHECKSUM: + hallBuffer->checkSum |= ch << ((hallBuffer->dataIndex++) * 8); + if (hallBuffer->dataIndex >= 2) { + hallBuffer->dataIndex = 0; + hallBuffer->status = CHECKSUM; + // fall through! + } else { + break; + } + + case CHECKSUM: + if (hallBuffer->checkSum == + crc16(CRC_1021, &hallBuffer->head, hallBuffer->length + 3, 0xffff)) { + hallBuffer->msg_OK = 1; + } + hallBuffer->status = GET_START; + break; + } +} + +static volatile bool _fs_gimbal_detected; + +static void flysky_gimbal_loop() +{ + uint8_t byte; + + while(_fs_get_byte(&byte)) + { + HallProtocol.index++; + + _fs_parse(&HallProtocol, byte); + if ( HallProtocol.msg_OK ) + { + HallProtocol.msg_OK = 0; + HallProtocol.stickState = HallProtocol.data[HallProtocol.length - 1]; + + switch ( HallProtocol.hallID.hall_Id.receiverID ) + { + case TRANSFER_DIR_TXMCU: + if(HallProtocol.hallID.hall_Id.packetID == FLYSKY_HALL_RESP_TYPE_VALUES) { + memcpy(hall_raw_values, HallProtocol.data, sizeof(hall_raw_values)); + for ( uint8_t channel = 0; channel < 4; channel++ ) + { + hall_adc_values[channel] = FLYSKY_OFFSET_VALUE + hall_raw_values[channel]; + } + } + break; + } + _fs_gimbal_detected = true; + } + } +} + +static void flysky_gimbal_deinit() +{ + STM32SerialDriver.deinit(_fs_usart_ctx); +} + +bool flysky_gimbal_init() +{ + etx_serial_init cfg = { + .baudrate = FLYSKY_HALL_BAUDRATE, + .encoding = ETX_Encoding_8N1, + .direction = ETX_Dir_RX, + .polarity = ETX_Pol_Normal, + }; + + _fs_gimbal_detected = false; + _fs_usart_ctx = STM32SerialDriver.init(REF_STM32_SERIAL_PORT(FSGimbal), &cfg); + STM32SerialDriver.setIdleCb(_fs_usart_ctx, flysky_gimbal_loop); + + // Wait 70ms for FlySky gimbals to respond. According to LA trace, minimally 23ms is required + for (uint8_t i = 0; i < 70; i++) { + delay_ms(1); + if (_fs_gimbal_detected) { + return true; + } + } + + flysky_gimbal_deinit(); + return false; +} diff --git a/radio/src/targets/horus/flyskyHallStick_driver.h b/radio/src/targets/common/arm/stm32/flysky_gimbal_driver.h similarity index 96% rename from radio/src/targets/horus/flyskyHallStick_driver.h rename to radio/src/targets/common/arm/stm32/flysky_gimbal_driver.h index 8d7973990..ed125dbfa 100644 --- a/radio/src/targets/horus/flyskyHallStick_driver.h +++ b/radio/src/targets/common/arm/stm32/flysky_gimbal_driver.h @@ -114,3 +114,7 @@ enum TRANSFER_DIR_E { extern signed short hall_raw_values[FLYSKY_HALL_CHANNEL_COUNT]; extern unsigned short hall_adc_values[FLYSKY_HALL_CHANNEL_COUNT]; + +// returns true if the gimbals were detected properly +bool flysky_gimbal_init(); + diff --git a/radio/src/targets/common/arm/stm32/heartbeat_driver.h b/radio/src/targets/common/arm/stm32/heartbeat_driver.h index de7d98866..065f8be69 100644 --- a/radio/src/targets/common/arm/stm32/heartbeat_driver.h +++ b/radio/src/targets/common/arm/stm32/heartbeat_driver.h @@ -32,5 +32,4 @@ struct HeartbeatCapture { extern volatile HeartbeatCapture heartbeatCapture; void init_intmodule_heartbeat(); -void check_intmodule_heartbeat(); void stop_intmodule_heartbeat(); diff --git a/radio/src/targets/common/arm/stm32/intmodule_serial_driver.cpp b/radio/src/targets/common/arm/stm32/intmodule_serial_driver.cpp deleted file mode 100755 index 9968effb2..000000000 --- a/radio/src/targets/common/arm/stm32/intmodule_serial_driver.cpp +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Copyright (C) EdgeTX - * - * Based on code named - * opentx - https://github.com/opentx/opentx - * th9x - http://code.google.com/p/th9x - * er9x - http://code.google.com/p/er9x - * gruvin9x - http://code.google.com/p/gruvin9x - * - * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "stm32_hal_ll.h" -#include "intmodule_serial_driver.h" -#include "stm32_usart_driver.h" -#include "board.h" - -#include "fifo.h" -#include "dmafifo.h" - -#if defined(INTMODULE_RX_DMA) -typedef DMAFifo RxFifo; -static RxFifo intmoduleFifo __DMA( - __LL_DMA_GET_STREAM_INSTANCE(INTMODULE_RX_DMA, INTMODULE_RX_DMA_STREAM)); -#else -typedef Fifo RxFifo; -static RxFifo intmoduleFifo; -#endif - -struct IntmoduleCtx -{ - RxFifo* rxFifo; - const stm32_usart_t* usart; -}; - -#if !defined(INTMODULE_DMA_STREAM) -static uint8_t * intmoduleTxBufferData; -static volatile uint8_t intmoduleTxBufferRemaining; - -uint8_t intmoduleTxBufferSend(uint8_t* data) -{ - if (intmoduleTxBufferRemaining) { - *data = *(intmoduleTxBufferData++); - intmoduleTxBufferRemaining--; - return true; - } - - // buffer is empty - return false; -} -#endif - -static etx_serial_callbacks_t intmodule_driver = { -#if !defined(INTMODULE_DMA_STREAM) - intmoduleTxBufferSend, -#else - nullptr, -#endif - nullptr, nullptr -}; - -#if !defined(INTMODULE_RX_DMA) -// TODO: move this somewhere else -static void intmoduleFifoReceive(uint8_t data) -{ - intmoduleFifo.push(data); -} -#endif - -static const LL_GPIO_InitTypeDef intmoduleUSART_PinDef = { - .Pin = INTMODULE_TX_GPIO_PIN | INTMODULE_RX_GPIO_PIN, - .Mode = LL_GPIO_MODE_ALTERNATE, - .Speed = LL_GPIO_SPEED_FREQ_LOW, - .OutputType = LL_GPIO_OUTPUT_PUSHPULL, - .Pull = LL_GPIO_PULL_UP, - .Alternate = INTMODULE_GPIO_AF, -}; - -static const stm32_usart_t intmoduleUSART = { - .USARTx = INTMODULE_USART, - .GPIOx = INTMODULE_GPIO, - .pinInit = &intmoduleUSART_PinDef, - .IRQn = INTMODULE_USART_IRQn, - .IRQ_Prio = INTMODULE_USART_IRQ_PRIORITY, -#if defined(INTMODULE_DMA) - .txDMA = INTMODULE_DMA, - .txDMA_Stream = INTMODULE_DMA_STREAM, - .txDMA_Channel = INTMODULE_DMA_CHANNEL, -#else - .txDMA = nullptr, - .txDMA_Stream = 0, - .txDMA_Channel = 0, -#endif -#if defined(INTMODULE_RX_DMA) - .rxDMA = INTMODULE_RX_DMA, - .rxDMA_Stream = INTMODULE_RX_DMA_STREAM, - .rxDMA_Channel = INTMODULE_RX_DMA_CHANNEL, -#else - .rxDMA = nullptr, - .rxDMA_Stream = 0, - .rxDMA_Channel = 0, -#endif -}; - -static const IntmoduleCtx intmoduleCtx = { - .rxFifo = &intmoduleFifo, - .usart = &intmoduleUSART, -}; - -void intmoduleStop() -{ - INTERNAL_MODULE_OFF(); - stm32_usart_deinit(&intmoduleUSART); - - // reset callbacks - intmodule_driver.on_receive = nullptr; - intmodule_driver.on_error = nullptr; -} - -static void intmoduleStop(void* ctx) -{ - (void)ctx; - intmoduleStop(); -} - -void* intmoduleSerialStart(const etx_serial_init* params) -{ - if (!params) return nullptr; - - // TODO: sanity check parameters - // - the UART seems to block when initialised with baudrate = 0 - - // init callbacks -#if !defined(INTMODULE_RX_DMA) - intmodule_driver.on_receive = intmoduleFifoReceive; -#else - intmodule_driver.on_receive = nullptr; -#endif - intmodule_driver.on_error = nullptr; - - stm32_usart_init(&intmoduleUSART, params); - - if (params->rx_enable && intmoduleUSART.rxDMA) { - stm32_usart_init_rx_dma(&intmoduleUSART, intmoduleFifo.buffer(), intmoduleFifo.size()); - } - intmoduleCtx.rxFifo->clear(); - - return (void*)&intmoduleCtx; -} - -#define USART_FLAG_ERRORS (USART_FLAG_ORE | USART_FLAG_NE | USART_FLAG_FE | USART_FLAG_PE) -extern "C" void INTMODULE_USART_IRQHandler(void) -{ - stm32_usart_isr(&intmoduleUSART, &intmodule_driver); -} - -void intmoduleSendByte(void* ctx, uint8_t byte) -{ - auto modCtx = (IntmoduleCtx*)ctx; - stm32_usart_send_byte(modCtx->usart, byte); -} - -void intmoduleSendBuffer(void* ctx, const uint8_t * data, uint8_t size) -{ - auto modCtx = (IntmoduleCtx*)ctx; - if (size == 0) - return; - -#if !defined(INTMODULE_DMA_STREAM) - intmoduleTxBufferData = (uint8_t *)data; - intmoduleTxBufferRemaining = size; -#endif - stm32_usart_send_buffer(modCtx->usart, data, size); -} - -void intmoduleWaitForTxCompleted(void* ctx) -{ -#if defined(INTMODULE_DMA_STREAM) - auto modCtx = (IntmoduleCtx*)ctx; - stm32_usart_wait_for_tx_dma(modCtx->usart); -#else - while (intmoduleTxBufferRemaining > 0); -#endif -} - -static int intmoduleGetByte(void* ctx, uint8_t* data) -{ - auto modCtx = (IntmoduleCtx*)ctx; - if (!modCtx->rxFifo) return -1; - return modCtx->rxFifo->pop(*data); -} - -static void intmoduleClearRxBuffer(void* ctx) -{ - auto modCtx = (IntmoduleCtx*)ctx; - if (!modCtx->rxFifo) return; - modCtx->rxFifo->clear(); -} - -const etx_serial_driver_t IntmoduleSerialDriver = { - .init = intmoduleSerialStart, - .deinit = intmoduleStop, - .sendByte = intmoduleSendByte, - .sendBuffer = intmoduleSendBuffer, - .waitForTxCompleted = intmoduleWaitForTxCompleted, - .getByte = intmoduleGetByte, - .clearRxBuffer = intmoduleClearRxBuffer, - .getBaudrate = nullptr, - .setReceiveCb = nullptr, - .setBaudrateCb = nullptr, -}; diff --git a/radio/src/targets/common/arm/stm32/module_timer_driver.cpp b/radio/src/targets/common/arm/stm32/module_timer_driver.cpp new file mode 100644 index 000000000..cde474fef --- /dev/null +++ b/radio/src/targets/common/arm/stm32/module_timer_driver.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "module_timer_driver.h" +#include "stm32_pulse_driver.h" + +static void* module_timer_init(void* hw_def, const etx_timer_config_t* cfg) +{ + auto timer = (const stm32_pulse_timer_t*)hw_def; + + bool polarity = cfg->polarity; + uint32_t ocval = cfg->cmp_val; + uint32_t ocmode = (cfg->type == ETX_PWM) ? LL_TIM_OCMODE_PWM1 : LL_TIM_OCMODE_TOGGLE; + + stm32_pulse_init(timer, 0); + stm32_pulse_config_output(timer, polarity, ocmode, ocval); + + return (void*)timer; +} + +static void module_timer_deinit(void* ctx) +{ + auto timer = (const stm32_pulse_timer_t*)ctx; + stm32_pulse_deinit(timer); +} + +static void module_timer_send(void* ctx, const etx_timer_config_t* cfg, + const void* pulses, uint16_t length) +{ + auto timer = (const stm32_pulse_timer_t*)ctx; + if (!stm32_pulse_if_not_running_disable(timer)) return; + + // Set polarity + stm32_pulse_set_polarity(timer, cfg->polarity); + + // Start DMA request and re-enable timer + uint32_t ocmode = (cfg->type == ETX_PWM) ? LL_TIM_OCMODE_PWM1 : LL_TIM_OCMODE_TOGGLE; + uint32_t ocval = cfg->cmp_val; + stm32_pulse_start_dma_req(timer, pulses, length, ocmode, ocval); +} + +const etx_timer_driver_t STM32ModuleTimerDriver = { + .init = module_timer_init, + .deinit = module_timer_deinit, + .send = module_timer_send, +}; diff --git a/radio/src/targets/common/arm/stm32/extmodule_serial_driver.h b/radio/src/targets/common/arm/stm32/module_timer_driver.h similarity index 70% rename from radio/src/targets/common/arm/stm32/extmodule_serial_driver.h rename to radio/src/targets/common/arm/stm32/module_timer_driver.h index b4c29605a..bc466f7fe 100644 --- a/radio/src/targets/common/arm/stm32/extmodule_serial_driver.h +++ b/radio/src/targets/common/arm/stm32/module_timer_driver.h @@ -21,13 +21,6 @@ #pragma once -#include -#include "hal/serial_driver.h" +#include "hal/timer_driver.h" -#define EXTMODULE_USART_IRQ_PRIORITY 6 - -// Use an alternative USART as external module -void extmoduleSetSerialPort(const etx_serial_driver_t* port); - -// Return the serial driver to be used as external module -const etx_serial_driver_t* extmoduleGetSerialPort(); +extern const etx_timer_driver_t STM32ModuleTimerDriver; diff --git a/radio/src/targets/common/arm/stm32/stm32_dma.h b/radio/src/targets/common/arm/stm32/stm32_dma.h new file mode 100644 index 000000000..6a47eb310 --- /dev/null +++ b/radio/src/targets/common/arm/stm32/stm32_dma.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) EdgeTx + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#pragma once + +#include +#include "stm32_hal_ll.h" + +inline static bool stm32_dma_check_tc_flag(DMA_TypeDef* DMAx, uint32_t DMA_Stream) +{ + switch(DMA_Stream) { + case LL_DMA_STREAM_1: + if (!LL_DMA_IsActiveFlag_TC1(DMAx)) return false; + LL_DMA_ClearFlag_TC1(DMAx); + break; + case LL_DMA_STREAM_5: + if (!LL_DMA_IsActiveFlag_TC5(DMAx)) return false; + LL_DMA_ClearFlag_TC5(DMAx); + break; + case LL_DMA_STREAM_6: + if (!LL_DMA_IsActiveFlag_TC6(DMAx)) return false; + LL_DMA_ClearFlag_TC6(DMAx); + break; + case LL_DMA_STREAM_7: + if (!LL_DMA_IsActiveFlag_TC7(DMAx)) return false; + LL_DMA_ClearFlag_TC7(DMAx); + break; + } + + return true; +} diff --git a/radio/src/targets/common/arm/stm32/stm32_exti_driver.cpp b/radio/src/targets/common/arm/stm32/stm32_exti_driver.cpp index dec872b4e..1f913d41e 100644 --- a/radio/src/targets/common/arm/stm32/stm32_exti_driver.cpp +++ b/radio/src/targets/common/arm/stm32/stm32_exti_driver.cpp @@ -82,7 +82,7 @@ static bool _has_handler(stm32_exti_handler_t* _handlers, uint8_t len) return false; } -void stm32_exti_enable(uint32_t line, uint32_t trigger, stm32_exti_handler_t cb) +void stm32_exti_enable(uint32_t line, uint8_t trigger, stm32_exti_handler_t cb) { if (line > LL_EXTI_LINE_15) return; diff --git a/radio/src/targets/common/arm/stm32/stm32_exti_driver.h b/radio/src/targets/common/arm/stm32/stm32_exti_driver.h index 641603f43..83ea115a6 100644 --- a/radio/src/targets/common/arm/stm32/stm32_exti_driver.h +++ b/radio/src/targets/common/arm/stm32/stm32_exti_driver.h @@ -34,7 +34,7 @@ typedef void (*stm32_exti_handler_t)(); // Set callback and enable IRQ -void stm32_exti_enable(uint32_t line, uint32_t trigger, stm32_exti_handler_t cb); +void stm32_exti_enable(uint32_t line, uint8_t trigger, stm32_exti_handler_t cb); // Reset callback and disable IRQ if no more handlers void stm32_exti_disable(uint32_t line); diff --git a/radio/src/targets/common/arm/stm32/stm32_hal_ll.h b/radio/src/targets/common/arm/stm32/stm32_hal_ll.h index f7b02bfcf..b97802b54 100644 --- a/radio/src/targets/common/arm/stm32/stm32_hal_ll.h +++ b/radio/src/targets/common/arm/stm32/stm32_hal_ll.h @@ -32,6 +32,7 @@ extern "C" { #include "STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_usart.h" #include "STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_exti.h" #include "STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_system.h" + #include "STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_rcc.h" #elif defined(STM32F2) // Workaround to prevent the other CMSIS header to be included @@ -47,5 +48,6 @@ extern "C" { #include "STM32F2xx_HAL_Driver/Inc/stm32f2xx_ll_usart.h" #include "STM32F2xx_HAL_Driver/Inc/stm32f2xx_ll_exti.h" #include "STM32F2xx_HAL_Driver/Inc/stm32f2xx_ll_system.h" + #include "STM32F2xx_HAL_Driver/Inc/stm32f2xx_ll_rcc.h" #endif } diff --git a/radio/src/targets/common/arm/stm32/stm32_pulse_driver.cpp b/radio/src/targets/common/arm/stm32/stm32_pulse_driver.cpp index 6ed59fa2b..b339e09f1 100644 --- a/radio/src/targets/common/arm/stm32/stm32_pulse_driver.cpp +++ b/radio/src/targets/common/arm/stm32/stm32_pulse_driver.cpp @@ -20,8 +20,20 @@ */ #include "stm32_pulse_driver.h" +#include "stm32_dma.h" + #include "definitions.h" +#include + + // 0.5uS (2Mhz) +#define STM32_DEFAULT_TIMER_FREQ 2000000 +#define STM32_DEFAULT_TIMER_AUTORELOAD 65535 + +// TODO: +// - DMA IRQ prio configurable (now 7) +// - Timer IRQ prio configurable (now 7) + static void enable_tim_clock(TIM_TypeDef* TIMx) { if (TIMx == TIM1) { @@ -37,8 +49,12 @@ static void enable_tim_clock(TIM_TypeDef* TIMx) } } -void stm32_pulse_init(const stm32_pulse_timer_t* tim) +void stm32_pulse_init(const stm32_pulse_timer_t* tim, uint32_t freq) { + if (tim->DMA_TC_CallbackPtr) { + memset(tim->DMA_TC_CallbackPtr, 0, sizeof(stm32_pulse_dma_tc_cb_t)); + } + LL_GPIO_InitTypeDef pinInit; LL_GPIO_StructInit(&pinInit); pinInit.Pin = tim->GPIO_Pin; @@ -49,9 +65,12 @@ void stm32_pulse_init(const stm32_pulse_timer_t* tim) LL_TIM_InitTypeDef timInit; LL_TIM_StructInit(&timInit); - // 0.5uS (2Mhz) - timInit.Prescaler = tim->TIM_Prescaler; - timInit.Autoreload = 65535; + if (!freq) { + freq = STM32_DEFAULT_TIMER_FREQ; + } + + timInit.Prescaler = __LL_TIM_CALC_PSC(tim->TIM_Freq, freq); + timInit.Autoreload = STM32_DEFAULT_TIMER_AUTORELOAD; enable_tim_clock(tim->TIMx); LL_TIM_Init(tim->TIMx, &timInit); @@ -93,6 +112,11 @@ void stm32_pulse_deinit(const stm32_pulse_timer_t* tim) if (tim->DMAx) { LL_DMA_DeInit(tim->DMAx, tim->DMA_Stream); } + + if (tim->DMA_TC_CallbackPtr) { + memset(tim->DMA_TC_CallbackPtr, 0, sizeof(stm32_pulse_dma_tc_cb_t)); + } + LL_TIM_DeInit(tim->TIMx); disable_tim_clock(tim->TIMx); @@ -144,7 +168,6 @@ void stm32_pulse_config_output(const stm32_pulse_timer_t* tim, bool polarity, LL_TIM_EnableAllOutputs(tim->TIMx); } - LL_TIM_EnableDMAReq_UPDATE(tim->TIMx); } void stm32_pulse_set_polarity(const stm32_pulse_timer_t* tim, bool polarity) @@ -158,6 +181,12 @@ void stm32_pulse_set_polarity(const stm32_pulse_timer_t* tim, bool polarity) LL_TIM_OC_SetPolarity(tim->TIMx, tim->TIM_Channel, ll_polarity); } +bool stm32_pulse_get_polarity(const stm32_pulse_timer_t* tim) +{ + return LL_TIM_OC_GetPolarity(tim->TIMx, tim->TIM_Channel) == + LL_TIM_OCPOLARITY_HIGH; +} + // return true if stopped, false otherwise bool stm32_pulse_if_not_running_disable(const stm32_pulse_timer_t* tim) { @@ -204,6 +233,16 @@ static void set_oc_mode(const stm32_pulse_timer_t* tim, uint32_t ocmode) LL_TIM_OC_SetMode(tim->TIMx, channel, ocmode); } +void stm32_pulse_wait_for_completed(const stm32_pulse_timer_t* tim) +{ + uint32_t channel = tim->TIM_Channel; + if (channel == LL_TIM_CHANNEL_CH1N) + channel = LL_TIM_CHANNEL_CH1; + + while(LL_TIM_IsEnabledCounter(tim->TIMx) && + LL_TIM_OC_GetMode(tim->TIMx, channel) != LL_TIM_OCMODE_FORCED_INACTIVE); +} + static void force_start_level(const stm32_pulse_timer_t* tim) { uint32_t channel = tim->TIM_Channel; @@ -259,48 +298,43 @@ void stm32_pulse_start_dma_req(const stm32_pulse_timer_t* tim, // Enable TC IRQ LL_DMA_EnableIT_TC(tim->DMAx, tim->DMA_Stream); - // Enable DMA - LL_TIM_ClearFlag_UPDATE(tim->TIMx); - LL_TIM_DisableDMAReq_UPDATE(tim->TIMx); - LL_TIM_SetCounter(tim->TIMx, 0); + // Reset counter close to overflow + if (IS_TIM_32B_COUNTER_INSTANCE(tim->TIMx)) { + LL_TIM_SetCounter(tim->TIMx, 0xFFFFFFFF); + } else { + LL_TIM_SetCounter(tim->TIMx, 0xFFFF); + } + + // only on PWM (preloads the first period) + if (ocmode == LL_TIM_OCMODE_PWM1) + LL_TIM_GenerateEvent_UPDATE(tim->TIMx); + + LL_TIM_EnableDMAReq_UPDATE(tim->TIMx); LL_DMA_EnableStream(tim->DMAx, tim->DMA_Stream); - // Trigger update to effect the first DMA transation + // Trigger update to effect the first DMA transaction // and thus load ARR with the first duration - LL_TIM_EnableDMAReq_UPDATE(tim->TIMx); - LL_TIM_GenerateEvent_UPDATE(tim->TIMx); // start timer - force_start_level(tim); LL_TIM_EnableCounter(tim->TIMx); } -static bool check_and_clean_dma_tc_flag(const stm32_pulse_timer_t* tim) -{ - switch(tim->DMA_Stream) { - case LL_DMA_STREAM_1: - if (!LL_DMA_IsActiveFlag_TC1(tim->DMAx)) return false; - LL_DMA_ClearFlag_TC1(tim->DMAx); - break; - case LL_DMA_STREAM_5: - if (!LL_DMA_IsActiveFlag_TC5(tim->DMAx)) return false; - LL_DMA_ClearFlag_TC5(tim->DMAx); - break; - case LL_DMA_STREAM_7: - if (!LL_DMA_IsActiveFlag_TC7(tim->DMAx)) return false; - LL_DMA_ClearFlag_TC7(tim->DMAx); - break; - } - return true; -} - void stm32_pulse_dma_tc_isr(const stm32_pulse_timer_t* tim) { - if (!check_and_clean_dma_tc_flag(tim)) return; + if (!stm32_dma_check_tc_flag(tim->DMAx, tim->DMA_Stream)) + return; + if (tim->DMA_TC_CallbackPtr) { + auto closure = tim->DMA_TC_CallbackPtr; + if (closure->cb && closure->cb(closure->ctx)) { + return; + } + } + LL_TIM_ClearFlag_UPDATE(tim->TIMx); LL_TIM_EnableIT_UPDATE(tim->TIMx); + // PWM mode with compare value = 0 then OCxRef is held at ‘0’ set_compare_reg(tim, 0); set_oc_mode(tim, LL_TIM_OCMODE_PWM1); } @@ -315,6 +349,7 @@ void stm32_pulse_tim_update_isr(const stm32_pulse_timer_t* tim) // Halt pulses by forcing to inactive level set_oc_mode(tim, LL_TIM_OCMODE_FORCED_INACTIVE); + LL_TIM_DisableCounter(tim->TIMx); } // input mode diff --git a/radio/src/targets/common/arm/stm32/stm32_pulse_driver.h b/radio/src/targets/common/arm/stm32/stm32_pulse_driver.h index 00820b1a1..1197f00d3 100644 --- a/radio/src/targets/common/arm/stm32/stm32_pulse_driver.h +++ b/radio/src/targets/common/arm/stm32/stm32_pulse_driver.h @@ -24,6 +24,14 @@ #include #include "stm32_hal_ll.h" +struct stm32_pulse_timer_t; +typedef bool (*stm32_pulse_dma_tc_fct)(void*); + +struct stm32_pulse_dma_tc_cb_t { + stm32_pulse_dma_tc_fct cb; + void* ctx; +}; + struct stm32_pulse_timer_t { GPIO_TypeDef* GPIOx; @@ -31,7 +39,7 @@ struct stm32_pulse_timer_t { uint32_t GPIO_Alternate; TIM_TypeDef* TIMx; - uint16_t TIM_Prescaler; + uint32_t TIM_Freq; uint32_t TIM_Channel; IRQn_Type TIM_IRQn; @@ -39,9 +47,10 @@ struct stm32_pulse_timer_t { uint32_t DMA_Stream; uint32_t DMA_Channel; IRQn_Type DMA_IRQn; + stm32_pulse_dma_tc_cb_t* DMA_TC_CallbackPtr; }; -void stm32_pulse_init(const stm32_pulse_timer_t* tim); +void stm32_pulse_init(const stm32_pulse_timer_t* tim, uint32_t freq); void stm32_pulse_deinit(const stm32_pulse_timer_t* tim); void stm32_pulse_config_input(const stm32_pulse_timer_t* tim); @@ -51,8 +60,12 @@ void stm32_pulse_config_output(const stm32_pulse_timer_t* tim, bool polarity, void stm32_pulse_set_polarity(const stm32_pulse_timer_t* tim, bool polarity); +bool stm32_pulse_get_polarity(const stm32_pulse_timer_t* tim); + void stm32_pulse_set_cmp_val(const stm32_pulse_timer_t* tim, uint32_t cmp_val); +void stm32_pulse_wait_for_completed(const stm32_pulse_timer_t* tim); + // return true if it could be disabled without interrupting a pulse train, false otherwise bool stm32_pulse_if_not_running_disable(const stm32_pulse_timer_t* tim); diff --git a/radio/src/targets/common/arm/stm32/stm32_serial_driver.cpp b/radio/src/targets/common/arm/stm32/stm32_serial_driver.cpp new file mode 100644 index 000000000..693fcae4c --- /dev/null +++ b/radio/src/targets/common/arm/stm32/stm32_serial_driver.cpp @@ -0,0 +1,497 @@ +/* + * Copyright (C) EdgeTx + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "stm32_serial_driver.h" +#include + +// Serial buffer state +struct stm32_buffer_state { + volatile uint32_t ridx; + volatile uint32_t widx; +}; + +struct stm32_send_buffer { + volatile const uint8_t* buf; + volatile uint32_t len; +}; + +struct stm32_serial_state { + const stm32_serial_port* sp; + stm32_buffer_state rx_buf; + union { + stm32_buffer_state tx_fifo; + stm32_send_buffer tx_buf; + } u; + etx_serial_callbacks_t callbacks; +}; + +enum _STM32_USART { + +#if defined(USART1) + _STM32_USART1, +#endif + +#if defined(USART2) + _STM32_USART2, +#endif + +#if defined(USART3) + _STM32_USART3, +#endif + +#if defined(UART4) + _STM32_UART4, +#endif + +#if defined(USART6) + _STM32_USART6, +#endif + +#if defined(UART7) + _STM32_UART7, +#endif + + _STM32_MAX_UARTS +}; + +#define STM32_MAX_UART_PORTS _STM32_MAX_UARTS + +// allocated as needed: index does not correspond +static stm32_serial_state _serial_states[STM32_MAX_UART_PORTS]; + +void stm32_serial_init_driver() +{ + memset(_serial_states, 0, sizeof(_serial_states)); +} + +// Serial context to be used in callbacks +// defined in this driver +static volatile stm32_serial_state* _isr_state; + +static uint8_t _on_send_fifo(uint8_t* data) +{ + auto st = _isr_state; + auto& buf_st = st->u.tx_fifo; + + if (buf_st.ridx == buf_st.widx) + return 0; + + const auto& tx_buf = st->sp->tx_buffer; + auto buf = tx_buf.buffer; + *data = buf[buf_st.ridx]; + + auto buf_len = tx_buf.length; + buf_st.ridx = (buf_st.ridx + 1) & (buf_len - 1); + + return 1; +} + +static uint8_t _on_send_single_buffer(uint8_t* data) +{ + auto sb = &_isr_state->u.tx_buf; + if (!sb->len) return 0; + + *data = *(sb->buf++); + sb->len--; + + return 1; +} + +static inline void _usart_isr_handler(_STM32_USART n) +{ + auto st = &(_serial_states[n]); + + // This tricks is necessary for now to allow + // callbacks to use the serial context while + // keeping the callbacks re-entrant + auto old_st = _isr_state; + _isr_state = st; + + stm32_usart_isr(st->sp->usart, &st->callbacks); + + _isr_state = old_st; +} + +#define DEFINE_USART_IRQ(usart) \ + extern "C" void usart ## _IRQHandler(void) \ + { \ + _usart_isr_handler(_STM32_ ## usart); \ + } + +#if defined (USART1) + DEFINE_USART_IRQ(USART1); +#endif + +#if defined (USART2) + DEFINE_USART_IRQ(USART2); +#endif + +#if defined (USART3) + DEFINE_USART_IRQ(USART3); +#endif + +#if defined (UART4) + DEFINE_USART_IRQ(UART4); +#endif + +#if defined (USART6) + DEFINE_USART_IRQ(USART6); +#endif + +#if defined (UART7) + DEFINE_USART_IRQ(UART7); +#endif + +static stm32_serial_state* stm32_serial_find_state(const stm32_usart_t* usart) +{ +#if defined (USART1) + if (usart->USARTx == USART1) return &_serial_states[_STM32_USART1]; +#endif +#if defined (USART2) + if (usart->USARTx == USART2) return &_serial_states[_STM32_USART2]; +#endif +#if defined (USART3) + if (usart->USARTx == USART3) return &_serial_states[_STM32_USART3]; +#endif +#if defined (UART4) + if (usart->USARTx == UART4) return &_serial_states[_STM32_UART4]; +#endif +#if defined (USART6) + if (usart->USARTx == USART6) return &_serial_states[_STM32_USART6]; +#endif +#if defined (UART7) + if (usart->USARTx == UART7) return &_serial_states[_STM32_UART7]; +#endif + + return nullptr; +} + +static void stm32_serial_free_state(stm32_serial_state* st) +{ + memset(st, 0, sizeof(stm32_serial_state)); +} + +static inline void _dma_clear(stm32_buffer_state* buf_st, uint32_t length, + DMA_TypeDef* DMAx, uint32_t stream) +{ + buf_st->ridx = length - LL_DMA_GetDataLength(DMAx, stream); +} + +static inline void _fifo_clear(stm32_buffer_state* buf_st) +{ + buf_st->widx = buf_st->ridx = 0; +} + +static inline bool _fifo_full(stm32_buffer_state* buf_st, uint32_t length) +{ + return ((buf_st->widx + 1) & (length - 1)) == buf_st->ridx; +} + +static inline void _fifo_push(uint8_t c, stm32_buffer_state* buf_st, + uint32_t length, uint8_t* buf) +{ + buf[buf_st->widx] = c; + buf_st->widx = (buf_st->widx + 1) & (length - 1); +} + +static void _on_rx_fifo(uint8_t data) +{ + auto st = _isr_state; + stm32_buffer_state* buf_st = (stm32_buffer_state*)&st->rx_buf; + + auto buf_len = st->sp->rx_buffer.length; + if (_fifo_full(buf_st, buf_len)) return; + + auto buf = st->sp->rx_buffer.buffer; + _fifo_push(data, buf_st, buf_len, buf); +} + +static void* stm32_serial_init(void* hw_def, const etx_serial_init* params) +{ + // TODO: check if port is already in use + auto sp = (const stm32_serial_port*)hw_def; + if (!sp) return nullptr; + + auto usart = sp->usart; + auto st = stm32_serial_find_state(usart); + if (!st || st->sp) return nullptr; + + stm32_usart_init(usart, params); + st->sp = sp; // TODO: only iff init() is sucessful + + if (params->direction & ETX_Dir_TX) { + // prepare for send_byte() + if (sp->tx_buffer.length > 0) { + st->callbacks.on_send = _on_send_fifo; + } + } + + if (params->direction & ETX_Dir_RX) { + + auto rx_buf = sp->rx_buffer.buffer; + auto buf_len = sp->rx_buffer.length; + + if (usart->rxDMA) { + stm32_usart_init_rx_dma(usart, rx_buf, buf_len); + + auto dma = usart->rxDMA; + auto stream = usart->rxDMA_Stream; + _dma_clear(&st->rx_buf, buf_len, dma, stream); + } else { + st->callbacks.on_receive = _on_rx_fifo; + } + } + + return (void*)st; +} + +static void stm32_serial_deinit(void* ctx) +{ + auto st = (stm32_serial_state*)ctx; + if (!st) return; + + stm32_usart_deinit(st->sp->usart); + stm32_serial_free_state(st); +} + +static void stm32_serial_send_byte(void* ctx, uint8_t c) +{ + // When sending single bytes, + // send is based on IRQ, so that this + // only enables the corresponding IRQ + + auto st = (stm32_serial_state*)ctx; + if (!st) return; + + auto sp = st->sp; + auto buf_len = sp->tx_buffer.length; + if (buf_len > 0) { + + auto buf_st = &st->u.tx_fifo; + auto buf = sp->tx_buffer.buffer; + + if (_fifo_full(buf_st, buf_len)) return; + _fifo_push(c, buf_st, buf_len, buf); + + stm32_usart_enable_tx_irq(sp->usart); + } else { + // No TX FIFO -> fall back to sync send + stm32_usart_send_byte(sp->usart, c); + } +} + +#define IS_CCM_RAM(addr) (((uint32_t)(addr) & (uint32_t)0xFFF00000) == 0x10000000) + +static void stm32_serial_send_buffer(void* ctx, const uint8_t* data, uint32_t size) +{ + auto st = (stm32_serial_state*)ctx; + if (!st) return; + + // try TX DMA first + auto sp = st->sp; + auto usart = sp->usart; + if (usart->txDMA && !IS_CCM_RAM(data)) { + stm32_usart_send_buffer(usart, data, size); + return; + } + + // no internal buffer: send one buffer at a time + if (!sp->tx_buffer.length) { + st->u.tx_buf.buf = data; + st->u.tx_buf.len = size; + st->callbacks.on_send = _on_send_single_buffer; + stm32_usart_enable_tx_irq(usart); + return; + } + + // else stack single bytes into our internal buffer + while(size > 0) { + stm32_serial_send_byte(ctx, *data++); + size--; + } +} + +static uint8_t stm32_serial_tx_completed(void* ctx) +{ + auto st = (stm32_serial_state*)ctx; + if (!st) return 1; + + return stm32_usart_tx_completed(st->sp->usart); +} + +static void stm32_wait_tx_completed(void* ctx) +{ + auto st = (stm32_serial_state*)ctx; + if (!st) return; + + while(!stm32_usart_tx_completed(st->sp->usart)); +} + +static void stm32_enable_rx(void* ctx) +{ + auto st = (stm32_serial_state*)ctx; + if (!st) return; + + stm32_usart_enable_rx(st->sp->usart); +} + +static int stm32_serial_get_byte(void* ctx, uint8_t* data) +{ + auto st = (stm32_serial_state*)ctx; + if (!st) return -1; + + auto sp = st->sp; + const auto& rx_buf = sp->rx_buffer; + auto buf_len = rx_buf.length; + if (!buf_len) return -1; + + auto buf = rx_buf.buffer; + auto& buf_st = st->rx_buf; + + uint32_t widx; + auto usart = sp->usart; + if (LL_USART_IsEnabledDMAReq_RX(usart->USARTx)) { + auto dma = usart->rxDMA; + auto stream = usart->rxDMA_Stream; + widx = buf_len - LL_DMA_GetDataLength(dma, stream); + } else { + widx = buf_st.widx; + } + + if (buf_st.ridx == widx) + return 0; + + *data = buf[buf_st.ridx]; + buf_st.ridx = (buf_st.ridx + 1) & (buf_len - 1); + + return 1; +} + +static int stm32_serial_get_last_byte(void* ctx, uint32_t idx, uint8_t* data) +{ + auto st = (stm32_serial_state*)ctx; + if (!st) return -1; + + auto sp = st->sp; + const auto& rx_buf = sp->rx_buffer; + auto buf_len = rx_buf.length; + if (!buf_len) return -1; + + auto buf = rx_buf.buffer; + auto& buf_st = st->rx_buf; + + uint32_t widx; + auto usart = sp->usart; + if (LL_USART_IsEnabledDMAReq_RX(usart->USARTx)) { + auto dma = usart->rxDMA; + auto stream = usart->rxDMA_Stream; + widx = buf_len - LL_DMA_GetDataLength(dma, stream); + } else { + widx = buf_st.widx; + } + + // Please note that we do not check the read cursor + // so that this function might return data that + // has already been read + uint32_t ridx = (buf_len + widx - idx) & (buf_len - 1); + *data = buf[ridx]; + + return 1; +} + +static void stm32_serial_clear_rx_buffer(void* ctx) +{ + auto st = (stm32_serial_state*)ctx; + if (!st) return; + + auto sp = st->sp; + auto buf_st = &st->rx_buf; + auto usart = sp->usart; + if (usart->rxDMA) { + auto buf_len = sp->rx_buffer.length; + auto dma = usart->rxDMA; + auto stream = usart->rxDMA_Stream; + _dma_clear(buf_st, buf_len, dma, stream); + } else { + _fifo_clear(buf_st); + } +} + +static uint32_t stm32_serial_get_baudrate(void* ctx) +{ + auto st = (stm32_serial_state*)ctx; + if (!st) return 0; + + auto sp = st->sp; + auto usart = sp->usart; + return stm32_usart_get_baudrate(usart); +} + +static void stm32_serial_set_baudrate(void* ctx, uint32_t baudrate) +{ + auto st = (stm32_serial_state*)ctx; + if (!st) return; + + auto sp = st->sp; + auto usart = sp->usart; + stm32_usart_set_baudrate(usart, baudrate); +} + +static void stm32_serial_hw_option(void* ctx, uint32_t option) +{ + auto st = (stm32_serial_state*)ctx; + if (!st) return; + + auto sp = st->sp; + auto usart = sp->usart; + stm32_usart_set_hw_option(usart, option); +} + +static void stm32_serial_set_idle_cb(void* ctx, void (*on_idle)()) +{ + auto st = (stm32_serial_state*)ctx; + if (!st) return; + + st->callbacks.on_idle = on_idle; + + uint32_t enabled = (on_idle != nullptr); + stm32_usart_set_idle_irq(st->sp->usart, enabled); +} + +const etx_serial_driver_t STM32SerialDriver = { + .init = stm32_serial_init, + .deinit = stm32_serial_deinit, + .sendByte = stm32_serial_send_byte, + .sendBuffer = stm32_serial_send_buffer, + .txCompleted = stm32_serial_tx_completed, + .waitForTxCompleted = stm32_wait_tx_completed, + .enableRx = stm32_enable_rx, + .getByte = stm32_serial_get_byte, + .getLastByte = stm32_serial_get_last_byte, + .clearRxBuffer = stm32_serial_clear_rx_buffer, + .getBaudrate = stm32_serial_get_baudrate, + .setBaudrate = stm32_serial_set_baudrate, + .setPolarity = nullptr, + .setHWOption = stm32_serial_hw_option, + .setReceiveCb = nullptr, // TODO + .setIdleCb = stm32_serial_set_idle_cb, + .setBaudrateCb = nullptr, +}; diff --git a/radio/src/targets/common/arm/stm32/stm32_serial_driver.h b/radio/src/targets/common/arm/stm32/stm32_serial_driver.h new file mode 100644 index 000000000..fb6944815 --- /dev/null +++ b/radio/src/targets/common/arm/stm32/stm32_serial_driver.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) EdgeTx + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#pragma once + +#include "stm32_usart_driver.h" +#include "hal/serial_driver.h" + +// __DMA +#include "definitions.h" + +// Serial buffer to be defined in boards +struct stm32_serial_buffer { + uint8_t* buffer; + uint32_t length; +}; + +// Serial port to be defined in boards +// (the board defines a buffer as well) +// +// etx_serial_driver.init() shall be passed +// this struct cast as (void*) +// +struct stm32_serial_port { + const stm32_usart_t* usart; + const stm32_serial_buffer rx_buffer; + const stm32_serial_buffer tx_buffer; +}; + +extern const etx_serial_driver_t STM32SerialDriver; + +#define DEFINE_STM32_SERIAL_PORT(p,usart,rx_buf_len,tx_buf_len) \ + static uint8_t p ## _RXBuffer[rx_buf_len] __DMA; \ + static uint8_t p ## _TXBuffer[tx_buf_len] __DMA; \ + static const stm32_serial_port p ## _STM32Serial = { \ + &usart, \ + { p ## _RXBuffer, rx_buf_len }, \ + { p ## _TXBuffer, tx_buf_len }, \ + } + +#define REF_STM32_SERIAL_PORT(p) ((void*)& p ## _STM32Serial) diff --git a/radio/src/targets/common/arm/stm32/stm32_softserial_driver.cpp b/radio/src/targets/common/arm/stm32/stm32_softserial_driver.cpp new file mode 100644 index 000000000..5489df0e8 --- /dev/null +++ b/radio/src/targets/common/arm/stm32/stm32_softserial_driver.cpp @@ -0,0 +1,510 @@ +/* + * Copyright (C) EdgeTx + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "stm32_softserial_driver.h" +#include "stm32_exti_driver.h" + +#include + +// constant TX bitlen, timer frequency is computed +// to reach the required baudrate +#define BITLEN 16 + +// RX state +static uint8_t rxBitCount; +static uint8_t rxByte; + +// RX FIFO +static volatile uint8_t rxRidx; +static volatile uint8_t rxWidx; +static uint8_t *rxBuffer; +static uint32_t rxBufLen; + +static const stm32_softserial_rx_port* _softserialPort; + +static void _softserial_exti() +{ + if (rxBitCount == 0) { + + // enable timer counter + auto TIMx = _softserialPort->TIMx; + LL_TIM_SetAutoReload(TIMx, (BITLEN + BITLEN/2) - 1); + LL_TIM_EnableCounter(TIMx); + + // disable start bit interrupt + LL_EXTI_DisableIT_0_31(_softserialPort->EXTI_Line); + } +} + +static inline void _rx_fifo_clear() +{ + rxWidx = 0; + rxRidx = 0; +} + +static void _softserial_init_rx(const stm32_softserial_rx_port* port, + const etx_serial_init* params) +{ + rxBitCount = 0; + rxBuffer = port->buffer.buffer; + rxBufLen = port->buffer.length; + _rx_fifo_clear(); + + // configure bit sample timer + LL_TIM_InitTypeDef timInit; + LL_TIM_StructInit(&timInit); + + uint32_t freq = params->baudrate * 16; + if (!freq) return; + + timInit.Prescaler = __LL_TIM_CALC_PSC(port->TIM_Freq, freq); + + // TODO: enable_tim_clock(port->TIMx); + LL_TIM_Init(port->TIMx, &timInit); + + LL_TIM_ClearFlag_UPDATE(port->TIMx); + LL_TIM_EnableIT_UPDATE(port->TIMx); + + NVIC_SetPriority(port->TIM_IRQn, 0); + NVIC_EnableIRQ(port->TIM_IRQn); + + LL_GPIO_InitTypeDef pinInit; + LL_GPIO_StructInit(&pinInit); + + if (port->dir_GPIOx) { + pinInit.Pin = port->dir_Pin; + pinInit.Mode = LL_GPIO_MODE_OUTPUT; + LL_GPIO_Init(port->dir_GPIOx, &pinInit); + if (!port->dir_Input) { + LL_GPIO_ResetOutputPin(port->dir_GPIOx, port->dir_Pin); + } else { + LL_GPIO_SetOutputPin(port->dir_GPIOx, port->dir_Pin); + } + } + + pinInit.Pin = port->GPIO_Pin; + pinInit.Mode = LL_GPIO_MODE_INPUT; + pinInit.OutputType = LL_GPIO_OUTPUT_PUSHPULL; + pinInit.Pull = LL_GPIO_PULL_DOWN; + LL_GPIO_Init(port->GPIOx, &pinInit); + + // Connect EXTI line to TELEMETRY RX pin + LL_SYSCFG_SetEXTISource(port->EXTI_Port, port->EXTI_SysLine); + + // Configure EXTI for raising edge (start bit; assuming inverted serial) + _softserialPort = port; + stm32_exti_enable(port->EXTI_Line, LL_EXTI_TRIGGER_RISING, _softserial_exti); +} + +static void _softserial_deinit_gpio(const stm32_softserial_rx_port* port) +{ + // Reconfigure pin as input + LL_GPIO_InitTypeDef pinInit; + LL_GPIO_StructInit(&pinInit); + + pinInit.Pin = port->GPIO_Pin; + pinInit.Mode = LL_GPIO_MODE_INPUT; + LL_GPIO_Init(port->GPIOx, &pinInit); +} + +static void _softserial_deinit_rx(const stm32_softserial_rx_port* port) +{ + stm32_exti_disable(port->EXTI_Line); + NVIC_DisableIRQ(port->TIM_IRQn); + LL_TIM_DeInit(port->TIMx); +} + +static void* stm32_softserial_rx_init(void* hw_def, const etx_serial_init* params) +{ + auto port = (const stm32_softserial_rx_port*)hw_def; + _softserial_init_rx(port, params); + return hw_def; +} + +static void stm32_softserial_rx_deinit(void* ctx) +{ + auto port = (const stm32_softserial_rx_port*)ctx; + + if (port == _softserialPort) { + _softserial_deinit_rx(port); + } + + _softserial_deinit_gpio(port); + _softserialPort = nullptr; +} + +static inline bool _rx_fifo_full() +{ + return ((rxWidx + 1) & (rxBufLen - 1)) == rxRidx; +} + +static inline void _rx_fifo_push(uint8_t c) +{ + rxBuffer[rxWidx] = c; + rxWidx = (rxWidx + 1) & (rxBufLen - 1); +} + +static int stm32_softserial_rx_get_byte(void* ctx, uint8_t* data) +{ + if (rxWidx == rxRidx) return 0; + + *data = rxBuffer[rxRidx]; + rxRidx = (rxRidx + 1) & (rxBufLen - 1); + + return 1; +} + +void stm32_softserial_rx_timer_isr(const stm32_softserial_rx_port* port) +{ + auto TIMx = port->TIMx; + LL_TIM_ClearFlag_UPDATE(TIMx); + + if (rxBitCount < 8) { + if (rxBitCount == 0) { + LL_TIM_SetAutoReload(TIMx, BITLEN - 1); + rxByte = 0; + } + else { + rxByte >>= 1; + } + + if (LL_GPIO_IsInputPinSet(port->GPIOx, port->GPIO_Pin) == 0) + rxByte |= 0x80; + + ++rxBitCount; + } + else if (rxBitCount == 8) { + + if (!_rx_fifo_full()) _rx_fifo_push(rxByte); + rxBitCount = 0; + + // disable timer + LL_TIM_DisableCounter(TIMx); + + // re-enable start bit interrupt + LL_EXTI_EnableIT_0_31(port->EXTI_Line); + } +} + +static void stm32_softserial_rx_clear_rx_buffer(void* ctx) +{ + rxWidx = 0; + rxRidx = 0; +} + +const etx_serial_driver_t STM32SoftSerialRxDriver = { + .init = stm32_softserial_rx_init, + .deinit = stm32_softserial_rx_deinit, + .sendByte = nullptr, + .sendBuffer = nullptr, + .waitForTxCompleted = nullptr, + .enableRx = nullptr, + .getByte = stm32_softserial_rx_get_byte, + .getLastByte = nullptr, + .clearRxBuffer = stm32_softserial_rx_clear_rx_buffer, + .getBaudrate = nullptr, + .setReceiveCb = nullptr, + .setBaudrateCb = nullptr, +}; + + +static inline void _set_level(stm32_softserial_tx_state* st, uint8_t v) +{ + *st->pulse_ptr = v - 1; +#if defined(STM32_SUPPORT_32BIT_TIMERS) + st->pulse_ptr += st->pulse_inc; +#else + ++st->pulse_ptr; +#endif +} + +// TODO: +// - support for different word len / stop bit(s) / parity config +// - now: only 8N1 and 8E2 +// +// max 11 changes 0 10 10 10 10 P 1 +static void _conv_byte_8e2(stm32_softserial_tx_state* st, uint8_t b) +{ + bool lev = 0; + uint8_t parity = 1; + + uint8_t len = BITLEN; // max val: 10*16 < 256 + for (uint8_t i = 0; i <= 9; i++) { // 8Bits + 1Parity + + bool nlev = b & 1; // lsb first + parity = parity ^ (uint8_t)nlev; + + if (lev == nlev) { + len += BITLEN; + } else { + _set_level(st, len); + len = BITLEN; + lev = nlev; + } + + b = (b >> 1) | 0x80; // shift in ones for stop bit and parity + if (i == 7) b = b ^ parity; // lowest bit is one from previous line + } + + // enlarge the last bit to be two stop bits long + _set_level(st, len + BITLEN); + + // update size + --st->serial_size; +} + +static void _conv_byte_8n1(stm32_softserial_tx_state* st, uint8_t b) +{ + bool lev = 0; + uint8_t len = BITLEN; // max val: 10*16 < 256 + for (uint8_t i = 0; i <= 8; i++) { // 8Bits + + bool nlev = b & 1; // lsb first + if (lev == nlev) { + len += BITLEN; + } else { + _set_level(st, len); + len = BITLEN; + lev = nlev; + } + + b = (b >> 1) | 0x80; // shift in ones for stop bit + } + + // write the last bit + _set_level(st, len); + + // update size + --st->serial_size; +} + + +// PXX1 PWM is encoded as a PWM signal +// with a fixed ON phase of 9us and a variable OFF phase +// depending on whether the bit is SET or RESET. +// +#define PXX1_FREQ 1000000 /* 1 MHz */ +#define PXX1_PWM_ON 9 /* 9us */ +#define PXX1_BIT_ZERO 16 /* 0 = 16us */ +#define PXX1_BIT_ONE 24 /* 1 = 24us */ + +static void _conv_byte_pxx1(stm32_softserial_tx_state* st, uint8_t b) +{ + uint32_t bits = st->serial_size < 8 ? st->serial_size : 8; + + for (uint8_t i = 0; i < bits; i++) { + // MSB first + if (b & 0x80) + _set_level(st, PXX1_BIT_ONE); + else + _set_level(st, PXX1_BIT_ZERO); + + // next bit + b <<= 1; + } + + st->serial_size -= bits; +} + +// stm32_pulse_timer_t based TX implementation +static void* stm32_softserial_tx_init(void* hw_def, const etx_serial_init* params) +{ + auto port = (const stm32_softserial_tx_port*)hw_def; + + // Init state + auto st = port->st; + memset(port->st, 0, sizeof(stm32_softserial_tx_state)); + + bool polarity = params->polarity == ETX_Pol_Normal; + uint32_t freq = params->baudrate * 16; + uint32_t ocmode = LL_TIM_OCMODE_TOGGLE; + uint32_t cmp_val = 0; + + switch(params->encoding) { + + case ETX_Encoding_8N1: + st->conv_byte = _conv_byte_8n1; + break; + + case ETX_Encoding_8E2: + st->conv_byte = _conv_byte_8e2; + break; + + case ETX_Encoding_PXX1_PWM: + st->conv_byte = _conv_byte_pxx1; + freq = PXX1_FREQ; + polarity = false; + ocmode = LL_TIM_OCMODE_PWM1; + cmp_val = PXX1_PWM_ON; + break; + + default: + return nullptr; + } + + // prevent dividing by 0 in stm32_pulse_init() + if (freq == 0) return nullptr; + + // Use a variable timer frequency to keep bitlen constant (16) + auto tim = port->tim; + stm32_pulse_init(tim, freq); + stm32_pulse_config_output(tim, polarity, ocmode, cmp_val); + +#if defined(STM32_SUPPORT_32BIT_TIMERS) + if (IS_TIM_32B_COUNTER_INSTANCE(tim->TIMx)) { + st->pulse_inc = 2; + } else { + st->pulse_inc = 1; + } +#endif + + return hw_def; +} + +static void stm32_softserial_tx_deinit(void* ctx) +{ + auto port = (const stm32_softserial_tx_port*)ctx; + stm32_pulse_deinit(port->tim); +} + +static void stm32_softserial_tx_wait(void* ctx) +{ + auto port = (const stm32_softserial_tx_port*)ctx; + auto timer = port->tim; + + stm32_pulse_wait_for_completed(timer); +} + +static void stm32_softserial_tx_send_buffer(void* ctx, const uint8_t* data, uint32_t size); + +static void stm32_softserial_tx_send_byte(void* ctx, uint8_t byte) +{ + stm32_softserial_tx_send_buffer(ctx, &byte, 1); + stm32_softserial_tx_wait(ctx); +} + +static uint16_t _fill_pulses(stm32_softserial_tx_state* st) +{ + st->pulse_ptr = (uint16_t*)st->pulse_buffer; + bool is_pxx1 = (st->conv_byte == _conv_byte_pxx1); + + uint32_t size = st->serial_size; + + // PXX1 uses a # bits rather than bytes + if (is_pxx1) { + // + size = (size + 7) / 8; + if (size > STM32_SOFTSERIAL_MAX_PULSES_TRANSITIONS / 8) // 12 + size = STM32_SOFTSERIAL_MAX_PULSES_TRANSITIONS / 8; // 12 + } else if (size > STM32_SOFTSERIAL_BUFFERED_PULSES) { + size = STM32_SOFTSERIAL_BUFFERED_PULSES; + } + + for (uint8_t i = 0; i < size; i++) { + st->conv_byte(st, *st->serial_data++); + } + + uint16_t length = st->pulse_ptr - (uint16_t*)st->pulse_buffer; +#if defined(STM32_SUPPORT_32BIT_TIMERS) + if (st->pulse_inc == 2) length >>= 1; +#endif + + return length; +} + +static bool stm32_softserial_tx_dma_tc_isr(void* ctx) +{ + auto port = (const stm32_softserial_tx_port*)ctx; + auto tim = port->tim; + auto st = port->st; + + if (!st->serial_size) + return false; + + uint16_t length = _fill_pulses(st); + LL_DMA_SetDataLength(tim->DMAx, tim->DMA_Stream, length); + LL_DMA_EnableStream(tim->DMAx, tim->DMA_Stream); + + return true; +} + +static void stm32_softserial_tx_send_buffer(void* ctx, const uint8_t* data, uint32_t size) +{ + auto port = (const stm32_softserial_tx_port*)ctx; + auto timer = port->tim; + if (!stm32_pulse_if_not_running_disable(timer)) + return; + + // transform serial payload into timer pulses/length + auto st = port->st; + st->serial_data = data; + st->serial_size = size; + + auto length = _fill_pulses(st); + + if (st->serial_size > 0 && timer->DMA_TC_CallbackPtr) { + auto closure = timer->DMA_TC_CallbackPtr; + closure->cb = stm32_softserial_tx_dma_tc_isr; + closure->ctx = ctx; + } + + // Start DMA request and re-enable timer + const void* pulses = st->pulse_buffer; + + // TODO: save encoding + uint32_t ocmode = LL_TIM_OCMODE_TOGGLE; + uint32_t cmp_val = 0; + + // dirty hack... + if (st->conv_byte == _conv_byte_pxx1) { + ocmode = LL_TIM_OCMODE_PWM1; + cmp_val = PXX1_PWM_ON; + } + + stm32_pulse_start_dma_req(timer, pulses, length, ocmode, cmp_val); +} + +void stm32_softserial_set_polarity(void* ctx, uint8_t polarity) +{ + auto port = (const stm32_softserial_tx_port*)ctx; + auto timer = port->tim; + + stm32_pulse_set_polarity(timer, polarity); +} + +const etx_serial_driver_t STM32SoftSerialTxDriver = { + .init = stm32_softserial_tx_init, + .deinit = stm32_softserial_tx_deinit, + .sendByte = stm32_softserial_tx_send_byte, + .sendBuffer = stm32_softserial_tx_send_buffer, + .txCompleted = nullptr, + .waitForTxCompleted = stm32_softserial_tx_wait, + .enableRx = nullptr, // TODO: combine with EXTI / Timer implementation? (S.PORT INV RX) + .getByte = nullptr, + .clearRxBuffer = nullptr, // TODO: same as enableRx + .getBaudrate = nullptr, + .setBaudrate = nullptr, + .setPolarity = stm32_softserial_set_polarity, + .setHWOption = nullptr, + .setReceiveCb = nullptr, + .setIdleCb = nullptr, + .setBaudrateCb = nullptr, +}; diff --git a/radio/src/targets/common/arm/stm32/stm32_softserial_driver.h b/radio/src/targets/common/arm/stm32/stm32_softserial_driver.h new file mode 100644 index 000000000..4d0a46882 --- /dev/null +++ b/radio/src/targets/common/arm/stm32/stm32_softserial_driver.h @@ -0,0 +1,107 @@ +/* + * Copyright (C) EdgeTx + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "stm32_serial_driver.h" +#include "stm32_pulse_driver.h" + +// +// RX soft-serial +// +// Warning: only a single instance can be +// used at the same time. +// +// etx_serial_driver.init() shall be passed +// this struct cast as (void*) +// +struct stm32_softserial_rx_port { + + GPIO_TypeDef* GPIOx; + uint32_t GPIO_Pin; + TIM_TypeDef* TIMx; + uint32_t TIM_Freq; + IRQn_Type TIM_IRQn; + uint32_t EXTI_Port; + uint32_t EXTI_SysLine; + uint32_t EXTI_Line; + + // Input/output direction pin + GPIO_TypeDef* dir_GPIOx; + uint32_t dir_Pin; + uint32_t dir_Input; + + const stm32_serial_buffer buffer; +}; + +void stm32_softserial_rx_timer_isr(const stm32_softserial_rx_port* port); + +extern const etx_serial_driver_t STM32SoftSerialRxDriver; + +// +// TX soft-serial +// + +#define STM32_SOFTSERIAL_BUFFERED_PULSES 8 + +// Max 12 toggles per serial byte +#define STM32_SOFTSERIAL_MAX_PULSES_TRANSITIONS \ + (12 * STM32_SOFTSERIAL_BUFFERED_PULSES) + +#if defined(STM32_SUPPORT_32BIT_TIMERS) +typedef uint32_t stm32_softserial_pulse_t; +#else +typedef uint16_t stm32_softserial_pulse_t; +#endif + +struct stm32_softserial_tx_state; +typedef void (*stm32_softserial_conv_byte_fct)(stm32_softserial_tx_state*, uint8_t); + +struct stm32_softserial_tx_state { + + stm32_softserial_conv_byte_fct conv_byte; + + stm32_softserial_pulse_t pulse_buffer[STM32_SOFTSERIAL_MAX_PULSES_TRANSITIONS]; + uint16_t* pulse_ptr; +#if defined(STM32_SUPPORT_32BIT_TIMERS) + uint8_t pulse_inc; +#endif + + const uint8_t* serial_data; + volatile uint32_t serial_size; +}; + +// etx_serial_driver.init() shall be passed +// this struct cast as (void*) +// +struct stm32_softserial_tx_port { + const stm32_pulse_timer_t* tim; + stm32_softserial_tx_state* st; +}; + +#define DEFINE_STM32_SOFTSERIAL_PORT(p,timer) \ + static stm32_softserial_tx_state p ## _SoftserialState __DMA; \ + static const stm32_softserial_tx_port p ## _STM32Softserial = { \ + &timer, \ + & p ## _SoftserialState, \ + } + +#define REF_STM32_SOFTSERIAL_PORT(p) ((void*)& p ## _STM32Softserial) + +extern const etx_serial_driver_t STM32SoftSerialTxDriver; diff --git a/radio/src/targets/common/arm/stm32/stm32_usart_driver.cpp b/radio/src/targets/common/arm/stm32/stm32_usart_driver.cpp index da42d5cfd..42ea30ea2 100644 --- a/radio/src/targets/common/arm/stm32/stm32_usart_driver.cpp +++ b/radio/src/targets/common/arm/stm32/stm32_usart_driver.cpp @@ -19,8 +19,9 @@ * GNU General Public License for more details. */ -#include "stm32_hal_ll.h" #include "stm32_usart_driver.h" +#include "stm32_dma.h" + #include // WARNING: @@ -51,6 +52,28 @@ static void _enable_usart_irq(const stm32_usart_t* usart) NVIC_EnableIRQ(usart->IRQn); } +static void _enable_tx_dma_irq(const stm32_usart_t* usart) +{ + NVIC_SetPriority(usart->txDMA_IRQn, usart->txDMA_IRQ_Prio); + NVIC_EnableIRQ(usart->txDMA_IRQn); +} + +static inline void _half_duplex_input(const stm32_usart_t* usart) +{ + if (usart->set_input) { + usart->set_input(true); + LL_USART_EnableDirectionRx(usart->USARTx); + } +} + +static inline void _half_duplex_output(const stm32_usart_t* usart) +{ + if (usart->set_input) { + usart->set_input(false); + LL_USART_DisableDirectionRx(usart->USARTx); + } +} + void stm32_usart_enable_tx_irq(const stm32_usart_t* usart) { if (LL_USART_IsEnabledDMAReq_TX(usart->USARTx)) { @@ -65,6 +88,19 @@ void stm32_usart_enable_tx_irq(const stm32_usart_t* usart) LL_USART_EnableIT_TXE(usart->USARTx); } +void stm32_usart_set_idle_irq(const stm32_usart_t* usart, uint32_t enabled) +{ + if (enabled) { + LL_USART_EnableIT_IDLE(usart->USARTx); + _enable_usart_irq(usart); + } else { + LL_USART_DisableIT_IDLE(usart->USARTx); + // Let's assume the port will be disabled soon + // and we don't need to figure out whether or + // not the IRQ needs to be disabled + } +} + static void enable_usart_clock(USART_TypeDef* USARTx) { if (USARTx == USART1) { @@ -106,15 +142,39 @@ static void disable_usart_clock(USART_TypeDef* USARTx) } -void stm32_usart_init_rx_dma(const stm32_usart_t* usart, void* buffer, uint32_t length) +static uint32_t _get_pin_speed(uint32_t baudrate) +{ + // 1 Mbps and above + if (baudrate >= 1000000) { + return LL_GPIO_SPEED_FREQ_VERY_HIGH; + } + // 400kbps and above + else if (baudrate >= 400000) { + return LL_GPIO_SPEED_FREQ_HIGH; + } + + // under 400kbps + return LL_GPIO_SPEED_FREQ_LOW; +} + +static uint32_t _get_usart_af(USART_TypeDef* USARTx) +{ + if (USARTx == USART1 || USARTx == USART2 || USARTx == USART3) { + return LL_GPIO_AF_7; + } else { + return LL_GPIO_AF_8; + } +} + +void stm32_usart_init_rx_dma(const stm32_usart_t* usart, const void* buffer, uint32_t length) { if (!usart->rxDMA) return; // Disable IRQ based RX LL_USART_DisableIT_RXNE(usart->USARTx); - // In case TX DMA is used, disable the ISR completely - if (usart->txDMA) { + // In case TX DMA is used and IDLE IRQ is not, disable the ISR completely + if (usart->txDMA && !LL_USART_IsEnabledIT_IDLE(usart->USARTx)) { NVIC_DisableIRQ(usart->IRQn); } @@ -151,69 +211,90 @@ void stm32_usart_deinit_rx_dma(const stm32_usart_t* usart) } } +// TODO: probably needs to be a separate API on the serial driver +// +// - USART_OneBitMethodCmd(TELEMETRY_USART, ENABLE); + +// OBSOLETE: +// - asymmetric bitrates for half-duplex (GHOST) +// - ??? ability to switch RX DMA OFF ??? (-> X12S) +// void stm32_usart_init(const stm32_usart_t* usart, const etx_serial_init* params) { enable_usart_clock(usart->USARTx); LL_USART_DeInit(usart->USARTx); - LL_GPIO_Init(usart->GPIOx, (LL_GPIO_InitTypeDef*)usart->pinInit); + + // TODO: enable GPIO clock + LL_GPIO_InitTypeDef pinInit; + LL_GPIO_StructInit(&pinInit); + + pinInit.Pin = usart->GPIO_Pin; + pinInit.Mode = LL_GPIO_MODE_ALTERNATE; + pinInit.Speed = _get_pin_speed(params->baudrate); + pinInit.OutputType = LL_GPIO_OUTPUT_PUSHPULL; + pinInit.Pull = LL_GPIO_PULL_UP; + pinInit.Alternate = _get_usart_af(usart->USARTx); + LL_GPIO_Init(usart->GPIOx, &pinInit); LL_USART_InitTypeDef usartInit; LL_USART_StructInit(&usartInit); usartInit.BaudRate = params->baudrate; + usartInit.Parity = LL_USART_PARITY_NONE; + usartInit.DataWidth = LL_USART_DATAWIDTH_8B; - uint32_t parity = LL_USART_PARITY_NONE; - switch(params->parity){ - case ETX_Parity_None: - parity = LL_USART_PARITY_NONE; - break; - case ETX_Parity_Even: - parity = LL_USART_PARITY_EVEN; - break; - case ETX_Parity_Odd: - parity = LL_USART_PARITY_ODD; - break; - } - usartInit.Parity = parity; + switch(params->encoding){ - uint16_t stop_bits = LL_USART_STOPBITS_1; - switch(params->stop_bits) { - case ETX_StopBits_One: - stop_bits = LL_USART_STOPBITS_1; - break; - case ETX_StopBits_OneAndHalf: - stop_bits = LL_USART_STOPBITS_1_5; - break; - case ETX_StopBits_Two: - stop_bits = LL_USART_STOPBITS_2; - break; - } - usartInit.StopBits = stop_bits; + case ETX_Encoding_8E2: + usartInit.Parity = LL_USART_PARITY_EVEN; + usartInit.StopBits = LL_USART_STOPBITS_2; + usartInit.DataWidth = LL_USART_DATAWIDTH_9B; + break; - if (params->word_length == ETX_WordLength_9) { - usartInit.DataWidth = LL_USART_DATAWIDTH_9B; - } else { - usartInit.DataWidth = LL_USART_DATAWIDTH_8B; + case ETX_Encoding_8N1: + break; + + default: + // TODO: return some error + return; } usartInit.HardwareFlowControl = LL_USART_HWCONTROL_NONE; - usartInit.TransferDirection = LL_USART_DIRECTION_TX_RX; + + usartInit.TransferDirection = LL_USART_DIRECTION_NONE; + + if (params->direction & ETX_Dir_RX) + usartInit.TransferDirection |= LL_USART_DIRECTION_RX; + + if (params->direction & ETX_Dir_TX) + usartInit.TransferDirection |= LL_USART_DIRECTION_TX; LL_USART_Init(usart->USARTx, &usartInit); LL_USART_Enable(usart->USARTx); - // Enable TX DMA request - if (usart->txDMA) { - LL_USART_EnableDMAReq_TX(usart->USARTx); + if (params->direction & ETX_Dir_TX) { + // Enable TX DMA request + if (usart->txDMA) { + LL_USART_EnableDMAReq_TX(usart->USARTx); + + // 2-wire half-duplex: setup TX DMA IRQ + if (usart->set_input && (int32_t)(usart->txDMA_IRQn) >= 0) { + _enable_tx_dma_irq(usart); + } + } } - // Enable RX IRQ - if (params->rx_enable) { + if (params->direction & ETX_Dir_RX) { // IRQ based RX LL_USART_EnableIT_RXNE(usart->USARTx); + + // half-duplex: start in input mode + if (usart->set_input) + _half_duplex_input(usart); } - if (!usart->txDMA || (params->rx_enable && !usart->rxDMA)) { + if (((params->direction & ETX_Dir_TX) && !usart->txDMA) || + LL_USART_IsEnabledIT_RXNE(usart->USARTx)) { _enable_usart_irq(usart); } } @@ -235,7 +316,8 @@ void stm32_usart_deinit(const stm32_usart_t* usart) // Reconfigure pin as output LL_GPIO_InitTypeDef pinInit; - memcpy(&pinInit, usart->pinInit, sizeof(LL_GPIO_InitTypeDef)); + LL_GPIO_StructInit(&pinInit); + pinInit.Pin = usart->GPIO_Pin; pinInit.Mode = LL_GPIO_MODE_OUTPUT; pinInit.Pull = LL_GPIO_PULL_NO; pinInit.Alternate = LL_GPIO_AF_0; @@ -247,11 +329,22 @@ void stm32_usart_send_byte(const stm32_usart_t* usart, uint8_t byte) { // TODO: split into 2 steps to avoid blocking on send while (!LL_USART_IsActiveFlag_TXE(usart->USARTx)); + + if (usart->set_input) { + _half_duplex_output(usart); + + // switch back to input after TC + LL_USART_ClearFlag_TC(usart->USARTx); + LL_USART_EnableIT_TC(usart->USARTx); + } + LL_USART_TransmitData8(usart->USARTx, byte); } void stm32_usart_send_buffer(const stm32_usart_t* usart, const uint8_t * data, uint32_t size) { + _half_duplex_output(usart); + if (usart->txDMA) { LL_DMA_DeInit(usart->txDMA, usart->txDMA_Stream); @@ -267,6 +360,10 @@ void stm32_usart_send_buffer(const stm32_usart_t* usart, const uint8_t * data, u dmaInit.Priority = LL_DMA_PRIORITY_VERYHIGH; // TODO: make it configurable LL_DMA_Init(usart->txDMA, usart->txDMA_Stream, &dmaInit); + + if (usart->set_input && (int32_t)(usart->txDMA_IRQn) >= 0) { + LL_DMA_EnableIT_TC(usart->txDMA, usart->txDMA_Stream); + } LL_DMA_EnableStream(usart->txDMA, usart->txDMA_Stream); return; @@ -278,6 +375,20 @@ void stm32_usart_send_buffer(const stm32_usart_t* usart, const uint8_t * data, u } } +uint8_t stm32_usart_tx_completed(const stm32_usart_t* usart) +{ + if (LL_USART_IsEnabledDMAReq_TX(usart->USARTx)) { + // TX DMA is configured, let's check if the stream is currently enabled + if (LL_DMA_IsEnabledStream(usart->txDMA, usart->txDMA_Stream) || + !LL_USART_IsActiveFlag_TXE(usart->USARTx)) + return 0; + } else if (LL_USART_IsEnabledIT_TXE(usart->USARTx)) { + return 0; + } + + return LL_USART_IsActiveFlag_TXE(usart->USARTx); +} + void stm32_usart_wait_for_tx_dma(const stm32_usart_t* usart) { // TODO: check if everything is properly initialised, this seems to block when @@ -286,29 +397,133 @@ void stm32_usart_wait_for_tx_dma(const stm32_usart_t* usart) switch(usart->txDMA_Stream) { case LL_DMA_STREAM_1: - while (LL_DMA_IsActiveFlag_TC1(usart->txDMA)); + while (!LL_DMA_IsActiveFlag_TC1(usart->txDMA)); LL_DMA_ClearFlag_TC1(usart->txDMA); break; case LL_DMA_STREAM_3: - while (LL_DMA_IsActiveFlag_TC3(usart->txDMA)); + while (!LL_DMA_IsActiveFlag_TC3(usart->txDMA)); LL_DMA_ClearFlag_TC3(usart->txDMA); break; case LL_DMA_STREAM_5: - while (LL_DMA_IsActiveFlag_TC5(usart->txDMA)); + while (!LL_DMA_IsActiveFlag_TC5(usart->txDMA)); LL_DMA_ClearFlag_TC5(usart->txDMA); break; case LL_DMA_STREAM_6: - while (LL_DMA_IsActiveFlag_TC6(usart->txDMA)); + while (!LL_DMA_IsActiveFlag_TC6(usart->txDMA)); LL_DMA_ClearFlag_TC6(usart->txDMA); break; case LL_DMA_STREAM_7: - while (LL_DMA_IsActiveFlag_TC7(usart->txDMA)); + while (!LL_DMA_IsActiveFlag_TC7(usart->txDMA)); LL_DMA_ClearFlag_TC7(usart->txDMA); break; } } } +void stm32_usart_enable_rx(const stm32_usart_t* usart) +{ + _half_duplex_input(usart); +} + +// from stm32f4xx_ll_usart.c +static uint32_t _get_usart_periph_clock(USART_TypeDef* USARTx) +{ + uint32_t periphclk = LL_RCC_PERIPH_FREQUENCY_NO; + LL_RCC_ClocksTypeDef rcc_clocks; + + LL_RCC_GetSystemClocksFreq(&rcc_clocks); + if (USARTx == USART1) { + periphclk = rcc_clocks.PCLK2_Frequency; + } else if (USARTx == USART2) { + periphclk = rcc_clocks.PCLK1_Frequency; + } +#if defined(USART3) + else if (USARTx == USART3) { + periphclk = rcc_clocks.PCLK1_Frequency; + } +#endif /* USART3 */ +#if defined(USART6) + else if (USARTx == USART6) { + periphclk = rcc_clocks.PCLK2_Frequency; + } +#endif /* USART6 */ +#if defined(UART4) + else if (USARTx == UART4) { + periphclk = rcc_clocks.PCLK1_Frequency; + } +#endif /* UART4 */ +#if defined(UART5) + else if (USARTx == UART5) { + periphclk = rcc_clocks.PCLK1_Frequency; + } +#endif /* UART5 */ +#if defined(UART7) + else if (USARTx == UART7) { + periphclk = rcc_clocks.PCLK1_Frequency; + } +#endif /* UART7 */ +#if defined(UART8) + else if (USARTx == UART8) { + periphclk = rcc_clocks.PCLK1_Frequency; + } +#endif /* UART8 */ +#if defined(UART9) + else if (USARTx == UART9) { + periphclk = rcc_clocks.PCLK2_Frequency; + } +#endif /* UART9 */ +#if defined(UART10) + else if (USARTx == UART10) { + periphclk = rcc_clocks.PCLK2_Frequency; + } +#endif /* UART10 */ + + return periphclk; +} + +uint32_t stm32_usart_get_baudrate(const stm32_usart_t* usart) +{ + auto periphclk = _get_usart_periph_clock(usart->USARTx); + auto oversampling = LL_USART_GetOverSampling(usart->USARTx); + return LL_USART_GetBaudRate(usart->USARTx, periphclk, oversampling); +} + +void stm32_usart_set_baudrate(const stm32_usart_t* usart, uint32_t baudrate) +{ + auto periphclk = _get_usart_periph_clock(usart->USARTx); + auto oversampling = LL_USART_GetOverSampling(usart->USARTx); + LL_USART_SetBaudRate(usart->USARTx, periphclk, oversampling, baudrate); + + // update pin speed accordingly (must be done one-by-one) + uint32_t pin_speed = _get_pin_speed(baudrate); + uint32_t pindef = usart->GPIO_Pin; + + // loop borrowed from LL_GPIO_init() + uint32_t pinpos = POSITION_VAL(pindef); + uint32_t currentpin = 0; + while ((pindef >> pinpos) != 0) { + currentpin = pindef & (1 << pinpos); + if (currentpin) LL_GPIO_SetPinSpeed(usart->GPIOx, currentpin, pin_speed); + pinpos++; + } +} + +void stm32_usart_set_hw_option(const stm32_usart_t* usart, uint32_t option) +{ + switch(option) { + case ETX_HWOption_OVER8: { + // BRR depends on oversampling as well, so we must + // re-compute the baudrate as well. + auto baudrate = stm32_usart_get_baudrate(usart); + LL_USART_SetOverSampling(usart->USARTx, LL_USART_OVERSAMPLING_8); + stm32_usart_set_baudrate(usart, baudrate); + } break; + case ETX_HWOption_ONEBIT: + LL_USART_EnableOneBitSamp(usart->USARTx); + break; + } +} + #define USART_FLAG_ERRORS \ (LL_USART_SR_ORE | LL_USART_SR_NE | LL_USART_SR_FE | LL_USART_SR_PE) @@ -316,6 +531,26 @@ void stm32_usart_isr(const stm32_usart_t* usart, etx_serial_callbacks_t* cb) { uint32_t status = LL_USART_ReadReg(usart->USARTx, SR); + // cache these first, as RXNE might clear SR + uint32_t idle = (status & LL_USART_SR_IDLE); + uint32_t txe = (status & LL_USART_SR_TXE); + + // TC is only enabled with 2-wire half-duplex when TX DMA was in use + if (LL_USART_IsEnabledIT_TC(usart->USARTx) && (status & LL_USART_SR_TC)) { + + // disable TC IRQ + LL_USART_DisableIT_TC(usart->USARTx); + + // switch to input + _half_duplex_input(usart); + + // and drain RX side first + while (status & LL_USART_SR_RXNE) { + status = LL_USART_ReadReg(usart->USARTx, DR); + status = LL_USART_ReadReg(usart->USARTx, SR); + } + } + // Receive: do it first as it is more time critical if (LL_USART_IsEnabledIT_RXNE(usart->USARTx)) { @@ -339,7 +574,7 @@ void stm32_usart_isr(const stm32_usart_t* usart, etx_serial_callbacks_t* cb) } // IRQ based send: TXE IRQ is enabled only during transfer - if (LL_USART_IsEnabledIT_TXE(usart->USARTx) && (status & LL_USART_SR_TXE)) { + if (LL_USART_IsEnabledIT_TXE(usart->USARTx) && txe) { uint8_t data; if (cb->on_send && cb->on_send(&data)) { @@ -348,4 +583,27 @@ void stm32_usart_isr(const stm32_usart_t* usart, etx_serial_callbacks_t* cb) LL_USART_DisableIT_TXE(usart->USARTx); } } + + if (LL_USART_IsEnabledIT_IDLE(usart->USARTx) && idle) { + // SR clear sequence + status = LL_USART_ReadReg(usart->USARTx, DR); + if (cb->on_idle) cb->on_idle(); + } +} + +void stm32_usart_tx_dma_isr(const stm32_usart_t* usart) +{ + if (!stm32_dma_check_tc_flag(usart->txDMA, usart->txDMA_Stream)) + return; + + auto USARTx = usart->USARTx; + + // clear TC flag before enabling USART TC interrupt: + // -> TC flag will be re-triggered once the last byte which has + // just been transfered from DMA to USART will be transmitted, + // thus triggering TELEMETRY_USART_IRQHandler(), which will + // switch from output to input mode. + // + LL_USART_ClearFlag_TC(USARTx); + LL_USART_EnableIT_TC(USARTx); } diff --git a/radio/src/targets/common/arm/stm32/stm32_usart_driver.h b/radio/src/targets/common/arm/stm32/stm32_usart_driver.h index 57970ca52..0a3ed976b 100644 --- a/radio/src/targets/common/arm/stm32/stm32_usart_driver.h +++ b/radio/src/targets/common/arm/stm32/stm32_usart_driver.h @@ -25,12 +25,14 @@ #include "hal/serial_driver.h" #include "stm32_hal_ll.h" +typedef void (*pin_setter_t)(uint8_t enable); + struct stm32_usart_t { // USART defs USART_TypeDef* USARTx; GPIO_TypeDef* GPIOx; - const LL_GPIO_InitTypeDef* pinInit; + uint32_t GPIO_Pin; // USART IRQ IRQn_Type IRQn; @@ -45,15 +47,26 @@ struct stm32_usart_t { DMA_TypeDef* rxDMA; uint32_t rxDMA_Stream; uint32_t rxDMA_Channel; + + // 2-wire Half-duplex settings (uses direction pin) + pin_setter_t set_input; + IRQn_Type txDMA_IRQn; + uint8_t txDMA_IRQ_Prio; }; void stm32_usart_init(const stm32_usart_t* usart, const etx_serial_init* params); -void stm32_usart_init_rx_dma(const stm32_usart_t* usart, void* buffer, uint32_t length); +void stm32_usart_init_rx_dma(const stm32_usart_t* usart, const void* buffer, uint32_t length); void stm32_usart_enable_tx_irq(const stm32_usart_t* usart); +void stm32_usart_set_idle_irq(const stm32_usart_t* usart, uint32_t enabled); void stm32_usart_deinit(const stm32_usart_t* usart); void stm32_usart_deinit_rx_dma(const stm32_usart_t* usart); void stm32_usart_send_byte(const stm32_usart_t* usart, uint8_t byte); void stm32_usart_send_buffer(const stm32_usart_t* usart, const uint8_t * data, uint32_t size); +uint8_t stm32_usart_tx_completed(const stm32_usart_t* usart); void stm32_usart_wait_for_tx_dma(const stm32_usart_t* usart); +void stm32_usart_enable_rx(const stm32_usart_t* usart); +uint32_t stm32_usart_get_baudrate(const stm32_usart_t* usart); +void stm32_usart_set_baudrate(const stm32_usart_t* usart, uint32_t baudrate); +void stm32_usart_set_hw_option(const stm32_usart_t* usart, uint32_t option); void stm32_usart_isr(const stm32_usart_t* usart, etx_serial_callbacks_t* cb); - +void stm32_usart_tx_dma_isr(const stm32_usart_t* usart); diff --git a/radio/src/targets/common/arm/stm32/timers_driver.cpp b/radio/src/targets/common/arm/stm32/timers_driver.cpp index 3384458e6..ef59d0b53 100644 --- a/radio/src/targets/common/arm/stm32/timers_driver.cpp +++ b/radio/src/targets/common/arm/stm32/timers_driver.cpp @@ -21,8 +21,6 @@ #include "opentx.h" -extern void flysky_hall_stick_loop( void ); - // Start TIMER at 2000000Hz void init2MhzTimer() { @@ -32,10 +30,10 @@ void init2MhzTimer() TIMER_2MHz_TIMER->CR1 = TIM_CR1_CEN; } -// Start TIMER at 1000Hz -void init1msTimer() +// Start TIMER at 200Hz +void init5msTimer() { - INTERRUPT_xMS_TIMER->ARR = 999; // 1mS in uS + INTERRUPT_xMS_TIMER->ARR = 4999; // 5mS in uS INTERRUPT_xMS_TIMER->PSC = (PERI1_FREQUENCY * TIMER_MULT_APB1) / 1000000 - 1; // 1uS INTERRUPT_xMS_TIMER->CCER = 0; INTERRUPT_xMS_TIMER->CCMR1 = 0; @@ -46,7 +44,7 @@ void init1msTimer() NVIC_SetPriority(INTERRUPT_xMS_IRQn, 4); } -void stop1msTimer() +void stop5msTimer() { INTERRUPT_xMS_TIMER->CR1 = 0; // stop timer NVIC_DisableIRQ(INTERRUPT_xMS_IRQn); @@ -59,33 +57,20 @@ void watchdogSuspend(uint32_t timeout) watchdogTimeout = timeout; } -void interrupt1ms() +static void interrupt5ms() { static uint8_t pre_scale; // Used to get 10 Hz counter - ++pre_scale; - // 1 ms loop -#if not defined(SIMU) && (defined(RADIO_FAMILY_T16) || defined(PCBNV14)) - if (globalData.flyskygimbals) - { - flysky_hall_stick_loop(); - } -#endif - // 5ms loop - if (pre_scale == 5 || pre_scale == 10) { #if defined(HAPTIC) - DEBUG_TIMER_START(debugTimerHaptic); - HAPTIC_HEARTBEAT(); - DEBUG_TIMER_STOP(debugTimerHaptic); + DEBUG_TIMER_START(debugTimerHaptic); + HAPTIC_HEARTBEAT(); + DEBUG_TIMER_STOP(debugTimerHaptic); #endif - } // 10ms loop - if (pre_scale == 10) { - pre_scale = 0; - + if (pre_scale & 1) { if (watchdogTimeout) { watchdogTimeout -= 1; WDG_RESET(); // Retrigger hardware watchdog @@ -101,6 +86,6 @@ void interrupt1ms() extern "C" void INTERRUPT_xMS_IRQHandler() { INTERRUPT_xMS_TIMER->SR &= ~TIM_SR_UIF; - interrupt1ms(); - DEBUG_INTERRUPT(INT_1MS); + interrupt5ms(); + DEBUG_INTERRUPT(INT_5MS); } diff --git a/radio/src/targets/common/arm/stm32/timers_driver.h b/radio/src/targets/common/arm/stm32/timers_driver.h index 5ba92aebc..c51734826 100644 --- a/radio/src/targets/common/arm/stm32/timers_driver.h +++ b/radio/src/targets/common/arm/stm32/timers_driver.h @@ -31,8 +31,8 @@ uint16_t getTmr2MHz(); #include "hal.h" void init2MhzTimer(); -void init1msTimer(); -void stop1msTimer(); +void init5msTimer(); +void stop5msTimer(); static inline uint16_t getTmr2MHz() { return TIMER_2MHz_TIMER->CNT; } diff --git a/radio/src/targets/common/arm/stm32/trainer_driver.cpp b/radio/src/targets/common/arm/stm32/trainer_driver.cpp index 92fca2436..0f0cac4d2 100644 --- a/radio/src/targets/common/arm/stm32/trainer_driver.cpp +++ b/radio/src/targets/common/arm/stm32/trainer_driver.cpp @@ -143,7 +143,7 @@ static void _init_trainer_capture(const stm32_pulse_timer_t* tim) _trainer_timer = tim; _trainer_timer_isr = trainer_in_isr; - stm32_pulse_init(tim); + stm32_pulse_init(tim, 0); stm32_pulse_config_input(tim); switch (tim->TIM_Channel) { @@ -171,13 +171,14 @@ static const stm32_pulse_timer_t trainerOutputTimer = { .GPIO_Pin = TRAINER_OUT_GPIO_PIN, .GPIO_Alternate = TRAINER_GPIO_AF, .TIMx = TRAINER_TIMER, - .TIM_Prescaler = __LL_TIM_CALC_PSC(TRAINER_TIMER_FREQ, 2000000), + .TIM_Freq = TRAINER_TIMER_FREQ, .TIM_Channel = TRAINER_OUT_TIMER_Channel, .TIM_IRQn = TRAINER_TIMER_IRQn, .DMAx = nullptr, .DMA_Stream = 0, .DMA_Channel = 0, .DMA_IRQn = (IRQn_Type)0, + .DMA_TC_CallbackPtr = nullptr, }; static void trainerSendNextFrame() @@ -228,7 +229,7 @@ void init_trainer_ppm() _trainer_timer = &trainerOutputTimer; _trainer_timer_isr = trainer_out_isr; - stm32_pulse_init(&trainerOutputTimer); + stm32_pulse_init(&trainerOutputTimer, 0); stm32_pulse_config_output(&trainerOutputTimer, GET_TRAINER_PPM_POLARITY(), LL_TIM_OCMODE_PWM1, GET_TRAINER_PPM_DELAY() * 2); @@ -248,13 +249,14 @@ static const stm32_pulse_timer_t trainerInputTimer = { .GPIO_Pin = TRAINER_IN_GPIO_PIN, .GPIO_Alternate = TRAINER_GPIO_AF, .TIMx = TRAINER_TIMER, - .TIM_Prescaler = __LL_TIM_CALC_PSC(TRAINER_TIMER_FREQ, 2000000), + .TIM_Freq = TRAINER_TIMER_FREQ, .TIM_Channel = TRAINER_IN_TIMER_Channel, .TIM_IRQn = TRAINER_TIMER_IRQn, .DMAx = nullptr, .DMA_Stream = 0, .DMA_Channel = 0, .DMA_IRQn = (IRQn_Type)0, + .DMA_TC_CallbackPtr = nullptr, }; void init_trainer_capture() @@ -309,13 +311,14 @@ static const stm32_pulse_timer_t trainerModuleTimer = { .GPIO_Pin = TRAINER_MODULE_CPPM_GPIO_PIN, .GPIO_Alternate = TRAINER_MODULE_CPPM_GPIO_AF, .TIMx = TRAINER_MODULE_CPPM_TIMER, - .TIM_Prescaler = __LL_TIM_CALC_PSC(TRAINER_MODULE_CPPM_FREQ, 2000000), + .TIM_Freq = TRAINER_MODULE_CPPM_FREQ, .TIM_Channel = TRAINER_MODULE_CPPM_TIMER_Channel, .TIM_IRQn = TRAINER_MODULE_CPPM_TIMER_IRQn, .DMAx = nullptr, .DMA_Stream = 0, .DMA_Channel = 0, .DMA_IRQn = (IRQn_Type)0, + .DMA_TC_CallbackPtr = nullptr, }; void init_trainer_module_cppm() @@ -344,38 +347,39 @@ extern "C" void TRAINER_MODULE_CPPM_TIMER_IRQHandler() const etx_serial_init sbusTrainerParams = { .baudrate = SBUS_BAUDRATE, - .parity = ETX_Parity_Even, - .stop_bits = ETX_StopBits_Two, - .word_length = ETX_WordLength_9, - .rx_enable = true, + .encoding = ETX_Encoding_8E2, + .direction = ETX_Dir_RX, + .polarity = ETX_Pol_Normal, }; -// external module has a full-duplex USART -#if defined(EXTMODULE_USART) -#include "extmodule_serial_driver.h" +// external module may have a full-duplex USART +#if defined(EXTMODULE_USART) || defined(CONFIGURABLE_MODULE_PORT) -static void* sbus_trainer_ctx = nullptr; +#include "hal/module_port.h" + +static etx_module_state_t* sbus_trainer_mod_st = nullptr; void init_trainer_module_sbus() { - auto serial_driver = extmoduleGetSerialPort(); - sbus_trainer_ctx = serial_driver->init(&sbusTrainerParams); + if (sbus_trainer_mod_st) return; + + sbus_trainer_mod_st = modulePortInitSerial(EXTERNAL_MODULE, ETX_MOD_PORT_UART, + &sbusTrainerParams); } void stop_trainer_module_sbus() { - auto serial_driver = extmoduleGetSerialPort(); - auto ctx = sbus_trainer_ctx; - if (ctx) { - sbus_trainer_ctx = nullptr; - serial_driver->deinit(ctx); - } + if (!sbus_trainer_mod_st) return; + modulePortDeInit(sbus_trainer_mod_st); } int trainerModuleSbusGetByte(uint8_t* data) { - auto serial_driver = extmoduleGetSerialPort(); - auto ctx = sbus_trainer_ctx; + if (!sbus_trainer_mod_st) return 0; + + auto serial_driver = modulePortGetSerialDrv(sbus_trainer_mod_st->rx); + auto ctx = modulePortGetCtx(sbus_trainer_mod_st->rx); + if (ctx) { return serial_driver->getByte(ctx, data); } @@ -384,21 +388,12 @@ int trainerModuleSbusGetByte(uint8_t* data) } #elif defined(TRAINER_MODULE_SBUS_USART) -#include "stm32_usart_driver.h" - -static const LL_GPIO_InitTypeDef sbus_trainer_USART_PinDef = { - .Pin = TRAINER_MODULE_SBUS_GPIO_PIN, - .Mode = LL_GPIO_MODE_ALTERNATE, - .Speed = LL_GPIO_SPEED_FREQ_LOW, - .OutputType = LL_GPIO_OUTPUT_PUSHPULL, - .Pull = LL_GPIO_PULL_UP, - .Alternate = TRAINER_MODULE_SBUS_GPIO_AF, -}; +#include "stm32_serial_driver.h" static const stm32_usart_t sbus_trainer_USART = { .USARTx = TRAINER_MODULE_SBUS_USART, .GPIOx = TRAINER_MODULE_SBUS_GPIO, - .pinInit = &sbus_trainer_USART_PinDef, + .GPIO_Pin = TRAINER_MODULE_SBUS_GPIO_PIN, .IRQn = (IRQn_Type)-1, .IRQ_Prio = 0, .txDMA = nullptr, @@ -409,23 +404,25 @@ static const stm32_usart_t sbus_trainer_USART = { .rxDMA_Channel = TRAINER_MODULE_SBUS_DMA_CHANNEL, }; -static DMAFifo<32> sbus_trainer_fifo __DMA (TRAINER_MODULE_SBUS_DMA_STREAM); +DEFINE_STM32_SERIAL_PORT(SbusTrainer, sbus_trainer_USART, 32, 0); + +static void* _sbus_trainer_ctx = nullptr; void init_trainer_module_sbus() { - stm32_usart_init(&sbus_trainer_USART, &sbusTrainerParams); - stm32_usart_init_rx_dma(&sbus_trainer_USART, sbus_trainer_fifo.buffer(), - sbus_trainer_fifo.size()); + _sbus_trainer_ctx = STM32SerialDriver.init(REF_STM32_SERIAL_PORT(SbusTrainer), + &sbusTrainerParams); } void stop_trainer_module_sbus() { - stm32_usart_deinit(&sbus_trainer_USART); + STM32SerialDriver.deinit(_sbus_trainer_ctx); + _sbus_trainer_ctx = nullptr; } int trainerModuleSbusGetByte(uint8_t* data) { - return sbus_trainer_fifo.pop(*data); + return STM32SerialDriver.getByte(_sbus_trainer_ctx, data); } #else diff --git a/radio/src/targets/common/arm/stm32/usbd_cdc.cpp b/radio/src/targets/common/arm/stm32/usbd_cdc.cpp index c54bb29e3..c4e888d40 100644 --- a/radio/src/targets/common/arm/stm32/usbd_cdc.cpp +++ b/radio/src/targets/common/arm/stm32/usbd_cdc.cpp @@ -296,8 +296,14 @@ void usbSerialSetBaudRateCb(void*, void (*cb)(uint32_t)) // ctrlLineStateCb = cb; // } +static void* usbSerialInit(void*, const etx_serial_init*) +{ + // always succeeds + return (void*)1; +} + static const etx_serial_driver_t usbSerialDriver = { - .init = nullptr, + .init = usbSerialInit, .deinit = nullptr, .sendByte = usbSerialPutc, .sendBuffer = nullptr, @@ -313,6 +319,7 @@ const etx_serial_port_t UsbSerialPort = { "USB-VCP", &usbSerialDriver, nullptr, + nullptr, }; // /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/radio/src/targets/horus/CMakeLists.txt b/radio/src/targets/horus/CMakeLists.txt index 1963b2e4b..84f680bfa 100644 --- a/radio/src/targets/horus/CMakeLists.txt +++ b/radio/src/targets/horus/CMakeLists.txt @@ -172,6 +172,7 @@ add_definitions(-DEEPROM_VARIANT=0 -DAUDIO -DVOICE -DRTCLOCK) add_definitions(-DGPS_USART_BAUDRATE=${INTERNAL_GPS_BAUDRATE}) add_definitions(-DPWR_BUTTON_${PWR_BUTTON}) add_definitions(-DHARDWARE_TRAINER_JACK) +add_definitions(-DSTM32_SUPPORT_32BIT_TIMERS) set(SDRAM ON) @@ -192,7 +193,7 @@ if(HARDWARE_EXTERNAL_ACCESS_MOD) endif() if(PCB STREQUAL X10) - set(FLYSKY_HALL_STICKS_DRIVER flyskyHallStick_driver.cpp) + set(FLYSKY_HALL_STICKS_DRIVER targets/common/arm/stm32/flysky_gimbal_driver.cpp) endif() if(IMU_LSM6DS33) @@ -262,7 +263,6 @@ endif() set(FIRMWARE_TARGET_SRC ${FIRMWARE_TARGET_SRC} ${LCD_DRIVER} - ${FLYSKY_HALL_STICKS_DRIVER} ${TOUCH_DRIVER} board.cpp backlight_driver.cpp @@ -273,19 +273,22 @@ set(FIRMWARE_TARGET_SRC set(FIRMWARE_SRC ${FIRMWARE_SRC} hal/adc_driver.cpp + boards/generic_stm32/module_ports.cpp + boards/generic_stm32/aux_ports.cpp + boards/generic_stm32/sport_update.cpp + boards/generic_stm32/intmodule_heartbeat.cpp targets/common/arm/stm32/stm32_exti_driver.cpp targets/common/arm/stm32/mixer_scheduler_driver.cpp targets/common/arm/stm32/timers_driver.cpp - targets/common/arm/stm32/intmodule_serial_driver.cpp targets/common/arm/stm32/extmodule_driver.cpp targets/common/arm/stm32/stm32_pulse_driver.cpp - targets/common/arm/stm32/extmodule_serial_driver.cpp targets/common/arm/stm32/stm32_usart_driver.cpp targets/common/arm/stm32/rotary_encoder_driver.cpp targets/common/arm/stm32/pwr_driver.cpp targets/common/arm/stm32/heartbeat_driver.cpp targets/common/arm/stm32/trainer_driver.cpp targets/common/arm/stm32/sdio_sd.c + ${FLYSKY_HALL_STICKS_DRIVER} ) if(BOOTLOADER) diff --git a/radio/src/targets/horus/board.cpp b/radio/src/targets/horus/board.cpp index 8145cd368..f1a6002fc 100644 --- a/radio/src/targets/horus/board.cpp +++ b/radio/src/targets/horus/board.cpp @@ -19,13 +19,13 @@ * GNU General Public License for more details. */ -#include "stm32_hal_ll.h" +#include "board.h" +#include "boards/generic_stm32/module_ports.h" +#include "boards/generic_stm32/intmodule_heartbeat.h" + #include "hal/adc_driver.h" -#include "hal/serial_driver.h" -#include "hal/serial_port.h" #include "hal/trainer_driver.h" -#include "board.h" #include "timers_driver.h" #include "dataconstants.h" #include "opentx_types.h" @@ -35,10 +35,6 @@ #include -#if defined(AUX_SERIAL) || defined(AUX2_SERIAL) -#include "aux_serial_driver.h" -#endif - #if !defined(PCBX12S) #include "stm32_hal_adc.h" #define ADC_DRIVER stm32_hal_adc_driver @@ -47,9 +43,9 @@ #define ADC_DRIVER x12s_adc_driver #endif -extern void flysky_hall_stick_check_init(void); -extern void flysky_hall_stick_init(void); -extern void flysky_hall_stick_loop( void ); +#if defined(RADIO_FAMILY_T16) || defined(PCBNV14) + #include "flysky_gimbal_driver.h" +#endif HardwareOptions hardwareOptions; bool boardBacklightOn = false; @@ -64,41 +60,9 @@ void watchdogInit(unsigned int duration) IWDG->KR = 0xCCCC; // start } -#if HAS_SPORT_UPDATE_CONNECTOR() && !defined(BOOT) - -// g_eeGeneral +#if !defined(BOOT) #include "opentx.h" -void sportUpdateInit() -{ - GPIO_InitTypeDef GPIO_InitStructure; - GPIO_InitStructure.GPIO_Pin = SPORT_UPDATE_PWR_GPIO_PIN; - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; - GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; - GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; - GPIO_Init(SPORT_UPDATE_PWR_GPIO, &GPIO_InitStructure); -} - -void sportUpdatePowerOn() -{ - GPIO_SetBits(SPORT_UPDATE_PWR_GPIO, SPORT_UPDATE_PWR_GPIO_PIN); -} - -void sportUpdatePowerOff() -{ - GPIO_ResetBits(SPORT_UPDATE_PWR_GPIO, SPORT_UPDATE_PWR_GPIO_PIN); -} - -void sportUpdatePowerInit() -{ - if (g_eeGeneral.sportUpdatePower == 1) - sportUpdatePowerOn(); - else - sportUpdatePowerOff(); -} -#endif - void boardInit() { RCC_AHB1PeriphClockCmd(PWR_RCC_AHB1Periph | @@ -160,6 +124,14 @@ void boardInit() #endif pwrInit(); + boardInitModulePorts(); + +#if defined(INTMODULE_HEARTBEAT) && \ + (defined(INTERNAL_MODULE_PXX1) || defined(INTERNAL_MODULE_PXX2)) + pulsesSetModuleInitCb(_intmodule_heartbeat_init); + pulsesSetModuleDeInitCb(_intmodule_heartbeat_deinit); +#endif + init_trainer(); pwrOn(); delaysInit(); @@ -186,34 +158,18 @@ void boardInit() } #endif - globalData.flyskygimbals = false; #if defined(RADIO_FAMILY_T16) || defined(PCBNV14) - flysky_hall_stick_check_init(); - - // Wait 70ms for FlySky gimbals to respond. According to LA trace, minimally 23ms is required - for (uint8_t ui8 = 0; ui8 < 70; ui8++) - { - flysky_hall_stick_loop(); - delay_ms(1); - if (globalData.flyskygimbals) - { - break; - } - } - + globalData.flyskygimbals = flysky_gimbal_init(); +#else + globalData.flyskygimbals = false; #endif - if (globalData.flyskygimbals) - { - flysky_hall_stick_init(); - } - if (!adcInit(&ADC_DRIVER)) - TRACE("adcInit failed"); - + TRACE("adcInit failed"); init2MhzTimer(); - init1msTimer(); + init5msTimer(); + usbInit(); hapticInit(); @@ -232,10 +188,6 @@ void boardInit() usbChargerInit(); #endif -#if HAS_SPORT_UPDATE_CONNECTOR() && !defined(BOOT) - sportUpdateInit(); -#endif - #if defined(RTCLOCK) && !defined(COPROCESSOR) ledRed(); rtcInit(); // RTC must be initialized before rambackupRestore() is called @@ -243,6 +195,7 @@ void boardInit() ledBlue(); } +#endif void boardOff() { @@ -305,73 +258,3 @@ bool isBacklightEnabled() return boardBacklightOn; } -#if defined(AUX_SERIAL_PWR_GPIO) || defined(AUX2_SERIAL_PWR_GPIO) -static void _aux_pwr(GPIO_TypeDef *GPIOx, uint32_t pin, uint8_t on) -{ - LL_GPIO_InitTypeDef pinInit; - LL_GPIO_StructInit(&pinInit); - pinInit.Pin = pin; - pinInit.Mode = LL_GPIO_MODE_OUTPUT; - pinInit.Pull = LL_GPIO_PULL_UP; - LL_GPIO_Init(GPIOx, &pinInit); - - if (on) { - LL_GPIO_SetOutputPin(GPIOx, pin); - } else { - LL_GPIO_ResetOutputPin(GPIOx, pin); - } -} -#endif - -#if defined(AUX_SERIAL) -void set_aux_pwr(uint8_t on) -{ -#if defined(AUX_SERIAL_PWR_GPIO) - _aux_pwr(AUX_SERIAL_PWR_GPIO, AUX_SERIAL_PWR_GPIO_PIN, on); -#endif -} - -const etx_serial_port_t auxSerialPort = { - "AUX1", - &AuxSerialDriver, - set_aux_pwr, -}; -#define AUX_SERIAL_PORT &auxSerialPort -#else -#define AUX_SERIAL_PORT nullptr -#endif - -#if defined(AUX2_SERIAL) -void set_aux2_pwr(uint8_t on) -{ -#if defined(AUX2_SERIAL_PWR_GPIO) - _aux_pwr(AUX2_SERIAL_PWR_GPIO, AUX2_SERIAL_PWR_GPIO_PIN, on); -#endif -} - -const etx_serial_port_t aux2SerialPort = { -#if !defined(PCBX12S) - "AUX2", -#else - // AUX2 is hardwired to the internal GPS - // on the X12S, let's hide the setting - nullptr, -#endif - &Aux2SerialDriver, - set_aux2_pwr, -}; -#define AUX2_SERIAL_PORT &aux2SerialPort -#else -#define AUX2_SERIAL_PORT nullptr -#endif // AUX2_SERIAL - -static const etx_serial_port_t* serialPorts[MAX_AUX_SERIAL] = { - AUX_SERIAL_PORT, - AUX2_SERIAL_PORT, -}; - -const etx_serial_port_t* auxSerialGetPort(int port_nr) -{ - if (port_nr >= MAX_AUX_SERIAL) return nullptr; - return serialPorts[port_nr]; -} diff --git a/radio/src/targets/horus/board.h b/radio/src/targets/horus/board.h index b83fa553c..77bacdb3b 100644 --- a/radio/src/targets/horus/board.h +++ b/radio/src/targets/horus/board.h @@ -165,11 +165,6 @@ void SDRAM_Init(); #define EXTERNAL_MODULE_ON() GPIO_SetBits(EXTMODULE_PWR_GPIO, EXTMODULE_PWR_GPIO_PIN) #define EXTERNAL_MODULE_OFF() GPIO_ResetBits(EXTMODULE_PWR_GPIO, EXTMODULE_PWR_GPIO_PIN) -#define IS_INTERNAL_MODULE_ON() \ - (GPIO_ReadInputDataBit(INTMODULE_PWR_GPIO, INTMODULE_PWR_GPIO_PIN) == Bit_SET) -#define IS_EXTERNAL_MODULE_ON() \ - (GPIO_ReadInputDataBit(EXTMODULE_PWR_GPIO, EXTMODULE_PWR_GPIO_PIN) == Bit_SET) - #if !defined(PXX2) #define IS_PXX2_INTERNAL_ENABLED() (false) #define IS_PXX1_INTERNAL_ENABLED() (true) @@ -617,21 +612,6 @@ extern uint32_t telemetryErrors; // soft-serial void telemetryPortInvertedInit(uint32_t baudrate); -// Sport update driver -#if HAS_SPORT_UPDATE_CONNECTOR() -void sportUpdatePowerOn(); -void sportUpdatePowerOff(); -void sportUpdatePowerInit(); -#define SPORT_UPDATE_POWER_ON() sportUpdatePowerOn() -#define SPORT_UPDATE_POWER_OFF() sportUpdatePowerOff() -#define SPORT_UPDATE_POWER_INIT() sportUpdatePowerInit() -#define IS_SPORT_UPDATE_POWER_ON() (GPIO_ReadInputDataBit(SPORT_UPDATE_PWR_GPIO, SPORT_UPDATE_PWR_GPIO_PIN) == Bit_SET) -#else -#define SPORT_UPDATE_POWER_ON() -#define SPORT_UPDATE_POWER_OFF() -#define SPORT_UPDATE_POWER_INIT() -#define IS_SPORT_UPDATE_POWER_ON() (false) -#endif // Aux serial port driver #if defined(RADIO_TX16S) diff --git a/radio/src/targets/horus/flyskyHallStick_driver.cpp b/radio/src/targets/horus/flyskyHallStick_driver.cpp deleted file mode 100644 index a2889b2b5..000000000 --- a/radio/src/targets/horus/flyskyHallStick_driver.cpp +++ /dev/null @@ -1,378 +0,0 @@ -/* - * Copyright (C) EdgeTX - * - * Based on code named - * opentx - https://github.com/opentx/opentx - * th9x - http://code.google.com/p/th9x - * er9x - http://code.google.com/p/er9x - * gruvin9x - http://code.google.com/p/gruvin9x - * - * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "opentx.h" -#include "flyskyHallStick_driver.h" - -#include "fifo.h" -#include "dmafifo.h" - -DMAFifo hallDMAFifo __DMA (FLYSKY_HALL_DMA_Stream_RX); -Fifo hallStickTxFifo; -unsigned char HallCmd[264] __DMA; - -STRUCT_HALL HallProtocol = { 0 }; -STRUCT_HALL HallProtocolTx = { 0 }; -signed short hall_raw_values[FLYSKY_HALL_CHANNEL_COUNT]; -unsigned short hall_adc_values[FLYSKY_HALL_CHANNEL_COUNT]; - -/* crc16 implementation according to CCITT standards */ -const unsigned short CRC16Table[256]= { - 0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7, - 0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef, - 0x1231,0x0210,0x3273,0x2252,0x52b5,0x4294,0x72f7,0x62d6, - 0x9339,0x8318,0xb37b,0xa35a,0xd3bd,0xc39c,0xf3ff,0xe3de, - 0x2462,0x3443,0x0420,0x1401,0x64e6,0x74c7,0x44a4,0x5485, - 0xa56a,0xb54b,0x8528,0x9509,0xe5ee,0xf5cf,0xc5ac,0xd58d, - 0x3653,0x2672,0x1611,0x0630,0x76d7,0x66f6,0x5695,0x46b4, - 0xb75b,0xa77a,0x9719,0x8738,0xf7df,0xe7fe,0xd79d,0xc7bc, - 0x48c4,0x58e5,0x6886,0x78a7,0x0840,0x1861,0x2802,0x3823, - 0xc9cc,0xd9ed,0xe98e,0xf9af,0x8948,0x9969,0xa90a,0xb92b, - 0x5af5,0x4ad4,0x7ab7,0x6a96,0x1a71,0x0a50,0x3a33,0x2a12, - 0xdbfd,0xcbdc,0xfbbf,0xeb9e,0x9b79,0x8b58,0xbb3b,0xab1a, - 0x6ca6,0x7c87,0x4ce4,0x5cc5,0x2c22,0x3c03,0x0c60,0x1c41, - 0xedae,0xfd8f,0xcdec,0xddcd,0xad2a,0xbd0b,0x8d68,0x9d49, - 0x7e97,0x6eb6,0x5ed5,0x4ef4,0x3e13,0x2e32,0x1e51,0x0e70, - 0xff9f,0xefbe,0xdfdd,0xcffc,0xbf1b,0xaf3a,0x9f59,0x8f78, - 0x9188,0x81a9,0xb1ca,0xa1eb,0xd10c,0xc12d,0xf14e,0xe16f, - 0x1080,0x00a1,0x30c2,0x20e3,0x5004,0x4025,0x7046,0x6067, - 0x83b9,0x9398,0xa3fb,0xb3da,0xc33d,0xd31c,0xe37f,0xf35e, - 0x02b1,0x1290,0x22f3,0x32d2,0x4235,0x5214,0x6277,0x7256, - 0xb5ea,0xa5cb,0x95a8,0x8589,0xf56e,0xe54f,0xd52c,0xc50d, - 0x34e2,0x24c3,0x14a0,0x0481,0x7466,0x6447,0x5424,0x4405, - 0xa7db,0xb7fa,0x8799,0x97b8,0xe75f,0xf77e,0xc71d,0xd73c, - 0x26d3,0x36f2,0x0691,0x16b0,0x6657,0x7676,0x4615,0x5634, - 0xd94c,0xc96d,0xf90e,0xe92f,0x99c8,0x89e9,0xb98a,0xa9ab, - 0x5844,0x4865,0x7806,0x6827,0x18c0,0x08e1,0x3882,0x28a3, - 0xcb7d,0xdb5c,0xeb3f,0xfb1e,0x8bf9,0x9bd8,0xabbb,0xbb9a, - 0x4a75,0x5a54,0x6a37,0x7a16,0x0af1,0x1ad0,0x2ab3,0x3a92, - 0xfd2e,0xed0f,0xdd6c,0xcd4d,0xbdaa,0xad8b,0x9de8,0x8dc9, - 0x7c26,0x6c07,0x5c64,0x4c45,0x3ca2,0x2c83,0x1ce0,0x0cc1, - 0xef1f,0xff3e,0xcf5d,0xdf7c,0xaf9b,0xbfba,0x8fd9,0x9ff8, - 0x6e17,0x7e36,0x4e55,0x5e74,0x2e93,0x3eb2,0x0ed1,0x1ef0 -}; - -//const uint8_t sticks_mapping[4] = { 0 /*STICK1*/, 1/*STICK2*/, 2/*STICK3*/, 3 /*STICK4*/}; - -unsigned short calc_crc16(void *pBuffer,unsigned char BufferSize) -{ - unsigned short crc16; - crc16 = 0xffff; - while (BufferSize) - { - crc16 = (crc16 << 8) ^ CRC16Table[((crc16>>8) ^ (*(unsigned char *)pBuffer)) & 0x00ff]; - pBuffer = (void *)((unsigned char *)pBuffer + 1); - BufferSize--; - } - return crc16; -} - -uint16_t get_flysky_hall_adc_value(uint8_t ch) -{ - if (ch >= FLYSKY_HALL_CHANNEL_COUNT) - { - return 0; - } - - return 2*FLYSKY_OFFSET_VALUE - hall_adc_values[ch]; -} - -void HallSendBuffer(uint8_t * buffer, uint32_t count) -{ - for(uint32_t idx = 0; buffer != HallCmd && idx < count; idx++) - { - HallCmd[idx] = buffer[idx]; - } - DMA_InitTypeDef DMA_InitStructure; - DMA_DeInit(FLYSKY_HALL_DMA_Stream_TX); - DMA_InitStructure.DMA_Channel = FLYSKY_HALL_DMA_Channel; - DMA_InitStructure.DMA_PeripheralBaseAddr = CONVERT_PTR_UINT(&FLYSKY_HALL_SERIAL_USART->DR); - DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; - DMA_InitStructure.DMA_Memory0BaseAddr = CONVERT_PTR_UINT(HallCmd); - DMA_InitStructure.DMA_BufferSize = count; - DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; - DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; - DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; - DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; - DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; - DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; - DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; - DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full; - DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; - DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; - DMA_Init(FLYSKY_HALL_DMA_Stream_TX, &DMA_InitStructure); - DMA_Cmd(FLYSKY_HALL_DMA_Stream_TX, ENABLE); - USART_DMACmd(FLYSKY_HALL_SERIAL_USART, USART_DMAReq_Tx, ENABLE); - DMA_ITConfig(FLYSKY_HALL_DMA_Stream_TX, DMA_IT_TC, ENABLE); - - /* enable interrupt and set it's priority */ - NVIC_EnableIRQ(FLYSKY_HALL_SERIAL_TX_DMA_Stream_IRQn); - NVIC_SetPriority(FLYSKY_HALL_SERIAL_TX_DMA_Stream_IRQn, 7); -} - -extern "C" void FLYSKY_HALL_TX_DMA_Stream_IRQHandler(void) -{ - DEBUG_INTERRUPT(INT_TELEM_DMA); - - if (DMA_GetITStatus(FLYSKY_HALL_DMA_Stream_TX, FLYSKY_HALL_DMA_TX_FLAG_TC)) - { - DMA_ClearITPendingBit(FLYSKY_HALL_DMA_Stream_TX, FLYSKY_HALL_DMA_TX_FLAG_TC); - FLYSKY_HALL_SERIAL_USART->CR1 |= USART_CR1_TCIE; - } -} - -uint8_t HallGetByte(uint8_t * byte) -{ - return hallDMAFifo.pop(*byte); -} - -void reset_hall_stick( void ) -{ - unsigned short crc16 = 0xffff; - - HallCmd[0] = FLYSKY_HALL_PROTOLO_HEAD; - HallCmd[1] = 0xD1; - HallCmd[2] = 0x01; - HallCmd[3] = 0x01; - - crc16 = calc_crc16(HallCmd, 4); - - HallCmd[4] = crc16 & 0xff; - HallCmd[5] = crc16 >>8 & 0xff; - - HallSendBuffer( HallCmd, 6); -} - -void flysky_hall_stick_check_init() -{ - USART_InitTypeDef USART_InitStructure; - GPIO_InitTypeDef GPIO_InitStructure; - - GPIO_PinAFConfig(FLYSKY_HALL_SERIAL_GPIO, FLYSKY_HALL_SERIAL_RX_GPIO_PinSource, FLYSKY_HALL_SERIAL_GPIO_AF); - - GPIO_InitStructure.GPIO_Pin = FLYSKY_HALL_SERIAL_RX_GPIO_PIN; - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; - GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; - GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; - GPIO_Init(FLYSKY_HALL_SERIAL_GPIO, &GPIO_InitStructure); - - USART_InitStructure.USART_BaudRate = FLYSKY_HALL_BAUDRATE; - USART_InitStructure.USART_WordLength = USART_WordLength_8b; - USART_InitStructure.USART_StopBits = USART_StopBits_1; - USART_InitStructure.USART_Parity = USART_Parity_No; - USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; - USART_InitStructure.USART_Mode = USART_Mode_Rx; - USART_Init(FLYSKY_HALL_SERIAL_USART, &USART_InitStructure); - - DMA_Cmd(FLYSKY_HALL_DMA_Stream_RX, DISABLE); - USART_DMACmd(FLYSKY_HALL_SERIAL_USART, USART_DMAReq_Rx, DISABLE); - DMA_DeInit(FLYSKY_HALL_DMA_Stream_RX); - - DMA_InitTypeDef DMA_InitStructure; - hallDMAFifo.clear(); - - USART_ITConfig(FLYSKY_HALL_SERIAL_USART, USART_IT_RXNE, DISABLE); - - DMA_InitStructure.DMA_Channel = FLYSKY_HALL_DMA_Channel; - DMA_InitStructure.DMA_PeripheralBaseAddr = CONVERT_PTR_UINT(&FLYSKY_HALL_SERIAL_USART->DR); - DMA_InitStructure.DMA_Memory0BaseAddr = CONVERT_PTR_UINT(hallDMAFifo.buffer()); - DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; - DMA_InitStructure.DMA_BufferSize = hallDMAFifo.size(); - DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; - DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; - DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; - DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; - DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; - DMA_InitStructure.DMA_Priority = DMA_Priority_Low; - DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; - DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full; - DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; - DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; - DMA_Init(FLYSKY_HALL_DMA_Stream_RX, &DMA_InitStructure); - USART_DMACmd(FLYSKY_HALL_SERIAL_USART, USART_DMAReq_Rx, ENABLE); - USART_Cmd(FLYSKY_HALL_SERIAL_USART, ENABLE); - DMA_Cmd(FLYSKY_HALL_DMA_Stream_RX, ENABLE); -} - -void flysky_hall_stick_init() -{ - USART_DeInit(FLYSKY_HALL_SERIAL_USART); - - USART_InitTypeDef USART_InitStructure; - GPIO_InitTypeDef GPIO_InitStructure; - - GPIO_PinAFConfig(FLYSKY_HALL_SERIAL_GPIO, FLYSKY_HALL_SERIAL_RX_GPIO_PinSource, FLYSKY_HALL_SERIAL_GPIO_AF); - GPIO_PinAFConfig(FLYSKY_HALL_SERIAL_GPIO, FLYSKY_HALL_SERIAL_TX_GPIO_PinSource, FLYSKY_HALL_SERIAL_GPIO_AF); - - GPIO_InitStructure.GPIO_Pin = FLYSKY_HALL_SERIAL_TX_GPIO_PIN | FLYSKY_HALL_SERIAL_RX_GPIO_PIN; - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; - GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; - GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; - GPIO_Init(FLYSKY_HALL_SERIAL_GPIO, &GPIO_InitStructure); - - USART_InitStructure.USART_BaudRate = FLYSKY_HALL_BAUDRATE; - USART_InitStructure.USART_WordLength = USART_WordLength_8b; - USART_InitStructure.USART_StopBits = USART_StopBits_1; - USART_InitStructure.USART_Parity = USART_Parity_No; - USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; - USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; - USART_Init(FLYSKY_HALL_SERIAL_USART, &USART_InitStructure); - - DMA_Cmd(FLYSKY_HALL_DMA_Stream_RX, DISABLE); - USART_DMACmd(FLYSKY_HALL_SERIAL_USART, USART_DMAReq_Rx, DISABLE); - DMA_DeInit(FLYSKY_HALL_DMA_Stream_RX); - - DMA_InitTypeDef DMA_InitStructure; - hallDMAFifo.clear(); - - USART_ITConfig(FLYSKY_HALL_SERIAL_USART, USART_IT_RXNE, DISABLE); - USART_ITConfig(FLYSKY_HALL_SERIAL_USART, USART_IT_TXE, DISABLE); - - DMA_InitStructure.DMA_Channel = FLYSKY_HALL_DMA_Channel; - DMA_InitStructure.DMA_PeripheralBaseAddr = CONVERT_PTR_UINT(&FLYSKY_HALL_SERIAL_USART->DR); - DMA_InitStructure.DMA_Memory0BaseAddr = CONVERT_PTR_UINT(hallDMAFifo.buffer()); - DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; - DMA_InitStructure.DMA_BufferSize = hallDMAFifo.size(); - DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; - DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; - DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; - DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; - DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; - DMA_InitStructure.DMA_Priority = DMA_Priority_Low; - DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; - DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full; - DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; - DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; - DMA_Init(FLYSKY_HALL_DMA_Stream_RX, &DMA_InitStructure); - USART_DMACmd(FLYSKY_HALL_SERIAL_USART, USART_DMAReq_Rx, ENABLE); - USART_Cmd(FLYSKY_HALL_SERIAL_USART, ENABLE); - DMA_Cmd(FLYSKY_HALL_DMA_Stream_RX, ENABLE); - - reset_hall_stick(); -} - -static int parse_ps_state = 0; -void Parse_Character(STRUCT_HALL *hallBuffer, unsigned char ch) -{ - if (parse_ps_state != 0) return; - parse_ps_state = 1; - - switch (hallBuffer->status) { - case GET_START: { - if (FLYSKY_HALL_PROTOLO_HEAD == ch) { - hallBuffer->head = FLYSKY_HALL_PROTOLO_HEAD; - hallBuffer->status = GET_ID; - hallBuffer->msg_OK = 0; - } - break; - } - case GET_ID: { - hallBuffer->hallID.ID = ch; - hallBuffer->status = GET_LENGTH; - break; - } - case GET_LENGTH: { - hallBuffer->length = ch; - hallBuffer->dataIndex = 0; - hallBuffer->status = GET_DATA; - if (0 == hallBuffer->length) { - hallBuffer->status = GET_CHECKSUM; - hallBuffer->checkSum = 0; - } - break; - } - case GET_DATA: { - hallBuffer->data[hallBuffer->dataIndex++] = ch; - if (hallBuffer->dataIndex >= hallBuffer->length) { - hallBuffer->checkSum = 0; - hallBuffer->dataIndex = 0; - hallBuffer->status = GET_STATE; - } - break; - } - case GET_STATE: { - hallBuffer->checkSum = 0; - hallBuffer->dataIndex = 0; - hallBuffer->status = GET_CHECKSUM; - } - case GET_CHECKSUM: { - hallBuffer->checkSum |= ch << ((hallBuffer->dataIndex++) * 8); - if (hallBuffer->dataIndex >= 2) { - hallBuffer->dataIndex = 0; - hallBuffer->status = CHECKSUM; - } else { - break; - } - } - case CHECKSUM: { - if (hallBuffer->checkSum == - calc_crc16((void *)&hallBuffer->head, hallBuffer->length + 3)) { - hallBuffer->msg_OK = 1; - goto Label_restart; - } else { - goto Label_error; - } - } - } - - goto exit; - -Label_error: -Label_restart: - hallBuffer->status = GET_START; -exit: - parse_ps_state = 0; - return; -} - -/* Run it in 1ms timer routine */ -void flysky_hall_stick_loop(void) -{ - uint8_t byte; - - while(HallGetByte(&byte)) - { - HallProtocol.index++; - - Parse_Character(&HallProtocol, byte); - if ( HallProtocol.msg_OK ) - { - HallProtocol.msg_OK = 0; - HallProtocol.stickState = HallProtocol.data[HallProtocol.length - 1]; - - switch ( HallProtocol.hallID.hall_Id.receiverID ) - { - case TRANSFER_DIR_TXMCU: - if(HallProtocol.hallID.hall_Id.packetID == FLYSKY_HALL_RESP_TYPE_VALUES) { - memcpy(hall_raw_values, HallProtocol.data, sizeof(hall_raw_values)); - for ( uint8_t channel = 0; channel < 4; channel++ ) - { - hall_adc_values[channel] = FLYSKY_OFFSET_VALUE + hall_raw_values[channel]; - } - } - break; - } - globalData.flyskygimbals = true; - } - } -} diff --git a/radio/src/targets/horus/hal.h b/radio/src/targets/horus/hal.h index 53da9c859..95be0e9a5 100644 --- a/radio/src/targets/horus/hal.h +++ b/radio/src/targets/horus/hal.h @@ -387,10 +387,8 @@ #define SPORT_UPDATE_RCC_AHB1Periph RCC_AHB1Periph_GPIOH #define SPORT_UPDATE_PWR_GPIO GPIOH #define SPORT_UPDATE_PWR_GPIO_PIN GPIO_Pin_13 // PH.13 - #define HAS_SPORT_UPDATE_CONNECTOR() true #else #define SPORT_UPDATE_RCC_AHB1Periph 0 - #define HAS_SPORT_UPDATE_CONNECTOR() false #endif // PCBREV @@ -465,7 +463,7 @@ #define AUX2_SERIAL_GPIO_RX_PinSource GPIO_PinSource1 #define AUX2_SERIAL_DMA_RX DMA1 #define AUX2_SERIAL_DMA_Stream_RX DMA1_Stream2 - #define AUX2_SERIAL_DMA_Channel_RX DMA_Channel_4 + #define AUX2_SERIAL_DMA_Channel_RX LL_DMA_CHANNEL_4 #define AUX2_SERIAL_DMA_Stream_RX_LL LL_DMA_STREAM_2 #else #define AUX2_SERIAL_RCC_AHB1Periph (RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOG | RCC_AHB1Periph_DMA2) @@ -481,7 +479,7 @@ #define AUX2_SERIAL_GPIO_PinSource_RX GPIO_PinSource9 #define AUX2_SERIAL_DMA_RX DMA2 #define AUX2_SERIAL_DMA_Stream_RX DMA2_Stream1 // or DMA2_Stream2 - #define AUX2_SERIAL_DMA_Channel_RX DMA_Channel_5 + #define AUX2_SERIAL_DMA_Channel_RX LL_DMA_CHANNEL_5 #define AUX2_SERIAL_DMA_Stream_RX_LL LL_DMA_STREAM_1 #define AUX2_SERIAL_PWR_GPIO GPIOB #define AUX2_SERIAL_PWR_GPIO_PIN GPIO_Pin_0 // PB.00 @@ -496,6 +494,7 @@ #define TELEMETRY_RCC_APB2Periph RCC_APB2Periph_TIM11 #define TELEMETRY_DIR_GPIO GPIOD #define TELEMETRY_DIR_GPIO_PIN GPIO_Pin_4 // PD.04 +#define TELEMETRY_SET_INPUT 0 #define TELEMETRY_GPIO GPIOD #define TELEMETRY_TX_GPIO_PIN GPIO_Pin_5 // PD.05 #define TELEMETRY_RX_GPIO_PIN GPIO_Pin_6 // PD.06 @@ -503,12 +502,13 @@ #define TELEMETRY_GPIO_PinSource_RX GPIO_PinSource6 #define TELEMETRY_GPIO_AF GPIO_AF_USART2 #define TELEMETRY_USART USART2 +#define TELEMETRY_DMA DMA1 #if defined(PCBX12S) - #define TELEMETRY_DMA_Stream_RX DMA1_Stream5 - #define TELEMETRY_DMA_Channel_RX DMA_Channel_4 + #define TELEMETRY_DMA_Stream_RX LL_DMA_STREAM_5 + #define TELEMETRY_DMA_Channel_RX LL_DMA_CHANNEL_4 #endif -#define TELEMETRY_DMA_Stream_TX DMA1_Stream6 -#define TELEMETRY_DMA_Channel_TX DMA_Channel_4 +#define TELEMETRY_DMA_Stream_TX LL_DMA_STREAM_6 +#define TELEMETRY_DMA_Channel_TX LL_DMA_CHANNEL_4 #define TELEMETRY_DMA_TX_Stream_IRQ DMA1_Stream6_IRQn #define TELEMETRY_DMA_TX_IRQHandler DMA1_Stream6_IRQHandler #define TELEMETRY_DMA_TX_FLAG_TC DMA_IT_TCIF6 @@ -792,26 +792,20 @@ // FlySky Hall Sticks #define FLYSKY_HALL_SERIAL_USART UART4 #define FLYSKY_HALL_SERIAL_GPIO GPIOA - #define FLYSKY_HALL_DMA_Channel DMA_Channel_4 - #define FLYSKY_HALL_SERIAL_TX_GPIO_PIN GPIO_Pin_0 // PA.00 - #define FLYSKY_HALL_SERIAL_RX_GPIO_PIN GPIO_Pin_1 // PA.01 - #define FLYSKY_HALL_SERIAL_TX_GPIO_PinSource GPIO_PinSource0 - #define FLYSKY_HALL_SERIAL_RX_GPIO_PinSource GPIO_PinSource1 - #define FLYSKY_HALL_SERIAL_GPIO_AF GPIO_AF_UART4 + #define FLYSKY_HALL_DMA_Channel LL_DMA_CHANNEL_4 + #define FLYSKY_HALL_SERIAL_TX_GPIO_PIN LL_GPIO_PIN_0 // PA.00 + #define FLYSKY_HALL_SERIAL_RX_GPIO_PIN LL_GPIO_PIN_1 // PA.01 + #define FLYSKY_HALL_SERIAL_GPIO_AF LL_GPIO_AF_8 #define FLYSKY_HALL_RCC_AHB1Periph RCC_AHB1Periph_DMA1 #define FLYSKY_HALL_RCC_APB1Periph RCC_APB1Periph_UART4 #define FLYSKY_HALL_SERIAL_USART_IRQHandler UART4_IRQHandler #define FLYSKY_HALL_SERIAL_USART_IRQn UART4_IRQn - #define FLYSKY_HALL_SERIAL_RX_DMA_Stream_IRQn DMA1_Stream2_IRQn - #define FLYSKY_HALL_SERIAL_TX_DMA_Stream_IRQn DMA1_Stream4_IRQn - #define FLYSKY_HALL_DMA_Stream_RX DMA1_Stream2 - #define FLYSKY_HALL_DMA_Stream_TX DMA1_Stream4 - #define FLYSKY_HALL_DMA_TX_FLAG_TC DMA_IT_TCIF4 + #define FLYSKY_HALL_SERIAL_DMA DMA1 + #define FLYSKY_HALL_DMA_Stream_RX LL_DMA_STREAM_2 + #define FLYSKY_HALL_DMA_Stream_TX LL_DMA_STREAM_4 - #define FLYSKY_HALL_RX_DMA_Stream_IRQHandler DMA1_Stream2_IRQHandler - #define FLYSKY_HALL_TX_DMA_Stream_IRQHandler DMA1_Stream4_IRQHandler #endif // Internal PXX1 Module: @@ -844,7 +838,8 @@ #define INTMODULE_BOOTCMD_GPIO GPIOI #define INTMODULE_BOOTCMD_GPIO_PIN GPIO_Pin_9 // PI.09 #endif -#define INIT_INTMODULE_BOOTCMD_PIN() GPIO_ResetBits(INTMODULE_BOOTCMD_GPIO, INTMODULE_BOOTCMD_GPIO_PIN); +#define INTMODULE_BOOTCMD_DEFAULT 0 // RESET +#define INIT_INTMODULE_BOOTCMD_PIN() GPIO_ResetBits(INTMODULE_BOOTCMD_GPIO, INTMODULE_BOOTCMD_GPIO_PIN); // External Module #define EXTMODULE_PWR_GPIO GPIOB @@ -1000,13 +995,11 @@ #if defined(BLUETOOTH) #define BT_RCC_APB2Periph RCC_APB2Periph_USART6 #define BT_USART USART6 -#define BT_GPIO_AF GPIO_AF_USART6 +#define BT_GPIO_AF LL_GPIO_AF_8 #define BT_USART_IRQn USART6_IRQn #define BT_USART_GPIO GPIOG -#define BT_TX_GPIO_PIN GPIO_Pin_14 // PG.14 -#define BT_RX_GPIO_PIN GPIO_Pin_9 // PG.09 -#define BT_TX_GPIO_PinSource GPIO_PinSource14 -#define BT_RX_GPIO_PinSource GPIO_PinSource9 +#define BT_TX_GPIO_PIN LL_GPIO_PIN_14 // PG.14 +#define BT_RX_GPIO_PIN LL_GPIO_PIN_9 // PG.09 #define BT_USART_IRQHandler USART6_IRQHandler #else #define BT_RCC_APB2Periph 0 @@ -1015,20 +1008,20 @@ #if PCBREV >= 13 #define BT_RCC_AHB1Periph (RCC_AHB1Periph_GPIOI | RCC_AHB1Periph_GPIOG) #define BT_EN_GPIO GPIOI - #define BT_EN_GPIO_PIN GPIO_Pin_10 // PI.10 + #define BT_EN_GPIO_PIN LL_GPIO_PIN_10 // PI.10 #else #define BT_RCC_AHB1Periph (RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOG) #define BT_EN_GPIO GPIOA - #define BT_EN_GPIO_PIN GPIO_Pin_6 // PA.06 + #define BT_EN_GPIO_PIN LL_GPIO_PIN_6 // PA.06 #endif - #define BT_BRTS_GPIO GPIOG - #define BT_BRTS_GPIO_PIN GPIO_Pin_10 // PG.10 - #define BT_BCTS_GPIO GPIOG - #define BT_BCTS_GPIO_PIN GPIO_Pin_11 // PG.11 + // #define BT_BRTS_GPIO GPIOG + // #define BT_BRTS_GPIO_PIN GPIO_Pin_10 // PG.10 + // #define BT_BCTS_GPIO GPIOG + // #define BT_BCTS_GPIO_PIN GPIO_Pin_11 // PG.11 #elif defined(PCBX10) #define BT_RCC_AHB1Periph RCC_AHB1Periph_GPIOG #define BT_EN_GPIO GPIOG - #define BT_EN_GPIO_PIN GPIO_Pin_10 // PG.10 + #define BT_EN_GPIO_PIN LL_GPIO_PIN_10 // PG.10 #endif #endif // _HAL_H_ diff --git a/radio/src/targets/horus/telemetry_driver.cpp b/radio/src/targets/horus/telemetry_driver.cpp deleted file mode 100644 index 24eacc792..000000000 --- a/radio/src/targets/horus/telemetry_driver.cpp +++ /dev/null @@ -1,434 +0,0 @@ -/* - * Copyright (C) EdgeTX - * - * Based on code named - * opentx - https://github.com/opentx/opentx - * th9x - http://code.google.com/p/th9x - * er9x - http://code.google.com/p/er9x - * gruvin9x - http://code.google.com/p/gruvin9x - * - * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "stm32_hal_ll.h" -#include "stm32_exti_driver.h" -#include "aux_serial_driver.h" - -#include "opentx.h" - -#if defined(GHOST) - #include "telemetry/ghost.h" -#endif - -Fifo telemetryNoDMAFifo; -uint32_t telemetryErrors = 0; - -#if defined(PCBX12S) -#include "dmafifo.h" - -DMAFifo telemetryDMAFifo __DMA (TELEMETRY_DMA_Stream_RX); -uint8_t telemetryFifoMode; -#endif - -static void telemetryInitDirPin() -{ - GPIO_InitTypeDef GPIO_InitStructure; - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; - GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; - GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; - GPIO_InitStructure.GPIO_Pin = TELEMETRY_DIR_GPIO_PIN; - GPIO_Init(TELEMETRY_DIR_GPIO, &GPIO_InitStructure); - GPIO_ResetBits(TELEMETRY_DIR_GPIO, TELEMETRY_DIR_GPIO_PIN); -} - -void telemetryPortInit(uint32_t baudrate, uint8_t mode) -{ - if (baudrate == 0) { - USART_DeInit(TELEMETRY_USART); - return; - } - //deinit inverted mode - telemetryPortInvertedInit(0); - NVIC_InitTypeDef NVIC_InitStructure; - NVIC_InitStructure.NVIC_IRQChannel = TELEMETRY_DMA_TX_Stream_IRQ; - NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; - NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; /* Not used as 4 bits are used for the pre-emption priority. */; - NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; - NVIC_Init(&NVIC_InitStructure); - - USART_InitTypeDef USART_InitStructure; - GPIO_InitTypeDef GPIO_InitStructure; - - GPIO_PinAFConfig(TELEMETRY_GPIO, TELEMETRY_GPIO_PinSource_RX, TELEMETRY_GPIO_AF); - GPIO_PinAFConfig(TELEMETRY_GPIO, TELEMETRY_GPIO_PinSource_TX, TELEMETRY_GPIO_AF); - - GPIO_InitStructure.GPIO_Pin = TELEMETRY_TX_GPIO_PIN | TELEMETRY_RX_GPIO_PIN; - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; - GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; - GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; - GPIO_InitStructure.GPIO_Speed = baudrate <= 400000 ? GPIO_Speed_2MHz : GPIO_Speed_25MHz; - GPIO_Init(TELEMETRY_GPIO, &GPIO_InitStructure); - - telemetryInitDirPin(); - - USART_DeInit(TELEMETRY_USART); - - USART_OverSampling8Cmd(TELEMETRY_USART, baudrate <= 400000 ? DISABLE : ENABLE); - - USART_InitStructure.USART_BaudRate = baudrate; - if (mode & TELEMETRY_SERIAL_8E2) { - USART_InitStructure.USART_WordLength = USART_WordLength_9b; - USART_InitStructure.USART_StopBits = USART_StopBits_2; - USART_InitStructure.USART_Parity = USART_Parity_Even; - } - else { - USART_InitStructure.USART_WordLength = USART_WordLength_8b; - USART_InitStructure.USART_StopBits = USART_StopBits_1; - USART_InitStructure.USART_Parity = USART_Parity_No; - } - USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; - USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; - if (g_eeGeneral.uartSampleMode == UART_SAMPLE_MODE_ONEBIT) { - USART_OneBitMethodCmd(TELEMETRY_USART, ENABLE); - } - USART_Init(TELEMETRY_USART, &USART_InitStructure); - -#if defined(PCBX12S) - telemetryFifoMode = mode; - - DMA_Cmd(TELEMETRY_DMA_Stream_RX, DISABLE); - USART_DMACmd(TELEMETRY_USART, USART_DMAReq_Rx, DISABLE); - DMA_DeInit(TELEMETRY_DMA_Stream_RX); - - if (mode & TELEMETRY_SERIAL_WITHOUT_DMA) { - USART_Cmd(TELEMETRY_USART, ENABLE); - USART_ITConfig(TELEMETRY_USART, USART_IT_RXNE, ENABLE); - NVIC_SetPriority(TELEMETRY_USART_IRQn, 6); - NVIC_EnableIRQ(TELEMETRY_USART_IRQn); - } - else { - DMA_InitTypeDef DMA_InitStructure; - telemetryDMAFifo.clear(); - - USART_ITConfig(TELEMETRY_USART, USART_IT_RXNE, DISABLE); - USART_ITConfig(TELEMETRY_USART, USART_IT_TXE, DISABLE); - NVIC_SetPriority(TELEMETRY_USART_IRQn, 6); - NVIC_EnableIRQ(TELEMETRY_USART_IRQn); - - DMA_InitStructure.DMA_Channel = TELEMETRY_DMA_Channel_RX; - DMA_InitStructure.DMA_PeripheralBaseAddr = CONVERT_PTR_UINT(&TELEMETRY_USART->DR); - DMA_InitStructure.DMA_Memory0BaseAddr = CONVERT_PTR_UINT(telemetryDMAFifo.buffer()); - DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; - DMA_InitStructure.DMA_BufferSize = telemetryDMAFifo.size(); - DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; - DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; - DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; - DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; - DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; - DMA_InitStructure.DMA_Priority = DMA_Priority_Low; - DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; - DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full; - DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; - DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; - DMA_Init(TELEMETRY_DMA_Stream_RX, &DMA_InitStructure); - USART_DMACmd(TELEMETRY_USART, USART_DMAReq_Rx, ENABLE); - USART_Cmd(TELEMETRY_USART, ENABLE); - DMA_Cmd(TELEMETRY_DMA_Stream_RX, ENABLE); - } -#else - USART_Cmd(TELEMETRY_USART, ENABLE); - USART_ITConfig(TELEMETRY_USART, USART_IT_RXNE, ENABLE); - NVIC_SetPriority(TELEMETRY_USART_IRQn, 6); - NVIC_EnableIRQ(TELEMETRY_USART_IRQn); -#endif -} - -// soft serial vars -static uint8_t rxBitCount; -static uint8_t rxByte; -// single bit length expresses in half us -static uint16_t bitLength; -static uint16_t probeTimeFromStartBit; - -static void do_telemetry_exti() -{ - if (rxBitCount == 0) { - - TELEMETRY_TIMER->ARR = probeTimeFromStartBit; // 1,5 cycle from start at 57600bps - TELEMETRY_TIMER->CR1 |= TIM_CR1_CEN; - - // disable start bit interrupt - EXTI->IMR &= ~EXTI_IMR_MR6; - } -} - -void telemetryPortInvertedInit(uint32_t baudrate) -{ - if (baudrate == 0) { - - stm32_exti_disable(TELEMETRY_EXTI_LINE); - NVIC_DisableIRQ(TELEMETRY_TIMER_IRQn); - return; - } - - rxBitCount = 0; - - switch(baudrate) { - case 115200: - bitLength = 17; - probeTimeFromStartBit = 23; //because pin is not probed immediately - break; - case 57600: - bitLength = 35; //34 was used before - I prefer to use use 35 because of lower error - probeTimeFromStartBit = 48; // 48 used in original implementation - break; - default: - bitLength = 2000000/baudrate; //because of 0,5 us tick - probeTimeFromStartBit = 3000000/baudrate; - } - -#if defined(PCBX12S) - telemetryFifoMode = TELEMETRY_SERIAL_WITHOUT_DMA; -#endif - - // configure bit sample timer - TELEMETRY_TIMER->PSC = (PERI2_FREQUENCY * TIMER_MULT_APB2) / 2000000 - 1; // 0.5uS - TELEMETRY_TIMER->CCER = 0; - TELEMETRY_TIMER->CCMR1 = 0; - TELEMETRY_TIMER->CR1 = TIM_CR1_CEN; - TELEMETRY_TIMER->DIER = TIM_DIER_UIE; - - NVIC_SetPriority(TELEMETRY_TIMER_IRQn, 0); - NVIC_EnableIRQ(TELEMETRY_TIMER_IRQn); - - // init TELEMETRY_RX_GPIO_PIN - GPIO_InitTypeDef GPIO_InitStructure; - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; - GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; - GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN; - GPIO_InitStructure.GPIO_Pin = TELEMETRY_RX_GPIO_PIN; - GPIO_Init(TELEMETRY_GPIO, &GPIO_InitStructure); - - telemetryInitDirPin(); - - // Connect EXTI line to TELEMETRY RX pin - LL_SYSCFG_SetEXTISource(TELEMETRY_EXTI_PORT, TELEMETRY_EXTI_SYS_LINE); - - // Configure EXTI for raising edge (start bit) - stm32_exti_enable(TELEMETRY_EXTI_LINE, TELEMETRY_EXTI_TRIGGER, do_telemetry_exti); -} - -void telemetryPortInvertedRxBit() -{ - if (rxBitCount < 8) { - if (rxBitCount == 0) { - TELEMETRY_TIMER->ARR = bitLength; - rxByte = 0; - } - else { - rxByte >>= 1; - } - - if (GPIO_ReadInputDataBit(TELEMETRY_GPIO, TELEMETRY_RX_GPIO_PIN) == Bit_RESET) - rxByte |= 0x80; - - ++rxBitCount; - } - else if (rxBitCount == 8) { - telemetryNoDMAFifo.push(rxByte); - rxBitCount = 0; - - // disable timer - TELEMETRY_TIMER->CR1 &= ~TIM_CR1_CEN; - - // re-enable start bit interrupt - EXTI->IMR |= EXTI_IMR_MR6; - } -} - -void telemetryPortSetDirectionOutput() -{ -#if defined(GHOST) && SPORT_MAX_BAUDRATE < 400000 - if (isModuleGhost(EXTERNAL_MODULE)) { - TELEMETRY_USART->BRR = BRR_400K; - } -#endif - GPIO_SetBits(TELEMETRY_DIR_GPIO, TELEMETRY_DIR_GPIO_PIN); - TELEMETRY_USART->CR1 &= ~USART_CR1_RE; // turn off receiver -} - -void sportWaitTransmissionComplete() -{ - while (!(TELEMETRY_USART->SR & USART_SR_TC)); -} - -void telemetryPortSetDirectionInput() -{ - sportWaitTransmissionComplete(); -#if defined(GHOST) && SPORT_MAX_BAUDRATE < 400000 - if (isModuleGhost(EXTERNAL_MODULE) && g_model.moduleData[EXTERNAL_MODULE].ghost.telemetryBaudrate == GHST_TELEMETRY_RATE_115K) { - TELEMETRY_USART->BRR = BRR_115K; - } -#endif - GPIO_ResetBits(TELEMETRY_DIR_GPIO, TELEMETRY_DIR_GPIO_PIN); - TELEMETRY_USART->CR1 |= USART_CR1_RE; // turn on receiver -} - -void sportSendByte(uint8_t byte) -{ - telemetryPortSetDirectionOutput(); - - while (!(TELEMETRY_USART->SR & USART_SR_TXE)); - USART_SendData(TELEMETRY_USART, byte); -} - -void sportSendByteLoop(uint8_t byte) -{ - telemetryPortSetDirectionOutput(); - - outputTelemetryBuffer.data[0] = byte; - - DMA_InitTypeDef DMA_InitStructure; - DMA_DeInit(TELEMETRY_DMA_Stream_TX); - DMA_InitStructure.DMA_Channel = TELEMETRY_DMA_Channel_TX; - DMA_InitStructure.DMA_PeripheralBaseAddr = CONVERT_PTR_UINT(&TELEMETRY_USART->DR); - DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; - DMA_InitStructure.DMA_Memory0BaseAddr = CONVERT_PTR_UINT(outputTelemetryBuffer.data); - DMA_InitStructure.DMA_BufferSize = 1; - DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; - DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable; - DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; - DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; - DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; - DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; - DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; - DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full; - DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; - DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; - DMA_Init(TELEMETRY_DMA_Stream_TX, &DMA_InitStructure); - DMA_Cmd(TELEMETRY_DMA_Stream_TX, ENABLE); - USART_DMACmd(TELEMETRY_USART, USART_DMAReq_Tx, ENABLE); -} - -void sportSendBuffer(const uint8_t * buffer, uint32_t count) -{ - telemetryPortSetDirectionOutput(); - - DMA_InitTypeDef DMA_InitStructure; - DMA_DeInit(TELEMETRY_DMA_Stream_TX); - DMA_InitStructure.DMA_Channel = TELEMETRY_DMA_Channel_TX; - DMA_InitStructure.DMA_PeripheralBaseAddr = CONVERT_PTR_UINT(&TELEMETRY_USART->DR); - DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; - DMA_InitStructure.DMA_Memory0BaseAddr = CONVERT_PTR_UINT(buffer); - DMA_InitStructure.DMA_BufferSize = count; - DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; - DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; - DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; - DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; - DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; - DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; - DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; - DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full; - DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; - DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; - DMA_Init(TELEMETRY_DMA_Stream_TX, &DMA_InitStructure); - DMA_Cmd(TELEMETRY_DMA_Stream_TX, ENABLE); - USART_DMACmd(TELEMETRY_USART, USART_DMAReq_Tx, ENABLE); - DMA_ITConfig(TELEMETRY_DMA_Stream_TX, DMA_IT_TC, ENABLE); - - // enable interrupt and set it's priority - NVIC_EnableIRQ(TELEMETRY_DMA_TX_Stream_IRQ) ; - NVIC_SetPriority(TELEMETRY_DMA_TX_Stream_IRQ, 7); -} - -extern "C" void TELEMETRY_DMA_TX_IRQHandler(void) -{ - DEBUG_INTERRUPT(INT_TELEM_DMA); - if (DMA_GetITStatus(TELEMETRY_DMA_Stream_TX, TELEMETRY_DMA_TX_FLAG_TC)) { - DMA_ClearITPendingBit(TELEMETRY_DMA_Stream_TX, TELEMETRY_DMA_TX_FLAG_TC); - - // clear TC flag before enabling interrupt - TELEMETRY_USART->SR &= ~USART_SR_TC; - TELEMETRY_USART->CR1 |= USART_CR1_TCIE; - - if (telemetryProtocol == PROTOCOL_TELEMETRY_FRSKY_SPORT) { - outputTelemetryBuffer.reset(); - } - } -} - -#define USART_FLAG_ERRORS (USART_FLAG_ORE | USART_FLAG_NE | USART_FLAG_FE | USART_FLAG_PE) -extern "C" void TELEMETRY_USART_IRQHandler(void) -{ - DEBUG_INTERRUPT(INT_TELEM_USART); - uint32_t status = TELEMETRY_USART->SR; - - if ((status & USART_SR_TC) && (TELEMETRY_USART->CR1 & USART_CR1_TCIE)) { - TELEMETRY_USART->CR1 &= ~USART_CR1_TCIE; - telemetryPortSetDirectionInput(); - while (status & (USART_FLAG_RXNE)) { - status = TELEMETRY_USART->DR; - status = TELEMETRY_USART->SR; - } - } - - while (status & (USART_FLAG_RXNE | USART_FLAG_ERRORS)) { - uint8_t data = TELEMETRY_USART->DR; - if (status & USART_FLAG_ERRORS) { - telemetryErrors++; - } - else { - telemetryNoDMAFifo.push(data); -#if defined(LUA) - if (telemetryProtocol == PROTOCOL_TELEMETRY_FRSKY_SPORT) { - static uint8_t prevdata; - if (prevdata == 0x7E && outputTelemetryBuffer.size > 0 && outputTelemetryBuffer.destination == TELEMETRY_ENDPOINT_SPORT && data == outputTelemetryBuffer.sport.physicalId) { - sportSendBuffer(outputTelemetryBuffer.data + 1, outputTelemetryBuffer.size - 1); - } - prevdata = data; - } -#endif - } - status = TELEMETRY_USART->SR; - } -} - -extern "C" void TELEMETRY_TIMER_IRQHandler() -{ - TELEMETRY_TIMER->SR &= ~TIM_SR_UIF; - telemetryPortInvertedRxBit(); -} - -// TODO we should have telemetry in an higher layer, functions above should move to a sport_driver.cpp -bool sportGetByte(uint8_t * byte) -{ -#if defined(PCBX12S) - if (telemetryFifoMode & TELEMETRY_SERIAL_WITHOUT_DMA) - return telemetryNoDMAFifo.pop(*byte); - else - return telemetryDMAFifo.pop(*byte); -#else - return telemetryNoDMAFifo.pop(*byte); -#endif -} - -void telemetryClearFifo() -{ -#if defined(PCBX12S) - telemetryDMAFifo.clear(); -#endif - - telemetryNoDMAFifo.clear(); -} - diff --git a/radio/src/targets/nv14/CMakeLists.txt b/radio/src/targets/nv14/CMakeLists.txt index 1074b7989..ac1190d72 100644 --- a/radio/src/targets/nv14/CMakeLists.txt +++ b/radio/src/targets/nv14/CMakeLists.txt @@ -138,24 +138,23 @@ set(FIRMWARE_TARGET_SRC battery_driver.cpp audio_spi_driver.cpp backlight_driver.cpp - extmodule_helper.cpp - ../horus/flyskyHallStick_driver.cpp ) set(FIRMWARE_SRC ${FIRMWARE_SRC} hal/adc_driver.cpp + boards/generic_stm32/module_ports.cpp + boards/generic_stm32/aux_ports.cpp targets/common/arm/stm32/stm32_hal_adc.cpp targets/common/arm/stm32/timers_driver.cpp targets/common/arm/stm32/mixer_scheduler_driver.cpp targets/common/arm/stm32/extmodule_driver.cpp targets/common/arm/stm32/stm32_pulse_driver.cpp - targets/common/arm/stm32/extmodule_serial_driver.cpp - targets/common/arm/stm32/intmodule_serial_driver.cpp targets/common/arm/stm32/stm32_usart_driver.cpp targets/common/arm/stm32/trainer_driver.cpp targets/common/arm/stm32/pwr_driver.cpp targets/common/arm/stm32/sdio_sd.c + targets/common/arm/stm32/flysky_gimbal_driver.cpp ) # Make malloc() thread-safe diff --git a/radio/src/targets/nv14/board.cpp b/radio/src/targets/nv14/board.cpp index 004da2815..c612094ae 100644 --- a/radio/src/targets/nv14/board.cpp +++ b/radio/src/targets/nv14/board.cpp @@ -20,14 +20,18 @@ */ #include "board.h" +#include "boards/generic_stm32/module_ports.h" + +#include "hal/adc_driver.h" +#include "hal/trainer_driver.h" + #include "globals.h" #include "sdcard.h" #include "touch.h" #include "debug.h" -#include "hal/adc_driver.h" -#include "hal/trainer_driver.h" #include "stm32_hal_adc.h" +#include "flysky_gimbal_driver.h" #include "timers_driver.h" #include "bitmapbuffer.h" @@ -44,8 +48,6 @@ extern "C" { } #endif -extern void flysky_hall_stick_init( void ); - HardwareOptions hardwareOptions; void watchdogInit(unsigned int duration) @@ -169,18 +171,21 @@ void boardInit() serialInit(SP_AUX1, UART_MODE_DEBUG); #endif - TRACE("\nNV14 board started :)"); + TRACE("\n%s board started :)", + hardwareOptions.pcbrev == PCBREV_NV14 ? + "NV14" : "EL18"); + delay_ms(10); TRACE("RCC->CSR = %08x", RCC->CSR); pwrInit(); + boardInitModulePorts(); + init_trainer(); - extModuleInit(); battery_charge_init(); - globalData.flyskygimbals = true; - flysky_hall_stick_init(); + globalData.flyskygimbals = flysky_gimbal_init(); init2MhzTimer(); - init1msTimer(); + init5msTimer(); TouchInit(); usbInit(); @@ -304,8 +309,3 @@ void boardOff() } } - -const etx_serial_port_t* auxSerialGetPort(int port_nr) -{ - return nullptr; -} diff --git a/radio/src/targets/nv14/board.h b/radio/src/targets/nv14/board.h index 26ec38dab..19c7736e5 100644 --- a/radio/src/targets/nv14/board.h +++ b/radio/src/targets/nv14/board.h @@ -127,18 +127,8 @@ extern HardwareOptions hardwareOptions; GPIO_SetBits(INTMODULE_PWR_GPIO, INTMODULE_PWR_GPIO_PIN); \ } while (0) -#define IS_INTERNAL_MODULE_ON() \ - (hardwareOptions.pcbrev == PCBREV_NV14 \ - ? (GPIO_ReadInputDataBit(INTMODULE_PWR_GPIO, INTMODULE_PWR_GPIO_PIN) == \ - Bit_SET) \ - : (GPIO_ReadInputDataBit(INTMODULE_PWR_GPIO, INTMODULE_PWR_GPIO_PIN) == \ - Bit_RESET)) - -#define IS_EXTERNAL_MODULE_ON() \ - (GPIO_ReadInputDataBit(EXTMODULE_PWR_GPIO, EXTMODULE_PWR_GPIO_PIN) == Bit_SET) - -void EXTERNAL_MODULE_ON(); -void EXTERNAL_MODULE_OFF(); +#define EXTERNAL_MODULE_ON() GPIO_SetBits(EXTMODULE_PWR_GPIO, EXTMODULE_PWR_GPIO_PIN) +#define EXTERNAL_MODULE_OFF() GPIO_ResetBits(EXTMODULE_PWR_GPIO, EXTMODULE_PWR_GPIO_PIN) #define BLUETOOTH_MODULE_ON() GPIO_ResetBits(BLUETOOTH_ON_GPIO, BLUETOOTH_ON_GPIO_PIN) #define BLUETOOTH_MODULE_OFF() GPIO_SetBits(BLUETOOTH_ON_GPIO, BLUETOOTH_ON_GPIO_PIN) @@ -511,24 +501,7 @@ int32_t getVolume(); // Telemetry driver #define INTMODULE_FIFO_SIZE 512 -#define TELEMETRY_FIFO_SIZE 512 -void telemetryPortInit(uint32_t baudrate, uint8_t mode); -void telemetryPortSetDirectionOutput(); -void telemetryPortSetDirectionInput(); -void sportSendBuffer(const uint8_t * buffer, uint32_t count); -bool sportGetByte(uint8_t * byte); -void telemetryClearFifo(); -void sportSendByte(uint8_t byte); -extern uint32_t telemetryErrors; - -// soft-serial -void telemetryPortInvertedInit(uint32_t baudrate); - -// Sport update driver -#define SPORT_UPDATE_POWER_ON() -#define SPORT_UPDATE_POWER_OFF() -#define SPORT_UPDATE_POWER_INIT() -#define IS_SPORT_UPDATE_POWER_ON() (false) +#define TELEMETRY_FIFO_SIZE 512 // Haptic driver void hapticInit(); diff --git a/radio/src/targets/nv14/extmodule_helper.cpp b/radio/src/targets/nv14/extmodule_helper.cpp deleted file mode 100644 index 18a386d01..000000000 --- a/radio/src/targets/nv14/extmodule_helper.cpp +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) EdgeTX - * - * Based on code named - * opentx - https://github.com/opentx/opentx - * th9x - http://code.google.com/p/th9x - * er9x - http://code.google.com/p/er9x - * gruvin9x - http://code.google.com/p/gruvin9x - * - * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "board.h" - -void EXTERNAL_MODULE_ON() -{ - GPIO_SetBits(EXTMODULE_PWR_GPIO, EXTMODULE_PWR_GPIO_PIN); - - if (hardwareOptions.pcbrev == PCBREV_NV14) { - GPIO_ResetBits(EXTMODULE_PWR_FIX_GPIO, EXTMODULE_PWR_FIX_GPIO_PIN); - } -} - -void EXTERNAL_MODULE_OFF() -{ - GPIO_ResetBits(EXTMODULE_PWR_GPIO, EXTMODULE_PWR_GPIO_PIN); - - if (hardwareOptions.pcbrev == PCBREV_NV14) { - GPIO_SetBits(EXTMODULE_PWR_FIX_GPIO, EXTMODULE_PWR_FIX_GPIO_PIN); - } -} - -void extModuleInit() -{ - GPIO_InitTypeDef GPIO_InitStructure; - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; - GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; - - if (hardwareOptions.pcbrev == PCBREV_NV14) { - GPIO_InitStructure.GPIO_Pin = EXTMODULE_PWR_FIX_GPIO_PIN; - // pin must be pulled to V+ (voltage of board - VCC is not enough to fully close transistor) - // for additional transistor to ensuring module is completely disabled - GPIO_InitStructure.GPIO_OType = GPIO_OType_OD; - GPIO_SetBits(EXTMODULE_PWR_FIX_GPIO, EXTMODULE_PWR_FIX_GPIO_PIN); - GPIO_Init(EXTMODULE_PWR_FIX_GPIO, &GPIO_InitStructure); - } - - GPIO_InitStructure.GPIO_Pin = EXTMODULE_TX_INVERT_GPIO_PIN; - // Use push pull for inverter output to ensure the output not floating - GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; - GPIO_Init(EXTMODULE_TX_INVERT_GPIO, &GPIO_InitStructure); - - GPIO_InitStructure.GPIO_Pin = EXTMODULE_RX_INVERT_GPIO_PIN; - GPIO_Init(EXTMODULE_RX_INVERT_GPIO, &GPIO_InitStructure); - - EXTMODULE_TX_INVERTED(); - EXTMODULE_RX_INVERTED(); -} diff --git a/radio/src/targets/nv14/hal.h b/radio/src/targets/nv14/hal.h index d57d5b0f0..6d20d7eab 100644 --- a/radio/src/targets/nv14/hal.h +++ b/radio/src/targets/nv14/hal.h @@ -171,7 +171,6 @@ // S.Port update connector #define SPORT_MAX_BAUDRATE 400000 #define SPORT_UPDATE_RCC_AHB1Periph 0 -#define HAS_SPORT_UPDATE_CONNECTOR() (false) // Led // #define STATUS_LEDS @@ -212,6 +211,7 @@ #define TELEMETRY_TX_REV_GPIO_PIN GPIO_Pin_7 // PJ.07 #define TELEMETRY_DIR_GPIO GPIOJ #define TELEMETRY_DIR_GPIO_PIN GPIO_Pin_13 // PJ.13 +#define TELEMETRY_SET_INPUT 1 #define TELEMETRY_GPIO GPIOD #define TELEMETRY_TX_GPIO_PIN GPIO_Pin_5 // PD.05 #define TELEMETRY_RX_GPIO_PIN GPIO_Pin_6 // PD.06 @@ -219,11 +219,14 @@ #define TELEMETRY_GPIO_PinSource_RX GPIO_PinSource6 #define TELEMETRY_GPIO_AF GPIO_AF_USART2 #define TELEMETRY_USART USART2 -#define TELEMETRY_DMA_Stream_TX DMA1_Stream6 +#define TELEMETRY_DMA DMA1 +#define TELEMETRY_DMA_Stream_TX LL_DMA_STREAM_6 #define TELEMETRY_DMA_Channel_TX DMA_Channel_4 #define TELEMETRY_DMA_TX_Stream_IRQ DMA1_Stream6_IRQn #define TELEMETRY_DMA_TX_IRQHandler DMA1_Stream6_IRQHandler #define TELEMETRY_DMA_TX_FLAG_TC DMA_IT_TCIF6 +// #define TELEMETRY_DMA_Stream_RX LL_DMA_STREAM_5 +// #define TELEMETRY_DMA_Channel_RX LL_DMA_CHANNEL_4 #define TELEMETRY_USART_IRQHandler USART2_IRQHandler #define TELEMETRY_USART_IRQn USART2_IRQn @@ -379,26 +382,19 @@ // Flysky Hall Stick #define FLYSKY_HALL_SERIAL_USART UART4 #define FLYSKY_HALL_SERIAL_GPIO GPIOA -#define FLYSKY_HALL_DMA_Channel DMA_Channel_4 -#define FLYSKY_HALL_SERIAL_TX_GPIO_PIN GPIO_Pin_0 // PA.00 -#define FLYSKY_HALL_SERIAL_RX_GPIO_PIN GPIO_Pin_1 // PA.01 -#define FLYSKY_HALL_SERIAL_TX_GPIO_PinSource GPIO_PinSource0 -#define FLYSKY_HALL_SERIAL_RX_GPIO_PinSource GPIO_PinSource1 -#define FLYSKY_HALL_SERIAL_GPIO_AF GPIO_AF_UART4 +#define FLYSKY_HALL_DMA_Channel LL_DMA_CHANNEL_4 +#define FLYSKY_HALL_SERIAL_TX_GPIO_PIN LL_GPIO_PIN_0 // PA.00 +#define FLYSKY_HALL_SERIAL_RX_GPIO_PIN LL_GPIO_PIN_1 // PA.01 +#define FLYSKY_HALL_SERIAL_GPIO_AF LL_GPIO_AF_8 #define FLYSKY_HALL_RCC_AHB1Periph RCC_AHB1Periph_DMA1 #define FLYSKY_HALL_RCC_APB1Periph RCC_APB1Periph_UART4 #define FLYSKY_HALL_SERIAL_USART_IRQHandler UART4_IRQHandler #define FLYSKY_HALL_SERIAL_USART_IRQn UART4_IRQn -#define FLYSKY_HALL_SERIAL_RX_DMA_Stream_IRQn DMA1_Stream2_IRQn -#define FLYSKY_HALL_SERIAL_TX_DMA_Stream_IRQn DMA1_Stream4_IRQn -#define FLYSKY_HALL_DMA_Stream_RX DMA1_Stream2 -#define FLYSKY_HALL_DMA_Stream_TX DMA1_Stream4 -#define FLYSKY_HALL_DMA_TX_FLAG_TC DMA_IT_TCIF4 - -#define FLYSKY_HALL_RX_DMA_Stream_IRQHandler DMA1_Stream2_IRQHandler -#define FLYSKY_HALL_TX_DMA_Stream_IRQHandler DMA1_Stream4_IRQHandler +#define FLYSKY_HALL_SERIAL_DMA DMA1 +#define FLYSKY_HALL_DMA_Stream_RX LL_DMA_STREAM_2 +#define FLYSKY_HALL_DMA_Stream_TX LL_DMA_STREAM_4 // Internal Module #define INTMODULE_RCC_AHB1Periph (RCC_AHB1Periph_GPIOF | RCC_AHB1Periph_GPIOH | RCC_AHB1Periph_DMA1) diff --git a/radio/src/targets/nv14/telemetry_driver.cpp b/radio/src/targets/nv14/telemetry_driver.cpp deleted file mode 100644 index b94ce7abc..000000000 --- a/radio/src/targets/nv14/telemetry_driver.cpp +++ /dev/null @@ -1,238 +0,0 @@ -/* - * Copyright (C) EdgeTX - * - * Based on code named - * opentx - https://github.com/opentx/opentx - * th9x - http://code.google.com/p/th9x - * er9x - http://code.google.com/p/er9x - * gruvin9x - http://code.google.com/p/gruvin9x - * - * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "opentx.h" - -Fifo telemetryNoDMAFifo; -uint32_t telemetryErrors = 0; - -#if defined(PCBX12S) -DMAFifo telemetryDMAFifo __DMA (TELEMETRY_DMA_Stream_RX); -uint8_t telemetryFifoMode; -#endif - -void telemetryPortInitCommon(uint32_t baudrate, uint8_t mode, uint8_t noinv = 0) -{ - if (baudrate == 0) { - USART_DeInit(TELEMETRY_USART); - return; - } - - NVIC_InitTypeDef NVIC_InitStructure; - NVIC_InitStructure.NVIC_IRQChannel = TELEMETRY_DMA_TX_Stream_IRQ; - NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; - NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; /* Not used as 4 bits are used for the pre-emption priority. */; - NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; - NVIC_Init(&NVIC_InitStructure); - - USART_InitTypeDef USART_InitStructure; - GPIO_InitTypeDef GPIO_InitStructure; - - GPIO_PinAFConfig(TELEMETRY_GPIO, TELEMETRY_GPIO_PinSource_RX, TELEMETRY_GPIO_AF); - GPIO_PinAFConfig(TELEMETRY_GPIO, TELEMETRY_GPIO_PinSource_TX, TELEMETRY_GPIO_AF); - - GPIO_InitStructure.GPIO_Pin = TELEMETRY_TX_GPIO_PIN | TELEMETRY_RX_GPIO_PIN; - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; - GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; - GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; - GPIO_Init(TELEMETRY_GPIO, &GPIO_InitStructure); - - GPIO_InitStructure.GPIO_Pin = TELEMETRY_DIR_GPIO_PIN; - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; - GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; - GPIO_Init(TELEMETRY_DIR_GPIO, &GPIO_InitStructure); - TELEMETRY_DIR_INPUT(); - - GPIO_InitStructure.GPIO_Pin = TELEMETRY_TX_REV_GPIO_PIN | TELEMETRY_RX_REV_GPIO_PIN; - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; - GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; - GPIO_Init(TELEMETRY_REV_GPIO, &GPIO_InitStructure); - - if (noinv != 0) { - TELEMETRY_TX_POL_NORM(); - TELEMETRY_RX_POL_NORM(); - } else { - TELEMETRY_TX_POL_INV(); - TELEMETRY_RX_POL_INV(); - } - - USART_InitStructure.USART_BaudRate = baudrate; - if (mode & TELEMETRY_SERIAL_8E2) { - USART_InitStructure.USART_WordLength = USART_WordLength_9b; - USART_InitStructure.USART_StopBits = USART_StopBits_2; - USART_InitStructure.USART_Parity = USART_Parity_Even; - } - else { - USART_InitStructure.USART_WordLength = USART_WordLength_8b; - USART_InitStructure.USART_StopBits = USART_StopBits_1; - USART_InitStructure.USART_Parity = USART_Parity_No; - } - USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; - USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; - USART_Init(TELEMETRY_USART, &USART_InitStructure); - - USART_Cmd(TELEMETRY_USART, ENABLE); - USART_ITConfig(TELEMETRY_USART, USART_IT_RXNE, ENABLE); - NVIC_SetPriority(TELEMETRY_USART_IRQn, 6); - NVIC_EnableIRQ(TELEMETRY_USART_IRQn); -} - -void telemetryPortInit(uint32_t baudrate, uint8_t mode) -{ - telemetryPortInitCommon(baudrate, mode, 0); -} - -void telemetryPortInvertedInit(uint32_t baudrate) -{ - telemetryPortInitCommon(baudrate, TELEMETRY_SERIAL_DEFAULT, 1); -} - -/*void extmoduleSendInvertedByte(uint8_t byte) -{ -#warning "TODO extmoduleSendInvertedByte"; -}*/ - -void telemetryPortSetDirectionOutput() -{ - TELEMETRY_DIR_OUTPUT(); - TELEMETRY_USART->CR1 &= ~USART_CR1_RE; // turn off receiver -} - -void telemetryPortSetDirectionInput() -{ - TELEMETRY_DIR_INPUT(); - TELEMETRY_USART->CR1 |= USART_CR1_RE; // turn on receiver -} - -void sportSendByte(uint8_t byte) -{ - telemetryPortSetDirectionOutput(); - - while (!(TELEMETRY_USART->SR & USART_SR_TXE)); - USART_SendData(TELEMETRY_USART, byte); -} - -void sportSendBuffer(const uint8_t * buffer, uint32_t count) -{ - telemetryPortSetDirectionOutput(); - - DMA_InitTypeDef DMA_InitStructure; - DMA_DeInit(TELEMETRY_DMA_Stream_TX); - DMA_InitStructure.DMA_Channel = TELEMETRY_DMA_Channel_TX; - DMA_InitStructure.DMA_PeripheralBaseAddr = CONVERT_PTR_UINT(&TELEMETRY_USART->DR); - DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; - DMA_InitStructure.DMA_Memory0BaseAddr = CONVERT_PTR_UINT(buffer); - DMA_InitStructure.DMA_BufferSize = count; - DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; - DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; - DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; - DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; - DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; - DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; - DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; - DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full; - DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; - DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; - DMA_Init(TELEMETRY_DMA_Stream_TX, &DMA_InitStructure); - DMA_Cmd(TELEMETRY_DMA_Stream_TX, ENABLE); - USART_DMACmd(TELEMETRY_USART, USART_DMAReq_Tx, ENABLE); - DMA_ITConfig(TELEMETRY_DMA_Stream_TX, DMA_IT_TC, ENABLE); - - // enable interrupt and set it's priority - NVIC_EnableIRQ(TELEMETRY_DMA_TX_Stream_IRQ) ; - NVIC_SetPriority(TELEMETRY_DMA_TX_Stream_IRQ, 7); -} - -extern "C" void TELEMETRY_DMA_TX_IRQHandler(void) -{ - DEBUG_INTERRUPT(INT_TELEM_DMA); - if (DMA_GetITStatus(TELEMETRY_DMA_Stream_TX, TELEMETRY_DMA_TX_FLAG_TC)) { - DMA_ClearITPendingBit(TELEMETRY_DMA_Stream_TX, TELEMETRY_DMA_TX_FLAG_TC); - - // clear TC flag before enabling interrupt - TELEMETRY_USART->SR &= ~USART_SR_TC; - TELEMETRY_USART->CR1 |= USART_CR1_TCIE; - - if (telemetryProtocol == PROTOCOL_TELEMETRY_FRSKY_SPORT) { - outputTelemetryBuffer.reset(); - } - } -} - -#define USART_FLAG_ERRORS (USART_FLAG_ORE | USART_FLAG_NE | USART_FLAG_FE | USART_FLAG_PE) -extern "C" void TELEMETRY_USART_IRQHandler(void) -{ - DEBUG_INTERRUPT(INT_TELEM_USART); - uint32_t status = TELEMETRY_USART->SR; - - if ((status & USART_SR_TC) && (TELEMETRY_USART->CR1 & USART_CR1_TCIE)) { - TELEMETRY_USART->CR1 &= ~USART_CR1_TCIE; - telemetryPortSetDirectionInput(); - while (status & (USART_FLAG_RXNE)) { - status = TELEMETRY_USART->DR; - status = TELEMETRY_USART->SR; - } - } - - while (status & (USART_FLAG_RXNE | USART_FLAG_ERRORS)) { - uint8_t data = TELEMETRY_USART->DR; - if (status & USART_FLAG_ERRORS) { - telemetryErrors++; - } - else { - telemetryNoDMAFifo.push(data); -#if defined(LUA) - if (telemetryProtocol == PROTOCOL_TELEMETRY_FRSKY_SPORT) { - static uint8_t prevdata; - if (prevdata == 0x7E && outputTelemetryBuffer.size > 0 && outputTelemetryBuffer.destination == TELEMETRY_ENDPOINT_SPORT && data == outputTelemetryBuffer.sport.physicalId) { - sportSendBuffer(outputTelemetryBuffer.data + 1, outputTelemetryBuffer.size - 1); - } - prevdata = data; - } -#endif - } - status = TELEMETRY_USART->SR; - } -} - -// TODO we should have telemetry in an higher layer, functions above should move to a sport_driver.cpp -bool sportGetByte(uint8_t * byte) -{ -#if defined(PCBX12S) - if (telemetryFifoMode & TELEMETRY_SERIAL_WITHOUT_DMA) - return telemetryNoDMAFifo.pop(*byte); - else - return telemetryDMAFifo.pop(*byte); -#else - return telemetryNoDMAFifo.pop(*byte); -#endif -} - -void telemetryClearFifo() -{ -#if defined(PCBX12S) - telemetryDMAFifo.clear(); -#endif - - telemetryNoDMAFifo.clear(); -} - diff --git a/radio/src/targets/simu/bt_driver.cpp b/radio/src/targets/simu/bt_driver.cpp index 31af8dcff..2648f5d26 100644 --- a/radio/src/targets/simu/bt_driver.cpp +++ b/radio/src/targets/simu/bt_driver.cpp @@ -21,15 +21,9 @@ #include "fifo.h" -#define BT_TX_FIFO_SIZE 64 -#define BT_RX_FIFO_SIZE 256 - -Fifo btTxFifo; -Fifo btRxFifo; - void bluetoothInit(unsigned int, bool) {} +void bluetoothWrite(const void*, uint32_t) {} +int bluetoothRead(uint8_t*) { return 0; } void bluetoothDisable() {} - -void bluetoothWriteWakeup() {} bool bluetoothIsWriting() { return false; } diff --git a/radio/src/targets/simu/module_drivers.cpp b/radio/src/targets/simu/module_drivers.cpp index 2376a538d..f04e2910a 100644 --- a/radio/src/targets/simu/module_drivers.cpp +++ b/radio/src/targets/simu/module_drivers.cpp @@ -21,8 +21,8 @@ #include "hal.h" #include "hal/serial_driver.h" -#include "intmodule_serial_driver.h" -#include "extmodule_serial_driver.h" +#include "hal/module_port.h" +#include "dataconstants.h" void intmoduleStop() {} void intmoduleFifoError() {} @@ -60,54 +60,165 @@ void stop_trainer_module_sbus() {} void init_intmodule_heartbeat() {} void stop_intmodule_heartbeat() {} -static void* init(const etx_serial_init*) { return nullptr; } +static void* init(void*, const etx_serial_init*) { return (void*)1; } static void deinit(void*) {} static void sendByte(void*, uint8_t) {} -static void sendBuffer(void*, const uint8_t*, uint8_t) {} +static void sendBuffer(void*, const uint8_t*, uint32_t) {} static void waitForTxCompleted(void*) {} static int getByte(void*,uint8_t*) { return -1; } -const etx_serial_driver_t IntmoduleSerialDriver = { +const etx_serial_driver_t _fakeSerialDriver = { .init = init, .deinit = deinit, .sendByte = sendByte, .sendBuffer = sendBuffer, + .txCompleted = nullptr, .waitForTxCompleted = waitForTxCompleted, + .enableRx = nullptr, .getByte = getByte, + .getLastByte = nullptr, .clearRxBuffer = nullptr, .getBaudrate = nullptr, + .setBaudrate = nullptr, + .setPolarity = nullptr, + .setHWOption = nullptr, .setReceiveCb = nullptr, + .setIdleCb = nullptr, .setBaudrateCb = nullptr, }; -#if defined(EXTMODULE_USART) -static const etx_serial_driver_t _extmoduleSerialDriver = { - .init = init, - .deinit = deinit, - .sendByte = sendByte, - .sendBuffer = sendBuffer, - .waitForTxCompleted = waitForTxCompleted, - .getByte = getByte, - .clearRxBuffer = nullptr, - .getBaudrate = nullptr, - .setReceiveCb = nullptr, - .setBaudrateCb = nullptr, +static void* module_timer_init(void* hw_def, const etx_timer_config_t* cfg) +{ return (void*)1; } + +static void module_timer_deinit(void* ctx) {} + +static void module_timer_send(void* ctx, const etx_timer_config_t* cfg, + const void* pulses, uint16_t length) +{} + +const etx_timer_driver_t _fakeTimerDriver = { + .init = module_timer_init, + .deinit = module_timer_deinit, + .send = module_timer_send, }; -constexpr const etx_serial_driver_t* _ext_default_drv = &_extmoduleSerialDriver; -#else -constexpr const etx_serial_driver_t* _ext_default_drv = nullptr; +#if defined(HARDWARE_INTERNAL_MODULE) +const etx_module_port_t _internal_ports[] = { +#if defined(INTMODULE_USART) + { + .port = ETX_MOD_PORT_UART, + .type = ETX_MOD_TYPE_SERIAL, + .dir_flags = ETX_MOD_DIR_TX_RX | ETX_MOD_FULL_DUPLEX, + .drv = { .serial = &_fakeSerialDriver }, + .hw_def = nullptr, + }, +#else // INTMODULE_USART + { + .port = ETX_MOD_PORT_SOFT_INV, + .type = ETX_MOD_TYPE_SERIAL, + .dir_flags = ETX_MOD_DIR_TX, + .drv = { .timer = &_fakeTimerDriver }, + .hw_def = nullptr, + }, +#endif +#if defined(INTERNAL_MODULE_PXX1) + { + .port = ETX_MOD_PORT_SPORT, + .type = ETX_MOD_TYPE_SERIAL, + .dir_flags = ETX_MOD_DIR_TX | ETX_MOD_DIR_RX, + .drv = { .serial = &_fakeSerialDriver }, + .hw_def = nullptr, + }, +#endif +}; + +static const etx_module_t _internal_module = { + .ports = _internal_ports, + .set_pwr = nullptr, + .set_bootcmd = nullptr, + .n_ports = DIM(_internal_ports), +}; #endif -const etx_serial_driver_t* _ext_drv = _ext_default_drv; +#if defined(SPORT_UPDATE_PWR_GPIO) +void _sport_set_pwr(uint8_t) {} +const etx_module_t _sport_module = { + .ports = nullptr, + .set_pwr = _sport_set_pwr, + .set_bootcmd = nullptr, + .n_ports = 0, +}; +#endif -void extmoduleSetSerialPort(const etx_serial_driver_t* drv) -{ - if (drv) _ext_drv = drv; - else _ext_drv = _ext_default_drv; -} +#if defined(HARDWARE_EXTERNAL_MODULE) +const etx_module_port_t _external_ports[] = { +#if defined(EXTMODULE_USART) + // TX on PPM, RX on HEARTBEAT + { + .port = ETX_MOD_PORT_UART, + .type = ETX_MOD_TYPE_SERIAL, + .dir_flags = ETX_MOD_DIR_TX_RX | ETX_MOD_FULL_DUPLEX, + .drv = { .serial = &_fakeSerialDriver }, + .hw_def = nullptr, + }, +#endif + // Timer output on PPM + { + .port = ETX_MOD_PORT_TIMER, + .type = ETX_MOD_TYPE_TIMER, + .dir_flags = ETX_MOD_DIR_TX, + .drv = { .timer = &_fakeTimerDriver }, + .hw_def = nullptr, + }, + // TX inverted DMA pulse train on S.PORT + { + .port = ETX_MOD_PORT_SOFT_INV, + .type = ETX_MOD_TYPE_SERIAL, + .dir_flags = ETX_MOD_DIR_TX, + .drv = { .serial = &_fakeSerialDriver }, + .hw_def = nullptr, + }, + // TX/RX half-duplex on S.PORT + { + .port = ETX_MOD_PORT_SPORT, + .type = ETX_MOD_TYPE_SERIAL, + .dir_flags = ETX_MOD_DIR_TX | ETX_MOD_DIR_RX, + .drv = { .serial = &_fakeSerialDriver }, + .hw_def = nullptr, + }, +#if defined(TELEMETRY_TIMER) + // RX soft-serial sampled bit-by-bit via timer IRQ on S.PORT + { + .port = ETX_MOD_PORT_SPORT_INV, + .type = ETX_MOD_TYPE_SERIAL, + .dir_flags = ETX_MOD_DIR_RX, + .drv = { .serial = &_fakeSerialDriver }, + .hw_def = nullptr, + }, +#endif +}; -const etx_serial_driver_t* extmoduleGetSerialPort() -{ - return _ext_drv; -} +static const etx_module_t _external_module = { + .ports = _external_ports, + .set_pwr = nullptr, + .set_bootcmd = nullptr, + .n_ports = DIM(_external_ports), +}; +#endif + + +BEGIN_MODULES() +#if defined(HARDWARE_INTERNAL_MODULE) + &_internal_module, +#else + nullptr, +#endif +#if defined(HARDWARE_EXTERNAL_MODULE) + &_external_module, +#else + nullptr, +#endif +#if defined(SPORT_UPDATE_PWR_GPIO) + &_sport_module, +#endif +END_MODULES() diff --git a/radio/src/targets/simu/opentxsimulator.cpp b/radio/src/targets/simu/opentxsimulator.cpp index a32994bc9..03d0d1bfa 100644 --- a/radio/src/targets/simu/opentxsimulator.cpp +++ b/radio/src/targets/simu/opentxsimulator.cpp @@ -396,7 +396,9 @@ void OpenTxSimulator::setTrainerTimeout(uint16_t ms) void OpenTxSimulator::sendTelemetry(const QByteArray data) { //ETXS_DBG << data; - sportProcessTelemetryPacket((uint8_t *)data.constData()); + sportProcessTelemetryPacket(INTERNAL_MODULE, + (uint8_t *)data.constData(), + data.count()); } uint8_t OpenTxSimulator::getSensorInstance(uint16_t id, uint8_t defaultValue) diff --git a/radio/src/targets/simu/simpgmspace.cpp b/radio/src/targets/simu/simpgmspace.cpp index 11f21e635..4759f4e88 100644 --- a/radio/src/targets/simu/simpgmspace.cpp +++ b/radio/src/targets/simu/simpgmspace.cpp @@ -53,7 +53,6 @@ volatile uint32_t rotencDt = 0; // TODO: remove all STM32 defs GPIO_TypeDef gpioa, gpiob, gpioc, gpiod, gpioe, gpiof, gpiog, gpioh, gpioi, gpioj; -USART_TypeDef Usart0, Usart1, Usart2, Usart3, Usart4; ADC_Common_TypeDef adc; RTC_TypeDef rtc; @@ -155,7 +154,6 @@ void simuStart(bool tests, const char * sdPath, const char * settingsPath) if (simu_running) return; - stopPulses(); #if !defined(COLORLCD) menuLevel = 0; #endif @@ -233,6 +231,9 @@ void simuStart(bool tests, const char * sdPath, const char * settingsPath) #endif } +extern RTOS_TASK_HANDLE mixerTaskId; +extern RTOS_TASK_HANDLE menusTaskId; + void simuStop() { if (!simu_running) @@ -569,51 +570,6 @@ void setSelectedUsbMode(int mode) {} void delay_ms(uint32_t ms) { } void delay_us(uint16_t us) { } -// GPIO fake functions -void GPIO_PinAFConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_PinSource, uint8_t GPIO_AF) { } - -// PWR fake functions -void PWR_BackupAccessCmd(FunctionalState NewState) { } -void PWR_BackupRegulatorCmd(FunctionalState NewState) { } - -// USART fake functions -void USART_DeInit(USART_TypeDef* ) { } -void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct) { } -void USART_Cmd(USART_TypeDef* USARTx, FunctionalState NewState) { } -void USART_ClearITPendingBit(USART_TypeDef*, unsigned short) { } -void USART_SendData(USART_TypeDef* USARTx, uint16_t Data) { } -uint16_t USART_ReceiveData(USART_TypeDef*) { return 0; } -void USART_DMACmd(USART_TypeDef* USARTx, uint16_t USART_DMAReq, FunctionalState NewState) { } -void USART_ITConfig(USART_TypeDef* USARTx, uint16_t USART_IT, FunctionalState NewState) { } -FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG) { return SET; } - -// TIM fake functions -void TIM_DMAConfig(TIM_TypeDef* TIMx, uint16_t TIM_DMABase, uint16_t TIM_DMABurstLength) { } -void TIM_DMACmd(TIM_TypeDef* TIMx, uint16_t TIM_DMASource, FunctionalState NewState) { } -void TIM_CtrlPWMOutputs(TIM_TypeDef* TIMx, FunctionalState NewState) { } - -// SPI fake functions -void SPI_I2S_DeInit(SPI_TypeDef* SPIx) { } -void SPI_I2S_ITConfig(SPI_TypeDef* SPIx, uint8_t SPI_I2S_IT, FunctionalState NewState) { } - -// RCC fake functions -void RCC_RTCCLKConfig(uint32_t RCC_RTCCLKSource) { } -void RCC_APB1PeriphClockCmd(uint32_t RCC_APB1Periph, FunctionalState NewState) { } -void RCC_RTCCLKCmd(FunctionalState NewState) { } -void RCC_PLLI2SConfig(uint32_t PLLI2SN, uint32_t PLLI2SR) { } -void RCC_PLLI2SCmd(FunctionalState NewState) { } -void RCC_I2SCLKConfig(uint32_t RCC_I2SCLKSource) { } -void RCC_LSEConfig(uint8_t RCC_LSE) { } -void RCC_GetClocksFreq(RCC_ClocksTypeDef* RCC_Clocks) { }; -FlagStatus RCC_GetFlagStatus(uint8_t RCC_FLAG) { return SET; } - -// EXTI fake functions -void SYSCFG_EXTILineConfig(uint8_t EXTI_PortSourceGPIOx, uint8_t EXTI_PinSourcex) { } -void EXTI_StructInit(EXTI_InitTypeDef* EXTI_InitStruct) { } -ITStatus EXTI_GetITStatus(uint32_t EXTI_Line) { return RESET; } -void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct) { } -void EXTI_ClearITPendingBit(uint32_t EXTI_Line) { } - void unlockFlash() { } @@ -717,21 +673,28 @@ const etx_serial_port_t UsbSerialPort = { "USB-VCP", nullptr, nullptr }; #endif #if defined(AUX_SERIAL) || defined(AUX2_SERIAL) -static void* _fake_drv_init(const etx_serial_init*) { return nullptr; } +static void* _fake_drv_init(void*, const etx_serial_init*) { return (void*)1; } static void _fake_drv_fct1(void*) {} static void _fake_drv_send_byte(void*, uint8_t) {} -static void _fake_drv_send_buffer(void*, const uint8_t*, uint8_t) {} +static void _fake_drv_send_buffer(void*, const uint8_t*, uint32_t) {} static int _fake_drv_get_byte(void*, uint8_t*) { return 0; } static const etx_serial_driver_t _fake_drv = { .init = _fake_drv_init, .deinit = _fake_drv_fct1, .sendByte = _fake_drv_send_byte, .sendBuffer = _fake_drv_send_buffer, - .waitForTxCompleted = _fake_drv_fct1, + .txCompleted = nullptr, + .waitForTxCompleted = nullptr, + .enableRx = nullptr, .getByte = _fake_drv_get_byte, + .getLastByte = nullptr, .clearRxBuffer = nullptr, .getBaudrate = nullptr, + .setBaudrate = nullptr, + .setPolarity = nullptr, + .setHWOption = nullptr, .setReceiveCb = nullptr, + .setIdleCb = nullptr, .setBaudrateCb = nullptr, }; #endif @@ -743,7 +706,12 @@ static const etx_serial_driver_t _fake_drv = { #else #define AUX_SERIAL_PWR nullptr #endif -static const etx_serial_port_t auxSerialPort = {"AUX1", &_fake_drv, AUX_SERIAL_PWR}; +static const etx_serial_port_t auxSerialPort = { + "AUX1", + &_fake_drv, + nullptr, + AUX_SERIAL_PWR +}; #define AUX_SERIAL_PORT &auxSerialPort #else #define AUX_SERIAL_PORT nullptr @@ -756,7 +724,12 @@ static const etx_serial_port_t auxSerialPort = {"AUX1", &_fake_drv, AUX_SERIAL_P #else #define AUX2_SERIAL_PWR nullptr #endif -static const etx_serial_port_t aux2SerialPort = {"AUX2", &_fake_drv, AUX2_SERIAL_PWR}; +static const etx_serial_port_t aux2SerialPort = { + "AUX2", + &_fake_drv, + nullptr, + AUX2_SERIAL_PWR +}; #define AUX2_SERIAL_PORT &aux2SerialPort #else #define AUX2_SERIAL_PORT nullptr diff --git a/radio/src/targets/taranis/CMakeLists.txt b/radio/src/targets/taranis/CMakeLists.txt index 743fe1155..448003107 100644 --- a/radio/src/targets/taranis/CMakeLists.txt +++ b/radio/src/targets/taranis/CMakeLists.txt @@ -473,11 +473,6 @@ if(INTERNAL_MODULE_SERIAL) if(PXX_FREQUENCY STREQUAL HIGH) add_definitions(-DPXX_FREQUENCY_HIGH) endif() - set(FIRMWARE_SRC - ${FIRMWARE_SRC} - targets/common/arm/stm32/intmodule_serial_driver.cpp - targets/common/arm/stm32/stm32_usart_driver.cpp - ) else() @@ -494,8 +489,6 @@ if(HARDWARE_EXTERNAL_MODULE) set(FIRMWARE_SRC ${FIRMWARE_SRC} targets/common/arm/stm32/extmodule_driver.cpp - targets/common/arm/stm32/extmodule_serial_driver.cpp - targets/common/arm/stm32/stm32_usart_driver.cpp ) endif() @@ -598,6 +591,10 @@ set(FIRMWARE_SRC ${FIRMWARE_SRC} hal/adc_driver.cpp targets/common/arm/loadboot.cpp + boards/generic_stm32/module_ports.cpp + boards/generic_stm32/aux_ports.cpp + boards/generic_stm32/sport_update.cpp + boards/generic_stm32/intmodule_heartbeat.cpp targets/common/arm/stm32/stm32_hal_adc.cpp targets/common/arm/stm32/heartbeat_driver.cpp targets/common/arm/stm32/mixer_scheduler_driver.cpp @@ -606,6 +603,7 @@ set(FIRMWARE_SRC targets/common/arm/stm32/pwr_driver.cpp targets/common/arm/stm32/stm32_exti_driver.cpp targets/common/arm/stm32/stm32_pulse_driver.cpp + targets/common/arm/stm32/stm32_usart_driver.cpp targets/common/arm/stm32/trainer_driver.cpp ) diff --git a/radio/src/targets/taranis/board.cpp b/radio/src/targets/taranis/board.cpp index ac711cc99..c5d3bd231 100644 --- a/radio/src/targets/taranis/board.cpp +++ b/radio/src/targets/taranis/board.cpp @@ -20,10 +20,14 @@ */ #include "board.h" +#include "boards/generic_stm32/module_ports.h" +#include "boards/generic_stm32/intmodule_heartbeat.h" + #include "debug.h" #include "rtc.h" #include "hal/adc_driver.h" +#include "hal/module_port.h" #include "stm32_hal_adc.h" #include "../common/arm/stm32/timers_driver.h" @@ -32,10 +36,13 @@ #if !defined(BOOT) #include "opentx.h" + #if defined(PXX1) + #include "pulses/pxx1.h" + #endif #endif -#if defined(AUX_SERIAL) -#include "aux_serial_driver.h" +#if defined(BLUETOOTH) + #include "bluetooth_driver.h" #endif #if defined(__cplusplus) @@ -59,37 +66,6 @@ void watchdogInit(unsigned int duration) IWDG->KR = 0xCCCC; // start } -#if defined(SPORT_UPDATE_PWR_GPIO) && !defined(BOOT) -void sportUpdateInit() -{ - GPIO_InitTypeDef GPIO_InitStructure; - GPIO_InitStructure.GPIO_Pin = SPORT_UPDATE_PWR_GPIO_PIN; - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; - GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; - GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; - GPIO_Init(SPORT_UPDATE_PWR_GPIO, &GPIO_InitStructure); -} - -void sportUpdatePowerOn() -{ - GPIO_SPORT_UPDATE_PWR_GPIO_ON(SPORT_UPDATE_PWR_GPIO, SPORT_UPDATE_PWR_GPIO_PIN); -} - -void sportUpdatePowerOff() -{ - GPIO_SPORT_UPDATE_PWR_GPIO_OFF(SPORT_UPDATE_PWR_GPIO, SPORT_UPDATE_PWR_GPIO_PIN); -} - -void sportUpdatePowerInit() -{ - if (g_eeGeneral.sportUpdatePower == 1) - sportUpdatePowerOn(); - else - sportUpdatePowerOff(); -} -#endif - #if !defined(BOOT) #if defined(RADIO_TPRO) @@ -154,13 +130,25 @@ void boardInit() } #endif + // Sets 'hardwareOption.pcbrev' as well pwrInit(); + boardInitModulePorts(); -#if defined(AUTOUPDATE) - telemetryPortInit(FRSKY_SPORT_BAUDRATE, TELEMETRY_SERIAL_WITHOUT_DMA); - sportSendByteLoop(0x7E); +#if defined(INTERNAL_MODULE_PXX1) && defined(PXX_FREQUENCY_HIGH) + pxx1SetInternalBaudrate(PXX1_FAST_SERIAL_BAUDRATE); #endif +#if defined(INTMODULE_HEARTBEAT) && \ + (defined(INTERNAL_MODULE_PXX1) || defined(INTERNAL_MODULE_PXX2)) + pulsesSetModuleInitCb(_intmodule_heartbeat_init); + pulsesSetModuleDeInitCb(_intmodule_heartbeat_deinit); +#endif + +// #if defined(AUTOUPDATE) +// telemetryPortInit(FRSKY_SPORT_BAUDRATE, TELEMETRY_SERIAL_WITHOUT_DMA); +// sportSendByteLoop(0x7E); +// #endif + #if defined(STATUS_LEDS) ledInit(); #if defined(RADIO_T8) || defined(RADIO_COMMANDO8) || defined(RADIO_TLITE) || \ @@ -230,7 +218,7 @@ void boardInit() lcdInit(); // delaysInit() must be called before audioInit(); init2MhzTimer(); - init1msTimer(); + init5msTimer(); __enable_irq(); usbInit(); @@ -264,10 +252,6 @@ void boardInit() usbChargerInit(); #endif - if (HAS_SPORT_UPDATE_CONNECTOR()) { - sportUpdateInit(); - } - #if defined(JACK_DETECT_GPIO) initJackDetect(); #endif @@ -402,27 +386,3 @@ void initJackDetect(void) GPIO_Init(JACK_DETECT_GPIO, &GPIO_InitStructure); } #endif - -#if defined(AUX_SERIAL) -const etx_serial_port_t auxSerialPort = { - "AUX1", - &AuxSerialDriver, - nullptr -}; -#define AUX_SERIAL_PORT &auxSerialPort -#else -#define AUX_SERIAL_PORT nullptr -#endif - -#define AUX2_SERIAL_PORT nullptr - -static const etx_serial_port_t* serialPorts[MAX_AUX_SERIAL] = { - AUX_SERIAL_PORT, - AUX2_SERIAL_PORT, -}; - -const etx_serial_port_t* auxSerialGetPort(int port_nr) -{ - if (port_nr >= MAX_AUX_SERIAL) return nullptr; - return serialPorts[port_nr]; -} diff --git a/radio/src/targets/taranis/board.h b/radio/src/targets/taranis/board.h index 619a23793..0970e95f0 100644 --- a/radio/src/targets/taranis/board.h +++ b/radio/src/targets/taranis/board.h @@ -109,12 +109,6 @@ uint32_t isBootloaderStart(const uint8_t * buffer); #define EXTERNAL_MODULE_ON() EXTERNAL_MODULE_PWR_ON() #define EXTERNAL_MODULE_OFF() EXTERNAL_MODULE_PWR_OFF() -#if defined(RADIO_T12) -#define IS_INTERNAL_MODULE_ON() false -#else -#define IS_INTERNAL_MODULE_ON() (GPIO_ReadInputDataBit(INTMODULE_PWR_GPIO, INTMODULE_PWR_GPIO_PIN) == Bit_SET) -#endif - // Trainer driver #define SLAVE_MODE() (g_model.trainerData.mode == TRAINER_MODE_SLAVE) @@ -754,49 +748,17 @@ uint8_t isBacklightEnabled(); void debugPutc(const char c); // Telemetry driver -void telemetryPortInit(uint32_t baudrate, uint8_t mode); -void telemetryPortSetDirectionInput(); -void telemetryPortSetDirectionOutput(); -void sportSendByte(uint8_t byte); -void sportSendByteLoop(uint8_t byte); -void sportStopSendByteLoop(); -void sportSendBuffer(const uint8_t * buffer, uint32_t count); -bool sportGetByte(uint8_t * byte); -void telemetryClearFifo(); -extern uint32_t telemetryErrors; +// void telemetryPortInit(uint32_t baudrate, uint8_t mode); +// void telemetryPortSetDirectionInput(); +// void telemetryPortSetDirectionOutput(); +// void sportSendByte(uint8_t byte); +// void sportSendByteLoop(uint8_t byte); +// void sportStopSendByteLoop(); +// void sportSendBuffer(const uint8_t * buffer, uint32_t count); +// bool sportGetByte(uint8_t * byte); +// void telemetryClearFifo(); +// extern uint32_t telemetryErrors; -// soft-serial -void telemetryPortInvertedInit(uint32_t baudrate); - -// PCBREV driver -#if defined(PCBX7ACCESS) - #define HAS_SPORT_UPDATE_CONNECTOR() true -#elif defined(PCBX7) - #define IS_PCBREV_40() (hardwareOptions.pcbrev == PCBREV_X7_40) - #define HAS_SPORT_UPDATE_CONNECTOR() IS_PCBREV_40() -#elif defined(SPORT_UPDATE_PWR_GPIO) - #define HAS_SPORT_UPDATE_CONNECTOR() true -#else - #define HAS_SPORT_UPDATE_CONNECTOR() false -#endif - -// Sport update driver -#if defined(SPORT_UPDATE_PWR_GPIO) -void sportUpdateInit(); -void sportUpdatePowerOn(); -void sportUpdatePowerOff(); -void sportUpdatePowerInit(); -#define SPORT_UPDATE_POWER_ON() sportUpdatePowerOn() -#define SPORT_UPDATE_POWER_OFF() sportUpdatePowerOff() -#define SPORT_UPDATE_POWER_INIT() sportUpdatePowerInit() -#define IS_SPORT_UPDATE_POWER_ON() (GPIO_ReadInputDataBit(SPORT_UPDATE_PWR_GPIO, SPORT_UPDATE_PWR_GPIO_PIN) == Bit_SET) -#else -#define sportUpdateInit() -#define SPORT_UPDATE_POWER_ON() -#define SPORT_UPDATE_POWER_OFF() -#define SPORT_UPDATE_POWER_INIT() -#define IS_SPORT_UPDATE_POWER_ON() (false) -#endif // Audio driver void audioInit() ; @@ -851,31 +813,6 @@ void hapticOff(); const etx_serial_port_t* auxSerialGetPort(int port_nr); -// BT driver -#define BLUETOOTH_BOOTLOADER_BAUDRATE 230400 -#define BLUETOOTH_DEFAULT_BAUDRATE 115200 -#if defined(PCBX9E) -#define BLUETOOTH_FACTORY_BAUDRATE 9600 -#else -#define BLUETOOTH_FACTORY_BAUDRATE 57600 -#endif -#define BT_TX_FIFO_SIZE 64 -#define BT_RX_FIFO_SIZE 256 -void bluetoothInit(uint32_t baudrate, bool enable); -void bluetoothWriteWakeup(); -uint8_t bluetoothIsWriting(); -void bluetoothDisable(); -#if defined(PCBX9LITES) || defined(PCBX7ACCESS) - #define IS_BLUETOOTH_CHIP_PRESENT() (true) -#elif defined(PCBX9LITE) - #define IS_BLUETOOTH_CHIP_PRESENT() (false) -#elif defined(BLUETOOTH_PROBE) && !defined(SIMU) - extern volatile uint8_t btChipPresent; - #define IS_BLUETOOTH_CHIP_PRESENT() (btChipPresent) -#else - #define IS_BLUETOOTH_CHIP_PRESENT() (true) -#endif - // USB Charger #if defined(USB_CHARGER) void usbChargerInit(); @@ -963,19 +900,12 @@ void setTopBatteryValue(uint32_t volts); #define USART_FLAG_ERRORS (USART_FLAG_ORE | USART_FLAG_NE | USART_FLAG_FE | USART_FLAG_PE) -#if defined(__cplusplus) -#include "fifo.h" -#include "dmafifo.h" - #if defined(CROSSFIRE) #define TELEMETRY_FIFO_SIZE 128 #else #define TELEMETRY_FIFO_SIZE 64 #endif -extern Fifo telemetryFifo; -#endif - #define INTMODULE_FIFO_SIZE 128 #if defined (RADIO_TX12) diff --git a/radio/src/targets/taranis/hal.h b/radio/src/targets/taranis/hal.h index b4fef0b9e..7770ee7f1 100644 --- a/radio/src/targets/taranis/hal.h +++ b/radio/src/targets/taranis/hal.h @@ -1610,6 +1610,7 @@ #if defined(PCBXLITES) #define INTMODULE_BOOTCMD_GPIO GPIOC #define INTMODULE_BOOTCMD_GPIO_PIN GPIO_Pin_8 // PC.08 + #define INTMODULE_BOOTCMD_DEFAULT 1 // SET #define INIT_INTMODULE_BOOTCMD_PIN() GPIO_SetBits(INTMODULE_BOOTCMD_GPIO, INTMODULE_BOOTCMD_GPIO_PIN); #endif #elif defined(RADIO_X9DP2019) @@ -1674,6 +1675,7 @@ #define INTMODULE_RX_DMA_CHANNEL LL_DMA_CHANNEL_4 #define INTMODULE_BOOTCMD_GPIO GPIOB #define INTMODULE_BOOTCMD_GPIO_PIN GPIO_Pin_1 // PB.01 + #define INTMODULE_BOOTCMD_DEFAULT 0 // RESET #define INIT_INTMODULE_BOOTCMD_PIN() GPIO_ResetBits(INTMODULE_BOOTCMD_GPIO, INTMODULE_BOOTCMD_GPIO_PIN); #elif defined(PCBX9E) || defined(PCBX9DP) || defined(RADIO_X7) #define INTMODULE_PULSES @@ -1708,21 +1710,23 @@ // #define INTMODULE_DMA NULL // #define INTMODULE_DMA_CHANNEL 0 // #define INTMODULE_DMA_STREAM 0 - // TODO: RX DMA seems to be buggy together with passthrough - // #define INTMODULE_RX_DMA DMA1 - // #define INTMODULE_RX_DMA_STREAM LL_DMA_STREAM_1 - // #define INTMODULE_RX_DMA_CHANNEL LL_DMA_CHANNEL_4 + #define INTMODULE_RX_DMA DMA1 + #define INTMODULE_RX_DMA_STREAM LL_DMA_STREAM_1 + #define INTMODULE_RX_DMA_CHANNEL LL_DMA_CHANNEL_4 #if defined(RADIO_TLITE) #define INTMODULE_BOOTCMD_GPIO GPIOA #define INTMODULE_BOOTCMD_GPIO_PIN GPIO_Pin_5 // PA.05 + #define INTMODULE_BOOTCMD_DEFAULT 0 // RESET #define INIT_INTMODULE_BOOTCMD_PIN() GPIO_ResetBits(INTMODULE_BOOTCMD_GPIO, INTMODULE_BOOTCMD_GPIO_PIN); #elif defined(RADIO_TPRO) #define INTMODULE_BOOTCMD_GPIO GPIOF #define INTMODULE_BOOTCMD_GPIO_PIN GPIO_Pin_11 // PF.11 + #define INTMODULE_BOOTCMD_DEFAULT 0 // RESET #define INIT_INTMODULE_BOOTCMD_PIN() GPIO_ResetBits(INTMODULE_BOOTCMD_GPIO, INTMODULE_BOOTCMD_GPIO_PIN); #elif defined(RADIO_LR3PRO) #define INTMODULE_BOOTCMD_GPIO GPIOB #define INTMODULE_BOOTCMD_GPIO_PIN GPIO_Pin_5 // PB.05 + #define INTMODULE_BOOTCMD_DEFAULT 0 // RESET #define INIT_INTMODULE_BOOTCMD_PIN() GPIO_ResetBits(INTMODULE_BOOTCMD_GPIO, INTMODULE_BOOTCMD_GPIO_PIN); #endif #elif defined(RADIO_COMMANDO8) @@ -1741,10 +1745,10 @@ #define INTMODULE_GPIO_AF_LL LL_GPIO_AF_7 #define INTMODULE_USART_IRQn USART3_IRQn #define INTMODULE_USART_IRQHandler USART3_IRQHandler - // DMA1_Stream3 is already used by SDIO - #define INTMODULE_DMA NULL - #define INTMODULE_DMA_CHANNEL 0 - #define INTMODULE_DMA_STREAM 0 + // // DMA1_Stream3 is already used by SDIO + // #define INTMODULE_DMA NULL + // #define INTMODULE_DMA_CHANNEL 0 + // #define INTMODULE_DMA_STREAM 0 #else #define INTMODULE_PULSES #define INTMODULE_RCC_AHB1Periph (RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_DMA2) @@ -1929,9 +1933,11 @@ #if defined(PCBXLITE) || defined(PCBX9LITE) || defined(RADIO_X9DP2019) || defined(RADIO_X7ACCESS) #define TELEMETRY_DIR_OUTPUT() LL_GPIO_ResetOutputPin(TELEMETRY_DIR_GPIO, TELEMETRY_DIR_GPIO_PIN) #define TELEMETRY_DIR_INPUT() LL_GPIO_SetOutputPin(TELEMETRY_DIR_GPIO, TELEMETRY_DIR_GPIO_PIN) + #define TELEMETRY_SET_INPUT 1 #else #define TELEMETRY_DIR_OUTPUT() LL_GPIO_SetOutputPin(TELEMETRY_DIR_GPIO, TELEMETRY_DIR_GPIO_PIN) #define TELEMETRY_DIR_INPUT() LL_GPIO_ResetOutputPin(TELEMETRY_DIR_GPIO, TELEMETRY_DIR_GPIO_PIN) + #define TELEMETRY_SET_INPUT 0 #endif #define TELEMETRY_GPIO GPIOD #define TELEMETRY_TX_GPIO_PIN GPIO_Pin_5 // PD.05 @@ -1940,7 +1946,8 @@ #define TELEMETRY_GPIO_PinSource_RX GPIO_PinSource6 #define TELEMETRY_GPIO_AF GPIO_AF_USART2 #define TELEMETRY_USART USART2 -#define TELEMETRY_DMA_Stream_TX DMA1_Stream6 +#define TELEMETRY_DMA DMA1 +#define TELEMETRY_DMA_Stream_TX LL_DMA_STREAM_6 #define TELEMETRY_DMA_Channel_TX DMA_Channel_4 #define TELEMETRY_DMA_TX_Stream_IRQ DMA1_Stream6_IRQn #define TELEMETRY_DMA_TX_IRQHandler DMA1_Stream6_IRQHandler @@ -1958,6 +1965,7 @@ #endif #define TELEMETRY_TIMER TIM11 +#define TELEMETRY_TIMER_PRESCALER () #define TELEMETRY_TIMER_IRQn TIM1_TRG_COM_TIM11_IRQn #define TELEMETRY_TIMER_IRQHandler TIM1_TRG_COM_TIM11_IRQHandler @@ -2516,20 +2524,20 @@ #if defined(PCBX9E) #define STORAGE_BLUETOOTH #define BT_USART USART6 - #define BT_GPIO_AF GPIO_AF_USART6 + #define BT_GPIO_AF LL_GPIO_AF_8 #define BT_USART_IRQn USART6_IRQn #define BT_RCC_AHB1Periph (RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_GPIOE | RCC_AHB1Periph_GPIOG) #define BT_RCC_APB1Periph 0 #define BT_RCC_APB2Periph RCC_APB2Periph_USART6 #define BT_USART_GPIO GPIOG - #define BT_TX_GPIO_PIN GPIO_Pin_14 // PG.14 - #define BT_RX_GPIO_PIN GPIO_Pin_9 // PG.09 + #define BT_TX_GPIO_PIN LL_GPIO_PIN_14 // PG.14 + #define BT_RX_GPIO_PIN LL_GPIO_PIN_9 // PG.09 #define BT_EN_GPIO GPIOD - #define BT_EN_GPIO_PIN GPIO_Pin_11 // PD.11 - #define BT_BRTS_GPIO GPIOE - #define BT_BRTS_GPIO_PIN GPIO_Pin_12 // PE.12 - #define BT_BCTS_GPIO GPIOG - #define BT_BCTS_GPIO_PIN GPIO_Pin_6 // PG.06 + #define BT_EN_GPIO_PIN LL_GPIO_PIN_11 // PD.11 + // #define BT_BRTS_GPIO GPIOE + // #define BT_BRTS_GPIO_PIN GPIO_Pin_12 // PE.12 + // #define BT_BCTS_GPIO GPIOG + // #define BT_BCTS_GPIO_PIN GPIO_Pin_6 // PG.06 #define BT_TX_GPIO_PinSource GPIO_PinSource14 #define BT_RX_GPIO_PinSource GPIO_PinSource9 #define BT_USART_IRQHandler USART6_IRQHandler @@ -2540,26 +2548,26 @@ #if defined(PCBX9DP) #define BT_RCC_AHB1Periph (RCC_AHB1Periph_GPIOB) // RCC_AHB1Periph_DMA1 #define BT_EN_GPIO GPIOB - #define BT_EN_GPIO_PIN GPIO_Pin_2 // PB.02 + #define BT_EN_GPIO_PIN LL_GPIO_PIN_2 // PB.02 #elif defined(PCBXLITE) #define BT_RCC_AHB1Periph (RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOE) // RCC_AHB1Periph_DMA1 #define BT_EN_GPIO GPIOE - #define BT_EN_GPIO_PIN GPIO_Pin_15 // PE.15 + #define BT_EN_GPIO_PIN LL_GPIO_PIN_15 // PE.15 #elif defined(PCBX9LITES) #define BT_RCC_AHB1Periph (RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOD) // RCC_AHB1Periph_DMA1 #define BT_EN_GPIO GPIOD - #define BT_EN_GPIO_PIN GPIO_Pin_14 // PD.14 + #define BT_EN_GPIO_PIN LL_GPIO_PIN_14 // PD.14 #else #define BT_RCC_AHB1Periph (RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOE) // RCC_AHB1Periph_DMA1 #define BT_EN_GPIO GPIOE - #define BT_EN_GPIO_PIN GPIO_Pin_12 // PE.12 + #define BT_EN_GPIO_PIN LL_GPIO_PIN_12 // PE.12 #endif #define BT_USART_GPIO GPIOB - #define BT_TX_GPIO_PIN GPIO_Pin_10 // PB.10 - #define BT_RX_GPIO_PIN GPIO_Pin_11 // PB.11 + #define BT_TX_GPIO_PIN LL_GPIO_PIN_10 // PB.10 + #define BT_RX_GPIO_PIN LL_GPIO_PIN_11 // PB.11 #define BT_TX_GPIO_PinSource GPIO_PinSource10 #define BT_RX_GPIO_PinSource GPIO_PinSource11 - #define BT_GPIO_AF GPIO_AF_USART3 + #define BT_GPIO_AF LL_GPIO_AF_7 #define BT_USART USART3 #define BT_USART_IRQHandler USART3_IRQHandler #define BT_USART_IRQn USART3_IRQn diff --git a/radio/src/targets/taranis/intmodule_pulses_driver.cpp b/radio/src/targets/taranis/intmodule_pulses_driver.cpp index 11fa2f84a..a999df0bf 100644 --- a/radio/src/targets/taranis/intmodule_pulses_driver.cpp +++ b/radio/src/targets/taranis/intmodule_pulses_driver.cpp @@ -19,24 +19,29 @@ * GNU General Public License for more details. */ -#include "stm32_pulse_driver.h" +#include "intmodule_pulses_driver.h" #include "hal.h" #include "board.h" #include "timers_driver.h" -static const stm32_pulse_timer_t intmoduleTimer = { +#if defined(INTMODULE_TIMER) + +static stm32_pulse_dma_tc_cb_t _int_timer_DMA_TC_Callback; + +const stm32_pulse_timer_t intmoduleTimer = { .GPIOx = INTMODULE_TX_GPIO, .GPIO_Pin = INTMODULE_TX_GPIO_PIN, .GPIO_Alternate = INTMODULE_TX_GPIO_AF, .TIMx = INTMODULE_TIMER, - .TIM_Prescaler = __LL_TIM_CALC_PSC(INTMODULE_TIMER_FREQ, 2000000), + .TIM_Freq = INTMODULE_TIMER_FREQ, .TIM_Channel = INTMODULE_TIMER_Channel, .TIM_IRQn = INTMODULE_TIMER_IRQn, .DMAx = INTMODULE_TIMER_DMA, .DMA_Stream = INTMODULE_TIMER_DMA_STREAM, .DMA_Channel = INTMODULE_TIMER_DMA_CHANNEL, .DMA_IRQn = INTMODULE_TIMER_DMA_STREAM_IRQn, + .DMA_TC_CallbackPtr = &_int_timer_DMA_TC_Callback, }; // Make sure the timer channel is supported @@ -65,26 +70,4 @@ extern "C" void INTMODULE_TIMER_IRQHandler() stm32_pulse_tim_update_isr(&intmoduleTimer); } -void intmoduleStop() -{ - INTERNAL_MODULE_OFF(); - stm32_pulse_deinit(&intmoduleTimer); -} - -#if defined(PXX1) -void intmodulePxx1PulsesStart() -{ - INTERNAL_MODULE_ON(); - stm32_pulse_init(&intmoduleTimer); - stm32_pulse_config_output(&intmoduleTimer, false, LL_TIM_OCMODE_PWM1, 9 * 2); -} - -void intmoduleSendNextFramePxx1(const uint16_t* data, uint8_t size) -{ - if (!stm32_pulse_if_not_running_disable(&intmoduleTimer)) return; - - // Start DMA request and re-enable timer - stm32_pulse_start_dma_req(&intmoduleTimer, data, size, LL_TIM_OCMODE_PWM1, - 9 * 2); -} -#endif +#endif // INTMODULE_TIMER diff --git a/radio/src/targets/taranis/intmodule_pulses_driver.h b/radio/src/targets/taranis/intmodule_pulses_driver.h index 40c531c6d..284733cda 100644 --- a/radio/src/targets/taranis/intmodule_pulses_driver.h +++ b/radio/src/targets/taranis/intmodule_pulses_driver.h @@ -21,14 +21,7 @@ #pragma once -#if defined(PXX1) -void intmodulePxx1PulsesStart(); -void intmoduleSendNextFramePxx1(const uint16_t* data, uint8_t size); -#endif +#include "stm32_pulse_driver.h" -#if defined(INTERNAL_MODULE_PPM) -void intmodulePpmStart(); -void intmoduleSendNextFramePPM(const uint8_t* data, uint8_t size); -#endif - -void intmoduleStop(); +// used in module_ports.cpp +extern const stm32_pulse_timer_t intmoduleTimer; diff --git a/radio/src/targets/taranis/telemetry_driver.cpp b/radio/src/targets/taranis/telemetry_driver.cpp deleted file mode 100644 index 61baaf38a..000000000 --- a/radio/src/targets/taranis/telemetry_driver.cpp +++ /dev/null @@ -1,375 +0,0 @@ -/* - * Copyright (C) EdgeTX - * - * Based on code named - * opentx - https://github.com/opentx/opentx - * th9x - http://code.google.com/p/th9x - * er9x - http://code.google.com/p/er9x - * gruvin9x - http://code.google.com/p/gruvin9x - * - * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "stm32_hal_ll.h" -#include "stm32_exti_driver.h" -#include "aux_serial_driver.h" - -#include "opentx.h" - -#if defined(GHOST) - #include "telemetry/ghost.h" -#endif - -Fifo telemetryFifo; -uint32_t telemetryErrors = 0; - -static void telemetryInitDirPin() -{ - GPIO_InitTypeDef GPIO_InitStructure; - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; - GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; - GPIO_InitStructure.GPIO_Pin = TELEMETRY_DIR_GPIO_PIN; - GPIO_Init(TELEMETRY_DIR_GPIO, &GPIO_InitStructure); - TELEMETRY_DIR_INPUT(); -} - -void telemetryPortInit(uint32_t baudrate, uint8_t mode) -{ - if (baudrate == 0) { - USART_DeInit(TELEMETRY_USART); - return; - } - //deinit inverted mode - telemetryPortInvertedInit(0); - NVIC_InitTypeDef NVIC_InitStructure; - NVIC_InitStructure.NVIC_IRQChannel = TELEMETRY_DMA_TX_Stream_IRQ; - NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; - NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; /* Not used as 4 bits are used for the pre-emption priority. */; - NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; - NVIC_Init(&NVIC_InitStructure); - - GPIO_PinAFConfig(TELEMETRY_GPIO, TELEMETRY_GPIO_PinSource_TX, TELEMETRY_GPIO_AF); - GPIO_PinAFConfig(TELEMETRY_GPIO, TELEMETRY_GPIO_PinSource_RX, TELEMETRY_GPIO_AF); - - GPIO_InitTypeDef GPIO_InitStructure; - GPIO_InitStructure.GPIO_Pin = TELEMETRY_TX_GPIO_PIN | TELEMETRY_RX_GPIO_PIN; - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; - GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; - GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; - GPIO_InitStructure.GPIO_Speed = baudrate <= 400000 ? GPIO_Speed_2MHz : GPIO_Speed_25MHz; - GPIO_Init(TELEMETRY_GPIO, &GPIO_InitStructure); - - telemetryInitDirPin(); - - USART_DeInit(TELEMETRY_USART); - - USART_OverSampling8Cmd(TELEMETRY_USART, baudrate <= 400000 ? DISABLE : ENABLE); - - USART_InitTypeDef USART_InitStructure; - USART_InitStructure.USART_BaudRate = baudrate; - if (mode & TELEMETRY_SERIAL_8E2) { - USART_InitStructure.USART_WordLength = USART_WordLength_9b; - USART_InitStructure.USART_StopBits = USART_StopBits_2; - USART_InitStructure.USART_Parity = USART_Parity_Even; - } - else { - USART_InitStructure.USART_WordLength = USART_WordLength_8b; - USART_InitStructure.USART_StopBits = USART_StopBits_1; - USART_InitStructure.USART_Parity = USART_Parity_No; - } - USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; - USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; - if (g_eeGeneral.uartSampleMode == UART_SAMPLE_MODE_ONEBIT) { - USART_OneBitMethodCmd(TELEMETRY_USART, ENABLE); - } - USART_Init(TELEMETRY_USART, &USART_InitStructure); - USART_Cmd(TELEMETRY_USART, ENABLE); - - USART_ITConfig(TELEMETRY_USART, USART_IT_RXNE, ENABLE); - NVIC_SetPriority(TELEMETRY_USART_IRQn, 6); - NVIC_EnableIRQ(TELEMETRY_USART_IRQn); -} - -// soft serial vars -static uint8_t rxBitCount; -static uint8_t rxByte; -// single bit length expresses in half us -static uint16_t bitLength; -static uint16_t probeTimeFromStartBit; - -static void do_telemetry_exti() -{ - if (rxBitCount == 0) { - - TELEMETRY_TIMER->ARR = probeTimeFromStartBit; // 1,5 cycle from start at 57600bps - TELEMETRY_TIMER->CR1 |= TIM_CR1_CEN; - - // disable start bit interrupt - EXTI->IMR &= ~EXTI_IMR_MR6; - } -} - -void telemetryPortInvertedInit(uint32_t baudrate) -{ - if (baudrate == 0) { - - stm32_exti_disable(TELEMETRY_EXTI_LINE); - NVIC_DisableIRQ(TELEMETRY_TIMER_IRQn); - return; - } - - rxBitCount = 0; - - switch(baudrate) { - case 115200: - bitLength = 17; - probeTimeFromStartBit = 25; - break; - case 57600: - bitLength = 35; - probeTimeFromStartBit = 48; - break; - default: - bitLength = 2000000/baudrate; //because of 0,5 us tick - probeTimeFromStartBit = 3000000/baudrate; - } - - // configure bit sample timer - TELEMETRY_TIMER->PSC = (PERI2_FREQUENCY * TIMER_MULT_APB2) / 2000000 - 1; // 0.5uS - TELEMETRY_TIMER->CCER = 0; - TELEMETRY_TIMER->CCMR1 = 0; - TELEMETRY_TIMER->CR1 = TIM_CR1_CEN; - TELEMETRY_TIMER->DIER = TIM_DIER_UIE; - - NVIC_SetPriority(TELEMETRY_TIMER_IRQn, 0); - NVIC_EnableIRQ(TELEMETRY_TIMER_IRQn); - - // init TELEMETRY_RX_GPIO_PIN - GPIO_InitTypeDef GPIO_InitStructure; - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; - GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; - GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN; - GPIO_InitStructure.GPIO_Pin = TELEMETRY_RX_GPIO_PIN; - GPIO_Init(TELEMETRY_GPIO, &GPIO_InitStructure); - - telemetryInitDirPin(); - - // Connect EXTI line to TELEMETRY RX pin - LL_SYSCFG_SetEXTISource(TELEMETRY_EXTI_PORT, TELEMETRY_EXTI_SYS_LINE); - - // Configure EXTI for raising edge (start bit) - stm32_exti_enable(TELEMETRY_EXTI_LINE, TELEMETRY_EXTI_TRIGGER, do_telemetry_exti); -} - -void telemetryPortInvertedRxBit() -{ - if (rxBitCount < 8) { - if (rxBitCount == 0) { - TELEMETRY_TIMER->ARR = bitLength; - rxByte = 0; - } - else { - rxByte >>= 1; - } - - if (GPIO_ReadInputDataBit(TELEMETRY_GPIO, TELEMETRY_RX_GPIO_PIN) == Bit_RESET) - rxByte |= 0x80; - - ++rxBitCount; - } - else if (rxBitCount == 8) { - - telemetryFifo.push(rxByte); - rxBitCount = 0; - - // disable timer - TELEMETRY_TIMER->CR1 &= ~TIM_CR1_CEN; - - // re-enable start bit interrupt - EXTI->IMR |= EXTI_IMR_MR6; - } -} - -void telemetryPortSetDirectionOutput() -{ -#if defined(GHOST) && SPORT_MAX_BAUDRATE < 400000 - if (isModuleGhost(EXTERNAL_MODULE)) { - TELEMETRY_USART->BRR = BRR_400K; - } -#endif - TELEMETRY_DIR_OUTPUT(); - TELEMETRY_USART->CR1 &= ~USART_CR1_RE; // turn off receiver -} - -void sportWaitTransmissionComplete() -{ - while (!(TELEMETRY_USART->SR & USART_SR_TC)); -} - -void telemetryPortSetDirectionInput() -{ - sportWaitTransmissionComplete(); -#if defined(GHOST) && SPORT_MAX_BAUDRATE < 400000 - if (isModuleGhost(EXTERNAL_MODULE) && g_model.moduleData[EXTERNAL_MODULE].ghost.telemetryBaudrate == GHST_TELEMETRY_RATE_115K) { - TELEMETRY_USART->BRR = BRR_115K; - } -#endif - TELEMETRY_DIR_INPUT(); - TELEMETRY_USART->CR1 |= USART_CR1_RE; // turn on receiver -} - -void sportSendByte(uint8_t byte) -{ - telemetryPortSetDirectionOutput(); - - while (!(TELEMETRY_USART->SR & USART_SR_TXE)); - USART_SendData(TELEMETRY_USART, byte); -} - -void sportStopSendByteLoop() -{ - DMA_Cmd(TELEMETRY_DMA_Stream_TX, DISABLE); - DMA_DeInit(TELEMETRY_DMA_Stream_TX); -} - -void sportSendByteLoop(uint8_t byte) -{ - telemetryPortSetDirectionOutput(); - - outputTelemetryBuffer.data[0] = byte; - - DMA_InitTypeDef DMA_InitStructure; - DMA_DeInit(TELEMETRY_DMA_Stream_TX); - DMA_InitStructure.DMA_Channel = TELEMETRY_DMA_Channel_TX; - DMA_InitStructure.DMA_PeripheralBaseAddr = CONVERT_PTR_UINT(&TELEMETRY_USART->DR); - DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; - DMA_InitStructure.DMA_Memory0BaseAddr = CONVERT_PTR_UINT(outputTelemetryBuffer.data); - DMA_InitStructure.DMA_BufferSize = 1; - DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; - DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable; - DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; - DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; - DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; - DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; - DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; - DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full; - DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; - DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; - DMA_Init(TELEMETRY_DMA_Stream_TX, &DMA_InitStructure); - DMA_Cmd(TELEMETRY_DMA_Stream_TX, ENABLE); - USART_DMACmd(TELEMETRY_USART, USART_DMAReq_Tx, ENABLE); -} - -void sportSendBuffer(const uint8_t * buffer, uint32_t count) -{ - telemetryPortSetDirectionOutput(); - - DMA_InitTypeDef DMA_InitStructure; - DMA_DeInit(TELEMETRY_DMA_Stream_TX); - DMA_InitStructure.DMA_Channel = TELEMETRY_DMA_Channel_TX; - DMA_InitStructure.DMA_PeripheralBaseAddr = CONVERT_PTR_UINT(&TELEMETRY_USART->DR); - DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; - DMA_InitStructure.DMA_Memory0BaseAddr = CONVERT_PTR_UINT(buffer); - DMA_InitStructure.DMA_BufferSize = count; - DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; - DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; - DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; - DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; - DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; - DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; - DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; - DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full; - DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; - DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; - DMA_Init(TELEMETRY_DMA_Stream_TX, &DMA_InitStructure); - DMA_Cmd(TELEMETRY_DMA_Stream_TX, ENABLE); - USART_DMACmd(TELEMETRY_USART, USART_DMAReq_Tx, ENABLE); - DMA_ITConfig(TELEMETRY_DMA_Stream_TX, DMA_IT_TC, ENABLE); - USART_ClearITPendingBit(TELEMETRY_USART, USART_IT_TC); - - // enable interrupt and set it's priority - NVIC_EnableIRQ(TELEMETRY_DMA_TX_Stream_IRQ) ; - NVIC_SetPriority(TELEMETRY_DMA_TX_Stream_IRQ, 7); -} - -extern "C" void TELEMETRY_DMA_TX_IRQHandler(void) -{ - DEBUG_INTERRUPT(INT_TELEM_DMA); - if (DMA_GetITStatus(TELEMETRY_DMA_Stream_TX, TELEMETRY_DMA_TX_FLAG_TC)) { - DMA_ClearITPendingBit(TELEMETRY_DMA_Stream_TX, TELEMETRY_DMA_TX_FLAG_TC); - - // clear TC flag before enabling interrupt - TELEMETRY_USART->SR &= ~USART_SR_TC; - TELEMETRY_USART->CR1 |= USART_CR1_TCIE; - - if (telemetryProtocol == PROTOCOL_TELEMETRY_FRSKY_SPORT) { - outputTelemetryBuffer.reset(); - } - } -} - -#define USART_FLAG_ERRORS (USART_FLAG_ORE | USART_FLAG_NE | USART_FLAG_FE | USART_FLAG_PE) -extern "C" void TELEMETRY_USART_IRQHandler(void) -{ - DEBUG_INTERRUPT(INT_TELEM_USART); - uint32_t status = TELEMETRY_USART->SR; - - if ((status & USART_SR_TC) && (TELEMETRY_USART->CR1 & USART_CR1_TCIE)) { - TELEMETRY_USART->CR1 &= ~USART_CR1_TCIE; - telemetryPortSetDirectionInput(); - while (status & (USART_FLAG_RXNE)) { - status = TELEMETRY_USART->DR; - status = TELEMETRY_USART->SR; - } - } - - while (status & (USART_FLAG_RXNE | USART_FLAG_ERRORS)) { - uint8_t data = TELEMETRY_USART->DR; - if (status & USART_FLAG_ERRORS) { - telemetryErrors++; - } - else { - telemetryFifo.push(data); -#if defined(LUA) - if (telemetryProtocol == PROTOCOL_TELEMETRY_FRSKY_SPORT) { - static uint8_t prevdata; - if (prevdata == 0x7E && outputTelemetryBuffer.destination == TELEMETRY_ENDPOINT_SPORT && data == outputTelemetryBuffer.sport.physicalId) { - sportSendBuffer(outputTelemetryBuffer.data + 1, outputTelemetryBuffer.size - 1); - } - prevdata = data; - } -#endif - } - status = TELEMETRY_USART->SR; - } -} - -extern "C" void TELEMETRY_TIMER_IRQHandler() -{ - TELEMETRY_TIMER->SR &= ~TIM_SR_UIF; - telemetryPortInvertedRxBit(); -} - -// TODO: we should have telemetry in an higher layer, -// functions above should move to a sport_driver.cpp -// -bool sportGetByte(uint8_t * byte) -{ - return telemetryFifo.pop(*byte); -} - -void telemetryClearFifo() -{ - telemetryFifo.clear(); -} diff --git a/radio/src/tasks.cpp b/radio/src/tasks.cpp index bed5b9018..08ac269f2 100644 --- a/radio/src/tasks.cpp +++ b/radio/src/tasks.cpp @@ -20,158 +20,18 @@ */ #include "opentx.h" -#include "mixer_scheduler.h" #include "timers_driver.h" +#include "tasks.h" +#include "tasks/mixer_task.h" + RTOS_TASK_HANDLE menusTaskId; RTOS_DEFINE_STACK(menusTaskId, menusStack, MENUS_STACK_SIZE); -RTOS_TASK_HANDLE mixerTaskId; -RTOS_DEFINE_STACK(mixerTaskId, mixerStack, MIXER_STACK_SIZE); - RTOS_TASK_HANDLE audioTaskId; RTOS_DEFINE_STACK(audioTaskId, audioStack, AUDIO_STACK_SIZE); RTOS_MUTEX_HANDLE audioMutex; -RTOS_MUTEX_HANDLE mixerMutex; - -volatile uint16_t timeForcePowerOffPressed = 0; - -bool isForcePowerOffRequested() -{ - if (pwrOffPressed()) { - if (timeForcePowerOffPressed == 0) { - timeForcePowerOffPressed = get_tmr10ms(); - } - else { - uint16_t delay = (uint16_t)get_tmr10ms() - timeForcePowerOffPressed; - if (delay > 1000/*10s*/) { - return true; - } - } - } - else { - resetForcePowerOffRequest(); - } - return false; -} - -void sendSynchronousPulses(uint8_t runMask) -{ -#if defined(HARDWARE_INTERNAL_MODULE) - if (runMask & (1 << INTERNAL_MODULE)) { - if (setupPulsesInternalModule()) - intmoduleSendNextFrame(); - } -#endif - -#if defined(HARDWARE_EXTERNAL_MODULE) - if (runMask & (1 << EXTERNAL_MODULE)) { - if (setupPulsesExternalModule()) - extmoduleSendNextFrame(); - } -#endif -} - -constexpr uint8_t MIXER_FREQUENT_ACTIONS_PERIOD = 5 /*ms*/; -constexpr uint8_t MIXER_MAX_PERIOD = MAX_REFRESH_RATE / 1000 /*ms*/; - -void execMixerFrequentActions() -{ -#if defined(SBUS_TRAINER) - // SBUS trainer - processSbusInput(); -#endif - -#if defined(IMU) - gyro.wakeup(); -#endif - -#if defined(BLUETOOTH) - bluetooth.wakeup(); -#endif - -#if defined(SIMU) - if (!s_pulses_paused) { - DEBUG_TIMER_START(debugTimerTelemetryWakeup); - telemetryWakeup(); - DEBUG_TIMER_STOP(debugTimerTelemetryWakeup); - } -#endif -} - -TASK_FUNCTION(mixerTask) -{ - s_pulses_paused = true; - - mixerSchedulerInit(); - mixerSchedulerStart(); - - while (true) { - int timeout = 0; - for (; timeout < MIXER_MAX_PERIOD; timeout += MIXER_FREQUENT_ACTIONS_PERIOD) { - - // run periodicals before waiting for the trigger - // to keep the delay short - execMixerFrequentActions(); - - // mixer flag triggered? - if (!mixerSchedulerWaitForTrigger(MIXER_FREQUENT_ACTIONS_PERIOD)) { - break; - } - } - -#if defined(DEBUG_MIXER_SCHEDULER) - GPIO_SetBits(EXTMODULE_TX_GPIO, EXTMODULE_TX_GPIO_PIN); - GPIO_ResetBits(EXTMODULE_TX_GPIO, EXTMODULE_TX_GPIO_PIN); -#endif - - // re-enable trigger - mixerSchedulerEnableTrigger(); - -#if defined(SIMU) - if (pwrCheck() == e_power_off) { - TASK_RETURN(); - } -#else - if (isForcePowerOffRequested()) { - boardOff(); - } -#endif - - if (!s_pulses_paused) { - uint16_t t0 = getTmr2MHz(); - - DEBUG_TIMER_START(debugTimerMixer); - RTOS_LOCK_MUTEX(mixerMutex); - - doMixerCalculations(); - sendSynchronousPulses((1 << INTERNAL_MODULE) | (1 << EXTERNAL_MODULE)); - doMixerPeriodicUpdates(); - - DEBUG_TIMER_START(debugTimerMixerCalcToUsage); - DEBUG_TIMER_SAMPLE(debugTimerMixerIterval); - RTOS_UNLOCK_MUTEX(mixerMutex); - DEBUG_TIMER_STOP(debugTimerMixer); - -#if defined(STM32) && !defined(SIMU) - if (getSelectedUsbMode() == USB_JOYSTICK_MODE) { - usbJoystickUpdate(); - } -#endif - - if (heartbeat == HEART_WDT_CHECK) { - WDG_RESET(); - heartbeat = 0; - } - - t0 = getTmr2MHz() - t0; - if (t0 > maxMixerDuration) - maxMixerDuration = t0; - } - } -} - #define MENU_TASK_PERIOD_TICKS (50 / RTOS_MS_PER_TICK) // 50ms @@ -254,14 +114,13 @@ TASK_FUNCTION(menusTask) void tasksStart() { RTOS_CREATE_MUTEX(audioMutex); - RTOS_CREATE_MUTEX(mixerMutex); #if defined(CLI) && !defined(SIMU) cliStart(); #endif - RTOS_CREATE_TASK(mixerTaskId, mixerTask, "mixer", mixerStack, - MIXER_STACK_SIZE, MIXER_TASK_PRIO); + mixerTaskInit(); + RTOS_CREATE_TASK(menusTaskId, menusTask, "menus", menusStack, MENUS_STACK_SIZE, MENUS_TASK_PRIO); diff --git a/radio/src/tasks.h b/radio/src/tasks.h index 17e8d13f7..0e6181e56 100644 --- a/radio/src/tasks.h +++ b/radio/src/tasks.h @@ -47,19 +47,11 @@ #endif -extern RTOS_MUTEX_HANDLE mixerMutex; - -extern RTOS_TASK_HANDLE menusTaskId; extern TaskStack menusStack; - -extern RTOS_TASK_HANDLE mixerTaskId; extern TaskStack mixerStack; - -extern RTOS_TASK_HANDLE audioTaskId; extern TaskStack audioStack; #if defined(CLI) -extern RTOS_TASK_HANDLE cliTaskId; extern TaskStack cliStack; #endif diff --git a/radio/src/tasks/mixer_task.cpp b/radio/src/tasks/mixer_task.cpp new file mode 100644 index 000000000..2ac5415d6 --- /dev/null +++ b/radio/src/tasks/mixer_task.cpp @@ -0,0 +1,243 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "tasks.h" +#include "mixer_task.h" +#include "mixer_scheduler.h" + +#include "opentx.h" + +RTOS_TASK_HANDLE mixerTaskId; +RTOS_DEFINE_STACK(mixerTaskId, mixerStack, MIXER_STACK_SIZE); + +// mixer hold this mutex while computing +// channels and sending them out +static RTOS_MUTEX_HANDLE mixerMutex; + +// The mixer will start in 'paused' mode +// and start working properly once +// mixerTaskStart() has been called. +static bool _mixer_running = false; +static bool _mixer_exit = false; + +void mixerTaskLock() +{ + RTOS_LOCK_MUTEX(mixerMutex); +} + +// returns true if the lock could be acquired +bool mixerTaskTryLock() +{ + return RTOS_TRYLOCK_MUTEX(mixerMutex); +} + +void mixerTaskUnlock() +{ + RTOS_UNLOCK_MUTEX(mixerMutex); +} + +void mixerTaskInit() +{ + RTOS_CREATE_MUTEX(mixerMutex); + RTOS_CREATE_TASK(mixerTaskId, mixerTask, "mixer", mixerStack, + MIXER_STACK_SIZE, MIXER_TASK_PRIO); +} + +void mixerTaskStart() +{ + _mixer_running = true; +} + +void mixerTaskStop() +{ + mixerTaskLock(); + _mixer_running = false; + mixerTaskUnlock(); +} + +void mixerTaskExit() +{ + _mixer_exit = true; +} + +bool mixerTaskRunning() +{ + return _mixer_running && !_mixer_exit; +} + +volatile uint16_t timeForcePowerOffPressed = 0; + +bool isForcePowerOffRequested() +{ + if (pwrOffPressed()) { + if (timeForcePowerOffPressed == 0) { + timeForcePowerOffPressed = get_tmr10ms(); + } + else { + uint16_t delay = (uint16_t)get_tmr10ms() - timeForcePowerOffPressed; + if (delay > 1000/*10s*/) { + return true; + } + } + } + else { + resetForcePowerOffRequest(); + } + return false; +} + +constexpr uint8_t MIXER_FREQUENT_ACTIONS_PERIOD = 5 /*ms*/; +constexpr uint8_t MIXER_MAX_PERIOD = MAX_REFRESH_RATE / 1000 /*ms*/; + +void execMixerFrequentActions() +{ +#if defined(SBUS_TRAINER) + // SBUS trainer + processSbusInput(); +#endif + +#if defined(IMU) + gyro.wakeup(); +#endif + +#if defined(BLUETOOTH) + bluetooth.wakeup(); +#endif + +#if defined(SIMU) + if (!_mixer_running) { + DEBUG_TIMER_START(debugTimerTelemetryWakeup); + telemetryWakeup(); + DEBUG_TIMER_STOP(debugTimerTelemetryWakeup); + } +#endif +} + +TASK_FUNCTION(mixerTask) +{ + mixerSchedulerInit(); + mixerSchedulerStart(); + + while (!_mixer_exit) { + + int timeout = 0; + for (; timeout < MIXER_MAX_PERIOD; timeout += MIXER_FREQUENT_ACTIONS_PERIOD) { + + // run periodicals before waiting for the trigger + // to keep the delay short + execMixerFrequentActions(); + + // mixer flag triggered? + if (!mixerSchedulerWaitForTrigger(MIXER_FREQUENT_ACTIONS_PERIOD)) { + break; + } + } + +#if defined(DEBUG_MIXER_SCHEDULER) + GPIO_SetBits(EXTMODULE_TX_GPIO, EXTMODULE_TX_GPIO_PIN); + GPIO_ResetBits(EXTMODULE_TX_GPIO, EXTMODULE_TX_GPIO_PIN); +#endif + + // re-enable trigger + mixerSchedulerEnableTrigger(); + +#if defined(SIMU) + // TODO: should be using mixerTaskExit() instead... + if (pwrCheck() == e_power_off) { + TASK_RETURN(); + } +#else + // Emergency power OFF: in case the UI is not functional anymore + // or maybe locked, this will effectively shutdown and cut power. + if (isForcePowerOffRequested()) { + boardOff(); + } +#endif + + if (_mixer_running) { + + uint16_t t0 = getTmr2MHz(); + + DEBUG_TIMER_START(debugTimerMixer); + mixerTaskLock(); + + doMixerCalculations(); + pulsesSendChannels(); + doMixerPeriodicUpdates(); + + // TODO: what are these for??? + DEBUG_TIMER_START(debugTimerMixerCalcToUsage); + DEBUG_TIMER_SAMPLE(debugTimerMixerIterval); + + mixerTaskUnlock(); + DEBUG_TIMER_STOP(debugTimerMixer); + +#if defined(STM32) && !defined(SIMU) + if (getSelectedUsbMode() == USB_JOYSTICK_MODE) { + usbJoystickUpdate(); + } +#endif + + // we are the main actor to reset the watchdog timer + // so let's do it here. + WDG_RESET(); + + t0 = getTmr2MHz() - t0; + if (t0 > maxMixerDuration) + maxMixerDuration = t0; + } + } + + TASK_RETURN(); +} + +void doMixerCalculations() +{ + static tmr10ms_t lastTMR = 0; + + tmr10ms_t tmr10ms = get_tmr10ms(); + +#if defined(DEBUG_LATENCY_MIXER_RF) || defined(DEBUG_LATENCY_RF_ONLY) + static tmr10ms_t lastLatencyToggle = 0; + if (tmr10ms - lastLatencyToggle >= 10) { + lastLatencyToggle = tmr10ms; + toggleLatencySwitch(); + } +#endif + + uint8_t tick10ms = (tmr10ms >= lastTMR ? tmr10ms - lastTMR : 1); + // handle tick10ms overrun + // correct overflow handling costs a lot of code; happens only each 11 min; + // therefore forget the exact calculation and use only 1 instead; good compromise + lastTMR = tmr10ms; + + DEBUG_TIMER_START(debugTimerGetAdc); + getADC(); + DEBUG_TIMER_STOP(debugTimerGetAdc); + + DEBUG_TIMER_START(debugTimerGetSwitches); + getSwitchesPosition(!s_mixer_first_run_done); + DEBUG_TIMER_STOP(debugTimerGetSwitches); + + DEBUG_TIMER_START(debugTimerEvalMixes); + evalMixes(tick10ms); + DEBUG_TIMER_STOP(debugTimerEvalMixes); +} diff --git a/radio/src/tasks/mixer_task.h b/radio/src/tasks/mixer_task.h new file mode 100644 index 000000000..e371c6744 --- /dev/null +++ b/radio/src/tasks/mixer_task.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "rtos.h" + +// needed by the mixer scheduler +extern RTOS_TASK_HANDLE mixerTaskId; + +// function running the mixer task +TASK_FUNCTION(mixerTask); + +// init, create and start the OS task itself +void mixerTaskInit(); + +// start the main computations +// and pushing channels out +// +// Please note: there is no guarantee as to when the next computation +// will be running. This is merely settings a flag allowing +// the main loop to run. +// +void mixerTaskStart(); + +// stop the mixer (without exiting). It can be restarted at +// any moment with `mixerTaskStart()`. +// +// Please note: the mixer computation and channel pushing is guaranteed +// to be stoppped as we lock the main mutex when setting +// the running flag. This means that mixer data and modules +// can be handled safely without interferences. +// +void mixerTaskStop(); + + +// exit the mixer forever. +// +// This is probably only useful for simulations as it is not needed to really +// exit the task under any normal conditions. There are no guarantees as to when +// the exit will happen, only that it will eventually happen. +// +void mixerTaskExit(); + +// hint at whether or not the mixer task should be running +// +// Please note: there is no guarantee on anything, this is just returning +// a combination of running and exit flags. +// +bool mixerTaskRunning(); + +// +// Lock / unlock functions: use with care! +// +void mixerTaskLock(); +void mixerTaskUnlock(); + +// returns true if the lock could be acquired +bool mixerTaskTryLock(); + diff --git a/radio/src/telemetry/crossfire.cpp b/radio/src/telemetry/crossfire.cpp index f51ce1b49..5bb6eca16 100644 --- a/radio/src/telemetry/crossfire.cpp +++ b/radio/src/telemetry/crossfire.cpp @@ -22,7 +22,6 @@ #include "crossfire.h" #include "opentx.h" -#include "aux_serial_driver.h" const CrossfireSensor crossfireSensors[] = { {LINK_ID, 0, STR_SENSOR_RX_RSSI1, UNIT_DB, 0}, @@ -62,19 +61,19 @@ const CrossfireSensor crossfireSensors[] = { const CrossfireSensor & getCrossfireSensor(uint8_t id, uint8_t subId) { if (id == LINK_ID) - return crossfireSensors[RX_RSSI1_INDEX+subId]; + return crossfireSensors[RX_RSSI1_INDEX + subId]; else if (id == LINK_RX_ID) - return crossfireSensors[RX_RSSI_PERC_INDEX+subId]; + return crossfireSensors[RX_RSSI_PERC_INDEX + subId]; else if (id == LINK_TX_ID) - return crossfireSensors[TX_RSSI_PERC_INDEX+subId]; + return crossfireSensors[TX_RSSI_PERC_INDEX + subId]; else if (id == BATTERY_ID) - return crossfireSensors[BATT_VOLTAGE_INDEX+subId]; + return crossfireSensors[BATT_VOLTAGE_INDEX + subId]; else if (id == GPS_ID) - return crossfireSensors[GPS_LATITUDE_INDEX+subId]; + return crossfireSensors[GPS_LATITUDE_INDEX + subId]; else if (id == CF_VARIO_ID) return crossfireSensors[VERTICAL_SPEED_INDEX]; else if (id == ATTITUDE_ID) - return crossfireSensors[ATTITUDE_PITCH_INDEX+subId]; + return crossfireSensors[ATTITUDE_PITCH_INDEX + subId]; else if (id == FLIGHT_MODE_ID) return crossfireSensors[FLIGHT_MODE_INDEX]; else if (id == BARO_ALT_ID) diff --git a/radio/src/telemetry/crossfire.h b/radio/src/telemetry/crossfire.h index c8a4ba07e..e2c238817 100644 --- a/radio/src/telemetry/crossfire.h +++ b/radio/src/telemetry/crossfire.h @@ -141,9 +141,26 @@ const uint8_t CROSSFIRE_FRAME_PERIODS[] = { % DIM(CROSSFIRE_BAUDRATES) #endif -#define INT_CROSSFIRE_BAUDRATE CROSSFIRE_BAUDRATES[CROSSFIRE_STORE_TO_INDEX(g_eeGeneral.internalModuleBaudrate)] -#define EXT_CROSSFIRE_BAUDRATE CROSSFIRE_BAUDRATES[CROSSFIRE_STORE_TO_INDEX(g_model.moduleData[EXTERNAL_MODULE].crsf.telemetryBaudrate)] -#define CROSSFIRE_PERIOD (CROSSFIRE_FRAME_PERIODS[CROSSFIRE_STORE_TO_INDEX(g_model.moduleData[EXTERNAL_MODULE].crsf.telemetryBaudrate)] * 1000) +#if defined(HARDWARE_INTERNAL_MODULE) +#define INT_CROSSFIRE_BR_IDX CROSSFIRE_STORE_TO_INDEX(g_eeGeneral.internalModuleBaudrate) +#define INT_CROSSFIRE_BAUDRATE CROSSFIRE_BAUDRATES[INT_CROSSFIRE_BR_IDX] +#define INT_CROSSFIRE_PERIOD (CROSSFIRE_FRAME_PERIODS[INT_CROSSFIRE_BR_IDX] * 1000) +#endif + +#if defined(HARDWARE_EXTERNAL_MODULE) +#define EXT_CROSSFIRE_BR_IDX CROSSFIRE_STORE_TO_INDEX(g_model.moduleData[EXTERNAL_MODULE].crsf.telemetryBaudrate) +#define EXT_CROSSFIRE_BAUDRATE CROSSFIRE_BAUDRATES[EXT_CROSSFIRE_BR_IDX] +#define EXT_CROSSFIRE_PERIOD (CROSSFIRE_FRAME_PERIODS[EXT_CROSSFIRE_BR_IDX] * 1000) +#endif + +#if defined(HARDWARE_INTERNAL_MODULE) && defined(HARDWARE_EXTERNAL_MODULE) +#define CROSSFIRE_PERIOD(module) \ + (module == INTERNAL_MODULE ? INT_CROSSFIRE_PERIOD : EXT_CROSSFIRE_PERIOD) +#elif defined(HARDWARE_INTERNAL_MODULE) +#define CROSSFIRE_PERIOD(module) INT_CROSSFIRE_PERIOD +#elif defined(HARDWARE_EXTERNAL_MODULE) +#define CROSSFIRE_PERIOD(module) EXT_CROSSFIRE_PERIOD +#endif #define CROSSFIRE_TELEM_MIRROR_BAUDRATE 115200 diff --git a/radio/src/telemetry/flysky_nv14.cpp b/radio/src/telemetry/flysky_nv14.cpp index f75594e17..ce2f7942f 100644 --- a/radio/src/telemetry/flysky_nv14.cpp +++ b/radio/src/telemetry/flysky_nv14.cpp @@ -22,6 +22,7 @@ #include "opentx.h" #include "flysky_nv14.h" #include "flysky_ibus.h" +#include "pulses/afhds2.h" #include "dataconstants.h" diff --git a/radio/src/telemetry/frsky.cpp b/radio/src/telemetry/frsky.cpp index f6a35f5a8..412442803 100644 --- a/radio/src/telemetry/frsky.cpp +++ b/radio/src/telemetry/frsky.cpp @@ -20,35 +20,23 @@ */ #include "opentx.h" -#include "aux_serial_driver.h" -void processFrskyTelemetryData(uint8_t data) -{ - if (pushFrskyTelemetryData(data)) { - if (IS_FRSKY_SPORT_PROTOCOL()) { - sportProcessTelemetryPacket(telemetryRxBuffer); - } - else { - frskyDProcessPacket(telemetryRxBuffer); - } - } -} - -bool pushFrskyTelemetryData(uint8_t data) +static inline bool pushFrskyTelemetryData(bool is_sport, uint8_t data, + uint8_t* buffer, uint8_t& len) { static uint8_t dataState = STATE_DATA_IDLE; switch (dataState) { case STATE_DATA_START: if (data == START_STOP) { - if (IS_FRSKY_SPORT_PROTOCOL()) { + if (is_sport) { dataState = STATE_DATA_IN_FRAME ; - telemetryRxBufferCount = 0; + len = 0; } } else { - if (telemetryRxBufferCount < TELEMETRY_RX_PACKET_SIZE) { - telemetryRxBuffer[telemetryRxBufferCount++] = data; + if (len < TELEMETRY_RX_PACKET_SIZE) { + buffer[len++] = data; } dataState = STATE_DATA_IN_FRAME; } @@ -59,39 +47,38 @@ bool pushFrskyTelemetryData(uint8_t data) dataState = STATE_DATA_XOR; // XOR next byte } else if (data == START_STOP) { - if (IS_FRSKY_SPORT_PROTOCOL()) { + if (is_sport) { dataState = STATE_DATA_IN_FRAME ; - telemetryRxBufferCount = 0; - } - else { + len = 0; + } else { // end of frame detected dataState = STATE_DATA_IDLE; return true; } break; } - else if (telemetryRxBufferCount < TELEMETRY_RX_PACKET_SIZE) { - telemetryRxBuffer[telemetryRxBufferCount++] = data; + else if (len < TELEMETRY_RX_PACKET_SIZE) { + buffer[len++] = data; } break; case STATE_DATA_XOR: - if (telemetryRxBufferCount < TELEMETRY_RX_PACKET_SIZE) { - telemetryRxBuffer[telemetryRxBufferCount++] = data ^ STUFF_MASK; + if (len < TELEMETRY_RX_PACKET_SIZE) { + buffer[len++] = data ^ STUFF_MASK; } dataState = STATE_DATA_IN_FRAME; break; case STATE_DATA_IDLE: if (data == START_STOP) { - telemetryRxBufferCount = 0; + len = 0; dataState = STATE_DATA_START; } break; } // switch - if (IS_FRSKY_SPORT_PROTOCOL() && telemetryRxBufferCount >= FRSKY_SPORT_PACKET_SIZE) { + if (is_sport && len >= FRSKY_SPORT_PACKET_SIZE) { // end of frame detected dataState = STATE_DATA_IDLE; return true; @@ -100,4 +87,16 @@ bool pushFrskyTelemetryData(uint8_t data) return false; } +void processFrskyDTelemetryData(uint8_t module, uint8_t data, uint8_t* buffer, uint8_t& len) +{ + if (pushFrskyTelemetryData(false, data, buffer, len)) { + frskyDProcessPacket(module, buffer, len); + } +} +void processFrskySportTelemetryData(uint8_t module, uint8_t data, uint8_t* buffer, uint8_t& len) +{ + if (pushFrskyTelemetryData(true, data, buffer, len)) { + sportProcessTelemetryPacket(module, buffer, len); + } +} diff --git a/radio/src/telemetry/frsky.h b/radio/src/telemetry/frsky.h index 939294f43..7f41de378 100644 --- a/radio/src/telemetry/frsky.h +++ b/radio/src/telemetry/frsky.h @@ -95,16 +95,21 @@ typedef enum { // FrSky D Telemetry Protocol void processHubPacket(uint8_t id, int16_t value); -void frskyDProcessPacket(const uint8_t *packet); +void frskyDProcessPacket(uint8_t module, const uint8_t *packet, uint8_t len); // FrSky S.PORT Telemetry Protocol -bool sportProcessTelemetryPacket(const uint8_t * packet); +bool sportProcessTelemetryPacket(uint8_t module, const uint8_t * packet, uint8_t len); void sportProcessTelemetryPacket(uint16_t id, uint8_t subId, uint8_t instance, uint32_t data, TelemetryUnit unit = UNIT_RAW); -void sportProcessTelemetryPacketWithoutCrc(uint8_t origin, const uint8_t *packet); -bool pushFrskyTelemetryData(uint8_t data); // returns true when end of frame detected -void processFrskyTelemetryData(uint8_t data); +void sportProcessTelemetryPacketWithoutCrc(uint8_t module, uint8_t origin, + const uint8_t *packet); + +void processFrskySportTelemetryData(uint8_t module, uint8_t data, + uint8_t* buffer, uint8_t& len); + +void processFrskyDTelemetryData(uint8_t module, uint8_t data, + uint8_t* buffer, uint8_t& len); #if defined(NO_RAS) inline bool isRasValueValid() diff --git a/radio/src/telemetry/frsky_d.cpp b/radio/src/telemetry/frsky_d.cpp index 4a01320dc..35cbd5fd7 100644 --- a/radio/src/telemetry/frsky_d.cpp +++ b/radio/src/telemetry/frsky_d.cpp @@ -62,31 +62,37 @@ void parseTelemHubByte(uint8_t byte) processHubPacket(structPos, (byte << 8) + lowByte); } -void frskyDProcessPacket(const uint8_t *packet) +void frskyDProcessPacket(uint8_t module, const uint8_t *packet, uint8_t len) { + const TelemetryProtocol proto = PROTOCOL_TELEMETRY_FRSKY_D; // What type of packet? switch (packet[0]) { - case LINKPKT: // A1/A2/RSSI values + // A1/A2/RSSI values + case LINKPKT: { - setTelemetryValue(PROTOCOL_TELEMETRY_FRSKY_D, D_A1_ID, 0, 0, packet[1], UNIT_VOLTS, 0); - setTelemetryValue(PROTOCOL_TELEMETRY_FRSKY_D, D_A2_ID, 0, 0, packet[2], UNIT_VOLTS, 0); - setTelemetryValue(PROTOCOL_TELEMETRY_FRSKY_D, D_RSSI_ID, 0, 0, packet[3], UNIT_RAW, 0); -#if defined(MULTIMODULE) - if (telemetryProtocol == PROTOCOL_TELEMETRY_MULTIMODULE) { - setTelemetryValue(PROTOCOL_TELEMETRY_FRSKY_D, TX_RSSI_ID, 0, 0, packet[4]>>1, UNIT_DB, 0); - setTelemetryValue(PROTOCOL_TELEMETRY_FRSKY_D, RX_LQI_ID, 0, 0, packet[5] , UNIT_RAW, 0); - setTelemetryValue(PROTOCOL_TELEMETRY_FRSKY_D, TX_LQI_ID , 0, 0, packet[6] , UNIT_RAW, 0); + setTelemetryValue(proto, D_A1_ID, 0, 0, packet[1], UNIT_VOLTS, 0); + setTelemetryValue(proto, D_A2_ID, 0, 0, packet[2], UNIT_VOLTS, 0); + setTelemetryValue(proto, D_RSSI_ID, 0, 0, packet[3], UNIT_RAW, 0); + + if (len >= 7) { + setTelemetryValue(proto, TX_RSSI_ID, 0, 0, packet[4]>>1, UNIT_DB, 0); + setTelemetryValue(proto, RX_LQI_ID, 0, 0, packet[5] , UNIT_RAW, 0); + setTelemetryValue(proto, TX_LQI_ID , 0, 0, packet[6] , UNIT_RAW, 0); } -#endif + + // reset counter only if valid packets are being detected telemetryData.rssi.set(packet[3]); - telemetryStreaming = TELEMETRY_TIMEOUT10ms; // reset counter only if valid packets are being detected + telemetryStreaming = TELEMETRY_TIMEOUT10ms; break; } - case USRPKT: // User Data packet - uint8_t numBytes = 3 + (packet[1] & 0x07); // sanitize in case of data corruption leading to buffer overflow - for (uint8_t i=3; isendBuffer(ctx, pxx2.getData(), pxx2.getSize()); + uint8_t* module_buffer = pulsesGetModuleBuffer(module); + Pxx2Pulses pxx2(module_buffer); + pxx2.setupAuthenticationFrame(module, cryptoType, (const uint8_t *)messageDigest); + drv->sendBuffer(ctx, module_buffer, pxx2.getSize()); // we remain in AUTHENTICATION mode to avoid a CHANNELS frame is sent at the // end of the mixing process @@ -417,3 +480,4 @@ void processPXX2Frame(uint8_t module, const uint8_t * frame, } } +#endif diff --git a/radio/src/telemetry/frsky_sport.cpp b/radio/src/telemetry/frsky_sport.cpp index a4d4f2e89..63befe60d 100644 --- a/radio/src/telemetry/frsky_sport.cpp +++ b/radio/src/telemetry/frsky_sport.cpp @@ -68,8 +68,8 @@ const FrSkySportSensor sportSensors[] = { { RBOX_BATT2_FIRST_ID, RBOX_BATT2_LAST_ID, 1, STR_SENSOR_BATT2_CURRENT, UNIT_AMPS, 2 }, { RBOX_CNSP_FIRST_ID, RBOX_CNSP_LAST_ID, 0, STR_SENSOR_BATT1_CONSUMPTION, UNIT_MAH, 0 }, { RBOX_CNSP_FIRST_ID, RBOX_CNSP_LAST_ID, 1, STR_SENSOR_BATT2_CONSUMPTION, UNIT_MAH, 0 }, - { RBOX_STATE_FIRST_ID, RBOX_STATE_LAST_ID, 0, STR_SENSOR_CHANS_STATE, UNIT_BITFIELD, 0 }, - { RBOX_STATE_FIRST_ID, RBOX_STATE_LAST_ID, 1, STR_SENSOR_RB_STATE, UNIT_BITFIELD, 0 }, + { RBOX_STATE_FIRST_ID, RBOX_STATE_LAST_ID, 0, STR_SENSOR_CHANS_STATE, UNIT_TEXT, 0 }, + { RBOX_STATE_FIRST_ID, RBOX_STATE_LAST_ID, 1, STR_SENSOR_RB_STATE, UNIT_TEXT, 0 }, { SD1_FIRST_ID, SD1_LAST_ID, 0, STR_SENSOR_SD1_CHANNEL, UNIT_RAW, 0 }, { ESC_POWER_FIRST_ID, ESC_POWER_LAST_ID, 0, STR_SENSOR_ESC_VOLTAGE, UNIT_VOLTS, 2 }, { ESC_POWER_FIRST_ID, ESC_POWER_LAST_ID, 1, STR_SENSOR_ESC_CURRENT, UNIT_AMPS, 2 }, @@ -86,7 +86,7 @@ const FrSkySportSensor sportSensors[] = { { GASSUIT_AVG_FLOW_FIRST_ID, GASSUIT_AVG_FLOW_LAST_ID, 0, STR_SENSOR_GASSUIT_AVG_FLOW, UNIT_MILLILITERS_PER_MINUTE, 0 }, { SBEC_POWER_FIRST_ID, SBEC_POWER_LAST_ID, 0, STR_SENSOR_SBEC_VOLTAGE, UNIT_VOLTS, 2 }, { SBEC_POWER_FIRST_ID, SBEC_POWER_LAST_ID, 1, STR_SENSOR_SBEC_CURRENT, UNIT_AMPS, 2 }, - { RB3040_OUTPUT_FIRST_ID, RB3040_OUTPUT_LAST_ID, 0, STR_RB3040_EXTRA_STATE, UNIT_BITFIELD, 0 }, + { RB3040_OUTPUT_FIRST_ID, RB3040_OUTPUT_LAST_ID, 0, STR_RB3040_EXTRA_STATE, UNIT_TEXT, 0 }, { RB3040_CH1_2_FIRST_ID, RB3040_CH1_2_LAST_ID, 0, STR_RB3040_CHANNEL1, UNIT_AMPS, 2 }, { RB3040_CH1_2_FIRST_ID, RB3040_CH1_2_LAST_ID, 1, STR_RB3040_CHANNEL2, UNIT_AMPS, 2 }, { RB3040_CH3_4_FIRST_ID, RB3040_CH3_4_LAST_ID, 0, STR_RB3040_CHANNEL3, UNIT_AMPS, 2 }, @@ -135,31 +135,34 @@ uint16_t rboxState; void sportProcessTelemetryPacket(uint16_t id, uint8_t subId, uint8_t instance, uint32_t data, TelemetryUnit unit) { + const TelemetryProtocol proto = PROTOCOL_TELEMETRY_FRSKY_SPORT; const FrSkySportSensor * sensor = getFrSkySportSensor(id, subId); uint8_t precision = 255; if (sensor) { - if (unit == UNIT_RAW) + if (unit == UNIT_RAW) { unit = sensor->unit; + } precision = sensor->prec; } if (unit == UNIT_CELLS) { uint8_t cellsCount = (data & 0xF0u) >> 4u; uint8_t cellIndex = (data & 0x0Fu); - if (cellIndex >= MAX_CELLS) - return; + if (cellIndex >= MAX_CELLS) return; uint32_t mask = (cellsCount << 24u) + (cellIndex << 16u); - setTelemetryValue(PROTOCOL_TELEMETRY_FRSKY_SPORT, id, subId, instance, mask + (((data & 0x000FFF00u) >> 8u) / 5), unit, precision); + uint32_t value = mask + (((data & 0x000FFF00u) >> 8u) / 5); + setTelemetryValue(proto, id, subId, instance, value, unit, precision); if (cellIndex + 1 < cellsCount) { mask += (1 << 16u); - setTelemetryValue(PROTOCOL_TELEMETRY_FRSKY_SPORT, id, subId, instance, mask + (((data & 0xFFF00000u) >> 20u) / 5), unit, precision); + value = mask + (((data & 0xFFF00000u) >> 20u) / 5); + setTelemetryValue(proto, id, subId, instance, value, unit, precision); } } else { - setTelemetryValue(PROTOCOL_TELEMETRY_FRSKY_SPORT, id, subId, instance, data, unit, precision); + setTelemetryValue(proto, id, subId, instance, data, unit, precision); } } -bool sportProcessTelemetryPacket(const uint8_t * packet) +bool sportProcessTelemetryPacket(uint8_t module, const uint8_t * packet, uint8_t len) { if (!checkSportPacket(packet)) { TRACE("sportProcessTelemetryPacket(): checksum error "); @@ -167,11 +170,85 @@ bool sportProcessTelemetryPacket(const uint8_t * packet) return false; } - sportProcessTelemetryPacketWithoutCrc(TELEMETRY_ENDPOINT_SPORT, packet); + sportProcessTelemetryPacketWithoutCrc(module, 0, packet); return true; } -void sportProcessTelemetryPacketWithoutCrc(uint8_t origin, const uint8_t * packet) +static void sportSetServoState(uint16_t id, uint8_t subId, uint8_t instance, uint16_t value) +{ + const TelemetryProtocol proto = PROTOCOL_TELEMETRY_FRSKY_SPORT; + if (value == 0) { + setTelemetryText(proto, id, subId, instance, "OK"); + } + else { + for (uint8_t i = 0; i < 16; i++) { + if (value & (1u << i)) { + char s[] = "CH__ KO"; + strAppendUnsigned(&s[2], i + 1, 2); + setTelemetryText(proto, id, subId, instance, s); + break; + } + } + } +} + +static void sportSetRBoxState(uint16_t id, uint8_t subId, uint8_t instance, uint16_t value) +{ + const TelemetryProtocol proto = PROTOCOL_TELEMETRY_FRSKY_SPORT; + if (value == 0) { + setTelemetryText(proto, id, subId, instance, "Rx OK"); + } + else { + static const char * const RXS_STATUS[] = { + "Rx1 Ovl", + "Rx2 Ovl", + "SBUS Ovl", + "Rx1 FS", + "Rx1 LF", + "Rx2 FS", + "Rx2 LF", + "Rx1 Lost", + "Rx2 Lost", + "Rx1 NS", + "Rx2 NS", + "Rx3 FS", + "Rx3 LF", + "Rx3 Lost", + "Rx3 NS" + }; + for (uint8_t i = 0; i < DIM(RXS_STATUS); i++) { + if (value & (1u << i)) { + setTelemetryText(proto, id, subId, instance, RXS_STATUS[i]); + break; + } + } + } +} + +static void sportSetRB3040State(uint16_t id, uint8_t subId, uint8_t instance, uint32_t value) +{ + const TelemetryProtocol proto = PROTOCOL_TELEMETRY_FRSKY_SPORT; + if (value == 0) { + setTelemetryText(proto, id, subId, instance, "OK"); + } + else { + for (uint8_t i = 0; i < 9; i++) { + if (value & (1u << i)) { + if (i < 8) { + char s[] = "CH__ KO"; + strAppendUnsigned(&s[2], i + 17, 2); + setTelemetryText(proto, id, subId, instance, s); + break; + } else { + setTelemetryText(proto, id, subId, instance, "S.P Ovl"); + break; + } + } + } + } +} + +void sportProcessTelemetryPacketWithoutCrc(uint8_t module, uint8_t origin, const uint8_t * packet) { uint8_t physicalId = packet[0] & 0x1F; uint8_t primId = packet[1]; @@ -179,29 +256,14 @@ void sportProcessTelemetryPacketWithoutCrc(uint8_t origin, const uint8_t * packe uint32_t data = SPORT_DATA_S32(packet); #if defined(BLUETOOTH) - if (g_eeGeneral.bluetoothMode == BLUETOOTH_TELEMETRY && bluetooth.state == BLUETOOTH_STATE_CONNECTED) { + if (g_eeGeneral.bluetoothMode == BLUETOOTH_TELEMETRY && + bluetooth.state == BLUETOOTH_STATE_CONNECTED) { bluetooth.forwardTelemetry(packet); } #endif if (primId == DATA_FRAME) { - uint8_t originMask; - uint8_t moduleIndex; - if (origin == TELEMETRY_ENDPOINT_SPORT) { -#if defined(SIMU) && defined(INTERNAL_MODULE_PXX2) - // When running simu on ACCESS radio, we set the origin as internal module - moduleIndex = 0; - origin = 0; - originMask = 0x01; -#else - moduleIndex = isSportLineUsedByInternalModule() ? 0 : 1; - originMask = 0x04; -#endif - } - else { - moduleIndex = (origin >> 2); - originMask = 0x01 << moduleIndex; - } + uint8_t originMask = 0x01 << module; uint8_t instance = physicalId + (origin << 5); if (dataId == RSSI_ID) { data = SPORT_DATA_U8(packet); @@ -230,7 +292,9 @@ void sportProcessTelemetryPacketWithoutCrc(uint8_t origin, const uint8_t * packe } else if (dataId == R9_PWR_ID) { // convert 'dBm' to 'mW' - static const uint32_t r9pwrs[][2] = {{0, 1}, {5, 3}, {10, 10}, {13, 20}, {14, 25}, {20, 100}, {23, 200}, {27, 500}, {30, 1000}}; + static const uint32_t r9pwrs[][2] = {{0, 1}, {5, 3}, {10, 10}, + {13, 20}, {14, 25}, {20, 100}, + {23, 200}, {27, 500}, {30, 1000}}; uint32_t dBm = SPORT_DATA_U8(packet); for (auto & r9pwr : r9pwrs) { if (dBm == r9pwr[0]) { @@ -242,22 +306,25 @@ void sportProcessTelemetryPacketWithoutCrc(uint8_t origin, const uint8_t * packe else if (dataId == XJT_VERSION_ID) { telemetryData.xjtVersion = HUB_DATA_U16(packet); if (!isRasValueValid()) { - telemetryData.setSwr(moduleIndex, 0); + telemetryData.setSwr(module, 0); } } else if (dataId == RAS_ID) { if (isRasValueValid()) { - telemetryData.setSwr(moduleIndex, SPORT_DATA_U8(packet)); + telemetryData.setSwr(module, SPORT_DATA_U8(packet)); } } - // here we discard the frame if it comes from an origin which has RSSI = 0 (RxBt and RSSI are sent in a loop by the module in some situations) - if (TELEMETRY_STREAMING() && (telemetryData.telemetryValid & originMask)/* because when Rx is OFF it happens that some old A1/A2 values are sent from the XJT module*/) { + // here we discard the frame if it comes from an origin which has RSSI = 0 + // (RxBt and RSSI are sent in a loop by the module in some situations) + if (TELEMETRY_STREAMING() && + // because when Rx is OFF it happens that some + // old A1/A2 values are sent from the XJT module + (telemetryData.telemetryValid & originMask)) { if ((dataId >> 8) == 0) { // The old FrSky IDs processHubPacket(dataId, HUB_DATA_U16(packet)); - } - else if (!IS_HIDDEN_TELEMETRY_VALUE(dataId)) { + } else if (!IS_HIDDEN_TELEMETRY_VALUE(dataId)) { if (dataId == ADC1_ID || dataId == ADC2_ID || dataId == BATT_ID || dataId == RAS_ID) { data = SPORT_DATA_U8(packet); } @@ -302,8 +369,11 @@ void sportProcessTelemetryPacketWithoutCrc(uint8_t origin, const uint8_t * packe } servosState = newServosState; rboxState = newRboxState; - sportProcessTelemetryPacket(dataId, 0, instance, servosState); - sportProcessTelemetryPacket(dataId, 1, instance, rboxState); + sportSetServoState(dataId, 0, instance, servosState); + sportSetRBoxState(dataId, 1, instance, rboxState); + } + else if (dataId >= RB3040_OUTPUT_FIRST_ID && dataId <= RB3040_OUTPUT_LAST_ID) { + sportSetRB3040State(dataId, 0, instance, data); } else if (dataId >= ESC_POWER_FIRST_ID && dataId <= ESC_POWER_LAST_ID) { sportProcessTelemetryPacket(dataId, 0, instance, data & 0xFFFFu); @@ -322,7 +392,9 @@ void sportProcessTelemetryPacketWithoutCrc(uint8_t origin, const uint8_t * packe } else if (dataId >= DIY_STREAM_FIRST_ID && dataId <= DIY_STREAM_LAST_ID) { #if defined(LUA) - if (luaInputTelemetryFifo && luaInputTelemetryFifo->hasSpace(sizeof(SportTelemetryPacket))) { + if (luaInputTelemetryFifo && + luaInputTelemetryFifo->hasSpace(sizeof(SportTelemetryPacket))) { + SportTelemetryPacket luaPacket; luaPacket.physicalId = physicalId; luaPacket.primId = primId; @@ -343,7 +415,8 @@ void sportProcessTelemetryPacketWithoutCrc(uint8_t origin, const uint8_t * packe sportProcessTelemetryPacket(dataId, 1, instance, (data >> 8u) & 0xFFu); sportProcessTelemetryPacket(dataId, 2, instance, (data >> 16u) & 0xFFu); uint8_t newServosState = data >> 24u; - setTelemetryText(PROTOCOL_TELEMETRY_FRSKY_SPORT, dataId, 3, instance, newServosState ? "STALL" : "OK"); + setTelemetryText(PROTOCOL_TELEMETRY_FRSKY_SPORT, dataId, 3, instance, + newServosState ? "STALL" : "OK"); if (newServosState != 0 && servosState == 0) { audioEvent(AU_SERVO_KO); servosState = newServosState; diff --git a/radio/src/telemetry/ghost.cpp b/radio/src/telemetry/ghost.cpp index 381e4c550..22034c30e 100755 --- a/radio/src/telemetry/ghost.cpp +++ b/radio/src/telemetry/ghost.cpp @@ -23,7 +23,6 @@ #include "ghost_menu.h" #include "opentx.h" -#include "aux_serial_driver.h" const char *ghstRfProfileValue[GHST_RF_PROFILE_COUNT] = { "Auto", "Norm", "Race", "Pure", "Long", "Unused", "Race2", "Pure2" }; const char *ghstVtxBandName[GHST_VTX_BAND_COUNT] = { "- - -" , "IRC", "Race", "BandE", "BandB", "BandA" }; @@ -92,14 +91,6 @@ const GhostSensor ghostSensors[] = { {0x00, NULL, UNIT_RAW, 0}, }; -uint8_t getGhostModuleAddr() { -#if SPORT_MAX_BAUDRATE < 400000 - return g_model.moduleData[EXTERNAL_MODULE].ghost.telemetryBaudrate == GHST_TELEMETRY_RATE_400K ? GHST_ADDR_MODULE_SYM : GHST_ADDR_MODULE_ASYM; -#else - return GHST_ADDR_MODULE_SYM; -#endif -} - const GhostSensor *getGhostSensor(uint8_t id) { for (const GhostSensor * sensor = ghostSensors; sensor->id; sensor++) { @@ -132,75 +123,78 @@ void processGhostTelemetryValueString(const GhostSensor * sensor, const char * s } } -bool checkGhostTelemetryFrameCRC() +static bool checkGhostTelemetryFrameCRC(const uint8_t* frame, uint32_t len) { - uint8_t len = telemetryRxBuffer[1]; - uint8_t crc = crc8(&telemetryRxBuffer[2], len - 1); - return (crc == telemetryRxBuffer[len + 1]); + uint8_t crc = crc8(frame, len - 1); + return (crc == frame[len - 1]); } // hifirst -uint16_t getTelemetryValue_u16(uint8_t index) +static uint16_t _get_u16(const uint8_t* frame, uint8_t offset) { - return (telemetryRxBuffer[index] << 8) | telemetryRxBuffer[index + 1]; + return (frame[offset] << 8) | frame[offset + 1]; } // lofirst -uint16_t getTelemetryValue_u16le(uint8_t index) +static uint16_t _get_u16le(const uint8_t* frame, uint8_t offset) { - return (telemetryRxBuffer[index + 1] << 8) | telemetryRxBuffer[index]; + return (frame[offset + 1] << 8) | frame[offset]; } // hifirst -uint32_t getTelemetryValue_s32(uint8_t index) +static uint32_t _get_s32(const uint8_t* frame, uint8_t offset) { uint32_t val = 0; for (int i = 0; i < 4; ++i) - val <<= 8, val |= telemetryRxBuffer[index + i]; + val <<= 8, val |= frame[offset + i]; return val; } // lofirst -uint32_t getTelemetryValue_s32le(uint8_t index) +static uint32_t _get_s32le(const uint8_t* frame, uint8_t offset) { uint32_t val = 0; for (int i = 0; i < 4; ++i) - val <<= 8, val |= telemetryRxBuffer[index + 3 - i]; + val <<= 8, val |= frame[offset + 3 - i]; return val; } -void processGhostTelemetryFrame() +void processGhostTelemetryFrame(uint8_t module, uint8_t* buffer, uint32_t length) { - if (!checkGhostTelemetryFrameCRC()) { + uint8_t frame_len = buffer[1]; + auto frame = buffer + 2; + if (!checkGhostTelemetryFrameCRC(frame, frame_len)) { TRACE("[GS] CRC error"); return; } - uint8_t id = telemetryRxBuffer[2]; + uint8_t id = frame[0]; switch(id) { case GHST_DL_OPENTX_SYNC: { - uint32_t update_interval = getTelemetryValue_s32(3); - int32_t offset = getTelemetryValue_s32(7); + uint32_t update_interval = _get_s32(frame, 1); + int32_t offset = _get_s32(frame, 5); // values are in units of 100ns update_interval /= 10; offset /= 10; - getModuleSyncStatus(EXTERNAL_MODULE).update(update_interval, offset); + getModuleSyncStatus(module).update(update_interval, offset); } break; case GHST_DL_LINK_STAT: { #if defined(BLUETOOTH) - if (g_eeGeneral.bluetoothMode == BLUETOOTH_TELEMETRY && bluetooth.state == BLUETOOTH_STATE_CONNECTED) { - bluetooth.write(telemetryRxBuffer, telemetryRxBufferCount); + if (g_eeGeneral.bluetoothMode == BLUETOOTH_TELEMETRY && + bluetooth.state == BLUETOOTH_STATE_CONNECTED) { + bluetooth.write(buffer, length); } #endif - uint8_t rssiVal = min(telemetryRxBuffer[3], 120); // RSSI is a negative value, but sent as a positive integer. - uint8_t lqVal = min(telemetryRxBuffer[4], 100); - uint8_t snrVal = min(telemetryRxBuffer[5], 100); + // RSSI is a negative value, but sent as a positive integer. + uint8_t rssiVal = min(frame[1], 120); + uint8_t lqVal = min(frame[2], 100); + uint8_t snrVal = min(frame[3], 100); processGhostTelemetryValue(GHOST_ID_RX_RSSI, - rssiVal); processGhostTelemetryValue(GHOST_ID_RX_LQ, lqVal); @@ -216,10 +210,10 @@ void processGhostTelemetryFrame() telemetryStreaming = 0; } - processGhostTelemetryValue(GHOST_ID_TX_POWER, getTelemetryValue_u16(6)); - processGhostTelemetryValue(GHOST_ID_FRAME_RATE, getTelemetryValue_u16(8)); - processGhostTelemetryValue(GHOST_ID_TOTAL_LATENCY, getTelemetryValue_u16(10)); - uint8_t rfModeEnum = min(telemetryRxBuffer[12], GHST_RF_PROFILE_MAX); + processGhostTelemetryValue(GHOST_ID_TX_POWER, _get_u16(frame, 4)); + processGhostTelemetryValue(GHOST_ID_FRAME_RATE, _get_u16(frame, 6)); + processGhostTelemetryValue(GHOST_ID_TOTAL_LATENCY, _get_u16(frame, 8)); + uint8_t rfModeEnum = min(frame[10], GHST_RF_PROFILE_MAX); // RF mode string, one char at a time const GhostSensor * sensor = getGhostSensor(GHOST_ID_RF_MODE); @@ -231,18 +225,19 @@ void processGhostTelemetryFrame() case GHST_DL_VTX_STAT: { #if defined(BLUETOOTH) - if (g_eeGeneral.bluetoothMode == BLUETOOTH_TELEMETRY && bluetooth.state == BLUETOOTH_STATE_CONNECTED) { - bluetooth.write(telemetryRxBuffer, telemetryRxBufferCount); + if (g_eeGeneral.bluetoothMode == BLUETOOTH_TELEMETRY && + bluetooth.state == BLUETOOTH_STATE_CONNECTED) { + bluetooth.write(buffer, length); } #endif - uint8_t vtxBandEnum = min(telemetryRxBuffer[8], GHST_VTX_BAND_MAX); + uint8_t vtxBandEnum = min(frame[6], GHST_VTX_BAND_MAX); const GhostSensor * sensor = getGhostSensor(GHOST_ID_VTX_BAND); const char * vtxBandString = ghstVtxBandName[vtxBandEnum]; - processGhostTelemetryValue(GHOST_ID_VTX_FREQ, getTelemetryValue_u16(4)); - processGhostTelemetryValue(GHOST_ID_VTX_POWER, getTelemetryValue_u16(6)); - processGhostTelemetryValue(GHOST_ID_VTX_CHAN, min(telemetryRxBuffer[9], 8)); + processGhostTelemetryValue(GHOST_ID_VTX_FREQ, _get_u16(frame, 2)); + processGhostTelemetryValue(GHOST_ID_VTX_POWER, _get_u16(frame, 4)); + processGhostTelemetryValue(GHOST_ID_VTX_CHAN, min(frame[7], 8)); processGhostTelemetryValueString(sensor, vtxBandString); break; } @@ -251,7 +246,7 @@ void processGhostTelemetryFrame() { GhostMenuFrame * packet; GhostMenuData * lineData; - packet = (GhostMenuFrame * ) telemetryRxBuffer; + packet = (GhostMenuFrame * )buffer; lineData = (GhostMenuData *) &reusableBuffer.ghostMenu.line[packet->lineIndex]; lineData->splitLine = 0; reusableBuffer.ghostMenu.menuStatus = packet->menuStatus; @@ -271,39 +266,42 @@ void processGhostTelemetryFrame() case GHST_DL_PACK_STAT: { #if defined(BLUETOOTH) - if (g_eeGeneral.bluetoothMode == BLUETOOTH_TELEMETRY && bluetooth.state == BLUETOOTH_STATE_CONNECTED) { - bluetooth.write(telemetryRxBuffer, telemetryRxBufferCount); + if (g_eeGeneral.bluetoothMode == BLUETOOTH_TELEMETRY && + bluetooth.state == BLUETOOTH_STATE_CONNECTED) { + bluetooth.write(buffer, length); } #endif - processGhostTelemetryValue(GHOST_ID_PACK_VOLTS, getTelemetryValue_u16le(3)); - processGhostTelemetryValue(GHOST_ID_PACK_AMPS, getTelemetryValue_u16le(5)); - processGhostTelemetryValue(GHOST_ID_PACK_MAH, getTelemetryValue_u16le(7) * 10); + processGhostTelemetryValue(GHOST_ID_PACK_VOLTS, _get_u16le(frame, 1)); + processGhostTelemetryValue(GHOST_ID_PACK_AMPS, _get_u16le(frame, 3)); + processGhostTelemetryValue(GHOST_ID_PACK_MAH, _get_u16le(frame, 5) * 10); break; } case GHST_DL_GPS_PRIMARY: { #if defined(BLUETOOTH) - if (g_eeGeneral.bluetoothMode == BLUETOOTH_TELEMETRY && bluetooth.state == BLUETOOTH_STATE_CONNECTED) { - bluetooth.write(telemetryRxBuffer, telemetryRxBufferCount); + if (g_eeGeneral.bluetoothMode == BLUETOOTH_TELEMETRY && + bluetooth.state == BLUETOOTH_STATE_CONNECTED) { + bluetooth.write(buffer, length); } #endif - processGhostTelemetryValue(GHOST_ID_GPS_LAT, ((int32_t)getTelemetryValue_s32le(3)) / 10); - processGhostTelemetryValue(GHOST_ID_GPS_LONG, ((int32_t)getTelemetryValue_s32le(7)) / 10); - processGhostTelemetryValue(GHOST_ID_GPS_ALT, (int16_t)getTelemetryValue_u16le(11)); + processGhostTelemetryValue(GHOST_ID_GPS_LAT, ((int32_t)_get_s32le(frame, 1)) / 10); + processGhostTelemetryValue(GHOST_ID_GPS_LONG, ((int32_t)_get_s32le(frame, 5)) / 10); + processGhostTelemetryValue(GHOST_ID_GPS_ALT, (int16_t)_get_u16le(frame, 9)); break; } case GHST_DL_GPS_SECONDARY: { #if defined(BLUETOOTH) - if (g_eeGeneral.bluetoothMode == BLUETOOTH_TELEMETRY && bluetooth.state == BLUETOOTH_STATE_CONNECTED) { - bluetooth.write(telemetryRxBuffer, telemetryRxBufferCount); + if (g_eeGeneral.bluetoothMode == BLUETOOTH_TELEMETRY && + bluetooth.state == BLUETOOTH_STATE_CONNECTED) { + bluetooth.write(buffer, length); } #endif - processGhostTelemetryValue(GHOST_ID_GPS_HDG, getTelemetryValue_u16le(5) / 10); + processGhostTelemetryValue(GHOST_ID_GPS_HDG, _get_u16le(frame, 3) / 10); // ground speed is passed via GHST as cm/s, converted to km/h for OpenTx - processGhostTelemetryValue(GHOST_ID_GPS_GSPD, (getTelemetryValue_u16le(3) * 36 + 50) / 100); - processGhostTelemetryValue(GHOST_ID_GPS_SATS, telemetryRxBuffer[7]); + processGhostTelemetryValue(GHOST_ID_GPS_GSPD, (_get_u16le(frame, 1) * 36 + 50) / 100); + processGhostTelemetryValue(GHOST_ID_GPS_SATS, frame[5]); break; } case GHST_DL_MAGBARO: { @@ -312,10 +310,10 @@ void processGhostTelemetryFrame() } #if defined(LUA) default: - if (luaInputTelemetryFifo && luaInputTelemetryFifo->hasSpace(telemetryRxBufferCount-2) ) { - for (uint8_t i=1; ipush(telemetryRxBuffer[i]); + // destination address and CRC are skipped + if (luaInputTelemetryFifo && luaInputTelemetryFifo->hasSpace(length - 2) ) { + for (uint8_t i = 1; i < length - 1; i++) { + luaInputTelemetryFifo->push(buffer[i]); } } break; @@ -323,31 +321,6 @@ void processGhostTelemetryFrame() } } -void processGhostTelemetryData(uint8_t data) -{ - if (telemetryRxBufferCount == 0 && data != GHST_ADDR_RADIO) { - TRACE("[GH] address 0x%02X error", data); - return; - } - - if (telemetryRxBufferCount < TELEMETRY_RX_PACKET_SIZE) { - telemetryRxBuffer[telemetryRxBufferCount++] = data; - } - else { - TRACE("[GH] array size %d error", telemetryRxBufferCount); - telemetryRxBufferCount = 0; - } - - if (telemetryRxBufferCount > 4) { - uint8_t length = telemetryRxBuffer[1]; - if (length + 2 == telemetryRxBufferCount) { - processGhostTelemetryFrame(); - telemetryRxBufferCount = 0; - } - } -} - - void ghostSetDefault(int index, uint8_t id, uint8_t subId) { TelemetrySensor &telemetrySensor = g_model.telemetrySensors[index]; diff --git a/radio/src/telemetry/ghost.h b/radio/src/telemetry/ghost.h index 81485fdc8..817c50f3b 100755 --- a/radio/src/telemetry/ghost.h +++ b/radio/src/telemetry/ghost.h @@ -105,10 +105,6 @@ enum GhstVtxBand GHST_VTX_BAND_COUNT }; -void processGhostTelemetryData(uint8_t data); -void ghostSetDefault(int index, uint8_t id, uint8_t subId); -uint8_t getGhostModuleAddr(); - #if SPORT_MAX_BAUDRATE < 400000 // For radios which can't support telemetry at high rates, offer baud rate choices // (modified vs. unmodified radios) @@ -165,3 +161,6 @@ enum GhostFrames GHST_MENU_CONTROL }; +void processGhostTelemetryFrame(uint8_t module, uint8_t* buffer, uint32_t length); +void ghostSetDefault(int index, uint8_t id, uint8_t subId); + diff --git a/radio/src/telemetry/multi.cpp b/radio/src/telemetry/multi.cpp index 1ab8eb0ea..c668e1bd8 100644 --- a/radio/src/telemetry/multi.cpp +++ b/radio/src/telemetry/multi.cpp @@ -19,7 +19,6 @@ * GNU General Public License for more details. */ #include "opentx.h" -#include "aux_serial_driver.h" #include "telemetry.h" #include "io/multi_protolist.h" @@ -157,14 +156,7 @@ bool isMultiModeScanning(uint8_t module) static MultiBufferState guessProtocol(uint8_t module) { - uint32_t moduleIdx = EXTERNAL_MODULE; -#if defined(INTERNAL_MODULE_MULTI) - if (isModuleMultimodule(INTERNAL_MODULE)) { - moduleIdx = INTERNAL_MODULE; - } -#endif - - if (g_model.moduleData[moduleIdx].multi.rfProtocol == MODULE_SUBTYPE_MULTI_DSM2) + if (g_model.moduleData[module].multi.rfProtocol == MODULE_SUBTYPE_MULTI_DSM2) return SpektrumTelemetryFallback; else if (g_model.moduleData[module].multi.rfProtocol == MODULE_SUBTYPE_MULTI_FS_AFHDS2A) return FlyskyTelemetryFallback; @@ -434,14 +426,14 @@ static void processMultiTelemetryPaket(const uint8_t * packet, uint8_t module) case FrSkyHubTelemetry: if (len >= 4) - frskyDProcessPacket(data); + frskyDProcessPacket(module, data, len); else TRACE("[MP] Received Frsky HUB telemetry len %d < 4", len); break; case FrSkySportTelemetry: if (len >= 4) { - if (sportProcessTelemetryPacket(data) && len >= 8) { + if (sportProcessTelemetryPacket(module, data, len) && len >= 8) { uint8_t primId = data[1]; uint16_t dataId = *((uint16_t *)(data+2)); if (primId == DATA_FRAME && dataId == RSSI_ID) { @@ -470,10 +462,13 @@ static void processMultiTelemetryPaket(const uint8_t * packet, uint8_t module) #if defined(LUA) case FrskySportPolling: - if (len >= 1 && outputTelemetryBuffer.destination == TELEMETRY_ENDPOINT_SPORT && data[0] == outputTelemetryBuffer.sport.physicalId) { - TRACE("MP Sending sport data out."); - sportSendBuffer(outputTelemetryBuffer.data, outputTelemetryBuffer.size); - } + // TODO + // if (len >= 1 && + // outputTelemetryBuffer.destination == TELEMETRY_ENDPOINT_SPORT && + // data[0] == outputTelemetryBuffer.sport.physicalId) { + // TRACE("MP Sending sport data out."); + // sportSendBuffer(outputTelemetryBuffer.data, outputTelemetryBuffer.size); + // } break; #endif case SpectrumScannerPacket: @@ -604,12 +599,9 @@ void processMultiTelemetryData(uint8_t data, uint8_t module) uint8_t &rxBufferCount = getTelemetryRxBufferCount(module); uint16_t &lastRxTS = getMultiTelemetryLastRxTS(module); - uint16_t nowMs = (uint16_t)RTOS_GET_MS(); - if (nowMs - lastRxTS > 15) - setMultiTelemetryBufferState(module, NoProtocolDetected); - lastRxTS = nowMs; - // debugPrintf("State: %d, byte received %02X, buflen: %d\r\n", getMultiTelemetryBufferState(module), data, rxBufferCount); + // debugPrintf("State: %d, byte received %02X, buflen: %d\r\n", + // getMultiTelemetryBufferState(module), data, rxBufferCount); switch (getMultiTelemetryBufferState(module)) { case NoProtocolDetected: @@ -629,7 +621,7 @@ void processMultiTelemetryData(uint8_t data, uint8_t module) case FrskyTelemetryFallback: setMultiTelemetryBufferState(module, FrskyTelemetryFallbackFirstByte); - processFrskyTelemetryData(data); + processFrskySportTelemetryData(module, data, rxBuffer, rxBufferCount); break; case FrskyTelemetryFallbackFirstByte: @@ -637,7 +629,7 @@ void processMultiTelemetryData(uint8_t data, uint8_t module) setMultiTelemetryBufferState(module, MultiStatusOrFrskyData); } else { - processFrskyTelemetryData(data); + processFrskySportTelemetryData(module, data, rxBuffer, rxBufferCount); if (data != 0x7e) setMultiTelemetryBufferState(module, FrskyTelemetryFallbackNextBytes); } @@ -645,7 +637,7 @@ void processMultiTelemetryData(uint8_t data, uint8_t module) break; case FrskyTelemetryFallbackNextBytes: - processFrskyTelemetryData(data); + processFrskySportTelemetryData(module, data, rxBuffer, rxBufferCount); if (data == 0x7e) { // end of packet or start of new packet setMultiTelemetryBufferState(module, FrskyTelemetryFallbackFirstByte); diff --git a/radio/src/telemetry/spektrum.cpp b/radio/src/telemetry/spektrum.cpp index 2b552203c..12bc52c04 100644 --- a/radio/src/telemetry/spektrum.cpp +++ b/radio/src/telemetry/spektrum.cpp @@ -21,6 +21,8 @@ #include "opentx.h" #include "spektrum.h" +#include "hal/module_port.h" +#include "tasks/mixer_task.h" /* * Documentation of the Spektrum protocol is available under @@ -519,7 +521,9 @@ void processDSMBindPacket(uint8_t module, const uint8_t *packet) packet[0] & 0x3F, packet[2]); storageDirty(EE_MODEL); - restartModule(EXTERNAL_MODULE); + + moduleState[module].mode = MODULE_MODE_NORMAL; + restartModuleAsync(module, 50); // ~200ms } else if (g_model.moduleData[module].type == MODULE_TYPE_MULTIMODULE && g_model.moduleData[module].multi.rfProtocol == diff --git a/radio/src/telemetry/telemetry.cpp b/radio/src/telemetry/telemetry.cpp index 96ca21100..cd15813cf 100644 --- a/radio/src/telemetry/telemetry.cpp +++ b/radio/src/telemetry/telemetry.cpp @@ -25,7 +25,7 @@ #include "pulses/flysky.h" #include "mixer_scheduler.h" #include "io/multi_protolist.h" -#include "aux_serial_driver.h" +#include "hal/module_port.h" #if defined(LIBOPENUI) #include "libopenui.h" @@ -57,12 +57,8 @@ #include "flysky_ibus.h" #endif -#if defined(INTMODULE_USART) -#include "intmodule_serial_driver.h" -#endif - uint8_t telemetryStreaming = 0; -uint8_t telemetryRxBuffer[TELEMETRY_RX_PACKET_SIZE]; // Receive buffer. 9 bytes (full packet), worst case 18 bytes with byte-stuffing (+1) +uint8_t telemetryRxBuffer[TELEMETRY_RX_PACKET_SIZE]; uint8_t telemetryRxBufferCount = 0; uint8_t telemetryState = TELEMETRY_INIT; @@ -94,27 +90,30 @@ uint8_t &getTelemetryRxBufferCount(uint8_t moduleIdx) return telemetryRxBufferCount; } -static int (*_telemetryGetByte)(void*, uint8_t*) = nullptr; -static void* _telemetryGetByteCtx = nullptr; +// TODO: move to module port driver +// +// static int (*_telemetryGetByte)(void*, uint8_t*) = nullptr; +// static void* _telemetryGetByteCtx = nullptr; -void telemetrySetGetByte(void* ctx, int (*fct)(void*, uint8_t*)) -{ - _telemetryGetByte = nullptr; - _telemetryGetByteCtx = ctx; - _telemetryGetByte = fct; -} +// void telemetrySetGetByte(void* ctx, int (*fct)(void*, uint8_t*)) +// { +// _telemetryGetByte = nullptr; +// _telemetryGetByteCtx = ctx; +// _telemetryGetByte = fct; +// } -static bool telemetryGetByte(uint8_t* data) -{ - auto _getByte = _telemetryGetByte; - auto _ctx = _telemetryGetByteCtx; +// static bool telemetryGetByte(uint8_t* data) +// { +// auto _getByte = _telemetryGetByte; +// auto _ctx = _telemetryGetByteCtx; - if (_getByte) { - return _getByte(_ctx, data); - } +// if (_getByte) { +// return _getByte(_ctx, data); +// } - return sportGetByte(data); -} +// // return sportGetByte(data); +// return false; +// } static void (*telemetryMirrorSendByte)(void*, uint8_t) = nullptr; static void* telemetryMirrorSendByteCtx = nullptr; @@ -143,11 +142,10 @@ static StaticTimer_t telemetryTimerBuffer; static void telemetryTimerCb(TimerHandle_t xTimer) { (void)xTimer; - if (!s_pulses_paused) { - DEBUG_TIMER_START(debugTimerTelemetryWakeup); - telemetryWakeup(); - DEBUG_TIMER_STOP(debugTimerTelemetryWakeup); - } + + DEBUG_TIMER_START(debugTimerTelemetryWakeup); + telemetryWakeup(); + DEBUG_TIMER_STOP(debugTimerTelemetryWakeup); } void telemetryStart() @@ -175,122 +173,61 @@ void telemetryStop() } #endif -void processTelemetryData(uint8_t data) -{ -// TODO: move these to new interface -#if defined(GHOST) - if (telemetryProtocol == PROTOCOL_TELEMETRY_GHOST) { - processGhostTelemetryData(data); - return; - } -#endif - - if (telemetryProtocol == PROTOCOL_TELEMETRY_SPEKTRUM || - telemetryProtocol == PROTOCOL_TELEMETRY_DSMP) { - processSpektrumTelemetryData(EXTERNAL_MODULE, data, telemetryRxBuffer, - telemetryRxBufferCount); - return; - } - -// TODO: move these to new interface -#if defined(MULTIMODULE) - if (telemetryProtocol == PROTOCOL_TELEMETRY_MULTIMODULE) { - processMultiTelemetryData(data, EXTERNAL_MODULE); - return; - } -#endif - -#if defined(PXX1) - if (telemetryProtocol == PROTOCOL_TELEMETRY_FRSKY_SPORT || - telemetryProtocol == PROTOCOL_TELEMETRY_FRSKY_D || - telemetryProtocol == PROTOCOL_TELEMETRY_FRSKY_D_SECONDARY) { - processFrskyTelemetryData(data); - } -#endif -} - inline bool isBadAntennaDetected() { if (!isRasValueValid()) return false; - if (telemetryData.swrInternal.isFresh() && telemetryData.swrInternal.value() > FRSKY_BAD_ANTENNA_THRESHOLD) + if (telemetryData.swrInternal.isFresh() && + telemetryData.swrInternal.value() > FRSKY_BAD_ANTENNA_THRESHOLD) return true; - if (telemetryData.swrExternal.isFresh() && telemetryData.swrExternal.value() > FRSKY_BAD_ANTENNA_THRESHOLD) + if (telemetryData.swrExternal.isFresh() && + telemetryData.swrExternal.value() > FRSKY_BAD_ANTENNA_THRESHOLD) return true; return false; } -static inline bool pollTelemetry(uint8_t module, const etx_module_driver_t* drv, void* ctx) +static inline void pollTelemetry(uint8_t module, const etx_proto_driver_t* drv, void* ctx) { - if (!drv || !drv->getByte || !drv->processData) return false; + if (!drv || !drv->processData) return; + + auto mod_st = (etx_module_state_t*)ctx; + auto serial_drv = modulePortGetSerialDrv(mod_st->rx); + auto serial_ctx = modulePortGetCtx(mod_st->rx); + + if (!serial_drv || !serial_ctx || !serial_drv->getByte) + return; uint8_t* rxBuffer = getTelemetryRxBuffer(module); uint8_t& rxBufferCount = getTelemetryRxBufferCount(module); uint8_t data; - if (drv->getByte(ctx, &data) > 0) { + if (serial_drv->getByte(serial_ctx, &data) > 0) { LOG_TELEMETRY_WRITE_START(); do { telemetryMirrorSend(data); drv->processData(ctx, data, rxBuffer, &rxBufferCount); LOG_TELEMETRY_WRITE_BYTE(data); - } while (drv->getByte(ctx, &data) > 0); + } while (serial_drv->getByte(serial_ctx, &data) > 0); } - - return true; } -static inline void pollExtTelemetryLegacy() -{ - uint8_t data; - if (telemetryGetByte(&data)) { - LOG_TELEMETRY_WRITE_START(); - do { - telemetryMirrorSend(data); - processTelemetryData(data); - LOG_TELEMETRY_WRITE_BYTE(data); - } while (telemetryGetByte(&data)); - } -} +// This can only be changed when the mixer is not +// running as the priority of the timer task is +// lower. +volatile uint8_t _telemetryIsPolling = false; -// TODO: this needs to be rewritten completely -// - telemetry polling needs to happen for each enabled module void telemetryWakeup() { -#if defined(HARDWARE_INTERNAL_MODULE) - auto int_drv = getIntModuleDriver(); - if (int_drv) pollTelemetry(INTERNAL_MODULE, int_drv, getIntModuleCtx()); -#endif - - bool disable_legacy_polling = false; -#if defined(HARDWARE_EXTERNAL_MODULE) - auto ext_drv = getExtModuleDriver(); - if (ext_drv) { - if (pollTelemetry(EXTERNAL_MODULE, ext_drv, getExtModuleCtx())) { - // skip legacy telemetry polling in case external module - // driver defines telemetry methods (getByte & processData) - disable_legacy_polling = true; - } - } -#endif - - if (!disable_legacy_polling) { - // TODO: needs to be moved to protocol/module init - // as-is, it implies only ONE telemetry protocol - // enabled at the same time - uint8_t requiredTelemetryProtocol = modelTelemetryProtocol(); - - if (telemetryProtocol != requiredTelemetryProtocol) { - telemetryInit(requiredTelemetryProtocol); - } - - // Poll external / S.PORT telemetry - // TODO: how to switch this OFF ??? - pollExtTelemetryLegacy(); + _telemetryIsPolling = true; + for (uint8_t i = 0; i < MAX_MODULES; i++) { + auto mod = pulsesGetModuleDriver(i); + if (!mod) continue; + pollTelemetry(i, mod->drv, mod->ctx); } + _telemetryIsPolling = false; for (int i=0; i= UNIT_KTS && (unit) <= UNIT_MPH) -extern uint8_t telemetryProtocol; - inline const char* getRssiLabel() { -#if defined(MULTIMODULE) - if (telemetryProtocol == PROTOCOL_TELEMETRY_MULTIMODULE && - (g_model.moduleData[EXTERNAL_MODULE].multi.rfProtocol == - MODULE_SUBTYPE_MULTI_FS_AFHDS2A || - g_model.moduleData[EXTERNAL_MODULE].multi.rfProtocol == - MODULE_SUBTYPE_MULTI_HOTT)) { - return "RQly"; - } -#endif -#if defined(GHOST) - if (telemetryProtocol == PROTOCOL_TELEMETRY_GHOST) { - return "RQly"; - } -#endif -#if defined (PCBNV14) - extern uint32_t NV14internalModuleFwVersion; - if ( (telemetryProtocol == PROTOCOL_TELEMETRY_FLYSKY_NV14) - && (NV14internalModuleFwVersion >= 0x1000E) ) - return "Sgnl"; -#endif - return "RSSI"; + return "Rx-Stats"; } // TODO: this should handle only the external S.PORT line @@ -161,6 +136,7 @@ inline const char* getRssiLabel() // inline uint8_t modelTelemetryProtocol() { +#if defined(HARDWARE_EXTERNAL_MODULE) bool sportUsed = isSportLineUsedByInternalModule(); #if defined(CROSSFIRE) @@ -175,6 +151,7 @@ inline uint8_t modelTelemetryProtocol() } #endif + // TODO: PPM driver should support setting up a telemetry parser callback if (!sportUsed && isModulePPM(EXTERNAL_MODULE)) { return g_model.telemetryProtocol; } @@ -191,17 +168,19 @@ inline uint8_t modelTelemetryProtocol() } #endif + if (isModuleDSMP(EXTERNAL_MODULE)) { + return PROTOCOL_TELEMETRY_DSMP; + } + +#endif // HARDWARE_EXTERNAL_MODULE + // TODO: Check if that is really necessary... -#if defined(AFHDS2) +#if defined(AFHDS2) && defined(HARDWARE_INTERNAL_MODULE) if (isModuleAFHDS2A(INTERNAL_MODULE)) { return PROTOCOL_TELEMETRY_FLYSKY_NV14; } #endif - if (isModuleDSMP(EXTERNAL_MODULE)) { - return PROTOCOL_TELEMETRY_DSMP; - } - // default choice return PROTOCOL_TELEMETRY_FRSKY_SPORT; } diff --git a/radio/src/telemetry/telemetry_sensors.cpp b/radio/src/telemetry/telemetry_sensors.cpp index 7231c43ac..f7b88e1be 100644 --- a/radio/src/telemetry/telemetry_sensors.cpp +++ b/radio/src/telemetry/telemetry_sensors.cpp @@ -57,45 +57,11 @@ uint8_t allowNewSensors; bool isFaiForbidden(source_t idx) { - if (idx < MIXSRC_FIRST_TELEM) { - return false; - } + if (idx < MIXSRC_FIRST_TELEM) return false; - TelemetrySensor * sensor = &g_model.telemetrySensors[(idx-MIXSRC_FIRST_TELEM)/3]; + auto unit = g_model.telemetrySensors[(idx - MIXSRC_FIRST_TELEM) / 3].unit; + if (unit == UNIT_VOLTS || unit == UNIT_DB) return false; - switch (telemetryProtocol) { - case PROTOCOL_TELEMETRY_FRSKY_SPORT: - if (sensor->id == RSSI_ID) { - return false; - } - else if (sensor->id == BATT_ID) { - return false; - } - break; - - case PROTOCOL_TELEMETRY_FRSKY_D: - if (sensor->id == D_RSSI_ID) { - return false; - } - else if (sensor->id == D_A1_ID) { - return false; - } - break; - -#if defined(CROSSFIRE) - case PROTOCOL_TELEMETRY_CROSSFIRE: - if (sensor->id == RX_RSSI1_INDEX) { - return false; - } - else if (sensor->id == RX_RSSI2_INDEX) { - return false; - } - else if (sensor->id == BATT_VOLTAGE_INDEX) { - return false; - } - break; -#endif - } return true; } @@ -105,7 +71,10 @@ uint32_t getDistFromEarthAxis(int32_t latitude) uint32_t lat = abs(latitude) / 10000; uint32_t angle2 = (lat * lat) / 10000; uint32_t angle4 = angle2 * angle2; - return 139*(((uint32_t)10000000 - ((angle2*(uint32_t)123370)/81) + (angle4/25))/12500); + + return 139 * (((uint32_t)10000000 - ((angle2 * (uint32_t)123370) / 81) + + (angle4 / 25)) / + 12500); } void TelemetryItem::setValue(const TelemetrySensor & sensor, const char * val, uint32_t, uint32_t) @@ -114,7 +83,8 @@ void TelemetryItem::setValue(const TelemetrySensor & sensor, const char * val, u setFresh(); } -void TelemetryItem::setValue(const TelemetrySensor & sensor, int32_t val, uint32_t unit, uint32_t prec) +void TelemetryItem::setValue(const TelemetrySensor &sensor, int32_t val, + uint32_t unit, uint32_t prec) { int32_t newVal = val; @@ -522,7 +492,9 @@ int lastUsedTelemetryIndex() } template -int setTelemetryValue(TelemetryProtocol protocol, uint16_t id, uint8_t subId, uint8_t instance, T value, uint32_t unit = 0, uint32_t prec = 0) +int setTelemetryValue(TelemetryProtocol protocol, uint16_t id, uint8_t subId, + uint8_t instance, T value, uint32_t unit = 0, + uint32_t prec = 0) { bool sensorFound = false; diff --git a/radio/src/tests/frsky.cpp b/radio/src/tests/frsky.cpp index 2d7f3e35f..8703ffaf6 100644 --- a/radio/src/tests/frsky.cpp +++ b/radio/src/tests/frsky.cpp @@ -191,16 +191,16 @@ TEST(FrSkySPORT, FrSkyDCells) uint8_t pkt1[] = { 0x7E, 0x98, 0x10, 0x06, 0x00, 0x07, 0xD0, 0x00, 0x00, 0x12 }; EXPECT_EQ(checkSportPacket(pkt1+1), true); - sportProcessTelemetryPacket(pkt1+1); + sportProcessTelemetryPacket(0, pkt1+1, sizeof(pkt1) - 1); uint8_t pkt2[] = { 0x7E, 0x98, 0x10, 0x06, 0x00, 0x17, 0xD0, 0x00, 0x00, 0x02 }; EXPECT_EQ(checkSportPacket(pkt2+1), true); - sportProcessTelemetryPacket(pkt2+1); + sportProcessTelemetryPacket(0, pkt2+1, sizeof(pkt2) - 1); uint8_t pkt3[] = { 0x7E, 0x98, 0x10, 0x06, 0x00, 0x27, 0xD0, 0x00, 0x00, 0xF1 }; EXPECT_EQ(checkSportPacket(pkt3+1), true); - sportProcessTelemetryPacket(pkt3+1); - sportProcessTelemetryPacket(pkt1+1); - sportProcessTelemetryPacket(pkt2+1); - sportProcessTelemetryPacket(pkt3+1); + sportProcessTelemetryPacket(0, pkt3+1, sizeof(pkt3) - 1); + sportProcessTelemetryPacket(0, pkt1+1, sizeof(pkt1) - 1); + sportProcessTelemetryPacket(0, pkt2+1, sizeof(pkt2) - 1); + sportProcessTelemetryPacket(0, pkt3+1, sizeof(pkt3) - 1); EXPECT_EQ(telemetryItems[0].cells.count, 3); EXPECT_EQ(telemetryItems[0].value, 1200); for (int i=0; i<3; i++) { @@ -220,12 +220,16 @@ TEST(FrSkySPORT, frskySetCellVoltage) allowNewSensors = true; // test that simulates 3 cell battery - generateSportCellPacket(packet, 3, 0, 410, 420); sportProcessTelemetryPacket(packet); + generateSportCellPacket(packet, 3, 0, 410, 420); + sportProcessTelemetryPacket(0, packet, sizeof(packet)); EXPECT_EQ(checkSportPacket(packet), true) << "Bad CRC generation in setSportPacketCrc()"; - generateSportCellPacket(packet, 3, 2, 430, 0); sportProcessTelemetryPacket(packet); + generateSportCellPacket(packet, 3, 2, 430, 0); + sportProcessTelemetryPacket(0, packet, sizeof(packet)); - generateSportCellPacket(packet, 3, 0, 405, 300); sportProcessTelemetryPacket(packet); - generateSportCellPacket(packet, 3, 2, 430, 0); sportProcessTelemetryPacket(packet); + generateSportCellPacket(packet, 3, 0, 405, 300); + sportProcessTelemetryPacket(0, packet, sizeof(packet)); + generateSportCellPacket(packet, 3, 2, 430, 0); + sportProcessTelemetryPacket(0, packet, sizeof(packet)); EXPECT_EQ(telemetryItems[0].cells.count, 3); EXPECT_EQ(telemetryItems[0].cells.values[0].value, 405); @@ -236,11 +240,17 @@ TEST(FrSkySPORT, frskySetCellVoltage) EXPECT_EQ(telemetryItems[0].valueMin, 1135); EXPECT_EQ(telemetryItems[0].valueMax, 1260); - generateSportCellPacket(packet, 3, 0, 405, 250); sportProcessTelemetryPacket(packet); - generateSportCellPacket(packet, 3, 2, 430, 0); sportProcessTelemetryPacket(packet); + generateSportCellPacket(packet, 3, 0, 405, 250); + sportProcessTelemetryPacket(0, packet, sizeof(packet)); - generateSportCellPacket(packet, 3, 0, 410, 420); sportProcessTelemetryPacket(packet); - generateSportCellPacket(packet, 3, 2, 430, 0); sportProcessTelemetryPacket(packet); + generateSportCellPacket(packet, 3, 2, 430, 0); + sportProcessTelemetryPacket(0, packet, sizeof(packet)); + + generateSportCellPacket(packet, 3, 0, 410, 420); + sportProcessTelemetryPacket(0, packet, sizeof(packet)); + + generateSportCellPacket(packet, 3, 2, 430, 0); + sportProcessTelemetryPacket(0, packet, sizeof(packet)); EXPECT_EQ(telemetryItems[0].cells.count, 3); EXPECT_EQ(telemetryItems[0].cells.values[0].value, 410); @@ -252,9 +262,12 @@ TEST(FrSkySPORT, frskySetCellVoltage) EXPECT_EQ(telemetryItems[0].valueMax, 1260); //add another two cells - 5 cell battery - generateSportCellPacket(packet, 5, 0, 418, 408); sportProcessTelemetryPacket(packet); - generateSportCellPacket(packet, 5, 2, 415, 420); sportProcessTelemetryPacket(packet); - generateSportCellPacket(packet, 5, 4, 410, 0); sportProcessTelemetryPacket(packet); + generateSportCellPacket(packet, 5, 0, 418, 408); + sportProcessTelemetryPacket(0, packet, sizeof(packet)); + generateSportCellPacket(packet, 5, 2, 415, 420); + sportProcessTelemetryPacket(0, packet, sizeof(packet)); + generateSportCellPacket(packet, 5, 4, 410, 0); + sportProcessTelemetryPacket(0, packet, sizeof(packet)); EXPECT_EQ(telemetryItems[0].cells.count, 5); EXPECT_EQ(telemetryItems[0].cells.values[0].value, 418); @@ -268,9 +281,12 @@ TEST(FrSkySPORT, frskySetCellVoltage) EXPECT_EQ(telemetryItems[0].valueMax, 2071); //simulate very low voltage for cell 3 - generateSportCellPacket(packet, 5, 0, 418, 408); sportProcessTelemetryPacket(packet); - generateSportCellPacket(packet, 5, 2, 100, 420); sportProcessTelemetryPacket(packet); - generateSportCellPacket(packet, 5, 4, 410, 0); sportProcessTelemetryPacket(packet); + generateSportCellPacket(packet, 5, 0, 418, 408); + sportProcessTelemetryPacket(0, packet, sizeof(packet)); + generateSportCellPacket(packet, 5, 2, 100, 420); + sportProcessTelemetryPacket(0, packet, sizeof(packet)); + generateSportCellPacket(packet, 5, 4, 410, 0); + sportProcessTelemetryPacket(0, packet, sizeof(packet)); EXPECT_EQ(telemetryItems[0].cells.count, 5); EXPECT_EQ(telemetryItems[0].cells.values[0].value, 418); @@ -284,10 +300,14 @@ TEST(FrSkySPORT, frskySetCellVoltage) EXPECT_EQ(telemetryItems[0].valueMax, 2071); //back to normal (but with reversed order of packets) - generateSportCellPacket(packet, 5, 4, 410, 0); sportProcessTelemetryPacket(packet); - generateSportCellPacket(packet, 5, 0, 418, 408); sportProcessTelemetryPacket(packet); - generateSportCellPacket(packet, 5, 2, 412, 420); sportProcessTelemetryPacket(packet); - generateSportCellPacket(packet, 5, 4, 410, 0); sportProcessTelemetryPacket(packet); + generateSportCellPacket(packet, 5, 4, 410, 0); + sportProcessTelemetryPacket(0, packet, sizeof(packet)); + generateSportCellPacket(packet, 5, 0, 418, 408); + sportProcessTelemetryPacket(0, packet, sizeof(packet)); + generateSportCellPacket(packet, 5, 2, 412, 420); + sportProcessTelemetryPacket(0, packet, sizeof(packet)); + generateSportCellPacket(packet, 5, 4, 410, 0); + sportProcessTelemetryPacket(0, packet, sizeof(packet)); EXPECT_EQ(telemetryItems[0].cells.count, 5); EXPECT_EQ(telemetryItems[0].cells.values[0].value, 418); @@ -311,7 +331,7 @@ TEST(FrSkySPORT, StrangeCellsBug) uint8_t pkt[] = { 0x7E, 0x48, 0x10, 0x00, 0x03, 0x30, 0x15, 0x50, 0x81, 0xD5 }; EXPECT_EQ(checkSportPacket(pkt+1), true); - sportProcessTelemetryPacket(pkt+1); + sportProcessTelemetryPacket(0, pkt+1, sizeof(pkt) - 1); EXPECT_EQ(telemetryItems[0].cells.count, 3); EXPECT_EQ(telemetryItems[0].cells.values[0].value, 0); // now we ignore such low values EXPECT_EQ(telemetryItems[0].cells.values[1].value, 413); @@ -328,8 +348,10 @@ TEST(FrSkySPORT, frskySetCellVoltageTwoSensors) allowNewSensors = true; //sensor 1: 3 cell battery - generateSportCellPacket(packet, 3, 0, 418, 416); sportProcessTelemetryPacket(packet); - generateSportCellPacket(packet, 3, 2, 415, 0); sportProcessTelemetryPacket(packet); + generateSportCellPacket(packet, 3, 0, 418, 416); + sportProcessTelemetryPacket(0, packet, sizeof(packet)); + generateSportCellPacket(packet, 3, 2, 415, 0); + sportProcessTelemetryPacket(0, packet, sizeof(packet)); EXPECT_EQ(telemetryItems[0].cells.count, 3); EXPECT_EQ(telemetryItems[0].cells.values[0].value, 418); @@ -341,8 +363,10 @@ TEST(FrSkySPORT, frskySetCellVoltageTwoSensors) EXPECT_EQ(telemetryItems[0].valueMax, 1249); //sensor 2: 4 cell battery - generateSportCellPacket(packet, 4, 0, 410, 420, DATA_ID_FLVSS+1); sportProcessTelemetryPacket(packet); - generateSportCellPacket(packet, 4, 2, 400, 405, DATA_ID_FLVSS+1); sportProcessTelemetryPacket(packet); + generateSportCellPacket(packet, 4, 0, 410, 420, DATA_ID_FLVSS+1); + sportProcessTelemetryPacket(0, packet, sizeof(packet)); + generateSportCellPacket(packet, 4, 2, 400, 405, DATA_ID_FLVSS+1); + sportProcessTelemetryPacket(0, packet, sizeof(packet)); EXPECT_EQ(telemetryItems[1].cells.count, 4); EXPECT_EQ(telemetryItems[1].cells.values[0].value, 410); @@ -366,10 +390,14 @@ TEST(FrSkySPORT, frskySetCellVoltageTwoSensors) EXPECT_EQ(telemetryItems[2].valueMax, 287); //now change some voltages - generateSportCellPacket(packet, 3, 2, 415, 0); sportProcessTelemetryPacket(packet); - generateSportCellPacket(packet, 4, 2, 390, 370, DATA_ID_FLVSS+1); sportProcessTelemetryPacket(packet); - generateSportCellPacket(packet, 3, 0, 420, 410); sportProcessTelemetryPacket(packet); - generateSportCellPacket(packet, 4, 0, 410, 420, DATA_ID_FLVSS+1); sportProcessTelemetryPacket(packet); + generateSportCellPacket(packet, 3, 2, 415, 0); + sportProcessTelemetryPacket(0, packet, sizeof(packet)); + generateSportCellPacket(packet, 4, 2, 390, 370, DATA_ID_FLVSS+1); + sportProcessTelemetryPacket(0, packet, sizeof(packet)); + generateSportCellPacket(packet, 3, 0, 420, 410); + sportProcessTelemetryPacket(0, packet, sizeof(packet)); + generateSportCellPacket(packet, 4, 0, 410, 420, DATA_ID_FLVSS+1); + sportProcessTelemetryPacket(0, packet, sizeof(packet)); telemetryWakeup(); @@ -398,22 +426,26 @@ TEST(FrSkySPORT, frskyVfas) allowNewSensors = true; // tests for Vfas - generateSportFasVoltagePacket(packet, 5000); sportProcessTelemetryPacket(packet); + generateSportFasVoltagePacket(packet, 5000); + sportProcessTelemetryPacket(0, packet, sizeof(packet)); EXPECT_EQ(telemetryItems[0].value, 5000); EXPECT_EQ(telemetryItems[0].valueMin, 5000); EXPECT_EQ(telemetryItems[0].valueMax, 5000); - generateSportFasVoltagePacket(packet, 6524); sportProcessTelemetryPacket(packet); + generateSportFasVoltagePacket(packet, 6524); + sportProcessTelemetryPacket(0, packet, sizeof(packet)); EXPECT_EQ(telemetryItems[0].value, 6524); EXPECT_EQ(telemetryItems[0].valueMin, 6524); // the batt was changed (val > old max) EXPECT_EQ(telemetryItems[0].valueMax, 6524); - generateSportFasVoltagePacket(packet, 1248); sportProcessTelemetryPacket(packet); + generateSportFasVoltagePacket(packet, 1248); + sportProcessTelemetryPacket(0, packet, sizeof(packet)); EXPECT_EQ(telemetryItems[0].value, 1248); EXPECT_EQ(telemetryItems[0].valueMin, 1248); EXPECT_EQ(telemetryItems[0].valueMax, 6524); - generateSportFasVoltagePacket(packet, 2248); sportProcessTelemetryPacket(packet); + generateSportFasVoltagePacket(packet, 2248); + sportProcessTelemetryPacket(0, packet, sizeof(packet)); EXPECT_EQ(telemetryItems[0].value, 2248); EXPECT_EQ(telemetryItems[0].valueMin, 1248); EXPECT_EQ(telemetryItems[0].valueMax, 6524); @@ -440,30 +472,35 @@ TEST(FrSkySPORT, frskyCurrent) // tests for Curr generateSportFasCurrentPacket(packet, 0); - sportProcessTelemetryPacket(packet); + sportProcessTelemetryPacket(0, packet, sizeof(packet)); g_model.telemetrySensors[0].custom.offset = -5; /* unit: 1/10 amps */ - generateSportFasCurrentPacket(packet, 0); sportProcessTelemetryPacket(packet); + generateSportFasCurrentPacket(packet, 0); + sportProcessTelemetryPacket(0, packet, sizeof(packet)); EXPECT_EQ(telemetryItems[0].value, 0); EXPECT_EQ(telemetryItems[0].valueMin, 0); EXPECT_EQ(telemetryItems[0].valueMax, 0); // measured current less then offset - value should be zero - generateSportFasCurrentPacket(packet, 4); sportProcessTelemetryPacket(packet); + generateSportFasCurrentPacket(packet, 4); + sportProcessTelemetryPacket(0, packet, sizeof(packet)); EXPECT_EQ(telemetryItems[0].value, 0); EXPECT_EQ(telemetryItems[0].valueMin, 0); EXPECT_EQ(telemetryItems[0].valueMax, 0); - generateSportFasCurrentPacket(packet, 10); sportProcessTelemetryPacket(packet); + generateSportFasCurrentPacket(packet, 10); + sportProcessTelemetryPacket(0, packet, sizeof(packet)); EXPECT_EQ(telemetryItems[0].value, 5); EXPECT_EQ(telemetryItems[0].valueMin, 0); EXPECT_EQ(telemetryItems[0].valueMax, 5); - generateSportFasCurrentPacket(packet, 500); sportProcessTelemetryPacket(packet); + generateSportFasCurrentPacket(packet, 500); + sportProcessTelemetryPacket(0, packet, sizeof(packet)); EXPECT_EQ(telemetryItems[0].value, 495); EXPECT_EQ(telemetryItems[0].valueMin, 0); EXPECT_EQ(telemetryItems[0].valueMax, 495); - generateSportFasCurrentPacket(packet, 200); sportProcessTelemetryPacket(packet); + generateSportFasCurrentPacket(packet, 200); + sportProcessTelemetryPacket(0, packet, sizeof(packet)); EXPECT_EQ(telemetryItems[0].value, 195); EXPECT_EQ(telemetryItems[0].valueMin, 0); EXPECT_EQ(telemetryItems[0].valueMax, 495); @@ -474,17 +511,20 @@ TEST(FrSkySPORT, frskyCurrent) telemetryData.telemetryValid = 0x07; g_model.telemetrySensors[0].custom.offset = +5; /* unit: 1/10 amps */ - generateSportFasCurrentPacket(packet, 0); sportProcessTelemetryPacket(packet); + generateSportFasCurrentPacket(packet, 0); + sportProcessTelemetryPacket(0, packet, sizeof(packet)); EXPECT_EQ(telemetryItems[0].value, 5); EXPECT_EQ(telemetryItems[0].valueMin, 5); EXPECT_EQ(telemetryItems[0].valueMax, 5); - generateSportFasCurrentPacket(packet, 500); sportProcessTelemetryPacket(packet); + generateSportFasCurrentPacket(packet, 500); + sportProcessTelemetryPacket(0, packet, sizeof(packet)); EXPECT_EQ(telemetryItems[0].value, 505); EXPECT_EQ(telemetryItems[0].valueMin, 5); EXPECT_EQ(telemetryItems[0].valueMax, 505); - generateSportFasCurrentPacket(packet, 200); sportProcessTelemetryPacket(packet); + generateSportFasCurrentPacket(packet, 200); + sportProcessTelemetryPacket(0, packet, sizeof(packet)); EXPECT_EQ(telemetryItems[0].value, 205); EXPECT_EQ(telemetryItems[0].valueMin, 5); EXPECT_EQ(telemetryItems[0].valueMax, 505); diff --git a/radio/src/trainer.cpp b/radio/src/trainer.cpp index a6acac4fe..3a5aa99fe 100644 --- a/radio/src/trainer.cpp +++ b/radio/src/trainer.cpp @@ -22,7 +22,6 @@ #include "opentx.h" #include "hal/trainer_driver.h" #include "heartbeat_driver.h" -#include "aux_serial_driver.h" int16_t ppmInput[MAX_TRAINER_CHANNELS]; uint8_t ppmInputValidityTimer; diff --git a/radio/src/translations.cpp b/radio/src/translations.cpp index c1c4a9d64..aaadbe3da 100644 --- a/radio/src/translations.cpp +++ b/radio/src/translations.cpp @@ -66,8 +66,7 @@ ISTR(JACK_MODES); ISTR(VFAILSAFE); ISTR(VTRAINERMODES); ISTR(FLYSKY_PROTOCOLS); -ISTR(EXTERNAL_MODULE_PROTOCOLS); -ISTR(INTERNAL_MODULE_PROTOCOLS); +ISTR(MODULE_PROTOCOLS); ISTR(R9M_REGION); ISTR(R9M_FCC_POWER_VALUES); ISTR(R9M_LBT_POWER_VALUES); diff --git a/radio/src/translations.h b/radio/src/translations.h index b5ea52c94..86708d760 100644 --- a/radio/src/translations.h +++ b/radio/src/translations.h @@ -184,8 +184,7 @@ extern const char* const STR_VFAILSAFE[]; extern const char* const STR_FONT_SIZES[]; extern const char* const STR_VTRAINERMODES[]; -extern const char* const STR_EXTERNAL_MODULE_PROTOCOLS[]; -extern const char* const STR_INTERNAL_MODULE_PROTOCOLS[]; +extern const char* const STR_MODULE_PROTOCOLS[]; extern const char* const STR_R9M_REGION[]; extern const char* const STR_R9M_FCC_POWER_VALUES[]; extern const char* const STR_R9M_LBT_POWER_VALUES[]; diff --git a/radio/src/translations/untranslated.h b/radio/src/translations/untranslated.h index 62222ddd9..e452d2608 100644 --- a/radio/src/translations/untranslated.h +++ b/radio/src/translations/untranslated.h @@ -103,7 +103,7 @@ #define TR_MODULE_R9M_LITE "R9MLite" -#define TR_EXTERNAL_MODULE_PROTOCOLS \ +#define TR_MODULE_PROTOCOLS \ TR_OFF, \ "PPM", \ "XJT", \ @@ -122,8 +122,6 @@ "FLYSKY", \ TR("Lemon DSMP","LemonRx DSMP") -#define TR_INTERNAL_MODULE_PROTOCOLS TR_EXTERNAL_MODULE_PROTOCOLS - #define TR_FLYSKY_PROTOCOLS "AFHDS3","AFHDS2A" #define TR_XJT_ACCST_RF_PROTOCOLS "D16","D8","LR12" #define TR_ISRM_RF_PROTOCOLS "ACCESS","D16","LR12"