1
0
Fork 0
mirror of https://github.com/EdgeTX/edgetx.git synced 2025-07-15 12:25:11 +03:00

feat: Flysky PL18 Support (#4105)

Co-authored-by: raphaelcoeffic <raphael.coeffic@frafos.com>
Co-authored-by: rotorman <risto.koiva@web.de>
Co-authored-by: Xy201207 <yaoxu@flysky.com>
Co-authored-by: Peter Feerick <peter.feerick@gmail.com>
This commit is contained in:
richardclli 2023-12-06 07:00:44 +08:00 committed by GitHub
parent 5153aaeea0
commit cc17046e7a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
128 changed files with 9178 additions and 171 deletions

View file

@ -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

View file

@ -16,6 +16,7 @@ jobs:
matrix:
target:
- nv14;el18
- pl18;pl18ev
- t12
- t16
- t18

View file

@ -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()

View file

@ -293,6 +293,10 @@
<file>images/simulator/NV14/right.png</file>
<file>images/simulator/NV14/top.png</file>
<file>images/simulator/NV14/bottom.png</file>
<file>images/simulator/PL18/left.png</file>
<file>images/simulator/PL18/right.png</file>
<file>images/simulator/PL18/top.png</file>
<file>images/simulator/PL18/bottom.png</file>
<file>images/wizard/ailerons.png</file>
<file>images/wizard/airbrakes.png</file>
<file>images/wizard/elevons.png</file>

View file

@ -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:

View file

@ -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)

View file

@ -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;

View file

@ -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));
}

View file

@ -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);

View file

@ -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);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 B

View file

@ -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);
}

View file

@ -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(" ");

View file

@ -40,6 +40,7 @@ set(${PROJECT_NAME}_SRCS
simulateduiwidgetJumperTPRO.cpp
simulateduiwidgetLR3PRO.cpp
simulateduiwidgetNV14.cpp
simulateduiwidgetPL18.cpp
simulateduiwidgetT8.cpp
simulateduiwidgetTX12.cpp
simulateduiwidgetTX16S.cpp

View file

@ -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

View file

@ -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<int>() << 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<int>() << 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<int>() << 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<int>() << 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<int>() << 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<int>() << 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<int>() << Qt::Key_Down << Qt::Key_Delete << Qt::Key_Escape << Qt::Key_Backspace,
SIMU_STR_HLP_KEY_DN % "<br>" % 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<int>() << 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<int>() << 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;
}

View file

@ -0,0 +1,206 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SimulatedUIWidgetPL18</class>
<widget class="QWidget" name="SimulatedUIWidgetPL18">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>520</width>
<height>500</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>520</width>
<height>500</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>520</width>
<height>500</height>
</size>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<property name="spacing">
<number>0</number>
</property>
<item row="0" column="2" rowspan="3">
<widget class="ButtonsWidget" name="rightbuttons" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>100</width>
<height>500</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>100</width>
<height>500</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">background:url(:/images/simulator/PL18/right.png)</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="LcdWidget" name="lcd" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>480</width>
<height>320</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>480</width>
<height>320</height>
</size>
</property>
<property name="font">
<font>
<pointsize>5</pointsize>
</font>
</property>
</widget>
</item>
<item row="0" column="0" rowspan="3">
<widget class="ButtonsWidget" name="leftbuttons" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>100</width>
<height>500</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>100</width>
<height>500</height>
</size>
</property>
<property name="mouseTracking">
<bool>true</bool>
</property>
<property name="styleSheet">
<string notr="true">background:url(:/images/simulator/PL18/left.png);</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QWidget" name="top" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>320</width>
<height>10</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>320</width>
<height>10</height>
</size>
</property>
<property name="font">
<font>
<pointsize>5</pointsize>
</font>
</property>
<property name="styleSheet">
<string notr="true">background:url(:/images/simulator/PL18/top.png)</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QWidget" name="bottom" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>320</width>
<height>10</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>320</width>
<height>10</height>
</size>
</property>
<property name="font">
<font>
<pointsize>5</pointsize>
<kerning>false</kerning>
</font>
</property>
<property name="styleSheet">
<string notr="true">background:url(:/images/simulator/PL18/bottom.png)</string>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>LcdWidget</class>
<extends>QWidget</extends>
<header>lcdwidget.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>ButtonsWidget</class>
<extends>QWidget</extends>
<header>buttonswidget.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View file

@ -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;

View file

@ -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-"],

View file

@ -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()

View file

@ -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()

View file

@ -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);

View file

@ -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;
}

View file

@ -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"

View file

@ -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, "<string to be encrypted>" },
#endif
#if defined(HARDWARE_TOUCH) && !defined(PCBNV14)
#if defined(HARDWARE_TOUCH) && !defined(PCBNV14) && !defined(PCBPL18)
{ "reset_gt911", cliResetGT911, ""},
#endif
{ nullptr, nullptr, nullptr } /* sentinel */

View file

@ -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
};

View file

@ -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

View file

@ -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

View file

@ -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__)

View file

@ -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();

View file

@ -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);

View file

@ -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]);
}

View file

@ -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) {

View file

@ -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;

View file

@ -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;

View file

@ -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

View file

@ -22,6 +22,8 @@
#include "key_driver.h"
#include "definitions.h"
#include "dataconstants.h"
#include "hal_keys.inc"
uint32_t keysGetSupported()

View file

@ -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();

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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;

View file

@ -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;

View file

@ -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()

View file

@ -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,

View file

@ -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)

View file

@ -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"

View file

@ -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)

View file

@ -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;
}

View file

@ -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})
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()
# 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)

View file

@ -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

View file

@ -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

View file

@ -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,
};

View file

@ -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

View file

@ -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();

View file

@ -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);

View file

@ -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);

View file

@ -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;

View file

@ -50,6 +50,7 @@ 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) ;

View file

@ -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

View file

@ -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;

View file

@ -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)

View file

@ -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)

View file

@ -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 \

View file

@ -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_

View file

@ -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
)

View file

@ -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;
}

View file

@ -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
}

View file

@ -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

View file

@ -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 <string.h>
#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;
}

View file

@ -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_

View file

@ -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 <lvgl/lvgl.h>
#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();
}

View file

@ -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();
}

View file

@ -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_

View file

@ -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);
}

View file

@ -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;
}

File diff suppressed because it is too large Load diff

View file

@ -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

View file

@ -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();
}

View file

@ -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

View file

@ -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();
}

View file

@ -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*) &reg, 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;
}

View file

@ -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();

View file

@ -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, &reg, 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;
}

View file

@ -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)

View file

@ -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

View file

@ -535,7 +535,7 @@ void boardOff()
void hapticOff() {}
#if defined(PCBFRSKY) || defined(PCBFLYSKY)
#if defined(PCBFRSKY) || defined(PCBNV14)
HardwareOptions hardwareOptions;
#endif

View file

@ -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; }

View file

@ -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()

View file

@ -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_

View file

@ -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)

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Some files were not shown because too many files have changed in this diff Show more