refactor: Notify module driver on config changes (#3780)
This commit is contained in:
@@ -1260,9 +1260,6 @@ void menuModelSetup(event_t event)
|
||||
MODULE_SUBTYPE_R9M_LAST, EE_MODEL);
|
||||
if (checkIncDec_Ret) {
|
||||
g_model.moduleData[moduleIdx].pxx.power = 0;
|
||||
g_model.moduleData[moduleIdx].channelsStart = 0;
|
||||
g_model.moduleData[moduleIdx].channelsCount =
|
||||
defaultModuleChannels_M8(moduleIdx);
|
||||
}
|
||||
} else {
|
||||
CHECK_INCDEC_MODELVAR(event,
|
||||
@@ -1274,6 +1271,8 @@ void menuModelSetup(event_t event)
|
||||
g_model.moduleData[moduleIdx].channelsStart = 0;
|
||||
g_model.moduleData[moduleIdx].channelsCount =
|
||||
defaultModuleChannels_M8(moduleIdx);
|
||||
|
||||
pulsesModuleSettingsUpdate(moduleIdx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1142,52 +1142,73 @@ void menuModelSetup(event_t event)
|
||||
if (s_editMode > 0) {
|
||||
switch (menuHorizontalPosition) {
|
||||
case 0:
|
||||
reusableBuffer.moduleSetup.newType = checkIncDec(event, reusableBuffer.moduleSetup.newType, MODULE_TYPE_NONE, MODULE_TYPE_MAX, 0, isExternalModuleAvailable);
|
||||
reusableBuffer.moduleSetup.newType = checkIncDec(
|
||||
event, reusableBuffer.moduleSetup.newType, MODULE_TYPE_NONE,
|
||||
MODULE_TYPE_MAX, 0, isExternalModuleAvailable);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
if (isModuleDSM2(EXTERNAL_MODULE)) {
|
||||
CHECK_INCDEC_MODELVAR(event, g_model.moduleData[EXTERNAL_MODULE].subType, DSM2_PROTO_LP45, DSM2_PROTO_DSMX);
|
||||
}
|
||||
CHECK_INCDEC_MODELVAR(
|
||||
event, g_model.moduleData[EXTERNAL_MODULE].subType,
|
||||
DSM2_PROTO_LP45, DSM2_PROTO_DSMX);
|
||||
}
|
||||
#if defined(PPM)
|
||||
else if (isModulePPM(EXTERNAL_MODULE)) {
|
||||
CHECK_INCDEC_MODELVAR(event, g_model.moduleData[EXTERNAL_MODULE].subType, PPM_PROTO_TLM_NONE, PPM_PROTO_TLM_MLINK);
|
||||
CHECK_INCDEC_MODELVAR(
|
||||
event, g_model.moduleData[EXTERNAL_MODULE].subType,
|
||||
PPM_PROTO_TLM_NONE, PPM_PROTO_TLM_MLINK);
|
||||
}
|
||||
#endif
|
||||
#if defined(MULTIMODULE)
|
||||
else if (isModuleMultimodule(EXTERNAL_MODULE)) {
|
||||
int multiRfProto = g_model.moduleData[EXTERNAL_MODULE].multi.rfProtocol;
|
||||
CHECK_INCDEC_MODELVAR_CHECK(event, multiRfProto, MODULE_SUBTYPE_MULTI_FIRST, MODULE_SUBTYPE_MULTI_LAST, isMultiProtocolSelectable);
|
||||
int multiRfProto =
|
||||
g_model.moduleData[EXTERNAL_MODULE].multi.rfProtocol;
|
||||
CHECK_INCDEC_MODELVAR_CHECK(
|
||||
event, multiRfProto, MODULE_SUBTYPE_MULTI_FIRST,
|
||||
MODULE_SUBTYPE_MULTI_LAST, isMultiProtocolSelectable);
|
||||
if (checkIncDec_Ret) {
|
||||
g_model.moduleData[EXTERNAL_MODULE].multi.rfProtocol = multiRfProto;
|
||||
g_model.moduleData[EXTERNAL_MODULE].multi.rfProtocol =
|
||||
multiRfProto;
|
||||
g_model.moduleData[EXTERNAL_MODULE].subType = 0;
|
||||
resetMultiProtocolsOptions(EXTERNAL_MODULE);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else if (isModuleR9MNonAccess(EXTERNAL_MODULE)) {
|
||||
g_model.moduleData[EXTERNAL_MODULE].subType = checkIncDec(event, g_model.moduleData[EXTERNAL_MODULE].subType,
|
||||
MODULE_SUBTYPE_R9M_FCC, MODULE_SUBTYPE_R9M_LAST, EE_MODEL);
|
||||
g_model.moduleData[EXTERNAL_MODULE].subType = checkIncDec(
|
||||
event, g_model.moduleData[EXTERNAL_MODULE].subType,
|
||||
MODULE_SUBTYPE_R9M_FCC, MODULE_SUBTYPE_R9M_LAST,
|
||||
EE_MODEL);
|
||||
}
|
||||
#if defined(AFHDS3)
|
||||
else if (isModuleAFHDS3(EXTERNAL_MODULE)) {
|
||||
CHECK_INCDEC_MODELVAR(event, g_model.moduleData[EXTERNAL_MODULE].subType, AFHDS_SUBTYPE_FIRST, AFHDS_SUBTYPE_LAST);
|
||||
CHECK_INCDEC_MODELVAR(
|
||||
event, g_model.moduleData[EXTERNAL_MODULE].subType,
|
||||
AFHDS_SUBTYPE_FIRST, AFHDS_SUBTYPE_LAST);
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
g_model.moduleData[EXTERNAL_MODULE].subType = checkIncDec(event, g_model.moduleData[EXTERNAL_MODULE].subType,
|
||||
MODULE_SUBTYPE_PXX1_ACCST_D16, MODULE_SUBTYPE_PXX1_LAST, EE_MODEL,
|
||||
isRfProtocolAvailable);
|
||||
g_model.moduleData[EXTERNAL_MODULE].subType = checkIncDec(
|
||||
event, g_model.moduleData[EXTERNAL_MODULE].subType,
|
||||
MODULE_SUBTYPE_PXX1_ACCST_D16, MODULE_SUBTYPE_PXX1_LAST,
|
||||
EE_MODEL, isRfProtocolAvailable);
|
||||
}
|
||||
|
||||
if (checkIncDec_Ret) {
|
||||
g_model.moduleData[EXTERNAL_MODULE].channelsStart = 0;
|
||||
g_model.moduleData[EXTERNAL_MODULE].channelsCount = defaultModuleChannels_M8(EXTERNAL_MODULE);
|
||||
g_model.moduleData[EXTERNAL_MODULE].channelsCount =
|
||||
defaultModuleChannels_M8(EXTERNAL_MODULE);
|
||||
|
||||
pulsesModuleSettingsUpdate(EXTERNAL_MODULE);
|
||||
}
|
||||
break;
|
||||
|
||||
#if defined(MULTIMODULE)
|
||||
case 2:
|
||||
CHECK_INCDEC_MODELVAR(event, g_model.moduleData[EXTERNAL_MODULE].subType, 0, getMaxMultiSubtype(EXTERNAL_MODULE));
|
||||
CHECK_INCDEC_MODELVAR(
|
||||
event, g_model.moduleData[EXTERNAL_MODULE].subType, 0,
|
||||
getMaxMultiSubtype(EXTERNAL_MODULE));
|
||||
if (checkIncDec_Ret) {
|
||||
resetMultiProtocolsOptions(EXTERNAL_MODULE);
|
||||
}
|
||||
@@ -1198,18 +1219,22 @@ void menuModelSetup(event_t event)
|
||||
#if POPUP_LEVEL > 1
|
||||
else if (old_editMode > 0) {
|
||||
if (isModuleR9MNonAccess(EXTERNAL_MODULE)) {
|
||||
if (g_model.moduleData[EXTERNAL_MODULE].subType > MODULE_SUBTYPE_R9M_EU) {
|
||||
if (g_model.moduleData[EXTERNAL_MODULE].subType >
|
||||
MODULE_SUBTYPE_R9M_EU) {
|
||||
POPUP_WARNING(STR_MODULE_PROTOCOL_FLEX_WARN_LINE1);
|
||||
SET_WARNING_INFO(STR_MODULE_PROTOCOL_WARN_LINE2, sizeof(TR_MODULE_PROTOCOL_WARN_LINE2) - 1, 0);
|
||||
SET_WARNING_INFO(STR_MODULE_PROTOCOL_WARN_LINE2,
|
||||
sizeof(TR_MODULE_PROTOCOL_WARN_LINE2) - 1, 0);
|
||||
}
|
||||
#if POPUP_LEVEL >= 3
|
||||
else if (g_model.moduleData[EXTERNAL_MODULE].subType == MODULE_SUBTYPE_R9M_EU) {
|
||||
else if (g_model.moduleData[EXTERNAL_MODULE].subType ==
|
||||
MODULE_SUBTYPE_R9M_EU) {
|
||||
POPUP_WARNING(STR_MODULE_PROTOCOL_EU_WARN_LINE1);
|
||||
SET_WARNING_INFO(STR_MODULE_PROTOCOL_WARN_LINE2, sizeof(TR_MODULE_PROTOCOL_WARN_LINE2) - 1, 0);
|
||||
}
|
||||
else {
|
||||
SET_WARNING_INFO(STR_MODULE_PROTOCOL_WARN_LINE2,
|
||||
sizeof(TR_MODULE_PROTOCOL_WARN_LINE2) - 1, 0);
|
||||
} else {
|
||||
POPUP_WARNING(STR_MODULE_PROTOCOL_FCC_WARN_LINE1);
|
||||
SET_WARNING_INFO(STR_MODULE_PROTOCOL_WARN_LINE2, sizeof(TR_MODULE_PROTOCOL_WARN_LINE2) - 1, 0);
|
||||
SET_WARNING_INFO(STR_MODULE_PROTOCOL_WARN_LINE2,
|
||||
sizeof(TR_MODULE_PROTOCOL_WARN_LINE2) - 1, 0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -714,11 +714,14 @@ static void update_module_window(lv_event_t* e)
|
||||
ModuleWindow* mw = (ModuleWindow*)lv_event_get_user_data(e);
|
||||
if (!mw) return;
|
||||
|
||||
if (isModuleISRM(mw->getModuleIdx())) {
|
||||
auto module = mw->getModuleIdx();
|
||||
if (isModuleISRM(module)) {
|
||||
mw->updateModule();
|
||||
} else {
|
||||
mw->updateSubType();
|
||||
}
|
||||
|
||||
pulsesModuleSettingsUpdate(module);
|
||||
}
|
||||
|
||||
ModulePage::ModulePage(uint8_t moduleIdx) : Page(ICON_MODEL_SETUP)
|
||||
|
||||
@@ -27,11 +27,8 @@ enum ChannelsProtocols {
|
||||
PROTOCOL_CHANNELS_UNINITIALIZED,
|
||||
PROTOCOL_CHANNELS_NONE,
|
||||
PROTOCOL_CHANNELS_PPM,
|
||||
PROTOCOL_CHANNELS_PPM_MLINK,
|
||||
PROTOCOL_CHANNELS_PXX1,
|
||||
PROTOCOL_CHANNELS_DSM2_LP45,
|
||||
PROTOCOL_CHANNELS_DSM2_DSM2,
|
||||
PROTOCOL_CHANNELS_DSM2_DSMX,
|
||||
PROTOCOL_CHANNELS_DSM2,
|
||||
PROTOCOL_CHANNELS_CROSSFIRE,
|
||||
PROTOCOL_CHANNELS_MULTIMODULE,
|
||||
PROTOCOL_CHANNELS_SBUS,
|
||||
@@ -57,5 +54,11 @@ struct etx_proto_driver_t {
|
||||
void (*sendPulses)(void* ctx, uint8_t* buffer, int16_t* channels, uint8_t nChannels);
|
||||
|
||||
// Process input data byte (telemetry)
|
||||
void (*processData)(void* context, uint8_t data, uint8_t* buffer, uint8_t* len);
|
||||
void (*processData)(void* ctx, uint8_t data, uint8_t* buffer, uint8_t* len);
|
||||
|
||||
// Some module settings may have been modified
|
||||
void (*onConfigChange)(void* ctx);
|
||||
|
||||
// Module state mode has been modified
|
||||
// void (*onModeChange)(void* ctx, uint8_t old_mode, uint8_t new_mode);
|
||||
};
|
||||
|
||||
+56
-22
@@ -37,51 +37,68 @@
|
||||
#define BAD_DATA 0x47
|
||||
|
||||
#define DSM2_BITRATE 125000
|
||||
#define DSM2_FRAME_SIZE 14
|
||||
|
||||
static bool _bind_restart = false;
|
||||
|
||||
static inline void sendByte(uint8_t*& p_buf, uint8_t b)
|
||||
{
|
||||
*p_buf++ = b;
|
||||
}
|
||||
|
||||
static void setupPulsesDSM2(uint8_t module, uint8_t*& p_buf)
|
||||
static void setupPulsesDSM2(uint8_t module, uint8_t type, uint8_t*& p_buf)
|
||||
{
|
||||
uint8_t dsmDat[14];
|
||||
uint8_t dsmDat[DSM2_FRAME_SIZE];
|
||||
|
||||
switch (moduleState[module].protocol) {
|
||||
case PROTOCOL_CHANNELS_DSM2_LP45:
|
||||
switch (type) {
|
||||
case DSM2_PROTO_LP45:
|
||||
dsmDat[0] = 0x00;
|
||||
break;
|
||||
case PROTOCOL_CHANNELS_DSM2_DSM2:
|
||||
case DSM2_PROTO_DSM2:
|
||||
dsmDat[0] = 0x10;
|
||||
break;
|
||||
default: // DSMX
|
||||
default: // DSM2_PROTO_DSMX
|
||||
dsmDat[0] = 0x10 | DSMX_BIT;
|
||||
break;
|
||||
}
|
||||
|
||||
if (moduleState[module].mode == MODULE_MODE_BIND) {
|
||||
|
||||
// The module is set to OFF during one second,
|
||||
// before BIND starts. It will start with bind packets
|
||||
// directly after restarts.
|
||||
if (!_bind_restart) {
|
||||
_bind_restart = true;
|
||||
// approx 1.1s @ 22ms cycle
|
||||
restartModuleAsync(module, 50);
|
||||
}
|
||||
|
||||
dsmDat[0] |= DSM2_SEND_BIND;
|
||||
} else {
|
||||
_bind_restart = false;
|
||||
}
|
||||
else if (moduleState[module].mode == MODULE_MODE_RANGECHECK) {
|
||||
|
||||
if (moduleState[module].mode == MODULE_MODE_RANGECHECK) {
|
||||
dsmDat[0] |= DSM2_SEND_RANGECHECK;
|
||||
}
|
||||
|
||||
dsmDat[1] = g_model.header.modelId[module]; // DSM2 Header second byte for model match
|
||||
|
||||
for (int i=0; i<DSM2_CHANS; i++) {
|
||||
int channel = g_model.moduleData[module].channelsStart+i;
|
||||
int value = channelOutputs[channel] + 2*PPM_CH_CENTER(channel) - 2*PPM_CENTER;
|
||||
uint16_t pulse = limit(0, ((value*13)>>5)+512, 1023);
|
||||
dsmDat[2+2*i] = (i<<2) | ((pulse>>8)&0x03);
|
||||
dsmDat[3+2*i] = pulse & 0xff;
|
||||
for (int i = 0; i < DSM2_CHANS; i++) {
|
||||
int channel = g_model.moduleData[module].channelsStart + i;
|
||||
int value =
|
||||
channelOutputs[channel] + 2 * PPM_CH_CENTER(channel) - 2 * PPM_CENTER;
|
||||
|
||||
uint16_t pulse = limit(0, ((value * 13) >> 5) + 512, 1023);
|
||||
dsmDat[2 + 2 * i] = (i << 2) | ((pulse >> 8) & 0x03);
|
||||
dsmDat[3 + 2 * i] = pulse & 0xff;
|
||||
}
|
||||
|
||||
for (int i=0; i<14; i++) {
|
||||
for (int i = 0; i < DSM2_FRAME_SIZE; i++) {
|
||||
sendByte(p_buf, dsmDat[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define DSMP_BITRATE 115200
|
||||
|
||||
static void setupPulsesLemonDSMP(uint8_t module, uint8_t*& p_buf)
|
||||
@@ -178,7 +195,8 @@ const etx_serial_init dsmUartParams = {
|
||||
.polarity = ETX_Pol_Inverted,
|
||||
};
|
||||
|
||||
static void* dsmInit(uint8_t module, uint32_t baudrate, uint16_t period, bool telemetry)
|
||||
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;
|
||||
@@ -201,20 +219,21 @@ static void* dsmInit(uint8_t module, uint32_t baudrate, uint16_t period, bool t
|
||||
}
|
||||
|
||||
mixerSchedulerSetPeriod(module, period);
|
||||
return (void*)mod_st;
|
||||
return mod_st;
|
||||
}
|
||||
|
||||
static void* dsm2Init(uint8_t module)
|
||||
{
|
||||
return dsmInit(module, DSM2_BITRATE, DSM2_PERIOD, false);
|
||||
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 dsmInit(module, DSMP_BITRATE, 11 * 1000 /* 11ms in us */, true);
|
||||
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;
|
||||
@@ -236,12 +255,25 @@ static void dsm2SendPulses(void* ctx, uint8_t* buffer, int16_t* channels, uint8_
|
||||
|
||||
auto mod_st = (etx_module_state_t*)ctx;
|
||||
auto module = modulePortGetModule(mod_st);
|
||||
auto type = (uint8_t)(uintptr_t)mod_st->user_data;
|
||||
|
||||
auto p_data = buffer;
|
||||
setupPulsesDSM2(module, p_data);
|
||||
setupPulsesDSM2(module, type, p_data);
|
||||
_dsm_send(mod_st, buffer, p_data - buffer);
|
||||
}
|
||||
|
||||
static void dsm2ConfigChange(void* ctx)
|
||||
{
|
||||
auto mod_st = (etx_module_state_t*)ctx;
|
||||
auto module = modulePortGetModule(mod_st);
|
||||
auto type = (uint8_t)(uintptr_t)mod_st->user_data;
|
||||
|
||||
if (type != g_model.moduleData[module].subType) {
|
||||
// restart during next mixer cycle
|
||||
restartModuleAsync(module, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void dsmpSendPulses(void* ctx, uint8_t* buffer, int16_t* channels, uint8_t nChannels)
|
||||
{
|
||||
// TODO:
|
||||
@@ -266,11 +298,12 @@ static void dsmpProcessData(void* ctx, uint8_t data, uint8_t* buffer, uint8_t* l
|
||||
|
||||
// No telemetry
|
||||
const etx_proto_driver_t DSM2Driver = {
|
||||
.protocol = PROTOCOL_CHANNELS_DSM2_LP45,
|
||||
.protocol = PROTOCOL_CHANNELS_DSM2,
|
||||
.init = dsm2Init,
|
||||
.deinit = dsmDeInit,
|
||||
.sendPulses = dsm2SendPulses,
|
||||
.processData = nullptr,
|
||||
.onConfigChange = dsm2ConfigChange,
|
||||
};
|
||||
|
||||
const etx_proto_driver_t DSMPDriver = {
|
||||
@@ -279,4 +312,5 @@ const etx_proto_driver_t DSMPDriver = {
|
||||
.deinit = dsmDeInit,
|
||||
.sendPulses = dsmpSendPulses,
|
||||
.processData = dsmpProcessData,
|
||||
.onConfigChange = nullptr,
|
||||
};
|
||||
|
||||
+69
-35
@@ -98,6 +98,46 @@ static uint32_t setupPulsesPPMModule(uint8_t module, pulse_duration_t*& data)
|
||||
return data - start;
|
||||
}
|
||||
|
||||
typedef void (*ppm_telemetry_fct_t)(uint8_t module, uint8_t data, uint8_t* buffer, uint8_t* len);
|
||||
static ppm_telemetry_fct_t _processTelemetryData;
|
||||
|
||||
static etx_serial_init ppmMLinkSerialParams = {
|
||||
.baudrate = PPM_MSB_BAUDRATE,
|
||||
.encoding = ETX_Encoding_8N1,
|
||||
.direction = ETX_Dir_RX,
|
||||
.polarity = ETX_Pol_Inverted,
|
||||
};
|
||||
|
||||
static bool ppmInitMLinkTelemetry(uint8_t module)
|
||||
{
|
||||
// Try S.PORT hardware USART (requires HW inverters)
|
||||
if (modulePortInitSerial(module, ETX_MOD_PORT_SPORT, &ppmMLinkSerialParams) != nullptr) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// fall-back to softserial
|
||||
if (modulePortInitSerial(module, ETX_MOD_PORT_SPORT_INV, &ppmMLinkSerialParams) != nullptr) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void _init_telemetry(uint8_t module, uint8_t telemetry_type)
|
||||
{
|
||||
switch (telemetry_type) {
|
||||
case PPM_PROTO_TLM_MLINK:
|
||||
if (ppmInitMLinkTelemetry(module)) {
|
||||
_processTelemetryData = processExternalMLinkSerialData;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
_processTelemetryData = nullptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void* ppmInit(uint8_t module)
|
||||
{
|
||||
#if defined(HARDWARE_INTERNAL_MODULE)
|
||||
@@ -116,6 +156,11 @@ static void* ppmInit(uint8_t module)
|
||||
if (!mod_st) return nullptr;
|
||||
|
||||
mixerSchedulerSetPeriod(module, PPM_PERIOD(module));
|
||||
|
||||
uint8_t telemetry_type = g_model.moduleData[module].subType;
|
||||
mod_st->user_data = (void*)(uintptr_t)telemetry_type;
|
||||
|
||||
_init_telemetry(module, telemetry_type);
|
||||
return (void*)mod_st;
|
||||
}
|
||||
|
||||
@@ -123,6 +168,7 @@ static void ppmDeInit(void* ctx)
|
||||
{
|
||||
auto mod_st = (etx_module_state_t*)ctx;
|
||||
modulePortDeInit(mod_st);
|
||||
_processTelemetryData = nullptr;
|
||||
}
|
||||
|
||||
static void ppmSendPulses(void* ctx, uint8_t* buffer, int16_t* channels, uint8_t nChannels)
|
||||
@@ -153,44 +199,32 @@ static void ppmSendPulses(void* ctx, uint8_t* buffer, int16_t* channels, uint8_t
|
||||
mixerSchedulerSetPeriod(module, PPM_PERIOD(module));
|
||||
}
|
||||
|
||||
static void ppmProcessTelemetryData(void* ctx, uint8_t data, uint8_t* buffer, uint8_t* len) {
|
||||
auto mod_st = (etx_module_state_t*)ctx;
|
||||
auto module = modulePortGetModule(mod_st);
|
||||
|
||||
if (_processTelemetryData) {
|
||||
_processTelemetryData(module, data, buffer, len);
|
||||
}
|
||||
}
|
||||
|
||||
static void ppmOnConfigChange(void* ctx)
|
||||
{
|
||||
auto mod_st = (etx_module_state_t*)ctx;
|
||||
auto module = modulePortGetModule(mod_st);
|
||||
|
||||
uint8_t telemetry_type = (uint8_t)(uintptr_t)mod_st->user_data;
|
||||
if (telemetry_type != g_model.moduleData[module].subType) {
|
||||
// restart during next mixer cycle
|
||||
restartModuleAsync(module, 0);
|
||||
}
|
||||
}
|
||||
|
||||
const etx_proto_driver_t PpmDriver = {
|
||||
.protocol = PROTOCOL_CHANNELS_PPM,
|
||||
.init = ppmInit,
|
||||
.deinit = ppmDeInit,
|
||||
.sendPulses = ppmSendPulses,
|
||||
.processData = nullptr,
|
||||
.processData = ppmProcessTelemetryData,
|
||||
.onConfigChange = ppmOnConfigChange,
|
||||
};
|
||||
|
||||
//
|
||||
// additions for PPM with external MLink Module telemetry
|
||||
//
|
||||
|
||||
static void* ppmMLinkInit(uint8_t module);
|
||||
|
||||
const etx_proto_driver_t PpmDriverMLink = {
|
||||
.protocol = PROTOCOL_CHANNELS_PPM_MLINK,
|
||||
.init = ppmMLinkInit,
|
||||
.deinit = ppmDeInit,
|
||||
.sendPulses = ppmSendPulses,
|
||||
.processData = processExternalMLinkSerialData,
|
||||
};
|
||||
|
||||
static etx_serial_init ppmMLinkSerialParams = {
|
||||
.baudrate = PPM_MSB_BAUDRATE,
|
||||
.encoding = ETX_Encoding_8N1,
|
||||
.direction = ETX_Dir_RX,
|
||||
.polarity = ETX_Pol_Inverted,
|
||||
};
|
||||
|
||||
static void* ppmMLinkInit(uint8_t module) {
|
||||
etx_module_state_t *mod_st = (etx_module_state_t *)ppmInit(module);
|
||||
|
||||
if (!mod_st)
|
||||
return nullptr;
|
||||
|
||||
if (!modulePortInitSerial(module, ETX_MOD_PORT_UART, &ppmMLinkSerialParams)) {
|
||||
modulePortInitSerial(module, ETX_MOD_PORT_SPORT_INV, &ppmMLinkSerialParams);
|
||||
}
|
||||
|
||||
return (void*)mod_st;
|
||||
}
|
||||
|
||||
@@ -24,4 +24,3 @@
|
||||
#include "hal/module_driver.h"
|
||||
|
||||
extern const etx_proto_driver_t PpmDriver;
|
||||
extern const etx_proto_driver_t PpmDriverMLink;
|
||||
|
||||
+26
-44
@@ -147,6 +147,11 @@ bool restartModuleAsync(uint8_t module, uint8_t cnt_delay)
|
||||
#endif
|
||||
}
|
||||
|
||||
void pulsesModuleSettingsUpdate(uint8_t module)
|
||||
{
|
||||
moduleState[module].settings_updated = 1;
|
||||
}
|
||||
|
||||
// TODO: this should be moved to PXX2 territory!
|
||||
#if defined(PXX2)
|
||||
// use only for PXX
|
||||
@@ -263,16 +268,7 @@ uint8_t getRequiredProtocol(uint8_t module)
|
||||
|
||||
switch (getModuleType(module)) {
|
||||
case MODULE_TYPE_PPM:
|
||||
switch (g_model.moduleData[module].subType) {
|
||||
case PPM_PROTO_TLM_NONE:
|
||||
protocol = PROTOCOL_CHANNELS_PPM;
|
||||
break;
|
||||
case PPM_PROTO_TLM_MLINK:
|
||||
protocol = PROTOCOL_CHANNELS_PPM_MLINK;
|
||||
break;
|
||||
default:
|
||||
protocol = PROTOCOL_CHANNELS_PPM;
|
||||
}
|
||||
protocol = PROTOCOL_CHANNELS_PPM;
|
||||
break;
|
||||
|
||||
case MODULE_TYPE_XJT_PXX1:
|
||||
@@ -301,25 +297,7 @@ uint8_t getRequiredProtocol(uint8_t module)
|
||||
|
||||
#if defined(DSM2)
|
||||
case MODULE_TYPE_DSM2:
|
||||
protocol = limit<uint8_t>(
|
||||
PROTOCOL_CHANNELS_DSM2_LP45,
|
||||
PROTOCOL_CHANNELS_DSM2_LP45 + g_model.moduleData[module].subType,
|
||||
PROTOCOL_CHANNELS_DSM2_DSMX);
|
||||
// The module is set to OFF during one second before BIND start
|
||||
// TODO: move this to DSM2 driver...
|
||||
{
|
||||
static tmr10ms_t bindStartTime = 0;
|
||||
if (moduleState[module].mode == MODULE_MODE_BIND) {
|
||||
if (bindStartTime == 0) bindStartTime = get_tmr10ms();
|
||||
if ((tmr10ms_t)(get_tmr10ms() - bindStartTime) < 100) {
|
||||
protocol = PROTOCOL_CHANNELS_NONE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
bindStartTime = 0;
|
||||
}
|
||||
}
|
||||
protocol = PROTOCOL_CHANNELS_DSM2;
|
||||
break;
|
||||
#endif
|
||||
|
||||
@@ -432,9 +410,7 @@ static void pulsesEnableModule(uint8_t module, uint8_t protocol)
|
||||
#endif
|
||||
|
||||
#if defined(DSM2)
|
||||
case PROTOCOL_CHANNELS_DSM2_LP45:
|
||||
case PROTOCOL_CHANNELS_DSM2_DSM2:
|
||||
case PROTOCOL_CHANNELS_DSM2_DSMX:
|
||||
case PROTOCOL_CHANNELS_DSM2:
|
||||
_init_module(module, &DSM2Driver);
|
||||
break;
|
||||
#endif
|
||||
@@ -473,9 +449,6 @@ static void pulsesEnableModule(uint8_t module, uint8_t protocol)
|
||||
case PROTOCOL_CHANNELS_PPM:
|
||||
_init_module(module, &PpmDriver);
|
||||
break;
|
||||
case PROTOCOL_CHANNELS_PPM_MLINK:
|
||||
_init_module(module, &PpmDriverMLink);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(INTERNAL_MODULE_AFHDS2A) && defined(AFHDS2)
|
||||
@@ -521,13 +494,15 @@ void pulsesStopModule(uint8_t module)
|
||||
|
||||
static bool _handle_async_restart(uint8_t module)
|
||||
{
|
||||
if (moduleState[module].forced_off) {
|
||||
if (--moduleState[module].counter > 0) {
|
||||
auto& state = moduleState[module];
|
||||
if (state.forced_off) {
|
||||
if (state.counter > 0) {
|
||||
_deinit_module(module);
|
||||
moduleState[module].protocol = PROTOCOL_CHANNELS_NONE;
|
||||
state.protocol = PROTOCOL_CHANNELS_NONE;
|
||||
--state.counter;
|
||||
return true;
|
||||
} else {
|
||||
moduleState[module].forced_off = 0;
|
||||
state.forced_off = 0;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@@ -539,9 +514,8 @@ void pulsesSendNextFrame(uint8_t module)
|
||||
|
||||
uint8_t protocol = getRequiredProtocol(module);
|
||||
|
||||
if (moduleState[module].protocol != protocol ||
|
||||
moduleState[module].forced_off) {
|
||||
// TODO: error checking!
|
||||
auto& state = moduleState[module];
|
||||
if (state.protocol != protocol || state.forced_off) {
|
||||
|
||||
if (_telemetryIsPolling) {
|
||||
// In case the telemetry timer is currently polling the port,
|
||||
@@ -555,16 +529,24 @@ void pulsesSendNextFrame(uint8_t module)
|
||||
pulsesEnableModule(module, protocol);
|
||||
moduleState[module].protocol = protocol;
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
auto mod = &(_module_drivers[module]);
|
||||
if (mod->drv) {
|
||||
|
||||
auto drv = mod->drv;
|
||||
auto ctx = mod->ctx;
|
||||
|
||||
if (state.settings_updated) {
|
||||
if (drv->onConfigChange) drv->onConfigChange(ctx);
|
||||
state.settings_updated = 0;
|
||||
}
|
||||
|
||||
uint8_t channelStart = g_model.moduleData[module].channelsStart;
|
||||
int16_t* channels = &channelOutputs[channelStart];
|
||||
uint8_t nChannels = 16; // TODO: MAX_CHANNELS - channelsStart
|
||||
|
||||
auto drv = mod->drv;
|
||||
auto ctx = mod->ctx;
|
||||
auto buffer = _module_buffers[module]._buffer;
|
||||
drv->sendPulses(ctx, buffer, channels, nChannels);
|
||||
}
|
||||
|
||||
@@ -66,7 +66,8 @@ PACK(struct ModuleState {
|
||||
uint8_t protocol;
|
||||
uint8_t mode:4;
|
||||
uint8_t forced_off:1;
|
||||
uint8_t spare:3;
|
||||
uint8_t settings_updated:1;
|
||||
uint8_t spare:2;
|
||||
uint16_t counter;
|
||||
|
||||
#if defined(PXX2)
|
||||
@@ -174,6 +175,8 @@ void pulsesSetModuleDeInitCb(module_deinit_cb_t cb);
|
||||
void restartModule(uint8_t module);
|
||||
bool restartModuleAsync(uint8_t module, uint8_t cnt_delay);
|
||||
|
||||
void pulsesModuleSettingsUpdate(uint8_t module);
|
||||
|
||||
void setupPulsesPPMTrainer();
|
||||
|
||||
void getModuleStatusString(uint8_t moduleIdx, char * statusText);
|
||||
|
||||
@@ -181,7 +181,7 @@ void mlinkSetDefault(int index, uint16_t id, uint8_t subId, uint8_t instance)
|
||||
storageDirty(EE_MODEL);
|
||||
}
|
||||
|
||||
void processExternalMLinkSerialData(void* ctx, uint8_t data, uint8_t* buffer, uint8_t* len) {
|
||||
void processExternalMLinkSerialData(uint8_t module, uint8_t data, uint8_t* buffer, uint8_t* len) {
|
||||
static bool destuff = false; // byte requires adjustment
|
||||
static bool started = false; // start of frame detected
|
||||
|
||||
|
||||
@@ -65,4 +65,4 @@ void processMLinkPacket(const uint8_t *packet, bool multi);
|
||||
// used by external MLink module driver
|
||||
#define PPM_MSB_BAUDRATE 115200
|
||||
|
||||
void processExternalMLinkSerialData(void* ctx, uint8_t data, uint8_t* buffer, uint8_t* len);
|
||||
void processExternalMLinkSerialData(uint8_t module, uint8_t data, uint8_t* buffer, uint8_t* len);
|
||||
|
||||
@@ -775,8 +775,7 @@ void processDSMBindPacket(uint8_t module, const uint8_t *packet)
|
||||
storageDirty(EE_MODEL);
|
||||
|
||||
moduleState[module].mode = MODULE_MODE_NORMAL;
|
||||
restartModuleAsync(module, 50); // ~200ms
|
||||
|
||||
restartModuleAsync(module, 50); // ~500ms
|
||||
}
|
||||
#if defined(MULTIMODULE)
|
||||
else if (g_model.moduleData[module].type == MODULE_TYPE_MULTIMODULE &&
|
||||
|
||||
@@ -127,7 +127,7 @@ rxStatStruct *getRxStatLabels() {
|
||||
break;
|
||||
#endif
|
||||
case MODULE_TYPE_PPM:
|
||||
if(moduleState[moduleToUse].protocol == PROTOCOL_CHANNELS_PPM_MLINK) {
|
||||
if(g_model.moduleData[moduleToUse].subType == PPM_PROTO_TLM_MLINK) {
|
||||
rxStat.label = STR_RXSTAT_LABEL_RQLY;
|
||||
rxStat.unit = STR_RXSTAT_UNIT_PERCENT;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user