diff --git a/.github/workflows/actions.yml b/.github/workflows/actions.yml
index 4fcb62a870f..91807761949 100644
--- a/.github/workflows/actions.yml
+++ b/.github/workflows/actions.yml
@@ -46,6 +46,8 @@ jobs:
- tx16s
- nv14
- el18
+ - pl18
+ - pl18ev
- t12
- t16
- t18
@@ -90,9 +92,9 @@ jobs:
matrix:
target:
- nv14;el18
+ - pl18;pl18ev
- t12
- - t16
- - t18
+ - t16;t18
- t8;zorro;pocket;mt12;commando8
- tlite;tpro;tprov2;lr3pro
- t20
diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml
index 009f2147320..4406634ecd4 100644
--- a/.github/workflows/nightly.yml
+++ b/.github/workflows/nightly.yml
@@ -16,6 +16,7 @@ jobs:
matrix:
target:
- nv14;el18
+ - pl18;pl18ev
- t12
- t16
- t18
diff --git a/companion/src/CMakeLists.txt b/companion/src/CMakeLists.txt
index c623a69a268..7cb6f9242a8 100644
--- a/companion/src/CMakeLists.txt
+++ b/companion/src/CMakeLists.txt
@@ -318,6 +318,8 @@ elseif(PCB STREQUAL X10 AND PCBREV STREQUAL T18)
set(FLAVOUR t18)
elseif(PCB STREQUAL NV14 AND PCBREV STREQUAL EL18)
set(FLAVOUR el18)
+elseif(PCB STREQUAL PL18)
+ set(FLAVOUR pl18)
else()
string(TOLOWER ${PCB} FLAVOUR)
endif()
diff --git a/companion/src/companion.qrc b/companion/src/companion.qrc
index 792e2f494b9..c28331e9a68 100644
--- a/companion/src/companion.qrc
+++ b/companion/src/companion.qrc
@@ -293,6 +293,10 @@
images/simulator/NV14/right.png
images/simulator/NV14/top.png
images/simulator/NV14/bottom.png
+ images/simulator/PL18/left.png
+ images/simulator/PL18/right.png
+ images/simulator/PL18/top.png
+ images/simulator/PL18/bottom.png
images/wizard/ailerons.png
images/wizard/airbrakes.png
images/wizard/elevons.png
diff --git a/companion/src/firmwares/boards.cpp b/companion/src/firmwares/boards.cpp
index 08e058ac863..f7f2be15615 100644
--- a/companion/src/firmwares/boards.cpp
+++ b/companion/src/firmwares/boards.cpp
@@ -110,7 +110,9 @@ uint32_t Boards::getFourCC(Type board)
case BOARD_FLYSKY_NV14:
return 0x3A78746F;
case BOARD_FLYSKY_EL18:
- return 0x3A78746F; // TODO: check this
+ return 0x3A78746F;
+ case BOARD_FLYSKY_PL18:
+ return 0x4878746F;
default:
return 0;
}
@@ -159,6 +161,7 @@ int Boards::getEEpromSize(Board::Type board)
case BOARD_RADIOMASTER_TX16S:
case BOARD_FLYSKY_NV14:
case BOARD_FLYSKY_EL18:
+ case BOARD_FLYSKY_PL18:
return 0;
default:
return 0;
@@ -206,6 +209,7 @@ int Boards::getFlashSize(Type board)
case BOARD_RADIOMASTER_TX16S:
case BOARD_FLYSKY_NV14:
case BOARD_FLYSKY_EL18:
+ case BOARD_FLYSKY_PL18:
return FSIZE_HORUS;
case BOARD_UNKNOWN:
return FSIZE_MAX;
@@ -419,6 +423,20 @@ SwitchInfo Boards::getSwitchInfo(Board::Type board, int index)
if (index < DIM(switches))
return switches[index];
}
+ else if (IS_FLYSKY_PL18(board)) {
+ const Board::SwitchInfo switches[] = {
+ {SWITCH_2POS, "SA"},
+ {SWITCH_3POS, "SB"},
+ {SWITCH_2POS, "SC"},
+ {SWITCH_3POS, "SD"},
+ {SWITCH_3POS, "SE"},
+ {SWITCH_2POS, "SF"},
+ {SWITCH_3POS, "SG"},
+ {SWITCH_3POS, "SH"}
+ };
+ if (index < DIM(switches))
+ return switches[index];
+ }
else if (IS_FAMILY_HORUS_OR_T16(board)) {
const Board::SwitchInfo switches[] = {
{SWITCH_3POS, "SA"},
@@ -497,6 +515,8 @@ int Boards::getCapability(Board::Type board, Board::Capability capability)
return 7;
else if (IS_HORUS_X12S(board))
return 3;
+ else if (IS_FLYSKY_PL18(board))
+ return 3;
else
return 3;
@@ -509,7 +529,7 @@ int Boards::getCapability(Board::Type board, Board::Capability capability)
case Sliders:
if (IS_HORUS_X12S(board) || IS_TARANIS_X9E(board) || IS_JUMPER_T20(board))
return 4;
- else if (IS_TARANIS_X9D(board) || IS_HORUS_X10(board) || IS_FAMILY_T16(board))
+ else if (IS_TARANIS_X9D(board) || IS_HORUS_X10(board) || IS_FAMILY_T16(board) || IS_FLYSKY_PL18(board))
return 2;
else
return 0;
@@ -531,7 +551,7 @@ int Boards::getCapability(Board::Type board, Board::Capability capability)
getCapability(board, Board::MouseAnalogs) + getCapability(board, Board::GyroAnalogs);
case MultiposPots:
- if (IS_HORUS_OR_TARANIS(board) && !(IS_FLYSKY_NV14(board) || IS_FLYSKY_EL18(board)))
+ if (IS_HORUS_OR_TARANIS(board) && !(IS_FLYSKY_NV14(board) || IS_FLYSKY_EL18(board) || IS_FLYSKY_PL18(board)))
return getCapability(board, Board::Pots);
else
return 0;
@@ -558,6 +578,8 @@ int Boards::getCapability(Board::Type board, Board::Capability capability)
return 6;
else if (board == BOARD_FLYSKY_NV14 || board == BOARD_FLYSKY_EL18)
return 8;
+ else if (board == BOARD_FLYSKY_PL18)
+ return 8;
else if (board == BOARD_RADIOMASTER_TX12_MK2 || board == BOARD_RADIOMASTER_BOXER || board == BOARD_JUMPER_TPRO)
return 6;
else if (board == BOARD_RADIOMASTER_POCKET)
@@ -600,7 +622,7 @@ int Boards::getCapability(Board::Type board, Board::Capability capability)
return getCapability(board, Board::Switches);
case SwitchPositions:
- if (IS_HORUS_OR_TARANIS(board) || IS_FLYSKY_NV14(board) || IS_FLYSKY_EL18(board))
+ if (IS_HORUS_OR_TARANIS(board) || IS_FLYSKY_NV14(board) || IS_FLYSKY_EL18(board) || IS_FLYSKY_PL18(board))
return getCapability(board, Board::Switches) * 3;
else
return 9;
@@ -610,7 +632,9 @@ int Boards::getCapability(Board::Type board, Board::Capability capability)
case NumTrims:
- if (IS_FAMILY_HORUS_OR_T16(board) && !(IS_FLYSKY_NV14(board) || IS_FLYSKY_EL18(board)))
+ if (IS_FLYSKY_PL18(board))
+ return 8;
+ else if (IS_FAMILY_HORUS_OR_T16(board) && !IS_FLYSKY_NV14(board))
return 6;
else if (IS_IFLIGHT_COMMANDO8(board))
return 0;
@@ -626,7 +650,7 @@ int Boards::getCapability(Board::Type board, Board::Capability capability)
return IS_STM32(board) ? true : false;
case HasColorLcd:
- return IS_FAMILY_HORUS_OR_T16(board);
+ return IS_FAMILY_HORUS_OR_T16(board) || IS_FLYSKY_NV14(board) || IS_FLYSKY_PL18(board);
case HasSDCard:
return IS_STM32(board);
@@ -647,7 +671,7 @@ int Boards::getCapability(Board::Type board, Board::Capability capability)
return false;
case SportMaxBaudRate:
- if (IS_FAMILY_T16(board) || IS_FLYSKY_NV14(board) || IS_FLYSKY_EL18(board) || IS_TARANIS_X7_ACCESS(board) ||
+ if (IS_FAMILY_T16(board) || IS_FLYSKY_NV14(board) || IS_FLYSKY_EL18(board) || IS_FLYSKY_PL18(board) ||IS_TARANIS_X7_ACCESS(board) ||
(IS_TARANIS(board) && !IS_TARANIS_XLITE(board) && !IS_TARANIS_X7(board) && !IS_TARANIS_X9LITE(board)))
return 400000; // 400K and higher
else
@@ -833,6 +857,14 @@ StringTagMappingTable Boards::getAnalogNamesLookupTable(Board::Type board, const
{tr("TltY").toStdString(), "TILT_Y", 14},
});
}
+ } else if (IS_FLYSKY_PL18(board)) {
+ tbl.insert(tbl.end(), {
+ {tr("VRA").toStdString(), "POT1"},
+ {tr("VRB").toStdString(), "POT2"},
+ {tr("VRC").toStdString(), "POT3"},
+ {tr("LS").toStdString(), "LS"},
+ {tr("RS").toStdString(), "RS"},
+ });
} else if (IS_HORUS_X10(board) || IS_FAMILY_T16(board)) {
if (version < adcVersion) {
tbl.insert(tbl.end(), {
@@ -964,6 +996,8 @@ QString Boards::getBoardName(Board::Type board)
return "FlySky NV14";
case BOARD_FLYSKY_EL18:
return "FlySky EL18";
+ case BOARD_FLYSKY_PL18:
+ return "FlySky PL18";
case BOARD_BETAFPV_LR3PRO:
return "BETAFPV LR3PRO";
case BOARD_IFLIGHT_COMMANDO8:
@@ -1198,6 +1232,7 @@ int Boards::getDefaultInternalModules(Board::Type board)
case BOARD_JUMPER_TLITE_F4:
case BOARD_JUMPER_TPRO:
case BOARD_JUMPER_TPROV2:
+ case BOARD_FLYSKY_PL18:
return (int)MODULE_TYPE_MULTIMODULE;
case BOARD_BETAFPV_LR3PRO:
diff --git a/companion/src/firmwares/boards.h b/companion/src/firmwares/boards.h
index 75c6473c918..b853436bdfe 100644
--- a/companion/src/firmwares/boards.h
+++ b/companion/src/firmwares/boards.h
@@ -69,6 +69,7 @@ namespace Board {
BOARD_JUMPER_TLITE,
BOARD_JUMPER_TLITE_F4,
BOARD_FLYSKY_NV14,
+ BOARD_FLYSKY_PL18,
BOARD_RADIOMASTER_ZORRO,
BOARD_JUMPER_TPRO,
BOARD_BETAFPV_LR3PRO,
@@ -398,6 +399,11 @@ inline bool IS_FLYSKY_EL18(Board::Type board)
return (board == Board::BOARD_FLYSKY_EL18);
}
+inline bool IS_FLYSKY_PL18(Board::Type board)
+{
+ return (board == Board::BOARD_FLYSKY_PL18);
+}
+
inline bool IS_TARANIS_XLITE(Board::Type board)
{
return board == Board::BOARD_TARANIS_XLITE || board == Board::BOARD_TARANIS_XLITES;
@@ -475,7 +481,9 @@ inline bool IS_FAMILY_HORUS(Board::Type board)
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*/;
+ return IS_FAMILY_HORUS(board) || IS_FAMILY_T16(board) ||
+ IS_FLYSKY_NV14(board)/*generally*/ || IS_FLYSKY_EL18(board)/*generally*/
+ || IS_FLYSKY_PL18(board);
}
inline bool IS_HORUS_OR_TARANIS(Board::Type board)
@@ -485,7 +493,8 @@ inline bool IS_HORUS_OR_TARANIS(Board::Type board)
inline bool IS_STM32(Board::Type board)
{
- return IS_TARANIS(board) || IS_FAMILY_HORUS_OR_T16(board) || IS_FLYSKY_NV14(board) || IS_FLYSKY_EL18(board);
+ return IS_TARANIS(board) || IS_FAMILY_HORUS_OR_T16(board) ||
+ IS_FLYSKY_NV14(board) || IS_FLYSKY_EL18(board) || IS_FLYSKY_PL18(board);
}
inline bool IS_ARM(Board::Type board)
diff --git a/companion/src/firmwares/generalsettings.cpp b/companion/src/firmwares/generalsettings.cpp
index b4cc9e80b55..9e7688c99ca 100644
--- a/companion/src/firmwares/generalsettings.cpp
+++ b/companion/src/firmwares/generalsettings.cpp
@@ -154,6 +154,8 @@ void GeneralSettings::init()
strcpy(bluetoothName, "t16");
else if (IS_FLYSKY_NV14(board))
strcpy(bluetoothName, "nv14");
+ else if (IS_FLYSKY_PL18(board))
+ strcpy(bluetoothName, "pl18");
else if (IS_FAMILY_HORUS_OR_T16(board))
strcpy(bluetoothName, "horus");
else if (IS_TARANIS_X9E(board) || IS_TARANIS_SMALL(board))
@@ -269,7 +271,7 @@ void GeneralSettings::init()
internalModule = g.profile[g.sessionId()].defaultInternalModule();
- if (IS_FLYSKY_NV14(board))
+ if (IS_FLYSKY_NV14(board) || IS_FLYSKY_PL18(board))
stickDeadZone = 2;
}
@@ -285,7 +287,7 @@ void GeneralSettings::setDefaultControlTypes(Board::Type board)
return;
// TODO: move to Boards, like with switches
- if (IS_FAMILY_HORUS_OR_T16(board) && !IS_FLYSKY_NV14(board)) {
+ if (IS_FAMILY_HORUS_OR_T16(board) && !IS_FLYSKY_NV14(board) && !IS_FLYSKY_PL18(board)) {
potConfig[0] = Board::POT_WITH_DETENT;
potConfig[1] = Board::POT_MULTIPOS_SWITCH;
potConfig[2] = Board::POT_WITH_DETENT;
@@ -294,6 +296,11 @@ void GeneralSettings::setDefaultControlTypes(Board::Type board)
potConfig[0] = Board::POT_WITHOUT_DETENT;
potConfig[1] = Board::POT_WITHOUT_DETENT;
}
+ else if (IS_FLYSKY_PL18(board)) {
+ potConfig[0] = Board::POT_WITHOUT_DETENT;
+ potConfig[1] = Board::POT_WITHOUT_DETENT;
+ potConfig[2] = Board::POT_WITHOUT_DETENT;
+ }
else if (IS_TARANIS_XLITE(board)) {
potConfig[0] = Board::POT_WITHOUT_DETENT;
potConfig[1] = Board::POT_WITHOUT_DETENT;
diff --git a/companion/src/firmwares/opentx/opentxeeprom.cpp b/companion/src/firmwares/opentx/opentxeeprom.cpp
index d5339d9982b..b7c44f0988e 100644
--- a/companion/src/firmwares/opentx/opentxeeprom.cpp
+++ b/companion/src/firmwares/opentx/opentxeeprom.cpp
@@ -116,7 +116,7 @@ inline int MAX_POTS_STORAGE(Board::Type board, int version)
{
if (version <= 218 && IS_FAMILY_HORUS_OR_T16(board))
return 3;
- if (version <= 220 && IS_FAMILY_HORUS_OR_T16(board) && !IS_FLYSKY_NV14(board))
+ if (version <= 220 && IS_FAMILY_HORUS_OR_T16(board) && !IS_FLYSKY_NV14(board) && !IS_FLYSKY_PL18(board))
return 5;
if (IS_FAMILY_T12(board))
return 2;
@@ -147,7 +147,7 @@ inline int MAX_XPOTS(Board::Type board, int version)
inline int MAX_SLIDERS_STORAGE(Board::Type board, int version)
{
- if (version >= 219 && (IS_FAMILY_HORUS_OR_T16(board) && !IS_FLYSKY_NV14(board)))
+ if (version >= 219 && (IS_FAMILY_HORUS_OR_T16(board) && !IS_FLYSKY_NV14(board) && !IS_FLYSKY_PL18(board)))
return 4;
return Boards::getCapability(board, Board::Sliders);
}
@@ -183,7 +183,7 @@ inline int SWITCHES_CONFIG_SIZE(Board::Type board, int version)
inline int MAX_MOUSE_ANALOG_SOURCES(Board::Type board, int version)
{
- if (IS_FAMILY_HORUS_OR_T16(board) && !IS_FLYSKY_NV14(board))
+ if (IS_FAMILY_HORUS_OR_T16(board) && !IS_FLYSKY_NV14(board) && !IS_FLYSKY_PL18(board))
return 2;
else
return 0;
@@ -211,10 +211,10 @@ inline int MAX_GYRO_ANALOGS(Board::Type board, int version)
#define MAX_CURVES(board, version) ((version >= 219 || HAS_LARGE_LCD(board)) ? 32 : 16)
#define MAX_GVARS(board, version) 9
#define MAX_SCRIPTS(board) (IS_FAMILY_HORUS_OR_T16(board) ? 9 : 7)
-#define MAX_TELEMETRY_SENSORS(board, version) (version <= 218 ? 32 : ((IS_FAMILY_HORUS_OR_T16(board) || IS_TARANIS_X9(board) || IS_FLYSKY_NV14(board)) ? 60 : 40))
+#define MAX_TELEMETRY_SENSORS(board, version) (version <= 218 ? 32 : ((IS_FAMILY_HORUS_OR_T16(board) || IS_TARANIS_X9(board) || IS_FLYSKY_NV14(board) || IS_FLYSKY_PL18(board)) ? 60 : 40))
#define NUM_PPM_INPUTS(board, version) 16
#define ROTENC_COUNT(board, version) ((IS_STM32(board) && version >= 218) ? 0 : 1)
-#define MAX_AUX_TRIMS(board) ((IS_FAMILY_HORUS_OR_T16(board) && !IS_FLYSKY_NV14(board)) ? 2 : 0)
+#define MAX_AUX_TRIMS(board) ((IS_FAMILY_HORUS_OR_T16(board) && !IS_FLYSKY_NV14(board) && !IS_FLYSKY_PL18(board)) ? 2 : 0)
#define MAX_SOURCE_TYPE_SPECIAL(board, version) SOURCE_TYPE_SPECIAL_COUNT
inline int switchIndex(int i, Board::Type board, unsigned int version)
@@ -2910,7 +2910,7 @@ void OpenTxModelData::beforeExport()
// TODO remove when enum not radio specific requires eeprom change and conversion
// Note: this must mirror reverse afterImport
- if (!IS_FLYSKY_NV14(board))
+ if (!IS_FLYSKY_NV14(board) && !IS_FLYSKY_PL18(board))
modelData.trainerMode -= 1;
if (modelData.trainerMode > TRAINER_MODE_SLAVE_JACK) {
@@ -2957,7 +2957,7 @@ void OpenTxModelData::afterImport()
// TODO remove when enum not radio specific requires eeprom change and conversion
// Note: this must mirror reverse beforeExport
- if (!IS_FLYSKY_NV14(board))
+ if (!IS_FLYSKY_NV14(board) && !IS_FLYSKY_PL18(board))
modelData.trainerMode += 1;
if (modelData.trainerMode > TRAINER_MODE_SLAVE_JACK) {
@@ -3003,7 +3003,7 @@ OpenTxGeneralData::OpenTxGeneralData(GeneralSettings & generalData, Board::Type
internalField.Append(new UnsignedField<16>(this, chkSum));
- if (!IS_FAMILY_HORUS_OR_T16(board) || (IS_FLYSKY_NV14(board))) {
+ if (!IS_FAMILY_HORUS_OR_T16(board) || IS_FLYSKY_NV14(board) || IS_FLYSKY_PL18(board)) {
internalField.Append(new UnsignedField<8>(this, generalData.currModelIndex));
internalField.Append(new UnsignedField<8>(this, generalData.contrast));
}
@@ -3067,11 +3067,11 @@ OpenTxGeneralData::OpenTxGeneralData(GeneralSettings & generalData, Board::Type
internalField.Append(new SignedField<8>(this, generalData.PPM_Multiplier));
internalField.Append(new SignedField<8>(this, generalData.hapticLength));
- if (version < 218 || (!IS_TARANIS(board) && !IS_FAMILY_HORUS_OR_T16(board)) || IS_FLYSKY_NV14(board)) {
+ if (version < 218 || (!IS_TARANIS(board) && !IS_FAMILY_HORUS_OR_T16(board)) || IS_FLYSKY_NV14(board) || IS_FLYSKY_PL18(board)) {
internalField.Append(new UnsignedField<8>(this, generalData.reNavigation));
}
- if ((!IS_TARANIS(board) && !IS_FAMILY_HORUS_OR_T16(board)) || IS_FLYSKY_NV14(board)) {
+ if ((!IS_TARANIS(board) && !IS_FAMILY_HORUS_OR_T16(board)) || IS_FLYSKY_NV14(board) || IS_FLYSKY_PL18(board)) {
internalField.Append(new UnsignedField<8>(this, generalData.stickReverse));
}
diff --git a/companion/src/firmwares/opentx/opentxinterface.cpp b/companion/src/firmwares/opentx/opentxinterface.cpp
index 34d441279c0..192fb4c32b7 100644
--- a/companion/src/firmwares/opentx/opentxinterface.cpp
+++ b/companion/src/firmwares/opentx/opentxinterface.cpp
@@ -124,6 +124,8 @@ const char * OpenTxEepromInterface::getName()
return "EdgeTX for FlySky NV14";
case BOARD_FLYSKY_EL18:
return "EdgeTX for FlySky EL18";
+ case BOARD_FLYSKY_PL18:
+ return "EdgeTX for FlySky PL18";
case BOARD_BETAFPV_LR3PRO:
return "EdgeTx for BETAFPV LR3PRO";
case BOARD_IFLIGHT_COMMANDO8:
@@ -664,6 +666,8 @@ int OpenTxFirmware::getCapability(::Capability capability)
case LcdWidth:
if (IS_FLYSKY_NV14(board) || IS_FLYSKY_EL18(board))
return 320;
+ else if (IS_FLYSKY_PL18(board))
+ return 480;
else if (IS_FAMILY_HORUS_OR_T16(board))
return 480;
else if (IS_TARANIS_SMALL(board))
@@ -675,6 +679,8 @@ int OpenTxFirmware::getCapability(::Capability capability)
case LcdHeight:
if (IS_FLYSKY_NV14(board) || IS_FLYSKY_EL18(board))
return 480;
+ else if (IS_FLYSKY_PL18(board))
+ return 320;
else if (IS_FAMILY_HORUS_OR_T16(board))
return 272;
else
@@ -777,7 +783,7 @@ int OpenTxFirmware::getCapability(::Capability capability)
IS_JUMPER_TPRO(board) || IS_RADIOMASTER_TX12_MK2(board) || IS_RADIOMASTER_BOXER(board) || IS_RADIOMASTER_POCKET(board);
case HasBluetooth:
return (IS_FAMILY_HORUS_OR_T16(board) || IS_TARANIS_X7(board) || IS_TARANIS_XLITE(board)|| IS_TARANIS_X9E(board) ||
- IS_TARANIS_X9DP_2019(board) || IS_FLYSKY_NV14(board) || IS_FLYSKY_EL18(board)) ? true : false;
+ IS_TARANIS_X9DP_2019(board) || IS_FLYSKY_NV14(board) || IS_FLYSKY_EL18(board) || IS_FLYSKY_PL18(board)) ? true : false;
case HasADCJitterFilter:
return IS_HORUS_OR_TARANIS(board);
case HasTelemetryBaudrate:
@@ -1244,6 +1250,13 @@ void registerOpenTxFirmwares()
addOpenTxRfOptions(firmware, FLEX + AFHDS2A + AFHDS3);
registerOpenTxFirmware(firmware);
+ /* FlySky PL18 board */
+ firmware = new OpenTxFirmware(FIRMWAREID("pl18"), Firmware::tr("FlySky PL18"), BOARD_FLYSKY_PL18);
+ addOpenTxFrskyOptions(firmware);
+ firmware->addOption("bluetooth", Firmware::tr("Support for bluetooth module"));
+ addOpenTxRfOptions(firmware, FLEX + AFHDS3);
+ registerOpenTxFirmware(firmware);
+
/* FrSky Horus X10 board */
firmware = new OpenTxFirmware(FIRMWAREID("x10"), Firmware::tr("FrSky Horus X10 / X10S"), BOARD_X10);
addOpenTxFrskyOptions(firmware);
diff --git a/companion/src/generaledit/generalsetup.cpp b/companion/src/generaledit/generalsetup.cpp
index 75d3b2dabc7..265aad75ac1 100644
--- a/companion/src/generaledit/generalsetup.cpp
+++ b/companion/src/generaledit/generalsetup.cpp
@@ -175,7 +175,7 @@ ui(new Ui::GeneralSetup)
ui->usbModeCB->hide();
}
- if (IS_FLYSKY_EL18(board) || IS_FLYSKY_NV14(board)) {
+ if (IS_FLYSKY_EL18(board) || IS_FLYSKY_NV14(board) || IS_FLYSKY_PL18(board)) {
ui->hatsModeCB->setModel(new FilteredItemModel(GeneralSettings::hatsModeItemModel()));
ui->hatsModeCB->setField(generalSettings.hatsMode, this);
}
diff --git a/companion/src/images/simulator/PL18/bottom.png b/companion/src/images/simulator/PL18/bottom.png
new file mode 100644
index 00000000000..5fc10a49d42
Binary files /dev/null and b/companion/src/images/simulator/PL18/bottom.png differ
diff --git a/companion/src/images/simulator/PL18/left.png b/companion/src/images/simulator/PL18/left.png
new file mode 100644
index 00000000000..6294e9922da
Binary files /dev/null and b/companion/src/images/simulator/PL18/left.png differ
diff --git a/companion/src/images/simulator/PL18/right.png b/companion/src/images/simulator/PL18/right.png
new file mode 100644
index 00000000000..6294e9922da
Binary files /dev/null and b/companion/src/images/simulator/PL18/right.png differ
diff --git a/companion/src/images/simulator/PL18/top.png b/companion/src/images/simulator/PL18/top.png
new file mode 100644
index 00000000000..5fc10a49d42
Binary files /dev/null and b/companion/src/images/simulator/PL18/top.png differ
diff --git a/companion/src/modeledit/setup.cpp b/companion/src/modeledit/setup.cpp
index 345e6aed9e1..d0911ccf99f 100644
--- a/companion/src/modeledit/setup.cpp
+++ b/companion/src/modeledit/setup.cpp
@@ -1696,7 +1696,7 @@ SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & ge
ui->trimsDisplay->setField(model.trimsDisplay, this);
- if (IS_FLYSKY_EL18(board) || IS_FLYSKY_NV14(board)) {
+ if (IS_FLYSKY_EL18(board) || IS_FLYSKY_NV14(board) || IS_FLYSKY_PL18(board)) {
ui->cboHatsMode->setModel(panelFilteredModels->getItemModel(FIM_HATSMODE));
ui->cboHatsMode->setField(model.hatsMode, this);
}
diff --git a/companion/src/modelprinter.cpp b/companion/src/modelprinter.cpp
index 5501340990f..e524454aaa3 100644
--- a/companion/src/modelprinter.cpp
+++ b/companion/src/modelprinter.cpp
@@ -841,7 +841,7 @@ QString ModelPrinter::printSettingsTrim()
str << printLabelValue(tr("Display"), printTrimsDisplayMode());
str << printLabelValue(tr("Extended"), printBoolean(model.extendedTrims, BOOLEAN_YESNO));
Board::Type board = firmware->getBoard();
- if (IS_FLYSKY_EL18(board) || IS_FLYSKY_NV14(board)) {
+ if (IS_FLYSKY_EL18(board) || IS_FLYSKY_NV14(board) || IS_FLYSKY_PL18(board)) {
str << printLabelValue(tr("Hats Mode"), printHatsMode());
}
return str.join(" ");
diff --git a/companion/src/simulation/CMakeLists.txt b/companion/src/simulation/CMakeLists.txt
index 54a994dcf4b..f700a917d5d 100644
--- a/companion/src/simulation/CMakeLists.txt
+++ b/companion/src/simulation/CMakeLists.txt
@@ -40,6 +40,7 @@ set(${PROJECT_NAME}_SRCS
simulateduiwidgetJumperTPRO.cpp
simulateduiwidgetLR3PRO.cpp
simulateduiwidgetNV14.cpp
+ simulateduiwidgetPL18.cpp
simulateduiwidgetT8.cpp
simulateduiwidgetTX12.cpp
simulateduiwidgetTX16S.cpp
diff --git a/companion/src/simulation/simulateduiwidget.h b/companion/src/simulation/simulateduiwidget.h
index a3856aa86a1..11f99a33743 100644
--- a/companion/src/simulation/simulateduiwidget.h
+++ b/companion/src/simulation/simulateduiwidget.h
@@ -125,6 +125,7 @@ namespace Ui {
class SimulatedUIWidgetT8;
class SimulatedUIWidgetNV14;
class SimulatedUIWidgetEL18;
+ class SimulatedUIWidgetPL18;
}
class SimulatedUIWidget9X: public SimulatedUIWidget
@@ -407,4 +408,16 @@ class SimulatedUIWidgetEL18: public SimulatedUIWidget
Ui::SimulatedUIWidgetEL18 * ui;
};
+class SimulatedUIWidgetPL18: public SimulatedUIWidget
+{
+ Q_OBJECT
+
+ public:
+ explicit SimulatedUIWidgetPL18(SimulatorInterface * simulator, QWidget * parent = nullptr);
+ virtual ~SimulatedUIWidgetPL18();
+
+ private:
+ Ui::SimulatedUIWidgetPL18 * ui;
+};
+
#endif // SIMULATEDUIWIDGET_H
diff --git a/companion/src/simulation/simulateduiwidgetPL18.cpp b/companion/src/simulation/simulateduiwidgetPL18.cpp
new file mode 100644
index 00000000000..5e3554245cc
--- /dev/null
+++ b/companion/src/simulation/simulateduiwidgetPL18.cpp
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+// NOTE: RadioUiAction(NUMBER,...): NUMBER relates to enum EnumKeys in the specific board.h
+
+#include "simulateduiwidget.h"
+#include "ui_simulateduiwidgetPL18.h"
+
+SimulatedUIWidgetPL18::SimulatedUIWidgetPL18(SimulatorInterface *simulator, QWidget * parent):
+ SimulatedUIWidget(simulator, parent),
+ ui(new Ui::SimulatedUIWidgetPL18)
+{
+ RadioUiAction * act;
+
+ ui->setupUi(this);
+
+ // add actions in order of appearance on the help menu
+
+ // Note: the PL18 has no physical buttons though at some point the trim joystick is repurposed
+ // allow for colorlcd key events and see what works
+ // the mouse click areas do not map to visual buttons on the background images
+
+ act = new RadioUiAction(3, QList() << Qt::Key_Up, SIMU_STR_HLP_KEY_UP, SIMU_STR_HLP_ACT_MDL);
+ addRadioWidget(ui->rightbuttons->addArea(QRect(10, 1, 80, 35), "PL18/left.png", act));
+
+ m_mouseMidClickAction = new RadioUiAction(2, QList() << Qt::Key_Enter << Qt::Key_Return, SIMU_STR_HLP_KEYS_ACTIVATE, SIMU_STR_HLP_ACT_ROT_DN);
+ addRadioWidget(ui->rightbuttons->addArea(QRect(10, 40, 80, 35), "PL18/left.png", m_mouseMidClickAction));
+
+ act = new RadioUiAction(6, QList() << Qt::Key_Left, SIMU_STR_HLP_KEY_LFT, SIMU_STR_HLP_ACT_SYS);
+ addRadioWidget(ui->leftbuttons->addArea(QRect(10, 80, 80, 35), "PL18/left.png", act));
+
+ act = new RadioUiAction(5, QList() << Qt::Key_Right, SIMU_STR_HLP_KEY_RGT, SIMU_STR_HLP_ACT_TELE);
+ addRadioWidget(ui->leftbuttons->addArea(QRect(10, 120, 80, 35), "PL18/left.png", act));
+
+ act = new RadioUiAction(1, QList() << Qt::Key_PageDown, SIMU_STR_HLP_KEY_PGDN, SIMU_STR_HLP_ACT_PGDN);
+ addRadioWidget(ui->leftbuttons->addArea(QRect(10, 160, 80, 35), "PL18/left.png", act));
+
+ act = new RadioUiAction(0, QList() << Qt::Key_PageUp, SIMU_STR_HLP_KEY_PGUP, SIMU_STR_HLP_ACT_PGUP);
+ addRadioWidget(ui->leftbuttons->addArea(QRect(10, 200, 80, 35), "PL18/left.png", act));
+
+ act = new RadioUiAction(4, QList() << Qt::Key_Down << Qt::Key_Delete << Qt::Key_Escape << Qt::Key_Backspace,
+ SIMU_STR_HLP_KEY_DN % "
" % SIMU_STR_HLP_KEYS_EXIT, SIMU_STR_HLP_ACT_RTN);
+ addRadioWidget(ui->leftbuttons->addArea(QRect(10, 240, 80, 35), "PL18/left.png", act));
+
+ m_scrollUpAction = new RadioUiAction(-1, QList() << Qt::Key_Minus, SIMU_STR_HLP_KEY_MIN % "|" % SIMU_STR_HLP_MOUSE_UP, SIMU_STR_HLP_ACT_ROT_LFT);
+ m_scrollDnAction = new RadioUiAction(-1, QList() << Qt::Key_Plus << Qt::Key_Equal, SIMU_STR_HLP_KEY_PLS % "|" % SIMU_STR_HLP_MOUSE_DN, SIMU_STR_HLP_ACT_ROT_RGT);
+ connectScrollActions();
+
+ addRadioWidget(ui->leftbuttons->addArea(QRect(10, 280, 30, 30), "PL18/left.png", m_screenshotAction));
+
+ m_backlightColors << QColor(47, 123, 227);
+
+ setLcd(ui->lcd);
+}
+
+SimulatedUIWidgetPL18::~SimulatedUIWidgetPL18()
+{
+ delete ui;
+}
diff --git a/companion/src/simulation/simulateduiwidgetPL18.ui b/companion/src/simulation/simulateduiwidgetPL18.ui
new file mode 100644
index 00000000000..c1bbcaedaf4
--- /dev/null
+++ b/companion/src/simulation/simulateduiwidgetPL18.ui
@@ -0,0 +1,206 @@
+
+
+ SimulatedUIWidgetPL18
+
+
+
+ 0
+ 0
+ 520
+ 500
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 520
+ 500
+
+
+
+
+ 520
+ 500
+
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 100
+ 500
+
+
+
+
+ 100
+ 500
+
+
+
+ background:url(:/images/simulator/PL18/right.png)
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 480
+ 320
+
+
+
+
+ 480
+ 320
+
+
+
+
+ 5
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 100
+ 500
+
+
+
+
+ 100
+ 500
+
+
+
+ true
+
+
+ background:url(:/images/simulator/PL18/left.png);
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 320
+ 10
+
+
+
+
+ 320
+ 10
+
+
+
+
+ 5
+
+
+
+ background:url(:/images/simulator/PL18/top.png)
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 320
+ 10
+
+
+
+
+ 320
+ 10
+
+
+
+
+ 5
+ false
+
+
+
+ background:url(:/images/simulator/PL18/bottom.png)
+
+
+
+
+
+
+
+ LcdWidget
+ QWidget
+
+ 1
+
+
+ ButtonsWidget
+ QWidget
+
+ 1
+
+
+
+
+
diff --git a/companion/src/simulation/simulatorwidget.cpp b/companion/src/simulation/simulatorwidget.cpp
index dc0d34acc26..36f30b2586c 100644
--- a/companion/src/simulation/simulatorwidget.cpp
+++ b/companion/src/simulation/simulatorwidget.cpp
@@ -133,6 +133,9 @@ SimulatorWidget::SimulatorWidget(QWidget * parent, SimulatorInterface * simulato
case Board::BOARD_FLYSKY_EL18:
radioUiWidget = new SimulatedUIWidgetEL18(simulator, this);
break;
+ case Board::BOARD_FLYSKY_PL18:
+ radioUiWidget = new SimulatedUIWidgetPL18(simulator, this);
+ break;
default:
radioUiWidget = new SimulatedUIWidget9X(simulator, this);
break;
diff --git a/fw.json b/fw.json
index 728a2188278..b92436535d2 100644
--- a/fw.json
+++ b/fw.json
@@ -3,6 +3,8 @@
["BETAFPV LiteRadio 3 Pro", "lr3pro-"],
["Flysky EL18", "el18-"],
["Flysky NV14", "nv14-"],
+ ["Flysky PL18", "pl18-"],
+ ["Flysky PL18EV", "pl18ev-"],
["FrSky Horus X10", "x10-"],
["FrSky Horus X10 Access", "x10-access-"],
["FrSky Horus X12s", "x12s-"],
diff --git a/radio/src/CMakeLists.txt b/radio/src/CMakeLists.txt
index 577889d7d4a..e72fe13f0fd 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)
+set(PCB_TYPES X9LITE X9LITES X7 XLITE XLITES X9D X9D+ X9E X10 X12S NV14 PL18)
set(RADIO_LANGUAGES CN CZ DA DE EN ES FI FR HE IT JP PT RU SK SE PL HU NL TW)
set(TTS_LANGUAGES CN CZ DA DE EN ES FR HE IT JP PT RU SK SE PL HU NL)
@@ -85,6 +85,8 @@ if(PCB STREQUAL X12S OR PCB STREQUAL X10)
include(targets/horus/CMakeLists.txt)
elseif(PCB STREQUAL NV14)
include(targets/nv14/CMakeLists.txt)
+elseif(PCB STREQUAL PL18)
+ include(targets/pl18/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)
include(targets/taranis/CMakeLists.txt)
else()
diff --git a/radio/src/bitmaps/480x272/CMakeLists.txt b/radio/src/bitmaps/480x272/CMakeLists.txt
index a1458053abd..6c0f81f6b0a 100644
--- a/radio/src/bitmaps/480x272/CMakeLists.txt
+++ b/radio/src/bitmaps/480x272/CMakeLists.txt
@@ -4,6 +4,8 @@ set(MASK_ARGS ${BITMAP_SIZE_ARGS})
if(PCB STREQUAL NV14)
set(BITMAP_TARGET_PREFIX nv14)
+elseif(PCB STREQUAL PL18)
+ set(BITMAP_TARGET_PREFIX pl18)
elseif(PCB STREQUAL X12S)
set(BITMAP_TARGET_PREFIX x12s)
else()
diff --git a/radio/src/boards/generic_stm32/analog_inputs.cpp b/radio/src/boards/generic_stm32/analog_inputs.cpp
index 19036a17973..bbcbc7edaab 100644
--- a/radio/src/boards/generic_stm32/analog_inputs.cpp
+++ b/radio/src/boards/generic_stm32/analog_inputs.cpp
@@ -47,6 +47,9 @@ constexpr uint8_t n_ADC_spi = DIM(_ADC_spi);
constexpr uint8_t n_GPIO = DIM(_ADC_GPIOs);
constexpr uint8_t n_inputs = DIM(_ADC_inputs);
+static_assert(n_inputs <= MAX_ADC_INPUTS, "Too many ADC inputs");
+static_assert(n_inputs <= MAX_ANALOG_INPUTS, "Too many analog inputs");
+
static bool adc_init()
{
bool success = stm32_hal_adc_init(_ADC_adc, n_ADC, _ADC_inputs, _ADC_GPIOs, n_GPIO);
diff --git a/radio/src/boards/generic_stm32/inputs.cpp b/radio/src/boards/generic_stm32/inputs.cpp
index 385400e03f0..c1c3341c049 100644
--- a/radio/src/boards/generic_stm32/inputs.cpp
+++ b/radio/src/boards/generic_stm32/inputs.cpp
@@ -26,23 +26,27 @@
#include "stm32_keys.inc"
-void keysInit()
+#define __weak __attribute__((weak))
+
+__weak void keysInit()
{
_init_keys();
_init_trims();
}
-uint32_t readKeys()
+__weak uint32_t readKeys()
{
return _read_keys();
}
-uint32_t readTrims()
+__weak uint32_t readTrims()
{
uint32_t trims = _read_trims();
+
#if defined(PCBXLITE)
if (_read_keys() & (1 << KEY_SHIFT))
return ((trims & 0x03) << 6) | ((trims & 0x0c) << 2);
#endif
+
return trims;
}
diff --git a/radio/src/boards/generic_stm32/module_ports.cpp b/radio/src/boards/generic_stm32/module_ports.cpp
index e4d37be48d7..e7e07fd3d74 100644
--- a/radio/src/boards/generic_stm32/module_ports.cpp
+++ b/radio/src/boards/generic_stm32/module_ports.cpp
@@ -28,6 +28,7 @@
#include "board.h"
#include "dataconstants.h"
+#if defined (HARDWARE_INTERNAL_MODULE)
#if defined(INTMODULE_USART)
#define INTMODULE_USART_IRQ_PRIORITY 5
@@ -110,7 +111,8 @@ extern "C" void INTMODULE_TIMER_IRQHandler()
DEFINE_STM32_SOFTSERIAL_PORT(InternalModule, intmoduleTimer);
-#endif
+#endif // INTMODULE_USART
+#endif // HARDWARE_INTERNAL_MODULE
#include "module_timer_driver.h"
diff --git a/radio/src/cli.cpp b/radio/src/cli.cpp
index 8a06aaa9269..f21ca87806d 100644
--- a/radio/src/cli.cpp
+++ b/radio/src/cli.cpp
@@ -1040,6 +1040,7 @@ int cliSet(const char **argv)
}
#if defined(ENABLE_SERIAL_PASSTHROUGH)
+#if defined(HARDWARE_INTERNAL_MODULE)
static etx_module_state_t *spInternalModuleState = nullptr;
static void spInternalModuleTx(uint8_t* buf, uint32_t len)
@@ -1060,6 +1061,7 @@ static const etx_serial_init spIntmoduleSerialInitParams = {
.polarity = ETX_Pol_Normal,
};
+#endif // HARDWARE_INTERNAL_MODULE
// TODO: use proper method instead
extern bool cdcConnected;
extern uint32_t usbSerialBaudRate(void*);
@@ -1576,7 +1578,7 @@ int cliCrypt(const char ** argv)
}
#endif
-#if defined(HARDWARE_TOUCH) && !defined(PCBNV14)
+#if defined(HARDWARE_TOUCH) && !defined(PCBNV14) && !defined(PCBPL18)
// from tp_gt911.cpp
extern uint8_t tp_gt911_cfgVer;
@@ -1648,7 +1650,7 @@ const CliCommand cliCommands[] = {
#if defined(ACCESS_DENIED) && defined(DEBUG_CRYPT)
{ "crypt", cliCrypt, "" },
#endif
-#if defined(HARDWARE_TOUCH) && !defined(PCBNV14)
+#if defined(HARDWARE_TOUCH) && !defined(PCBNV14) && !defined(PCBPL18)
{ "reset_gt911", cliResetGT911, ""},
#endif
{ nullptr, nullptr, nullptr } /* sentinel */
diff --git a/radio/src/dataconstants.h b/radio/src/dataconstants.h
index 2459207fdb2..c69b8071d12 100644
--- a/radio/src/dataconstants.h
+++ b/radio/src/dataconstants.h
@@ -39,7 +39,7 @@
#define LABELS_LENGTH 100 // Maximum length of the label string
#define LABEL_LENGTH 16
-#if defined(PCBHORUS) || defined(PCBNV14)
+#if defined(PCBHORUS) || defined(PCBNV14) || defined(PCBPL18)
#define MAX_MODELS 60
#define MAX_OUTPUT_CHANNELS 32 // number of real output channels CH1-CH32
#define MAX_FLIGHT_MODES 9
@@ -98,7 +98,7 @@ enum CurveType {
#define MIN_POINTS_PER_CURVE 3
#define MAX_POINTS_PER_CURVE 17
-#if defined(PCBHORUS) || defined(PCBNV14)
+#if defined(PCBHORUS) || defined(PCBNV14) || defined(PCBPL18)
#define LEN_MODEL_NAME 15
#define LEN_TIMER_NAME 8
#define LEN_FLIGHT_MODE_NAME 10
@@ -408,10 +408,10 @@ enum PotsWarnMode {
#define MAX_FLEX_SWITCHES 0
#endif
-#if defined(RADIO_T20)
-#define MAX_TRIMS 8
+#if NUM_TRIMS > 6
+#define MAX_TRIMS 8
#else
-#define MAX_TRIMS 6
+#define MAX_TRIMS 6
#endif
#define MAX_XPOTS_POSITIONS (MAX_POTS * XPOTS_MULTIPOS_COUNT)
@@ -428,6 +428,13 @@ enum SwitchSources {
SWSRC_FIRST_TRIM SKIP,
SWSRC_LAST_TRIM SKIP = SWSRC_FIRST_TRIM + 2 * MAX_TRIMS - 1,
+#if NUM_TRIMS > 6
+ SWSRC_TrimT7Down,
+ SWSRC_TrimT7Up,
+ SWSRC_TrimT8Down,
+ SWSRC_TrimT8Up,
+#endif
+
SWSRC_FIRST_LOGICAL_SWITCH SKIP,
SWSRC_LAST_LOGICAL_SWITCH SKIP = SWSRC_FIRST_LOGICAL_SWITCH + MAX_LOGICAL_SWITCHES - 1,
@@ -605,7 +612,7 @@ enum Functions {
#if defined(DEBUG)
FUNC_MAX SKIP
#else
- FUNC_MAX SKIP = FUNC_TEST - 1
+ FUNC_MAX SKIP = FUNC_TEST
#endif
};
diff --git a/radio/src/datastructs.h b/radio/src/datastructs.h
index 392aefe8fba..fba828f073a 100644
--- a/radio/src/datastructs.h
+++ b/radio/src/datastructs.h
@@ -87,7 +87,7 @@ static inline void check_struct()
CHKSIZE(CurveHeader, 4);
CHKSIZE(CustomScreenData, 852);
CHKTYPE(TopBarPersistentData, 444);
-#elif defined(PCBNV14)
+#elif defined(PCBNV14) || defined(PCBPL18)
// TODO
#else
// Common for all variants
diff --git a/radio/src/datastructs_private.h b/radio/src/datastructs_private.h
index b149e4e12c0..3c8ec69cde9 100644
--- a/radio/src/datastructs_private.h
+++ b/radio/src/datastructs_private.h
@@ -602,7 +602,7 @@ PACK(struct CustomScreenData {
#define TOPBAR_DATA
#endif
-#if defined(PCBHORUS) || defined(PCBTARANIS) || defined(PCBNV14)
+#if defined(PCBHORUS) || defined(PCBTARANIS) || defined(PCBNV14) || defined(PCBPL18)
#define SCRIPT_DATA \
NOBACKUP(ScriptData scriptsData[MAX_SCRIPTS]);
#else
diff --git a/radio/src/debug.h b/radio/src/debug.h
index aa31b77cf1d..a5f84ddbec1 100644
--- a/radio/src/debug.h
+++ b/radio/src/debug.h
@@ -46,8 +46,8 @@ EXTERN_C(extern volatile uint32_t g_tmr10ms);
#define debugPrintf(...)
#endif
-#define TRACE_TIME_FORMAT "%0.2fs: "
-#define TRACE_TIME_VALUE ((float)g_tmr10ms / 100.0)
+#define TRACE_TIME_FORMAT "%dms: "
+#define TRACE_TIME_VALUE (g_tmr10ms * 10)
#define TRACE_NOCRLF(...) debugPrintf(__VA_ARGS__)
#define TRACE(f_, ...) debugPrintf((TRACE_TIME_FORMAT f_ CRLF), TRACE_TIME_VALUE, ##__VA_ARGS__)
diff --git a/radio/src/gui/colorlcd/radio_calibration.cpp b/radio/src/gui/colorlcd/radio_calibration.cpp
index 9c54cbea837..8ddba702d29 100644
--- a/radio/src/gui/colorlcd/radio_calibration.cpp
+++ b/radio/src/gui/colorlcd/radio_calibration.cpp
@@ -93,7 +93,7 @@ void RadioCalibrationPage::buildBody(FormWindow * window)
deco->setSlidersVisible(true);
deco->setFlightModeVisible(false);
-#if defined(PCBNV14)
+#if defined(PCBNV14) || defined(PCBPL18)
new TextButton(window, {LCD_W - 120, LCD_H - 140, 90, 40}, "Next",
[=]() -> uint8_t {
nextStep();
diff --git a/radio/src/gui/colorlcd/radio_diaganas.cpp b/radio/src/gui/colorlcd/radio_diaganas.cpp
index 903c32c8161..18ef7709ba9 100644
--- a/radio/src/gui/colorlcd/radio_diaganas.cpp
+++ b/radio/src/gui/colorlcd/radio_diaganas.cpp
@@ -177,7 +177,7 @@ class AnaCalibratedViewWindow: public AnaViewWindow {
}, COLOR_THEME_PRIMARY1);
lv_obj_set_grid_cell(lbl->getLvObj(), LV_GRID_ALIGN_STRETCH, 0, 5, LV_GRID_ALIGN_CENTER, 0, 1);
-#if !defined(SIMU) && !defined(PCBNV14)
+#if !defined(SIMU) && !defined(PCBNV14) && !defined(PCBPL18)
line = newLine(grid);
auto lbl2 = new StaticText(line, rect_t{}, std::string("Touch GT911 FW ver: ") + std::to_string(touchGT911fwver), COLOR_THEME_PRIMARY1);
lv_obj_set_grid_cell(lbl2->getLvObj(), LV_GRID_ALIGN_STRETCH, 0, 5, LV_GRID_ALIGN_CENTER, 0, 1);
diff --git a/radio/src/gui/colorlcd/radio_diagkeys.cpp b/radio/src/gui/colorlcd/radio_diagkeys.cpp
index a12c102e85c..d8dee02bb92 100644
--- a/radio/src/gui/colorlcd/radio_diagkeys.cpp
+++ b/radio/src/gui/colorlcd/radio_diagkeys.cpp
@@ -25,7 +25,11 @@
#include "hal/rotary_encoder.h"
+#if defined(PCBPL18)
+static const uint8_t _trimMap[MAX_TRIMS * 2] = {8, 9, 10, 11, 12, 13, 14, 15, 2, 3, 4, 5, 0, 1, 6, 7};
+#else
static const uint8_t _trimMap[MAX_TRIMS * 2] = {6, 7, 4, 5, 2, 3, 0, 1, 8, 9, 10, 11};
+#endif
static EnumKeys get_ith_key(uint8_t i)
{
@@ -122,8 +126,13 @@ class RadioKeyDiagsWindow : public Window
for (uint8_t i = 0; i < keysGetMaxTrims() * 2; i++) {
coord_t y = 1 + FH + FH * (i / 2);
if (i & 1) {
+#if defined(PCBPL18)
+ dc->drawText(TRIM_COLUMN, y, "TR", COLOR_THEME_PRIMARY1);
+ dc->drawNumber(TRIM_COLUMN + 20, y, i / 2 + 1, COLOR_THEME_PRIMARY1);
+#else
dc->drawText(TRIM_COLUMN, y, "T", COLOR_THEME_PRIMARY1);
dc->drawNumber(TRIM_COLUMN + 10, y, i / 2 + 1, COLOR_THEME_PRIMARY1);
+#endif
}
displayTrimState(dc, i & 1 ? TRIM_PLUS_COLUMN : TRIM_MINUS_COLUMN, y, _trimMap[i]);
}
diff --git a/radio/src/gui/colorlcd/radio_ghost_module_config.cpp b/radio/src/gui/colorlcd/radio_ghost_module_config.cpp
index f5976861f1c..0120f1775ff 100644
--- a/radio/src/gui/colorlcd/radio_ghost_module_config.cpp
+++ b/radio/src/gui/colorlcd/radio_ghost_module_config.cpp
@@ -110,12 +110,14 @@ static void ghostmoduleconfig_cb(lv_event_t* e)
}
}
+#if defined(HARDWARE_KEYS) && !defined(PCBPL18)
void RadioGhostModuleConfig::onCancel()
{
reusableBuffer.ghostMenu.buttonAction = GHST_BTN_JOYLEFT;
reusableBuffer.ghostMenu.menuAction = GHST_MENU_CTRL_NONE;
moduleState[EXTERNAL_MODULE].counter = GHST_MENU_CONTROL;
}
+#endif
RadioGhostModuleConfig::RadioGhostModuleConfig(uint8_t moduleIdx) :
Page(ICON_RADIO_TOOLS),
@@ -144,7 +146,7 @@ void RadioGhostModuleConfig::buildBody(FormWindow * window)
new GhostModuleConfigWindow(window, {0, 0, LCD_W, LCD_H - MENU_HEADER_HEIGHT - 5});
}
-#if defined(HARDWARE_KEYS)
+#if defined(HARDWARE_KEYS) && !defined(PCBPL18)
void RadioGhostModuleConfig::onEvent(event_t event)
{
switch (event) {
diff --git a/radio/src/gui/colorlcd/radio_ghost_module_config.h b/radio/src/gui/colorlcd/radio_ghost_module_config.h
index d80a6991559..3d758ff37ea 100644
--- a/radio/src/gui/colorlcd/radio_ghost_module_config.h
+++ b/radio/src/gui/colorlcd/radio_ghost_module_config.h
@@ -28,7 +28,7 @@ class RadioGhostModuleConfig: public Page
public:
explicit RadioGhostModuleConfig(uint8_t moduleIdx);
-#if defined(HARDWARE_KEYS)
+#if defined(HARDWARE_KEYS) && !defined(PCBPL18)
void onEvent(event_t event) override;
void checkEvents() override;
void onCancel() override;
diff --git a/radio/src/gui/colorlcd/radio_version.cpp b/radio/src/gui/colorlcd/radio_version.cpp
index ce97935bd25..7d38e02b685 100644
--- a/radio/src/gui/colorlcd/radio_version.cpp
+++ b/radio/src/gui/colorlcd/radio_version.cpp
@@ -77,13 +77,14 @@ class VersionDialog : public Dialog
memclear(&reusableBuffer.hardwareAndSettings.modules,
sizeof(reusableBuffer.hardwareAndSettings.modules));
reusableBuffer.hardwareAndSettings.updateTime = get_tmr10ms();
-
+#if defined(HARDWARE_INTERNAL_MODULE)
// Query modules
if (isModulePXX2(INTERNAL_MODULE) && modulePortPowered(INTERNAL_MODULE)) {
moduleState[INTERNAL_MODULE].readModuleInformation(
&reusableBuffer.hardwareAndSettings.modules[INTERNAL_MODULE],
PXX2_HW_INFO_TX_ID, PXX2_MAX_RECEIVERS_PER_MODULE - 1);
}
+#endif
if (isModulePXX2(EXTERNAL_MODULE) && modulePortPowered(EXTERNAL_MODULE)) {
moduleState[EXTERNAL_MODULE].readModuleInformation(
@@ -165,11 +166,13 @@ class VersionDialog : public Dialog
void update()
{
+#if defined(HARDWARE_INTERNAL_MODULE)
updateModule(INTERNAL_MODULE,
int_name,
int_module_status_w, int_status,
int_rx_name_w, int_rx_name,
int_rx_status_w, int_rx_status);
+#endif
updateModule(EXTERNAL_MODULE,
ext_name,
ext_module_status_w, ext_status,
@@ -309,11 +312,13 @@ class VersionDialog : public Dialog
{
if (get_tmr10ms() >= reusableBuffer.hardwareAndSettings.updateTime) {
// Query modules
+#if defined(HARDWARE_INTERNAL_MODULE)
if (isModulePXX2(INTERNAL_MODULE) && modulePortPowered(INTERNAL_MODULE)) {
moduleState[INTERNAL_MODULE].readModuleInformation(
&reusableBuffer.hardwareAndSettings.modules[INTERNAL_MODULE],
PXX2_HW_INFO_TX_ID, PXX2_MAX_RECEIVERS_PER_MODULE - 1);
}
+#endif
if (isModulePXX2(EXTERNAL_MODULE) && modulePortPowered(EXTERNAL_MODULE)) {
moduleState[EXTERNAL_MODULE].readModuleInformation(
&reusableBuffer.hardwareAndSettings.modules[EXTERNAL_MODULE],
@@ -332,7 +337,7 @@ RadioVersionPage::RadioVersionPage():
{
}
-#if defined(PCBNV14)
+#if defined(PCBNV14) || defined(PCBPL18)
extern const char* boardLcdType;
#endif
@@ -355,7 +360,7 @@ void RadioVersionPage::build(FormWindow * window)
version += options[i];
}
-#if defined(PCBNV14) && !defined(SIMU)
+#if (defined(PCBNV14) || defined(PCBPL18)) && !defined(SIMU)
version += nl;
version += "LCD: ";
version += boardLcdType;
diff --git a/radio/src/gui/colorlcd/special_functions.cpp b/radio/src/gui/colorlcd/special_functions.cpp
index 20b2056ce45..1d35d1b0a43 100644
--- a/radio/src/gui/colorlcd/special_functions.cpp
+++ b/radio/src/gui/colorlcd/special_functions.cpp
@@ -180,20 +180,21 @@ class SpecialFunctionEditPage : public Page
case FUNC_PLAY_TRACK:
case FUNC_BACKGND_MUSIC:
case FUNC_PLAY_SCRIPT:
+ case FUNC_RGB_LED:
new StaticText(line, rect_t{}, STR_VALUE, 0, COLOR_THEME_PRIMARY1);
new FileChoice(
line, rect_t{},
- func == FUNC_PLAY_SCRIPT
- ? SCRIPTS_FUNCS_PATH
+ func == FUNC_PLAY_SCRIPT || func == FUNC_RGB_LED
+ ? (func == FUNC_PLAY_SCRIPT ? SCRIPTS_FUNCS_PATH : SCRIPTS_RGB_PATH)
: std::string(SOUNDS_PATH, SOUNDS_PATH_LNG_OFS) +
std::string(currentLanguagePack->id, 2),
- func == FUNC_PLAY_SCRIPT ? SCRIPTS_EXT : SOUNDS_EXT,
+ (func == FUNC_PLAY_SCRIPT || func == FUNC_RGB_LED) ? SCRIPTS_EXT : SOUNDS_EXT,
sizeof(cfn->play.name),
[=]() { return std::string(cfn->play.name, ZLEN(cfn->play.name)); },
[=](std::string newValue) {
strncpy(cfn->play.name, newValue.c_str(), sizeof(cfn->play.name));
SET_DIRTY();
- if (func == FUNC_PLAY_SCRIPT)
+ if (func == FUNC_PLAY_SCRIPT || func == FUNC_RGB_LED)
LUA_LOAD_MODEL_SCRIPTS();
},
true); // strip extension
diff --git a/radio/src/hal/key_driver.cpp b/radio/src/hal/key_driver.cpp
index 6529bc04d70..dc500167f8e 100644
--- a/radio/src/hal/key_driver.cpp
+++ b/radio/src/hal/key_driver.cpp
@@ -22,6 +22,8 @@
#include "key_driver.h"
#include "definitions.h"
+#include "dataconstants.h"
+
#include "hal_keys.inc"
uint32_t keysGetSupported()
diff --git a/radio/src/hal/key_driver.h b/radio/src/hal/key_driver.h
index f0d20baa5f5..1701071a621 100644
--- a/radio/src/hal/key_driver.h
+++ b/radio/src/hal/key_driver.h
@@ -50,11 +50,7 @@ enum EnumKeys {
MAX_KEYS
};
-#if defined(RADIO_T20)
-#define MAX_TRIMS 8
-#else
-#define MAX_TRIMS 6
-#endif
+
// returns a bit field with each key set as (1 << KEY_xxx)
uint32_t readKeys();
diff --git a/radio/src/keys.cpp b/radio/src/keys.cpp
index e9cd936dfa0..54e3f3a238c 100644
--- a/radio/src/keys.cpp
+++ b/radio/src/keys.cpp
@@ -30,11 +30,7 @@
#include "timers_driver.h"
#include "hal/watchdog_driver.h"
#include "hal/rotary_encoder.h"
-
-// required by watchdog macro..
-#if !defined(SIMU)
-#include "stm32_cmsis.h"
-#endif
+#include "dataconstants.h"
// long key press minimum duration (x10ms),
// must be less than KEY_REPEAT_DELAY
diff --git a/radio/src/myeeprom.h b/radio/src/myeeprom.h
index a1ca3c55395..69eafc19f2a 100644
--- a/radio/src/myeeprom.h
+++ b/radio/src/myeeprom.h
@@ -169,7 +169,13 @@ enum CurveRefType {
#define TRIM_ELE (-2)
#define TRIM_THR (-3)
#define TRIM_AIL (-4)
-#if defined(PCBHORUS)
+#if defined(PCBPL18)
+ #define TRIM_T5 (-5)
+ #define TRIM_T6 (-6)
+ #define TRIM_T7 (-7)
+ #define TRIM_T8 (-8)
+ #define TRIM_LAST TRIM_T8
+#elif defined(PCBHORUS)
#define TRIM_T5 (-5)
#define TRIM_T6 (-6)
#define TRIM_LAST TRIM_T6
diff --git a/radio/src/opentx.h b/radio/src/opentx.h
index 101d417d255..ffb7cc60477 100644
--- a/radio/src/opentx.h
+++ b/radio/src/opentx.h
@@ -203,10 +203,6 @@ extern uint8_t heartbeat;
#include "keys.h"
#include "pwr.h"
-// #if defined(PCBFRSKY) || defined(PCBNV14)
-// extern uint8_t potsPos[NUM_XPOTS];
-// #endif
-
bool trimDown(uint8_t idx);
#if defined(KEYS_GPIO_REG_BIND)
diff --git a/radio/src/opentx_types.h b/radio/src/opentx_types.h
index 4f556d12c04..07bcd68b809 100644
--- a/radio/src/opentx_types.h
+++ b/radio/src/opentx_types.h
@@ -83,6 +83,7 @@ typedef uint32_t LcdFlags;
typedef uint16_t event_t;
typedef uint32_t tmr10ms_t;
+typedef int32_t rotenc_t;
typedef int32_t getvalue_t;
typedef uint32_t mixsrc_t;
typedef int32_t swsrc_t;
diff --git a/radio/src/pulses/multi.cpp b/radio/src/pulses/multi.cpp
index 27ddaf56cd2..e2fbd4bd6c7 100644
--- a/radio/src/pulses/multi.cpp
+++ b/radio/src/pulses/multi.cpp
@@ -116,12 +116,9 @@ static void sendFailsafeChannels(uint8_t*& p_buf, uint8_t module)
static void setupPulsesMulti(uint8_t*& p_buf, uint8_t module)
{
static int counter[2] = {0,0}; //TODO
- static uint8_t invert[2] = {0x00, //internal
-#if defined(PCBTARANIS) || defined(PCBHORUS) || defined(PCBNV14)
+ static uint8_t invert[2] = {
+ 0x00, //internal
0x08 //external
-#else
- 0x00 //external
-#endif
};
uint8_t type=MULTI_NORMAL;
diff --git a/radio/src/sdcard.cpp b/radio/src/sdcard.cpp
index 9555ebb60ca..7b45c20d9f7 100644
--- a/radio/src/sdcard.cpp
+++ b/radio/src/sdcard.cpp
@@ -545,7 +545,7 @@ void sdMount()
void sdDone()
{
TRACE("sdDone");
-
+
if (sdMounted()) {
audioQueue.stopSD();
@@ -557,8 +557,10 @@ void sdDone()
f_close(&g_bluetoothFile);
#endif
- f_mount(nullptr, "", 0); // unmount SD
+ f_mount(nullptr, "", 0); // unmount SD
}
+
+ storageDeInit();
}
uint32_t sdMounted()
diff --git a/radio/src/simu.cpp b/radio/src/simu.cpp
index 9523affbbbc..e06ab5936ed 100644
--- a/radio/src/simu.cpp
+++ b/radio/src/simu.cpp
@@ -348,7 +348,7 @@ long OpenTxSim::onMouseMove(FXObject*,FXSelector,void*v)
void OpenTxSim::updateKeysAndSwitches(bool start)
{
static int keys[] = {
-#if defined(PCBNV14)
+#if defined(PCBFLYSKY)
// no keys
#elif defined(PCBHORUS)
KEY_Page_Up, KEY_PAGEUP,
diff --git a/radio/src/storage/yaml/CMakeLists.txt b/radio/src/storage/yaml/CMakeLists.txt
index b320ff016a9..6a7e537bbe6 100644
--- a/radio/src/storage/yaml/CMakeLists.txt
+++ b/radio/src/storage/yaml/CMakeLists.txt
@@ -20,6 +20,8 @@ elseif(PCB STREQUAL X10)
set(YAML_GEN_OUTPUT storage/yaml/yaml_datastructs_x10.cpp)
elseif(PCB STREQUAL NV14)
set(YAML_GEN_OUTPUT storage/yaml/yaml_datastructs_nv14.cpp)
+elseif(PCB STREQUAL PL18)
+ set(YAML_GEN_OUTPUT storage/yaml/yaml_datastructs_pl18.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 fe77e7c5220..3b1a2254cf1 100644
--- a/radio/src/storage/yaml/yaml_datastructs.cpp
+++ b/radio/src/storage/yaml/yaml_datastructs.cpp
@@ -34,6 +34,8 @@
#include "yaml_datastructs_x10.cpp"
#elif defined(PCBNV14)
#include "yaml_datastructs_nv14.cpp"
+#elif defined(PCBPL18)
+ #include "yaml_datastructs_pl18.cpp"
#elif defined(PCBX7)
#if defined(RADIO_TPRO) || defined(RADIO_TPROV2)
#include "yaml_datastructs_tpro.cpp"
diff --git a/radio/src/storage/yaml/yaml_datastructs_funcs.cpp b/radio/src/storage/yaml/yaml_datastructs_funcs.cpp
index 85cec0b2301..0745654ef8f 100644
--- a/radio/src/storage/yaml/yaml_datastructs_funcs.cpp
+++ b/radio/src/storage/yaml/yaml_datastructs_funcs.cpp
@@ -38,7 +38,7 @@
// ========
//
// If any of these static_assert() fails, you need to check that
-// the functions bellow are still applicable.
+// the functions below are still applicable.
//
// Please note that the sizes used here are those from the v220 format
// (see storage/conversions/yaml/datastructs_220.h)
diff --git a/radio/src/storage/yaml/yaml_datastructs_pl18.cpp b/radio/src/storage/yaml/yaml_datastructs_pl18.cpp
new file mode 100644
index 00000000000..283256262bd
--- /dev/null
+++ b/radio/src/storage/yaml/yaml_datastructs_pl18.cpp
@@ -0,0 +1,915 @@
+// generated by generate_yaml.py
+
+//
+// Enums first
+//
+
+const struct YamlIdStr enum_HatsMode[] = {
+ { HATSMODE_TRIMS_ONLY, "TRIMS_ONLY" },
+ { HATSMODE_KEYS_ONLY, "KEYS_ONLY" },
+ { HATSMODE_SWITCHABLE, "SWITCHABLE" },
+ { HATSMODE_GLOBAL, "GLOBAL" },
+ { 0, NULL }
+};
+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_TEST, "TEST" },
+ { 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_MIN, "MIN" },
+ { MIXSRC_MAX, "MAX" },
+ { MIXSRC_TrimRud, "TrimRud" },
+ { MIXSRC_TrimEle, "TrimEle" },
+ { MIXSRC_TrimThr, "TrimThr" },
+ { MIXSRC_TrimAil, "TrimAil" },
+ { MIXSRC_TrimT5, "TrimT5" },
+ { MIXSRC_TrimT6, "TrimT6" },
+ { MIXSRC_TrimT7, "TrimT7" },
+ { MIXSRC_TrimT8, "TrimT8" },
+ { 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_TrimT7Down, "TrimT7Down" },
+ { SWSRC_TrimT7Up, "TrimT7Up" },
+ { SWSRC_TrimT8Down, "TrimT8Down" },
+ { SWSRC_TrimT8Up, "TrimT8Up" },
+ { 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),
+ 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", 6),
+ YAML_END
+};
+static const struct YamlNode struct_anonymous_2[] = {
+ YAML_SIGNED( "val", 16 ),
+ YAML_UNSIGNED( "mode", 8 ),
+ YAML_UNSIGNED( "param", 8 ),
+ YAML_SIGNED( "spare", 16 ),
+ YAML_END
+};
+static const struct YamlNode struct_anonymous_3[] = {
+ YAML_SIGNED( "val1", 32 ),
+ YAML_SIGNED( "val2", 16 ),
+ YAML_END
+};
+static const struct YamlNode union_anonymous_0_elmts[] = {
+ YAML_STRUCT("play", 48, struct_anonymous_1, NULL),
+ YAML_STRUCT("all", 48, struct_anonymous_2, NULL),
+ YAML_STRUCT("clear", 48, 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),
+ YAML_CUSTOM("def",r_customFn,w_customFn),
+ YAML_PADDING( 48 ),
+ YAML_PADDING( 1 ),
+ YAML_PADDING( 7 ),
+ YAML_END
+};
+static const struct YamlNode struct_RadioData[] = {
+ YAML_UNSIGNED( "manuallyEdited", 1 ),
+ YAML_SIGNED( "timezoneMinutes", 3 ),
+ YAML_ENUM("hatsMode", 2, enum_HatsMode),
+ YAML_UNSIGNED( "ppmunit", 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_SIGNED( "currModel", 8 ),
+ YAML_UNSIGNED( "contrast", 8 ),
+ YAML_UNSIGNED( "vBatWarn", 8 ),
+ YAML_SIGNED( "txVoltageCalibration", 8 ),
+ YAML_ENUM("backlightMode", 3, enum_BacklightMode),
+ YAML_ENUM("antennaMode", 2, enum_AntennaModes),
+ YAML_UNSIGNED( "disableRtcWarning", 1 ),
+ YAML_UNSIGNED( "keysBacklight", 1 ),
+ YAML_UNSIGNED( "dontPlayHello", 1 ),
+ YAML_ENUM("internalModule", 8, enum_ModuleType),
+ 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_PADDING( 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),
+ 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", 72, 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_ARRAY("potsConfig", 4, 16, struct_potConfig, nullptr),
+ YAML_ARRAY("switchConfig", 2, 32, struct_switchConfig, nullptr),
+ 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", 2 ),
+ YAML_SIGNED( "uartSampleMode", 2 ),
+ YAML_PADDING( 3 ),
+ YAML_UNSIGNED( "audioMuteEnable", 1 ),
+ YAML_STRING("selectedTheme", 26),
+ 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_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),
+ 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", 8 ),
+ YAML_SIGNED_CUST( "value", 8, in_read_weight, in_write_weight ),
+ YAML_END
+};
+static const struct YamlNode struct_MixData[] = {
+ YAML_SIGNED_CUST( "weight", 11, in_read_weight, in_write_weight ),
+ YAML_UNSIGNED( "destCh", 5 ),
+ YAML_UNSIGNED_CUST( "srcRaw", 10, r_mixSrcRaw, w_mixSrcRaw ),
+ YAML_UNSIGNED( "carryTrim", 1 ),
+ YAML_UNSIGNED( "mixWarn", 2 ),
+ YAML_ENUM("mltpx", 2, enum_MixerMultiplex),
+ YAML_PADDING( 1 ),
+ YAML_SIGNED_CUST( "offset", 13, in_read_weight, in_write_weight ),
+ YAML_SIGNED_CUST( "swtch", 10, r_swtchSrc, w_swtchSrc ),
+ YAML_UNSIGNED_CUST( "flightModes", 9, r_flightModes, w_flightModes ),
+ 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_UNSIGNED_CUST( "srcRaw", 10, r_mixSrcRaw, w_mixSrcRaw ),
+ YAML_UNSIGNED( "chn", 5 ),
+ YAML_SIGNED_CUST( "swtch", 10, r_swtchSrc, w_swtchSrc ),
+ YAML_UNSIGNED_CUST( "flightModes", 9, r_flightModes, w_flightModes ),
+ YAML_SIGNED_CUST( "weight", 8, in_read_weight, in_write_weight ),
+ YAML_STRING("name", 6),
+ YAML_SIGNED_CUST( "offset", 8, in_read_weight, in_write_weight ),
+ YAML_STRUCT("curve", 16, struct_CurveRef, NULL),
+ 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),
+ YAML_CUSTOM("def",r_logicSw,w_logicSw),
+ YAML_PADDING( 10 ),
+ YAML_PADDING( 10 ),
+ YAML_SIGNED_CUST( "andsw", 10, r_swtchSrc, w_swtchSrc ),
+ YAML_PADDING( 1 ),
+ YAML_PADDING( 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),
+ YAML_UNSIGNED( "value", 8 ),
+ YAML_UNSIGNED_CUST( "collectiveSource", 8, r_mixSrcRaw, w_mixSrcRaw ),
+ YAML_UNSIGNED_CUST( "aileronSource", 8, r_mixSrcRaw, w_mixSrcRaw ),
+ YAML_UNSIGNED_CUST( "elevatorSource", 8, r_mixSrcRaw, w_mixSrcRaw ),
+ YAML_SIGNED( "collectiveWeight", 8 ),
+ YAML_SIGNED( "aileronWeight", 8 ),
+ YAML_SIGNED( "elevatorWeight", 8 ),
+ YAML_END
+};
+static const struct YamlNode struct_trim_t[] = {
+ YAML_IDX,
+ YAML_SIGNED( "value", 11 ),
+ YAML_UNSIGNED( "mode", 5 ),
+ YAML_END
+};
+static const struct YamlNode struct_FlightModeData[] = {
+ YAML_IDX,
+ YAML_ARRAY("trim", 16, 8, struct_trim_t, NULL),
+ YAML_STRING("name", 10),
+ YAML_SIGNED_CUST( "swtch", 10, r_swtchSrc, w_swtchSrc ),
+ YAML_PADDING( 6 ),
+ YAML_UNSIGNED( "fadeIn", 8 ),
+ YAML_UNSIGNED( "fadeOut", 8 ),
+ YAML_ARRAY("gvars", 16, 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_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", 8, 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),
+ 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),
+ 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),
+ 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", 8),
+ 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),
+ YAML_UNION("value", 64, union_ZoneOptionValue_elmts, select_zov),
+ YAML_END
+};
+static const struct YamlNode struct_WidgetPersistentData[] = {
+ YAML_ARRAY("options", 96, 5, struct_ZoneOptionValueTyped, NULL),
+ YAML_END
+};
+static const struct YamlNode struct_ZonePersistentData[] = {
+ YAML_IDX,
+ YAML_STRING("widgetName", 12),
+ YAML_STRUCT("widgetData", 480, struct_WidgetPersistentData, NULL),
+ YAML_END
+};
+static const struct YamlNode struct_LayoutPersistentData[] = {
+ YAML_ARRAY("zones", 576, 10, struct_ZonePersistentData, NULL),
+ YAML_ARRAY("options", 96, 10, struct_ZoneOptionValueTyped, NULL),
+ YAML_END
+};
+static const struct YamlNode struct_CustomScreenData[] = {
+ YAML_IDX,
+ YAML_STRING("LayoutId", 12),
+ YAML_STRUCT("layoutData", 6720, struct_LayoutPersistentData, NULL),
+ YAML_END
+};
+static const struct YamlNode struct_TopBarPersistentData[] = {
+ YAML_ARRAY("zones", 576, 6, struct_ZonePersistentData, NULL),
+ YAML_ARRAY("options", 96, 1, struct_ZoneOptionValueTyped, NULL),
+ YAML_END
+};
+static const struct YamlNode struct_USBJoystickChData[] = {
+ YAML_IDX,
+ YAML_ENUM("mode", 3, enum_USBJoystickCh),
+ 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_ENUM("hatsMode", 2, enum_HatsMode),
+ YAML_PADDING( 2 ),
+ 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", 136, 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", 72, 64, struct_CustomFunctionData, cfn_is_active),
+ YAML_STRUCT("swashR", 64, struct_SwashRingData, swash_is_active),
+ YAML_ARRAY("flightModeData", 384, 9, struct_FlightModeData, fmd_is_active),
+ YAML_UNSIGNED_CUST( "thrTraceSrc", 8, r_thrSrc, w_thrSrc ),
+ YAML_CUSTOM("switchWarningState",r_swtchWarn,w_swtchWarn),
+ YAML_PADDING( 64 ),
+ 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),
+ YAML_ENUM("jitterFilter", 2, enum_ModelOverridableEnable),
+ 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", 6816, 10, struct_CustomScreenData, NULL),
+ YAML_STRUCT("topbarData", 3552, struct_TopBarPersistentData, NULL),
+ YAML_UNSIGNED( "view", 8 ),
+ YAML_STRING("modelRegistrationID", 8),
+ YAML_UNSIGNED( "usbJoystickExtMode", 1 ),
+ YAML_ENUM("usbJoystickIfMode", 3, enum_USBJoystickIfMode),
+ YAML_UNSIGNED( "usbJoystickCircularCut", 4 ),
+ YAML_ARRAY("usbJoystickCh", 16, 26, struct_USBJoystickChData, NULL),
+ YAML_ENUM("radioThemesDisabled", 2, enum_ModelOverridableEnable),
+ YAML_ENUM("radioGFDisabled", 2, enum_ModelOverridableEnable),
+ YAML_ENUM("radioTrainerDisabled", 2, enum_ModelOverridableEnable),
+ YAML_ENUM("modelHeliDisabled", 2, enum_ModelOverridableEnable),
+ YAML_ENUM("modelFMDisabled", 2, enum_ModelOverridableEnable),
+ YAML_ENUM("modelCurvesDisabled", 2, enum_ModelOverridableEnable),
+ YAML_ENUM("modelGVDisabled", 2, enum_ModelOverridableEnable),
+ YAML_ENUM("modelLSDisabled", 2, enum_ModelOverridableEnable),
+ YAML_ENUM("modelSFDisabled", 2, enum_ModelOverridableEnable),
+ YAML_ENUM("modelCustomScriptsDisabled", 2, enum_ModelOverridableEnable),
+ YAML_ENUM("modelTelemetryDisabled", 2, enum_ModelOverridableEnable),
+ 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/common/arm/CMakeLists.txt b/radio/src/targets/common/arm/CMakeLists.txt
index a24ee4e8242..e7e353b02e2 100644
--- a/radio/src/targets/common/arm/CMakeLists.txt
+++ b/radio/src/targets/common/arm/CMakeLists.txt
@@ -22,17 +22,19 @@ option(DEBUG_USB_INTERRUPTS "Count individual USB interrupts" OFF)
option(DEBUG_TIMERS "Time critical parts of the code" OFF)
option(DEBUG_BLUETOOTH "Debug Bluetooth" OFF)
-# option to select the default internal module
-#set(DEFAULT_INTERNAL_MODULE NONE CACHE STRING "Default internal module")
-set_property(CACHE DEFAULT_INTERNAL_MODULE PROPERTY STRINGS ${INTERNAL_MODULES})
-
-# define variables for internal modules
-foreach(module ${INTERNAL_MODULES})
- set(INTERNAL_MODULE_${module} ON CACHE BOOL "Support for ${module} internal module")
- if (INTERNAL_MODULE_${module})
- message("-- Adding support for ${module} as internal module")
- endif()
-endforeach()
+if(INTERNAL_MODULES)
+ # option to select the default internal module
+ #set(DEFAULT_INTERNAL_MODULE NONE CACHE STRING "Default internal module")
+ set_property(CACHE DEFAULT_INTERNAL_MODULE PROPERTY STRINGS ${INTERNAL_MODULES})
+
+ # define variables for internal modules
+ foreach(module ${INTERNAL_MODULES})
+ set(INTERNAL_MODULE_${module} ON CACHE BOOL "Support for ${module} internal module")
+ if (INTERNAL_MODULE_${module})
+ message("-- Adding support for ${module} as internal module")
+ endif()
+ endforeach()
+endif()
if(INTERNAL_MODULE_PXX1)
add_definitions(-DHARDWARE_INTERNAL_MODULE)
diff --git a/radio/src/targets/common/arm/stm32/bootloader/CMakeLists.txt b/radio/src/targets/common/arm/stm32/bootloader/CMakeLists.txt
index 117e1c6431c..85e66458cf2 100644
--- a/radio/src/targets/common/arm/stm32/bootloader/CMakeLists.txt
+++ b/radio/src/targets/common/arm/stm32/bootloader/CMakeLists.txt
@@ -69,8 +69,7 @@ if(DEBUG_SEGGER_RTT)
)
endif()
-
-if(PCB STREQUAL X10 OR PCB STREQUAL X12S OR PCB STREQUAL NV14)
+if(PCB STREQUAL X10 OR PCB STREQUAL X12S OR PCB STREQUAL NV14 OR PCB STREQUAL PL18)
set(BOOTLOADER_SRC
${BOOTLOADER_SRC}
../../../../../gui/colorlcd/fonts.cpp
@@ -79,7 +78,6 @@ if(PCB STREQUAL X10 OR PCB STREQUAL X12S OR PCB STREQUAL NV14)
../../../../../thirdparty/libopenui/src/bitmapbuffer.cpp
../../../../../thirdparty/libopenui/thirdparty/lz4/lz4.c
../../../../../targets/common/arm/stm32/dma2d.cpp
- ../../../../../targets/common/arm/stm32/diskio_sdio.cpp
../../../../../targets/common/arm/stm32/rtc_driver.cpp
../../../../../targets/common/arm/stm32/diskio_spi_flash.cpp
../../../../../targets/common/arm/stm32/spi_flash.cpp
@@ -90,12 +88,22 @@ if(PCB STREQUAL X10 OR PCB STREQUAL X12S OR PCB STREQUAL NV14)
../../../../../targets/${TARGET_DIR}/haptic_driver.cpp
)
+ if(NOT PCB STREQUAL PL18)
+ set(BOOTLOADER_SRC ${BOOTLOADER_SRC}
+ ../../../../../targets/common/arm/stm32/diskio_sdio.cpp
+ )
+ else()
+ set(BOOTLOADER_SRC ${BOOTLOADER_SRC}
+ ../../../../../targets/pl18/key_driver.cpp
+ )
+ endif()
+
# Add LVGL sources
foreach(LVGL_FILE ${LVGL_SRC_FILES_MINIMAL})
set(BOOTLOADER_SRC ${BOOTLOADER_SRC} ../../../../../${LVGL_FILE})
endforeach()
- if(NOT PCB STREQUAL NV14)
+ if(NOT (PCB STREQUAL NV14 OR PCB STREQUAL PL18))
set(BOOTLOADER_SRC
${BOOTLOADER_SRC}
../../../../../targets/${TARGET_DIR}/led_driver.cpp
diff --git a/radio/src/targets/common/arm/stm32/bootloader/boot.cpp b/radio/src/targets/common/arm/stm32/bootloader/boot.cpp
index a83ab59afd2..32a1bdce27f 100644
--- a/radio/src/targets/common/arm/stm32/bootloader/boot.cpp
+++ b/radio/src/targets/common/arm/stm32/bootloader/boot.cpp
@@ -56,12 +56,17 @@
#define APP_START_ADDRESS (uint32_t)(FIRMWARE_ADDRESS + BOOTLOADER_SIZE)
-#if defined(EEPROM)
+#if defined(EEPROM) || defined(SPI_FLASH)
#define MAIN_MENU_LEN 3
#else
#define MAIN_MENU_LEN 2
#endif
+#if defined(SPI_FLASH)
+ #include "spi_flash.h"
+ #define SEL_CLEAR_FLASH_STORAGE_MENU_LEN 2
+#endif
+
typedef void (*voidFunction)(void);
#define jumpTo(addr) do { \
@@ -369,6 +374,10 @@ int bootloaderMain()
memoryType = MEM_EEPROM;
state = ST_DIR_CHECK;
break;
+#elif defined(SPI_FLASH)
+ case 1:
+ state = ST_CLEAR_FLASH_CHECK;
+ break;
#endif
default:
if(vpos < bootloaderGetMenuItemCount(MAIN_MENU_LEN-1))
@@ -511,6 +520,35 @@ int bootloaderMain()
else if (memoryType == MEM_EEPROM && eepromWritten >= EEPROM_SIZE) {
state = ST_FLASH_DONE; // Backstop
}
+#endif
+#if defined(SPI_FLASH)
+ } else if (state == ST_CLEAR_FLASH_CHECK) {
+ bootloaderDrawScreen(state, vpos);
+ if (event == EVT_KEY_REPT(KEY_DOWN) || event == EVT_KEY_FIRST(KEY_DOWN)) {
+ if (vpos < SEL_CLEAR_FLASH_STORAGE_MENU_LEN - 1) { vpos++; }
+ continue;
+ }
+ if (event == EVT_KEY_REPT(KEY_UP) || event == EVT_KEY_FIRST(KEY_UP)) {
+ if (vpos > 0) { vpos--; }
+ continue;
+ }
+ if (event == EVT_KEY_LONG(KEY_ENTER) && vpos == 0)
+ {
+ state = ST_CLEAR_FLASH;
+ } else if (event == EVT_KEY_BREAK(KEY_EXIT) ||
+ (event == EVT_KEY_BREAK(KEY_ENTER) && vpos == 1) ) {
+ vpos = 0;
+ state = ST_START;
+ continue;
+ }
+ } else if (state == ST_CLEAR_FLASH) {
+ bootloaderDrawScreen(state, 0);
+ lcdRefresh();
+ if(event != EVT_KEY_BREAK(KEY_ENTER))
+ continue;
+ flashSpiEraseAll();
+ vpos = 0;
+ state = ST_START;
#endif
} else if (state == ST_RADIO_MENU) {
if(bootloaderRadioMenu(radioMenuItem, event))
@@ -565,6 +603,6 @@ int bootloaderMain()
return 0;
}
-#if !defined(SIMU) && (defined(PCBHORUS) || defined(PCBNV14))
+#if !defined(SIMU) && (defined(PCBHORUS) || defined(PCBFLYSKY))
void *__dso_handle = nullptr;
#endif
diff --git a/radio/src/targets/common/arm/stm32/bootloader/boot.h b/radio/src/targets/common/arm/stm32/bootloader/boot.h
index fd93b3ef567..5f747239fef 100644
--- a/radio/src/targets/common/arm/stm32/bootloader/boot.h
+++ b/radio/src/targets/common/arm/stm32/bootloader/boot.h
@@ -54,6 +54,10 @@ enum BootloaderState {
ST_FLASH_DONE,
ST_RESTORE_MENU,
ST_USB,
+#if defined(SPI_FLASH)
+ ST_CLEAR_FLASH_CHECK,
+ ST_CLEAR_FLASH,
+#endif
ST_RADIO_MENU,
ST_REBOOT,
};
diff --git a/radio/src/targets/common/arm/stm32/diskio_spi_flash.cpp b/radio/src/targets/common/arm/stm32/diskio_spi_flash.cpp
index bdd7db86785..3f8dc014b6f 100644
--- a/radio/src/targets/common/arm/stm32/diskio_spi_flash.cpp
+++ b/radio/src/targets/common/arm/stm32/diskio_spi_flash.cpp
@@ -30,6 +30,7 @@
#include "drivers/frftl.h"
static FrFTL _frftl;
+static bool frftlInitDone = false;
static bool flashRead(uint32_t addr, uint8_t* buf, uint32_t len)
{
@@ -89,6 +90,7 @@ static DSTATUS spi_flash_initialize(BYTE lun)
if (!ftlInit(&_frftl, &_frftl_cb, flashSizeMB)) {
return STA_NOINIT;
}
+ frftlInitDone = true;
#endif
return 0;
@@ -102,7 +104,7 @@ static DSTATUS spi_flash_status (BYTE lun)
static DRESULT spi_flash_read(BYTE lun, BYTE * buff, DWORD sector, UINT count)
{
#if defined(USE_FLASH_FTL)
- while(count) {
+ while(frftlInitDone && count) {
if(!ftlRead(&_frftl, sector, (uint8_t*)buff)) {
return RES_ERROR;
@@ -122,7 +124,7 @@ static DRESULT spi_flash_read(BYTE lun, BYTE * buff, DWORD sector, UINT count)
static DRESULT spi_flash_write(BYTE lun, const BYTE *buff, DWORD sector, UINT count)
{
#if defined(USE_FLASH_FTL)
- if (!ftlWrite(&_frftl, sector, count, (uint8_t*)buff)) {
+ if (frftlInitDone && !ftlWrite(&_frftl, sector, count, (uint8_t*)buff)) {
return RES_ERROR;
}
#else
@@ -166,7 +168,7 @@ static DRESULT spi_flash_ioctl(BYTE lun, BYTE ctrl, void *buff)
case CTRL_SYNC:
#if defined(USE_FLASH_FTL)
- if (!ftlSync(&_frftl)) {
+ if (frftlInitDone && !ftlSync(&_frftl)) {
res = RES_ERROR;
}
#else
@@ -176,7 +178,7 @@ static DRESULT spi_flash_ioctl(BYTE lun, BYTE ctrl, void *buff)
case CTRL_TRIM:
#if defined(USE_FLASH_FTL)
- if (!ftlTrim(&_frftl, *(DWORD*)buff, 1 + *((DWORD*)buff + 1) - *(DWORD*)buff)) {
+ if (frftlInitDone && !ftlTrim(&_frftl, *(DWORD*)buff, 1 + *((DWORD*)buff + 1) - *(DWORD*)buff)) {
res = RES_ERROR;
}
#endif
diff --git a/radio/src/targets/common/arm/stm32/pwr_driver.cpp b/radio/src/targets/common/arm/stm32/pwr_driver.cpp
index 46a50b36e72..fb5b7e49e96 100644
--- a/radio/src/targets/common/arm/stm32/pwr_driver.cpp
+++ b/radio/src/targets/common/arm/stm32/pwr_driver.cpp
@@ -38,9 +38,11 @@ void pwrInit()
#endif
// Internal module power
+#if defined(HARDWARE_INTERNAL_MODULE)
INTERNAL_MODULE_OFF();
GPIO_InitStructure.GPIO_Pin = INTMODULE_PWR_GPIO_PIN;
GPIO_Init(INTMODULE_PWR_GPIO, &GPIO_InitStructure);
+#endif
// External module power
EXTERNAL_MODULE_PWR_OFF();
diff --git a/radio/src/targets/common/arm/stm32/spi_flash.cpp b/radio/src/targets/common/arm/stm32/spi_flash.cpp
index 100ce9559ec..c9e25567837 100644
--- a/radio/src/targets/common/arm/stm32/spi_flash.cpp
+++ b/radio/src/targets/common/arm/stm32/spi_flash.cpp
@@ -223,10 +223,19 @@ static bool flash_read_sfdp(SpiFlashDescriptor* desc)
return true;
}
+void flashSpiSync()
+{
+ uint8_t status;
+ do {
+ flash_do_cmd(FLASH_CMD_STATUS, 0, &status, 1);
+ } while (status & 0x01);
+}
+
bool flashSpiInit(void)
{
stm32_spi_init(&_flash_spi);
delay_ms(1);
+ flashSpiSync();
if (!flash_read_id(&_flashDescriptor)) {
return false;
@@ -239,14 +248,6 @@ bool flashSpiInit(void)
return true;
}
-void flashSpiSync()
-{
- uint8_t status;
- do {
- flash_do_cmd(FLASH_CMD_STATUS, 0, &status, 1);
- } while (status & 0x01);
-}
-
uint32_t flashSpiGetSize()
{
return (1UL << _flashDescriptor.log2Size);
diff --git a/radio/src/targets/common/arm/stm32/stm32_adc.cpp b/radio/src/targets/common/arm/stm32/stm32_adc.cpp
index 4244a5d96a9..48c98278ee9 100644
--- a/radio/src/targets/common/arm/stm32/stm32_adc.cpp
+++ b/radio/src/targets/common/arm/stm32/stm32_adc.cpp
@@ -26,9 +26,10 @@
#include "opentx.h"
-#define ADC_COMMON ((ADC_Common_TypeDef *) ADC_BASE)
-#define MAX_ADC_INPUTS 32
-#define OVERSAMPLING 4
+#define ADC_COMMON ((ADC_Common_TypeDef *)ADC_BASE)
+#define OVERSAMPLING 4
+
+#define SAMPLING_TIMEOUT_US 500
// Please note that we use the same prio for DMA TC and ADC IRQs
// to avoid issues with preemption between these 2
@@ -43,7 +44,7 @@ static volatile uint32_t _adc_inhibit_mask;
static uint16_t _adc_dma_buffer[MAX_ADC_INPUTS] __DMA;
// ADCs started
-static uint8_t _adc_started_mask;
+static volatile uint8_t _adc_started_mask;
static volatile uint8_t _adc_completed;
static const stm32_adc_t* _adc_ADCs;
@@ -532,8 +533,14 @@ void stm32_hal_adc_wait_completion(const stm32_adc_t* ADCs, uint8_t n_ADC,
(void)inputs;
(void)n_inputs;
+ auto timeout = timersGetUsTick();
while(!_adc_completed) {
// busy wait
+ if ((uint32_t)(timersGetUsTick() - timeout) >= SAMPLING_TIMEOUT_US) {
+ TRACE("ADC timeout");
+ _adc_started_mask = 0;
+ return;
+ }
}
}
@@ -572,8 +579,7 @@ static void _adc_chain_conversions(const stm32_adc_t* adc)
void stm32_hal_adc_dma_isr(const stm32_adc_t* adc)
{
// Disable IRQ
- auto dma_stream = _dma_get_stream(adc->DMAx, adc->DMA_Stream);
- CLEAR_BIT(dma_stream->CR, DMA_SxCR_TCIE | DMA_SxCR_TEIE | DMA_SxCR_DMEIE);
+ adc_dma_clear_flags(adc->DMAx, adc->DMA_Stream);
uint16_t* dma_buffer = _adc_dma_buffer + adc->offset;
copy_adc_values(dma_buffer, adc, _adc_inputs);
diff --git a/radio/src/targets/common/arm/stm32/stm32_adc.h b/radio/src/targets/common/arm/stm32/stm32_adc.h
index 9d73a709988..97ee324e1dc 100644
--- a/radio/src/targets/common/arm/stm32/stm32_adc.h
+++ b/radio/src/targets/common/arm/stm32/stm32_adc.h
@@ -24,6 +24,7 @@
#include "stm32_hal_ll.h"
#include "hal/adc_driver.h"
+#define MAX_ADC_INPUTS 32
struct stm32_adc_input_t {
GPIO_TypeDef* GPIOx;
diff --git a/radio/src/targets/common/arm/stm32/usb_bsp.c b/radio/src/targets/common/arm/stm32/usb_bsp.c
index 1317a11a87c..26a964749e9 100644
--- a/radio/src/targets/common/arm/stm32/usb_bsp.c
+++ b/radio/src/targets/common/arm/stm32/usb_bsp.c
@@ -49,7 +49,8 @@ void USB_OTG_BSP_Init(USB_OTG_CORE_HANDLE *pdev)
GPIO_PinAFConfig(USB_GPIO, USB_GPIO_PinSource_DM, USB_GPIO_AF);
GPIO_PinAFConfig(USB_GPIO, USB_GPIO_PinSource_DP, USB_GPIO_AF);
-
+
+#if defined(USB_GPIO_PIN_VBUS)
/* Configure VBUS Pin */
GPIO_InitStructure.GPIO_Pin = USB_GPIO_PIN_VBUS;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
@@ -57,6 +58,7 @@ void USB_OTG_BSP_Init(USB_OTG_CORE_HANDLE *pdev)
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
GPIO_Init(USB_GPIO, &GPIO_InitStructure);
+#endif
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_OTG_FS, ENABLE) ;
diff --git a/radio/src/targets/common/arm/stm32/usb_conf.h b/radio/src/targets/common/arm/stm32/usb_conf.h
index 22f3b2656db..337195ed4c9 100644
--- a/radio/src/targets/common/arm/stm32/usb_conf.h
+++ b/radio/src/targets/common/arm/stm32/usb_conf.h
@@ -29,6 +29,8 @@
#include "stm32f2xx.h"
#endif
+#include "hal.h"
+
/* USB Core and PHY interface configuration.
Tip: To avoid modifying these defines each time you need to change the USB
configuration, you can declare the needed define in your toolchain
@@ -97,7 +99,9 @@
#endif
/****************** USB OTG MISC CONFIGURATION ********************************/
+#if defined(USB_GPIO_PIN_VBUS)
#define VBUS_SENSING_ENABLED
+#endif
/****************** USB OTG MODE CONFIGURATION ********************************/
//#define USE_HOST_MODE
diff --git a/radio/src/targets/common/arm/stm32/usb_driver.cpp b/radio/src/targets/common/arm/stm32/usb_driver.cpp
index 57545f2e90b..67f43716dae 100644
--- a/radio/src/targets/common/arm/stm32/usb_driver.cpp
+++ b/radio/src/targets/common/arm/stm32/usb_driver.cpp
@@ -57,6 +57,7 @@ void setSelectedUsbMode(int mode)
selectedUsbMode = usbMode(mode);
}
+#if defined(USB_GPIO_PIN_VBUS)
int usbPlugged()
{
static uint8_t debouncedState = 0;
@@ -71,6 +72,7 @@ int usbPlugged()
return debouncedState;
}
+#endif
USB_OTG_CORE_HANDLE USB_OTG_dev;
diff --git a/radio/src/targets/horus/CMakeLists.txt b/radio/src/targets/horus/CMakeLists.txt
index 8d409d6cf71..62b2a30e399 100644
--- a/radio/src/targets/horus/CMakeLists.txt
+++ b/radio/src/targets/horus/CMakeLists.txt
@@ -158,7 +158,6 @@ add_definitions(-DPCBHORUS -DSTM32F429_439xx -DSTM32F429xx -DSDRAM -DCCMRAM -DCO
add_definitions(-DEEPROM_VARIANT=0 -DAUDIO -DVOICE -DRTCLOCK)
add_definitions(-DGPS_USART_BAUDRATE=${INTERNAL_GPS_BAUDRATE})
add_definitions(-DPWR_BUTTON_${PWR_BUTTON})
-add_definitions(-DHARDWARE_TRAINER_JACK)
add_definitions(-DSTM32_SUPPORT_32BIT_TIMERS)
set(SDRAM ON)
diff --git a/radio/src/targets/nv14/CMakeLists.txt b/radio/src/targets/nv14/CMakeLists.txt
index cc502c9307b..3913b075ed1 100644
--- a/radio/src/targets/nv14/CMakeLists.txt
+++ b/radio/src/targets/nv14/CMakeLists.txt
@@ -19,7 +19,6 @@ set(BITMAPS_DIR 480x272)
set(HARDWARE_EXTERNAL_MODULE YES)
set(TARGET_DIR nv14)
-add_definitions(-DHARDWARE_TRAINER_JACK)
set(RTC_BACKUP_RAM YES)
set(PPM_LIMITS_SYMETRICAL YES)
diff --git a/radio/src/targets/nv14/board.cpp b/radio/src/targets/nv14/board.cpp
index becfd623c3c..2c1ba8680dd 100644
--- a/radio/src/targets/nv14/board.cpp
+++ b/radio/src/targets/nv14/board.cpp
@@ -38,7 +38,6 @@
#include "flysky_gimbal_driver.h"
#include "timers_driver.h"
-#include "lcd_driver.h"
#include "lcd_driver.h"
#include "battery_driver.h"
#include "touch_driver.h"
@@ -73,7 +72,8 @@ void delay_self(int count)
for (; count > 0; count--);
}
}
-#define RCC_AHB1PeriphMinimum (PWR_RCC_AHB1Periph |\
+
+#define RCC_AHB1PeriphMinimum (PWR_RCC_AHB1Periph | \
LCD_RCC_AHB1Periph |\
BACKLIGHT_RCC_AHB1Periph |\
SDRAM_RCC_AHB1Periph \
diff --git a/radio/src/targets/nv14/board.h b/radio/src/targets/nv14/board.h
index af203d5de4b..19f50e6a643 100644
--- a/radio/src/targets/nv14/board.h
+++ b/radio/src/targets/nv14/board.h
@@ -115,25 +115,17 @@ extern HardwareOptions hardwareOptions;
#endif // defined(SIMU)
#define EXTERNAL_MODULE_PWR_OFF EXTERNAL_MODULE_OFF
-#define IS_UART_MODULE(port) (port == INTERNAL_MODULE)
-#define IS_PXX2_INTERNAL_ENABLED() (false)
#if !defined(NUM_FUNCTIONS_SWITCHES)
#define NUM_FUNCTIONS_SWITCHES 0
#endif
-#define NUM_TRIMS_KEYS (NUM_TRIMS * 2)
-
-#define DEFAULT_STICK_DEADZONE 2
-
-// 2 pots without detent
-#define DEFAULT_POTS_CONFIG \
- (POT_WITHOUT_DETENT << 0) + \
- (POT_WITHOUT_DETENT << 2)
+#define DEFAULT_STICK_DEADZONE 2
#define BATTERY_WARN 36 // 3.6V
#define BATTERY_MIN 35 // 3.5V
#define BATTERY_MAX 42 // 4.2V
+#define BATTERY_DIVIDER 2942
#if defined(__cplusplus) && !defined(SIMU)
extern "C" {
@@ -275,6 +267,4 @@ bool touchPanelEventOccured();
struct TouchState touchPanelRead();
struct TouchState getInternalTouchState();
-#define BATTERY_DIVIDER 2942
-
#endif // _BOARD_H_
diff --git a/radio/src/targets/pl18/CMakeLists.txt b/radio/src/targets/pl18/CMakeLists.txt
new file mode 100644
index 00000000000..10eb2ed1469
--- /dev/null
+++ b/radio/src/targets/pl18/CMakeLists.txt
@@ -0,0 +1,167 @@
+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)
+
+set(PWR_BUTTON "PRESS" CACHE STRING "Pwr button type (PRESS/SWITCH)")
+set(CPU_TYPE STM32F4)
+set(HSE_VALUE 12000000)
+set(SDCARD YES)
+set(STORAGE_MODELSLIST YES)
+set(HAPTIC YES)
+set(GUI_DIR colorlcd)
+set(BITMAPS_DIR 480x272)
+set(TARGET_DIR pl18)
+set(LINKER_SCRIPT targets/pl18/stm32f4_flash.ld)
+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(WIRELESS_CHARGER YES)
+
+#option(STICKS_DEAD_ZONE "Enable sticks dead zone" YES)
+#option(AFHDS2 "Support for AFHDS2" OFF)
+
+# for size report script
+set(CPU_TYPE_FULL STM32F429xI)
+set(TARGET_LINKER_DIR stm32f429_sdram)
+set(TARGET_LINKER_PARAMS "-Wl,--defsym=__SDRAM_START__=0xC0000000")
+set(SIZE_TARGET_MEM_DEFINE "MEM_SIZE_SDRAM1=8192")
+
+#set(RF_BAUD_RATE 921600 230400 115200 57600 38400 19200 9600 4800 2400 1200)
+#set(PCB_RF_BAUD 921600 CACHE STRING "INTERNAL_MODULE_BAUDRATE: ${RF_BAUD_RATE}")
+#set_property(CACHE PCB_RF_BAUD PROPERTY STRINGS ${RF_BAUD_RATE})
+
+add_definitions(-DPCBPL18 -DPCBFLYSKY)
+add_definitions(-DBATTERY_CHARGE)
+add_definitions(-DSOFTWARE_VOLUME)
+add_definitions(-DSPI_FLASH)
+add_definitions(-DSTM32_SUPPORT_32BIT_TIMERS)
+
+if(PCBREV STREQUAL PL18EV)
+ set(FLAVOUR pl18ev)
+ add_definitions(-DRADIO_PL18EV)
+else()
+ set(FLAVOUR pl18)
+ add_definitions(-DRADIO_PL18)
+
+ # Defines internal modules for PL18 via UART7
+ set(INTERNAL_MODULES MULTI CACHE STRING "Internal modules")
+ set(DEFAULT_INTERNAL_MODULE MULTIMODULE CACHE STRING "Default internal module")
+endif()
+
+set(BITMAPS_TARGET pl18_bitmaps)
+set(FONTS_TARGET x12_fonts)
+set(LCD_DRIVER lcd_driver.cpp)
+set(TOUCH_DRIVER touch_driver.cpp)
+set(HARDWARE_TOUCH YES)
+set(RADIO_DEPENDENCIES ${RADIO_DEPENDENCIES} ${BITMAPS_TARGET})
+set(FIRMWARE_DEPENDENCIES datacopy)
+
+set(HARDWARE_TOUCH ON)
+set(SOFTWARE_KEYBOARD ON)
+set(FLYSKY_GIMBAL ON)
+
+add_definitions(
+ -DSTM32F429_439xx -DSTM32F429xx
+ -DSDRAM -DCCMRAM -DCOLORLCD -DLIBOPENUI
+ -DHARDWARE_TOUCH -DHARDWARE_KEYS
+ -DSOFTWARE_KEYBOARD -DUSE_HATS_AS_KEYS)
+
+set(SDRAM ON)
+
+add_definitions(-DEEPROM_VARIANT=0 -DAUDIO -DVOICE -DRTCLOCK)
+add_definitions(-DGPS_USART_BAUDRATE=${INTERNAL_GPS_BAUDRATE})
+add_definitions(-DPWR_BUTTON_${PWR_BUTTON})
+add_definitions(-DCROSSFIRE_NATIVE)
+add_definitions(-DHARDWARE_EXTERNAL_MODULE)
+
+if(WIRELESS_CHARGER)
+ add_definitions(-DWIRELESS_CHARGER)
+endif()
+
+if(STICKS_DEAD_ZONE)
+ add_definitions(-DSTICK_DEAD_ZONE)
+endif()
+
+if(NOT UNEXPECTED_SHUTDOWN)
+ add_definitions(-DNO_UNEXPECTED_SHUTDOWN)
+endif()
+
+set(AFHDS3 ON)
+
+# VCP CLI
+set(ENABLE_SERIAL_PASSTHROUGH ON CACHE BOOL "Enable serial passthrough")
+set(CLI ON CACHE BOOL "Enable CLI")
+
+include_directories(${RADIO_SRC_DIR}/fonts/colorlcd gui/${GUI_DIR} gui/${GUI_DIR}/layouts)
+
+file(GLOB THEMES_SRC RELATIVE ${RADIO_SRC_DIR}/gui/colorlcd ${RADIO_SRC_DIR}/gui/colorlcd/themes/*.cpp)
+file(GLOB LAYOUTS_SRC RELATIVE ${RADIO_SRC_DIR}/gui/colorlcd ${RADIO_SRC_DIR}/gui/colorlcd/layouts/*.cpp)
+file(GLOB WIDGETS_SRC RELATIVE ${RADIO_SRC_DIR}/gui/colorlcd ${RADIO_SRC_DIR}/gui/colorlcd/widgets/*.cpp)
+
+set(SRC
+ ${SRC}
+ io/frsky_firmware_update.cpp
+ )
+
+set(GVAR_SCREEN model_gvars.cpp)
+
+if(BOOTLOADER)
+ set(FIRMWARE_TARGET_SRC
+ ${FIRMWARE_TARGET_SRC}
+ ../common/arm/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()
+
+set(FIRMWARE_TARGET_SRC
+ ${FIRMWARE_TARGET_SRC}
+ ${LCD_DRIVER}
+ ${TOUCH_DRIVER}
+ board.cpp
+ key_driver.cpp
+ battery_driver.cpp
+ backlight_driver.cpp
+ led_driver.cpp
+ sdram_driver.c
+ )
+
+set(FIRMWARE_SRC
+ ${FIRMWARE_SRC}
+ targets/common/arm/stm32/audio_dac_driver.cpp
+ targets/common/arm/stm32/dma2d.cpp
+ targets/common/arm/stm32/spi_flash.cpp
+ targets/common/arm/stm32/diskio_spi_flash.cpp
+ targets/common/arm/stm32/stm32_ws2812.cpp
+ boards/generic_stm32/rgb_leds.cpp
+ drivers/frftl.cpp
+ )
+
+# Make malloc() thread-safe
+add_definitions(-DTHREADSAFE_MALLOC)
+
+set(STM32LIB_SRC
+ STM32F4xx_StdPeriph_Driver/src/stm32f4xx_sdio.c
+ STM32F4xx_StdPeriph_Driver/src/stm32f4xx_fmc.c
+ STM32F4xx_StdPeriph_Driver/src/stm32f4xx_ltdc.c
+ STM32F4xx_StdPeriph_Driver/src/stm32f4xx_tim.c
+ STM32F4xx_StdPeriph_Driver/src/stm32f4xx_dma2d.c
+ )
+
diff --git a/radio/src/targets/pl18/backlight_driver.cpp b/radio/src/targets/pl18/backlight_driver.cpp
new file mode 100644
index 00000000000..3ddd078c2c6
--- /dev/null
+++ b/radio/src/targets/pl18/backlight_driver.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) EdgeTX
+ *
+ * Based on code named
+ * opentx - https://github.com/opentx/opentx
+ * th9x - http://code.google.com/p/th9x
+ * er9x - http://code.google.com/p/er9x
+ * gruvin9x - http://code.google.com/p/gruvin9x
+ *
+ * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "opentx_types.h"
+#include "board.h"
+
+#include "globals.h"
+#include "lcd_driver.h"
+
+void backlightLowInit( void )
+{
+ RCC_AHB1PeriphClockCmd(BACKLIGHT_RCC_AHB1Periph, ENABLE);
+ GPIO_InitTypeDef GPIO_InitStructure;
+ GPIO_InitStructure.GPIO_Pin = BACKLIGHT_GPIO_PIN;
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
+ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
+ GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
+ GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
+ GPIO_Init(BACKLIGHT_GPIO, &GPIO_InitStructure);
+ GPIO_WriteBit( BACKLIGHT_GPIO, BACKLIGHT_GPIO_PIN, Bit_RESET );
+}
+
+void backlightInit()
+{
+ // PIN init
+ GPIO_InitTypeDef GPIO_InitStructure;
+ GPIO_InitStructure.GPIO_Pin = BACKLIGHT_GPIO_PIN;
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
+ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
+ GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
+ GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
+ GPIO_Init(BACKLIGHT_GPIO, &GPIO_InitStructure);
+ GPIO_PinAFConfig(BACKLIGHT_GPIO, BACKLIGHT_GPIO_PinSource, BACKLIGHT_GPIO_AF);
+
+ // TODO review this when the timer will be chosen
+ BACKLIGHT_TIMER->ARR = 100;
+ BACKLIGHT_TIMER->PSC = BACKLIGHT_TIMER_FREQ / 1000000 - 1; // 10kHz (same as FrOS)
+ BACKLIGHT_TIMER->CCMR1 = TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1PE; // PWM mode 1
+ BACKLIGHT_TIMER->CCER = TIM_CCER_CC1E | TIM_CCER_CC1NE;
+ BACKLIGHT_TIMER->CCR1 = 100; // 100% on init
+ BACKLIGHT_TIMER->EGR = TIM_EGR_UG;
+ BACKLIGHT_TIMER->CR1 |= TIM_CR1_CEN; // Counter enable
+ BACKLIGHT_TIMER->BDTR |= TIM_BDTR_MOE;
+}
+
+uint8_t lastDutyCycle = 0;
+
+void backlightEnable(uint8_t dutyCycle)
+{
+ BACKLIGHT_TIMER->CCR1 = 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/pl18/battery_driver.cpp b/radio/src/targets/pl18/battery_driver.cpp
new file mode 100644
index 00000000000..b12a1ea7ff2
--- /dev/null
+++ b/radio/src/targets/pl18/battery_driver.cpp
@@ -0,0 +1,436 @@
+/*
+ * Copyright (C) EdgeTX
+ *
+ * Based on code named
+ * opentx - https://github.com/opentx/opentx
+ * th9x - http://code.google.com/p/th9x
+ * er9x - http://code.google.com/p/er9x
+ * gruvin9x - http://code.google.com/p/gruvin9x
+ *
+ * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "opentx.h"
+#include "battery_driver.h"
+
+#define __BATTERY_DRIVER_C__
+
+#define BATTERY_W 140
+#define BATTERY_H 200
+#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
+#define WCHARGER_SAMPLING_CNT 30
+#define WCHARGER_CHARGING_SAMPLING_CNT 10
+#define WCHARGER_LOW_CURRENT_DELAY_CNT 6000
+#define WCHARGER_HIGH_CURRENT_DELAY_CNT 24000
+
+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
+#if defined(WIRELESS_CHARGER)
+STRUCT_BATTERY_CHARGER wCharger; // Wireless charger
+uint16_t wirelessLowCurrentDelay = 0;
+uint16_t wirelessHighCurrentDelay = 0;
+#endif
+
+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();
+ }
+ }
+
+#if defined(WIRELESS_CHARGER)
+ chargerDetection(&wCharger, IS_WCHARGER_ACTIVE(), WCHARGER_SAMPLING_CNT);
+ if (wCharger.isChargerDetectionReady)
+ {
+ if (wCharger.hasCharger) // Wireless charger can only be detected when USB charger is disabled
+ {
+ chargeEndDetection(&wCharger, IS_WCHARGER_CHARGE_END_ACTIVE(), WCHARGER_CHARGING_SAMPLING_CNT);
+ if (wCharger.isChargingDetectionReady)
+ {
+ if (wCharger.isChargeEnd)
+ {
+ state = CHARGE_FINISHED;
+ }
+ else
+ {
+ state = CHARGE_STARTED;
+ }
+ }
+
+ // Charge current control
+ wirelessLowCurrentDelay = 0;
+ if (wirelessHighCurrentDelay >= WCHARGER_HIGH_CURRENT_DELAY_CNT)
+ {
+ wCharger.isHighCurrent = true;
+ WCHARGER_CURRENT_HIGH();
+ }
+ else
+ {
+ wirelessHighCurrentDelay++;
+ }
+ }
+ else
+ {
+ resetChargeEndDetection(&wCharger);
+
+ // Charge current control
+ wirelessHighCurrentDelay = 0;
+ if (wirelessLowCurrentDelay >= WCHARGER_LOW_CURRENT_DELAY_CNT)
+ {
+ wCharger.isHighCurrent = false;
+ WCHARGER_CURRENT_LOW();
+ }
+ else
+ {
+ wirelessLowCurrentDelay++;
+ }
+ }
+ }
+
+#endif
+
+ return state;
+}
+
+bool isChargerActive()
+{
+#if defined(WIRELESS_CHARGER)
+ while (!(uCharger.isChargerDetectionReady && wCharger.isChargerDetectionReady))
+ {
+ get_battery_charge_state();
+ delay_ms(10);
+ }
+ return uCharger.hasCharger || wCharger.hasCharger;
+#else
+ while (!uCharger.isChargerDetectionReady)
+ {
+ get_battery_charge_state();
+ delay_ms(10);
+ }
+ return uCharger.hasCharger;
+#endif
+}
+
+void battery_charge_init()
+{
+ GPIO_InitTypeDef GPIO_InitStructure;
+
+ // Input pins
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
+ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
+ GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
+ GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
+
+ // USB charger status pins
+ GPIO_InitStructure.GPIO_Pin = UCHARGER_GPIO_PIN;
+ GPIO_Init(UCHARGER_GPIO, &GPIO_InitStructure);
+ GPIO_InitStructure.GPIO_Pin = UCHARGER_CHARGE_END_GPIO_PIN;
+ GPIO_Init(UCHARGER_CHARGE_END_GPIO, &GPIO_InitStructure);
+
+#if defined(WIRELESS_CHARGER)
+ // Wireless charger status pins
+ GPIO_InitStructure.GPIO_Pin = WCHARGER_GPIO_PIN;
+ GPIO_Init(WCHARGER_GPIO, &GPIO_InitStructure);
+ GPIO_InitStructure.GPIO_Pin = WCHARGER_CHARGE_END_GPIO_PIN;
+ GPIO_Init(WCHARGER_CHARGE_END_GPIO, &GPIO_InitStructure);
+#endif
+
+ // Output pins
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
+
+ // USB charger control pins
+ GPIO_InitStructure.GPIO_Pin = UCHARGER_EN_GPIO_PIN;
+ GPIO_Init(UCHARGER_EN_GPIO, &GPIO_InitStructure);
+
+ // USB charger state init
+ ENABLE_UCHARGER();
+ uCharger.hasCharger = !IS_UCHARGER_ACTIVE(); // Init for sampling count works
+ uCharger.isChargerDetectionReady = false;
+ resetChargeEndDetection(&uCharger);
+
+#if defined(WIRELESS_CHARGER)
+ // Wireless charger control pins
+ GPIO_InitStructure.GPIO_Pin = WCHARGER_EN_GPIO_PIN;
+ GPIO_Init(WCHARGER_EN_GPIO, &GPIO_InitStructure);
+ GPIO_InitStructure.GPIO_Pin = WCHARGER_I_CONTROL_GPIO_PIN;
+ GPIO_Init(WCHARGER_I_CONTROL_GPIO, &GPIO_InitStructure);
+
+ // Wireless charger state init
+ ENABLE_WCHARGER();
+ WCHARGER_CURRENT_LOW();
+ wCharger.hasCharger = !IS_WCHARGER_ACTIVE(); // Init for sampling count works
+ wCharger.isChargerDetectionReady = false;
+ resetChargeEndDetection(&wCharger);
+
+#endif
+}
+
+void drawChargingInfo(uint16_t chargeState) {
+ static int progress = 0;
+ const char* text = chargeState == CHARGE_STARTED ? STR_BATTERYCHARGING : STR_BATTERYFULL;
+ int h = 0;
+ LcdFlags color = 0;
+ if (CHARGE_STARTED == chargeState)
+ {
+ if (progress >= 100)
+ {
+ progress = 0;
+ }
+ else
+ {
+ progress += 25;
+ }
+ text = STR_BATTERYCHARGING;
+ h = ((BATTERY_H_INNER * progress) / 100);
+ color = COLOR_THEME_EDIT;
+ }
+ else if (CHARGE_FINISHED == chargeState)
+ {
+ text = STR_BATTERYFULL;
+ h = BATTERY_H_INNER;
+ color = COLOR_THEME_EDIT;
+ }
+ else
+ {
+ text = STR_BATTERYNONE;
+ h = BATTERY_H_INNER;
+ color = COLOR_THEME_PRIMARY1;
+ }
+
+ BACKLIGHT_ENABLE();
+ lcd->drawSizedText(LCD_W / 2, LCD_H - 50, text, strlen(text), CENTERED | COLOR_THEME_PRIMARY2);
+
+ lcd->drawFilledRect((LCD_W - BATTERY_W) / 2, BATTERY_TOP, BATTERY_W, BATTERY_H, SOLID, COLOR_THEME_PRIMARY2);
+ lcd->drawFilledRect((LCD_W - BATTERY_W_INNER) / 2, BATTERY_TOP_INNER, BATTERY_W_INNER, BATTERY_H_INNER, SOLID, COLOR_THEME_PRIMARY1);
+
+ lcd->drawFilledRect((LCD_W - BATTERY_W_INNER) / 2, BATTERY_TOP_INNER + BATTERY_H_INNER - h, BATTERY_W_INNER, h, SOLID, color);
+ lcd->drawFilledRect((LCD_W - BATTERY_CONNECTOR_W) / 2, BATTERY_TOP - BATTERY_CONNECTOR_H, BATTERY_CONNECTOR_W, BATTERY_CONNECTOR_H, SOLID, COLOR_THEME_PRIMARY2);
+}
+#define CHARGE_INFO_DURATION 500
+
+//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 = get_tmr10ms();
+ 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(now > info_until) {
+ info_until = 0;
+ lcd->clear();
+ BACKLIGHT_DISABLE();
+ if(lcdInited) {
+ lcdOff();
+ }
+ return;
+ }
+
+
+ if (updateTime == 0 || ((get_tmr10ms() - updateTime) >= 50))
+ {
+ if (!lcdInited) {
+ backlightInit();
+ lcdInit();
+ lcdInitDisplayDriver();
+ lcdInited = true;
+ }
+ else {
+ lcdOn();
+ }
+ updateTime = get_tmr10ms();
+ lcdInitDirectDrawing();
+ lcd->clear();
+ drawChargingInfo(chargeState);
+
+ // DEBUG INFO
+#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,%d,%d,%d,%d", wCharger.isChargerDetectionReady, wCharger.hasCharger, IS_WCHARGER_ACTIVE(), wCharger.chargerSamplingCount, wCharger.isHighCurrent);
+ lcd->drawSizedText(100, 70, buffer, strlen(buffer), CENTERED | COLOR_THEME_PRIMARY2);
+
+ sprintf(buffer, "%d,%d,%d,%d,%d,", wCharger.isChargingDetectionReady, wCharger.isChargeEnd, IS_WCHARGER_CHARGE_END_ACTIVE(), wCharger.chargingSamplingCount, wCharger.chargeEndSamplingCount);
+ lcd->drawSizedText(100, 100, buffer, strlen(buffer), CENTERED | COLOR_THEME_PRIMARY2);
+
+ sprintf(buffer, "%d", isChargerActive());
+ lcd->drawSizedText(100, 130, buffer, strlen(buffer), CENTERED | COLOR_THEME_PRIMARY2);
+#endif
+
+ lcdRefresh();
+ }
+#endif
+}
+
diff --git a/radio/src/targets/pl18/battery_driver.h b/radio/src/targets/pl18/battery_driver.h
new file mode 100644
index 00000000000..6fdd651d51f
--- /dev/null
+++ b/radio/src/targets/pl18/battery_driver.h
@@ -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.
+ */
+
+/***************************************************************************************************
+
+***************************************************************************************************/
+#ifndef __BATTERY_DRIVER_H__
+ #define __BATTERY_DRIVER_H__
+/***************************************************************************************************
+
+***************************************************************************************************/
+
+#include "board.h"
+#include "hal.h"
+
+enum ChargeState
+{
+ CHARGE_UNKNOWN,
+ CHARGE_NONE,
+ CHARGE_STARTED,
+ CHARGE_FINISHED
+};
+
+#define IS_UCHARGER_ACTIVE() GPIO_ReadInputDataBit(UCHARGER_GPIO, UCHARGER_GPIO_PIN)
+#define IS_UCHARGER_CHARGE_END_ACTIVE() GPIO_ReadInputDataBit(UCHARGER_CHARGE_END_GPIO, UCHARGER_CHARGE_END_GPIO_PIN)
+#define ENABLE_UCHARGER() GPIO_SetBits(UCHARGER_EN_GPIO, UCHARGER_EN_GPIO_PIN)
+#define DISABLE_UCHARGER() GPIO_ResetBits(UCHARGER_EN_GPIO, UCHARGER_EN_GPIO_PIN)
+
+#define IS_WCHARGER_ACTIVE() GPIO_ReadInputDataBit(WCHARGER_GPIO, WCHARGER_GPIO_PIN)
+#define IS_WCHARGER_CHARGE_END_ACTIVE() GPIO_ReadInputDataBit(WCHARGER_CHARGE_END_GPIO, WCHARGER_CHARGE_END_GPIO_PIN)
+#define ENABLE_WCHARGER() GPIO_SetBits(WCHARGER_EN_GPIO, WCHARGER_EN_GPIO_PIN)
+#define DISABLE_WCHARGER() GPIO_ResetBits(WCHARGER_EN_GPIO, WCHARGER_EN_GPIO_PIN)
+#define WCHARGER_CURRENT_LOW() GPIO_ResetBits(WCHARGER_I_CONTROL_GPIO, WCHARGER_I_CONTROL_GPIO_PIN)
+#define WCHARGER_CURRENT_HIGH() GPIO_SetBits(WCHARGER_I_CONTROL_GPIO, WCHARGER_I_CONTROL_GPIO_PIN)
+
+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();
+
+#endif
diff --git a/radio/src/targets/pl18/board.cpp b/radio/src/targets/pl18/board.cpp
new file mode 100644
index 00000000000..7c4cd43166b
--- /dev/null
+++ b/radio/src/targets/pl18/board.cpp
@@ -0,0 +1,261 @@
+/*
+ * 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_ws2812.h"
+#include "boards/generic_stm32/rgb_leds.h"
+
+#include "board.h"
+#include "boards/generic_stm32/module_ports.h"
+
+#include "hal/adc_driver.h"
+#include "hal/trainer_driver.h"
+#include "hal/switch_driver.h"
+#include "hal/abnormal_reboot.h"
+#include "hal/watchdog_driver.h"
+
+#include "globals.h"
+#include "sdcard.h"
+#include "touch.h"
+#include "debug.h"
+
+#include "flysky_gimbal_driver.h"
+#include "timers_driver.h"
+
+#include "battery_driver.h"
+#include "touch_driver.h"
+
+#include "bitmapbuffer.h"
+#include "colors.h"
+
+#include
+
+#if defined(__cplusplus) && !defined(SIMU)
+extern "C" {
+#endif
+#include "usb_dcd_int.h"
+#include "usb_bsp.h"
+#if defined(__cplusplus) && !defined(SIMU)
+}
+#endif
+
+// 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
+
+void delay_self(int count)
+{
+ for (int i = 50000; i > 0; i--)
+ {
+ for (; count > 0; count--);
+ }
+}
+#define RCC_AHB1PeriphMinimum (PWR_RCC_AHB1Periph |\
+ LCD_RCC_AHB1Periph |\
+ BACKLIGHT_RCC_AHB1Periph |\
+ SDRAM_RCC_AHB1Periph \
+ )
+#define RCC_AHB1PeriphOther (AUDIO_RCC_AHB1Periph |\
+ TELEMETRY_RCC_AHB1Periph |\
+ TRAINER_RCC_AHB1Periph |\
+ HAPTIC_RCC_AHB1Periph |\
+ EXTMODULE_RCC_AHB1Periph \
+ )
+#define RCC_AHB3PeriphMinimum (SDRAM_RCC_AHB3Periph)
+#define RCC_APB1PeriphMinimum (BACKLIGHT_RCC_APB1Periph)
+#define RCC_APB1PeriphOther (TELEMETRY_RCC_APB1Periph |\
+ AUDIO_RCC_APB1Periph \
+ )
+#define RCC_APB2PeriphMinimum (LCD_RCC_APB2Periph)
+#define RCC_APB2PeriphOther (HAPTIC_RCC_APB2Periph)
+
+void boardInit()
+{
+#if defined(SEMIHOSTING)
+ initialise_monitor_handles();
+#endif
+
+#if !defined(SIMU)
+ RCC_AHB1PeriphClockCmd(RCC_AHB1PeriphMinimum | RCC_AHB1PeriphOther, ENABLE);
+ RCC_AHB3PeriphClockCmd(RCC_AHB3PeriphMinimum, ENABLE);
+ RCC_APB1PeriphClockCmd(RCC_APB1PeriphMinimum | RCC_APB1PeriphOther, ENABLE);
+ RCC_APB2PeriphClockCmd(RCC_APB2PeriphMinimum | RCC_APB2PeriphOther, ENABLE);
+
+ // enable interrupts
+ __enable_irq();
+#endif
+
+#if defined(DEBUG)
+ serialSetMode(SP_AUX1, UART_MODE_DEBUG); // indicate AUX1 is used
+ serialInit(SP_AUX1, UART_MODE_DEBUG); // early AUX1 init
+#endif
+
+ TRACE("\nPL18 board started :)");
+ delay_ms(10);
+ TRACE("RCC->CSR = %08x", RCC->CSR);
+
+ pwrInit();
+ boardInitModulePorts();
+
+ init_trainer();
+ battery_charge_init();
+ flysky_gimbal_init();
+ timersInit();
+ touchPanelInit();
+ usbInit();
+
+ extern const stm32_pulse_timer_t _led_timer;
+
+ ws2812_init(&_led_timer, LED_STRIP_LENGTH);
+ for (uint8_t i = 0; i < LED_STRIP_LENGTH; i++) {
+ ws2812_set_color(i, 0, 0, 0);
+ }
+ ws2812_update(&_led_timer);
+
+ uint32_t press_start = 0;
+ uint32_t press_end = 0;
+
+ if (UNEXPECTED_SHUTDOWN()) {
+ pwrOn();
+ } else if (isChargerActive()) {
+ while (true) {
+ pwrOn();
+ uint32_t now = get_tmr10ms();
+ 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;
+ if (touchPanelEventOccured()) {
+ touchPanelRead();
+ press_end_touch = get_tmr10ms();
+ }
+ press_start = 0;
+ handle_battery_charge(press_end_touch);
+ delay_ms(10);
+ press_end = 0;
+ }
+ }
+ }
+
+ keysInit();
+ switchInit();
+ audioInit();
+ adcInit(&_adc_driver);
+ hapticInit();
+
+
+ #if defined(RTCLOCK)
+ rtcInit(); // RTC must be initialized before rambackupRestore() is called
+#endif
+
+ lcdSetInitalFrameBuffer(lcdFront->getData());
+
+#if defined(DEBUG)
+ DBGMCU_APB1PeriphConfig(
+ DBGMCU_IWDG_STOP | DBGMCU_TIM1_STOP | DBGMCU_TIM2_STOP |
+ DBGMCU_TIM3_STOP | DBGMCU_TIM4_STOP | DBGMCU_TIM5_STOP |
+ DBGMCU_TIM6_STOP | DBGMCU_TIM7_STOP | DBGMCU_TIM8_STOP |
+ DBGMCU_TIM9_STOP | DBGMCU_TIM10_STOP | DBGMCU_TIM11_STOP |
+ DBGMCU_TIM12_STOP | DBGMCU_TIM13_STOP | DBGMCU_TIM14_STOP,
+ ENABLE);
+#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)
+ if (isChargerActive())
+ {
+ delay_ms(100); // Add a delay to wait for lcdOff
+// 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_CR_MRUDS) && defined(PWR_CR_LPUDS) && defined(PWR_CR_FPDS)
+ MODIFY_REG(PWR->CR, (PWR_CR_PDDS | PWR_CR_LPDS | PWR_CR_FPDS | PWR_CR_LPUDS | PWR_CR_MRUDS), PDMode);
+#elif defined(PWR_CR_MRLVDS) && defined(PWR_CR_LPLVDS) && defined(PWR_CR_FPDS)
+ MODIFY_REG(PWR->CR, (PWR_CR_PDDS | PWR_CR_LPDS | PWR_CR_FPDS | PWR_CR_LPLVDS | PWR_CR_MRLVDS), PDMode);
+#else
+ MODIFY_REG(PWR->CR, (PWR_CR_PDDS| PWR_CR_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 = GPIO_ReadInputDataBit(UCHARGER_GPIO, UCHARGER_GPIO_PIN);
+
+ if (state == lastState)
+ debouncedState = state;
+ else
+ lastState = state;
+
+ return debouncedState;
+}
diff --git a/radio/src/targets/pl18/board.h b/radio/src/targets/pl18/board.h
new file mode 100644
index 00000000000..631f0b82d2d
--- /dev/null
+++ b/radio/src/targets/pl18/board.h
@@ -0,0 +1,250 @@
+/*
+ * 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 "opentx_constants.h"
+
+#include "board_common.h"
+#include "hal.h"
+#include "hal/serial_port.h"
+#include "hal/watchdog_driver.h"
+
+#define FLASHSIZE 0x200000
+#define BOOTLOADER_SIZE 0x20000
+#define FIRMWARE_ADDRESS 0x08000000
+
+#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
+void SDRAM_Init();
+
+// Pulses driver
+#if !defined(SIMU)
+
+#define INTERNAL_MODULE_ON() GPIO_SetBits(INTMODULE_PWR_GPIO, INTMODULE_PWR_GPIO_PIN)
+#define INTERNAL_MODULE_OFF() GPIO_ResetBits(INTMODULE_PWR_GPIO, INTMODULE_PWR_GPIO_PIN)
+#define EXTERNAL_MODULE_ON() GPIO_SetBits(EXTMODULE_PWR_GPIO, EXTMODULE_PWR_GPIO_PIN)
+#define EXTERNAL_MODULE_OFF() GPIO_ResetBits(EXTMODULE_PWR_GPIO, EXTMODULE_PWR_GPIO_PIN)
+#define EXTERNAL_MODULE_PWR_OFF EXTERNAL_MODULE_OFF
+#define BLUETOOTH_MODULE_ON() GPIO_ResetBits(BT_EN_GPIO, BT_EN_GPIO_PIN)
+#define BLUETOOTH_MODULE_OFF() GPIO_SetBits(BT_EN_GPIO, BT_EN_GPIO_PIN)
+#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(NUM_FUNCTIONS_SWITCHES)
+#define NUM_FUNCTIONS_SWITCHES 0
+#endif
+
+#define NUM_TRIMS 8
+#define DEFAULT_STICK_DEADZONE 2
+
+#define BATTERY_WARN 37 // 3.7V
+#define BATTERY_MIN 35 // 3.4V
+#define BATTERY_MAX 43 // 4.3V
+#define BATTERY_DIVIDER 962
+
+#if defined(__cplusplus) && !defined(SIMU)
+extern "C" {
+#endif
+
+// Power driver
+#define SOFT_PWR_CTRL
+#define POWER_ON_DELAY 10 // 1s
+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(SIMU)
+void usbJoystickUpdate();
+#endif
+#if defined(RADIO_PL18EV)
+#define USB_NAME "FlySky PL18EV"
+#define USB_MANUFACTURER 'F', 'l', 'y', 'S', 'k', 'y', ' ', ' ' /* 8 bytes */
+#define USB_PRODUCT 'P', 'L', '1', '8', 'E', 'V', ' ', ' ' /* 8 Bytes */
+#else
+#define USB_NAME "FlySky PL18"
+#define USB_MANUFACTURER 'F', 'l', 'y', 'S', 'k', 'y', ' ', ' ' /* 8 bytes */
+#define USB_PRODUCT 'P', 'L', '1', '8', ' ', ' ', ' ', ' ' /* 8 Bytes */
+#endif
+
+#if defined(__cplusplus) && !defined(SIMU)
+}
+#endif
+
+// Audio driver
+void audioInit();
+void audioConsumeCurrentBuffer();
+void audioSpiWriteBuffer(const uint8_t * buffer, uint32_t size);
+void audioSpiSetSpeed(uint8_t speed);
+uint8_t audioHardReset();
+uint8_t audioSoftReset();
+void audioSendRiffHeader();
+void audioOn();
+void audioOff();
+bool isAudioReady();
+bool audioChipReset();
+
+#define SPI_SPEED_2 0
+#define SPI_SPEED_4 1
+#define SPI_SPEED_8 2
+#define SPI_SPEED_16 3
+#define SPI_SPEED_32 4
+#define SPI_SPEED_64 5
+#define SPI_SPEED_128 6
+#define SPI_SPEED_256 7
+
+#define audioDisableIrq() // interrupts must stay enabled on Horus
+#define audioEnableIrq() // interrupts must stay enabled on Horus
+#if defined(PCBNV14)
+#define setSampleRate(freq)
+#else
+void setSampleRate(uint32_t frequency);
+#endif
+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();
+
+#endif // _BOARD_H_
diff --git a/radio/src/targets/pl18/bootloader/boot_menu.cpp b/radio/src/targets/pl18/bootloader/boot_menu.cpp
new file mode 100644
index 00000000000..3acc373092c
--- /dev/null
+++ b/radio/src/targets/pl18/bootloader/boot_menu.cpp
@@ -0,0 +1,261 @@
+/*
+ * 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"
+#include "fw_version.h"
+#include "lcd.h"
+
+#include "translations.h"
+
+#include "../../common/arm/stm32/bootloader/boot.h"
+#include "../../common/arm/stm32/bootloader/bin_files.h"
+
+#include
+
+#define SELECTED_COLOR (INVERS | COLOR_THEME_SECONDARY1)
+#define DEFAULT_PADDING 28
+#define DOUBLE_PADDING 56
+#define MESSAGE_TOP (LCD_H - (2*DOUBLE_PADDING))
+
+const uint8_t __bmp_plug_usb[] {
+#include "bmp_plug_usb.lbm"
+};
+LZ4Bitmap BMP_PLUG_USB(BMP_ARGB4444, __bmp_plug_usb);
+
+const uint8_t __bmp_usb_plugged[] {
+#include "bmp_usb_plugged.lbm"
+};
+LZ4Bitmap BMP_USB_PLUGGED(BMP_ARGB4444, __bmp_usb_plugged);
+
+#define BL_GREEN COLOR2FLAGS(RGB(73, 219, 62))
+#define BL_RED COLOR2FLAGS(RGB(229, 32, 30))
+#define BL_BACKGROUND COLOR2FLAGS(BLACK)
+#define BL_FOREGROUND COLOR2FLAGS(WHITE)
+#define BL_SELECTED COLOR2FLAGS(RGB(11, 65, 244)) // deep blue
+
+extern BitmapBuffer * lcd;
+
+void bootloaderInitScreen()
+{
+ lcdInitDisplayDriver();
+ backlightInit();
+ backlightEnable(100);
+ setHatsAsKeys(true);
+}
+
+static void bootloaderDrawTitle(const char* text)
+{
+ lcd->drawText(LCD_W/2, DEFAULT_PADDING, text, CENTERED | BL_FOREGROUND);
+ lcd->drawSolidFilledRect(DEFAULT_PADDING, DOUBLE_PADDING, LCD_W - DOUBLE_PADDING, 2, BL_FOREGROUND);
+}
+
+static void bootloaderDrawFooter()
+{
+ lcd->drawSolidFilledRect(DEFAULT_PADDING, LCD_H - (DEFAULT_PADDING + 10), LCD_W - DOUBLE_PADDING, 2, BL_FOREGROUND);
+}
+
+static void bootloaderDrawBackground()
+{
+ lcd->clear(BL_BACKGROUND);
+}
+
+void bootloaderDrawScreen(BootloaderState st, int opt, const char* str)
+{
+ lcdInitDirectDrawing();
+ bootloaderDrawBackground();
+
+ int center = LCD_W/2;
+ if (st == ST_START) {
+
+ bootloaderDrawTitle(BOOTLOADER_TITLE);
+
+ lcd->drawText(102, 75, LV_SYMBOL_CHARGE, BL_FOREGROUND);
+ coord_t pos = lcd->drawText(124, 75, TR_BL_WRITE_FW, BL_FOREGROUND);
+ pos += 8;
+
+#if defined(SPI_FLASH)
+ lcd->drawText(102, 110, LV_SYMBOL_SD_CARD, BL_FOREGROUND);
+ pos = lcd->drawText(124, 110, TR_BL_ERASE_FLASH, BL_FOREGROUND);
+ pos += 8;
+
+ lcd->drawText(100, 145, LV_SYMBOL_NEW_LINE, BL_FOREGROUND);
+ lcd->drawText(124, 145, TR_BL_EXIT, BL_FOREGROUND);
+#else
+ lcd->drawText(100, 110, LV_SYMBOL_NEW_LINE, BL_FOREGROUND);
+ lcd->drawText(124, 110, TR_BL_EXIT, BL_FOREGROUND);
+#endif
+
+ pos -= 92;
+ lcd->drawSolidRect(92, 72 + (opt * 35), pos, 26, 2, BL_SELECTED);
+
+ lcd->drawBitmap(60, 214, (const BitmapBuffer*)&BMP_PLUG_USB);
+ lcd->drawText(195, 223, TR_BL_USB_PLUGIN, BL_FOREGROUND);
+ lcd->drawText(195, 248, TR_BL_USB_MASS_STORE, BL_FOREGROUND);
+
+ bootloaderDrawFooter();
+ lcd->drawText(center, LCD_H - DEFAULT_PADDING, getFirmwareVersion(), CENTERED | BL_FOREGROUND);
+ }
+#if defined(SPI_FLASH)
+ else if (st == ST_CLEAR_FLASH_CHECK) {
+
+ bootloaderDrawTitle(TR_BL_ERASE_INT_FLASH);
+
+ lcd->drawText(102, 75, LV_SYMBOL_SD_CARD, BL_FOREGROUND);
+ coord_t pos = lcd->drawText(124, 75, TR_BL_ERASE_FLASH, BL_FOREGROUND);
+ pos += 8;
+
+ lcd->drawText(100, 110, LV_SYMBOL_NEW_LINE, BL_FOREGROUND);
+ lcd->drawText(124, 110, TR_BL_EXIT, BL_FOREGROUND);
+
+ pos -= 92;
+ lcd->drawSolidRect(92, 72 + (opt * 35), pos, 26, 2, BL_SELECTED);
+
+ bootloaderDrawFooter();
+ lcd->drawText(DEFAULT_PADDING, LCD_H - DEFAULT_PADDING,
+ LV_SYMBOL_SD_CARD TR_BL_ERASE_KEY, BL_FOREGROUND);
+ lcd->drawText(305, LCD_H - DEFAULT_PADDING,
+ LV_SYMBOL_NEW_LINE TR_BL_EXIT_KEY, BL_FOREGROUND);
+ }
+ else if (st == ST_CLEAR_FLASH) {
+ bootloaderDrawTitle(TR_BL_ERASE_INT_FLASH);
+
+ lcd->drawText(center, 75, TR_BL_ERASE_FLASH_MSG, CENTERED | BL_FOREGROUND);
+ bootloaderDrawFooter();
+ }
+#endif
+
+ else if (st == ST_USB) {
+ lcd->drawBitmap(center - 26, 98, (const BitmapBuffer*)&BMP_USB_PLUGGED);
+ lcd->drawText(center, 168, TR_BL_USB_CONNECTED, CENTERED | BL_FOREGROUND);
+ } else if (st == ST_FILE_LIST || st == ST_DIR_CHECK ||
+ st == ST_FLASH_CHECK || st == ST_FLASHING ||
+ st == ST_FLASH_DONE) {
+
+ bootloaderDrawTitle(LV_SYMBOL_SD_CARD " /FIRMWARE");
+
+ if (st == ST_FLASHING || st == ST_FLASH_DONE) {
+ LcdFlags color = BL_RED; // red
+
+ if (st == ST_FLASH_DONE) {
+ color = BL_GREEN /* green */;
+ opt = 100; // Completed > 100%
+ }
+
+ lcd->drawRect(DEFAULT_PADDING, 120, LCD_W - DOUBLE_PADDING, 31, 2,
+ SOLID, BL_SELECTED);
+ lcd->drawSolidFilledRect(DEFAULT_PADDING + 4, 124,
+ ((LCD_W - DOUBLE_PADDING - 8) * opt) / 100, 23,
+ color);
+ } else if (st == ST_DIR_CHECK) {
+ if (opt == FR_NO_PATH) {
+ lcd->drawText(20, MESSAGE_TOP,
+ LV_SYMBOL_CLOSE TR_BL_DIR_MISSING, BL_FOREGROUND);
+ } else {
+ lcd->drawText(20, MESSAGE_TOP, LV_SYMBOL_CLOSE TR_BL_DIR_EMPTY,
+ BL_FOREGROUND);
+ }
+ } else if (st == ST_FLASH_CHECK) {
+ bootloaderDrawFilename(str, 0, true);
+
+ if (opt == FC_ERROR) {
+ lcd->drawText(20, MESSAGE_TOP,
+ LV_SYMBOL_CLOSE " " TR_BL_INVALID_FIRMWARE,
+ BL_FOREGROUND);
+ } else if (opt == FC_OK) {
+ VersionTag tag;
+ memset(&tag, 0, sizeof(tag));
+ extractFirmwareVersion(&tag);
+
+ lcd->drawText(LCD_W / 4 + DEFAULT_PADDING,
+ MESSAGE_TOP - DEFAULT_PADDING,
+ TR_BL_FORK, RIGHT | BL_FOREGROUND);
+ lcd->drawSizedText(LCD_W / 4 + 6 + DEFAULT_PADDING,
+ MESSAGE_TOP - DEFAULT_PADDING, tag.fork, 6,
+ BL_FOREGROUND);
+
+ lcd->drawText(LCD_W / 4 + DEFAULT_PADDING, MESSAGE_TOP,
+ TR_BL_VERSION, RIGHT | BL_FOREGROUND);
+ lcd->drawText(LCD_W / 4 + 6 + DEFAULT_PADDING, MESSAGE_TOP,
+ tag.version, BL_FOREGROUND);
+
+ lcd->drawText(LCD_W / 4 + DEFAULT_PADDING,
+ MESSAGE_TOP + DEFAULT_PADDING,
+ TR_BL_RADIO, RIGHT | BL_FOREGROUND);
+ lcd->drawText(LCD_W / 4 + 6 + DEFAULT_PADDING,
+ MESSAGE_TOP + DEFAULT_PADDING, tag.flavour,
+ BL_FOREGROUND);
+
+ lcd->drawText(DOUBLE_PADDING, MESSAGE_TOP, LV_SYMBOL_OK, BL_GREEN);
+ }
+ }
+
+ bootloaderDrawFooter();
+
+ if (st != ST_DIR_CHECK && (st != ST_FLASH_CHECK || opt == FC_OK)) {
+
+ if (st == ST_FILE_LIST) {
+ lcd->drawText(DEFAULT_PADDING, LCD_H - DEFAULT_PADDING,
+ LV_SYMBOL_CHARGE TR_BL_SELECT_KEY, BL_FOREGROUND);
+ } else if (st == ST_FLASH_CHECK && opt == FC_OK) {
+ lcd->drawText(DEFAULT_PADDING, LCD_H - DEFAULT_PADDING,
+ LV_SYMBOL_CHARGE TR_BL_FLASH_KEY, BL_FOREGROUND);
+ } else if (st == ST_FLASHING) {
+ lcd->drawText(DEFAULT_PADDING, LCD_H - DEFAULT_PADDING,
+ LV_SYMBOL_CHARGE TR_BL_WRITING_FW, BL_FOREGROUND);
+ } else if (st == ST_FLASH_DONE) {
+ lcd->drawText(DEFAULT_PADDING, LCD_H - DEFAULT_PADDING,
+ LV_SYMBOL_CHARGE TR_BL_WRITING_COMPL, BL_FOREGROUND);
+ }
+ }
+
+ if (st != ST_FLASHING) {
+ lcd->drawText(305, LCD_H - DEFAULT_PADDING,
+ LV_SYMBOL_NEW_LINE TR_BL_EXIT_KEY, BL_FOREGROUND);
+ }
+ }
+}
+
+void bootloaderDrawFilename(const char* str, uint8_t line, bool selected)
+{
+ lcd->drawText(DEFAULT_PADDING, 75 + (line * 25), LV_SYMBOL_FILE, BL_FOREGROUND);
+ lcd->drawText(DEFAULT_PADDING + 30, 75 + (line * 25), str, BL_FOREGROUND);
+
+ if (selected) {
+ lcd->drawSolidRect(DEFAULT_PADDING + 25, 72 + (line * 25),
+ LCD_W - (DEFAULT_PADDING + 25) - 28, 26, 2, BL_SELECTED);
+ }
+}
+uint32_t bootloaderGetMenuItemCount(int baseCount)
+{
+ return baseCount;
+}
+
+bool bootloaderRadioMenu(uint32_t menuItem, event_t event)
+{
+ return true;
+}
+
+void blExit(void)
+{
+ lcdClear();
+ lcdRefresh();
+ lcdRefreshWait();
+}
diff --git a/radio/src/targets/pl18/extmodule_helper.cpp b/radio/src/targets/pl18/extmodule_helper.cpp
new file mode 100644
index 00000000000..dbb02e90be2
--- /dev/null
+++ b/radio/src/targets/pl18/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/pl18/hal.h b/radio/src/targets/pl18/hal.h
new file mode 100644
index 00000000000..ce3f32c9623
--- /dev/null
+++ b/radio/src/targets/pl18/hal.h
@@ -0,0 +1,719 @@
+/*
+ * 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 168000000
+
+// HSI is at 168Mhz (over-drive is not enabled!)
+#define PERI1_FREQUENCY 42000000
+#define PERI2_FREQUENCY 84000000
+#define TIMER_MULT_APB1 2
+#define TIMER_MULT_APB2 2
+
+/* Timers Allocation:
+ * TIM1 = Haptic
+ * TIM4 = Trainer
+ * TIM6 = Audio
+ * TIM7 = 2 MHz counter
+ *
+ *
+ * TIM14 = 5 ms counter
+ */
+
+/* DMA Allocation:
+ DMA/Stream/Channel
+ 1/5/7 DAC/Audio
+ 2/4/0 ADC1
+ 2/0/2 ADC3
+ 2/3/4 SDIO
+*/
+
+// Keys
+// PL18/PL18EV only has virtual keys via trim buttons
+// #define KEYS_GPIO_PIN_PGUP /* for activating PGUP in keys diagnose screen */
+
+// Trims
+#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
+
+#define TRIMS_GPIO_REG_LSD
+#define TRIMS_GPIO_PIN_LSD
+
+#define TRIMS_GPIO_REG_LSU
+#define TRIMS_GPIO_PIN_LSU
+
+#define TRIMS_GPIO_REG_RSD
+#define TRIMS_GPIO_PIN_RSD
+
+#define TRIMS_GPIO_REG_RSU
+#define TRIMS_GPIO_PIN_RSU
+
+#define TRIMS_GPIO_REG_T7L
+#define TRIMS_GPIO_PIN_T7L
+
+#define TRIMS_GPIO_REG_T7R
+#define TRIMS_GPIO_PIN_T7R
+
+#define TRIMS_GPIO_REG_T8D
+#define TRIMS_GPIO_PIN_T8D
+
+#define TRIMS_GPIO_REG_T8U
+#define TRIMS_GPIO_PIN_T8U
+
+#define TRIMS_GPIO_REG_TR1U GPIOH->IDR
+#define TRIMS_GPIO_PIN_TR1U LL_GPIO_PIN_8 // PH.08
+#define TRIMS_GPIO_REG_TR1D GPIOH->IDR
+#define TRIMS_GPIO_PIN_TR1D LL_GPIO_PIN_9 // PH.09
+#define TRIMS_GPIO_REG_TR2U GPIOH->IDR
+#define TRIMS_GPIO_PIN_TR2U LL_GPIO_PIN_10 // PH.10
+#define TRIMS_GPIO_REG_TR2D GPIOH->IDR
+#define TRIMS_GPIO_PIN_TR2D LL_GPIO_PIN_11 // PH.11
+
+// active 4x4 column/row based key-matrix to support up to 16 buttons with only 8 GPIOs
+#define TRIMS_GPIO_OUT1 GPIOG
+#define TRIMS_GPIO_OUT1_PIN LL_GPIO_PIN_2 // PG.02
+#define TRIMS_GPIO_OUT2 GPIOG
+#define TRIMS_GPIO_OUT2_PIN LL_GPIO_PIN_10 // PG.10
+#define TRIMS_GPIO_OUT3 GPIOG
+#define TRIMS_GPIO_OUT3_PIN LL_GPIO_PIN_11 // PG.11
+// OUT4 routed on MCU PCB, but not attached to any physical buttons, free to use for extensions
+#define TRIMS_GPIO_OUT4 GPIOH
+#define TRIMS_GPIO_OUT4_PIN LL_GPIO_PIN_7 // PH.07
+
+#define TRIMS_GPIO_REG_IN1 GPIOB->IDR
+#define TRIMS_GPIO_PIN_IN1 LL_GPIO_PIN_15 // PB.15
+#define TRIMS_GPIO_REG_IN2 GPIOC->IDR
+#define TRIMS_GPIO_PIN_IN2 LL_GPIO_PIN_13 // PC.13
+#define TRIMS_GPIO_REG_IN3 GPIOD->IDR
+#define TRIMS_GPIO_PIN_IN3 LL_GPIO_PIN_7 // PD.07
+#define TRIMS_GPIO_REG_IN4 GPIOJ->IDR
+#define TRIMS_GPIO_PIN_IN4 LL_GPIO_PIN_12 // PJ.12
+
+// Index of all trims
+
+#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 (LL_GPIO_PIN_7)
+
+#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 | LL_GPIO_PIN_10 | LL_GPIO_PIN_11)
+
+#define KEYS_OUT_GPIOH_PINS (LL_GPIO_PIN_7)
+
+
+// Monitor pin
+// #define MONITOR_RCC_AHB1Periph (RCC_AHB1Periph_GPIOJ)
+// #define VBUS_MONITOR_GPIO (GPIOJ)
+// #define VBUS_MONITOR_PIN (LL_GPIO_PIN_14)
+
+// Switches:
+// Switches A and C on PL18/PL18EV are 2-position switches,
+// so there is no NEED to configure two pins for Switches A and C.
+//
+// Especially, as on current dev. state, using PC8 for SDIO D0.
+// (happy coincidence ;)
+//
+// #define SWITCHES_GPIO_REG_A_H GPIOC
+// #define SWITCHES_GPIO_PIN_A_H LL_GPIO_PIN_8 // PC.08
+// #define SWITCHES_GPIO_REG_A_L GPIOC
+// #define SWITCHES_GPIO_PIN_A_L LL_GPIO_PIN_9 // PC.09
+
+#define SWITCHES_GPIO_REG_A GPIOC
+#define SWITCHES_GPIO_PIN_A LL_GPIO_PIN_9 // PC.09
+
+// High rail of Switch C is not required and thus PC10 is free to use for
+// customizations.
+//
+// #define SWITCHES_GPIO_REG_C_H GPIOC
+// #define SWITCHES_GPIO_PIN_C_H LL_GPIO_PIN_10 // PC.10
+// #define SWITCHES_GPIO_REG_C_L GPIOC
+// #define SWITCHES_GPIO_PIN_C_L LL_GPIO_PIN_11 // PC.11
+
+#define SWITCHES_GPIO_REG_C GPIOC
+#define SWITCHES_GPIO_PIN_C LL_GPIO_PIN_11 // PC.11
+
+// 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_POT1 LL_GPIO_PIN_6 // PA.06 VRA
+#define ADC_GPIO_PIN_POT2 LL_GPIO_PIN_4 // PC.04 VRB
+#define ADC_GPIO_PIN_POT3 LL_GPIO_PIN_8 // PF.08 VRC
+#define ADC_GPIO_PIN_SLIDER1 LL_GPIO_PIN_9 // PF.09 VRD/LS
+#define ADC_GPIO_PIN_SLIDER2 LL_GPIO_PIN_7 // PA.07 VRE/RS
+
+#if defined(RADIO_PL18EV)
+#define ADC_GPIO_PIN_EXT1 LL_GPIO_PIN_5 // PA.05
+#define ADC_GPIO_PIN_EXT2 LL_GPIO_PIN_2 // PA.02
+#define ADC_GPIO_PIN_EXT3 LL_GPIO_PIN_6 // PF.06
+#define ADC_GPIO_PIN_EXT4 LL_GPIO_PIN_3 // PA.03
+#endif
+
+#define ADC_GPIO_PIN_SWB LL_GPIO_PIN_1 // PC.01
+#define ADC_GPIO_PIN_SWD LL_GPIO_PIN_0 // PC.00
+#define ADC_GPIO_PIN_SWE LL_GPIO_PIN_2 // PC.02
+#define ADC_GPIO_PIN_SWF LL_GPIO_PIN_0 // PB.00
+#define ADC_GPIO_PIN_SWG LL_GPIO_PIN_1 // PB.01
+#define ADC_GPIO_PIN_SWH LL_GPIO_PIN_10 // PF.10
+
+#define ADC_GPIO_PIN_BATT LL_GPIO_PIN_5 // PC.05
+
+#define ADC_GPIOA_PINS (ADC_GPIO_PIN_POT1 | ADC_GPIO_PIN_SLIDER2 | \
+ ADC_GPIO_PIN_EXT1 | ADC_GPIO_PIN_EXT2 | ADC_GPIO_PIN_EXT4)
+#define ADC_GPIOB_PINS (ADC_GPIO_PIN_SWF | ADC_GPIO_PIN_SWG)
+#define ADC_GPIOC_PINS (ADC_GPIO_PIN_POT2 | ADC_GPIO_PIN_BATT | \
+ ADC_GPIO_PIN_SWB | ADC_GPIO_PIN_SWD | ADC_GPIO_PIN_SWE)
+#define ADC_GPIOF_PINS (ADC_GPIO_PIN_POT3 | ADC_GPIO_PIN_SLIDER1 | \
+ ADC_GPIO_PIN_EXT3 | ADC_GPIO_PIN_SWH)
+
+#define ADC_CHANNEL_STICK_LH
+#define ADC_CHANNEL_STICK_LV
+#define ADC_CHANNEL_STICK_RV
+#define ADC_CHANNEL_STICK_RH
+
+// Each ADC cannot map more than 8 channels, otherwise it will cause problems
+
+#define ADC_CHANNEL_POT1 LL_ADC_CHANNEL_6 // ADC12_IN6 -> ADC1_IN6
+#define ADC_CHANNEL_POT2 LL_ADC_CHANNEL_14 // ADC12_IN14 -> ADC1_IN14
+#define ADC_CHANNEL_POT3 LL_ADC_CHANNEL_6 // ADC3_IN6 -> ADC3_IN6
+#define ADC_CHANNEL_SLIDER1 LL_ADC_CHANNEL_7 // ADC3_IN7 -> ADC3_IN7
+#define ADC_CHANNEL_SLIDER2 LL_ADC_CHANNEL_7 // ADC12_IN7 -> ADC1_IN7
+
+#if defined(RADIO_PL18EV)
+// Left, right stick end pot on PL18EV
+#define ADC_CHANNEL_EXT1 LL_ADC_CHANNEL_5 // ADC12_IN5 -> ADC1_IN5
+#define ADC_CHANNEL_EXT2 LL_ADC_CHANNEL_2 // ADC123_IN2 -> ADC1_IN2
+
+// Left, right stick end buttons on PL18EV
+#define ADC_CHANNEL_EXT3 LL_ADC_CHANNEL_4 // ADC3_IN4 -> ADC3_IN4
+#define ADC_CHANNEL_EXT4 LL_ADC_CHANNEL_3 // ADC123_IN3 -> ADC3_IN3
+#endif
+
+// Analog switches
+#define ADC_CHANNEL_SWB LL_ADC_CHANNEL_11 // ADC123_IN11 -> ADC3_IN11
+#define ADC_CHANNEL_SWD LL_ADC_CHANNEL_10 // ADC123_IN10 -> ADC3_IN10
+#define ADC_CHANNEL_SWE LL_ADC_CHANNEL_12 // ADC123_IN12 -> ADC3_IN12
+#define ADC_CHANNEL_SWF LL_ADC_CHANNEL_8 // ADC12_IN8 -> ADC1_IN8
+#define ADC_CHANNEL_SWG LL_ADC_CHANNEL_9 // ADC12_IN9 -> ADC1_IN9
+#define ADC_CHANNEL_SWH LL_ADC_CHANNEL_8 // ADC3_IN8 -> ADC3_IN8
+
+#define ADC_CHANNEL_BATT LL_ADC_CHANNEL_15 // ADC12_IN15 -> ADC1_IN15
+
+#if !defined(RADIO_PL18EV)
+// Disabled for PL18EV because 2 ADC 16 channels are fully mapped already
+#define ADC_CHANNEL_RTC_BAT LL_ADC_CHANNEL_VBAT // ADC1_IN18
+#endif
+
+#define ADC_MAIN ADC1
+#define ADC_EXT ADC3
+
+#define ADC_EXT_CHANNELS \
+ { ADC_CHANNEL_POT3, ADC_CHANNEL_SLIDER1, ADC_CHANNEL_EXT3, ADC_CHANNEL_EXT4, \
+ ADC_CHANNEL_SWB, ADC_CHANNEL_SWD, ADC_CHANNEL_SWE, ADC_CHANNEL_SWH \
+ }
+
+#define ADC_SAMPTIME LL_ADC_SAMPLINGTIME_28CYCLES
+#define ADC_DMA DMA2
+#define ADC_DMA_CHANNEL LL_DMA_CHANNEL_0
+#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_EXT_DMA DMA2
+#define ADC_EXT_DMA_CHANNEL LL_DMA_CHANNEL_2
+#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_28CYCLES
+
+#define ADC_VREF_PREC2 660
+
+#if defined(RADIO_PL18EV)
+#define ADC_DIRECTION { \
+ 0,0,0,0, /* gimbals */ \
+ 0,0,0, /* pots */ \
+ -1,-1, /* sliders */ \
+ 0,0,0,0, /* ext1-4 */ \
+ 0, /* vbat */ \
+ -1, /* SWB */ \
+ -1, /* SWD */ \
+ 0, /* SWE */ \
+ 0, /* SWF */ \
+ 0, /* SWG */ \
+ 0 /* SWH */ \
+ }
+#else
+#define ADC_DIRECTION { \
+ 0,0,0,0, /* gimbals */ \
+ 0,0,0, /* pots */ \
+ -1,-1, /* sliders */ \
+ 0, /* vbat */ \
+ 0, /* rtc_bat */ \
+ -1, /* SWB */ \
+ -1, /* SWD */ \
+ 0, /* SWE */ \
+ 0, /* SWF */ \
+ 0, /* SWG */ \
+ 0 /* SWH */ \
+ }
+#endif
+
+// Power
+#define PWR_RCC_AHB1Periph RCC_AHB1Periph_GPIOI
+#define PWR_ON_GPIO GPIOI
+#define PWR_SWITCH_GPIO GPIOI
+#define PWR_SWITCH_GPIO_PIN GPIO_Pin_11 // PI.11
+#define PWR_ON_GPIO_PIN GPIO_Pin_14 // PI.14
+
+// Chargers (USB and wireless)
+#define CHARGER_RCC_AHB1Periph ( RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOG | RCC_AHB1Periph_GPIOH | RCC_AHB1Periph_GPIOI )
+
+#define UCHARGER_GPIO GPIOB
+#define UCHARGER_GPIO_PIN GPIO_Pin_14 // PB.14 input
+
+#define UCHARGER_CHARGE_END_GPIO GPIOB
+#define UCHARGER_CHARGE_END_GPIO_PIN GPIO_Pin_13 // PB.13 input
+
+#define UCHARGER_EN_GPIO GPIOG
+#define UCHARGER_EN_GPIO_PIN GPIO_Pin_3 // PG.03 output
+
+#if defined (WIRELESS_CHARGER)
+
+ #define WCHARGER_GPIO GPIOI
+ #define WCHARGER_GPIO_PIN GPIO_Pin_9 // PI.09 input
+
+ #define WCHARGER_CHARGE_END_GPIO GPIOI
+ #define WCHARGER_CHARGE_END_GPIO_PIN GPIO_Pin_10 // PI.10 input
+
+ #define WCHARGER_EN_GPIO GPIOH
+ #define WCHARGER_EN_GPIO_PIN GPIO_Pin_4 // PH.04 output
+
+ #define WCHARGER_I_CONTROL_GPIO GPIOH
+ #define WCHARGER_I_CONTROL_GPIO_PIN GPIO_Pin_13 // PH.13 output
+
+#endif
+
+// TODO! Check IOLL1 to PI.01 connectivity!
+
+// S.Port update connector
+#define SPORT_MAX_BAUDRATE 400000
+#define SPORT_UPDATE_RCC_AHB1Periph 0
+#define HAS_SPORT_UPDATE_CONNECTOR() (false)
+
+// Serial Port (DEBUG)
+// We will temporarily used the PPM and the HEARTBEAT PINS
+#define AUX_SERIAL_RCC_AHB1Periph (RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOE)
+#define AUX_SERIAL_RCC_APB1Periph 0
+#define AUX_SERIAL_RCC_APB2Periph RCC_APB2Periph_USART6
+#define AUX_SERIAL_GPIO GPIOC
+#define AUX_SERIAL_GPIO_PIN_TX GPIO_Pin_6 // PC.06
+#define AUX_SERIAL_GPIO_PIN_RX GPIO_Pin_7 // PC.07
+#define AUX_SERIAL_GPIO_PinSource_TX GPIO_PinSource6
+#define AUX_SERIAL_GPIO_PinSource_RX GPIO_PinSource7
+#define AUX_SERIAL_GPIO_AF GPIO_AF_USART6
+#define AUX_SERIAL_USART USART6
+#define AUX_SERIAL_USART_IRQHandler USART6_IRQHandler
+#define AUX_SERIAL_USART_IRQn USART6_IRQn
+#define AUX_SERIAL_TX_INVERT_GPIO GPIOE
+#define AUX_SERIAL_TX_INVERT_GPIO_PIN GPIO_Pin_3 // PE.03
+#define AUX_SERIAL_RX_INVERT_GPIO GPIOI
+#define AUX_SERIAL_RX_INVERT_GPIO_PIN GPIO_Pin_15 // PI.15
+
+//used in BOOTLOADER
+#define SERIAL_RCC_AHB1Periph 0
+#define SERIAL_RCC_APB1Periph 0
+#define AUX2_SERIAL_RCC_AHB1Periph 0
+#define AUX2_SERIAL_RCC_APB1Periph 0
+#define AUX2_SERIAL_RCC_APB2Periph 0
+#define KEYS_BACKLIGHT_RCC_AHB1Periph 0
+
+// Telemetry
+#define TELEMETRY_RCC_AHB1Periph (RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_GPIOJ | RCC_AHB1Periph_DMA1)
+#define TELEMETRY_RCC_APB1Periph RCC_APB1Periph_USART2
+#define TELEMETRY_REV_GPIO GPIOJ
+#define TELEMETRY_RX_REV_GPIO_PIN GPIO_Pin_8 // PJ.08
+#define TELEMETRY_TX_REV_GPIO_PIN GPIO_Pin_7 // PJ.07
+#define TELEMETRY_DIR_GPIO GPIOJ
+#define TELEMETRY_DIR_GPIO_PIN GPIO_Pin_13 // PJ.13
+#define TELEMETRY_SET_INPUT 1
+#define TELEMETRY_GPIO GPIOD
+#define TELEMETRY_TX_GPIO_PIN GPIO_Pin_5 // PD.05
+#define TELEMETRY_RX_GPIO_PIN GPIO_Pin_6 // PD.06
+#define TELEMETRY_GPIO_PinSource_TX GPIO_PinSource5
+#define TELEMETRY_GPIO_PinSource_RX GPIO_PinSource6
+#define TELEMETRY_GPIO_AF GPIO_AF_USART2
+#define TELEMETRY_USART USART2
+#define TELEMETRY_DMA DMA1
+#define TELEMETRY_DMA_Stream_TX LL_DMA_STREAM_6
+#define TELEMETRY_DMA_Channel_TX DMA_Channel_4
+#define TELEMETRY_DMA_TX_Stream_IRQ DMA1_Stream6_IRQn
+#define TELEMETRY_DMA_TX_IRQHandler DMA1_Stream6_IRQHandler
+#define TELEMETRY_DMA_TX_FLAG_TC DMA_IT_TCIF6
+// #define TELEMETRY_DMA_Stream_RX LL_DMA_STREAM_5
+// #define TELEMETRY_DMA_Channel_RX LL_DMA_CHANNEL_4
+#define TELEMETRY_USART_IRQHandler USART2_IRQHandler
+#define TELEMETRY_USART_IRQn USART2_IRQn
+
+#define TELEMETRY_DIR_OUTPUT() TELEMETRY_DIR_GPIO->BSRRH = TELEMETRY_DIR_GPIO_PIN
+#define TELEMETRY_DIR_INPUT() TELEMETRY_DIR_GPIO->BSRRL = TELEMETRY_DIR_GPIO_PIN
+#define TELEMETRY_TX_POL_NORM() TELEMETRY_REV_GPIO->BSRRH = TELEMETRY_TX_REV_GPIO_PIN
+#define TELEMETRY_TX_POL_INV() TELEMETRY_REV_GPIO->BSRRL = TELEMETRY_TX_REV_GPIO_PIN
+#define TELEMETRY_RX_POL_NORM() TELEMETRY_REV_GPIO->BSRRH = TELEMETRY_RX_REV_GPIO_PIN
+#define TELEMETRY_RX_POL_INV() TELEMETRY_REV_GPIO->BSRRL = TELEMETRY_RX_REV_GPIO_PIN
+
+// Software IRQ (Prio 5 -> FreeRTOS compatible)
+#define TELEMETRY_RX_FRAME_EXTI_LINE LL_EXTI_LINE_4
+#define USE_EXTI4_IRQ
+#define EXTI4_IRQ_Priority 5
+
+// USB
+#define USB_RCC_AHB1Periph_GPIO RCC_AHB1Periph_GPIOA
+#define USB_GPIO GPIOA
+// #define USB_GPIO_PIN_VBUS GPIO_Pin_9 // PA.09
+#define USB_GPIO_PIN_ID GPIO_Pin_10 // PA.10
+#define USB_GPIO_PIN_DM GPIO_Pin_11 // PA.11
+#define USB_GPIO_PIN_DP GPIO_Pin_12 // PA.12
+#define USB_GPIO_PinSource_DM GPIO_PinSource11
+#define USB_GPIO_PinSource_DP GPIO_PinSource12
+#define USB_GPIO_AF GPIO_AF_OTG1_FS
+
+// LCD
+#define LCD_RCC_AHB1Periph (RCC_AHB1Periph_GPIOE | RCC_AHB1Periph_GPIOG | RCC_AHB1Periph_GPIOI | RCC_AHB1Periph_GPIOJ | RCC_AHB1Periph_GPIOK | RCC_AHB1Periph_DMA2D)
+#define LCD_RCC_APB1Periph 0
+#define LCD_RCC_APB2Periph RCC_APB2Periph_LTDC
+#define LCD_NRST_GPIO GPIOG
+#define LCD_NRST_GPIO_PIN LL_GPIO_PIN_9 // PG.09
+#define LCD_SPI_GPIO GPIOE
+#define LCD_SPI_CS_GPIO_PIN LL_GPIO_PIN_4 // PE.04
+#define LCD_SPI_SCK_GPIO_PIN LL_GPIO_PIN_2 // PE.02
+#define LCD_SPI_MISO_GPIO_PIN LL_GPIO_PIN_5 // PE.05
+#define LCD_SPI_MOSI_GPIO_PIN LL_GPIO_PIN_6 // PE.06
+#define LTDC_IRQ_PRIO 4
+#define DMA_SCREEN_IRQ_PRIO 6
+
+// Backlight
+// TODO TIM3, TIM8, TIM14, review the channel in backlight_driver.cpp according to the chosen timer
+#define BACKLIGHT_RCC_AHB1Periph RCC_AHB1Periph_GPIOA
+#define BACKLIGHT_RCC_APB1Periph RCC_APB1Periph_TIM2
+#define BACKLIGHT_RCC_APB2Periph 0
+#define BACKLIGHT_GPIO GPIOA
+#define BACKLIGHT_GPIO_PIN GPIO_Pin_15
+#define BACKLIGHT_GPIO_PinSource GPIO_PinSource15
+#define BACKLIGHT_TIMER TIM2
+#define BACKLIGHT_GPIO_AF GPIO_AF_TIM2
+#define BACKLIGHT_TIMER_FREQ (PERI1_FREQUENCY * TIMER_MULT_APB1)
+
+//used in BOOTLOADER
+#define SERIAL_RCC_AHB1Periph 0
+#define SERIAL_RCC_APB1Periph 0
+#define ROTARY_ENCODER_RCC_APB1Periph 0
+
+// SPI NOR Flash
+#define FLASH_SPI SPI6
+#define FLASH_SPI_CS_GPIO GPIOG
+#define FLASH_SPI_CS_GPIO_PIN LL_GPIO_PIN_6 // PG.06
+#define FLASH_SPI_GPIO GPIOG
+#define FLASH_SPI_SCK_GPIO_PIN LL_GPIO_PIN_13 // PG.13
+#define FLASH_SPI_MISO_GPIO_PIN LL_GPIO_PIN_12 // PG.12
+#define FLASH_SPI_MOSI_GPIO_PIN LL_GPIO_PIN_14 // PG.14
+// #define FLASH_SPI_DMA DMA2
+// #define FLASH_SPI_DMA_CHANNEL LL_DMA_CHANNEL_1
+// #define FLASH_SPI_DMA_TX_STREAM LL_DMA_STREAM_5
+// #define FLASH_SPI_DMA_TX_IRQn DMA2_Stream5_IRQn
+// #define FLASH_SPI_DMA_TX_IRQHandler DMA2_Stream5_IRQHandler
+// #define FLASH_SPI_DMA_RX_STREAM LL_DMA_STREAM_6
+// #define FLASH_SPI_DMA_RX_IRQn DMA2_Stream6_IRQn
+// #define FLASH_SPI_DMA_RX_IRQHandler DMA2_Stream6_IRQHandler
+#define STORAGE_USE_SPI_FLASH
+
+// SDRAM
+#define SDRAM_RCC_AHB1Periph (RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_GPIOE | RCC_AHB1Periph_GPIOF | RCC_AHB1Periph_GPIOG | RCC_AHB1Periph_GPIOH)
+#define SDRAM_RCC_AHB3Periph RCC_AHB3Periph_FMC
+
+// Audio
+#define AUDIO_RCC_APB1Periph (RCC_APB1Periph_TIM6 | RCC_APB1Periph_DAC)
+#define AUDIO_RCC_AHB1Periph (RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_DMA1)
+#define AUDIO_OUTPUT_GPIO GPIOA
+#define AUDIO_OUTPUT_GPIO_PIN GPIO_Pin_4 // PA.04
+#define AUDIO_GPIO_PinSource GPIO_PinSource4
+#define AUDIO_DMA_Stream DMA1_Stream5
+#define AUDIO_DMA_Stream_IRQn DMA1_Stream5_IRQn
+#define AUDIO_TIM_IRQn TIM6_DAC_IRQn
+#define AUDIO_TIM_IRQHandler TIM6_DAC_IRQHandler
+#define AUDIO_DMA_Stream_IRQHandler DMA1_Stream5_IRQHandler
+#define AUDIO_TIMER TIM6
+#define AUDIO_DMA DMA1
+
+// I2C Bus
+#define I2C_B1 I2C1
+#define I2C_B1_GPIO GPIOB
+#define I2C_B1_SDA_GPIO_PIN LL_GPIO_PIN_7 // PB.07
+#define I2C_B1_SCL_GPIO_PIN LL_GPIO_PIN_8 // PB.08
+#define I2C_B1_GPIO_AF LL_GPIO_AF_4
+
+// Touch
+#define TOUCH_I2C_BUS I2C_Bus_1
+#define TOUCH_I2C_CLK_RATE 400000
+#define TOUCH_INT_GPIO GPIOB
+#define TOUCH_INT_GPIO_PIN LL_GPIO_PIN_9 // PB.09
+#define TOUCH_RST_GPIO GPIOB
+#define TOUCH_RST_GPIO_PIN LL_GPIO_PIN_12 // PB.12
+#define TOUCH_INT_EXTI_Line LL_EXTI_LINE_9
+#define TOUCH_INT_EXTI_Port LL_SYSCFG_EXTI_PORTB
+#define TOUCH_INT_EXTI_SysCfgLine LL_SYSCFG_EXTI_LINE9
+
+// TOUCH_INT_EXTI IRQ
+#if !defined(USE_EXTI9_5_IRQ)
+ #define USE_EXTI9_5_IRQ
+ #define EXTI9_5_IRQ_Priority 9
+#endif
+
+// Haptic: TIM1_CH1
+#define HAPTIC_PWM
+#define HAPTIC_RCC_AHB1Periph RCC_AHB1Periph_GPIOA
+#define HAPTIC_RCC_APB2Periph RCC_APB2ENR_TIM1EN
+#define HAPTIC_GPIO GPIOA
+#define HAPTIC_GPIO_PIN GPIO_Pin_8
+#define HAPTIC_GPIO_TIMER TIM1
+#define HAPTIC_GPIO_AF GPIO_AF_TIM1
+#define HAPTIC_GPIO_PinSource GPIO_PinSource8
+#define HAPTIC_TIMER_OUTPUT_ENABLE TIM_CCER_CC1E | TIM_CCER_CC1NE;
+#define HAPTIC_TIMER_MODE TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1PE
+#define HAPTIC_TIMER_COMPARE_VALUE HAPTIC_GPIO_TIMER->CCR1
+
+// Flysky Hall Stick
+#define FLYSKY_HALL_SERIAL_USART UART4
+#define FLYSKY_HALL_SERIAL_GPIO GPIOA
+#define FLYSKY_HALL_DMA_Channel LL_DMA_CHANNEL_4
+#define FLYSKY_HALL_SERIAL_TX_GPIO_PIN LL_GPIO_PIN_0 // PA.00
+#define FLYSKY_HALL_SERIAL_RX_GPIO_PIN LL_GPIO_PIN_1 // PA.01
+#define FLYSKY_HALL_SERIAL_GPIO_AF LL_GPIO_AF_8
+
+#define FLYSKY_HALL_RCC_AHB1Periph RCC_AHB1Periph_DMA1
+#define FLYSKY_HALL_RCC_APB1Periph RCC_APB1Periph_UART4
+
+#define FLYSKY_HALL_SERIAL_USART_IRQHandler UART4_IRQHandler
+#define FLYSKY_HALL_SERIAL_USART_IRQn UART4_IRQn
+#define FLYSKY_HALL_SERIAL_DMA DMA1
+#define FLYSKY_HALL_DMA_Stream_RX LL_DMA_STREAM_2
+#define FLYSKY_HALL_DMA_Stream_TX LL_DMA_STREAM_4
+
+// LED Strip
+#define LED_STRIP_LENGTH 4
+#define LED_STRIP_GPIO GPIOH
+#define LED_STRIP_GPIO_PIN_DATA LL_GPIO_PIN_12 // PH.12 / TIM5_CH3
+#define LED_STRIP_GPIO_PIN_AF LL_GPIO_AF_2 // TIM3/4/5
+#define LED_STRIP_TIMER TIM5
+#define LED_STRIP_TIMER_FREQ (PERI1_FREQUENCY * TIMER_MULT_APB1)
+#define LED_STRIP_TIMER_CHANNEL LL_TIM_CHANNEL_CH3
+#define LED_STRIP_TIMER_DMA DMA1
+#define LED_STRIP_TIMER_DMA_CHANNEL LL_DMA_CHANNEL_6
+#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 STATUS_LEDS
+
+
+// Internal Module
+#if defined(RADIO_PL18)
+#define INTMODULE_RCC_AHB1Periph (RCC_AHB1Periph_GPIOF | RCC_AHB1Periph_GPIOI | RCC_AHB1Periph_DMA1)
+#define INTMODULE_PWR_GPIO GPIOI
+#define INTMODULE_PWR_GPIO_PIN GPIO_Pin_0 // PI.00
+#define INTMODULE_GPIO GPIOF
+#define INTMODULE_TX_GPIO_PIN LL_GPIO_PIN_7 // PF.07
+#define INTMODULE_RX_GPIO_PIN LL_GPIO_PIN_6 // PF.06
+#define INTMODULE_USART UART7
+#define INTMODULE_GPIO_AF LL_GPIO_AF_8
+#define INTMODULE_USART_IRQn UART7_IRQn
+#define INTMODULE_USART_IRQHandler UART7_IRQHandler
+#define INTMODULE_DMA DMA1
+#define INTMODULE_DMA_STREAM LL_DMA_STREAM_1
+#define INTMODULE_DMA_STREAM_IRQ DMA1_Stream1_IRQn
+#define INTMODULE_DMA_FLAG_TC DMA_FLAG_TCIF1
+#define INTMODULE_DMA_CHANNEL LL_DMA_CHANNEL_5
+#define INTMODULE_RX_DMA DMA1
+#define INTMODULE_RX_DMA_STREAM LL_DMA_STREAM_3
+#define INTMODULE_RX_DMA_CHANNEL LL_DMA_CHANNEL_5
+// #define INTMODULE_RX_DMA_Stream_IRQn DMA1_Stream3_IRQn
+// #define INTMODULE_RX_DMA_Stream_IRQHandler DMA1_Stream_IRQHandler
+
+#define INTMODULE_TIMER TIM3
+#define INTMODULE_TIMER_IRQn TIM3_IRQn
+#define INTMODULE_TIMER_IRQHandler TIM3_IRQHandler
+#define INTMODULE_TIMER_FREQ (PERI1_FREQUENCY * TIMER_MULT_APB1)
+#endif
+
+// External Module
+#define EXTMODULE
+#define EXTMODULE_PULSES
+#define EXTMODULE_PWR_GPIO GPIOD
+#define EXTMODULE_PWR_GPIO_PIN GPIO_Pin_11 // PD.11
+#define EXTMODULE_RCC_AHB1Periph \
+ (RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_GPIOC | \
+ RCC_AHB1Periph_GPIOI | RCC_AHB1Periph_GPIOE | RCC_AHB1Periph_DMA2)
+#define EXTMODULE_TX_GPIO GPIOC
+#define EXTMODULE_TX_GPIO_PIN LL_GPIO_PIN_6 // PC.06
+#define EXTMODULE_TX_GPIO_AF LL_GPIO_AF_3 // TIM8_CH1
+#define EXTMODULE_TX_GPIO_AF_USART GPIO_AF_USART6
+#define EXTMODULE_RX_GPIO GPIOC
+#define EXTMODULE_RX_GPIO_PIN LL_GPIO_PIN_7 // PC.07
+#define EXTMODULE_RX_GPIO_AF_USART GPIO_AF_USART6
+#define EXTMODULE_TIMER TIM8
+#define EXTMODULE_TIMER_Channel LL_TIM_CHANNEL_CH1
+#define EXTMODULE_TIMER_IRQn TIM8_UP_TIM13_IRQn
+#define EXTMODULE_TIMER_IRQHandler TIM8_UP_TIM13_IRQHandler
+#define EXTMODULE_TIMER_FREQ (PERI2_FREQUENCY * TIMER_MULT_APB2)
+#define EXTMODULE_TIMER_TX_GPIO_AF LL_GPIO_AF_3
+//USART
+#define EXTMODULE_USART USART6
+#define EXTMODULE_USART_GPIO GPIOC
+#define EXTMODULE_USART_GPIO_AF GPIO_AF_USART6
+#define EXTMODULE_USART_GPIO_AF_LL LL_GPIO_AF_8
+#define EXTMODULE_USART_TX_DMA DMA2
+#define EXTMODULE_USART_TX_DMA_CHANNEL LL_DMA_CHANNEL_5
+#define EXTMODULE_USART_TX_DMA_STREAM DMA2_Stream7
+#define EXTMODULE_USART_TX_DMA_STREAM_LL LL_DMA_STREAM_7
+
+#define EXTMODULE_USART_RX_DMA_CHANNEL LL_DMA_CHANNEL_5
+#define EXTMODULE_USART_RX_DMA_STREAM DMA2_Stream2
+#define EXTMODULE_USART_RX_DMA_STREAM_LL LL_DMA_STREAM_2
+
+#define EXTMODULE_USART_IRQHandler USART6_IRQHandler
+#define EXTMODULE_USART_IRQn USART6_IRQn
+
+//TIMER
+#define EXTMODULE_TIMER_DMA_CHANNEL LL_DMA_CHANNEL_7
+#define EXTMODULE_TIMER_DMA_STREAM DMA2_Stream1
+#define EXTMODULE_TIMER_DMA DMA2
+#define EXTMODULE_TIMER_DMA_STREAM_LL LL_DMA_STREAM_1
+#define EXTMODULE_TIMER_DMA_STREAM_IRQn DMA2_Stream1_IRQn
+#define EXTMODULE_TIMER_DMA_IRQHandler DMA2_Stream1_IRQHandler
+
+#define EXTMODULE_TX_INVERT_GPIO GPIOE
+#define EXTMODULE_TX_INVERT_GPIO_PIN GPIO_Pin_3 // PE.03
+#define EXTMODULE_RX_INVERT_GPIO GPIOI
+#define EXTMODULE_RX_INVERT_GPIO_PIN GPIO_Pin_15 // PI.15
+
+#define EXTMODULE_TX_NORMAL() EXTMODULE_TX_INVERT_GPIO->BSRRH = EXTMODULE_TX_INVERT_GPIO_PIN
+#define EXTMODULE_TX_INVERTED() EXTMODULE_TX_INVERT_GPIO->BSRRL = EXTMODULE_TX_INVERT_GPIO_PIN
+#define EXTMODULE_RX_NORMAL() EXTMODULE_RX_INVERT_GPIO->BSRRH = EXTMODULE_RX_INVERT_GPIO_PIN
+#define EXTMODULE_RX_INVERTED() EXTMODULE_RX_INVERT_GPIO->BSRRL = EXTMODULE_RX_INVERT_GPIO_PIN
+
+// Trainer Port
+#define TRAINER_RCC_AHB1Periph (RCC_AHB1Periph_GPIOD)
+#define TRAINER_GPIO GPIOD
+
+#define TRAINER_IN_GPIO_PIN LL_GPIO_PIN_12 // PD.12
+#define TRAINER_IN_TIMER_Channel LL_TIM_CHANNEL_CH1
+
+#define TRAINER_OUT_GPIO_PIN LL_GPIO_PIN_13 // PD.13
+#define TRAINER_OUT_TIMER_Channel LL_TIM_CHANNEL_CH2
+
+#define TRAINER_TIMER TIM4
+#define TRAINER_TIMER_IRQn TIM4_IRQn
+#define TRAINER_TIMER_IRQHandler TIM4_IRQHandler
+#define TRAINER_GPIO_AF LL_GPIO_AF_2
+#define TRAINER_TIMER_FREQ (PERI1_FREQUENCY * TIMER_MULT_APB1)
+
+//ROTARY emulation for trims as buttons
+#define ROTARY_ENCODER_NAVIGATION
+
+//BLUETOOTH
+#define BLUETOOTH_ON_RCC_AHB1Periph RCC_AHB1Periph_GPIOI
+#define BT_EN_GPIO GPIOI
+#define BT_EN_GPIO_PIN GPIO_Pin_8 // PI.8
+
+#define BT_RCC_AHB1Periph (RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOI | RCC_AHB1Periph_GPIOH)
+#define BT_RCC_APB1Periph (RCC_APB1Periph_USART3)
+#define BT_RCC_APB2Periph 0
+
+#define BT_USART USART3
+#define BT_GPIO_AF GPIO_AF_USART3
+#define BT_USART_IRQn USART3_IRQn
+#define BT_GPIO_TXRX GPIOB
+#define BT_TX_GPIO_PIN GPIO_Pin_10 // PB.10
+#define BT_RX_GPIO_PIN GPIO_Pin_11 // PB.11
+#define BT_TX_GPIO_PinSource GPIO_PinSource10
+#define BT_RX_GPIO_PinSource GPIO_PinSource11
+#define BT_USART_IRQHandler USART3_IRQHandler
+
+#define BT_CONNECTED_GPIO GPIOJ
+#define BT_CONNECTED_GPIO_PIN GPIO_Pin_1 // PJ.01
+
+#define BT_CMD_MODE_GPIO GPIOH
+#define BT_CMD_MODE_GPIO_PIN GPIO_Pin_6 // PH.6
+
+// 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
+
+#define LCD_W 480
+#define LCD_H 320
+
+#define LCD_PHYS_W 320
+#define LCD_PHYS_H 480
+
+#define LCD_DEPTH 16
+#define LCD_CONTRAST_DEFAULT 20
+
+#endif // _HAL_H_
diff --git a/radio/src/targets/pl18/haptic_driver.cpp b/radio/src/targets/pl18/haptic_driver.cpp
new file mode 100644
index 00000000000..d8fc8f809da
--- /dev/null
+++ b/radio/src/targets/pl18/haptic_driver.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) EdgeTX
+ *
+ * Based on code named
+ * opentx - https://github.com/opentx/opentx
+ * th9x - http://code.google.com/p/th9x
+ * er9x - http://code.google.com/p/er9x
+ * gruvin9x - http://code.google.com/p/gruvin9x
+ *
+ * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "board.h"
+
+void hapticOff(void)
+{
+ HAPTIC_TIMER_COMPARE_VALUE = 0;
+}
+
+void hapticOn(uint32_t pwmPercent)
+{
+ if (pwmPercent > 100) {
+ pwmPercent = 100;
+ }
+ HAPTIC_TIMER_COMPARE_VALUE = pwmPercent;
+}
+
+void hapticInit(void)
+{
+ GPIO_InitTypeDef GPIO_InitStructure;
+ GPIO_InitStructure.GPIO_Pin = HAPTIC_GPIO_PIN;
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
+ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
+ GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
+ GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
+ GPIO_Init(HAPTIC_GPIO, &GPIO_InitStructure);
+
+ GPIO_PinAFConfig(HAPTIC_GPIO, HAPTIC_GPIO_PinSource, HAPTIC_GPIO_AF);
+
+ HAPTIC_GPIO_TIMER->ARR = 100;
+ HAPTIC_GPIO_TIMER->PSC = (PERI2_FREQUENCY * TIMER_MULT_APB2) / 10000 - 1;
+ HAPTIC_GPIO_TIMER->CCMR1 = HAPTIC_TIMER_MODE; // PWM
+ HAPTIC_GPIO_TIMER->CCER = HAPTIC_TIMER_OUTPUT_ENABLE;
+ HAPTIC_GPIO_TIMER->CCR1 = 0;
+ HAPTIC_GPIO_TIMER->EGR = TIM_EGR_UG;
+ HAPTIC_GPIO_TIMER->CR1 = TIM_CR1_CEN; // counter enable
+ HAPTIC_GPIO_TIMER->BDTR |= TIM_BDTR_MOE;
+}
+
+void hapticDone(void)
+{
+ hapticOff();
+ RCC_AHB1PeriphClockCmd(HAPTIC_RCC_AHB1Periph, DISABLE);
+}
diff --git a/radio/src/targets/pl18/key_driver.cpp b/radio/src/targets/pl18/key_driver.cpp
new file mode 100644
index 00000000000..cd09c374d71
--- /dev/null
+++ b/radio/src/targets/pl18/key_driver.cpp
@@ -0,0 +1,220 @@
+/*
+ * 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 "stm32_hal_ll.h"
+#include "stm32_gpio_driver.h"
+
+#include "hal.h"
+#include "delays_driver.h"
+#include "keys.h"
+
+/* The output bit-order has to be:
+ 0 LHL TR7L (Left equals down)
+ 1 LHR TR7R
+ 2 LVD TR5D
+ 3 LVU TR5U
+ 4 RVD TR6D
+ 5 RVU TR6U
+ 6 RHL TR8L
+ 7 RHR TR8R
+ 8 LSD TR1D
+ 9 LSU TR1U
+ 10 RSD TR2D
+ 11 RSU TR2U
+ 12 EX1D TR3D
+ 13 EX1U TR3U
+ 14 EX2D TR4D
+ 15 EX2U TR4U
+*/
+
+enum PhysicalTrims
+{
+ TR7L = 0,
+ TR7R,
+ TR5D = 2,
+ TR5U,
+ TR6D = 4,
+ TR6U,
+ TR8L = 6,
+ TR8R,
+ TR1D = 8,
+ TR1U,
+ TR2D = 10,
+ TR2U,
+ TR3D = 12,
+ TR3U,
+ TR4D = 14,
+ TR4U,
+};
+
+void keysInit()
+{
+ stm32_gpio_enable_clock(GPIOB);
+ stm32_gpio_enable_clock(GPIOC);
+ stm32_gpio_enable_clock(GPIOD);
+ stm32_gpio_enable_clock(GPIOF);
+ stm32_gpio_enable_clock(GPIOH);
+ stm32_gpio_enable_clock(GPIOJ);
+
+ LL_GPIO_InitTypeDef pinInit;
+ LL_GPIO_StructInit(&pinInit);
+ pinInit.Mode = LL_GPIO_MODE_INPUT;
+ pinInit.Pull = LL_GPIO_PULL_DOWN;
+
+ pinInit.Pin = KEYS_GPIOB_PINS;
+ LL_GPIO_Init(GPIOB, &pinInit);
+
+ pinInit.Pin = KEYS_GPIOC_PINS;
+ LL_GPIO_Init(GPIOC, &pinInit);
+
+ pinInit.Pin = KEYS_GPIOD_PINS;
+ LL_GPIO_Init(GPIOD, &pinInit);
+
+ pinInit.Pin = KEYS_GPIOH_PINS;
+ LL_GPIO_Init(GPIOH, &pinInit);
+
+ pinInit.Pin = KEYS_GPIOJ_PINS;
+ LL_GPIO_Init(GPIOJ, &pinInit);
+
+ // Matrix outputs
+ pinInit.Mode = LL_GPIO_MODE_OUTPUT;
+ pinInit.Pull = LL_GPIO_PULL_NO;
+
+ pinInit.Pin = KEYS_OUT_GPIOG_PINS;
+ LL_GPIO_Init(GPIOG, &pinInit);
+
+ pinInit.Pin = KEYS_OUT_GPIOH_PINS;
+ LL_GPIO_Init(GPIOH, &pinInit);
+}
+
+static uint32_t _readKeyMatrix()
+{
+ // This function avoids concurrent matrix agitation
+
+ uint32_t result = 0;
+ /* Bit 0 - TR3 down
+ * Bit 1 - TR3 up
+ * Bit 2 - TR4 down
+ * Bit 3 - TR4 up
+ * Bit 4 - TR5 down
+ * Bit 5 - TR5 up
+ * Bit 6 - TR6 down
+ * Bit 7 - TR6 up
+ * Bit 8 - TR7 left
+ * Bit 9 - TR7 right
+ * Bit 10 - TR8 left
+ * Bit 11 - TR8 right
+ */
+
+ volatile static struct
+ {
+ uint32_t oldResult = 0;
+ uint8_t ui8ReadInProgress = 0;
+ } syncelem;
+
+ if (syncelem.ui8ReadInProgress != 0) return syncelem.oldResult;
+
+ // ui8ReadInProgress was 0, increment it
+ syncelem.ui8ReadInProgress++;
+ // Double check before continuing, as non-atomic, non-blocking so far
+ // If ui8ReadInProgress is above 1, then there was concurrent task calling it, exit
+ if (syncelem.ui8ReadInProgress > 1) return syncelem.oldResult;
+
+ // If we land here, we have exclusive access to Matrix
+ LL_GPIO_ResetOutputPin(TRIMS_GPIO_OUT1, TRIMS_GPIO_OUT1_PIN);
+ LL_GPIO_SetOutputPin(TRIMS_GPIO_OUT2, TRIMS_GPIO_OUT2_PIN);
+ LL_GPIO_SetOutputPin(TRIMS_GPIO_OUT3, TRIMS_GPIO_OUT3_PIN);
+ LL_GPIO_SetOutputPin(TRIMS_GPIO_OUT4, TRIMS_GPIO_OUT4_PIN);
+ delay_us(10);
+ if (~TRIMS_GPIO_REG_IN1 & TRIMS_GPIO_PIN_IN1)
+ result |= 1 << TR7L;
+ if (~TRIMS_GPIO_REG_IN2 & TRIMS_GPIO_PIN_IN2)
+ result |= 1 << TR7R;
+ if (~TRIMS_GPIO_REG_IN3 & TRIMS_GPIO_PIN_IN3)
+ result |= 1 << TR5D;
+ if (~TRIMS_GPIO_REG_IN4 & TRIMS_GPIO_PIN_IN4)
+ result |= 1 << TR5U;
+
+ LL_GPIO_SetOutputPin(TRIMS_GPIO_OUT1, TRIMS_GPIO_OUT1_PIN);
+ LL_GPIO_ResetOutputPin(TRIMS_GPIO_OUT2, TRIMS_GPIO_OUT2_PIN);
+ delay_us(10);
+ if (~TRIMS_GPIO_REG_IN1 & TRIMS_GPIO_PIN_IN1)
+ result |= 1 << TR3D;
+ if (~TRIMS_GPIO_REG_IN2 & TRIMS_GPIO_PIN_IN2)
+ result |= 1 << TR3U;
+ if (~TRIMS_GPIO_REG_IN3 & TRIMS_GPIO_PIN_IN3)
+ result |= 1 << TR4U;
+ if (~TRIMS_GPIO_REG_IN4 & TRIMS_GPIO_PIN_IN4)
+ result |= 1 << TR4D;
+
+ LL_GPIO_SetOutputPin(TRIMS_GPIO_OUT2, TRIMS_GPIO_OUT2_PIN);
+ LL_GPIO_ResetOutputPin(TRIMS_GPIO_OUT3, TRIMS_GPIO_OUT3_PIN);
+ delay_us(10);
+ if (~TRIMS_GPIO_REG_IN1 & TRIMS_GPIO_PIN_IN1)
+ result |= 1 << TR6U;
+ if (~TRIMS_GPIO_REG_IN2 & TRIMS_GPIO_PIN_IN2)
+ result |= 1 << TR6D;
+ if (~TRIMS_GPIO_REG_IN3 & TRIMS_GPIO_PIN_IN3)
+ result |= 1 << TR8L;
+ if (~TRIMS_GPIO_REG_IN4 & TRIMS_GPIO_PIN_IN4)
+ result |= 1 << TR8R;
+
+ LL_GPIO_SetOutputPin(TRIMS_GPIO_OUT3, TRIMS_GPIO_OUT3_PIN);
+
+ syncelem.oldResult = result;
+ syncelem.ui8ReadInProgress = 0;
+
+ return result;
+}
+
+uint32_t readKeys()
+{
+ uint32_t result = 0;
+
+ if (getHatsAsKeys()) {
+ uint32_t mkeys = _readKeyMatrix();
+ if (mkeys & (1 << TR4D)) result |= 1 << KEY_ENTER;
+ if (mkeys & (1 << TR4U)) result |= 1 << KEY_EXIT;
+ }
+
+ return result;
+}
+
+uint32_t readTrims()
+{
+ uint32_t result = 0;
+
+ result |= _readKeyMatrix();
+
+ if (~TRIMS_GPIO_REG_TR1U & TRIMS_GPIO_PIN_TR1U)
+ result |= 1 << (TR1U);
+ if (~TRIMS_GPIO_REG_TR1D & TRIMS_GPIO_PIN_TR1D)
+ result |= 1 << (TR1D);
+
+ if (~TRIMS_GPIO_REG_TR2U & TRIMS_GPIO_PIN_TR2U)
+ result |= 1 << (TR2U);
+ if (~TRIMS_GPIO_REG_TR2D & TRIMS_GPIO_PIN_TR2D)
+ result |= 1 << (TR2D);
+
+ return result;
+}
diff --git a/radio/src/targets/pl18/lcd_driver.cpp b/radio/src/targets/pl18/lcd_driver.cpp
new file mode 100644
index 00000000000..7067e9d4cb7
--- /dev/null
+++ b/radio/src/targets/pl18/lcd_driver.cpp
@@ -0,0 +1,2876 @@
+/*
+ * Copyright (C) EdgeTX
+ *
+ * Based on code named
+ * opentx - https://github.com/opentx/opentx
+ * th9x - http://code.google.com/p/th9x
+ * er9x - http://code.google.com/p/er9x
+ * gruvin9x - http://code.google.com/p/gruvin9x
+ *
+ * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "stm32_hal_ll.h"
+#include "stm32_hal.h"
+#include "opentx_types.h"
+#include "dma2d.h"
+#include "hal.h"
+#include "delays_driver.h"
+#include "debug.h"
+#include "lcd.h"
+#include "lcd_driver.h"
+
+uint8_t TouchControllerType = 0; //0:cst340; 1 ft6236
+static volatile uint16_t lcd_phys_w = LCD_PHYS_W;
+static volatile uint16_t lcd_phys_h = LCD_PHYS_H;
+
+static LTDC_HandleTypeDef hltdc;
+static void* initialFrameBuffer = nullptr;
+
+static volatile uint8_t _frame_addr_reloaded = 0;
+
+static void startLcdRefresh(lv_disp_drv_t *disp_drv, uint16_t *buffer,
+ const rect_t ©_area)
+{
+ (void)disp_drv;
+ (void)copy_area;
+
+ LTDC_Layer1->CFBAR &= ~(LTDC_LxCFBAR_CFBADD);
+ LTDC_Layer1->CFBAR = (uint32_t)buffer;
+ // reload shadow registers on vertical blank
+ _frame_addr_reloaded = 0;
+ LTDC->SRCR = LTDC_SRCR_VBR;
+ __HAL_LTDC_ENABLE_IT(&hltdc, LTDC_IT_LI);
+
+ // wait for reload
+ // TODO: replace through some smarter mechanism without busy wait
+ while(_frame_addr_reloaded == 0);
+}
+
+lcdSpiInitFucPtr lcdInitFunction;
+lcdSpiInitFucPtr lcdOffFunction;
+lcdSpiInitFucPtr lcdOnFunction;
+uint32_t lcdPixelClock;
+
+volatile uint8_t LCD_ReadBuffer[24] = { 0, 0 };
+
+static void LCD_Delay(void) {
+ volatile unsigned int i;
+
+ for (i = 0; i < 20; i++) {
+ ;
+ }
+}
+
+enum ENUM_IO_SPEED
+{
+ IO_SPEED_LOW,
+ IO_SPEED_MID,
+ IO_SPEED_QUICK,
+ IO_SPEED_HIGH
+};
+
+enum ENUM_IO_MODE
+{
+ IO_MODE_INPUT,
+ IO_MODE_OUTPUT,
+ IO_MODE_ALTERNATE,
+ IO_MODE_ANALOG
+};
+
+static void LCD_AF_GPIOConfig(void) {
+ /*
+ -----------------------------------------------------------------------------
+ LCD_CLK <-> PG.07 | LCD_HSYNC <-> PI.12 | LCD_R3 <-> PJ.02 | LCD_G5 <-> PK.00
+ | LCD VSYNC <-> PI.13 | LCD_R4 <-> PJ.03 | LCD_G6 <-> PK.01
+ | | LCD_R5 <-> PJ.04 | LCD_G7 <-> PK.02
+ | | LCD_R6 <-> PJ.05 | LCD_B4 <-> PK.03
+ | | LCD_R7 <-> PJ.06 | LCD_B5 <-> PK.04
+ | | LCD_G2 <-> PJ.09 | LCD_B6 <-> PK.05
+ | | LCD_G3 <-> PJ.10 | LCD_B7 <-> PK.06
+ | | LCD_G4 <-> PJ.11 | LCD_DE <-> PK.07
+ | | LCD_B3 <-> PJ.15 |
+ */
+
+ LL_GPIO_InitTypeDef GPIO_InitStructure;
+ LL_GPIO_StructInit(&GPIO_InitStructure);
+
+ // GPIOG configuration
+ GPIO_InitStructure.Pin = LL_GPIO_PIN_7;
+ GPIO_InitStructure.Speed = LL_GPIO_SPEED_FREQ_LOW;
+ GPIO_InitStructure.Mode = LL_GPIO_MODE_ALTERNATE;
+ GPIO_InitStructure.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
+ GPIO_InitStructure.Pull = LL_GPIO_PULL_NO;
+ GPIO_InitStructure.Alternate = LL_GPIO_AF_14; // AF LTDC
+ LL_GPIO_Init(GPIOG, &GPIO_InitStructure);
+
+ // GPIOI configuration
+ GPIO_InitStructure.Pin = LL_GPIO_PIN_12 | LL_GPIO_PIN_13;
+ LL_GPIO_Init(GPIOI, &GPIO_InitStructure);
+
+ // GPIOJ configuration
+ GPIO_InitStructure.Pin = LL_GPIO_PIN_2 | LL_GPIO_PIN_3 | LL_GPIO_PIN_4 | LL_GPIO_PIN_5 | LL_GPIO_PIN_6 | LL_GPIO_PIN_9 | LL_GPIO_PIN_10 | LL_GPIO_PIN_11 | LL_GPIO_PIN_15;
+ LL_GPIO_Init(GPIOJ, &GPIO_InitStructure);
+
+ // GPIOK configuration
+ GPIO_InitStructure.Pin = LL_GPIO_PIN_0 | LL_GPIO_PIN_1 | LL_GPIO_PIN_2 | LL_GPIO_PIN_3 | LL_GPIO_PIN_4 | LL_GPIO_PIN_5 | LL_GPIO_PIN_6 | LL_GPIO_PIN_7;
+ LL_GPIO_Init(GPIOK, &GPIO_InitStructure);
+}
+
+static void lcdSpiConfig(void) {
+ LL_GPIO_InitTypeDef GPIO_InitStructure;
+ LL_GPIO_StructInit(&GPIO_InitStructure);
+
+ GPIO_InitStructure.Pin = LCD_SPI_SCK_GPIO_PIN | LCD_SPI_MOSI_GPIO_PIN;
+ GPIO_InitStructure.Speed = LL_GPIO_SPEED_FREQ_LOW;
+ GPIO_InitStructure.Mode = LL_GPIO_MODE_OUTPUT;
+ GPIO_InitStructure.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
+ GPIO_InitStructure.Pull = LL_GPIO_PULL_NO;
+ LL_GPIO_Init(LCD_SPI_GPIO, &GPIO_InitStructure);
+
+ GPIO_InitStructure.Pin = LCD_SPI_CS_GPIO_PIN;
+ GPIO_InitStructure.Speed = LL_GPIO_SPEED_FREQ_LOW;
+ GPIO_InitStructure.Mode = LL_GPIO_MODE_OUTPUT;
+ GPIO_InitStructure.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
+ GPIO_InitStructure.Pull = LL_GPIO_PULL_UP;
+ LL_GPIO_Init(LCD_SPI_GPIO, &GPIO_InitStructure);
+
+ GPIO_InitStructure.Pin = LCD_NRST_GPIO_PIN;
+ LL_GPIO_Init(LCD_NRST_GPIO, &GPIO_InitStructure);
+
+ /* Set the chip select pin always low */
+ LCD_CS_LOW();
+}
+
+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(100);
+}
+
+unsigned char LCD_ReadByteOnFallingEdge(void) {
+ unsigned int i;
+ unsigned char ReceiveData = 0;
+
+ LCD_MOSI_HIGH();
+ LCD_MOSI_AS_INPUT();
+
+ for (i = 0; i < 8; i++) {
+ LCD_DELAY();
+ LCD_SCK_HIGH();
+ LCD_DELAY();
+ LCD_DELAY();
+ ReceiveData <<= 1;
+
+ LCD_SCK_LOW();
+ LCD_DELAY();
+ LCD_DELAY();
+ if (LCD_READ_DATA_PIN()) {
+ ReceiveData |= 0x01;
+ }
+ }
+
+ LCD_MOSI_AS_OUTPUT();
+
+ return (ReceiveData);
+}
+
+static void lcdWriteByte(uint8_t data_enable, uint8_t byte) {
+
+ LCD_SCK_LOW();
+ lcdDelay();
+
+ if (data_enable) {
+ LCD_MOSI_HIGH();
+ } else {
+ LCD_MOSI_LOW();
+ }
+
+ LCD_SCK_HIGH();
+ lcdDelay();
+
+ for (int i = 0; i < 8; i++) {
+ LCD_SCK_LOW();
+ lcdDelay();
+
+ if (byte & 0x80) {
+ LCD_MOSI_HIGH();
+ } else {
+ LCD_MOSI_LOW();
+ }
+
+ LCD_SCK_HIGH();
+ byte <<= 1;
+
+ lcdDelay();
+ }
+
+ LCD_SCK_LOW();
+}
+
+unsigned char LCD_ReadByte(void) {
+ unsigned int i;
+ unsigned char ReceiveData = 0;
+
+ LCD_MOSI_HIGH();
+ LCD_MOSI_AS_INPUT();
+ for (i = 0; i < 8; i++) {
+ LCD_SCK_LOW();
+ lcdDelay();
+ ReceiveData <<= 1;
+ LCD_SCK_HIGH();
+ lcdDelay();
+ if (LCD_READ_DATA_PIN()) {
+ ReceiveData |= 0x01;
+ }
+ }
+ LCD_SCK_LOW();
+ LCD_MOSI_AS_OUTPUT();
+ return (ReceiveData);
+}
+
+unsigned char LCD_ReadRegister(unsigned char Register) {
+ unsigned char ReadData = 0;
+
+ lcdWriteByte(0, Register);
+ lcdDelay();
+ lcdDelay();
+ ReadData = LCD_ReadByte();
+ return (ReadData);
+}
+
+void lcdWriteCommand(uint8_t command) {
+ lcdWriteByte(0, command);
+}
+
+void lcdWriteData(uint8_t data) {
+ lcdWriteByte(1, data);
+}
+
+void LCD_HX8357D_Init(void) {
+#if 0
+ lcdWriteCommand(0x11);
+ delay_ms(200);
+
+ lcdWriteCommand(0xB9);
+ lcdWriteData(0xFF);
+ lcdWriteData(0x83);
+ lcdWriteData(0x57);
+
+ lcdWriteCommand(0xB1);
+ lcdWriteData(0x00);
+ lcdWriteData(0x14);
+ lcdWriteData(0x1C);
+ lcdWriteData(0x1C);
+ lcdWriteData(0xC7);
+ lcdWriteData(0x21);
+
+ lcdWriteCommand(0xB3);
+ lcdWriteData(0x83);
+ lcdWriteData(0x00);
+ lcdWriteData(0x06);
+ lcdWriteData(0x06);
+
+ lcdWriteCommand(0xB4);
+ lcdWriteData(0x11);
+ lcdWriteData(0x40);
+ lcdWriteData(0x00);
+ lcdWriteData(0x2A);
+ lcdWriteData(0x2A);
+ lcdWriteData(0x20);
+ lcdWriteData(0x4E);
+
+ lcdWriteCommand(0xB5);
+ lcdWriteData(0x03);
+ lcdWriteData(0x03);
+
+ lcdWriteCommand(0xB6);
+ lcdWriteData(0x38);
+
+ lcdWriteCommand(0xC0);
+ lcdWriteData(0x24);
+ lcdWriteData(0x24);
+ lcdWriteData(0x00);
+ lcdWriteData(0x10);
+ lcdWriteData(0xc8);
+ lcdWriteData(0x08);
+
+ lcdWriteCommand(0xC2);
+ lcdWriteData(0x00);
+ lcdWriteData(0x08);
+ lcdWriteData(0x04);
+
+ lcdWriteCommand(0xCC);
+ lcdWriteData(0x00);
+
+//GAMMA 2.5"
+ lcdWriteCommand(0xE0);
+ lcdWriteData(0x00);
+ lcdWriteData(0x06);
+ lcdWriteData(0x0D);
+ lcdWriteData(0x18);
+ lcdWriteData(0x23);
+ lcdWriteData(0x3B);
+ lcdWriteData(0x45);
+ lcdWriteData(0x4D);
+ lcdWriteData(0x4D);
+ lcdWriteData(0x46);
+ lcdWriteData(0x40);
+ lcdWriteData(0x37);
+ lcdWriteData(0x34);
+ lcdWriteData(0x2F);
+ lcdWriteData(0x2B);
+ lcdWriteData(0x21);
+ lcdWriteData(0x00);
+ lcdWriteData(0x06);
+ lcdWriteData(0x0D);
+ lcdWriteData(0x18);
+ lcdWriteData(0x23);
+ lcdWriteData(0x3B);
+ lcdWriteData(0x45);
+ lcdWriteData(0x4D);
+ lcdWriteData(0x4D);
+ lcdWriteData(0x46);
+ lcdWriteData(0x40);
+ lcdWriteData(0x37);
+ lcdWriteData(0x34);
+ lcdWriteData(0x2F);
+ lcdWriteData(0x2B);
+ lcdWriteData(0x21);
+ lcdWriteData(0x00);
+ lcdWriteData(0x01);
+
+ lcdWriteCommand(0x3A);
+ lcdWriteData(0x66);
+
+ lcdWriteCommand(0x36);
+ lcdWriteData(0x28);
+ lcdWriteCommand( 0x2A );
+ lcdWriteData( 0x00 );
+ lcdWriteData( 0x00 );
+ lcdWriteData( 0x01 );
+ lcdWriteData( 0xDF );
+ lcdWriteCommand( 0x2B );
+ lcdWriteData( 0x00 );
+ lcdWriteData( 0x00 );
+ lcdWriteData( 0x01 );
+ lcdWriteData( 0x3F );
+
+ lcdWriteCommand(0x29);
+ delay_ms(10);
+#elif 0
+ delay_ms(50);
+ lcdWriteCommand(0xB9); //EXTC
+ lcdWriteData(0xFF); //EXTC
+ lcdWriteData(0x83); //EXTC
+ lcdWriteData(0x57); //EXTC
+ delay_ms(5);
+
+ lcdWriteCommand(0x3A);
+ lcdWriteData(0x65); //262k
+
+ lcdWriteCommand(0xB3); //COLOR FORMAT
+ lcdWriteData(0x83); //SDO_EN,BYPASS,EPF[1:0],0,0,RM,DM //43
+
+ lcdWriteCommand(0xB6); //
+ lcdWriteData(0x5a); //VCOMDC
+
+ lcdWriteCommand(0x35); // TE ON
+ lcdWriteData(0x01);
+
+ lcdWriteCommand(0xB0);
+ lcdWriteData(0x68); //70Hz
+
+ lcdWriteCommand(0xCC); // Set Panel
+ lcdWriteData(0x00); //
+
+ lcdWriteCommand(0xB1); //
+ lcdWriteData(0x00); //
+ lcdWriteData(0x11); //BT
+ lcdWriteData(0x1C); //VSPR
+ lcdWriteData(0x1C); //VSNR
+ lcdWriteData(0x83); //AP
+ lcdWriteData(0x48); //FS 0xAA
+
+ lcdWriteCommand(0xB4); //
+ lcdWriteData(0x02); //NW
+ lcdWriteData(0x40); //RTN
+ lcdWriteData(0x00); //DIV
+ lcdWriteData(0x2A); //DUM
+ lcdWriteData(0x2A); //DUM
+ lcdWriteData(0x0D); //GDON
+ lcdWriteData(0x78); //GDOFF 0x4F
+ lcdWriteCommand(0xC0); //STBA
+ lcdWriteData(0x50); //OPON
+ lcdWriteData(0x50); //OPON
+ lcdWriteData(0x01); //
+ lcdWriteData(0x3C); //
+ lcdWriteData(0x1E); //
+ lcdWriteData(0x08); //GEN
+
+ /*
+ lcdWriteCommand(0xE0); //
+ lcdWriteData(0x02); //1
+ lcdWriteData(0x06); //2
+ lcdWriteData(0x09); //3
+ lcdWriteData(0x1C); //4
+ lcdWriteData(0x27); //5
+ lcdWriteData(0x3C); //6
+ lcdWriteData(0x48); //7
+ lcdWriteData(0x50); //8
+ lcdWriteData(0x49); //9
+ lcdWriteData(0x42); //10
+ lcdWriteData(0x3E); //11
+ lcdWriteData(0x35); //12
+ lcdWriteData(0x31); //13
+ lcdWriteData(0x2A); //14
+ lcdWriteData(0x28); //15
+ lcdWriteData(0x03); //16
+ lcdWriteData(0x02); //17 v1
+ lcdWriteData(0x06); //18
+ lcdWriteData(0x09); //19
+ lcdWriteData(0x1C); //20
+ lcdWriteData(0x27); //21
+ lcdWriteData(0x3C); //22
+ lcdWriteData(0x48); //23
+ lcdWriteData(0x50); //24
+ lcdWriteData(0x49); //25
+ lcdWriteData(0x42); //26
+ lcdWriteData(0x3E); //27
+ lcdWriteData(0x35); //28
+ lcdWriteData(0x31); //29
+ lcdWriteData(0x2A); //30
+ lcdWriteData(0x28); //31
+ lcdWriteData(0x03); //32
+ lcdWriteData(0x44); //33
+ lcdWriteData(0x01); //34
+ */
+ lcdWriteCommand(0xE0);
+ lcdWriteData(0x00);
+ lcdWriteData(0x06);
+ lcdWriteData(0x0D);
+ lcdWriteData(0x18);
+ lcdWriteData(0x23);
+ lcdWriteData(0x3B);
+ lcdWriteData(0x45);
+ lcdWriteData(0x4D);
+ lcdWriteData(0x4D);
+ lcdWriteData(0x46);
+ lcdWriteData(0x40);
+ lcdWriteData(0x37);
+ lcdWriteData(0x34);
+ lcdWriteData(0x2F);
+ lcdWriteData(0x2B);
+ lcdWriteData(0x21);
+ lcdWriteData(0x00);
+ lcdWriteData(0x06);
+ lcdWriteData(0x0D);
+ lcdWriteData(0x18);
+ lcdWriteData(0x23);
+ lcdWriteData(0x3B);
+ lcdWriteData(0x45);
+ lcdWriteData(0x4D);
+ lcdWriteData(0x4D);
+ lcdWriteData(0x46);
+ lcdWriteData(0x40);
+ lcdWriteData(0x37);
+ lcdWriteData(0x34);
+ lcdWriteData(0x2F);
+ lcdWriteData(0x2B);
+ lcdWriteData(0x21);
+ lcdWriteData(0x00);
+ lcdWriteData(0x01);
+ lcdWriteCommand(0x36);
+ lcdWriteData(0x38);
+
+ lcdWriteCommand(0x11); // SLPOUT
+ delay_ms(200);
+
+ lcdWriteCommand(0x29); // Display On
+ delay_ms(25);
+ lcdWriteCommand(0x2C);
+#else
+ lcdWriteCommand(0x11);
+ delay_ms(200);
+
+ lcdWriteCommand(0xB9);
+ lcdWriteData(0xFF);
+ lcdWriteData(0x83);
+ lcdWriteData(0x57);
+ delay_ms(5);
+
+// lcdWriteCommand(0x36);
+// lcdWriteData(0x10);
+
+ lcdWriteCommand(0xB1);
+ lcdWriteData(0x00);
+ lcdWriteData(0x14);
+ lcdWriteData(0x1C);
+ lcdWriteData(0x1C);
+ lcdWriteData(0xC7);
+ lcdWriteData(0x21);
+ lcdWriteCommand(0xB3);
+ lcdWriteData(0x83);
+ lcdWriteData(0x00);
+ lcdWriteData(0x06);
+ lcdWriteData(0x06);
+ lcdWriteCommand(0xB4);
+ lcdWriteData(0x11);
+ lcdWriteData(0x40);
+ lcdWriteData(0x00);
+ lcdWriteData(0x2A);
+ lcdWriteData(0x2A);
+ lcdWriteData(0x20);
+ lcdWriteData(0x4E);
+ lcdWriteCommand(0xB5);
+ lcdWriteData(0x03);
+ lcdWriteData(0x03);
+
+ lcdWriteCommand(0xB6);
+ lcdWriteData(0x38);
+
+ lcdWriteCommand(0xC0);
+ lcdWriteData(0x24);
+ lcdWriteData(0x24);
+ lcdWriteData(0x00);
+ lcdWriteData(0x10);
+ lcdWriteData(0xc8);
+ lcdWriteData(0x08);
+ lcdWriteCommand(0xC2);
+ lcdWriteData(0x00);
+ lcdWriteData(0x08);
+ lcdWriteData(0x04);
+ //GAMMA 2.5"
+ lcdWriteCommand(0xE0);
+ lcdWriteData(0x00);
+ lcdWriteData(0x06);
+ lcdWriteData(0x0D);
+ lcdWriteData(0x18);
+ lcdWriteData(0x23);
+ lcdWriteData(0x3B);
+ lcdWriteData(0x45);
+ lcdWriteData(0x4D);
+ lcdWriteData(0x4D);
+ lcdWriteData(0x46);
+ lcdWriteData(0x40);
+ lcdWriteData(0x37);
+ lcdWriteData(0x34);
+ lcdWriteData(0x2F);
+ lcdWriteData(0x2B);
+ lcdWriteData(0x21);
+ lcdWriteData(0x00);
+ lcdWriteData(0x06);
+ lcdWriteData(0x0D);
+ lcdWriteData(0x18);
+ lcdWriteData(0x23);
+ lcdWriteData(0x3B);
+ lcdWriteData(0x45);
+ lcdWriteData(0x4D);
+ lcdWriteData(0x4D);
+ lcdWriteData(0x46);
+ lcdWriteData(0x40);
+ lcdWriteData(0x37);
+ lcdWriteData(0x34);
+ lcdWriteData(0x2F);
+ lcdWriteData(0x2B);
+ lcdWriteData(0x21);
+ lcdWriteData(0x00);
+ lcdWriteData(0x01);
+ // lcdWriteCommand(0x2A);
+ // lcdWriteData(0);
+ // lcdWriteData(0);
+ // lcdWriteData(480 >> 8);
+ // lcdWriteData(480);
+ // lcdWriteCommand(0x2B);
+ // lcdWriteData(0);
+ // lcdWriteData(0);
+ // lcdWriteData(320 >> 8);
+ // lcdWriteData(320);
+ lcdWriteCommand(0x3A);
+ lcdWriteData(0x66);
+
+ lcdWriteCommand(0xCC);
+ lcdWriteData(0x01);
+
+ lcdWriteCommand( 0x2A );
+ lcdWriteData( 0x00 );
+ lcdWriteData( 0x00 );
+ lcdWriteData( 0x01 );
+ lcdWriteData( 0xDF );
+ lcdWriteCommand( 0x2B );
+ lcdWriteData( 0x00 );
+ lcdWriteData( 0x00 );
+ lcdWriteData( 0x01 );
+ lcdWriteData( 0x3F );
+
+ lcdWriteCommand(0x36);
+ lcdWriteData(0x20);
+
+ lcdWriteCommand(0xB9);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ delay_ms(5);
+ lcdWriteCommand(0x29);
+#endif
+}
+
+void LCD_HX8357D_On(void) {
+ lcdWriteCommand(0x28);
+ lcdWriteCommand(0x29);
+}
+
+void LCD_HX8357D_Off(void) {
+ lcdWriteCommand(0x28);
+}
+
+unsigned int LCD_HX8357D_ReadID(void) {
+ lcdReset();
+ int ID = 0;
+
+ lcdWriteCommand( 0xB9 );
+ lcdWriteData( 0xff );
+ lcdWriteData( 0x83 );
+ lcdWriteData( 0x57 );
+
+ lcdWriteCommand( 0xFE );
+ lcdWriteData( 0xd0 );
+ ID = LCD_ReadRegister( 0xff );
+
+ lcdWriteCommand( 0xB9 );
+ lcdWriteData( 0x00 );
+ lcdWriteData( 0x00 );
+ lcdWriteData( 0x00 );
+
+ return (ID);
+}
+
+void LCD_ILI9481_Init(void) {
+ lcdWriteCommand(0x11);
+ delay_ms(120);
+
+ lcdWriteCommand(0xE4);
+ lcdWriteData(0x0A);
+
+ lcdWriteCommand(0xF0);
+ lcdWriteData(0x01);
+
+ lcdWriteCommand(0xF3);
+ lcdWriteData(0x02);
+ lcdWriteData(0x1A);
+
+ lcdWriteCommand(0xD0);
+ lcdWriteData(0x07);
+ lcdWriteData(0x42);
+ lcdWriteData(0x1B);
+
+ lcdWriteCommand(0xD1);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00); //04
+ lcdWriteData(0x1A);
+
+ lcdWriteCommand(0xD2);
+ lcdWriteData(0x01);
+ lcdWriteData(0x00); //11
+
+ lcdWriteCommand(0xC0);
+ lcdWriteData(0x10);
+ lcdWriteData(0x3B); //
+ lcdWriteData(0x00); //
+ lcdWriteData(0x02);
+ lcdWriteData(0x11);
+
+ lcdWriteCommand(0xC5);
+ lcdWriteData(0x03);
+
+ lcdWriteCommand(0xC8);
+ lcdWriteData(0x00);
+ lcdWriteData(0x01);
+ lcdWriteData(0x47);
+ lcdWriteData(0x60);
+ lcdWriteData(0x04);
+ lcdWriteData(0x16);
+ lcdWriteData(0x03);
+ lcdWriteData(0x67);
+ lcdWriteData(0x67);
+ lcdWriteData(0x06);
+ lcdWriteData(0x0F);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0x36);
+ lcdWriteData(0x08);
+
+ lcdWriteCommand(0x3A);
+ lcdWriteData(0x66); //0x55=65k color, 0x66=262k color.
+
+ lcdWriteCommand(0x2A);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x01);
+ lcdWriteData(0x3F);
+
+ lcdWriteCommand(0x2B);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x01);
+ lcdWriteData(0xE0);
+
+ lcdWriteCommand(0xB4);
+ lcdWriteData(0x11);
+
+ lcdWriteCommand(0xc6);
+ lcdWriteData(0x82);
+
+ delay_ms(120);
+
+ lcdWriteCommand(0x21);
+ lcdWriteCommand(0x29);
+ lcdWriteCommand(0x2C);
+
+}
+
+void LCD_ILI9481_On(void) {
+ lcdWriteCommand(0x29);
+}
+
+void LCD_ILI9481_Off(void) {
+ lcdWriteCommand(0x28);
+}
+
+unsigned int LCD_ILI9481_ReadID(void) {
+#if 1
+ /* Have a issue here */
+ return 0;
+#else
+ int ID = 0;
+ int Data;
+
+
+ lcdWriteByte(0, 0xBF);
+
+ Data = LCD_ReadByteOnFallingEdge();
+ Data = LCD_ReadByteOnFallingEdge();
+ ID = LCD_ReadByteOnFallingEdge();
+ ID <<= 8;
+ ID |= LCD_ReadByteOnFallingEdge();
+ Data = LCD_ReadByteOnFallingEdge();
+ Data = LCD_ReadByteOnFallingEdge();
+
+ LCD_DELAY();
+ LCD_DELAY();
+ LCD_DELAY();
+
+ lcdWriteCommand(0xC6);
+ lcdWriteData(0x82);
+ //lcdWriteData( 0x9b );
+ return (ID);
+#endif
+}
+
+void LCD_ILI9486_On(void) {
+ lcdWriteCommand(0x29);
+}
+
+void LCD_ILI9486_Init(void) {
+ lcdWriteCommand(0XFB);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xf2);
+ lcdWriteData(0x18);
+ lcdWriteData(0xa3);
+ lcdWriteData(0x12);
+ lcdWriteData(0x02);
+ lcdWriteData(0xb2);
+ lcdWriteData(0x12);
+ lcdWriteData(0xff);
+ lcdWriteData(0x13);
+ lcdWriteData(0x00);
+ lcdWriteCommand(0xf1);
+ lcdWriteData(0x36);
+ lcdWriteData(0x04);
+ lcdWriteData(0x00);
+ lcdWriteData(0x3c);
+ lcdWriteData(0x0f);
+ lcdWriteData(0x8f);
+ lcdWriteCommand(0xf8);
+ lcdWriteData(0x21);
+ lcdWriteData(0x04);
+ lcdWriteCommand(0xf9);
+ lcdWriteData(0x00);
+ lcdWriteData(0x08);
+ lcdWriteCommand(0x36);
+ lcdWriteData(0x18);
+ lcdWriteCommand(0x3a);
+ lcdWriteData(0x65);
+ lcdWriteCommand(0xc0);
+ lcdWriteData(0x0f);
+ lcdWriteData(0x0f);
+ lcdWriteCommand(0xc1);
+ lcdWriteData(0x41);
+
+ lcdWriteCommand(0xc5);
+ lcdWriteData(0x00);
+ lcdWriteData(0x27);
+ lcdWriteData(0x80);
+ lcdWriteCommand(0xb6);
+ lcdWriteData(0xb2);
+ lcdWriteData(0x42);
+ lcdWriteData(0x3b);
+ lcdWriteCommand(0xb1);
+ lcdWriteData(0xb0);
+ lcdWriteData(0x11);
+ lcdWriteCommand(0xb4);
+ lcdWriteData(0x02);
+ lcdWriteCommand(0xb7);
+ lcdWriteData(0xC6);
+
+ lcdWriteCommand(0xe0);
+ lcdWriteData(0x0f);
+ lcdWriteData(0x1C);
+ lcdWriteData(0x18);
+ lcdWriteData(0x0B);
+ lcdWriteData(0x0D);
+ lcdWriteData(0x06);
+ lcdWriteData(0x48);
+ lcdWriteData(0x87);
+ lcdWriteData(0x3A);
+ lcdWriteData(0x09);
+ lcdWriteData(0x15);
+ lcdWriteData(0x08);
+ lcdWriteData(0x0D);
+ lcdWriteData(0x04);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xe1);
+ lcdWriteData(0x0f);
+ lcdWriteData(0x37);
+ lcdWriteData(0x34);
+ lcdWriteData(0x0A);
+ lcdWriteData(0x0B);
+ lcdWriteData(0x03);
+ lcdWriteData(0x4B);
+ lcdWriteData(0x31);
+ lcdWriteData(0x39);
+ lcdWriteData(0x03);
+ lcdWriteData(0x0F);
+ lcdWriteData(0x03);
+ lcdWriteData(0x22);
+ lcdWriteData(0x1D);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0x21);
+ lcdWriteCommand(0x11);
+ delay_ms(120);
+ lcdWriteCommand(0x28);
+
+ LCD_ILI9486_On();
+}
+
+void LCD_ILI9486_Off(void) {
+ lcdWriteCommand(0x28);
+}
+
+unsigned int LCD_ILI9486_ReadID(void) {
+ int ID = 0;
+
+ lcdWriteCommand(0XF7);
+ lcdWriteData(0xA9);
+ lcdWriteData(0x51);
+ lcdWriteData(0x2C);
+ lcdWriteData(0x82);
+ lcdWriteCommand(0XB0);
+ lcdWriteData(0X80);
+
+ lcdWriteCommand(0XFB);
+ lcdWriteData(0x10 | 0x00);
+ ID = LCD_ReadRegister(0xd3);
+
+ lcdWriteCommand(0XFB);
+ lcdWriteData(0x10 | 0x01);
+ ID = LCD_ReadRegister(0xd3);
+
+ lcdWriteCommand(0XFB);
+ lcdWriteData(0x10 | 0x02);
+ ID = LCD_ReadRegister(0xd3);
+ ID <<= 8;
+ lcdWriteCommand(0XFB);
+ lcdWriteData(0x10 | 0x03);
+ ID |= LCD_ReadRegister(0xd3);
+
+ lcdWriteCommand(0XFB);
+ lcdWriteData(0x00);
+
+ return (ID);
+}
+
+void LCD_ILI9488_On(void) {
+ // Display ON
+ lcdWriteCommand(0x29);
+}
+
+void LCD_ILI9488_Init(void) {
+
+ // lcdWriteCommand(0xFB);
+ // lcdWriteData(0x00);
+
+ // Adjust Control 3:
+ // -> DSI write DCS command, use stream packet RGB 666
+ lcdWriteCommand(0xF7);
+ lcdWriteData(0xA9);
+ lcdWriteData(0x51);
+ lcdWriteData(0x2C);
+ lcdWriteData(0x82);
+
+ // Power Control 1:
+ // -> VREG1OUT = 4.6250
+ // -> VREG2OUT = -4.1250
+ lcdWriteCommand(0xC0);
+ lcdWriteData(0x11);
+ lcdWriteData(0x09);
+
+ // Power Control 2:
+ // -> VGH = VCI x 6, VGL = VCI x 4
+ lcdWriteCommand(0xC1);
+ lcdWriteData(0x41);
+
+ // VCOM Control
+ lcdWriteCommand(0xC5);
+ lcdWriteData(0x00); // NV memory not programmed
+ lcdWriteData(0x0A); // VCM_REG
+ lcdWriteData(0x80); // VCM_REG_EN
+
+ // Frame Rate Control
+ lcdWriteCommand(0xB1);
+ lcdWriteData(0xB0);
+ lcdWriteData(0x11);
+
+ // Display Inversion Control
+ lcdWriteCommand(0xB4);
+ lcdWriteData(0x01);
+
+ lcdWriteCommand(0xB5);
+ lcdWriteData(VFP);
+ lcdWriteData(VBP);
+ lcdWriteData(HFP);
+ lcdWriteData(HBP);
+
+ // Display Function Control
+ lcdWriteCommand(0xB6);
+ // !DM | RM | RCM
+ lcdWriteData(0x20 | 0x40);
+ lcdWriteData(0x02);
+ lcdWriteData(0x3B); // (59 + 1) x 8 = 480 lines
+
+ // Entry Set Mode
+ lcdWriteCommand(0xB7);
+ lcdWriteData(0xc6);
+
+ lcdWriteCommand(0xBE);
+ lcdWriteData(0x00);
+ // lcdWriteData(0x04); // ????
+
+ lcdWriteCommand(0xE9);
+ lcdWriteData(0x00);
+
+ // Column Address Set
+ // -> SC=0, EC=479
+ lcdWriteCommand( 0x2A );
+ lcdWriteData( 0x00 );
+ lcdWriteData( 0x00 );
+ lcdWriteData( 0x01 );
+ lcdWriteData( 0xDF );
+
+ // Page Address Set
+ // -> SP=0, EP=319
+ lcdWriteCommand( 0x2B );
+ lcdWriteData( 0x00 );
+ lcdWriteData( 0x00 );
+ lcdWriteData( 0x01 );
+ lcdWriteData( 0x3F );
+
+ // Memory Access Control
+ lcdWriteCommand(0x36);
+ lcdWriteData(0x28); // 0x20 -> swap col/rows
+
+ lcdWriteCommand(0x3A);
+ lcdWriteData(0x66);
+
+ lcdWriteCommand(0xE0);
+ lcdWriteData(0x00);
+ lcdWriteData(0x07);
+ lcdWriteData(0x10);
+ lcdWriteData(0x09);
+ lcdWriteData(0x17);
+ lcdWriteData(0x0B);
+ lcdWriteData(0x41);
+ lcdWriteData(0x89);
+ lcdWriteData(0x4B);
+ lcdWriteData(0x0A);
+ lcdWriteData(0x0C);
+ lcdWriteData(0x0E);
+ lcdWriteData(0x18);
+ lcdWriteData(0x1B);
+ lcdWriteData(0x0F);
+
+ lcdWriteCommand(0xE1);
+ lcdWriteData(0x00);
+ lcdWriteData(0x17);
+ lcdWriteData(0x1A);
+ lcdWriteData(0x04);
+ lcdWriteData(0x0E);
+ lcdWriteData(0x06);
+ lcdWriteData(0x2F);
+ lcdWriteData(0x45);
+ lcdWriteData(0x43);
+ lcdWriteData(0x02);
+ lcdWriteData(0x0A);
+ lcdWriteData(0x09);
+ lcdWriteData(0x32);
+ lcdWriteData(0x36);
+ lcdWriteData(0x0F);
+
+ // Sleep OUT
+ lcdWriteCommand(0x11);
+ delay_ms(120);
+
+ // Display OFF
+ lcdWriteCommand(0x28);
+
+ LCD_ILI9488_On();
+}
+
+void LCD_ILI9488_Off(void) {
+ lcdWriteCommand(0x28);
+}
+
+void LCD_ILI9488_ReadDevice(void) {
+ int Index = 0;
+ int Parameter = 0x80;
+
+ lcdWriteCommand(0xF7);
+ lcdWriteData(0xA9);
+ lcdWriteData(0x51);
+ lcdWriteData(0x2C);
+ lcdWriteData(0x82);
+
+ lcdWriteCommand(0xB0);
+ lcdWriteData(0x80);
+
+ lcdWriteCommand(0xFB);
+ lcdWriteData(Parameter | 0x00);
+ LCD_ReadBuffer[Index++] = LCD_ReadRegister(0xd3);
+
+ //lcdWriteCommand(0X2E);
+ lcdWriteCommand(0xFB);
+ lcdWriteData(Parameter | 0x01); //Parameter2=0x88
+ LCD_ReadBuffer[Index++] = LCD_ReadRegister(0xd3);
+
+ lcdWriteCommand(0XFB);
+ lcdWriteData(Parameter | 0x02); //Parameter2=0x88
+ LCD_ReadBuffer[Index++] = LCD_ReadRegister(0xd3);
+
+ lcdWriteCommand(0XFB);
+ lcdWriteData(Parameter | 0x03); //Parameter2=0x88
+ LCD_ReadBuffer[Index++] = LCD_ReadRegister(0xd3);
+}
+
+unsigned int LCD_ILI9488_ReadID(void) {
+ int ID = 0;
+
+ // Adjust Control 3:
+ // -> DSI write DCS command, use stream packet RGB 666
+ lcdWriteCommand(0xF7);
+ lcdWriteData(0xA9);
+ lcdWriteData(0x51);
+ lcdWriteData(0x2C);
+ lcdWriteData(0x82);
+
+ // Interface Mode Control:
+ // SDA_EN = 1, DIN/SDA pin is used for 3/4 wire serial
+ // interface and SDO pin is not used.
+ lcdWriteCommand(0xB0);
+ lcdWriteData(0x80);
+
+ // first byte is dummy one
+ lcdWriteCommand(0xFB);
+ lcdWriteData(0x80 | 0x00);
+ ID = LCD_ReadRegister(0xd3);
+
+ lcdWriteCommand(0xFB);
+ lcdWriteData(0x80 | 0x01);
+ ID = LCD_ReadRegister(0xd3);
+
+ lcdWriteCommand(0xFB);
+ lcdWriteData(0x80 | 0x02);
+ ID = LCD_ReadRegister(0xd3);
+ ID <<= 8;
+
+ lcdWriteCommand(0xFB);
+ lcdWriteData(0x80 | 0x03);
+ ID |= LCD_ReadRegister(0xd3);
+
+ lcdWriteCommand(0xFB);
+ lcdWriteData(0x00);
+
+ return (ID);
+}
+
+void LCD_ST7796S_On(void) {
+ lcdWriteCommand(0x29);
+}
+
+void LCD_ST7796S_Init(void) {
+ delay_ms(120);
+
+ lcdWriteCommand( 0x11 );
+ delay_ms(120);
+
+ lcdWriteCommand( 0xF0 );
+ lcdWriteData( 0xC3 );
+
+ lcdWriteCommand( 0xF0 );
+ lcdWriteData( 0x96 );
+
+ lcdWriteCommand( 0x36 );
+ lcdWriteData( 0x28 );
+
+ lcdWriteCommand( 0x2A );
+ lcdWriteData( 0x00 );
+ lcdWriteData( 0x00 );
+ lcdWriteData( 0x01 );
+ lcdWriteData( 0xDF );
+ lcdWriteCommand( 0x2B );
+ lcdWriteData( 0x00 );
+ lcdWriteData( 0x00 );
+ lcdWriteData( 0x01 );
+ lcdWriteData( 0x3F );
+
+ lcdWriteCommand( 0x3A );
+ lcdWriteData( 0x66 );
+
+ //SET RGB STRAT
+ lcdWriteCommand (0xB0 ); //SET HS VS DE CLK 上升还是下降有效
+ lcdWriteData( 0x80 );
+
+ lcdWriteCommand( 0xB4 );
+ lcdWriteData( 0x01 );
+
+ lcdWriteCommand( 0xB6 );
+ // lcdWriteData( 0x20 );
+ // lcdWriteData( 0x02 );
+ // lcdWriteData( 0x3B );
+ lcdWriteData( 0x20 );
+ lcdWriteData( 0x02 );
+ lcdWriteData( 0x3B );
+ //SET RGB END
+
+ lcdWriteCommand( 0xB7);
+ lcdWriteData( 0xC6);
+
+ lcdWriteCommand( 0xB9 );
+ lcdWriteData( 0x02 );
+ lcdWriteData( 0xE0 );
+
+ lcdWriteCommand( 0xC0 );
+ lcdWriteData( 0x80 );
+ lcdWriteData( 0x65 );
+
+ lcdWriteCommand( 0xC1 );
+ lcdWriteData( 0x0D );
+
+ lcdWriteCommand( 0xC2 );
+ lcdWriteData( 0xA7 );
+
+ lcdWriteCommand( 0xC5 );
+ lcdWriteData( 0x14 );
+
+ lcdWriteCommand( 0xE8 );
+ lcdWriteData( 0x40 );
+ lcdWriteData( 0x8A );
+ lcdWriteData( 0x00 );
+ lcdWriteData( 0x00 );
+ lcdWriteData( 0x29 );
+ lcdWriteData( 0x19 );
+ lcdWriteData( 0xA5 );
+ lcdWriteData( 0x33 );
+
+ lcdWriteCommand( 0xE0 );
+ lcdWriteData( 0xD0 );
+ lcdWriteData( 0x00 );
+ lcdWriteData( 0x04 );
+ lcdWriteData( 0x05 );
+ lcdWriteData( 0x04 );
+ lcdWriteData( 0x21 );
+ lcdWriteData( 0x25 );
+ lcdWriteData( 0x43 );
+ lcdWriteData( 0x3F );
+ lcdWriteData( 0x37 );
+ lcdWriteData( 0x13 );
+ lcdWriteData( 0x13 );
+ lcdWriteData( 0x29 );
+ lcdWriteData( 0x32 );
+
+ lcdWriteCommand( 0xE1 );
+ lcdWriteData( 0xD0 );
+ lcdWriteData( 0x04 );
+ lcdWriteData( 0x06 );
+ lcdWriteData( 0x09 );
+ lcdWriteData( 0x06 );
+ lcdWriteData( 0x03 );
+ lcdWriteData( 0x25 );
+ lcdWriteData( 0x32 );
+ lcdWriteData( 0x3E );
+ lcdWriteData( 0x18 );
+ lcdWriteData( 0x15 );
+ lcdWriteData( 0x15 );
+ lcdWriteData( 0x2B );
+ lcdWriteData( 0x30 );
+
+ lcdWriteCommand( 0xF0 );
+ lcdWriteData( 0x3C );
+
+ lcdWriteCommand( 0xF0 );
+ lcdWriteData( 0x69 );
+
+ delay_ms(120);
+
+ if( !TouchControllerType ) {
+ lcdWriteCommand( 0x21 );
+ }
+
+ LCD_ST7796S_On();
+}
+
+void LCD_ST7796S_Off(void) {
+ lcdWriteCommand(0x28);
+}
+
+unsigned int LCD_ST7796S_ReadID(void) {
+ lcdReset();
+ unsigned int ID = 0;
+
+ lcdWriteCommand( 0XF0 );
+ lcdWriteData( 0XC3 );
+ lcdWriteCommand( 0XF0 );
+ lcdWriteData( 0X96 );
+
+ lcdWriteCommand( 0XB0 );
+ lcdWriteData( 0X80 );
+
+ lcdWriteCommand( 0XD3 );
+
+ LCD_MOSI_AS_INPUT();
+ LCD_SCK_LOW();
+ lcdDelay();
+ lcdDelay();
+ LCD_SCK_HIGH();
+ lcdDelay();
+ lcdDelay();
+
+ LCD_ReadByte();
+ ID += (uint16_t)(LCD_ReadByte())<<8;
+ ID += LCD_ReadByte();
+
+ return (ID);
+ }
+
+
+unsigned int LCD_NT35310_ReadID( void )
+{
+ unsigned int ID = 0x3531;
+
+ return( ID );
+
+}
+
+void LCD_NT35310_Init( void )
+{
+#if 1
+ lcdWriteCommand(0xED);
+ lcdWriteData(0x01);
+ lcdWriteData(0xFE);
+
+ lcdWriteCommand(0xEE);
+ lcdWriteData(0xDE);
+ lcdWriteData(0x21);
+
+ lcdWriteCommand(0x11);
+ delay_ms(120);
+ lcdWriteCommand(0xB3);
+ lcdWriteData(0x21);
+
+
+
+ lcdWriteCommand(0xC0);
+ lcdWriteData(0x33);
+ lcdWriteData(0x33);
+ lcdWriteData(0x10);
+ lcdWriteData(0x10);
+
+
+ lcdWriteCommand(0xC4);
+ lcdWriteData(0x56); //3a
+
+ lcdWriteCommand(0xBF);
+ lcdWriteData(0xAA);
+
+ lcdWriteCommand(0xB0);
+ lcdWriteData(0x0D);
+ lcdWriteData(0x00);
+ lcdWriteData(0x0D);
+ lcdWriteData(0x00);
+ lcdWriteData(0x11);
+ lcdWriteData(0x00);
+ lcdWriteData(0x19);
+ lcdWriteData(0x00);
+ lcdWriteData(0x21);
+ lcdWriteData(0x00);
+ lcdWriteData(0x2D);
+ lcdWriteData(0x00);
+ lcdWriteData(0x3D);
+ lcdWriteData(0x00);
+ lcdWriteData(0x5D);
+ lcdWriteData(0x00);
+ lcdWriteData(0x5D);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xB1);
+ lcdWriteData(0x80);
+ lcdWriteData(0x00);
+ lcdWriteData(0x8B);
+ lcdWriteData(0x00);
+ lcdWriteData(0x96);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xB2);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x02);
+ lcdWriteData(0x00);
+ lcdWriteData(0x03);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xB3);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xB4);
+ lcdWriteData(0x8B);
+ lcdWriteData(0x00);
+ lcdWriteData(0x96);
+ lcdWriteData(0x00);
+ lcdWriteData(0xA1);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xB5);
+ lcdWriteData(0x02);
+ lcdWriteData(0x00);
+ lcdWriteData(0x03);
+ lcdWriteData(0x00);
+ lcdWriteData(0x04);
+ lcdWriteData(0x00);
+ lcdWriteCommand(0xB6);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xB7);
+ lcdWriteData(0x3E);
+ lcdWriteData(0x00);
+ lcdWriteData(0x5E);
+ lcdWriteData(0x00);
+ lcdWriteData(0x9E);
+ lcdWriteData(0x00);
+ lcdWriteData(0x74);
+ lcdWriteData(0x00);
+ lcdWriteData(0x8C);
+ lcdWriteData(0x00);
+ lcdWriteData(0xAC);
+ lcdWriteData(0x00);
+ lcdWriteData(0xDC);
+ lcdWriteData(0x00);
+ lcdWriteData(0x70);
+ lcdWriteData(0x00);
+ lcdWriteData(0xB9);
+ lcdWriteData(0x00);
+ lcdWriteData(0xEC);
+ lcdWriteData(0x00);
+ lcdWriteData(0xDC);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xB8);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xBA);
+ lcdWriteData(0x24);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xC1);
+ lcdWriteData(0x20);
+ lcdWriteData(0x00);
+ lcdWriteData(0x54);
+ lcdWriteData(0x00);
+ lcdWriteData(0xFF);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xC2);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x04);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xC3);
+ lcdWriteData(0x3C);
+ lcdWriteData(0x00);
+ lcdWriteData(0x3A);
+ lcdWriteData(0x00);
+ lcdWriteData(0x39);
+ lcdWriteData(0x00);
+ lcdWriteData(0x37);
+ lcdWriteData(0x00);
+ lcdWriteData(0x3C);
+ lcdWriteData(0x00);
+ lcdWriteData(0x36);
+ lcdWriteData(0x00);
+ lcdWriteData(0x32);
+ lcdWriteData(0x00);
+ lcdWriteData(0x2F);
+ lcdWriteData(0x00);
+ lcdWriteData(0x2C);
+ lcdWriteData(0x00);
+ lcdWriteData(0x29);
+ lcdWriteData(0x00);
+ lcdWriteData(0x26);
+ lcdWriteData(0x00);
+ lcdWriteData(0x24);
+ lcdWriteData(0x00);
+ lcdWriteData(0x24);
+ lcdWriteData(0x00);
+ lcdWriteData(0x23);
+ lcdWriteData(0x00);
+ lcdWriteData(0x3C);
+ lcdWriteData(0x00);
+ lcdWriteData(0x36);
+ lcdWriteData(0x00);
+ lcdWriteData(0x32);
+ lcdWriteData(0x00);
+ lcdWriteData(0x2F);
+ lcdWriteData(0x00);
+ lcdWriteData(0x2C);
+ lcdWriteData(0x00);
+ lcdWriteData(0x29);
+ lcdWriteData(0x00);
+ lcdWriteData(0x26);
+ lcdWriteData(0x00);
+ lcdWriteData(0x24);
+ lcdWriteData(0x00);
+ lcdWriteData(0x24);
+ lcdWriteData(0x00);
+ lcdWriteData(0x23);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xC4);
+ lcdWriteData(0x62);
+ lcdWriteData(0x00);
+ lcdWriteData(0x05);
+ lcdWriteData(0x00);
+ lcdWriteData(0x84);
+ lcdWriteData(0x00);
+ lcdWriteData(0xF0);
+ lcdWriteData(0x00);
+ lcdWriteData(0x18);
+ lcdWriteData(0x00);
+ lcdWriteData(0xA4);
+ lcdWriteData(0x00);
+ lcdWriteData(0x18);
+ lcdWriteData(0x00);
+ lcdWriteData(0x50);
+ lcdWriteData(0x00);
+ lcdWriteData(0x0C);
+ lcdWriteData(0x00);
+ lcdWriteData(0x17);
+ lcdWriteData(0x00);
+ lcdWriteData(0x95);
+ lcdWriteData(0x00);
+ lcdWriteData(0xF3);
+ lcdWriteData(0x00);
+ lcdWriteData(0xE6);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xC5);
+ lcdWriteData(0x32);
+ lcdWriteData(0x00);
+ lcdWriteData(0x44);
+ lcdWriteData(0x00);
+ lcdWriteData(0x65);
+ lcdWriteData(0x00);
+ lcdWriteData(0x76);
+ lcdWriteData(0x00);
+ lcdWriteData(0x88);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xC6);
+ lcdWriteData(0x20);
+ lcdWriteData(0x00);
+ lcdWriteData(0x17);
+ lcdWriteData(0x00);
+ lcdWriteData(0x01);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xC7);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xC8);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xC9);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xE0);
+ lcdWriteData(0x02);
+ lcdWriteData(0x00);
+ lcdWriteData(0x06);
+ lcdWriteData(0x00);
+ lcdWriteData(0x10);
+ lcdWriteData(0x00);
+ lcdWriteData(0x25);
+ lcdWriteData(0x00);
+ lcdWriteData(0x36);
+ lcdWriteData(0x00);
+ lcdWriteData(0x44);
+ lcdWriteData(0x00);
+ lcdWriteData(0x57);
+ lcdWriteData(0x00);
+ lcdWriteData(0x6F);
+ lcdWriteData(0x00);
+ lcdWriteData(0x7F);
+ lcdWriteData(0x00);
+ lcdWriteData(0x8C);
+ lcdWriteData(0x00);
+ lcdWriteData(0x98);
+ lcdWriteData(0x00);
+ lcdWriteData(0xA6);
+ lcdWriteData(0x00);
+ lcdWriteData(0xAE);
+ lcdWriteData(0x00);
+ lcdWriteData(0xB4);
+ lcdWriteData(0x00);
+ lcdWriteData(0xBB);
+ lcdWriteData(0x00);
+ lcdWriteData(0xC0);
+ lcdWriteData(0x00);
+ lcdWriteData(0xC9);
+ lcdWriteData(0x00);
+ lcdWriteData(0xF3);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xE1);
+ lcdWriteData(0x01);
+ lcdWriteData(0x00);
+ lcdWriteData(0x05);
+ lcdWriteData(0x00);
+ lcdWriteData(0x10);
+ lcdWriteData(0x00);
+ lcdWriteData(0x25);
+ lcdWriteData(0x00);
+ lcdWriteData(0x36);
+ lcdWriteData(0x00);
+ lcdWriteData(0x44);
+ lcdWriteData(0x00);
+ lcdWriteData(0x57);
+ lcdWriteData(0x00);
+ lcdWriteData(0x6F);
+ lcdWriteData(0x00);
+ lcdWriteData(0x7F);
+ lcdWriteData(0x00);
+ lcdWriteData(0x8C);
+ lcdWriteData(0x00);
+ lcdWriteData(0x98);
+ lcdWriteData(0x00);
+ lcdWriteData(0xA6);
+ lcdWriteData(0x00);
+ lcdWriteData(0xAE);
+ lcdWriteData(0x00);
+ lcdWriteData(0xB4);
+ lcdWriteData(0x00);
+ lcdWriteData(0xBB);
+ lcdWriteData(0x00);
+ lcdWriteData(0xC0);
+ lcdWriteData(0x00);
+ lcdWriteData(0xC9);
+ lcdWriteData(0x00);
+ lcdWriteData(0xF3);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xE2);
+ lcdWriteData(0x02);
+ lcdWriteData(0x00);
+ lcdWriteData(0x06);
+ lcdWriteData(0x00);
+ lcdWriteData(0x10);
+ lcdWriteData(0x00);
+ lcdWriteData(0x25);
+ lcdWriteData(0x00);
+ lcdWriteData(0x36);
+ lcdWriteData(0x00);
+ lcdWriteData(0x44);
+ lcdWriteData(0x00);
+ lcdWriteData(0x57);
+ lcdWriteData(0x00);
+ lcdWriteData(0x6F);
+ lcdWriteData(0x00);
+ lcdWriteData(0x7F);
+ lcdWriteData(0x00);
+ lcdWriteData(0x8C);
+ lcdWriteData(0x00);
+ lcdWriteData(0x98);
+ lcdWriteData(0x00);
+ lcdWriteData(0xA6);
+ lcdWriteData(0x00);
+ lcdWriteData(0xAE);
+ lcdWriteData(0x00);
+ lcdWriteData(0xB4);
+ lcdWriteData(0x00);
+ lcdWriteData(0xBB);
+ lcdWriteData(0x00);
+ lcdWriteData(0xC0);
+ lcdWriteData(0x00);
+ lcdWriteData(0xC9);
+ lcdWriteData(0x00);
+ lcdWriteData(0xF3);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xE3);
+ lcdWriteData(0x01);
+ lcdWriteData(0x00);
+ lcdWriteData(0x05);
+ lcdWriteData(0x00);
+ lcdWriteData(0x10);
+ lcdWriteData(0x00);
+ lcdWriteData(0x25);
+ lcdWriteData(0x00);
+ lcdWriteData(0x36);
+ lcdWriteData(0x00);
+ lcdWriteData(0x44);
+ lcdWriteData(0x00);
+ lcdWriteData(0x57);
+ lcdWriteData(0x00);
+ lcdWriteData(0x6F);
+ lcdWriteData(0x00);
+ lcdWriteData(0x7F);
+ lcdWriteData(0x00);
+ lcdWriteData(0x8C);
+ lcdWriteData(0x00);
+ lcdWriteData(0x98);
+ lcdWriteData(0x00);
+ lcdWriteData(0xA6);
+ lcdWriteData(0x00);
+ lcdWriteData(0xAE);
+ lcdWriteData(0x00);
+ lcdWriteData(0xB4);
+ lcdWriteData(0x00);
+ lcdWriteData(0xBB);
+ lcdWriteData(0x00);
+ lcdWriteData(0xC0);
+ lcdWriteData(0x00);
+ lcdWriteData(0xC9);
+ lcdWriteData(0x00);
+ lcdWriteData(0xF3);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xE4);
+ lcdWriteData(0x02);
+ lcdWriteData(0x00);
+ lcdWriteData(0x06);
+ lcdWriteData(0x00);
+ lcdWriteData(0x10);
+ lcdWriteData(0x00);
+ lcdWriteData(0x25);
+ lcdWriteData(0x00);
+ lcdWriteData(0x36);
+ lcdWriteData(0x00);
+ lcdWriteData(0x44);
+ lcdWriteData(0x00);
+ lcdWriteData(0x57);
+ lcdWriteData(0x00);
+ lcdWriteData(0x6F);
+ lcdWriteData(0x00);
+ lcdWriteData(0x7F);
+ lcdWriteData(0x00);
+ lcdWriteData(0x8C);
+ lcdWriteData(0x00);
+ lcdWriteData(0x98);
+ lcdWriteData(0x00);
+ lcdWriteData(0xA6);
+ lcdWriteData(0x00);
+ lcdWriteData(0xAE);
+ lcdWriteData(0x00);
+ lcdWriteData(0xB4);
+ lcdWriteData(0x00);
+ lcdWriteData(0xBB);
+ lcdWriteData(0x00);
+ lcdWriteData(0xC0);
+ lcdWriteData(0x00);
+ lcdWriteData(0xC9);
+ lcdWriteData(0x00);
+ lcdWriteData(0xF3);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xE5);
+ lcdWriteData(0x01);
+ lcdWriteData(0x00);
+ lcdWriteData(0x05);
+ lcdWriteData(0x00);
+ lcdWriteData(0x10);
+ lcdWriteData(0x00);
+ lcdWriteData(0x25);
+ lcdWriteData(0x00);
+ lcdWriteData(0x36);
+ lcdWriteData(0x00);
+ lcdWriteData(0x44);
+ lcdWriteData(0x00);
+ lcdWriteData(0x57);
+ lcdWriteData(0x00);
+ lcdWriteData(0x6F);
+ lcdWriteData(0x00);
+ lcdWriteData(0x7F);
+ lcdWriteData(0x00);
+ lcdWriteData(0x8C);
+ lcdWriteData(0x00);
+ lcdWriteData(0x98);
+ lcdWriteData(0x00);
+ lcdWriteData(0xA6);
+ lcdWriteData(0x00);
+ lcdWriteData(0xAE);
+ lcdWriteData(0x00);
+ lcdWriteData(0xB4);
+ lcdWriteData(0x00);
+ lcdWriteData(0xBB);
+ lcdWriteData(0x00);
+ lcdWriteData(0xC0);
+ lcdWriteData(0x00);
+ lcdWriteData(0xC9);
+ lcdWriteData(0x00);
+ lcdWriteData(0xF3);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xE6);
+ lcdWriteData(0x55);
+ lcdWriteData(0x00);
+ lcdWriteData(0x66);
+ lcdWriteData(0x00);
+ lcdWriteData(0x56);
+ lcdWriteData(0x00);
+ lcdWriteData(0x66);
+ lcdWriteData(0x00);
+ lcdWriteData(0x57);
+ lcdWriteData(0x00);
+ lcdWriteData(0x66);
+ lcdWriteData(0x00);
+ lcdWriteData(0x77);
+ lcdWriteData(0x00);
+ lcdWriteData(0x66);
+ lcdWriteData(0x00);
+ lcdWriteData(0x44);
+ lcdWriteData(0x00);
+ lcdWriteData(0x33);
+ lcdWriteData(0x00);
+ lcdWriteData(0x44);
+ lcdWriteData(0x00);
+ lcdWriteData(0x33);
+ lcdWriteData(0x00);
+ lcdWriteData(0x33);
+ lcdWriteData(0x00);
+ lcdWriteData(0x23);
+ lcdWriteData(0x00);
+ lcdWriteData(0x23);
+ lcdWriteData(0x00);
+ lcdWriteData(0x65);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xE7);
+ lcdWriteData(0x55);
+ lcdWriteData(0x00);
+ lcdWriteData(0x66);
+ lcdWriteData(0x00);
+ lcdWriteData(0x56);
+ lcdWriteData(0x00);
+ lcdWriteData(0x66);
+ lcdWriteData(0x00);
+ lcdWriteData(0x57);
+ lcdWriteData(0x00);
+ lcdWriteData(0x66);
+ lcdWriteData(0x00);
+ lcdWriteData(0x77);
+ lcdWriteData(0x00);
+ lcdWriteData(0x66);
+ lcdWriteData(0x00);
+ lcdWriteData(0x44);
+ lcdWriteData(0x00);
+ lcdWriteData(0x33);
+ lcdWriteData(0x00);
+ lcdWriteData(0x44);
+ lcdWriteData(0x00);
+ lcdWriteData(0x33);
+ lcdWriteData(0x00);
+ lcdWriteData(0x33);
+ lcdWriteData(0x00);
+ lcdWriteData(0x23);
+ lcdWriteData(0x00);
+ lcdWriteData(0x23);
+ lcdWriteData(0x00);
+ lcdWriteData(0x65);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xE8);
+ lcdWriteData(0x55);
+ lcdWriteData(0x00);
+ lcdWriteData(0x66);
+ lcdWriteData(0x00);
+ lcdWriteData(0x56);
+ lcdWriteData(0x00);
+ lcdWriteData(0x66);
+ lcdWriteData(0x00);
+ lcdWriteData(0x57);
+ lcdWriteData(0x00);
+ lcdWriteData(0x66);
+ lcdWriteData(0x00);
+ lcdWriteData(0x77);
+ lcdWriteData(0x00);
+ lcdWriteData(0x66);
+ lcdWriteData(0x00);
+ lcdWriteData(0x44);
+ lcdWriteData(0x00);
+ lcdWriteData(0x33);
+ lcdWriteData(0x00);
+ lcdWriteData(0x44);
+ lcdWriteData(0x00);
+ lcdWriteData(0x33);
+ lcdWriteData(0x00);
+ lcdWriteData(0x33);
+ lcdWriteData(0x00);
+ lcdWriteData(0x23);
+ lcdWriteData(0x00);
+ lcdWriteData(0x23);
+ lcdWriteData(0x00);
+ lcdWriteData(0x65);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xE9);
+ lcdWriteData(0xAA);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0x00);
+ lcdWriteData(0xAA);
+
+ lcdWriteCommand(0xCF);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xF0);
+ lcdWriteData(0x00);
+ lcdWriteData(0x50);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xF1);
+ lcdWriteData(0x01);
+
+ lcdWriteCommand(0xF9);
+ lcdWriteData(0x06);
+ lcdWriteData(0x10);
+ lcdWriteData(0x29);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xDF);
+ lcdWriteData(0x10);
+ delay_ms(20);
+ lcdWriteCommand(0x36);
+// if( IsHorizontal )
+// lcdWriteData(0x00);//需修改
+// else
+ lcdWriteData(0x14);
+
+ lcdWriteCommand(0x3A);
+ lcdWriteData(0x66);
+
+ lcdWriteCommand(0x21);
+
+ lcdWriteCommand(0x35);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0x29);
+#else
+ lcdWriteCommand(0xED);
+ lcdWriteData(0x01);
+ lcdWriteData(0xFE);
+
+ lcdWriteCommand(0xEE);
+ lcdWriteData(0xDE);
+ lcdWriteData(0x21);
+
+ lcdWriteCommand(0x11);
+ SYSTEM_DelayMS(120);
+ lcdWriteCommand(0xB3);
+ lcdWriteData(0x21);
+
+
+ lcdWriteCommand(0xc0);
+ lcdWriteData(0x56);
+ lcdWriteData(0x56);
+ lcdWriteData(0x24);
+ lcdWriteData(0x24);
+
+ lcdWriteCommand(0xC4);
+ lcdWriteData(0x30); //3a
+
+ lcdWriteCommand(0xBF);
+ lcdWriteData(0xAA);
+
+ lcdWriteCommand(0xB0);
+ lcdWriteData(0x0D);
+ lcdWriteData(0x00);
+ lcdWriteData(0x0D);
+ lcdWriteData(0x00);
+ lcdWriteData(0x11);
+ lcdWriteData(0x00);
+ lcdWriteData(0x19);
+ lcdWriteData(0x00);
+ lcdWriteData(0x21);
+ lcdWriteData(0x00);
+ lcdWriteData(0x2D);
+ lcdWriteData(0x00);
+ lcdWriteData(0x3D);
+ lcdWriteData(0x00);
+ lcdWriteData(0x5D);
+ lcdWriteData(0x00);
+ lcdWriteData(0x5D);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xB1);
+ lcdWriteData(0x80);
+ lcdWriteData(0x00);
+ lcdWriteData(0x8B);
+ lcdWriteData(0x00);
+ lcdWriteData(0x96);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xB2);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x02);
+ lcdWriteData(0x00);
+ lcdWriteData(0x03);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xB3);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xB4);
+ lcdWriteData(0x8B);
+ lcdWriteData(0x00);
+ lcdWriteData(0x96);
+ lcdWriteData(0x00);
+ lcdWriteData(0xA1);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xB5);
+ lcdWriteData(0x02);
+ lcdWriteData(0x00);
+ lcdWriteData(0x03);
+ lcdWriteData(0x00);
+ lcdWriteData(0x04);
+ lcdWriteData(0x00);
+ lcdWriteCommand(0xB6);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xB7);
+ lcdWriteData(0x3E);
+ lcdWriteData(0x00);
+ lcdWriteData(0x5E);
+ lcdWriteData(0x00);
+ lcdWriteData(0x9E);
+ lcdWriteData(0x00);
+ lcdWriteData(0x74);
+ lcdWriteData(0x00);
+ lcdWriteData(0x8C);
+ lcdWriteData(0x00);
+ lcdWriteData(0xAC);
+ lcdWriteData(0x00);
+ lcdWriteData(0xDC);
+ lcdWriteData(0x00);
+ lcdWriteData(0x70);
+ lcdWriteData(0x00);
+ lcdWriteData(0xB9);
+ lcdWriteData(0x00);
+ lcdWriteData(0xEC);
+ lcdWriteData(0x00);
+ lcdWriteData(0xDC);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xB8);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xBA);
+ lcdWriteData(0x24);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xC1);
+ lcdWriteData(0x20);
+ lcdWriteData(0x00);
+ lcdWriteData(0x54);
+ lcdWriteData(0x00);
+ lcdWriteData(0xFF);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xC2);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x04);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xC3);
+ lcdWriteData(0x3C);
+ lcdWriteData(0x00);
+ lcdWriteData(0x3A);
+ lcdWriteData(0x00);
+ lcdWriteData(0x39);
+ lcdWriteData(0x00);
+ lcdWriteData(0x37);
+ lcdWriteData(0x00);
+ lcdWriteData(0x3C);
+ lcdWriteData(0x00);
+ lcdWriteData(0x36);
+ lcdWriteData(0x00);
+ lcdWriteData(0x32);
+ lcdWriteData(0x00);
+ lcdWriteData(0x2F);
+ lcdWriteData(0x00);
+ lcdWriteData(0x2C);
+ lcdWriteData(0x00);
+ lcdWriteData(0x29);
+ lcdWriteData(0x00);
+ lcdWriteData(0x26);
+ lcdWriteData(0x00);
+ lcdWriteData(0x24);
+ lcdWriteData(0x00);
+ lcdWriteData(0x24);
+ lcdWriteData(0x00);
+ lcdWriteData(0x23);
+ lcdWriteData(0x00);
+ lcdWriteData(0x3C);
+ lcdWriteData(0x00);
+ lcdWriteData(0x36);
+ lcdWriteData(0x00);
+ lcdWriteData(0x32);
+ lcdWriteData(0x00);
+ lcdWriteData(0x2F);
+ lcdWriteData(0x00);
+ lcdWriteData(0x2C);
+ lcdWriteData(0x00);
+ lcdWriteData(0x29);
+ lcdWriteData(0x00);
+ lcdWriteData(0x26);
+ lcdWriteData(0x00);
+ lcdWriteData(0x24);
+ lcdWriteData(0x00);
+ lcdWriteData(0x24);
+ lcdWriteData(0x00);
+ lcdWriteData(0x23);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xC4);
+ lcdWriteData(0x62);
+ lcdWriteData(0x00);
+ lcdWriteData(0x05);
+ lcdWriteData(0x00);
+ lcdWriteData(0x84);
+ lcdWriteData(0x00);
+ lcdWriteData(0xF0);
+ lcdWriteData(0x00);
+ lcdWriteData(0x18);
+ lcdWriteData(0x00);
+ lcdWriteData(0xA4);
+ lcdWriteData(0x00);
+ lcdWriteData(0x18);
+ lcdWriteData(0x00);
+ lcdWriteData(0x50);
+ lcdWriteData(0x00);
+ lcdWriteData(0x0C);
+ lcdWriteData(0x00);
+ lcdWriteData(0x17);
+ lcdWriteData(0x00);
+ lcdWriteData(0x95);
+ lcdWriteData(0x00);
+ lcdWriteData(0xF3);
+ lcdWriteData(0x00);
+ lcdWriteData(0xE6);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xC5);
+ lcdWriteData(0x32);
+ lcdWriteData(0x00);
+ lcdWriteData(0x44);
+ lcdWriteData(0x00);
+ lcdWriteData(0x65);
+ lcdWriteData(0x00);
+ lcdWriteData(0x76);
+ lcdWriteData(0x00);
+ lcdWriteData(0x88);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xC6);
+ lcdWriteData(0x20);
+ lcdWriteData(0x00);
+ lcdWriteData(0x17);
+ lcdWriteData(0x00);
+ lcdWriteData(0x01);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xC7);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xC8);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xC9);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xE0);
+ lcdWriteData(0x01);
+ lcdWriteData(0x00);
+ lcdWriteData(0x1F);
+ lcdWriteData(0x00);
+ lcdWriteData(0x3C);
+ lcdWriteData(0x00);
+ lcdWriteData(0x59);
+ lcdWriteData(0x00);
+ lcdWriteData(0x67);
+ lcdWriteData(0x00);
+ lcdWriteData(0x72);
+ lcdWriteData(0x00);
+ lcdWriteData(0x82);
+ lcdWriteData(0x00);
+ lcdWriteData(0x93);
+ lcdWriteData(0x00);
+ lcdWriteData(0xA0);
+ lcdWriteData(0x00);
+ lcdWriteData(0xAB);
+ lcdWriteData(0x00);
+ lcdWriteData(0xB4);
+ lcdWriteData(0x00);
+ lcdWriteData(0xBF);
+ lcdWriteData(0x00);
+ lcdWriteData(0xC6);
+ lcdWriteData(0x00);
+ lcdWriteData(0xCA);
+ lcdWriteData(0x00);
+ lcdWriteData(0xCF);
+ lcdWriteData(0x00);
+ lcdWriteData(0xD3);
+ lcdWriteData(0x00);
+ lcdWriteData(0xDA);
+ lcdWriteData(0x00);
+ lcdWriteData(0xF3);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xE1);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x1F);
+ lcdWriteData(0x00);
+ lcdWriteData(0x3C);
+ lcdWriteData(0x00);
+ lcdWriteData(0x59);
+ lcdWriteData(0x00);
+ lcdWriteData(0x67);
+ lcdWriteData(0x00);
+ lcdWriteData(0x72);
+ lcdWriteData(0x00);
+ lcdWriteData(0x82);
+ lcdWriteData(0x00);
+ lcdWriteData(0x93);
+ lcdWriteData(0x00);
+ lcdWriteData(0xA0);
+ lcdWriteData(0x00);
+ lcdWriteData(0xAB);
+ lcdWriteData(0x00);
+ lcdWriteData(0xB4);
+ lcdWriteData(0x00);
+ lcdWriteData(0xBF);
+ lcdWriteData(0x00);
+ lcdWriteData(0xC6);
+ lcdWriteData(0x00);
+ lcdWriteData(0xCA);
+ lcdWriteData(0x00);
+ lcdWriteData(0xD0);
+ lcdWriteData(0x00);
+ lcdWriteData(0xD4);
+ lcdWriteData(0x00);
+ lcdWriteData(0xD9);
+ lcdWriteData(0x00);
+ lcdWriteData(0xF3);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xE2);
+ lcdWriteData(0x10);
+ lcdWriteData(0x00);
+ lcdWriteData(0x1F);
+ lcdWriteData(0x00);
+ lcdWriteData(0x3C);
+ lcdWriteData(0x00);
+ lcdWriteData(0x59);
+ lcdWriteData(0x00);
+ lcdWriteData(0x67);
+ lcdWriteData(0x00);
+ lcdWriteData(0x72);
+ lcdWriteData(0x00);
+ lcdWriteData(0x82);
+ lcdWriteData(0x00);
+ lcdWriteData(0x93);
+ lcdWriteData(0x00);
+ lcdWriteData(0xA0);
+ lcdWriteData(0x00);
+ lcdWriteData(0xAB);
+ lcdWriteData(0x00);
+ lcdWriteData(0xB4);
+ lcdWriteData(0x00);
+ lcdWriteData(0xBF);
+ lcdWriteData(0x00);
+ lcdWriteData(0xC6);
+ lcdWriteData(0x00);
+ lcdWriteData(0xCA);
+ lcdWriteData(0x00);
+ lcdWriteData(0xCF);
+ lcdWriteData(0x00);
+ lcdWriteData(0xD3);
+ lcdWriteData(0x00);
+ lcdWriteData(0xDA);
+ lcdWriteData(0x00);
+ lcdWriteData(0xF3);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xE3);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x1F);
+ lcdWriteData(0x00);
+ lcdWriteData(0x3C);
+ lcdWriteData(0x00);
+ lcdWriteData(0x59);
+ lcdWriteData(0x00);
+ lcdWriteData(0x67);
+ lcdWriteData(0x00);
+ lcdWriteData(0x72);
+ lcdWriteData(0x00);
+ lcdWriteData(0x82);
+ lcdWriteData(0x00);
+ lcdWriteData(0x93);
+ lcdWriteData(0x00);
+ lcdWriteData(0xA0);
+ lcdWriteData(0x00);
+ lcdWriteData(0xAB);
+ lcdWriteData(0x00);
+ lcdWriteData(0xB4);
+ lcdWriteData(0x00);
+ lcdWriteData(0xBF);
+ lcdWriteData(0x00);
+ lcdWriteData(0xC6);
+ lcdWriteData(0x00);
+ lcdWriteData(0xCA);
+ lcdWriteData(0x00);
+ lcdWriteData(0xD0);
+ lcdWriteData(0x00);
+ lcdWriteData(0xD4);
+ lcdWriteData(0x00);
+ lcdWriteData(0xD9);
+ lcdWriteData(0x00);
+ lcdWriteData(0xF3);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xE4);
+ lcdWriteData(0x01);
+ lcdWriteData(0x00);
+ lcdWriteData(0x1F);
+ lcdWriteData(0x00);
+ lcdWriteData(0x3C);
+ lcdWriteData(0x00);
+ lcdWriteData(0x59);
+ lcdWriteData(0x00);
+ lcdWriteData(0x67);
+ lcdWriteData(0x00);
+ lcdWriteData(0x72);
+ lcdWriteData(0x00);
+ lcdWriteData(0x82);
+ lcdWriteData(0x00);
+ lcdWriteData(0x93);
+ lcdWriteData(0x00);
+ lcdWriteData(0xA0);
+ lcdWriteData(0x00);
+ lcdWriteData(0xAB);
+ lcdWriteData(0x00);
+ lcdWriteData(0xB4);
+ lcdWriteData(0x00);
+ lcdWriteData(0xBF);
+ lcdWriteData(0x00);
+ lcdWriteData(0xC6);
+ lcdWriteData(0x00);
+ lcdWriteData(0xCA);
+ lcdWriteData(0x00);
+ lcdWriteData(0xCF);
+ lcdWriteData(0x00);
+ lcdWriteData(0xD3);
+ lcdWriteData(0x00);
+ lcdWriteData(0xDA);
+ lcdWriteData(0x00);
+ lcdWriteData(0xF3);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xE5);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x1F);
+ lcdWriteData(0x00);
+ lcdWriteData(0x3C);
+ lcdWriteData(0x00);
+ lcdWriteData(0x59);
+ lcdWriteData(0x00);
+ lcdWriteData(0x67);
+ lcdWriteData(0x00);
+ lcdWriteData(0x72);
+ lcdWriteData(0x00);
+ lcdWriteData(0x82);
+ lcdWriteData(0x00);
+ lcdWriteData(0x93);
+ lcdWriteData(0x00);
+ lcdWriteData(0xA0);
+ lcdWriteData(0x00);
+ lcdWriteData(0xAB);
+ lcdWriteData(0x00);
+ lcdWriteData(0xB4);
+ lcdWriteData(0x00);
+ lcdWriteData(0xBF);
+ lcdWriteData(0x00);
+ lcdWriteData(0xC6);
+ lcdWriteData(0x00);
+ lcdWriteData(0xCA);
+ lcdWriteData(0x00);
+ lcdWriteData(0xD0);
+ lcdWriteData(0x00);
+ lcdWriteData(0xD4);
+ lcdWriteData(0x00);
+ lcdWriteData(0xD9);
+ lcdWriteData(0x00);
+ lcdWriteData(0xF3);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xE6);
+ lcdWriteData(0x55);
+ lcdWriteData(0x00);
+ lcdWriteData(0x66);
+ lcdWriteData(0x00);
+ lcdWriteData(0x56);
+ lcdWriteData(0x00);
+ lcdWriteData(0x66);
+ lcdWriteData(0x00);
+ lcdWriteData(0x57);
+ lcdWriteData(0x00);
+ lcdWriteData(0x66);
+ lcdWriteData(0x00);
+ lcdWriteData(0x77);
+ lcdWriteData(0x00);
+ lcdWriteData(0x66);
+ lcdWriteData(0x00);
+ lcdWriteData(0x44);
+ lcdWriteData(0x00);
+ lcdWriteData(0x33);
+ lcdWriteData(0x00);
+ lcdWriteData(0x44);
+ lcdWriteData(0x00);
+ lcdWriteData(0x33);
+ lcdWriteData(0x00);
+ lcdWriteData(0x33);
+ lcdWriteData(0x00);
+ lcdWriteData(0x23);
+ lcdWriteData(0x00);
+ lcdWriteData(0x23);
+ lcdWriteData(0x00);
+ lcdWriteData(0x65);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xE7);
+ lcdWriteData(0x55);
+ lcdWriteData(0x00);
+ lcdWriteData(0x66);
+ lcdWriteData(0x00);
+ lcdWriteData(0x56);
+ lcdWriteData(0x00);
+ lcdWriteData(0x66);
+ lcdWriteData(0x00);
+ lcdWriteData(0x57);
+ lcdWriteData(0x00);
+ lcdWriteData(0x66);
+ lcdWriteData(0x00);
+ lcdWriteData(0x77);
+ lcdWriteData(0x00);
+ lcdWriteData(0x66);
+ lcdWriteData(0x00);
+ lcdWriteData(0x44);
+ lcdWriteData(0x00);
+ lcdWriteData(0x33);
+ lcdWriteData(0x00);
+ lcdWriteData(0x44);
+ lcdWriteData(0x00);
+ lcdWriteData(0x33);
+ lcdWriteData(0x00);
+ lcdWriteData(0x33);
+ lcdWriteData(0x00);
+ lcdWriteData(0x23);
+ lcdWriteData(0x00);
+ lcdWriteData(0x23);
+ lcdWriteData(0x00);
+ lcdWriteData(0x65);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xE8);
+ lcdWriteData(0x55);
+ lcdWriteData(0x00);
+ lcdWriteData(0x66);
+ lcdWriteData(0x00);
+ lcdWriteData(0x56);
+ lcdWriteData(0x00);
+ lcdWriteData(0x66);
+ lcdWriteData(0x00);
+ lcdWriteData(0x57);
+ lcdWriteData(0x00);
+ lcdWriteData(0x66);
+ lcdWriteData(0x00);
+ lcdWriteData(0x77);
+ lcdWriteData(0x00);
+ lcdWriteData(0x66);
+ lcdWriteData(0x00);
+ lcdWriteData(0x44);
+ lcdWriteData(0x00);
+ lcdWriteData(0x33);
+ lcdWriteData(0x00);
+ lcdWriteData(0x44);
+ lcdWriteData(0x00);
+ lcdWriteData(0x33);
+ lcdWriteData(0x00);
+ lcdWriteData(0x33);
+ lcdWriteData(0x00);
+ lcdWriteData(0x23);
+ lcdWriteData(0x00);
+ lcdWriteData(0x23);
+ lcdWriteData(0x00);
+ lcdWriteData(0x65);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xE9);
+ lcdWriteData(0xAA);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0x00);
+ lcdWriteData(0xAA);
+
+ lcdWriteCommand(0xCF);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xF0);
+ lcdWriteData(0x00);
+ lcdWriteData(0x50);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xF1);
+ lcdWriteData(0x01);
+
+ lcdWriteCommand(0xee);
+ lcdWriteData(0xde);
+ lcdWriteData(0x21);
+
+ lcdWriteCommand(0xF3);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xF9);
+ lcdWriteData(0x06);
+ lcdWriteData(0x10);
+ lcdWriteData(0x29);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0xDF);
+ lcdWriteData(0x10);
+ SYSTEM_DelayMS(20);
+ lcdWriteCommand(0x36);
+ if( IsHorizontal )
+ lcdWriteData(0x14);//需修改
+ else
+ lcdWriteData(0x14);
+
+ lcdWriteCommand(0x3A);
+ lcdWriteData(0x66);
+
+ lcdWriteCommand(0x21);
+
+ lcdWriteCommand(0x35);
+ lcdWriteData(0x00);
+
+ lcdWriteCommand(0x28);
+#endif
+}
+
+void LCD_NT35310_On( void )
+{
+ lcdWriteCommand( 0x29 );
+}
+
+void LCD_NT35310_Off( void )
+{
+ lcdWriteCommand( 0x28 );
+}
+
+void LCD_Init_LTDC() {
+ hltdc.Instance = LTDC;
+
+ /* Configure PLLSAI prescalers for LCD */
+ /* PLLSAI_VCO Input = HSE_VALUE/PLL_M = 1 Mhz */
+ /* PLLSAI_VCO Output = PLLSAI_VCO Input * lcdPixelclock * 16 = XX Mhz */
+ /* PLLLCDCLK = PLLSAI_VCO Output/PLL_LTDC = PLLSAI_VCO/4 = YY Mhz */
+ /* LTDC clock frequency = PLLLCDCLK / RCC_PLLSAIDivR = YY/4 = lcdPixelClock Mhz */
+ uint32_t clock = (lcdPixelClock*16) / 1000000; // clock*16 in MHz
+ RCC_PeriphCLKInitTypeDef clkConfig;
+ clkConfig.PeriphClockSelection = RCC_PERIPHCLK_LTDC;
+ clkConfig.PLLSAI.PLLSAIN = clock;
+ clkConfig.PLLSAI.PLLSAIR = 4;
+ clkConfig.PLLSAIDivQ = 6;
+ clkConfig.PLLSAIDivR = RCC_PLLSAIDIVR_4;
+ HAL_RCCEx_PeriphCLKConfig(&clkConfig);
+
+ /* LTDC Configuration *********************************************************/
+ /* Polarity configuration */
+ /* Initialize the horizontal synchronization polarity as active low */
+ hltdc.Init.HSPolarity = LTDC_HSPOLARITY_AL;
+ /* Initialize the vertical synchronization polarity as active low */
+ hltdc.Init.VSPolarity = LTDC_VSPOLARITY_AL;
+ /* Initialize the data enable polarity as active low */
+ hltdc.Init.DEPolarity = LTDC_DEPOLARITY_AL;
+ /* Initialize the pixel clock polarity as input pixel clock */
+ hltdc.Init.PCPolarity = LTDC_PCPOLARITY_IIPC;
+
+ /* Configure R,G,B component values for LCD background color */
+ hltdc.Init.Backcolor.Red = 0;
+ hltdc.Init.Backcolor.Green = 0;
+ hltdc.Init.Backcolor.Blue = 0;
+
+ /* Configure horizontal synchronization width */
+ hltdc.Init.HorizontalSync = HSW;
+ /* Configure vertical synchronization height */
+ hltdc.Init.VerticalSync = VSH;
+ /* Configure accumulated horizontal back porch */
+ hltdc.Init.AccumulatedHBP = HBP;
+ /* Configure accumulated vertical back porch */
+ hltdc.Init.AccumulatedVBP = VBP;
+ /* Configure accumulated active width */
+ hltdc.Init.AccumulatedActiveW = lcd_phys_w + HBP;
+ /* Configure accumulated active height */
+ hltdc.Init.AccumulatedActiveH = lcd_phys_h + VBP;
+ /* Configure total width */
+ hltdc.Init.TotalWidth = lcd_phys_w + HBP + HFP;
+ /* Configure total height */
+ hltdc.Init.TotalHeigh = lcd_phys_h + VBP + VFP;
+
+ HAL_LTDC_Init(&hltdc);
+
+ // Configure IRQ (line)
+ NVIC_SetPriority(LTDC_IRQn, LTDC_IRQ_PRIO);
+ NVIC_EnableIRQ(LTDC_IRQn);
+
+ // Trigger on last line
+ HAL_LTDC_ProgramLineEvent(&hltdc, lcd_phys_h);
+ __HAL_LTDC_ENABLE_IT(&hltdc, LTDC_IT_LI);
+}
+
+void LCD_LayerInit() {
+ auto& layer = hltdc.LayerCfg[0];
+
+ /* Windowing configuration */
+ layer.WindowX0 = 0;
+ layer.WindowX1 = lcd_phys_w;
+ layer.WindowY0 = 0;
+ layer.WindowY1 = lcd_phys_h;
+
+ /* Pixel Format configuration*/
+ layer.PixelFormat = LTDC_PIXEL_FORMAT_RGB565;
+
+ /* Alpha constant (255 totally opaque) */
+ layer.Alpha = 255;
+
+ /* Default Color configuration (configure A,R,G,B component values) */
+ layer.Backcolor.Blue = 0;
+ layer.Backcolor.Green = 0;
+ layer.Backcolor.Red = 0;
+ layer.Alpha0 = 0;
+
+ /* Configure blending factors */
+ layer.BlendingFactor1 = LTDC_BLENDING_FACTOR1_CA;
+ layer.BlendingFactor2 = LTDC_BLENDING_FACTOR2_CA;
+
+ layer.ImageWidth = lcd_phys_w;
+ layer.ImageHeight = lcd_phys_h;
+
+ /* Start Address configuration : the LCD Frame buffer is defined on SDRAM w/ Offset */
+ layer.FBStartAdress = (intptr_t)initialFrameBuffer;
+
+ /* Initialize LTDC layer 1 */
+ HAL_LTDC_ConfigLayer(&hltdc, &hltdc.LayerCfg[0], 0);
+
+ /* dithering activation */
+ HAL_LTDC_EnableDither(&hltdc);
+}
+
+extern "C"
+void lcdSetInitalFrameBuffer(void* fbAddress)
+{
+ initialFrameBuffer = fbAddress;
+}
+
+const char* boardLcdType = "";
+
+extern "C"
+void lcdInit(void)
+{
+ /* Configure the LCD SPI+RESET pins */
+ lcdSpiConfig();
+
+ /* Reset the LCD --------------------------------------------------------*/
+ lcdReset();
+
+ /* Configure the LCD Control pins */
+ LCD_AF_GPIOConfig();
+
+ /* Send LCD initialization commands */
+ if (LCD_ILI9481_ReadID() == LCD_ILI9481_ID) {
+ TRACE("LCD INIT: ILI9481");
+ boardLcdType = "ILI9481";
+ lcdInitFunction = LCD_ILI9481_Init;
+ lcdOffFunction = LCD_ILI9481_Off;
+ lcdOnFunction = LCD_ILI9481_On;
+ lcdPixelClock = 12000000;
+ } else if (LCD_ILI9486_ReadID() == LCD_ILI9486_ID) {
+ TRACE("LCD INIT: ILI9486");
+ boardLcdType = "ILI9486";
+ lcdInitFunction = LCD_ILI9486_Init;
+ lcdOffFunction = LCD_ILI9486_Off;
+ lcdOnFunction = LCD_ILI9486_On;
+ lcdPixelClock = 12000000;
+ } else if (LCD_ILI9488_ReadID() == LCD_ILI9488_ID) {
+ TRACE("LCD INIT: ILI9488");
+ boardLcdType = "ILI9488";
+ lcdInitFunction = LCD_ILI9488_Init;
+ lcdOffFunction = LCD_ILI9488_Off;
+ lcdOnFunction = LCD_ILI9488_On;
+ lcdPixelClock = 12000000;
+ lcd_phys_w = LCD_PHYS_H;
+ lcd_phys_h = LCD_PHYS_W;
+ } else if (LCD_HX8357D_ReadID() == LCD_HX8357D_ID) {
+ TRACE("LCD INIT: HX8357D");
+ boardLcdType = "HX8357D";
+ lcdInitFunction = LCD_HX8357D_Init;
+ lcdOffFunction = LCD_HX8357D_Off;
+ lcdOnFunction = LCD_HX8357D_On;
+ lcdPixelClock = 12000000;
+ } else if (LCD_ST7796S_ReadID() == LCD_ST7796S_ID ) {
+ TRACE("LCD INIT: ST7796S");
+ boardLcdType = "ST7796S";
+ lcdInitFunction = LCD_ST7796S_Init;
+ lcdOffFunction = LCD_ST7796S_Off;
+ lcdOnFunction = LCD_ST7796S_On;
+ lcdPixelClock = 14500000;
+ }
+ else{
+ TRACE("LCD INIT (default): ST7796S");
+ boardLcdType = "ST7796S (Default)";
+ lcdInitFunction = LCD_ST7796S_Init;
+ lcdOffFunction = LCD_ST7796S_Off;
+ lcdOnFunction = LCD_ST7796S_On;
+ lcdPixelClock = 12000000;
+ }
+
+ lcdInitFunction();
+
+ LCD_Init_LTDC();
+ LCD_LayerInit();
+
+ // Enable LCD display
+ __HAL_LTDC_ENABLE(&hltdc);
+
+ lcdSetFlushCb(startLcdRefresh);
+}
+
+extern "C" void LTDC_IRQHandler(void)
+{
+ __HAL_LTDC_CLEAR_FLAG(&hltdc, LTDC_FLAG_LI);
+ __HAL_LTDC_DISABLE_IT(&hltdc, LTDC_IT_LI);
+ _frame_addr_reloaded = 1;
+}
+
diff --git a/radio/src/targets/pl18/lcd_driver.h b/radio/src/targets/pl18/lcd_driver.h
new file mode 100644
index 00000000000..d1c4c756c64
--- /dev/null
+++ b/radio/src/targets/pl18/lcd_driver.h
@@ -0,0 +1,92 @@
+/*
+ * 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 HBP ( 24 ) // TODO use names from FlySky
+#define VBP ( 10 )
+
+#define HSW ( 4 )
+#define VSH ( 2 )
+
+#define HFP ( 140 - HBP )
+#define VFP ( 22 - VBP )
+
+#define LCD_ST7796S_ID ( 0x7796 )
+#define LCD_ILI9481_ID ( 0x9481 )
+#define LCD_ILI9486_ID ( 0x9486 )
+#define LCD_ILI9488_ID ( 0x9488 )
+#define LCD_HX8357D_ID ( 0x99 )
+
+#define LCD_DELAY() LCD_Delay()
+
+typedef void (*lcdSpiInitFucPtr)(void);
+typedef unsigned int LcdReadIDFucPtr( void );
+
+extern lcdSpiInitFucPtr lcdInitFunction;
+extern lcdSpiInitFucPtr lcdOffFunction;
+extern lcdSpiInitFucPtr lcdOnFunction;
+
+#define SET_IO_INPUT( PORT, PIN ) LL_GPIO_SetPinMode( PORT, PIN, LL_GPIO_MODE_INPUT )
+#define SET_IO_OUTPUT( PORT, PIN ) LL_GPIO_SetPinMode( PORT, PIN, LL_GPIO_MODE_OUTPUT )
+
+#define LCD_NRST_HIGH() LL_GPIO_SetOutputPin(LCD_NRST_GPIO, LCD_NRST_GPIO_PIN)
+#define LCD_NRST_LOW() LL_GPIO_ResetOutputPin(LCD_NRST_GPIO, LCD_NRST_GPIO_PIN)
+
+#define LCD_CS_HIGH() LL_GPIO_SetOutputPin(LCD_SPI_GPIO, LCD_SPI_CS_GPIO_PIN)
+#define LCD_CS_LOW() LL_GPIO_ResetOutputPin(LCD_SPI_GPIO, LCD_SPI_CS_GPIO_PIN)
+
+#define LCD_SCK_HIGH() LL_GPIO_SetOutputPin(LCD_SPI_GPIO, LCD_SPI_SCK_GPIO_PIN)
+#define LCD_SCK_LOW() LL_GPIO_ResetOutputPin(LCD_SPI_GPIO, LCD_SPI_SCK_GPIO_PIN)
+
+#define LCD_MOSI_HIGH() LL_GPIO_SetOutputPin(LCD_SPI_GPIO, LCD_SPI_MOSI_GPIO_PIN)
+#define LCD_MOSI_LOW() LL_GPIO_ResetOutputPin(LCD_SPI_GPIO, LCD_SPI_MOSI_GPIO_PIN)
+
+#define LCD_MOSI_AS_INPUT() SET_IO_INPUT( LCD_SPI_GPIO, LCD_SPI_MOSI_GPIO_PIN )
+#define LCD_MOSI_AS_OUTPUT() SET_IO_OUTPUT( LCD_SPI_GPIO, LCD_SPI_MOSI_GPIO_PIN )
+
+#define LCD_READ_DATA_PIN() LL_GPIO_IsInputPinSet(LCD_SPI_GPIO, LCD_SPI_MOSI_GPIO_PIN)
+
+
+#if 1
+#define HORIZONTAL_SYNC_WIDTH ( 4 )
+#define HORIZONTAL_BACK_PORCH ( 24 )
+#define HORIZONTAL_FRONT_PORCH ( 140 - HORIZONTAL_BACK_PORCH )
+#define VERTICAL_SYNC_HEIGHT ( 2 )
+#define VERTICAL_BACK_PORCH ( 10 )
+#define VERTICAL_FRONT_PORCH ( 22 - VERTICAL_BACK_PORCH )
+#else
+#define HORIZONTAL_SYNC_WIDTH ( 4 )
+#define HORIZONTAL_BACK_PORCH ( 20 )
+#define HORIZONTAL_FRONT_PORCH ( 60 - HORIZONTAL_BACK_PORCH )
+#define VERTICAL_SYNC_HEIGHT ( 2 )
+#define VERTICAL_BACK_PORCH ( 6 )
+#define VERTICAL_FRONT_PORCH ( 14 - VERTICAL_BACK_PORCH )
+#endif
+
+
+
+#endif
+
+
+
+
diff --git a/radio/src/targets/pl18/led_driver.cpp b/radio/src/targets/pl18/led_driver.cpp
new file mode 100644
index 00000000000..8b909202fd0
--- /dev/null
+++ b/radio/src/targets/pl18/led_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 "board.h"
+#include "boards/generic_stm32/rgb_leds.h"
+
+void ledInit()
+{
+ // Do nothing
+}
+
+void ledOff()
+{
+ for (uint8_t i = 0; i < LED_STRIP_LENGTH; i++) {
+ rgbSetLedColor(i, 0, 0, 0);
+ }
+ rgbLedColorApply();
+}
+
+void ledRed()
+{
+ for (uint8_t i = 0; i < LED_STRIP_LENGTH; i++) {
+ rgbSetLedColor(i, 50, 0, 0);
+ }
+ rgbLedColorApply();
+}
+
+void ledGreen()
+{
+ for (uint8_t i = 0; i < LED_STRIP_LENGTH; i++) {
+ rgbSetLedColor(i, 0, 50, 0);
+ }
+ rgbLedColorApply();
+}
+
+void ledBlue()
+{
+ for (uint8_t i = 0; i < LED_STRIP_LENGTH; i++) {
+ rgbSetLedColor(i, 0, 0, 50);
+ }
+ rgbLedColorApply();
+}
diff --git a/radio/src/targets/pl18/libopenui_config.h b/radio/src/targets/pl18/libopenui_config.h
new file mode 100644
index 00000000000..5a5abf70a3f
--- /dev/null
+++ b/radio/src/targets/pl18/libopenui_config.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.
+ */
+
+#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;
+
+// Disable rotary encoder, as the PL18 does not have one
+#define ROTARY_ENCODER_SPEED() 0
diff --git a/radio/src/targets/pl18/sdram_driver.c b/radio/src/targets/pl18/sdram_driver.c
new file mode 100644
index 00000000000..2cc88ae84a5
--- /dev/null
+++ b/radio/src/targets/pl18/sdram_driver.c
@@ -0,0 +1,257 @@
+/*
+ * 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 "board.h"
+#include "stm32f4xx_fmc.h"
+
+#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)
+
+void SDRAM_GPIOConfig(void)
+{
+ /*
+ ------------------------------------------------------------------------------------------------------------------------------------------------
+ PC3 <-> FMC_SDCKE0 | PD0 <-> FMC_D2 | PE0 <-> FMC_NBL0 | PF0 <-> FMC_A0 | PG0 <-> FMC_A10 | PH3 <-> FMC_SDNE0 | PI0 <-> FMC_D24
+ | PD1 <-> FMC_D3 | PE1 <-> FMC_NBL1 | PF1 <-> FMC_A1 | PG1 <-> FMC_A11 | PH5 <-> FMC_SDNWE | PI1 <-> FMC_D25
+ | PD8 <-> FMC_D13 | PE7 <-> FMC_D4 | PF2 <-> FMC_A2 | PG4 <-> FMC_BA0 | PH8 <-> FMC_D16 | PI2 <-> FMC_D26
+ | PD9 <-> FMC_D14 | PE8 <-> FMC_D5 | PF3 <-> FMC_A3 | PG5 <-> FMC_BA1 | PH9 <-> FMC_D17 | PI3 <-> FMC_D27
+ | PD10 <-> FMC_D15 | PE9 <-> FMC_D6 | PF4 <-> FMC_A4 | PG8 <-> FMC_SDCLK | PH10 <-> FMC_D18 | PI4 <-> FMC_NBL2
+ | PD14 <-> FMC_D0 | PE10 <-> FMC_D7 | PF5 <-> FMC_A5 | PG15 <-> FMC_NCAS | PH11 <-> FMC_D19 | PI5 <-> FMC_NBL3
+ | PD15 <-> FMC_D1 | PE11 <-> FMC_D8 | PF11 <-> FMC_NRAS | | PH12 <-> FMC_D20 | PI6 <-> FMC_D28
+ | | PE12 <-> FMC_D9 | PF12 <-> FMC_A6 | | PH13 <-> FMC_D21 | PI7 <-> FMC_D29
+ | | PE13 <-> FMC_D10 | PF13 <-> FMC_A7 | | PH14 <-> FMC_D22 | PI9 <-> FMC_D30
+ | | PE14 <-> FMC_D11 | PF14 <-> FMC_A8 | | PH15 <-> FMC_D23 | PI10 <-> FMC_D31
+ | | PE15 <-> FMC_D12 | PF15 <-> FMC_A9 | | |
+ */
+
+ GPIO_InitTypeDef GPIO_InitStructure;
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
+ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
+ GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
+ GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
+
+ /* GPIOC configuration */
+ GPIO_PinAFConfig(GPIOC, GPIO_PinSource3 , GPIO_AF_FMC);
+ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 ;
+ GPIO_Init(GPIOC, &GPIO_InitStructure);
+
+ /* GPIOD configuration */
+ GPIO_PinAFConfig(GPIOD, GPIO_PinSource0, GPIO_AF_FMC);
+ GPIO_PinAFConfig(GPIOD, GPIO_PinSource1, GPIO_AF_FMC);
+ GPIO_PinAFConfig(GPIOD, GPIO_PinSource8, GPIO_AF_FMC);
+ GPIO_PinAFConfig(GPIOD, GPIO_PinSource9, GPIO_AF_FMC);
+ GPIO_PinAFConfig(GPIOD, GPIO_PinSource10, GPIO_AF_FMC);
+ GPIO_PinAFConfig(GPIOD, GPIO_PinSource14, GPIO_AF_FMC);
+ GPIO_PinAFConfig(GPIOD, GPIO_PinSource15, GPIO_AF_FMC);
+ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_14 | GPIO_Pin_15;
+ GPIO_Init(GPIOD, &GPIO_InitStructure);
+
+ /* GPIOE configuration */
+ GPIO_PinAFConfig(GPIOE, GPIO_PinSource0, GPIO_AF_FMC);
+ GPIO_PinAFConfig(GPIOE, GPIO_PinSource1, GPIO_AF_FMC);
+ GPIO_PinAFConfig(GPIOE, GPIO_PinSource7, GPIO_AF_FMC);
+ GPIO_PinAFConfig(GPIOE, GPIO_PinSource8, GPIO_AF_FMC);
+ GPIO_PinAFConfig(GPIOE, GPIO_PinSource9, GPIO_AF_FMC);
+ GPIO_PinAFConfig(GPIOE, GPIO_PinSource10, GPIO_AF_FMC);
+ GPIO_PinAFConfig(GPIOE, GPIO_PinSource11, GPIO_AF_FMC);
+ GPIO_PinAFConfig(GPIOE, GPIO_PinSource12, GPIO_AF_FMC);
+ GPIO_PinAFConfig(GPIOE, GPIO_PinSource13, GPIO_AF_FMC);
+ GPIO_PinAFConfig(GPIOE, GPIO_PinSource14, GPIO_AF_FMC);
+ GPIO_PinAFConfig(GPIOE, GPIO_PinSource15, GPIO_AF_FMC);
+ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
+ GPIO_Init(GPIOE, &GPIO_InitStructure);
+
+ /* GPIOF configuration */
+ GPIO_PinAFConfig(GPIOF, GPIO_PinSource0, GPIO_AF_FMC);
+ GPIO_PinAFConfig(GPIOF, GPIO_PinSource1, GPIO_AF_FMC);
+ GPIO_PinAFConfig(GPIOF, GPIO_PinSource2, GPIO_AF_FMC);
+ GPIO_PinAFConfig(GPIOF, GPIO_PinSource3, GPIO_AF_FMC);
+ GPIO_PinAFConfig(GPIOF, GPIO_PinSource4, GPIO_AF_FMC);
+ GPIO_PinAFConfig(GPIOF, GPIO_PinSource5, GPIO_AF_FMC);
+ GPIO_PinAFConfig(GPIOF, GPIO_PinSource11, GPIO_AF_FMC);
+ GPIO_PinAFConfig(GPIOF, GPIO_PinSource12, GPIO_AF_FMC);
+ GPIO_PinAFConfig(GPIOF, GPIO_PinSource13, GPIO_AF_FMC);
+ GPIO_PinAFConfig(GPIOF, GPIO_PinSource14, GPIO_AF_FMC);
+ GPIO_PinAFConfig(GPIOF, GPIO_PinSource15, GPIO_AF_FMC);
+ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
+ GPIO_Init(GPIOF, &GPIO_InitStructure);
+
+ /* GPIOG configuration */
+ GPIO_PinAFConfig(GPIOG, GPIO_PinSource0 , GPIO_AF_FMC);
+ GPIO_PinAFConfig(GPIOG, GPIO_PinSource1 , GPIO_AF_FMC);
+ GPIO_PinAFConfig(GPIOG, GPIO_PinSource4 , GPIO_AF_FMC);
+ GPIO_PinAFConfig(GPIOG, GPIO_PinSource5 , GPIO_AF_FMC);
+ GPIO_PinAFConfig(GPIOG, GPIO_PinSource8 , GPIO_AF_FMC);
+ GPIO_PinAFConfig(GPIOG, GPIO_PinSource15 , GPIO_AF_FMC);
+ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_8 | GPIO_Pin_15;
+ GPIO_Init(GPIOG, &GPIO_InitStructure);
+
+ /* GPIOH configuration */
+ GPIO_PinAFConfig(GPIOH, GPIO_PinSource3, GPIO_AF_FMC);
+ GPIO_PinAFConfig(GPIOH, GPIO_PinSource5, GPIO_AF_FMC);
+ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_5;
+ GPIO_Init(GPIOH, &GPIO_InitStructure);
+}
+
+void SDRAM_InitSequence(void)
+{
+ FMC_SDRAMCommandTypeDef FMC_SDRAMCommandStructure;
+ uint32_t tmpr = 0;
+
+ /* Step 3 --------------------------------------------------------------------*/
+ /* Configure a clock configuration enable command */
+ FMC_SDRAMCommandStructure.FMC_CommandMode = FMC_Command_Mode_CLK_Enabled;
+ FMC_SDRAMCommandStructure.FMC_CommandTarget = FMC_Command_Target_bank1;
+ FMC_SDRAMCommandStructure.FMC_AutoRefreshNumber = 1;
+ FMC_SDRAMCommandStructure.FMC_ModeRegisterDefinition = 0;
+ /* Wait until the SDRAM controller is ready */
+ while(FMC_GetFlagStatus(FMC_Bank1_SDRAM, FMC_FLAG_Busy) != RESET) {
+ }
+ /* Send the command */
+ FMC_SDRAMCmdConfig(&FMC_SDRAMCommandStructure);
+
+ /* Step 4 --------------------------------------------------------------------*/
+ /* Insert 100 ms delay */
+ delay_ms(100);
+
+ /* Step 5 --------------------------------------------------------------------*/
+ /* Configure a PALL (precharge all) command */
+ FMC_SDRAMCommandStructure.FMC_CommandMode = FMC_Command_Mode_PALL;
+ FMC_SDRAMCommandStructure.FMC_CommandTarget = FMC_Command_Target_bank1;
+ FMC_SDRAMCommandStructure.FMC_AutoRefreshNumber = 1;
+ FMC_SDRAMCommandStructure.FMC_ModeRegisterDefinition = 0;
+ /* Wait until the SDRAM controller is ready */
+ while(FMC_GetFlagStatus(FMC_Bank1_SDRAM, FMC_FLAG_Busy) != RESET) {
+ }
+ /* Send the command */
+ FMC_SDRAMCmdConfig(&FMC_SDRAMCommandStructure);
+
+ /* Step 6 --------------------------------------------------------------------*/
+ /* Configure a Auto-Refresh command */
+ FMC_SDRAMCommandStructure.FMC_CommandMode = FMC_Command_Mode_AutoRefresh;
+ FMC_SDRAMCommandStructure.FMC_CommandTarget = FMC_Command_Target_bank1;
+ FMC_SDRAMCommandStructure.FMC_AutoRefreshNumber = 4;
+ FMC_SDRAMCommandStructure.FMC_ModeRegisterDefinition = 0;
+ /* Wait until the SDRAM controller is ready */
+ while(FMC_GetFlagStatus(FMC_Bank1_SDRAM, FMC_FLAG_Busy) != RESET) {
+ }
+ /* Send the first command */
+ FMC_SDRAMCmdConfig(&FMC_SDRAMCommandStructure);
+
+ /* Wait until the SDRAM controller is ready */
+ while(FMC_GetFlagStatus(FMC_Bank1_SDRAM, FMC_FLAG_Busy) != RESET) {
+ }
+ /* Send the second command */
+ FMC_SDRAMCmdConfig(&FMC_SDRAMCommandStructure);
+
+ /* 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.FMC_CommandMode = FMC_Command_Mode_LoadMode;
+ FMC_SDRAMCommandStructure.FMC_CommandTarget = FMC_Command_Target_bank1;
+ FMC_SDRAMCommandStructure.FMC_AutoRefreshNumber = 1;
+ FMC_SDRAMCommandStructure.FMC_ModeRegisterDefinition = tmpr;
+ /* Wait until the SDRAM controller is ready */
+ while(FMC_GetFlagStatus(FMC_Bank1_SDRAM, FMC_FLAG_Busy) != RESET) {
+ }
+ /* Send the command */
+ FMC_SDRAMCmdConfig(&FMC_SDRAMCommandStructure);
+
+ /* Step 8 --------------------------------------------------------------------*/
+ /* Set the refresh rate counter */
+ /* (15.62 us x Freq) - 20 */
+ /* Set the device refresh counter */
+ FMC_SetRefreshCount(683);//904
+ /* Wait until the SDRAM controller is ready */
+ while(FMC_GetFlagStatus(FMC_Bank1_SDRAM, FMC_FLAG_Busy) != RESET) {
+ }
+}
+
+
+void SDRAM_Init(void)
+{
+ //delay funcion needed
+ delaysInit();
+ // Clocks must be enabled here, because the sdramInit is called before main
+ RCC_AHB1PeriphClockCmd(SDRAM_RCC_AHB1Periph, ENABLE);
+ RCC_AHB3PeriphClockCmd(SDRAM_RCC_AHB3Periph, ENABLE);
+
+ /* GPIO configuration for FMC SDRAM bank */
+ SDRAM_GPIOConfig();
+
+ /* FMC Configuration ---------------------------------------------------------*/
+ FMC_SDRAMInitTypeDef FMC_SDRAMInitStructure;
+ FMC_SDRAMTimingInitTypeDef FMC_SDRAMTimingInitStructure;
+
+ /* FMC SDRAM Bank configuration */
+ /* Timing configuration for 90 Mhz of SD clock frequency (168Mhz/2) */
+ /* TMRD: 2 Clock cycles */
+ FMC_SDRAMTimingInitStructure.FMC_LoadToActiveDelay = 2;
+ /* TXSR: min=70ns (7x11.11ns) */
+ FMC_SDRAMTimingInitStructure.FMC_ExitSelfRefreshDelay = 7;
+ /* TRAS: min=42ns (4x11.11ns) max=120k (ns) */
+ FMC_SDRAMTimingInitStructure.FMC_SelfRefreshTime = 4;
+ /* TRC: min=70 (7x11.11ns) */
+ FMC_SDRAMTimingInitStructure.FMC_RowCycleDelay = 7;
+ /* TWR: min=1+ 7ns (1+1x11.11ns) */
+ FMC_SDRAMTimingInitStructure.FMC_WriteRecoveryTime = 2;
+ /* TRP: 20ns => 2x11.11ns */
+ FMC_SDRAMTimingInitStructure.FMC_RPDelay = 2;
+ /* TRCD: 20ns => 2x11.11ns */
+ FMC_SDRAMTimingInitStructure.FMC_RCDDelay = 2;
+
+ /* FMC SDRAM control configuration */
+ FMC_SDRAMInitStructure.FMC_Bank = FMC_Bank1_SDRAM;
+ /* Row addressing: [7:0] */
+ FMC_SDRAMInitStructure.FMC_ColumnBitsNumber = FMC_ColumnBits_Number_8b;
+ /* Column addressing: [11:0] */
+ FMC_SDRAMInitStructure.FMC_RowBitsNumber = FMC_RowBits_Number_12b;
+ FMC_SDRAMInitStructure.FMC_SDMemoryDataWidth = FMC_SDMemory_Width_16b;
+ FMC_SDRAMInitStructure.FMC_InternalBankNumber = FMC_InternalBank_Number_4;
+ FMC_SDRAMInitStructure.FMC_CASLatency = FMC_CAS_Latency_3;
+ FMC_SDRAMInitStructure.FMC_WriteProtection = FMC_Write_Protection_Disable;
+ FMC_SDRAMInitStructure.FMC_SDClockPeriod = FMC_SDClock_Period_2;
+ FMC_SDRAMInitStructure.FMC_ReadBurst = FMC_Read_Burst_Enable;
+ FMC_SDRAMInitStructure.FMC_ReadPipeDelay = FMC_ReadPipe_Delay_1;
+ FMC_SDRAMInitStructure.FMC_SDRAMTimingStruct = &FMC_SDRAMTimingInitStructure;
+
+ /* FMC SDRAM bank initialization */
+ FMC_SDRAMInit(&FMC_SDRAMInitStructure);
+
+ /* FMC SDRAM device initialization sequence */
+ SDRAM_InitSequence();
+}
diff --git a/radio/src/targets/pl18/touch_driver.cpp b/radio/src/targets/pl18/touch_driver.cpp
new file mode 100644
index 00000000000..c672aa925bb
--- /dev/null
+++ b/radio/src/targets/pl18/touch_driver.cpp
@@ -0,0 +1,470 @@
+/*
+ * Copyright (C) EdgeTX
+ *
+ * Based on code named
+ * opentx - https://github.com/opentx/opentx
+ * th9x - http://code.google.com/p/th9x
+ * er9x - http://code.google.com/p/er9x
+ * gruvin9x - http://code.google.com/p/gruvin9x
+ *
+ * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "stm32_hal_ll.h"
+#include "stm32_hal.h"
+#include "stm32_i2c_driver.h"
+#include "stm32_gpio_driver.h"
+#include "stm32_exti_driver.h"
+
+#include "hal.h"
+#include "timers_driver.h"
+#include "delays_driver.h"
+#include "touch_driver.h"
+
+#include "debug.h"
+
+#define TAP_TIME 25
+#define I2C_TIMEOUT_MAX 5 // 5 ms
+
+// FT6236 definitions
+#define TOUCH_FT6236_I2C_ADDRESS (0x70>>1)
+#define TOUCH_FT6236_REG_TH_GROUP 0x80
+#define TOUCH_FT6236_REG_PERIODACTIVE 0x88
+#define TOUCH_FT6236_REG_LIB_VER_H 0xa1
+#define TOUCH_FT6236_REG_LIB_VER_L 0xa2
+#define TOUCH_FT6236_REG_CIPHER 0xa3
+#define TOUCH_FT6236_REG_FIRMID 0xa6
+#define TOUCH_FT6236_REG_FOCALTECH_ID 0xa8
+#define TOUCH_FT6236_REG_RELEASE_CODE_ID 0xaf
+#define TOUCH_FT6206_REG_TD_STAT 0x02
+#define TOUCH_FT6206_REG_P1_XH 0x03
+#define TOUCH_FT6206_EVT_SHIFT 6
+#define TOUCH_FT6206_EVT_MASK (3 << TOUCH_FT6206_EVT_SHIFT)
+#define TOUCH_FT6206_EVT_CONTACT 0x02
+#define TOUCH_FT6206_MASK_TD_STAT 0x0f
+
+// CST340 definitions
+#define TOUCH_CST340_I2C_ADDRESS 0x1a
+#define TOUCH_CST340_REG_FINGER1 0x00
+#define TOUCH_CST340_EVT_CONTACT 0x06
+
+// CHSC5448 definitions
+#define TOUCH_CHSC5448_I2C_ADDRESS 0x2e
+#define TOUCH_CHSC5448_REG_ADDR 0x2c000020
+#define TOUCH_CHSC5448_EVT_CONTACT 0x08
+#define TOUCH_CHSC5448_MAX_POINTS 5
+
+typedef enum {TC_NONE, TC_FT6236, TC_CST340, TC_CHSC5448} TouchController;
+
+#if defined(DEBUG)
+const char TOUCH_CONTROLLER_STR[][10] = {"", "FT6236", "CST340", "CHSC5448"};
+#endif
+
+TouchController touchController = TC_NONE;
+
+struct TouchControllerDescriptor
+{
+ bool (*hasTouchEvent)();
+ bool (*touchRead)(uint16_t * X, uint16_t * Y);
+ void (*printDebugInfo)();
+ bool needTranspose;
+};
+
+union rpt_point_t
+{
+ struct
+ {
+ unsigned char x_l8;
+ unsigned char y_l8;
+ unsigned char z;
+ unsigned char x_h4:4;
+ unsigned char y_h4:4;
+ unsigned char id:4;
+ unsigned char event:4;
+ }rp;
+ unsigned char data[5];
+};
+
+extern uint8_t TouchControllerType;
+
+static const TouchControllerDescriptor *tcd = nullptr;
+static TouchState internalTouchState = {};
+volatile static bool touchEventOccured;
+static tmr10ms_t downTime = 0;
+static tmr10ms_t tapTime = 0;
+static short tapCount = 0;
+
+static void _touch_exti_isr(void)
+{
+ touchEventOccured = true;
+}
+
+static void _touch_exti_stop(void)
+{
+ stm32_exti_disable(TOUCH_INT_EXTI_Line);
+}
+
+static void _touch_exti_config(void)
+{
+ __HAL_RCC_SYSCFG_CLK_ENABLE();
+ LL_SYSCFG_SetEXTISource(TOUCH_INT_EXTI_Port, TOUCH_INT_EXTI_SysCfgLine);
+
+ stm32_exti_enable(TOUCH_INT_EXTI_Line, LL_EXTI_TRIGGER_FALLING, _touch_exti_isr);
+}
+
+static void _touch_gpio_config(void)
+{
+ LL_GPIO_InitTypeDef gpioInit;
+ LL_GPIO_StructInit(&gpioInit);
+
+ stm32_gpio_enable_clock(TOUCH_RST_GPIO);
+ stm32_gpio_enable_clock(TOUCH_INT_GPIO);
+
+ gpioInit.Mode = LL_GPIO_MODE_OUTPUT;
+ gpioInit.Speed = LL_GPIO_SPEED_FREQ_LOW;
+ gpioInit.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
+ gpioInit.Pull = LL_GPIO_PULL_NO;
+
+ gpioInit.Pin = TOUCH_RST_GPIO_PIN;
+ LL_GPIO_Init(TOUCH_RST_GPIO, &gpioInit);
+ LL_GPIO_SetOutputPin(TOUCH_RST_GPIO, TOUCH_RST_GPIO_PIN);
+
+ gpioInit.Pin = TOUCH_INT_GPIO_PIN;
+ gpioInit.Mode = LL_GPIO_MODE_INPUT;
+ gpioInit.Pull = LL_GPIO_PULL_UP;
+ gpioInit.OutputType = LL_GPIO_OUTPUT_OPENDRAIN;
+ LL_GPIO_Init(TOUCH_INT_GPIO, &gpioInit);
+ LL_GPIO_SetOutputPin(TOUCH_INT_GPIO, TOUCH_INT_GPIO_PIN);
+}
+
+static void _touch_reset()
+{
+ LL_GPIO_ResetOutputPin(TOUCH_RST_GPIO, TOUCH_RST_GPIO_PIN);
+ delay_ms(10);
+ LL_GPIO_SetOutputPin(TOUCH_RST_GPIO, TOUCH_RST_GPIO_PIN);
+ delay_ms(300);
+}
+
+static void _i2c_init(void)
+{
+ TRACE("Touch I2C Init");
+
+ if (stm32_i2c_init(TOUCH_I2C_BUS, TOUCH_I2C_CLK_RATE) < 0) {
+ TRACE("Touch I2C Init ERROR: stm32_i2c_init failed");
+ return;
+ }
+}
+
+static void _i2c_reInit(void)
+{
+ stm32_i2c_deinit(TOUCH_I2C_BUS);
+ _i2c_init();
+}
+
+static int _i2c_read(uint8_t addr, uint32_t reg, uint8_t regSize, uint8_t* data, uint16_t len, uint32_t timeout)
+{
+ if (regSize > 2) {
+ if(stm32_i2c_master_tx(TOUCH_I2C_BUS, addr, (uint8_t*) ®, regSize, 3) < 0)
+ return false;
+ delay_us(5);
+ if(stm32_i2c_master_rx(TOUCH_I2C_BUS, addr, data, len, I2C_TIMEOUT_MAX) < 0)
+ return false;
+ return true;
+ } else {
+ return stm32_i2c_read(TOUCH_I2C_BUS, addr, reg, regSize, data, len, timeout);
+ }
+}
+
+static uint8_t _i2c_readRetry(uint8_t addr, uint32_t reg, uint8_t regSize)
+{
+ uint8_t result;
+ uint8_t tryCount = 3;
+ while (_i2c_read(addr, reg, regSize, &result, 1, I2C_TIMEOUT_MAX) < 0) {
+ if (--tryCount == 0) break;
+ _i2c_reInit();
+ }
+ return result;
+}
+
+static uint16_t _i2c_readMultipleRetry(uint8_t addr, uint32_t reg, uint8_t regSize, uint8_t * buffer, uint16_t length)
+{
+ uint8_t tryCount = 3;
+ while (_i2c_read(addr, reg, regSize, buffer, length, I2C_TIMEOUT_MAX) < 0) {
+ if (--tryCount == 0) break;
+ _i2c_reInit();
+ }
+ return length;
+}
+
+static bool ft6236TouchRead(uint16_t * X, uint16_t * Y)
+{
+ // Read register FT6206_TD_STAT_REG to check number of touches detection
+ uint8_t nbTouch = _i2c_readRetry(TOUCH_FT6236_I2C_ADDRESS, TOUCH_FT6206_REG_TD_STAT, 1);
+ nbTouch &= TOUCH_FT6206_MASK_TD_STAT;
+ bool hasTouch = nbTouch > 0;
+
+ if (hasTouch) {
+ uint8_t dataxy[4];
+ // Read X and Y positions and event
+ _i2c_readMultipleRetry(TOUCH_FT6236_I2C_ADDRESS, TOUCH_FT6206_REG_P1_XH, 1, dataxy, sizeof(dataxy));
+
+ // Send back ready X position to caller
+ *X = ((dataxy[0] & 0x0f) << 8) | dataxy[1];
+ // Send back ready Y position to caller
+ *Y = ((dataxy[2] & 0x0f) << 8) | dataxy[3];
+
+ uint8_t event = (dataxy[0] & TOUCH_FT6206_EVT_MASK) >> TOUCH_FT6206_EVT_SHIFT;
+ return event == TOUCH_FT6206_EVT_CONTACT;
+ }
+ return false;
+}
+
+static bool ft6236HasTouchEvent()
+{
+ return touchEventOccured;
+}
+
+static void ft6236PrintDebugInfo()
+{
+#if defined(DEBUG)
+ TRACE("ft6x36: thrhld = %d", _i2c_readRetry(TOUCH_FT6236_I2C_ADDRESS, TOUCH_FT6236_REG_TH_GROUP, 1) * 4);
+ TRACE("ft6x36: rep rate=", _i2c_readRetry(TOUCH_FT6236_I2C_ADDRESS, TOUCH_FT6236_REG_PERIODACTIVE, 1) * 10);
+ TRACE("ft6x36: fw lib 0x%02X %02X", _i2c_readRetry(TOUCH_FT6236_I2C_ADDRESS, TOUCH_FT6236_REG_LIB_VER_H, 1),
+ _i2c_readRetry(TOUCH_FT6236_I2C_ADDRESS, TOUCH_FT6236_REG_LIB_VER_L, 1));
+ TRACE("ft6x36: fw v 0x%02X", _i2c_readRetry(TOUCH_FT6236_I2C_ADDRESS, TOUCH_FT6236_REG_FIRMID, 1));
+ TRACE("ft6x36: CHIP ID 0x%02X", _i2c_readRetry(TOUCH_FT6236_I2C_ADDRESS, TOUCH_FT6236_REG_CIPHER, 1));
+ TRACE("ft6x36: CTPM ID 0x%02X", _i2c_readRetry(TOUCH_FT6236_I2C_ADDRESS, TOUCH_FT6236_REG_FOCALTECH_ID, 1));
+ TRACE("ft6x36: rel code 0x%02X", _i2c_readRetry(TOUCH_FT6236_I2C_ADDRESS, TOUCH_FT6236_REG_RELEASE_CODE_ID, 1));
+#endif
+
+}
+
+static bool cst340TouchRead(uint16_t * X, uint16_t * Y)
+{
+ uint8_t data[4];
+
+ // Read X and Y positions
+ _i2c_readMultipleRetry(TOUCH_CST340_I2C_ADDRESS, TOUCH_CST340_REG_FINGER1, 1, data, sizeof(data));
+
+ // Send back X position to caller
+ if (X) *X = ((data[1]<<4) + ((data[3]>>4)&0x0f));
+ // Send back Y position to caller
+ if (Y) *Y = ((data[2]<<4) + ((data[3])&0x0f));
+
+ return data[0] == TOUCH_CST340_EVT_CONTACT;
+}
+
+static bool cst340HasTouchEvent()
+{
+ static bool lastHasTouch = false;
+ bool ret = touchEventOccured;
+ if (ret) {
+ uint8_t hasTouch = cst340TouchRead(nullptr, nullptr);
+ if (!hasTouch && !lastHasTouch) {
+ TRACE("Interrupt occurs without touch event!!");
+ touchEventOccured = false;
+ ret = false;
+ }
+ lastHasTouch = hasTouch;
+ }
+
+ return ret;
+}
+
+static void cst340PrintDebugInfo()
+{
+ // TODO, when necessary
+}
+
+static bool chsc5448TouchRead(uint16_t * X, uint16_t * Y)
+{
+ static uint8_t readbuffer[84];
+ const uint8_t reportSize = ((TOUCH_CHSC5448_MAX_POINTS * 5 + 2) + 3) & 0xfc;
+
+ int ptCnt = 0;
+ union rpt_point_t* ppt;
+
+ _i2c_readMultipleRetry(TOUCH_CHSC5448_I2C_ADDRESS, TOUCH_CHSC5448_REG_ADDR, 4, readbuffer, reportSize);
+ ptCnt = readbuffer[1] & 0x0f;
+ ppt = (union rpt_point_t*)&readbuffer[2];
+ *X = ((ppt->rp.x_h4 & 0x0f) << 8) | ppt->rp.x_l8;
+ *Y = ((ppt->rp.y_h4 & 0x0f) << 8) | ppt->rp.y_l8;
+ uint8_t event = ppt->rp.event;
+
+ return ptCnt > 0 && event == TOUCH_CHSC5448_EVT_CONTACT;
+}
+
+static bool chsc5448HasTouchEvent()
+{
+ return touchEventOccured;
+}
+
+static void chsc5448PrintDebugInfo()
+{
+ // TODO, when necessary
+}
+
+static const TouchControllerDescriptor FT6236 =
+{
+ .hasTouchEvent = ft6236HasTouchEvent,
+ .touchRead = ft6236TouchRead,
+ .printDebugInfo = ft6236PrintDebugInfo,
+ .needTranspose = true,
+};
+
+static const TouchControllerDescriptor CST340 =
+{
+ .hasTouchEvent = cst340HasTouchEvent,
+ .touchRead = cst340TouchRead,
+ .printDebugInfo = cst340PrintDebugInfo,
+ .needTranspose = true,
+};
+
+static const TouchControllerDescriptor CHSC5448 =
+{
+ .hasTouchEvent = chsc5448HasTouchEvent,
+ .touchRead = chsc5448TouchRead,
+ .printDebugInfo = chsc5448PrintDebugInfo,
+ .needTranspose = false,
+};
+
+void _detect_touch_controller()
+{
+ if (stm32_i2c_is_dev_ready(TOUCH_I2C_BUS, TOUCH_CST340_I2C_ADDRESS, 3, I2C_TIMEOUT_MAX) == 0) {
+ touchController = TC_CST340;
+ tcd = &CST340;
+ TouchControllerType = 0;
+ } else if (stm32_i2c_is_dev_ready(TOUCH_I2C_BUS, TOUCH_CHSC5448_I2C_ADDRESS, 3, I2C_TIMEOUT_MAX) == 0) {
+ touchController = TC_CHSC5448;
+ tcd = &CHSC5448;
+ TouchControllerType = 0;
+ } else {
+ touchController = TC_FT6236;
+ tcd = &FT6236;
+ TouchControllerType = 1;
+ }
+}
+
+void touchPanelDeInit()
+{
+ _touch_exti_stop();
+}
+
+bool touchPanelInit()
+{
+ _touch_gpio_config();
+ _i2c_init();
+ _touch_reset();
+ _detect_touch_controller();
+ _touch_exti_config();
+
+ tcd->printDebugInfo();
+
+ return touchController != TC_NONE;
+}
+
+bool touchPanelEventOccured()
+{
+ return tcd->hasTouchEvent();
+}
+
+struct TouchState touchPanelRead()
+{
+ if (!touchEventOccured) return internalTouchState;
+
+ touchEventOccured = false;
+
+ tmr10ms_t now = get_tmr10ms();
+ internalTouchState.tapCount = 0;
+ unsigned short touchX;
+ unsigned short touchY;
+ bool hasTouchContact = tcd->touchRead(&touchX, &touchY);
+
+ if (tcd->needTranspose) {
+ // Touch sensor is rotated by 90 deg
+ unsigned short tmp = touchY;
+ touchY = 319 - touchX;
+ touchX = tmp;
+ }
+
+ if (hasTouchContact) {
+ int dx = touchX - internalTouchState.x;
+ int dy = touchY - internalTouchState.y;
+ internalTouchState.x = touchX;
+ internalTouchState.y = touchY;
+
+ if (internalTouchState.event == TE_NONE || internalTouchState.event == TE_UP || internalTouchState.event == TE_SLIDE_END) {
+ internalTouchState.startX = internalTouchState.x;
+ internalTouchState.startY = internalTouchState.y;
+ internalTouchState.event = TE_DOWN;
+ }
+ else if (internalTouchState.event == TE_DOWN) {
+ if (dx >= SLIDE_RANGE || dx <= -SLIDE_RANGE || dy >= SLIDE_RANGE || dy <= -SLIDE_RANGE) {
+ internalTouchState.event = TE_SLIDE;
+ internalTouchState.deltaX = (short) dx;
+ internalTouchState.deltaY = (short) dy;
+ }
+ else {
+ internalTouchState.event = TE_DOWN;
+ internalTouchState.deltaX = 0;
+ internalTouchState.deltaY = 0;
+ }
+ }
+ else if (internalTouchState.event == TE_SLIDE) {
+ internalTouchState.event = TE_SLIDE; //no change
+ internalTouchState.deltaX = (short) dx;
+ internalTouchState.deltaY = (short) dy;
+ }
+
+ if (internalTouchState.event == TE_DOWN && downTime == 0) {
+ downTime = now;
+ }
+ }
+ else {
+ if (internalTouchState.event == TE_DOWN) {
+ internalTouchState.event = TE_UP;
+ if (now - downTime <= TAP_TIME) {
+ if (now - tapTime > TAP_TIME) {
+ tapCount = 1;
+ } else {
+ tapCount++;
+ }
+ internalTouchState.tapCount = tapCount;
+ tapTime = now;
+ } else {
+ internalTouchState.tapCount = 0; // not a tap
+ }
+ downTime = 0;
+ } else {
+ tapCount = 0;
+ internalTouchState.tapCount = 0;
+ internalTouchState.event = TE_SLIDE_END;
+ }
+ }
+
+ TouchState ret = internalTouchState;
+ internalTouchState.deltaX = 0;
+ internalTouchState.deltaY = 0;
+ if (internalTouchState.event == TE_UP || internalTouchState.event == TE_SLIDE_END)
+ internalTouchState.event = TE_NONE;
+
+#if defined(DEBUG)
+ TRACE("%s: event=%d,X=%d,Y=%d", TOUCH_CONTROLLER_STR[touchController], ret.event, ret.x, ret.y);
+#endif
+
+ return ret;
+}
+
+struct TouchState getInternalTouchState()
+{
+ return internalTouchState;
+}
diff --git a/radio/src/targets/pl18/touch_driver.h b/radio/src/targets/pl18/touch_driver.h
new file mode 100644
index 00000000000..6b0fb01a8f6
--- /dev/null
+++ b/radio/src/targets/pl18/touch_driver.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) EdgeTX
+ *
+ * Based on code named
+ * opentx - https://github.com/opentx/opentx
+ * th9x - http://code.google.com/p/th9x
+ * er9x - http://code.google.com/p/er9x
+ * gruvin9x - http://code.google.com/p/gruvin9x
+ *
+ * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#pragma once
+
+#include "touch.h"
+
+extern void touchPanelDeInit();
+extern bool touchPanelInit();
+
+struct TouchState touchPanelRead();
+bool touchPanelEventOccured();
+struct TouchState getInternalTouchState();
diff --git a/radio/src/targets/pl18/tp_cst340.cpp b/radio/src/targets/pl18/tp_cst340.cpp
new file mode 100644
index 00000000000..c8e633ff3cf
--- /dev/null
+++ b/radio/src/targets/pl18/tp_cst340.cpp
@@ -0,0 +1,560 @@
+/*
+ * Copyright (C) EdgeTX
+ *
+ * Based on code named
+ * opentx - https://github.com/opentx/opentx
+ * th9x - http://code.google.com/p/th9x
+ * er9x - http://code.google.com/p/er9x
+ * gruvin9x - http://code.google.com/p/gruvin9x
+ *
+ * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "stm32_hal_ll.h"
+#include "stm32_hal.h"
+#include "stm32_i2c_driver.h"
+#include "stm32_gpio_driver.h"
+#include "stm32_exti_driver.h"
+
+#include "hal.h"
+#include "timers_driver.h"
+#include "delays_driver.h"
+#include "tp_cst340.h"
+
+#include "debug.h"
+
+#define TOUCH_FT6236_I2C_ADDRESS (0x70>>1)
+#define TOUCH_CST340_I2C_ADDRESS 0x1A
+
+
+extern uint8_t TouchControllerType;
+
+volatile static bool touchEventOccured;
+enum TouchControllers {TC_NONE, TC_FT6236, TC_CST340};
+TouchControllers touchController = TC_NONE;
+
+static tc_handle_TypeDef tc_handle = {0, 0};
+
+tmr10ms_t downTime = 0;
+tmr10ms_t tapTime = 0;
+short tapCount = 0;
+#define TAP_TIME 25
+
+struct TouchControllerDescriptor
+{
+ void (*read)(uint16_t * X, uint16_t * Y, uint32_t * event);
+ uint8_t (*detectTouch)();
+ void (*printDebugInfo)();
+ uint32_t contactEvent;
+};
+
+static const TouchControllerDescriptor *tc = nullptr;
+
+static TouchState internalTouchState = {};
+
+static void _cst340_exti_isr(void)
+{
+ touchEventOccured = true;
+}
+
+static void TOUCH_AF_ExtiStop(void)
+{
+ stm32_exti_disable(TOUCH_INT_EXTI_Line);
+}
+
+static void TOUCH_AF_ExtiConfig(void)
+{
+ __HAL_RCC_SYSCFG_CLK_ENABLE();
+ LL_SYSCFG_SetEXTISource(TOUCH_INT_EXTI_Port, TOUCH_INT_EXTI_SysCfgLine);
+
+ stm32_exti_enable(TOUCH_INT_EXTI_Line,
+ LL_EXTI_TRIGGER_FALLING,
+ _cst340_exti_isr);
+}
+
+static void TOUCH_AF_GPIOConfig(void)
+{
+ LL_GPIO_InitTypeDef gpioInit;
+ LL_GPIO_StructInit(&gpioInit);
+
+ stm32_gpio_enable_clock(TOUCH_RST_GPIO);
+ stm32_gpio_enable_clock(TOUCH_INT_GPIO);
+
+ gpioInit.Mode = LL_GPIO_MODE_OUTPUT;
+ gpioInit.Speed = LL_GPIO_SPEED_FREQ_LOW;
+ gpioInit.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
+ gpioInit.Pull = LL_GPIO_PULL_NO;
+
+ gpioInit.Pin = TOUCH_RST_GPIO_PIN;
+ LL_GPIO_Init(TOUCH_RST_GPIO, &gpioInit);
+ LL_GPIO_SetOutputPin(TOUCH_RST_GPIO, TOUCH_RST_GPIO_PIN);
+
+ gpioInit.Pin = TOUCH_INT_GPIO_PIN;
+ gpioInit.Mode = LL_GPIO_MODE_INPUT;
+ gpioInit.Pull = LL_GPIO_PULL_UP;
+ gpioInit.OutputType = LL_GPIO_OUTPUT_OPENDRAIN;
+ LL_GPIO_Init(TOUCH_INT_GPIO, &gpioInit);
+ LL_GPIO_SetOutputPin(TOUCH_INT_GPIO, TOUCH_INT_GPIO_PIN);
+}
+
+void I2C_Init_Radio(void)
+{
+ TRACE("CST340 I2C Init");
+
+ if (stm32_i2c_init(TOUCH_I2C_BUS, TOUCH_I2C_CLK_RATE) < 0) {
+ TRACE("CST340 ERROR: stm32_i2c_init failed");
+ return;
+ }
+}
+
+// void Touch_DeInit()
+// {
+// I2C_DeInit(I2C_B1);
+// __HAL_RCC_I2C1_FORCE_RESET();
+// delay_ms(150);
+// __HAL_RCC_I2C1_RELEASE_RESET();
+// }
+
+#define I2C_TIMEOUT_MAX 5 // 5 ms
+
+bool touch_i2c_read(uint8_t addr, uint8_t reg, uint8_t * data, uint8_t len)
+{
+// if(touchController == TC_CST836U)
+// {
+// if(stm32_i2c_master_tx(TOUCH_I2C_BUS, addr, ®, 1, 3) < 0)
+// return false;
+// delay_us(5);
+// if(stm32_i2c_master_rx(TOUCH_I2C_BUS, addr, data, len, I2C_TIMEOUT_MAX) < 0)
+// return false;
+// } else {
+ if (stm32_i2c_read(TOUCH_I2C_BUS, addr, reg, 1, data, len, I2C_TIMEOUT_MAX) < 0)
+ return false;
+// }
+
+ return true;
+}
+
+#if 0
+static bool touch_i2c_write(uint8_t addr, uint8_t reg, uint8_t * data, uint8_t len)
+{
+ if (stm32_i2c_write(TOUCH_I2C_BUS, addr, reg, 1, data, len, I2C_TIMEOUT_MAX) < 0)
+ return false;
+
+ return true;
+}
+
+static void TS_IO_Write(uint8_t addr, uint8_t reg, uint8_t data)
+{
+ uint8_t tryCount = 3;
+ while (!touch_i2c_write(addr, reg, &data, 1)) {
+ if (--tryCount == 0) break;
+ I2C_Init();
+ }
+}
+#endif
+
+static uint8_t TS_IO_Read(uint8_t addr, uint8_t reg)
+{
+ uint8_t result;
+ uint8_t tryCount = 3;
+ while (!touch_i2c_read(addr, reg, &result, 1)) {
+ if (--tryCount == 0) break;
+ I2C_Init_Radio();
+// I2C_Init();
+ }
+ return result;
+}
+
+static uint16_t TS_IO_ReadMultiple(uint8_t addr, uint8_t reg, uint8_t * buffer, uint16_t length)
+{
+ uint8_t tryCount = 3;
+ while (!touch_i2c_read(addr, reg, buffer, length)) {
+ if (--tryCount == 0) break;
+ I2C_Init_Radio();
+// I2C_Init();
+ }
+ return 1;
+}
+
+static void touch_ft6236_debug_info(void)
+{
+#if defined(DEBUG)
+ TRACE("ft6x36: thrhld = %d", TS_IO_Read(TOUCH_FT6236_I2C_ADDRESS, TOUCH_FT6236_REG_TH_GROUP) * 4);
+ TRACE("ft6x36: rep rate=", TS_IO_Read(TOUCH_FT6236_I2C_ADDRESS, TOUCH_FT6236_REG_PERIODACTIVE) * 10);
+ TRACE("ft6x36: fw lib 0x%02X %02X", TS_IO_Read(TOUCH_FT6236_I2C_ADDRESS, TOUCH_FT6236_REG_LIB_VER_H), TS_IO_Read(TOUCH_FT6236_I2C_ADDRESS, TOUCH_FT6236_REG_LIB_VER_L));
+ TRACE("ft6x36: fw v 0x%02X", TS_IO_Read(TOUCH_FT6236_I2C_ADDRESS, TOUCH_FT6236_REG_FIRMID));
+ TRACE("ft6x36: CHIP ID 0x%02X", TS_IO_Read(TOUCH_FT6236_I2C_ADDRESS, TOUCH_FT6236_REG_CIPHER));
+ TRACE("ft6x36: CTPM ID 0x%02X", TS_IO_Read(TOUCH_FT6236_I2C_ADDRESS, TOUCH_FT6236_REG_FOCALTECH_ID));
+ TRACE("ft6x36: rel code 0x%02X", TS_IO_Read(TOUCH_FT6236_I2C_ADDRESS, TOUCH_FT6236_REG_RELEASE_CODE_ID));
+#endif
+}
+
+/**
+ * @brief Return if there is touches detected or not.
+ * Try to detect new touches and forget the old ones (reset internal global
+ * variables).
+ * @param DeviceAddr: Device address on communication Bus.
+ * @retval : Number of active touches detected (can be 0, 1 or 2).
+ */
+static uint8_t ft6x06_TS_DetectTouch()
+{
+ volatile uint8_t nbTouch = 0;
+
+ /* Read register FT6206_TD_STAT_REG to check number of touches detection */
+ nbTouch = TS_IO_Read(TOUCH_FT6236_I2C_ADDRESS, FT6206_TD_STAT_REG);
+ nbTouch &= FT6206_TD_STAT_MASK;
+ if (nbTouch > FT6206_MAX_DETECTABLE_TOUCH) {
+ /* If invalid number of touch detected, set it to zero */
+ nbTouch = 0;
+ }
+ /* Update ft6x06 driver internal global : current number of active touches */
+ tc_handle.currActiveTouchNb = nbTouch;
+
+ /* Reset current active touch index on which to work on */
+ tc_handle.currActiveTouchIdx = 0;
+ return (nbTouch);
+}
+
+#if 0
+/**
+ * @brief Get the touch detailed informations on touch number 'touchIdx' (0..1)
+ * This touch detailed information contains :
+ * - weight that was applied to this touch
+ * - sub-area of the touch in the touch panel
+ * - event of linked to the touch (press down, lift up, ...)
+ * @param DeviceAddr: Device address on communication Bus (I2C slave address of FT6x06).
+ * @param touchIdx : Passed index of the touch (0..1) on which we want to get the
+ * detailed information.
+ * @param pWeight : Pointer to to get the weight information of 'touchIdx'.
+ * @param pArea : Pointer to to get the sub-area information of 'touchIdx'.
+ * @param pEvent : Pointer to to get the event information of 'touchIdx'.
+
+ * @retval None.
+ */
+static void ft6x06_TS_GetTouchInfo(uint16_t DeviceAddr,
+ uint32_t touchIdx,
+ uint32_t * pWeight,
+ uint32_t * pArea,
+ uint32_t * pEvent)
+{
+ uint8_t regAddress = 0;
+ uint8_t dataxy[3];
+
+ if (touchIdx < ft6x06_handle.currActiveTouchNb) {
+ switch (touchIdx) {
+ case 0 :
+ regAddress = FT6206_P1_WEIGHT_REG;
+ break;
+
+ case 1 :
+ regAddress = FT6206_P2_WEIGHT_REG;
+ break;
+
+ default :
+ break;
+
+ } /* end switch(touchIdx) */
+
+ /* Read weight, area and Event Id of touch index */
+ TS_IO_ReadMultiple(DeviceAddr, regAddress, dataxy, sizeof(dataxy));
+
+ /* Return weight of touch index */
+ *pWeight = (dataxy[0] & FT6206_TOUCH_WEIGHT_MASK) >> FT6206_TOUCH_WEIGHT_SHIFT;
+ /* Return area of touch index */
+ *pArea = (dataxy[1] & FT6206_TOUCH_AREA_MASK) >> FT6206_TOUCH_AREA_SHIFT;
+ /* Return Event Id of touch index */
+ *pEvent = (dataxy[2] & FT6206_TOUCH_EVT_FLAG_MASK) >> FT6206_TOUCH_EVT_FLAG_SHIFT;
+
+ } /* of if(touchIdx < ft6x06_handle.currActiveTouchNb) */
+}
+#endif
+
+/**
+ * @brief Get the touch screen X and Y positions values
+ * Manage multi touch thanks to touch Index global
+ * variable 'tc_handle.currActiveTouchIdx'.
+ * @param DeviceAddr: Device address on communication Bus.
+ * @param X: Pointer to X position value
+ * @param Y: Pointer to Y position value
+ * @retval None.
+ */
+static void ft6x06_TS_GetXY(uint16_t * X, uint16_t * Y, uint32_t * event)
+{
+ uint8_t regAddress = 0;
+ uint8_t dataxy[4];
+
+ if (tc_handle.currActiveTouchIdx < tc_handle.currActiveTouchNb) {
+ switch (tc_handle.currActiveTouchIdx) {
+ case 0 :
+ regAddress = FT6206_P1_XH_REG;
+ break;
+ case 1 :
+ regAddress = FT6206_P2_XH_REG;
+ break;
+
+ default :
+ break;
+ }
+
+ /* Read X and Y positions */
+ TS_IO_ReadMultiple(TOUCH_FT6236_I2C_ADDRESS, regAddress, dataxy, sizeof(dataxy));
+ /* Send back ready X position to caller */
+ *X = ((dataxy[0] & FT6206_MSB_MASK) << 8) | (dataxy[1] & FT6206_LSB_MASK);
+ /* Send back ready Y position to caller */
+ *Y = ((dataxy[2] & FT6206_MSB_MASK) << 8) | (dataxy[3] & FT6206_LSB_MASK);
+
+ *event = (dataxy[0] & FT6206_TOUCH_EVT_FLAG_MASK) >> FT6206_TOUCH_EVT_FLAG_SHIFT;
+ /*
+ uint32_t weight;
+ uint32_t area;
+ ft6x06_TS_GetTouchInfo(DeviceAddr, ft6x06_handle.currActiveTouchIdx, &weight, &area, event);
+ */
+ tc_handle.currActiveTouchIdx++;
+ }
+}
+
+static void touch_cst340_debug_info(void)
+{
+#if 0 // Disabled because cannot compile, will fix when necessary
+#if defined(DEBUG)
+ uint8_t tmp[4];
+ if (!TS_IO_Write(CST340_MODE_DEBUG_INFO, tmp, 0))
+ TRACE("CST340 chip NOT FOUND");
+
+ // Check the value, expected ChipID
+ uint32_t chipId = tmp[0] << 8) + tmp[1];
+
+ if (!I2C_CST340_ReadRegister(CST340_FWVER_REG, tmp, 4))
+ TRACE("Error reading CST340 firmware version!");
+ uint32_t fwVersion = tmp[0] << 24 | tmp[1]<<16 | tmp[2]<<8 | tmp[0];
+
+ // Enter normal mode
+ if (!I2C_CST340_WriteRegister(CST340_MODE_NORMAL, tmp, 0))
+ TRACE("ERROR chaning CST340 mode back to normal!");
+
+ TRACE("cst340: fw ver 0x%08X", fwVersion);
+ TRACE("cst836u: chip id 0x%04X", chipId);
+#endif
+#endif
+}
+
+/**
+ * @brief Get the touch screen X and Y positions values
+ * @param DeviceAddr: Device address on communication Bus.
+ * @param X: Pointer to X position value
+ * @param Y: Pointer to Y position value
+ * @retval None.
+ */
+static void cst340_TS_GetXY(uint16_t * X, uint16_t * Y, uint32_t * event)
+{
+ uint8_t dataxy[4];
+
+ /* Read X and Y positions */
+ TS_IO_ReadMultiple(TOUCH_CST340_I2C_ADDRESS, CST340_FINGER1_REG, dataxy, sizeof(dataxy));
+ /* Send back ready X position to caller */
+ *X = ((dataxy[1]<<4) + ((dataxy[3]>>4)&0x0f));
+ *Y = ((dataxy[2]<<4) + ((dataxy[3])&0x0f));
+ /* Send back ready Y position to caller */
+
+ *event = dataxy[0];
+}
+
+/**
+ * @brief Return if there is touches detected or not.
+ * Try to detect new touches and forget the old ones (reset internal global
+ * variables).
+ * @param DeviceAddr: Device address on communication Bus.
+ * @retval : Number of active touches detected
+ */
+static uint8_t cst340_TS_DetectTouch()
+{
+ uint8_t nbTouch;
+ uint8_t reg = TS_IO_Read(TOUCH_CST340_I2C_ADDRESS, CST340_FINGER1_REG);
+ if( reg == 0x06 )
+ nbTouch = 1;
+ else
+ nbTouch = 0;
+
+ tc_handle.currActiveTouchNb = nbTouch;
+
+ tc_handle.currActiveTouchIdx = 0;
+ return (nbTouch);
+}
+
+void TouchReset()
+{
+ LL_GPIO_ResetOutputPin(TOUCH_RST_GPIO, TOUCH_RST_GPIO_PIN);
+ delay_ms(10);
+ LL_GPIO_SetOutputPin(TOUCH_RST_GPIO, TOUCH_RST_GPIO_PIN);
+ delay_ms(300);
+}
+
+static const TouchControllerDescriptor FT6236 =
+{
+ .read = ft6x06_TS_GetXY,
+ .detectTouch = ft6x06_TS_DetectTouch,
+ .printDebugInfo = touch_ft6236_debug_info,
+ .contactEvent = FT6206_TOUCH_EVT_FLAG_CONTACT
+};
+static const TouchControllerDescriptor CST340 =
+{
+ .read = cst340_TS_GetXY,
+ .detectTouch = cst340_TS_DetectTouch,
+ .printDebugInfo = touch_cst340_debug_info,
+ .contactEvent = CST340_TOUCH_EVT_FLAG_CONTACT
+};
+
+void detectTouchController()
+{
+ if( stm32_i2c_is_dev_ready(TOUCH_I2C_BUS, TOUCH_CST340_I2C_ADDRESS, 3, 5) == 0)
+ {
+ TouchControllerType = 0;
+ touchController = TC_CST340;
+ tc = &CST340;
+ } else {
+ TouchControllerType = 1;
+ touchController = TC_FT6236;
+ tc = &FT6236;
+ }
+}
+
+void TouchInit()
+{
+ TOUCH_AF_GPIOConfig(); // SET RST=OUT INT=IN INT=HIGH
+ I2C_Init_Radio();
+ TouchReset();
+ detectTouchController();
+ TOUCH_AF_ExtiConfig();
+
+ tc->printDebugInfo();
+}
+
+void handleTouch()
+{
+ unsigned short touchX;
+ unsigned short touchY;
+ uint32_t tEvent = 0;
+ tc->read(&touchX, &touchY, &tEvent);
+
+#if defined(DEBUG)
+ TRACE("handleTouch: touchX=%d, touchY=%d, tEvent=%d", touchX, touchY, tEvent);
+#endif
+ // touch sensor is rotated by 90 deg
+ unsigned short tmp = touchY;
+ touchY = 319 - touchX;
+ touchX = tmp;
+
+ if (tEvent == tc->contactEvent) {
+ int dx = touchX - internalTouchState.x;
+ int dy = touchY - internalTouchState.y;
+
+ internalTouchState.x = touchX;
+ internalTouchState.y = touchY;
+
+ if (internalTouchState.event == TE_NONE || internalTouchState.event == TE_UP || internalTouchState.event == TE_SLIDE_END) {
+ internalTouchState.startX = internalTouchState.x;
+ internalTouchState.startY = internalTouchState.y;
+ internalTouchState.event = TE_DOWN;
+ }
+ else if (internalTouchState.event == TE_DOWN) {
+ if (dx >= SLIDE_RANGE || dx <= -SLIDE_RANGE || dy >= SLIDE_RANGE || dy <= -SLIDE_RANGE) {
+ internalTouchState.event = TE_SLIDE;
+ internalTouchState.deltaX = (short) dx;
+ internalTouchState.deltaY = (short) dy;
+ }
+ else {
+ internalTouchState.event = TE_DOWN;
+ internalTouchState.deltaX = 0;
+ internalTouchState.deltaY = 0;
+ }
+ }
+ else if (internalTouchState.event == TE_SLIDE) {
+ internalTouchState.event = TE_SLIDE; //no change
+ internalTouchState.deltaX = (short) dx;
+ internalTouchState.deltaY = (short) dy;
+ }
+
+ }
+}
+
+static bool lastHasTouch = false;
+bool touchPanelEventOccured()
+{
+ bool result = touchEventOccured;
+ uint8_t hasTouch = false;
+ if (touchEventOccured) {
+ hasTouch = tc->detectTouch();
+ if (!hasTouch && !lastHasTouch) {
+ touchEventOccured = false;
+ result = false;
+ }
+ lastHasTouch = hasTouch;
+ }
+
+#if defined(DEBUG)
+ TRACE("TouchEvent: %d, %d, %d, %d", touchEventOccured, lastHasTouch, hasTouch, result);
+#endif
+ return result;
+}
+
+TouchState touchPanelRead()
+{
+ if (!touchEventOccured) return internalTouchState;
+
+ touchEventOccured = false;
+
+ tmr10ms_t now = get_tmr10ms();
+ internalTouchState.tapCount = 0;
+
+ if (tc->detectTouch()) {
+ handleTouch();
+ if (internalTouchState.event == TE_DOWN && downTime == 0) {
+ downTime = now;
+ }
+ } else {
+ if (internalTouchState.event == TE_DOWN) {
+ internalTouchState.event = TE_UP;
+ if (now - downTime <= TAP_TIME) {
+ if (now - tapTime > TAP_TIME) {
+ tapCount = 1;
+ } else {
+ tapCount++;
+ }
+ internalTouchState.tapCount = tapCount;
+ tapTime = now;
+ } else {
+ internalTouchState.tapCount = 0; // not a tap
+ }
+ downTime = 0;
+ } else {
+ tapCount = 0;
+ internalTouchState.tapCount = 0;
+ internalTouchState.event = TE_SLIDE_END;
+ }
+ }
+ TouchState ret = internalTouchState;
+ internalTouchState.deltaX = 0;
+ internalTouchState.deltaY = 0;
+ if(internalTouchState.event == TE_UP || internalTouchState.event == TE_SLIDE_END)
+ internalTouchState.event = TE_NONE;
+
+#if defined(DEBUG)
+ TRACE("%s: Event = %d", touchController == TC_CST340 ? "CST340" : "FT6236", ret.event);
+#endif
+
+ return ret;
+}
+
+TouchState getInternalTouchState()
+{
+ return internalTouchState;
+}
diff --git a/radio/src/targets/pl18/tp_cst340.h b/radio/src/targets/pl18/tp_cst340.h
new file mode 100644
index 00000000000..ec5f1610749
--- /dev/null
+++ b/radio/src/targets/pl18/tp_cst340.h
@@ -0,0 +1,289 @@
+/*
+ * Copyright (C) EdgeTX
+ *
+ * Based on code named
+ * opentx - https://github.com/opentx/opentx
+ * th9x - http://code.google.com/p/th9x
+ * er9x - http://code.google.com/p/er9x
+ * gruvin9x - http://code.google.com/p/gruvin9x
+ *
+ * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#pragma once
+
+#include "touch.h"
+
+typedef struct
+{
+ /* field holding the current number of simultaneous active touches */
+ uint8_t currActiveTouchNb;
+
+ /* field holding the touch index currently managed */
+ uint8_t currActiveTouchIdx;
+
+} tc_handle_TypeDef;
+
+
+#define TOUCH_FT6236_MAX_TOUCH_POINTS 2
+
+#define TOUCH_FT6236_REG_TH_GROUP 0x80
+#define TOUCH_FT6236_REG_PERIODACTIVE 0x88
+#define TOUCH_FT6236_REG_LIB_VER_H 0xa1
+#define TOUCH_FT6236_REG_LIB_VER_L 0xa2
+#define TOUCH_FT6236_REG_CIPHER 0xa3
+#define TOUCH_FT6236_REG_FIRMID 0xa6
+#define TOUCH_FT6236_REG_FOCALTECH_ID 0xa8
+#define TOUCH_FT6236_REG_RELEASE_CODE_ID 0xaf
+
+#define TOUCH_FT6236_EVENT_PRESS_DOWN 0
+#define TOUCH_FT6236_EVENT_LIFT_UP 1
+#define TOUCH_FT6236_EVENT_CONTACT 2
+#define TOUCH_FT6236_EVENT_NO_EVENT 3
+
+#define TOUCH_FT6236_GESTURE_MOVE_FLAG 0x10
+#define TOUCH_FT6236_GESTURE_MOVE_UP 0x10
+#define TOUCH_FT6236_GESTURE_MOVE_RIGHT 0x14
+#define TOUCH_FT6236_GESTURE_MOVE_DOWN 0x18
+#define TOUCH_FT6236_GESTURE_MOVE_LEFT 0x1C
+#define TOUCH_FT6236_GESTURE_ZOOM_IN 0x48
+#define TOUCH_FT6236_GESTURE_ZOOM_OUT 0x49
+#define TOUCH_FT6236_GESTURE_NONE 0x00
+
+#define TOUCH_GESTURE_UP ((TOUCH_FT6236_GESTURE_MOVE_UP & 0x0F)+1)
+#define TOUCH_GESTURE_DOWN ((TOUCH_FT6236_GESTURE_MOVE_DOWN & 0x0F)+1)
+#define TOUCH_GESTURE_LEFT ((TOUCH_FT6236_GESTURE_MOVE_LEFT & 0x0F)+1)
+#define TOUCH_GESTURE_RIGHT ((TOUCH_FT6236_GESTURE_MOVE_RIGHT & 0x0F)+1)
+#define TOUCH_GESTURE_MOUSE_DOWN (0x80+TOUCH_FT6236_EVENT_PRESS_DOWN)
+#define TOUCH_GESTURE_MOUSE_UP (0x80+TOUCH_FT6236_EVENT_LIFT_UP)
+#define TOUCH_GESTURE_MOUSE_MOVE (0x80+TOUCH_FT6236_EVENT_CONTACT)
+#define TOUCH_GESTURE_MOUSE_NONE (0x80+TOUCH_FT6236_EVENT_NO_EVENT)
+
+
+
+ /* Maximum border values of the touchscreen pad */
+#define FT_6206_MAX_WIDTH ((uint16_t)800) /* Touchscreen pad max width */
+#define FT_6206_MAX_HEIGHT ((uint16_t)480) /* Touchscreen pad max height */
+
+ /* Possible values of driver functions return status */
+#define FT6206_STATUS_OK 0
+#define FT6206_STATUS_NOT_OK 1
+
+ /* Max detectable simultaneous touches */
+#define FT6206_MAX_DETECTABLE_TOUCH 2
+
+ /**
+ * @brief : Definitions for FT6206 I2C register addresses on 8 bit
+ **/
+
+ /* Current mode register of the FT6206 (R/W) */
+#define FT6206_DEV_MODE_REG 0x00
+
+ /* Possible values of FT6206_DEV_MODE_REG */
+#define FT6206_DEV_MODE_WORKING 0x00
+#define FT6206_DEV_MODE_FACTORY 0x04
+
+#define FT6206_DEV_MODE_MASK 0x7
+#define FT6206_DEV_MODE_SHIFT 4
+
+ /* Gesture ID register */
+#define FT6206_GEST_ID_REG 0x01
+
+ /* Possible values of FT6206_GEST_ID_REG */
+#define FT6206_GEST_ID_NO_GESTURE 0x00
+#define FT6206_GEST_ID_MOVE_UP 0x10
+#define FT6206_GEST_ID_MOVE_RIGHT 0x14
+#define FT6206_GEST_ID_MOVE_DOWN 0x18
+#define FT6206_GEST_ID_MOVE_LEFT 0x1C
+#define FT6206_GEST_ID_ZOOM_IN 0x48
+#define FT6206_GEST_ID_ZOOM_OUT 0x49
+
+ /* Touch Data Status register : gives number of active touch points (0..2) */
+#define FT6206_TD_STAT_REG 0x02
+
+ /* Values related to FT6206_TD_STAT_REG */
+#define FT6206_TD_STAT_MASK 0x0F
+#define FT6206_TD_STAT_SHIFT 0x00
+
+ /* Values Pn_XH and Pn_YH related */
+#define FT6206_TOUCH_EVT_FLAG_PRESS_DOWN 0x00
+#define FT6206_TOUCH_EVT_FLAG_LIFT_UP 0x01
+#define FT6206_TOUCH_EVT_FLAG_CONTACT 0x02
+#define FT6206_TOUCH_EVT_FLAG_NO_EVENT 0x03
+
+#define FT6206_TOUCH_EVT_FLAG_SHIFT 6
+#define FT6206_TOUCH_EVT_FLAG_MASK (3 << FT6206_TOUCH_EVT_FLAG_SHIFT)
+
+#define FT6206_MSB_MASK 0x0F
+#define FT6206_MSB_SHIFT 0
+
+ /* Values Pn_XL and Pn_YL related */
+#define FT6206_LSB_MASK 0xFF
+#define FT6206_LSB_SHIFT 0
+
+#define FT6206_P1_XH_REG 0x03
+#define FT6206_P1_XL_REG 0x04
+#define FT6206_P1_YH_REG 0x05
+#define FT6206_P1_YL_REG 0x06
+
+ /* Touch Pressure register value (R) */
+#define FT6206_P1_WEIGHT_REG 0x07
+
+ /* Values Pn_WEIGHT related */
+#define FT6206_TOUCH_WEIGHT_MASK 0xFF
+#define FT6206_TOUCH_WEIGHT_SHIFT 0
+
+ /* Touch area register */
+#define FT6206_P1_MISC_REG 0x08
+
+ /* Values related to FT6206_Pn_MISC_REG */
+#define FT6206_TOUCH_AREA_MASK (0x04 << 4)
+#define FT6206_TOUCH_AREA_SHIFT 0x04
+
+#define FT6206_P2_XH_REG 0x09
+#define FT6206_P2_XL_REG 0x0A
+#define FT6206_P2_YH_REG 0x0B
+#define FT6206_P2_YL_REG 0x0C
+#define FT6206_P2_WEIGHT_REG 0x0D
+#define FT6206_P2_MISC_REG 0x0E
+
+ /* Threshold for touch detection */
+#define FT6206_TH_GROUP_REG 0x80
+
+ /* Values FT6206_TH_GROUP_REG : threshold related */
+#define FT6206_THRESHOLD_MASK 0xFF
+#define FT6206_THRESHOLD_SHIFT 0
+
+ /* Filter function coefficients */
+#define FT6206_TH_DIFF_REG 0x85
+
+ /* Control register */
+#define FT6206_CTRL_REG 0x86
+
+ /* Values related to FT6206_CTRL_REG */
+
+ /* Will keep the Active mode when there is no touching */
+#define FT6206_CTRL_KEEP_ACTIVE_MODE 0x00
+
+ /* Switching from Active mode to Monitor mode automatically when there is no touching */
+#define FT6206_CTRL_KEEP_AUTO_SWITCH_MONITOR_MODE 0x01
+
+ /* The time period of switching from Active mode to Monitor mode when there is no touching */
+#define FT6206_TIMEENTERMONITOR_REG 0x87
+
+ /* Report rate in Active mode */
+#define FT6206_PERIODACTIVE_REG 0x88
+
+ /* Report rate in Monitor mode */
+#define FT6206_PERIODMONITOR_REG 0x89
+
+ /* The value of the minimum allowed angle while Rotating gesture mode */
+#define FT6206_RADIAN_VALUE_REG 0x91
+
+ /* Maximum offset while Moving Left and Moving Right gesture */
+#define FT6206_OFFSET_LEFT_RIGHT_REG 0x92
+
+ /* Maximum offset while Moving Up and Moving Down gesture */
+#define FT6206_OFFSET_UP_DOWN_REG 0x93
+
+ /* Minimum distance while Moving Left and Moving Right gesture */
+#define FT6206_DISTANCE_LEFT_RIGHT_REG 0x94
+
+ /* Minimum distance while Moving Up and Moving Down gesture */
+#define FT6206_DISTANCE_UP_DOWN_REG 0x95
+
+ /* Maximum distance while Zoom In and Zoom Out gesture */
+#define FT6206_DISTANCE_ZOOM_REG 0x96
+
+ /* High 8-bit of LIB Version info */
+#define FT6206_LIB_VER_H_REG 0xA1
+
+ /* Low 8-bit of LIB Version info */
+#define FT6206_LIB_VER_L_REG 0xA2
+
+ /* Chip Selecting */
+#define FT6206_CIPHER_REG 0xA3
+
+ /* Interrupt mode register (used when in interrupt mode) */
+#define FT6206_GMODE_REG 0xA4
+
+#define FT6206_G_MODE_INTERRUPT_MASK 0x03
+#define FT6206_G_MODE_INTERRUPT_SHIFT 0x00
+
+ /* Possible values of FT6206_GMODE_REG */
+#define FT6206_G_MODE_INTERRUPT_POLLING 0x00
+#define FT6206_G_MODE_INTERRUPT_TRIGGER 0x01
+
+ /* Current power mode the FT6206 system is in (R) */
+#define FT6206_PWR_MODE_REG 0xA5
+
+ /* FT6206 firmware version */
+#define FT6206_FIRMID_REG 0xA6
+
+ /* FT6206 Chip identification register */
+#define FT6206_CHIP_ID_REG 0xA8
+
+ /* Possible values of FT6206_CHIP_ID_REG */
+#define FT6206_ID_VALUE 0x11
+
+ /* Release code version */
+#define FT6206_RELEASE_CODE_ID_REG 0xAF
+
+ /* Current operating mode the FT6206 system is in (R) */
+#define FT6206_STATE_REG 0xBC
+
+
+
+#define HAS_TOUCH_PANEL() touchCST340Flag == true
+
+#define CST340_MODE_DEBUG_INFO 0xD101 // To read out chip ID and firmware version
+#define CST340_MODE_NORMAL 0xD109 // Normal mode
+#define CST340_FINGER1_REG 0xD000 // Touch info register
+#define CST340_CHIPTYPE_REG 0xD204 // uint16_t chip IC type & uint16_t project ID register
+#define CST340_FWVER_REG 0xD208 // Firmware version register(uint8_t major, uint8_t minor, uint16_t build)
+#define CST340_TOUCH_EVT_FLAG_CONTACT 6
+
+#define CST340_CHIP_ID 0x011C // Expected answer to CST340_CHIPTYPE_REG query for the ChipID field
+
+#define TOUCH_POINTS_MAX 5 // Max touch points
+
+#define TOUCH_ACK 0
+#define TOUCH_NACK 1
+
+#define CST340_I2C_ADDR 0x1A
+
+extern bool touchCST340Flag;
+extern uint32_t touchI2Chiccups;
+extern uint16_t touchICfwver;
+void TouchInit();
+
+struct TouchState touchPanelRead();
+bool touchPanelEventOccured();
+
+PACK(typedef struct {
+ uint8_t track;
+ uint16_t x;
+ uint16_t y;
+ uint16_t size;
+ uint8_t reserved;
+}) TouchPoint;
+
+PACK(struct TouchData {
+ union
+ {
+ TouchPoint points[TOUCH_POINTS_MAX];
+ uint8_t data[TOUCH_POINTS_MAX * sizeof(TouchPoint)];
+ };
+});
+
+#define TPRST_LOW() do { TOUCH_RST_GPIO->BSRRH = TOUCH_RST_GPIO_PIN; } while(0)
+#define TPRST_HIGH() do { TOUCH_RST_GPIO->BSRRL = TOUCH_RST_GPIO_PIN; } while(0)
diff --git a/radio/src/targets/simu/opentxsimulator.cpp b/radio/src/targets/simu/opentxsimulator.cpp
index 3c13292347f..4f51bc44bb2 100644
--- a/radio/src/targets/simu/opentxsimulator.cpp
+++ b/radio/src/targets/simu/opentxsimulator.cpp
@@ -712,6 +712,8 @@ class OpenTxSimulatorFactory: public SimulatorFactory
return Board::BOARD_TARANIS_X9LITE;
#elif defined(PCBNV14)
return Board::BOARD_FLYSKY_NV14;
+#elif defined(PCBPL18)
+ return Board::BOARD_FLYSKY_PL18;
#else
return Board::BOARD_TARANIS_X9D;
#endif
diff --git a/radio/src/targets/simu/simpgmspace.cpp b/radio/src/targets/simu/simpgmspace.cpp
index 76aaef71ee2..04e6dff25dd 100644
--- a/radio/src/targets/simu/simpgmspace.cpp
+++ b/radio/src/targets/simu/simpgmspace.cpp
@@ -535,7 +535,7 @@ void boardOff()
void hapticOff() {}
-#if defined(PCBFRSKY) || defined(PCBFLYSKY)
+#if defined(PCBFRSKY) || defined(PCBNV14)
HardwareOptions hardwareOptions;
#endif
diff --git a/radio/src/targets/simu/simufatfs.cpp b/radio/src/targets/simu/simufatfs.cpp
index bd6abc90c0c..c1c15c63a97 100644
--- a/radio/src/targets/simu/simufatfs.cpp
+++ b/radio/src/targets/simu/simufatfs.cpp
@@ -616,6 +616,7 @@ FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs)
#include "hal/storage.h"
void storageInit() {}
+void storageDeInit() {}
void storagePreMountHook() {}
bool storageIsPresent() { return true; }
diff --git a/radio/src/targets/taranis/CMakeLists.txt b/radio/src/targets/taranis/CMakeLists.txt
index 7fc9ef2113c..4207ed87203 100644
--- a/radio/src/targets/taranis/CMakeLists.txt
+++ b/radio/src/targets/taranis/CMakeLists.txt
@@ -480,10 +480,6 @@ else()
message( FATAL_ERROR "Unknown CPU_TYPE_FULL" )
endif()
-if(NOT PCB STREQUAL PCBXLITE)
- add_definitions(-DHARDWARE_TRAINER_JACK)
-endif()
-
if(ENABLE_SERIAL_PASSTHROUGH)
set(CLI ON "Enable CLI")
endif()
diff --git a/radio/src/targets/taranis/board.h b/radio/src/targets/taranis/board.h
index 26bfff7d1d1..d5400c773d3 100644
--- a/radio/src/targets/taranis/board.h
+++ b/radio/src/targets/taranis/board.h
@@ -479,4 +479,12 @@ void setTopBatteryValue(uint32_t volts);
#define VOLTAGE_DROP 20
#endif
+#if defined(RADIO_T20)
+#define NUM_TRIMS 8
+#else
+#define NUM_TRIMS 4
+#endif
+
+#define NUM_TRIMS_KEYS (NUM_TRIMS * 2)
+
#endif // _BOARD_H_
diff --git a/radio/src/tasks.h b/radio/src/tasks.h
index 0e6181e5660..e12829108de 100644
--- a/radio/src/tasks.h
+++ b/radio/src/tasks.h
@@ -30,8 +30,15 @@
#else
#define MENUS_STACK_SIZE 2000
#endif
+
+#if !defined(DEBUG)
#define MIXER_STACK_SIZE 400
#define AUDIO_STACK_SIZE 400
+#else
+#define MIXER_STACK_SIZE 512
+#define AUDIO_STACK_SIZE 512
+#endif
+
#define CLI_STACK_SIZE 1024 // only consumed with CLI build option
#if defined(FREE_RTOS)
diff --git a/radio/src/tests/images/color/bitmap_480x320.png b/radio/src/tests/images/color/bitmap_480x320.png
new file mode 100644
index 00000000000..f3d818510e9
Binary files /dev/null and b/radio/src/tests/images/color/bitmap_480x320.png differ
diff --git a/radio/src/tests/images/color/clipping_480x320.png b/radio/src/tests/images/color/clipping_480x320.png
new file mode 100644
index 00000000000..f14ef839bd3
Binary files /dev/null and b/radio/src/tests/images/color/clipping_480x320.png differ
diff --git a/radio/src/tests/images/color/lines_480x320.png b/radio/src/tests/images/color/lines_480x320.png
new file mode 100644
index 00000000000..885a7a1e0ca
Binary files /dev/null and b/radio/src/tests/images/color/lines_480x320.png differ
diff --git a/radio/src/tests/images/color/masks_480x320.png b/radio/src/tests/images/color/masks_480x320.png
new file mode 100644
index 00000000000..21a81ec7fd7
Binary files /dev/null and b/radio/src/tests/images/color/masks_480x320.png differ
diff --git a/radio/src/tests/images/color/primitives_EN_480x320.png b/radio/src/tests/images/color/primitives_EN_480x320.png
new file mode 100644
index 00000000000..365a2a20fb2
Binary files /dev/null and b/radio/src/tests/images/color/primitives_EN_480x320.png differ
diff --git a/radio/src/tests/images/color/transparency_EN_480x320.png b/radio/src/tests/images/color/transparency_EN_480x320.png
new file mode 100644
index 00000000000..54827cd1611
Binary files /dev/null and b/radio/src/tests/images/color/transparency_EN_480x320.png differ
diff --git a/radio/src/tests/images/color/vline_480x320.png b/radio/src/tests/images/color/vline_480x320.png
new file mode 100644
index 00000000000..7acb28b2413
Binary files /dev/null and b/radio/src/tests/images/color/vline_480x320.png differ
diff --git a/radio/src/translations/cn.h b/radio/src/translations/cn.h
index f338756d2e4..4f144dc0653 100644
--- a/radio/src/translations/cn.h
+++ b/radio/src/translations/cn.h
@@ -216,7 +216,7 @@
#if defined(PCBFRSKY)
#define TR_ENTER "[ENTER]"
-#elif defined(PCBNV14)
+#elif defined(PCBNV14) || defined(PCBPL18)
#define TR_ENTER "[NEXT]"
#else
#define TR_ENTER "[MENU]"
@@ -1032,6 +1032,16 @@
#define TR_BL_SELECT_KEY "[R TRIM] to select file"
#define TR_BL_FLASH_KEY "Hold [R TRIM] long to flash"
#define TR_BL_EXIT_KEY " [L TRIM] to exit"
+#elif defined(PCBPL18)
+ // Bootloader PL18 specific - Ascii only
+ #define TR_BL_RF_USB_ACCESS "RF USB access"
+ #define TR_BL_ERASE_INT_FLASH "Erase Internal Flash Storage"
+ #define TR_BL_ERASE_FLASH "Erase Flash Storage"
+ #define TR_BL_ERASE_FLASH_MSG "This may take up to 200s"
+ #define TR_BL_SELECT_KEY " [TR4 Dn] to select file"
+ #define TR_BL_FLASH_KEY " Hold [TR4 Dn] long to flash"
+ #define TR_BL_ERASE_KEY " Hold [TR4 Dn] long to erase"
+ #define TR_BL_EXIT_KEY " [TR4 Up] to exit"
#endif
// About screen
diff --git a/radio/src/translations/cz.h b/radio/src/translations/cz.h
index aa001fff4e2..a3e8df750a3 100644
--- a/radio/src/translations/cz.h
+++ b/radio/src/translations/cz.h
@@ -229,7 +229,7 @@
#if defined(PCBTARANIS) || defined(PCBHORUS)
#define TR_ENTER "[ENTER]"
-#elif defined(PCBNV14)
+#elif defined(PCBNV14) || defined(PCBPL18)
#define TR_ENTER "[DALŠÍ]"
#else
#define TR_ENTER "[MENU]"
@@ -330,7 +330,7 @@
#define TR_SLOWUP TR3("Zpomalení(+)", "Zpomal(\176)", "Zpomalení(\176)")
#define TR_MIXES "MIXER"
#define TR_CV "K"
-#if defined(PCBNV14)
+#if defined(PCBNV14) || defined(PCBPL18)
#define TR_GV "GP"
#else
#define TR_GV TR("G", "GP")
@@ -1053,6 +1053,16 @@
#define TR_BL_SELECT_KEY "[R TRIM] pro vybrani souboru"
#define TR_BL_FLASH_KEY "Drzet dlouze [R TRIM] pro nahrani"
#define TR_BL_EXIT_KEY " [L TRIM] pro ukonceni"
+#elif defined(PCBPL18)
+ // Bootloader PL18 specific - Ascii only
+ #define TR_BL_RF_USB_ACCESS "RF USB access"
+ #define TR_BL_ERASE_INT_FLASH "Erase Internal Flash Storage"
+ #define TR_BL_ERASE_FLASH "Erase Flash Storage"
+ #define TR_BL_ERASE_FLASH_MSG "This may take up to 200s"
+ #define TR_BL_SELECT_KEY " [TR4 Dn] to select file"
+ #define TR_BL_FLASH_KEY " Hold [TR4 Dn] long to flash"
+ #define TR_BL_ERASE_KEY " Hold [TR4 Dn] long to erase"
+ #define TR_BL_EXIT_KEY " [TR4 Up] to exit"
#endif
// About screen
diff --git a/radio/src/translations/da.h b/radio/src/translations/da.h
index 6b234030acb..ecffd00d5e1 100644
--- a/radio/src/translations/da.h
+++ b/radio/src/translations/da.h
@@ -1046,6 +1046,16 @@
#define TR_BL_SELECT_KEY "[R TRIM] for at bruge fil"
#define TR_BL_FLASH_KEY "[R TRIM] lang til for at starte"
#define TR_BL_EXIT_KEY "[L TRIM] for at forlade"
+#elif defined(PCBPL18)
+ // Bootloader PL18 specific - Ascii only
+ #define TR_BL_RF_USB_ACCESS "RF USB access"
+ #define TR_BL_ERASE_INT_FLASH "Erase Internal Flash Storage"
+ #define TR_BL_ERASE_FLASH "Erase Flash Storage"
+ #define TR_BL_ERASE_FLASH_MSG "This may take up to 200s"
+ #define TR_BL_SELECT_KEY " [TR4 Dn] to select file"
+ #define TR_BL_FLASH_KEY " Hold [TR4 Dn] long to flash"
+ #define TR_BL_ERASE_KEY " Hold [TR4 Dn] long to erase"
+ #define TR_BL_EXIT_KEY " [TR4 Up] to exit"
#endif
// About screen
diff --git a/radio/src/translations/de.h b/radio/src/translations/de.h
index 9b1697762e1..e406ceabaf6 100644
--- a/radio/src/translations/de.h
+++ b/radio/src/translations/de.h
@@ -220,7 +220,7 @@
#if defined(PCBFRSKY)
#define TR_ENTER "[ENTER]"
-#elif defined(PCBNV14)
+#elif defined(PCBNV14) || defined(PCBPL18)
#define TR_ENTER "[NEXT]"
#else
#define TR_ENTER "[MENU]"
@@ -321,7 +321,7 @@
#define TR_SLOWUP "Langs.Up"
#define TR_MIXES "MISCHER"
#define TR_CV "KV"
-#if defined(PCBNV14)
+#if defined(PCBNV14) || defined(PCBPL18)
#define TR_GV "GV"
#else
#define TR_GV TR("G", "GV")
@@ -1034,6 +1034,16 @@
#define TR_BL_SELECT_KEY "[R TRIM] um Datei auszuwählen"
#define TR_BL_FLASH_KEY "Halte [R TRIM] gedrückt, zum schreiben"
#define TR_BL_EXIT_KEY " [L TRIM] zum beenden"
+#elif defined(PCBPL18)
+ // Bootloader PL18 specific - Ascii only
+ #define TR_BL_RF_USB_ACCESS "RF USB access"
+ #define TR_BL_ERASE_INT_FLASH "Erase Internal Flash Storage"
+ #define TR_BL_ERASE_FLASH "Erase Flash Storage"
+ #define TR_BL_ERASE_FLASH_MSG "This may take up to 200s"
+ #define TR_BL_SELECT_KEY " [TR4 Dn] to select file"
+ #define TR_BL_FLASH_KEY " Hold [TR4 Dn] long to flash"
+ #define TR_BL_ERASE_KEY " Hold [TR4 Dn] long to erase"
+ #define TR_BL_EXIT_KEY " [TR4 Up] to exit"
#endif
// Taranis Info Zeile Anzeigen
diff --git a/radio/src/translations/en.h b/radio/src/translations/en.h
index 05e9267a613..43750aa4d8f 100644
--- a/radio/src/translations/en.h
+++ b/radio/src/translations/en.h
@@ -220,7 +220,7 @@
#if defined(PCBFRSKY)
#define TR_ENTER "[ENTER]"
-#elif defined(PCBNV14)
+#elif defined(PCBNV14) || defined(PCBPL18)
#define TR_ENTER "[NEXT]"
#else
#define TR_ENTER "[MENU]"
@@ -320,7 +320,7 @@
#define TR_SLOWUP "Slow up"
#define TR_MIXES "MIXES"
#define TR_CV "CV"
-#if defined(PCBNV14)
+#if defined(PCBNV14) || defined(PCBPL18)
#define TR_GV "GV"
#else
#define TR_GV TR("G", "GV")
@@ -1042,6 +1042,16 @@
#define TR_BL_SELECT_KEY "[R TRIM] to select file"
#define TR_BL_FLASH_KEY "Hold [R TRIM] long to flash"
#define TR_BL_EXIT_KEY " [L TRIM] to exit"
+#elif defined(PCBPL18)
+ // Bootloader PL18 specific - Ascii only
+ #define TR_BL_RF_USB_ACCESS "RF USB access"
+ #define TR_BL_ERASE_INT_FLASH "Erase Internal Flash Storage"
+ #define TR_BL_ERASE_FLASH "Erase Flash Storage"
+ #define TR_BL_ERASE_FLASH_MSG "This may take up to 200s"
+ #define TR_BL_SELECT_KEY " [TR4 Dn] to select file"
+ #define TR_BL_FLASH_KEY " Hold [TR4 Dn] long to flash"
+ #define TR_BL_ERASE_KEY " Hold [TR4 Dn] long to erase"
+ #define TR_BL_EXIT_KEY " [TR4 Up] to exit"
#endif
// About screen
diff --git a/radio/src/translations/es.h b/radio/src/translations/es.h
index 71d1448c879..254c9866112 100644
--- a/radio/src/translations/es.h
+++ b/radio/src/translations/es.h
@@ -216,7 +216,7 @@
#if defined(PCBTARANIS) || defined(PCBHORUS)
#define TR_ENTER "[ENTER]"
-#elif defined(PCBNV14)
+#elif defined(PCBNV14) || defined(PCBPL18)
#define TR_ENTER "[NEXT]"
#else
#define TR_ENTER "[MENU]"
@@ -318,7 +318,7 @@
#define TR_SLOWUP "Subir lento"
#define TR_MIXES "MIXES"
#define TR_CV "CV"
-#if defined(PCBNV14)
+#if defined(PCBNV14) || defined(PCBPL18)
#define TR_GV "GV"
#else
#define TR_GV TR("G", "GV")
@@ -1044,6 +1044,16 @@
#define TR_BL_SELECT_KEY "[R TRIM] to select file"
#define TR_BL_FLASH_KEY "Hold [R TRIM] long to flash"
#define TR_BL_EXIT_KEY " [L TRIM] to exit"
+#elif defined(PCBPL18)
+ // Bootloader PL18 specific - Ascii only
+ #define TR_BL_RF_USB_ACCESS "RF USB access"
+ #define TR_BL_ERASE_INT_FLASH "Erase Internal Flash Storage"
+ #define TR_BL_ERASE_FLASH "Erase Flash Storage"
+ #define TR_BL_ERASE_FLASH_MSG "This may take up to 200s"
+ #define TR_BL_SELECT_KEY " [TR4 Dn] to select file"
+ #define TR_BL_FLASH_KEY " Hold [TR4 Dn] long to flash"
+ #define TR_BL_ERASE_KEY " Hold [TR4 Dn] long to erase"
+ #define TR_BL_EXIT_KEY " [TR4 Up] to exit"
#endif
// About screen
diff --git a/radio/src/translations/fi.h b/radio/src/translations/fi.h
index acc72488422..6814f004e32 100644
--- a/radio/src/translations/fi.h
+++ b/radio/src/translations/fi.h
@@ -1057,6 +1057,16 @@
#define TR_BL_SELECT_KEY "[R TRIM] to select file"
#define TR_BL_FLASH_KEY "Hold [R TRIM] long to flash"
#define TR_BL_EXIT_KEY " [L TRIM] to exit"
+#elif defined(PCBPL18)
+ // Bootloader PL18 specific - Ascii only
+ #define TR_BL_RF_USB_ACCESS "RF USB access"
+ #define TR_BL_ERASE_INT_FLASH "Erase Internal Flash Storage"
+ #define TR_BL_ERASE_FLASH "Erase Flash Storage"
+ #define TR_BL_ERASE_FLASH_MSG "This may take up to 200s"
+ #define TR_BL_SELECT_KEY " [TR4 Dn] to select file"
+ #define TR_BL_FLASH_KEY " Hold [TR4 Dn] long to flash"
+ #define TR_BL_ERASE_KEY " Hold [TR4 Dn] long to erase"
+ #define TR_BL_EXIT_KEY " [TR4 Up] to exit"
#endif
// About screen
diff --git a/radio/src/translations/fr.h b/radio/src/translations/fr.h
index 490924f143d..c72e0d68ab3 100644
--- a/radio/src/translations/fr.h
+++ b/radio/src/translations/fr.h
@@ -226,7 +226,7 @@
#if defined(PCBFRSKY)
#define TR_ENTER "[ENTER]"
-#elif defined(PCBNV14)
+#elif defined(PCBNV14) || defined(PCBPL18)
#define TR_ENTER "[SUIVANT]"
#else
#define TR_ENTER "[MENU]"
@@ -327,7 +327,7 @@
#define TR_SLOWUP "Ralenti haut"
#define TR_MIXES "MIXEUR"
#define TR_CV "CV"
-#if defined(PCBNV14)
+#if defined(PCBNV14) || defined(PCBPL18)
#define TR_GV "VG"
#else
#define TR_GV TR("G", "VG")
@@ -1058,6 +1058,16 @@
#define TR_BL_SELECT_KEY "[R TRIM] pour sélect. fichier"
#define TR_BL_FLASH_KEY "Appui long [R TRIM] pour flasher"
#define TR_BL_EXIT_KEY " [L TRIM] pour quitter"
+#elif defined(PCBPL18)
+ // Bootloader PL18 specific - Ascii only
+ #define TR_BL_RF_USB_ACCESS "RF USB access"
+ #define TR_BL_ERASE_INT_FLASH "Erase Internal Flash Storage"
+ #define TR_BL_ERASE_FLASH "Erase Flash Storage"
+ #define TR_BL_ERASE_FLASH_MSG "This may take up to 200s"
+ #define TR_BL_SELECT_KEY " [TR4 Dn] to select file"
+ #define TR_BL_FLASH_KEY " Hold [TR4 Dn] long to flash"
+ #define TR_BL_ERASE_KEY " Hold [TR4 Dn] long to erase"
+ #define TR_BL_EXIT_KEY " [TR4 Up] to exit"
#endif
// About screen
diff --git a/radio/src/translations/he.h b/radio/src/translations/he.h
index 234335035be..a2c47087b76 100644
--- a/radio/src/translations/he.h
+++ b/radio/src/translations/he.h
@@ -1050,6 +1050,16 @@
#define TR_BL_SELECT_KEY "[R TRIM] to select file"
#define TR_BL_FLASH_KEY "Hold [R TRIM] long to flash"
#define TR_BL_EXIT_KEY " [L TRIM] ליציאה"
+#elif defined(PCBPL18)
+ // Bootloader PL18 specific - Ascii only
+ #define TR_BL_RF_USB_ACCESS "RF USB access"
+ #define TR_BL_ERASE_INT_FLASH "Erase Internal Flash Storage"
+ #define TR_BL_ERASE_FLASH "Erase Flash Storage"
+ #define TR_BL_ERASE_FLASH_MSG "This may take up to 200s"
+ #define TR_BL_SELECT_KEY " [TR4 Dn] to select file"
+ #define TR_BL_FLASH_KEY " Hold [TR4 Dn] long to flash"
+ #define TR_BL_ERASE_KEY " Hold [TR4 Dn] long to erase"
+ #define TR_BL_EXIT_KEY " [TR4 Up] to exit"
#endif
// About screen
diff --git a/radio/src/translations/it.h b/radio/src/translations/it.h
index 0b87268d50b..2489dd2f376 100644
--- a/radio/src/translations/it.h
+++ b/radio/src/translations/it.h
@@ -220,7 +220,7 @@
#if defined(PCBFRSKY)
#define TR_ENTER "[ENTER]"
-#elif defined(PCBNV14)
+#elif defined(PCBNV14) || defined(PCBPL18)
#define TR_ENTER "[NEXT]"
#else
#define TR_ENTER "[MENU]"
@@ -320,7 +320,7 @@
#define TR_SLOWUP "Rall.Su"
#define TR_MIXES "MIXER"
#define TR_CV "CV"
-#if defined(PCBNV14)
+#if defined(PCBNV14) || defined(PCBPL18)
#define TR_GV "GV"
#else
#define TR_GV TR("G", "GV")
@@ -1041,6 +1041,16 @@
#define TR_BL_SELECT_KEY "[R TRIM] per scegliere il file"
#define TR_BL_FLASH_KEY "Tener premuto [R TRIM] per scrivere"
#define TR_BL_EXIT_KEY " [L TRIM] per uscire"
+#elif defined(PCBPL18)
+ // Bootloader PL18 specific - Ascii only
+ #define TR_BL_RF_USB_ACCESS "RF USB access"
+ #define TR_BL_ERASE_INT_FLASH "Erase Internal Flash Storage"
+ #define TR_BL_ERASE_FLASH "Erase Flash Storage"
+ #define TR_BL_ERASE_FLASH_MSG "This may take up to 200s"
+ #define TR_BL_SELECT_KEY " [TR4 Dn] to select file"
+ #define TR_BL_FLASH_KEY " Hold [TR4 Dn] long to flash"
+ #define TR_BL_ERASE_KEY " Hold [TR4 Dn] long to erase"
+ #define TR_BL_EXIT_KEY " [TR4 Up] to exit"
#endif
// About screen
diff --git a/radio/src/translations/jp.h b/radio/src/translations/jp.h
index 1e961499e0a..540897e2037 100644
--- a/radio/src/translations/jp.h
+++ b/radio/src/translations/jp.h
@@ -1037,6 +1037,16 @@
#define TR_BL_SELECT_KEY "[R TRIM] to select file"
#define TR_BL_FLASH_KEY "Hold [R TRIM] long to flash"
#define TR_BL_EXIT_KEY " [L TRIM] to exit"
+#elif defined(PCBPL18)
+ // Bootloader PL18 specific - Ascii only
+ #define TR_BL_RF_USB_ACCESS "RF USB access"
+ #define TR_BL_ERASE_INT_FLASH "Erase Internal Flash Storage"
+ #define TR_BL_ERASE_FLASH "Erase Flash Storage"
+ #define TR_BL_ERASE_FLASH_MSG "This may take up to 200s"
+ #define TR_BL_SELECT_KEY " [TR4 Dn] to select file"
+ #define TR_BL_FLASH_KEY " Hold [TR4 Dn] long to flash"
+ #define TR_BL_ERASE_KEY " Hold [TR4 Dn] long to erase"
+ #define TR_BL_EXIT_KEY " [TR4 Up] to exit"
#endif
// About screen
diff --git a/radio/src/translations/nl.h b/radio/src/translations/nl.h
index afe22cb2a53..e7850c53634 100644
--- a/radio/src/translations/nl.h
+++ b/radio/src/translations/nl.h
@@ -217,7 +217,7 @@
#if defined(PCBFRSKY)
#define TR_ENTER "[ENTER]"
-#elif defined(PCBNV14)
+#elif defined(PCBNV14) || defined(PCBPL18)
#define TR_ENTER "[NEXT]"
#else
#define TR_ENTER "[MENU]"
@@ -317,7 +317,7 @@
#define TR_SLOWUP "Langz.Up"
#define TR_MIXES "MIXER"
#define TR_CV "CV"
-#if defined(PCBNV14)
+#if defined(PCBNV14) || defined(PCBPL18)
#define TR_GV "GV"
#else
#define TR_GV TR("G", "GV")
@@ -1049,6 +1049,16 @@
#define TR_BL_SELECT_KEY "[R TRIM] to select file"
#define TR_BL_FLASH_KEY "Hold [R TRIM] long to flash"
#define TR_BL_EXIT_KEY " [L TRIM] to exit"
+#elif defined(PCBPL18)
+ // Bootloader PL18 specific - Ascii only
+ #define TR_BL_RF_USB_ACCESS "RF USB access"
+ #define TR_BL_ERASE_INT_FLASH "Erase Internal Flash Storage"
+ #define TR_BL_ERASE_FLASH "Erase Flash Storage"
+ #define TR_BL_ERASE_FLASH_MSG "This may take up to 200s"
+ #define TR_BL_SELECT_KEY " [TR4 Dn] to select file"
+ #define TR_BL_FLASH_KEY " Hold [TR4 Dn] long to flash"
+ #define TR_BL_ERASE_KEY " Hold [TR4 Dn] long to erase"
+ #define TR_BL_EXIT_KEY " [TR4 Up] to exit"
#endif
// About screen
diff --git a/radio/src/translations/pl.h b/radio/src/translations/pl.h
index 7dcb4acd8c1..0ddc68d059c 100644
--- a/radio/src/translations/pl.h
+++ b/radio/src/translations/pl.h
@@ -216,7 +216,7 @@
#if defined(PCBTARANIS) || defined(PCBHORUS)
#define TR_ENTER "[ENTER]"
-#elif defined(PCBNV14)
+#elif defined(PCBNV14) || defined(PCBPL18)
#define TR_ENTER "[NEXT]"
#else
#define TR_ENTER "[MENU]"
@@ -318,7 +318,7 @@
#define TR_SLOWUP "Spowoln.(+)"
#define TR_MIXES "MIKSERY"
#define TR_CV "Kr"
-#if defined(PCBNV14)
+#if defined(PCBNV14) || defined(PCBPL18)
#define TR_GV "ZG"
#else
#define TR_GV TR("G", "ZG")
@@ -1039,6 +1039,16 @@
#define TR_BL_SELECT_KEY "[R TRIM] aby wybrac plik"
#define TR_BL_FLASH_KEY "Przytrzymaj [R TRIM] aby flashowac"
#define TR_BL_EXIT_KEY " [L TRIM] aby wyjsc"
+#elif defined(PCBPL18)
+ // Bootloader PL18 specific - Ascii only
+ #define TR_BL_RF_USB_ACCESS "RF USB access"
+ #define TR_BL_ERASE_INT_FLASH "Erase Internal Flash Storage"
+ #define TR_BL_ERASE_FLASH "Erase Flash Storage"
+ #define TR_BL_ERASE_FLASH_MSG "This may take up to 200s"
+ #define TR_BL_SELECT_KEY " [TR4 Dn] to select file"
+ #define TR_BL_FLASH_KEY " Hold [TR4 Dn] long to flash"
+ #define TR_BL_ERASE_KEY " Hold [TR4 Dn] long to erase"
+ #define TR_BL_EXIT_KEY " [TR4 Up] to exit"
#endif
// About screen
diff --git a/radio/src/translations/pt.h b/radio/src/translations/pt.h
index 2000191a1e8..44d38b0295b 100644
--- a/radio/src/translations/pt.h
+++ b/radio/src/translations/pt.h
@@ -223,7 +223,7 @@
#if defined(PCBFRSKY)
#define TR_ENTER "[ENTER]"
-#elif defined(PCBNV14)
+#elif defined(PCBNV14) || defined(PCBPL18)
#define TR_ENTER "[NEXT]"
#else
#define TR_ENTER "[MENU]"
@@ -323,7 +323,7 @@
#define TR_SLOWUP "Slow up"
#define TR_MIXES "MIXES"
#define TR_CV "CV"
-#if defined(PCBNV14)
+#if defined(PCBNV14) || defined(PCBPL18)
#define TR_GV "GV"
#else
#define TR_GV TR("G", "GV")
@@ -1045,6 +1045,16 @@
#define TR_BL_SELECT_KEY "[R TRIM] to select file"
#define TR_BL_FLASH_KEY "Hold [R TRIM] long to flash"
#define TR_BL_EXIT_KEY " [L TRIM] to exit"
+#elif defined(PCBPL18)
+ // Bootloader PL18 specific - Ascii only
+ #define TR_BL_RF_USB_ACCESS "RF USB access"
+ #define TR_BL_ERASE_INT_FLASH "Erase Internal Flash Storage"
+ #define TR_BL_ERASE_FLASH "Erase Flash Storage"
+ #define TR_BL_ERASE_FLASH_MSG "This may take up to 200s"
+ #define TR_BL_SELECT_KEY " [TR4 Dn] to select file"
+ #define TR_BL_FLASH_KEY " Hold [TR4 Dn] long to flash"
+ #define TR_BL_ERASE_KEY " Hold [TR4 Dn] long to erase"
+ #define TR_BL_EXIT_KEY " [TR4 Up] to exit"
#endif
// About screen
diff --git a/radio/src/translations/ru.h b/radio/src/translations/ru.h
index eff4b3afc01..9679e3aa863 100644
--- a/radio/src/translations/ru.h
+++ b/radio/src/translations/ru.h
@@ -1044,6 +1044,16 @@
#define TR_BL_SELECT_KEY "[П ТРИМ] для выбора файла"
#define TR_BL_FLASH_KEY "Удерживайте [П ТРИМ] для прошивки"
#define TR_BL_EXIT_KEY "[Л ТРИМ] для выхода"
+#elif defined(PCBPL18)
+ // Bootloader PL18 specific - Ascii only
+ #define TR_BL_RF_USB_ACCESS "RF USB access"
+ #define TR_BL_ERASE_INT_FLASH "Erase Internal Flash Storage"
+ #define TR_BL_ERASE_FLASH "Erase Flash Storage"
+ #define TR_BL_ERASE_FLASH_MSG "This may take up to 200s"
+ #define TR_BL_SELECT_KEY " [TR4 Dn] to select file"
+ #define TR_BL_FLASH_KEY " Hold [TR4 Dn] long to flash"
+ #define TR_BL_ERASE_KEY " Hold [TR4 Dn] long to erase"
+ #define TR_BL_EXIT_KEY " [TR4 Up] to exit"
#endif
// About screen
diff --git a/radio/src/translations/se.h b/radio/src/translations/se.h
index 5af95224792..c3b427a1ecb 100644
--- a/radio/src/translations/se.h
+++ b/radio/src/translations/se.h
@@ -1071,6 +1071,16 @@
#define TR_BL_SELECT_KEY "[R TRIM] foer att vaelja fil"
#define TR_BL_FLASH_KEY "Tryck [R TRIM] foer att flasha"
#define TR_BL_EXIT_KEY " [L TRIM] för att avsluta"
+#elif defined(PCBPL18)
+ // Bootloader PL18 specific - Ascii only
+ #define TR_BL_RF_USB_ACCESS "RF USB access"
+ #define TR_BL_ERASE_INT_FLASH "Erase Internal Flash Storage"
+ #define TR_BL_ERASE_FLASH "Erase Flash Storage"
+ #define TR_BL_ERASE_FLASH_MSG "This may take up to 200s"
+ #define TR_BL_SELECT_KEY " [TR4 Dn] to select file"
+ #define TR_BL_FLASH_KEY " Hold [TR4 Dn] long to flash"
+ #define TR_BL_ERASE_KEY " Hold [TR4 Dn] long to erase"
+ #define TR_BL_EXIT_KEY " [TR4 Up] to exit"
#endif
// About screen
diff --git a/radio/src/translations/tw.h b/radio/src/translations/tw.h
index c589312a46e..0792092d191 100644
--- a/radio/src/translations/tw.h
+++ b/radio/src/translations/tw.h
@@ -1037,6 +1037,16 @@
#define TR_BL_SELECT_KEY "[R TRIM] to select file"
#define TR_BL_FLASH_KEY "Hold [R TRIM] long to flash"
#define TR_BL_EXIT_KEY " [L TRIM] to exit"
+#elif defined(PCBPL18)
+ // Bootloader PL18 specific - Ascii only
+ #define TR_BL_RF_USB_ACCESS "RF USB access"
+ #define TR_BL_ERASE_INT_FLASH "Erase Internal Flash Storage"
+ #define TR_BL_ERASE_FLASH "Erase Flash Storage"
+ #define TR_BL_ERASE_FLASH_MSG "This may take up to 200s"
+ #define TR_BL_SELECT_KEY " [TR4 Dn] to select file"
+ #define TR_BL_FLASH_KEY " Hold [TR4 Dn] long to flash"
+ #define TR_BL_ERASE_KEY " Hold [TR4 Dn] long to erase"
+ #define TR_BL_EXIT_KEY " [TR4 Up] to exit"
#endif
// About screen
diff --git a/radio/util/hw_defs/hal_keys.jinja b/radio/util/hw_defs/hal_keys.jinja
index 499a41a397c..15b563d94e3 100644
--- a/radio/util/hw_defs/hal_keys.jinja
+++ b/radio/util/hw_defs/hal_keys.jinja
@@ -14,14 +14,11 @@ const char* const _key_labels[] = {
{% endfor %}
};
-constexpr uint32_t _defined_keys =
+constexpr uint32_t _defined_keys = 0
{% for key in keys %}
- {% if loop.last %}
- (1 << {{ key.key }});
- {% else %}
- (1 << {{ key.key }}) |
- {% endif %}
+ | (1 << {{ key.key }})
{% endfor %}
+;
constexpr uint8_t _n_keys = {{ keys | length }};
constexpr uint8_t _n_trims = {{ trims | length }};
diff --git a/radio/util/hw_defs/legacy_names.py b/radio/util/hw_defs/legacy_names.py
index 77f21d27c08..a313326a791 100644
--- a/radio/util/hw_defs/legacy_names.py
+++ b/radio/util/hw_defs/legacy_names.py
@@ -338,6 +338,142 @@
}
}
},
+ {
+ "targets": {
+ "pl18"
+ },
+ "inputs": {
+ "LH": {
+ "yaml": "Rud"
+ },
+ "LV": {
+ "yaml": "Ele"
+ },
+ "RV": {
+ "yaml": "Thr"
+ },
+ "RH": {
+ "yaml": "Ail"
+ },
+ "P1": {
+ "yaml": "POT1",
+ "lua": "s1",
+ "label": "S1",
+ "short_label": "1",
+ "description": "Potentiometer 1"
+ },
+ "P2": {
+ "yaml": "POT2",
+ "lua": "s2",
+ "label": "S2",
+ "short_label": "2",
+ "description": "Potentiometer 2"
+ },
+ "P3": {
+ "yaml": "POT3",
+ "lua": "s3",
+ "label": "S3",
+ "short_label": "3",
+ "description": "Potentiometer 3"
+ },
+ "SL1": {
+ "yaml": "LS",
+ "lua": "ls",
+ "label": "LS",
+ "short_label": "L",
+ "description": "Left slider"
+ },
+ "SL2": {
+ "yaml": "RS",
+ "lua": "rs",
+ "label": "RS",
+ "short_label": "R",
+ "description": "Right slider"
+ },
+ }
+ },
+ {
+ "targets": {
+ "pl18ev"
+ },
+ "inputs": {
+ "LH": {
+ "yaml": "Rud"
+ },
+ "LV": {
+ "yaml": "Ele"
+ },
+ "RV": {
+ "yaml": "Thr"
+ },
+ "RH": {
+ "yaml": "Ail"
+ },
+ "P1": {
+ "yaml": "POT1",
+ "lua": "s1",
+ "label": "S1",
+ "short_label": "1",
+ "description": "Potentiometer 1"
+ },
+ "P2": {
+ "yaml": "POT2",
+ "lua": "s2",
+ "label": "S2",
+ "short_label": "2",
+ "description": "Potentiometer 2"
+ },
+ "P3": {
+ "yaml": "POT3",
+ "lua": "s3",
+ "label": "S3",
+ "short_label": "3",
+ "description": "Potentiometer 3"
+ },
+ "SL1": {
+ "yaml": "LS",
+ "lua": "ls",
+ "label": "LS",
+ "short_label": "L",
+ "description": "Left slider"
+ },
+ "SL2": {
+ "yaml": "RS",
+ "lua": "rs",
+ "label": "RS",
+ "short_label": "R",
+ "description": "Right slider"
+ },
+ "EXT1": {
+ "yaml": "EXT1",
+ "lua": "ext1",
+ "label": "EXT1",
+ "short_label": "E1",
+ "description": "Ext 1"
+ },
+ "EXT2": {
+ "yaml": "EXT2",
+ "lua": "ext2",
+ "label": "EXT2",
+ "short_label": "E2",
+ "description": "Ext 2"
+ },
+ "EXT3": {
+ "yaml": "EXT3",
+ "lua": "ext3",
+ "label": "EXT3",
+ "short_label": "E3",
+ "description": "Ext 3"
+ },
+ "EXT4": {
+ "yaml": "EXT4",
+ "lua": "ext4",
+ "label": "EXT4",
+ "short_label": "E4",
+ "description": "Ext 4"
+ }
+ }
+ },
{
"targets": {"t20"},
"inputs": {
diff --git a/radio/util/hw_defs/pot_config.py b/radio/util/hw_defs/pot_config.py
index 637ac16717e..f80cd6fa142 100644
--- a/radio/util/hw_defs/pot_config.py
+++ b/radio/util/hw_defs/pot_config.py
@@ -14,6 +14,24 @@
"P1": {"default": "POT_CENTER"},
"P2": {"default": "POT_CENTER"}
},
+ "pl18": {
+ "P1": {"default": "POT"},
+ "P2": {"default": "POT"},
+ "P3": {"default": "POT"},
+ "SL1": {"default": "SLIDER"},
+ "SL2": {"default": "SLIDER"}
+ },
+ "pl18ev": {
+ "P1": {"default": "POT_CENTER"},
+ "P2": {"default": "POT"},
+ "P3": {"default": "POT_CENTER"},
+ "SL1": {"default": "SLIDER"},
+ "SL2": {"default": "SLIDER"},
+ "EXT1": {"default": "POT_CENTER"},
+ "EXT2": {"default": "POT_CENTER"},
+ "EXT3": {"default": "MULTIPOS"},
+ "EXT4": {"default": "MULTIPOS"}
+ },
"mt12": {
"P1": {"default": "POT"},
"P2": {"default": "POT"},
diff --git a/radio/util/hw_defs/stm32_adc_inputs.jinja b/radio/util/hw_defs/stm32_adc_inputs.jinja
index b30ce7d2c2c..fc1103021f5 100644
--- a/radio/util/hw_defs/stm32_adc_inputs.jinja
+++ b/radio/util/hw_defs/stm32_adc_inputs.jinja
@@ -6,6 +6,7 @@
static const stm32_adc_input_t _ADC_inputs[] = {
{% for input in adc_inputs.inputs %}
{
+ // {{ input.name }}
// ADC_INPUT_{{ input.type }},
{{ input.gpio if input.gpio else 'nullptr' }},
{{ input.pin if input.gpio else '0' }},
diff --git a/radio/util/hw_defs/switch_config.py b/radio/util/hw_defs/switch_config.py
index 3d7cb80cd25..de3461f53ca 100644
--- a/radio/util/hw_defs/switch_config.py
+++ b/radio/util/hw_defs/switch_config.py
@@ -29,6 +29,28 @@
"SG": { "default": "3POS" },
"SH": { "default": "TOGGLE" }
},
+ "pl18": {
+ "SA": { "default": "2POS" },
+ "SB": { "default": "3POS" },
+ "SC": { "default": "2POS" },
+ "SD": { "default": "3POS" },
+ "SE": { "default": "3POS" },
+ "SF": { "default": "2POS" },
+ "SG": { "default": "3POS" },
+ "SH": { "default": "TOGGLE" }
+ },
+ "pl18ev": {
+ "SA": { "default": "2POS" },
+ "SB": { "default": "3POS" },
+ "SC": { "default": "2POS" },
+ "SD": { "default": "3POS" },
+ "SE": { "default": "3POS" },
+ "SF": { "default": "2POS" },
+ "SG": { "default": "3POS" },
+ "SH": { "default": "3POS" },
+ "SI": { "default": "3POS" },
+ "SJ": { "default": "3POS" }
+ },
"lr3pro": {
# left side
"SA": {"default": "3POS", "display": [0, 0]},
diff --git a/tools/build-companion.sh b/tools/build-companion.sh
index 128fba24c5c..d1dc928b62e 100755
--- a/tools/build-companion.sh
+++ b/tools/build-companion.sh
@@ -70,7 +70,7 @@ declare -a simulator_plugins=(x9lite x9lites
tlite tpro lr3pro
x9d x9dp x9dp2019 x9e
xlite xlites
- nv14
+ nv14 pl18 pl18ev
x10 x10-access x12s
t16 t18 tx16s)
@@ -170,6 +170,12 @@ do
commando8)
BUILD_OPTIONS+="-DPCB=X7 -DPCBREV=COMMANDO8"
;;
+ pl18)
+ BUILD_OPTIONS+="-DPCB=PL18"
+ ;;
+ pl18ev)
+ BUILD_OPTIONS+="-DPCB=PL18 -DPCBREV=PL18EV"
+ ;;
*)
echo "Unknown target: $target_name"
exit 1
diff --git a/tools/build-flysky.py b/tools/build-flysky.py
index c6c60ad74d0..22be920ccee 100644
--- a/tools/build-flysky.py
+++ b/tools/build-flysky.py
@@ -9,15 +9,10 @@
boards = {
- "NV14": {
- "PCB": "NV14",
- "DEFAULT_MODE": "1",
- },
- "EL18": {
- "PCB": "NV14",
- "PCBREV": "EL18",
- "DEFAULT_MODE": "1",
- },
+ "NV14": { "PCB": "NV14" },
+ "EL18": { "PCB": "NV14", "PCBREV": "EL18" },
+ "PL18": { "PCB": "PL18" },
+ "PL18EV": { "PCB": "PL18", "PCBREV": "PL18EV" },
}
translations = [
diff --git a/tools/build-gh.sh b/tools/build-gh.sh
index aa154af5959..16f0aa512ba 100755
--- a/tools/build-gh.sh
+++ b/tools/build-gh.sh
@@ -191,6 +191,12 @@ do
el18)
BUILD_OPTIONS+="-DPCB=NV14 -DPCBREV=EL18"
;;
+ pl18)
+ BUILD_OPTIONS+="-DPCB=PL18"
+ ;;
+ pl18ev)
+ BUILD_OPTIONS+="-DPCB=PL18 -DPCBREV=PL18EV"
+ ;;
commando8)
BUILD_OPTIONS+="-DPCB=X7 -DPCBREV=COMMANDO8"
;;
diff --git a/tools/commit-tests.sh b/tools/commit-tests.sh
index 66ea77e8516..1d9c9634f6d 100755
--- a/tools/commit-tests.sh
+++ b/tools/commit-tests.sh
@@ -148,6 +148,12 @@ do
el18)
BUILD_OPTIONS+="-DPCB=NV14 -DPCBREV=EL18"
;;
+ pl18)
+ BUILD_OPTIONS+="-DPCB=PL18"
+ ;;
+ pl18ev)
+ BUILD_OPTIONS+="-DPCB=PL18 -DPCBREV=PL18EV"
+ ;;
commando8)
BUILD_OPTIONS+="-DPCB=X7 -DPCBREV=COMMANDO8"
;;
diff --git a/tools/generate-yaml.sh b/tools/generate-yaml.sh
index aa1b04c33ec..cb834c7a05f 100755
--- a/tools/generate-yaml.sh
+++ b/tools/generate-yaml.sh
@@ -8,7 +8,7 @@ if [[ -n ${GCC_ARM} ]] ; then
export PATH=${GCC_ARM}:$PATH
fi
-: ${FLAVOR:="tx16s;x12s;nv14;x9d;x9dp;x9e;x9lite;xlites;x7;tpro;t20"}
+: ${FLAVOR:="tx16s;x12s;nv14;pl18;x9d;x9dp;x9e;x9lite;xlites;x7;tpro;t20"}
: ${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"}
@@ -110,6 +110,9 @@ do
nv14)
BUILD_OPTIONS+="-DPCB=NV14"
;;
+ pl18)
+ BUILD_OPTIONS+="-DPCB=PL18"
+ ;;
commando8)
BUILD_OPTIONS+="-DPCB=X7 -DPCBREV=COMMANDO8"
;;