feat: Major serial driver re-write - see #1089 for details

Serial refactor
This commit is contained in:
Peter Feerick
2022-03-21 19:58:26 +10:00
committed by GitHub
717 changed files with 942251 additions and 4095 deletions
@@ -59,7 +59,7 @@ const YamlLookupTable bluetoothModeLut = {
{ GeneralSettings::BLUETOOTH_MODE_TRAINER, "TRAINER" },
};
const YamlLookupTable uartModeLut = {
const YamlLookupTable oldUartModeLut = {
{ GeneralSettings::AUX_SERIAL_OFF, "MODE_NONE" },
{ GeneralSettings::AUX_SERIAL_TELE_MIRROR, "MODE_TELEMETRY_MIRROR" },
{ GeneralSettings::AUX_SERIAL_TELE_IN, "MODE_TELEMETRY" },
@@ -67,6 +67,23 @@ const YamlLookupTable uartModeLut = {
{ GeneralSettings::AUX_SERIAL_LUA, "MODE_LUA" },
};
const YamlLookupTable serialPortLut = {
{ GeneralSettings::SP_AUX1, "AUX1" },
{ GeneralSettings::SP_AUX2, "AUX2" },
{ GeneralSettings::SP_VCP, "VCP" },
};
const YamlLookupTable uartModeLut = {
{ GeneralSettings::AUX_SERIAL_OFF, "NONE" },
{ GeneralSettings::AUX_SERIAL_TELE_MIRROR, "TELEMETRY_MIRROR" },
{ GeneralSettings::AUX_SERIAL_TELE_IN, "TELEMETRY" },
{ GeneralSettings::AUX_SERIAL_SBUS_TRAINER, "SBUS_TRAINER" },
{ GeneralSettings::AUX_SERIAL_LUA, "LUA" },
{ GeneralSettings::AUX_SERIAL_CLI, "CLI" },
{ GeneralSettings::AUX_SERIAL_GPS, "GPS" },
{ GeneralSettings::AUX_SERIAL_DEBUG, "DEBUG" },
};
const YamlLookupTable antennaModeLut = {
{ GeneralSettings::ANTENNA_MODE_INTERNAL, "MODE_INTERNAL" },
{ GeneralSettings::ANTENNA_MODE_ASK, "MODE_ASK" },
@@ -195,8 +212,17 @@ Node convert<GeneralSettings>::encode(const GeneralSettings& rhs)
node["varioRange"] = rhs.varioRange * 15;
node["varioRepeat"] = rhs.varioRepeat;
node["backgroundVolume"] = rhs.backgroundVolume + 2;
node["auxSerialMode"] = uartModeLut << rhs.auxSerialMode;
node["aux2SerialMode"] = uartModeLut << rhs.aux2SerialMode;
Node serialPort;
for (int i = 0; i < GeneralSettings::SP_COUNT; i++) {
if (rhs.serialPort[i] != UART_MODE_NONE) {
Node mode = uartModeLut << rhs.serialPort[i];
serialPort[LookupValue(serialPortLut, i)]["mode"] = mode;
}
}
if (serialPort && serialPort.IsMap())
node["serialPort"] = serialPort;
node["antennaMode"] = antennaModeLut << rhs.antennaMode;
node["backlightColor"] = rhs.backlightColor;
node["pwrOnSpeed"] = rhs.pwrOnSpeed;
@@ -372,8 +398,31 @@ bool convert<GeneralSettings>::decode(const Node& node, GeneralSettings& rhs)
node["varioRange"] >> ifactor<int>(rhs.varioRange, 15);
node["varioRepeat"] >> rhs.varioRepeat;
node["backgroundVolume"] >> ioffset_int(rhs.backgroundVolume, 2);
node["auxSerialMode"] >> uartModeLut >> rhs.auxSerialMode;
node["aux2SerialMode"] >> uartModeLut >> rhs.aux2SerialMode;
if (node["auxSerialMode"]) {
node["auxSerialMode"] >> oldUartModeLut >>
rhs.serialPort[GeneralSettings::SP_AUX1];
}
if (node["aux2SerialMode"]) {
node["aux2SerialMode"] >> oldUartModeLut >>
rhs.serialPort[GeneralSettings::SP_AUX2];
}
if (node["serialPort"]) {
Node serialPort = node["serialPort"];
if (serialPort.IsMap()) {
for (const auto& port : serialPort) {
YAML::Node port_nr = port.first >> serialPortLut;
if (port_nr) {
int p = port_nr.as<int>();
if (p >= 0 && p < GeneralSettings::SP_COUNT && port.second.IsMap())
port.second["mode"] >> uartModeLut >> rhs.serialPort[p];
}
}
}
}
node["antennaMode"] >> antennaModeLut >> rhs.antennaMode;
node["backlightColor"] >> rhs.backlightColor;
node["pwrOnSpeed"] >> rhs.pwrOnSpeed;
@@ -160,6 +160,7 @@ enum Capability {
Sensors,
HasAuxSerialMode,
HasAux2SerialMode,
HasVCPSerialMode,
HasBluetooth,
HasAntennaChoice,
HasADCJitterFilter,
+22 -6
View File
@@ -418,9 +418,12 @@ QString GeneralSettings::bluetoothModeToString() const
return bluetoothModeToString(bluetoothMode);
}
QString GeneralSettings::auxSerialModeToString() const
QString GeneralSettings::serialPortModeToString(int port_nr) const
{
return auxSerialModeToString(auxSerialMode);
if (port_nr < 0 || port_nr >= SP_COUNT)
return QString();
return serialModeToString(serialPort[port_nr]);
}
QString GeneralSettings::telemetryBaudrateToString() const
@@ -467,7 +470,7 @@ QString GeneralSettings::bluetoothModeToString(int value)
}
// static
QString GeneralSettings::auxSerialModeToString(int value)
QString GeneralSettings::serialModeToString(int value)
{
switch(value) {
case AUX_SERIAL_OFF:
@@ -480,6 +483,12 @@ QString GeneralSettings::auxSerialModeToString(int value)
return tr("SBUS Trainer");
case AUX_SERIAL_LUA:
return tr("LUA");
case AUX_SERIAL_CLI:
return tr("CLI");
case AUX_SERIAL_GPS:
return tr("GPS");
case AUX_SERIAL_DEBUG:
return tr("Debug");
default:
return CPN_STR_UNKNOWN_ITEM;
}
@@ -546,13 +555,20 @@ AbstractStaticItemModel * GeneralSettings::bluetoothModeItemModel()
}
// static
AbstractStaticItemModel * GeneralSettings::auxSerialModeItemModel()
AbstractStaticItemModel * GeneralSettings::serialModeItemModel(int port_nr)
{
AbstractStaticItemModel * mdl = new AbstractStaticItemModel();
mdl->setName(AIM_GS_AUXSERIALMODE);
mdl->setName(QString(AIM_GS_SERIALMODE).arg(port_nr));
for (int i = 0; i < AUX_SERIAL_COUNT; i++) {
mdl->appendToItemList(auxSerialModeToString(i), i);
if (port_nr == SP_VCP &&
(i == AUX_SERIAL_TELE_IN ||
i == AUX_SERIAL_SBUS_TRAINER ||
i == AUX_SERIAL_GPS)) {
// These 3 are disabled on VCP
continue;
}
mdl->appendToItemList(serialModeToString(i), i);
}
mdl->loadItemList();
+15 -6
View File
@@ -38,7 +38,7 @@ class AbstractStaticItemModel;
// identiying names of static abstract item models
constexpr char AIM_GS_ANTENNAMODE[] {"gs.antennamode"};
constexpr char AIM_GS_BLUETOOTHMODE[] {"gs.bluetoothmode"};
constexpr char AIM_GS_AUXSERIALMODE[] {"gs.auxserialmode"};
constexpr char AIM_GS_SERIALMODE[] {"gs.serialmode%1"};
constexpr char AIM_GS_TELEMETRYBAUDRATE[] {"gs.telemetrybaudrate"};
constexpr char AIM_TRAINERMIX_MODE[] {"trainermix.mode"};
constexpr char AIM_TRAINERMIX_SRC[] {"trainermix.src"};
@@ -135,12 +135,22 @@ class GeneralSettings {
AUX_SERIAL_TELE_IN,
AUX_SERIAL_SBUS_TRAINER,
AUX_SERIAL_LUA,
AUX_SERIAL_CLI,
AUX_SERIAL_GPS,
AUX_SERIAL_DEBUG,
AUX_SERIAL_COUNT
};
enum TelemetryBaudrate {
};
enum SerialPort {
SP_AUX1,
SP_AUX2,
SP_VCP,
SP_COUNT,
};
GeneralSettings() { clear(); }
void clear();
void init();
@@ -228,8 +238,7 @@ class GeneralSettings {
int backgroundVolume;
unsigned int mavbaud;
unsigned int switchUnlockStates;
unsigned int auxSerialMode;
unsigned int aux2SerialMode;
unsigned int serialPort[SP_COUNT];
int antennaMode;
unsigned int backlightColor;
CustomFunctionData customFn[CPN_MAX_SPECIAL_FUNCTIONS];
@@ -257,17 +266,17 @@ class GeneralSettings {
bool isSliderAvailable(int index) const;
QString antennaModeToString() const;
QString bluetoothModeToString() const;
QString auxSerialModeToString() const;
QString serialPortModeToString(int port_nr) const;
QString telemetryBaudrateToString() const;
static QString antennaModeToString(int value);
static QString bluetoothModeToString(int value);
static QString auxSerialModeToString(int value);
static QString serialModeToString(int value);
static QString telemetryBaudrateToString(int value);
static FieldRange getPPM_MultiplierRange();
static FieldRange getTxCurrentCalibration();
static AbstractStaticItemModel * antennaModeItemModel();
static AbstractStaticItemModel * bluetoothModeItemModel();
static AbstractStaticItemModel * auxSerialModeItemModel();
static AbstractStaticItemModel * serialModeItemModel(int port_nr);
static AbstractStaticItemModel * telemetryBaudrateItemModel();
};
+14 -9
View File
@@ -1649,18 +1649,23 @@ bool ModelData::isTrainerModeAvailable(const GeneralSettings & generalSettings,
if (!IS_FLYSKY_NV14(board) && value == TRAINER_MODE_OFF)
ret = false;
else if (!IS_TARANIS(board) || IS_ACCESS_RADIO(board, Firmware::getCurrentVariant()->getId())) {
if (value >= TRAINER_MODE_MASTER_SBUS_EXTERNAL_MODULE && value <= TRAINER_MODE_MASTER_BATTERY_COMPARTMENT)
ret = false;
}
else if (generalSettings.auxSerialMode != UART_MODE_SBUS_TRAINER && value == TRAINER_MODE_MASTER_BATTERY_COMPARTMENT)
else if (!IS_TARANIS(board) ||
IS_ACCESS_RADIO(board, Firmware::getCurrentVariant()->getId())) {
if (value >= TRAINER_MODE_MASTER_SBUS_EXTERNAL_MODULE &&
value <= TRAINER_MODE_MASTER_BATTERY_COMPARTMENT)
ret = false;
} else if (generalSettings.serialPort[GeneralSettings::SP_AUX1] !=
UART_MODE_SBUS_TRAINER &&
value == TRAINER_MODE_MASTER_BATTERY_COMPARTMENT)
ret = false;
if (generalSettings.bluetoothMode != GeneralSettings::BLUETOOTH_MODE_TRAINER && value >= TRAINER_MODE_MASTER_BLUETOOTH && value <= TRAINER_MODE_SLAVE_BLUETOOTH)
ret = false;
if (generalSettings.bluetoothMode !=
GeneralSettings::BLUETOOTH_MODE_TRAINER &&
value >= TRAINER_MODE_MASTER_BLUETOOTH &&
value <= TRAINER_MODE_SLAVE_BLUETOOTH)
ret = false;
if (!IS_RADIOMASTER_TX16S(board) && value == TRAINER_MODE_MULTI)
ret = false;
if (!IS_RADIOMASTER_TX16S(board) && value == TRAINER_MODE_MULTI) ret = false;
return ret;
}
@@ -3168,9 +3168,9 @@ OpenTxGeneralData::OpenTxGeneralData(GeneralSettings & generalData, Board::Type
if (IS_STM32(board)) {
if (version >= 218) {
internalField.Append(new UnsignedField<4>(this, generalData.auxSerialMode));
internalField.Append(new UnsignedField<4>(this, generalData.serialPort[GeneralSettings::SP_AUX1]));
if (IS_FAMILY_HORUS_OR_T16(board) && version >= 219) {
internalField.Append(new UnsignedField<4>(this, generalData.aux2SerialMode));
internalField.Append(new UnsignedField<4>(this, generalData.serialPort[GeneralSettings::SP_AUX2]));
}
else {
for (uint8_t i=0; i<SLIDERS_CONFIG_SIZE(board,version); i++) {
@@ -3179,7 +3179,7 @@ OpenTxGeneralData::OpenTxGeneralData(GeneralSettings & generalData, Board::Type
}
}
else {
internalField.Append(new UnsignedField<6>(this, generalData.auxSerialMode));
internalField.Append(new UnsignedField<6>(this, generalData.serialPort[GeneralSettings::SP_AUX1]));
if (IS_TARANIS_X9E(board)) {
internalField.Append(new UnsignedField<1>(this, generalData.sliderConfig[2]));
internalField.Append(new UnsignedField<1>(this, generalData.sliderConfig[3]));
@@ -744,9 +744,14 @@ int OpenTxFirmware::getCapability(::Capability capability)
else
return 40;
case HasAuxSerialMode:
return (IS_FAMILY_HORUS_OR_T16(board) && !IS_TARANIS_SMALL(board)) ? true : false;
return (IS_FAMILY_HORUS_OR_T16(board) && !IS_FLYSKY_NV14(board)) ||
(IS_TARANIS_X9(board) && !IS_TARANIS_X9DP_2019(board)) ||
IS_RADIOMASTER_ZORRO(board);
case HasAux2SerialMode:
return (IS_FAMILY_HORUS_OR_T16(board) && !IS_TARANIS_SMALL(board) && !IS_FLYSKY_NV14(board)) ? true : false;
return IS_FAMILY_T16(board);
case HasVCPSerialMode:
return IS_FAMILY_HORUS_OR_T16(board) || IS_RADIOMASTER_ZORRO(board) ||
IS_JUMPER_TPRO(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)) ? true : false;
case HasAntennaChoice:
+66 -6
View File
@@ -35,6 +35,50 @@ constexpr char FIM_SWITCHTYPE2POS[] {"Switch Type 2 Pos"};
constexpr char FIM_SWITCHTYPE3POS[] {"Switch Type 3 Pos"};
constexpr char FIM_INTERNALMODULES[] {"Internal Modules"};
class ExclusiveComboGroup: public QObject
{
static constexpr auto _role = Qt::UserRole + 500;
QList<QComboBox*> combos;
std::function<bool(const QVariant&)> filter;
public:
ExclusiveComboGroup(QObject *parent, std::function<bool(const QVariant&)> filter) :
QObject(parent), filter(std::move(filter))
{
}
void addCombo(QComboBox *comboBox)
{
connect(comboBox, QOverload<int>::of(&QComboBox::activated),
[=](int index) { this->handleActivated(comboBox, index); });
combos.append(comboBox);
}
void handleActivated(QComboBox* target, int index) {
auto data = target->itemData(index);
auto targetidx = combos.indexOf(target);
for (auto combo : combos) {
if (target == combo) continue;
auto view = dynamic_cast<QListView*>(combo->view());
Q_ASSERT(view);
auto previous = combo->findData(targetidx, _role);
if (previous >= 0) {
view->setRowHidden(previous, false);
combo->setItemData(previous, QVariant(), _role);
}
if (!filter(data)) {
auto idx = combo->findData(data);
if (idx >= 0) {
view->setRowHidden(idx, true);
combo->setItemData(idx, targetidx, _role);
}
}
}
}
};
HardwarePanel::HardwarePanel(QWidget * parent, GeneralSettings & generalSettings, Firmware * firmware, CompoundItemModelFactory * sharedItemModels):
GeneralPanel(parent, generalSettings, firmware),
board(firmware->getBoard()),
@@ -50,7 +94,8 @@ HardwarePanel::HardwarePanel(QWidget * parent, GeneralSettings & generalSettings
int antmodelid = editorItemModels->registerItemModel(GeneralSettings::antennaModeItemModel());
int btmodelid = editorItemModels->registerItemModel(GeneralSettings::bluetoothModeItemModel());
int auxmodelid = editorItemModels->registerItemModel(GeneralSettings::auxSerialModeItemModel());
int auxmodelid = editorItemModels->registerItemModel(GeneralSettings::serialModeItemModel(GeneralSettings::SP_AUX1));
int vcpmodelid = editorItemModels->registerItemModel(GeneralSettings::serialModeItemModel(GeneralSettings::SP_VCP));
int baudmodelid = editorItemModels->registerItemModel(GeneralSettings::telemetryBaudrateItemModel());
id = editorItemModels->registerItemModel(ModuleData::internalModuleItemModel());
@@ -149,6 +194,10 @@ HardwarePanel::HardwarePanel(QWidget * parent, GeneralSettings & generalSettings
addParams(row, maxBaudRate);
}
// All values except 0 are mutually exclusive
ExclusiveComboGroup *exclGroup = new ExclusiveComboGroup(
this, [=](const QVariant &value) { return value == 0; });
if (firmware->getCapability(HasAuxSerialMode)) {
QString lbl = "Serial Port";
if (IS_RADIOMASTER_TX16S(board))
@@ -156,7 +205,8 @@ HardwarePanel::HardwarePanel(QWidget * parent, GeneralSettings & generalSettings
addLabel(tr("%1").arg(lbl), row, 0);
AutoComboBox *serialPortMode = new AutoComboBox(this);
serialPortMode->setModel(editorItemModels->getItemModel(auxmodelid));
serialPortMode->setField(generalSettings.auxSerialMode);
serialPortMode->setField(generalSettings.serialPort[GeneralSettings::SP_AUX1]);
exclGroup->addCombo(serialPortMode);
addParams(row, serialPortMode);
}
@@ -165,10 +215,20 @@ HardwarePanel::HardwarePanel(QWidget * parent, GeneralSettings & generalSettings
if (IS_RADIOMASTER_TX16S(board))
lbl.append(" (TTL)");
addLabel(tr("%1").arg(lbl), row, 0);
AutoComboBox *serialPort2Mode = new AutoComboBox(this);
serialPort2Mode->setModel(editorItemModels->getItemModel(auxmodelid));
serialPort2Mode->setField(generalSettings.aux2SerialMode);
addParams(row, serialPort2Mode);
AutoComboBox *serialPortMode = new AutoComboBox(this);
serialPortMode->setModel(editorItemModels->getItemModel(auxmodelid));
serialPortMode->setField(generalSettings.serialPort[GeneralSettings::SP_AUX2]);
exclGroup->addCombo(serialPortMode);
addParams(row, serialPortMode);
}
if (firmware->getCapability(HasVCPSerialMode)) {
addLabel(tr("Serial Port VCP"), row, 0);
AutoComboBox *serialPortMode = new AutoComboBox(this);
serialPortMode->setModel(editorItemModels->getItemModel(vcpmodelid));
serialPortMode->setField(generalSettings.serialPort[GeneralSettings::SP_VCP]);
exclGroup->addCombo(serialPortMode);
addParams(row, serialPortMode);
}
if (firmware->getCapability(HasADCJitterFilter)) {
+3 -1
View File
@@ -509,7 +509,9 @@ void TelemetryPanel::setup()
ui->telemetryProtocol->addItem(tr("FrSky S.PORT"), 0);
ui->telemetryProtocol->addItem(tr("FrSky D"), 1);
if (IS_9XRPRO(firmware->getBoard()) ||
(IS_TARANIS(firmware->getBoard()) && generalSettings.auxSerialMode == 2)) {
(IS_TARANIS(firmware->getBoard()) &&
generalSettings.serialPort[GeneralSettings::SP_AUX1] ==
GeneralSettings::AUX_SERIAL_TELE_IN)) {
ui->telemetryProtocol->addItem(tr("FrSky D (cable)"), 2);
}
ui->telemetryProtocol->setCurrentIndex(model->telemetryProtocol);
+2
View File
@@ -474,6 +474,8 @@ set(SRC
timers.cpp
trainer.cpp
model_init.cpp
serial.cpp
sbus.cpp
)
if(GUI)
+319 -201
View File
File diff suppressed because it is too large Load Diff
+3 -8
View File
@@ -22,17 +22,12 @@
#ifndef _CLI_H_
#define _CLI_H_
#include <stdint.h>
#include <FreeRTOS.h>
#include <stream_buffer.h>
#include "cli_traces.h"
#include "hal/serial_driver.h"
// CLI task function
void cliStart();
// Called from receive ISR (either USB or UART)
void cliReceiveData(uint8_t* buf, uint32_t len);
// Connect serial driver to CLI
void cliSetSerialDriver(void* ctx, const etx_serial_driver_t* drv);
#endif // _CLI_H_
+18 -36
View File
@@ -177,7 +177,6 @@ enum BeeperMode {
e_mode_all
};
#if defined(PCBFRSKY) || defined(PCBNV14)
enum ModuleIndex {
INTERNAL_MODULE,
EXTERNAL_MODULE,
@@ -185,45 +184,32 @@ enum ModuleIndex {
};
enum TrainerMode {
#if defined(PCBNV14)
TRAINER_MODE_OFF,
#endif
TRAINER_MODE_MASTER_TRAINER_JACK,
TRAINER_MODE_SLAVE,
#if defined(PCBTARANIS) || defined(PCBNV14)
TRAINER_MODE_MASTER_SBUS_EXTERNAL_MODULE,
TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE,
#endif
#if defined(PCBTARANIS) || defined(AUX_SERIAL) || defined(AUX2_SERIAL)
TRAINER_MODE_MASTER_BATTERY_COMPARTMENT,
#endif
TRAINER_MODE_MASTER_SERIAL,
TRAINER_MODE_MASTER_BLUETOOTH,
TRAINER_MODE_SLAVE_BLUETOOTH,
TRAINER_MODE_MULTI,
};
#endif
#define TRAINER_MODE_MIN() TRAINER_MODE_MASTER_TRAINER_JACK
#define TRAINER_MODE_MIN() TRAINER_MODE_OFF
#define TRAINER_MODE_MAX() TRAINER_MODE_MULTI
#if !defined(HARDWARE_EXTERNAL_MODULE)
#define TRAINER_MODE_MAX() TRAINER_MODE_SLAVE
#elif defined(RADIO_T16) && !defined(INTERNAL_MODULE_MULTI)
#if defined(BLUETOOTH)
#define TRAINER_MODE_MAX() TRAINER_MODE_SLAVE_BLUETOOTH
#else
#define TRAINER_MODE_MAX() TRAINER_MODE_SLAVE
#endif
#elif defined(INTERNAL_MODULE_MULTI) || defined(ALLOW_TRAINER_MULTI)
#define TRAINER_MODE_MAX() TRAINER_MODE_MULTI
#elif defined(BLUETOOTH)
#define TRAINER_MODE_MAX() TRAINER_MODE_SLAVE_BLUETOOTH
#elif defined(PCBX7) || defined(PCBXLITE) || defined(PCBNV14)
#define TRAINER_MODE_MAX() TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE
#elif defined(PCBTARANIS)
#define TRAINER_MODE_MAX() (IS_TRAINER_AUX_SERIAL() ? TRAINER_MODE_MASTER_BATTERY_COMPARTMENT : TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE)
#else
#define TRAINER_MODE_MAX() TRAINER_MODE_MASTER_BATTERY_COMPARTMENT
#endif
enum SerialPort {
SP_AUX1=0,
SP_AUX2,
SP_VCP,
MAX_SERIAL_PORTS SKIP,
};
#define MAX_AUX_SERIAL (SP_AUX2 + 1)
#define STORAGE_SERIAL_PORTS 4
// GPS
#define PILOTPOS_MIN_HDOP 500
#if defined(HARDWARE_INTERNAL_MODULE)
#define IS_INTERNAL_MODULE_ENABLED() (g_model.moduleData[INTERNAL_MODULE].type != MODULE_TYPE_NONE)
@@ -241,21 +227,17 @@ enum TrainerMode {
enum UartModes {
UART_MODE_NONE,
#if defined(CLI) || defined(DEBUG)
UART_MODE_DEBUG SKIP = UART_MODE_NONE,
#endif
UART_MODE_TELEMETRY_MIRROR,
UART_MODE_TELEMETRY,
UART_MODE_SBUS_TRAINER,
UART_MODE_LUA,
UART_MODE_CLI,
UART_MODE_GPS,
UART_MODE_DEBUG,
UART_MODE_COUNT SKIP,
UART_MODE_MAX SKIP = UART_MODE_COUNT-1
};
#if defined(CLI) || defined(DEBUG)
#define UART_MODE_NONE UART_MODE_DEBUG
#endif
#define LEN_SWITCH_NAME 3
#define LEN_ANA_NAME 3
#define LEN_MODEL_FILENAME 16
+8 -8
View File
@@ -116,29 +116,29 @@ static inline void check_struct()
CHKSIZE(TrainerData, 16);
#if defined(PCBXLITES)
CHKSIZE(RadioData, 857);
CHKSIZE(RadioData, 859);
CHKSIZE(ModelData, 6161);
#elif defined(PCBXLITE)
CHKSIZE(RadioData, 855);
CHKSIZE(RadioData, 857);
CHKSIZE(ModelData, 6161);
#elif defined(RADIO_TPRO)
CHKSIZE(RadioData, 838);
CHKSIZE(RadioData, 840);
CHKSIZE(ModelData, 6186);
#elif defined(PCBX7)
CHKSIZE(RadioData, 861);
CHKSIZE(RadioData, 863);
CHKSIZE(ModelData, 6161);
#elif defined(PCBX9E)
CHKSIZE(RadioData, 951);
CHKSIZE(RadioData, 953);
CHKSIZE(ModelData, 6613);
#elif defined(PCBX9D) || defined(PCBX9DP)
CHKSIZE(RadioData, 893);
CHKSIZE(RadioData, 895);
CHKSIZE(ModelData, 6605);
#elif defined(PCBHORUS)
#if defined(PCBX10)
CHKSIZE(RadioData, 918);
CHKSIZE(RadioData, 919);
CHKSIZE(ModelData, 11025);
#else
CHKSIZE(RadioData, 900);
CHKSIZE(RadioData, 901);
CHKSIZE(ModelData, 11023);
#endif
#endif
+8 -8
View File
@@ -787,10 +787,8 @@ PACK(struct TrainerData {
#define GYRO_FIELDS
#endif
#if defined(PCBHORUS) || defined(PCBNV14)
#if defined(COLORLCD)
#define EXTRA_GENERAL_FIELDS \
NOBACKUP(uint8_t auxSerialMode:4 ENUM(UartModes)); \
NOBACKUP(uint8_t aux2SerialMode:4 ENUM(UartModes)); \
CUST_ARRAY(sticksConfig, struct_sticksConfig, stick_name_valid); \
swconfig_t switchConfig ARRAY(2,struct_switchConfig,nullptr); \
uint16_t potsConfig ARRAY(2,struct_potConfig,nullptr); /* two bits per pot */ \
@@ -801,17 +799,17 @@ PACK(struct TrainerData {
NOBACKUP(uint8_t spare5:1 SKIP); \
NOBACKUP(uint8_t blOffBright:7); \
NOBACKUP(char bluetoothName[LEN_BLUETOOTH_NAME]);
#elif defined(PCBTARANIS)
#else
#if defined(STORAGE_BLUETOOTH)
#define BLUETOOTH_FIELDS \
uint8_t spare5 SKIP; \
uint8_t spare6 SKIP; \
char bluetoothName[LEN_BLUETOOTH_NAME];
#else
#define BLUETOOTH_FIELDS
#endif
#define EXTRA_GENERAL_FIELDS \
uint8_t auxSerialMode:4 ENUM(UartModes); \
uint8_t slidersConfig:4 ARRAY(1,struct_sliderConfig,nullptr); \
uint8_t spare5:4 SKIP; \
uint8_t potsConfig ARRAY(2,struct_potConfig,nullptr); /* two bits per pot */\
uint8_t backlightColor; \
CUST_ARRAY(sticksConfig, struct_sticksConfig, stick_name_valid); \
@@ -819,8 +817,6 @@ PACK(struct TrainerData {
char switchNames[STORAGE_NUM_SWITCHES - NUM_FUNCTIONS_SWITCHES][LEN_SWITCH_NAME] SKIP; \
char anaNames[NUM_STICKS+STORAGE_NUM_POTS+STORAGE_NUM_SLIDERS][LEN_ANA_NAME] SKIP; \
BLUETOOTH_FIELDS
#else
#define EXTRA_GENERAL_FIELDS
#endif
#if defined(COLORLCD) && !defined(BACKUP)
@@ -912,6 +908,10 @@ PACK(struct RadioData {
NOBACKUP(int8_t varioRepeat);
CustomFunctionData customFn[MAX_SPECIAL_FUNCTIONS] FUNC(cfn_is_active);
CUST_ATTR(auxSerialMode, r_serialMode, nullptr);
CUST_ATTR(aux2SerialMode, r_serialMode, nullptr);
NOBACKUP(uint16_t serialPort ARRAY(STORAGE_SERIAL_PORTS,struct_serialConfig,nullptr));
EXTRA_GENERAL_FIELDS
THEME_DATA
+1 -7
View File
@@ -33,9 +33,6 @@
extern volatile uint32_t g_tmr10ms;
uint8_t auxSerialTracesEnabled();
uint8_t aux2SerialTracesEnabled();
#if defined(SIMU)
typedef void (*traceCallbackFunc)(const char * text);
extern traceCallbackFunc traceCallback;
@@ -43,11 +40,8 @@ uint8_t aux2SerialTracesEnabled();
#elif defined(SEMIHOSTING)
#include <stdio.h>
#define debugPrintf(...) printf(__VA_ARGS__)
#elif defined(DEBUG) && defined(CLI)
#include "cli_traces.h"
#define debugPrintf(...) do { if (cliTracesEnabled) serialPrintf(__VA_ARGS__); } while(0)
#elif defined(DEBUG)
#define debugPrintf(...) do { serialPrintf(__VA_ARGS__); } while(0)
#define debugPrintf(...) do { dbgSerialPrintf(__VA_ARGS__); } while(0)
#else
#define debugPrintf(...)
#endif
+1 -1
View File
@@ -24,7 +24,7 @@
#if defined(SIMU)
#define dumpPrintf(...) debugPrintf(__VA_ARGS__)
#else
#define dumpPrintf(...) serialPrintf(__VA_ARGS__)
#define dumpPrintf(...) dbgSerialPrintf(__VA_ARGS__)
#endif
#if defined(DEBUG) || defined(CLI)
+38 -7
View File
@@ -320,10 +320,33 @@ void gpsNewData(uint8_t c)
}
}
static const etx_serial_driver_t* gpsSerialDrv = nullptr;
static void* gpsSerialCtx = nullptr;
#if defined(DEBUG)
uint8_t gpsTraceEnabled = false;
#endif
void gpsSetSerialDriver(void* ctx, const etx_serial_driver_t* drv)
{
gpsSerialCtx = ctx;
gpsSerialDrv = drv;
}
void gpsWakeup()
{
if (!gpsSerialDrv) return;
auto _getByte = gpsSerialDrv->getByte;
if (!_getByte) return;
uint8_t byte;
while (gpsGetByte(&byte)) {
while (_getByte(gpsSerialCtx, &byte)) {
#if defined(DEBUG)
if (gpsTraceEnabled) {
dbgSerialPutc(byte);
}
#endif
gpsNewData(byte);
}
}
@@ -334,18 +357,26 @@ char hex(uint8_t b) {
void gpsSendFrame(const char * frame)
{
if (!gpsSerialDrv) return;
auto _sendByte = gpsSerialDrv->sendByte;
if (!_sendByte) return;
// send given frame, add checksum and CRLF
uint8_t parity = 0;
TRACE_NOCRLF("gps> %s", frame);
while (*frame) {
if (*frame != '$') parity ^= *frame;
gpsSendByte(*frame);
_sendByte(gpsSerialCtx, *frame);
++frame;
}
gpsSendByte('*');
gpsSendByte(hex(parity >> 4));
gpsSendByte(hex(parity & 0x0F));
gpsSendByte('\r');
gpsSendByte('\n');
_sendByte(gpsSerialCtx, '*');
_sendByte(gpsSerialCtx, hex(parity >> 4));
_sendByte(gpsSerialCtx, hex(parity & 0x0F));
_sendByte(gpsSerialCtx, '\r');
_sendByte(gpsSerialCtx, '\n');
TRACE("*%02x", parity);
}
+10
View File
@@ -39,8 +39,18 @@ struct gpsdata_t
};
extern gpsdata_t gpsData;
#if defined(DEBUG)
extern uint8_t gpsTraceEnabled;
#endif
// Setup GPS serial port
void gpsSetSerialDriver(void* ctx, const etx_serial_driver_t* drv);
// Periodic processing
void gpsWakeup();
// Send a 0-terminated frame
void gpsSendFrame(const char * frame);
#endif // _GPS_H_
-12
View File
@@ -163,18 +163,6 @@ void menuStatisticsDebug(event_t event)
uint8_t y = FH + 1;
#if defined(STM32) && !defined(SIMU) && defined(DEBUG)
lcdDrawTextAlignedLeft(y, "Usb");
lcdDrawNumber(MENU_DEBUG_COL1_OFS, y, charsWritten, LEFT);
lcdDrawText(lcdLastRightPos, y, " ");
lcdDrawNumber(lcdLastRightPos, y, APP_Rx_ptr_in, LEFT);
lcdDrawText(lcdLastRightPos, y, " ");
lcdDrawNumber(lcdLastRightPos, y, APP_Rx_ptr_out, LEFT);
lcdDrawText(lcdLastRightPos, y, " ");
lcdDrawNumber(lcdLastRightPos, y, usbWraps, LEFT);
y += FH;
#endif
#if defined(STM32)
lcdDrawTextAlignedLeft(y, "Free Mem");
lcdDrawNumber(MENU_DEBUG_COL1_OFS, y, availableMemory(), LEFT);
+12 -7
View File
@@ -34,7 +34,9 @@ TopbarImpl::TopbarImpl(Window * parent) :
unsigned int TopbarImpl::getZonesCount() const
{
#if defined(INTERNAL_GPS)
return MAX_TOPBAR_ZONES-1;
if (hasSerialMode(UART_MODE_GPS)) {
return MAX_TOPBAR_ZONES-1;
}
#endif
return MAX_TOPBAR_ZONES;
}
@@ -96,13 +98,16 @@ void TopbarImpl::paint(BitmapBuffer * dc)
dc->drawText(DATETIME_MIDDLE, DATETIME_LINE2, str, FONT(XS) | CENTERED | COLOR_THEME_PRIMARY2);
#if defined(INTERNAL_GPS)
if (gpsData.fix) {
char s[10];
sprintf(s, "%d", gpsData.numSat);
dc->drawText(GPS_X, 4, s, FONT(XS) | CENTERED | COLOR_THEME_PRIMARY2);
if (hasSerialMode(UART_MODE_GPS) != -1) {
if (gpsData.fix) {
char s[10];
sprintf(s, "%d", gpsData.numSat);
dc->drawText(GPS_X, 4, s, FONT(XS) | CENTERED | COLOR_THEME_PRIMARY2);
}
dc->drawBitmapPattern(
GPS_X - 10, 22, LBM_TOPMENU_GPS,
(gpsData.fix) ? COLOR_THEME_PRIMARY2 : COLOR_THEME_PRIMARY3);
}
dc->drawBitmapPattern(GPS_X - 10, 22, LBM_TOPMENU_GPS,
(gpsData.fix) ? COLOR_THEME_PRIMARY2 : COLOR_THEME_PRIMARY3);
#endif
// USB icon
+54 -31
View File
@@ -26,6 +26,7 @@
#include "opentx.h"
#include "libopenui.h"
#include "hal/adc_driver.h"
#include "aux_serial_driver.h"
#define SET_DIRTY() storageDirty(EE_GENERAL)
@@ -196,6 +197,56 @@ class BluetoothConfigWindow : public FormGroup
};
#endif
class SerialConfigWindow : public FormGroup
{
public:
SerialConfigWindow(FormWindow *parent, const rect_t &rect) :
FormGroup(parent, rect, FORWARD_SCROLL | FORM_FORWARD_FOCUS)
{
update();
}
void update()
{
FormGridLayout grid;
#if LCD_W > LCD_H
grid.setLabelWidth(180);
#else
grid.setLabelWidth(130);
#endif
clear();
bool display_ttl_warning = false;
for (uint8_t port_nr = 0; port_nr < MAX_SERIAL_PORTS; port_nr++) {
auto port = serialGetPort(port_nr);
if (!port || !port->name) continue;
display_ttl_warning = true;
new StaticText(this, grid.getLabelSlot(true), port->name, 0,
COLOR_THEME_PRIMARY1);
auto aux = new Choice(
this, grid.getFieldSlot(), STR_AUX_SERIAL_MODES, 0,
UART_MODE_MAX, [=]() { return serialGetMode(port_nr); },
[=](int value) {
serialSetMode(port_nr, value);
serialInit(port_nr, value);
SET_DIRTY();
});
aux->setAvailableHandler(
[=](int value) { return isSerialModeAvailable(port_nr, value); });
grid.nextLine();
}
if (display_ttl_warning) {
new StaticText(this, grid.getFieldSlot(), STR_TTL_WARNING, 0,
COLOR_THEME_WARNING);
grid.nextLine();
}
getParent()->moveWindowsTop(top() + 1, adjustHeight());
}
};
void restartExternalModule()
{
if (!IS_EXTERNAL_MODULE_ON()) {
@@ -372,38 +423,10 @@ void RadioHardwarePage::build(FormWindow * window)
}
#endif
#if defined(AUX_SERIAL)
new StaticText(window, grid.getLabelSlot(), STR_AUX_SERIAL_MODE, 0, COLOR_THEME_PRIMARY1);
auto aux =
new Choice(window, grid.getFieldSlot(1, 0), STR_AUX_SERIAL_MODES, 0,
UART_MODE_MAX, GET_DEFAULT(g_eeGeneral.auxSerialMode),
[](int value) {
g_eeGeneral.auxSerialMode = value;
auxSerialInit(g_eeGeneral.auxSerialMode, modelTelemetryProtocol());
SET_DIRTY();
});
aux->setAvailableHandler(isAuxModeAvailable);
new Subtitle(window, grid.getLineSlot(), STR_AUX_SERIAL_MODE, 0,
COLOR_THEME_PRIMARY1);
grid.nextLine();
#endif
#if defined(AUX2_SERIAL)
new StaticText(window, grid.getLabelSlot(), STR_AUX2_SERIAL_MODE, 0, COLOR_THEME_PRIMARY1);
auto aux2 =
new Choice(window, grid.getFieldSlot(1, 0), STR_AUX_SERIAL_MODES, 0,
UART_MODE_MAX, GET_DEFAULT(g_eeGeneral.aux2SerialMode),
[](int value) {
g_eeGeneral.aux2SerialMode = value;
aux2SerialInit(g_eeGeneral.aux2SerialMode, modelTelemetryProtocol());
SET_DIRTY();
});
aux2->setAvailableHandler(isAux2ModeAvailable);
grid.nextLine();
#endif
#if defined(AUX_SERIAL) || defined(AUX2_SERIAL)
new StaticText(window, grid.getFieldSlot(1,0), STR_TTL_WARNING, 0, COLOR_THEME_WARNING);
grid.nextLine();
#endif
grid.addWindow(new SerialConfigWindow(window, {0, grid.getWindowHeight(), LCD_W, 0}));
// ADC filter
new StaticText(window, grid.getLabelSlot(), STR_JITTER_FILTER, 0, COLOR_THEME_PRIMARY1);
+1 -1
View File
@@ -418,7 +418,7 @@ void RadioSetupPage::build(FormWindow * window)
#if defined(INTERNAL_GPS)
// GPS
{
if (hasSerialMode(UART_MODE_GPS)) {
new Subtitle(window, grid.getLabelSlot(), STR_GPS, 0, COLOR_THEME_PRIMARY1);
grid.nextLine();
+15 -13
View File
@@ -240,19 +240,21 @@ void DebugViewPage::build(FormWindow *window)
#endif
#if defined(INTERNAL_GPS)
new StaticText(window, grid.getLabelSlot(), STR_INT_GPS_LABEL, 0,
COLOR_THEME_PRIMARY1);
new DynamicText(
window, grid.getFieldSlot(3, 0),
[] { return std::string(gpsData.fix ? "[Fix] Yes" : "[Fix] No"); },
COLOR_THEME_PRIMARY1);
new DebugInfoNumber<uint8_t>(
window, grid.getFieldSlot(3, 1), [] { return gpsData.numSat; },
COLOR_THEME_PRIMARY1, "[Sats] ", nullptr);
new DebugInfoNumber<uint16_t>(
window, grid.getFieldSlot(3, 2), [] { return gpsData.hdop; },
COLOR_THEME_PRIMARY1, "[Hdop] ", nullptr);
grid.nextLine();
if (hasSerialMode(UART_MODE_GPS)) {
new StaticText(window, grid.getLabelSlot(), STR_INT_GPS_LABEL, 0,
COLOR_THEME_PRIMARY1);
new DynamicText(
window, grid.getFieldSlot(3, 0),
[] { return std::string(gpsData.fix ? "[Fix] Yes" : "[Fix] No"); },
COLOR_THEME_PRIMARY1);
new DebugInfoNumber<uint8_t>(
window, grid.getFieldSlot(3, 1), [] { return gpsData.numSat; },
COLOR_THEME_PRIMARY1, "[Sats] ", nullptr);
new DebugInfoNumber<uint16_t>(
window, grid.getFieldSlot(3, 2), [] { return gpsData.hdop; },
COLOR_THEME_PRIMARY1, "[Hdop] ", nullptr);
grid.nextLine();
}
#endif
// Reset
+47 -12
View File
@@ -21,6 +21,7 @@
#include <opentx.h>
#include "hal/adc_driver.h"
#include "aux_serial_driver.h"
#if defined(PCBTARANIS)
enum {
@@ -117,9 +118,13 @@ enum {
ITEM_RADIO_HARDWARE_EXTERNAL_ANTENNA,
#endif
#if defined(AUX_SERIAL)
ITEM_RADIO_HARDWARE_AUX_SERIAL_MODE,
#if defined(AUX_SERIAL) || defined(USB_SERIAL)
ITEM_RADIO_HARDWARE_SERIAL_PORT_LABEL,
ITEM_RADIO_HARDWARE_AUX1_SERIAL_MODE,
ITEM_RADIO_HARDWARE_AUX2_SERIAL_MODE,
ITEM_RADIO_HARDWARE_VCP_SERIAL_MODE,
#endif
ITEM_RADIO_HARDWARE_JITTER_FILTER,
ITEM_RADIO_HARDWARE_RAS,
#if defined(SPORT_UPDATE_PWR_GPIO)
@@ -239,10 +244,17 @@ enum {
#define SERIAL_SAMPLE_MODE_ROWS 0,
#if defined(AUX_SERIAL)
#define AUX_SERIAL_ROWS 0,
#if defined(AUX_SERIAL) || defined(USB_SERIAL)
static uint8_t _dispSerialPort(uint8_t port_nr)
{
auto port = serialGetPort(port_nr);
if (!port || !port->name) return HIDDEN_ROW;
return 0;
}
#define SERIAL_PORT_ROWS \
0, _dispSerialPort(SP_AUX1), _dispSerialPort(SP_AUX2), _dispSerialPort(SP_VCP),
#else
#define AUX_SERIAL_ROWS
#define SERIAL_PORT_ROWS
#endif
#if LCD_W >= 212
@@ -285,6 +297,14 @@ void restartExternalModule()
resumeMixerCalculations();
}
static bool _isAux1ModeAvailable(int m) { return isSerialModeAvailable(SP_AUX1, m); }
static bool _isAux2ModeAvailable(int m) { return isSerialModeAvailable(SP_AUX2, m); }
static bool _isVCPModeAvailable(int m) { return isSerialModeAvailable(SP_VCP, m); }
static const IsValueAvailable _isSerialModeAvailable[MAX_SERIAL_PORTS] = {
_isAux1ModeAvailable, _isAux2ModeAvailable, _isVCPModeAvailable
};
void menuRadioHardware(event_t event)
{
uint8_t old_editMode = s_editMode;
@@ -307,7 +327,7 @@ void menuRadioHardware(event_t event)
SERIAL_SAMPLE_MODE_ROWS
BLUETOOTH_ROWS
EXTERNAL_ANTENNA_ROW
AUX_SERIAL_ROWS
SERIAL_PORT_ROWS
0 /* ADC filter */,
READONLY_ROW /* RAS */,
SPORT_POWER_ROWS
@@ -595,13 +615,28 @@ void menuRadioHardware(event_t event)
break;
#endif
#if defined(AUX_SERIAL)
case ITEM_RADIO_HARDWARE_AUX_SERIAL_MODE:
g_eeGeneral.auxSerialMode = editChoice(HW_SETTINGS_COLUMN2, y, STR_AUX_SERIAL_MODE, STR_AUX_SERIAL_MODES, g_eeGeneral.auxSerialMode, 0, UART_MODE_MAX, attr, event);
if (attr && checkIncDec_Ret) {
auxSerialInit(g_eeGeneral.auxSerialMode, modelTelemetryProtocol());
}
#if defined(AUX_SERIAL) || defined(USB_SERIAL)
case ITEM_RADIO_HARDWARE_SERIAL_PORT_LABEL:
lcdDrawTextAlignedLeft(y, STR_AUX_SERIAL_MODE);
break;
case ITEM_RADIO_HARDWARE_AUX1_SERIAL_MODE:
case ITEM_RADIO_HARDWARE_AUX2_SERIAL_MODE:
case ITEM_RADIO_HARDWARE_VCP_SERIAL_MODE:
{
auto port_nr = k - ITEM_RADIO_HARDWARE_AUX1_SERIAL_MODE;
auto port = serialGetPort(port_nr);
lcdDrawText(INDENT_WIDTH, y, port->name);
auto mode = serialGetMode(port_nr);
mode = editChoice(HW_SETTINGS_COLUMN2, y, nullptr,
STR_AUX_SERIAL_MODES, mode, 0, UART_MODE_MAX, attr,
event, _isSerialModeAvailable[port_nr]);
if (attr && checkIncDec_Ret) {
serialSetMode(port_nr, mode);
serialInit(port_nr, mode);
}
} break;
#endif
case ITEM_RADIO_HARDWARE_JITTER_FILTER:
g_eeGeneral.noJitterFilter = 1 - editCheckBox(1 - g_eeGeneral.noJitterFilter, HW_SETTINGS_COLUMN2, y, STR_JITTER_FILTER, attr, event);
+67 -44
View File
@@ -367,29 +367,52 @@ bool isSwitchAvailable(int swtch, SwitchContext context)
return true;
}
bool isAuxModeAvailable(int mode)
int hasSerialMode(int mode)
{
#if defined(AUX2_SERIAL)
if (mode == UART_MODE_SBUS_TRAINER)
return g_eeGeneral.aux2SerialMode != UART_MODE_SBUS_TRAINER;
#if defined(RADIO_TX16S)
else
return (g_model.trainerData.mode != TRAINER_MODE_MASTER_BATTERY_COMPARTMENT || g_eeGeneral.aux2SerialMode == UART_MODE_SBUS_TRAINER);
#endif
#endif
return true;
for (int p = 0; p < MAX_SERIAL_PORTS; p++) {
if (serialGetMode(p) == mode) return p;
}
return -1;
}
bool isAux2ModeAvailable(int mode)
bool isSerialModeAvailable(uint8_t port_nr, int mode)
{
#if defined(AUX_SERIAL)
if (mode == UART_MODE_SBUS_TRAINER)
return g_eeGeneral.auxSerialMode != UART_MODE_SBUS_TRAINER;
#if defined(RADIO_TX16S)
else
return (g_model.trainerData.mode != TRAINER_MODE_MASTER_BATTERY_COMPARTMENT || g_eeGeneral.auxSerialMode == UART_MODE_SBUS_TRAINER);
if (mode == UART_MODE_NONE)
return true;
#if !defined(DEBUG)
if (mode == UART_MODE_DEBUG)
return false;
#endif
#if !defined(CLI)
if (mode == UART_MODE_CLI)
return false;
#endif
#if !defined(INTERNAL_GPS)
if (mode == UART_MODE_GPS)
return false;
#elif defined(USB_SERIAL)
// GPS is not supported on VCP
if (port_nr == SP_VCP && mode == UART_MODE_GPS)
return false;
#endif
#if !defined(LUA)
if (mode == UART_MODE_LUA)
return false;
#endif
#if defined(USB_SERIAL)
// Telemetry input & SBUS trainer on VCP is not yet supported
if (port_nr == SP_VCP &&
(mode == UART_MODE_TELEMETRY || mode == UART_MODE_SBUS_TRAINER))
return false;
#endif
auto p = hasSerialMode(mode);
if (p >= 0 && p != port_nr) return false;
return true;
}
@@ -755,7 +778,8 @@ bool isRfProtocolAvailable(int protocol)
bool isTelemetryProtocolAvailable(int protocol)
{
#if defined(PCBTARANIS)
if (protocol == PROTOCOL_TELEMETRY_FRSKY_D_SECONDARY && g_eeGeneral.auxSerialMode != UART_MODE_TELEMETRY) {
if (protocol == PROTOCOL_TELEMETRY_FRSKY_D_SECONDARY &&
hasSerialMode(UART_MODE_TELEMETRY) < 0) {
return false;
}
#endif
@@ -791,51 +815,50 @@ bool isTelemetryProtocolAvailable(int protocol)
bool isTrainerModeAvailable(int mode)
{
#if defined(PCBTARANIS)
if (IS_EXTERNAL_MODULE_ENABLED() && (mode == TRAINER_MODE_MASTER_SBUS_EXTERNAL_MODULE || mode == TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE))
return false;
#endif
#if defined(PCBX9E)
if (g_eeGeneral.bluetoothMode && mode == TRAINER_MODE_MASTER_SBUS_EXTERNAL_MODULE) {
if (g_eeGeneral.bluetoothMode &&
mode == TRAINER_MODE_MASTER_SBUS_EXTERNAL_MODULE) {
// bluetooth uses the same USART than SBUS
return false;
}
#endif
#if defined(RADIO_TX16S) && defined(TRAINER_BATTERY_COMPARTMENT)
if (mode == TRAINER_MODE_MASTER_BATTERY_COMPARTMENT)
return (g_eeGeneral.auxSerialMode == UART_MODE_SBUS_TRAINER || g_eeGeneral.aux2SerialMode == UART_MODE_SBUS_TRAINER);
#elif defined(PCBTARANIS) && !defined(TRAINER_BATTERY_COMPARTMENT)
if (mode == TRAINER_MODE_MASTER_BATTERY_COMPARTMENT)
return false;
#elif defined(PCBTARANIS)
if (mode == TRAINER_MODE_MASTER_BATTERY_COMPARTMENT)
return g_eeGeneral.auxSerialMode == UART_MODE_SBUS_TRAINER;
#endif
#if defined(BLUETOOTH) && !defined(PCBX9E)
if (g_eeGeneral.bluetoothMode != BLUETOOTH_TRAINER && (mode == TRAINER_MODE_MASTER_BLUETOOTH || mode == TRAINER_MODE_SLAVE_BLUETOOTH))
return false;
if (mode == TRAINER_MODE_MASTER_SERIAL) {
#if defined(SBUS_TRAINER)
return hasSerialMode(UART_MODE_SBUS_TRAINER) >= 0;
#else
if (mode == TRAINER_MODE_MASTER_BLUETOOTH || mode == TRAINER_MODE_SLAVE_BLUETOOTH)
return false;
#endif
}
if ((mode == TRAINER_MODE_MASTER_BLUETOOTH ||
mode == TRAINER_MODE_SLAVE_BLUETOOTH)
#if defined(BLUETOOTH) && !defined(PCBX9E)
&& g_eeGeneral.bluetoothMode != BLUETOOTH_TRAINER
#endif
)
return false;
#if defined(PCBXLITE) && !defined(PCBXLITES)
if (mode == TRAINER_MODE_MASTER_TRAINER_JACK || mode == TRAINER_MODE_SLAVE)
return false;
#endif
#if defined(PCBTARANIS) || defined(PCBNV14)
#if !defined(TRAINER_MODULE_CPPM)
#if !defined(TRAINER_MODULE_CPPM)
if (mode == TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE)
return false;
#endif
#if !defined(TRAINER_MODULE_SBUS)
#endif
#if !defined(TRAINER_MODULE_SBUS)
if (mode == TRAINER_MODE_MASTER_SBUS_EXTERNAL_MODULE)
return false;
#endif
#endif
#if defined(TRAINER_MODULE_CPPM) || defined(TRAINER_MODULE_SBUS)
if (IS_EXTERNAL_MODULE_ENABLED() &&
(mode == TRAINER_MODE_MASTER_SBUS_EXTERNAL_MODULE ||
mode == TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE))
return false;
#endif
return true;
+2 -2
View File
@@ -86,8 +86,8 @@ bool isSourceAvailableInCustomSwitches(int source);
bool isSourceAvailableInResetSpecialFunction(int index);
bool isSourceAvailableInGlobalResetSpecialFunction(int index);
bool isSwitchAvailable(int swtch, SwitchContext context);
bool isAuxModeAvailable(int mode);
bool isAux2ModeAvailable(int mode);
bool isSerialModeAvailable(uint8_t port_nr, int mode);
int hasSerialMode(int mode);
bool isSwitchAvailableInLogicalSwitches(int swtch);
bool isSwitchAvailableInCustomFunctions(int swtch);
bool isSwitchAvailableInMixes(int swtch);
+65
View File
@@ -0,0 +1,65 @@
/*
* 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 <stdint.h>
enum ChannelsProtocols {
PROTOCOL_CHANNELS_UNINITIALIZED,
PROTOCOL_CHANNELS_NONE,
PROTOCOL_CHANNELS_PPM,
PROTOCOL_CHANNELS_PXX1_PULSES,
PROTOCOL_CHANNELS_PXX1_SERIAL,
PROTOCOL_CHANNELS_DSM2_LP45,
PROTOCOL_CHANNELS_DSM2_DSM2,
PROTOCOL_CHANNELS_DSM2_DSMX,
PROTOCOL_CHANNELS_CROSSFIRE,
PROTOCOL_CHANNELS_MULTIMODULE,
PROTOCOL_CHANNELS_SBUS,
PROTOCOL_CHANNELS_PXX2_LOWSPEED,
PROTOCOL_CHANNELS_PXX2_HIGHSPEED,
PROTOCOL_CHANNELS_AFHDS2A,
PROTOCOL_CHANNELS_AFHDS3,
PROTOCOL_CHANNELS_GHOST
};
struct etx_module_driver_t {
// Protocol implemented by this module driver
ChannelsProtocols protocol;
// Init module communication
void* (*init)(uint8_t module);
// // Default pulse period in microseconds
// uint16_t (*get_default_period)(uint8_t module);
// De-Init module communication
void (*deinit)(void* context);
// Prepare the pulses to be sent
void (*setupPulses)(void* context, int16_t* channels, uint8_t nChannels);
// Send the pulses
void (*sendPulses)(void* context);
};
+87
View File
@@ -0,0 +1,87 @@
/*
* 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 <stdint.h>
enum SerialParity {
ETX_Parity_None,
ETX_Parity_Even,
ETX_Parity_Odd,
};
enum SerialStopBits {
ETX_StopBits_One,
ETX_StopBits_OneAndHalf,
ETX_StopBits_Two,
};
enum SerialWordLength {
ETX_WordLength_8,
ETX_WordLength_9,
};
typedef struct {
uint32_t baudrate; // = 0;
uint8_t parity; // = ETX_Parity_None;
uint8_t stop_bits; // = ETX_StopBits_One;
uint8_t word_length; // = ETX_WordLength_8;
uint8_t rx_enable; // = false;
void (*on_receive)(uint8_t data); // = nullptr;
void (*on_error)(); // = nullptr;
} etx_serial_init;
struct etx_serial_callbacks_t {
uint8_t (*on_send)(uint8_t* data);
void (*on_receive)(uint8_t data);
void (*on_error)();
};
typedef struct {
// Init serial communication
void* (*init)(const etx_serial_init* params);
// De-Init serial communication
void (*deinit)(void* ctx);
// Send a single byte
void (*sendByte)(void* ctx, uint8_t byte);
// Send a buffer
void (*sendBuffer)(void* ctx, const uint8_t* data, uint8_t size);
// Wait for last send operation to complete
void (*waitForTxCompleted)(void* ctx);
// Fetch byte from internal buffer
int (*getByte)(void* ctx, uint8_t* data);
// Get current baudrate
uint32_t (*getBaudrate)(void*);
// Callbacks
void (*setReceiveCb)(void* ctx, void (*on_receive)(uint8_t*, uint32_t));
void (*setBaudrateCb)(void* ctx, void (*on_set_baudrate)(uint32_t));
} etx_serial_driver_t;
+32
View File
@@ -0,0 +1,32 @@
/*
* 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 "serial_driver.h"
typedef void etx_pwr_driver;
typedef struct {
const char* name;
const etx_serial_driver_t* uart;
void (*set_pwr)(uint8_t on);
} etx_serial_port_t;
+31 -18
View File
@@ -175,7 +175,7 @@ const uint8_t * FrskyDeviceFirmwareUpdate::readHalfDuplexFrame(uint32_t timeout)
{
for (int i = timeout; i >= 0; i--) {
uint8_t byte ;
while (telemetryGetByte(&byte)) {
while (sportGetByte(&byte)) {
if (pushFrskyTelemetryData(byte)) {
return telemetryRxBuffer;
}
@@ -251,11 +251,14 @@ void FrskyDeviceFirmwareUpdate::sendFrame()
switch (module) {
#if defined(INTERNAL_MODULE_PXX2)
case INTERNAL_MODULE:
return intmoduleSendBuffer(outputTelemetryBuffer.data, ptr - outputTelemetryBuffer.data);
IntmoduleSerialDriver.sendBuffer(uart_ctx, outputTelemetryBuffer.data,
ptr - outputTelemetryBuffer.data);
return;
#endif
default:
return sportSendBuffer(outputTelemetryBuffer.data, ptr - outputTelemetryBuffer.data);
sportSendBuffer(outputTelemetryBuffer.data, ptr - outputTelemetryBuffer.data);
return;
}
}
@@ -306,6 +309,18 @@ const char * FrskyDeviceFirmwareUpdate::sendReqVersion()
// X9D / X9D+ / X9E / XLite IXJT = use S.PORT @ 57600 bauds
// XLite PRO / X9Lite / X9D+ 2019 ISRM = use TX + RX @ 57600 bauds
#if defined(INTMODULE_USART)
static const etx_serial_init serialInitParams = {
.baudrate = 0,
.parity = ETX_Parity_None,
.stop_bits = ETX_StopBits_One,
.word_length = ETX_WordLength_8,
.rx_enable = true,
.on_receive = intmoduleFifoReceive,
.on_error = intmoduleFifoError,
};
#endif
const char * FrskyDeviceFirmwareUpdate::doFlashFirmware(const char * filename, ProgressHandler progressHandler)
{
FIL file;
@@ -335,10 +350,9 @@ const char * FrskyDeviceFirmwareUpdate::doFlashFirmware(const char * filename, P
INTERNAL_MODULE_ON();
RTOS_WAIT_MS(1);
etx_serial_init params;
etx_serial_init params(serialInitParams);
params.baudrate = 38400;
params.rx_enable = true;
intmoduleSerialStart(&params);
uart_ctx = IntmoduleSerialDriver.init(&params);
GPIO_SetBits(INTMODULE_BOOTCMD_GPIO, INTMODULE_BOOTCMD_GPIO_PIN);
result = uploadFileToHorusXJT(filename, &file, progressHandler);
@@ -352,10 +366,9 @@ const char * FrskyDeviceFirmwareUpdate::doFlashFirmware(const char * filename, P
switch (module) {
#if defined(INTERNAL_MODULE_PXX2)
case INTERNAL_MODULE: {
etx_serial_init params;
etx_serial_init params(serialInitParams);
params.baudrate = 57600;
params.rx_enable = true;
intmoduleSerialStart(&params);
uart_ctx = IntmoduleSerialDriver.init(&params);
} break;
#endif
@@ -387,14 +400,14 @@ const char * FrskyDeviceFirmwareUpdate::uploadFileToHorusXJT(const char * filena
return STR_DEVICE_NO_RESPONSE;
}
intmoduleSendByte(0x81);
IntmoduleSerialDriver.sendByte(uart_ctx, 0x81);
readBuffer(frame, 1, 100);
if (!readBuffer(frame, 8, 100) || frame[0] != 0x02) {
return STR_DEVICE_NO_RESPONSE;
}
intmoduleSendByte(0x82);
IntmoduleSerialDriver.sendByte(uart_ctx, 0x82);
readBuffer(frame, 1, 100);
uint8_t index = 0;
@@ -412,7 +425,7 @@ const char * FrskyDeviceFirmwareUpdate::uploadFileToHorusXJT(const char * filena
return STR_DEVICE_WRONG_REQUEST;
if (count == 0) {
intmoduleSendByte(0xA1);
IntmoduleSerialDriver.sendByte(uart_ctx, 0xA1);
RTOS_WAIT_MS(50);
return nullptr;
}
@@ -420,15 +433,15 @@ const char * FrskyDeviceFirmwareUpdate::uploadFileToHorusXJT(const char * filena
if (count < 1024)
memset(((uint8_t *)buffer) + count, 0, 1024 - count);
intmoduleSendByte(frame[0] + 0x80);
intmoduleSendByte(frame[1]);
IntmoduleSerialDriver.sendByte(uart_ctx, frame[0] + 0x80);
IntmoduleSerialDriver.sendByte(uart_ctx, frame[1]);
uint16_t crc_16 = crc16(CRC_1189, (uint8_t *)buffer, 1024, crc16(CRC_1189, &frame[1], 1));
for (size_t i = 0; i < sizeof(buffer); i++) {
intmoduleSendByte(((uint8_t *)buffer)[i]);
IntmoduleSerialDriver.sendByte(uart_ctx, ((uint8_t *)buffer)[i]);
}
intmoduleSendByte(crc_16 >> 8);
intmoduleSendByte(crc_16);
IntmoduleSerialDriver.sendByte(uart_ctx, crc_16 >> 8);
IntmoduleSerialDriver.sendByte(uart_ctx, crc_16);
index++;
}
@@ -582,7 +595,7 @@ const char * FrskyChipFirmwareUpdate::waitAnswer(uint8_t & status)
for (uint8_t i = 0; i < sizeof(buffer); i++) {
uint32_t retry = 0;
while (true) {
if (telemetryGetByte(&buffer[i])) {
if (sportGetByte(&buffer[i])) {
if ((i == 0 && buffer[0] != 0x7F) ||
(i == 1 && buffer[1] != 0xFE) ||
(i == 10 && buffer[10] != 0x0D) ||
+1
View File
@@ -137,6 +137,7 @@ class FrskyDeviceFirmwareUpdate {
uint32_t address = 0;
ModuleIndex module;
uint8_t frame[12];
void* uart_ctx = nullptr;
void startFrame(uint8_t command);
void sendFrame();
+49 -31
View File
@@ -26,6 +26,9 @@
#include "multi_firmware_update.h"
#include "stk500.h"
#include "debug.h"
#include "timers_driver.h"
#include <memory>
#if defined(LIBOPENUI)
#include "libopenui.h"
@@ -41,50 +44,66 @@
#include "intmodule_serial_driver.h"
#endif
#include "extmodule_driver.h"
#define UPDATE_MULTI_EXT_BIN ".bin"
class MultiFirmwareUpdateDriver
{
public:
MultiFirmwareUpdateDriver() {}
const char * flashFirmware(FIL * file, const char * label, ProgressHandler progressHandler) const;
virtual ~MultiFirmwareUpdateDriver() {}
const char* flashFirmware(FIL* file, const char* label,
ProgressHandler progressHandler);
protected:
virtual void moduleOn() const = 0;
virtual void init(bool inverted) const = 0;
virtual void init(bool inverted) = 0;
virtual bool getByte(uint8_t & byte) const = 0;
virtual void sendByte(uint8_t byte) const = 0;
virtual void clear() const = 0;
virtual void deinit(bool inverted) const {}
virtual void deinit(bool inverted) {}
private:
bool getRxByte(uint8_t & byte) const;
bool checkRxByte(uint8_t byte) const;
const char * waitForInitialSync(bool& inverted) const;
const char * waitForInitialSync(bool& inverted);
const char * getDeviceSignature(uint8_t * signature) const;
const char * loadAddress(uint32_t offset) const;
const char * progPage(uint8_t * buffer, uint16_t size) const;
void leaveProgMode(bool inverted) const;
void leaveProgMode(bool inverted);
};
#if defined(INTERNAL_MODULE_MULTI)
static const etx_serial_init serialInitParams = {
.baudrate = 0,
.parity = ETX_Parity_None,
.stop_bits = ETX_StopBits_One,
.word_length = ETX_WordLength_8,
.rx_enable = true,
.on_receive = intmoduleFifoReceive,
.on_error = intmoduleFifoError,
};
class MultiInternalUpdateDriver: public MultiFirmwareUpdateDriver
{
public:
MultiInternalUpdateDriver() {}
protected:
void* uart_ctx = nullptr;
void moduleOn() const override
{
INTERNAL_MODULE_ON();
}
void init(bool inverted) const override
void init(bool inverted) override
{
etx_serial_init params;
etx_serial_init params(serialInitParams);
params.baudrate = 57600;
params.rx_enable = true;
intmoduleSerialStart(&params);
uart_ctx = IntmoduleSerialDriver.init(&params);
}
bool getByte(uint8_t & byte) const override
@@ -94,7 +113,7 @@ class MultiInternalUpdateDriver: public MultiFirmwareUpdateDriver
void sendByte(uint8_t byte) const override
{
intmoduleSendByte(byte);
IntmoduleSerialDriver.sendByte(uart_ctx, byte);
}
void clear() const override
@@ -102,13 +121,13 @@ class MultiInternalUpdateDriver: public MultiFirmwareUpdateDriver
intmoduleFifo.clear();
}
void deinit(bool inverted) const override
void deinit(bool inverted) override
{
IntmoduleSerialDriver.deinit(uart_ctx);
uart_ctx = nullptr;
clear();
}
};
static const MultiInternalUpdateDriver multiInternalUpdateDriver;
#endif
class MultiExternalUpdateDriver: public MultiFirmwareUpdateDriver
@@ -122,7 +141,7 @@ class MultiExternalUpdateDriver: public MultiFirmwareUpdateDriver
EXTERNAL_MODULE_ON();
}
void init(bool inverted) const override
void init(bool inverted) override
{
#if !defined(EXTMODULE_USART)
GPIO_InitTypeDef GPIO_InitStructure;
@@ -142,7 +161,7 @@ class MultiExternalUpdateDriver: public MultiFirmwareUpdateDriver
bool getByte(uint8_t & byte) const override
{
return telemetryGetByte(&byte);
return sportGetByte(&byte);
}
void sendByte(uint8_t byte) const override
@@ -157,7 +176,7 @@ class MultiExternalUpdateDriver: public MultiFirmwareUpdateDriver
telemetryClearFifo();
}
void deinit(bool inverted) const override
void deinit(bool inverted) override
{
if (inverted)
telemetryPortInvertedInit(0);
@@ -168,8 +187,6 @@ class MultiExternalUpdateDriver: public MultiFirmwareUpdateDriver
}
};
static const MultiExternalUpdateDriver multiExternalUpdateDriver;
class MultiExtSportUpdateDriver: public MultiFirmwareUpdateDriver
{
public:
@@ -181,14 +198,14 @@ class MultiExtSportUpdateDriver: public MultiFirmwareUpdateDriver
EXTERNAL_MODULE_ON();
}
void init(bool inverted) const override
void init(bool inverted) override
{
telemetryPortInit(57600, TELEMETRY_SERIAL_WITHOUT_DMA);
}
bool getByte(uint8_t & byte) const override
{
return telemetryGetByte(&byte);
return sportGetByte(&byte);
}
void sendByte(uint8_t byte) const override
@@ -202,15 +219,13 @@ class MultiExtSportUpdateDriver: public MultiFirmwareUpdateDriver
telemetryClearFifo();
}
void deinit(bool inverted) const override
void deinit(bool inverted) override
{
telemetryPortInit(0, 0);
clear();
}
};
static const MultiExtSportUpdateDriver multiExtSportUpdateDriver;
bool MultiFirmwareUpdateDriver::getRxByte(uint8_t & byte) const
{
uint16_t time;
@@ -236,7 +251,7 @@ bool MultiFirmwareUpdateDriver::checkRxByte(uint8_t byte) const
return getRxByte(rxchar) ? rxchar == byte : false;
}
const char * MultiFirmwareUpdateDriver::waitForInitialSync(bool & inverted) const
const char * MultiFirmwareUpdateDriver::waitForInitialSync(bool & inverted)
{
uint8_t byte;
int retries = 200;
@@ -360,7 +375,7 @@ const char * MultiFirmwareUpdateDriver::progPage(uint8_t * buffer, uint16_t size
return nullptr;
}
void MultiFirmwareUpdateDriver::leaveProgMode(bool inverted) const
void MultiFirmwareUpdateDriver::leaveProgMode(bool inverted)
{
sendByte(STK_LEAVE_PROGMODE);
sendByte(CRC_EOP);
@@ -370,7 +385,8 @@ void MultiFirmwareUpdateDriver::leaveProgMode(bool inverted) const
deinit(inverted);
}
const char * MultiFirmwareUpdateDriver::flashFirmware(FIL * file, const char * label, ProgressHandler progressHandler) const
const char* MultiFirmwareUpdateDriver::flashFirmware(
FIL* file, const char* label, ProgressHandler progressHandler)
{
#if defined(SIMU)
for (uint16_t i = 0; i < 100; i++) {
@@ -601,13 +617,15 @@ bool MultiDeviceFirmwareUpdate::flashFirmware(const char * filename, ProgressHan
}
}
const MultiFirmwareUpdateDriver * driver = &multiExternalUpdateDriver;
std::unique_ptr<MultiFirmwareUpdateDriver> driver;
if (module == EXTERNAL_MODULE)
driver.reset(new MultiExternalUpdateDriver());
#if defined(INTERNAL_MODULE_MULTI)
if (module == INTERNAL_MODULE)
driver = &multiInternalUpdateDriver;
else if (module == INTERNAL_MODULE)
driver.reset(new MultiInternalUpdateDriver());
#endif
if (type == MULTI_TYPE_ELRS)
driver = &multiExtSportUpdateDriver;
else if (type == MULTI_TYPE_ELRS)
driver.reset(new MultiExtSportUpdateDriver());
pausePulses();
+97 -59
View File
@@ -27,6 +27,7 @@
#include "api_filesystem.h"
#include "telemetry/frsky.h"
#include "telemetry/multi.h"
#include "aux_serial_driver.h"
#if defined(LIBOPENUI)
#include "libopenui.h"
@@ -90,9 +91,61 @@
{ "EVT_"#xxx"_LONG", EVT_KEY_LONG(yyy) }, \
{ "EVT_"#xxx"_REPT", EVT_KEY_REPT(yyy) }
#if defined(LUA) && !defined(CLI)
Fifo<uint8_t, LUA_FIFO_SIZE> * luaRxFifo = nullptr;
#endif
// Note:
// - luaRxFifo & luaReceiveData are used only for USB serial
// - otherwise, the AUX serial buffer is used directly
//
static Fifo<uint8_t, LUA_FIFO_SIZE>* luaRxFifo = nullptr;
static int luaRxFifoGetByte(void*, uint8_t* data)
{
if (!luaRxFifo) return -1;
return luaRxFifo->pop(*data);
}
void luaAllocRxFifo()
{
if (!luaRxFifo) {
auto fifo = new Fifo<uint8_t, LUA_FIFO_SIZE>();
luaRxFifo = fifo;
luaSetGetSerialByte(nullptr, luaRxFifoGetByte);
}
}
void luaFreeRxFifo()
{
auto fifo = luaRxFifo;
luaSetGetSerialByte(nullptr, nullptr);
luaRxFifo = nullptr;
delete(fifo);
}
void luaReceiveData(uint8_t* buf, uint32_t len)
{
if (luaRxFifo) {
while(len--) luaRxFifo->push(*buf++);
}
}
static void (*luaSendDataCb)(void*, uint8_t) = nullptr;
static void* luaSendDataCtx = nullptr;
void luaSetSendCb(void* ctx, void (*cb)(void*, uint8_t))
{
luaSendDataCb = nullptr;
luaSendDataCtx = ctx;
luaSendDataCb = cb;
}
static int (*luaGetSerialByte)(void*, uint8_t*) = nullptr;
static void* luaGetSerialByteCtx = nullptr;
void luaSetGetSerialByte(void* ctx, int (*fct)(void*, uint8_t*))
{
luaGetSerialByte = nullptr;
luaGetSerialByteCtx = ctx;
luaGetSerialByte = fct;
}
/*luadoc
@function getVersion()
@@ -1881,22 +1934,23 @@ Set baudrate for serial port(s) affected to LUA
*/
static int luaSetSerialBaudrate(lua_State * L)
{
#if defined(AUX_SERIAL) || defined(AUX2_SERIAL)
unsigned int baudrate = luaL_checkunsigned(L, 1);
#endif
// #if defined(AUX_SERIAL) || defined(AUX2_SERIAL)
// unsigned int baudrate = luaL_checkunsigned(L, 1);
// #endif
#if defined(AUX_SERIAL)
if (auxSerialMode == UART_MODE_LUA) {
auxSerialStop();
auxSerialSetup(baudrate, false);
}
#endif
#if defined(AUX2_SERIAL)
if (aux2SerialMode == UART_MODE_LUA) {
aux2SerialStop();
aux2SerialSetup(baudrate, false);
}
#endif
// TODO: add some callbacks for serial settings
// #if defined(AUX_SERIAL)
// if (auxSerialMode == UART_MODE_LUA) {
// auxSerialStop();
// auxSerialSetup(baudrate, false);
// }
// #endif
// #if defined(AUX2_SERIAL)
// if (aux2SerialMode == UART_MODE_LUA) {
// aux2SerialStop();
// aux2SerialSetup(baudrate, false);
// }
// #endif
return 1;
}
@@ -1916,30 +1970,15 @@ static int luaSerialWrite(lua_State * L)
if (!str || len < 1)
return 0;
#if defined(USB_SERIAL)
if (getSelectedUsbMode() == USB_SERIAL_MODE) {
auto _sendCb = luaSendDataCb;
auto _ctx = luaSendDataCtx;
if (_sendCb) {
size_t wr_len = len;
const char* p = str;
while(wr_len--) usbSerialPutc(*p++);
while(wr_len--) _sendCb(_ctx, *p++);
}
#endif
#if defined(AUX_SERIAL)
if (auxSerialMode == UART_MODE_LUA) {
size_t wr_len = len;
const char* p = str;
while(wr_len--) auxSerialPutc(*p++);
}
#endif
#if defined(AUX2_SERIAL)
if (aux2SerialMode == UART_MODE_LUA) {
size_t wr_len = len;
const char* p = str;
while(wr_len--) aux2SerialPutc(*p++);
}
#endif
return 0;
}
@@ -1961,30 +2000,29 @@ static int luaSerialRead(lua_State * L)
#if defined(LUA) && !defined(CLI)
int num = luaL_optunsigned(L, 1, 0);
if (!luaRxFifo) {
luaRxFifo = new Fifo<uint8_t, LUA_FIFO_SIZE>();
if (!luaRxFifo) {
lua_pushlstring(L, "", 0);
return 1;
}
}
uint8_t str[LUA_FIFO_SIZE];
uint8_t *p = str;
while (luaRxFifo->pop(*p)) {
p++; // increment only when pop was successful
if (p - str >= LUA_FIFO_SIZE) {
// buffer full
break;
}
if (num == 0) {
if (*(p - 1) == '\n' || *(p - 1) == '\r') {
// found newline
auto _getByte = luaGetSerialByte;
auto _ctx = luaGetSerialByteCtx;
if (_getByte) {
while (_getByte(_ctx, p) > 0) {
p++; // increment only when pop was successful
if (p - str >= LUA_FIFO_SIZE) {
// buffer full
break;
}
if (num == 0) {
if (*(p - 1) == '\n' || *(p - 1) == '\r') {
// found newline
break;
}
}
else if (p - str >= num) {
// requested number of characters reached
break;
}
}
else if (p - str >= num) {
// requested number of characters reached
break;
}
}
lua_pushlstring(L, (const char*)str, p - str);
+7 -3
View File
@@ -48,10 +48,14 @@ extern "C" {
#endif
#endif
#if !defined(CLI) || defined(AUX2_SERIAL)
// LUA serial connection
#define LUA_FIFO_SIZE 256
extern Fifo<uint8_t, LUA_FIFO_SIZE> * luaRxFifo;
#endif
void luaAllocRxFifo();
void luaFreeRxFifo();
void luaReceiveData(uint8_t* buf, uint32_t len);
void luaSetSendCb(void* ctx, void (*cb)(void*, uint8_t));
void luaSetGetSerialByte(void* ctx, int (*fct)(void*, uint8_t*));
extern lua_State * lsScripts;
+13
View File
@@ -26,6 +26,10 @@
#include "libopenui.h"
#endif
#if defined(CLI)
#include "cli.h"
#endif
uint8_t currentSpeakerVolume = 255;
uint8_t requiredSpeakerVolume = 255;
uint8_t currentBacklightBright = 0;
@@ -90,9 +94,11 @@ void onUSBConnectMenu(const char *result)
else if (result == STR_USB_JOYSTICK) {
setSelectedUsbMode(USB_JOYSTICK_MODE);
}
#if defined(USB_SERIAL)
else if (result == STR_USB_SERIAL) {
setSelectedUsbMode(USB_SERIAL_MODE);
}
#endif
else if (result == STR_EXIT) {
_usbDisabled = true;
}
@@ -153,6 +159,11 @@ void handleUsbConnection()
opentxClose(false);
usbPluggedIn();
}
#if defined(USB_SERIAL)
else if (getSelectedUsbMode() == USB_SERIAL_MODE) {
serialInit(SP_VCP, serialGetMode(SP_VCP));
}
#endif
usbStart();
TRACE("USB started");
@@ -165,6 +176,8 @@ void handleUsbConnection()
if (getSelectedUsbMode() == USB_MASS_STORAGE_MODE) {
opentxResume();
pushEvent(EVT_ENTRY);
} else if (getSelectedUsbMode() == USB_SERIAL_MODE) {
serialStop(SP_VCP);
}
TRACE("reset selected USB mode");
setSelectedUsbMode(USB_UNSELECTED_MODE);
+26 -21
View File
@@ -22,6 +22,32 @@
#include "opentx.h"
#include "mixer_scheduler.h"
bool mixerSchedulerWaitForTrigger(uint8_t timeoutMs)
{
#if !defined(SIMU)
uint32_t ulNotificationValue;
const TickType_t xMaxBlockTime = pdMS_TO_TICKS( timeoutMs );
/* Wait to be notified that the transmission is complete. Note
the first parameter is pdTRUE, which has the effect of clearing
the task's notification value back to 0, making the notification
value act like a binary (rather than a counting) semaphore. */
ulNotificationValue = ulTaskNotifyTake( pdTRUE, xMaxBlockTime );
if( ulNotificationValue == 1 ) {
/* The transmission ended as expected. */
return false;
} else {
/* The call to ulTaskNotifyTake() timed out. */
return true;
}
#else
simuSleep(timeoutMs);
return true;
#endif
}
#if !defined(SIMU)
// Global trigger flag
@@ -72,27 +98,6 @@ void mixerSchedulerSetPeriod(uint8_t moduleIdx, uint16_t periodUs)
mixerSchedules[moduleIdx].period = periodUs;
}
bool mixerSchedulerWaitForTrigger(uint8_t timeoutMs)
{
uint32_t ulNotificationValue;
const TickType_t xMaxBlockTime = pdMS_TO_TICKS( timeoutMs );
/* Wait to be notified that the transmission is complete. Note
the first parameter is pdTRUE, which has the effect of clearing
the task's notification value back to 0, making the notification
value act like a binary (rather than a counting) semaphore. */
ulNotificationValue = ulTaskNotifyTake( pdTRUE, xMaxBlockTime );
if( ulNotificationValue == 1 ) {
/* The transmission ended as expected. */
return false;
} else {
/* The call to ulTaskNotifyTake() timed out. */
return true;
}
}
void mixerSchedulerISRTrigger()
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
+6 -15
View File
@@ -19,8 +19,9 @@
* GNU General Public License for more details.
*/
#ifndef _MIXER_SCHEDULER_H_
#define _MIXER_SCHEDULER_H_
#pragma once
#include <stdint.h>
#define MIXER_SCHEDULER_DEFAULT_PERIOD_US 4000u // 4ms
#define MIXER_SCHEDULER_JOYSTICK_PERIOD_US 2000u // 2ms
@@ -45,12 +46,6 @@ void mixerSchedulerResetTimer();
// Set the scheduling period for a given module
void mixerSchedulerSetPeriod(uint8_t moduleIdx, uint16_t periodUs);
// Clear the flag before waiting
// Wait for the scheduler timer to trigger
// returns true if timeout, false otherwise
bool mixerSchedulerWaitForTrigger(uint8_t timeoutMs);
// Enable the timer trigger
void mixerSchedulerEnableTrigger();
@@ -72,12 +67,6 @@ void mixerSchedulerISRTrigger();
#define mixerSchedulerSetPeriod(m,p)
#define mixerSchedulerClearTrigger()
static inline bool mixerSchedulerWaitForTrigger(uint8_t timeout)
{
simuSleep(timeout);
return false;
}
#define mixerSchedulerEnableTrigger()
#define mixerSchedulerDisableTrigger()
@@ -86,4 +75,6 @@ static inline bool mixerSchedulerWaitForTrigger(uint8_t timeout)
#endif
#endif
// Wait for the scheduler timer to trigger
// returns true if timeout, false otherwise
bool mixerSchedulerWaitForTrigger(uint8_t timeoutMs);
-2
View File
@@ -44,8 +44,6 @@
#define IS_TRAINER_EXTERNAL_MODULE() false
#endif
#define IS_TRAINER_AUX_SERIAL() (g_eeGeneral.auxSerialMode == UART_MODE_SBUS_TRAINER)
#define IS_PLAY_FUNC(func) ((func) >= FUNC_PLAY_SOUND && func <= FUNC_PLAY_VALUE)
#if defined(GVARS)
+3 -8
View File
@@ -22,6 +22,7 @@
#include "opentx.h"
#include "io/frsky_firmware_update.h"
#include "hal/adc_driver.h"
#include "aux_serial_driver.h"
#if defined(LIBOPENUI)
#include "libopenui.h"
@@ -1868,14 +1869,8 @@ void opentxInit()
#endif
#endif // #if !defined(EEPROM)
#if defined(AUX_SERIAL)
auxSerialInit(g_eeGeneral.auxSerialMode, modelTelemetryProtocol());
#endif
#if defined(AUX2_SERIAL)
aux2SerialInit(g_eeGeneral.aux2SerialMode, modelTelemetryProtocol());
#endif
initSerialPorts();
currentSpeakerVolume = requiredSpeakerVolume = g_eeGeneral.speakerVolume + VOLUME_LEVEL_DEF;
currentBacklightBright = requiredBacklightBright = g_eeGeneral.backlightBright;
#if !defined(SOFTWARE_VOLUME)
-8
View File
@@ -582,14 +582,6 @@ void flightReset(uint8_t check=true);
#define RESET_THR_TRACE() s_timeCum16ThrP = s_timeCumThr = 0
#endif
#if defined(SIMU)
uint16_t getTmr2MHz();
uint16_t getTmr16KHz();
#else
static inline uint16_t getTmr2MHz() { return TIMER_2MHz_TIMER->CNT; }
#endif
#if defined(SPLASH)
void doSplash();
#endif
+75
View File
@@ -20,6 +20,15 @@
*/
#include "afhds2.h"
#include "flysky.h"
#include "intmodule_serial_driver.h"
#include "mixer_scheduler.h"
// solely for 'intmoduleFifo'
// TODO: remove this non-sense
#include "opentx.h"
#include "pulses/pxx2.h"
afhds2::afhds2() {
// TODO Auto-generated constructor stub
@@ -30,3 +39,69 @@ afhds2::~afhds2() {
// TODO Auto-generated destructor stub
}
const etx_serial_init afhds2SerialInitParams = {
.baudrate = INTMODULE_USART_AFHDS2_BAUDRATE,
.parity = ETX_Parity_None,
.stop_bits = ETX_StopBits_One,
.word_length = ETX_WordLength_8,
.rx_enable = true,
.on_receive = intmoduleFifoReceive,
.on_error = intmoduleFifoError,
};
static void* afhds2Init(uint8_t module)
{
(void)module;
// serial port setup
resetPulsesAFHDS2();
intmoduleFifo.clear();
IntmoduleSerialDriver.init(&afhds2SerialInitParams);
// mixer setup
mixerSchedulerSetPeriod(INTERNAL_MODULE, AFHDS2_PERIOD);
INTERNAL_MODULE_ON();
return nullptr;
}
static void afhds2DeInit(void* context)
{
INTERNAL_MODULE_OFF();
intmoduleFifo.clear();
IntmoduleSerialDriver.deinit(context);
// mixer setup
mixerSchedulerSetPeriod(INTERNAL_MODULE, 0);
}
static void afhds2SetupPulses(void* context, int16_t* channels, uint8_t nChannels)
{
(void)context;
// TODO:
(void)channels;
(void)nChannels;
ModuleSyncStatus& status = getModuleSyncStatus(INTERNAL_MODULE);
mixerSchedulerSetPeriod(INTERNAL_MODULE, status.isValid()
? status.getAdjustedRefreshRate()
: AFHDS2_PERIOD);
status.invalidate();
setupPulsesAFHDS2();
}
static void afhds2SendPulses(void* context)
{
uint8_t* data = (uint8_t*)intmodulePulsesData.flysky.pulses;
uint16_t size = intmodulePulsesData.flysky.ptr - data;
IntmoduleSerialDriver.sendBuffer(context, data, size);
}
const etx_module_driver_t Afhds2InternalDriver = {
.protocol = PROTOCOL_CHANNELS_AFHDS2A,
.init = afhds2Init,
.deinit = afhds2DeInit,
.setupPulses = afhds2SetupPulses,
.sendPulses = afhds2SendPulses,
};
+6
View File
@@ -27,6 +27,9 @@
#include <map>
#include <list>
#include "hal/serial_driver.h"
#include "hal/module_driver.h"
#define AFHDS2_PERIOD (2 * 1000) /* us */
struct FlySkySerialPulsesData {
@@ -56,4 +59,7 @@ public:
virtual ~afhds2();
};
extern const etx_serial_init afhds2SerialInitParams;
extern const etx_module_driver_t Afhds2InternalDriver;
#endif /* PULSES_AFHDS2_H_ */
+134 -9
View File
@@ -20,6 +20,12 @@
*/
#include "opentx.h"
#include "mixer_scheduler.h"
#include "hal/module_driver.h"
#if defined(INTMODULE_USART)
#include "intmodule_serial_driver.h"
#endif
#define CROSSFIRE_CH_BITS 11
#define CROSSFIRE_CENTER 0x3E0
@@ -71,7 +77,8 @@ uint8_t createCrossfireChannelsFrame(uint8_t * frame, int16_t * pulses)
}
static void setupPulsesCrossfire(uint8_t idx, CrossfirePulsesData* p_data,
uint8_t endpoint)
uint8_t endpoint, int16_t* channels,
uint8_t nChannels)
{
#if defined(LUA)
if (outputTelemetryBuffer.destination == endpoint) {
@@ -88,18 +95,136 @@ static void setupPulsesCrossfire(uint8_t idx, CrossfirePulsesData* p_data,
} else {
p_data->length = createCrossfireChannelsFrame(
p_data->pulses,
&channelOutputs[g_model.moduleData[idx].channelsStart]);
channels /*TODO: nChannels*/);
}
}
}
void setupPulsesCrossfire(uint8_t idx)
static void crossfireSetupMixerScheduler(uint8_t module)
{
if (idx == INTERNAL_MODULE) {
auto* p_data = &intmodulePulsesData.crossfire;
setupPulsesCrossfire(idx, p_data, 0);
} else if (telemetryProtocol == PROTOCOL_TELEMETRY_CROSSFIRE) {
auto* p_data = &extmodulePulsesData.crossfire;
setupPulsesCrossfire(idx, p_data, TELEMETRY_ENDPOINT_SPORT);
ModuleSyncStatus& status = getModuleSyncStatus(module);
if (status.isValid()) {
mixerSchedulerSetPeriod(module, status.getAdjustedRefreshRate());
} else {
mixerSchedulerSetPeriod(module, CROSSFIRE_PERIOD);
}
}
#if defined(INTERNAL_MODULE_CRSF)
static void intmoduleCRSF_rx(uint8_t data)
{
intmoduleFifo.push(data);
#if !defined(SIMU)
// wakeup mixer when rx buffer is quarter full (16 bytes)
if (intmoduleFifo.size() >= 16) {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xTaskNotifyFromISR(mixerTaskId.rtos_handle, 0, eNoAction,
&xHigherPriorityTaskWoken);
// might effect a context switch on ISR exit
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
#endif
}
static const etx_serial_init intmoduleCrossfireInitParams = {
.baudrate = 0,
.parity = ETX_Parity_None,
.stop_bits = ETX_StopBits_One,
.word_length = ETX_WordLength_8,
.rx_enable = true,
.on_receive = intmoduleCRSF_rx,
.on_error = nullptr,
};
static void* crossfireInitInternal(uint8_t module)
{
(void)module;
// serial port setup
etx_serial_init params(intmoduleCrossfireInitParams);
params.baudrate = CROSSFIRE_BAUDRATE;
// wakeup mixer when rx buffer is quarter full (16 bytes)
params.on_receive = intmoduleCRSF_rx;
intmoduleFifo.clear();
IntmoduleSerialDriver.init(&params);
INTERNAL_MODULE_ON();
return nullptr;
}
static void crossfireDeInitInternal(void* context)
{
(void)context;
INTERNAL_MODULE_OFF();
mixerSchedulerSetPeriod(INTERNAL_MODULE, 0);
intmoduleStop();
intmoduleFifo.clear();
}
static void crossfireSetupPulsesInternal(void* context, int16_t* channels, uint8_t nChannels)
{
auto* p_data = &intmodulePulsesData.crossfire;
crossfireSetupMixerScheduler(INTERNAL_MODULE);
setupPulsesCrossfire(INTERNAL_MODULE, p_data, 0, channels, nChannels);
}
static void crossfireSendPulsesInternal(void* context)
{
IntmoduleSerialDriver.sendBuffer(context, intmodulePulsesData.crossfire.pulses,
intmodulePulsesData.crossfire.length);
}
etx_module_driver_t CrossfireInternalDriver = {
.protocol = PROTOCOL_CHANNELS_CROSSFIRE,
.init = crossfireInitInternal,
.deinit = crossfireDeInitInternal,
.setupPulses = crossfireSetupPulsesInternal,
.sendPulses = crossfireSendPulsesInternal,
};
#endif
static void* crossfireInitExternal(uint8_t module)
{
telemetryInit(PROTOCOL_TELEMETRY_CROSSFIRE);
mixerSchedulerSetPeriod(module, CROSSFIRE_PERIOD);
EXTERNAL_MODULE_ON();
return nullptr;
}
static void crossfireDeInitExternal(void* context)
{
(void)context;
telemetryProtocol = 0xFF;
EXTERNAL_MODULE_OFF();
mixerSchedulerSetPeriod(EXTERNAL_MODULE, 0);
}
static void crossfireSetupPulsesExternal(void* context, int16_t* channels, uint8_t nChannels)
{
auto* p_data = &extmodulePulsesData.crossfire;
crossfireSetupMixerScheduler(EXTERNAL_MODULE);
setupPulsesCrossfire(EXTERNAL_MODULE, p_data, TELEMETRY_ENDPOINT_SPORT,
channels, nChannels);
}
static void crossfireSendPulsesExternal(void* context)
{
(void)context;
sportSendBuffer(extmodulePulsesData.crossfire.pulses,
extmodulePulsesData.crossfire.length);
}
etx_module_driver_t CrossfireExternalDriver = {
.protocol = PROTOCOL_CHANNELS_CROSSFIRE,
.init = crossfireInitExternal,
.deinit = crossfireDeInitExternal,
.setupPulses = crossfireSetupPulsesExternal,
.sendPulses = crossfireSendPulsesExternal
};
+27
View File
@@ -0,0 +1,27 @@
/*
* Copyright (C) EdgeTx
*
* Based on code named
* opentx - https://github.com/opentx/opentx
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#pragma once
#include "hal/module_driver.h"
extern etx_module_driver_t CrossfireInternalDriver;
extern etx_module_driver_t CrossfireExternalDriver;
+2 -2
View File
@@ -66,9 +66,9 @@ void sendByteDsm2(uint8_t b) // max 10 changes 0 10 10 10 10 1
void putDsm2Flush()
{
if (extmodulePulsesData.dsm2.index & 1)
*extmodulePulsesData.dsm2.ptr++ = 60000;
*extmodulePulsesData.dsm2.ptr++ = 255;
else
*(extmodulePulsesData.dsm2.ptr - 1) = 60000;
*(extmodulePulsesData.dsm2.ptr - 1) = 255;
}
// This is the data stream to send, prepare after 19.5 mS
+75
View File
@@ -24,6 +24,7 @@
#include "io/multi_protolist.h"
#include "telemetry/multi.h"
#include "mixer_scheduler.h"
// for the MULTI protocol definition
// see https://github.com/pascallanger/DIY-Multiprotocol-TX-Module
@@ -50,6 +51,20 @@ static void sendConfig(uint8_t moduleIdx);
static void sendDSM(uint8_t moduleIdx);
#endif
#if defined(INTMODULE_USART)
#include "intmodule_serial_driver.h"
etx_serial_init multiSerialInitParams = {
.baudrate = MULTIMODULE_BAUDRATE,
.parity = ETX_Parity_Even,
.stop_bits = ETX_StopBits_Two,
.word_length = ETX_WordLength_9,
.rx_enable = true,
.on_receive = intmoduleFifoReceive,
.on_error = intmoduleFifoError,
};
#endif
void multiPatchCustom(uint8_t moduleIdx)
{
if (g_model.moduleData[moduleIdx].multi.customProto) {
@@ -235,6 +250,66 @@ void setupPulsesMultiInternalModule()
intmodulePulsesData.multi.initFrame();
setupPulsesMulti(INTERNAL_MODULE);
}
static void* multiInit(uint8_t module)
{
(void)module;
// serial port setup
intmodulePulsesData.multi.initFrame();
intmoduleFifo.clear();
void* uart_ctx = IntmoduleSerialDriver.init(&multiSerialInitParams);
// mixer setup
mixerSchedulerSetPeriod(INTERNAL_MODULE, MULTIMODULE_PERIOD);
INTERNAL_MODULE_ON();
// reset status
getMultiModuleStatus(INTERNAL_MODULE).failsafeChecked = false;
getMultiModuleStatus(INTERNAL_MODULE).flags = 0;
#if defined(MULTI_PROTOLIST)
TRACE("enablePulsesInternalModule(): trigger scan");
MultiRfProtocols::instance(INTERNAL_MODULE)->triggerScan();
TRACE("counter = %d", moduleState[INTERNAL_MODULE].counter);
#endif
return uart_ctx;
}
static void multiDeInit(void* context)
{
INTERNAL_MODULE_OFF();
mixerSchedulerSetPeriod(INTERNAL_MODULE, 0);
IntmoduleSerialDriver.deinit(context);
}
static void multiSetupPulses(void* context, int16_t* channels, uint8_t nChannels)
{
(void)context;
// TODO:
(void)channels;
(void)nChannels;
intmodulePulsesData.multi.initFrame();
setupPulsesMulti(INTERNAL_MODULE);
}
static void multiSendPulses(void* context)
{
IntmoduleSerialDriver.sendBuffer(context, intmodulePulsesData.multi.getData(),
intmodulePulsesData.multi.getSize());
}
#include "hal/module_driver.h"
const etx_module_driver_t MultiInternalDriver = {
.protocol = PROTOCOL_CHANNELS_MULTIMODULE,
.init = multiInit,
.deinit = multiDeInit,
.setupPulses = multiSetupPulses,
.sendPulses = multiSendPulses
};
#endif
void sendChannels(uint8_t moduleIdx)
+5
View File
@@ -23,6 +23,8 @@
#define _MULTI_PULSES_H_
#include "pulses_common.h"
#include "hal/serial_driver.h"
#include "hal/module_driver.h"
void multiPatchCustom(uint8_t moduleIdx);
void convertEtxProtocolToMulti(int *protocol, int *subprotocol);
@@ -43,4 +45,7 @@ class UartMultiPulses: public DataBuffer<uint8_t, 64>
}
};
extern etx_serial_init multiSerialInitParams;
extern const etx_module_driver_t MultiInternalDriver;
#endif
+30 -17
View File
@@ -22,46 +22,59 @@
#include "opentx.h"
template<class T>
void setupPulsesPPM(PpmPulsesData<T> * ppmPulsesData, uint8_t channelsStart, int8_t channelsCount, int8_t frameLength)
void setupPulsesPPM(PpmPulsesData<T> * ppmPulsesData, uint8_t channelsStart, int8_t channelsCount)
{
int16_t PPM_range = g_model.extendedLimits ? (512*LIMIT_EXT_PERCENT/100) * 2 : 512 * 2; // range of 0.7 .. 1.7msec
int16_t PPM_range = g_model.extendedLimits ?
// range of 0.7 .. 1.7msec
(512*LIMIT_EXT_PERCENT/100) * 2 : 512 * 2;
// Total frame length = 22.5msec
// each pulse is 0.7..1.7ms long with a 0.3ms stop tail
// The pulse ISR is 2mhz that's why everything is multiplied by 2
uint8_t firstCh = channelsStart;
uint8_t lastCh = min<uint8_t>(MAX_OUTPUT_CHANNELS, firstCh + 8 + channelsCount);
uint8_t lastCh =
min<uint8_t>(MAX_OUTPUT_CHANNELS, firstCh + 8 + channelsCount);
ppmPulsesData->ptr = ppmPulsesData->pulses;
int32_t rest = 22500u * 2;
rest += int32_t(frameLength) * 1000;
for (uint32_t i=firstCh; i<lastCh; i++) {
int16_t v = limit((int16_t)-PPM_range, channelOutputs[i], (int16_t)PPM_range) + 2*PPM_CH_CENTER(i);
rest -= v;
*ppmPulsesData->ptr++ = v; /* as Pat MacKenzie suggests */
for (uint32_t i = firstCh; i < lastCh; i++) {
int16_t v =
limit((int16_t)-PPM_range, channelOutputs[i], (int16_t)PPM_range) +
2 * PPM_CH_CENTER(i);
*ppmPulsesData->ptr++ = v;
}
rest = limit<int32_t>(9000, rest, 65535); /* avoids that CCR2 is bigger than ARR which would cause reboot */
*ppmPulsesData->ptr++ = rest;
*ppmPulsesData->ptr = 0; // it's needed in case PPM is sent without DMA (we stop when we reach this 0)
// Set the final period to the max
// (a new transfer is issued before it expires)
// debug: set the last period to the ppm_delay
*ppmPulsesData->ptr++ = 2000;
//*ppmPulsesData->ptr++ = 65535;
// it's needed in case PPM is sent without DMA
// (we stop when we reach this 0)
*ppmPulsesData->ptr = 0;
}
void setupPulsesPPMTrainer()
{
setupPulsesPPM<trainer_pulse_duration_t>(&trainerPulsesData.ppm, g_model.trainerData.channelsStart, g_model.trainerData.channelsCount, g_model.trainerData.frameLength);
setupPulsesPPM<trainer_pulse_duration_t>(
&trainerPulsesData.ppm, g_model.trainerData.channelsStart,
g_model.trainerData.channelsCount);
}
#if defined(PCBTARANIS) && defined(INTERNAL_MODULE_PPM)
void setupPulsesPPMInternalModule()
{
setupPulsesPPM(&intmodulePulsesData.ppm, g_model.moduleData[INTERNAL_MODULE].channelsStart, g_model.moduleData[INTERNAL_MODULE].channelsCount, g_model.moduleData[INTERNAL_MODULE].ppm.frameLength);
setupPulsesPPM(&intmodulePulsesData.ppm,
g_model.moduleData[INTERNAL_MODULE].channelsStart,
g_model.moduleData[INTERNAL_MODULE].channelsCount);
}
#endif
void setupPulsesPPMExternalModule()
{
setupPulsesPPM(&extmodulePulsesData.ppm, g_model.moduleData[EXTERNAL_MODULE].channelsStart, g_model.moduleData[EXTERNAL_MODULE].channelsCount, g_model.moduleData[EXTERNAL_MODULE].ppm.frameLength);
setupPulsesPPM(&extmodulePulsesData.ppm,
g_model.moduleData[EXTERNAL_MODULE].channelsStart,
g_model.moduleData[EXTERNAL_MODULE].channelsCount);
}
+273 -320
View File
@@ -21,9 +21,9 @@
#include "opentx.h"
#include "mixer_scheduler.h"
#include "heartbeat_driver.h"
#include "io/frsky_pxx2.h"
#include "io/multi_protolist.h"
#include "pulses/pxx2.h"
#include "pulses/flysky.h"
@@ -33,6 +33,22 @@
#include "intmodule_pulses_driver.h"
#endif
#include "extmodule_serial_driver.h"
#include "extmodule_driver.h"
#if defined(CROSSFIRE)
#include "pulses/crossfire.h"
#endif
#if defined(MULTIMODULE)
#include "io/multi_protolist.h"
#include "pulses/multi.h"
#endif
#if defined(AFHDS2)
#include "pulses/afhds2.h"
#endif
uint8_t s_pulses_paused = 0;
ModuleState moduleState[NUM_MODULES];
InternalModulePulsesData intmodulePulsesData __DMA;
@@ -272,10 +288,183 @@ uint8_t getRequiredProtocol(uint8_t module)
return protocol;
}
#if defined(HARDWARE_INTERNAL_MODULE)
static void* internalModuleContext = nullptr;
static const etx_module_driver_t* internalModuleDriver = nullptr;
static void enablePulsesInternalModule(uint8_t protocol)
{
// start new protocol hardware here
if (internalModuleDriver) {
internalModuleDriver->deinit(internalModuleContext);
internalModuleContext = nullptr;
internalModuleDriver = nullptr;
} else {
intmoduleStop();
}
switch (protocol) {
#if defined(PXX1) && !defined(INTMODULE_USART)
case PROTOCOL_CHANNELS_PXX1_PULSES:
intmodulePxx1PulsesStart();
#if defined(INTMODULE_HEARTBEAT)
init_intmodule_heartbeat();
#endif
mixerSchedulerSetPeriod(INTERNAL_MODULE, INTMODULE_PXX1_SERIAL_PERIOD);
break;
#endif
#if defined(PXX1) && defined(INTMODULE_USART)
case PROTOCOL_CHANNELS_PXX1_SERIAL:
internalModuleContext = Pxx1InternalSerialDriver.init(INTERNAL_MODULE);
internalModuleDriver = &Pxx1InternalSerialDriver;
break;
#endif
#if defined(PXX2)
case PROTOCOL_CHANNELS_PXX2_HIGHSPEED:
internalModuleContext = Pxx2InternalDriver.init(INTERNAL_MODULE);
internalModuleDriver = &Pxx2InternalDriver;
break;
#endif
#if defined(INTERNAL_MODULE_MULTI)
case PROTOCOL_CHANNELS_MULTIMODULE:
internalModuleContext = MultiInternalDriver.init(INTERNAL_MODULE);
internalModuleDriver = &MultiInternalDriver;
break;
#endif
#if defined(INTERNAL_MODULE_CRSF)
case PROTOCOL_CHANNELS_CROSSFIRE:
internalModuleContext = CrossfireInternalDriver.init(INTERNAL_MODULE);
internalModuleDriver = &CrossfireInternalDriver;
break;
#endif
#if defined(INTERNAL_MODULE_PPM)
case PROTOCOL_CHANNELS_PPM:
intmodulePpmStart();
mixerSchedulerSetPeriod(INTERNAL_MODULE, PPM_PERIOD(INTERNAL_MODULE));
break;
#endif
#if defined(INTERNAL_MODULE_AFHDS2A)
case PROTOCOL_CHANNELS_AFHDS2A:
internalModuleContext = Afhds2InternalDriver.init(INTERNAL_MODULE);
internalModuleDriver = &Afhds2InternalDriver;
break;
#endif
default:
// internal module stopped, use default mixer period
mixerSchedulerSetPeriod(INTERNAL_MODULE, 0);
break;
}
}
bool setupPulsesInternalModule(uint8_t protocol)
{
uint8_t channelStart = g_model.moduleData[INTERNAL_MODULE].channelsStart;
int16_t* channels = &channelOutputs[channelStart];
uint8_t nChannels = 16; // TODO: MAX_CHANNELS - channelsStart
if (internalModuleDriver) {
internalModuleDriver->setupPulses(internalModuleContext,
channels, nChannels);
return true;
}
switch (protocol) {
#if defined(HARDWARE_INTERNAL_MODULE) && defined(PXX1) && !defined(INTMODULE_USART)
case PROTOCOL_CHANNELS_PXX1_PULSES:
intmodulePulsesData.pxx.setupFrame(INTERNAL_MODULE);
return true;
#endif
#if defined(PCBTARANIS) && defined(INTERNAL_MODULE_PPM)
case PROTOCOL_CHANNELS_PPM:
setupPulsesPPMInternalModule();
return true;
#endif
default:
return false;
}
}
void stopPulsesInternalModule()
{
if (moduleState[INTERNAL_MODULE].protocol != PROTOCOL_CHANNELS_UNINITIALIZED) {
if (internalModuleDriver) {
internalModuleDriver->deinit(internalModuleContext);
internalModuleDriver = nullptr;
internalModuleContext = nullptr;
} else {
mixerSchedulerSetPeriod(INTERNAL_MODULE, 0);
intmoduleStop();
}
moduleState[INTERNAL_MODULE].protocol = PROTOCOL_CHANNELS_NONE;
}
}
void intmoduleSendNextFrame()
{
if (internalModuleDriver) {
internalModuleDriver->sendPulses(internalModuleContext);
return;
}
switch (moduleState[INTERNAL_MODULE].protocol) {
#if defined(INTERNAL_MODULE_PPM)
case PROTOCOL_CHANNELS_PPM:
intmoduleSendNextFramePPM(
intmodulePulsesData.ppm.pulses,
intmodulePulsesData.ppm.ptr - intmodulePulsesData.ppm.pulses);
break;
#endif
#if defined(PXX1) && !defined(INTMODULE_USART)
case PROTOCOL_CHANNELS_PXX1_PULSES:
intmoduleSendNextFramePxx1(intmodulePulsesData.pxx.getData(),
intmodulePulsesData.pxx.getSize());
break;
#endif
}
}
bool setupPulsesInternalModule()
{
uint8_t protocol = getRequiredProtocol(INTERNAL_MODULE);
heartbeat |= (HEART_TIMER_PULSES << INTERNAL_MODULE);
if (moduleState[INTERNAL_MODULE].protocol != protocol) {
enablePulsesInternalModule(protocol);
moduleState[INTERNAL_MODULE].protocol = protocol;
return false;
}
else {
return setupPulsesInternalModule(protocol);
}
}
#endif
#if defined(HARDWARE_EXTERNAL_MODULE)
static void* externalModuleContext = nullptr;
static const etx_module_driver_t* externalModuleDriver = nullptr;
void enablePulsesExternalModule(uint8_t protocol)
{
// start new protocol hardware here
if (externalModuleDriver) {
externalModuleDriver->deinit(externalModuleContext);
externalModuleDriver = nullptr;
externalModuleContext = nullptr;
} else {
extmoduleStop();
}
switch (protocol) {
#if defined(PXX1)
@@ -287,8 +476,8 @@ void enablePulsesExternalModule(uint8_t protocol)
#if defined(PXX1) && defined(HARDWARE_EXTERNAL_MODULE_SIZE_SML)
case PROTOCOL_CHANNELS_PXX1_SERIAL:
extmodulePxx1SerialStart();
mixerSchedulerSetPeriod(EXTERNAL_MODULE, EXTMODULE_PXX1_SERIAL_PERIOD);
externalModuleContext = Pxx1ExternalSerialDriver.init(EXTERNAL_MODULE);
externalModuleDriver = &Pxx1ExternalSerialDriver;
break;
#endif
@@ -296,15 +485,19 @@ void enablePulsesExternalModule(uint8_t protocol)
case PROTOCOL_CHANNELS_DSM2_LP45:
case PROTOCOL_CHANNELS_DSM2_DSM2:
case PROTOCOL_CHANNELS_DSM2_DSMX:
#if defined(PCBSKY9X)
extmoduleSerialStart(DSM2_BAUDRATE, DSM2_PERIOD * 2000, false);
#else
extmoduleSerialStart();
mixerSchedulerSetPeriod(EXTERNAL_MODULE, DSM2_PERIOD);
#endif
break;
#endif
#if defined(CROSSFIRE)
case PROTOCOL_CHANNELS_CROSSFIRE:
EXTERNAL_MODULE_ON();
mixerSchedulerSetPeriod(EXTERNAL_MODULE, CROSSFIRE_PERIOD);
externalModuleContext = CrossfireExternalDriver.init(EXTERNAL_MODULE);
externalModuleDriver = &CrossfireExternalDriver;
break;
#endif
@@ -317,13 +510,13 @@ void enablePulsesExternalModule(uint8_t protocol)
#if defined(PXX2) && defined(EXTMODULE_USART)
case PROTOCOL_CHANNELS_PXX2_HIGHSPEED:
extmoduleInvertedSerialStart(PXX2_HIGHSPEED_BAUDRATE);
mixerSchedulerSetPeriod(EXTERNAL_MODULE, PXX2_NO_HEARTBEAT_PERIOD);
externalModuleContext = Pxx2ExternalDriver.init(EXTERNAL_MODULE);
externalModuleDriver = &Pxx2ExternalDriver;
break;
case PROTOCOL_CHANNELS_PXX2_LOWSPEED:
extmoduleInvertedSerialStart(PXX2_LOWSPEED_BAUDRATE);
mixerSchedulerSetPeriod(EXTERNAL_MODULE, PXX2_NO_HEARTBEAT_PERIOD);
externalModuleContext = Pxx2LowSpeedExternalDriver.init(EXTERNAL_MODULE);
externalModuleDriver = &Pxx2LowSpeedExternalDriver;
break;
#endif
@@ -341,20 +534,27 @@ void enablePulsesExternalModule(uint8_t protocol)
#if defined(SBUS)
case PROTOCOL_CHANNELS_SBUS:
#if defined(PCBSKY9X)
extmoduleSerialStart(SBUS_BAUDRATE, SBUS_PERIOD_HALF_US, false);
#else
extmoduleSerialStart();
mixerSchedulerSetPeriod(EXTERNAL_MODULE, SBUS_PERIOD);
#endif
break;
#endif
#if defined(PPM)
case PROTOCOL_CHANNELS_PPM:
extmodulePpmStart();
extmodulePpmStart(
GET_MODULE_PPM_DELAY(EXTERNAL_MODULE),
GET_MODULE_PPM_POLARITY(EXTERNAL_MODULE));
mixerSchedulerSetPeriod(EXTERNAL_MODULE, PPM_PERIOD(EXTERNAL_MODULE));
break;
#endif
#if defined(AFHDS3)
case PROTOCOL_CHANNELS_AFHDS3:
// convert to serial module interface
extmodulePulsesData.afhds3.init(EXTERNAL_MODULE);
extmoduleSerialStart();
mixerSchedulerSetPeriod(EXTERNAL_MODULE, AFHDS3_COMMAND_TIMEOUT * 1000 /* us */);
@@ -370,6 +570,16 @@ void enablePulsesExternalModule(uint8_t protocol)
bool setupPulsesExternalModule(uint8_t protocol)
{
uint8_t channelStart = g_model.moduleData[EXTERNAL_MODULE].channelsStart;
int16_t* channels = &channelOutputs[channelStart];
uint8_t nChannels = 16; // TODO: MAX_CHANNELS - channelsStart
if (externalModuleDriver) {
externalModuleDriver->setupPulses(externalModuleContext,
channels, nChannels);
return true;
}
switch (protocol) {
#if defined(PXX1)
@@ -378,19 +588,6 @@ bool setupPulsesExternalModule(uint8_t protocol)
return true;
#endif
#if defined(PXX1) && defined(HARDWARE_EXTERNAL_MODULE_SIZE_SML)
case PROTOCOL_CHANNELS_PXX1_SERIAL:
extmodulePulsesData.pxx_uart.setupFrame(EXTERNAL_MODULE);
return true;
#endif
#if defined(PXX2)
case PROTOCOL_CHANNELS_PXX2_HIGHSPEED:
case PROTOCOL_CHANNELS_PXX2_LOWSPEED:
extmodulePulsesData.pxx2.setupFrame(EXTERNAL_MODULE);
return true;
#endif
#if defined(SBUS)
case PROTOCOL_CHANNELS_SBUS:
setupPulsesSbus();
@@ -407,19 +604,6 @@ bool setupPulsesExternalModule(uint8_t protocol)
return true;
#endif
#if defined(CROSSFIRE)
case PROTOCOL_CHANNELS_CROSSFIRE:
{
ModuleSyncStatus& status = getModuleSyncStatus(EXTERNAL_MODULE);
if (status.isValid())
mixerSchedulerSetPeriod(EXTERNAL_MODULE, status.getAdjustedRefreshRate());
else
mixerSchedulerSetPeriod(EXTERNAL_MODULE, CROSSFIRE_PERIOD);
setupPulsesCrossfire(EXTERNAL_MODULE);
return true;
}
#endif
#if defined(GHOST)
case PROTOCOL_CHANNELS_GHOST:
{
@@ -462,314 +646,84 @@ bool setupPulsesExternalModule(uint8_t protocol)
return false;
}
}
#endif
#if defined(HARDWARE_INTERNAL_MODULE)
#if defined(INTERNAL_MODULE_CRSF)
static void intmoduleCRSF_rx(uint8_t data)
void extmoduleSendNextFrame()
{
intmoduleFifo.push(data);
#if !defined(SIMU)
// wakeup mixer when rx buffer is quarter full (16 bytes)
if (intmoduleFifo.size() >= 16) {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xTaskNotifyFromISR(mixerTaskId.rtos_handle, 0, eNoAction,
&xHigherPriorityTaskWoken);
// might effect a context switch on ISR exit
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
if (externalModuleDriver) {
externalModuleDriver->sendPulses(externalModuleContext);
return;
}
#endif
}
#endif
static void enablePulsesInternalModule(uint8_t protocol)
{
// start new protocol hardware here
switch (moduleState[EXTERNAL_MODULE].protocol) {
switch (protocol) {
#if defined(PXX1) && !defined(INTMODULE_USART)
case PROTOCOL_CHANNELS_PXX1_PULSES:
intmodulePxx1PulsesStart();
#if defined(INTMODULE_HEARTBEAT)
init_intmodule_heartbeat();
#endif
mixerSchedulerSetPeriod(INTERNAL_MODULE, INTMODULE_PXX1_SERIAL_PERIOD);
break;
#endif
#if defined(PXX1) && defined(INTMODULE_USART)
case PROTOCOL_CHANNELS_PXX1_SERIAL:
intmodulePxx1SerialStart();
#if defined(INTMODULE_HEARTBEAT)
init_intmodule_heartbeat();
#endif
mixerSchedulerSetPeriod(INTERNAL_MODULE, INTMODULE_PXX1_SERIAL_PERIOD);
break;
#endif
#if defined(PXX2)
case PROTOCOL_CHANNELS_PXX2_HIGHSPEED: {
etx_serial_init params;
params.baudrate = PXX2_HIGHSPEED_BAUDRATE;
params.rx_enable = true;
intmoduleFifo.clear();
intmoduleSerialStart(&params);
resetAccessAuthenticationCount();
#if defined(INTMODULE_HEARTBEAT)
// use backup trigger (1 ms later)
init_intmodule_heartbeat();
#endif
mixerSchedulerSetPeriod(INTERNAL_MODULE, PXX2_PERIOD);
} break;
#endif
#if defined(INTERNAL_MODULE_MULTI)
case PROTOCOL_CHANNELS_MULTIMODULE: {
// serial port setup
etx_serial_init params;
params.baudrate = MULTIMODULE_BAUDRATE;
params.rx_enable = true;
params.parity = USART_Parity_Even;
params.stop_bits = USART_StopBits_2;
params.word_length = USART_WordLength_9b;
intmodulePulsesData.multi.initFrame();
intmoduleFifo.clear();
intmoduleSerialStart(&params);
// mixer setup
mixerSchedulerSetPeriod(INTERNAL_MODULE, MULTIMODULE_PERIOD);
// reset status
getMultiModuleStatus(INTERNAL_MODULE).failsafeChecked = false;
getMultiModuleStatus(INTERNAL_MODULE).flags = 0;
#if defined(MULTI_PROTOLIST)
TRACE("enablePulsesInternalModule(): trigger scan");
MultiRfProtocols::instance(INTERNAL_MODULE)->triggerScan();
TRACE("counter = %d", moduleState[INTERNAL_MODULE].counter);
#endif
} break;
#endif
#if defined(INTERNAL_MODULE_CRSF)
case PROTOCOL_CHANNELS_CROSSFIRE: {
// serial port setup
etx_serial_init params;
params.baudrate = CROSSFIRE_BAUDRATE;
params.rx_enable = true;
// wakeup mixer when rx buffer is quarter full (16 bytes)
params.on_receive = intmoduleCRSF_rx;
intmoduleFifo.clear();
intmoduleSerialStart(&params);
// mixer setup
mixerSchedulerSetPeriod(INTERNAL_MODULE, CROSSFIRE_PERIOD);
} break;
#endif
#if defined(INTERNAL_MODULE_PPM)
case PROTOCOL_CHANNELS_PPM:
intmodulePpmStart();
mixerSchedulerSetPeriod(INTERNAL_MODULE, PPM_PERIOD(INTERNAL_MODULE));
extmoduleSendNextFramePpm(
extmodulePulsesData.ppm.pulses,
extmodulePulsesData.ppm.ptr - extmodulePulsesData.ppm.pulses,
GET_MODULE_PPM_DELAY(EXTERNAL_MODULE),
GET_MODULE_PPM_POLARITY(EXTERNAL_MODULE));
mixerSchedulerSetPeriod(EXTERNAL_MODULE, PPM_PERIOD(EXTERNAL_MODULE));
break;
#endif
#if defined(AFHDS2)
case PROTOCOL_CHANNELS_AFHDS2A: {
// serial port setup
etx_serial_init params;
params.baudrate = INTMODULE_USART_AFHDS2_BAUDRATE;
params.rx_enable = true;
resetPulsesAFHDS2();
intmoduleFifo.clear();
intmoduleSerialStart(&params);
// mixer setup
mixerSchedulerSetPeriod(INTERNAL_MODULE, AFHDS2_PERIOD);
} break;
#endif
default:
// internal module stopped, use default mixer period
mixerSchedulerSetPeriod(INTERNAL_MODULE, 0);
break;
}
}
bool setupPulsesInternalModule(uint8_t protocol)
{
switch (protocol) {
#if defined(HARDWARE_INTERNAL_MODULE) && defined(PXX1) && !defined(INTMODULE_USART)
case PROTOCOL_CHANNELS_PXX1_PULSES:
intmodulePulsesData.pxx.setupFrame(INTERNAL_MODULE);
return true;
#endif
#if defined(PXX1) && defined(INTMODULE_USART)
case PROTOCOL_CHANNELS_PXX1_SERIAL:
intmodulePulsesData.pxx_uart.setupFrame(INTERNAL_MODULE);
return true;
#endif
#if defined(PXX2)
case PROTOCOL_CHANNELS_PXX2_HIGHSPEED:
{
bool result = intmodulePulsesData.pxx2.setupFrame(INTERNAL_MODULE);
if (moduleState[INTERNAL_MODULE].mode == MODULE_MODE_SPECTRUM_ANALYSER || moduleState[INTERNAL_MODULE].mode == MODULE_MODE_POWER_METER) {
mixerSchedulerSetPeriod(INTERNAL_MODULE, PXX2_TOOLS_PERIOD);
}
else {
mixerSchedulerSetPeriod(INTERNAL_MODULE, PXX2_PERIOD);
}
return result;
}
#endif
#if defined(PCBTARANIS) && defined(INTERNAL_MODULE_PPM)
case PROTOCOL_CHANNELS_PPM:
setupPulsesPPMInternalModule();
return true;
#endif
#if defined(INTERNAL_MODULE_CRSF)
case PROTOCOL_CHANNELS_CROSSFIRE:
{
ModuleSyncStatus& status = getModuleSyncStatus(INTERNAL_MODULE);
if (status.isValid())
mixerSchedulerSetPeriod(INTERNAL_MODULE, status.getAdjustedRefreshRate());
else
mixerSchedulerSetPeriod(INTERNAL_MODULE, CROSSFIRE_PERIOD);
setupPulsesCrossfire(INTERNAL_MODULE);
return true;
}
#endif
#if defined(INTERNAL_MODULE_MULTI)
case PROTOCOL_CHANNELS_MULTIMODULE:
setupPulsesMultiInternalModule();
mixerSchedulerSetPeriod(INTERNAL_MODULE, MULTIMODULE_PERIOD);
return true;
#endif
#if defined(AFHDS2)
case PROTOCOL_CHANNELS_AFHDS2A:
{
ModuleSyncStatus& status = getModuleSyncStatus(INTERNAL_MODULE);
mixerSchedulerSetPeriod(
INTERNAL_MODULE,
status.isValid() ? status.getAdjustedRefreshRate() : AFHDS2_PERIOD);
status.invalidate();
setupPulsesAFHDS2();
return true;
}
#endif
default:
return false;
}
}
void stopPulsesInternalModule()
{
if (moduleState[INTERNAL_MODULE].protocol != PROTOCOL_CHANNELS_UNINITIALIZED) {
mixerSchedulerSetPeriod(INTERNAL_MODULE, 0);
intmoduleStop();
moduleState[INTERNAL_MODULE].protocol = PROTOCOL_CHANNELS_NONE;
}
}
void intmoduleSendNextFrame()
{
switch (moduleState[INTERNAL_MODULE].protocol) {
#if defined(PXX2)
case PROTOCOL_CHANNELS_PXX2_HIGHSPEED:
intmoduleSendBuffer(intmodulePulsesData.pxx2.getData(),
intmodulePulsesData.pxx2.getSize());
break;
#endif
#if defined(INTERNAL_MODULE_PPM)
case PROTOCOL_CHANNELS_PPM:
intmoduleSendNextFramePPM(
intmodulePulsesData.ppm.pulses,
intmodulePulsesData.ppm.ptr - intmodulePulsesData.ppm.pulses);
break;
#endif
#if defined(PXX1)
#if defined(INTMODULE_USART)
case PROTOCOL_CHANNELS_PXX1_SERIAL:
intmoduleSendBuffer(intmodulePulsesData.pxx_uart.getData(),
intmodulePulsesData.pxx_uart.getSize());
break;
#else
case PROTOCOL_CHANNELS_PXX1_PULSES:
intmoduleSendNextFramePxx1(intmodulePulsesData.pxx.getData(),
intmodulePulsesData.pxx.getSize());
extmoduleSendNextFramePxx1(extmodulePulsesData.pxx.getData(),
extmodulePulsesData.pxx.getSize());
break;
#endif
#if defined(AFHDS3)
case PROTOCOL_CHANNELS_AFHDS3:
#if defined(EXTMODULE_USART) && defined(EXTMODULE_TX_INVERT_GPIO)
extmoduleSendBuffer(extmodulePulsesData.afhds3.getData(),
extmodulePulsesData.afhds3.getSize());
#else
extmoduleSendNextFrameSoftSerial(extmodulePulsesData.afhds3.getData(),
extmodulePulsesData.afhds3.getSize(),
false);
#endif
break;
#endif
#if defined(INTERNAL_MODULE_MULTI)
#if defined(SBUS) || defined(DSM2) || defined(MULTIMODULE)
case PROTOCOL_CHANNELS_SBUS:
extmoduleSendNextFrameSoftSerial(
extmodulePulsesData.dsm2.pulses,
extmodulePulsesData.dsm2.ptr - extmodulePulsesData.dsm2.pulses,
GET_SBUS_POLARITY(EXTERNAL_MODULE));
break;
case PROTOCOL_CHANNELS_DSM2_LP45:
case PROTOCOL_CHANNELS_DSM2_DSM2:
case PROTOCOL_CHANNELS_DSM2_DSMX:
case PROTOCOL_CHANNELS_MULTIMODULE:
intmoduleSendBuffer(intmodulePulsesData.multi.getData(),
intmodulePulsesData.multi.getSize());
extmoduleSendNextFrameSoftSerial(
extmodulePulsesData.dsm2.pulses,
extmodulePulsesData.dsm2.ptr - extmodulePulsesData.dsm2.pulses);
break;
#endif
#if defined(INTERNAL_MODULE_CRSF)
case PROTOCOL_CHANNELS_CROSSFIRE:
intmoduleSendBuffer(intmodulePulsesData.crossfire.pulses,
intmodulePulsesData.crossfire.length);
#if defined(GHOST)
case PROTOCOL_CHANNELS_GHOST:
sportSendBuffer(extmodulePulsesData.ghost.pulses,
extmodulePulsesData.ghost.length);
break;
#endif
#if defined(AFHDS2)
case PROTOCOL_CHANNELS_AFHDS2A: {
uint8_t* data = (uint8_t*)intmodulePulsesData.flysky.pulses;
uint16_t size = intmodulePulsesData.flysky.ptr - data;
intmoduleSendBuffer(data, size);
} break;
#endif
}
}
bool setupPulsesInternalModule()
{
uint8_t protocol = getRequiredProtocol(INTERNAL_MODULE);
heartbeat |= (HEART_TIMER_PULSES << INTERNAL_MODULE);
if (moduleState[INTERNAL_MODULE].protocol != protocol) {
intmoduleStop();
enablePulsesInternalModule(protocol);
moduleState[INTERNAL_MODULE].protocol = protocol;
return false;
}
else {
return setupPulsesInternalModule(protocol);
}
}
#endif
#if defined(HARDWARE_EXTERNAL_MODULE)
void stopPulsesExternalModule()
{
if (moduleState[EXTERNAL_MODULE].protocol != PROTOCOL_CHANNELS_UNINITIALIZED) {
mixerSchedulerSetPeriod(EXTERNAL_MODULE, 0);
extmoduleStop();
if (moduleState[EXTERNAL_MODULE].protocol !=
PROTOCOL_CHANNELS_UNINITIALIZED) {
if (externalModuleDriver) {
externalModuleDriver->deinit(externalModuleContext);
externalModuleDriver = nullptr;
externalModuleContext = nullptr;
} else {
mixerSchedulerSetPeriod(EXTERNAL_MODULE, 0);
extmoduleStop();
}
moduleState[EXTERNAL_MODULE].protocol = PROTOCOL_CHANNELS_NONE;
}
}
@@ -781,7 +735,6 @@ bool setupPulsesExternalModule()
heartbeat |= (HEART_TIMER_PULSES << EXTERNAL_MODULE);
if (moduleState[EXTERNAL_MODULE].protocol != protocol) {
extmoduleStop();
enablePulsesExternalModule(protocol);
moduleState[EXTERNAL_MODULE].protocol = protocol;
return false;
+2 -19
View File
@@ -32,6 +32,7 @@
#include "afhds2.h"
#include "modules_helpers.h"
#include "ff.h"
#include "hal/module_driver.h"
#if defined(DSM2)
@@ -230,6 +231,7 @@ void intmoduleSendNextFrame();
#if defined(HARDWARE_EXTERNAL_MODULE)
bool setupPulsesExternalModule();
void stopPulsesExternalModule();
void extmoduleSendNextFrame();
#endif
void setupPulsesDSM2();
void setupPulsesCrossfire(uint8_t idx);
@@ -276,25 +278,6 @@ inline void startPulses()
#endif
}
enum ChannelsProtocols {
PROTOCOL_CHANNELS_UNINITIALIZED,
PROTOCOL_CHANNELS_NONE,
PROTOCOL_CHANNELS_PPM,
PROTOCOL_CHANNELS_PXX1_PULSES,
PROTOCOL_CHANNELS_PXX1_SERIAL,
PROTOCOL_CHANNELS_DSM2_LP45,
PROTOCOL_CHANNELS_DSM2_DSM2,
PROTOCOL_CHANNELS_DSM2_DSMX,
PROTOCOL_CHANNELS_CROSSFIRE,
PROTOCOL_CHANNELS_MULTIMODULE,
PROTOCOL_CHANNELS_SBUS,
PROTOCOL_CHANNELS_PXX2_LOWSPEED,
PROTOCOL_CHANNELS_PXX2_HIGHSPEED,
PROTOCOL_CHANNELS_AFHDS2A,
PROTOCOL_CHANNELS_AFHDS3,
PROTOCOL_CHANNELS_GHOST
};
inline void stopPulses()
{
s_pulses_paused = true;
+1 -4
View File
@@ -107,25 +107,22 @@ class SerialPxxBitTransport: public DataBuffer<uint8_t, 64> {
class PwmPxxBitTransport: public PulsesBuffer<pulse_duration_t, 200> {
protected:
uint16_t rest;
void initFrame(uint32_t period)
{
initBuffer();
rest = period * 2000; // 0.5uS (2Mhz)
}
void addPart(uint8_t value)
{
pulse_duration_t duration = value ? 47 : 31;
*ptr++ = duration;
rest -= duration + 1;
}
void addTail()
{
// rest min value is 18000 - 200 * 48 = 8400 (4.2ms)
*(ptr - 1) = 60000;
*(ptr - 1) = 255;
}
};
+121
View File
@@ -21,6 +21,8 @@
#include "opentx.h"
#include "pulses/pxx1.h"
#include "mixer_scheduler.h"
#include "heartbeat_driver.h"
template <class PxxTransport>
void Pxx1Pulses<PxxTransport>::addFlag1(uint8_t module, uint8_t sendFailsafe)
@@ -219,3 +221,122 @@ void Pxx1Pulses<PxxTransport>::setupFrame(uint8_t module)
template class Pxx1Pulses<StandardPxx1Transport<PwmPxxBitTransport> >;
template class Pxx1Pulses<StandardPxx1Transport<SerialPxxBitTransport> >;
template class Pxx1Pulses<UartPxx1Transport>;
#if defined(INTMODULE_USART)
#include "intmodule_serial_driver.h"
static const etx_serial_init pxx1SerialInit = {
.baudrate = INTMODULE_PXX1_SERIAL_BAUDRATE,
.parity = ETX_Parity_None,
.stop_bits = ETX_StopBits_One,
.word_length = ETX_WordLength_8,
.rx_enable = false,
.on_receive = intmoduleFifoReceive,
.on_error = intmoduleFifoError,
};
static void* pxx1InitInternal(uint8_t module)
{
void* uart_ctx = IntmoduleSerialDriver.init(&pxx1SerialInit);
#if defined(INTMODULE_HEARTBEAT)
init_intmodule_heartbeat();
#endif
mixerSchedulerSetPeriod(INTERNAL_MODULE, INTMODULE_PXX1_SERIAL_PERIOD);
INTERNAL_MODULE_ON();
return uart_ctx;
}
static void pxx1DeInitInternal(void* context)
{
INTERNAL_MODULE_OFF();
mixerSchedulerSetPeriod(INTERNAL_MODULE, 0);
#if defined(INTMODULE_HEARTBEAT)
stop_intmodule_heartbeat();
#endif
IntmoduleSerialDriver.deinit(context);
}
static void pxx1SetupPulsesInternal(void* context, int16_t* channels, uint8_t nChannels)
{
(void)context;
// TODO:
(void)channels;
(void)nChannels;
intmodulePulsesData.pxx_uart.setupFrame(INTERNAL_MODULE);
}
static void pxx1SendPulsesInternal(void* context)
{
IntmoduleSerialDriver.sendBuffer(context, intmodulePulsesData.pxx_uart.getData(),
intmodulePulsesData.pxx_uart.getSize());
}
const etx_module_driver_t Pxx1InternalSerialDriver = {
.protocol = PROTOCOL_CHANNELS_PXX1_SERIAL,
.init = pxx1InitInternal,
.deinit = pxx1DeInitInternal,
.setupPulses = pxx1SetupPulsesInternal,
.sendPulses = pxx1SendPulsesInternal,
};
#endif
#if defined(EXTMODULE_USART) && defined(HARDWARE_EXTERNAL_MODULE_SIZE_SML)
#include "extmodule_serial_driver.h"
static const etx_serial_init pxx1ExtSerialInit = {
.baudrate = EXTMODULE_PXX1_SERIAL_BAUDRATE,
.parity = ETX_Parity_None,
.stop_bits = ETX_StopBits_One,
.word_length = ETX_WordLength_8,
.rx_enable = false,
.on_receive = extmoduleFifoReceive,
.on_error = extmoduleFifoError,
};
static void* pxx1InitExternal(uint8_t module)
{
void* uart_ctx = ExtmoduleSerialDriver.init(&pxx1ExtSerialInit);
mixerSchedulerSetPeriod(EXTERNAL_MODULE, EXTMODULE_PXX1_SERIAL_PERIOD);
EXTERNAL_MODULE_ON();
return uart_ctx;
}
static void pxx1DeInitExternal(void* context)
{
EXTERNAL_MODULE_OFF();
mixerSchedulerSetPeriod(EXTERNAL_MODULE, 0);
ExtmoduleSerialDriver.deinit(context);
}
static void pxx1SetupPulsesExternal(void* context, int16_t* channels, uint8_t nChannels)
{
(void)context;
// TODO:
(void)channels;
(void)nChannels;
extmodulePulsesData.pxx_uart.setupFrame(EXTERNAL_MODULE);
}
static void pxx1SendPulsesExternal(void* context)
{
ExtmoduleSerialDriver.sendBuffer(context, extmodulePulsesData.pxx_uart.getData(),
extmodulePulsesData.pxx_uart.getSize());
}
const etx_module_driver_t Pxx1ExternalSerialDriver = {
.protocol = PROTOCOL_CHANNELS_PXX1_SERIAL,
.init = pxx1InitExternal,
.deinit = pxx1DeInitExternal,
.setupPulses = pxx1SetupPulsesExternal,
.sendPulses = pxx1SendPulsesExternal,
};
#endif
+9 -13
View File
@@ -25,19 +25,7 @@
#include "pxx.h"
#include "crc.h"
#if defined(INTMODULE_HEARTBEAT_GPIO)
struct HeartbeatCapture {
#if !defined(INTMODULE_USART)
uint32_t timestamp;
#endif
#if defined(DEBUG_LATENCY)
uint32_t count;
#endif
uint8_t valid;
};
extern volatile HeartbeatCapture heartbeatCapture;
#endif
#include "hal/module_driver.h"
class Pxx1CrcMixin {
protected:
@@ -180,4 +168,12 @@ typedef Pxx1Pulses<UartPxx1Transport> UartPxx1Pulses;
typedef Pxx1Pulses<StandardPxx1Transport<PwmPxxBitTransport>> PwmPxx1Pulses;
typedef Pxx1Pulses<StandardPxx1Transport<SerialPxxBitTransport>> SerialPxx1Pulses;
#if defined(INTMODULE_USART)
extern const etx_module_driver_t Pxx1InternalSerialDriver;
#endif
#if defined(EXTMODULE_USART)
extern const etx_module_driver_t Pxx1ExternalSerialDriver;
#endif
#endif
+166 -16
View File
@@ -24,6 +24,22 @@
#include "pulses/pxx2.h"
#include "io/frsky_firmware_update.h"
#include "libopenui/src/libopenui_file.h"
#include "mixer_scheduler.h"
#include "heartbeat_driver.h"
#if defined(INTMODULE_USART)
#include "intmodule_serial_driver.h"
const etx_serial_init pxx2SerialInitParams = {
.baudrate = PXX2_HIGHSPEED_BAUDRATE,
.parity = ETX_Parity_None,
.stop_bits = ETX_StopBits_One,
.word_length = ETX_WordLength_8,
.rx_enable = true,
.on_receive = intmoduleFifoReceive,
.on_error = intmoduleFifoError,
};
#endif
bool isPXX2PowerAvailable(const PXX2HardwareInformation& info, int value)
{
@@ -110,7 +126,7 @@ void Pxx2Pulses::addPulsesValues(uint16_t low, uint16_t high)
Pxx2Transport::addByte(high >> 4u); // High byte of channel
}
void Pxx2Pulses::addChannels(uint8_t module)
void Pxx2Pulses::addChannels(uint8_t module, int16_t* channels, uint8_t nChannels)
{
uint16_t pulseValue = 0;
uint16_t pulseValueLow = 0;
@@ -119,7 +135,7 @@ void Pxx2Pulses::addChannels(uint8_t module)
uint8_t count = sentModuleChannels(module);
for (int8_t i = 0; i < count; i++, channel++) {
int value = channelOutputs[channel] + 2*PPM_CH_CENTER(channel) - 2*PPM_CENTER;
int value = channels[i] + 2*PPM_CH_CENTER(channel) - 2*PPM_CENTER;
pulseValue = limit(1, (value * 512 / 682) + 1024, 2046);
#if defined(DEBUG_LATENCY_RF_ONLY)
if (latencyToggleSwitch)
@@ -169,7 +185,7 @@ void Pxx2Pulses::addFailsafe(uint8_t module)
}
}
void Pxx2Pulses::setupChannelsFrame(uint8_t module)
void Pxx2Pulses::setupChannelsFrame(uint8_t module, int16_t* channels, uint8_t nChannels)
{
addFrameType(PXX2_TYPE_C_MODULE, PXX2_TYPE_ID_CHANNELS);
@@ -183,7 +199,7 @@ void Pxx2Pulses::setupChannelsFrame(uint8_t module)
if (flag0 & PXX2_CHANNELS_FLAG0_FAILSAFE)
addFailsafe(module);
else
addChannels(module);
addChannels(module, channels, nChannels);
}
void Pxx2Pulses::setupTelemetryFrame(uint8_t module)
@@ -195,7 +211,7 @@ void Pxx2Pulses::setupTelemetryFrame(uint8_t module)
}
}
void Pxx2Pulses::setupHardwareInfoFrame(uint8_t module)
void Pxx2Pulses::setupHardwareInfoFrame(uint8_t module, int16_t* channels, uint8_t nChannels)
{
ModuleInformation * destination = moduleState[module].moduleInformation;
@@ -208,12 +224,12 @@ void Pxx2Pulses::setupHardwareInfoFrame(uint8_t module)
}
else {
moduleState[module].mode = MODULE_MODE_NORMAL;
setupChannelsFrame(module);
setupChannelsFrame(module, channels, nChannels);
}
}
else {
destination->timeout--;
setupChannelsFrame(module);
setupChannelsFrame(module, channels, nChannels);
}
}
@@ -236,7 +252,7 @@ void Pxx2Pulses::setupRegisterFrame(uint8_t module)
}
}
void Pxx2Pulses::setupModuleSettingsFrame(uint8_t module)
void Pxx2Pulses::setupModuleSettingsFrame(uint8_t module, int16_t* channels, uint8_t nChannels)
{
ModuleSettings * destination = moduleState[module].moduleSettings;
@@ -256,11 +272,11 @@ void Pxx2Pulses::setupModuleSettingsFrame(uint8_t module)
destination->timeout = get_tmr10ms() + 200/*next try in 2s*/;
}
else {
setupChannelsFrame(module);
setupChannelsFrame(module, channels, nChannels);
}
}
void Pxx2Pulses::setupReceiverSettingsFrame(uint8_t module)
void Pxx2Pulses::setupReceiverSettingsFrame(uint8_t module, int16_t* channels, uint8_t nChannels)
{
if (get_tmr10ms() > reusableBuffer.hardwareAndSettings.receiverSettings.timeout) {
addFrameType(PXX2_TYPE_C_MODULE, PXX2_TYPE_ID_RX_SETTINGS);
@@ -291,7 +307,7 @@ void Pxx2Pulses::setupReceiverSettingsFrame(uint8_t module)
reusableBuffer.hardwareAndSettings.receiverSettings.timeout = get_tmr10ms() + 200/*next try in 2s*/;
}
else {
setupChannelsFrame(module);
setupChannelsFrame(module, channels, nChannels);
}
}
@@ -442,7 +458,7 @@ void Pxx2Pulses::setupAuthenticationFrame(uint8_t module, uint8_t mode, const ui
endFrame();
}
bool Pxx2Pulses::setupFrame(uint8_t module)
bool Pxx2Pulses::setupFrame(uint8_t module, int16_t* channels, uint8_t nChannels)
{
if (moduleState[module].mode == MODULE_MODE_OTA_UPDATE)
return false;
@@ -456,13 +472,13 @@ bool Pxx2Pulses::setupFrame(uint8_t module)
switch (moduleState[module].mode) {
case MODULE_MODE_GET_HARDWARE_INFO:
setupHardwareInfoFrame(module);
setupHardwareInfoFrame(module, channels, nChannels);
break;
case MODULE_MODE_MODULE_SETTINGS:
setupModuleSettingsFrame(module);
setupModuleSettingsFrame(module, channels, nChannels);
break;
case MODULE_MODE_RECEIVER_SETTINGS:
setupReceiverSettingsFrame(module);
setupReceiverSettingsFrame(module, channels, nChannels);
break;
case MODULE_MODE_REGISTER:
setupRegisterFrame(module);
@@ -495,7 +511,7 @@ bool Pxx2Pulses::setupFrame(uint8_t module)
outputTelemetryBuffer.reset();
}
else {
setupChannelsFrame(module);
setupChannelsFrame(module, channels, nChannels);
}
break;
}
@@ -630,3 +646,137 @@ void Pxx2OtaUpdate::flashFirmware(const char * filename, ProgressHandler progres
resumePulses();
}
static void* pxx2InitInternal(uint8_t moduleType)
{
intmoduleFifo.clear();
void* uart_ctx = IntmoduleSerialDriver.init(&pxx2SerialInitParams);
resetAccessAuthenticationCount();
#if defined(INTMODULE_HEARTBEAT)
// use backup trigger (1 ms later)
init_intmodule_heartbeat();
#endif
mixerSchedulerSetPeriod(INTERNAL_MODULE, PXX2_PERIOD);
INTERNAL_MODULE_ON();
return uart_ctx;
}
static void pxx2DeInitInternal(void* context)
{
INTERNAL_MODULE_OFF();
IntmoduleSerialDriver.deinit(context);
#if defined(INTMODULE_HEARTBEAT)
stop_intmodule_heartbeat();
#endif
mixerSchedulerSetPeriod(INTERNAL_MODULE, 0);
}
static bool pxx2InternalSendNextFrame = true;
static void pxx2SetupPulsesInternal(void* context, int16_t* channels, uint8_t nChannels)
{
(void)context;
pxx2InternalSendNextFrame =
intmodulePulsesData.pxx2.setupFrame(INTERNAL_MODULE, channels, nChannels);
if (moduleState[INTERNAL_MODULE].mode == MODULE_MODE_SPECTRUM_ANALYSER ||
moduleState[INTERNAL_MODULE].mode == MODULE_MODE_POWER_METER) {
mixerSchedulerSetPeriod(INTERNAL_MODULE, PXX2_TOOLS_PERIOD);
} else {
mixerSchedulerSetPeriod(INTERNAL_MODULE, PXX2_PERIOD);
}
}
static void pxx2SendPulsesInternal(void* context)
{
if (pxx2InternalSendNextFrame) {
IntmoduleSerialDriver.sendBuffer(context, intmodulePulsesData.pxx2.getData(),
intmodulePulsesData.pxx2.getSize());
}
}
#include "hal/module_driver.h"
const etx_module_driver_t Pxx2InternalDriver = {
.protocol = PROTOCOL_CHANNELS_PXX2_HIGHSPEED,
.init = pxx2InitInternal,
.deinit = pxx2DeInitInternal,
.setupPulses = pxx2SetupPulsesInternal,
.sendPulses = pxx2SendPulsesInternal,
};
#if defined(EXTMODULE_USART)
#include "extmodule_serial_driver.h"
static const etx_serial_init pxx2ExtSerialInitParams = {
.baudrate = 0,
.parity = ETX_Parity_None,
.stop_bits = ETX_StopBits_One,
.word_length = ETX_WordLength_8,
.rx_enable = true,
.on_receive = extmoduleFifoReceive,
.on_error = extmoduleFifoError,
};
static void* pxx2InitLowSpeed(uint8_t module)
{
etx_serial_init params(pxx2ExtSerialInitParams);
params.baudrate = PXX2_LOWSPEED_BAUDRATE;
ExtmoduleSerialDriver.init(&params);
mixerSchedulerSetPeriod(EXTERNAL_MODULE, PXX2_NO_HEARTBEAT_PERIOD);
EXTERNAL_MODULE_ON();
return nullptr;
}
static void* pxx2InitExternal(uint8_t module)
{
etx_serial_init params(pxx2ExtSerialInitParams);
params.baudrate = PXX2_HIGHSPEED_BAUDRATE;
void* uart_ctx = ExtmoduleSerialDriver.init(&params);
mixerSchedulerSetPeriod(EXTERNAL_MODULE, PXX2_NO_HEARTBEAT_PERIOD);
EXTERNAL_MODULE_ON();
return uart_ctx;
}
static void pxx2DeInitExternal(void* context)
{
EXTERNAL_MODULE_OFF();
mixerSchedulerSetPeriod(EXTERNAL_MODULE, 0);
ExtmoduleSerialDriver.deinit(context);
}
static void pxx2SetupPulsesExternal(void* context, int16_t* channels, uint8_t nChannels)
{
(void)context;
extmodulePulsesData.pxx2.setupFrame(EXTERNAL_MODULE, channels, nChannels);
}
static void pxx2SendPulsesExternal(void* context)
{
ExtmoduleSerialDriver.sendBuffer(context, extmodulePulsesData.pxx2.getData(),
extmodulePulsesData.pxx2.getSize());
}
const etx_module_driver_t Pxx2ExternalDriver = {
.protocol = PROTOCOL_CHANNELS_PXX2_HIGHSPEED,
.init = pxx2InitExternal,
.deinit = pxx2DeInitExternal,
.setupPulses = pxx2SetupPulsesExternal,
.sendPulses = pxx2SendPulsesExternal,
};
const etx_module_driver_t Pxx2LowSpeedExternalDriver = {
.protocol = PROTOCOL_CHANNELS_PXX2_LOWSPEED,
.init = pxx2InitLowSpeed,
.deinit = pxx2DeInitExternal,
.setupPulses = pxx2SetupPulsesExternal,
.sendPulses = pxx2SendPulsesExternal,
};
#endif
+15 -6
View File
@@ -27,6 +27,9 @@
#include "popups.h"
#include "./pxx.h"
#include "hal/serial_driver.h"
#include "hal/module_driver.h"
#define PXX2_TYPE_C_MODULE 0x01
#define PXX2_TYPE_ID_REGISTER 0x01
#define PXX2_TYPE_ID_BIND 0x02
@@ -465,11 +468,11 @@ class Pxx2Pulses: public Pxx2Transport {
friend class Pxx2OtaUpdate;
public:
bool setupFrame(uint8_t module);
bool setupFrame(uint8_t module, int16_t* channels, uint8_t nChannels);
void setupAuthenticationFrame(uint8_t module, uint8_t mode, const uint8_t * outputMessage);
protected:
void setupHardwareInfoFrame(uint8_t module);
void setupHardwareInfoFrame(uint8_t module, int16_t* channels, uint8_t nChannels);
void setupRegisterFrame(uint8_t module);
@@ -481,11 +484,11 @@ class Pxx2Pulses: public Pxx2Transport {
void setupShareMode(uint8_t module);
void setupModuleSettingsFrame(uint8_t module);
void setupModuleSettingsFrame(uint8_t module, int16_t* channels, uint8_t nChannels);
void setupReceiverSettingsFrame(uint8_t module);
void setupReceiverSettingsFrame(uint8_t module, int16_t* channels, uint8_t nChannels);
void setupChannelsFrame(uint8_t module);
void setupChannelsFrame(uint8_t module, int16_t* channels, uint8_t nChannels);
void setupTelemetryFrame(uint8_t module);
@@ -517,7 +520,7 @@ class Pxx2Pulses: public Pxx2Transport {
void addPulsesValues(uint16_t low, uint16_t high);
void addChannels(uint8_t module);
void addChannels(uint8_t module, int16_t* channels, uint8_t nChannels);
void addFailsafe(uint8_t module);
@@ -575,4 +578,10 @@ class Pxx2OtaUpdate {
const char * nextStep(uint8_t step, const char * rxName, uint32_t address, const uint8_t * buffer);
};
extern const etx_serial_init pxx2SerialInitParams;
extern const etx_module_driver_t Pxx2InternalDriver;
extern const etx_module_driver_t Pxx2ExternalDriver;
extern const etx_module_driver_t Pxx2LowSpeedExternalDriver;
#endif
+2 -2
View File
@@ -92,9 +92,9 @@ inline int getChannelValue(uint8_t port, int channel)
static void sbusFlush()
{
if (extmodulePulsesData.dsm2.index & 1)
*extmodulePulsesData.dsm2.ptr++ = 60000;
*extmodulePulsesData.dsm2.ptr++ = 255;
else
*(extmodulePulsesData.dsm2.ptr - 1) = 60000;
*(extmodulePulsesData.dsm2.ptr - 1) = 255;
}
void setupPulsesSbus()
+54 -17
View File
@@ -21,6 +21,7 @@
#include "opentx.h"
#include "sbus.h"
#include "timers_driver.h"
#define SBUS_FRAME_GAP_DELAY 1000 // 500uS
@@ -35,14 +36,45 @@
#define SBUS_CH_CENTER 0x3E0
static int (*_sbusAuxGetByte)(void*, uint8_t*) = nullptr;
static void* _sbusAuxGetByteCtx = nullptr;
void sbusSetAuxGetByte(void* ctx, int (*fct)(void*, uint8_t*))
{
_sbusAuxGetByte = nullptr;
_sbusAuxGetByteCtx = ctx;
_sbusAuxGetByte = fct;
}
int sbusAuxGetByte(uint8_t* byte)
{
auto _getByte = _sbusAuxGetByte;
auto _ctx = _sbusAuxGetByteCtx;
if (_getByte) {
return _getByte(_ctx, byte);
}
return -1;
}
static int (*sbusGetByte)(uint8_t*) = nullptr;
void sbusSetGetByte(int (*fct)(uint8_t*))
{
sbusGetByte = fct;
}
// Range for pulses (ppm input) is [-512:+512]
void processSbusFrame(uint8_t * sbus, int16_t * pulses, uint32_t size)
{
if (size != SBUS_FRAME_SIZE || sbus[0] != SBUS_START_BYTE || sbus[SBUS_FRAME_SIZE-1] != SBUS_END_BYTE) {
return; // not a valid SBUS frame
if (size != SBUS_FRAME_SIZE || sbus[0] != SBUS_START_BYTE ||
sbus[SBUS_FRAME_SIZE - 1] != SBUS_END_BYTE) {
return; // not a valid SBUS frame
}
if ((sbus[SBUS_FLAGS_IDX] & (1<<SBUS_FAILSAFE_BIT)) || (sbus[SBUS_FLAGS_IDX] & (1<<SBUS_FRAMELOST_BIT))) {
return; // SBUS invalid frame or failsafe mode
if ((sbus[SBUS_FLAGS_IDX] & (1 << SBUS_FAILSAFE_BIT)) ||
(sbus[SBUS_FLAGS_IDX] & (1 << SBUS_FRAMELOST_BIT))) {
return; // SBUS invalid frame or failsafe mode
}
sbus++; // skip start byte
@@ -64,31 +96,36 @@ void processSbusFrame(uint8_t * sbus, int16_t * pulses, uint32_t size)
void processSbusInput()
{
#if !defined(SIMU)
uint8_t rxchar;
uint32_t active = 0;
// TODO: place this outside of the function
static uint8_t SbusIndex = 0;
static uint16_t SbusTimer;
static uint8_t SbusFrame[SBUS_FRAME_SIZE];
while (sbusGetByte(&rxchar)) {
uint32_t active = 0;
// Drain input first (if existing)
uint8_t rxchar;
auto _getByte = sbusGetByte;
while (_getByte && (_getByte(&rxchar) > 0)) {
active = 1;
if (SbusIndex > SBUS_FRAME_SIZE-1) {
SbusIndex = SBUS_FRAME_SIZE-1;
if (SbusIndex > SBUS_FRAME_SIZE - 1) {
SbusIndex = SBUS_FRAME_SIZE - 1;
}
SbusFrame[SbusIndex++] = rxchar;
}
// Data has been received
if (active) {
SbusTimer = getTmr2MHz();
return;
}
else {
if (SbusIndex) {
if ((uint16_t) (getTmr2MHz() - SbusTimer) > SBUS_FRAME_GAP_DELAY) {
processSbusFrame(SbusFrame, ppmInput, SbusIndex);
SbusIndex = 0;
}
// Check if end-of-frame is detected
if (SbusIndex) {
if ((uint16_t)(getTmr2MHz() - SbusTimer) > SBUS_FRAME_GAP_DELAY) {
processSbusFrame(SbusFrame, ppmInput, SbusIndex);
SbusIndex = 0;
}
}
#endif
}
+11
View File
@@ -25,6 +25,17 @@
#define SBUS_BAUDRATE 100000
#define SBUS_FRAME_SIZE 25
// Setup SBUS AUX serial input
void sbusSetAuxGetByte(void* ctx, int (*fct)(void*, uint8_t*));
// SBUS AUX serial getter:
// if set, it will fetch data from the handler set
// with sbusSetAuxGetByte()
int sbusAuxGetByte(uint8_t* byte);
// Setup general SBUS input source
void sbusSetGetByte(int (*fct)(uint8_t*));
void processSbusInput();
#endif // _SBUS_H_
+327 -19
View File
@@ -23,42 +23,350 @@
#include "serial.h"
#include <stdarg.h>
#include <stdio.h>
#include "aux_serial_driver.h"
#include "hal/serial_port.h"
//#include "cli.h"
#define PRINTF_BUFFER_SIZE 128
void serialPutc(char c) {
#if !defined(BOOT) && defined(USB_SERIAL)
if (getSelectedUsbMode() == USB_SERIAL_MODE)
usbSerialPutc(c);
#endif
#if defined(AUX_SERIAL)
if (auxSerialTracesEnabled())
auxSerialPutc(c);
#endif
#if defined(AUX2_SERIAL)
if (aux2SerialTracesEnabled())
aux2SerialPutc(c);
#endif
static void (*dbg_serial_putc)(void*, uint8_t) = nullptr;
static void* dbg_serial_ctx = nullptr;
void (*dbgSerialGetSendCb())(void*, uint8_t)
{
return dbg_serial_putc;
}
void serialPrintf(const char * format, ...)
void* dbgSerialGetSendCbCtx()
{
return dbg_serial_ctx;
}
void dbgSerialSetSendCb(void* ctx, void (*cb)(void*, uint8_t))
{
dbg_serial_putc = nullptr;
dbg_serial_ctx = ctx;
dbg_serial_putc = cb;
}
extern "C" void dbgSerialPutc(char c)
{
auto _putc = dbg_serial_putc;
auto _ctx = dbg_serial_ctx;
if (_putc) _putc(_ctx, c);
}
extern "C" void dbgSerialPrintf(const char * format, ...)
{
va_list arglist;
char tmp[PRINTF_BUFFER_SIZE+1];
// no need to do anything if we don't have an output
if (!dbg_serial_putc) return;
va_start(arglist, format);
vsnprintf(tmp, PRINTF_BUFFER_SIZE, format, arglist);
tmp[PRINTF_BUFFER_SIZE] = '\0';
va_end(arglist);
const char *t = tmp;
while (*t) {
serialPutc(*t++);
while (*t && dbg_serial_putc) {
dbg_serial_putc(dbg_serial_ctx, *t++);
}
}
void serialCrlf()
extern "C" void dbgSerialCrlf()
{
serialPutc('\r');
serialPutc('\n');
dbgSerialPutc('\r');
dbgSerialPutc('\n');
}
int8_t getSerialPortMode(uint8_t port_nr)
{
#if !defined(BOOT)
if (port_nr < MAX_SERIAL_PORTS) {
auto cfg = g_eeGeneral.serialPort;
cfg >>= port_nr * 4; // 4 bits per port
return cfg & 0xF;
}
#endif
return UART_MODE_NONE;
}
struct SerialPortState
{
uint8_t mode;
const etx_serial_port_t* port;
void* usart_ctx;
};
static SerialPortState serialPortStates[MAX_SERIAL_PORTS];
static SerialPortState* getSerialPortState(uint8_t port_nr)
{
if (port_nr >= MAX_SERIAL_PORTS) return nullptr;
return &serialPortStates[port_nr];
}
// TODO: replace serialSetupCallBacks & serialSetupPort
// with usage based handlers.
//
static void serialSetCallBacks(int mode, void* ctx, const etx_serial_port_t* port)
{
void (*sendByte)(void*, uint8_t) = nullptr;
int (*getByte)(void*, uint8_t*) = nullptr;
void (*setRxCb)(void*, void (*)(uint8_t*, uint32_t)) = nullptr;
const etx_serial_driver_t* drv = nullptr;
if (port) {
drv = port->uart;
if (drv) {
sendByte = drv->sendByte;
getByte = drv->getByte;
setRxCb = drv->setReceiveCb;
}
}
// prevent compiler warnings
(void)sendByte;
(void)getByte;
(void)setRxCb;
switch(mode) {
#if defined(DEBUG)
case UART_MODE_DEBUG:
// TODO: should we handle 2 outputs?
dbgSerialSetSendCb(ctx, sendByte);
break;
#endif
#if !defined(BOOT)
#if defined(LUA)
case UART_MODE_LUA:
luaSetSendCb(ctx, sendByte);
if (getByte) {
luaSetGetSerialByte(ctx, getByte);
} else if (setRxCb) {
luaAllocRxFifo();
setRxCb(ctx, luaReceiveData);
} else {
luaFreeRxFifo();
}
break;
#endif
#if defined(SBUS_TRAINER)
case UART_MODE_SBUS_TRAINER:
sbusSetAuxGetByte(ctx, getByte);
// TODO: setRxCb (see MODE_LUA)
break;
#endif
case UART_MODE_TELEMETRY:
telemetrySetGetByte(ctx, getByte);
// TODO: setRxCb (see MODE_LUA)
// de we really need telemetry
// input over USB VCP?
break;
case UART_MODE_TELEMETRY_MIRROR:
telemetrySetMirrorCb(ctx, sendByte);
break;
#if defined(CLI)
case UART_MODE_CLI:
cliSetSerialDriver(ctx, drv);
break;
#endif
#if defined(INTERNAL_GPS)
case UART_MODE_GPS:
gpsSetSerialDriver(ctx, drv);
break;
#endif
#endif
}
}
static void serialSetupPort(int mode, etx_serial_init& params, bool& power_required)
{
switch (mode) {
#if defined(DEBUG) || defined(CLI)
case UART_MODE_DEBUG:
case UART_MODE_CLI:
params.baudrate = DEBUG_BAUDRATE;
break;
#endif
#if !defined(BOOT)
case UART_MODE_TELEMETRY_MIRROR:
// TODO: query telemetry baudrate / add setting for module
power_required = true;
#if defined(CROSSFIRE)
if (modelTelemetryProtocol() == PROTOCOL_TELEMETRY_CROSSFIRE) {
params.baudrate = CROSSFIRE_TELEM_MIRROR_BAUDRATE;
break;
}
#endif
params.baudrate = FRSKY_TELEM_MIRROR_BAUDRATE;
break;
case UART_MODE_TELEMETRY:
if (modelTelemetryProtocol() == PROTOCOL_TELEMETRY_FRSKY_D_SECONDARY) {
params.baudrate = FRSKY_D_BAUDRATE;
params.rx_enable = true;
power_required = true;
}
break;
case UART_MODE_SBUS_TRAINER:
params.baudrate = SBUS_BAUDRATE;
params.word_length = ETX_WordLength_9;
params.parity = ETX_Parity_Even;
params.stop_bits = ETX_StopBits_Two;
params.rx_enable = true;
power_required = true;
break;
#if defined(LUA)
case UART_MODE_LUA:
params.baudrate = LUA_DEFAULT_BAUDRATE;
params.rx_enable = true;
power_required = true;
break;
#endif
#if defined(INTERNAL_GPS)
case UART_MODE_GPS:
params.baudrate = GPS_USART_BAUDRATE;
params.rx_enable = true;
power_required = true;
break;
#endif
#endif
}
}
const etx_serial_port_t* serialGetPort(uint8_t port_nr)
{
const etx_serial_port_t* port = nullptr;
if (port_nr != SP_VCP) {
port = auxSerialGetPort(port_nr);
}
#if defined(USB_SERIAL)
else {
port = &UsbSerialPort;
}
#endif
return port;
}
void serialInit(uint8_t port_nr, int mode)
{
auto state = getSerialPortState(port_nr);
if (!state) return;
const etx_serial_port_t* port = serialGetPort(port_nr);
if (!port) return;
if (state->port) {
auto drv = state->port->uart;
if (drv && drv->deinit) {
drv->deinit(state->usart_ctx);
}
if (state->mode != 0) {
// Clear callbacks
serialSetCallBacks(state->mode, nullptr, nullptr);
}
memset(state, 0, sizeof(SerialPortState));
}
etx_serial_init params = {
.baudrate = 0,
.parity = ETX_Parity_None,
.stop_bits = ETX_StopBits_One,
.word_length = ETX_WordLength_8,
.rx_enable = false,
.on_receive = nullptr,
.on_error = nullptr,
};
bool power_required = false;
serialSetupPort(mode, params, power_required);
if (params.baudrate != 0) {
state->mode = mode;
state->port = port;
if (port) {
if (port->uart && port->uart->init)
state->usart_ctx = port->uart->init(&params);
// Set power on/off
if (port->set_pwr) {
port->set_pwr(power_required);
}
}
// Update callbacks once the port is setup
serialSetCallBacks(mode, state->usart_ctx, state->port);
}
}
void initSerialPorts()
{
memset(serialPortStates, 0, sizeof(serialPortStates));
for (uint8_t port_nr = 0; port_nr < MAX_AUX_SERIAL; port_nr++) {
auto mode = getSerialPortMode(port_nr);
serialInit(port_nr, mode);
}
}
int serialGetMode(uint8_t port_nr)
{
return getSerialPortMode(port_nr);
}
void serialSetMode(uint8_t port_nr, int mode)
{
if (port_nr >= MAX_SERIAL_PORTS) return;
uint16_t m = mode & 0xF;
g_eeGeneral.serialPort =
(g_eeGeneral.serialPort & ~(0xF << port_nr * 4)) | (m << port_nr * 4);
}
// uint8_t serialTracesEnabled(int port_nr)
// {
// #if defined(DEBUG)
// return serialGetMode(port_nr) == UART_MODE_DEBUG;
// #else
// return false;
// #endif
// }
void serialStop(uint8_t port_nr)
{
auto state = getSerialPortState(port_nr);
if (!state) return;
if (state->port) {
auto port = state->port;
auto drv = port->uart;
if (drv && drv->deinit) {
drv->deinit(state->usart_ctx);
}
if (port->set_pwr) {
// Power OFF
port->set_pwr(0);
}
if (state->mode != 0) {
// Clear callbacks
serialSetCallBacks(state->mode, nullptr, nullptr);
}
}
memset(state, 0, sizeof(SerialPortState));
}
+25 -4
View File
@@ -22,19 +22,40 @@
#ifndef _SERIAL_H_
#define _SERIAL_H_
#include <stdint.h>
#include "hal/serial_port.h"
const etx_serial_port_t* serialGetPort(uint8_t port_nr);
int serialGetMode(uint8_t port_nr);
void serialSetMode(uint8_t port_nr, int mode);
void initSerialPorts();
void serialInit(uint8_t port_nr, int mode);
void serialStop(uint8_t port_nr);
//
// Functions used by debug.h
//
#ifdef __cplusplus
extern "C" {
#endif
void serialPutc(char c);
void serialPrintf(const char *format, ...);
void serialCrlf();
void dbgSerialPutc(char c);
void dbgSerialPrintf(const char *format, ...);
void dbgSerialCrlf();
#ifdef __cplusplus
}
#endif
#define serialPrint(...) do { serialPrintf(__VA_ARGS__); serialCrlf(); } while(0)
#define dbgSerialPrint(...) do { dbgSerialPrintf(__VA_ARGS__); dbgSerialCrlf(); } while(0)
// Debug serial callback
void dbgSerialSetSendCb(void* ctx, void (*cb)(void*, uint8_t));
// Query debug callback
void (*dbgSerialGetSendCb())(void*, uint8_t);
void* dbgSerialGetSendCbCtx();
#endif // _SERIAL_H_
@@ -711,7 +711,6 @@ bool w_vPitch(const YamlNode* node, uint32_t val, yaml_writer_func wf, void* opa
return wf(opaque, s, strlen(s));
}
extern const struct YamlIdStr enum_TrainerMode[];
const struct YamlIdStr enum_TrainerMode[] = {
#if defined(PCBNV14)
{ TRAINER_MODE_OFF, "OFF" },
@@ -733,8 +732,8 @@ const struct YamlIdStr enum_TrainerMode[] = {
#define r_trainerMode nullptr
bool w_trainerMode(const YamlNode* node, uint32_t val,
yaml_writer_func wf, void* opaque)
static bool w_trainerMode(const YamlNode* node, uint32_t val,
yaml_writer_func wf, void* opaque)
{
const char* str = nullptr;
str = yaml_output_enum(val, enum_TrainerMode);
@@ -1168,3 +1167,6 @@ bool w_channelsCount(const YamlNode* node, uint32_t val, yaml_writer_func wf, vo
const char* str = yaml_signed2str(sval);
return wf(opaque,str,strlen(str));
}
// force storage class
extern const struct YamlIdStr enum_UartModes[];
+11
View File
@@ -82,6 +82,17 @@ void postRadioSettingsLoad()
setDefaultOwnerId();
}
#endif
#if defined(PCBX12S)
// AUX2 is hardwired to AUX2 on X12S
serialSetMode(SP_AUX2, UART_MODE_GPS);
#endif
#if defined(USB_SERIAL)
// default VCP to CLI if not configured
// to something else as NONE.
if (serialGetMode(SP_VCP) == UART_MODE_NONE) {
serialSetMode(SP_VCP, UART_MODE_CLI);
}
#endif
}
#if defined(EXTERNAL_ANTENNA) && defined(INTERNAL_MODULE_PXX1)
@@ -58,10 +58,6 @@ namespace yaml_conv_220 {
bool w_spPitch(const YamlNode* node, uint32_t val, yaml_writer_func wf, void* opaque);
bool w_vPitch(const YamlNode* node, uint32_t val, yaml_writer_func wf, void* opaque);
extern const struct YamlIdStr enum_TrainerMode[];
bool w_trainerMode(const YamlNode* node, uint32_t val,
yaml_writer_func wf, void* opaque);
extern const char* _tele_screen_type_lookup[];
bool w_tele_screen_type(void* user, uint8_t* data, uint32_t bitoffs,
yaml_writer_func wf, void* opaque);
@@ -99,6 +95,7 @@ namespace yaml_conv_220 {
bool w_channelsCount(const YamlNode* node, uint32_t val, yaml_writer_func wf,
void* opaque);
extern const struct YamlIdStr enum_UartModes[];
};
//
@@ -1029,15 +1026,36 @@ static bool w_vPitch(const YamlNode* node, uint32_t val, yaml_writer_func wf, vo
return yaml_conv_220::w_vPitch(node, val, wf, opaque);
}
static const struct YamlIdStr enum_TrainerMode[] = {
{ TRAINER_MODE_OFF, "OFF" },
{ TRAINER_MODE_MASTER_TRAINER_JACK, "MASTER_TRAINER_JACK" },
{ TRAINER_MODE_SLAVE, "SLAVE" },
{ TRAINER_MODE_MASTER_SBUS_EXTERNAL_MODULE, "MASTER_SBUS_EXT" },
{ TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE, "MASTER_CPPM_EXT" },
{ TRAINER_MODE_MASTER_SERIAL, "MASTER_SERIAL" },
{ TRAINER_MODE_MASTER_SERIAL, "MASTER_BATT_COMP" },
{ TRAINER_MODE_MASTER_BLUETOOTH, "MASTER_BT" },
{ TRAINER_MODE_SLAVE_BLUETOOTH, "SLAVE_BT" },
{ TRAINER_MODE_MULTI, "MASTER_MULTI" },
{ 0, NULL }
};
static uint32_t r_trainerMode(const YamlNode* node, const char* val, uint8_t val_len)
{
return yaml_parse_enum(yaml_conv_220::enum_TrainerMode, val, val_len);
return yaml_parse_enum(enum_TrainerMode, val, val_len);
}
static bool w_trainerMode(const YamlNode* node, uint32_t val,
yaml_writer_func wf, void* opaque)
{
return yaml_conv_220::w_trainerMode(node, val, wf, opaque);
const char* str = nullptr;
str = yaml_output_enum(val, enum_TrainerMode);
if (str) {
return wf(opaque, str, strlen(str));
}
return true;
}
#if !defined(COLORLCD)
@@ -1733,3 +1751,70 @@ static void r_jitterFilter(void* user, uint8_t* data, uint32_t bitoffs,
uint32_t i = yaml_str2uint(val, val_len);
yaml_put_bits(data, i, bitoffs, 1);
}
//struct_serialConfig
static const struct YamlIdStr enum_SerialPort[] = {
{ SP_AUX1, "AUX1" },
{ SP_AUX2, "AUX2" },
{ SP_VCP, "VCP" },
{ 0, NULL }
};
static const struct YamlIdStr enum_UartModes[] = {
{ UART_MODE_NONE, "NONE" },
{ UART_MODE_TELEMETRY_MIRROR, "TELEMETRY_MIRROR" },
{ UART_MODE_TELEMETRY, "TELEMETRY_IN" },
{ UART_MODE_SBUS_TRAINER, "SBUS_TRAINER" },
{ UART_MODE_LUA, "LUA" },
{ UART_MODE_CLI, "CLI" },
{ UART_MODE_GPS, "GPS" },
{ UART_MODE_DEBUG, "DEBUG" },
{ 0, NULL }
};
static uint32_t port_read(void* user, const char* val, uint8_t val_len)
{
(void)user;
uint32_t port = yaml_parse_enum(enum_SerialPort, val, val_len);
if (port < MAX_SERIAL_PORTS) return port;
return -1;
}
static bool port_write(void* user, yaml_writer_func wf, void* opaque)
{
auto tw = reinterpret_cast<YamlTreeWalker*>(user);
uint16_t idx = tw->getElmts();
const char* str = yaml_output_enum(idx, enum_SerialPort);
return str ? wf(opaque, str, strlen(str)) : true;
}
static const struct YamlNode struct_serialConfig[] = {
YAML_IDX_CUST( "port", port_read, port_write),
YAML_ENUM( "mode", 4, enum_UartModes),
YAML_END
};
static void r_serialMode(void* user, uint8_t* data, uint32_t bitoffs,
const char* val, uint8_t val_len)
{
auto tw = reinterpret_cast<YamlTreeWalker*>(user);
auto node = tw->getAttr();
if (!node || node->tag_len < 4) return;
uint8_t port_nr;
if (node->tag[3] == 'S')
port_nr = SP_AUX1;
else if (node->tag[3] == '2')
port_nr = SP_AUX2;
else
return;
auto m = yaml_parse_enum(yaml_conv_220::enum_UartModes, val, val_len);
if (!m) return;
auto serialPort = reinterpret_cast<uint16_t*>(data);
*serialPort = (*serialPort & ~(0xF << port_nr * 4)) | (m << port_nr * 4);
}
@@ -85,14 +85,6 @@ const struct YamlIdStr enum_Functions[] = {
{ FUNC_DISABLE_TOUCH, "DISABLE_TOUCH" },
{ 0, NULL }
};
const struct YamlIdStr enum_UartModes[] = {
{ UART_MODE_NONE, "MODE_NONE" },
{ UART_MODE_TELEMETRY_MIRROR, "MODE_TELEMETRY_MIRROR" },
{ UART_MODE_TELEMETRY, "MODE_TELEMETRY" },
{ UART_MODE_SBUS_TRAINER, "MODE_SBUS_TRAINER" },
{ UART_MODE_LUA, "MODE_LUA" },
{ 0, NULL }
};
const struct YamlIdStr enum_ZoneOptionValueEnum[] = {
{ ZOV_Unsigned, "Unsigned" },
{ ZOV_Signed, "Signed" },
@@ -427,8 +419,9 @@ static const struct YamlNode struct_RadioData[] = {
YAML_SIGNED_CUST( "varioRange", 8, r_vPitch, w_vPitch ),
YAML_SIGNED( "varioRepeat", 8 ),
YAML_ARRAY("customFn", 72, 64, struct_CustomFunctionData, cfn_is_active),
YAML_ENUM("auxSerialMode", 4, enum_UartModes),
YAML_ENUM("aux2SerialMode", 4, enum_UartModes),
YAML_CUSTOM("auxSerialMode",r_serialMode,nullptr),
YAML_CUSTOM("aux2SerialMode",r_serialMode,nullptr),
YAML_ARRAY("serialPort", 4, 4, struct_serialConfig, nullptr),
YAML_ARRAY("sticksConfig", 0, 4, struct_sticksConfig, stick_name_valid),
YAML_ARRAY("switchConfig", 2, 16, struct_switchConfig, nullptr),
YAML_ARRAY("potsConfig", 2, 8, struct_potConfig, nullptr),
@@ -84,14 +84,6 @@ const struct YamlIdStr enum_Functions[] = {
{ FUNC_RACING_MODE, "RACING_MODE" },
{ 0, NULL }
};
const struct YamlIdStr enum_UartModes[] = {
{ UART_MODE_NONE, "MODE_NONE" },
{ UART_MODE_TELEMETRY_MIRROR, "MODE_TELEMETRY_MIRROR" },
{ UART_MODE_TELEMETRY, "MODE_TELEMETRY" },
{ UART_MODE_SBUS_TRAINER, "MODE_SBUS_TRAINER" },
{ UART_MODE_LUA, "MODE_LUA" },
{ 0, NULL }
};
const struct YamlIdStr enum_TimerModes[] = {
{ TMRMODE_OFF, "OFF" },
{ TMRMODE_ON, "ON" },
@@ -398,8 +390,11 @@ static const struct YamlNode struct_RadioData[] = {
YAML_SIGNED_CUST( "varioRange", 8, r_vPitch, w_vPitch ),
YAML_SIGNED( "varioRepeat", 8 ),
YAML_ARRAY("customFn", 88, 64, struct_CustomFunctionData, cfn_is_active),
YAML_ENUM("auxSerialMode", 4, enum_UartModes),
YAML_CUSTOM("auxSerialMode",r_serialMode,nullptr),
YAML_CUSTOM("aux2SerialMode",r_serialMode,nullptr),
YAML_ARRAY("serialPort", 4, 4, struct_serialConfig, nullptr),
YAML_ARRAY("slidersConfig", 1, 4, struct_sliderConfig, nullptr),
YAML_PADDING( 4 ),
YAML_ARRAY("potsConfig", 2, 4, struct_potConfig, nullptr),
YAML_UNSIGNED( "backlightColor", 8 ),
YAML_ARRAY("sticksConfig", 0, 4, struct_sticksConfig, stick_name_valid),
@@ -84,14 +84,6 @@ const struct YamlIdStr enum_Functions[] = {
{ FUNC_RACING_MODE, "RACING_MODE" },
{ 0, NULL }
};
const struct YamlIdStr enum_UartModes[] = {
{ UART_MODE_NONE, "MODE_NONE" },
{ UART_MODE_TELEMETRY_MIRROR, "MODE_TELEMETRY_MIRROR" },
{ UART_MODE_TELEMETRY, "MODE_TELEMETRY" },
{ UART_MODE_SBUS_TRAINER, "MODE_SBUS_TRAINER" },
{ UART_MODE_LUA, "MODE_LUA" },
{ 0, NULL }
};
const struct YamlIdStr enum_TimerModes[] = {
{ TMRMODE_OFF, "OFF" },
{ TMRMODE_ON, "ON" },
@@ -398,8 +390,11 @@ static const struct YamlNode struct_RadioData[] = {
YAML_SIGNED_CUST( "varioRange", 8, r_vPitch, w_vPitch ),
YAML_SIGNED( "varioRepeat", 8 ),
YAML_ARRAY("customFn", 88, 64, struct_CustomFunctionData, cfn_is_active),
YAML_ENUM("auxSerialMode", 4, enum_UartModes),
YAML_CUSTOM("auxSerialMode",r_serialMode,nullptr),
YAML_CUSTOM("aux2SerialMode",r_serialMode,nullptr),
YAML_ARRAY("serialPort", 4, 4, struct_serialConfig, nullptr),
YAML_ARRAY("slidersConfig", 1, 4, struct_sliderConfig, nullptr),
YAML_PADDING( 4 ),
YAML_ARRAY("potsConfig", 2, 4, struct_potConfig, nullptr),
YAML_UNSIGNED( "backlightColor", 8 ),
YAML_ARRAY("sticksConfig", 0, 4, struct_sticksConfig, stick_name_valid),
@@ -84,14 +84,6 @@ const struct YamlIdStr enum_Functions[] = {
{ FUNC_RACING_MODE, "RACING_MODE" },
{ 0, NULL }
};
const struct YamlIdStr enum_UartModes[] = {
{ UART_MODE_NONE, "MODE_NONE" },
{ UART_MODE_TELEMETRY_MIRROR, "MODE_TELEMETRY_MIRROR" },
{ UART_MODE_TELEMETRY, "MODE_TELEMETRY" },
{ UART_MODE_SBUS_TRAINER, "MODE_SBUS_TRAINER" },
{ UART_MODE_LUA, "MODE_LUA" },
{ 0, NULL }
};
const struct YamlIdStr enum_TimerModes[] = {
{ TMRMODE_OFF, "OFF" },
{ TMRMODE_ON, "ON" },
@@ -398,8 +390,11 @@ static const struct YamlNode struct_RadioData[] = {
YAML_SIGNED_CUST( "varioRange", 8, r_vPitch, w_vPitch ),
YAML_SIGNED( "varioRepeat", 8 ),
YAML_ARRAY("customFn", 88, 64, struct_CustomFunctionData, cfn_is_active),
YAML_ENUM("auxSerialMode", 4, enum_UartModes),
YAML_CUSTOM("auxSerialMode",r_serialMode,nullptr),
YAML_CUSTOM("aux2SerialMode",r_serialMode,nullptr),
YAML_ARRAY("serialPort", 4, 4, struct_serialConfig, nullptr),
YAML_ARRAY("slidersConfig", 1, 4, struct_sliderConfig, nullptr),
YAML_PADDING( 4 ),
YAML_ARRAY("potsConfig", 2, 4, struct_potConfig, nullptr),
YAML_UNSIGNED( "backlightColor", 8 ),
YAML_ARRAY("sticksConfig", 0, 4, struct_sticksConfig, stick_name_valid),
@@ -84,14 +84,6 @@ const struct YamlIdStr enum_Functions[] = {
{ FUNC_RACING_MODE, "RACING_MODE" },
{ 0, NULL }
};
const struct YamlIdStr enum_UartModes[] = {
{ UART_MODE_NONE, "MODE_NONE" },
{ UART_MODE_TELEMETRY_MIRROR, "MODE_TELEMETRY_MIRROR" },
{ UART_MODE_TELEMETRY, "MODE_TELEMETRY" },
{ UART_MODE_SBUS_TRAINER, "MODE_SBUS_TRAINER" },
{ UART_MODE_LUA, "MODE_LUA" },
{ 0, NULL }
};
const struct YamlIdStr enum_TimerModes[] = {
{ TMRMODE_OFF, "OFF" },
{ TMRMODE_ON, "ON" },
@@ -406,8 +398,11 @@ static const struct YamlNode struct_RadioData[] = {
YAML_SIGNED_CUST( "varioRange", 8, r_vPitch, w_vPitch ),
YAML_SIGNED( "varioRepeat", 8 ),
YAML_ARRAY("customFn", 88, 64, struct_CustomFunctionData, cfn_is_active),
YAML_ENUM("auxSerialMode", 4, enum_UartModes),
YAML_CUSTOM("auxSerialMode",r_serialMode,nullptr),
YAML_CUSTOM("aux2SerialMode",r_serialMode,nullptr),
YAML_ARRAY("serialPort", 4, 4, struct_serialConfig, nullptr),
YAML_ARRAY("slidersConfig", 1, 4, struct_sliderConfig, nullptr),
YAML_PADDING( 4 ),
YAML_ARRAY("potsConfig", 2, 4, struct_potConfig, nullptr),
YAML_UNSIGNED( "backlightColor", 8 ),
YAML_ARRAY("sticksConfig", 0, 4, struct_sticksConfig, stick_name_valid),
@@ -84,14 +84,6 @@ const struct YamlIdStr enum_Functions[] = {
{ FUNC_RACING_MODE, "RACING_MODE" },
{ 0, NULL }
};
const struct YamlIdStr enum_UartModes[] = {
{ UART_MODE_NONE, "MODE_NONE" },
{ UART_MODE_TELEMETRY_MIRROR, "MODE_TELEMETRY_MIRROR" },
{ UART_MODE_TELEMETRY, "MODE_TELEMETRY" },
{ UART_MODE_SBUS_TRAINER, "MODE_SBUS_TRAINER" },
{ UART_MODE_LUA, "MODE_LUA" },
{ 0, NULL }
};
const struct YamlIdStr enum_TimerModes[] = {
{ TMRMODE_OFF, "OFF" },
{ TMRMODE_ON, "ON" },
@@ -398,8 +390,11 @@ static const struct YamlNode struct_RadioData[] = {
YAML_SIGNED_CUST( "varioRange", 8, r_vPitch, w_vPitch ),
YAML_SIGNED( "varioRepeat", 8 ),
YAML_ARRAY("customFn", 88, 64, struct_CustomFunctionData, cfn_is_active),
YAML_ENUM("auxSerialMode", 4, enum_UartModes),
YAML_CUSTOM("auxSerialMode",r_serialMode,nullptr),
YAML_CUSTOM("aux2SerialMode",r_serialMode,nullptr),
YAML_ARRAY("serialPort", 4, 4, struct_serialConfig, nullptr),
YAML_ARRAY("slidersConfig", 1, 4, struct_sliderConfig, nullptr),
YAML_PADDING( 4 ),
YAML_ARRAY("potsConfig", 2, 4, struct_potConfig, nullptr),
YAML_UNSIGNED( "backlightColor", 8 ),
YAML_ARRAY("sticksConfig", 0, 4, struct_sticksConfig, stick_name_valid),
@@ -85,14 +85,6 @@ const struct YamlIdStr enum_Functions[] = {
{ FUNC_DISABLE_TOUCH, "DISABLE_TOUCH" },
{ 0, NULL }
};
const struct YamlIdStr enum_UartModes[] = {
{ UART_MODE_NONE, "MODE_NONE" },
{ UART_MODE_TELEMETRY_MIRROR, "MODE_TELEMETRY_MIRROR" },
{ UART_MODE_TELEMETRY, "MODE_TELEMETRY" },
{ UART_MODE_SBUS_TRAINER, "MODE_SBUS_TRAINER" },
{ UART_MODE_LUA, "MODE_LUA" },
{ 0, NULL }
};
const struct YamlIdStr enum_ZoneOptionValueEnum[] = {
{ ZOV_Unsigned, "Unsigned" },
{ ZOV_Signed, "Signed" },
@@ -448,8 +440,9 @@ static const struct YamlNode struct_RadioData[] = {
YAML_SIGNED_CUST( "varioRange", 8, r_vPitch, w_vPitch ),
YAML_SIGNED( "varioRepeat", 8 ),
YAML_ARRAY("customFn", 72, 64, struct_CustomFunctionData, cfn_is_active),
YAML_ENUM("auxSerialMode", 4, enum_UartModes),
YAML_ENUM("aux2SerialMode", 4, enum_UartModes),
YAML_CUSTOM("auxSerialMode",r_serialMode,nullptr),
YAML_CUSTOM("aux2SerialMode",r_serialMode,nullptr),
YAML_ARRAY("serialPort", 4, 4, struct_serialConfig, nullptr),
YAML_ARRAY("sticksConfig", 0, 4, struct_sticksConfig, stick_name_valid),
YAML_ARRAY("switchConfig", 2, 16, struct_switchConfig, nullptr),
YAML_ARRAY("potsConfig", 2, 8, struct_potConfig, nullptr),
@@ -85,14 +85,6 @@ const struct YamlIdStr enum_Functions[] = {
{ FUNC_DISABLE_TOUCH, "DISABLE_TOUCH" },
{ 0, NULL }
};
const struct YamlIdStr enum_UartModes[] = {
{ UART_MODE_NONE, "MODE_NONE" },
{ UART_MODE_TELEMETRY_MIRROR, "MODE_TELEMETRY_MIRROR" },
{ UART_MODE_TELEMETRY, "MODE_TELEMETRY" },
{ UART_MODE_SBUS_TRAINER, "MODE_SBUS_TRAINER" },
{ UART_MODE_LUA, "MODE_LUA" },
{ 0, NULL }
};
const struct YamlIdStr enum_ZoneOptionValueEnum[] = {
{ ZOV_Unsigned, "Unsigned" },
{ ZOV_Signed, "Signed" },
@@ -446,8 +438,9 @@ static const struct YamlNode struct_RadioData[] = {
YAML_SIGNED_CUST( "varioRange", 8, r_vPitch, w_vPitch ),
YAML_SIGNED( "varioRepeat", 8 ),
YAML_ARRAY("customFn", 72, 64, struct_CustomFunctionData, cfn_is_active),
YAML_ENUM("auxSerialMode", 4, enum_UartModes),
YAML_ENUM("aux2SerialMode", 4, enum_UartModes),
YAML_CUSTOM("auxSerialMode",r_serialMode,nullptr),
YAML_CUSTOM("aux2SerialMode",r_serialMode,nullptr),
YAML_ARRAY("serialPort", 4, 4, struct_serialConfig, nullptr),
YAML_ARRAY("sticksConfig", 0, 4, struct_sticksConfig, stick_name_valid),
YAML_ARRAY("switchConfig", 2, 16, struct_switchConfig, nullptr),
YAML_ARRAY("potsConfig", 2, 8, struct_potConfig, nullptr),
@@ -84,14 +84,6 @@ const struct YamlIdStr enum_Functions[] = {
{ FUNC_RACING_MODE, "RACING_MODE" },
{ 0, NULL }
};
const struct YamlIdStr enum_UartModes[] = {
{ UART_MODE_NONE, "MODE_NONE" },
{ UART_MODE_TELEMETRY_MIRROR, "MODE_TELEMETRY_MIRROR" },
{ UART_MODE_TELEMETRY, "MODE_TELEMETRY" },
{ UART_MODE_SBUS_TRAINER, "MODE_SBUS_TRAINER" },
{ UART_MODE_LUA, "MODE_LUA" },
{ 0, NULL }
};
const struct YamlIdStr enum_TimerModes[] = {
{ TMRMODE_OFF, "OFF" },
{ TMRMODE_ON, "ON" },
@@ -398,8 +390,11 @@ static const struct YamlNode struct_RadioData[] = {
YAML_SIGNED_CUST( "varioRange", 8, r_vPitch, w_vPitch ),
YAML_SIGNED( "varioRepeat", 8 ),
YAML_ARRAY("customFn", 88, 64, struct_CustomFunctionData, cfn_is_active),
YAML_ENUM("auxSerialMode", 4, enum_UartModes),
YAML_CUSTOM("auxSerialMode",r_serialMode,nullptr),
YAML_CUSTOM("aux2SerialMode",r_serialMode,nullptr),
YAML_ARRAY("serialPort", 4, 4, struct_serialConfig, nullptr),
YAML_ARRAY("slidersConfig", 1, 4, struct_sliderConfig, nullptr),
YAML_PADDING( 4 ),
YAML_ARRAY("potsConfig", 2, 4, struct_potConfig, nullptr),
YAML_UNSIGNED( "backlightColor", 8 ),
YAML_ARRAY("sticksConfig", 0, 4, struct_sticksConfig, stick_name_valid),
@@ -84,14 +84,6 @@ const struct YamlIdStr enum_Functions[] = {
{ FUNC_RACING_MODE, "RACING_MODE" },
{ 0, NULL }
};
const struct YamlIdStr enum_UartModes[] = {
{ UART_MODE_NONE, "MODE_NONE" },
{ UART_MODE_TELEMETRY_MIRROR, "MODE_TELEMETRY_MIRROR" },
{ UART_MODE_TELEMETRY, "MODE_TELEMETRY" },
{ UART_MODE_SBUS_TRAINER, "MODE_SBUS_TRAINER" },
{ UART_MODE_LUA, "MODE_LUA" },
{ 0, NULL }
};
const struct YamlIdStr enum_TimerModes[] = {
{ TMRMODE_OFF, "OFF" },
{ TMRMODE_ON, "ON" },
@@ -405,8 +397,11 @@ static const struct YamlNode struct_RadioData[] = {
YAML_SIGNED_CUST( "varioRange", 8, r_vPitch, w_vPitch ),
YAML_SIGNED( "varioRepeat", 8 ),
YAML_ARRAY("customFn", 88, 64, struct_CustomFunctionData, cfn_is_active),
YAML_ENUM("auxSerialMode", 4, enum_UartModes),
YAML_CUSTOM("auxSerialMode",r_serialMode,nullptr),
YAML_CUSTOM("aux2SerialMode",r_serialMode,nullptr),
YAML_ARRAY("serialPort", 4, 4, struct_serialConfig, nullptr),
YAML_ARRAY("slidersConfig", 1, 4, struct_sliderConfig, nullptr),
YAML_PADDING( 4 ),
YAML_ARRAY("potsConfig", 2, 4, struct_potConfig, nullptr),
YAML_UNSIGNED( "backlightColor", 8 ),
YAML_ARRAY("sticksConfig", 0, 4, struct_sticksConfig, stick_name_valid),
@@ -84,14 +84,6 @@ const struct YamlIdStr enum_Functions[] = {
{ FUNC_RACING_MODE, "RACING_MODE" },
{ 0, NULL }
};
const struct YamlIdStr enum_UartModes[] = {
{ UART_MODE_NONE, "MODE_NONE" },
{ UART_MODE_TELEMETRY_MIRROR, "MODE_TELEMETRY_MIRROR" },
{ UART_MODE_TELEMETRY, "MODE_TELEMETRY" },
{ UART_MODE_SBUS_TRAINER, "MODE_SBUS_TRAINER" },
{ UART_MODE_LUA, "MODE_LUA" },
{ 0, NULL }
};
const struct YamlIdStr enum_TimerModes[] = {
{ TMRMODE_OFF, "OFF" },
{ TMRMODE_ON, "ON" },
@@ -444,8 +436,11 @@ static const struct YamlNode struct_RadioData[] = {
YAML_SIGNED_CUST( "varioRange", 8, r_vPitch, w_vPitch ),
YAML_SIGNED( "varioRepeat", 8 ),
YAML_ARRAY("customFn", 88, 64, struct_CustomFunctionData, cfn_is_active),
YAML_ENUM("auxSerialMode", 4, enum_UartModes),
YAML_CUSTOM("auxSerialMode",r_serialMode,nullptr),
YAML_CUSTOM("aux2SerialMode",r_serialMode,nullptr),
YAML_ARRAY("serialPort", 4, 4, struct_serialConfig, nullptr),
YAML_ARRAY("slidersConfig", 1, 4, struct_sliderConfig, nullptr),
YAML_PADDING( 4 ),
YAML_ARRAY("potsConfig", 2, 4, struct_potConfig, nullptr),
YAML_UNSIGNED( "backlightColor", 8 ),
YAML_ARRAY("sticksConfig", 0, 4, struct_sticksConfig, stick_name_valid),
@@ -84,14 +84,6 @@ const struct YamlIdStr enum_Functions[] = {
{ FUNC_RACING_MODE, "RACING_MODE" },
{ 0, NULL }
};
const struct YamlIdStr enum_UartModes[] = {
{ UART_MODE_NONE, "MODE_NONE" },
{ UART_MODE_TELEMETRY_MIRROR, "MODE_TELEMETRY_MIRROR" },
{ UART_MODE_TELEMETRY, "MODE_TELEMETRY" },
{ UART_MODE_SBUS_TRAINER, "MODE_SBUS_TRAINER" },
{ UART_MODE_LUA, "MODE_LUA" },
{ 0, NULL }
};
const struct YamlIdStr enum_TimerModes[] = {
{ TMRMODE_OFF, "OFF" },
{ TMRMODE_ON, "ON" },
@@ -385,8 +377,11 @@ static const struct YamlNode struct_RadioData[] = {
YAML_SIGNED_CUST( "varioRange", 8, r_vPitch, w_vPitch ),
YAML_SIGNED( "varioRepeat", 8 ),
YAML_ARRAY("customFn", 88, 64, struct_CustomFunctionData, cfn_is_active),
YAML_ENUM("auxSerialMode", 4, enum_UartModes),
YAML_CUSTOM("auxSerialMode",r_serialMode,nullptr),
YAML_CUSTOM("aux2SerialMode",r_serialMode,nullptr),
YAML_ARRAY("serialPort", 4, 4, struct_serialConfig, nullptr),
YAML_ARRAY("slidersConfig", 1, 4, struct_sliderConfig, nullptr),
YAML_PADDING( 4 ),
YAML_ARRAY("potsConfig", 2, 4, struct_potConfig, nullptr),
YAML_UNSIGNED( "backlightColor", 8 ),
YAML_ARRAY("sticksConfig", 0, 4, struct_sticksConfig, stick_name_valid),
@@ -84,14 +84,6 @@ const struct YamlIdStr enum_Functions[] = {
{ FUNC_RACING_MODE, "RACING_MODE" },
{ 0, NULL }
};
const struct YamlIdStr enum_UartModes[] = {
{ UART_MODE_NONE, "MODE_NONE" },
{ UART_MODE_TELEMETRY_MIRROR, "MODE_TELEMETRY_MIRROR" },
{ UART_MODE_TELEMETRY, "MODE_TELEMETRY" },
{ UART_MODE_SBUS_TRAINER, "MODE_SBUS_TRAINER" },
{ UART_MODE_LUA, "MODE_LUA" },
{ 0, NULL }
};
const struct YamlIdStr enum_TimerModes[] = {
{ TMRMODE_OFF, "OFF" },
{ TMRMODE_ON, "ON" },
@@ -393,8 +385,11 @@ static const struct YamlNode struct_RadioData[] = {
YAML_SIGNED_CUST( "varioRange", 8, r_vPitch, w_vPitch ),
YAML_SIGNED( "varioRepeat", 8 ),
YAML_ARRAY("customFn", 88, 64, struct_CustomFunctionData, cfn_is_active),
YAML_ENUM("auxSerialMode", 4, enum_UartModes),
YAML_CUSTOM("auxSerialMode",r_serialMode,nullptr),
YAML_CUSTOM("aux2SerialMode",r_serialMode,nullptr),
YAML_ARRAY("serialPort", 4, 4, struct_serialConfig, nullptr),
YAML_ARRAY("slidersConfig", 1, 4, struct_sliderConfig, nullptr),
YAML_PADDING( 4 ),
YAML_ARRAY("potsConfig", 2, 4, struct_potConfig, nullptr),
YAML_UNSIGNED( "backlightColor", 8 ),
YAML_ARRAY("sticksConfig", 0, 4, struct_sticksConfig, stick_name_valid),
@@ -84,14 +84,6 @@ const struct YamlIdStr enum_Functions[] = {
{ FUNC_RACING_MODE, "RACING_MODE" },
{ 0, NULL }
};
const struct YamlIdStr enum_UartModes[] = {
{ UART_MODE_NONE, "MODE_NONE" },
{ UART_MODE_TELEMETRY_MIRROR, "MODE_TELEMETRY_MIRROR" },
{ UART_MODE_TELEMETRY, "MODE_TELEMETRY" },
{ UART_MODE_SBUS_TRAINER, "MODE_SBUS_TRAINER" },
{ UART_MODE_LUA, "MODE_LUA" },
{ 0, NULL }
};
const struct YamlIdStr enum_TimerModes[] = {
{ TMRMODE_OFF, "OFF" },
{ TMRMODE_ON, "ON" },
@@ -390,8 +382,11 @@ static const struct YamlNode struct_RadioData[] = {
YAML_SIGNED_CUST( "varioRange", 8, r_vPitch, w_vPitch ),
YAML_SIGNED( "varioRepeat", 8 ),
YAML_ARRAY("customFn", 88, 64, struct_CustomFunctionData, cfn_is_active),
YAML_ENUM("auxSerialMode", 4, enum_UartModes),
YAML_CUSTOM("auxSerialMode",r_serialMode,nullptr),
YAML_CUSTOM("aux2SerialMode",r_serialMode,nullptr),
YAML_ARRAY("serialPort", 4, 4, struct_serialConfig, nullptr),
YAML_ARRAY("slidersConfig", 1, 4, struct_sliderConfig, nullptr),
YAML_PADDING( 4 ),
YAML_ARRAY("potsConfig", 2, 4, struct_potConfig, nullptr),
YAML_UNSIGNED( "backlightColor", 8 ),
YAML_ARRAY("sticksConfig", 0, 4, struct_sticksConfig, stick_name_valid),
@@ -84,14 +84,6 @@ const struct YamlIdStr enum_Functions[] = {
{ FUNC_RACING_MODE, "RACING_MODE" },
{ 0, NULL }
};
const struct YamlIdStr enum_UartModes[] = {
{ UART_MODE_NONE, "MODE_NONE" },
{ UART_MODE_TELEMETRY_MIRROR, "MODE_TELEMETRY_MIRROR" },
{ UART_MODE_TELEMETRY, "MODE_TELEMETRY" },
{ UART_MODE_SBUS_TRAINER, "MODE_SBUS_TRAINER" },
{ UART_MODE_LUA, "MODE_LUA" },
{ 0, NULL }
};
const struct YamlIdStr enum_TimerModes[] = {
{ TMRMODE_OFF, "OFF" },
{ TMRMODE_ON, "ON" },
@@ -392,8 +384,11 @@ static const struct YamlNode struct_RadioData[] = {
YAML_SIGNED_CUST( "varioRange", 8, r_vPitch, w_vPitch ),
YAML_SIGNED( "varioRepeat", 8 ),
YAML_ARRAY("customFn", 88, 64, struct_CustomFunctionData, cfn_is_active),
YAML_ENUM("auxSerialMode", 4, enum_UartModes),
YAML_CUSTOM("auxSerialMode",r_serialMode,nullptr),
YAML_CUSTOM("aux2SerialMode",r_serialMode,nullptr),
YAML_ARRAY("serialPort", 4, 4, struct_serialConfig, nullptr),
YAML_ARRAY("slidersConfig", 1, 4, struct_sliderConfig, nullptr),
YAML_PADDING( 4 ),
YAML_ARRAY("potsConfig", 2, 4, struct_potConfig, nullptr),
YAML_UNSIGNED( "backlightColor", 8 ),
YAML_ARRAY("sticksConfig", 0, 4, struct_sticksConfig, stick_name_valid),
@@ -84,14 +84,6 @@ const struct YamlIdStr enum_Functions[] = {
{ FUNC_RACING_MODE, "RACING_MODE" },
{ 0, NULL }
};
const struct YamlIdStr enum_UartModes[] = {
{ UART_MODE_NONE, "MODE_NONE" },
{ UART_MODE_TELEMETRY_MIRROR, "MODE_TELEMETRY_MIRROR" },
{ UART_MODE_TELEMETRY, "MODE_TELEMETRY" },
{ UART_MODE_SBUS_TRAINER, "MODE_SBUS_TRAINER" },
{ UART_MODE_LUA, "MODE_LUA" },
{ 0, NULL }
};
const struct YamlIdStr enum_TimerModes[] = {
{ TMRMODE_OFF, "OFF" },
{ TMRMODE_ON, "ON" },
@@ -398,8 +390,11 @@ static const struct YamlNode struct_RadioData[] = {
YAML_SIGNED_CUST( "varioRange", 8, r_vPitch, w_vPitch ),
YAML_SIGNED( "varioRepeat", 8 ),
YAML_ARRAY("customFn", 88, 64, struct_CustomFunctionData, cfn_is_active),
YAML_ENUM("auxSerialMode", 4, enum_UartModes),
YAML_CUSTOM("auxSerialMode",r_serialMode,nullptr),
YAML_CUSTOM("aux2SerialMode",r_serialMode,nullptr),
YAML_ARRAY("serialPort", 4, 4, struct_serialConfig, nullptr),
YAML_ARRAY("slidersConfig", 1, 4, struct_sliderConfig, nullptr),
YAML_PADDING( 4 ),
YAML_ARRAY("potsConfig", 2, 4, struct_potConfig, nullptr),
YAML_UNSIGNED( "backlightColor", 8 ),
YAML_ARRAY("sticksConfig", 0, 4, struct_sticksConfig, stick_name_valid),
+2 -1
View File
@@ -164,7 +164,7 @@ endif()
if(HAPTIC)
add_definitions(-DHAPTIC)
set(SRC ${SRC} haptic.cpp)
set(TARGET_SRC ${TARGET_SRC} haptic_driver.cpp)
set(FIRMWARE_TARGET_SRC ${FIRMWARE_TARGET_SRC} haptic_driver.cpp)
endif()
# Protocols supported
@@ -268,6 +268,7 @@ add_definitions(-g)
add_definitions(-DCPUARM)
add_definitions(-DGPS)
add_definitions(-DBATTGRAPH -DTHRTRACE)
add_definitions(-DSBUS_TRAINER)
include_directories(${RTOS_DIR}/include)
@@ -29,7 +29,6 @@ set(STM32USB_SRC
set(FIRMWARE_TARGET_SRC
${FIRMWARE_TARGET_SRC}
../common/arm/stm32/rtc_driver.cpp
${AUX_SERIAL_DRIVER}
../common/arm/stm32/delays_driver.cpp
../common/arm/stm32/usb_bsp.c
../common/arm/stm32/usbd_desc.c
@@ -40,6 +39,18 @@ set(FIRMWARE_TARGET_SRC
../common/arm/stm32/usbd_hid_joystick.c
)
if(AUX_SERIAL OR AUX2_SERIAL)
set(FIRMWARE_TARGET_SRC ${FIRMWARE_TARGET_SRC}
../common/arm/stm32/aux_serial_driver.cpp
)
if(AUX_SERIAL)
add_definitions(-DAUX_SERIAL)
endif()
if(AUX2_SERIAL)
add_definitions(-DAUX2_SERIAL)
endif()
endif()
if(DEBUG OR CLI OR USB_SERIAL)
set(STM32USB_SRC
${STM32USB_SRC}
@@ -70,7 +81,6 @@ endif()
set(FIRMWARE_SRC
${FIRMWARE_SRC}
serial.cpp
syscalls.c
)
@@ -19,415 +19,259 @@
* GNU General Public License for more details.
*/
#include "stm32_hal_ll.h"
#include "stm32_usart_driver.h"
#include "opentx.h"
#include "targets/horus/board.h"
#include "aux_serial_driver.h"
#include "fifo.h"
#include "dmafifo.h"
#define AUX_SERIAL_TX_BUFFER 512
#if defined(SDRAM)
#define AUX_SERIAL_RX_BUFFER 128
#else
#define AUX_SERIAL_RX_BUFFER 32
#endif
typedef Fifo<uint8_t, AUX_SERIAL_TX_BUFFER> TxFifo;
typedef DMAFifo<AUX_SERIAL_RX_BUFFER> RxFifo;
struct SerialState
{
TxFifo* txFifo;
RxFifo* rxFifo;
const stm32_usart_t* usart;
};
static void* aux_serial_init(const SerialState* st, const etx_serial_init* params)
{
stm32_usart_init(st->usart, params);
if (params->rx_enable && st->usart->rxDMA && !params->on_receive) {
st->rxFifo->clear();
stm32_usart_init_rx_dma(st->usart, st->rxFifo->buffer(), st->rxFifo->size());
}
return (void*)st;
}
static void aux_serial_putc(void* ctx, uint8_t c)
{
auto st = (const SerialState*)ctx;
if (st->txFifo->isFull()) return;
st->txFifo->push(c);
// Send is based on IRQ, so that this
// only enables the corresponding IRQ
stm32_usart_send_buffer(st->usart, &c, 1);
}
static void aux_serial_send_buffer(void* ctx, const uint8_t* data, uint8_t size)
{
while(size > 0) {
aux_serial_putc(ctx, *data++);
size--;
}
}
static void aux_wait_tx_completed(void* ctx)
{
// TODO
(void)ctx;
}
static int aux_get_byte(void* ctx, uint8_t* data)
{
auto st = (const SerialState*)ctx;
if (!st->rxFifo) return -1;
return st->rxFifo->pop(*data);
}
void aux_serial_deinit(void* ctx)
{
auto st = (const SerialState*)ctx;
stm32_usart_deinit(st->usart);
}
#if defined(AUX_SERIAL)
uint8_t auxSerialMode = UART_MODE_COUNT; // Prevent debug output before port is setup
Fifo<uint8_t, 512> auxSerialTxFifo;
#if defined(AUX_SERIAL_DMA_Stream_RX)
AuxSerialRxFifo auxSerialRxFifo __DMA (AUX_SERIAL_DMA_Stream_RX);
#else
AuxSerialRxFifo auxSerialRxFifo;
#endif
static TxFifo auxSerialTxFifo;
static RxFifo auxSerialRxFifo __DMA (AUX_SERIAL_DMA_Stream_RX);
void auxSerialSetup(unsigned int baudrate, bool dma, uint16_t length, uint16_t parity, uint16_t stop)
static const LL_GPIO_InitTypeDef auxUSARTPinInit = {
.Pin = AUX_SERIAL_GPIO_PIN_TX | AUX_SERIAL_GPIO_PIN_RX,
.Mode = LL_GPIO_MODE_ALTERNATE,
.Speed = LL_GPIO_SPEED_FREQ_LOW,
.OutputType = LL_GPIO_OUTPUT_PUSHPULL,
.Pull = LL_GPIO_PULL_UP,
.Alternate = AUX_SERIAL_GPIO_AF_LL,
};
static const stm32_usart_t auxUSART = {
.USARTx = AUX_SERIAL_USART,
.GPIOx = AUX_SERIAL_GPIO,
.pinInit = &auxUSARTPinInit,
.IRQn = AUX_SERIAL_USART_IRQn,
.IRQ_Prio = 7, // TODO: define constant
.txDMA = nullptr,
.txDMA_Stream = 0,
.txDMA_Channel = 0,
.rxDMA = AUX_SERIAL_DMA_RX,
.rxDMA_Stream = AUX_SERIAL_DMA_Stream_RX_LL,
.rxDMA_Channel = AUX_SERIAL_DMA_Channel_RX,
};
static const SerialState auxSerialState = {
.txFifo = &auxSerialTxFifo,
.rxFifo = &auxSerialRxFifo,
.usart = &auxUSART,
};
// TODO: grab context to get buffer
static uint8_t auxSerialOnSend(uint8_t* data)
{
USART_InitTypeDef USART_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_PinAFConfig(AUX_SERIAL_GPIO, AUX_SERIAL_GPIO_PinSource_RX, AUX_SERIAL_GPIO_AF);
GPIO_PinAFConfig(AUX_SERIAL_GPIO, AUX_SERIAL_GPIO_PinSource_TX, AUX_SERIAL_GPIO_AF);
GPIO_InitStructure.GPIO_Pin = AUX_SERIAL_GPIO_PIN_TX | AUX_SERIAL_GPIO_PIN_RX;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(AUX_SERIAL_GPIO, &GPIO_InitStructure);
#if defined(AUX_SERIAL_PWR_GPIO)
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Pin = AUX_SERIAL_PWR_GPIO_PIN;
GPIO_Init(AUX_SERIAL_PWR_GPIO, &GPIO_InitStructure);
#endif
USART_InitStructure.USART_BaudRate = baudrate;
USART_InitStructure.USART_WordLength = length;
USART_InitStructure.USART_StopBits = stop;
USART_InitStructure.USART_Parity = parity;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
USART_Init(AUX_SERIAL_USART, &USART_InitStructure);
#if defined(AUX_SERIAL_TX_INVERT_GPIO_PIN)
GPIO_InitStructure.GPIO_Pin = AUX_SERIAL_TX_INVERT_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_Init(AUX_SERIAL_TX_INVERT_GPIO, &GPIO_InitStructure);
GPIO_ResetBits(AUX_SERIAL_TX_INVERT_GPIO, AUX_SERIAL_TX_INVERT_GPIO_PIN);
#endif
#if defined(AUX_SERIAL_RX_INVERT_GPIO_PIN)
GPIO_InitStructure.GPIO_Pin = AUX_SERIAL_RX_INVERT_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_Init(AUX_SERIAL_RX_INVERT_GPIO, &GPIO_InitStructure);
GPIO_ResetBits(AUX_SERIAL_RX_INVERT_GPIO, AUX_SERIAL_RX_INVERT_GPIO_PIN);
#endif
#if defined(AUX_SERIAL_DMA_Stream_RX)
if (dma) {
DMA_InitTypeDef DMA_InitStructure;
auxSerialRxFifo.clear();
USART_ITConfig(AUX_SERIAL_USART, USART_IT_RXNE, DISABLE);
USART_ITConfig(AUX_SERIAL_USART, USART_IT_TXE, DISABLE);
DMA_InitStructure.DMA_Channel = AUX_SERIAL_DMA_Channel_RX;
DMA_InitStructure.DMA_PeripheralBaseAddr = CONVERT_PTR_UINT(&AUX_SERIAL_USART->DR);
DMA_InitStructure.DMA_Memory0BaseAddr = CONVERT_PTR_UINT(auxSerialRxFifo.buffer());
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStructure.DMA_BufferSize = auxSerialRxFifo.size();
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_Low;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(AUX_SERIAL_DMA_Stream_RX, &DMA_InitStructure);
USART_DMACmd(AUX_SERIAL_USART, USART_DMAReq_Rx, ENABLE);
USART_Cmd(AUX_SERIAL_USART, ENABLE);
DMA_Cmd(AUX_SERIAL_DMA_Stream_RX, ENABLE);
return;
}
#endif
// no DMA ...
USART_Cmd(AUX_SERIAL_USART, ENABLE);
USART_ITConfig(AUX_SERIAL_USART, USART_IT_RXNE, ENABLE);
USART_ITConfig(AUX_SERIAL_USART, USART_IT_TXE, DISABLE);
NVIC_SetPriority(AUX_SERIAL_USART_IRQn, 7);
NVIC_EnableIRQ(AUX_SERIAL_USART_IRQn);
return auxSerialTxFifo.pop(*data);
}
void auxSerialInit(unsigned int mode, unsigned int protocol)
// TODO: add to state
static etx_serial_callbacks_t auxSerialCb = {
.on_send = auxSerialOnSend,
.on_receive = nullptr,
.on_error = nullptr,
};
static void* auxSerialInit(const etx_serial_init* params)
{
auxSerialStop();
return aux_serial_init(&auxSerialState, params);
}
auxSerialMode = mode;
static void (*aux1RxCb)(uint8_t*, uint32_t);
switch (mode) {
case UART_MODE_TELEMETRY_MIRROR:
#if defined(CROSSFIRE)
if (protocol == PROTOCOL_TELEMETRY_CROSSFIRE) {
auxSerialSetup(CROSSFIRE_TELEM_MIRROR_BAUDRATE, false);
AUX_SERIAL_POWER_ON();
break;
}
#endif
auxSerialSetup(FRSKY_TELEM_MIRROR_BAUDRATE, false);
AUX_SERIAL_POWER_ON();
break;
static void aux1_on_rx_byte(uint8_t data)
{
if (aux1RxCb) aux1RxCb(&data, 1);
}
#if defined(DEBUG) || defined(CLI)
case UART_MODE_DEBUG:
auxSerialSetup(DEBUG_BAUDRATE, false);
AUX_SERIAL_POWER_OFF();
break;
#endif
case UART_MODE_TELEMETRY:
if (protocol == PROTOCOL_TELEMETRY_FRSKY_D_SECONDARY) {
auxSerialSetup(FRSKY_D_BAUDRATE, true);
AUX_SERIAL_POWER_ON();
}
break;
case UART_MODE_SBUS_TRAINER:
auxSerialSetup(SBUS_BAUDRATE, true, USART_WordLength_9b, USART_Parity_Even, USART_StopBits_2); // USART_WordLength_9b due to parity bit
AUX_SERIAL_POWER_ON();
break;
case UART_MODE_LUA:
auxSerialSetup(LUA_DEFAULT_BAUDRATE, false);
AUX_SERIAL_POWER_ON();
static void aux1SetRxCb(void*, void (*cb)(uint8_t*, uint32_t))
{
aux1RxCb = cb;
if (aux1RxCb) {
auxSerialCb.on_receive = aux1_on_rx_byte;
stm32_usart_deinit_rx_dma(&auxUSART);
} else {
auxSerialCb.on_receive = nullptr;
}
}
void auxSerialPutc(char c)
{
#if !defined(SIMU)
if (auxSerialTxFifo.isFull()) return;
auxSerialTxFifo.push(c);
USART_ITConfig(AUX_SERIAL_USART, USART_IT_TXE, ENABLE);
#endif
}
void auxSerialSbusInit()
{
auxSerialInit(UART_MODE_SBUS_TRAINER, 0);
}
void auxSerialStop()
{
#if defined(AUX_SERIAL_DMA_Stream_RX)
DMA_DeInit(AUX_SERIAL_DMA_Stream_RX);
#endif
USART_DeInit(AUX_SERIAL_USART);
}
uint8_t auxSerialTracesEnabled()
{
#if defined(DEBUG)
return (auxSerialMode == UART_MODE_DEBUG);
#else
return false;
#endif
}
const etx_serial_driver_t AuxSerialDriver = {
.init = auxSerialInit,
.deinit = aux_serial_deinit,
.sendByte = aux_serial_putc,
.sendBuffer = aux_serial_send_buffer,
.waitForTxCompleted = aux_wait_tx_completed,
.getByte = aux_get_byte,
.getBaudrate = nullptr,
.setReceiveCb = aux1SetRxCb,
.setBaudrateCb = nullptr,
};
extern "C" void AUX_SERIAL_USART_IRQHandler(void)
{
DEBUG_INTERRUPT(INT_SER2);
// Send
if (USART_GetITStatus(AUX_SERIAL_USART, USART_IT_TXE) != RESET) {
uint8_t txchar;
if (auxSerialTxFifo.pop(txchar)) {
/* Write one byte to the transmit data register */
USART_SendData(AUX_SERIAL_USART, txchar);
}
else {
USART_ITConfig(AUX_SERIAL_USART, USART_IT_TXE, DISABLE);
}
}
#if defined(CLI)
if (getSelectedUsbMode() != USB_SERIAL_MODE) {
// Receive
uint32_t status = AUX_SERIAL_USART->SR;
while (status & (USART_FLAG_RXNE | USART_FLAG_ERRORS)) {
uint8_t data = AUX_SERIAL_USART->DR;
if (!(status & USART_FLAG_ERRORS)) {
switch (auxSerialMode) {
case UART_MODE_DEBUG:
cliReceiveData(&data, 1);
break;
}
}
status = AUX_SERIAL_USART->SR;
}
}
#endif
// Receive
uint32_t status = AUX_SERIAL_USART->SR;
while (status & (USART_FLAG_RXNE | USART_FLAG_ERRORS)) {
uint8_t data = AUX_SERIAL_USART->DR;
UNUSED(data);
if (!(status & USART_FLAG_ERRORS)) {
#if defined(LUA) & !defined(CLI)
if (luaRxFifo && auxSerialMode == UART_MODE_LUA)
luaRxFifo->push(data);
#endif
}
status = AUX_SERIAL_USART->SR;
}
stm32_usart_isr(&auxUSART, &auxSerialCb);
}
#endif // AUX_SERIAL
#if defined(AUX2_SERIAL)
uint8_t aux2SerialMode = UART_MODE_COUNT; // Prevent debug output before port is setup
Fifo<uint8_t, 512> aux2SerialTxFifo;
AuxSerialRxFifo aux2SerialRxFifo __DMA (AUX2_SERIAL_DMA_Stream_RX);
void aux2SerialSetup(unsigned int baudrate, bool dma, uint16_t length, uint16_t parity, uint16_t stop)
static TxFifo aux2SerialTxFifo;
static RxFifo aux2SerialRxFifo __DMA (AUX2_SERIAL_DMA_Stream_RX);
static const LL_GPIO_InitTypeDef aux2USARTPinInit = {
.Pin = AUX2_SERIAL_GPIO_PIN_TX | AUX2_SERIAL_GPIO_PIN_RX,
.Mode = LL_GPIO_MODE_ALTERNATE,
.Speed = LL_GPIO_SPEED_FREQ_LOW,
.OutputType = LL_GPIO_OUTPUT_PUSHPULL,
.Pull = LL_GPIO_PULL_UP,
.Alternate = AUX2_SERIAL_GPIO_AF_LL,
};
static const stm32_usart_t aux2USART = {
.USARTx = AUX2_SERIAL_USART,
.GPIOx = AUX2_SERIAL_GPIO,
.pinInit = &aux2USARTPinInit,
.IRQn = AUX2_SERIAL_USART_IRQn,
.IRQ_Prio = 7, // TODO: define constant
.txDMA = nullptr,
.txDMA_Stream = 0,
.txDMA_Channel = 0,
.rxDMA = AUX2_SERIAL_DMA_RX,
.rxDMA_Stream = AUX2_SERIAL_DMA_Stream_RX_LL,
.rxDMA_Channel = AUX2_SERIAL_DMA_Channel_RX,
};
static const SerialState aux2SerialState = {
.txFifo = &aux2SerialTxFifo,
.rxFifo = &aux2SerialRxFifo,
.usart = &aux2USART,
};
static uint8_t aux2SerialOnSend(uint8_t* data)
{
USART_InitTypeDef USART_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
return aux2SerialTxFifo.pop(*data);
}
GPIO_PinAFConfig(AUX2_SERIAL_GPIO, AUX2_SERIAL_GPIO_PinSource_RX, AUX2_SERIAL_GPIO_AF);
GPIO_PinAFConfig(AUX2_SERIAL_GPIO, AUX2_SERIAL_GPIO_PinSource_TX, AUX2_SERIAL_GPIO_AF);
static etx_serial_callbacks_t aux2SerialCb = {
.on_send = aux2SerialOnSend,
.on_receive = nullptr,
.on_error = nullptr,
};
GPIO_InitStructure.GPIO_Pin = AUX2_SERIAL_GPIO_PIN_TX | AUX2_SERIAL_GPIO_PIN_RX;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(AUX2_SERIAL_GPIO, &GPIO_InitStructure);
static void* aux2SerialInit(const etx_serial_init* params)
{
return aux_serial_init(&aux2SerialState, params);
}
#if defined(AUX2_SERIAL_PWR_GPIO)
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Pin = AUX2_SERIAL_PWR_GPIO_PIN;
GPIO_Init(AUX2_SERIAL_PWR_GPIO, &GPIO_InitStructure);
#endif
static void (*aux2RxCb)(uint8_t*, uint32_t);
USART_InitStructure.USART_BaudRate = baudrate;
USART_InitStructure.USART_WordLength = length;
USART_InitStructure.USART_StopBits = stop;
USART_InitStructure.USART_Parity = parity;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
USART_Init(AUX2_SERIAL_USART, &USART_InitStructure);
static void aux2_on_rx_byte(uint8_t data)
{
if (aux2RxCb) aux2RxCb(&data, 1);
}
if (dma) {
DMA_InitTypeDef DMA_InitStructure;
aux2SerialRxFifo.clear();
USART_ITConfig(AUX2_SERIAL_USART, USART_IT_RXNE, DISABLE);
USART_ITConfig(AUX2_SERIAL_USART, USART_IT_TXE, DISABLE);
DMA_InitStructure.DMA_Channel = AUX2_SERIAL_DMA_Channel_RX;
DMA_InitStructure.DMA_PeripheralBaseAddr = CONVERT_PTR_UINT(&AUX2_SERIAL_USART->DR);
DMA_InitStructure.DMA_Memory0BaseAddr = CONVERT_PTR_UINT(aux2SerialRxFifo.buffer());
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStructure.DMA_BufferSize = aux2SerialRxFifo.size();
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_Low;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(AUX2_SERIAL_DMA_Stream_RX, &DMA_InitStructure);
USART_DMACmd(AUX2_SERIAL_USART, USART_DMAReq_Rx, ENABLE);
USART_Cmd(AUX2_SERIAL_USART, ENABLE);
DMA_Cmd(AUX2_SERIAL_DMA_Stream_RX, ENABLE);
static void aux2SetRxCb(void*, void (*cb)(uint8_t*, uint32_t))
{
aux2RxCb = cb;
if (aux2RxCb) {
aux2SerialCb.on_receive = aux2_on_rx_byte;
stm32_usart_deinit_rx_dma(&aux2USART);
} else {
aux2SerialCb.on_receive = nullptr;
}
else {
USART_Cmd(AUX2_SERIAL_USART, ENABLE);
USART_ITConfig(AUX2_SERIAL_USART, USART_IT_RXNE, ENABLE);
USART_ITConfig(AUX2_SERIAL_USART, USART_IT_TXE, DISABLE);
NVIC_SetPriority(AUX2_SERIAL_USART_IRQn, 7);
NVIC_EnableIRQ(AUX2_SERIAL_USART_IRQn);
}
}
void aux2SerialInit(unsigned int mode, unsigned int protocol)
{
aux2SerialStop();
aux2SerialMode = mode;
switch (mode) {
case UART_MODE_TELEMETRY_MIRROR:
#if defined(CROSSFIRE)
if (protocol == PROTOCOL_TELEMETRY_CROSSFIRE) {
aux2SerialSetup(CROSSFIRE_TELEM_MIRROR_BAUDRATE, false);
AUX2_SERIAL_POWER_ON();
break;
}
#endif
aux2SerialSetup(FRSKY_TELEM_MIRROR_BAUDRATE, false);
AUX2_SERIAL_POWER_ON();
break;
#if defined(DEBUG) || defined(CLI)
case UART_MODE_DEBUG:
aux2SerialSetup(DEBUG_BAUDRATE, false);
AUX2_SERIAL_POWER_OFF();
break;
#endif
case UART_MODE_TELEMETRY:
if (protocol == PROTOCOL_TELEMETRY_FRSKY_D_SECONDARY) {
aux2SerialSetup(FRSKY_D_BAUDRATE, true);
AUX2_SERIAL_POWER_ON();
}
break;
case UART_MODE_SBUS_TRAINER:
aux2SerialSetup(SBUS_BAUDRATE, true, USART_WordLength_9b, USART_Parity_Even, USART_StopBits_2); // 2 stop bits requires USART_WordLength_9b
AUX2_SERIAL_POWER_ON();
break;
case UART_MODE_LUA:
aux2SerialSetup(LUA_DEFAULT_BAUDRATE, false);
AUX2_SERIAL_POWER_ON();
}
}
void aux2SerialPutc(char c)
{
#if !defined(SIMU)
if (aux2SerialTxFifo.isFull()) return;
aux2SerialTxFifo.push(c);
USART_ITConfig(AUX2_SERIAL_USART, USART_IT_TXE, ENABLE);
#endif
}
void aux2SerialSbusInit()
{
aux2SerialInit(UART_MODE_SBUS_TRAINER, 0);
}
void aux2SerialStop()
{
DMA_DeInit(AUX2_SERIAL_DMA_Stream_RX);
USART_DeInit(AUX2_SERIAL_USART);
}
uint8_t aux2SerialTracesEnabled()
{
#if defined(DEBUG)
return (aux2SerialMode == UART_MODE_DEBUG);
#else
return false;
#endif
}
extern "C" void AUX2_SERIAL_USART_IRQHandler(void)
{
DEBUG_INTERRUPT(INT_SER2);
// Send
if (USART_GetITStatus(AUX2_SERIAL_USART, USART_IT_TXE) != RESET) {
uint8_t txchar;
if (aux2SerialTxFifo.pop(txchar)) {
/* Write one byte to the transmit data register */
USART_SendData(AUX2_SERIAL_USART, txchar);
}
else {
USART_ITConfig(AUX2_SERIAL_USART, USART_IT_TXE, DISABLE);
}
}
#if defined(CLI)
if (getSelectedUsbMode() != USB_SERIAL_MODE) {
// Receive
uint32_t status = AUX2_SERIAL_USART->SR;
while (status & (USART_FLAG_RXNE | USART_FLAG_ERRORS)) {
uint8_t data = AUX2_SERIAL_USART->DR;
if (!(status & USART_FLAG_ERRORS)) {
switch (aux2SerialMode) {
case UART_MODE_DEBUG:
cliReceiveData(&data, 1);
break;
}
}
status = AUX2_SERIAL_USART->SR;
}
}
#endif
// Receive
uint32_t status = AUX2_SERIAL_USART->SR;
while (status & (USART_FLAG_RXNE | USART_FLAG_ERRORS)) {
uint8_t data = AUX2_SERIAL_USART->DR;
UNUSED(data);
if (!(status & USART_FLAG_ERRORS)) {
#if defined(LUA) & !defined(CLI)
if (luaRxFifo && aux2SerialMode == UART_MODE_LUA) {
luaRxFifo->push(data);
}
#endif
}
status = AUX2_SERIAL_USART->SR;
}
stm32_usart_isr(&aux2USART, &aux2SerialCb);
}
const etx_serial_driver_t Aux2SerialDriver = {
.init = aux2SerialInit,
.deinit = aux_serial_deinit,
.sendByte = aux_serial_putc,
.sendBuffer = aux_serial_send_buffer,
.waitForTxCompleted = aux_wait_tx_completed,
.getByte = aux_get_byte,
.getBaudrate = nullptr,
.setReceiveCb = aux2SetRxCb,
.setBaudrateCb = nullptr,
};
#endif // AUX2_SERIAL
@@ -0,0 +1,33 @@
/*
* Copyright (C) EdgeTX
*
* Based on code named
* opentx - https://github.com/opentx/opentx
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <stdint.h>
#include "hal/serial_driver.h"
#if defined(AUX_SERIAL)
extern const etx_serial_driver_t AuxSerialDriver;
#endif
#if defined(AUX2_SERIAL)
extern const etx_serial_driver_t Aux2SerialDriver;
#endif
@@ -80,26 +80,8 @@
#endif
#if defined(__cplusplus) && !defined(SIMU)
extern "C" {
#endif
#include "usb_driver.h"
#if !defined(SIMU)
#include "usbd_cdc_core.h"
#include "usbd_msc_core.h"
#include "usbd_hid_core.h"
#include "usbd_usr.h"
#include "usbd_desc.h"
#include "usb_conf.h"
#include "usbd_conf.h"
#endif
#if defined(__cplusplus) && !defined(SIMU)
}
#endif
#if defined(SIMU)
#include "../simu/simpgmspace.h"
#endif
@@ -144,6 +144,7 @@ if(PCB STREQUAL X10 OR PCB STREQUAL X12S OR PCB STREQUAL NV14)
../../../../../${STM32LIB_DIR}/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_usart.c
../../../../../serial.cpp
../../../../../targets/common/arm/stm32/aux_serial_driver.cpp
../../../../../targets/common/arm/stm32/stm32_usart_driver.cpp
)
endif()
else()
@@ -244,12 +244,9 @@ int main()
#endif
delaysInit(); // needed for lcdInit()
#if defined(DEBUG) && defined(AUX_SERIAL)
auxSerialInit(UART_MODE_DEBUG, 0); // default serial mode (None if DEBUG not defined)
#endif
#if defined(DEBUG) && defined(AUX2_SERIAL)
aux2SerialInit(UART_MODE_DEBUG, 0); // default serial mode (None if DEBUG not defined)
#if defined(DEBUG)
initSerialPorts();
#endif
__enable_irq();
+3 -2
View File
@@ -20,8 +20,9 @@
*/
#include <inttypes.h>
#include "definitions.h"
void getCPUUniqueID(char * s);
EXTERN_C(void getCPUUniqueID(char * s));
#define LEN_CPU_UID (3*8+2)
@@ -29,4 +30,4 @@ void getCPUUniqueID(char * s);
extern const uint32_t cpu_uid[3];
#else
extern const uint32_t * cpu_uid;
#endif
#endif
@@ -0,0 +1,178 @@
/*
* 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 "extmodule_driver.h"
#include "stm32_pulse_driver.h"
#include "hal.h"
#include "timers_driver.h"
static const stm32_pulse_timer_t extmoduleTimer = {
.GPIOx = EXTMODULE_TX_GPIO,
.GPIO_Pin = EXTMODULE_TX_GPIO_PIN,
.GPIO_Alternate = EXTMODULE_TIMER_TX_GPIO_AF,
.TIMx = EXTMODULE_TIMER,
.TIM_Prescaler = __LL_TIM_CALC_PSC(EXTMODULE_TIMER_FREQ, 2000000),
.TIM_Channel = EXTMODULE_TIMER_Channel,
.TIM_IRQn = EXTMODULE_TIMER_IRQn,
.DMAx = EXTMODULE_TIMER_DMA,
.DMA_Stream = EXTMODULE_TIMER_DMA_STREAM_LL,
.DMA_Channel = EXTMODULE_TIMER_DMA_CHANNEL,
.DMA_IRQn = EXTMODULE_TIMER_DMA_STREAM_IRQn,
};
// Make sure the timer channel is supported
static_assert(__STM32_PULSE_IS_TIMER_CHANNEL_SUPPORTED(EXTMODULE_TIMER_Channel),
"Unsupported timer channel");
// Make sure the DMA channel is supported
static_assert(__STM32_PULSE_IS_DMA_STREAM_SUPPORTED(EXTMODULE_TIMER_DMA_STREAM_LL),
"Unsupported DMA stream");
#if !defined(EXTMODULE_TIMER_DMA_IRQHandler)
#error "Missing EXTMODULE_TIMER_DMA_IRQHandler definition"
#endif
extern "C" void EXTMODULE_TIMER_DMA_IRQHandler()
{
stm32_pulse_dma_tc_isr(&extmoduleTimer);
}
#if !defined(EXTMODULE_TIMER_IRQHandler)
#error "Missing EXTMODULE_TIMER_IRQHandler definition"
#endif
extern "C" void EXTMODULE_TIMER_IRQHandler()
{
stm32_pulse_tim_update_isr(&extmoduleTimer);
}
void extmoduleStop()
{
EXTERNAL_MODULE_OFF();
stm32_pulse_deinit(&extmoduleTimer);
}
static void config_ppm_output(uint16_t ppm_delay, bool polarity)
{
// PPM generation principle:
//
// Hardware timer in PWM mode is used for PPM generation
// Output is OFF if CNT<CCR1(delay) and ON if bigger
// CCR1 register defines duration of pulse length and is constant
// AAR register defines duration of each pulse, it is
// updated after every pulse in Update interrupt handler.
stm32_pulse_config_output(&extmoduleTimer, !polarity, LL_TIM_OCMODE_PWM1,
ppm_delay * 2);
}
void extmodulePpmStart(uint16_t ppm_delay, bool polarity)
{
EXTERNAL_MODULE_ON();
stm32_pulse_init(&extmoduleTimer);
config_ppm_output(ppm_delay, polarity);
}
void extmoduleSendNextFramePpm(void* pulses, uint16_t length,
uint16_t ppm_delay, bool polarity)
{
if (!stm32_pulse_if_not_running_disable(&extmoduleTimer))
return;
// Set polarity
stm32_pulse_set_polarity(&extmoduleTimer, !polarity);
// Start DMA request and re-enable timer
stm32_pulse_start_dma_req(&extmoduleTimer, pulses, length,
LL_TIM_OCMODE_PWM1, ppm_delay * 2);
}
#if defined(PXX1)
void extmodulePxx1PulsesStart()
{
EXTERNAL_MODULE_ON();
stm32_pulse_config_output(&extmoduleTimer, false, LL_TIM_OCMODE_PWM1, 9 * 2);
stm32_pulse_init(&extmoduleTimer);
}
void extmoduleSendNextFramePxx1(const void* pulses, uint16_t length)
{
if (!stm32_pulse_if_not_running_disable(&extmoduleTimer)) return;
// Start DMA request and re-enable timer
stm32_pulse_start_dma_req(&extmoduleTimer, pulses, length, LL_TIM_OCMODE_PWM1,
9 * 2);
}
#endif
// TODO: polarity?
void extmoduleSerialStart()
{
EXTERNAL_MODULE_ON();
stm32_pulse_init(&extmoduleTimer);
stm32_pulse_config_output(&extmoduleTimer, true, LL_TIM_OCMODE_TOGGLE, 0);
}
void extmoduleSendNextFrameSoftSerial(const void* pulses, uint16_t length, bool polarity)
{
if (!stm32_pulse_if_not_running_disable(&extmoduleTimer))
return;
// Set polarity
stm32_pulse_set_polarity(&extmoduleTimer, polarity);
// Start DMA request and re-enable timer
stm32_pulse_start_dma_req(&extmoduleTimer, pulses, length, LL_TIM_OCMODE_TOGGLE, 0);
}
// Delay based byte sending @ 57600 bps
void extmoduleSendInvertedByte(uint8_t byte)
{
uint16_t time;
uint32_t i;
__disable_irq();
time = getTmr2MHz();
LL_GPIO_SetOutputPin(EXTMODULE_TX_GPIO, EXTMODULE_TX_GPIO_PIN);
while ((uint16_t) (getTmr2MHz() - time) < 34) {
// wait
}
time += 34;
for (i = 0; i < 8; i++) {
if (byte & 1) {
LL_GPIO_ResetOutputPin(EXTMODULE_TX_GPIO, EXTMODULE_TX_GPIO_PIN);
}
else {
LL_GPIO_SetOutputPin(EXTMODULE_TX_GPIO, EXTMODULE_TX_GPIO_PIN);
}
byte >>= 1 ;
while ((uint16_t) (getTmr2MHz() - time) < 35) {
// wait
}
time += 35 ;
}
LL_GPIO_ResetOutputPin(EXTMODULE_TX_GPIO, EXTMODULE_TX_GPIO_PIN);
__enable_irq(); // No need to wait for the stop bit to complete
while ((uint16_t) (getTmr2MHz() - time) < 34) {
// wait
}
}
@@ -0,0 +1,44 @@
/*
* 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 <stdint.h>
void extmoduleStop();
void extmodulePpmStart(uint16_t ppm_delay, bool polarity);
#if defined(PXX1)
void extmodulePxx1PulsesStart();
void extmoduleSendNextFramePxx1(const void* pulses, uint16_t length);
#endif
// Soft serial on PPM pin
void extmoduleSerialStart();
void extmoduleSendNextFramePpm(void* pulses, uint16_t length,
uint16_t ppm_delay, bool polarity);
void extmoduleSendNextFrameSoftSerial(const void* pulses, uint16_t length,
bool polarity = true);
// Bitbang serial
void extmoduleSendInvertedByte(uint8_t byte);
@@ -0,0 +1,153 @@
/*
* 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 "extmodule_serial_driver.h"
#include "board.h"
#if defined(EXTMODULE_USART)
#include "stm32_usart_driver.h"
#include "io/frsky_pxx2.h"
ModuleFifo extmoduleFifo;
static etx_serial_callbacks_t extmodule_driver = {
nullptr, nullptr, nullptr
};
void extmoduleFifoReceive(uint8_t data)
{
extmoduleFifo.push(data);
}
void extmoduleFifoError()
{
extmoduleFifo.errors++;
}
static const etx_serial_init extmoduleSerialParams = {
.baudrate = 0,
.parity = ETX_Parity_None,
.stop_bits = ETX_StopBits_One,
.word_length = ETX_WordLength_8,
.rx_enable = true,
.on_receive = extmoduleFifoReceive,
.on_error = extmoduleFifoError,
};
static const LL_GPIO_InitTypeDef extmoduleUSART_PinDef = {
.Pin = EXTMODULE_TX_GPIO_PIN | EXTMODULE_RX_GPIO_PIN,
.Mode = LL_GPIO_MODE_ALTERNATE,
.Speed = LL_GPIO_SPEED_FREQ_LOW,
.OutputType = LL_GPIO_OUTPUT_PUSHPULL,
.Pull = LL_GPIO_PULL_UP,
.Alternate = EXTMODULE_USART_GPIO_AF_LL,
};
static const stm32_usart_t extmoduleUSART = {
.USARTx = EXTMODULE_USART,
.GPIOx = EXTMODULE_TX_GPIO,
.pinInit = &extmoduleUSART_PinDef,
.IRQn = EXTMODULE_USART_IRQn,
.IRQ_Prio = EXTMODULE_USART_IRQ_PRIORITY,
.txDMA = EXTMODULE_USART_TX_DMA,
.txDMA_Stream = EXTMODULE_USART_TX_DMA_STREAM_LL,
.txDMA_Channel = EXTMODULE_USART_TX_DMA_CHANNEL,
.rxDMA = nullptr,
.rxDMA_Stream = 0,
.rxDMA_Channel = 0,
};
static void* extmoduleSerialStart(const etx_serial_init* params)
{
if (!params) return nullptr;
extmodule_driver.on_receive = params->on_receive;
extmodule_driver.on_error = params->on_error;
// UART config
stm32_usart_init(&extmoduleUSART, params);
extmoduleFifo.clear();
return nullptr;
}
void extmoduleInvertedSerialStart(uint32_t baudrate)
{
EXTERNAL_MODULE_ON();
etx_serial_init params(extmoduleSerialParams);
params.baudrate = baudrate;
extmoduleSerialStart(&params);
}
#if defined(PXX1)
void extmodulePxx1SerialStart()
{
EXTERNAL_MODULE_ON();
etx_serial_init params(extmoduleSerialParams);
params.baudrate = EXTMODULE_PXX1_SERIAL_BAUDRATE;
ExtmoduleSerialDriver.init(&params);
}
#endif
void extmoduleSerialStop(void*)
{
stm32_usart_deinit(&extmoduleUSART);
// reset callbacks
extmodule_driver.on_receive = nullptr;
extmodule_driver.on_error = nullptr;
}
static void extmoduleSendByte(void*, uint8_t byte)
{
stm32_usart_send_byte(&extmoduleUSART, byte);
}
static void extmoduleSendBuffer(void*, const uint8_t * data, uint8_t size)
{
if (size == 0) return;
stm32_usart_send_buffer(&extmoduleUSART, data, size);
}
static void extmoduleWaitForTxCompleted(void*)
{
stm32_usart_wait_for_tx_dma(&extmoduleUSART);
}
const etx_serial_driver_t ExtmoduleSerialDriver = {
.init = extmoduleSerialStart,
.deinit = extmoduleSerialStop,
.sendByte = extmoduleSendByte,
.sendBuffer = extmoduleSendBuffer,
.waitForTxCompleted = extmoduleWaitForTxCompleted,
.getByte = nullptr,
.getBaudrate = nullptr,
.setReceiveCb = nullptr,
.setBaudrateCb = nullptr,
};
extern "C" void EXTMODULE_USART_IRQHandler(void)
{
stm32_usart_isr(&extmoduleUSART, &extmodule_driver);
}
#endif // defined(EXTMODULE_USART)
@@ -0,0 +1,42 @@
/*
* Copyright (C) EdgeTX
*
* Based on code named
* opentx - https://github.com/opentx/opentx
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#pragma once
#include <stdint.h>
#include "hal/serial_driver.h"
#define EXTMODULE_USART_IRQ_PRIORITY 6
// Callbacks using intmoduleFifo
void extmoduleFifoReceive(uint8_t data);
void extmoduleFifoError();
// void extmoduleSerialStart();
// void extmoduleInvertedSerialStart(uint32_t baudrate);
// void extmoduleSendBuffer(const uint8_t * data, uint8_t size);
// void extmoduleSendNextFrame();
#if defined(PXX1)
void extmodulePxx1SerialStart();
#endif
extern const etx_serial_driver_t ExtmoduleSerialDriver;
@@ -1,11 +1,31 @@
set(CPU_FAMILY STM32)
set(MCU cortex-m3)
set(FPU_FLAGS "")
set(STM32LIB_DIR ${THIRDPARTY_DIR}/STM32F2xx_StdPeriph_Lib_V1.1.0/Libraries)
# STM32 HAL/LL library
set(STM32CUBE_DIR ${THIRDPARTY_DIR}/STM32F2xx_HAL_Driver)
add_library(stm32cube_ll OBJECT EXCLUDE_FROM_ALL
${STM32CUBE_DIR}/Src/stm32f2xx_ll_gpio.c
${STM32CUBE_DIR}/Src/stm32f2xx_ll_tim.c
${STM32CUBE_DIR}/Src/stm32f2xx_ll_dma.c
${STM32CUBE_DIR}/Src/stm32f2xx_ll_usart.c
${STM32CUBE_DIR}/Src/stm32f2xx_ll_rcc.c
)
target_compile_options(stm32cube_ll PRIVATE -DUSE_FULL_LL_DRIVER)
target_include_directories(stm32cube_ll PRIVATE
${STM32CUBE_DIR}/Inc
${THIRDPARTY_DIR}/CMSIS/Device/ST/STM32F2xx/Include
${THIRDPARTY_DIR}/CMSIS/Include)
set(FIRMWARE_SRC ${FIRMWARE_SRC} $<TARGET_OBJECTS:stm32cube_ll>)
# StdPeriph library
set(STM32LIB_DIR ${THIRDPARTY_DIR}/STM32F2xx_StdPeriph_Lib_V1.1.0/Libraries)
include_directories(${STM32LIB_DIR}/STM32F2xx_StdPeriph_Driver/inc)
include_directories(${STM32LIB_DIR}/CMSIS/Device/ST/STM32F2xx/Include)
include_directories(${STM32LIB_DIR}/CMSIS/include)
include_directories(${STM32LIB_DIR}/CMSIS/Include)
add_definitions(-DSTM32F2)
@@ -88,6 +88,7 @@
uint32_t SystemCoreClock = 120000000;
__I uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};
__I uint8_t APBPrescTable[8] = {0, 0, 0, 0, 1, 2, 3, 4};
/**
* @}
@@ -1,8 +1,29 @@
set(CPU_FAMILY STM32)
set(MCU cortex-m4)
set(FPU_FLAGS "-mfloat-abi=hard -mfpu=fpv4-sp-d16")
set(STM32LIB_DIR ${THIRDPARTY_DIR}/STM32F4xx_DSP_StdPeriph_Lib_V1.8.0/Libraries)
# STM32 HAL/LL library
set(STM32CUBE_DIR ${THIRDPARTY_DIR}/STM32F4xx_HAL_Driver)
add_library(stm32cube_ll OBJECT EXCLUDE_FROM_ALL
${STM32CUBE_DIR}/Src/stm32f4xx_ll_gpio.c
${STM32CUBE_DIR}/Src/stm32f4xx_ll_tim.c
${STM32CUBE_DIR}/Src/stm32f4xx_ll_dma.c
${STM32CUBE_DIR}/Src/stm32f4xx_ll_usart.c
${STM32CUBE_DIR}/Src/stm32f4xx_ll_rcc.c
)
target_compile_options(stm32cube_ll PRIVATE -DUSE_FULL_LL_DRIVER)
target_include_directories(stm32cube_ll PRIVATE
${STM32CUBE_DIR}/Inc
${THIRDPARTY_DIR}/CMSIS/Device/ST/STM32F4xx/Include
${THIRDPARTY_DIR}/CMSIS/Include)
set(FIRMWARE_SRC ${FIRMWARE_SRC} $<TARGET_OBJECTS:stm32cube_ll>)
set(BOOTLOADER_SRC ${BOOTLOADER_SRC} $<TARGET_OBJECTS:stm32cube_ll>)
# StdPeriph library
set(STM32LIB_DIR ${THIRDPARTY_DIR}/STM32F4xx_DSP_StdPeriph_Lib_V1.8.0/Libraries)
include_directories(${STM32LIB_DIR}/STM32F4xx_StdPeriph_Driver/inc)
include_directories(${STM32LIB_DIR}/CMSIS/Device/ST/STM32F4xx/Include)
include_directories(${STM32LIB_DIR}/CMSIS/Include)
@@ -182,6 +182,7 @@
uint32_t SystemCoreClock = 168000000;
__I uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};
__I uint8_t APBPrescTable[8] = {0, 0, 0, 0, 1, 2, 3, 4};
/**
* @}
@@ -19,8 +19,12 @@
* GNU General Public License for more details.
*/
#include "opentx.h"
#include "mixer_scheduler.h"
#include "board.h"
#include "debug.h"
#include "heartbeat_driver.h"
#include "timers_driver.h"
#if defined(INTMODULE_HEARTBEAT_GPIO)
@@ -79,9 +83,7 @@ void stop_intmodule_heartbeat()
void check_intmodule_heartbeat()
{
if (EXTI_GetITStatus(INTMODULE_HEARTBEAT_EXTI_LINE) != RESET) {
#if !defined(INTMODULE_USART)
heartbeatCapture.timestamp = getTmr2MHz();
#endif
#if defined(DEBUG_LATENCY)
heartbeatCapture.count++;
#endif
@@ -0,0 +1,36 @@
/*
* 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
struct HeartbeatCapture {
uint32_t timestamp;
uint8_t valid;
#if defined(DEBUG_LATENCY)
uint32_t count;
#endif
};
extern volatile HeartbeatCapture heartbeatCapture;
void init_intmodule_heartbeat();
void check_intmodule_heartbeat();
void stop_intmodule_heartbeat();
@@ -19,217 +19,147 @@
* GNU General Public License for more details.
*/
#include "opentx.h"
#include "stm32_hal_ll.h"
#include "intmodule_serial_driver.h"
#include "stm32_usart_driver.h"
#include "board.h"
#include "io/frsky_pxx2.h"
ModuleFifo intmoduleFifo;
#if !defined(INTMODULE_DMA_STREAM)
uint8_t * intmoduleTxBufferData;
volatile uint8_t intmoduleTxBufferRemaining;
static uint8_t * intmoduleTxBufferData;
static volatile uint8_t intmoduleTxBufferRemaining;
uint8_t intmoduleTxBufferSend(uint8_t* data)
{
if (intmoduleTxBufferRemaining) {
*data = *(intmoduleTxBufferData++);
intmoduleTxBufferRemaining--;
return true;
}
// buffer is empty
return false;
}
#endif
struct etx_serial_driver {
void (*on_receive)(uint8_t data);
void (*on_error)();
static etx_serial_callbacks_t intmodule_driver = {
#if !defined(INTMODULE_DMA_STREAM)
intmoduleTxBufferSend,
#else
nullptr,
#endif
nullptr, nullptr
};
static etx_serial_driver intmodule_driver = { nullptr, nullptr };
// TODO: move this somewhere else
static void intmoduleFifoReceive(uint8_t data)
void intmoduleFifoReceive(uint8_t data)
{
intmoduleFifo.push(data);
}
static void intmoduleFifoError()
void intmoduleFifoError()
{
intmoduleFifo.errors++;
}
etx_serial_init::etx_serial_init():
baudrate(0),
parity(USART_Parity_No),
stop_bits(USART_StopBits_1),
word_length(USART_WordLength_8b),
rx_enable(false),
// TODO: this should not be needed
on_receive(intmoduleFifoReceive),
on_error(intmoduleFifoError)
{
}
static const LL_GPIO_InitTypeDef intmoduleUSART_PinDef = {
.Pin = INTMODULE_TX_GPIO_PIN | INTMODULE_RX_GPIO_PIN,
.Mode = LL_GPIO_MODE_ALTERNATE,
.Speed = LL_GPIO_SPEED_FREQ_LOW,
.OutputType = LL_GPIO_OUTPUT_PUSHPULL,
.Pull = LL_GPIO_PULL_UP,
.Alternate = INTMODULE_GPIO_AF_LL,
};
static const stm32_usart_t intmoduleUSART = {
.USARTx = INTMODULE_USART,
.GPIOx = INTMODULE_GPIO,
.pinInit = &intmoduleUSART_PinDef,
.IRQn = INTMODULE_USART_IRQn,
.IRQ_Prio = INTMODULE_USART_IRQ_PRIORITY,
.txDMA = INTMODULE_DMA,
.txDMA_Stream = INTMODULE_DMA_STREAM_LL,
.txDMA_Channel = INTMODULE_DMA_CHANNEL,
.rxDMA = nullptr,
.rxDMA_Stream = 0,
.rxDMA_Channel = 0,
};
void intmoduleStop()
{
GPIO_ResetBits(INTMODULE_PWR_GPIO, INTMODULE_PWR_GPIO_PIN);
#if defined(INTMODULE_DMA_STREAM)
INTMODULE_DMA_STREAM->CR &= ~DMA_SxCR_EN; // Disable DMA
#endif
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = INTMODULE_TX_GPIO_PIN | INTMODULE_RX_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(INTMODULE_GPIO, &GPIO_InitStructure);
USART_DeInit(INTMODULE_USART);
GPIO_ResetBits(INTMODULE_GPIO, INTMODULE_TX_GPIO_PIN | INTMODULE_RX_GPIO_PIN);
stm32_usart_deinit(&intmoduleUSART);
// reset callbacks
intmodule_driver.on_receive = nullptr;
intmodule_driver.on_error = nullptr;
}
void intmodulePxx1SerialStart()
static void intmoduleStop(void* ctx)
{
etx_serial_init params;
params.baudrate = INTMODULE_PXX1_SERIAL_BAUDRATE;
intmoduleSerialStart(&params);
(void)ctx;
intmoduleStop();
}
void intmoduleSerialStart(const etx_serial_init* params)
void* intmoduleSerialStart(const etx_serial_init* params)
{
if (!params) return;
INTERNAL_MODULE_ON();
if (!params) return nullptr;
// TODO: sanity check parameters
// - the UART seems to block when initialised with baudrate = 0
// init callbacks
intmodule_driver.on_receive = params->on_receive;
intmodule_driver.on_error = params->on_error;
uint32_t baudrate = params->baudrate;
#if !defined(INTMODULE_DMA_STREAM)
// IRQ based TX
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = INTMODULE_USART_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
// rco: workaround for high baudrate not supported with
// IRQ based TX.
if (baudrate > 1870000) {
TRACE("limiting baudrate to 1.87 MBit/s");
baudrate = 1870000;
}
#endif
GPIO_PinAFConfig(INTMODULE_GPIO, INTMODULE_GPIO_PinSource_TX, INTMODULE_GPIO_AF);
GPIO_PinAFConfig(INTMODULE_GPIO, INTMODULE_GPIO_PinSource_RX, INTMODULE_GPIO_AF);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = INTMODULE_TX_GPIO_PIN | INTMODULE_RX_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(INTMODULE_GPIO, &GPIO_InitStructure);
USART_DeInit(INTMODULE_USART);
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = baudrate;
USART_InitStructure.USART_Parity = params->parity;
USART_InitStructure.USART_StopBits = params->stop_bits;
USART_InitStructure.USART_WordLength = params->word_length;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
USART_Init(INTMODULE_USART, &USART_InitStructure);
USART_Cmd(INTMODULE_USART, ENABLE);
if (params->rx_enable) {
USART_ITConfig(INTMODULE_USART, USART_IT_RXNE, ENABLE);
NVIC_SetPriority(INTMODULE_USART_IRQn, 6);
NVIC_EnableIRQ(INTMODULE_USART_IRQn);
}
stm32_usart_init(&intmoduleUSART, params);
return nullptr;
}
#define USART_FLAG_ERRORS (USART_FLAG_ORE | USART_FLAG_NE | USART_FLAG_FE | USART_FLAG_PE)
extern "C" void INTMODULE_USART_IRQHandler(void)
{
#if !defined(INTMODULE_DMA_STREAM)
// Send
if (USART_GetITStatus(INTMODULE_USART, USART_IT_TXE) != RESET) {
if (intmoduleTxBufferRemaining) {
USART_SendData(INTMODULE_USART, intmoduleTxBufferData[0]);
intmoduleTxBufferData++;
intmoduleTxBufferRemaining--;
}
else {
USART_ITConfig(INTMODULE_USART, USART_IT_TXE, DISABLE);
}
}
#endif
// Receive
uint32_t status = INTMODULE_USART->SR;
while (status & (USART_FLAG_RXNE | USART_FLAG_ERRORS)) {
uint8_t data = INTMODULE_USART->DR;
if (status & USART_FLAG_ERRORS) {
if (intmodule_driver.on_error)
intmodule_driver.on_error();
}
else {
if (intmodule_driver.on_receive)
intmodule_driver.on_receive(data);
}
status = INTMODULE_USART->SR;
}
stm32_usart_isr(&intmoduleUSART, &intmodule_driver);
}
void intmoduleSendByte(uint8_t byte)
void intmoduleSendByte(void* ctx, uint8_t byte)
{
while (!(INTMODULE_USART->SR & USART_SR_TXE));
USART_SendData(INTMODULE_USART, byte);
(void)ctx;
stm32_usart_send_byte(&intmoduleUSART, byte);
}
void intmoduleSendBuffer(const uint8_t * data, uint8_t size)
void intmoduleSendBuffer(void* ctx, const uint8_t * data, uint8_t size)
{
(void)ctx;
if (size == 0)
return;
#if defined(INTMODULE_DMA_STREAM)
DMA_InitTypeDef DMA_InitStructure;
DMA_DeInit(INTMODULE_DMA_STREAM);
DMA_InitStructure.DMA_Channel = INTMODULE_DMA_CHANNEL;
DMA_InitStructure.DMA_PeripheralBaseAddr = CONVERT_PTR_UINT(&INTMODULE_USART->DR);
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
DMA_InitStructure.DMA_Memory0BaseAddr = CONVERT_PTR_UINT(data);
DMA_InitStructure.DMA_BufferSize = size;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(INTMODULE_DMA_STREAM, &DMA_InitStructure);
DMA_Cmd(INTMODULE_DMA_STREAM, ENABLE);
USART_DMACmd(INTMODULE_USART, USART_DMAReq_Tx, ENABLE);
#else
#if !defined(INTMODULE_DMA_STREAM)
intmoduleTxBufferData = (uint8_t *)data;
intmoduleTxBufferRemaining = size;
USART_ITConfig(INTMODULE_USART, USART_IT_TXE, ENABLE);
#endif
stm32_usart_send_buffer(&intmoduleUSART, data, size);
}
void intmoduleWaitForTxCompleted()
void intmoduleWaitForTxCompleted(void* ctx)
{
#if !defined(SIMU)
(void)ctx;
#if defined(INTMODULE_DMA_STREAM)
if (DMA_GetCmdStatus(INTMODULE_DMA_STREAM) == ENABLE) {
while(DMA_GetFlagStatus(INTMODULE_DMA_STREAM, INTMODULE_DMA_FLAG_TC) == RESET);
DMA_ClearFlag(INTMODULE_DMA_STREAM, INTMODULE_DMA_FLAG_TC);
}
stm32_usart_wait_for_tx_dma(&intmoduleUSART);
#else
while (intmoduleTxBufferRemaining > 0);
#endif
#endif
}
const etx_serial_driver_t IntmoduleSerialDriver = {
.init = intmoduleSerialStart,
.deinit = intmoduleStop,
.sendByte = intmoduleSendByte,
.sendBuffer = intmoduleSendBuffer,
.waitForTxCompleted = intmoduleWaitForTxCompleted,
.getByte = nullptr,
.getBaudrate = nullptr,
.setReceiveCb = nullptr,
.setBaudrateCb = nullptr,
};
@@ -22,22 +22,12 @@
#pragma once
#include <stdint.h>
#include "hal/serial_driver.h"
struct etx_serial_init {
uint32_t baudrate;
uint16_t parity;
uint16_t stop_bits;
uint16_t word_length;
bool rx_enable;
void (*on_receive)(uint8_t data);
void (*on_error)();
#define INTMODULE_USART_IRQ_PRIORITY 6
etx_serial_init();
};
// Callbacks using intmoduleFifo
void intmoduleFifoReceive(uint8_t data);
void intmoduleFifoError();
void intmoduleSerialStart(const etx_serial_init* params);
void intmoduleSerialStop();
void intmoduleSendByte(uint8_t byte);
void intmoduleSendBuffer(const uint8_t* data, uint8_t size);
void intmoduleWaitForTxCompleted();
extern const etx_serial_driver_t IntmoduleSerialDriver;

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