From e89a4414ac7580e5463c97c0468edb426eedadc5 Mon Sep 17 00:00:00 2001 From: richardclli Date: Sun, 17 Aug 2025 18:13:43 +0800 Subject: [PATCH] feat: Flysky PA01 support (#6392) Co-authored-by: Malte Langermann Co-authored-by: philmoz Co-authored-by: 3djc <3djc@gh.com> Co-authored-by: raphaelcoeffic <1050031+raphaelcoeffic@users.noreply.github.com> Co-authored-by: xlong <984929678@qq.com> Co-authored-by: Peter Feerick --- .github/workflows/actions.yml | 1 + .github/workflows/nightly.yml | 1 + companion/src/firmwares/boards.cpp | 20 +- companion/src/firmwares/boards.h | 8 +- .../src/firmwares/opentx/opentxinterface.cpp | 6 + fw.json | 1 + radio/src/CMakeLists.txt | 4 +- .../src/boards/generic_stm32/module_ports.cpp | 8 +- radio/src/boards/generic_stm32/switches.cpp | 1 + radio/src/datastructs.h | 8 +- radio/src/drivers/aw9523b.cpp | 124 +++ radio/src/drivers/aw9523b.h | 55 + radio/src/fonts/CMakeLists.txt | 1 + radio/src/gui/colorlcd/libui/tabsgroup.cpp | 3 - radio/src/storage/yaml/CMakeLists.txt | 2 + radio/src/storage/yaml/yaml_datastructs.cpp | 2 + .../storage/yaml/yaml_datastructs_pa01.cpp | 985 ++++++++++++++++++ radio/src/targets/pa01/CMakeLists.txt | 188 ++++ radio/src/targets/pa01/backlight_driver.cpp | 94 ++ radio/src/targets/pa01/battery_driver.cpp | 677 ++++++++++++ radio/src/targets/pa01/battery_driver.h | 55 + radio/src/targets/pa01/board.cpp | 379 +++++++ radio/src/targets/pa01/board.h | 295 ++++++ radio/src/targets/pa01/bsp_io.cpp | 90 ++ radio/src/targets/pa01/bsp_io.h | 55 + radio/src/targets/pa01/extflash_driver.cpp | 154 +++ radio/src/targets/pa01/extflash_driver.h | 33 + radio/src/targets/pa01/extmodule_helper.cpp | 49 + radio/src/targets/pa01/hal.h | 498 +++++++++ radio/src/targets/pa01/haptic_driver.cpp | 60 ++ radio/src/targets/pa01/key_driver.cpp | 204 ++++ radio/src/targets/pa01/lcd_driver.cpp | 333 ++++++ radio/src/targets/pa01/lcd_driver.h | 42 + radio/src/targets/pa01/led_driver.cpp | 127 +++ radio/src/targets/pa01/libopenui_config.h | 27 + radio/src/targets/pa01/sdram_driver.cpp | 279 +++++ radio/src/targets/pa01/system_clock.c | 116 +++ radio/src/targets/pa01/system_clock.h | 23 + radio/src/targets/pa01/usb_descriptor.h | 29 + radio/util/hw_defs/legacy_names.py | 23 + radio/util/hw_defs/pot_config.py | 4 + radio/util/hw_defs/switch_config.py | 13 + tools/build-common.sh | 3 + tools/build-companion.sh | 2 +- tools/generate-yaml.sh | 2 +- 45 files changed, 5067 insertions(+), 17 deletions(-) create mode 100644 radio/src/drivers/aw9523b.cpp create mode 100644 radio/src/drivers/aw9523b.h create mode 100644 radio/src/storage/yaml/yaml_datastructs_pa01.cpp create mode 100644 radio/src/targets/pa01/CMakeLists.txt create mode 100644 radio/src/targets/pa01/backlight_driver.cpp create mode 100644 radio/src/targets/pa01/battery_driver.cpp create mode 100644 radio/src/targets/pa01/battery_driver.h create mode 100644 radio/src/targets/pa01/board.cpp create mode 100644 radio/src/targets/pa01/board.h create mode 100644 radio/src/targets/pa01/bsp_io.cpp create mode 100644 radio/src/targets/pa01/bsp_io.h create mode 100644 radio/src/targets/pa01/extflash_driver.cpp create mode 100644 radio/src/targets/pa01/extflash_driver.h create mode 100644 radio/src/targets/pa01/extmodule_helper.cpp create mode 100644 radio/src/targets/pa01/hal.h create mode 100644 radio/src/targets/pa01/haptic_driver.cpp create mode 100644 radio/src/targets/pa01/key_driver.cpp create mode 100644 radio/src/targets/pa01/lcd_driver.cpp create mode 100644 radio/src/targets/pa01/lcd_driver.h create mode 100644 radio/src/targets/pa01/led_driver.cpp create mode 100644 radio/src/targets/pa01/libopenui_config.h create mode 100644 radio/src/targets/pa01/sdram_driver.cpp create mode 100644 radio/src/targets/pa01/system_clock.c create mode 100644 radio/src/targets/pa01/system_clock.h create mode 100644 radio/src/targets/pa01/usb_descriptor.h diff --git a/.github/workflows/actions.yml b/.github/workflows/actions.yml index 560a89797..28110226c 100644 --- a/.github/workflows/actions.yml +++ b/.github/workflows/actions.yml @@ -92,6 +92,7 @@ jobs: target: - nv14;el18 - pl18;pl18ev;pl18u + - pa01 - t12max - t15;t16;t18 - zorro;pocket;mt12;commando8 diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 53f25888f..a6d6beda8 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -18,6 +18,7 @@ jobs: target: - nv14;el18 - pl18;pl18ev;pl18u + - pa01 - t12max - t15;t16;t18 - zorro;pocket;mt12;commando8 diff --git a/companion/src/firmwares/boards.cpp b/companion/src/firmwares/boards.cpp index 9cad3a025..7c9632238 100644 --- a/companion/src/firmwares/boards.cpp +++ b/companion/src/firmwares/boards.cpp @@ -152,6 +152,8 @@ uint32_t Boards::getFourCC(Type board) case BOARD_FLYSKY_PL18EV: case BOARD_FLYSKY_PL18U: return 0x4878746F; + case BOARD_FLYSKY_PA01: + return 0x4A78746F; case BOARD_FLYSKY_ST16: return 0x4C78746F; case BOARD_HELLORADIOSKY_V14: @@ -210,6 +212,7 @@ int Boards::getEEpromSize(Board::Type board) case BOARD_RADIOMASTER_TX16S: case BOARD_FLYSKY_NV14: case BOARD_FLYSKY_EL18: + case BOARD_FLYSKY_PA01: case BOARD_FLYSKY_PL18: case BOARD_FLYSKY_PL18EV: case BOARD_FLYSKY_PL18U: @@ -268,10 +271,11 @@ int Boards::getFlashSize(Type board) case BOARD_RADIOMASTER_TX16S: case BOARD_FLYSKY_NV14: case BOARD_FLYSKY_EL18: + case BOARD_FLYSKY_PA01: // 8MB SDRAM case BOARD_FLYSKY_PL18: case BOARD_FLYSKY_PL18EV: case BOARD_FLYSKY_PL18U: - case BOARD_FLYSKY_ST16: + case BOARD_FLYSKY_ST16: // 8MB SDRAM case BOARD_FATFISH_F16: case BOARD_HELLORADIOSKY_V16: return FSIZE_2MB; @@ -378,13 +382,15 @@ int Boards::getCapability(Board::Type board, Board::Capability capability) return 480; else if (IS_FAMILY_PL18(board) || IS_JUMPER_T15(board) || IS_FLYSKY_ST16(board)) return 320; + else if (IS_FLYSKY_PA01(board)) + return 240; else if (IS_FAMILY_HORUS_OR_T16(board)) return 272; else return 64; case LcdWidth: - if (IS_FLYSKY_NV14(board) || IS_FLYSKY_EL18(board)) + if (IS_FLYSKY_NV14(board) || IS_FLYSKY_EL18(board) || IS_FLYSKY_PA01(board)) return 320; else if (IS_FAMILY_PL18(board) || IS_FLYSKY_ST16(board)) return 480; @@ -412,7 +418,7 @@ int Boards::getCapability(Board::Type board, Board::Capability capability) return IS_RADIOMASTER_MT12(board); case FunctionSwitchColors: - return IS_RADIOMASTER_GX12(board) || IS_FLYSKY_ST16(board); + return IS_RADIOMASTER_GX12(board) || IS_FLYSKY_ST16(board) || IS_FLYSKY_PA01(board); default: return getBoardJson(board)->getCapability(capability); @@ -650,6 +656,8 @@ QString Boards::getBoardName(Board::Type board) return "FlySky NV14"; case BOARD_FLYSKY_EL18: return "FlySky EL18"; + case BOARD_FLYSKY_PA01: + return "FlySky PA01"; case BOARD_FLYSKY_PL18: return "FlySky PL18"; case BOARD_FLYSKY_PL18EV: @@ -768,7 +776,6 @@ int Boards::getDefaultInternalModules(Board::Type board) case BOARD_JUMPER_TPROV2: case BOARD_FLYSKY_PL18: case BOARD_FLYSKY_PL18EV: - case BOARD_FLYSKY_ST16: return (int)MODULE_TYPE_MULTIMODULE; case BOARD_BETAFPV_LR3PRO: @@ -796,6 +803,8 @@ int Boards::getDefaultInternalModules(Board::Type board) case BOARD_FLYSKY_EL18: case BOARD_FLYSKY_PL18U: + case BOARD_FLYSKY_PA01: // ANT + case BOARD_FLYSKY_ST16: // ANT return (int)MODULE_TYPE_FLYSKY_AFHDS3; default: @@ -861,7 +870,8 @@ void Boards::getBattRange(Board::Type board, int& vmin, int& vmax, unsigned int& BR(35, 43, 37) break; case BOARD_FLYSKY_ST16: - BR(70, 86,80) + case BOARD_FLYSKY_PA01: + BR(70, 86, 80) break; case BOARD_IFLIGHT_COMMANDO8: BR(30, 42, 32) diff --git a/companion/src/firmwares/boards.h b/companion/src/firmwares/boards.h index 96927e17f..63bc75a50 100644 --- a/companion/src/firmwares/boards.h +++ b/companion/src/firmwares/boards.h @@ -74,6 +74,7 @@ namespace Board { BOARD_JUMPER_TLITE, BOARD_JUMPER_TLITE_F4, BOARD_FLYSKY_NV14, + BOARD_FLYSKY_PA01, BOARD_FLYSKY_PL18, BOARD_FLYSKY_PL18EV, BOARD_FLYSKY_PL18U, @@ -661,6 +662,11 @@ inline bool IS_FLYSKY_EL18(Board::Type board) return (board == Board::BOARD_FLYSKY_EL18); } +inline bool IS_FLYSKY_PA01(Board::Type board) +{ + return (board == Board::BOARD_FLYSKY_PA01); +} + inline bool IS_FLYSKY_PL18(Board::Type board) { return (board == Board::BOARD_FLYSKY_PL18); @@ -765,7 +771,7 @@ inline bool IS_FAMILY_HORUS_OR_T16(Board::Type board) { return IS_FAMILY_HORUS(board) || IS_FAMILY_T16(board) || IS_FLYSKY_NV14(board)/*generally*/ || IS_FLYSKY_EL18(board)/*generally*/ - || IS_FAMILY_PL18(board) || IS_FLYSKY_ST16(board)/*generally*/; + || IS_FAMILY_PL18(board) || IS_FLYSKY_ST16(board)/*generally*/ || IS_FLYSKY_PA01(board)/*generally*/; } 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 f99c709b1..dc4f32119 100644 --- a/companion/src/firmwares/opentx/opentxinterface.cpp +++ b/companion/src/firmwares/opentx/opentxinterface.cpp @@ -496,6 +496,12 @@ void registerOpenTxFirmwares() addOpenTxRfOptions(firmware, FLEX + AFHDS2A + AFHDS3); registerOpenTxFirmware(firmware); + /* FlySky PA01 board */ + firmware = new OpenTxFirmware(FIRMWAREID("pa01"), Firmware::tr("FlySky PA01"), BOARD_FLYSKY_PA01); + addOpenTxFrskyOptions(firmware); + addOpenTxRfOptions(firmware, FLEX + AFHDS3); + registerOpenTxFirmware(firmware); + /* FlySky PL18 board */ firmware = new OpenTxFirmware(FIRMWAREID("pl18"), Firmware::tr("FlySky PL18"), BOARD_FLYSKY_PL18); addOpenTxFrskyOptions(firmware); diff --git a/fw.json b/fw.json index b21ca7276..5fb7dcaeb 100644 --- a/fw.json +++ b/fw.json @@ -3,6 +3,7 @@ ["Fatfish F16","f16-"], ["Flysky EL18", "el18-"], ["Flysky NV14", "nv14-"], + ["Flysky PA01", "pa01-"], ["Flysky PL18", "pl18-"], ["Flysky PL18EV", "pl18ev-"], ["Flysky PL18U", "pl18u-"], diff --git a/radio/src/CMakeLists.txt b/radio/src/CMakeLists.txt index ed36c9e3e..dcb9355c0 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 NV14 PL18 ST16) +set(PCB_TYPES X9LITE X9LITES X7 XLITE XLITES X9D X9D+ X9E X10 X12S NV14 PL18 ST16 PA01) 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 FR HE HU IT JP KO NL PL PT RU SE SK UA) @@ -88,6 +88,8 @@ elseif(PCB STREQUAL PL18) include(targets/pl18/CMakeLists.txt) elseif(PCB STREQUAL ST16) include(targets/st16/CMakeLists.txt) +elseif(PCB STREQUAL PA01) + include(targets/pa01/CMakeLists.txt) elseif(PCB STREQUAL STM32H7S78_DK) include(targets/stm32h7s78-dk/CMakeLists.txt) elseif(PCB STREQUAL X9E OR PCB STREQUAL X9D+ OR PCB STREQUAL X9D OR PCB STREQUAL X7 OR PCB STREQUAL X9LITE OR PCB STREQUAL X9LITES OR PCB STREQUAL XLITE OR PCB STREQUAL XLITES) diff --git a/radio/src/boards/generic_stm32/module_ports.cpp b/radio/src/boards/generic_stm32/module_ports.cpp index de2f72839..2be636284 100644 --- a/radio/src/boards/generic_stm32/module_ports.cpp +++ b/radio/src/boards/generic_stm32/module_ports.cpp @@ -393,15 +393,19 @@ static void _internal_module_set_pwr(uint8_t enable) } } -#if defined(INTMODULE_BOOTCMD_GPIO) +#if defined(INTMODULE_BOOTCMD_GPIO) || defined(INTMODULE_BOOTCMD_BSP) static void _internal_module_set_bootcmd(uint8_t enable) { +#if defined(INTMODULE_BOOTCMD_BSP) + INTERNAL_MODULE_BOOTCMD(enable); +#else // If default state is SET, invert the logic if (INTMODULE_BOOTCMD_DEFAULT) { enable = !enable; } gpio_write(INTMODULE_BOOTCMD_GPIO, enable); +#endif } #endif @@ -437,7 +441,7 @@ static const etx_module_port_t _internal_ports[] = { static const etx_module_t _internal_module = { .ports = _internal_ports, .set_pwr = _internal_module_set_pwr, -#if defined(INTMODULE_BOOTCMD_GPIO) +#if defined(INTMODULE_BOOTCMD_GPIO) || defined(INTMODULE_BOOTCMD_BSP) .set_bootcmd = _internal_module_set_bootcmd, #else .set_bootcmd = nullptr, diff --git a/radio/src/boards/generic_stm32/switches.cpp b/radio/src/boards/generic_stm32/switches.cpp index 3cc9f64d6..c9ef2a24a 100644 --- a/radio/src/boards/generic_stm32/switches.cpp +++ b/radio/src/boards/generic_stm32/switches.cpp @@ -24,6 +24,7 @@ #include "stm32_gpio_driver.h" #include "drivers/pca95xx.h" +#include "drivers/aw9523b.h" #include "definitions.h" #include "myeeprom.h" diff --git a/radio/src/datastructs.h b/radio/src/datastructs.h index 4c4a86694..b1a7b8ac2 100644 --- a/radio/src/datastructs.h +++ b/radio/src/datastructs.h @@ -75,6 +75,8 @@ static inline void check_struct() CHKSIZE(CustomScreenData, 1972); #if defined(PCBNV14) || defined(RADIO_NB4P) || defined(RADIO_NV14_FAMILY) CHKTYPE(TopBarPersistentData, 736); + #elif defined(PCBPA01) + CHKTYPE(TopBarPersistentData, 916); #elif defined(RADIO_H7RS) // TODO #else @@ -86,14 +88,12 @@ static inline void check_struct() #if defined(PCBXLITES) CHKSIZE(RadioData, 945); -#elif defined(RADIO_ST16) +#elif defined(RADIO_ST16) || defined(PCBPA01) CHKSIZE(RadioData, 1159); #elif defined(COLORLCD) CHKSIZE(RadioData, 1039); #elif defined(RADIO_GX12) CHKSIZE(RadioData, 1063); -#elif defined(RADIO_GX12) - CHKSIZE(RadioData, 1062); #else CHKSIZE(RadioData, 943); #endif @@ -122,6 +122,8 @@ static inline void check_struct() CHKSIZE(ModelData, 27295); #elif defined(PCBST16) CHKSIZE(ModelData, 27761); +#elif defined(PCBPA01) + CHKSIZE(ModelData, 27522); #elif defined(RADIO_T15) CHKSIZE(ModelData, 27683); #elif defined(RADIO_H7RS) diff --git a/radio/src/drivers/aw9523b.cpp b/radio/src/drivers/aw9523b.cpp new file mode 100644 index 000000000..2ca231687 --- /dev/null +++ b/radio/src/drivers/aw9523b.cpp @@ -0,0 +1,124 @@ +/* + * 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 "aw9523b.h" + +#define REG_INPUT 0x00 +#define REG_OUTPUT 0x02 +#define REG_DIRECTION 0x04 +#define REG_INTERRUPT 0x06 +#define REG_CONTROL 0x11 +#define REG_LED_MODE 0x12 + +#define CTL_P0_DRIVE_MODE_OD 0 +#define CTL_P0_DRIVE_MODE_PP (1<<4) + +static int aw9523b_i2c_write16(aw9523b_t* dev, uint16_t reg, uint16_t value) +{ + if (!dev->addr) return -1; + + uint8_t val8 = value&0xFF; + if (i2c_write(dev->bus, dev->addr, reg, 1, (uint8_t*)&val8, 1) < 0) { + return -1; + } + val8 = (value>>8)&0xFF; + if (i2c_write(dev->bus, dev->addr, reg+1, 1, (uint8_t*)&val8, 1) < 0) { + return -1; + } + + return 0; +} + +int aw9523b_init(aw9523b_t* dev, etx_i2c_bus_t bus, uint16_t addr) +{ + dev->bus = 0; + dev->addr = 0; + //dev->interrupt = 0; + dev->direction = 0xFFFF; + dev->output = 0; + + if (i2c_init(bus) < 0) { + return -1; + } + + if (i2c_dev_ready(bus, addr) < 0) { + return -1; + } + + dev->bus = bus; + dev->addr = addr; + volatile uint8_t test = 0; + uint8_t tmp = CTL_P0_DRIVE_MODE_PP; + i2c_read(dev->bus, dev->addr, REG_CONTROL, 1, (uint8_t*)&test, 1); + i2c_write(dev->bus, dev->addr, REG_CONTROL, 1, (uint8_t*)&tmp, 1); + i2c_read(dev->bus, dev->addr, REG_CONTROL, 1, (uint8_t*)&test, 1); + aw9523b_i2c_write16(dev, REG_LED_MODE, 0xFFFF); // set all pins to GPIO mode not LED mode + aw9523b_i2c_write16(dev, REG_INTERRUPT, 0); // enable interrupts for all pins + + return 0; +} + +int aw9523b_set_direction(aw9523b_t* dev, uint16_t mask, uint16_t dir) +{ + uint16_t tmp = dev->direction; + tmp &= ~mask; + tmp |= dir & mask; + + if (aw9523b_i2c_write16(dev, REG_DIRECTION, tmp) < 0) { + return -1; + } + + dev->direction = tmp; + return 0; +} + +int aw9523b_write(aw9523b_t* dev, uint16_t mask, uint16_t value) +{ + uint16_t tmp = dev->output; + tmp &= ~mask; + tmp |= value & mask; + + if (aw9523b_i2c_write16(dev, REG_OUTPUT, tmp) < 0) { + return -1; + } + + dev->output = tmp; + return 0; +} + +int aw9523b_read(aw9523b_t* dev, uint16_t mask, uint16_t* value) +{ + if (!dev->addr) return -1; + + uint16_t tmp; + uint8_t tmp8; + if (i2c_read(dev->bus, dev->addr, REG_INPUT, 1, (uint8_t*)&tmp8, 1) < 0) { + return -1; + } + tmp = tmp8; + if (i2c_read(dev->bus, dev->addr, REG_INPUT+1, 1, (uint8_t*)&tmp8, 1) < 0) { + return -1; + } + + tmp |= ((uint16_t)tmp)<<8; + *value = tmp & mask; + return 0; +} diff --git a/radio/src/drivers/aw9523b.h b/radio/src/drivers/aw9523b.h new file mode 100644 index 000000000..81416f879 --- /dev/null +++ b/radio/src/drivers/aw9523b.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) EdgeTx + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#pragma once + +#include "hal/i2c_driver.h" + +#define AW9523B_PIN_0 (1 << 0) +#define AW9523B_PIN_1 (1 << 1) +#define AW9523B_PIN_2 (1 << 2) +#define AW9523B_PIN_3 (1 << 3) +#define AW9523B_PIN_4 (1 << 4) +#define AW9523B_PIN_5 (1 << 5) +#define AW9523B_PIN_6 (1 << 6) +#define AW9523B_PIN_7 (1 << 7) +#define AW9523B_PIN_8 (1 << 8) +#define AW9523B_PIN_9 (1 << 9) +#define AW9523B_PIN_10 (1 << 10) +#define AW9523B_PIN_11 (1 << 11) +#define AW9523B_PIN_12 (1 << 12) +#define AW9523B_PIN_13 (1 << 13) +#define AW9523B_PIN_14 (1 << 14) +#define AW9523B_PIN_15 (1 << 15) + +typedef struct { + etx_i2c_bus_t bus; + uint16_t addr; + // uint16_t interrupt; // unused, the direction config is used to enable interrupts for all input pins + uint16_t direction; + uint16_t output; +} aw9523b_t; + +int aw9523b_init(aw9523b_t* dev, etx_i2c_bus_t bus, uint16_t addr); +int aw9523b_set_direction(aw9523b_t* dev, uint16_t mask, uint16_t dir); +int aw9523b_set_polarity(aw9523b_t* dev, uint16_t mask, uint16_t dir); +int aw9523b_write(aw9523b_t* dev, uint16_t mask, uint16_t value); +int aw9523b_read(aw9523b_t* dev, uint16_t mask, uint16_t* value); diff --git a/radio/src/fonts/CMakeLists.txt b/radio/src/fonts/CMakeLists.txt index 4a79a5b76..f8baf5481 100644 --- a/radio/src/fonts/CMakeLists.txt +++ b/radio/src/fonts/CMakeLists.txt @@ -20,3 +20,4 @@ set(LVGL_FONT_SOURCES_MINIMAL fonts/lvgl/${FONT_DIR}/lv_font_bl.c PARENT_SCOPE ) + diff --git a/radio/src/gui/colorlcd/libui/tabsgroup.cpp b/radio/src/gui/colorlcd/libui/tabsgroup.cpp index f208e340f..c2233641d 100644 --- a/radio/src/gui/colorlcd/libui/tabsgroup.cpp +++ b/radio/src/gui/colorlcd/libui/tabsgroup.cpp @@ -25,10 +25,7 @@ #include "etx_lv_theme.h" #include "view_main.h" #include "topbar_impl.h" - -#if defined(HARDWARE_TOUCH) #include "keyboard_base.h" -#endif #if defined(DEBUG) static uint32_t dsms, dems, end_ms, start_ms; diff --git a/radio/src/storage/yaml/CMakeLists.txt b/radio/src/storage/yaml/CMakeLists.txt index 123186e92..afab89eb1 100644 --- a/radio/src/storage/yaml/CMakeLists.txt +++ b/radio/src/storage/yaml/CMakeLists.txt @@ -36,6 +36,8 @@ elseif(PCB STREQUAL PL18) endif() elseif(PCB STREQUAL ST16) set(YAML_GEN_OUTPUT storage/yaml/yaml_datastructs_st16.cpp) +elseif(PCB STREQUAL PA01) + set(YAML_GEN_OUTPUT storage/yaml/yaml_datastructs_pa01.cpp) elseif(PCB STREQUAL X7) if(PCBREV STREQUAL TPRO) set(YAML_GEN_OUTPUT storage/yaml/yaml_datastructs_tpro.cpp) diff --git a/radio/src/storage/yaml/yaml_datastructs.cpp b/radio/src/storage/yaml/yaml_datastructs.cpp index 268613413..f0129cfcb 100644 --- a/radio/src/storage/yaml/yaml_datastructs.cpp +++ b/radio/src/storage/yaml/yaml_datastructs.cpp @@ -50,6 +50,8 @@ #include "yaml_datastructs_nv14.cpp" #elif defined(PCBST16) #include "yaml_datastructs_st16.cpp" +#elif defined(PCBPA01) + #include "yaml_datastructs_pa01.cpp" #elif defined(PCBX7) #if defined(RADIO_TPRO) || defined(RADIO_TPROV2) || defined(RADIO_BUMBLEBEE) #include "yaml_datastructs_tpro.cpp" diff --git a/radio/src/storage/yaml/yaml_datastructs_pa01.cpp b/radio/src/storage/yaml/yaml_datastructs_pa01.cpp new file mode 100644 index 000000000..ff953a026 --- /dev/null +++ b/radio/src/storage/yaml/yaml_datastructs_pa01.cpp @@ -0,0 +1,985 @@ +// 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_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_TILT_X, "TILT_X" }, + { MIXSRC_TILT_Y, "TILT_Y" }, + { 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_ZoneOptionValueEnum[] = { + { ZOV_Unsigned, "Unsigned" }, + { ZOV_Signed, "Signed" }, + { ZOV_Bool, "Bool" }, + { ZOV_String, "String" }, + { ZOV_Source, "Source" }, + { ZOV_Color, "Color" }, + { 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_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_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( "modelQuickSelect", 1 ), + YAML_UNSIGNED( "blOffBright", 7 ), + YAML_STRING("bluetoothName", 10), + YAML_STRING("ownerRegistrationID", 8), + YAML_CUSTOM("rotEncDirection",r_rotEncDirection,nullptr), + YAML_UNSIGNED( "rotEncMode", 3 ), + YAML_SIGNED( "uartSampleMode", 2 ), + YAML_UNSIGNED( "stickDeadZone", 3 ), + YAML_SIGNED( "imuMax", 8 ), + YAML_SIGNED( "imuOffset", 8 ), + 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_PADDING( 6 ), + YAML_UNSIGNED( "pwrOffIfInactive", 8 ), + 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, 6, 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, 9, 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_SIGNED( "antennaMode", 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_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", 8, struct_anonymous_13, NULL), + YAML_END +}; +static const struct YamlNode struct_ModuleData[] = { + YAML_IDX, + YAML_UNSIGNED_CUST( "type", 8, r_moduleType, w_moduleType ), + 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_ZoneOptionValue_elmts[] = { + YAML_UNSIGNED( "unsignedValue", 32 ), + YAML_SIGNED( "signedValue", 32 ), + YAML_UNSIGNED( "boolValue", 32 ), + YAML_STRING("stringValue", 12), + YAML_CUSTOM("source",r_zov_source,w_zov_source), + YAML_CUSTOM("color",r_zov_color,w_zov_color), + YAML_END +}; +static const struct YamlNode struct_ZoneOptionValueTyped[] = { + YAML_IDX, + YAML_ENUM("type", 32, enum_ZoneOptionValueEnum, NULL), + YAML_UNION("value", 96, union_ZoneOptionValue_elmts, select_zov), + YAML_END +}; +static const struct YamlNode struct_WidgetPersistentData[] = { + YAML_ARRAY("options", 128, 10, struct_ZoneOptionValueTyped, NULL), + YAML_END +}; +static const struct YamlNode struct_ZonePersistentData[] = { + YAML_IDX, + YAML_STRING("widgetName", 20), + YAML_STRUCT("widgetData", 1280, struct_WidgetPersistentData, NULL), + YAML_END +}; +static const struct YamlNode struct_LayoutPersistentData[] = { + YAML_ARRAY("zones", 1440, 10, struct_ZonePersistentData, NULL), + YAML_ARRAY("options", 128, 10, struct_ZoneOptionValueTyped, NULL), + YAML_END +}; +static const struct YamlNode struct_CustomScreenData[] = { + YAML_IDX, + YAML_STRING("LayoutId", 12), + YAML_STRUCT("layoutData", 15680, struct_LayoutPersistentData, NULL), + YAML_END +}; +static const struct YamlNode struct_TopBarPersistentData[] = { + YAML_ARRAY("zones", 1440, 5, struct_ZonePersistentData, NULL), + YAML_ARRAY("options", 128, 1, struct_ZoneOptionValueTyped, NULL), + 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", 352, 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, 9, 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, 60, struct_TelemetrySensor, NULL), + YAML_ARRAY("screenData", 15776, 10, struct_CustomScreenData, NULL), + YAML_STRUCT("topbarData", 7328, struct_TopBarPersistentData, NULL), + YAML_ARRAY("topbarWidgetWidth", 8, 5, 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, 4, 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_STRUCT("header", 1048, struct_ModelHeader, NULL), + YAML_ARRAY("timers", 136, 3, struct_TimerData, 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/pa01/CMakeLists.txt b/radio/src/targets/pa01/CMakeLists.txt new file mode 100644 index 000000000..d60283e57 --- /dev/null +++ b/radio/src/targets/pa01/CMakeLists.txt @@ -0,0 +1,188 @@ +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 12000000) +set(SDCARD YES) +set(STORAGE_MODELSLIST YES) +set(HAPTIC YES) +set(GUI_DIR colorlcd) +set(BITMAPS_DIR 320x240) +set(TARGET_DIR pa01) +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 YES) +set(ROTARY_ENCODER YES) +set(FUNCTION_SWITCHES_WITH_RGB YES) + +#option(STICKS_DEAD_ZONE "Enable sticks dead zone" YES) + +# IMU support +set(IMU ON) + +# for size report script +set(CPU_TYPE_FULL STM32H750xB) +set(TARGET_LINKER_DIR stm32h750_sdram) +set(TARGET_EXTRAM_START 0xC0000000) +set(SIZE_TARGET_MEM_DEFINE "MEM_SIZE_SDRAM1=8192") +set(FIRMWARE_STRIP_BOOTLOADER YES) + +add_definitions(-DPCBPA01 -DPCBHORUS -DPCBFLYSKY) +add_definitions(-DBATTERY_CHARGE) +add_definitions(-DSTM32_SUPPORT_32BIT_TIMERS) +add_definitions(-DFIRMWARE_QSPI) +add_definitions(-DFIRMWARE_FORMAT_UF2) +add_definitions(-DUSE_CUSTOM_EXTI_IRQ) + +set(FLAVOUR pa01) +add_definitions(-DRADIO_PA01) + +# Defines internal modules for PL18 via UART7 +set(INTERNAL_MODULES AFHDS3;CRSF CACHE STRING "Internal modules") +set(DEFAULT_INTERNAL_MODULE CROSSFIRE CACHE STRING "Default internal module") + +set(BITMAPS_TARGET bm320_bitmaps) +set(FONTS_TARGET x12_fonts) +set(LCD_DRIVER lcd_driver.cpp) +set(HARDWARE_TOUCH YES) +set(RADIO_DEPENDENCIES ${RADIO_DEPENDENCIES} ${BITMAPS_TARGET}) +set(FIRMWARE_DEPENDENCIES datacopy) +set(SOFTWARE_KEYBOARD ON) +set(FLYSKY_GIMBAL ON) +set(FUNCTION_SWITCHES ON) + + +add_definitions( + -DSTM32H750ZBTx -DSTM32H750xx + -DSDRAM -DCCMRAM + -DCOLORLCD -DLIBOPENUI + -DHARDWARE_KEYS -DSOFTWARE_KEYBOARD + -DWS2812_MAX_LEDS=24 +) + +set(SDRAM ON) + +add_definitions(-DAUDIO -DVOICE) +add_definitions(-DSOFTWARE_VOLUME) +add_definitions(-DRTCLOCK) +add_definitions(-DGPS_USART_BAUDRATE=${INTERNAL_GPS_BAUDRATE}) +add_definitions(-DPWR_BUTTON_${PWR_BUTTON}) + +if(STICKS_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_WITH_RGB) + set(FUNCTION_SWITCHES YES) + add_definitions(-DFUNCTION_SWITCHES) + add_definitions(-DFUNCTION_SWITCHES_RGB_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(TARGET_SRC_DIR targets/${TARGET_DIR}) + +set(BOARD_COMMON_SRC + ${TARGET_SRC_DIR}/board.cpp + ${TARGET_SRC_DIR}/bsp_io.cpp + ${TARGET_SRC_DIR}/key_driver.cpp + ${TARGET_SRC_DIR}/lcd_driver.cpp + ${TARGET_SRC_DIR}/backlight_driver.cpp + ${TARGET_SRC_DIR}/haptic_driver.cpp + ${TARGET_SRC_DIR}/extflash_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/aw9523b.cpp +) + +# Bootloader board library +add_library(board_bl OBJECT EXCLUDE_FROM_ALL + ${BOARD_COMMON_SRC} + ${TARGET_SRC_DIR}/system_clock.c + ${TARGET_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} $) + +# Firmware board library +add_library(board OBJECT EXCLUDE_FROM_ALL + ${BOARD_COMMON_SRC} + ${TARGET_SRC_DIR}/led_driver.cpp + ${TARGET_SRC_DIR}/battery_driver.cpp + targets/common/arm/stm32/audio_dac_driver.cpp + targets/common/arm/stm32/heartbeat_driver.cpp + targets/common/arm/stm32/lsm6ds_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/pa01/backlight_driver.cpp b/radio/src/targets/pa01/backlight_driver.cpp new file mode 100644 index 000000000..bbb46234e --- /dev/null +++ b/radio/src/targets/pa01/backlight_driver.cpp @@ -0,0 +1,94 @@ +/* + * 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 "stm32_gpio.h" +#include "stm32_timer.h" +#include "stm32_pulse_driver.h" + +#include "edgetx_types.h" +#include "board.h" + +#include "globals.h" +#include "lcd_driver.h" + +static const stm32_pulse_timer_t _bl_timer = { + .GPIO = (gpio_t)BACKLIGHT_GPIO, + .GPIO_Alternate = BACKLIGHT_GPIO_AF, + .TIMx = BACKLIGHT_TIMER, + .TIM_Freq = BACKLIGHT_TIMER_FREQ, + .TIM_Channel = LL_TIM_CHANNEL_CH2, + .TIM_IRQn = (IRQn_Type)-1, + .DMAx = nullptr, + .DMA_Stream = 0, + .DMA_Channel = 0, + .DMA_IRQn = (IRQn_Type)-1, + .DMA_TC_CallbackPtr = nullptr, +}; + +void backlightLowInit() +{ + gpio_init(BACKLIGHT_GPIO, GPIO_OUT, GPIO_PIN_SPEED_LOW); + gpio_clear(BACKLIGHT_GPIO); +} + +void backlightInit() +{ + stm32_pulse_init(&_bl_timer, 10000); + stm32_pulse_config_output(&_bl_timer, true, LL_TIM_OCMODE_PWM1, 0); + LL_TIM_SetAutoReload(_bl_timer.TIMx, 100); + LL_TIM_EnableCounter(_bl_timer.TIMx); +} + +uint8_t lastDutyCycle = 0; + +void backlightEnable(uint8_t dutyCycle) +{ + stm32_pulse_set_cmp_val(&_bl_timer, dutyCycle); + + if(!dutyCycle) { + //experimental to turn off LCD when no backlight + if(lcdOffFunction) lcdOffFunction(); + } + else if(!lastDutyCycle) { + if(lcdOnFunction) lcdOnFunction(); + else lcdInit(); + } + + lastDutyCycle = dutyCycle; +} + +void lcdOff() { + backlightEnable(0); +} + +void lcdOn(){ + if(lcdOnFunction) lcdOnFunction(); + else lcdInit(); + backlightEnable(BACKLIGHT_LEVEL_MAX); +} + +bool boardBacklightOn; + +bool isBacklightEnabled() +{ + return boardBacklightOn; +} diff --git a/radio/src/targets/pa01/battery_driver.cpp b/radio/src/targets/pa01/battery_driver.cpp new file mode 100644 index 000000000..0fa115037 --- /dev/null +++ b/radio/src/targets/pa01/battery_driver.cpp @@ -0,0 +1,677 @@ +/* + * 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 "edgetx.h" +#include "battery_driver.h" +#include "boards/generic_stm32/rgb_leds.h" +#include "bsp_io.h" +#include "stm32_ws2812.h" + +#define __BATTERY_DRIVER_C__ + +#define BATTERY_W 140 +#define BATTERY_H (LCD_H - 120) +#define BATTERY_TOP ((LCD_H - BATTERY_H)/2) +#define BATTERY_CONNECTOR_W 32 +#define BATTERY_CONNECTOR_H 10 +#define BATTERY_BORDER 4 +#define BATTERY_W_INNER (BATTERY_W - 2*BATTERY_BORDER) +#define BATTERY_H_INNER (BATTERY_H - 2*BATTERY_BORDER) +#define BATTERY_TOP_INNER (BATTERY_TOP + BATTERY_BORDER) + +#define UCHARGER_SAMPLING_CNT 10 +#define UCHARGER_CHARGING_SAMPLING_CNT 10 + +typedef struct +{ + bool hasCharger : 1; + bool isChargeEnd : 1; + bool isChargerDetectionReady : 1; + bool isChargingDetectionReady : 1; + bool isHighCurrent : 1; + uint8_t chargerSamplingCount; + uint8_t chargingSamplingCount; + uint8_t chargeEndSamplingCount; +} STRUCT_BATTERY_CHARGER; + +STRUCT_BATTERY_CHARGER uCharger; // USB charger + +void chargerDetection(STRUCT_BATTERY_CHARGER* charger, uint8_t chargerPinActive, uint8_t samplingCountThreshold) +{ + if ((charger->hasCharger && chargerPinActive) || (!charger->hasCharger && !chargerPinActive)) + { + charger->chargerSamplingCount = 0; + } + else + { + charger->chargerSamplingCount++; + if (charger->chargerSamplingCount >= samplingCountThreshold) + { + charger->chargerSamplingCount = 0; + charger->hasCharger = !charger->hasCharger; + charger->isChargerDetectionReady = true; + } + } +} + +void resetChargeEndDetection(STRUCT_BATTERY_CHARGER* charger) +{ + charger->isChargeEnd = false; + charger->isChargingDetectionReady = false; + charger->chargingSamplingCount = 0; + charger->isHighCurrent = false; +} + +void chargeEndDetection(STRUCT_BATTERY_CHARGER* charger, uint8_t chargeEndPinActive, uint8_t samplingCountThreshold) +{ + if (charger->isChargeEnd) + { + if (chargeEndPinActive) + { + charger->chargingSamplingCount = 0; + if (charger->isChargingDetectionReady) + { + charger->chargeEndSamplingCount = 0; + } + else + { + charger->chargeEndSamplingCount++; + if (charger->chargeEndSamplingCount >= samplingCountThreshold) + { + charger->chargeEndSamplingCount = 0; + charger->isChargingDetectionReady = true; + } + } + } + else + { + charger->chargeEndSamplingCount = 0; + charger->chargingSamplingCount++; + if (charger->chargingSamplingCount >= samplingCountThreshold) + { + charger->chargingSamplingCount = 0; + charger->isChargeEnd = false; + charger->isChargingDetectionReady = true; + } + } + } + else + { + if (!chargeEndPinActive) + { + charger->chargeEndSamplingCount = 0; + if (charger->isChargingDetectionReady) + { + charger->chargingSamplingCount = 0; + } + else + { + charger->chargingSamplingCount++; + if (charger->chargingSamplingCount >= samplingCountThreshold) + { + charger->chargingSamplingCount = 0; + charger->isChargingDetectionReady = true; + } + } + } + else + { + charger->chargingSamplingCount = 0; + charger->chargeEndSamplingCount++; + if (charger->chargeEndSamplingCount >= samplingCountThreshold) + { + charger->chargeEndSamplingCount = 0; + charger->isChargeEnd = true; + charger->isChargingDetectionReady = true; + } + } + } +} + +uint16_t get_battery_charge_state() +{ + uint16_t state = CHARGE_UNKNOWN; + + chargerDetection(&uCharger, IS_UCHARGER_ACTIVE(), UCHARGER_SAMPLING_CNT); + if (uCharger.isChargerDetectionReady) + { + if (uCharger.hasCharger) // USB charger can be detected properly no matter it is enabled or not + { + ENABLE_UCHARGER(); + chargeEndDetection(&uCharger, IS_UCHARGER_CHARGE_END_ACTIVE(), UCHARGER_CHARGING_SAMPLING_CNT); + if (uCharger.isChargingDetectionReady) + { + if (uCharger.isChargeEnd) + { + state = CHARGE_FINISHED; + } + else + { + state = CHARGE_STARTED; + } + } + } + else + { + resetChargeEndDetection(&uCharger); + + // Disable USB charger if it is not present, so that wireless charger can be detected properly + DISABLE_UCHARGER(); + } + } + + return state; +} + +bool isChargerActive() +{ + if (uCharger.isChargerDetectionReady) { + // Detect the removal of the charger. + get_battery_charge_state(); + } else { + while (!uCharger.isChargerDetectionReady) + { + get_battery_charge_state(); + delay_ms(10); + } + } + return uCharger.hasCharger; +} + +void battery_charge_init() +{ + // USB charger status pins + gpio_init(UCHARGER_GPIO, GPIO_IN, GPIO_PIN_SPEED_LOW); + gpio_init(UCHARGER_CHARGE_END_GPIO, GPIO_IN_PD, GPIO_PIN_SPEED_LOW); + + // USB charger state init + ENABLE_UCHARGER(); + uCharger.hasCharger = !IS_UCHARGER_ACTIVE(); // Init for sampling count works + uCharger.isChargerDetectionReady = false; + resetChargeEndDetection(&uCharger); +} + +void ledChargingInfo(uint16_t chargeState) { +#if defined(LED_STRIP_GPIO) + static int ledIdx = LED_CHARGING_END; + if (ledIdx == LED_CHARGING_END) + ledIdx = LED_CHARGING_START; + else + ledIdx += LED_CHARGING_START > LED_CHARGING_END ? -1 : 1; + for (uint8_t i = 0; i < LED_STRIP_LENGTH; i++) { + uint8_t green = 0; + if (CHARGE_FINISHED == chargeState) { + if (LED_CHARGING_START > LED_CHARGING_END && i <= LED_CHARGING_START && i >= LED_CHARGING_END) + { + green = 20; + } + if (LED_CHARGING_START <= LED_CHARGING_END && i >= LED_CHARGING_START && i <= LED_CHARGING_END) + { + green = 20; + } + } else if (ledIdx == i) { + green = 20; + } + rgbSetLedColor(i, 0, green, 0); + } + rgbLedColorApply(); +#endif +} + +static Window* chargeWindow = nullptr; + +void drawChargingInfo(uint16_t chargeState) { + static int progress = -1; + static StaticText* stateText = nullptr; + static lv_obj_t* battBox = nullptr; + + const char* text; + int h; + LcdColorIndex color = COLOR_THEME_EDIT_INDEX; + + switch (chargeState) { + case CHARGE_STARTED: + progress += 1; + if (progress > 4) progress = 0; + text = STR_BATTERYCHARGING; + h = ((BATTERY_H_INNER * progress) / 4); + break; + case CHARGE_FINISHED: + text = STR_BATTERYFULL; + h = BATTERY_H_INNER; + break; + default: + text = STR_BATTERYNONE; + h = BATTERY_H_INNER; + color = COLOR_THEME_PRIMARY1_INDEX; + break; + } + + if (chargeWindow == nullptr) { + chargeWindow = new Window(MainWindow::instance(), {0, 0, LCD_W, LCD_H}); + etx_solid_bg(chargeWindow->getLvObj(), COLOR_THEME_PRIMARY1_INDEX); + + stateText = new StaticText(chargeWindow, {0, LCD_H - 50, LCD_W, 50}, "", COLOR_THEME_PRIMARY2_INDEX, CENTERED); + + lv_obj_t* box = lv_obj_create(chargeWindow->getLvObj()); + lv_obj_set_pos(box, (LCD_W - BATTERY_W) / 2, BATTERY_TOP); + lv_obj_set_size(box, BATTERY_W, BATTERY_H); + lv_obj_set_style_border_opa(box, LV_OPA_COVER, LV_PART_MAIN); + lv_obj_set_style_border_width(box, 2, LV_PART_MAIN); + etx_border_color(box, COLOR_THEME_PRIMARY2_INDEX); + + box = lv_obj_create(chargeWindow->getLvObj()); + lv_obj_set_pos(box, (LCD_W - BATTERY_CONNECTOR_W) / 2, BATTERY_TOP - BATTERY_CONNECTOR_H); + lv_obj_set_size(box, BATTERY_CONNECTOR_W, BATTERY_CONNECTOR_H); + etx_solid_bg(box, COLOR_THEME_PRIMARY2_INDEX); + + battBox = lv_obj_create(chargeWindow->getLvObj()); + } + + stateText->setText(text); + + lv_obj_set_pos(battBox, (LCD_W - BATTERY_W_INNER) / 2, BATTERY_TOP_INNER + BATTERY_H_INNER - h); + lv_obj_set_size(battBox, BATTERY_W_INNER, h); + etx_solid_bg(battBox, color); + + LvglWrapper::instance()->run(); + lv_refr_now(nullptr); + + BACKLIGHT_ENABLE(); +} + +void battery_charge_end() +{ + chargeWindow->clear(); + delete chargeWindow; + chargeWindow = nullptr; +} + +#define CHARGE_INFO_DURATION 5000 // ms + +//this method should be called by timer interrupt or by GPIO interrupt +void handle_battery_charge(uint32_t last_press_time) +{ +#if !defined(SIMU) + static uint32_t updateTime = 0; + static uint16_t lastState = CHARGE_UNKNOWN; + static uint32_t info_until = 0; + static bool lcdInited = false; + + uint32_t now = timersGetMsTick(); + uint16_t chargeState = get_battery_charge_state(); + if (chargeState != CHARGE_UNKNOWN) { + + if (lastState != chargeState) { + //avoid positive check when none and unknown + if (lastState + chargeState > 1) { + //charge state changed - last state known + info_until = now + (CHARGE_INFO_DURATION); + } + } + //power buttons pressed + else if (now - last_press_time < POWER_ON_DELAY) { + info_until = now + CHARGE_INFO_DURATION; + } + lastState = chargeState; + } + + if (!lcdInited) { + lcdInited = true; + backlightInit(); + lcdInitDisplayDriver(); + } + + if (updateTime == 0 || ((timersGetMsTick() - updateTime) >= 500)) + { + updateTime = timersGetMsTick(); + ledChargingInfo(chargeState); + + if(now > info_until) { + info_until = 0; + BACKLIGHT_DISABLE(); + if(lcdInited) { + lcdOff(); + } + } else { + if (lcdInited) { + lcdOn(); + } + drawChargingInfo(chargeState); + + // DEBUG INFO - TODO delete or replace with LVGL objects +#if 0 + char buffer[1024]; + + sprintf(buffer, "%d,%d,%d,%d", uCharger.isChargerDetectionReady, uCharger.hasCharger, IS_UCHARGER_ACTIVE(), uCharger.chargerSamplingCount); + lcd->drawSizedText(100, 10, buffer, strlen(buffer), CENTERED | COLOR_THEME_PRIMARY2); + + sprintf(buffer, "%d,%d,%d,%d,%d,", uCharger.isChargingDetectionReady, uCharger.isChargeEnd, IS_UCHARGER_CHARGE_END_ACTIVE(), uCharger.chargingSamplingCount, uCharger.chargeEndSamplingCount); + lcd->drawSizedText(100, 40, buffer, strlen(buffer), CENTERED | COLOR_THEME_PRIMARY2); + + sprintf(buffer, "%d", isChargerActive()); + lcd->drawSizedText(100, 130, buffer, strlen(buffer), CENTERED | COLOR_THEME_PRIMARY2); +#endif + } + + } +#endif +} + +#define BRIGHTNESS_MAX 255 + +void rgbPowerOn(uint8_t color) { + // Sequential RGB On + static uint8_t power_on_step = RGB_STEP_POWER_AROUND; + switch (power_on_step) + { + case RGB_STEP_POWER_AROUND: + setLedGroupColor(4, color, BRIGHTNESS_MAX); + setLedGroupColor(5, color, BRIGHTNESS_MAX); + setLedGroupColor(6, color, BRIGHTNESS_MAX); + break; + + case RGB_STEP_FUNC1: + setLedGroupColor(0, color, BRIGHTNESS_MAX); + break; + + case RGB_STEP_FUNC2: + setLedGroupColor(1, color, BRIGHTNESS_MAX); + break; + + case RGB_STEP_FUNC3: + setLedGroupColor(2, color, BRIGHTNESS_MAX); + break; + + case RGB_STEP_FUNC4: + setLedGroupColor(3, color, BRIGHTNESS_MAX); + break; + + default: + break; + } + power_on_step++; +} + +void rgbBatteryLevelInfo(uint8_t power_level, uint8_t rgb_state) { + uint8_t color = 0; + uint8_t breath_index = 0; + switch (power_level) + { + case POWER_LEVEL_CRITICAL: + color = RGB_COLOR_NONE; + if (rgb_state == RGB_STATE_CHARGE) { + color = RGB_COLOR_RED; + breath_index |= RGB_GROUP_MASK_FUNC_1; + setLedGroupColor(1, color, 0); + setLedGroupColor(2, color, 0); + setLedGroupColor(3, color, 0); + } + break; + + case POWER_LEVEL_LOW: + color = RGB_COLOR_RED; + if (rgb_state == RGB_STATE_CHARGE) { + breath_index |= RGB_GROUP_MASK_FUNC_1; + setLedGroupColor(1, color, 0); + setLedGroupColor(2, color, 0); + setLedGroupColor(3, color, 0); + } + break; + + case POWER_LEVEL_MEDIUM: + color = RGB_COLOR_PURPLE; + if (rgb_state == RGB_STATE_CHARGE) { + breath_index |= RGB_GROUP_MASK_FUNC_2; + setLedGroupColor(0, color, BRIGHTNESS_MAX); + setLedGroupColor(2, color, 0); + setLedGroupColor(3, color, 0); + } + break; + + case POWER_LEVEL_HIGH: + color = RGB_COLOR_YELLOW; + if (rgb_state == RGB_STATE_CHARGE) { + breath_index |= RGB_GROUP_MASK_FUNC_3; + setLedGroupColor(0, color, BRIGHTNESS_MAX); + setLedGroupColor(1, color, BRIGHTNESS_MAX); + setLedGroupColor(3, color, 0); + } + break; + + case POWER_LEVEL_NEAR_FULL: + color = RGB_COLOR_GREEN; + if (rgb_state == RGB_STATE_CHARGE) { + breath_index |= RGB_GROUP_MASK_FUNC_4; + setLedGroupColor(0, color, BRIGHTNESS_MAX); + setLedGroupColor(1, color, BRIGHTNESS_MAX); + setLedGroupColor(2, color, BRIGHTNESS_MAX); + } + break; + + case POWER_LEVEL_FULL: + color = RGB_COLOR_GREEN; + if (rgb_state == RGB_STATE_CHARGE) { + setLedGroupColor(0, color, BRIGHTNESS_MAX); + setLedGroupColor(1, color, BRIGHTNESS_MAX); + setLedGroupColor(2, color, BRIGHTNESS_MAX); + setLedGroupColor(3, color, BRIGHTNESS_MAX); + } + break; + + default: + break; + } + + switch (rgb_state) + { + case RGB_STATE_BREATH: + ledSetGroup(RGB_GROUP_MASK_ALL); + break; + + case RGB_STATE_CHARGE: + breath_index |= RGB_GROUP_MASK_AROUND_L | RGB_GROUP_MASK_AROUND_R | RGB_GROUP_MASK_POWER; + ledSetGroup(breath_index); + break; + + case RGB_STATE_POWER_ON: + rgbPowerOn(color); + break; + + default: + break; + } + + ledSetState(rgb_state); + ledSetColor(color); +} + +#define BREATH_INTERVAL 7 +#define GAMMA 6 +#define PI 3.14159265358979323846f +#define BREATH_STEP 0.0089759771428571 // PI / 350.0f; // step size + +typedef struct +{ + uint8_t led_color; + uint8_t led_state; + uint8_t led_group; +} ledInfo_t; + +// used to map all led number in the rgbled chain +// function 1~4 power right left +uint8_t rgbMapping[] = {4, 6, 0, 2, 8, 12, 10}; + +ledInfo_t led_info = {0}; + +void ledSetColor(uint8_t color) { + led_info.led_color = color; +} + +void ledSetState(uint8_t state) { + led_info.led_state = state; +} + +void ledSetGroup(uint8_t group) { + led_info.led_group = group; +} + +void setLedGroupColor(uint8_t index, uint8_t color, uint8_t brightness) { + + uint8_t scaled_r = 0; + uint8_t scaled_g = 0; + uint8_t scaled_b = 0; + + if (color & RGB_COLOR_RED) { + scaled_r = brightness; + } + if (color & RGB_COLOR_GREEN) { + scaled_g = brightness; + } + if (color & RGB_COLOR_BLUE) { + scaled_b = brightness; + } + + ws2812_set_color(rgbMapping[index], scaled_r, scaled_g, scaled_b); + ws2812_set_color(rgbMapping[index] + 1, scaled_r, scaled_g, scaled_b); +} + +uint8_t ledBreathBright(float angle) { + float brightness = sin(angle) * 0.5 + 0.5; // map range 0-1 + brightness = pow(brightness, GAMMA); // gamma correction + uint8_t bright = (uint8_t)(brightness * 255); + return bright; +} + +void ledBreathUpdate(uint8_t state, uint8_t color, uint8_t group) { + static uint32_t breath_tick = 0; + + if (timersGetMsTick() - breath_tick < BREATH_INTERVAL && breath_tick != 0) { + if (state == RGB_STATE_BREATH || state == RGB_STATE_CHARGE) { + return; + } + } + breath_tick = timersGetMsTick(); + uint8_t bright = 0; + static float breath_angle = 0; + + bright = ledBreathBright(breath_angle); + breath_angle += BREATH_STEP; + if (breath_angle > PI) breath_angle = 0; // reset angle + + if (group & RGB_GROUP_MASK_FUNC_1) setLedGroupColor(0, color, bright); + if (group & RGB_GROUP_MASK_FUNC_2) setLedGroupColor(1, color, bright); + if (group & RGB_GROUP_MASK_FUNC_3) setLedGroupColor(2, color, bright); + if (group & RGB_GROUP_MASK_FUNC_4) setLedGroupColor(3, color, bright); + if (group & RGB_GROUP_MASK_POWER) setLedGroupColor(4, color, bright); + if (group & RGB_GROUP_MASK_AROUND_L) setLedGroupColor(5, color, bright); + if (group & RGB_GROUP_MASK_AROUND_R) setLedGroupColor(6, color, bright); + + rgbLedColorApply(); +} + +void ledLoop(void) { + if (led_info.led_state == RGB_STATE_OFF) { + led_info.led_state = RGB_STATE_NONE; + rgbLedClearAll(); + return; + } else if (led_info.led_state == RGB_STATE_POWER_ON) { + rgbLedColorApply(); + return; + } else if (led_info.led_state == RGB_STATE_NONE) { + return; + } + ledBreathUpdate(led_info.led_state, led_info.led_color, led_info.led_group); +} + +extern const stm32_pulse_timer_t _led_timer; +static uint8_t _led_charge_colors[WS2812_BYTES_PER_LED * LED_STRIP_LENGTH]; +void rgbChargeInit(void) { + ws2812_init(&_led_timer, _led_charge_colors, LED_STRIP_LENGTH, WS2812_GRB); + rgbLedClearAll(); +} + +constexpr uint16_t vbatLedTable[] = {660, 720, 760, 800, 823}; +constexpr uint16_t HYSTERESIS = 5; +void updateBatteryState(uint8_t rgb_state) { + uint16_t bat_v = getBatteryVoltage(); + uint8_t power_level = POWER_LEVEL_NONE; + static uint8_t last_power_level = POWER_LEVEL_NONE; + + uint16_t current_level_min = 0; + uint16_t current_level_max = 0; + bool need_update = true; + if (last_power_level != POWER_LEVEL_NONE) { + switch (last_power_level) { + case POWER_LEVEL_CRITICAL: + current_level_min = 0; + current_level_max = vbatLedTable[0] + HYSTERESIS; + break; + case POWER_LEVEL_LOW: + current_level_min = vbatLedTable[0] - HYSTERESIS; + current_level_max = vbatLedTable[1] + HYSTERESIS; + break; + case POWER_LEVEL_MEDIUM: + current_level_min = vbatLedTable[1] - HYSTERESIS; + current_level_max = vbatLedTable[2] + HYSTERESIS; + break; + case POWER_LEVEL_HIGH: + current_level_min = vbatLedTable[2] - HYSTERESIS; + current_level_max = vbatLedTable[3] + HYSTERESIS; + break; + case POWER_LEVEL_NEAR_FULL: + current_level_min = vbatLedTable[3] - HYSTERESIS; + current_level_max = vbatLedTable[4] + HYSTERESIS; + break; + case POWER_LEVEL_FULL: + current_level_min = vbatLedTable[4] - HYSTERESIS; + current_level_max = UINT16_MAX; + break; + default: + need_update = true; + } + + if (bat_v >= current_level_min && bat_v <= current_level_max) { + need_update = false; + power_level = last_power_level; + } + } + + if (need_update) { + if (bat_v < vbatLedTable[0]) { + power_level = POWER_LEVEL_CRITICAL; + } else if (bat_v < vbatLedTable[1]) { + power_level = POWER_LEVEL_LOW; + } else if (bat_v < vbatLedTable[2]) { + power_level = POWER_LEVEL_MEDIUM; + } else if (bat_v < vbatLedTable[3]) { + power_level = POWER_LEVEL_HIGH; + } else if (bat_v < vbatLedTable[4]){ + power_level = POWER_LEVEL_NEAR_FULL; + } else { + power_level = POWER_LEVEL_FULL; + } + } + rgbBatteryLevelInfo(power_level, rgb_state); + ledLoop(); + last_power_level = power_level; +} + diff --git a/radio/src/targets/pa01/battery_driver.h b/radio/src/targets/pa01/battery_driver.h new file mode 100644 index 000000000..5cfcb15aa --- /dev/null +++ b/radio/src/targets/pa01/battery_driver.h @@ -0,0 +1,55 @@ +/* + * 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 "board.h" +#include "hal.h" + +#include "hal/gpio.h" +#include "stm32_gpio.h" + +enum ChargeState +{ + CHARGE_UNKNOWN, + CHARGE_NONE, + CHARGE_STARTED, + CHARGE_FINISHED +}; + +enum PowerLevel { + POWER_LEVEL_NONE, + POWER_LEVEL_CRITICAL, + POWER_LEVEL_LOW, + POWER_LEVEL_MEDIUM, + POWER_LEVEL_HIGH, + POWER_LEVEL_NEAR_FULL, + POWER_LEVEL_FULL, +}; + +extern void battery_charge_init(); +extern void handle_battery_charge(uint32_t last_press_time); +extern uint16_t get_battery_charge_state(); +extern uint16_t getBatteryVoltage(); // returns current battery voltage in 10mV steps +extern bool isChargerActive(); +extern void battery_charge_end(); +void rgbBatteryLevelInfo(uint8_t power_level, uint8_t rgb_state); +void updateBatteryState(uint8_t rgb_state); \ No newline at end of file diff --git a/radio/src/targets/pa01/board.cpp b/radio/src/targets/pa01/board.cpp new file mode 100644 index 000000000..6ca0af821 --- /dev/null +++ b/radio/src/targets/pa01/board.cpp @@ -0,0 +1,379 @@ +/* + * 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_adc.h" +#include "stm32_gpio.h" +#include "stm32_i2c_driver.h" +#include "stm32_hal.h" +#include "stm32_ws2812.h" +#include "stm32_spi.h" + +#include "flash_driver.h" +#include "extflash_driver.h" + +#include "board.h" +#include "boards/generic_stm32/module_ports.h" +#include "boards/generic_stm32/rgb_leds.h" +#include "bsp_io.h" + +#include "hal/adc_driver.h" +#include "hal/trainer_driver.h" +#include "hal/rotary_encoder.h" +#include "hal/switch_driver.h" +#include "hal/abnormal_reboot.h" +#include "hal/watchdog_driver.h" +#include "hal/usb_driver.h" +#include "hal/gpio.h" + +#include "globals.h" +#include "sdcard.h" +#include "debug.h" + +#include "flysky_gimbal_driver.h" +#include "timers_driver.h" + +#include "battery_driver.h" + +#include "bitmapbuffer.h" +#include "colors.h" + + +#include + +// common ADC driver +extern const etx_hal_adc_driver_t _adc_driver; + +#if defined(SEMIHOSTING) +extern "C" void initialise_monitor_handles(); +#endif + +#if defined(SPI_FLASH) +extern "C" void flushFTL(); +#endif + +constexpr uint8_t ledMapping[] = {4, 6, 0, 2}; + +void INTERNAL_MODULE_BOOTCMD(uint8_t enable) +{ + if (enable) + bsp_output_set(BSP_INTMOD_BOOTCMD); + else + bsp_output_clear(BSP_INTMOD_BOOTCMD); +} + +void INTERNAL_MODULE_ON() +{ + bsp_output_set(BSP_INTMOD_PWR_EN); +} + +void INTERNAL_MODULE_OFF() +{ + bsp_output_clear(BSP_INTMOD_PWR_EN); +} + +void EXTERNAL_MODULE_ON() +{ + bsp_output_set(BSP_EXTMOD_PWR_EN); +} + +void EXTERNAL_MODULE_OFF() +{ + bsp_output_clear(BSP_EXTMOD_PWR_EN); +} + +void boardBLEarlyInit() +{ + timersInit(); + bsp_io_init(); + gpio_init(UCHARGER_GPIO, GPIO_IN, GPIO_PIN_SPEED_LOW); +} + + +void boardBLPreJump() +{ + ExtFLASH_Init(); + SDRAM_Init(); + + // Stop 1ms timer + MS_TIMER->CR1 &= ~TIM_CR1_CEN; +} + +void boardBLInit() +{ + ExtFLASH_Init(); + SDRAM_Init(); + + // register external FLASH for DFU + usbRegisterDFUMedia((void*)extflash_dfu_media); + + // register internal & external FLASH for UF2 + flashRegisterDriver(FLASH_BANK1_BASE, BOOTLOADER_SIZE, &stm32_flash_driver); + flashRegisterDriver(QSPI_BASE, 8 * 1024 * 1024, &extflash_driver); +} + +void boardInit() +{ + // enable interrupts + __enable_irq(); + +#if defined(DEBUG) + serialSetMode(SP_AUX1, UART_MODE_DEBUG); // indicate AUX1 is used + serialInit(SP_AUX1, UART_MODE_DEBUG); // early AUX1 init +#endif + + boardInitModulePorts(); + + pwrInit(); + delaysInit(); + timersInit(); + + bsp_io_init(); + + ExtFLASH_InitRuntime(); + + // register internal & external FLASH for UF2 + flashRegisterDriver(FLASH_BANK1_BASE, BOOTLOADER_SIZE, &stm32_flash_driver); + flashRegisterDriver(QSPI_BASE, QSPI_FLASH_SIZE, &extflash_driver); + + board_trainer_init(); + battery_charge_init(); + + adcInit(&_adc_driver); + getADC(); + + flysky_gimbal_init(); + usbInit(); + rgbChargeInit(); // RTOS was not running, timer_create will prevent the ADC from reading. + + rotaryEncoderInit(); + +#if !defined(DEBUG_SEGGER_RTT) + +#if defined(SHORT_LONG_PRESS) + uint32_t short_press = 0; + uint32_t first_short_press = 0; + uint32_t long_press = 0; + uint32_t last_pulse = 0; + uint32_t now = 0; + + pwrOn(); + + // Handle charging state if charger is active + if (isChargerActive()) { + static uint32_t adc_sample_time = 0; // Hardware ADC sample tick + bool is_charging = true; + while (1) + { + now = timersGetMsTick(); + while (now - adc_sample_time > 10) + { + adc_sample_time = now; + getADC(); + is_charging = isChargerActive(); + } + // Exit conditions: button pressed or charger disconnected + if (!pwrPressed() && is_charging) { + updateBatteryState(RGB_STATE_CHARGE); + } else { + rgbLedClearAll(); + if (!is_charging) { + boardOff(); + } + break; + } + } + } + + // First stage: Detect initial button press and handle press duration + first_short_press = timersGetMsTick(); + while (pwrPressed()) { + now = timersGetMsTick(); + short_press = now; + last_pulse = now; + updateBatteryState(RGB_STATE_BREATH); + + // Shutdown after 10s continuous press + if (now - first_short_press > FRIST_PRESS_TIMEOUT) { + rgbLedClearAll(); + boardOff(); + } + } + + // Second stage: Detect secondary long-press sequence + while (1) + { + now = timersGetMsTick(); + + if (pwrPressed()) { + if (long_press == 0) { + updateBatteryState(RGB_STATE_OFF); + long_press = now; + } + + // Successful long-press completion + if (now - long_press > POWER_ON_DELAY) { + // updateBatteryState(RGB_STATE_OFF); + break; + } + + // Pulsing effect during long-press + if (now - last_pulse > POWER_ON_STEP) { + last_pulse = now; + updateBatteryState(RGB_STATE_POWER_ON); + } + } else { + // Breathing effect between press sequences + updateBatteryState(RGB_STATE_BREATH); + + // Shutdown conditions: + // 1. Incomplete secondary press (released too soon) + // 2. Timeout between press sequences + if ((long_press != 0) || (now - short_press > INTER_PRESS_TIMEOUT)) { + boardOff(); + } + } + } + +#else + uint32_t press_start = 0; + uint32_t press_end = 0; + rotenc_t lastEncoderValue = 0; + + if (UNEXPECTED_SHUTDOWN()) { + pwrOn(); + } else if (isChargerActive()) { + while (true) { + pwrOn(); + uint32_t now = timersGetMsTick(); + if (pwrPressed()) { + press_end = now; + if (press_start == 0) press_start = now; + if ((now - press_start) > POWER_ON_DELAY) { + break; + } + } else if (!isChargerActive()) { + boardOff(); + } else { + uint32_t press_end_touch = press_end; + extern void rotaryEncoderCheck(); + rotaryEncoderCheck(); + rotenc_t value = rotaryEncoderGetValue(); + if (value != lastEncoderValue) { + lastEncoderValue = value; + press_end_touch = timersGetMsTick(); + } + press_start = 0; + handle_battery_charge(press_end_touch); + delay_ms(10); + press_end = 0; + } + } + battery_charge_end(); + } +#endif +#endif + + rgbLedInit(); + rgbLedClearAll(); + keysInit(); + switchInit(); + audioInit(); + hapticInit(); + +#if defined(RTCLOCK) + rtcInit(); // RTC must be initialized before rambackupRestore() is called +#endif +} + +extern void rtcDisableBackupReg(); + +void boardOff() +{ + lcdOff(); + + while (pwrPressed()) { + WDG_RESET(); + } + + SysTick->CTRL = 0; // turn off systick + + // Shutdown the Haptic + hapticDone(); + + rtcDisableBackupReg(); + +#if !defined(BOOT) + rgbLedClearAll(); + if (IS_UCHARGER_ACTIVE()) + { +// RTC->BKP0R = SOFTRESET_REQUEST; + NVIC_SystemReset(); + } + else +#endif + +// RTC->BKP0R = SHUTDOWN_REQUEST; + pwrOff(); + + // We reach here only in forced power situations, such as hw-debugging with external power + // Enter STM32 stop mode / deep-sleep + // Code snippet from ST Nucleo PWR_EnterStopMode example +#define PDMode 0x00000000U +#if defined(PWR_CR1_MRUDS) && defined(PWR_CR1_LPUDS) && defined(PWR_CR1_FPDS) + MODIFY_REG(PWR->CR1, (PWR_CR1_PDDS | PWR_CR1_LPDS | PWR_CR1_FPDS | PWR_CR1_LPUDS | PWR_CR1_MRUDS), PDMode); +#elif defined(PWR_CR_MRLVDS) && defined(PWR_CR_LPLVDS) && defined(PWR_CR_FPDS) + MODIFY_REG(PWR->CR1, (PWR_CR1_PDDS | PWR_CR1_LPDS | PWR_CR1_FPDS | PWR_CR1_LPLVDS | PWR_CR1_MRLVDS), PDMode); +#else +// MODIFY_REG(PWR->CR1, (PWR_CR1_P_PDDS| PWR_CR1_LPDS), PDMode); +#endif /* PWR_CR_MRUDS && PWR_CR_LPUDS && PWR_CR_FPDS */ + +/* Set SLEEPDEEP bit of Cortex System Control Register */ + SET_BIT(SCB->SCR, ((uint32_t)SCB_SCR_SLEEPDEEP_Msk)); + + // To avoid HardFault at return address, end in an endless loop + while (1) { + + } +} +/* +int usbPlugged() +{ + static uint8_t debouncedState = 0; + static uint8_t lastState = 0; + + uint8_t state = IS_UCHARGER_ACTIVE(); + + if (state == lastState) + debouncedState = state; + else + lastState = state; + + return debouncedState; +} +*/ +// extern "C" void * memcpy(void* dst, const void*src, size_t count) +// { +// uint8_t* d = (uint8_t*)dst; +// const uint8_t* s = (const uint8_t*)src; +// while(count--) +// *d++ = *s++; +// return dst; +// } diff --git a/radio/src/targets/pa01/board.h b/radio/src/targets/pa01/board.h new file mode 100644 index 000000000..759b05f29 --- /dev/null +++ b/radio/src/targets/pa01/board.h @@ -0,0 +1,295 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _BOARD_H_ +#define _BOARD_H_ + +#include "definitions.h" +#include "edgetx_constants.h" + +#include "board_common.h" +#include "hal.h" +#include "hal/serial_port.h" +#include "hal/watchdog_driver.h" + +#define FLASHSIZE 0x800000 +#define FLASH_PAGESIZE 256 +#define BOOTLOADER_SIZE 0x10000 +#define BOOTLOADER_ADDRESS 0x08000000 +#define FIRMWARE_ADDRESS 0x90000000 +#define FIRMWARE_LEN(fsize) (fsize) +#define FIRMWARE_MAX_LEN FLASHSIZE +#define APP_START_ADDRESS (uint32_t)(FIRMWARE_ADDRESS) + +#define BOOTLOADER_KEYS 0x42 + +#define MB *1024*1024 +#define LUA_MEM_EXTRA_MAX (2 MB) // max allowed memory usage for Lua bitmaps (in bytes) +#define LUA_MEM_MAX (6 MB) // max allowed memory usage for complete Lua (in bytes), 0 means unlimited + +extern uint16_t sessionTimer; + +#define SLAVE_MODE() (g_model.trainerData.mode == TRAINER_MODE_SLAVE) + +// Board driver +void boardInit(); +void boardOff(); + +// CPU Unique ID +#define LEN_CPU_UID (3*8+2) +void getCPUUniqueID(char * s); + +// Flash Write driver +#define FLASH_PAGESIZE 256 +void unlockFlash(); +void lockFlash(); +void flashWrite(uint32_t * address, const uint32_t * buffer); +uint32_t isFirmwareStart(const uint8_t * buffer); +uint32_t isBootloaderStart(const uint8_t * buffer); + +// SDRAM driver +extern "C" void SDRAM_Init(); + +// Pulses driver +#if !defined(SIMU) + +void INTERNAL_MODULE_ON(); /*gpio_set(INTMODULE_PWR_GPIO)*/ +void INTERNAL_MODULE_OFF(); /*gpio_clear(INTMODULE_PWR_GPIO);*/ +void INTERNAL_MODULE_BOOTCMD(uint8_t enable); +void EXTERNAL_MODULE_ON(); /*gpio_set(EXTMODULE_PWR_GPIO)*/ +void EXTERNAL_MODULE_OFF(); /*gpio_clear(EXTMODULE_PWR_GPIO)*/ +#define EXTERNAL_MODULE_PWR_OFF EXTERNAL_MODULE_OFF +#define BLUETOOTH_MODULE_ON() gpio_clear(BLUETOOTH_ON_GPIO) +#define BLUETOOTH_MODULE_OFF() gpio_set(BLUETOOTH_ON_GPIO) +#define IS_INTERNAL_MODULE_ON() (false) +#define IS_EXTERNAL_MODULE_ON() (GPIO_ReadInputDataBit(EXTMODULE_PWR_GPIO, EXTMODULE_PWR_GPIO_PIN) == Bit_SET) + +#else + +#define INTERNAL_MODULE_OFF() +#define INTERNAL_MODULE_ON() +#define EXTERNAL_MODULE_ON() +#define EXTERNAL_MODULE_OFF() +#define BLUETOOTH_MODULE_ON() +#define BLUETOOTH_MODULE_OFF() +#define IS_INTERNAL_MODULE_ON() (false) +#define IS_EXTERNAL_MODULE_ON() (false) + +#endif // defined(SIMU) + +#if defined(FUNCTION_SWITCHES) +#define NUM_FUNCTIONS_SWITCHES 4 +#define NUM_FUNCTIONS_GROUPS 2 +#define DEFAULT_FS_CONFIG \ + (SWITCH_2POS << 6) + \ + (SWITCH_2POS << 4) + (SWITCH_2POS << 2) + (SWITCH_2POS << 0) + +#define DEFAULT_FS_GROUPS \ + (1 << 6) + (1 << 4) + (1 << 2) + \ + (1 << 0) // Set all FS to group 1 to act like a 6pos + +#define DEFAULT_FS_STARTUP_CONFIG \ + ((FS_START_PREVIOUS << 6) + (FS_START_PREVIOUS << 4) + \ + (FS_START_PREVIOUS << 2) + \ + (FS_START_PREVIOUS << 0)) // keep last state by default + +#else +#define NUM_FUNCTIONS_SWITCHES 0 +#endif + +#define NUM_TRIMS 4 +#define DEFAULT_STICK_DEADZONE 2 + +#define BATTERY_WARN 74 // 7.4V +#define BATTERY_MIN 70 // 6.8V +#define BATTERY_MAX 86 // 8.6V +#define BATTERY_DIVIDER 2323 + +#if defined(__cplusplus) && !defined(SIMU) +extern "C" { +#endif + +// Power driver +#define SOFT_PWR_CTRL +#define POWER_ON_DELAY 1500 // 1.5s +#define POWER_ON_STEP 250 // 300ms +#define INTER_PRESS_TIMEOUT 5000 // 5s +#define FRIST_PRESS_TIMEOUT 10000 // 10s +void pwrInit(); +void extModuleInit(); +uint32_t pwrCheck(); +uint32_t lowPowerCheck(); + +void pwrOn(); +void pwrSoftReboot(); +void pwrOff(); +void pwrResetHandler(); +bool pwrPressed(); +bool pwrOffPressed(); +#if defined(PWR_EXTRA_SWITCH_GPIO) + bool pwrForcePressed(); +#else + #define pwrForcePressed() false +#endif +uint32_t pwrPressedDuration();; + +const etx_serial_port_t* auxSerialGetPort(int port_nr); +#define AUX_SERIAL_POWER_ON() +#define AUX_SERIAL_POWER_OFF() + +// LED driver +void ledInit(); +void ledOff(); +void ledRed(); +void ledBlue(); +void ledGreen(); + +// LCD driver +void lcdSetInitalFrameBuffer(void* fbAddress); +void lcdInit(); +void lcdCopy(void * dest, void * src); + +void lcdOff(); +void lcdOn(); + +#define lcdRefreshWait(...) + +// Backlight driver +#define BACKLIGHT_LEVEL_MAX 100 +#define BACKLIGHT_FORCED_ON BACKLIGHT_LEVEL_MAX + 1 +#define BACKLIGHT_LEVEL_MIN 1 + +extern bool boardBacklightOn; +void backlightLowInit( void ); +void backlightInit(); +void backlightEnable(uint8_t dutyCycle); +void backlightFullOn(); +bool isBacklightEnabled(); + +#define BACKLIGHT_ENABLE() \ + { \ + boardBacklightOn = true; \ + backlightEnable(BACKLIGHT_LEVEL_MAX - currentBacklightBright); \ + } + +#define BACKLIGHT_DISABLE() \ + { \ + boardBacklightOn = false; \ + backlightEnable(((g_eeGeneral.blOffBright == BACKLIGHT_LEVEL_MIN) && \ + (g_eeGeneral.backlightMode != e_backlight_mode_off)) \ + ? 0 \ + : g_eeGeneral.blOffBright); \ + } + +#if defined(__cplusplus) && !defined(SIMU) +} +#endif + +#define IS_UCHARGER_ACTIVE() gpio_read(UCHARGER_GPIO) ? 1 : 0 +#define IS_UCHARGER_CHARGE_END_ACTIVE() gpio_read(UCHARGER_CHARGE_END_GPIO) ? 0 : 1 +#define ENABLE_UCHARGER() bsp_output_set(BSP_CHARGE_EN); +#define DISABLE_UCHARGER() bsp_output_clear(BSP_CHARGE_EN) + +// Audio driver +void audioInit(); +void audioConsumeCurrentBuffer(); +void setSampleRate(uint32_t frequency); +#define audioWaitReady() +#define audioDisableIrq() // interrupts must stay enabled on Horus +#define audioEnableIrq() // interrupts must stay enabled on Horus +#define setSampleRate(freq) +void setScaledVolume(uint8_t volume); +void setVolume(uint8_t volume); +int32_t getVolume(); +#define VOLUME_LEVEL_MAX 23 +#define VOLUME_LEVEL_DEF 12 + +// Telemetry driver +#define INTMODULE_FIFO_SIZE 512 +#define TELEMETRY_FIFO_SIZE 512 + +// Haptic driver +void hapticInit(); +void hapticDone(); +void hapticOff(); +void hapticOn(uint32_t pwmPercent); + +// Second serial port driver +//#define AUX_SERIAL +#define DEBUG_BAUDRATE 115200 +#define LUA_DEFAULT_BAUDRATE 115200 + +extern uint8_t currentTrainerMode; +void checkTrainerSettings(); + +// Touch panel driver +bool touchPanelEventOccured(); +struct TouchState touchPanelRead(); +struct TouchState getInternalTouchState(); + +enum rgb_state_e { + RGB_STATE_NONE, + RGB_STATE_BREATH, + RGB_STATE_CHARGE, + RGB_STATE_ON, + RGB_STATE_OFF, + RGB_STATE_POWER_ON, + RGB_STATE_POWER_OFF, +}; + +enum rgb_color_e { + RGB_COLOR_NONE = 0, + RGB_COLOR_RED = (1 << 0), // 00000001 + RGB_COLOR_GREEN = (1 << 1), // 00000010 + RGB_COLOR_BLUE = (1 << 2), // 00000100 + RGB_COLOR_YELLOW = RGB_COLOR_RED | RGB_COLOR_GREEN, + RGB_COLOR_PURPLE = RGB_COLOR_RED | RGB_COLOR_BLUE, + RGB_COLOR_WHITE = RGB_COLOR_RED | RGB_COLOR_GREEN | RGB_COLOR_BLUE, +}; + +enum rgb_group_e { + RGB_GROUP_MASK_NONE = 0, + RGB_GROUP_MASK_FUNC_1 = (1 << 0), + RGB_GROUP_MASK_FUNC_2 = (1 << 1), + RGB_GROUP_MASK_FUNC_3 = (1 << 2), + RGB_GROUP_MASK_FUNC_4 = (1 << 3), + RGB_GROUP_MASK_POWER = (1 << 4), + RGB_GROUP_MASK_AROUND_L = (1 << 5), + RGB_GROUP_MASK_AROUND_R = (1 << 6), + RGB_GROUP_MASK_ALL = 0x7f, // 0111 1111 +}; + +enum rgb_power_step_e { + RGB_STEP_POWER_AROUND, + RGB_STEP_FUNC1, + RGB_STEP_FUNC2, + RGB_STEP_FUNC3, + RGB_STEP_FUNC4, +}; + +void rgbChargeInit(void); +void ledLoop(void); +void ledSetColor(uint8_t color); +void ledSetState(uint8_t state); +void ledSetGroup(uint8_t group); +void setLedGroupColor(uint8_t index, uint8_t color, uint8_t brightness); + +#endif // _BOARD_H_ diff --git a/radio/src/targets/pa01/bsp_io.cpp b/radio/src/targets/pa01/bsp_io.cpp new file mode 100644 index 000000000..aaa499638 --- /dev/null +++ b/radio/src/targets/pa01/bsp_io.cpp @@ -0,0 +1,90 @@ +/* + * 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 "bsp_io.h" +#include "hal.h" + +#include "drivers/aw9523b.h" +#include "stm32_i2c_driver.h" +#include "stm32_switch_driver.h" + +#define BSP_I2C_BUS I2C_Bus_1 +#define BSP_I2C_ADDR 0x5b + +#define BSP_IN_MASK \ + (AW9523B_PIN_0 | AW9523B_PIN_1 | AW9523B_PIN_2 | AW9523B_PIN_3) + +#define BSP_OUT_MASK \ + (AW9523B_PIN_7 | AW9523B_PIN_8 | AW9523B_PIN_9 | AW9523B_PIN_10 | \ + AW9523B_PIN_11 | AW9523B_PIN_12 | AW9523B_PIN_13 | AW9523B_PIN_14 | \ + AW9523B_PIN_15) + +#define BSP_CHECK(x) if ((x) < 0) return -1 + +static aw9523b_t i2c_exp; + +static uint16_t inputState = 0; +static bool shouldReadKeys = false; + +static void _io_int_handler() +{ + shouldReadKeys = true; +} + +bool bsp_get_shouldReadKeys() +{ + bool tmp = shouldReadKeys; + shouldReadKeys = false; + return tmp; +} + +static void bsp_input_read() +{ + uint16_t value; + if (aw9523b_read(&i2c_exp, BSP_IN_MASK, &value) < 0) return; + inputState = value; +} + +int bsp_io_init() +{ + // init outputs + BSP_CHECK(aw9523b_init(&i2c_exp, BSP_I2C_BUS, BSP_I2C_ADDR)); + BSP_CHECK(aw9523b_write(&i2c_exp, BSP_OUT_MASK, + BSP_KEY_OUT1 | BSP_KEY_OUT2 | BSP_KEY_OUT3 | BSP_KEY_OUT4)); + BSP_CHECK(aw9523b_set_direction(&i2c_exp, 0xFFFF, BSP_IN_MASK)); + + // setup expanders pin change interrupt + gpio_init_int(IO_INT_GPIO, GPIO_IN, GPIO_FALLING, _io_int_handler); + bsp_output_clear(BSP_U6_SELECT); + return 0; +} + +void bsp_output_set(uint16_t pin) { aw9523b_write(&i2c_exp, pin, pin); } + +void bsp_output_set(uint16_t mask, uint16_t pin) { aw9523b_write(&i2c_exp, mask, pin); } + +void bsp_output_clear(uint16_t pin) { aw9523b_write(&i2c_exp, pin, 0); } + +uint16_t bsp_input_get() +{ + bsp_input_read(); + return inputState; +} diff --git a/radio/src/targets/pa01/bsp_io.h b/radio/src/targets/pa01/bsp_io.h new file mode 100644 index 000000000..8055e3912 --- /dev/null +++ b/radio/src/targets/pa01/bsp_io.h @@ -0,0 +1,55 @@ +/* + * 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 "drivers/aw9523b.h" +#include "stm32_switch_driver.h" +#include "hal/switch_driver.h" + +bool getFctKeyState(int index); + +// Input port expander +#define BSP_KEY_IN1 AW9523B_PIN_0 +#define BSP_KEY_IN2 AW9523B_PIN_1 +#define BSP_KEY_IN3 AW9523B_PIN_2 +#define BSP_KEY_IN4 AW9523B_PIN_3 + +// Output port expander +#define BSP_INTMOD_PWR_EN AW9523B_PIN_7 +#define BSP_CHARGE_EN AW9523B_PIN_8 +#define BSP_INTMOD_BOOTCMD AW9523B_PIN_9 +#define BSP_KEY_OUT1 AW9523B_PIN_10 +#define BSP_KEY_OUT2 AW9523B_PIN_11 +#define BSP_KEY_OUT3 AW9523B_PIN_12 +#define BSP_KEY_OUT4 AW9523B_PIN_13 +#define BSP_U6_SELECT AW9523B_PIN_14 +#define BSP_EXTMOD_PWR_EN AW9523B_PIN_15 + +int bsp_io_init(); +bool bsp_get_shouldReadKeys(); + + +void bsp_output_set(uint16_t pin); +void bsp_output_set(uint16_t mask, uint16_t pin); +void bsp_output_clear(uint16_t pin); + +uint16_t bsp_input_get(); diff --git a/radio/src/targets/pa01/extflash_driver.cpp b/radio/src/targets/pa01/extflash_driver.cpp new file mode 100644 index 000000000..2354db468 --- /dev/null +++ b/radio/src/targets/pa01/extflash_driver.cpp @@ -0,0 +1,154 @@ +#include "extflash_driver.h" + +#include "stm32_hal.h" +#include "stm32_qspi.h" + +#include "board.h" + +#define QSPI_NOR_PAGE_SIZE 256 + +int32_t ExtFLASH_Init() +{ + if (stm32_qspi_nor_init() != 0) { + return -1; + } + + return stm32_qspi_nor_memory_mapped(); +} + +void ExtFLASH_InitRuntime() { stm32_qspi_no_init_runtime(); } + +// +// ETX HAL flash interface +// + +static uint32_t extflash_get_size_kb() +{ + return QSPI_FLASH_SIZE / 1024; +} + +static uint32_t extflash_get_sector(uint32_t address) +{ + address -= QSPI_BASE; + return address / (64 * 1024); +} + +static uint32_t extflash_get_sector_size(uint32_t sector) +{ + (void)sector; + return (64 * 1024); +} + +static int extflash_erase_sector(uint32_t address) +{ + address -= QSPI_BASE; + return stm32_qspi_nor_erase_sector(address); +} + +static int extflash_program(uint32_t address, void* data, uint32_t len) +{ + address -= QSPI_BASE; + + int ret = 0; + while (len > 0) { + uint32_t size = (len > QSPI_NOR_PAGE_SIZE) ? QSPI_NOR_PAGE_SIZE : len; + ret = stm32_qspi_nor_program(address, data, size); + if (ret != 0) break; + len -= size; + address += size; + data = (uint8_t*)data + size; + } + + return ret; +} + +static int extflash_read(uint32_t address, void* data, uint32_t len) +{ + address -= QSPI_BASE; + return stm32_qspi_nor_read(address, data, len); +} + +const etx_flash_driver_t extflash_driver = { + .get_size_kb = extflash_get_size_kb, + .get_sector = extflash_get_sector, + .get_sector_size = extflash_get_sector_size, + .erase_sector = extflash_erase_sector, + .program = extflash_program, + .read = extflash_read, +}; + +#if defined(BOOT) +// +// USB DFU interface +// +#include "usbd_dfu.h" + +#define MEDIA_DESC_STR "@External Flash /0x90000000/128*064Kg" + +static uint16_t extflash_dfu_init() +{ + return USBD_OK; +} + +static uint16_t extflash_dfu_deinit() +{ + return USBD_OK; +} + +static uint16_t extflash_dfu_erase(uint32_t address) +{ + if (extflash_erase_sector(address) < 0) { + return USBD_FAIL; + } + return USBD_OK; +} + +static uint16_t extflash_dfu_write(uint8_t* src, uint8_t* dest, uint32_t len) +{ + if (extflash_program((intptr_t)dest, (void*)src, len) < 0) { + return USBD_FAIL; + } + return USBD_OK; +} + +static uint8_t* extflash_dfu_read(uint8_t* src, uint8_t* dest, uint32_t len) +{ + if (extflash_read((intptr_t)src, (void*)dest, len) < 0) { + return nullptr; + } + return dest; +} + +static uint16_t extflash_dfu_get_status(uint32_t address, uint8_t cmd, uint8_t *buffer) +{ + switch (cmd) { + case DFU_MEDIA_PROGRAM: + buffer[1] = 1; + buffer[2] = 0; + buffer[3] = 0; + break; + + case DFU_MEDIA_ERASE: + default: + buffer[1] = 20; + buffer[2] = 0; + buffer[3] = 0; + break; + } + + return USBD_OK; +} + +const USBD_DFU_MediaTypeDef _extflash_dfu_media = { + .pStrDesc = (uint8_t*)MEDIA_DESC_STR, + .Init = extflash_dfu_init, + .DeInit = extflash_dfu_deinit, + .Erase = extflash_dfu_erase, + .Write = extflash_dfu_write, + .Read = extflash_dfu_read, + .GetStatus = extflash_dfu_get_status, +}; + +const void* extflash_dfu_media = &_extflash_dfu_media; + +#endif // BOOT diff --git a/radio/src/targets/pa01/extflash_driver.h b/radio/src/targets/pa01/extflash_driver.h new file mode 100644 index 000000000..c51d6a3aa --- /dev/null +++ b/radio/src/targets/pa01/extflash_driver.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#pragma once + +#include "hal/flash_driver.h" + +extern const etx_flash_driver_t extflash_driver; +extern const void* extflash_dfu_media; + +// init external FLASH hardware +int32_t ExtFLASH_Init(); + +// init only runtime structures +void ExtFLASH_InitRuntime(); diff --git a/radio/src/targets/pa01/extmodule_helper.cpp b/radio/src/targets/pa01/extmodule_helper.cpp new file mode 100644 index 000000000..dbb02e90b --- /dev/null +++ b/radio/src/targets/pa01/extmodule_helper.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "board.h" + +void EXTERNAL_MODULE_ON() +{ + GPIO_SetBits(EXTMODULE_PWR_GPIO, EXTMODULE_PWR_GPIO_PIN); +} + +void EXTERNAL_MODULE_OFF() +{ + GPIO_ResetBits(EXTMODULE_PWR_GPIO, EXTMODULE_PWR_GPIO_PIN); +} + +void extModuleInit() +{ + GPIO_InitTypeDef GPIO_InitStructure; + GPIO_InitStructure.GPIO_Pin = EXTMODULE_TX_INVERT_GPIO_PIN; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; + GPIO_Init(EXTMODULE_TX_INVERT_GPIO, &GPIO_InitStructure); + + GPIO_InitStructure.GPIO_Pin = EXTMODULE_RX_INVERT_GPIO_PIN; + GPIO_Init(EXTMODULE_RX_INVERT_GPIO, &GPIO_InitStructure); + + EXTMODULE_TX_INVERTED(); + EXTMODULE_RX_INVERTED(); +} diff --git a/radio/src/targets/pa01/hal.h b/radio/src/targets/pa01/hal.h new file mode 100644 index 000000000..2bc20e0ec --- /dev/null +++ b/radio/src/targets/pa01/hal.h @@ -0,0 +1,498 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _HAL_H_ +#define _HAL_H_ + +#define CPU_FREQ 400000000 + +#define PERI1_FREQUENCY 100000000 +#define PERI2_FREQUENCY 100000000 +#define TIMER_MULT_APB1 2 +#define TIMER_MULT_APB2 2 + +/* Timers Allocation: + * TIM3 = Haptic / Backlight + * TIM15 = Trainer + * + * TIM14 = 5 ms counter + */ + +/* DMA Allocation: +*/ + +// Keys +#define KEYS_GPIO_REG_ENTER +#define KEYS_GPIO_PIN_ENTER +#define KEYS_GPIO_ENTER GPIO_PIN(GPIOG, 13) // PG.13 + +// Keys in bsp matrix +#define KEYS_GPIO_REG_PAGEUP +#define KEYS_GPIO_PIN_PAGEUP +#define KEYS_GPIO_REG_PAGEDN +#define KEYS_GPIO_PIN_PAGEDN +#define KEYS_GPIO_REG_SYS +#define KEYS_GPIO_PIN_SYS +#define KEYS_GPIO_REG_EXIT +#define KEYS_GPIO_PIN_EXIT + +// Trims in bsp matrix +#define TRIMS_GPIO_REG_LHL +#define TRIMS_GPIO_PIN_LHL + +#define TRIMS_GPIO_REG_LHR +#define TRIMS_GPIO_PIN_LHR + +#define TRIMS_GPIO_REG_LVD +#define TRIMS_GPIO_PIN_LVD + +#define TRIMS_GPIO_REG_LVU +#define TRIMS_GPIO_PIN_LVU + +#define TRIMS_GPIO_REG_RHL +#define TRIMS_GPIO_PIN_RHL + +#define TRIMS_GPIO_REG_RHR +#define TRIMS_GPIO_PIN_RHR + +#define TRIMS_GPIO_REG_RVD +#define TRIMS_GPIO_PIN_RVD + +#define TRIMS_GPIO_REG_RVU +#define TRIMS_GPIO_PIN_RVU + +// function switches +#define FUNCTION_SWITCH_1 SK +#define SWITCHES_GPIO_REG_K +#define SWITCHES_GPIO_PIN_K AW9523B_PIN_0 +#define SWITCHES_K_CFS_IDX 0 +#define FUNCTION_SWITCH_2 SL +#define SWITCHES_GPIO_REG_L +#define SWITCHES_GPIO_PIN_L AW9523B_PIN_1 +#define SWITCHES_L_CFS_IDX 1 +#define FUNCTION_SWITCH_3 SM +#define SWITCHES_GPIO_REG_M +#define SWITCHES_GPIO_PIN_M AW9523B_PIN_2 +#define SWITCHES_M_CFS_IDX 2 +#define FUNCTION_SWITCH_4 SN +#define SWITCHES_GPIO_REG_N +#define SWITCHES_GPIO_PIN_N AW9523B_PIN_3 +#define SWITCHES_N_CFS_IDX 3 + +// Direct switches +// SWA +#define STORAGE_SWITCH_A +#define HARDWARE_SWITCH_A +#define SWITCHES_GPIO_REG_A GPIOA +#define SWITCHES_GPIO_PIN_A LL_GPIO_PIN_2 // PA.02 + +// SWD +#define STORAGE_SWITCH_D +#define HARDWARE_SWITCH_D +#define SWITCHES_GPIO_REG_D GPIOF +#define SWITCHES_GPIO_PIN_D LL_GPIO_PIN_8 // PF.08 + +// SWE +#define STORAGE_SWITCH_E +#define HARDWARE_SWITCH_E +#define SWITCHES_GPIO_REG_E GPIOG +#define SWITCHES_GPIO_PIN_E LL_GPIO_PIN_3 // PG.03 + +// SWF +#define STORAGE_SWITCH_F +#define HARDWARE_SWITCH_F +#define SWITCHES_GPIO_REG_F GPIOG +#define SWITCHES_GPIO_PIN_F LL_GPIO_PIN_2 // PG.02 + +#define KEYS_GPIOB_PINS (LL_GPIO_PIN_15) + +// PC8 allocated to SDIO D0, is not required to sample SWA ! +#define KEYS_GPIOC_PINS (LL_GPIO_PIN_13) + +#define KEYS_GPIOD_PINS () + +#define KEYS_GPIOH_PINS \ + (LL_GPIO_PIN_8 | LL_GPIO_PIN_9 | LL_GPIO_PIN_10 | LL_GPIO_PIN_11) + +#define KEYS_GPIOJ_PINS (LL_GPIO_PIN_12) + +#define KEYS_OUT_GPIOG_PINS (LL_GPIO_PIN_2 ) + +#define KEYS_OUT_GPIOH_PINS (LL_GPIO_PIN_7) + +// ADC +#define ADC_GPIO_PIN_STICK_LH +#define ADC_GPIO_PIN_STICK_LV +#define ADC_GPIO_PIN_STICK_RV +#define ADC_GPIO_PIN_STICK_RH + +#define ADC_GPIO_PIN_SLIDER1 LL_GPIO_PIN_3 // PA.03 S1 +#define ADC_GPIO_PIN_SLIDER2 LL_GPIO_PIN_5 // PA.05 S2 + +#define ADC_GPIO_PIN_SWB LL_GPIO_PIN_5 // PC.05 +#define ADC_GPIO_PIN_SWC LL_GPIO_PIN_7 // PF.07 + +#define ADC_GPIO_PIN_BATT LL_GPIO_PIN_1 // PC.01 + +#define ADC_GPIOA_PINS ( ADC_GPIO_PIN_SLIDER1 | ADC_GPIO_PIN_SLIDER2 ) + +#define ADC_GPIOC_PINS ( ADC_GPIO_PIN_BATT | ADC_GPIO_PIN_SWB ) + +#define ADC_GPIOF_PINS ( ADC_GPIO_PIN_SWC ) + +#define ADC_CHANNEL_STICK_LH +#define ADC_CHANNEL_STICK_LV +#define ADC_CHANNEL_STICK_RV +#define ADC_CHANNEL_STICK_RH + +// Sliders +#define ADC_CHANNEL_SLIDER1 LL_ADC_CHANNEL_15 // ADC12_INP15 +#define ADC_CHANNEL_SLIDER2 LL_ADC_CHANNEL_19 // ADC12_INP19 + +// Analog switches +#define ADC_CHANNEL_SWB LL_ADC_CHANNEL_8 // ADC12_INP8 +#define ADC_CHANNEL_SWC LL_ADC_CHANNEL_3 // ADC3_INP3 + +#define ADC_CHANNEL_BATT LL_ADC_CHANNEL_11 // ADC123_INP11 +#define ADC_CHANNEL_RTC_BAT LL_ADC_CHANNEL_VBAT // ADC12_IN16 + +#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_64CYCLES_5 + +#define ADC_EXT ADC3 +#define ADC_EXT_CHANNELS \ + { ADC_CHANNEL_SWC, ADC_CHANNEL_SWD } + +#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_64CYCLES_5 + +#define ADC_VREF_PREC2 329 + +#define ADC_DIRECTION { \ + 0,0,0,0, /* gimbals */ \ + 0,0, /* sliders */ \ + 0, /* vbat */ \ + 0, /* rtc_bat */ \ + -1, /* SWB */ \ + -1, /* SWC */ \ + 0, /* SWE */ \ + 0 /* SWF */ \ + } + +// Power +#define PWR_SWITCH_GPIO GPIO_PIN(GPIOE, 6) // PE.06 +#define PWR_ON_GPIO GPIO_PIN(GPIOE, 3) // PE.03 +#define SHORT_LONG_PRESS + +// USB Chargers +#define UCHARGER_GPIO GPIO_PIN(GPIOB, 0) // PB.00 +#define UCHARGER_CHARGE_END_GPIO GPIO_PIN(GPIOG, 14) // PG.14 + +#define IO_INT_GPIO GPIO_PIN(GPIOB, 4) // PB.04 +#if !defined(USE_EXTI4_IRQ) + #define USE_EXTI4_IRQ + #define EXTI4_IRQ_Priority 5 +#endif + +// S.Port update connector +#define HAS_SPORT_UPDATE_CONNECTOR() (false) + +// Telemetry + #define TELEMETRY_TX_GPIO GPIO_PIN(GPIOB, 14) + #define TELEMETRY_RX_GPIO GPIO_UNDEF + #define TELEMETRY_USART USART1 + #define TELEMETRY_USART_IRQn USART1_IRQn + #define TELEMETRY_DMA DMA1 + #define TELEMETRY_DMA_Stream_TX LL_DMA_STREAM_7 + #define TELEMETRY_DMA_Channel_TX LL_DMAMUX1_REQ_USART1_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_USART1_RX + #define TELEMETRY_USART_IRQHandler USART1_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(GPIOB, 0) // PB.00 +#define USB_GPIO_DM GPIO_PIN(GPIOA, 11) // PA.11 +#define USB_GPIO_DP GPIO_PIN(GPIOA, 12) // PA.12 +#define USB_GPIO_AF GPIO_AF10 + +// LCD +#define LCD_SPI SPI1 +#define LCD_SPI_DMA DMA1 +#define LCD_SPI_TX_DMA LL_DMAMUX1_REQ_SPI1_TX +#define LCD_SPI_RX_DMA LL_DMAMUX1_REQ_SPI1_RX +#define LCD_SPI_TX_DMA_STREAM LL_DMA_STREAM_4 +#define LCD_SPI_RX_DMA_STREAM LL_DMA_STREAM_5 +#define LCD_FMARK GPIO_PIN(GPIOB, 7) +#define LCD_NRST GPIO_PIN(GPIOD, 7) +#define LCD_SPI_RS GPIO_PIN(GPIOG, 12) +#define LCD_SPI_CS GPIO_PIN(GPIOG, 10) +#define LCD_SPI_CLK GPIO_PIN(GPIOG, 11) +#define LCD_SPI_MOSI GPIO_PIN(GPIOB, 5) +#define LCD_SPI_MISO GPIO_PIN(GPIOG, 9) +#define LCD_SPI_BAUD 100000000 + +// Backlight +#define BACKLIGHT_GPIO GPIO_PIN(GPIOB, 03) // TIM2_CH2 +#define BACKLIGHT_TIMER TIM2 +#define BACKLIGHT_GPIO_AF GPIO_AF1 +#define BACKLIGHT_TIMER_FREQ (PERI1_FREQUENCY * TIMER_MULT_APB1) + +// QSPI Flash +#define QSPI_MAX_FREQ 80000000U // 80 MHz +#define QSPI_CLK_GPIO GPIO_PIN(GPIOB, 2) +#define QSPI_CLK_GPIO_AF GPIO_AF9 +#define QSPI_CS_GPIO GPIO_PIN(GPIOB, 6) +#define QSPI_CS_GPIO_AF GPIO_AF10 +#define QSPI_MISO_GPIO GPIO_PIN(GPIOD, 12) +#define QSPI_MISO_GPIO_AF GPIO_AF9 +#define QSPI_MOSI_GPIO GPIO_PIN(GPIOD, 11) +#define QSPI_MOSI_GPIO_AF GPIO_AF9 +#define QSPI_WP_GPIO GPIO_PIN(GPIOE, 2) +#define QSPI_WP_GPIO_AF GPIO_AF9 +#define QSPI_HOLD_GPIO GPIO_PIN(GPIOD, 13) +#define QSPI_HOLD_GPIO_AF GPIO_AF9 +#define QSPI_FLASH_SIZE 0x800000 +#define QSPI_QE_REG 1 +#define QSPI_QE_BIT (1 << 6) + +// Storage +#define STORAGE_USE_SDIO + +/* + * SDIO pins: + * - SDMMC1_D0-D3 (PC.08-11) + * - SDMMC1_CK (PC.12) + * - SDMMC1_CMD (PD.02) + */ +#define SD_SDIO SDMMC1 +#define SD_SDIO_TRANSFER_CLK_DIV SDMMC_HSPEED_CLK_DIV + +// Audio +#define AUDIO_MUTE_GPIO GPIO_PIN(GPIOE, 4) // PE.04 +#define AUDIO_OUTPUT_GPIO GPIO_PIN(GPIOA, 4) // PA.04 +#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 DMA1_Stream1_IRQn +#define AUDIO_DMA_Stream_IRQHandler DMA1_Stream1_IRQHandler +#define AUDIO_TIMER TIM6 +#define AUDIO_DMA DMA1 +#define AUDIO_UNMUTE_DELAY 100 // ms +#define AUDIO_MUTE_DELAY 100 // ms +#define INVERTED_MUTE_PIN + +// I2C Bus +#define I2C_B1 I2C1 +#define I2C_B1_SDA_GPIO GPIO_PIN(GPIOB, 9) // PB.09 +#define I2C_B1_SCL_GPIO GPIO_PIN(GPIOB, 8) // PB.08 +#define I2C_B1_GPIO_AF LL_GPIO_AF_4 +#define I2C_B1_CLK_RATE 400000 + +#define I2C_B2 I2C2 +#define I2C_B2_SDA_GPIO GPIO_PIN(GPIOB, 10) // PB.10 +#define I2C_B2_SCL_GPIO GPIO_PIN(GPIOB, 11) // PB.11 +#define I2C_B2_GPIO_AF LL_GPIO_AF_4 +#define I2C_B2_CLK_RATE 400000 + + +// Haptic: TIM3_CH2 +#define HAPTIC_PWM +#define HAPTIC_GPIO GPIO_PIN(GPIOA, 15) // PA.15 +#define HAPTIC_GPIO_TIMER TIM2 +#define HAPTIC_GPIO_AF GPIO_AF1 + +// Flysky Hall Stick +#define FLYSKY_HALL_SERIAL_USART USART2 + +#define FLYSKY_HALL_SERIAL_TX_GPIO GPIO_PIN(GPIOD, 5) // PD.05 +#define FLYSKY_HALL_SERIAL_RX_GPIO GPIO_PIN(GPIOD, 6) // PD.06 +#define FLYSKY_HALL_SERIAL_USART_IRQn USART2_IRQn + +#define FLYSKY_HALL_SERIAL_DMA DMA1 +#define FLYSKY_HALL_DMA_Stream_RX LL_DMA_STREAM_2 +#define FLYSKY_HALL_DMA_Stream_TX LL_DMA_STREAM_4 +#define FLYSKY_HALL_DMA_Channel LL_DMAMUX1_REQ_USART2_RX + +// TODO LED Strip PF.06 + +// LED Strip +#define LED_STRIP_LENGTH 14 +#define BLING_LED_STRIP_START 0 +#define BLING_LED_STRIP_LENGTH 10 +#define CFS_LED_STRIP_START 10 +#define CFS_LED_STRIP_LENGTH 4 +#define CFS_LEDS_PER_SWITCH 1 +#define LED_STRIP_GPIO GPIO_PIN(GPIOF, 06) // PF.06 / TIM16_CH1 +#define LED_STRIP_GPIO_AF LL_GPIO_AF_1 // TIM1/2/16/17 +#define LED_STRIP_TIMER TIM16 +#define LED_STRIP_TIMER_FREQ (PERI1_FREQUENCY * TIMER_MULT_APB1) +#define LED_STRIP_TIMER_CHANNEL LL_TIM_CHANNEL_CH1 +#define LED_STRIP_TIMER_DMA DMA1 +#define LED_STRIP_TIMER_DMA_CHANNEL LL_DMAMUX1_REQ_TIM16_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 +#define RGB_LED_OFFSET 10 + +#define STATUS_LEDS + +#define LED_CHARGING_START 0 +#define LED_CHARGING_END 13 + + +// Internal Module +#define INTMODULE_TX_GPIO GPIO_PIN(GPIOA, 0) // PA.00 +#define INTMODULE_RX_GPIO GPIO_PIN(GPIOA, 1) // PA.01 +#define INTMODULE_USART UART4 +#define INTMODULE_GPIO_AF LL_GPIO_AF_8 +#define INTMODULE_USART_IRQn UART4_IRQn +#define INTMODULE_USART_IRQHandler UART4_IRQHandler +#define INTMODULE_DMA DMA2 +#define INTMODULE_DMA_STREAM LL_DMA_STREAM_6 +#define INTMODULE_DMA_CHANNEL LL_DMAMUX1_REQ_UART4_TX +#define INTMODULE_RX_DMA DMA2 +#define INTMODULE_RX_DMA_STREAM LL_DMA_STREAM_5 +#define INTMODULE_RX_DMA_CHANNEL LL_DMAMUX1_REQ_UART4_RX +#define INTMODULE_BOOTCMD_BSP + +// External Module +#define EXTMODULE +#define EXTMODULE_PULSES +#define EXTMODULE_TX_GPIO GPIO_PIN(GPIOC, 6) // PC.06 +#define EXTMODULE_RX_GPIO GPIO_PIN(GPIOC, 7) // PC.07 +#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_RX_GPIO GPIO_PIN(GPIOC, 7) // PC.07 +#define EXTMODULE_USART_TX_GPIO GPIO_PIN(GPIOC, 6) // PC.06 +#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_1 + +#define EXTMODULE_USART_RX_DMA_CHANNEL LL_DMAMUX1_REQ_USART6_RX +#define EXTMODULE_USART_RX_DMA_STREAM LL_DMA_STREAM_3 + +#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_1 +#define EXTMODULE_TIMER_DMA_STREAM_IRQn DMA2_Stream1_IRQn +#define EXTMODULE_TIMER_DMA_IRQHandler DMA2_Stream1_IRQHandler + +// Trainer Port +#define TRAINER_RCC_AHB1Periph (RCC_AHB1Periph_GPIOD) + +#define TRAINER_IN_GPIO GPIO_PIN(GPIOA, 10) // PA.10 +#define TRAINER_IN_TIMER_Channel LL_TIM_CHANNEL_CH3 + +#define TRAINER_OUT_GPIO GPIO_PIN(GPIOA, 9) // PA.09 +#define TRAINER_OUT_TIMER_Channel LL_TIM_CHANNEL_CH2 + +#define TRAINER_TIMER TIM1 +#define TRAINER_TIMER_IRQn TIM1_CC_IRQn +#define TRAINER_TIMER_IRQHandler TIM1_CC_IRQHandler +#define TRAINER_GPIO_AF LL_GPIO_AF_1 +#define TRAINER_TIMER_FREQ (PERI1_FREQUENCY * TIMER_MULT_APB1) + +#define TOUCH_I2C_BUS I2C_Bus_1 +#define TOUCH_I2C_CLK_RATE 100000 + + +// Rotary Encoder +#define ROTARY_ENCODER_NAVIGATION +#define ROTARY_ENCODER_GPIO GPIOA +#define ROTARY_ENCODER_GPIO_PIN_A LL_GPIO_PIN_6 // PA.06 +#define ROTARY_ENCODER_GPIO_PIN_B LL_GPIO_PIN_7 // PA.07 +#define ROTARY_ENCODER_POSITION() ((ROTARY_ENCODER_GPIO->IDR >> 6) & 0x03) +#define ROTARY_ENCODER_EXTI_LINE1 LL_EXTI_LINE_6 +#define ROTARY_ENCODER_EXTI_LINE2 LL_EXTI_LINE_7 +// port extender interrupt +#if !defined(USE_EXTI9_5_IRQ) + #define USE_EXTI9_5_IRQ + #define EXTI9_5_IRQ_Priority 5 +#endif +#define ROTARY_ENCODER_EXTI_PORT 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 timer +#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 + +// IMU / Gyro +#define IMU_I2C_BUS I2C_Bus_2 +#define IMU_I2C_ADDRESS 0x6A + +#define LCD_W 320 +#define LCD_H 240 + +#define LCD_PHYS_W LCD_W +#define LCD_PHYS_H LCD_H + +#define LCD_DEPTH 16 + +#endif // _HAL_H_ diff --git a/radio/src/targets/pa01/haptic_driver.cpp b/radio/src/targets/pa01/haptic_driver.cpp new file mode 100644 index 000000000..60e460b06 --- /dev/null +++ b/radio/src/targets/pa01/haptic_driver.cpp @@ -0,0 +1,60 @@ +/* + * 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 "stm32_gpio.h" +#include "stm32_timer.h" +#include "stm32_pulse_driver.h" + +#include "board.h" + +#define HAPTIC_TIMER_FREQ 200000000 + +static const stm32_pulse_timer_t _haptic_timer = { + .GPIO = (gpio_t)HAPTIC_GPIO, + .GPIO_Alternate = HAPTIC_GPIO_AF, + .TIMx = HAPTIC_GPIO_TIMER, + .TIM_Freq = HAPTIC_TIMER_FREQ, + .TIM_Channel = LL_TIM_CHANNEL_CH1, + .TIM_IRQn = (IRQn_Type)-1, + .DMAx = nullptr, + .DMA_Stream = 0, + .DMA_Channel = 0, + .DMA_IRQn = (IRQn_Type)-1, + .DMA_TC_CallbackPtr = nullptr, +}; + +void hapticInit(void) +{ + stm32_pulse_init(&_haptic_timer, 10000); + stm32_pulse_config_output(&_haptic_timer, true, LL_TIM_OCMODE_PWM1, 0); + LL_TIM_SetAutoReload(_haptic_timer.TIMx, 100); + LL_TIM_EnableCounter(_haptic_timer.TIMx); +} + +void hapticOn(uint32_t pwmPercent) +{ + if (pwmPercent > 100) pwmPercent = 100; + stm32_pulse_set_cmp_val(&_haptic_timer, pwmPercent); +} + +void hapticOff(void) { hapticOn(0); } +void hapticDone(void) { hapticOff(); } diff --git a/radio/src/targets/pa01/key_driver.cpp b/radio/src/targets/pa01/key_driver.cpp new file mode 100644 index 000000000..e8435d255 --- /dev/null +++ b/radio/src/targets/pa01/key_driver.cpp @@ -0,0 +1,204 @@ +/* + * 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/key_driver.h" + +#include "bsp_io.h" +#include "stm32_hal_ll.h" +#include "stm32_gpio_driver.h" +#include "stm32_i2c_driver.h" + +#include "hal.h" +#include "delays_driver.h" +#include "keys.h" + +#define BSP_READ_AFTER_WRITE_DELAY 10 // us +#define BSP_KEY_OUT_MASK \ + (BSP_KEY_OUT1 | BSP_KEY_OUT2 | BSP_KEY_OUT3 | BSP_KEY_OUT4) + +/* The output bit-order has to be: + 0 LHL TR3L (Left equals down) + 1 LHR TR3R + 2 LVD TR1D + 3 LVU TR1U + 4 RVD TR2D + 5 RVU TR2U + 6 RHL TR4L + 7 RHR TR4R +*/ + +enum PhysicalKeys +{ + // Trims + TR3L = 0, + TR3R, + TR1D = 2, + TR1U, + TR2D = 4, + TR2U, + TR4L = 6, + TR4R, + // Keys + PGUP = 8, + PGDN, + RTN = 10, + MODEL, + KEY1 = 12, + KEY2, + KEY3 = 14, + KEY4, + ENT = 16 +}; + +static bool fct_state[4] = {false, false, false, false}; +static uint32_t keyState = 0; +static uint32_t nonReadCount = 0; + +static uint32_t _readKeyMatrix() +{ +#if !defined(BOOT) + if(!bsp_get_shouldReadKeys() && nonReadCount < 10) + { + if (gpio_read(KEYS_GPIO_ENTER) == 0) + keyState |= 1< 1) return syncelem.oldResult; + + // If we land here, we have exclusive access to Matrix + bsp_output_set(BSP_KEY_OUT_MASK, ~BSP_KEY_OUT1); + delay_us(BSP_READ_AFTER_WRITE_DELAY); + bsp_input = bsp_input_get(); + if ((bsp_input & BSP_KEY_IN1) == 0) + result |= 1<> 8), + (uint8_t)(start & 0xFF), + (uint8_t)(end >> 8), + (uint8_t)(end & 0xFF), + }; + + stm32_spi_select(&lcdSpi); + + LCD_COMMAND_MODE(); + stm32_spi_transfer_byte(&lcdSpi, cmd); + + LCD_DATA_MODE(); + stm32_spi_transfer_bytes(&lcdSpi, (uint8_t *)buf, nullptr, sizeof(buf)); + + stm32_spi_unselect(&lcdSpi); +} + +static inline void set_column_addr(uint16_t xs, uint16_t xe) +{ + write_start_end(CASET, xs, xe); +} + +static inline void set_row_addr(uint16_t ys, uint16_t ye) +{ + write_start_end(RASET, ys, ye); +} + +static void memory_write(const uint16_t* data, uint32_t length) +{ + stm32_spi_select(&lcdSpi); + + LCD_COMMAND_MODE(); + stm32_spi_transfer_byte(&lcdSpi, RAMWR); + + LCD_DATA_MODE(); + stm32_spi_set_data_width(&lcdSpi, LL_SPI_DATAWIDTH_16BIT); + + SCB_CleanDCache_by_Addr((void *)data, length * sizeof(uint16_t)); + stm32_spi_dma_transmit_words(&lcdSpi, data, length); + + stm32_spi_unselect(&lcdSpi); + stm32_spi_set_data_width(&lcdSpi, LL_SPI_DATAWIDTH_8BIT); +} + +static void startLcdRefresh(lv_disp_drv_t *disp_drv, uint16_t *buffer, + const rect_t ©_area) +{ + (void)disp_drv; + + // TODO: replace through some smarter mechanism without busy wait + while (!gpio_read(LCD_FMARK)); + + coord_t x1 = copy_area.x; + coord_t x2 = x1 + copy_area.w - 1; + set_column_addr(x1, x2); + + coord_t y1 = copy_area.y; + coord_t y2 = y1 + copy_area.h - 1; + set_row_addr(y1, y2); + + memory_write(buffer, copy_area.w * copy_area.h); +} + +lcdSpiInitFucPtr lcdInitFunction; +lcdSpiInitFucPtr lcdOffFunction; +lcdSpiInitFucPtr lcdOnFunction; +uint32_t lcdPixelClock; + +static void lcdSpiConfig(void) +{ + stm32_spi_init(&lcdSpi, LL_SPI_DATAWIDTH_8BIT); + stm32_spi_set_max_baudrate(&lcdSpi, LCD_SPI_BAUD); + + gpio_init(LCD_FMARK, GPIO_IN, GPIO_PIN_SPEED_HIGH); + gpio_init(LCD_NRST, GPIO_OUT, GPIO_PIN_SPEED_HIGH); + gpio_init(LCD_SPI_RS, GPIO_OUT, GPIO_PIN_SPEED_HIGH); +} + +void lcdDelay() { + delay_01us(1); +} + +static void lcdReset() { + LCD_NRST_HIGH(); + delay_ms(1); + + LCD_NRST_LOW(); // RESET(); + delay_ms(100); + + LCD_NRST_HIGH(); + delay_ms(120); +} + +static void lcdWriteCommand(uint8_t cmd) +{ + LCD_COMMAND_MODE(); + stm32_spi_select(&lcdSpi); + stm32_spi_transfer_byte(&lcdSpi, cmd); + stm32_spi_unselect(&lcdSpi); +} + +// static void lcdWriteReg(uint8_t reg, uint8_t data) +// { +// LCD_COMMAND_MODE(); +// stm32_spi_select(&lcdSpi); +// stm32_spi_transfer_byte(&lcdSpi, reg); +// LCD_DATA_MODE(); +// stm32_spi_transfer_byte(&lcdSpi, data); +// stm32_spi_unselect(&lcdSpi); +// } + +static void lcdWriteData(uint8_t data) +{ + LCD_DATA_MODE(); + stm32_spi_select(&lcdSpi); + stm32_spi_transfer_byte(&lcdSpi, data); + stm32_spi_unselect(&lcdSpi); +} + +// static uint8_t lcdReadReg(uint8_t reg) +// { +// uint8_t data = 0; +// LCD_COMMAND_MODE(); +// stm32_spi_select(&lcdSpi); +// stm32_spi_transfer_byte(&lcdSpi, reg); +// LCD_DATA_MODE(); +// data = stm32_spi_transfer_byte(&lcdSpi, 0xFF); +// stm32_spi_unselect(&lcdSpi); +// return data; +// } + +extern "C" void lcdSetInitalFrameBuffer(void *fbAddress) +{ + initialFrameBuffer = fbAddress; +} + +static void lcdSetOn(void) { lcdWriteCommand(0x29); } +static void lcdSetOff(void) { lcdWriteCommand(0x28); } + +extern "C" void lcdInit() +{ + // Configure the LCD SPI + RESET pins + lcdSpiConfig(); + stm32_spi_unselect(&lcdSpi); + + // hard reset + lcdReset(); + + // Init command start + lcdWriteCommand( 0xFE ); + lcdWriteCommand( 0xEF ); + + // Display orientation + lcdWriteCommand( 0x36 ); + lcdWriteData( 0xE8 ); + + // Color mode + lcdWriteCommand( 0x3A ); + lcdWriteData( 0x05 ); // 16-bit color + + // Display control + lcdWriteCommand( 0x86 ); + lcdWriteData( 0x98 ); + lcdWriteCommand( 0x89 ); + lcdWriteData( 0x33 ); + lcdWriteCommand( 0x8B ); + lcdWriteData( 0x80 ); + lcdWriteCommand( 0x8D ); + lcdWriteData( 0x33 ); + lcdWriteCommand( 0x3A ); + lcdWriteData( 0x05 ); + lcdWriteCommand( 0x8E ); + lcdWriteData( 0x0F ); + + lcdWriteCommand( 0xEC ); + lcdWriteData( 0x33 ); + lcdWriteData( 0x07 ); + lcdWriteData( 0x00 ); + + lcdWriteCommand( 0xED ); + lcdWriteData( 0x18 ); + lcdWriteData( 0x08 ); + + lcdWriteCommand( 0xE8 ); + lcdWriteData( 0x12 ); + lcdWriteData( 0x00 ); + + // Init command ends + lcdWriteCommand( 0xFF ); + lcdWriteCommand( 0x62 ); + + // Display control + lcdWriteCommand( 0x99 ); + lcdWriteData( 0x3E ); + lcdWriteCommand( 0x9D ); + lcdWriteData( 0x4B ); + lcdWriteCommand( 0x98 ); + lcdWriteData( 0x3E ); + lcdWriteCommand( 0x9C ); + lcdWriteData( 0x4B ); + lcdWriteCommand( 0xC3 ); + lcdWriteData( 0x39 ); + lcdWriteCommand( 0xC4 ); + lcdWriteData( 0x29 ); + lcdWriteCommand( 0xC9 ); + lcdWriteData( 0x09 ); + + // Gamma Control + lcdWriteCommand( 0xF0 ); + lcdWriteData( 0x0B ); + lcdWriteData( 0x0C ); + lcdWriteData( 0x07 ); + lcdWriteData( 0x07 ); + lcdWriteData( 0x05 ); + lcdWriteData( 0x22 ); + lcdWriteCommand( 0xF1); + lcdWriteData( 0x42 ); + lcdWriteData( 0x78 ); + lcdWriteData( 0x56 ); + lcdWriteData( 0x1E ); + lcdWriteData( 0x1A ); + lcdWriteData( 0x95 ); + lcdWriteCommand( 0xF2 ); + lcdWriteData( 0x0B ); + lcdWriteData( 0x0C ); + lcdWriteData( 0x07 ); + lcdWriteData( 0x07 ); + lcdWriteData( 0x05 ); + lcdWriteData( 0x44 ); + lcdWriteCommand( 0xF3 ); + lcdWriteData( 0x56 ); + lcdWriteData( 0x92 ); + lcdWriteData( 0x30 ); + lcdWriteData( 0x31 ); + lcdWriteData( 0x35 ); + lcdWriteData( 0x7F ); + + // Display orientation + lcdWriteCommand( 0x36 ); + lcdWriteData( 0xA0 ); + + // Display size + lcdWriteCommand( 0x2A ); + lcdWriteData( 0x00 ); + lcdWriteData( 0x00 ); + lcdWriteData( 0x01 ); + lcdWriteData( 0x40 ); + lcdWriteCommand( 0x2B ); + lcdWriteData( 0x00 ); + lcdWriteData( 0x00 ); + lcdWriteData( 0x00 ); + lcdWriteData( 0xF0 ); + + // No, invert color + lcdWriteCommand( 0x20 ); + + // Tear on + lcdWriteCommand( 0x35 ); + + // Exit sleep + lcdWriteCommand( 0x11 ); + + // Init LCD RAM + memory_write((const uint16_t*)initialFrameBuffer, LCD_W * LCD_H); + + lcdSetOn(); + + lcdOnFunction = lcdSetOn; + lcdOffFunction = lcdSetOff; + + lcdSetFlushCb(startLcdRefresh); +} diff --git a/radio/src/targets/pa01/lcd_driver.h b/radio/src/targets/pa01/lcd_driver.h new file mode 100644 index 000000000..9c0410f71 --- /dev/null +++ b/radio/src/targets/pa01/lcd_driver.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __LCD_DRIVER_H__ +#define __LCD_DRIVER_H__ + +#define LCD_DELAY() LCD_Delay() + +typedef void (*lcdSpiInitFucPtr)(void); + +extern lcdSpiInitFucPtr lcdInitFunction; +extern lcdSpiInitFucPtr lcdOffFunction; +extern lcdSpiInitFucPtr lcdOnFunction; + +#define LCD_NRST_HIGH() gpio_set(LCD_NRST) +#define LCD_NRST_LOW() gpio_clear(LCD_NRST) +#define LCD_COMMAND_MODE() gpio_clear(LCD_SPI_RS) +#define LCD_DATA_MODE() gpio_set(LCD_SPI_RS) + +#endif + + + + diff --git a/radio/src/targets/pa01/led_driver.cpp b/radio/src/targets/pa01/led_driver.cpp new file mode 100644 index 000000000..17c633f43 --- /dev/null +++ b/radio/src/targets/pa01/led_driver.cpp @@ -0,0 +1,127 @@ +/* + * 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/rgbleds.h" +#include "stm32_gpio.h" +#include "stm32_ws2812.h" + +#include "boards/generic_stm32/rgb_leds.h" +#include "board.h" +#if defined(LED_STRIP_GPIO) +#include "boards/generic_stm32/rgb_leds.h" +#endif + +#define GET_RED(color) (((color) & 0xF80000) >>16) +#define GET_GREEN(color) (((color) & 0x000F800) >> 8) +#define GET_BLUE(color) (((color) & 0xF8)) + +#if defined(FUNCTION_SWITCHES) && !defined(FUNCTION_SWITCHES_RGB_LEDS) +static const uint32_t fsLeds[] = {FSLED_GPIO_PIN_1, FSLED_GPIO_PIN_2, + FSLED_GPIO_PIN_3, FSLED_GPIO_PIN_4, + FSLED_GPIO_PIN_5, FSLED_GPIO_PIN_6}; +#endif + +void ledInit() +{ +#if defined(LED_GREEN_GPIO) + gpio_init(LED_GREEN_GPIO, GPIO_OUT, GPIO_PIN_SPEED_LOW); +#endif + +#if defined(LED_RED_GPIO) + gpio_init(LED_RED_GPIO, GPIO_OUT, GPIO_PIN_SPEED_LOW); +#endif + +#if defined(LED_BLUE_GPIO) + gpio_init(LED_BLUE_GPIO, GPIO_OUT, GPIO_PIN_SPEED_LOW); +#endif + +#if defined(FUNCTION_SWITCHES) && !defined(FUNCTION_SWITCHES_RGB_LEDS) + for (size_t i = 0; i < DIM(fsLeds); i++) { + gpio_init(fsLeds[i], GPIO_OUT, GPIO_PIN_SPEED_LOW); + } +#endif +} + +#if defined(FUNCTION_SWITCHES_RGB_LEDS) +// used to map switch number to led number in the rgbled chain +uint8_t ledMapping[] = {4, 6, 0, 2}; + +void fsLedRGB(uint8_t index, uint32_t color) +{ + ws2812_set_color(ledMapping[index], GET_RED(color), + GET_GREEN(color),GET_BLUE(color)); + ws2812_set_color(ledMapping[index]+1, GET_RED(color), + GET_GREEN(color),GET_BLUE(color)); +} + +uint32_t fsGetLedRGB(uint8_t index) +{ + return rgbGetLedColor(ledMapping[index]); +} +uint8_t getRGBColorIndex(uint32_t color) +{ + for (uint8_t i = 0; i < (sizeof(colorTable) / sizeof(colorTable[0])); i++) { + if (color == colorTable[i]) + return(i); + } + return 5; // Custom value set with Companion +} +#elif defined(FUNCTION_SWITCHES) +void fsLedOff(uint8_t index) +{ + gpio_clear(fsLeds[index]); +} + +void fsLedOn(uint8_t index) +{ + gpio_set(fsLeds[index]); +} + +bool fsLedState(uint8_t index) +{ + return gpio_read(fsLeds[index]) ? true : false; +} +#endif + +void ledOff() +{ + ws2812_set_color(8, 0, 0, 0); + ws2812_set_color(9, 0, 0, 0); +} + +void ledRed() +{ + ws2812_set_color(8, 20, 0, 0); + ws2812_set_color(9, 20, 0, 0); +} + +void ledGreen() +{ + ws2812_set_color(8, 0, 20, 0); + ws2812_set_color(9, 0, 20, 0); +} + +void ledBlue() +{ + ws2812_set_color(8, 0, 0, 20); + ws2812_set_color(9, 0, 0, 20); +} diff --git a/radio/src/targets/pa01/libopenui_config.h b/radio/src/targets/pa01/libopenui_config.h new file mode 100644 index 000000000..7fa1b09a6 --- /dev/null +++ b/radio/src/targets/pa01/libopenui_config.h @@ -0,0 +1,27 @@ +/* + * 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 + +constexpr coord_t INPUT_EDIT_CURVE_WIDTH = 132; +constexpr coord_t INPUT_EDIT_CURVE_HEIGHT = INPUT_EDIT_CURVE_WIDTH; +constexpr coord_t MENUS_MAX_HEIGHT = (MENUS_LINE_HEIGHT * 8) + 8; + diff --git a/radio/src/targets/pa01/sdram_driver.cpp b/radio/src/targets/pa01/sdram_driver.cpp new file mode 100644 index 000000000..03a9ef7cf --- /dev/null +++ b/radio/src/targets/pa01/sdram_driver.cpp @@ -0,0 +1,279 @@ +/* + * Copyright (C) OpenTX + * + * Based on code named + * 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 "stm32_gpio.h" +#include "stm32_hal_ll.h" + +#include "board.h" + +#define SDRAM_MEMORY_WIDTH FMC_SDRAM_MEM_BUS_WIDTH_16 + +#define SDRAM_CAS_LATENCY FMC_SDRAM_CAS_LATENCY_3 + +#define SDCLOCK_PERIOD FMC_SDRAM_CLOCK_PERIOD_3 + +#define SDRAM_TIMEOUT ((uint32_t)0xFFFF) + +#define SDRAM_READBURST FMC_SDRAM_RBURST_DISABLE + +#define SDRAM_MODEREG_BURST_LENGTH_1 ((uint16_t)0x0000) +#define SDRAM_MODEREG_BURST_LENGTH_2 ((uint16_t)0x0001) +#define SDRAM_MODEREG_BURST_LENGTH_4 ((uint16_t)0x0002) +#define SDRAM_MODEREG_BURST_LENGTH_8 ((uint16_t)0x0004) +#define SDRAM_MODEREG_BURST_FULL_PAGE ((uint16_t)0x0007) +#define SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL ((uint16_t)0x0000) +#define SDRAM_MODEREG_BURST_TYPE_INTERLEAVED ((uint16_t)0x0008) +#define SDRAM_MODEREG_CAS_LATENCY_1 ((uint16_t)0x0010) +#define SDRAM_MODEREG_CAS_LATENCY_2 ((uint16_t)0x0020) +#define SDRAM_MODEREG_CAS_LATENCY_3 ((uint16_t)0x0030) +#define SDRAM_MODEREG_OPERATING_MODE_STANDARD ((uint16_t)0x0000) +#define SDRAM_MODEREG_WRITEBURST_MODE_PROGRAMMED ((uint16_t)0x0000) +#define SDRAM_MODEREG_WRITEBURST_MODE_SINGLE ((uint16_t)0x0200) + +#define GPIO_AF_FMC GPIO_AF12 + +extern "C" void SDRAM_GPIOConfig(void) +{ + // __HAL_RCC_SYSCFG_CLK_ENABLE(); // needed for syscfg register, to route P2C and P3C pins to the AF + /*-- GPIOs Configuration -----------------------------------------------------*/ + /* + */ + + /* GPIOD configuration */ + gpio_init_af(GPIO_PIN(GPIOD, 0), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOD, 1), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOD, 8), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOD, 9), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOD, 10), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOD, 14), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOD, 15), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + + /* GPIOE configuration */ + gpio_init_af(GPIO_PIN(GPIOE, 0), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOE, 1), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOE, 7), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOE, 8), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOE, 9), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOE, 10), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOE, 11), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOE, 12), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOE, 13), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOE, 14), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOE, 15), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + + /* GPIOF configuration */ + gpio_init_af(GPIO_PIN(GPIOF, 0), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOF, 1), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOF, 2), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOF, 3), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOF, 4), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOF, 5), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOF, 11), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOF, 12), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOF, 13), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOF, 14), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOF, 15), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + + /* GPIOG configuration */ + gpio_init_af(GPIO_PIN(GPIOG, 0), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOG, 1), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOG, 4), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOG, 5), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOG, 8), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOG, 15), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + + + gpio_init_af(GPIO_PIN(GPIOC, 0), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOC, 2), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + gpio_init_af(GPIO_PIN(GPIOC, 3), GPIO_AF_FMC, GPIO_PIN_SPEED_VERY_HIGH); + +} + +extern "C" void SDRAM_InitSequence(void) +{ + FMC_SDRAM_CommandTypeDef FMC_SDRAMCommandStructure; + uint32_t tmpr = 0; + uint32_t timeout = SDRAM_TIMEOUT; + + /* Step 3 --------------------------------------------------------------------*/ + /* Configure a clock configuration enable command */ + FMC_SDRAMCommandStructure.CommandMode = FMC_SDRAM_CMD_CLK_ENABLE; + FMC_SDRAMCommandStructure.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1; + FMC_SDRAMCommandStructure.AutoRefreshNumber = 1; + FMC_SDRAMCommandStructure.ModeRegisterDefinition = 0; + /* Wait until the SDRAM controller is ready */ + // while((__FMC_SDRAM_GET_FLAG(FMC_Bank5_6_R, FMC_SDRAM_FLAG_BUSY) != 0) && + // (timeout > 0)) + // { + // timeout--; + // } + /* Send the command */ + FMC_SDRAM_SendCommand(FMC_Bank5_6_R, &FMC_SDRAMCommandStructure, 10); + + /* Step 4 --------------------------------------------------------------------*/ + /* Insert 1 ms delay */ + delay_ms(100); + + /* Step 5 --------------------------------------------------------------------*/ + /* Configure a PALL (precharge all) command */ + FMC_SDRAMCommandStructure.CommandMode = FMC_SDRAM_CMD_PALL; + FMC_SDRAMCommandStructure.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1; + FMC_SDRAMCommandStructure.AutoRefreshNumber = 1; + FMC_SDRAMCommandStructure.ModeRegisterDefinition = 0; + /* Wait until the SDRAM controller is ready */ + // timeout = SDRAM_TIMEOUT; + // while((__FMC_SDRAM_GET_FLAG(FMC_Bank5_6_R, FMC_SDRAM_FLAG_BUSY) != 0) && (timeout > 0)) + // { + // timeout--; + // } + /* Send the command */ + FMC_SDRAM_SendCommand(FMC_Bank5_6_R, &FMC_SDRAMCommandStructure, 10); + // delay_ms(1); + + /* Step 6 --------------------------------------------------------------------*/ + /* Configure a Auto-Refresh command */ + FMC_SDRAMCommandStructure.CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE; + FMC_SDRAMCommandStructure.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1; + FMC_SDRAMCommandStructure.AutoRefreshNumber = 8; + FMC_SDRAMCommandStructure.ModeRegisterDefinition = 0; + + /* Wait until the SDRAM controller is ready */ + // timeout = SDRAM_TIMEOUT; + // while((__FMC_SDRAM_GET_FLAG(FMC_Bank5_6_R, FMC_SDRAM_FLAG_BUSY) != 0) && + // (timeout > 0)) + // { + // timeout--; + // } + /* Send the command */ + FMC_SDRAM_SendCommand(FMC_Bank5_6_R, &FMC_SDRAMCommandStructure, 10); + // delay_ms(1); + + /* Step 7 --------------------------------------------------------------------*/ + /* Program the external memory mode register */ + tmpr = (uint32_t)SDRAM_MODEREG_BURST_LENGTH_2 | + SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL | + SDRAM_MODEREG_CAS_LATENCY_3 | + SDRAM_MODEREG_OPERATING_MODE_STANDARD | + SDRAM_MODEREG_WRITEBURST_MODE_SINGLE; + + /* Configure a load Mode register command*/ + FMC_SDRAMCommandStructure.CommandMode = FMC_SDRAM_CMD_LOAD_MODE; + FMC_SDRAMCommandStructure.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1; + FMC_SDRAMCommandStructure.AutoRefreshNumber = 1; + FMC_SDRAMCommandStructure.ModeRegisterDefinition = tmpr; + + /* Wait until the SDRAM controller is ready */ + // timeout = SDRAM_TIMEOUT; + // while((__FMC_SDRAM_GET_FLAG(FMC_Bank5_6_R, FMC_SDRAM_FLAG_BUSY) != 0) && (timeout > 0)) + // { + // timeout--; + // } + /* Send the command */ + FMC_SDRAM_SendCommand(FMC_Bank5_6_R, &FMC_SDRAMCommandStructure, 10); + // delay_ms(1); + + /* Step 8 --------------------------------------------------------------------*/ + /* Set the refresh rate counter */ + /* (15.62 us x Freq) - 20 */ + /* Set the device refresh counter */ + FMC_SDRAM_SetAutoRefreshNumber(FMC_Bank5_6_R, 15); + FMC_SDRAM_ProgramRefreshRate(FMC_Bank5_6_R, 1855); + /* Wait until the SDRAM controller is ready */ + // timeout = SDRAM_TIMEOUT; + // while((__FMC_SDRAM_GET_FLAG(FMC_Bank5_6_R, FMC_SDRAM_FLAG_BUSY) != 0) && (timeout > 0)) + // { + // timeout--; + // } + // delay_ms(1); +} + +extern "C" void SDRAM_Init(void) +{ + //delay funcion needed + delaysInit(); + + /* GPIO configuration for FMC SDRAM bank */ + SDRAM_GPIOConfig(); + + /* Enable FMC clock */ + LL_AHB3_GRP1_EnableClock(LL_AHB3_GRP1_PERIPH_FMC); + + /* FMC Configuration ---------------------------------------------------------*/ + FMC_SDRAM_InitTypeDef FMC_SDRAMInitStructure; + FMC_SDRAM_TimingTypeDef FMC_SDRAMTimingInitStructure; + + /* FMC SDRAM Bank configuration */ + /* Timing configuration for 80 Mhz of SD clock */ + FMC_SDRAMTimingInitStructure.LoadToActiveDelay = 2; + FMC_SDRAMTimingInitStructure.ExitSelfRefreshDelay = 7; + FMC_SDRAMTimingInitStructure.SelfRefreshTime = 4; + FMC_SDRAMTimingInitStructure.RowCycleDelay = 7; + FMC_SDRAMTimingInitStructure.WriteRecoveryTime = 3; + FMC_SDRAMTimingInitStructure.RPDelay = 2; + FMC_SDRAMTimingInitStructure.RCDDelay = 2; + + /* FMC SDRAM control configuration */ + FMC_SDRAMInitStructure.SDBank = FMC_SDRAM_BANK1; + FMC_SDRAMInitStructure.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_8; + FMC_SDRAMInitStructure.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_12; + FMC_SDRAMInitStructure.MemoryDataWidth = FMC_SDRAM_MEM_BUS_WIDTH_16; + FMC_SDRAMInitStructure.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4; + FMC_SDRAMInitStructure.CASLatency = FMC_SDRAM_CAS_LATENCY_3; + FMC_SDRAMInitStructure.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE; + FMC_SDRAMInitStructure.SDClockPeriod = FMC_SDRAM_CLOCK_PERIOD_3; + FMC_SDRAMInitStructure.ReadBurst = FMC_SDRAM_RBURST_ENABLE; + FMC_SDRAMInitStructure.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_0; + + /* FMC SDRAM bank initialization */ + FMC_SDRAM_Init(FMC_Bank5_6_R, &FMC_SDRAMInitStructure); + FMC_SDRAM_Timing_Init(FMC_Bank5_6_R, &FMC_SDRAMTimingInitStructure, FMC_SDRAM_BANK1); + + __FMC_ENABLE(); + + /* FMC SDRAM device initialization sequence */ + SDRAM_InitSequence(); + + + uint32_t data = 0x12345678; + uint32_t* base = (uint32_t*)0xc0000000; + while(true&&0) + { + uint32_t dataStart = data; + uint32_t buf=dataStart; + for(int i=0; i<(8*1024*1024)/4; ++i) + { + base[i] = buf; + __asm__ ("ror %0, %1, %2" : "=r" (buf) : "r" (buf), "M" (1)); + } + buf=dataStart; + SCB_CleanDCache(); + delay_ms(100); + SCB_InvalidateDCache(); + for(int i=0; i<(8*1024*1024)/4; ++i) + { + if(base[i] != buf) + asm("bkpt"); + __asm__ ("ror %0, %1, %2" : "=r" (buf) : "r" (buf), "M" (1)); + } + + __asm__ ("ror %0, %1, %2" : "=r" (data) : "r" (data), "M" (1)); + } +} diff --git a/radio/src/targets/pa01/system_clock.c b/radio/src/targets/pa01/system_clock.c new file mode 100644 index 000000000..86ff40a31 --- /dev/null +++ b/radio/src/targets/pa01/system_clock.c @@ -0,0 +1,116 @@ +/* + * 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 "stm32h7xx_ll_pwr.h" +#include "stm32h7xx_ll_rcc.h" +#include "stm32h7xx_ll_system.h" +#include "stm32h7xx_ll_bus.h" + +#define BOOTSTRAP __attribute__((section(".bootstrap"))) + +BOOTSTRAP void SystemClock_Config(void) +{ + /* Power Configuration */ + LL_PWR_ConfigSupply(LL_PWR_EXTERNAL_SOURCE_SUPPLY); + LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1); + while (LL_PWR_IsActiveFlag_VOS() == 0){ + } + + /* Enable HSE oscillator */ + LL_RCC_HSE_Enable(); + while (LL_RCC_HSE_IsReady() != 1) { + } + + /* Set FLASH latency */ + LL_FLASH_SetLatency(LL_FLASH_LATENCY_5); + + /* Main PLL configuration and activation */ + LL_RCC_PLL_SetSource(LL_RCC_PLLSOURCE_HSE); + LL_RCC_PLL1P_Enable(); + LL_RCC_PLL1Q_Enable(); + LL_RCC_PLL1R_Enable(); + LL_RCC_PLL1FRACN_Disable(); + LL_RCC_PLL1_SetVCOInputRange(LL_RCC_PLLINPUTRANGE_2_4); + LL_RCC_PLL1_SetVCOOutputRange(LL_RCC_PLLVCORANGE_WIDE); + LL_RCC_PLL1_SetM(3); + LL_RCC_PLL1_SetN(200); + LL_RCC_PLL1_SetP(2); + LL_RCC_PLL1_SetQ(4); + LL_RCC_PLL1_SetR(2); + LL_RCC_PLL1_Enable(); + while (LL_RCC_PLL1_IsReady() != 1) { + } + + /* Set Sys & AHB & APB1 & APB2 & APB4 prescaler */ + LL_RCC_SetSysPrescaler(LL_RCC_SYSCLK_DIV_1); + LL_RCC_SetAHBPrescaler(LL_RCC_AHB_DIV_2); + LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_2); + LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_2); + LL_RCC_SetAPB4Prescaler(LL_RCC_APB4_DIV_2); + + /* Set PLL1 as System Clock Source */ + LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL1); + while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL1) { + } + + /* Config & activate PLL2 */ + LL_RCC_PLL2P_Enable(); + LL_RCC_PLL2Q_Enable(); + LL_RCC_PLL2R_Enable(); + LL_RCC_PLL2FRACN_Disable(); + LL_RCC_PLL2_SetVCOInputRange(LL_RCC_PLLINPUTRANGE_2_4); + LL_RCC_PLL2_SetVCOOutputRange(LL_RCC_PLLVCORANGE_WIDE); + LL_RCC_PLL2_SetM(3); + LL_RCC_PLL2_SetN(240); + LL_RCC_PLL2_SetP(12); + LL_RCC_PLL2_SetQ(2); + LL_RCC_PLL2_SetR(4); + LL_RCC_PLL2_Enable(); + while (LL_RCC_PLL2_IsReady() != 1) { + } + + /* Config & activate PLL3 */ + LL_RCC_PLL3P_Enable(); + LL_RCC_PLL3Q_Enable(); + LL_RCC_PLL3R_Enable(); + LL_RCC_PLL3FRACN_Disable(); + LL_RCC_PLL3_SetVCOInputRange(LL_RCC_PLLINPUTRANGE_2_4); + LL_RCC_PLL3_SetVCOOutputRange(LL_RCC_PLLVCORANGE_WIDE); + LL_RCC_PLL3_SetM(3); + LL_RCC_PLL3_SetN(240); + LL_RCC_PLL3_SetP(5); + LL_RCC_PLL3_SetQ(20); + LL_RCC_PLL3_SetR(80); + LL_RCC_PLL3_Enable(); + while (LL_RCC_PLL3_IsReady() != 1) { + } + + /* Enable SRAM1, SRAM2 & SRAM3 */ + LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_D2SRAM1 | + LL_AHB2_GRP1_PERIPH_D2SRAM2 | + LL_AHB2_GRP1_PERIPH_D2SRAM3); + + /* Set periph clock sources */ + LL_RCC_SetFMCClockSource(LL_RCC_FMC_CLKSOURCE_HCLK); + LL_RCC_SetSPIClockSource(LL_RCC_SPI123_CLKSOURCE_PLL3P); + LL_RCC_SetUSBClockSource(LL_RCC_USB_CLKSOURCE_PLL3Q); + LL_RCC_SetADCClockSource(LL_RCC_ADC_CLKSOURCE_CLKP); +} diff --git a/radio/src/targets/pa01/system_clock.h b/radio/src/targets/pa01/system_clock.h new file mode 100644 index 000000000..10b69a118 --- /dev/null +++ b/radio/src/targets/pa01/system_clock.h @@ -0,0 +1,23 @@ +/* + * 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. + */ + +void SystemClock_Config(); + diff --git a/radio/src/targets/pa01/usb_descriptor.h b/radio/src/targets/pa01/usb_descriptor.h new file mode 100644 index 000000000..6574f5fff --- /dev/null +++ b/radio/src/targets/pa01/usb_descriptor.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _USB_DESCRIPTOR_H_ +#define _USB_DESCRIPTOR_H_ + +#define USB_NAME "PA01" +#define USB_MANUFACTURER 'F', 'l', 'y', 'S', 'k', 'y', ' ', ' ' /* 8 bytes */ +#define USB_PRODUCT 'P', 'A', '0', '1', ' ', ' ', ' ', ' ' /* 8 Bytes */ + +#endif // _USB_DESCRIPTOR_H_ diff --git a/radio/util/hw_defs/legacy_names.py b/radio/util/hw_defs/legacy_names.py index 484b06420..5af58e37a 100644 --- a/radio/util/hw_defs/legacy_names.py +++ b/radio/util/hw_defs/legacy_names.py @@ -982,6 +982,29 @@ LEGACY_NAMES = [ }, }, }, + { + "targets": {"pa01"}, + "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"}, + "SL1": { + "yaml": "SLIDER1", + "lua": "ls", + "label": "LS", + "short_label": "L", + "description": "Left slider" + }, + "SL2": { + "yaml": "SLIDER2", + "lua": "rs", + "label": "RS", + "short_label": "R", + "description": "Right slider", + }, + }, + }, { "targets": {"h747", "h7rs"}, "inputs": { diff --git a/radio/util/hw_defs/pot_config.py b/radio/util/hw_defs/pot_config.py index 53c7a2df5..5cee112c3 100644 --- a/radio/util/hw_defs/pot_config.py +++ b/radio/util/hw_defs/pot_config.py @@ -244,6 +244,10 @@ POT_CONFIG = { "SL1": {"default": "SLIDER"}, "SL2": {"default": "SLIDER"}, }, + "pa01": { + "SL1": {"default": "SLIDER"}, + "SL2": {"default": "SLIDER"}, + }, } diff --git a/radio/util/hw_defs/switch_config.py b/radio/util/hw_defs/switch_config.py index 5544cf476..6cd0061d9 100644 --- a/radio/util/hw_defs/switch_config.py +++ b/radio/util/hw_defs/switch_config.py @@ -105,6 +105,19 @@ SWITCH_CONFIG = { "SO": {"default": "2POS"}, "SP": {"default": "2POS"}, }, + "pa01": { + "SA": { "default": "2POS" }, + "SB": { "default": "3POS" }, + "SC": { "default": "3POS" }, + "SD": { "default": "TOGGLE" }, + "SE": { "default": "TOGGLE" }, + "SF": { "default": "TOGGLE" }, + # custom switches + "SK": {"default": "2POS"}, + "SL": {"default": "2POS"}, + "SM": {"default": "2POS"}, + "SN": {"default": "2POS"}, + }, "lr3pro": { # left side "SA": {"default": "3POS", "display": [0, 0]}, diff --git a/tools/build-common.sh b/tools/build-common.sh index 3613f3d31..763e5802f 100644 --- a/tools/build-common.sh +++ b/tools/build-common.sh @@ -158,6 +158,9 @@ get_target_build_options() { st16) BUILD_OPTIONS+="-DPCB=ST16 -DNANO=NO" ;; + pa01) + BUILD_OPTIONS+="-DPCB=PA01 -DNANO=NO" + ;; *) echo "Unknown target: $target_name" return 1 diff --git a/tools/build-companion.sh b/tools/build-companion.sh index cda59a05d..5411cc575 100755 --- a/tools/build-companion.sh +++ b/tools/build-companion.sh @@ -211,7 +211,7 @@ declare -a simulator_plugins=( zorro tx16s commando8 boxer pocket mt12 gx12 tlite tpro tprov2 tpros bumblebee lr3pro t14 - nv14 el18 pl18 pl18ev pl18u st16 + nv14 el18 pl18 pl18ev pl18u st16 pa01 f16 v14 v16 ) diff --git a/tools/generate-yaml.sh b/tools/generate-yaml.sh index ef569312a..5508c775a 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:="t15;tx16s;pl18;nv14;pl18u;nb4p;x9d;x9dp2019;x9e;xlite;xlites;x7;tpro;t20;f16;gx12;st16"} +: ${FLAVOR:="t15;tx16s;pl18;nv14;pl18u;nb4p;x9d;x9dp2019;x9e;xlite;xlites;x7;tpro;t20;f16;gx12;st16;pa01"} : ${SRCDIR:=$(dirname "$(pwd)/$0")/..} : ${COMMON_OPTIONS:="-DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_RULE_MESSAGES=OFF -Wno-dev -DDISABLE_COMPANION=YES -DCMAKE_MESSAGE_LOG_LEVEL=WARNING"}