From 75b1767c4482a1e6c9ce6e3ad89f9085d31bebbb Mon Sep 17 00:00:00 2001 From: rotorman Date: Thu, 8 Oct 2026 15:15:13 +0200 Subject: [PATCH 1/6] feat: Adds Jumper T18 H7 support. Work done by 3djc - thx! The board matched no colour-LCD family, so getCapability() returned 128x64 depth 1 and the simulator drew a monochrome screen. Add T18H7 to the LcdDepth/LcdWidth/LcdHeight cases directly rather than to IS_FAMILY_T16: that family also drives BoardJson::afterLoadFixups(), which injects TILT_X/TILT_Y gyro inputs the T18H7 does not have. Also add it to IS_STM32H7 alongside t15pro/t22. The switch/pot defaults that main carries in the hw def JSON live in switch_config.py / pot_config.py on 2.12; without an entry every switch generated as default NONE and the flex inputs had no default at all. Also add T18H7 to the rotary encoder granularity list (same encoder as t15pro) and to build-companion.sh's simulator plugin list. 2.12 generates the hw def JSON from hal.h and has no hal_settings.h, so the hand-written boards/hw_defs/t18h7.json is dead there. Move the description into hal.h, drop the JSON, and regenerate the yaml map against 2.12. stm32_rgbleds.cpp is stm32_ws2812.cpp on 2.12; RGB_LEDS_900NS has no effect there as that driver's bit timing is fixed at 1250ns. --- .github/workflows/build_fw.yml | 2 + .github/workflows/nightly.yml | 1 + companion/src/firmwares/boards.cpp | 11 +- companion/src/firmwares/boards.h | 7 + .../src/firmwares/opentx/opentxinterface.cpp | 8 +- fw.json | 1 + radio/src/CMakeLists.txt | 4 +- radio/src/boards/jumper-h750/board.cpp | 6 +- .../boards/jumper-h750/lcd_driver_480x272.cpp | 236 ++++ .../boards/jumper-h750/lcd_driver_480x272.h | 43 + radio/src/boards/jumper-h750/tp_gt911.cpp | 555 +++++++++ radio/src/boards/jumper-h750/tp_gt911.h | 83 ++ radio/src/datastructs.h | 5 +- radio/src/storage/yaml/CMakeLists.txt | 2 + radio/src/storage/yaml/yaml_datastructs.cpp | 2 + .../storage/yaml/yaml_datastructs_t18h7.cpp | 1039 +++++++++++++++++ radio/src/targets/t18h7/CMakeLists.txt | 189 +++ radio/src/targets/t18h7/hal.h | 515 ++++++++ radio/src/targets/t18h7/usb_descriptor.h | 26 + radio/util/hw_defs/legacy_names.py | 53 + radio/util/hw_defs/pot_config.py | 6 + radio/util/hw_defs/switch_config.py | 17 + tools/build-common.sh | 3 + tools/build-companion.sh | 2 +- tools/generate-hw-defs.sh | 2 +- tools/generate-yaml.sh | 2 +- 26 files changed, 2810 insertions(+), 10 deletions(-) create mode 100644 radio/src/boards/jumper-h750/lcd_driver_480x272.cpp create mode 100644 radio/src/boards/jumper-h750/lcd_driver_480x272.h create mode 100644 radio/src/boards/jumper-h750/tp_gt911.cpp create mode 100644 radio/src/boards/jumper-h750/tp_gt911.h create mode 100644 radio/src/storage/yaml/yaml_datastructs_t18h7.cpp create mode 100644 radio/src/targets/t18h7/CMakeLists.txt create mode 100644 radio/src/targets/t18h7/hal.h create mode 100644 radio/src/targets/t18h7/usb_descriptor.h diff --git a/.github/workflows/build_fw.yml b/.github/workflows/build_fw.yml index 913219172fc..7f3cfba8d71 100644 --- a/.github/workflows/build_fw.yml +++ b/.github/workflows/build_fw.yml @@ -57,6 +57,7 @@ jobs: - st16 - t15pro - t15h7 + - t18h7 - pa01 - t22 - h17 @@ -114,6 +115,7 @@ jobs: - st16 - t15pro - t15h7 + - t18h7 - t22 - c14 - h17 diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index c272e65b653..8d41b083824 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -42,6 +42,7 @@ jobs: - t15h7 - gx15 - h17 + - t18h7 container: image: ghcr.io/edgetx/edgetx-dev:2.12 volumes: diff --git a/companion/src/firmwares/boards.cpp b/companion/src/firmwares/boards.cpp index 730d3b91a47..14a35b3071e 100644 --- a/companion/src/firmwares/boards.cpp +++ b/companion/src/firmwares/boards.cpp @@ -228,6 +228,7 @@ int Boards::getEEpromSize(Board::Type board) case BOARD_JUMPER_T22: case BOARD_JUMPER_T16: case BOARD_JUMPER_T18: + case BOARD_JUMPER_T18H7: case BOARD_RADIOMASTER_TX16S: case BOARD_RADIOMASTER_TX16SMK3: case BOARD_RADIOMASTER_TX15: @@ -298,6 +299,7 @@ int Boards::getFlashSize(Type board) case BOARD_JUMPER_T22: case BOARD_JUMPER_T16: case BOARD_JUMPER_T18: + case BOARD_JUMPER_T18H7: case BOARD_RADIOMASTER_TX16S: case BOARD_RADIOMASTER_TX16SMK3: case BOARD_RADIOMASTER_TX15: @@ -442,7 +444,7 @@ int Boards::getCapability(Board::Type board, Board::Capability capability) IS_HELLORADIOSKY_V14(board); case LcdDepth: - if (IS_FAMILY_HORUS_OR_T16(board)) + if (IS_FAMILY_HORUS_OR_T16(board) || IS_JUMPER_T18H7(board)) return 16; else if (IS_TARANIS_SMALL(board)) return 1; @@ -458,7 +460,7 @@ int Boards::getCapability(Board::Type board, Board::Capability capability) return 320; else if (IS_FLYSKY_PA01(board) || IS_HELLORADIOSKY_V12(board)) return 240; - else if (IS_FAMILY_HORUS_OR_T16(board)) + else if (IS_FAMILY_HORUS_OR_T16(board) || IS_JUMPER_T18H7(board)) return 272; else return 64; @@ -468,7 +470,7 @@ int Boards::getCapability(Board::Type board, Board::Capability capability) return 800; else if (IS_FLYSKY_NV14(board) || IS_FLYSKY_EL18(board) || IS_FLYSKY_PA01(board) || IS_HELLORADIOSKY_V12(board)) return 320; - else if (IS_FAMILY_HORUS_OR_T16(board) || IS_RADIOMASTER_TX15(board) || IS_FAMILY_PL18(board) || IS_FLYSKY_ST16(board)) + else if (IS_FAMILY_HORUS_OR_T16(board) || IS_JUMPER_T18H7(board) || IS_RADIOMASTER_TX15(board) || IS_FAMILY_PL18(board) || IS_FLYSKY_ST16(board)) return 480; else if (IS_TARANIS(board) && !IS_TARANIS_SMALL(board)) return 212; @@ -713,6 +715,8 @@ QString Boards::getBoardName(Board::Type board) return "Jumper T16"; case BOARD_JUMPER_T18: return "Jumper T18"; + case BOARD_JUMPER_T18H7: + return "Jumper T18H7"; case BOARD_JUMPER_T20: return "Jumper T20"; case BOARD_JUMPER_T20V2: @@ -898,6 +902,7 @@ int Boards::getDefaultInternalModules(Board::Type board) case BOARD_JUMPER_T15: case BOARD_JUMPER_T15PRO: case BOARD_JUMPER_T15H7: + case BOARD_JUMPER_T18H7: case BOARD_JUMPER_T22: case BOARD_JUMPER_T20: case BOARD_JUMPER_TPROS: diff --git a/companion/src/firmwares/boards.h b/companion/src/firmwares/boards.h index 017bfddf2b8..13416070249 100644 --- a/companion/src/firmwares/boards.h +++ b/companion/src/firmwares/boards.h @@ -104,6 +104,7 @@ namespace Board { BOARD_HELLORADIOSKY_V14LCD, BOARD_IFLIGHT_COMMANDO14, BOARD_SENDUWING_H17, + BOARD_JUMPER_T18H7, BOARD_TYPE_COUNT, BOARD_TYPE_MAX = BOARD_TYPE_COUNT - 1 }; @@ -596,6 +597,11 @@ inline bool IS_JUMPER_T18(Board::Type board) return board == Board::BOARD_JUMPER_T18; } +inline bool IS_JUMPER_T18H7(Board::Type board) +{ + return board == Board::BOARD_JUMPER_T18H7; +} + inline bool IS_JUMPER_T20(Board::Type board) { return board == Board::BOARD_JUMPER_T20 || board == Board::BOARD_JUMPER_T20V2; @@ -908,6 +914,7 @@ inline bool IS_STM32H7(Board::Type board) IS_HELLORADIOSKY_V12(board) || IS_JUMPER_T15PRO(board) || IS_JUMPER_T15H7(board) || + IS_JUMPER_T18H7(board) || IS_JUMPER_T22(board) || IS_RADIOMASTER_TX15(board) || IS_RADIOMASTER_TX16SMK3(board) || diff --git a/companion/src/firmwares/opentx/opentxinterface.cpp b/companion/src/firmwares/opentx/opentxinterface.cpp index a0d6f2ec5b9..f90feefa6a7 100644 --- a/companion/src/firmwares/opentx/opentxinterface.cpp +++ b/companion/src/firmwares/opentx/opentxinterface.cpp @@ -352,7 +352,7 @@ int OpenTxFirmware::getCapability(::Capability capability) return id.contains("internalelrs") || IS_RADIOMASTER_TX12_MK2(board) || IS_IFLIGHT_COMMANDO8(board) || IS_RADIOMASTER_BOXER(board) || IS_RADIOMASTER_POCKET(board) || IS_JUMPER_T20(board) || - IS_RADIOMASTER_MT12(board) || IS_RADIOMASTER_TX15(board) || IS_JUMPER_T15PRO(board) || IS_JUMPER_T15H7(board) || IS_JUMPER_T22(board) || + IS_RADIOMASTER_MT12(board) || IS_RADIOMASTER_TX15(board) || IS_JUMPER_T15PRO(board) || IS_JUMPER_T15H7(board) || IS_JUMPER_T22(board) || IS_JUMPER_T18H7(board) || IS_SENDUWING_H17(board); case HasIntModuleFlySky: return id.contains("afhds2a") || id.contains("afhds3") || @@ -776,6 +776,12 @@ void registerOpenTxFirmwares() addOpenTxRfOptions(firmware, FLEX); registerOpenTxFirmware(firmware); + /* Jumper T18H7 board */ + firmware = new OpenTxFirmware(FIRMWAREID("t18h7"), Firmware::tr("Jumper T18H7"), BOARD_JUMPER_T18H7); + addOpenTxFrskyOptions(firmware); + addOpenTxRfOptions(firmware, FLEX); + registerOpenTxFirmware(firmware); + /* Jumper T22 board */ firmware = new OpenTxFirmware(FIRMWAREID("t22"), Firmware::tr("Jumper T22"), BOARD_JUMPER_T22); addOpenTxFrskyOptions(firmware); diff --git a/fw.json b/fw.json index 1e65f7d2f16..d82a0efdf1f 100644 --- a/fw.json +++ b/fw.json @@ -30,6 +30,7 @@ ["Jumper T15-H7", "t15h7-"], ["Jumper T16", "t16-"], ["Jumper T18", "t18-"], + ["Jumper T18H7", "t18h7-"], ["Jumper T20", "t20-"], ["Jumper T20 V2", "t20v2-"], ["Jumper T22", "t22-"], diff --git a/radio/src/CMakeLists.txt b/radio/src/CMakeLists.txt index 59ecedaad66..0d32b121e2d 100644 --- a/radio/src/CMakeLists.txt +++ b/radio/src/CMakeLists.txt @@ -1,7 +1,7 @@ include(CMakeForceCompiler) include(Bitmaps) -set(PCB_TYPES X9LITE X9LITES X7 XLITE XLITES X9D X9D+ X9E X10 X12S PL18 T15PRO T15H7 ST16 PA01 TX15 TX16SMK3 T22 V12 GX15 H17) +set(PCB_TYPES X9LITE X9LITES X7 XLITE XLITES X9D X9D+ X9E X10 X12S PL18 T15PRO T15H7 T18H7 ST16 PA01 TX15 TX16SMK3 T22 V12 GX15 H17) set(RADIO_LANGUAGES CN CZ DA DE EN ES FI FR HE HU IT JP KO NL PL PT RU SE SK TW UA) set(TTS_LANGUAGES CN CZ DA DE EN ES FI FR HE HU IT JP KO NL PL PT RU SE SK TW UA) @@ -96,6 +96,8 @@ elseif(PCB STREQUAL T15PRO) include(targets/t15pro/CMakeLists.txt) elseif(PCB STREQUAL T15H7) include(targets/t15h7/CMakeLists.txt) +elseif(PCB STREQUAL T18H7) + include(targets/t18h7/CMakeLists.txt) elseif(PCB STREQUAL ST16) include(targets/st16/CMakeLists.txt) elseif(PCB STREQUAL C14) diff --git a/radio/src/boards/jumper-h750/board.cpp b/radio/src/boards/jumper-h750/board.cpp index e891983d91a..a90fb035a9a 100644 --- a/radio/src/boards/jumper-h750/board.cpp +++ b/radio/src/boards/jumper-h750/board.cpp @@ -54,7 +54,11 @@ #include "colors.h" -#include "touch_driver.h" +#if defined(TOUCH_PANEL_GT911) + #include "tp_gt911.h" +#else + #include "touch_driver.h" +#endif #include diff --git a/radio/src/boards/jumper-h750/lcd_driver_480x272.cpp b/radio/src/boards/jumper-h750/lcd_driver_480x272.cpp new file mode 100644 index 00000000000..6fc54383ed1 --- /dev/null +++ b/radio/src/boards/jumper-h750/lcd_driver_480x272.cpp @@ -0,0 +1,236 @@ +/* + * 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_hal.h" +#include "edgetx_types.h" +#include "dma2d.h" +#include "hal.h" +#include "delays_driver.h" +#include "debug.h" +#include "lcd.h" +#include "lcd_driver_480x272.h" +#include "board.h" + +#include "hal/gpio.h" +#include "stm32_gpio.h" + +uint8_t TouchControllerType = 0; // 0: other; 1: CST836U + +static const uint16_t lcd_phys_w = LCD_PHYS_W; +static const uint16_t lcd_phys_h = LCD_PHYS_H; + +static LTDC_HandleTypeDef hltdc; +static void* initialFrameBuffer = nullptr; + +static void startLcdRefresh(lv_disp_drv_t *disp_drv, uint16_t *buffer, + const rect_t ©_area) +{ + (void)disp_drv; + (void)copy_area; + + // given the data cache size, this is probably + // faster than cleaning by address + SCB_CleanDCache(); + + LTDC_Layer1->CFBAR = (uint32_t)buffer; + // reload shadow registers on vertical blank + LTDC->SRCR = LTDC_SRCR_VBR; + + __HAL_LTDC_ENABLE_IT(&hltdc, LTDC_IT_LI); +} + +// The panel needs no SPI init sequence, but these are referenced by the +// backlight driver, so keep them defined and unused. +lcdSpiInitFucPtr lcdInitFunction; +lcdSpiInitFucPtr lcdOffFunction; +lcdSpiInitFucPtr lcdOnFunction; + +static void LCD_AF_GPIOConfig(void) +{ + const gpio_t _lcd_af_gpios[] = { + GPIO_PIN(GPIOI, 12), GPIO_PIN(GPIOI, 13), GPIO_PIN(GPIOI, 14), + + GPIO_PIN(GPIOJ, 2), GPIO_PIN(GPIOJ, 3), GPIO_PIN(GPIOJ, 4), + GPIO_PIN(GPIOJ, 5), GPIO_PIN(GPIOJ, 6), GPIO_PIN(GPIOJ, 9), + GPIO_PIN(GPIOJ, 10), GPIO_PIN(GPIOJ, 11), GPIO_PIN(GPIOJ, 15), + + GPIO_PIN(GPIOK, 0), GPIO_PIN(GPIOK, 1), GPIO_PIN(GPIOK, 2), + GPIO_PIN(GPIOK, 3), GPIO_PIN(GPIOK, 4), GPIO_PIN(GPIOK, 5), + GPIO_PIN(GPIOK, 6), GPIO_PIN(GPIOK, 7), + }; + + for (unsigned i = 0; i < sizeof(_lcd_af_gpios) / sizeof(_lcd_af_gpios[0]); i++) { + gpio_init_af(_lcd_af_gpios[i], GPIO_AF14, GPIO_SPEED_FREQ_LOW); + } +} + +static void lcdResetConfig(void) +{ + LL_GPIO_InitTypeDef GPIO_InitStructure; + LL_GPIO_StructInit(&GPIO_InitStructure); + + GPIO_InitStructure.Pin = LCD_NRST_GPIO_PIN; + GPIO_InitStructure.Speed = LL_GPIO_SPEED_FREQ_LOW; + GPIO_InitStructure.Mode = LL_GPIO_MODE_OUTPUT; + GPIO_InitStructure.OutputType = LL_GPIO_OUTPUT_PUSHPULL; + GPIO_InitStructure.Pull = LL_GPIO_PULL_NO; + LL_GPIO_Init(LCD_NRST_GPIO, &GPIO_InitStructure); +} + +static void lcdReset() +{ + // As on the T18, this panel misbehaves if NRST is ever driven low, so it is + // only ever released high. + LCD_NRST_HIGH(); + delay_ms(30); +} + +void LCD_Init_LTDC() +{ + hltdc.Instance = LTDC; + + // LTDC is clocked from PLL3R, configured in system_clock.c (~10.7 MHz). + // Together with the totals below that gives roughly 69 Hz refresh. + + /* LTDC Configuration *********************************************************/ + /* Polarity configuration */ + /* Initialize the horizontal synchronization polarity as active low */ + hltdc.Init.HSPolarity = LTDC_HSPOLARITY_AL; + /* Initialize the vertical synchronization polarity as active low */ + hltdc.Init.VSPolarity = LTDC_VSPOLARITY_AL; + /* Initialize the data enable polarity as active low */ + hltdc.Init.DEPolarity = LTDC_DEPOLARITY_AL; + /* Initialize the pixel clock polarity as input pixel clock */ + hltdc.Init.PCPolarity = LTDC_PCPOLARITY_IPC; + + /* Configure R,G,B component values for LCD background color */ + hltdc.Init.Backcolor.Red = 0; + hltdc.Init.Backcolor.Green = 0; + hltdc.Init.Backcolor.Blue = 0; + + /* Configure horizontal synchronization width */ + hltdc.Init.HorizontalSync = HSW; + /* Configure vertical synchronization height */ + hltdc.Init.VerticalSync = VSH; + /* Configure accumulated horizontal back porch */ + hltdc.Init.AccumulatedHBP = HBP; + /* Configure accumulated vertical back porch */ + hltdc.Init.AccumulatedVBP = VBP; + /* Configure accumulated active width */ + hltdc.Init.AccumulatedActiveW = lcd_phys_w + HBP; + /* Configure accumulated active height */ + hltdc.Init.AccumulatedActiveH = lcd_phys_h + VBP; + /* Configure total width */ + hltdc.Init.TotalWidth = lcd_phys_w + HBP + HFP; + /* Configure total height */ + hltdc.Init.TotalHeigh = lcd_phys_h + VBP + VFP; + + HAL_LTDC_Init(&hltdc); + + // Configure IRQ (line) + NVIC_SetPriority(LTDC_IRQn, LTDC_IRQ_PRIO); + NVIC_EnableIRQ(LTDC_IRQn); + + // Trigger on last line + HAL_LTDC_ProgramLineEvent(&hltdc, lcd_phys_h); + __HAL_LTDC_ENABLE_IT(&hltdc, LTDC_IT_LI); +} + +void LCD_LayerInit() +{ + auto& layer = hltdc.LayerCfg[0]; + + /* Windowing configuration */ + layer.WindowX0 = 0; + layer.WindowX1 = lcd_phys_w; + layer.WindowY0 = 0; + layer.WindowY1 = lcd_phys_h; + + /* Pixel Format configuration*/ + layer.PixelFormat = LTDC_PIXEL_FORMAT_RGB565; + + /* Alpha constant (255 totally opaque) */ + layer.Alpha = 255; + + /* Default Color configuration (configure A,R,G,B component values) */ + layer.Backcolor.Blue = 0; + layer.Backcolor.Green = 0; + layer.Backcolor.Red = 0; + layer.Alpha0 = 0; + + /* Configure blending factors */ + layer.BlendingFactor1 = LTDC_BLENDING_FACTOR1_CA; + layer.BlendingFactor2 = LTDC_BLENDING_FACTOR2_CA; + + layer.ImageWidth = lcd_phys_w; + layer.ImageHeight = lcd_phys_h; + + /* Start Address configuration : the LCD Frame buffer is defined on SDRAM w/ Offset */ + layer.FBStartAdress = (intptr_t)initialFrameBuffer; + + /* Initialize LTDC layer 1 */ + HAL_LTDC_ConfigLayer(&hltdc, &hltdc.LayerCfg[0], 0); + + /* dithering activation */ + HAL_LTDC_EnableDither(&hltdc); +} + +extern "C" +void lcdSetInitalFrameBuffer(void* fbAddress) +{ + initialFrameBuffer = fbAddress; +} + +const char* boardLcdType = ""; + +extern "C" +void lcdInit(void) +{ + /* Configure the LCD reset pin */ + lcdResetConfig(); + + /* Release the LCD from reset ------------------------------------------*/ + lcdReset(); + + /* Configure the LCD Control pins */ + LCD_AF_GPIOConfig(); + + boardLcdType = "RGB 480x272"; + + __HAL_RCC_LTDC_CLK_ENABLE(); + + LCD_Init_LTDC(); + LCD_LayerInit(); + + // Enable LCD display + __HAL_LTDC_ENABLE(&hltdc); + + lcdSetFlushCb(startLcdRefresh); +} + +extern "C" void LTDC_IRQHandler(void) +{ + __HAL_LTDC_CLEAR_FLAG(&hltdc, LTDC_FLAG_LI); + __HAL_LTDC_DISABLE_IT(&hltdc, LTDC_IT_LI); + + lcdFlushed(); +} diff --git a/radio/src/boards/jumper-h750/lcd_driver_480x272.h b/radio/src/boards/jumper-h750/lcd_driver_480x272.h new file mode 100644 index 00000000000..dfb9517b74b --- /dev/null +++ b/radio/src/boards/jumper-h750/lcd_driver_480x272.h @@ -0,0 +1,43 @@ +/* + * 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 + +// Timings for the 480x272 RGB panel, taken from the T18 (STM32F4) target. +// These are already expressed as LTDC register values (accumulated, 0-based), +// so they are programmed without further adjustment. +#define HBP ( 43 ) +#define VBP ( 12 ) + +#define HSW ( 2 ) +#define VSH ( 4 ) + +#define HFP ( 8 ) +#define VFP ( 8 ) + +typedef void (*lcdSpiInitFucPtr)(void); + +extern lcdSpiInitFucPtr lcdInitFunction; +extern lcdSpiInitFucPtr lcdOffFunction; +extern lcdSpiInitFucPtr lcdOnFunction; + +#define LCD_NRST_HIGH() LL_GPIO_SetOutputPin(LCD_NRST_GPIO, LCD_NRST_GPIO_PIN) +#define LCD_NRST_LOW() LL_GPIO_ResetOutputPin(LCD_NRST_GPIO, LCD_NRST_GPIO_PIN) diff --git a/radio/src/boards/jumper-h750/tp_gt911.cpp b/radio/src/boards/jumper-h750/tp_gt911.cpp new file mode 100644 index 00000000000..6d7687a2331 --- /dev/null +++ b/radio/src/boards/jumper-h750/tp_gt911.cpp @@ -0,0 +1,555 @@ +/* + * 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/gpio.h" +#include "hal/i2c_driver.h" +#include "stm32_gpio.h" +#include "stm32_hal_ll.h" +#include "stm32_hal.h" +#include "stm32_i2c_driver.h" +#include "stm32_gpio_driver.h" +#include "stm32_exti_driver.h" + +#include "hal.h" +#include "timers_driver.h" +#include "tp_gt911.h" +#include "delays_driver.h" + +#include "os/sleep.h" +#include "edgetx_types.h" +#include "debug.h" + +#include +#include + +#define TP_GT911_ID "911" + + +// GT911 configuration for the 480x272 panel, taken verbatim from the T18 +// (STM32F4) target, which uses the same panel. +const uint8_t TOUCH_GT911_Cfg[] = { + GT911_CFG_NUMBER, // 0x8047 Config version + 0xE0, // 0x8048 X output map : x 480 + 0x01, + 0x10, // 0x804A Y ouptut max : y 272 + 0x01, + GT911_MAX_TP, // 0x804C Touch number + 0x0C, // 0x804D Module switch 1 : bit4= xy change Int mode + 0x00, // 0x804E Module switch 2 + 0x01, // 0x804F Shake_Count + 0x18, // 0x8050 Filter + 0x28, // 0x8051 Larger touch + 0x0F, // 0x8052 Noise reduction + 0x50, // 0x8053 Screen touch level + 0x3C, // 0x8054 Screen touch leave + 0x03, // 0x8055 Low power control + 0x0F, // 0x8056 Refresh rate + 0x01, // 0x8057 X threshold + 0x01, // 0x8058 Y threshold + 0x00, // 0x8059 Reserved + 0x00, // 0x805A Reserved + 0x00, // 0x805B Space (top, bottom) + 0x00, // 0x805C Space (left, right) + 0x04, // 0x805D Mini filter + 0x18, // 0x805E Strech R0 + 0x1A, // 0x805F Strech R1 + 0x1E, // 0x8060 Strech R2 + 0x14, // 0x8061 Strech RM + 0x87, // 0x8062 Drv groupA num + 0x29, // 0x8063 Drv groupB num + 0x0A, // 0x8064 Sensor num + 0x4B, // 0x8065 FreqA factor + 0x4D, // 0x8066 FreqB factor + 0xD3, // 0x8067 Panel bit freq + 0x07, + 0x00, // 0x8069 Reserved + 0x00, + 0x00, // 0x806B Panel tx gain + 0x19, // 0x806C Panel rx gain + 0x02, // 0x806D Panel dump shift + 0x10, // 0x806E Drv frame control + 0x32, // 0x806F Charging level up + 0x00, // 0x8070 Module switch 3 + 0x00, // 0x8071 Gesture distance + 0x00, // 0x8072 Gesture long press time + 0x00, // 0x8073 X/Y slope adjust + 0x03, // 0x8074 Gesture control + 0x00, // 0x8075 Gesture switch 1 + 0x00, // 0x8076 Gesture switch 2 + 0x00, // 0x8077 Gesture refresh rate + 0x00, // 0x8078 Gesture touch level + 0x00, // 0x8079 New green wake up level + 0x32, // 0x807A Freq hopping start + 0x73, // 0x807B Freq hopping end + 0x94, // 0x807C Noise detect time + 0xD5, // 0x807D Hopping flag + 0x02, // 0x807E Hopping flag + 0x07, // 0x807F Noise threshold + 0x00, // 0x8080 Nois min threshold old + 0x00, // 0x8081 Reserved + 0x04, // 0x8082 Hopping sensor group + 0xAE, // 0x8083 Hopping Seg1 normalize + 0x36, // 0x8084 Hopping Seg1 factor + 0x00, // 0x8085 Main clock adjust + 0x94, // 0x8086 Hopping Seg2 normalize + 0x40, // 0x8087 Hopping Seg2 factor + 0x00, // 0x8088 Reserved + 0x7E, // 0x8089 Hopping Seg3 normalize + 0x4C, // 0x808A Hopping Seg3 factor + 0x00, // 0x808B Reserved + 0x6D, // 0x808C Hopping Seg4 normalize + 0x59, // 0x808D Hopping Seg4 factor + 0x00, // 0x808E Reserved + 0x5D, // 0x808F Hopping Seg5 normalize + 0x6A, // 0x8090 Hopping Seg5 factor + 0x00, // 0x8091 Reserved + 0x5D, // 0x8092 Hopping Seg6 normalize + 0x00, // 0x8093 Key1 + 0x00, // 0x8094 Key2 + 0x00, // 0x8095 Key3 + 0x00, // 0x8096 Key4 + 0x00, // 0x8097 Key area + 0x00, // 0x8098 Key touch level + 0x00, // 0x8099 Key leave level + 0x00, // 0x809A Key sens + 0x00, // 0x809B Key sens + 0x00, // 0x809C Key restrain + 0x00, // 0x809D Key restrain time + 0x00, // 0x809E Large gesture touch + 0x00, // 0x809F Reserved + 0x00, // 0x80A0 Reserved + 0x00, // 0x80A1 Hotknot noise map + 0x00, // 0x80A2 Link threshold + 0x00, // 0x80A3 Pxy threshold + 0x00, // 0x80A4 GHot dump shift + 0x00, // 0x80A5 GHot rx gain + 0x00, // 0x80A6 Freg gain + 0x00, // 0x80A7 Freg gain 1 + 0x00, // 0x80A8 Freg gain 2 + 0x00, // 0x80A9 Freg gain 3 + 0x00, // 0x80AA Reserved + 0x00, // 0x80AB Reserved + 0x00, // 0x80AC Reserved + 0x00, // 0x80AD Reserved + 0x00, // 0x80AE Reserved + 0x00, // 0x80AF Reserved + 0x00, // 0x80B0 Reserved + 0x00, // 0x80B1 Reserved + 0x00, // 0x80B2 Reserved + 0x00, // 0x80B3 Combine dis + 0x00, // 0x80B4 Split set + 0x00, // 0x80B5 Reserved + 0x00, // 0x80B6 Reserved + 0x0A, // 0x80B7 Sensor CH0 + 0x0C, // 0x80B8 Sensor CH1 + 0x0E, // 0x80B9 Sensor CH2 + 0x10, // 0x80BA Sensor CH3 + 0x12, // 0x80BB Sensor CH4 + 0x14, // 0x80BC Sensor CH5 + 0x16, // 0x80BD Sensor CH6 + 0x18, // 0x80BE Sensor CH7 + 0x1A, // 0x80BF Sensor CH8 + 0x1C, // 0x80C0 Sensor CH9 + 0xFF, // 0x80C1 Sensor CH10 + 0xFF, // 0x80C2 Sensor CH11 + 0xFF, // 0x80C3 Sensor CH12 + 0xFF, // 0x80C4 Sensor CH13 + 0xFF, // 0x80C5 Reserved + 0xFF, // 0x80C6 Reserved + 0xFF, // 0x80C7 Reserved + 0xFF, // 0x80C8 Reserved + 0xFF, // 0x80C9 Reserved + 0xFF, // 0x80CA Reserved + 0xFF, // 0x80CB Reserved + 0xFF, // 0x80CC Reserved + 0xFF, // 0x80CD Reserved + 0xFF, // 0x80CE Reserved + 0xFF, // 0x80CF Reserved + 0xFF, // 0x80D0 Reserved + 0xFF, // 0x80D1 Reserved + 0xFF, // 0x80D2 Reserved + 0xFF, // 0x80D3 Reserved + 0xFF, // 0x80D4 Reserved + 0x00, // 0x80D5 Driver CH0 + 0x02, // 0x80D6 Driver CH1 + 0x04, // 0x80D7 Driver CH2 + 0x06, // 0x80D8 Driver CH3 + 0x08, // 0x80D9 Driver CH4 + 0x0A, // 0x80DA Driver CH5 + 0x0C, // 0x80DB Driver CH6 + 0x1D, // 0x80DC Driver CH7 + 0x1E, // 0x80DD Driver CH8 + 0x1F, // 0x80DE Driver CH9 + 0x20, // 0x80DF Driver CH10 + 0x21, // 0x80E0 Driver CH11 + 0x22, // 0x80E1 Driver CH12 + 0x24, // 0x80E2 Driver CH13 + 0x26, // 0x80E3 Driver CH14 + 0x28, // 0x80E4 Driver CH15 + 0xFF, // 0x80E5 Driver CH16 + 0xFF, // 0x80E6 Driver CH17 + 0xFF, // 0x80E7 Driver CH18 + 0xFF, // 0x80E8 Driver CH19 + 0xFF, // 0x80E9 Driver CH20 + 0xFF, // 0x80EA Driver CH21 + 0xFF, // 0x80EB Driver CH22 + 0xFF, // 0x80EC Driver CH23 + 0xFF, // 0x80ED Driver CH24 + 0xFF, // 0x80EE Driver CH25 + 0xFF, // 0x80EF Reserved + 0xFF, // 0x80F0 Reserved + 0xFF, // 0x80F1 Reserved + 0xFF, // 0x80F2 Reserved + 0xFF, // 0x80F3 Reserved + 0xFF, // 0x80F4 Reserved + 0xFF, // 0x80F5 Reserved + 0xFF, // 0x80F6 Reserved + 0xFF, // 0x80F7 Reserved + 0xFF, // 0x80F8 Reserved + 0xFF, // 0x80F9 Reserved + 0xFF, // 0x80FA Reserved + 0xFF, // 0x80FB Reserved + 0xFF, // 0x80FC Reserved + 0xFF, // 0x80FD Reserved + 0xFF // 0x80FE Reserved +}; + + +bool touchGT911Flag = false; +volatile static bool touchEventOccured = false; +struct TouchData touchData; +uint16_t touchGT911fwver = 0; +uint32_t touchGT911hiccups = 0; + +static tmr10ms_t downTime = 0; +static tmr10ms_t tapTime = 0; +static short tapCount = 0; + +static TouchState internalTouchState = {}; + +static void _gt911_exti_isr(void) +{ + touchEventOccured = true; +} + +void I2C_Init_Radio(void) +{ + TRACE("GT911 I2C Init"); + + if (i2c_init(TOUCH_I2C_BUS) < 0) { + TRACE("GT911 ERROR: i2c_init failed"); + return; + } +} + +bool I2C_GT911_WriteRegister(uint16_t reg, uint8_t *buf, uint8_t len) +{ + uint8_t uAddrAndBuf[258]; + uAddrAndBuf[0] = (uint8_t)((reg & 0xFF00) >> 8); + uAddrAndBuf[1] = (uint8_t)(reg & 0x00FF); + + if (len > 0) { + for (int i = 0; i < len; i++) { + uAddrAndBuf[i + 2] = buf[i]; + } + } + + if (stm32_i2c_master_tx(TOUCH_I2C_BUS, GT911_I2C_ADDR, uAddrAndBuf, len + 2, + 100) < 0) { + TRACE("I2C B1 ERROR: WriteRegister failed"); + return false; + } + return true; +} + +bool I2C_GT911_ReadRegister(uint16_t reg, uint8_t *buf, uint8_t len) +{ + uint8_t uRegAddr[2]; + uRegAddr[0] = (uint8_t)((reg & 0xFF00) >> 8); + uRegAddr[1] = (uint8_t)(reg & 0x00FF); + + if (stm32_i2c_master_tx(TOUCH_I2C_BUS, GT911_I2C_ADDR, uRegAddr, 2, 10) < 0) { + TRACE("I2C B1 ERROR: ReadRegister write reg address failed"); + return false; + } + + if (stm32_i2c_master_rx(TOUCH_I2C_BUS, GT911_I2C_ADDR, buf, len, 100) < 0) { + TRACE("I2C B1 ERROR: ReadRegister read reg address failed"); + return false; + } + return true; +} + +bool I2C_GT911_SendConfig(uint8_t cfgVer) +{ + uint8_t buf[2] = { cfgVer, 1 }; + bool bResult = true; + + for (uint8_t i = 1; i < sizeof(TOUCH_GT911_Cfg); i++) { + buf[0] += TOUCH_GT911_Cfg[i]; //check sum + } + + buf[0] = (~buf[0]) + 1; + + if (!I2C_GT911_WriteRegister(GT911_CONFIG_REG, (uint8_t *)&cfgVer, 1)) { + TRACE("GT911 ERROR: write config failed"); + bResult = false; + } + + if (!I2C_GT911_WriteRegister(GT911_CONFIG_REG+1, (uint8_t *)&TOUCH_GT911_Cfg[1], + sizeof(TOUCH_GT911_Cfg)-1)) { + TRACE("GT911 ERROR: write config failed"); + bResult = false; + } + + // write checksum and config_fresh + if (!I2C_GT911_WriteRegister(GT911_CONFIG_CHECKSUM_REG, buf, 2)) { + TRACE("GT911 ERROR: write config checksum failed"); + bResult = false; + } + + return bResult; +} + +void touchPanelDeInit(void) +{ + gpio_int_disable(TOUCH_INT_GPIO); + touchGT911Flag = false; +} + +uint8_t tp_gt911_cfgVer = GT911_CFG_NUMBER; + +bool touchPanelInit(void) +{ + uint8_t tmp[4] = {0}; + + if (touchGT911Flag) { + gpio_init_int(TOUCH_INT_GPIO, GPIO_IN_PU, GPIO_RISING, _gt911_exti_isr); + return true; + } else { + TRACE("Touchpanel init start ..."); + + gpio_init(TOUCH_RST_GPIO, GPIO_OUT, GPIO_PIN_SPEED_LOW); + gpio_init(TOUCH_INT_GPIO, GPIO_OUT, GPIO_PIN_SPEED_LOW); + I2C_Init_Radio(); + + gpio_clear(TOUCH_RST_GPIO); + gpio_set(TOUCH_INT_GPIO); + delay_us(200); + + gpio_set(TOUCH_RST_GPIO); + delay_ms(6); + + gpio_clear(TOUCH_INT_GPIO); + delay_ms(55); + + gpio_init(TOUCH_INT_GPIO, GPIO_IN_PU, GPIO_PIN_SPEED_LOW); + + delay_ms(50); + + TRACE("Reading Touch registry"); + if (!I2C_GT911_ReadRegister(GT911_PRODUCT_ID_REG, tmp, 4)) { + TRACE("GT911 ERROR: Product ID read failed"); + } + + if (strcmp((char *)tmp, TP_GT911_ID) == 0) { + TRACE("GT911 chip detected"); + tmp[0] = 0X02; + if (!I2C_GT911_WriteRegister(GT911_COMMAND_REG, tmp, 1)) { + TRACE("GT911 ERROR: write to control register failed"); + } + if (!I2C_GT911_ReadRegister(GT911_CONFIG_REG, tmp, 1)) { + TRACE("GT911 ERROR: configuration register read failed"); + } + + TRACE("Chip config Ver:%x", tmp[0]); + if ((tp_gt911_cfgVer == 0) || (tmp[0] < tp_gt911_cfgVer)) { // Config ver + TRACE("Sending new config %d", GT911_CFG_NUMBER); + if (!I2C_GT911_SendConfig(tp_gt911_cfgVer)) { + TRACE("GT911 ERROR: sending configration failed"); + } + if (!I2C_GT911_ReadRegister(GT911_CONFIG_REG, tmp, 1)) { + TRACE("GT911 ERROR: configuration register read failed"); + } + tp_gt911_cfgVer = tmp[0]; + } + + if (!I2C_GT911_ReadRegister(GT911_FIRMWARE_VERSION_REG, tmp, 2)) { + TRACE("GT911 ERROR: reading firmware version failed"); + } else { + touchGT911fwver = (tmp[1] << 8) + tmp[0]; + TRACE("GT911 FW version: %u", touchGT911fwver); + } + + delay_ms(10); + tmp[0] = 0X00; + if (!I2C_GT911_WriteRegister(GT911_COMMAND_REG, tmp, 1)) { // end reset + TRACE("GT911 ERROR: write to command register failed"); + } + touchGT911Flag = true; + + gpio_init_int(TOUCH_INT_GPIO, GPIO_IN_PU, GPIO_RISING, _gt911_exti_isr); + + return true; + } + TRACE("GT911 chip NOT FOUND"); + return false; + } +} + +bool I2C_ReInit(void) +{ + TRACE("I2C B1 ReInit"); + touchPanelDeInit(); + if (stm32_i2c_deinit(TOUCH_I2C_BUS) < 0) + TRACE("I2C B1 ReInit - I2C DeInit failed"); + + // If DeInit fails, try to re-init anyway + if (!touchPanelInit()) { + TRACE("I2C B1 ReInit - touchPanelInit failed"); + return false; + } + return true; +} + +#if defined(SIMU) || defined(SEMIHOSTING) || defined(DEBUG) +static const char *event2str(uint8_t ev) +{ + switch (ev) { + case TE_NONE: + return "NONE"; + case TE_UP: + return "UP"; + case TE_DOWN: + return "DOWN"; + case TE_SLIDE_END: + return "SLIDE_END"; + case TE_SLIDE: + return "SLIDE"; + default: + return "UNKNOWN"; + } +} +#endif + +struct TouchState touchPanelRead() +{ + uint8_t state = 0; + + if (!touchEventOccured) return internalTouchState; + + touchEventOccured = false; + + uint32_t startReadStatus = timersGetMsTick(); + do { + if (!I2C_GT911_ReadRegister(GT911_READ_XY_REG, &state, 1)) { + // ledRed(); + touchGT911hiccups++; + TRACE("GT911 I2C read XY error"); + if (!I2C_ReInit()) TRACE("I2C B1 ReInit failed"); + return internalTouchState; + } + + if (state & 0x80u) { + // ready + break; + } + sleep_ms(1); + } while (timersGetMsTick() - startReadStatus < GT911_TIMEOUT); + + internalTouchState.deltaX = 0; + internalTouchState.deltaY = 0; + TRACE("touch state = 0x%x", state); + if (state & 0x80u) { + uint8_t pointsCount = (state & 0x0Fu); + uint32_t now = timersGetMsTick(); + internalTouchState.tapCount = 0; + + if (pointsCount > 0 && pointsCount <= GT911_MAX_TP) { + if (!I2C_GT911_ReadRegister(GT911_READ_XY_REG + 1, touchData.data, + pointsCount * sizeof(TouchPoint))) { + // ledRed(); + touchGT911hiccups++; + TRACE("GT911 I2C data read error"); + if (!I2C_ReInit()) TRACE("I2C B1 ReInit failed"); + return internalTouchState; + } + + if (internalTouchState.event == TE_NONE || + internalTouchState.event == TE_UP || + internalTouchState.event == TE_SLIDE_END) { + internalTouchState.event = TE_DOWN; + internalTouchState.startX = internalTouchState.x = + touchData.points[0].x; + internalTouchState.startY = internalTouchState.y = + touchData.points[0].y; + downTime = now; + } else { + internalTouchState.deltaX = + touchData.points[0].x - internalTouchState.x; + internalTouchState.deltaY = + touchData.points[0].y - internalTouchState.y; + if (internalTouchState.event == TE_SLIDE || + abs(internalTouchState.deltaX) >= SLIDE_RANGE || + abs(internalTouchState.deltaY) >= SLIDE_RANGE) { + internalTouchState.event = TE_SLIDE; + internalTouchState.x = touchData.points[0].x; + internalTouchState.y = touchData.points[0].y; + } + } + } else { + if (internalTouchState.event == TE_SLIDE) { + internalTouchState.event = TE_SLIDE_END; + } else if (internalTouchState.event == TE_DOWN) { + internalTouchState.event = TE_UP; + if (now - downTime <= GT911_TAP_TIME) { + if (now - tapTime > GT911_TAP_TIME) + tapCount = 1; + else + tapCount++; + internalTouchState.tapCount = tapCount; + tapTime = now; + } + } else { + internalTouchState.event = TE_NONE; + } + } + } + + uint8_t zero = 0; + if (!I2C_GT911_WriteRegister(GT911_READ_XY_REG, &zero, 1)) { + TRACE("GT911 ERROR: clearing XY register failed"); + } + + TRACE("touch event = %s", event2str(internalTouchState.event)); + return internalTouchState; +} + +bool touchPanelEventOccured() +{ + return touchEventOccured; +} + +TouchState getInternalTouchState() +{ + return internalTouchState; +} + diff --git a/radio/src/boards/jumper-h750/tp_gt911.h b/radio/src/boards/jumper-h750/tp_gt911.h new file mode 100644 index 00000000000..2e7f2c81836 --- /dev/null +++ b/radio/src/boards/jumper-h750/tp_gt911.h @@ -0,0 +1,83 @@ +/* + * 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 "touch.h" +#include "definitions.h" + +#define HAS_TOUCH_PANEL() (touchGT911Flag == true) + +extern bool touchGT911Flag; +extern uint16_t touchGT911fwver; +extern uint32_t touchGT911hiccups; + +extern void touchPanelDeInit(); +extern bool touchPanelInit(); + +struct TouchState touchPanelRead(); +bool touchPanelEventOccured(); +struct TouchState getInternalTouchState(); + +#define GT911_TIMEOUT 3 // 3ms +#define GT911_TAP_TIME 250 // 250 ms + +#define GT911_MAX_TP 5 + +#define GT911_CFG_NUMBER 0x6D + +//I2C +#define GT911_I2C_ADDR 0x14 + +//#define GT_CMD_WR 0x28 +//#define GT_CMD_RD 0x29 +//#define I2C_TIMEOUT_MAX 1000 + +#define GT911_COMMAND_REG 0x8040 +#define GT911_CONFIG_REG 0x8047 +#define GT911_COORDINATE_REG 0x804D +#define GT911_CONFIG_CHECKSUM_REG 0x80FF + +#define GT911_PRODUCT_ID_REG 0x8140 +#define GT911_FIRMWARE_VERSION_REG 0x8144 +#define GT911_VENDOR_ID_REG 0x814A +#define GT911_READ_XY_REG 0x814E +#define GT911_TP1_REG 0x8150 +#define GT911_TP2_REG 0x8158 +#define GT911_TP3_REG 0x8160 +#define GT911_TP4_REG 0x8168 +#define GT911_TP5_REG 0x8170 + +PACK(typedef struct { + uint8_t track; + uint16_t x; + uint16_t y; + uint16_t size; + uint8_t reserved; +}) TouchPoint; + +PACK(struct TouchData { + union + { + TouchPoint points[GT911_MAX_TP]; + uint8_t data[GT911_MAX_TP * sizeof(TouchPoint)]; + }; +}); diff --git a/radio/src/datastructs.h b/radio/src/datastructs.h index aadd50606f6..d8bcac460a6 100644 --- a/radio/src/datastructs.h +++ b/radio/src/datastructs.h @@ -78,6 +78,9 @@ static inline void check_struct() #if defined(PCBXLITES) CHKSIZE(RadioData, 948); +#elif defined(RADIO_T18H7) + // as the group below, less the 3 IMU bytes + CHKSIZE(RadioData, 1177); #elif defined(RADIO_ST16) || defined(PCBPA01) || defined(RADIO_TX15) || defined(RADIO_T15PRO) || defined(RADIO_T15H7) || defined(RADIO_TX16SMK3) || defined(RADIO_T22) || defined(RADIO_GX15) CHKSIZE(RadioData, 1180); #elif defined(RADIO_H17) @@ -114,7 +117,7 @@ static inline void check_struct() #else CHKSIZE(ModelData, 6877); #endif -#elif defined(PCBST16) || defined(RADIO_T15PRO) || defined(RADIO_T15H7) || defined(RADIO_TX15) || defined(RADIO_T22) || defined(RADIO_GX15) +#elif defined(PCBST16) || defined(RADIO_T15PRO) || defined(RADIO_T15H7) || defined(RADIO_T18H7) || defined(RADIO_TX15) || defined(RADIO_T22) || defined(RADIO_GX15) CHKSIZE(ModelData, 7305); #elif defined(PCBC14) || defined(RADIO_H17) CHKSIZE(ModelData, 7237); diff --git a/radio/src/storage/yaml/CMakeLists.txt b/radio/src/storage/yaml/CMakeLists.txt index 32a51bc89d1..cc910b9ba22 100644 --- a/radio/src/storage/yaml/CMakeLists.txt +++ b/radio/src/storage/yaml/CMakeLists.txt @@ -36,6 +36,8 @@ elseif(PCB STREQUAL T15PRO) set(YAML_GEN_OUTPUT storage/yaml/yaml_datastructs_t15pro.cpp) elseif(PCB STREQUAL T15H7) set(YAML_GEN_OUTPUT storage/yaml/yaml_datastructs_t15h7.cpp) +elseif(PCB STREQUAL T18H7) + set(YAML_GEN_OUTPUT storage/yaml/yaml_datastructs_t18h7.cpp) elseif(PCB STREQUAL T22) set(YAML_GEN_OUTPUT storage/yaml/yaml_datastructs_t22.cpp) elseif(PCB STREQUAL V12) diff --git a/radio/src/storage/yaml/yaml_datastructs.cpp b/radio/src/storage/yaml/yaml_datastructs.cpp index 17b2e5b1963..2aa9dc062e2 100644 --- a/radio/src/storage/yaml/yaml_datastructs.cpp +++ b/radio/src/storage/yaml/yaml_datastructs.cpp @@ -42,6 +42,8 @@ #include "yaml_datastructs_t15pro.cpp" #elif defined(PCBT15H7) #include "yaml_datastructs_t15h7.cpp" +#elif defined(PCBT18H7) + #include "yaml_datastructs_t18h7.cpp" #elif defined(PCBTX16SMK3) #include "yaml_datastructs_tx16smk3.cpp" #elif defined(PCBH17) diff --git a/radio/src/storage/yaml/yaml_datastructs_t18h7.cpp b/radio/src/storage/yaml/yaml_datastructs_t18h7.cpp new file mode 100644 index 00000000000..9f628133e7e --- /dev/null +++ b/radio/src/storage/yaml/yaml_datastructs_t18h7.cpp @@ -0,0 +1,1039 @@ +// generated by generate_yaml.py + +// +// Enums first +// + +const struct YamlIdStr enum_BacklightMode[] = { + { e_backlight_mode_off, "backlight_mode_off" }, + { e_backlight_mode_keys, "backlight_mode_keys" }, + { e_backlight_mode_sticks, "backlight_mode_sticks" }, + { e_backlight_mode_all, "backlight_mode_all" }, + { e_backlight_mode_on, "backlight_mode_on" }, + { 0, NULL } +}; +const struct YamlIdStr enum_AntennaModes[] = { + { ANTENNA_MODE_INTERNAL, "MODE_INTERNAL" }, + { ANTENNA_MODE_ASK, "MODE_ASK" }, + { ANTENNA_MODE_PER_MODEL, "MODE_PER_MODEL" }, + { ANTENNA_MODE_EXTERNAL, "MODE_EXTERNAL" }, + { 0, NULL } +}; +const struct YamlIdStr enum_ModuleType[] = { + { MODULE_TYPE_NONE, "TYPE_NONE" }, + { MODULE_TYPE_PPM, "TYPE_PPM" }, + { MODULE_TYPE_XJT_PXX1, "TYPE_XJT_PXX1" }, + { MODULE_TYPE_ISRM_PXX2, "TYPE_ISRM_PXX2" }, + { MODULE_TYPE_DSM2, "TYPE_DSM2" }, + { MODULE_TYPE_CROSSFIRE, "TYPE_CROSSFIRE" }, + { MODULE_TYPE_MULTIMODULE, "TYPE_MULTIMODULE" }, + { MODULE_TYPE_R9M_PXX1, "TYPE_R9M_PXX1" }, + { MODULE_TYPE_R9M_PXX2, "TYPE_R9M_PXX2" }, + { MODULE_TYPE_R9M_LITE_PXX1, "TYPE_R9M_LITE_PXX1" }, + { MODULE_TYPE_R9M_LITE_PXX2, "TYPE_R9M_LITE_PXX2" }, + { MODULE_TYPE_GHOST, "TYPE_GHOST" }, + { MODULE_TYPE_R9M_LITE_PRO_PXX2, "TYPE_R9M_LITE_PRO_PXX2" }, + { MODULE_TYPE_SBUS, "TYPE_SBUS" }, + { MODULE_TYPE_XJT_LITE_PXX2, "TYPE_XJT_LITE_PXX2" }, + { MODULE_TYPE_FLYSKY_AFHDS2A, "TYPE_FLYSKY_AFHDS2A" }, + { MODULE_TYPE_FLYSKY_AFHDS3, "TYPE_FLYSKY_AFHDS3" }, + { MODULE_TYPE_LEMON_DSMP, "TYPE_LEMON_DSMP" }, + { 0, NULL } +}; +const struct YamlIdStr enum_TrainerMultiplex[] = { + { TRAINER_OFF, "OFF" }, + { TRAINER_ADD, "ADD" }, + { TRAINER_REPL, "REPL" }, + { 0, NULL } +}; +const struct YamlIdStr enum_BeeperMode[] = { + { e_mode_quiet, "mode_quiet" }, + { e_mode_alarms, "mode_alarms" }, + { e_mode_nokeys, "mode_nokeys" }, + { e_mode_all, "mode_all" }, + { 0, NULL } +}; +const struct YamlIdStr enum_BluetoothModes[] = { + { BLUETOOTH_OFF, "OFF" }, + { BLUETOOTH_TELEMETRY, "TELEMETRY" }, + { BLUETOOTH_TRAINER, "TRAINER" }, + { 0, NULL } +}; +const struct YamlIdStr enum_Functions[] = { + { FUNC_OVERRIDE_CHANNEL, "OVERRIDE_CHANNEL" }, + { FUNC_TRAINER, "TRAINER" }, + { FUNC_INSTANT_TRIM, "INSTANT_TRIM" }, + { FUNC_RESET, "RESET" }, + { FUNC_SET_TIMER, "SET_TIMER" }, + { FUNC_ADJUST_GVAR, "ADJUST_GVAR" }, + { FUNC_VOLUME, "VOLUME" }, + { FUNC_SET_FAILSAFE, "SET_FAILSAFE" }, + { FUNC_RANGECHECK, "RANGECHECK" }, + { FUNC_BIND, "BIND" }, + { FUNC_PLAY_SOUND, "PLAY_SOUND" }, + { FUNC_PLAY_TRACK, "PLAY_TRACK" }, + { FUNC_PLAY_VALUE, "PLAY_VALUE" }, + { FUNC_PLAY_SCRIPT, "PLAY_SCRIPT" }, + { FUNC_BACKGND_MUSIC, "BACKGND_MUSIC" }, + { FUNC_BACKGND_MUSIC_PAUSE, "BACKGND_MUSIC_PAUSE" }, + { FUNC_VARIO, "VARIO" }, + { FUNC_HAPTIC, "HAPTIC" }, + { FUNC_LOGS, "LOGS" }, + { FUNC_BACKLIGHT, "BACKLIGHT" }, + { FUNC_SCREENSHOT, "SCREENSHOT" }, + { FUNC_RACING_MODE, "RACING_MODE" }, + { FUNC_DISABLE_TOUCH, "DISABLE_TOUCH" }, + { FUNC_SET_SCREEN, "SET_SCREEN" }, + { FUNC_DISABLE_AUDIO_AMP, "DISABLE_AUDIO_AMP" }, + { FUNC_RGB_LED, "RGB_LED" }, + { FUNC_PUSH_CUST_SWITCH, "PUSH_CUST_SWITCH" }, + { FUNC_TEST, "TEST" }, + { 0, NULL } +}; +const struct YamlIdStr enum_SwitchConfig[] = { + { SWITCH_NONE, "NONE" }, + { SWITCH_TOGGLE, "TOGGLE" }, + { SWITCH_2POS, "2POS" }, + { SWITCH_3POS, "3POS" }, + { SWITCH_GLOBAL, "GLOBAL" }, + { SWITCH_none, "none" }, + { SWITCH_toggle, "toggle" }, + { SWITCH_2pos, "2pos" }, + { SWITCH_3pos, "3pos" }, + { 0, NULL } +}; +const struct YamlIdStr enum_fsStartPositionType[] = { + { FS_START_OFF, "START_OFF" }, + { FS_START_ON, "START_ON" }, + { FS_START_PREVIOUS, "START_PREVIOUS" }, + { 0, NULL } +}; +const struct YamlIdStr enum_booleanEnum[] = { + { BOOL_OFF, "OFF" }, + { BOOL_ON, "ON" }, + { 0, NULL } +}; +const struct YamlIdStr enum_QMPage[] = { + { QM_NONE, "NONE" }, + { QM_OPEN_QUICK_MENU, "OPEN_QUICK_MENU" }, + { QM_MANAGE_MODELS, "MANAGE_MODELS" }, + { QM_MODEL_SETUP, "MODEL_SETUP" }, + { QM_MODEL_FLIGHTMODES, "MODEL_FLIGHTMODES" }, + { QM_MODEL_INPUTS, "MODEL_INPUTS" }, + { QM_MODEL_MIXES, "MODEL_MIXES" }, + { QM_MODEL_OUTPUTS, "MODEL_OUTPUTS" }, + { QM_MODEL_CURVES, "MODEL_CURVES" }, + { QM_MODEL_GVARS, "MODEL_GVARS" }, + { QM_MODEL_LS, "MODEL_LS" }, + { QM_MODEL_SF, "MODEL_SF" }, + { QM_MODEL_SCRIPTS, "MODEL_SCRIPTS" }, + { QM_MODEL_TELEMETRY, "MODEL_TELEMETRY" }, + { QM_MODEL_NOTES, "MODEL_NOTES" }, + { QM_RADIO_SETUP, "RADIO_SETUP" }, + { QM_RADIO_GF, "RADIO_GF" }, + { QM_RADIO_TRAINER, "RADIO_TRAINER" }, + { QM_RADIO_HARDWARE, "RADIO_HARDWARE" }, + { QM_RADIO_VERSION, "RADIO_VERSION" }, + { QM_UI_THEMES, "UI_THEMES" }, + { QM_UI_SETUP, "UI_SETUP" }, + { QM_UI_SCREEN1, "UI_SCREEN1" }, + { QM_UI_SCREEN2, "UI_SCREEN2" }, + { QM_UI_SCREEN3, "UI_SCREEN3" }, + { QM_UI_SCREEN4, "UI_SCREEN4" }, + { QM_UI_SCREEN5, "UI_SCREEN5" }, + { QM_UI_SCREEN6, "UI_SCREEN6" }, + { QM_UI_SCREEN7, "UI_SCREEN7" }, + { QM_UI_SCREEN8, "UI_SCREEN8" }, + { QM_UI_SCREEN9, "UI_SCREEN9" }, + { QM_UI_SCREEN10, "UI_SCREEN10" }, + { QM_UI_ADD_PG, "UI_ADD_PG" }, + { QM_TOOLS_APPS, "TOOLS_APPS" }, + { QM_TOOLS_STORAGE, "TOOLS_STORAGE" }, + { QM_TOOLS_RESET, "TOOLS_RESET" }, + { QM_TOOLS_CHAN_MON, "TOOLS_CHAN_MON" }, + { QM_TOOLS_LS_MON, "TOOLS_LS_MON" }, + { QM_TOOLS_STATS, "TOOLS_STATS" }, + { QM_TOOLS_DEBUG, "TOOLS_DEBUG" }, + { 0, NULL } +}; +const struct YamlIdStr enum_TimerModes[] = { + { TMRMODE_OFF, "OFF" }, + { TMRMODE_ON, "ON" }, + { TMRMODE_START, "START" }, + { TMRMODE_THR, "THR" }, + { TMRMODE_THR_REL, "THR_REL" }, + { TMRMODE_THR_START, "THR_START" }, + { 0, NULL } +}; +const struct YamlIdStr enum_MixerMultiplex[] = { + { MLTPX_ADD, "ADD" }, + { MLTPX_MUL, "MUL" }, + { MLTPX_REPL, "REPL" }, + { 0, NULL } +}; +const struct YamlIdStr enum_MixSources[] = { + { MIXSRC_NONE, "NONE" }, + { MIXSRC_SPACEMOUSE_A, "SPACEMOUSE_A" }, + { MIXSRC_SPACEMOUSE_B, "SPACEMOUSE_B" }, + { MIXSRC_SPACEMOUSE_C, "SPACEMOUSE_C" }, + { MIXSRC_SPACEMOUSE_D, "SPACEMOUSE_D" }, + { MIXSRC_SPACEMOUSE_E, "SPACEMOUSE_E" }, + { MIXSRC_SPACEMOUSE_F, "SPACEMOUSE_F" }, + { MIXSRC_MIN, "MIN" }, + { MIXSRC_MAX, "MAX" }, + { MIXSRC_TX_VOLTAGE, "TX_VOLTAGE" }, + { MIXSRC_TX_TIME, "TX_TIME" }, + { MIXSRC_TX_GPS, "TX_GPS" }, + { 0, NULL } +}; +const struct YamlIdStr enum_LogicalSwitchesFunctions[] = { + { LS_FUNC_NONE, "FUNC_NONE" }, + { LS_FUNC_VEQUAL, "FUNC_VEQUAL" }, + { LS_FUNC_VALMOSTEQUAL, "FUNC_VALMOSTEQUAL" }, + { LS_FUNC_VPOS, "FUNC_VPOS" }, + { LS_FUNC_VNEG, "FUNC_VNEG" }, + { LS_FUNC_APOS, "FUNC_APOS" }, + { LS_FUNC_ANEG, "FUNC_ANEG" }, + { LS_FUNC_AND, "FUNC_AND" }, + { LS_FUNC_OR, "FUNC_OR" }, + { LS_FUNC_XOR, "FUNC_XOR" }, + { LS_FUNC_EDGE, "FUNC_EDGE" }, + { LS_FUNC_EQUAL, "FUNC_EQUAL" }, + { LS_FUNC_GREATER, "FUNC_GREATER" }, + { LS_FUNC_LESS, "FUNC_LESS" }, + { LS_FUNC_DIFFEGREATER, "FUNC_DIFFEGREATER" }, + { LS_FUNC_ADIFFEGREATER, "FUNC_ADIFFEGREATER" }, + { LS_FUNC_TIMER, "FUNC_TIMER" }, + { LS_FUNC_STICKY, "FUNC_STICKY" }, + { 0, NULL } +}; +const struct YamlIdStr enum_SwashType[] = { + { SWASH_TYPE_NONE, "TYPE_NONE" }, + { SWASH_TYPE_120, "TYPE_120" }, + { SWASH_TYPE_120X, "TYPE_120X" }, + { SWASH_TYPE_140, "TYPE_140" }, + { SWASH_TYPE_90, "TYPE_90" }, + { 0, NULL } +}; +const struct YamlIdStr enum_SwitchSources[] = { + { SWSRC_NONE, "NONE" }, + { SWSRC_ON, "ON" }, + { SWSRC_ONE, "ONE" }, + { SWSRC_TELEMETRY_STREAMING, "TELEMETRY_STREAMING" }, + { SWSRC_RADIO_ACTIVITY, "RADIO_ACTIVITY" }, + { SWSRC_TRAINER_CONNECTED, "TRAINER_CONNECTED" }, + { SWSRC_OFF, "OFF" }, + { 0, NULL } +}; +const struct YamlIdStr enum_PotsWarnMode[] = { + { POTS_WARN_OFF, "WARN_OFF" }, + { POTS_WARN_MANUAL, "WARN_MANUAL" }, + { POTS_WARN_AUTO, "WARN_AUTO" }, + { 0, NULL } +}; +const struct YamlIdStr enum_ModelOverridableEnable[] = { + { OVERRIDE_GLOBAL, "GLOBAL" }, + { OVERRIDE_OFF, "OFF" }, + { OVERRIDE_ON, "ON" }, + { 0, NULL } +}; +const struct YamlIdStr enum_FailsafeModes[] = { + { FAILSAFE_NOT_SET, "NOT_SET" }, + { FAILSAFE_HOLD, "HOLD" }, + { FAILSAFE_CUSTOM, "CUSTOM" }, + { FAILSAFE_NOPULSES, "NOPULSES" }, + { FAILSAFE_RECEIVER, "RECEIVER" }, + { 0, NULL } +}; +const struct YamlIdStr enum_TelemetrySensorFormula[] = { + { TELEM_FORMULA_ADD, "FORMULA_ADD" }, + { TELEM_FORMULA_AVERAGE, "FORMULA_AVERAGE" }, + { TELEM_FORMULA_MIN, "FORMULA_MIN" }, + { TELEM_FORMULA_MAX, "FORMULA_MAX" }, + { TELEM_FORMULA_MULTIPLY, "FORMULA_MULTIPLY" }, + { TELEM_FORMULA_TOTALIZE, "FORMULA_TOTALIZE" }, + { TELEM_FORMULA_CELL, "FORMULA_CELL" }, + { TELEM_FORMULA_CONSUMPTION, "FORMULA_CONSUMPTION" }, + { TELEM_FORMULA_DIST, "FORMULA_DIST" }, + { 0, NULL } +}; +const struct YamlIdStr enum_TelemetrySensorType[] = { + { TELEM_TYPE_CUSTOM, "TYPE_CUSTOM" }, + { TELEM_TYPE_CALCULATED, "TYPE_CALCULATED" }, + { 0, NULL } +}; +const struct YamlIdStr enum_USBJoystickIfMode[] = { + { USBJOYS_JOYSTICK, "JOYSTICK" }, + { USBJOYS_GAMEPAD, "GAMEPAD" }, + { USBJOYS_MULTIAXIS, "MULTIAXIS" }, + { 0, NULL } +}; +const struct YamlIdStr enum_USBJoystickCh[] = { + { USBJOYS_CH_NONE, "CH_NONE" }, + { USBJOYS_CH_BUTTON, "CH_BUTTON" }, + { USBJOYS_CH_AXIS, "CH_AXIS" }, + { USBJOYS_CH_SIM, "CH_SIM" }, + { 0, NULL } +}; + +// +// Structs last +// + +static const struct YamlNode struct_CalibData[] = { + YAML_IDX_CUST("calib",r_calib,w_calib), + YAML_SIGNED( "mid", 16 ), + YAML_SIGNED( "spanNeg", 16 ), + YAML_SIGNED( "spanPos", 16 ), + YAML_END +}; +static const struct YamlNode struct_signed_16[] = { + YAML_IDX, + YAML_SIGNED( "val", 16 ), + YAML_END +}; +static const struct YamlNode struct_TrainerMix[] = { + YAML_IDX, + YAML_UNSIGNED( "srcChn", 6 ), + YAML_ENUM("mode", 2, enum_TrainerMultiplex, NULL), + YAML_SIGNED( "studWeight", 8 ), + YAML_END +}; +static const struct YamlNode struct_TrainerData[] = { + YAML_ARRAY("calib", 16, 4, struct_signed_16, NULL), + YAML_ARRAY("mix", 16, 4, struct_TrainerMix, NULL), + YAML_END +}; +static const struct YamlNode struct_anonymous_1[] = { + YAML_STRING("name", 8), + YAML_END +}; +static const struct YamlNode struct_anonymous_2[] = { + YAML_SIGNED( "val", 16 ), + YAML_UNSIGNED( "mode", 8 ), + YAML_UNSIGNED( "param", 8 ), + YAML_SIGNED( "val2", 32 ), + YAML_END +}; +static const struct YamlNode struct_anonymous_3[] = { + YAML_SIGNED( "val1", 32 ), + YAML_SIGNED( "val2", 32 ), + YAML_END +}; +static const struct YamlNode union_anonymous_0_elmts[] = { + YAML_STRUCT("play", 64, struct_anonymous_1, NULL), + YAML_STRUCT("all", 64, struct_anonymous_2, NULL), + YAML_STRUCT("clear", 64, struct_anonymous_3, NULL), + YAML_END +}; +static const struct YamlNode struct_CustomFunctionData[] = { + YAML_IDX, + YAML_SIGNED_CUST( "swtch", 10, r_swtchSrc, w_swtchSrc ), + YAML_ENUM("func", 6, enum_Functions, NULL), + YAML_CUSTOM("def",r_customFn,w_customFn), + YAML_PADDING( 64 ), + YAML_PADDING( 1 ), + YAML_PADDING( 7 ), + YAML_END +}; +static const struct YamlNode struct_RGBLedColor[] = { + YAML_UNSIGNED( "r", 8 ), + YAML_UNSIGNED( "g", 8 ), + YAML_UNSIGNED( "b", 8 ), + YAML_END +}; +static const struct YamlNode struct_switchDef[] = { + YAML_IDX_CUST("sw",sw_idx_read,sw_idx_write), + YAML_STRING("name", 3), + YAML_ENUM("type", 3, enum_SwitchConfig, NULL), + YAML_ENUM("start", 2, enum_fsStartPositionType, switch_is_cfs), + YAML_ENUM("onColorLuaOverride", 1, enum_booleanEnum, switch_is_cfs), + YAML_ENUM("offColorLuaOverride", 1, enum_booleanEnum, switch_is_cfs), + YAML_PADDING( 1 ), + YAML_STRUCT("onColor", 24, struct_RGBLedColor, switch_is_cfs), + YAML_STRUCT("offColor", 24, struct_RGBLedColor, switch_is_cfs), + YAML_END +}; +static const struct YamlNode struct_QuickMenuPage[] = { + YAML_IDX, + YAML_ENUM("shortcut", 8, enum_QMPage, NULL), + YAML_END +}; +static const struct YamlNode struct_RadioData[] = { + YAML_UNSIGNED( "manuallyEdited", 1 ), + YAML_SIGNED( "timezoneMinutes", 3 ), + YAML_UNSIGNED( "ppmunit", 2 ), + YAML_PADDING( 2 ), + YAML_CUSTOM("semver",nullptr,w_semver), + YAML_CUSTOM("board",nullptr,w_board), + YAML_ARRAY("calib", 48, 20, struct_CalibData, NULL), + YAML_PADDING( 16 ), + YAML_UNSIGNED( "vBatWarn", 8 ), + YAML_SIGNED( "txVoltageCalibration", 8 ), + YAML_ENUM("backlightMode", 3, enum_BacklightMode, NULL), + YAML_ENUM("antennaMode", 2, enum_AntennaModes, NULL), + YAML_UNSIGNED( "disableRtcWarning", 1 ), + YAML_UNSIGNED( "keysBacklight", 1 ), + YAML_UNSIGNED( "dontPlayHello", 1 ), + YAML_ENUM("internalModule", 8, enum_ModuleType, NULL), + YAML_STRUCT("trainer", 128, struct_TrainerData, NULL), + YAML_UNSIGNED( "view", 8 ), + YAML_PADDING( 2 ), + YAML_UNSIGNED( "fai", 1 ), + YAML_SIGNED_CUST( "beepMode", 2, r_beeperMode, w_beeperMode ), + YAML_UNSIGNED( "alarmsFlash", 1 ), + YAML_UNSIGNED( "disableMemoryWarning", 1 ), + YAML_UNSIGNED( "disableAlarmWarning", 1 ), + YAML_UNSIGNED( "stickMode", 2 ), + YAML_SIGNED( "timezone", 5 ), + YAML_UNSIGNED( "adjustRTC", 1 ), + YAML_UNSIGNED( "inactivityTimer", 8 ), + YAML_CUSTOM("telemetryBaudrate",r_telemetryBaudrate,nullptr), + YAML_UNSIGNED( "internalModuleBaudrate", 3 ), + YAML_SIGNED( "splashMode", 3 ), + YAML_SIGNED_CUST( "hapticMode", 2, r_beeperMode, w_beeperMode ), + YAML_SIGNED( "switchesDelay", 8 ), + YAML_UNSIGNED( "lightAutoOff", 8 ), + YAML_UNSIGNED( "templateSetup", 8 ), + YAML_SIGNED( "PPM_Multiplier", 8 ), + YAML_SIGNED_CUST( "hapticLength", 8, r_5pos, w_5pos ), + YAML_SIGNED_CUST( "beepLength", 3, r_5pos, w_5pos ), + YAML_SIGNED_CUST( "hapticStrength", 3, r_5pos, w_5pos ), + YAML_UNSIGNED( "gpsFormat", 1 ), + YAML_UNSIGNED( "audioMuteEnable", 1 ), + YAML_UNSIGNED_CUST( "speakerPitch", 8, r_spPitch, w_spPitch ), + YAML_SIGNED_CUST( "speakerVolume", 8, r_vol, w_vol ), + YAML_SIGNED_CUST( "vBatMin", 8, r_vbat_min, w_vbat_min ), + YAML_SIGNED_CUST( "vBatMax", 8, r_vbat_max, w_vbat_max ), + YAML_UNSIGNED( "backlightBright", 8 ), + YAML_UNSIGNED( "globalTimer", 32 ), + YAML_UNSIGNED( "bluetoothBaudrate", 4 ), + YAML_ENUM("bluetoothMode", 4, enum_BluetoothModes, NULL), + YAML_UNSIGNED( "countryCode", 2 ), + YAML_SIGNED( "pwrOnSpeed", 3 ), + YAML_SIGNED( "pwrOffSpeed", 3 ), + YAML_CUSTOM("jitterFilter",r_jitterFilter,nullptr), + YAML_UNSIGNED( "noJitterFilter", 1 ), + YAML_UNSIGNED( "imperial", 1 ), + YAML_UNSIGNED( "disableRssiPoweroffAlarm", 1 ), + YAML_UNSIGNED( "USBMode", 2 ), + YAML_UNSIGNED( "jackMode", 2 ), + YAML_PADDING( 1 ), + YAML_STRING("ttsLanguage", 2), + YAML_STRING("uiLanguage", 2), + YAML_SIGNED_CUST( "beepVolume", 4, r_5pos, w_5pos ), + YAML_SIGNED_CUST( "wavVolume", 4, r_5pos, w_5pos ), + YAML_SIGNED_CUST( "varioVolume", 4, r_5pos, w_5pos ), + YAML_SIGNED_CUST( "backgroundVolume", 4, r_5pos, w_5pos ), + YAML_SIGNED_CUST( "varioPitch", 8, r_vPitch, w_vPitch ), + YAML_SIGNED_CUST( "varioRange", 8, r_vPitch, w_vPitch ), + YAML_SIGNED( "varioRepeat", 8 ), + YAML_ARRAY("customFn", 88, 64, struct_CustomFunctionData, cfn_is_active), + YAML_CUSTOM("auxSerialMode",r_serialMode,nullptr), + YAML_CUSTOM("aux2SerialMode",r_serialMode,nullptr), + YAML_ARRAY("serialPort", 8, 4, struct_serialConfig, nullptr), + YAML_ARRAY("sticksConfig", 0, MAX_STICKS, struct_stickConfig, stick_name_valid), + YAML_ARRAY("slidersConfig", 0, MAX_POTS, struct_sliderConfig, nullptr), + YAML_PADDING( 8 ), + YAML_ARRAY("potsConfig", 4, 16, struct_potConfig, nullptr), + YAML_ARRAY("switchConfig", 80, 20, struct_switchDef, switchIsActive), + YAML_ARRAY("flexSwitches", 0, MAX_FLEX_SWITCHES, struct_flexSwitch, flex_sw_valid), + YAML_STRING("currModelFilename", 17), + YAML_UNSIGNED( "blOffBright", 8 ), + YAML_STRING("bluetoothName", 10), + YAML_STRING("ownerRegistrationID", 8), + YAML_CUSTOM("rotEncDirection",r_rotEncDirection,nullptr), + YAML_UNSIGNED( "rotEncMode", 3 ), + YAML_PADDING( 2 ), + YAML_PADDING( 3 ), + YAML_STRING("selectedTheme", 26), + YAML_UNSIGNED( "labelSingleSelect", 1 ), + YAML_UNSIGNED( "labelMultiMode", 1 ), + YAML_UNSIGNED( "favMultiMode", 1 ), + YAML_UNSIGNED( "modelSelectLayout", 2 ), + YAML_UNSIGNED( "radioThemesDisabled", 1 ), + YAML_UNSIGNED( "radioGFDisabled", 1 ), + YAML_UNSIGNED( "radioTrainerDisabled", 1 ), + YAML_UNSIGNED( "modelHeliDisabled", 1 ), + YAML_UNSIGNED( "modelFMDisabled", 1 ), + YAML_UNSIGNED( "modelCurvesDisabled", 1 ), + YAML_UNSIGNED( "modelGVDisabled", 1 ), + YAML_UNSIGNED( "modelLSDisabled", 1 ), + YAML_UNSIGNED( "modelSFDisabled", 1 ), + YAML_UNSIGNED( "modelCustomScriptsDisabled", 1 ), + YAML_UNSIGNED( "modelTelemetryDisabled", 1 ), + YAML_UNSIGNED( "disableTrainerPoweroffAlarm", 1 ), + YAML_UNSIGNED( "disablePwrOnOffHaptic", 1 ), + YAML_UNSIGNED( "modelQuickSelect", 1 ), + YAML_UNSIGNED( "oneLogPerDay", 1 ), + YAML_UNSIGNED( "keyLockEnabled", 1 ), + YAML_PADDING( 3 ), + YAML_UNSIGNED( "pwrOffIfInactive", 8 ), + YAML_ARRAY("keyShortcuts", 8, 6, struct_QuickMenuPage, NULL), + YAML_ARRAY("qmFavorites", 8, 12, struct_QuickMenuPage, NULL), + YAML_END +}; +static const struct YamlNode struct_unsigned_8[] = { + YAML_IDX, + YAML_UNSIGNED( "val", 8 ), + YAML_END +}; +static const struct YamlNode struct_ModelHeader[] = { + YAML_STRING("name", 15), + YAML_ARRAY("modelId", 8, 2, struct_unsigned_8, NULL), + YAML_STRING("bitmap", 14), + YAML_STRING("labels", 100), + YAML_END +}; +static const struct YamlNode struct_TimerData[] = { + YAML_IDX, + YAML_UNSIGNED( "start", 22 ), + YAML_SIGNED_CUST( "swtch", 10, r_swtchSrc, w_swtchSrc ), + YAML_SIGNED( "value", 22 ), + YAML_ENUM("mode", 3, enum_TimerModes, NULL), + YAML_UNSIGNED( "countdownBeep", 2 ), + YAML_UNSIGNED( "minuteBeep", 1 ), + YAML_UNSIGNED( "persistent", 2 ), + YAML_SIGNED( "countdownStart", 2 ), + YAML_UNSIGNED( "showElapsed", 1 ), + YAML_UNSIGNED( "extraHaptic", 1 ), + YAML_PADDING( 6 ), + YAML_STRING("name", 8), + YAML_END +}; +static const struct YamlNode struct_CurveRef[] = { + YAML_UNSIGNED( "type", 5 ), + YAML_UNSIGNED_CUST( "value", 11, r_sourceNumVal, w_sourceNumVal ), + YAML_END +}; +static const struct YamlNode struct_MixData[] = { + YAML_UNSIGNED( "destCh", 5 ), + YAML_SIGNED_CUST( "srcRaw", 10, r_mixSrcRawEx, w_mixSrcRawEx ), + YAML_UNSIGNED( "carryTrim", 1 ), + YAML_UNSIGNED( "mixWarn", 2 ), + YAML_ENUM("mltpx", 2, enum_MixerMultiplex, NULL), + YAML_UNSIGNED( "delayPrec", 1 ), + YAML_UNSIGNED( "speedPrec", 1 ), + YAML_UNSIGNED_CUST( "flightModes", 9, r_flightModes, w_flightModes ), + YAML_PADDING( 1 ), + YAML_UNSIGNED_CUST( "weight", 11, r_sourceNumVal, w_sourceNumVal ), + YAML_UNSIGNED_CUST( "offset", 11, r_sourceNumVal, w_sourceNumVal ), + YAML_SIGNED_CUST( "swtch", 10, r_swtchSrc, w_swtchSrc ), + YAML_STRUCT("curve", 16, struct_CurveRef, NULL), + YAML_UNSIGNED( "delayUp", 8 ), + YAML_UNSIGNED( "delayDown", 8 ), + YAML_UNSIGNED( "speedUp", 8 ), + YAML_UNSIGNED( "speedDown", 8 ), + YAML_STRING("name", 6), + YAML_END +}; +static const struct YamlNode struct_LimitData[] = { + YAML_IDX, + YAML_SIGNED_CUST( "min", 11, in_read_weight, in_write_weight ), + YAML_SIGNED_CUST( "max", 11, in_read_weight, in_write_weight ), + YAML_SIGNED( "ppmCenter", 10 ), + YAML_SIGNED_CUST( "offset", 11, in_read_weight, in_write_weight ), + YAML_UNSIGNED( "symetrical", 1 ), + YAML_UNSIGNED( "revert", 1 ), + YAML_PADDING( 3 ), + YAML_SIGNED( "curve", 8 ), + YAML_STRING("name", 6), + YAML_END +}; +static const struct YamlNode struct_ExpoData[] = { + YAML_UNSIGNED( "mode", 2 ), + YAML_UNSIGNED( "scale", 14 ), + YAML_CUSTOM("carryTrim",r_carryTrim,nullptr), + YAML_SIGNED( "trimSource", 6 ), + YAML_SIGNED_CUST( "srcRaw", 10, r_mixSrcRawEx, w_mixSrcRawEx ), + YAML_UNSIGNED_CUST( "weight", 11, r_sourceNumVal, w_sourceNumVal ), + YAML_UNSIGNED_CUST( "offset", 11, r_sourceNumVal, w_sourceNumVal ), + YAML_SIGNED_CUST( "swtch", 10, r_swtchSrc, w_swtchSrc ), + YAML_STRUCT("curve", 16, struct_CurveRef, NULL), + YAML_UNSIGNED( "chn", 5 ), + YAML_UNSIGNED_CUST( "flightModes", 9, r_flightModes, w_flightModes ), + YAML_PADDING( 2 ), + YAML_STRING("name", 6), + YAML_END +}; +static const struct YamlNode struct_CurveHeader[] = { + YAML_IDX, + YAML_UNSIGNED( "type", 1 ), + YAML_UNSIGNED( "smooth", 1 ), + YAML_SIGNED( "points", 6 ), + YAML_STRING("name", 3), + YAML_END +}; +static const struct YamlNode struct_signed_8[] = { + YAML_IDX, + YAML_SIGNED( "val", 8 ), + YAML_END +}; +static const struct YamlNode struct_LogicalSwitchData[] = { + YAML_IDX, + YAML_ENUM("func", 8, enum_LogicalSwitchesFunctions, NULL), + YAML_CUSTOM("def",r_logicSw,w_logicSw), + YAML_PADDING( 10 ), + YAML_PADDING( 10 ), + YAML_SIGNED_CUST( "andsw", 10, r_swtchSrc, w_swtchSrc ), + YAML_UNSIGNED( "lsPersist", 1 ), + YAML_UNSIGNED( "lsState", 1 ), + YAML_PADDING( 16 ), + YAML_UNSIGNED( "delay", 8 ), + YAML_UNSIGNED( "duration", 8 ), + YAML_END +}; +static const struct YamlNode struct_SwashRingData[] = { + YAML_ENUM("type", 8, enum_SwashType, NULL), + YAML_UNSIGNED( "value", 8 ), + YAML_UNSIGNED_CUST( "collectiveSource", 8, r_mixSrcRaw, w_mixSrcRaw ), + YAML_UNSIGNED_CUST( "aileronSource", 8, r_mixSrcRaw, w_mixSrcRaw ), + YAML_UNSIGNED_CUST( "elevatorSource", 8, r_mixSrcRaw, w_mixSrcRaw ), + YAML_SIGNED( "collectiveWeight", 8 ), + YAML_SIGNED( "aileronWeight", 8 ), + YAML_SIGNED( "elevatorWeight", 8 ), + YAML_END +}; +static const struct YamlNode struct_trim_t[] = { + YAML_IDX, + YAML_SIGNED( "value", 11 ), + YAML_UNSIGNED( "mode", 5 ), + YAML_END +}; +static const struct YamlNode struct_FlightModeData[] = { + YAML_IDX, + YAML_ARRAY("trim", 16, 8, struct_trim_t, NULL), + YAML_STRING("name", 10), + YAML_SIGNED_CUST( "swtch", 10, r_swtchSrc, w_swtchSrc ), + YAML_PADDING( 6 ), + YAML_UNSIGNED( "fadeIn", 8 ), + YAML_UNSIGNED( "fadeOut", 8 ), + YAML_ARRAY("gvars", 16, 15, struct_signed_16, gvar_is_active), + YAML_END +}; +static const struct YamlNode struct_GVarData[] = { + YAML_IDX, + YAML_STRING("name", 3), + YAML_UNSIGNED( "min", 12 ), + YAML_UNSIGNED( "max", 12 ), + YAML_UNSIGNED( "popup", 1 ), + YAML_UNSIGNED( "prec", 1 ), + YAML_UNSIGNED( "unit", 2 ), + YAML_PADDING( 4 ), + YAML_END +}; +static const struct YamlNode struct_VarioData[] = { + YAML_UNSIGNED_CUST( "source", 7, r_tele_sensor, w_tele_sensor ), + YAML_UNSIGNED( "centerSilent", 1 ), + YAML_SIGNED( "centerMax", 8 ), + YAML_SIGNED( "centerMin", 8 ), + YAML_SIGNED( "min", 8 ), + YAML_SIGNED( "max", 8 ), + YAML_END +}; +static const struct YamlNode struct_RssiAlarmData[] = { + YAML_CUSTOM("disabled",r_rssiDisabled,nullptr), + YAML_CUSTOM("warning",r_rssiWarning,nullptr), + YAML_CUSTOM("critical",r_rssiCritical,nullptr), + YAML_END +}; +static const struct YamlNode struct_RFAlarmData[] = { + YAML_SIGNED( "warning", 8 ), + YAML_SIGNED( "critical", 8 ), + YAML_END +}; +static const struct YamlNode struct_PpmModule[] = { + YAML_SIGNED( "delay", 6 ), + YAML_UNSIGNED( "pulsePol", 1 ), + YAML_UNSIGNED( "outputType", 1 ), + YAML_SIGNED( "frameLength", 8 ), + YAML_END +}; +static const struct YamlNode struct_anonymous_5[] = { + YAML_PADDING( 8 ), + YAML_UNSIGNED( "disableTelemetry", 1 ), + YAML_UNSIGNED( "disableMapping", 1 ), + YAML_UNSIGNED( "autoBindMode", 1 ), + YAML_UNSIGNED( "lowPowerMode", 1 ), + YAML_UNSIGNED( "receiverTelemetryOff", 1 ), + YAML_UNSIGNED( "receiverHigherChannels", 1 ), + YAML_PADDING( 2 ), + YAML_SIGNED( "optionValue", 8 ), + YAML_END +}; +static const struct YamlNode struct_anonymous_6[] = { + YAML_UNSIGNED( "power", 2 ), + YAML_PADDING( 2 ), + YAML_UNSIGNED( "receiverTelemetryOff", 1 ), + YAML_UNSIGNED( "receiverHigherChannels", 1 ), + YAML_PADDING( 2 ), + YAML_PADDING( 8 ), + YAML_END +}; +static const struct YamlNode struct_anonymous_7[] = { + YAML_PADDING( 6 ), + YAML_UNSIGNED( "noninverted", 1 ), + YAML_PADDING( 1 ), + YAML_SIGNED( "refreshRate", 8 ), + YAML_END +}; +static const struct YamlNode struct_string_64[] = { + YAML_IDX, + YAML_STRING("val", 8), + YAML_END +}; +static const struct YamlNode struct_anonymous_8[] = { + YAML_UNSIGNED( "receivers", 7 ), + YAML_UNSIGNED( "racingMode", 1 ), + YAML_ARRAY("receiverName", 64, 3, struct_string_64, NULL), + YAML_END +}; +static const struct YamlNode struct_anonymous_9[] = { + YAML_ARRAY("rx_id", 8, 4, struct_unsigned_8, NULL), + YAML_UNSIGNED( "mode", 3 ), + YAML_UNSIGNED( "rfPower", 1 ), + YAML_UNSIGNED( "reserved", 4 ), + YAML_ARRAY("rx_freq", 8, 2, struct_unsigned_8, NULL), + YAML_END +}; +static const struct YamlNode struct_anonymous_10[] = { + YAML_UNSIGNED( "emi", 2 ), + YAML_UNSIGNED( "telemetry", 1 ), + YAML_UNSIGNED( "phyMode", 3 ), + YAML_UNSIGNED( "reserved", 2 ), + YAML_UNSIGNED( "rfPower", 8 ), + YAML_END +}; +static const struct YamlNode struct_anonymous_11[] = { + YAML_UNSIGNED( "raw12bits", 1 ), + YAML_UNSIGNED( "telemetryBaudrate", 3 ), + YAML_PADDING( 4 ), + YAML_END +}; +static const struct YamlNode struct_anonymous_12[] = { + YAML_UNSIGNED( "telemetryBaudrate", 3 ), + YAML_UNSIGNED( "crsfArmingMode", 1 ), + YAML_PADDING( 4 ), + YAML_SIGNED_CUST( "crsfArmingTrigger", 10, r_swtchSrc, w_swtchSrc ), + YAML_SIGNED( "spare3", 6 ), + YAML_END +}; +static const struct YamlNode struct_anonymous_13[] = { + YAML_UNSIGNED( "flags", 8 ), + YAML_UNSIGNED( "enableAETR", 1 ), + YAML_END +}; +static const struct YamlNode union_anonymous_4_elmts[] = { + YAML_ARRAY("raw", 8, 25, struct_unsigned_8, NULL), + YAML_STRUCT("ppm", 16, struct_PpmModule, NULL), + YAML_STRUCT("multi", 24, struct_anonymous_5, NULL), + YAML_STRUCT("pxx", 16, struct_anonymous_6, NULL), + YAML_STRUCT("sbus", 16, struct_anonymous_7, NULL), + YAML_STRUCT("pxx2", 200, struct_anonymous_8, NULL), + YAML_STRUCT("flysky", 56, struct_anonymous_9, NULL), + YAML_STRUCT("afhds3", 16, struct_anonymous_10, NULL), + YAML_STRUCT("ghost", 8, struct_anonymous_11, NULL), + YAML_STRUCT("crsf", 24, struct_anonymous_12, NULL), + YAML_STRUCT("dsmp", 16, struct_anonymous_13, NULL), + YAML_END +}; +static const struct YamlNode struct_ModuleData[] = { + YAML_IDX, + YAML_UNSIGNED_CUST( "type", 6, r_moduleType, w_moduleType ), + YAML_ENUM("antennaMode", 2, enum_AntennaModes, NULL), + YAML_CUSTOM("subType",r_modSubtype,w_modSubtype), + YAML_UNSIGNED( "channelsStart", 8 ), + YAML_SIGNED_CUST( "channelsCount", 8, r_channelsCount, w_channelsCount ), + YAML_ENUM("failsafeMode", 4, enum_FailsafeModes, NULL), + YAML_PADDING( 4 ), + YAML_UNION("mod", 200, union_anonymous_4_elmts, select_mod_type), + YAML_END +}; +static const struct YamlNode struct_TrainerModuleData[] = { + YAML_UNSIGNED_CUST( "mode", 8, r_trainerMode, w_trainerMode ), + YAML_UNSIGNED( "channelsStart", 8 ), + YAML_SIGNED( "channelsCount", 8 ), + YAML_SIGNED( "frameLength", 8 ), + YAML_SIGNED( "delay", 6 ), + YAML_UNSIGNED( "pulsePol", 1 ), + YAML_PADDING( 1 ), + YAML_END +}; +static const struct YamlNode union_ScriptDataInput_elmts[] = { + YAML_SIGNED( "value", 16 ), + YAML_UNSIGNED_CUST( "source", 16, r_mixSrcRaw, w_mixSrcRaw ), + YAML_END +}; +static const struct YamlNode union_ScriptDataInput[] = { + YAML_IDX, + YAML_UNION("u", 16, union_ScriptDataInput_elmts, select_script_input), + YAML_END +}; +static const struct YamlNode struct_ScriptData[] = { + YAML_IDX, + YAML_STRING("file", 6), + YAML_STRING("name", 6), + YAML_ARRAY("inputs", 16, 6, union_ScriptDataInput, NULL), + YAML_END +}; +static const struct YamlNode struct_string_32[] = { + YAML_IDX, + YAML_STRING("val", 4), + YAML_END +}; +static const struct YamlNode union_anonymous_14_elmts[] = { + YAML_UNSIGNED( "id", 16 ), + YAML_UNSIGNED( "persistentValue", 16 ), + YAML_END +}; +static const struct YamlNode struct_anonymous_16[] = { + YAML_UNSIGNED( "physID", 5 ), + YAML_UNSIGNED( "rxIndex", 3 ), + YAML_END +}; +static const struct YamlNode union_anonymous_15_elmts[] = { + YAML_STRUCT("frskyInstance", 8, struct_anonymous_16, NULL), + YAML_UNSIGNED( "instance", 8 ), + YAML_ENUM("formula", 8, enum_TelemetrySensorFormula, NULL), + YAML_END +}; +static const struct YamlNode struct_anonymous_18[] = { + YAML_UNSIGNED( "ratio", 16 ), + YAML_SIGNED( "offset", 16 ), + YAML_END +}; +static const struct YamlNode struct_anonymous_19[] = { + YAML_UNSIGNED( "source", 8 ), + YAML_UNSIGNED( "index", 8 ), + YAML_PADDING( 16 ), + YAML_END +}; +static const struct YamlNode struct_anonymous_20[] = { + YAML_ARRAY("sources", 8, 4, struct_signed_8, NULL), + YAML_END +}; +static const struct YamlNode struct_anonymous_21[] = { + YAML_UNSIGNED( "source", 8 ), + YAML_PADDING( 24 ), + YAML_END +}; +static const struct YamlNode struct_anonymous_22[] = { + YAML_UNSIGNED( "gps", 8 ), + YAML_UNSIGNED( "alt", 8 ), + YAML_PADDING( 16 ), + YAML_END +}; +static const struct YamlNode union_anonymous_17_elmts[] = { + YAML_STRUCT("custom", 32, struct_anonymous_18, NULL), + YAML_STRUCT("cell", 32, struct_anonymous_19, NULL), + YAML_STRUCT("calc", 32, struct_anonymous_20, NULL), + YAML_STRUCT("consumption", 32, struct_anonymous_21, NULL), + YAML_STRUCT("dist", 32, struct_anonymous_22, NULL), + YAML_UNSIGNED( "param", 32 ), + YAML_END +}; +static const struct YamlNode struct_TelemetrySensor[] = { + YAML_IDX, + YAML_UNION("id1", 16, union_anonymous_14_elmts, select_id1), + YAML_UNION("id2", 8, union_anonymous_15_elmts, select_id2), + YAML_STRING("label", 4), + YAML_UNSIGNED( "subId", 8 ), + YAML_ENUM("type", 1, enum_TelemetrySensorType, NULL), + YAML_PADDING( 1 ), + YAML_UNSIGNED( "unit", 6 ), + YAML_UNSIGNED( "prec", 2 ), + YAML_UNSIGNED( "autoOffset", 1 ), + YAML_UNSIGNED( "filter", 1 ), + YAML_UNSIGNED( "logs", 1 ), + YAML_UNSIGNED( "persistent", 1 ), + YAML_UNSIGNED( "onlyPositive", 1 ), + YAML_PADDING( 1 ), + YAML_UNION("cfg", 32, union_anonymous_17_elmts, select_sensor_cfg), + YAML_END +}; +static const struct YamlNode union_WidgetOptionValue_elmts[] = { + YAML_CUSTOM("unsignedValue",r_wov_unsigned,w_wov_unsigned), + YAML_CUSTOM("signedValue",r_wov_signed,w_wov_signed), + YAML_CUSTOM("boolValue",r_wov_unsigned,w_wov_unsigned), + YAML_CUSTOM("stringValue",r_wov_string,w_wov_string), + YAML_CUSTOM("source",r_wov_source,w_wov_source), + YAML_CUSTOM("color",r_wov_color,w_wov_color), + YAML_END +}; +static const struct YamlNode struct_WidgetOptionValueTyped[] = { + YAML_IDX, + YAML_CUSTOM("type",r_wov_type,w_wov_type), + YAML_UNION("value", 0, union_WidgetOptionValue_elmts, select_wov), + YAML_END +}; +static const struct YamlNode struct_WidgetPersistentData[] = { + YAML_ARRAY("options", 0, 50, struct_WidgetOptionValueTyped, widget_option_is_active), + YAML_END +}; +static const struct YamlNode struct_ZonePersistentData[] = { + YAML_IDX, + YAML_CUSTOM("widgetName",r_widget_name,w_widget_name), + YAML_STRUCT("widgetData", 0, struct_WidgetPersistentData, isAlwaysActive), + YAML_END +}; +static const struct YamlNode union_LayoutOptionValue_elmts[] = { + YAML_CUSTOM("unsignedValue",r_lov_unsigned,w_lov_unsigned), + YAML_CUSTOM("boolValue",r_lov_unsigned,w_lov_unsigned), + YAML_CUSTOM("color",r_lov_color,w_lov_color), + YAML_END +}; +static const struct YamlNode struct_LayoutOptionValueTyped[] = { + YAML_IDX, + YAML_CUSTOM("type",r_lov_type,w_lov_type), + YAML_UNION("value", 0, union_LayoutOptionValue_elmts, select_lov), + YAML_END +}; +static const struct YamlNode struct_LayoutPersistentData[] = { + YAML_ARRAY("zones", 0, 10, struct_ZonePersistentData, widget_is_active), + YAML_ARRAY("options", 0, 10, struct_LayoutOptionValueTyped, layout_option_is_active), + YAML_END +}; +static const struct YamlNode struct_CustomScreenData[] = { + YAML_IDX, + YAML_CUSTOM("LayoutId",r_screen_id,w_screen_id), + YAML_STRUCT("layoutData", 0, struct_LayoutPersistentData, isAlwaysActive), + YAML_END +}; +static const struct YamlNode struct_TopBarPersistentData[] = { + YAML_ARRAY("zones", 0, 6, struct_ZonePersistentData, widget_is_active), + YAML_END +}; +static const struct YamlNode struct_customSwitch[] = { + YAML_IDX_CUST("sw",cfs_idx_read,cfs_idx_write), + YAML_STRING("name", 3), + YAML_ENUM("type", 3, enum_SwitchConfig, NULL), + YAML_UNSIGNED( "group", 2 ), + YAML_ENUM("start", 2, enum_fsStartPositionType, NULL), + YAML_UNSIGNED( "state", 1 ), + YAML_ENUM("onColorLuaOverride", 1, enum_booleanEnum, NULL), + YAML_ENUM("offColorLuaOverride", 1, enum_booleanEnum, NULL), + YAML_PADDING( 6 ), + YAML_STRUCT("onColor", 24, struct_RGBLedColor, isAlwaysActive), + YAML_STRUCT("offColor", 24, struct_RGBLedColor, isAlwaysActive), + YAML_END +}; +static const struct YamlNode struct_USBJoystickChData[] = { + YAML_IDX, + YAML_ENUM("mode", 3, enum_USBJoystickCh, NULL), + YAML_UNSIGNED( "inversion", 1 ), + YAML_UNSIGNED( "param", 4 ), + YAML_UNSIGNED( "btn_num", 5 ), + YAML_UNSIGNED( "switch_npos", 3 ), + YAML_END +}; +static const struct YamlNode struct_ModelData[] = { + YAML_CUSTOM("semver",nullptr,w_semver), + YAML_STRUCT("header", 1048, struct_ModelHeader, NULL), + YAML_ARRAY("timers", 136, 3, struct_TimerData, NULL), + YAML_UNSIGNED( "telemetryProtocol", 3 ), + YAML_UNSIGNED( "thrTrim", 1 ), + YAML_UNSIGNED( "noGlobalFunctions", 1 ), + YAML_UNSIGNED( "displayTrims", 2 ), + YAML_UNSIGNED( "ignoreSensorIds", 1 ), + YAML_SIGNED( "trimInc", 3 ), + YAML_UNSIGNED( "disableThrottleWarning", 1 ), + YAML_UNSIGNED( "displayChecklist", 1 ), + YAML_UNSIGNED( "extendedLimits", 1 ), + YAML_UNSIGNED( "extendedTrims", 1 ), + YAML_UNSIGNED( "throttleReversed", 1 ), + YAML_UNSIGNED( "enableCustomThrottleWarning", 1 ), + YAML_UNSIGNED( "disableTelemetryWarning", 1 ), + YAML_UNSIGNED( "showInstanceIds", 1 ), + YAML_UNSIGNED( "checklistInteractive", 1 ), + YAML_PADDING( 4 ), + YAML_SIGNED( "customThrottleWarningPosition", 8 ), + YAML_UNSIGNED( "beepANACenter", 16 ), + YAML_ARRAY("mixData", 160, 64, struct_MixData, NULL), + YAML_ARRAY("limitData", 104, 32, struct_LimitData, NULL), + YAML_ARRAY("expoData", 144, 64, struct_ExpoData, NULL), + YAML_ARRAY("curves", 32, 32, struct_CurveHeader, NULL), + YAML_ARRAY("points", 8, 512, struct_signed_8, NULL), + YAML_ARRAY("logicalSw", 72, 64, struct_LogicalSwitchData, NULL), + YAML_ARRAY("customFn", 88, 64, struct_CustomFunctionData, cfn_is_active), + YAML_STRUCT("swashR", 64, struct_SwashRingData, swash_is_active), + YAML_ARRAY("flightModeData", 480, 9, struct_FlightModeData, fmd_is_active), + YAML_UNSIGNED_CUST( "thrTraceSrc", 8, r_thrSrc, w_thrSrc ), + YAML_CUSTOM("switchWarningState",r_swtchWarn,nullptr), + YAML_ARRAY("switchWarning", 2, 32, struct_swtchWarn, nullptr), + YAML_ARRAY("gvars", 56, 15, struct_GVarData, NULL), + YAML_STRUCT("varioData", 40, struct_VarioData, NULL), + YAML_UNSIGNED_CUST( "rssiSource", 8, r_tele_sensor, w_tele_sensor ), + YAML_STRUCT("rssiAlarms", 0, struct_RssiAlarmData, NULL), + YAML_STRUCT("rfAlarms", 16, struct_RFAlarmData, NULL), + YAML_UNSIGNED( "thrTrimSw", 3 ), + YAML_ENUM("potsWarnMode", 2, enum_PotsWarnMode, NULL), + YAML_ENUM("jitterFilter", 2, enum_ModelOverridableEnable, NULL), + YAML_PADDING( 1 ), + YAML_ARRAY("moduleData", 232, 2, struct_ModuleData, NULL), + YAML_ARRAY("failsafeChannels", 16, 32, struct_signed_16, NULL), + YAML_STRUCT("trainerData", 40, struct_TrainerModuleData, NULL), + YAML_ARRAY("scriptsData", 192, 9, struct_ScriptData, NULL), + YAML_ARRAY("inputNames", 32, 32, struct_string_32, NULL), + YAML_UNSIGNED( "potsWarnEnabled", 16 ), + YAML_ARRAY("potsWarnPosition", 8, 16, struct_signed_8, NULL), + YAML_ARRAY("telemetrySensors", 112, 75, struct_TelemetrySensor, NULL), + YAML_ARRAY("screenData", 0, 10, struct_CustomScreenData, screen_is_active), + YAML_STRUCT("topbarData", 0, struct_TopBarPersistentData, isAlwaysActive), + YAML_ARRAY("topbarWidgetWidth", 8, 6, struct_unsigned_8, NULL), + YAML_UNSIGNED( "view", 8 ), + YAML_STRING("modelRegistrationID", 8), + YAML_CUSTOM("functionSwitchConfig",r_functionSwitchConfig,nullptr), + YAML_CUSTOM("functionSwitchGroup",r_functionSwitchGroup,nullptr), + YAML_CUSTOM("functionSwitchStartConfig",r_functionSwitchStartConfig,nullptr), + YAML_CUSTOM("functionSwitchLogicalState",r_functionSwitchLogicalState,nullptr), + YAML_ARRAY("switchNames", 0, NUM_FUNCTIONS_SWITCHES, struct_cfsNameConfig, nullptr), + YAML_ARRAY("functionSwitchLedONColor", 0, NUM_FUNCTIONS_SWITCHES, struct_cfsOnColorConfig, nullptr), + YAML_ARRAY("functionSwitchLedOFFColor", 0, NUM_FUNCTIONS_SWITCHES, struct_cfsOffColorConfig, nullptr), + YAML_ARRAY("customSwitches", 88, 6, struct_customSwitch, isAlwaysActive), + YAML_ARRAY("cfsGroupOn", 1, 8, struct_cfsGroupOn, cfsGroupIsActive), + YAML_PADDING( 8 ), + YAML_UNSIGNED( "usbJoystickExtMode", 1 ), + YAML_ENUM("usbJoystickIfMode", 3, enum_USBJoystickIfMode, NULL), + YAML_UNSIGNED( "usbJoystickCircularCut", 4 ), + YAML_ARRAY("usbJoystickCh", 16, 26, struct_USBJoystickChData, NULL), + YAML_ENUM("radioThemesDisabled", 2, enum_ModelOverridableEnable, NULL), + YAML_ENUM("radioGFDisabled", 2, enum_ModelOverridableEnable, NULL), + YAML_ENUM("radioTrainerDisabled", 2, enum_ModelOverridableEnable, NULL), + YAML_ENUM("modelHeliDisabled", 2, enum_ModelOverridableEnable, NULL), + YAML_ENUM("modelFMDisabled", 2, enum_ModelOverridableEnable, NULL), + YAML_ENUM("modelCurvesDisabled", 2, enum_ModelOverridableEnable, NULL), + YAML_ENUM("modelGVDisabled", 2, enum_ModelOverridableEnable, NULL), + YAML_ENUM("modelLSDisabled", 2, enum_ModelOverridableEnable, NULL), + YAML_ENUM("modelSFDisabled", 2, enum_ModelOverridableEnable, NULL), + YAML_ENUM("modelCustomScriptsDisabled", 2, enum_ModelOverridableEnable, NULL), + YAML_ENUM("modelTelemetryDisabled", 2, enum_ModelOverridableEnable, NULL), + YAML_END +}; +static const struct YamlNode struct_PartialModel[] = { + YAML_CUSTOM("semver",nullptr,w_semver), + YAML_STRUCT("header", 1048, struct_ModelHeader, NULL), + YAML_ARRAY("moduleData", 232, 2, struct_ModuleData, NULL), + YAML_END +}; + +#define MAX_RADIODATA_MODELDATA_PARTIALMODEL_STR_LEN 29 + +static const struct YamlNode __RadioData_root_node = YAML_ROOT( struct_RadioData ); + +const YamlNode* get_radiodata_nodes() +{ + return &__RadioData_root_node; +} +static const struct YamlNode __ModelData_root_node = YAML_ROOT( struct_ModelData ); + +const YamlNode* get_modeldata_nodes() +{ + return &__ModelData_root_node; +} +static const struct YamlNode __PartialModel_root_node = YAML_ROOT( struct_PartialModel ); + +const YamlNode* get_partialmodel_nodes() +{ + return &__PartialModel_root_node; +} + diff --git a/radio/src/targets/t18h7/CMakeLists.txt b/radio/src/targets/t18h7/CMakeLists.txt new file mode 100644 index 00000000000..2c14cfa9522 --- /dev/null +++ b/radio/src/targets/t18h7/CMakeLists.txt @@ -0,0 +1,189 @@ +option(UNEXPECTED_SHUTDOWN "Enable the Unexpected Shutdown screen" ON) +option(PXX1 "PXX1 protocol support" ON) +option(PXX2 "PXX2 protocol support" OFF) +option(AFHDS3 "AFHDS3 TX Module" ON) +option(MULTIMODULE "DIY Multiprotocol TX Module (https://github.com/pascallanger/DIY-Multiprotocol-TX-Module)" ON) +option(GHOST "Ghost TX Module" ON) +option(MODULE_SIZE_STD "Standard size TX Module" ON) +option(LUA_MIXER "Enable LUA mixer/model scripts support" ON) +option(DISK_CACHE "Enable SD card disk cache" ON) + +set(FIRMWARE_QSPI YES) +set(FIRMWARE_FORMAT_UF2 YES) +set(PWR_BUTTON "PRESS" CACHE STRING "Pwr button type (PRESS/SWITCH)") +set(CPU_TYPE STM32H7) +set(HSE_VALUE 48000000) +set(SDCARD YES) +set(STORAGE_MODELSLIST YES) +set(HAPTIC YES) +set(GUI_DIR colorlcd) +set(BITMAPS_DIR 480x272) +set(TARGET_DIR t18h7) +set(RTC_BACKUP_RAM YES) +set(PPM_LIMITS_SYMETRICAL YES) +set(USB_SERIAL ON CACHE BOOL "Enable USB serial (CDC)") +set(HARDWARE_EXTERNAL_MODULE YES) +set(INTERNAL_MODULE_AFHDS3 NO) +set(ROTARY_ENCODER YES) +set(FUNCTION_SWITCHES YES) +set(FUNCTION_SWITCHES_RGB_LEDS YES) + +#option(STICK_DEAD_ZONE "Enable sticks dead zone" YES) + +# for size report script +set(CPU_TYPE_FULL STM32H750xB) +set(TARGET_LINKER_DIR stm32h750_sdram) +set(TARGET_EXTRAM_START 0xD0000000) +set(SIZE_TARGET_MEM_DEFINE "MEM_SIZE_SDRAM1=8192") +set(FIRMWARE_STRIP_BOOTLOADER YES) + +add_definitions(-DPCBT18H7 -DPCBHORUS) +add_definitions(-DSTM32_SUPPORT_32BIT_TIMERS) +add_definitions(-DFIRMWARE_QSPI) +add_definitions(-DFIRMWARE_FORMAT_UF2) +add_definitions(-DUSE_CUSTOM_EXTI_IRQ) +add_definitions(-DUSB_CHARGER) + +set(FLAVOUR t18h7) +add_definitions(-DRADIO_T18H7) + +# defines existing internal modules +set(INTERNAL_MODULES CRSF CACHE STRING "Internal modules") +set(DEFAULT_INTERNAL_MODULE CROSSFIRE CACHE STRING "Default internal module") + +set(BITMAPS_TARGET bm480_bitmaps) +set(FONTS_TARGET x12_fonts) +set(LCD_DRIVER lcd_driver_480x272.cpp) +set(HARDWARE_TOUCH YES) +set(RADIO_DEPENDENCIES ${RADIO_DEPENDENCIES} ${BITMAPS_TARGET}) +set(FIRMWARE_DEPENDENCIES datacopy) +set(SOFTWARE_KEYBOARD ON) +set(FLYSKY_GIMBAL OFF) + +add_definitions( + -DSTM32H750XBTx -DSTM32H750xx + -DSDRAM -DCCMRAM + -DHARDWARE_TOUCH -DHARDWARE_KEYS -DSOFTWARE_KEYBOARD + -DTOUCH_PANEL_GT911 +) + +set(SDRAM ON) + +add_definitions(-DSOFTWARE_VOLUME) +add_definitions(-DRTCLOCK) +add_definitions(-DGPS_USART_BAUDRATE=${INTERNAL_GPS_BAUDRATE}) +add_definitions(-DPWR_BUTTON_${PWR_BUTTON}) + +if(STICK_DEAD_ZONE) + add_definitions(-DSTICK_DEAD_ZONE) +endif() + +if(NOT UNEXPECTED_SHUTDOWN) + add_definitions(-DNO_UNEXPECTED_SHUTDOWN) +endif() + +if(DISK_CACHE) + set(SRC ${SRC} disk_cache.cpp) + add_definitions(-DDISK_CACHE) +endif() + +if(FUNCTION_SWITCHES_RGB_LEDS) + set(RGB_LEDS YES) + add_definitions(-DFUNCTION_SWITCHES_RGB_LEDS) + add_definitions(-DRGB_LEDS_900NS) +endif() + +if(RGB_LEDS) + add_definitions(-DRGB_LEDS) +endif() + +if(FUNCTION_SWITCHES) +add_definitions(-DFUNCTION_SWITCHES) +endif() + +set(AFHDS3 ON) + +# VCP CLI +set(ENABLE_SERIAL_PASSTHROUGH ON CACHE BOOL "Enable serial passthrough") +set(CLI ON CACHE BOOL "Enable CLI") + +set(BOARD jumper-h750) +set(BOARD_SRC_DIR boards/${BOARD}) +include_directories(boards/${BOARD}) + +set(TARGET_SRC_DIR targets/${TARGET_DIR}) + +set(BOARD_COMMON_SRC + ${BOARD_SRC_DIR}/board.cpp + ${BOARD_SRC_DIR}/key_driver.cpp + ${BOARD_SRC_DIR}/${LCD_DRIVER} + ${BOARD_SRC_DIR}/backlight_driver.cpp + ${BOARD_SRC_DIR}/haptic_driver.cpp + ${BOARD_SRC_DIR}/extflash_driver.cpp + ${BOARD_SRC_DIR}/usb_charger_driver.cpp + targets/common/arm/stm32/abnormal_reboot.cpp + targets/common/arm/stm32/delays_driver.cpp + targets/common/arm/stm32/dma2d.cpp + targets/common/arm/stm32/flash_driver.cpp + targets/common/arm/stm32/pwr_driver.cpp + targets/common/arm/stm32/rotary_encoder_driver.cpp + targets/common/arm/stm32/rtc_driver.cpp + targets/common/arm/stm32/watchdog_driver.cpp + drivers/pca95xx.cpp +) + +# Bootloader board library +add_library(board_bl OBJECT EXCLUDE_FROM_ALL + ${BOARD_COMMON_SRC} + ${BOARD_SRC_DIR}/sdram_driver.cpp + ${RADIO_SRC_DIR}/gui/colorlcd/boot_menu.cpp + targets/common/arm/stm32/stm32_qspi.cpp + targets/common/arm/stm32/stm32_pulse_driver.cpp +) +add_dependencies(board_bl minimal_board_lib) +set(BOOTLOADER_SRC ${BOOTLOADER_SRC} $) + +set(CMSIS_SRC ${BOARD_SRC_DIR}/system_clock.c) + +# Firmware board library +add_library(board OBJECT EXCLUDE_FROM_ALL + ${BOARD_COMMON_SRC} + ${BOARD_SRC_DIR}/tp_gt911.cpp + targets/common/arm/stm32/audio_dac_driver.cpp + targets/common/arm/stm32/heartbeat_driver.cpp + targets/common/arm/stm32/mixer_scheduler_driver.cpp + targets/common/arm/stm32/module_timer_driver.cpp + targets/common/arm/stm32/stm32_pulse_driver.cpp + targets/common/arm/stm32/stm32_softserial_driver.cpp + targets/common/arm/stm32/stm32_qspi.cpp + targets/common/arm/stm32/stm32_switch_driver.cpp + targets/common/arm/stm32/stm32_ws2812.cpp + targets/common/arm/stm32/trainer_driver.cpp +) +add_dependencies(board board_lib) +set(FIRMWARE_SRC ${FIRMWARE_SRC} $) + +include_directories(${RADIO_SRC_DIR}/fonts/colorlcd gui/${GUI_DIR} gui/${GUI_DIR}/layouts) + +if(BOOTLOADER) + set(FIRMWARE_TARGET_SRC + ${FIRMWARE_TARGET_SRC} + ../../bootloader/loadboot.cpp + ) +endif() + +set(SRC + ${SRC} + io/frsky_firmware_update.cpp + io/multi_firmware_update.cpp + ) + +if (MULTIMODULE) + add_definitions(-DMULTI_PROTOLIST) + set(SRC ${SRC} + io/multi_protolist.cpp + ) +endif() + +# Make malloc() thread-safe +add_definitions(-DTHREADSAFE_MALLOC) diff --git a/radio/src/targets/t18h7/hal.h b/radio/src/targets/t18h7/hal.h new file mode 100644 index 00000000000..450ea9965a8 --- /dev/null +++ b/radio/src/targets/t18h7/hal.h @@ -0,0 +1,515 @@ +/* + * 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. + */ + +/* +STM32H750 +DMA1 +Stream0: LED_STRIP_TIMER_DMA_STREAM +Stream1: INTMODULE_DMA_STREAM +Stream2: FLYSKY_HALL_DMA_Stream_RX +Stream3: TELEMETRY_DMA_Stream_RX +Stream4: +Stream5: INTMODULE_RX_DMA_STREAM +Stream6: +Stream7: TELEMETRY_DMA_Stream_TX + +DMA2 +Stream0: ADC_EXT_DMA_STREAM +Stream1: AUDIO_DMA_Stream +Stream2: +Stream3: EXTMODULE_TIMER_DMA_STREAM +Stream4: ADC_DMA_STREAM +Stream5: EXTMODULE_USART_RX_DMA_STREAM +Stream6: EXTMODULE_USART_TX_DMA_STREAM + +TIM1: LED_STRIP_TIMER +TIM2: BACKLIGHT_TIMER +TIM3: EXTMODULE_TIMER +TIM4: (no pins) +TIM5: +TIM6: AUDIO_TIMER +TIM7: (no pins) +TIM8: TRAINER_TIMER +TIM12: MIXER_SCHEDULER_TIMER +TIM13: +TIM14: MS_TIMER +TIM15: HAPTIC_GPIO_TIMER +TIM16: +TIM17: ROTARY_ENCODER_TIMER + +USARTS +USART1: INTMODULE_USART +USART2: TELEMETRY_USART +USART3: DGONE +USART4: BT MODULE +USART6: EXTMODULE_USART +*/ + +#ifndef _HAL_H_ +#define _HAL_H_ + +#define CPU_FREQ 480000000 + +#define PERI1_FREQUENCY 120000000 +#define PERI2_FREQUENCY 120000000 +#define TIMER_MULT_APB1 2 +#define TIMER_MULT_APB2 2 + +// Keys +#define KEYS_GPIO_REG_EXIT GPIOI +#define KEYS_GPIO_PIN_EXIT LL_GPIO_PIN_5 // PI.05 +#define KEYS_GPIO_REG_ENTER GPIOI +#define KEYS_GPIO_PIN_ENTER LL_GPIO_PIN_2 // PI.02 +#define KEYS_GPIO_REG_PAGEDN GPIOG +#define KEYS_GPIO_PIN_PAGEDN LL_GPIO_PIN_9 // PG.09 +#define KEYS_GPIO_REG_MDL GPIOJ +#define KEYS_GPIO_PIN_MDL LL_GPIO_PIN_12 // PJ.12 +#define KEYS_GPIO_REG_TELE GPIOG +#define KEYS_GPIO_PIN_TELE LL_GPIO_PIN_11 // PG.11 +#define KEYS_GPIO_REG_SYS GPIOG +#define KEYS_GPIO_PIN_SYS LL_GPIO_PIN_13 // PG.13 + +// Trims +#define TRIMS_GPIO_REG_LHL GPIOG +#define TRIMS_GPIO_PIN_LHL LL_GPIO_PIN_12 // PG.12 +#define TRIMS_GPIO_REG_LHR GPIOH +#define TRIMS_GPIO_PIN_LHR LL_GPIO_PIN_2 // PH.02 + +#define TRIMS_GPIO_REG_LVD GPIOJ +#define TRIMS_GPIO_PIN_LVD LL_GPIO_PIN_13 // PJ.13 +#define TRIMS_GPIO_REG_LVU GPIOE +#define TRIMS_GPIO_PIN_LVU LL_GPIO_PIN_4 // PE.04 + +#define TRIMS_GPIO_REG_RVD GPIOI +#define TRIMS_GPIO_PIN_RVD LL_GPIO_PIN_11 // PI.11 +#define TRIMS_GPIO_REG_RVU GPIOH +#define TRIMS_GPIO_PIN_RVU LL_GPIO_PIN_14 // PH.14 + +#define TRIMS_GPIO_REG_RHL GPIOA +#define TRIMS_GPIO_PIN_RHL LL_GPIO_PIN_15 // PA.15 +#define TRIMS_GPIO_REG_RHR GPIOI +#define TRIMS_GPIO_PIN_RHR LL_GPIO_PIN_4 // PI.04 + +#define TRIMS_GPIO_REG_LSD GPIOH +#define TRIMS_GPIO_PIN_LSD LL_GPIO_PIN_9 // PH.09 +#define TRIMS_GPIO_REG_LSU GPIOH +#define TRIMS_GPIO_PIN_LSU LL_GPIO_PIN_12 // PH.12 + +#define TRIMS_GPIO_REG_RSD GPIOH +#define TRIMS_GPIO_PIN_RSD LL_GPIO_PIN_8 // PH.08 +#define TRIMS_GPIO_REG_RSU GPIOB +#define TRIMS_GPIO_PIN_RSU LL_GPIO_PIN_14 // PB.14 + +// Switches +#define SWITCHES_GPIO_REG_A_H GPIOE +#define SWITCHES_GPIO_PIN_A_H LL_GPIO_PIN_5 // PE.05 +#define SWITCHES_GPIO_REG_A_L GPIOE +#define SWITCHES_GPIO_PIN_A_L LL_GPIO_PIN_3 // PE.03 +#define SWITCHES_A_INVERTED + +#define SWITCHES_GPIO_REG_B_H GPIOH +#define SWITCHES_GPIO_PIN_B_H LL_GPIO_PIN_13 // PH.13 +#define SWITCHES_GPIO_REG_B_L GPIOC +#define SWITCHES_GPIO_PIN_B_L LL_GPIO_PIN_13 // PC.13 +#define SWITCHES_B_INVERTED + +#define SWITCHES_GPIO_REG_C_H GPIOG +#define SWITCHES_GPIO_PIN_C_H LL_GPIO_PIN_7 // PG.07 +#define SWITCHES_GPIO_REG_C_L GPIOA +#define SWITCHES_GPIO_PIN_C_L LL_GPIO_PIN_8 // PA.08 +#define SWITCHES_C_INVERTED + +#define SWITCHES_GPIO_REG_D_H GPIOG +#define SWITCHES_GPIO_PIN_D_H LL_GPIO_PIN_2 // PG.02 +#define SWITCHES_GPIO_REG_D_L GPIOD +#define SWITCHES_GPIO_PIN_D_L LL_GPIO_PIN_4 // PD.04 +#define SWITCHES_D_INVERTED + +#define SWITCHES_GPIO_REG_E_H GPIOI +#define SWITCHES_GPIO_PIN_E_H LL_GPIO_PIN_8 // PI.08 +#define SWITCHES_GPIO_REG_E_L GPIOG +#define SWITCHES_GPIO_PIN_E_L LL_GPIO_PIN_3 // PG.03 +#define SWITCHES_E_INVERTED + +#define SWITCHES_GPIO_REG_F GPIOG +#define SWITCHES_GPIO_PIN_F LL_GPIO_PIN_14 // PG.14 + +#define SWITCHES_GPIO_REG_G_H GPIOJ +#define SWITCHES_GPIO_PIN_G_H LL_GPIO_PIN_8 // PJ.08 +#define SWITCHES_GPIO_REG_G_L GPIOJ +#define SWITCHES_GPIO_PIN_G_L LL_GPIO_PIN_7 // PJ.07 + +#define SWITCHES_GPIO_REG_H GPIOH +#define SWITCHES_GPIO_PIN_H LL_GPIO_PIN_15 // PH.15 + +#define SWITCHES_GPIO_REG_I GPIOB +#define SWITCHES_GPIO_PIN_I LL_GPIO_PIN_0 // PB.00 + +#define SWITCHES_GPIO_REG_J GPIOC +#define SWITCHES_GPIO_PIN_J LL_GPIO_PIN_1 // PC.01 + +#define SWITCHES_GPIO_REG_K GPIOC +#define SWITCHES_GPIO_PIN_K LL_GPIO_PIN_0 // PC.00 + +#define SWITCHES_GPIO_REG_L GPIOI +#define SWITCHES_GPIO_PIN_L LL_GPIO_PIN_9 // PI.09 + +#define SWITCHES_GPIO_REG_M GPIOI +#define SWITCHES_GPIO_PIN_M LL_GPIO_PIN_10 // PI.10 + +#define SWITCHES_GPIO_REG_N GPIOH +#define SWITCHES_GPIO_PIN_N LL_GPIO_PIN_3 // PH.03 + +// Customisable function switches +#define FUNCTION_SWITCH_1 SI +#define SWITCHES_I_CFS_IDX 0 + +#define FUNCTION_SWITCH_2 SJ +#define SWITCHES_J_CFS_IDX 1 + +#define FUNCTION_SWITCH_3 SK +#define SWITCHES_K_CFS_IDX 2 + +#define FUNCTION_SWITCH_4 SL +#define SWITCHES_L_CFS_IDX 3 + +#define FUNCTION_SWITCH_5 SM +#define SWITCHES_M_CFS_IDX 4 + +#define FUNCTION_SWITCH_6 SN +#define SWITCHES_N_CFS_IDX 5 + +// ADC +#define ADC_GPIO_PIN_STICK_LH LL_GPIO_PIN_0 // PA.00 ADC INP16 +#define ADC_GPIO_PIN_STICK_LV LL_GPIO_PIN_3 // PA.03 ADC INP15 +#define ADC_GPIO_PIN_STICK_RV LL_GPIO_PIN_1 // PA.01 ADC INP17 +#define ADC_GPIO_PIN_STICK_RH LL_GPIO_PIN_2 // PA.02 ADC INP14 +#define ADC_GPIO_PIN_POT1 LL_GPIO_PIN_3 // PC.03 ADC INP13 +#define ADC_GPIO_PIN_POT2 LL_GPIO_PIN_2 // PC.02 ADC INP12 +#define ADC_GPIO_PIN_POT3 LL_GPIO_PIN_4 // PC.04 ADC INP4 +#define ADC_GPIO_PIN_POT4 LL_GPIO_PIN_1 // PB.01 ADC INP5 +#define ADC_GPIO_PIN_BATT LL_GPIO_PIN_5 // PC.05 ADC INP8 + +#define ADC_GPIOA_PINS (ADC_GPIO_PIN_STICK_LH | ADC_GPIO_PIN_STICK_LV | ADC_GPIO_PIN_STICK_RV | ADC_GPIO_PIN_STICK_RH) +#define ADC_GPIOC_PINS (ADC_GPIO_PIN_POT1 | ADC_GPIO_PIN_POT2 | ADC_GPIO_PIN_POT3 | ADC_GPIO_PIN_BATT) +#define ADC_GPIOB_PINS (ADC_GPIO_PIN_POT4) + +#define ADC_CHANNEL_STICK_LH LL_ADC_CHANNEL_16 +#define ADC_CHANNEL_STICK_LV LL_ADC_CHANNEL_15 +#define ADC_CHANNEL_STICK_RV LL_ADC_CHANNEL_17 +#define ADC_CHANNEL_STICK_RH LL_ADC_CHANNEL_14 +#define ADC_CHANNEL_POT1 LL_ADC_CHANNEL_13 +#define ADC_CHANNEL_POT2 LL_ADC_CHANNEL_12 +#define ADC_CHANNEL_POT3 LL_ADC_CHANNEL_4 +#define ADC_CHANNEL_POT4 LL_ADC_CHANNEL_5 +#define ADC_CHANNEL_BATT LL_ADC_CHANNEL_8 +#define ADC_CHANNEL_RTC_BAT LL_ADC_CHANNEL_VBAT + +#define ADC_MAIN ADC1 +#define ADC_DMA DMA2 +#define ADC_DMA_CHANNEL LL_DMAMUX1_REQ_ADC1 +#define ADC_DMA_STREAM LL_DMA_STREAM_4 +#define ADC_DMA_STREAM_IRQ DMA2_Stream4_IRQn +#define ADC_DMA_STREAM_IRQHandler DMA2_Stream4_IRQHandler +#define ADC_SAMPTIME LL_ADC_SAMPLINGTIME_8CYCLES_5 + +#define ADC_EXT ADC3 +#define ADC_EXT_CHANNELS { ADC_CHANNEL_RTC_BAT } +#define ADC_EXT_DMA DMA2 +#define ADC_EXT_DMA_CHANNEL LL_DMAMUX1_REQ_ADC3 +#define ADC_EXT_DMA_STREAM LL_DMA_STREAM_0 +#define ADC_EXT_DMA_STREAM_IRQ DMA2_Stream0_IRQn +#define ADC_EXT_DMA_STREAM_IRQHandler DMA2_Stream0_IRQHandler +#define ADC_EXT_SAMPTIME LL_ADC_SAMPLINGTIME_8CYCLES_5 + +#define ADC_VREF_PREC2 330 + +#define ADC_DIRECTION { \ +1,-1,1,-1, /* gimbals */ \ +-1,-1,-1,1, /* pots */ \ +1, /* vbat */ \ +1 /* rtc_bat */ \ +} + + +// Power +#define PWR_SWITCH_GPIO GPIO_PIN(GPIOI, 3) +#define PWR_EXTRA_SWITCH_GPIO GPIO_PIN(GPIOJ, 14) +#define PWR_ON_GPIO GPIO_PIN(GPIOD, 3) + +// S.Port update connector +#define HAS_SPORT_UPDATE_CONNECTOR() (false) + + +// Telemetry +#define TELEMETRY_SET_INPUT 0 +#define TELEMETRY_TX_GPIO GPIO_PIN(GPIOD, 5) +#define TELEMETRY_RX_GPIO GPIO_UNDEF +#define TELEMETRY_USART USART2 +#define TELEMETRY_USART_IRQn USART2_IRQn +#define TELEMETRY_DMA DMA1 +#define TELEMETRY_DMA_Stream_TX LL_DMA_STREAM_7 +#define TELEMETRY_DMA_Channel_TX LL_DMAMUX1_REQ_USART2_TX +#define TELEMETRY_DMA_TX_Stream_IRQ DMA1_Stream7_IRQn +#define TELEMETRY_DMA_TX_IRQHandler DMA1_Stream7_IRQHandler +#define TELEMETRY_DMA_Stream_RX LL_DMA_STREAM_3 +#define TELEMETRY_DMA_Channel_RX LL_DMAMUX1_REQ_USART2_RX +#define TELEMETRY_USART_IRQHandler USART2_IRQHandler + +// Software IRQ (Prio 5 -> FreeRTOS compatible) +//#define USE_CUSTOM_EXTI_IRQ +#define TELEMETRY_USE_CUSTOM_EXTI +#define CUSTOM_EXTI_IRQ_NAME ETH_WKUP_IRQ +#define ETH_WKUP_IRQ_Priority 5 +#define CUSTOM_EXTI_IRQ_LINE 86 +//#define USE_EXTI15_10_IRQ +//#define CUSTOM_EXTI_IRQ_Priority 5 +#define TELEMETRY_RX_FRAME_EXTI_LINE CUSTOM_EXTI_IRQ_LINE + +// USB +#define USB_GPIO GPIOA +#define USB_GPIO_VBUS GPIO_PIN(GPIOA, 9) +#define USB_GPIO_DM GPIO_PIN(GPIOA, 11) +#define USB_GPIO_DP GPIO_PIN(GPIOA, 12) +#define USB_GPIO_AF GPIO_AF10 + +// LCD (LTDC-only, no SPI panel-init sequence) +#define LCD_NRST_GPIO GPIOI +#define LCD_NRST_GPIO_PIN LL_GPIO_PIN_15 + +// QSPI Flash +#define QSPI_CLK_GPIO GPIO_PIN(GPIOF, 10) +#define QSPI_CLK_GPIO_AF GPIO_AF9 +#define QSPI_CS_GPIO GPIO_PIN(GPIOG, 6) +#define QSPI_CS_GPIO_AF GPIO_AF10 +#define QSPI_MISO_GPIO GPIO_PIN(GPIOF, 9) +#define QSPI_MISO_GPIO_AF GPIO_AF10 +#define QSPI_MOSI_GPIO GPIO_PIN(GPIOF, 8) +#define QSPI_MOSI_GPIO_AF GPIO_AF10 +#define QSPI_WP_GPIO GPIO_PIN(GPIOF, 7) +#define QSPI_WP_GPIO_AF GPIO_AF9 +#define QSPI_HOLD_GPIO GPIO_PIN(GPIOF, 6) +#define QSPI_HOLD_GPIO_AF GPIO_AF9 +#define QSPI_FLASH_SIZE 0x1000000 + +#define SD_SDIO SDMMC1 +#define SD_SDIO_CLK_DIV(fq) (HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SDMMC) / (2 * fq)) +#define SD_SDIO_TRANSFER_CLK_DIV SD_SDIO_CLK_DIV(24000000) +#define STORAGE_USE_SDIO + +// Chargers (USB and wireless) +#define UCHARGER_GPIO GPIO_PIN(GPIOD, 6) + +// Audio +#define AUDIO_MUTE_GPIO GPIO_PIN(GPIOH, 4) +#define AUDIO_MUTE_DELAY 200 // ms +#define AUDIO_UNMUTE_DELAY 100 // ms +#define AUDIO_OUTPUT_GPIO GPIO_PIN(GPIOA, 4) +#define AUDIO_DAC DAC1 +#define AUDIO_DMA_Stream LL_DMA_STREAM_1 +#define AUDIO_DMA_Channel LL_DMAMUX1_REQ_DAC1_CH1 +#define AUDIO_TIM_IRQn TIM6_DAC_IRQn +#define AUDIO_TIM_IRQHandler TIM6_DAC_IRQHandler +#define AUDIO_DMA_Stream_IRQn DMA2_Stream1_IRQn +#define AUDIO_DMA_Stream_IRQHandler DMA2_Stream1_IRQHandler +#define AUDIO_TIMER TIM6 +#define AUDIO_DMA DMA2 + +// I2C Bus (touch only, no IMU) +#define I2C_B2 I2C4 +#define I2C_B2_SDA_GPIO GPIO_PIN(GPIOD, 13) +#define I2C_B2_SCL_GPIO GPIO_PIN(GPIOD, 12) +#define I2C_B2_GPIO_AF LL_GPIO_AF_4 +#define I2C_B2_CLK_RATE 400000 + +// Internal Module +#define INTMODULE_PWR_GPIO GPIO_PIN(GPIOI, 1) +#define INTMODULE_BOOTCMD_GPIO GPIO_PIN(GPIOD, 7) +#define INTMODULE_BOOTCMD_DEFAULT 0 +#define INTMODULE_TX_GPIO GPIO_PIN(GPIOB, 6) +#define INTMODULE_RX_GPIO GPIO_PIN(GPIOB, 7) +#define INTMODULE_USART USART1 +#define INTMODULE_GPIO_AF LL_GPIO_AF_7 +#define INTMODULE_USART_IRQn USART1_IRQn +#define INTMODULE_USART_IRQHandler USART1_IRQHandler +#define INTMODULE_DMA DMA1 +#define INTMODULE_DMA_STREAM LL_DMA_STREAM_1 +#define INTMODULE_DMA_STREAM_IRQ DMA1_Stream1_IRQn +#define INTMODULE_DMA_FLAG_TC DMA_FLAG_TCIF1 +#define INTMODULE_DMA_CHANNEL LL_DMAMUX1_REQ_USART1_TX +#define INTMODULE_RX_DMA DMA1 +#define INTMODULE_RX_DMA_STREAM LL_DMA_STREAM_5 +#define INTMODULE_RX_DMA_CHANNEL LL_DMAMUX1_REQ_USART1_RX +#define INTMODULE_RX_DMA_Stream_IRQn DMA1_Stream5_IRQn +#define INTMODULE_RX_DMA_Stream_IRQHandler DMA1_Stream5_IRQHandler + +// External Module +#define EXTMODULE +#define EXTMODULE_PULSES +#define EXTMODULE_PWR_GPIO GPIO_PIN(GPIOI, 0) +#define EXTMODULE_TX_GPIO GPIO_PIN(GPIOC, 6) // TIM3_CH1 +#define EXTMODULE_RX_GPIO GPIO_PIN(GPIOC, 7) + +#define EXTMODULE_TIMER TIM3 +#define EXTMODULE_TIMER_Channel LL_TIM_CHANNEL_CH1 +#define EXTMODULE_TIMER_IRQn TIM3_IRQn +#define EXTMODULE_TIMER_IRQHandler TIM3_IRQHandler +#define EXTMODULE_TIMER_FREQ (PERI1_FREQUENCY * TIMER_MULT_APB1) +#define EXTMODULE_TIMER_TX_GPIO_AF LL_GPIO_AF_2 + +//USART +#define EXTMODULE_USART USART6 +#define EXTMODULE_USART_TX_DMA DMA2 +#define EXTMODULE_USART_TX_DMA_CHANNEL LL_DMAMUX1_REQ_USART6_TX +#define EXTMODULE_USART_TX_DMA_STREAM LL_DMA_STREAM_6 +#define EXTMODULE_USART_RX_DMA_CHANNEL LL_DMAMUX1_REQ_USART6_RX +#define EXTMODULE_USART_RX_DMA_STREAM LL_DMA_STREAM_5 +#define EXTMODULE_USART_IRQHandler USART6_IRQHandler +#define EXTMODULE_USART_IRQn USART6_IRQn + +//TIMER +#define EXTMODULE_TIMER_DMA_CHANNEL LL_DMAMUX1_REQ_TIM3_UP +#define EXTMODULE_TIMER_DMA DMA2 +#define EXTMODULE_TIMER_DMA_STREAM LL_DMA_STREAM_3 +#define EXTMODULE_TIMER_DMA_STREAM_IRQn DMA2_Stream3_IRQn +#define EXTMODULE_TIMER_DMA_IRQHandler DMA2_Stream3_IRQHandler + +// Trainer Port +#define TRAINER_IN_GPIO GPIO_PIN(GPIOI, 6) // TIM8_CH2 +#define TRAINER_IN_TIMER_Channel LL_TIM_CHANNEL_CH2 + +#define TRAINER_OUT_GPIO GPIO_PIN(GPIOI, 7) // TIM8_CH3 +#define TRAINER_OUT_TIMER_Channel LL_TIM_CHANNEL_CH3 + +#define TRAINER_DETECT_GPIO GPIO_PIN(GPIOE, 2) // PE.02 + +#define TRAINER_TIMER TIM8 +#define TRAINER_TIMER_IRQn TIM8_CC_IRQn +#define TRAINER_TIMER_IRQHandler TIM8_CC_IRQHandler +#define TRAINER_GPIO_AF LL_GPIO_AF_3 +#define TRAINER_TIMER_FREQ (PERI2_FREQUENCY * TIMER_MULT_APB2) + +// Touch +#define TOUCH_I2C_BUS I2C_Bus_2 +#define TOUCH_RST_GPIO GPIO_PIN(GPIOJ, 1) // PJ.01 +#define TOUCH_INT_GPIO GPIO_PIN(GPIOD, 11) // PD.11 + +#define TOUCH_INT_EXTI_Line LL_EXTI_LINE_11 +#define TOUCH_INT_EXTI_Port LL_SYSCFG_EXTI_PORTD +#define TOUCH_INT_EXTI_SysCfgLine LL_SYSCFG_EXTI_LINE11 + +// TOUCH_INT_EXTI IRQ +#if !defined(USE_EXTI15_10_IRQ) +#define USE_EXTI15_10_IRQ +#define EXTI15_10_IRQ_Priority 9 +#endif + +#define LSE_DRIVE_STRENGTH RCC_LSEDRIVE_HIGH + +// Backlight +#define BACKLIGHT_GPIO GPIO_PIN(GPIOA, 5) // TIM2_CH1 +#define BACKLIGHT_TIMER TIM2 +#define BACKLIGHT_TIMER_CHANNEL LL_TIM_CHANNEL_CH1 +#define BACKLIGHT_GPIO_AF GPIO_AF1 +#define BACKLIGHT_TIMER_FREQ (PERI1_FREQUENCY * TIMER_MULT_APB1) + +// Rotary encoder +#define ROTARY_ENCODER_NAVIGATION +#define ROTARY_ENCODER_GPIO_A GPIOA +#define ROTARY_ENCODER_GPIO_PIN_A LL_GPIO_PIN_6 +#define ROTARY_ENCODER_GPIO_B GPIOA +#define ROTARY_ENCODER_GPIO_PIN_B LL_GPIO_PIN_7 +#define ROTARY_ENCODER_POSITION() (((ROTARY_ENCODER_GPIO_A->IDR >> 6) & 0x01)|((ROTARY_ENCODER_GPIO_B->IDR >> 6) & 0x02)) +#define ROTARY_ENCODER_EXTI_LINE1 LL_EXTI_LINE_6 +#define ROTARY_ENCODER_EXTI_LINE2 LL_EXTI_LINE_7 +#if !defined(USE_EXTI9_5_IRQ) + #define USE_EXTI9_5_IRQ + #define EXTI9_5_IRQ_Priority 9 +#endif +#define ROTARY_ENCODER_EXTI_PORT_A LL_SYSCFG_EXTI_PORTA +#define ROTARY_ENCODER_EXTI_PORT_B LL_SYSCFG_EXTI_PORTA +#define ROTARY_ENCODER_EXTI_SYS_LINE1 LL_SYSCFG_EXTI_LINE6 +#define ROTARY_ENCODER_EXTI_SYS_LINE2 LL_SYSCFG_EXTI_LINE7 +#define ROTARY_ENCODER_TIMER TIM17 +#define ROTARY_ENCODER_TIMER_IRQn TIM17_IRQn +#define ROTARY_ENCODER_TIMER_IRQHandler TIM17_IRQHandler + +// Millisecond timer +#define MS_TIMER TIM14 +#define MS_TIMER_IRQn TIM8_TRG_COM_TIM14_IRQn +#define MS_TIMER_IRQHandler TIM8_TRG_COM_TIM14_IRQHandler + +// Mixer scheduler +#define MIXER_SCHEDULER_TIMER TIM12 +#define MIXER_SCHEDULER_TIMER_FREQ (PERI1_FREQUENCY * TIMER_MULT_APB1) +#define MIXER_SCHEDULER_TIMER_IRQn TIM8_BRK_TIM12_IRQn +#define MIXER_SCHEDULER_TIMER_IRQHandler TIM8_BRK_TIM12_IRQHandler + +// Haptic +#define HAPTIC_PWM +#define HAPTIC_GPIO GPIO_PIN(GPIOE, 6) // TIM15_CH2 +#define HAPTIC_GPIO_TIMER TIM15 +#define HAPTIC_GPIO_AF GPIO_AF4 +#define HAPTIC_TIMER_OUTPUT_ENABLE TIM_CCER_CC2E | TIM_CCER_CC2NE; +#define HAPTIC_TIMER_MODE TIM_CCMR1_OC2M_1 | TIM_CCMR1_OC2M_2 | TIM_CCMR1_OC2PE +#define HAPTIC_TIMER_COMPARE_VALUE HAPTIC_GPIO_TIMER->CCR2 + +// LED Strip +#define LED_STRIP_LENGTH 7 // 6 CFS + 1 bling +#define BLING_LED_STRIP_START 6 +#define BLING_LED_STRIP_LENGTH 1 +#define CFS_LED_STRIP_START 0 +#define CFS_LED_STRIP_LENGTH 6 +#define CFS_LEDS_PER_SWITCH 1 +#define LED_STRIP_GPIO GPIO_PIN(GPIOA, 10) // TIM1_CH3 +#define LED_STRIP_GPIO_AF LL_GPIO_AF_1 +#define LED_STRIP_TIMER TIM1 +#define LED_STRIP_TIMER_FREQ (PERI1_FREQUENCY * TIMER_MULT_APB1) +#define LED_STRIP_TIMER_CHANNEL LL_TIM_CHANNEL_CH3 +#define LED_STRIP_TIMER_DMA DMA1 +#define LED_STRIP_TIMER_DMA_CHANNEL LL_DMAMUX1_REQ_TIM1_UP +#define LED_STRIP_TIMER_DMA_STREAM LL_DMA_STREAM_0 +#define LED_STRIP_TIMER_DMA_IRQn DMA1_Stream0_IRQn +#define LED_STRIP_TIMER_DMA_IRQHandler DMA1_Stream0_IRQHandler +#define LED_STRIP_REFRESH_PERIOD 50 //ms + +// Status LEDs +#define STATUS_LEDS +#define GPIO_LED_GPIO_ON gpio_set +#define GPIO_LED_GPIO_OFF gpio_clear +#define LED_RED_GPIO GPIO_PIN(GPIOH, 11) +#define LED_GREEN_GPIO GPIO_PIN(GPIOB, 13) +#define LED_BLUE_GPIO GPIO_PIN(GPIOB, 12) + +// LCD +#define LCD_W 480 +#define LCD_H 272 +#define LCD_PHYS_W LCD_W +#define LCD_PHYS_H LCD_H +#define LCD_DEPTH 16 +#define LTDC_IRQ_PRIO 4 +#define DMA_SCREEN_IRQ_PRIO 6 + +// Keys held together to toggle the keyboard lock +#define KEYS_LOCK_KEY1 KEY_PAGEDN +#define KEYS_LOCK_KEY2 KEY_ENTER + +#endif // _HAL_H_ diff --git a/radio/src/targets/t18h7/usb_descriptor.h b/radio/src/targets/t18h7/usb_descriptor.h new file mode 100644 index 00000000000..0c9d2f5c183 --- /dev/null +++ b/radio/src/targets/t18h7/usb_descriptor.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 + +#define USB_NAME "T18H7" +#define USB_MANUFACTURER 'J', 'U', 'M', 'P', 'E', 'R', ' ', ' ' /* 8 bytes */ +#define USB_PRODUCT 'T', '1', '8', 'D', 'u', 'o', ' ', ' ' /* 8 Bytes */ diff --git a/radio/util/hw_defs/legacy_names.py b/radio/util/hw_defs/legacy_names.py index 82a1bb72d49..744e5a0f4ea 100644 --- a/radio/util/hw_defs/legacy_names.py +++ b/radio/util/hw_defs/legacy_names.py @@ -389,6 +389,59 @@ } } }, + { + "targets": {"t18h7"}, + "inputs": { + "LH": { + "yaml": "Rud", + "lua": "rud", + "description": "Rudder" + }, + "LV": { + "yaml": "Ele", + "lua": "ele", + "description": "Elevator" + }, + "RV": { + "yaml": "Thr", + "lua": "thr", + "description": "Throttle" + }, + "RH": { + "yaml": "Ail", + "lua": "ail", + "description": "Aileron" + }, + "P1": { + "yaml": "S1", + "lua": "s1", + "label": "S1", + "short_label": "1", + "description": "Potentiometer S1" + }, + "P2": { + "yaml": "S2", + "lua": "s2", + "label": "S2", + "short_label": "2", + "description": "Potentiometer S2" + }, + "P3": { + "yaml": "S3", + "lua": "s3", + "label": "S3", + "short_label": "3", + "description": "Potentiometer S3" + }, + "P4": { + "yaml": "S4", + "lua": "s4", + "label": "S4", + "short_label": "4", + "description": "Potentiometer S4" + } + } + }, { "targets": {"x12s"}, "inputs": { diff --git a/radio/util/hw_defs/pot_config.py b/radio/util/hw_defs/pot_config.py index 815ab4439ac..d3fedb305a4 100644 --- a/radio/util/hw_defs/pot_config.py +++ b/radio/util/hw_defs/pot_config.py @@ -175,6 +175,12 @@ "P1": {"default": "POT_CENTER"}, "P2": {"default": "POT_CENTER"}, }, + "t18h7": { + "P1": {"default": "POT"}, + "P2": {"default": "POT"}, + "P3": {"default": "POT"}, + "P4": {"default": "POT"}, + }, "gx15": { "P1": {"default": "POT_CENTER"}, "P2": {"default": "POT_CENTER"}, diff --git a/radio/util/hw_defs/switch_config.py b/radio/util/hw_defs/switch_config.py index 175441bdcce..3f328e4db9d 100644 --- a/radio/util/hw_defs/switch_config.py +++ b/radio/util/hw_defs/switch_config.py @@ -431,6 +431,23 @@ "SK": {"default": "2POS"}, "SL": {"default": "2POS"}, }, + "t18h7": { + "SA": {"default": "3POS"}, + "SB": {"default": "3POS"}, + "SC": {"default": "3POS"}, + "SD": {"default": "3POS"}, + "SE": {"default": "3POS"}, + "SF": {"default": "2POS"}, + "SG": {"default": "3POS"}, + "SH": {"default": "2POS"}, + # custom switches + "SI": {"default": "2POS"}, + "SJ": {"default": "2POS"}, + "SK": {"default": "2POS"}, + "SL": {"default": "2POS"}, + "SM": {"default": "2POS"}, + "SN": {"default": "2POS"}, + }, "t22": { "SA": {"default": "2POS"}, "SB": {"default": "2POS"}, diff --git a/tools/build-common.sh b/tools/build-common.sh index 872d1defba3..45ce33adf55 100644 --- a/tools/build-common.sh +++ b/tools/build-common.sh @@ -122,6 +122,9 @@ get_target_build_options() { t15h7) BUILD_OPTIONS+="-DPCB=T15H7" ;; + t18h7) + BUILD_OPTIONS+="-DPCB=T18H7" + ;; t22) BUILD_OPTIONS+="-DPCB=T22" ;; diff --git a/tools/build-companion.sh b/tools/build-companion.sh index fac1e1d7e77..4ba9a9d0b32 100755 --- a/tools/build-companion.sh +++ b/tools/build-companion.sh @@ -232,7 +232,7 @@ build_plugin() { declare -a simulator_plugins=( x9lite x9lites x9d x9dp x9dp2019 x9e x7 x7access - t8 t12 t12max tx12 tx12mk2 t15 t15pro t15h7 t22 t16 t18 t20 t20v2 + t8 t12 t12max tx12 tx12mk2 t15 t15pro t15h7 t18h7 t22 t16 t18 t20 t20v2 xlite xlites x10 x10express x12s zorro tx16s tx16smk3 tx15 gx15 diff --git a/tools/generate-hw-defs.sh b/tools/generate-hw-defs.sh index 50f5b169933..afadd827c05 100755 --- a/tools/generate-hw-defs.sh +++ b/tools/generate-hw-defs.sh @@ -9,7 +9,7 @@ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" : "${SRCDIR:=$(dirname "$(pwd)/$0")/..}" -: ${FLAVOR:="nv14;el18;pl18;pl18ev;nb4p;st16;c14;t12;t12max;t15;t15pro;t15h7;t22;t16;t18;t8;zorro;pocket;commando8;tlite;tpro;tprov2;tpros;bumblebee;t20;t20v2;t14;lr3pro;mt12;gx12;tx12;tx12mk2;boxer;tx16s;tx16smk3;x10;x10express;x12s;x7;x7access;x9d;x9dp;x9dp2019;x9e;x9lite;x9lites;xlite;xlites;f16;v16;v14;v14lcd;v12;tx15;gx15;h17"} +: ${FLAVOR:="nv14;el18;pl18;pl18ev;nb4p;st16;c14;t12;t12max;t15;t15pro;t15h7;t18h7;t22;t16;t18;t8;zorro;pocket;commando8;tlite;tpro;tprov2;tpros;bumblebee;t20;t20v2;t14;lr3pro;mt12;gx12;tx12;tx12mk2;boxer;tx16s;tx16smk3;x10;x10express;x12s;x7;x7access;x9d;x9dp;x9dp2019;x9e;x9lite;x9lites;xlite;xlites;f16;v16;v14;v14lcd;v12;tx15;gx15;h17"} : ${COMMON_OPTIONS:="-DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_RULE_MESSAGES=OFF -Wno-dev -DCMAKE_MESSAGE_LOG_LEVEL=WARNING"} # wipe build directory clean diff --git a/tools/generate-yaml.sh b/tools/generate-yaml.sh index 18b9b73388a..65bcea83d53 100755 --- a/tools/generate-yaml.sh +++ b/tools/generate-yaml.sh @@ -11,7 +11,7 @@ if [[ -n ${GCC_ARM} ]] ; then export PATH=${GCC_ARM}:$PATH fi -: ${FLAVOR:="x10;t15;pl18;nv14;pl18u;nb4p;v12;x9d;x9dp2019;x9e;xlite;xlites;x7;tpro;t20;f16;gx12;st16;c14;pa01;tx15;t15pro;t15h7;tx16smk3;t22;gx15;h17"} +: ${FLAVOR:="x10;t15;pl18;nv14;pl18u;nb4p;v12;x9d;x9dp2019;x9e;xlite;xlites;x7;tpro;t20;f16;gx12;st16;c14;pa01;tx15;t15pro;t15h7;t18h7;tx16smk3;t22;gx15;h17"} : ${SRCDIR:="$(dirname "$SCRIPT_DIR")"} : ${COMMON_OPTIONS:="-DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_RULE_MESSAGES=OFF -Wno-dev -DDISABLE_COMPANION=YES -DCMAKE_MESSAGE_LOG_LEVEL=WARNING"} From 5b678e85aba30cf7330eba2c0aa869d467410d5f Mon Sep 17 00:00:00 2001 From: Peter Feerick <5500713+pfeerick@users.noreply.github.com> Date: Sun, 11 Oct 2026 04:59:32 +0000 Subject: [PATCH 2/6] fix(t18h7): add to Horus/T16 family, enable rotary encoder, fix USB product - Companion: include T18H7 in IS_FAMILY_HORUS_OR_T16 (as T15H7 is) so it is treated as a colour radio throughout, rather than special-casing only the LCD dimensions; exclude it from the TILT input fixup as it has no IMU - Companion: enable RotaryEncoderNavigation for T18H7 - USB product string was copied from T18 Duo; report "T18H7" as on main Co-Authored-By: Claude Opus 5.5 --- companion/src/firmwares/boardjson.cpp | 4 ++-- companion/src/firmwares/boards.cpp | 6 +++--- companion/src/firmwares/boards.h | 2 +- companion/src/firmwares/opentx/opentxinterface.cpp | 2 +- radio/src/targets/t18h7/usb_descriptor.h | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/companion/src/firmwares/boardjson.cpp b/companion/src/firmwares/boardjson.cpp index c1d1846340e..863ab3d0ef8 100644 --- a/companion/src/firmwares/boardjson.cpp +++ b/companion/src/firmwares/boardjson.cpp @@ -89,11 +89,11 @@ void BoardJson::afterLoadFixups(Board::Type board, InputsTable * inputs, Switche { // TODO json files do not contain gyro defs // Radio cmake directive IMU is currently used - // H17 has no IMU + // H17 and T18H7 have no IMU if ((IS_TARANIS_XLITES(board) || IS_FAMILY_HORUS_OR_T16(board) || IS_RADIOMASTER_TX15(board) || IS_RADIOMASTER_TX16SMK3(board) || IS_FLYSKY_PA01(board)) && - !IS_SENDUWING_H17(board)) { + !IS_SENDUWING_H17(board) && !IS_JUMPER_T18H7(board)) { if (getInputIndex(inputs, "TILT_X", Board::LVT_TAG) < 0) { InputDefn defn; defn.type = AIT_FLEX; diff --git a/companion/src/firmwares/boards.cpp b/companion/src/firmwares/boards.cpp index 14a35b3071e..55665880d4d 100644 --- a/companion/src/firmwares/boards.cpp +++ b/companion/src/firmwares/boards.cpp @@ -444,7 +444,7 @@ int Boards::getCapability(Board::Type board, Board::Capability capability) IS_HELLORADIOSKY_V14(board); case LcdDepth: - if (IS_FAMILY_HORUS_OR_T16(board) || IS_JUMPER_T18H7(board)) + if (IS_FAMILY_HORUS_OR_T16(board)) return 16; else if (IS_TARANIS_SMALL(board)) return 1; @@ -460,7 +460,7 @@ int Boards::getCapability(Board::Type board, Board::Capability capability) return 320; else if (IS_FLYSKY_PA01(board) || IS_HELLORADIOSKY_V12(board)) return 240; - else if (IS_FAMILY_HORUS_OR_T16(board) || IS_JUMPER_T18H7(board)) + else if (IS_FAMILY_HORUS_OR_T16(board)) return 272; else return 64; @@ -470,7 +470,7 @@ int Boards::getCapability(Board::Type board, Board::Capability capability) return 800; else if (IS_FLYSKY_NV14(board) || IS_FLYSKY_EL18(board) || IS_FLYSKY_PA01(board) || IS_HELLORADIOSKY_V12(board)) return 320; - else if (IS_FAMILY_HORUS_OR_T16(board) || IS_JUMPER_T18H7(board) || IS_RADIOMASTER_TX15(board) || IS_FAMILY_PL18(board) || IS_FLYSKY_ST16(board)) + else if (IS_FAMILY_HORUS_OR_T16(board) || IS_RADIOMASTER_TX15(board) || IS_FAMILY_PL18(board) || IS_FLYSKY_ST16(board)) return 480; else if (IS_TARANIS(board) && !IS_TARANIS_SMALL(board)) return 212; diff --git a/companion/src/firmwares/boards.h b/companion/src/firmwares/boards.h index 13416070249..742b6029534 100644 --- a/companion/src/firmwares/boards.h +++ b/companion/src/firmwares/boards.h @@ -854,7 +854,7 @@ inline bool IS_FAMILY_HORUS_OR_T16(Board::Type board) IS_FLYSKY_NV14(board)/*generally*/ || IS_FLYSKY_EL18(board)/*generally*/ || IS_FAMILY_PL18(board) || IS_FLYSKY_ST16(board)/*generally*/ || IS_FLYSKY_PA01(board)/*generally*/ || IS_IFLIGHT_C14(board) || IS_SENDUWING_H17(board)/*generally*/ - || IS_JUMPER_T15PRO(board) || IS_JUMPER_T15H7(board); + || IS_JUMPER_T15PRO(board) || IS_JUMPER_T15H7(board) || IS_JUMPER_T18H7(board); } inline bool IS_HORUS_OR_TARANIS(Board::Type board) diff --git a/companion/src/firmwares/opentx/opentxinterface.cpp b/companion/src/firmwares/opentx/opentxinterface.cpp index f90feefa6a7..16e301a4bdf 100644 --- a/companion/src/firmwares/opentx/opentxinterface.cpp +++ b/companion/src/firmwares/opentx/opentxinterface.cpp @@ -333,7 +333,7 @@ int OpenTxFirmware::getCapability(::Capability capability) IS_RADIOMASTER_BOXER(board) || IS_RADIOMASTER_GX12(board) || IS_RADIOMASTER_MT12(board) || IS_RADIOMASTER_POCKET(board) || IS_RADIOMASTER_TX12(board) || IS_RADIOMASTER_TX12_MK2(board) || IS_RADIOMASTER_TX16S(board) || IS_RADIOMASTER_ZORRO(board) || IS_RADIOMASTER_TX15(board) || IS_JUMPER_T15PRO(board) || - IS_JUMPER_T15H7(board) || + IS_JUMPER_T15H7(board) || IS_JUMPER_T18H7(board) || IS_FLYSKY_PA01(board) || IS_FLYSKY_ST16(board) || IS_RADIOMASTER_TX16SMK3(board) || IS_JUMPER_T22(board)) || IS_RADIOMASTER_GX15(board) || IS_SENDUWING_H17(board); diff --git a/radio/src/targets/t18h7/usb_descriptor.h b/radio/src/targets/t18h7/usb_descriptor.h index 0c9d2f5c183..aa3ff521e69 100644 --- a/radio/src/targets/t18h7/usb_descriptor.h +++ b/radio/src/targets/t18h7/usb_descriptor.h @@ -23,4 +23,4 @@ #define USB_NAME "T18H7" #define USB_MANUFACTURER 'J', 'U', 'M', 'P', 'E', 'R', ' ', ' ' /* 8 bytes */ -#define USB_PRODUCT 'T', '1', '8', 'D', 'u', 'o', ' ', ' ' /* 8 Bytes */ +#define USB_PRODUCT 'T', '1', '8', 'H', '7', ' ', ' ', ' ' /* 8 Bytes */ From 9c7378552f2f9e780e1915f7606fa5357e83a5f4 Mon Sep 17 00:00:00 2001 From: Peter Feerick <5500713+pfeerick@users.noreply.github.com> Date: Sun, 11 Oct 2026 08:54:49 +0000 Subject: [PATCH 3/6] chore(t18h7): remove unused LCD globals and fix resource map comment - lcd_driver_480x272: drop the unused lcdInit/Off/OnFunction pointers (never set, and all callers are commented out) and TouchControllerType - hal.h: the resource map was copied from T15H7; T18H7 has no FlySky hall gimbal DMA, DGONE or Bluetooth UART Co-Authored-By: Claude Opus 5.5 --- radio/src/boards/jumper-h750/lcd_driver_480x272.cpp | 8 -------- radio/src/boards/jumper-h750/lcd_driver_480x272.h | 6 ------ radio/src/targets/t18h7/hal.h | 4 +--- 3 files changed, 1 insertion(+), 17 deletions(-) diff --git a/radio/src/boards/jumper-h750/lcd_driver_480x272.cpp b/radio/src/boards/jumper-h750/lcd_driver_480x272.cpp index 6fc54383ed1..a12bc351c2f 100644 --- a/radio/src/boards/jumper-h750/lcd_driver_480x272.cpp +++ b/radio/src/boards/jumper-h750/lcd_driver_480x272.cpp @@ -33,8 +33,6 @@ #include "hal/gpio.h" #include "stm32_gpio.h" -uint8_t TouchControllerType = 0; // 0: other; 1: CST836U - static const uint16_t lcd_phys_w = LCD_PHYS_W; static const uint16_t lcd_phys_h = LCD_PHYS_H; @@ -58,12 +56,6 @@ static void startLcdRefresh(lv_disp_drv_t *disp_drv, uint16_t *buffer, __HAL_LTDC_ENABLE_IT(&hltdc, LTDC_IT_LI); } -// The panel needs no SPI init sequence, but these are referenced by the -// backlight driver, so keep them defined and unused. -lcdSpiInitFucPtr lcdInitFunction; -lcdSpiInitFucPtr lcdOffFunction; -lcdSpiInitFucPtr lcdOnFunction; - static void LCD_AF_GPIOConfig(void) { const gpio_t _lcd_af_gpios[] = { diff --git a/radio/src/boards/jumper-h750/lcd_driver_480x272.h b/radio/src/boards/jumper-h750/lcd_driver_480x272.h index dfb9517b74b..2c6c30f66c0 100644 --- a/radio/src/boards/jumper-h750/lcd_driver_480x272.h +++ b/radio/src/boards/jumper-h750/lcd_driver_480x272.h @@ -33,11 +33,5 @@ #define HFP ( 8 ) #define VFP ( 8 ) -typedef void (*lcdSpiInitFucPtr)(void); - -extern lcdSpiInitFucPtr lcdInitFunction; -extern lcdSpiInitFucPtr lcdOffFunction; -extern lcdSpiInitFucPtr lcdOnFunction; - #define LCD_NRST_HIGH() LL_GPIO_SetOutputPin(LCD_NRST_GPIO, LCD_NRST_GPIO_PIN) #define LCD_NRST_LOW() LL_GPIO_ResetOutputPin(LCD_NRST_GPIO, LCD_NRST_GPIO_PIN) diff --git a/radio/src/targets/t18h7/hal.h b/radio/src/targets/t18h7/hal.h index 450ea9965a8..a6c03d794cd 100644 --- a/radio/src/targets/t18h7/hal.h +++ b/radio/src/targets/t18h7/hal.h @@ -24,7 +24,7 @@ STM32H750 DMA1 Stream0: LED_STRIP_TIMER_DMA_STREAM Stream1: INTMODULE_DMA_STREAM -Stream2: FLYSKY_HALL_DMA_Stream_RX +Stream2: Stream3: TELEMETRY_DMA_Stream_RX Stream4: Stream5: INTMODULE_RX_DMA_STREAM @@ -58,8 +58,6 @@ TIM17: ROTARY_ENCODER_TIMER USARTS USART1: INTMODULE_USART USART2: TELEMETRY_USART -USART3: DGONE -USART4: BT MODULE USART6: EXTMODULE_USART */ From 6b385964f22f09ff752e83e936a2b271ec5b8d14 Mon Sep 17 00:00:00 2001 From: Peter Feerick <5500713+pfeerick@users.noreply.github.com> Date: Sun, 11 Oct 2026 09:04:14 +0000 Subject: [PATCH 4/6] fix(t18h7): SH defaults to toggle SH is a momentary switch, as on the T18. Co-Authored-By: Claude Opus 5.5 --- radio/util/hw_defs/switch_config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/radio/util/hw_defs/switch_config.py b/radio/util/hw_defs/switch_config.py index 3f328e4db9d..14cf86c0851 100644 --- a/radio/util/hw_defs/switch_config.py +++ b/radio/util/hw_defs/switch_config.py @@ -439,7 +439,7 @@ "SE": {"default": "3POS"}, "SF": {"default": "2POS"}, "SG": {"default": "3POS"}, - "SH": {"default": "2POS"}, + "SH": {"default": "TOGGLE"}, # custom switches "SI": {"default": "2POS"}, "SJ": {"default": "2POS"}, From 3c25fc613722833fc99d2b44e781e6366d6dab9e Mon Sep 17 00:00:00 2001 From: Peter Feerick <5500713+pfeerick@users.noreply.github.com> Date: Mon, 12 Oct 2026 02:56:51 +0000 Subject: [PATCH 5/6] fix(t18h7): use the T18H7 battery voltage divider (499k/160k) The T18H7 shares the jumper-h750 board header with the T15H7 but has a different VBAT divider, so the battery read ~27% high. Co-Authored-By: Claude Opus 5.5 --- radio/src/boards/jumper-h750/board.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/radio/src/boards/jumper-h750/board.h b/radio/src/boards/jumper-h750/board.h index 354d4bbd9b6..794a6314f56 100644 --- a/radio/src/boards/jumper-h750/board.h +++ b/radio/src/boards/jumper-h750/board.h @@ -124,8 +124,13 @@ void EXTERNAL_MODULE_OFF(); // --- MOSFET ---- R1 --- MCU // |__ R2 --- GND // +#if defined(RADIO_T18H7) +#define VBAT_DIV_R1 499 // kOhms +#define VBAT_DIV_R2 160 // kOhms +#else #define VBAT_DIV_R1 680 // kOhms #define VBAT_DIV_R2 158 // kOhms +#endif #define VBAT_MOSFET_DROP 0 // * 10mV // #define BATTERY_DIVIDER 1211 // = 2047 * 165k / (165k + 680k) * 10 / 3.3V From 1785dcec2ba83bf0781e7b9e85dcb0f5ba98b6a7 Mon Sep 17 00:00:00 2001 From: Peter Feerick <5500713+pfeerick@users.noreply.github.com> Date: Mon, 12 Oct 2026 09:40:31 +0000 Subject: [PATCH 6/6] fix(t18h7): run backlight PWM at 10kHz The backlight timer was counting at 10kHz with a reload of 100, giving a ~100Hz PWM. At that rate the backlight driver shuts off below ~35% brightness. Use 10kHz PWM as on the T18, which has the same type of panel. Co-Authored-By: Claude Opus 5.5 --- radio/src/boards/jumper-h750/backlight_driver.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/radio/src/boards/jumper-h750/backlight_driver.cpp b/radio/src/boards/jumper-h750/backlight_driver.cpp index b87dc4a2656..20767e1e765 100644 --- a/radio/src/boards/jumper-h750/backlight_driver.cpp +++ b/radio/src/boards/jumper-h750/backlight_driver.cpp @@ -51,7 +51,13 @@ void backlightLowInit() void backlightInit() { +#if defined(RADIO_T18H7) + // 10kHz PWM as on the T18: at 100Hz the backlight driver shuts off + // at low duty cycles + stm32_pulse_init(&_bl_timer, 1000000); +#else stm32_pulse_init(&_bl_timer, 10000); +#endif stm32_pulse_config_output(&_bl_timer, true, LL_TIM_OCMODE_PWM1, 100); LL_TIM_SetAutoReload(_bl_timer.TIMx, 100); LL_TIM_EnableCounter(_bl_timer.TIMx);