chore(dsmp): separate DSMP and DSM2, cleanup code, add DSMP status display and Enable AETR option (#6932)

Co-authored-by: Peter Feerick <peter.feerick@gmail.com>
This commit is contained in:
Peter Feerick
2026-01-21 09:01:49 +10:00
parent 35f943e3f5
commit a7f2e619ca
69 changed files with 1056 additions and 360 deletions
@@ -259,6 +259,7 @@ Node convert<ModuleData>::encode(const ModuleData& rhs)
case PULSES_LEMON_DSMP: {
Node dsmp;
dsmp["flags"] = rhs.dsmp.flags;
dsmp["enableAETR"] = (int)rhs.dsmp.enableAETR;
mod["dsmp"] = dsmp;
} break;
case PULSES_FLYSKY_AFHDS2A: {
@@ -419,6 +420,7 @@ bool convert<ModuleData>::decode(const Node& node, ModuleData& rhs)
} else if (mod["dsmp"]) {
Node dsmp = mod["dsmp"];
dsmp["flags"] >> rhs.dsmp.flags;
dsmp["enableAETR"] >> rhs.dsmp.enableAETR;
} else if (mod["flysky"]) {
Node flysky = mod["flysky"];
for (int i = 0; i < 4; i++) {
+1
View File
@@ -213,6 +213,7 @@ class ModuleData {
struct DSMP {
unsigned int flags;
bool enableAETR;
} dsmp;
void clear();
+16 -2
View File
@@ -54,6 +54,7 @@
#define MASK_AFHDS (1<<22)
#define MASK_CSRF_ARMING_MODE (1<<23)
#define MASK_CSRF_ARMING_TRIGGER (1<<24)
#define MASK_ENABLE_AETR (1<<25)
quint8 ModulePanel::failsafesValueDisplayType = ModulePanel::FAILSAFE_DISPLAY_PERCENT;
@@ -409,7 +410,7 @@ void ModulePanel::update()
mask |= MASK_CHANNELS_RANGE| MASK_CHANNELS_COUNT | MASK_FAILSAFES | MASK_AFHDS;
break;
case PULSES_LEMON_DSMP:
mask |= MASK_CHANNELS_RANGE;
mask |= MASK_CHANNELS_RANGE | MASK_ENABLE_AETR;
break;
default:
break;
@@ -448,6 +449,8 @@ void ModulePanel::update()
ui->channelsCount->setMaximum(module.getMaxChannelCount());
ui->channelsCount->setValue(module.channelsCount);
ui->channelsCount->setSingleStep(firmware->getCapability(HasPPMStart) ? 1 : 2);
// CRSF
ui->label_crsfArmingMode->setVisible(mask & MASK_CSRF_ARMING_MODE);
ui->crsfArmingMode->setVisible(mask & MASK_CSRF_ARMING_MODE);
ui->crsfArmingTrigger->setVisible(mask & MASK_CSRF_ARMING_TRIGGER);
@@ -611,6 +614,12 @@ void ModulePanel::update()
ui->raw12bits->setChecked(module.ghost.raw12bits);
}
// DSMP settings fields
ui->enableAETR->setVisible(mask & MASK_ENABLE_AETR);
if (mask & MASK_ENABLE_AETR) {
ui->enableAETR->setChecked(module.dsmp.enableAETR);
}
if (mask & MASK_ACCESS) {
ui->rx1->setText(module.access.receiverName[0]);
ui->rx2->setText(module.access.receiverName[1]);
@@ -632,7 +641,7 @@ void ModulePanel::update()
ui->clearRx3->setVisible((mask & MASK_ACCESS) && (module.access.receivers & (1 << 2)));
ui->rx3->setVisible((mask & MASK_ACCESS) && (module.access.receivers & (1 << 2)));
// AFHFS
// AFHDS2A / AFHDS3
if (mask & MASK_AFHDS) {
if (protocol == PULSES_FLYSKY_AFHDS2A) {
ui->label_afhds->setText(tr("Options"));
@@ -915,6 +924,11 @@ void ModulePanel::on_raw12bits_stateChanged(int state)
module.ghost.raw12bits = (state == Qt::Checked);
}
void ModulePanel::on_enableAETR_stateChanged(int state)
{
module.dsmp.enableAETR = (state == Qt::Checked);
}
void ModulePanel::on_racingMode_stateChanged(int state)
{
module.access.racingMode = (state == Qt::Checked);
+1
View File
@@ -70,6 +70,7 @@ class ModulePanel : public ModelPanel
void on_autoBind_stateChanged(int state);
void on_disableChMap_stateChanged(int state);
void on_raw12bits_stateChanged(int state);
void on_enableAETR_stateChanged(int state);
void on_racingMode_stateChanged(int state);
void on_disableTelem_stateChanged(int state);
void on_lowPower_stateChanged(int state);
+10 -3
View File
@@ -399,7 +399,7 @@
</property>
</widget>
</item>
<item row="16" column="0" colspan="2">
<item row="17" column="0" colspan="2">
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
@@ -429,14 +429,14 @@
</item>
</layout>
</item>
<item row="15" column="0">
<item row="16" column="0">
<widget class="QLabel" name="label_crsfArmingMode">
<property name="text">
<string>Arm using</string>
</property>
</widget>
</item>
<item row="15" column="1">
<item row="16" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_crsfarm">
<item>
<widget class="QComboBox" name="crsfArmingMode"/>
@@ -446,6 +446,13 @@
</item>
</layout>
</item>
<item row="15" column="1">
<widget class="QCheckBox" name="enableAETR">
<property name="text">
<string>Enable AETR</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="1">
+3
View File
@@ -234,6 +234,9 @@ QString ModelPrinter::printModule(int idx)
if (module.protocol == PULSES_GHOST) {
str << printLabelValue(tr("Raw 12 bits"), printBoolean(module.ghost.raw12bits, BOOLEAN_YN));
}
if (module.protocol == PULSES_LEMON_DSMP) {
str << printLabelValue(tr("Enable AETR"), printBoolean(module.dsmp.enableAETR, BOOLEAN_YN));
}
if (module.protocol == PULSES_CROSSFIRE) {
str << printLabelValue(tr("Arming mode"), module.crsfArmingModeToString());
if (module.crsf.crsfArmingMode == ModuleData::CRSF_ARMING_MODE_SWITCH) {
+1
View File
@@ -575,6 +575,7 @@ PACK(struct ModuleData {
}) crsf);
NOBACKUP(struct {
uint8_t flags;
uint8_t enableAETR : 1;
} dsmp);
} NAME(mod) FUNC(select_mod_type);
+27 -10
View File
@@ -194,6 +194,10 @@ enum MenuModelSetupItems {
ITEM_MODEL_SETUP_EXTERNAL_MODULE_AFHDS3_MODE,
ITEM_MODEL_SETUP_EXTERNAL_MODULE_AFHDS3_STATUS,
ITEM_MODEL_SETUP_EXTERNAL_MODULE_AFHDS3_POWER_STATUS,
#endif
#if defined(DSMP)
ITEM_MODEL_SETUP_EXTERNAL_MODULE_DSMP_STATUS,
ITEM_MODEL_SETUP_EXTERNAL_MODULE_DSMP_ENABLE_AETR,
#endif
ITEM_MODEL_SETUP_EXTERNAL_MODULE_CHANNELS,
ITEM_MODEL_SETUP_EXTERNAL_MODULE_NOT_ACCESS_RXNUM_BIND_RANGE,
@@ -542,6 +546,7 @@ void editTimerCountdown(int timerIdx, coord_t y, LcdFlags attr, event_t event)
MULTIMODULE_STATUS_ROWS(EXTERNAL_MODULE) \
AFHDS3_PROTOCOL_ROW(EXTERNAL_MODULE) \
AFHDS3_MODE_ROWS(EXTERNAL_MODULE) \
DSMP_STATUS_ROWS(EXTERNAL_MODULE) \
MODULE_CHANNELS_ROWS(EXTERNAL_MODULE), \
IF_NOT_ACCESS_MODULE_RF(EXTERNAL_MODULE, MODULE_BIND_ROWS(EXTERNAL_MODULE)), /* line reused for PPM: PPM settings */ \
IF_ACCESS_MODULE_RF(EXTERNAL_MODULE, 0), /* RxNum */ \
@@ -2125,12 +2130,13 @@ void menuModelSetup(event_t event)
}
}
#endif
if (isModuleDSMP(moduleIdx) &&
(oldFlag != newFlag) &&
#if defined(DSMP)
if (isModuleDSMP(moduleIdx) && (oldFlag != newFlag) &&
(oldFlag == MODULE_MODE_BIND)) {
// Restart DSMP module when exiting bind mode
restartModule(moduleIdx);
}
#endif
}
}
break;
@@ -2435,12 +2441,31 @@ void menuModelSetup(event_t event)
#if defined(HARDWARE_EXTERNAL_MODULE)
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_STATUS:
#endif
#endif
#if defined(AFHDS3) && defined(HARDWARE_EXTERNAL_MODULE)
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_AFHDS3_STATUS:
#endif
#if (defined(MULTIMODULE) | defined(DSMP) | defined(AFHDS3)) && defined(HARDWARE_EXTERNAL_MODULE)
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_DSMP_STATUS:
{
// MultiModule & LemonDSMP & AFHDS3 Status
lcdDrawTextIndented(y, STR_MODULE_STATUS);
getModuleStatusString(moduleIdx, reusableBuffer.moduleSetup.msg);
lcdDrawText(MODEL_SETUP_2ND_COLUMN, y, reusableBuffer.moduleSetup.msg);
break;
}
#endif
#if defined(DSMP) && defined(HARDWARE_EXTERNAL_MODULE)
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_DSMP_ENABLE_AETR:
g_model.moduleData[EXTERNAL_MODULE].dsmp.enableAETR =
editCheckBox(g_model.moduleData[EXTERNAL_MODULE].dsmp.enableAETR,
MODEL_SETUP_2ND_COLUMN, y, STR_DSMP_ENABLE_AETR, attr,
event, INDENT_WIDTH);
break;
#endif
#if defined(MULTIMODULE)
#if defined(HARDWARE_INTERNAL_MODULE)
case ITEM_MODEL_SETUP_INTERNAL_MODULE_SYNCSTATUS:
#endif
@@ -2456,14 +2481,6 @@ void menuModelSetup(event_t event)
#endif
#if defined(AFHDS3) && defined(HARDWARE_EXTERNAL_MODULE)
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_AFHDS3_STATUS: {
lcdDrawTextIndented(y, STR_MODULE_STATUS);
char statusText[64];
getModuleStatusString(moduleIdx, statusText);
lcdDrawText(MODEL_SETUP_2ND_COLUMN, y, statusText);
break;
}
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_AFHDS3_POWER_STATUS: {
lcdDrawTextIndented(y, STR_AFHDS3_POWER_SOURCE);
char statusText[64];
+30 -10
View File
@@ -139,6 +139,10 @@ enum MenuModelSetupItems {
ITEM_MODEL_SETUP_EXTERNAL_MODULE_AFHDS3_MODE,
ITEM_MODEL_SETUP_EXTERNAL_MODULE_AFHDS3_STATUS,
ITEM_MODEL_SETUP_EXTERNAL_MODULE_AFHDS3_POWER_STATUS,
#endif
#if defined(DSMP)
ITEM_MODEL_SETUP_EXTERNAL_MODULE_DSMP_STATUS,
ITEM_MODEL_SETUP_EXTERNAL_MODULE_DSMP_ENABLE_AETR,
#endif
ITEM_MODEL_SETUP_EXTERNAL_MODULE_CHANNELS,
ITEM_MODEL_SETUP_EXTERNAL_MODULE_NOT_ACCESS_RXNUM_BIND_RANGE,
@@ -561,6 +565,7 @@ void menuModelSetup(event_t event)
MULTIMODULE_TYPE_ROW(EXTERNAL_MODULE) // ITEM_MODEL_SETUP_EXTERNAL_MODULE_PROTOCOL
MULTIMODULE_DSM_CLONED_RAW(EXTERNAL_MODULE), // ITEM_MODEL_SETUP_EXTERNAL_MODULE_DSM_CLONED
MULTIMODULE_STATUS_ROWS(EXTERNAL_MODULE) // ITEM_MODEL_SETUP_EXTERNAL_MODULE_STATUS + ITEM_MODEL_SETUP_EXTERNAL_MODULE_SYNCSTATUS
DSMP_STATUS_ROWS(EXTERNAL_MODULE) // ITEM_MODEL_SETUP_EXTERNAL_MODULE_DSMP_STATUS
AFHDS3_MODE_ROWS(EXTERNAL_MODULE) // ITEM_MODEL_SETUP_EXTERNAL_MODULE_AFHDS3_MODE + ITEM_MODEL_SETUP_EXTERNAL_MODULE_AFHDS3_STATUS + ITEM_MODEL_SETUP_EXTERNAL_MODULE_AFHDS3_POWER_STATUS
MODULE_CHANNELS_ROWS(EXTERNAL_MODULE), // ITEM_MODEL_SETUP_EXTERNAL_MODULE_CHANNELS
IF_NOT_ACCESS_MODULE_RF(EXTERNAL_MODULE, MODULE_BIND_ROWS(EXTERNAL_MODULE)), // ITEM_MODEL_SETUP_EXTERNAL_MODULE_NOT_ACCESS_RXNUM_BIND_RANGE
@@ -1619,12 +1624,13 @@ void menuModelSetup(event_t event)
}
}
#endif
if (isModuleDSMP(moduleIdx) &&
(oldFlag != newFlag) &&
#if defined(DSMP)
if (isModuleDSMP(moduleIdx) && (oldFlag != newFlag) &&
(oldFlag == MODULE_MODE_BIND)) {
// Restart DSMP module when exiting bind mode
restartModule(moduleIdx);
}
#endif
}
}
break;
@@ -1834,11 +1840,33 @@ void menuModelSetup(event_t event)
#if defined (MULTIMODULE)
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_STATUS:
#endif
#if defined(AFHDS3)
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_AFHDS3_STATUS:
#endif
#if defined(DSMP)
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_DSMP_STATUS:
#endif
#if (defined(DSMP) || defined(MULTIMODULE) || defined(AFHDS3))
{
// MultiModule & LemonDSMP & AFHDS Status
lcdDrawTextIndented(y, STR_MODULE_STATUS);
getModuleStatusString(EXTERNAL_MODULE, reusableBuffer.moduleSetup.msg);
lcdDrawText(MODEL_SETUP_2ND_COLUMN, y, reusableBuffer.moduleSetup.msg);
break;
}
#endif
#if defined(DSMP)
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_DSMP_ENABLE_AETR:
g_model.moduleData[EXTERNAL_MODULE].dsmp.enableAETR =
editCheckBox(g_model.moduleData[EXTERNAL_MODULE].dsmp.enableAETR,
MODEL_SETUP_2ND_COLUMN, y, STR_DSMP_ENABLE_AETR, attr,
event, INDENT_WIDTH);
break;
#endif
#if defined(MULTIMODULE) && defined(HARDWARE_EXTERNAL_MODULE)
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_SYNCSTATUS:
lcdDrawTextIndented(y, STR_MODULE_SYNC);
getModuleSyncStatusString(EXTERNAL_MODULE, reusableBuffer.moduleSetup.msg);
@@ -1852,14 +1880,6 @@ void menuModelSetup(event_t event)
lcdDrawText(MODEL_SETUP_2ND_COLUMN, y,
g_model.moduleData[EXTERNAL_MODULE].afhds3.telemetry ? STR_AFHDS3_ONE_TO_ONE_TELEMETRY : TR_AFHDS3_ONE_TO_MANY);
break;
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_AFHDS3_STATUS:
{
lcdDrawTextIndented(y, TR_MODULE_STATUS);
char statusText[64];
getModuleStatusString(EXTERNAL_MODULE, statusText);
lcdDrawText(MODEL_SETUP_2ND_COLUMN, y, statusText);
break;
}
case ITEM_MODEL_SETUP_EXTERNAL_MODULE_AFHDS3_POWER_STATUS:
{
lcdDrawTextIndented(y, STR_AFHDS3_POWER_SOURCE);
+4
View File
@@ -109,6 +109,10 @@ macro(add_gui_src src)
)
endmacro(add_gui_src)
if(DSMP)
add_gui_src(module/dsmp_settings.cpp)
endif()
if(LUA)
add_gui_src(standalone_lua.cpp)
set(SRC ${SRC}
@@ -118,6 +118,13 @@ void ModuleChannelRange::update()
{
ChannelRange::update();
#if defined(DSMP)
if (isModuleDSMP(moduleIdx)) {
// Disable Ch start, module asume starting in Ch1
chStart->enable(false);
}
#endif
auto min_mod_ch = minModuleChannels(moduleIdx);
auto max_mod_ch = maxModuleChannels(moduleIdx);
chEnd->enable(min_mod_ch < max_mod_ch);
@@ -0,0 +1,79 @@
/*
* 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 "dsmp_settings.h"
#include "choice.h"
#include "edgetx.h"
#define SET_DIRTY() storageDirty(EE_MODEL)
struct DSMPEnableAETR : public FormLine {
DSMPEnableAETR(Window* form, FlexGridLayout& layout, uint8_t moduleIdx) :
FormLine(form, layout)
{
new StaticText(this, rect_t{}, STR_DSMP_ENABLE_AETR);
auto md = &g_model.moduleData[moduleIdx];
cb = new ToggleSwitch(this, rect_t{}, GET_SET_DEFAULT(md->dsmp.enableAETR));
}
void update()
{
show();
cb->update();
}
private:
ToggleSwitch* cb;
};
DSMPSettings::DSMPSettings(Window* parent,
const FlexGridLayout& g,
uint8_t moduleIdx) :
Window(parent, rect_t{}),
md(&g_model.moduleData[moduleIdx]),
moduleIdx(moduleIdx)
{
FlexGridLayout grid(g);
setFlexLayout();
// DSMP status
auto line = newLine(grid);
new StaticText(line, rect_t{}, STR_MODULE_STATUS);
new DynamicText(
line, rect_t{},
[=] {
char msg[64] = "";
getModuleStatusString(moduleIdx, msg);
return std::string(msg);
});
enableAETR_line = new DSMPEnableAETR(this, grid, moduleIdx);
// Ensure elements properly initalised
update();
}
void DSMPSettings::update() {
enableAETR_line->update();
}
@@ -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 "window.h"
#include "module_setup.h"
class ToggleSwitch;
struct ModuleData;
struct DSMPEnableAETR;
class DSMPSettings : public Window, public ModuleOptions
{
ModuleData* md;
uint8_t moduleIdx;
DSMPEnableAETR *enableAETR_line;
public:
DSMPSettings(Window* parent, const FlexGridLayout& g,
uint8_t moduleIdx);
void update() override;
};
@@ -65,6 +65,10 @@
#include "multi_rfprotos.h"
#endif
#if defined(DSMP)
#include "dsmp_settings.h"
#endif
#define SET_DIRTY() storageDirty(EE_MODEL)
#define ETX_STATE_UNIQUE_ID_WARN LV_STATE_USER_1
@@ -163,6 +167,11 @@ class ModuleWindow : public Window
modOpts = new PXX1AntennaSettings(this, grid, moduleIdx);
}
#endif
#if defined(DSMP)
else if (isModuleDSMP(moduleIdx)) {
modOpts = new DSMPSettings(this, grid, moduleIdx);
}
#endif
// Channel Range
auto line = newLine(grid);
@@ -152,10 +152,10 @@ if (event == EVT_ENTRY) {
y += FH;
continue;
}
#if defined(MULTIMODULE)
if (isModuleMultimodule(module)) {
#if defined(MULTIMODULE) || defined(DSMP)
if (isModuleMultimodule(module) || isModuleDSMP(module)) {
char statusText[64] = "";
getMultiModuleStatus(module).getStatusString(statusText);
getModuleStatusString(module,statusText);
lcdDrawText(COLUMN2_X, y, statusText);
y += FH;
continue;
+6
View File
@@ -218,6 +218,12 @@ extern uint8_t MULTIMODULE_HASOPTIONS(uint8_t moduleIdx);
#define AFHDS3_MODULE_ROWS(moduleIdx)
#endif
#if defined(DSMP)
#define DSMP_STATUS_ROWS(moduleIdx) isModuleDSMP(moduleIdx) ? TITLE_ROW : HIDDEN_ROW, isModuleDSMP(moduleIdx) ? (uint8_t) 0 : HIDDEN_ROW,
#else
#define DSMP_STATUS_ROWS(moduleIdx)
#endif
#define FAILSAFE_ROW(moduleIdx) isModuleFailsafeAvailable(moduleIdx) ? (g_model.moduleData[moduleIdx].failsafeMode==FAILSAFE_CUSTOM ? (uint8_t)1 : (uint8_t)0) : HIDDEN_ROW
extern uint8_t MODULE_OPTION_ROW(uint8_t moduleIdx);
+19
View File
@@ -38,6 +38,10 @@
#include "pulses/multi.h"
#endif
#if defined(DSMP)
#include "pulses/dsmp.h"
#endif
/*luadoc
@function model.getInfo()
@@ -138,6 +142,9 @@ Get RF module parameters
* 12 R9M_LITE_PRO_PXX2
* 13 SBUS
* 14 XJT_LITE_PXX2
* 15 MODULE_TYPE_FLYSKY_AFHDS3,
* 16 ??
* 17 MODULE_TYPE_LEMON_DSMP
`subType` values for XJT_PXX1:
* -1 OFF
@@ -159,6 +166,8 @@ Get RF module parameters
* `protocol` (number) protocol number (Multi only)
* `subProtocol` (number) sub-protocol number (Multi only)
* `channelsOrder` (number) first 4 channels expected order (Multi only)
* if the module type is LemonDSMP additional info is available
* `channelsOrder` (number) first 4 channels expected order (DSMP only)
@status current Introduced in 2.2.0
*/
@@ -189,6 +198,16 @@ static int luaModelGetModule(lua_State *L)
lua_pushtableinteger(L, "channelsOrder", -1);
}
}
#endif
#if defined(DSMP)
if (module.type == MODULE_TYPE_LEMON_DSMP) {
auto& status = getDSMPStatus(idx);
int ch_order = -1;
if (status.isValid() && status.ch_order != 0xFF) {
ch_order = status.ch_order;
}
lua_pushtableinteger(L, "channelsOrder", ch_order);
}
#endif
}
else {
+46 -183
View File
@@ -24,7 +24,6 @@
#include "mixer_scheduler.h"
#include "edgetx.h"
#include "telemetry/spektrum.h"
#define DSM2_SEND_BIND (1 << 7)
#define DSM2_SEND_RANGECHECK (1 << 5)
@@ -41,11 +40,48 @@
static bool _bind_restart = false;
static inline void sendByte(uint8_t*& p_buf, uint8_t b)
const etx_serial_init dsmUartParams = {
.baudrate = 0,
.encoding = ETX_Encoding_8N1,
.direction = ETX_Dir_TX,
.polarity = ETX_Pol_Inverted,
};
etx_module_state_t* dsmInit(uint8_t module, uint32_t baudrate,
uint16_t period, bool telemetry)
{
*p_buf++ = b;
// only external module supported
if (module == INTERNAL_MODULE) return nullptr;
etx_serial_init params(dsmUartParams);
params.baudrate = baudrate;
auto mod_st = modulePortInitSerial(module, ETX_MOD_PORT_UART, &params, true);
if (!mod_st) return nullptr;
if (telemetry) {
params.direction = ETX_Dir_RX;
modulePortInitSerial(module, ETX_MOD_PORT_SPORT, &params, true);
}
mixerSchedulerSetPeriod(module, period);
return mod_st;
}
void dsmDeInit(void* ctx)
{
auto mod_st = (etx_module_state_t*)ctx;
modulePortDeInit(mod_st);
}
static void* dsm2Init(uint8_t module)
{
auto mod_st = dsmInit(module, DSM2_BITRATE, DSM2_PERIOD, false);
mod_st->user_data = (void*)(uintptr_t)g_model.moduleData[module].subType;
return (void*)mod_st;
}
static inline void sendByte(uint8_t*& p_buf, uint8_t b) { *p_buf++ = b; }
static void setupPulsesDSM2(uint8_t module, uint8_t type, uint8_t*& p_buf)
{
uint8_t dsmDat[DSM2_FRAME_SIZE];
@@ -99,160 +135,20 @@ static void setupPulsesDSM2(uint8_t module, uint8_t type, uint8_t*& p_buf)
}
}
#define DSMP_BITRATE 115200
static void setupPulsesLemonDSMP(uint8_t module, uint8_t*& p_buf)
static void dsm2SendPulses(void* ctx, uint8_t* buffer, int16_t* channels,
uint8_t nChannels)
{
static uint8_t pass = 0;
const auto& md = g_model.moduleData[module];
uint8_t start_channel = md.channelsStart;
auto channels = md.getChannelsCount();
auto flags = md.dsmp.flags & 0x3F;
// Force setup packet in Bind mode.
auto module_mode = getModuleMode(module);
sendByte(p_buf, 0xAA);
sendByte(p_buf, pass);
// Setup packet
if (pass == 0) {
if (module_mode == MODULE_MODE_BIND) {
flags = DSM2_SEND_BIND | (1 << 6 /* AUTO */);
channels = 12;
}
sendByte(p_buf, flags);
uint8_t pwr = 7;
if (module_mode == MODULE_MODE_RANGECHECK) {
pwr = 4;
}
sendByte(p_buf, pwr);
sendByte(p_buf, channels );
// Model number
sendByte(p_buf, 1);
// Send only 1 single Setup packet
pass = 1;
} else {
uint8_t current_channel = 0;
if (pass == 2) {
current_channel += 7;
}
// Send channels
for (int i=0; i<7; i++) {
if (current_channel < channels) {
uint8_t channel = start_channel + current_channel;
int value = channelOutputs[channel] + 2*PPM_CH_CENTER(channel) - 2*PPM_CENTER;
uint16_t pulse;
// Use 11-bit ?
if (flags & (1 << 2)) {
pulse = limit(0, ((value*349)>>9)+1024, 2047) | (current_channel << 11);
} else {
pulse = limit(0, ((value*13)>>5)+512, 1023) | (current_channel << 10);
}
sendByte(p_buf, pulse >> 8);
sendByte(p_buf, pulse & 0xFF);
} else {
// Outside of announced number of channels:
// -> send invalid value
sendByte(p_buf, 0xFF);
sendByte(p_buf, 0xFF);
}
current_channel++;
}
}
if (++pass > 2) pass = 1;
if (channels < 8) pass = 1;
if (module_mode == MODULE_MODE_BIND) {
// bind packet is setup
pass = 0;
}
else if (--moduleState[module].counter == 0) {
// every 100th packet is setup
pass = 0;
moduleState[module].counter = 100;
}
}
const etx_serial_init dsmUartParams = {
.baudrate = 0,
.encoding = ETX_Encoding_8N1,
.direction = ETX_Dir_TX,
.polarity = ETX_Pol_Inverted,
};
static etx_module_state_t* dsmInit(uint8_t module, uint32_t baudrate,
uint16_t period, bool telemetry)
{
// only external module supported
if (module == INTERNAL_MODULE) return nullptr;
etx_serial_init params(dsmUartParams);
params.baudrate = baudrate;
auto mod_st = modulePortInitSerial(module, ETX_MOD_PORT_UART, &params, true);
if (!mod_st) return nullptr;
if (telemetry) {
params.direction = ETX_Dir_RX;
modulePortInitSerial(module, ETX_MOD_PORT_SPORT, &params, true);
}
mixerSchedulerSetPeriod(module, period);
return mod_st;
}
static void* dsm2Init(uint8_t module)
{
auto mod_st = dsmInit(module, DSM2_BITRATE, DSM2_PERIOD, false);
mod_st->user_data = (void*)(uintptr_t)g_model.moduleData[module].subType;
return (void*)mod_st;
}
static void* dsmpInit(uint8_t module)
{
return (void*)dsmInit(module, DSMP_BITRATE, 11 * 1000 /* 11ms in us */, true);
}
static void dsmDeInit(void* ctx)
{
auto mod_st = (etx_module_state_t*)ctx;
modulePortDeInit(mod_st);
}
static void _dsm_send(etx_module_state_t* st, uint8_t* buffer, uint32_t len)
{
auto drv = modulePortGetSerialDrv(st->tx);
auto ctx = modulePortGetCtx(st->tx);
drv->sendBuffer(ctx, buffer, len);
}
static void dsm2SendPulses(void* ctx, uint8_t* buffer, int16_t* channels, uint8_t nChannels)
{
// TODO:
(void)channels;
(void)nChannels;
auto mod_st = (etx_module_state_t*)ctx;
auto module = modulePortGetModule(mod_st);
auto drv = modulePortGetSerialDrv(mod_st->tx);
auto drvCtx = modulePortGetCtx(mod_st->tx);
auto type = (uint8_t)(uintptr_t)mod_st->user_data;
auto p_data = buffer;
setupPulsesDSM2(module, type, p_data);
_dsm_send(mod_st, buffer, p_data - buffer);
drv->sendBuffer(drvCtx, buffer, p_data - buffer);
}
static void dsm2ConfigChange(void* ctx)
@@ -267,28 +163,6 @@ static void dsm2ConfigChange(void* ctx)
}
}
static void dsmpSendPulses(void* ctx, uint8_t* buffer, int16_t* channels, uint8_t nChannels)
{
// TODO:
(void)channels;
(void)nChannels;
auto mod_st = (etx_module_state_t*)ctx;
auto module = modulePortGetModule(mod_st);
auto p_data = buffer;
setupPulsesLemonDSMP(module, p_data);
_dsm_send(mod_st, buffer, p_data - buffer);
}
static void dsmpProcessData(void* ctx, uint8_t data, uint8_t* buffer, uint8_t* len)
{
auto mod_st = (etx_module_state_t*)ctx;
auto module = modulePortGetModule(mod_st);
processSpektrumTelemetryData(module, data, buffer, *len);
}
// No telemetry
const etx_proto_driver_t DSM2Driver = {
.protocol = PROTOCOL_CHANNELS_DSM2,
@@ -299,15 +173,4 @@ const etx_proto_driver_t DSM2Driver = {
.processFrame = nullptr,
.onConfigChange = dsm2ConfigChange,
.txCompleted = modulePortSerialTxCompleted,
};
const etx_proto_driver_t DSMPDriver = {
.protocol = PROTOCOL_CHANNELS_DSMP,
.init = dsmpInit,
.deinit = dsmDeInit,
.sendPulses = dsmpSendPulses,
.processData = dsmpProcessData,
.processFrame = nullptr,
.onConfigChange = nullptr,
.txCompleted = modulePortSerialTxCompleted,
};
};
+6 -3
View File
@@ -21,10 +21,13 @@
#pragma once
#include "hal/module_port.h"
#include "hal/module_driver.h"
#include "timers_driver.h"
// DSM2/DSMX
extern const etx_proto_driver_t DSM2Driver;
// Lemon RX DSMP
extern const etx_proto_driver_t DSMPDriver;
extern etx_module_state_t* dsmInit(uint8_t module, uint32_t baudrate,
uint16_t period, bool telemetry);
extern void dsmDeInit(void* ctx);
extern const etx_proto_driver_t DSM2Driver;
+537
View File
@@ -0,0 +1,537 @@
/*
* 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 "dsmp.h"
#include "hal/module_port.h"
#include "mixer_scheduler.h"
#include "edgetx.h"
#include "telemetry/spektrum.h"
#define DSMP_SEND_X_PLUS 0
#define DSMP_BITRATE 115200
#define MAX_REG_CHANNELS 12
#define MAX_CHANNELS 20
// DSMP Flags
#define DSMP_FLAGS_DSMX 0x01
#define DSMP_FLAGS_DSM2 0x00
#define DSMP_FLAGS_11mS 0x02
#define DSMP_FLAGS_22mS 0x00
#define DSMP_FLAGS_2048 0x04 // 11 bits
#define DSMP_FLAGS_1024 0x00 // 10 bits
#define DSMP_FLAGS_FUTABA 0x10 // Translate to AETR -> TAER
// #define DSMP_FLAGS_DEVO 0x20
#define DSMP_FLAGS_AUTO 0x40
#define DSMP_FLAGS_BIND 0x80
#define DSMP_FLAGS_TXMODE (DSMP_FLAGS_DSMX | DSMP_FLAGS_11mS | DSMP_FLAGS_2048)
// DSMP Power Settings
#define DSMP_POWER_NORMAL 7
#define DSMP_POWER_RANGE 4
// Same Encoding as MultiModule (What channel is each of the functions)
// R | T | E | A
#define DSMP_CH_AETR ((3<<6)|(2<<4)|(1<<2)|0)
#define DSMP_CH_TAER ((3<<6)|(0<<4)|(2<<2)|1)
#define DSMP_NO_CHANNEL 0xFF
// MAP AETR->TAER:
static uint8_t AETR_TAER_MAP[] = {2, 0, 1};
static DSMPModuleStatus dsmpStatus = DSMPModuleStatus();
// Power cycle of the DSMP module
// The DSMP module code has the channel data initialized to 0 and initial number of bits as 10b (ch resolution 1024)
// The Setup message pass the last BIND configuration to the Module via the setup package (for example, 2048 it was bound to DSMX).
// Scenario 1: Setup package processed by DSMP before Ch data
// When the Setup package is received, will send the existing CH values (0), so servos will move to the side until valid
// Ch data is received.
// Scenario 2: Channel packed process by DSMP before Setup package
// In this case, it will assume that the Ch data is encoded in 10bits instead of 2048 (if DSMX), then the servos move to
// to extreme too.
//
// Both scenarios are not right, so initially send more frequently the Setup package (usualy every 2.2 sec), but will
// be sent every 2 messages (66ms). There is still jump, but for an instant.
// The only way to properly fix it is at the DSMP firmware level.. (fixed on DSMP V2).
#define FAST_INITIAL_SETUP_COUNT 50 // 3*22*50=3.3 sec of sending fast status after module activation
// Using 22.06ms instead of 22ms for V1 module.. This is becuase the module try to send 4 RF
// packets to the RX with with spacing 4/7/4/7 (22ms cycle) just after receiving
// the message from the TX (perfect world). But the timing is not perfect on the
// DSMP module, is really 4.025/7.033/4.025/6.x and the last will be cut too short
// to 6.88 by the new TX message (needs to be at least 6.92, up to 7.05). That
// can create problems in some RXs (Servos not moving smoth). Compensating for
// that little extra delay to make the last closer to 7ms spacing.
#define SCHEDULER_PERIOD_V1 22060
#define SCHEDULER_PERIOD_V2 11000
static uint8_t pass;
static uint8_t pass0_counter;
static uint8_t pass0_period;
static uint16_t fastSetup_count;
#if DSMP_SEND_X_PLUS
static uint8_t x_plus_ch = 0;
#endif
DSMPModuleStatus& getDSMPStatus(uint8_t module)
{
return dsmpStatus;
}
static void* dsmpInit(uint8_t module)
{
TRACE("[DSMP] dsmpInit()");
pass0_counter = 2; // Send Setup every 2 ch data packages
pass = 1; // Start Sending channels
pass0_period = 100; // Send pass0 every 100 messages
fastSetup_count = FAST_INITIAL_SETUP_COUNT;
return (void*)dsmInit(module, DSMP_BITRATE, SCHEDULER_PERIOD_V1, true);
}
static inline void sendByte(uint8_t*& p_buf, uint8_t b)
{
*p_buf++ = b;
}
#if defined(LUA)
static uint8_t isFPDataReady()
{
// Check for Forward Programming data
// Multi_Buffer[0..2]=="DSM" -> Lua script is running
// Multi_Buffer[3]==0x70 + len -> TX to RX data ready to be sent
// Multi_Buffer[4..9]=6 bytes of TX to RX data
return (Multi_Buffer && (Multi_Buffer[3] & 0xF8) == 0x70 &&
memcmp(Multi_Buffer, "DSM", 3) == 0);
}
static void sendFPLemonDSMP(uint8_t*& p_buf)
{
auto forwardProgLen = Multi_Buffer[3] & 0x0F;
TRACE("LemonDSMP: DSMP FwdProg Send data len = [%d]", forwardProgLen);
// Send Forward Prog Data (Includes Len + 6 bytes).. 9 bytes totat
sendByte(p_buf, 0xAA);
sendByte(p_buf, 3); // Pass=3
for (uint8_t i = 0; i < 7; i++) {
sendByte(p_buf, Multi_Buffer[3 + i]);
}
Multi_Buffer[3] = 0x00; // Data sent, clear LUA to send more
}
#endif
static void updateModuleStatus(uint8_t flags)
{
// Update Status
dsmpStatus.lastUpdate = get_tmr10ms();
dsmpStatus.flags = flags;
dsmpStatus.ch_order = (flags & DSMP_FLAGS_FUTABA) ? DSMP_CH_AETR : DSMP_CH_TAER;
}
static uint16_t getDSMPChannelValue(uint8_t module, uint8_t flags, uint8_t channel)
{
uint8_t txChannel = channel;
// Map from AETR->TAER ???
if ((flags & DSMP_FLAGS_FUTABA) && (channel < 3)) {
txChannel = AETR_TAER_MAP[channel];
}
int value = channelOutputs[txChannel] + 2 * PPM_CH_CENTER(txChannel) - 2 * PPM_CENTER;
uint16_t pulse;
if (flags & DSMP_FLAGS_2048) { // Use 11-bit ?
// Scale to 349/512=0.681, MultiModule is about 0.667
pulse = limit(0, ((value * 349) >> 9) + 1024, 2047) | (channel << 11);
} else {
pulse = limit(0, ((value * 13) >> 5) + 512, 1023) | (channel << 10);
}
return pulse;
}
static void setupPulsesLemonDSMP(uint8_t module, uint8_t*& p_buf)
{
const auto modelId = g_model.header.modelId[module];
/* const*/ auto& md = g_model.moduleData[module];
//uint8_t start_channel = md.channelsStart;
auto channels = md.getChannelsCount();
auto flags = md.dsmp.flags;
auto module_mode = getModuleMode(module);
auto version = dsmpStatus.version[0];
if (md.dsmp.enableAETR) { // Move GUI settings to flags
flags |= DSMP_FLAGS_FUTABA;
}
if (pass0_counter == pass0_period/2) {
// update status String.. about each second
updateModuleStatus(flags);
}
#if defined(LUA)
if ((version> 1) && isFPDataReady()) { // Sent any forward prog data??
sendFPLemonDSMP(p_buf);
Multi_Buffer[3] = 0x00; // Data sent, clear LUA to send more
return;
}
#endif
// Send channel data
sendByte(p_buf, 0xAA);
sendByte(p_buf, pass);
// Setup packet
if (pass == 0) {
flags &= DSMP_FLAGS_TXMODE; // Only the TXMODE part
if (module_mode == MODULE_MODE_BIND) {
flags = DSMP_FLAGS_BIND | DSMP_FLAGS_AUTO;
channels = min<uint8_t>(channels, MAX_REG_CHANNELS);
md.dsmp.flags = DSMP_FLAGS_DSMX | DSMP_FLAGS_11mS | DSMP_FLAGS_2048;
storageDirty(EE_MODEL);
}
sendByte(p_buf, flags);
uint8_t pwr = DSMP_POWER_NORMAL;
if (module_mode == MODULE_MODE_RANGECHECK) {
pwr = DSMP_POWER_RANGE;
}
sendByte(p_buf, pwr);
sendByte(p_buf, channels );
sendByte(p_buf, modelId); // V1.0 ignores it, V2.0 use it
pass = 1; // move to send Ch data
return;
} else {
#if DSMP_SEND_X_PLUS
uint8_t xPlusEnabled = (version > 1) && (channels >= MAX_REG_CHANNELS) && (flags & DSMP_FLAGS_DSMX);
#endif
// Channel DATA messages
uint8_t current_channel = 0;
if (pass == 2) {
current_channel += 7;
}
// Send channels
for (int i=0; i<7; i++) {
uint16_t pulse = 0xFFFF; // NO-DATA
uint8_t ch_to_send = DSMP_NO_CHANNEL;
if (current_channel < min<uint8_t>(channels,MAX_REG_CHANNELS)) {
ch_to_send = current_channel;
}
#if DSMP_SEND_X_PLUS
else if (xPlusEnabled && (current_channel >= MAX_REG_CHANNELS)) {
// X-plus channel multiplexing (Ch13-20)
ch_to_send = MAX_REG_CHANNELS + x_plus_ch;
x_plus_ch = (x_plus_ch + 1) % 8; // 8 X-plus channels
}
#endif
if (ch_to_send != DSMP_NO_CHANNEL) {
pulse = getDSMPChannelValue(module, flags, ch_to_send);
}
sendByte(p_buf, pulse >> 8);
sendByte(p_buf, pulse & 0xFF);
current_channel++;
} // For
}
if (++pass > 2) pass = 1;
if (channels < 8) pass = 1;
if (module_mode == MODULE_MODE_BIND) { // Force setup packet in Bind mode.
pass = 0;
} else if (--pass0_counter == 0) {
pass = 0;
updateModuleStatus(flags);
if ((version == 1) && (fastSetup_count > 0)) {
fastSetup_count--;
pass0_counter = 2; // Keep sendint setup every 2 ch messages
} else {
pass0_counter = pass0_period; // restar counter
}
}
}
static void dsmpSendPulses(void* ctx, uint8_t* buffer, int16_t* channels, uint8_t nChannels)
{
auto mod_st = (etx_module_state_t*)ctx;
auto module = modulePortGetModule(mod_st);
auto drv = modulePortGetSerialDrv(mod_st->tx);
auto drvCtx = modulePortGetCtx(mod_st->tx);
auto p_data = buffer;
setupPulsesLemonDSMP(module, p_data);
drv->sendBuffer(drvCtx, buffer, p_data - buffer);
}
/* The DSMP Bind Return Message contains:
Byte
0 Flags:
Protocol: Maxk 0x01 0=DSM2, 1=DSMX
RefreshCycle: Mask 0x02 0=22ms, 1=11ms
Resolution: Mask 0x04 0=1024, 1=2048
Bind: Mask 0x80 1=Enter Bind Mode (Output only)
Bind_Auto: Mask 0x40 1=Use AutoBind (Output only)
1 ?? Always 0x00; ?? RX type maybe
2 Number of Channels (Up to 12)
3 TX Mode:
0x01 - DSM2 1024/22ms,
0x02 - DSM2 1024/22ms >7 channels,
0x11 - DSM2 2048/11ms
0x12 - DSM2 2048/11ms >7 channels,
0xa2 - DSMX 22ms > 7 channels,
0xb2 - DSMX 11ms
*/
static void processDSMPBindPacket(uint8_t module, uint8_t* packet)
{
uint8_t flags = packet[0];
uint8_t rxType = packet[1];
uint8_t channels = packet[2];
uint8_t txMode = packet[3];
// save flags, only the TXMode Part
g_model.moduleData[module].dsmp.flags = flags & DSMP_FLAGS_TXMODE;
// save number of channels
if (channels > MAX_REG_CHANNELS) {
channels = MAX_REG_CHANNELS;
}
g_model.moduleData[module].channelsCount = channels - 8;
if (dsmpStatus.version[0] == 1) { // V1.0 always use modelId=0
g_model.header.modelId[module] = 0;
}
TRACE("[DSMP] DSMP bind packet: flags:0x%X / Ch: %i / TxMode =0x%X", flags & 0x3F, channels, txMode);
storageDirty(EE_MODEL);
/* Finally stop binding as the rx just told us that it is bound */
if (getModuleMode(module) == MODULE_MODE_BIND) {
setModuleMode(module, MODULE_MODE_NORMAL);
}
// Convert DSMP bind to Spektrum compatible bind and continue with common Spektrum.cpp bind processing
uint8_t newPacket[10] = {0, 0, 0, 0, rxType, channels, txMode, 0, 0, 0};
processDSMBindPacket(newPacket);
// FARZU:.. The real problem was using module[moduleID].counter.. is actually used by the restart mechanism
restartModuleAsync(module, 10); // ~100ms
}
static void processDSMPManufacturerData(uint8_t module, uint8_t* packet)
{
// Format M,M,M,M, V, V where M is 4 byte manufacturer data, and V is 2 byte
dsmpStatus.version[0] = packet[4]; // Major
dsmpStatus.version[1] = packet[5]; // Minor
TRACE("LemonDSMP: Ver [%d.%d]", dsmpStatus.version[0], dsmpStatus.version[1]);
if (dsmpStatus.version[0] > 1 && mixerSchedulerGetPeriod(module) != SCHEDULER_PERIOD_V2) {
// V2 suppors 11ms
mixerSchedulerSetPeriod(module, SCHEDULER_PERIOD_V2);
pass0_period = 200; // extend period
}
}
static void dsmpTelemetryData(uint8_t module, uint8_t data,
uint8_t* rxBuffer, uint8_t& rxBufferCount)
{
dsmpStatus.lastUpdate = get_tmr10ms();
if (rxBuffer[1] == 0x80 && rxBufferCount >= DSM_BIND_PACKET_LENGTH) {
processDSMPBindPacket(module, rxBuffer + 2); // Skip 0xAA 0x80
rxBufferCount = 0;
return;
}
if (rxBuffer[1] == 0xFF && rxBufferCount >= SPEKTRUM_TELEMETRY_LENGTH) {
processDSMPManufacturerData(module, rxBuffer + 2); // Skip 0xAA 0xFF
rxBufferCount = 0;
return;
}
if (rxBufferCount >= SPEKTRUM_TELEMETRY_LENGTH) {
// Debug print content of Telemetry to console
#if 0
debugPrintf("[DSMP] Packet 0x%02X rssi 0x%02X: ic2 0x%02x, %02x: ",
rxBuffer[0], rxBuffer[1], rxBuffer[2], rxBuffer[3]);
for (int i=4; i<SPEKTRUM_TELEMETRY_LENGTH; i+=4) {
debugPrintf("%02X%02X %02X%02X ", rxBuffer[i], rxBuffer[i + 1],
rxBuffer[i + 2], rxBuffer[i + 3]);
}
debugPrintf(CRLF);
#endif
processSpektrumPacket(rxBuffer);
rxBufferCount = 0;
}
}
static void dsmpDebugData(uint8_t module, uint8_t data, uint8_t* rxBuffer,
uint8_t& rxBufferCount)
{
// Format is: 0xAB, <len> <type> <data>
if (rxBufferCount < 2) return; // Keep buiding
auto expectedLen = rxBuffer[1];
// Overflow???
if (expectedLen + 2 > TELEMETRY_RX_PACKET_SIZE) {
expectedLen = TELEMETRY_RX_PACKET_SIZE - 2;
}
if (rxBufferCount >= expectedLen + 2) {
// msg Completed
auto dataType = rxBuffer[2];
if (dataType == 1) { // Debug Msg
TRACE_NOCRLF("[DSMP] Debug: ");
for (auto i = 0; i < expectedLen - 1; i++) {
TRACE_NOCRLF("%c", rxBuffer[3 + i]);
}
TRACE(CRLF);
}
rxBufferCount = 0; // Build new message
}
}
static void dsmpProcessData(void* ctx, uint8_t data, uint8_t* buffer,
uint8_t* len)
{
auto mod_st = (etx_module_state_t*)ctx;
auto module = modulePortGetModule(mod_st);
uint8_t& rxBufferCount = *len;
if (rxBufferCount == 0 && (data != 0xAA && data != 0xAB)) {
TRACE("[DSMP] invalid start byte 0x%02X", data);
return;
}
if (rxBufferCount < TELEMETRY_RX_PACKET_SIZE) {
TRACE("[DSMP] Data 0x%02X, len = %d", data, rxBufferCount);
buffer[rxBufferCount++] = data; // Keep building message
} else {
TRACE("[DSMP] array size %d error", rxBufferCount);
rxBufferCount = 0;
}
if (buffer[0] == 0xAA) { // Telemetry data or Bind
dsmpTelemetryData(module, data, buffer, *len);
} else if (buffer[0] == 0xAB) { // Status
dsmpDebugData(module, data, buffer, *len);
}
}
void DSMPModuleStatus::getStatusString(char* statusText) const
{
if (!isValid()) {
strcpy(statusText, STR_MODULE_NO_TELEMETRY);
return;
}
const auto& md = g_model.moduleData[EXTERNAL_MODULE];
auto channels = md.getChannelsCount();
char* tmp = statusText;
// Version
*tmp = 0;
tmp = strAppend(tmp, "v", 1);
tmp = strAppendUnsigned(tmp, dsmpStatus.version[0]);
tmp = strAppend(tmp, ".", 1);
tmp = strAppendUnsigned(tmp, dsmpStatus.version[1]);
char b[] = "? ";
if (ch_order != 0xFF) { // Same encoding as MultiModule
uint8_t temp = ch_order;
b[temp & 0x03] = 'A';
temp >>= 2;
b[temp & 0x03] = 'E';
temp >>= 2;
b[temp & 0x03] = 'T';
temp >>= 2;
b[temp & 0x03] = 'R';
}
tmp = strAppend(tmp, " ", 1);
tmp = strAppend(tmp, b, strlen(b));
const char* mode;
mode = (flags & DSMP_FLAGS_DSMX) ? " X" : " 2"; // DSMX or DSM2
tmp = strAppend(tmp, mode, strlen(mode));
mode = (flags & DSMP_FLAGS_11mS) ? "_2F" : "_1F"; // 1 or 2 Frames (11ms/22ms)
tmp = strAppend(tmp, mode, strlen(mode));
#if 0
// Good for Debugging, but not much for regular users
//mode = (flags & DSMP_FLAGS_2048) ? " 2048" : " 1024";
//tmp = strAppend(tmp, mode, strlen(mode));
tmp = strAppend(tmp, " S:", 4);
uint16_t servoRefresh = (mixerSchedulerGetPeriod(EXTERNAL_MODULE) / 1000);
if (channels > 7) servoRefresh *= 2;
tmp = strAppendUnsigned(tmp, servoRefresh);
tmp = strAppend(tmp, "ms", 2);
servoRefresh = mixerSchedulerGetPeriod(EXTERNAL_MODULE);
tmp = strAppend(tmp, " TX:", 5);
tmp = strAppendUnsigned(tmp, servoRefresh);
tmp = strAppend(tmp, "us", 2);
#endif
}
const etx_proto_driver_t DSMPDriver = {
.protocol = PROTOCOL_CHANNELS_DSMP,
.init = dsmpInit,
.deinit = dsmDeInit,
.sendPulses = dsmpSendPulses,
.processData = dsmpProcessData,
.processFrame = nullptr,
.onConfigChange = nullptr,
.txCompleted = modulePortSerialTxCompleted,
};
+39
View File
@@ -0,0 +1,39 @@
/*
* 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 "dsm2.h"
struct DSMPModuleStatus {
uint8_t version[2] = {1, 0}; // Default Version 1.0
tmr10ms_t lastUpdate;
uint8_t ch_order = 0xFF;
uint8_t flags = 0;
inline bool isValid() const { return (bool)(get_tmr10ms() - lastUpdate < 500);}
void getStatusString(char *statusText) const;
};
extern DSMPModuleStatus &getDSMPStatus(uint8_t module);
// Lemon RX DSMP
extern const etx_proto_driver_t DSMPDriver;
+5 -3
View File
@@ -67,9 +67,8 @@ int8_t maxModuleChannels_M8(uint8_t moduleIdx)
}
} else if (isModuleMultimoduleDSM2(moduleIdx)) {
return 4; // 12 channels
} else if (isModuleDSMP(moduleIdx) &&
(g_model.moduleData[moduleIdx].dsmp.flags != 0)) {
return g_model.moduleData[moduleIdx].channelsCount;
} else if (isModuleDSMP(moduleIdx)) {
return 4; // 12 channels
} else {
return maxChannelsModules_M8[g_model.moduleData[moduleIdx].type];
}
@@ -129,6 +128,9 @@ void setModuleType(uint8_t moduleIdx, uint8_t moduleType)
}
else if (moduleData.type == MODULE_TYPE_FLYSKY_AFHDS3) {
resetAfhds3Options(moduleIdx);
}
else if (moduleData.type == MODULE_TYPE_LEMON_DSMP) {
restartModule(moduleIdx); // Restart DSMP when switching to it (example PPM->DSMP)
}
else
resetAccessAuthenticationCount();
+7 -1
View File
@@ -487,7 +487,7 @@ inline int8_t minModuleChannels(uint8_t idx)
else if (isModuleSBUS(idx))
return 16;
else if (isModuleDSMP(idx))
return maxModuleChannels(idx);
return 1; // FARZU: module assume always start with Ch1. Was: maxModuleChannels(idx);
else
return 1;
}
@@ -532,6 +532,9 @@ inline bool isModuleRxNumAvailable(uint8_t moduleIdx)
if (isModuleCrossfire(moduleIdx))
return true;
if (isModuleDSMP(moduleIdx))
return true;
return false;
}
@@ -557,6 +560,9 @@ inline bool isModuleModelIndexAvailable(uint8_t idx)
if (isModuleAFHDS3(idx))
return true;
if (isModuleDSMP(idx))
return true;
return false;
}
+13
View File
@@ -31,7 +31,14 @@
#include "pulses/pxx2.h"
#include "pulses/flysky.h"
#if defined(DSM2)
#include "pulses/dsm2.h"
#endif
#if defined(DSMP)
#include "pulses/dsmp.h"
#endif
#if defined(PPM)
#include "pulses/ppm.h"
@@ -228,6 +235,12 @@ void getModuleStatusString(uint8_t moduleIdx, char * statusText)
afhds3::getStatusString(moduleIdx, statusText);
}
#endif
#if defined(DSMP)
if (isModuleDSMP(moduleIdx)) {
getDSMPStatus(moduleIdx).getStatusString(statusText);
}
#endif
}
void getModuleSyncStatusString(uint8_t moduleIdx, char * statusText)
@@ -633,6 +633,7 @@ static const struct YamlNode struct_anonymous_12[] = {
};
static const struct YamlNode struct_anonymous_13[] = {
YAML_UNSIGNED( "flags", 8 ),
YAML_UNSIGNED( "enableAETR", 1 ),
YAML_END
};
static const struct YamlNode union_anonymous_4_elmts[] = {
@@ -646,7 +647,7 @@ static const struct YamlNode union_anonymous_4_elmts[] = {
YAML_STRUCT("afhds3", 16, struct_anonymous_10, NULL),
YAML_STRUCT("ghost", 8, struct_anonymous_11, NULL),
YAML_STRUCT("crsf", 24, struct_anonymous_12, NULL),
YAML_STRUCT("dsmp", 8, struct_anonymous_13, NULL),
YAML_STRUCT("dsmp", 16, struct_anonymous_13, NULL),
YAML_END
};
static const struct YamlNode struct_ModuleData[] = {
@@ -701,6 +701,7 @@ static const struct YamlNode struct_anonymous_12[] = {
};
static const struct YamlNode struct_anonymous_13[] = {
YAML_UNSIGNED( "flags", 8 ),
YAML_UNSIGNED( "enableAETR", 1 ),
YAML_END
};
static const struct YamlNode union_anonymous_4_elmts[] = {
@@ -714,7 +715,7 @@ static const struct YamlNode union_anonymous_4_elmts[] = {
YAML_STRUCT("afhds3", 16, struct_anonymous_10, NULL),
YAML_STRUCT("ghost", 8, struct_anonymous_11, NULL),
YAML_STRUCT("crsf", 24, struct_anonymous_12, NULL),
YAML_STRUCT("dsmp", 8, struct_anonymous_13, NULL),
YAML_STRUCT("dsmp", 16, struct_anonymous_13, NULL),
YAML_END
};
static const struct YamlNode struct_ModuleData[] = {
@@ -657,6 +657,7 @@ static const struct YamlNode struct_anonymous_12[] = {
};
static const struct YamlNode struct_anonymous_13[] = {
YAML_UNSIGNED( "flags", 8 ),
YAML_UNSIGNED( "enableAETR", 1 ),
YAML_END
};
static const struct YamlNode union_anonymous_4_elmts[] = {
@@ -670,7 +671,7 @@ static const struct YamlNode union_anonymous_4_elmts[] = {
YAML_STRUCT("afhds3", 16, struct_anonymous_10, NULL),
YAML_STRUCT("ghost", 8, struct_anonymous_11, NULL),
YAML_STRUCT("crsf", 24, struct_anonymous_12, NULL),
YAML_STRUCT("dsmp", 8, struct_anonymous_13, NULL),
YAML_STRUCT("dsmp", 16, struct_anonymous_13, NULL),
YAML_END
};
static const struct YamlNode struct_ModuleData[] = {
@@ -692,6 +692,7 @@ static const struct YamlNode struct_anonymous_12[] = {
};
static const struct YamlNode struct_anonymous_13[] = {
YAML_UNSIGNED( "flags", 8 ),
YAML_UNSIGNED( "enableAETR", 1 ),
YAML_END
};
static const struct YamlNode union_anonymous_4_elmts[] = {
@@ -705,7 +706,7 @@ static const struct YamlNode union_anonymous_4_elmts[] = {
YAML_STRUCT("afhds3", 16, struct_anonymous_10, NULL),
YAML_STRUCT("ghost", 8, struct_anonymous_11, NULL),
YAML_STRUCT("crsf", 24, struct_anonymous_12, NULL),
YAML_STRUCT("dsmp", 8, struct_anonymous_13, NULL),
YAML_STRUCT("dsmp", 16, struct_anonymous_13, NULL),
YAML_END
};
static const struct YamlNode struct_ModuleData[] = {
@@ -699,6 +699,7 @@ static const struct YamlNode struct_anonymous_12[] = {
};
static const struct YamlNode struct_anonymous_13[] = {
YAML_UNSIGNED( "flags", 8 ),
YAML_UNSIGNED( "enableAETR", 1 ),
YAML_END
};
static const struct YamlNode union_anonymous_4_elmts[] = {
@@ -712,7 +713,7 @@ static const struct YamlNode union_anonymous_4_elmts[] = {
YAML_STRUCT("afhds3", 16, struct_anonymous_10, NULL),
YAML_STRUCT("ghost", 8, struct_anonymous_11, NULL),
YAML_STRUCT("crsf", 24, struct_anonymous_12, NULL),
YAML_STRUCT("dsmp", 8, struct_anonymous_13, NULL),
YAML_STRUCT("dsmp", 16, struct_anonymous_13, NULL),
YAML_END
};
static const struct YamlNode struct_ModuleData[] = {
@@ -724,6 +724,7 @@ static const struct YamlNode struct_anonymous_12[] = {
};
static const struct YamlNode struct_anonymous_13[] = {
YAML_UNSIGNED( "flags", 8 ),
YAML_UNSIGNED( "enableAETR", 1 ),
YAML_END
};
static const struct YamlNode union_anonymous_4_elmts[] = {
@@ -737,7 +738,7 @@ static const struct YamlNode union_anonymous_4_elmts[] = {
YAML_STRUCT("afhds3", 16, struct_anonymous_10, NULL),
YAML_STRUCT("ghost", 8, struct_anonymous_11, NULL),
YAML_STRUCT("crsf", 24, struct_anonymous_12, NULL),
YAML_STRUCT("dsmp", 8, struct_anonymous_13, NULL),
YAML_STRUCT("dsmp", 16, struct_anonymous_13, NULL),
YAML_END
};
static const struct YamlNode struct_ModuleData[] = {
@@ -699,6 +699,7 @@ static const struct YamlNode struct_anonymous_12[] = {
};
static const struct YamlNode struct_anonymous_13[] = {
YAML_UNSIGNED( "flags", 8 ),
YAML_UNSIGNED( "enableAETR", 1 ),
YAML_END
};
static const struct YamlNode union_anonymous_4_elmts[] = {
@@ -712,7 +713,7 @@ static const struct YamlNode union_anonymous_4_elmts[] = {
YAML_STRUCT("afhds3", 16, struct_anonymous_10, NULL),
YAML_STRUCT("ghost", 8, struct_anonymous_11, NULL),
YAML_STRUCT("crsf", 24, struct_anonymous_12, NULL),
YAML_STRUCT("dsmp", 8, struct_anonymous_13, NULL),
YAML_STRUCT("dsmp", 16, struct_anonymous_13, NULL),
YAML_END
};
static const struct YamlNode struct_ModuleData[] = {
@@ -692,6 +692,7 @@ static const struct YamlNode struct_anonymous_12[] = {
};
static const struct YamlNode struct_anonymous_13[] = {
YAML_UNSIGNED( "flags", 8 ),
YAML_UNSIGNED( "enableAETR", 1 ),
YAML_END
};
static const struct YamlNode union_anonymous_4_elmts[] = {
@@ -705,7 +706,7 @@ static const struct YamlNode union_anonymous_4_elmts[] = {
YAML_STRUCT("afhds3", 16, struct_anonymous_10, NULL),
YAML_STRUCT("ghost", 8, struct_anonymous_11, NULL),
YAML_STRUCT("crsf", 24, struct_anonymous_12, NULL),
YAML_STRUCT("dsmp", 8, struct_anonymous_13, NULL),
YAML_STRUCT("dsmp", 16, struct_anonymous_13, NULL),
YAML_END
};
static const struct YamlNode struct_ModuleData[] = {
@@ -724,6 +724,7 @@ static const struct YamlNode struct_anonymous_12[] = {
};
static const struct YamlNode struct_anonymous_13[] = {
YAML_UNSIGNED( "flags", 8 ),
YAML_UNSIGNED( "enableAETR", 1 ),
YAML_END
};
static const struct YamlNode union_anonymous_4_elmts[] = {
@@ -737,7 +738,7 @@ static const struct YamlNode union_anonymous_4_elmts[] = {
YAML_STRUCT("afhds3", 16, struct_anonymous_10, NULL),
YAML_STRUCT("ghost", 8, struct_anonymous_11, NULL),
YAML_STRUCT("crsf", 24, struct_anonymous_12, NULL),
YAML_STRUCT("dsmp", 8, struct_anonymous_13, NULL),
YAML_STRUCT("dsmp", 16, struct_anonymous_13, NULL),
YAML_END
};
static const struct YamlNode struct_ModuleData[] = {
@@ -709,6 +709,7 @@ static const struct YamlNode struct_anonymous_12[] = {
};
static const struct YamlNode struct_anonymous_13[] = {
YAML_UNSIGNED( "flags", 8 ),
YAML_UNSIGNED( "enableAETR", 1 ),
YAML_END
};
static const struct YamlNode union_anonymous_4_elmts[] = {
@@ -722,7 +723,7 @@ static const struct YamlNode union_anonymous_4_elmts[] = {
YAML_STRUCT("afhds3", 16, struct_anonymous_10, NULL),
YAML_STRUCT("ghost", 8, struct_anonymous_11, NULL),
YAML_STRUCT("crsf", 24, struct_anonymous_12, NULL),
YAML_STRUCT("dsmp", 8, struct_anonymous_13, NULL),
YAML_STRUCT("dsmp", 16, struct_anonymous_13, NULL),
YAML_END
};
static const struct YamlNode struct_ModuleData[] = {
@@ -724,6 +724,7 @@ static const struct YamlNode struct_anonymous_12[] = {
};
static const struct YamlNode struct_anonymous_13[] = {
YAML_UNSIGNED( "flags", 8 ),
YAML_UNSIGNED( "enableAETR", 1 ),
YAML_END
};
static const struct YamlNode union_anonymous_4_elmts[] = {
@@ -737,7 +738,7 @@ static const struct YamlNode union_anonymous_4_elmts[] = {
YAML_STRUCT("afhds3", 16, struct_anonymous_10, NULL),
YAML_STRUCT("ghost", 8, struct_anonymous_11, NULL),
YAML_STRUCT("crsf", 24, struct_anonymous_12, NULL),
YAML_STRUCT("dsmp", 8, struct_anonymous_13, NULL),
YAML_STRUCT("dsmp", 16, struct_anonymous_13, NULL),
YAML_END
};
static const struct YamlNode struct_ModuleData[] = {
@@ -642,6 +642,7 @@ static const struct YamlNode struct_anonymous_12[] = {
};
static const struct YamlNode struct_anonymous_13[] = {
YAML_UNSIGNED( "flags", 8 ),
YAML_UNSIGNED( "enableAETR", 1 ),
YAML_END
};
static const struct YamlNode union_anonymous_4_elmts[] = {
@@ -655,7 +656,7 @@ static const struct YamlNode union_anonymous_4_elmts[] = {
YAML_STRUCT("afhds3", 16, struct_anonymous_10, NULL),
YAML_STRUCT("ghost", 8, struct_anonymous_11, NULL),
YAML_STRUCT("crsf", 24, struct_anonymous_12, NULL),
YAML_STRUCT("dsmp", 8, struct_anonymous_13, NULL),
YAML_STRUCT("dsmp", 16, struct_anonymous_13, NULL),
YAML_END
};
static const struct YamlNode struct_ModuleData[] = {
@@ -642,6 +642,7 @@ static const struct YamlNode struct_anonymous_12[] = {
};
static const struct YamlNode struct_anonymous_13[] = {
YAML_UNSIGNED( "flags", 8 ),
YAML_UNSIGNED( "enableAETR", 1 ),
YAML_END
};
static const struct YamlNode union_anonymous_4_elmts[] = {
@@ -655,7 +656,7 @@ static const struct YamlNode union_anonymous_4_elmts[] = {
YAML_STRUCT("afhds3", 16, struct_anonymous_10, NULL),
YAML_STRUCT("ghost", 8, struct_anonymous_11, NULL),
YAML_STRUCT("crsf", 24, struct_anonymous_12, NULL),
YAML_STRUCT("dsmp", 8, struct_anonymous_13, NULL),
YAML_STRUCT("dsmp", 16, struct_anonymous_13, NULL),
YAML_END
};
static const struct YamlNode struct_ModuleData[] = {
@@ -724,6 +724,7 @@ static const struct YamlNode struct_anonymous_12[] = {
};
static const struct YamlNode struct_anonymous_13[] = {
YAML_UNSIGNED( "flags", 8 ),
YAML_UNSIGNED( "enableAETR", 1 ),
YAML_END
};
static const struct YamlNode union_anonymous_4_elmts[] = {
@@ -737,7 +738,7 @@ static const struct YamlNode union_anonymous_4_elmts[] = {
YAML_STRUCT("afhds3", 16, struct_anonymous_10, NULL),
YAML_STRUCT("ghost", 8, struct_anonymous_11, NULL),
YAML_STRUCT("crsf", 24, struct_anonymous_12, NULL),
YAML_STRUCT("dsmp", 8, struct_anonymous_13, NULL),
YAML_STRUCT("dsmp", 16, struct_anonymous_13, NULL),
YAML_END
};
static const struct YamlNode struct_ModuleData[] = {
@@ -700,6 +700,7 @@ static const struct YamlNode struct_anonymous_12[] = {
};
static const struct YamlNode struct_anonymous_13[] = {
YAML_UNSIGNED( "flags", 8 ),
YAML_UNSIGNED( "enableAETR", 1 ),
YAML_END
};
static const struct YamlNode union_anonymous_4_elmts[] = {
@@ -713,7 +714,7 @@ static const struct YamlNode union_anonymous_4_elmts[] = {
YAML_STRUCT("afhds3", 16, struct_anonymous_10, NULL),
YAML_STRUCT("ghost", 8, struct_anonymous_11, NULL),
YAML_STRUCT("crsf", 24, struct_anonymous_12, NULL),
YAML_STRUCT("dsmp", 8, struct_anonymous_13, NULL),
YAML_STRUCT("dsmp", 16, struct_anonymous_13, NULL),
YAML_END
};
static const struct YamlNode struct_ModuleData[] = {
@@ -633,6 +633,7 @@ static const struct YamlNode struct_anonymous_12[] = {
};
static const struct YamlNode struct_anonymous_13[] = {
YAML_UNSIGNED( "flags", 8 ),
YAML_UNSIGNED( "enableAETR", 1 ),
YAML_END
};
static const struct YamlNode union_anonymous_4_elmts[] = {
@@ -646,7 +647,7 @@ static const struct YamlNode union_anonymous_4_elmts[] = {
YAML_STRUCT("afhds3", 16, struct_anonymous_10, NULL),
YAML_STRUCT("ghost", 8, struct_anonymous_11, NULL),
YAML_STRUCT("crsf", 24, struct_anonymous_12, NULL),
YAML_STRUCT("dsmp", 8, struct_anonymous_13, NULL),
YAML_STRUCT("dsmp", 16, struct_anonymous_13, NULL),
YAML_END
};
static const struct YamlNode struct_ModuleData[] = {
@@ -633,6 +633,7 @@ static const struct YamlNode struct_anonymous_12[] = {
};
static const struct YamlNode struct_anonymous_13[] = {
YAML_UNSIGNED( "flags", 8 ),
YAML_UNSIGNED( "enableAETR", 1 ),
YAML_END
};
static const struct YamlNode union_anonymous_4_elmts[] = {
@@ -646,7 +647,7 @@ static const struct YamlNode union_anonymous_4_elmts[] = {
YAML_STRUCT("afhds3", 16, struct_anonymous_10, NULL),
YAML_STRUCT("ghost", 8, struct_anonymous_11, NULL),
YAML_STRUCT("crsf", 24, struct_anonymous_12, NULL),
YAML_STRUCT("dsmp", 8, struct_anonymous_13, NULL),
YAML_STRUCT("dsmp", 16, struct_anonymous_13, NULL),
YAML_END
};
static const struct YamlNode struct_ModuleData[] = {
@@ -633,6 +633,7 @@ static const struct YamlNode struct_anonymous_12[] = {
};
static const struct YamlNode struct_anonymous_13[] = {
YAML_UNSIGNED( "flags", 8 ),
YAML_UNSIGNED( "enableAETR", 1 ),
YAML_END
};
static const struct YamlNode union_anonymous_4_elmts[] = {
@@ -646,7 +647,7 @@ static const struct YamlNode union_anonymous_4_elmts[] = {
YAML_STRUCT("afhds3", 16, struct_anonymous_10, NULL),
YAML_STRUCT("ghost", 8, struct_anonymous_11, NULL),
YAML_STRUCT("crsf", 24, struct_anonymous_12, NULL),
YAML_STRUCT("dsmp", 8, struct_anonymous_13, NULL),
YAML_STRUCT("dsmp", 16, struct_anonymous_13, NULL),
YAML_END
};
static const struct YamlNode struct_ModuleData[] = {
@@ -633,6 +633,7 @@ static const struct YamlNode struct_anonymous_12[] = {
};
static const struct YamlNode struct_anonymous_13[] = {
YAML_UNSIGNED( "flags", 8 ),
YAML_UNSIGNED( "enableAETR", 1 ),
YAML_END
};
static const struct YamlNode union_anonymous_4_elmts[] = {
@@ -646,7 +647,7 @@ static const struct YamlNode union_anonymous_4_elmts[] = {
YAML_STRUCT("afhds3", 16, struct_anonymous_10, NULL),
YAML_STRUCT("ghost", 8, struct_anonymous_11, NULL),
YAML_STRUCT("crsf", 24, struct_anonymous_12, NULL),
YAML_STRUCT("dsmp", 8, struct_anonymous_13, NULL),
YAML_STRUCT("dsmp", 16, struct_anonymous_13, NULL),
YAML_END
};
static const struct YamlNode struct_ModuleData[] = {
@@ -637,6 +637,7 @@ static const struct YamlNode struct_anonymous_12[] = {
};
static const struct YamlNode struct_anonymous_13[] = {
YAML_UNSIGNED( "flags", 8 ),
YAML_UNSIGNED( "enableAETR", 1 ),
YAML_END
};
static const struct YamlNode union_anonymous_4_elmts[] = {
@@ -650,7 +651,7 @@ static const struct YamlNode union_anonymous_4_elmts[] = {
YAML_STRUCT("afhds3", 16, struct_anonymous_10, NULL),
YAML_STRUCT("ghost", 8, struct_anonymous_11, NULL),
YAML_STRUCT("crsf", 24, struct_anonymous_12, NULL),
YAML_STRUCT("dsmp", 8, struct_anonymous_13, NULL),
YAML_STRUCT("dsmp", 16, struct_anonymous_13, NULL),
YAML_END
};
static const struct YamlNode struct_ModuleData[] = {
@@ -11,6 +11,7 @@ option(DEBUG_TRACE_BUFFER "Debug Trace Screen" OFF)
option(XJT "XJT TX Module" ON)
option(PPM "PPM TX Module" ON)
option(DSM2 "DSM2 TX Module" ON)
option(DSMP "DSMP LemonRX TX Module" ON)
option(SBUS "SBUS TX Module" ON)
option(CROSSFIRE "Crossfire TX Module" ON)
option(AFHDS2 "Support for AFHDS2" OFF)
@@ -192,6 +193,12 @@ if(DSM2)
add_definitions(-DDSM2)
endif()
if(DSMP)
add_definitions(-DDSM2)
add_definitions(-DDSMP)
endif()
if(SBUS)
add_definitions(-DSBUS)
endif()
@@ -312,6 +319,14 @@ if(DSM2)
)
endif()
if(DSMP)
set(PULSES_SRC
${PULSES_SRC}
dsmp.cpp
)
endif()
if(SBUS)
set(PULSES_SRC
${PULSES_SRC}
+53 -1
View File
@@ -357,6 +357,58 @@ static void processMultiProtoDef(uint8_t module, const uint8_t * packet, uint8_t
#endif
static void processMultiDSMBindPacket(uint8_t module, const uint8_t *packet)
{
if (//g_model.moduleData[module].type == MODULE_TYPE_MULTIMODULE &&
//g_model.moduleData[module].multi.rfProtocol ==
// MODULE_SUBTYPE_MULTI_DSM2 &&
g_model.moduleData[module].subType == MM_RF_DSM2_SUBTYPE_AUTO) {
// Only sets channel etc when in DSM/AUTO mode
int channels = packet[5];
if (channels > 12) {
channels = 12;
} else if (channels < 3) {
channels = 3;
}
switch (packet[6]) {
case 0xa2:
g_model.moduleData[module].subType = MM_RF_DSM2_SUBTYPE_DSMX_22;
break;
case 0x12:
g_model.moduleData[module].subType = MM_RF_DSM2_SUBTYPE_DSM2_11;
if (channels == 7) {
channels = 12; // change the number of channels if 7
}
break;
case 0x01:
case 0x02:
g_model.moduleData[module].subType = MM_RF_DSM2_SUBTYPE_DSM2_22;
break;
default: // 0xb2 or unknown
g_model.moduleData[module].subType = MM_RF_DSM2_SUBTYPE_DSMX_11;
if (channels == 7) {
channels = 12; // change the number of channels if 7
}
break;
}
g_model.moduleData[module].channelsCount = channels - 8;
// clear the 11ms servo refresh rate flag
g_model.moduleData[module].multi.optionValue &= 0xFD;
storageDirty(EE_MODEL);
}
/* Finally stop binding as the rx just told us that it is bound */
if (getModuleMode(module) == MODULE_MODE_BIND) {
setMultiBindStatus(module, MULTI_BIND_FINISHED);
}
// Continue with the common Spektrum Processing
processDSMBindPacket(packet);
}
static void processMultiTelemetryPaket(const uint8_t * packet, uint8_t module)
{
uint8_t type = packet[0];
@@ -372,7 +424,7 @@ static void processMultiTelemetryPaket(const uint8_t * packet, uint8_t module)
case DSMBindPacket:
if (len >= 10)
processDSMBindPacket(module, data);
processMultiDSMBindPacket(module, data);
break;
case SpektrumTelemetry:
+1 -116
View File
@@ -849,131 +849,16 @@ void processSpektrumPacket(const uint8_t *packet)
LemonRX+Sat+tele 0xb2 07 1
*/
void processDSMBindPacket(uint8_t module, const uint8_t *packet)
void processDSMBindPacket(const uint8_t *packet)
{
uint32_t debugval;
if (g_model.moduleData[module].type == MODULE_TYPE_LEMON_DSMP) {
// save flags
g_model.moduleData[module].dsmp.flags = packet[0];
// save number of channels
uint8_t channels = packet[2];
if (channels > 12) { channels = 12; }
g_model.moduleData[module].channelsCount = channels - 8;
TRACE("[SPK] DSMP bind packet: 0x%X / %i",
packet[0] & 0x3F, packet[2]);
storageDirty(EE_MODEL);
moduleState[module].mode = MODULE_MODE_NORMAL;
restartModuleAsync(module, 50); // ~500ms
}
#if defined(MULTIMODULE)
else if (g_model.moduleData[module].type == MODULE_TYPE_MULTIMODULE &&
g_model.moduleData[module].multi.rfProtocol ==
MODULE_SUBTYPE_MULTI_DSM2 &&
g_model.moduleData[module].subType == MM_RF_DSM2_SUBTYPE_AUTO) {
// Only sets channel etc when in DSM/AUTO mode
int channels = packet[5];
if (channels > 12) {
channels = 12;
}
else if (channels < 3) {
channels = 3;
}
switch(packet[6]) {
case 0xa2:
g_model.moduleData[module].subType = MM_RF_DSM2_SUBTYPE_DSMX_22;
break;
case 0x12:
g_model.moduleData[module].subType = MM_RF_DSM2_SUBTYPE_DSM2_11;
if (channels == 7) {
channels = 12; // change the number of channels if 7
}
break;
case 0x01:
case 0x02:
g_model.moduleData[module].subType = MM_RF_DSM2_SUBTYPE_DSM2_22;
break;
default: // 0xb2 or unknown
g_model.moduleData[module].subType = MM_RF_DSM2_SUBTYPE_DSMX_11;
if (channels == 7) {
channels = 12; // change the number of channels if 7
}
break;
}
g_model.moduleData[module].channelsCount = channels - 8;
// clear the 11ms servo refresh rate flag
g_model.moduleData[module].multi.optionValue &= 0xFD;
storageDirty(EE_MODEL);
}
#endif
debugval = packet[7] << 24 | packet[6] << 16 | packet[5] << 8 | packet[4];
/* log the bind packet as telemetry for quick debugging */
setTelemetryValue(PROTOCOL_TELEMETRY_SPEKTRUM, I2C_PSEUDO_TX_BIND, 0, 0,
debugval, UNIT_RAW, 0);
/* Finally stop binding as the rx just told us that it is bound */
if (getModuleMode(module) == MODULE_MODE_BIND) {
auto module_type = g_model.moduleData[module].type;
#if defined(MULTIMODULE)
if (module_type == MODULE_TYPE_MULTIMODULE &&
g_model.moduleData[module].multi.rfProtocol ==
MODULE_SUBTYPE_MULTI_DSM2) {
setMultiBindStatus(module, MULTI_BIND_FINISHED);
} else
#endif
if (module_type == MODULE_TYPE_LEMON_DSMP) {
setModuleMode(module, MODULE_MODE_NORMAL);
}
}
}
void processSpektrumTelemetryData(uint8_t module, uint8_t data,
uint8_t *rxBuffer, uint8_t &rxBufferCount)
{
if (rxBufferCount == 0 && data != 0xAA) {
TRACE("[SPK] invalid start byte 0x%02X", data);
return;
}
if (rxBufferCount < TELEMETRY_RX_PACKET_SIZE) {
rxBuffer[rxBufferCount++] = data;
}
else {
TRACE("[SPK] array size %d error", rxBufferCount);
rxBufferCount = 0;
}
if (rxBuffer[1] == 0x80 && rxBufferCount >= DSM_BIND_PACKET_LENGTH) {
processDSMBindPacket(module, rxBuffer+2);
rxBufferCount = 0;
return;
}
if (rxBufferCount >= SPEKTRUM_TELEMETRY_LENGTH) {
// Debug print content of Telemetry to console
#if 0
debugPrintf("[SPK] Packet 0x%02X rssi 0x%02X: ic2 0x%02x, %02x: ",
rxBuffer[0], rxBuffer[1], rxBuffer[2], rxBuffer[3]);
for (int i=4; i<SPEKTRUM_TELEMETRY_LENGTH; i+=4) {
debugPrintf("%02X%02X %02X%02X ", rxBuffer[i], rxBuffer[i + 1],
rxBuffer[i + 2], rxBuffer[i + 3]);
}
debugPrintf(CRLF);
#endif
processSpektrumPacket(rxBuffer);
rxBufferCount = 0;
}
}
const SpektrumSensor *getSpektrumSensor(uint16_t pseudoId)
{
+5 -3
View File
@@ -21,9 +21,11 @@
#pragma once
void processSpektrumTelemetryData(uint8_t module, uint8_t data, uint8_t* rxBuffer, uint8_t& rxBufferCount);
#define SPEKTRUM_TELEMETRY_LENGTH 18
#define DSM_BIND_PACKET_LENGTH 12
void spektrumSetDefault(int index, uint16_t id, uint8_t subId, uint8_t instance);
// Used directly by multi telemetry protocol
// Used directly by multi and DSMP telemetry protocol
void processSpektrumPacket(const uint8_t *packet);
void processDSMBindPacket(uint8_t module, const uint8_t *packet);
void processDSMBindPacket(const uint8_t *packet);
+1
View File
@@ -672,6 +672,7 @@
#define TR_MULTI_OPTION TR("选项值", "选项值")
#define TR_MULTI_AUTOBIND TR("对频通道", "通道控制对频")
#define TR_DISABLE_CH_MAP TR("禁用通道映射", "禁用通道重映射")
#define TR_DSMP_ENABLE_AETR TR("Enb. AETR", "Enable AETR")
#define TR_DISABLE_TELEM TR("禁用回传", "禁用回传")
#define TR_MULTI_LOWPOWER TR("低功率", "低功率模式")
#define TR_MULTI_LNA_DISABLE "禁用接收放大器"
+1
View File
@@ -677,6 +677,7 @@
#define TR_MULTI_OPTION TR("Možnosti", "Hodnota")
#define TR_MULTI_AUTOBIND TR("Bind Ch.","Bind při zapnutí")
#define TR_DISABLE_CH_MAP TR("No Ch. map", "Vypnout mapování kanálů")
#define TR_DSMP_ENABLE_AETR TR("Enb. AETR", "Enable AETR")
#define TR_DISABLE_TELEM TR("No Telem", "Vypnout telemetrii")
#define TR_MULTI_LOWPOWER TR("Nízký výkon", "Režim nízkého výkonu")
#define TR_MULTI_LNA_DISABLE "LNA vypnuto"
+1
View File
@@ -677,6 +677,7 @@
#define TR_MULTI_OPTION TR("Tilvalg", "Tilvalg værdi")
#define TR_MULTI_AUTOBIND TR("Tilslut ka.", "Tilslut kanal")
#define TR_DISABLE_CH_MAP TR("% ka. kort", "Deaktiver kanal kort")
#define TR_DSMP_ENABLE_AETR TR("Enb. AETR", "Enable AETR")
#define TR_DISABLE_TELEM TR("% Telem.", "Deaktiver telemetri")
#define TR_MULTI_LOWPOWER TR("Lav strøm", "Lav strøm tilstand")
#define TR_MULTI_LNA_DISABLE "LNA deaktiver"
+1
View File
@@ -673,6 +673,7 @@
#define TR_MULTI_OPTION TR("Option", "Optionswert")
#define TR_MULTI_AUTOBIND TR("Bind Ka.","Bindung an Kanal")
#define TR_DISABLE_CH_MAP TR("No Ch. map", "Deaktiviere Ch. map")
#define TR_DSMP_ENABLE_AETR TR("Enb. AETR", "Enable AETR")
#define TR_DISABLE_TELEM TR("No Telem", "Deaktiviere Telem.")
#define TR_MULTI_LOWPOWER TR("Low power", "reduzierte Leistung")
#define TR_MULTI_LNA_DISABLE "LNA disable"
+1
View File
@@ -673,6 +673,7 @@
#define TR_MULTI_OPTION TR("Option", "Option value")
#define TR_MULTI_AUTOBIND TR("Bind Ch.", "Bind on channel")
#define TR_DISABLE_CH_MAP TR("No Ch. map", "Disable Ch. map")
#define TR_DSMP_ENABLE_AETR TR("Enb. AETR", "Enable AETR")
#define TR_DISABLE_TELEM TR("No Telem", "Disable Telemetry")
#define TR_MULTI_LOWPOWER TR("Low power", "Low power mode")
#define TR_MULTI_LNA_DISABLE "LNA disable"
+1
View File
@@ -672,6 +672,7 @@
#define TR_MULTI_OPTION TR("Opción", "Valor opción")
#define TR_MULTI_AUTOBIND TR("Emp Cnl","Emparejar en canal")
#define TR_DISABLE_CH_MAP TR("No ch map", "Desactivar mapa cnl")
#define TR_DSMP_ENABLE_AETR TR("Hab. AETR", "Habilitar AETR")
#define TR_DISABLE_TELEM TR("No telem", "Desactivar telem.")
#define TR_MULTI_LOWPOWER TR("Baja poten.", "Modo de baja poten.")
#define TR_MULTI_LNA_DISABLE "LNA desact."
+1
View File
@@ -672,6 +672,7 @@
#define TR_MULTI_OPTION TR("Option", "Option value")
#define TR_MULTI_AUTOBIND TR("Bind Ch.","Bind on channel")
#define TR_DISABLE_CH_MAP TR("No Ch. map", "Disable Ch. map")
#define TR_DSMP_ENABLE_AETR TR("Enb. AETR", "Enable AETR")
#define TR_DISABLE_TELEM TR("No Telem", "Disable Telemetry")
#define TR_MULTI_LOWPOWER TR("Low power", "Low power mode")
#define TR_MULTI_LNA_DISABLE "LNA disable"
+1
View File
@@ -677,6 +677,7 @@
#define TR_MULTI_OPTION TR("Option", "Option perso")
#define TR_MULTI_AUTOBIND TR("Bind voie", "Bind sur voie")
#define TR_DISABLE_CH_MAP TR("No Ch. map", "Désact. réorg. voies")
#define TR_DSMP_ENABLE_AETR TR("Enb. AETR", "Enable AETR")
#define TR_DISABLE_TELEM TR("Pas de Télém.", "Désact. Télémétrie")
#define TR_MULTI_LOWPOWER TR("Basse puis.", "Mode basse puiss.")
#define TR_MULTI_LNA_DISABLE "LNA désactivé"
+1
View File
@@ -675,6 +675,7 @@
#define TR_MULTI_OPTION TR("Option", "Option value")
#define TR_MULTI_AUTOBIND TR("Bind Ch.", "צימוד על ערוץ")
#define TR_DISABLE_CH_MAP TR("No Ch. map", "השבתת מיפוי ערוצים")
#define TR_DSMP_ENABLE_AETR TR("Enb. AETR", "Enable AETR")
#define TR_DISABLE_TELEM TR("No Telem", "השבתת טלמטריה")
#define TR_MULTI_LOWPOWER TR("Low power", "מצב מתח נמוך")
#define TR_MULTI_LNA_DISABLE "LNA disable"
+1
View File
@@ -672,6 +672,7 @@
#define TR_MULTI_OPTION TR("Opzione", "Opzione valore")
#define TR_MULTI_AUTOBIND TR("Ass. Ch.","Associa al canale")
#define TR_DISABLE_CH_MAP TR("No Ch. map", "Disab. mappa Ch.")
#define TR_DSMP_ENABLE_AETR TR("Enb. AETR", "Enable AETR")
#define TR_DISABLE_TELEM TR("No Telem", "Telem. disabil.")
#define TR_MULTI_LOWPOWER TR("Bassa pot.", "Modo bassa potenza")
#define TR_MULTI_LNA_DISABLE "Disabilita LNA"
+1
View File
@@ -671,6 +671,7 @@
#define TR_MULTI_OPTION TR("Option", "オプション値")
#define TR_MULTI_AUTOBIND TR("Bind Ch.", "チャンネルバインド")
#define TR_DISABLE_CH_MAP TR("No Ch. map", "CHマップ無効")
#define TR_DSMP_ENABLE_AETR TR("Enb. AETR", "Enable AETR")
#define TR_DISABLE_TELEM TR("No Telem", "テレメトリー無効")
#define TR_MULTI_LOWPOWER TR("Low power", "低出力モード")
#define TR_MULTI_LNA_DISABLE "LNA無効"
+1
View File
@@ -696,6 +696,7 @@
#define TR_MULTI_OPTION TR("옵션", "옵션 값")
#define TR_MULTI_AUTOBIND TR("바인드 채널", "채널에서 자동 바인딩")
#define TR_DISABLE_CH_MAP TR("채널 매핑 없음", "채널 매핑 비활성화")
#define TR_DSMP_ENABLE_AETR TR("Enb. AETR", "Enable AETR")
#define TR_DISABLE_TELEM TR("텔레메트리 없음", "텔레메트리 비활성화")
#define TR_MULTI_LOWPOWER TR("저전력", "저전력 모드")
#define TR_MULTI_LNA_DISABLE "LNA 비활성화"
+1
View File
@@ -674,6 +674,7 @@
#define TR_MULTI_OPTION TR("Option", "Option value")
#define TR_MULTI_AUTOBIND TR("Bind Ch.","Bind on channel")
#define TR_DISABLE_CH_MAP TR("No Ch. map", "Disable Ch. map")
#define TR_DSMP_ENABLE_AETR TR("Enb. AETR", "Enable AETR")
#define TR_DISABLE_TELEM TR("No Telem", "Disable Telemetry")
#define TR_MULTI_LOWPOWER TR("Low power", "Low power mode")
#define TR_MULTI_LNA_DISABLE "LNA disable"
+1
View File
@@ -671,6 +671,7 @@
#define TR_MULTI_OPTION TR("Opcja", "Wartość opcji")
#define TR_MULTI_AUTOBIND TR("Bind Ch.","Bind on channel")
#define TR_DISABLE_CH_MAP TR("No Ch. map", "Disable Ch. map")
#define TR_DSMP_ENABLE_AETR TR("Enb. AETR", "Enable AETR")
#define TR_DISABLE_TELEM TR("No Telem", "Disable Telemetry")
#define TR_MULTI_LOWPOWER TR("Low power", "Low power mode")
#define TR_MULTI_LNA_DISABLE "LNA disable"
+1
View File
@@ -672,6 +672,7 @@
#define TR_MULTI_OPTION TR("Opção", "Valor opção")
#define TR_MULTI_AUTOBIND TR("Bind Ch.", "Bind on channel")
#define TR_DISABLE_CH_MAP TR("No Ch. map", "Disable Ch. map")
#define TR_DSMP_ENABLE_AETR TR("Enb. AETR", "Enable AETR")
#define TR_DISABLE_TELEM TR("No Telem", "Disable Telemetry")
#define TR_MULTI_LOWPOWER TR("Low power", "Low power mode")
#define TR_MULTI_LNA_DISABLE "LNA disable"
+1
View File
@@ -674,6 +674,7 @@
#define TR_MULTI_OPTION TR("Опция", "Знач опции")
#define TR_MULTI_AUTOBIND TR("Прив к кан", "Прив к кан")
#define TR_DISABLE_CH_MAP TR("Откл карту кан", "Откл карту кан")
#define TR_DSMP_ENABLE_AETR TR("Enb. AETR", "Enable AETR")
#define TR_DISABLE_TELEM TR("Без телеметрии", "Откл телем")
#define TR_MULTI_LOWPOWER TR("Низк потребл", "Низк потребл")
#define TR_MULTI_LNA_DISABLE "Откл LNA"
+1
View File
@@ -677,6 +677,7 @@
#define TR_MULTI_OPTION TR("Alternativ", "Alternativets värde")
#define TR_MULTI_AUTOBIND TR("Bind ka.","Parkoppla via kanal")
#define TR_DISABLE_CH_MAP TR("Mappa ej KA", "Inaktivera kanalmappning")
#define TR_DSMP_ENABLE_AETR TR("Enb. AETR", "Enable AETR")
#define TR_DISABLE_TELEM TR("Ej telem.", "Inaktivera telemetri")
#define TR_MULTI_LOWPOWER TR("Låg effekt", "Lågeffektläge")
#define TR_MULTI_LNA_DISABLE "LNA disable"
+1
View File
@@ -669,6 +669,7 @@
#define TR_MULTI_OPTION TR("選項值", "選項值")
#define TR_MULTI_AUTOBIND TR("對頻通道", "通道控制對頻")
#define TR_DISABLE_CH_MAP TR("禁用通道映射", "禁用通道重映射")
#define TR_DSMP_ENABLE_AETR TR("Enb. AETR", "Enable AETR")
#define TR_DISABLE_TELEM TR("禁用回傳", "禁用回傳")
#define TR_MULTI_LOWPOWER TR("低功率", "低功率模式")
#define TR_MULTI_LNA_DISABLE "禁用接收放大器"
+1
View File
@@ -673,6 +673,7 @@
#define TR_MULTI_OPTION TR("Опція", "Значення опції")
#define TR_MULTI_AUTOBIND TR("Прив'язка до кан.", "Прив'язка до каналу")
#define TR_DISABLE_CH_MAP TR("Викл. карту каналів", "Виключити карту каналів")
#define TR_DSMP_ENABLE_AETR TR("Enb. AETR", "Enable AETR")
#define TR_DISABLE_TELEM TR("Викл. телеметрії", "Виключити телеметрію")
#define TR_MULTI_LOWPOWER TR("Низька потужн.", "Режим низької потужності")
#define TR_MULTI_LNA_DISABLE "Вимкн. LNA"
+5 -1
View File
@@ -330,7 +330,7 @@
#define STR_MENUCUSTOMSCRIPTS currentLangStrings->STR_MENUCUSTOMSCRIPTS
#endif
#if defined(DSM2) || defined(PXX)
#if defined(DSM2) || defined(PXX) || defined(DSMP)
#define STR_BIND_OK currentLangStrings->STR_BIND_OK
#define STR_REBIND currentLangStrings->STR_REBIND
#define STR_RECEIVER_NUM currentLangStrings->STR_RECEIVER_NUM
@@ -338,6 +338,10 @@
#define STR_REG_OK currentLangStrings->STR_REG_OK
#endif
#if defined(DSMP)
#define STR_DSMP_ENABLE_AETR currentLangStrings->STR_DSMP_ENABLE_AETR
#endif
#if defined(AFHDS3)
#define STR_AFHDS3_ACTUAL_POWER currentLangStrings->STR_AFHDS3_ACTUAL_POWER
#define STR_AFHDS3_ONE_TO_MANY currentLangStrings->STR_AFHDS3_ONE_TO_MANY
+5 -1
View File
@@ -329,7 +329,7 @@ STR(STRENGTH)
STR(MENUCUSTOMSCRIPTS)
#endif
#if defined(DSM2) || defined(PXX)
#if defined(DSM2) || defined(PXX) || defined(DSMP)
STR(BIND_OK)
STR(REBIND)
STR(RECEIVER_NUM)
@@ -337,6 +337,10 @@ STR(RECEIVER)
STR(REG_OK)
#endif
#if defined(DSMP)
STR(DSMP_ENABLE_AETR)
#endif
#if defined(AFHDS3)
STR(AFHDS3_ACTUAL_POWER)
STR(AFHDS3_ONE_TO_MANY)