From f4f1602c2903bdfd4bac0fb474822a8644eb7e48 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Mon, 25 Feb 2019 18:08:53 +0100 Subject: [PATCH 01/15] Will only send a fake RX_UID on BIND for now --- radio/src/pulses/pxx2.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/radio/src/pulses/pxx2.cpp b/radio/src/pulses/pxx2.cpp index 6c520643c..4780e77fc 100644 --- a/radio/src/pulses/pxx2.cpp +++ b/radio/src/pulses/pxx2.cpp @@ -143,6 +143,7 @@ bool Pxx2Pulses::setupBindFrame(uint8_t module) for (uint8_t i=0; i Date: Tue, 26 Feb 2019 08:31:13 +0100 Subject: [PATCH 02/15] Telemetry frame updated --- radio/src/telemetry/telemetry.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/radio/src/telemetry/telemetry.cpp b/radio/src/telemetry/telemetry.cpp index 737e22a80..08b4fa62a 100644 --- a/radio/src/telemetry/telemetry.cpp +++ b/radio/src/telemetry/telemetry.cpp @@ -123,7 +123,7 @@ void processBindFrame(uint8_t module, uint8_t * frame) void processTelemetryFrame(uint8_t module, uint8_t * frame) { - sportProcessTelemetryPacketWithoutCrc(&frame[2]); + sportProcessTelemetryPacketWithoutCrc(&frame[3]); } void processSpectrumFrame(uint8_t module, uint8_t * frame) From 98ee035b551ead45fea0f7b3ea661af0f94a14d6 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Wed, 27 Feb 2019 10:00:25 +0100 Subject: [PATCH 03/15] Trace for HJ (Ext module debug) --- radio/src/telemetry/telemetry.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/radio/src/telemetry/telemetry.cpp b/radio/src/telemetry/telemetry.cpp index 08b4fa62a..2051be581 100644 --- a/radio/src/telemetry/telemetry.cpp +++ b/radio/src/telemetry/telemetry.cpp @@ -221,6 +221,7 @@ void telemetryWakeup() #if defined(EXTMODULE_USART) if (extmoduleFifo.getFrame(frame)) { + TRACE("EXT Frame"); processModuleFrame(EXTERNAL_MODULE, frame); } #endif From 8d35e1f1c8232f969c91f95867cd2c0f792f7f26 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Wed, 27 Feb 2019 10:15:46 +0100 Subject: [PATCH 04/15] Trace for HJ (Ext module debug) --- radio/src/targets/taranis/extmodule_driver.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/radio/src/targets/taranis/extmodule_driver.cpp b/radio/src/targets/taranis/extmodule_driver.cpp index 72da992ca..1b3959083 100644 --- a/radio/src/targets/taranis/extmodule_driver.cpp +++ b/radio/src/targets/taranis/extmodule_driver.cpp @@ -181,6 +181,8 @@ void extmoduleSendBuffer(const uint8_t * data, uint8_t size) #define USART_FLAG_ERRORS (USART_FLAG_ORE | USART_FLAG_NE | USART_FLAG_FE | USART_FLAG_PE) extern "C" void EXTMODULE_USART_IRQHandler(void) { + TRACE_NOCRLF("I"); + uint32_t status = EXTMODULE_USART->SR; while (status & (USART_FLAG_RXNE | USART_FLAG_ERRORS)) { From fcc31ef41dcacf47bca2fe7e3b5106995935d478 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Thu, 28 Feb 2019 10:29:24 +0100 Subject: [PATCH 05/15] 450K Bauds on external module --- radio/src/pulses/pxx.h | 2 +- radio/src/targets/taranis/extmodule_driver.cpp | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/radio/src/pulses/pxx.h b/radio/src/pulses/pxx.h index 361ee2930..89993a8c4 100644 --- a/radio/src/pulses/pxx.h +++ b/radio/src/pulses/pxx.h @@ -28,7 +28,7 @@ #define PXX_SEND_RANGECHECK (1 << 5) #if defined(PXX_FREQUENCY_HIGH) - #define EXTMODULE_USART_PXX_BAUDRATE 420000 + #define EXTMODULE_USART_PXX_BAUDRATE 450000 #define INTMODULE_USART_PXX_BAUDRATE 450000 #define PXX_PERIOD 4/*ms*/ #else diff --git a/radio/src/targets/taranis/extmodule_driver.cpp b/radio/src/targets/taranis/extmodule_driver.cpp index 1b3959083..72da992ca 100644 --- a/radio/src/targets/taranis/extmodule_driver.cpp +++ b/radio/src/targets/taranis/extmodule_driver.cpp @@ -181,8 +181,6 @@ void extmoduleSendBuffer(const uint8_t * data, uint8_t size) #define USART_FLAG_ERRORS (USART_FLAG_ORE | USART_FLAG_NE | USART_FLAG_FE | USART_FLAG_PE) extern "C" void EXTMODULE_USART_IRQHandler(void) { - TRACE_NOCRLF("I"); - uint32_t status = EXTMODULE_USART->SR; while (status & (USART_FLAG_RXNE | USART_FLAG_ERRORS)) { From d707860ace7d2b6f75d3abaeffb8a94ff0af64c0 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Mon, 4 Mar 2019 14:04:37 +0100 Subject: [PATCH 06/15] ModuleData splitted from ReceiverData --- radio/src/dataconstants.h | 11 ++-- radio/src/datastructs.h | 33 +++++++++--- radio/src/gui/128x64/model_setup.cpp | 78 +++++++++++++++++++++------- radio/src/pulses/modules.h | 4 +- 4 files changed, 96 insertions(+), 30 deletions(-) diff --git a/radio/src/dataconstants.h b/radio/src/dataconstants.h index beb637a0f..3c34e019c 100644 --- a/radio/src/dataconstants.h +++ b/radio/src/dataconstants.h @@ -37,7 +37,6 @@ #if defined(PCBHORUS) #define MAX_MODELS 60 - #define MAX_RECEIVERS_PER_MODULE 5 #define MAX_OUTPUT_CHANNELS 32 // number of real output channels CH1-CH32 #define MAX_FLIGHT_MODES 9 #define MAX_MIXERS 64 @@ -51,7 +50,6 @@ #define MAX_CUSTOM_SCREENS 5 #elif defined(PCBTARANIS) #define MAX_MODELS 60 - #define MAX_RECEIVERS_PER_MODULE 2 #define MAX_OUTPUT_CHANNELS 32 // number of real output channels CH1-CH32 #define MAX_FLIGHT_MODES 9 #define MAX_MIXERS 64 @@ -64,7 +62,6 @@ #define MAX_TELEMETRY_SENSORS 32 #elif defined(PCBSKY9X) #define MAX_MODELS 60 - #define MAX_RECEIVERS_PER_MODULE 2 #define MAX_OUTPUT_CHANNELS 32 // number of real output channels CH1-CH32 #define MAX_FLIGHT_MODES 9 #define MAX_MIXERS 64 @@ -127,6 +124,14 @@ enum CurveType { #define MAX_CURVE_POINTS 512 #endif +#if defined(PCBHORUS) + #define NUM_RECEIVERS 10 + #define MAX_RECEIVERS_PER_MODULE 5 +#else + #define NUM_RECEIVERS 4 + #define MAX_RECEIVERS_PER_MODULE 4 +#endif + #if defined(PCBTARANIS) || defined(PCBSKY9X) || defined(PCBHORUS) #define NUM_MODULES 2 #else diff --git a/radio/src/datastructs.h b/radio/src/datastructs.h index 1c74bd98b..2aaf97a6d 100644 --- a/radio/src/datastructs.h +++ b/radio/src/datastructs.h @@ -25,6 +25,7 @@ #include "board.h" #include "dataconstants.h" #include "definitions.h" +#include "bitfield.h" #if defined(PCBTARANIS) #define N_TARANIS_FIELD(x) @@ -415,10 +416,13 @@ PACK(struct TrainerModuleData { */ PACK(struct ReceiverData { - uint8_t enabled:1; + uint8_t used:1; uint8_t telemetry:1; - uint8_t spare:6; - uint64_t channelMapping; // each receiver output (16) can be assigned to one of the 16 channels + uint8_t spare:2; + // 5 bits per receiver output (24) as it can be assigned to one of the 24 channels + uint64_t channelMapping0:60; + uint64_t channelMapping1:64; + char name[8]; }); /* @@ -478,8 +482,24 @@ PACK(struct ModuleData { NOBACKUP(struct { uint8_t power:2; // 0=10 mW, 1=100 mW, 2=500 mW, 3=1W uint8_t external_antenna:1; // false = internal antenna, true = external antenna +#if defined(PCBHORUS) uint8_t spare:5; - ReceiverData receivers[MAX_RECEIVERS_PER_MODULE]; + uint32_t receivers; // max 5 receivers per module and 10 receivers in total (4bits per receiver with 0 = unused) +#else + uint8_t spare:1; + uint16_t receivers:12; // max 4 receivers per module and 4 receivers in total (3bits per receiver with 0 = unused) +#endif + NOBACKUP(inline uint8_t getReceiverSlot(uint8_t receiver) { + return (receivers >> (3 * receiver)) & 0b111; + }) + + NOBACKUP(inline void setReceiverSlot(uint8_t receiver, uint8_t slot) { + receivers = BF_SET(receivers, slot, 3 * receiver, 3); + }) + + NOBACKUP(inline void clearReceiverSlot(uint8_t receiver) { + setReceiverSlot(receiver, 0); + }) } pxx2); }; @@ -490,12 +510,10 @@ PACK(struct ModuleData { return ((uint8_t) (rfProtocol & 0x0f)) + (multi.rfProtocolExtra << 4); }) - NOBACKUP(inline void setMultiProtocol(uint8_t proto) - { + NOBACKUP(inline void setMultiProtocol(uint8_t proto) { rfProtocol = (uint8_t) (proto & 0x0f); multi.rfProtocolExtra = (proto & 0x30) >> 4; }) - }); /* @@ -610,6 +628,7 @@ PACK(struct ModelData { NOBACKUP(uint8_t spare:6); NOBACKUP(uint8_t potsWarnMode:2); ModuleData moduleData[NUM_MODULES]; + ReceiverData receiverData[NUM_RECEIVERS]; int16_t failsafeChannels[MAX_OUTPUT_CHANNELS]; TrainerModuleData trainerData; diff --git a/radio/src/gui/128x64/model_setup.cpp b/radio/src/gui/128x64/model_setup.cpp index ee9bdeff2..a5beddc11 100644 --- a/radio/src/gui/128x64/model_setup.cpp +++ b/radio/src/gui/128x64/model_setup.cpp @@ -91,6 +91,14 @@ enum MenuModelSetupItems { ITEM_MODEL_INTERNAL_MODULE_PXX2_RECEIVER_2_PINMAP, ITEM_MODEL_INTERNAL_MODULE_PXX2_RECEIVER_2_TELEM, ITEM_MODEL_INTERNAL_MODULE_PXX2_RECEIVER_2_BIND_SHARE, + ITEM_MODEL_INTERNAL_MODULE_PXX2_RECEIVER_3_LABEL, + ITEM_MODEL_INTERNAL_MODULE_PXX2_RECEIVER_3_PINMAP, + ITEM_MODEL_INTERNAL_MODULE_PXX2_RECEIVER_3_TELEM, + ITEM_MODEL_INTERNAL_MODULE_PXX2_RECEIVER_3_BIND_SHARE, + ITEM_MODEL_INTERNAL_MODULE_PXX2_RECEIVER_4_LABEL, + ITEM_MODEL_INTERNAL_MODULE_PXX2_RECEIVER_4_PINMAP, + ITEM_MODEL_INTERNAL_MODULE_PXX2_RECEIVER_4_TELEM, + ITEM_MODEL_INTERNAL_MODULE_PXX2_RECEIVER_4_BIND_SHARE, #endif ITEM_MODEL_EXTERNAL_MODULE_LABEL, ITEM_MODEL_EXTERNAL_MODULE_MODE, @@ -123,6 +131,14 @@ enum MenuModelSetupItems { ITEM_MODEL_EXTERNAL_MODULE_PXX2_RECEIVER_2_PINMAP, ITEM_MODEL_EXTERNAL_MODULE_PXX2_RECEIVER_2_TELEM, ITEM_MODEL_EXTERNAL_MODULE_PXX2_RECEIVER_2_BIND_SHARE, + ITEM_MODEL_EXTERNAL_MODULE_PXX2_RECEIVER_3_LABEL, + ITEM_MODEL_EXTERNAL_MODULE_PXX2_RECEIVER_3_PINMAP, + ITEM_MODEL_EXTERNAL_MODULE_PXX2_RECEIVER_3_TELEM, + ITEM_MODEL_EXTERNAL_MODULE_PXX2_RECEIVER_3_BIND_SHARE, + ITEM_MODEL_EXTERNAL_MODULE_PXX2_RECEIVER_4_LABEL, + ITEM_MODEL_EXTERNAL_MODULE_PXX2_RECEIVER_4_PINMAP, + ITEM_MODEL_EXTERNAL_MODULE_PXX2_RECEIVER_4_TELEM, + ITEM_MODEL_EXTERNAL_MODULE_PXX2_RECEIVER_4_BIND_SHARE, #if defined(PCBSKY9X) && !defined(REVA) ITEM_MODEL_EXTRA_MODULE_LABEL, ITEM_MODEL_EXTRA_MODULE_CHANNELS, @@ -159,11 +175,11 @@ enum MenuModelSetupItems { #define IF_PXX2_MODULE(module, xxx) (isModulePXX2(module) ? (uint8_t)(xxx) : HIDDEN_ROW) #define IF_NOT_PXX2_MODULE(module, xxx) (isModulePXX2(module) ? HIDDEN_ROW : (uint8_t)(xxx)) -#define IF_PXX2_RECEIVER_DISPLAYED(module, idx, xxx) ((isModulePXX2(module) && g_model.moduleData[module].pxx2.receivers[idx].enabled) ? (uint8_t)(xxx) : HIDDEN_ROW) +#define IF_PXX2_RECEIVER_DISPLAYED(module, idx, xxx) ((isModulePXX2(module) && g_model.moduleData[module].pxx2.getReceiverSlot(idx)) ? (uint8_t)(xxx) : HIDDEN_ROW) #if defined(PCBTARANIS) #define CURRENT_MODULE_EDITED(k) (k >= ITEM_MODEL_EXTERNAL_MODULE_LABEL ? EXTERNAL_MODULE : INTERNAL_MODULE) - #define CURRENT_RECEIVER_EDITED(k) (k >= (k >= ITEM_MODEL_EXTERNAL_MODULE_LABEL ? ITEM_MODEL_EXTERNAL_MODULE_PXX2_RECEIVER_2_LABEL : ITEM_MODEL_INTERNAL_MODULE_PXX2_RECEIVER_2_LABEL) ? 1 : 0) + #define CURRENT_RECEIVER_EDITED(k) ((k - (k >= ITEM_MODEL_EXTERNAL_MODULE_LABEL ? ITEM_MODEL_EXTERNAL_MODULE_PXX2_RECEIVER_1_LABEL : ITEM_MODEL_INTERNAL_MODULE_PXX2_RECEIVER_1_LABEL)) / 4) #elif defined(PCBSKY9X) && !defined(REVA) #define CURRENT_MODULE_EDITED(k) (k >= ITEM_MODEL_EXTRA_MODULE_LABEL ? EXTRA_MODULE : EXTERNAL_MODULE) #else @@ -361,6 +377,16 @@ inline bool isDefaultModelRegistrationID() return memcmp(g_model.modelRegistrationID, g_eeGeneral.ownerRegistrationID, PXX2_LEN_REGISTRATION_ID) == 0; } +uint8_t findEmptyReceiverSlot() +{ + for (uint8_t slot=0; slot 0) { - if (receiverIdx == 0) { - memcpy(&g_model.moduleData[moduleIdx].pxx2.receivers[0], &g_model.moduleData[moduleIdx].pxx2.receivers[1], sizeof(ReceiverData)); - } - memclear(&g_model.moduleData[moduleIdx].pxx2.receivers[1], sizeof(ReceiverData)); // we always remove the second receiver data + g_model.moduleData[moduleIdx].pxx2.receivers = (g_model.moduleData[moduleIdx].pxx2.receivers & BF_MASK(0, receiverIdx * 3)) | ((g_model.moduleData[moduleIdx].pxx2.receivers & BF_MASK((receiverIdx + 1) * 3, (MAX_RECEIVERS_PER_MODULE - 1 - receiverIdx) * 3)) >> 3); + memclear(&g_model.receiverData[receiverSlot], sizeof(ReceiverData)); s_editMode = 0; killEvents(event); storageDirty(EE_MODEL); @@ -1217,18 +1263,14 @@ void menuModelSetup(event_t event) else { lcdDrawText(MODEL_SETUP_2ND_COLUMN, y, STR_RXADD_BUTTON, attr); if (attr && s_editMode > 0) { - if (g_model.moduleData[moduleIdx].pxx2.receivers[0].enabled) { - g_model.moduleData[moduleIdx].pxx2.receivers[1].enabled = 0x01; - memcpy(&g_model.moduleData[moduleIdx].pxx2.receivers[1].channelMapping, DEFAULT_CHANNEL_MAPPING, sizeof(uint64_t)); - } - else { - g_model.moduleData[moduleIdx].pxx2.receivers[0].enabled = 0x01; - memcpy(&g_model.moduleData[moduleIdx].pxx2.receivers[0].channelMapping, DEFAULT_CHANNEL_MAPPING, sizeof(uint64_t)); - } - menuVerticalPosition += 3; s_editMode = 0; killEvents(event); - storageDirty(EE_MODEL); + uint8_t slot = findEmptyReceiverSlot(); + if (slot > 0) { + g_model.moduleData[moduleIdx].pxx2.receivers |= slot << (receiverIdx * 3); + g_model.receiverData[receiverSlot - 1].used = 1; + storageDirty(EE_MODEL); + } } } } @@ -1258,7 +1300,7 @@ void menuModelSetup(event_t event) case ITEM_MODEL_EXTERNAL_MODULE_PXX2_RECEIVER_2_TELEM: { uint8_t receiverIdx = CURRENT_RECEIVER_EDITED(k); - g_model.moduleData[INTERNAL_MODULE].pxx2.receivers[receiverIdx].telemetry = editCheckBox(g_model.moduleData[INTERNAL_MODULE].pxx2.receivers[receiverIdx].telemetry, MODEL_SETUP_2ND_COLUMN, y, INDENT INDENT "Telemetry", attr, event); + // g_model.moduleData[INTERNAL_MODULE].pxx2.receivers[receiverIdx].telemetry = editCheckBox(g_model.moduleData[INTERNAL_MODULE].pxx2.receivers[receiverIdx].telemetry, MODEL_SETUP_2ND_COLUMN, y, INDENT INDENT "Telemetry", attr, event); } break; diff --git a/radio/src/pulses/modules.h b/radio/src/pulses/modules.h index 1d8fd157f..8b07460b6 100644 --- a/radio/src/pulses/modules.h +++ b/radio/src/pulses/modules.h @@ -208,12 +208,12 @@ constexpr int8_t MAX_EXTRA_MODULE_CHANNELS_M8 = 8; // only 16ch PPM inline uint8_t getPinOuput(uint8_t receiverIdx, uint8_t moduleIdx, uint8_t pin) { - return ((g_model.moduleData[moduleIdx].pxx2.receivers[receiverIdx].channelMapping >> (pin + ((pin & 0x01) ? -1 : 1 )) * 4) & 0x0F); + // TODO return ((g_model.moduleData[moduleIdx].pxx2.receivers[receiverIdx].channelMapping >> (pin + ((pin & 0x01) ? -1 : 1 )) * 4) & 0x0F); } inline void setPinOuput(uint8_t receiverIdx, uint8_t moduleIdx, uint8_t pin, uint8_t chan) { - g_model.moduleData[moduleIdx].pxx2.receivers[receiverIdx].channelMapping = BF_SET(g_model.moduleData[moduleIdx].pxx2.receivers[receiverIdx].channelMapping, chan, (pin + ((pin & 0x01) ? -1 : 1 )) * 4, 4); + // TODO g_model.moduleData[moduleIdx].pxx2.receivers[receiverIdx].channelMapping = BF_SET(g_model.moduleData[moduleIdx].pxx2.receivers[receiverIdx].channelMapping, chan, (pin + ((pin & 0x01) ? -1 : 1 )) * 4, 4); } inline int8_t maxModuleChannels_M8(uint8_t idx) From ee956f0a30f8c4bb9648cb180e25763bf815644e Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Mon, 4 Mar 2019 16:45:54 +0100 Subject: [PATCH 07/15] Fixes --- radio/src/datastructs.h | 8 +-- radio/src/gui/128x64/gui.h | 2 - radio/src/gui/128x64/model_setup.cpp | 86 +++++++++++++++++----------- radio/src/pulses/modules.h | 20 +++++-- 4 files changed, 71 insertions(+), 45 deletions(-) diff --git a/radio/src/datastructs.h b/radio/src/datastructs.h index 2aaf97a6d..44a115986 100644 --- a/radio/src/datastructs.h +++ b/radio/src/datastructs.h @@ -416,13 +416,13 @@ PACK(struct TrainerModuleData { */ PACK(struct ReceiverData { + // 5 bits per receiver output (24) as it can be assigned to one of the 24 channels + uint64_t channelMapping0; // 12 first channels (4 bits spare) + uint64_t channelMapping1:60; // 12 last channels uint8_t used:1; uint8_t telemetry:1; uint8_t spare:2; - // 5 bits per receiver output (24) as it can be assigned to one of the 24 channels - uint64_t channelMapping0:60; - uint64_t channelMapping1:64; - char name[8]; + char name[PXX2_LEN_RX_NAME]; }); /* diff --git a/radio/src/gui/128x64/gui.h b/radio/src/gui/128x64/gui.h index cd794dd0e..648e56f14 100644 --- a/radio/src/gui/128x64/gui.h +++ b/radio/src/gui/128x64/gui.h @@ -199,8 +199,6 @@ void title(const char * s); #define SIMPLE_SUBMENU_NOTITLE(lines_count) \ check_submenu_simple(event, (lines_count)-1); - - #endif #define SIMPLE_MENU(title, tab, menu, lines_count) \ diff --git a/radio/src/gui/128x64/model_setup.cpp b/radio/src/gui/128x64/model_setup.cpp index a5beddc11..59fb2ed4d 100644 --- a/radio/src/gui/128x64/model_setup.cpp +++ b/radio/src/gui/128x64/model_setup.cpp @@ -1267,8 +1267,12 @@ void menuModelSetup(event_t event) killEvents(event); uint8_t slot = findEmptyReceiverSlot(); if (slot > 0) { - g_model.moduleData[moduleIdx].pxx2.receivers |= slot << (receiverIdx * 3); - g_model.receiverData[receiverSlot - 1].used = 1; + g_model.moduleData[moduleIdx].pxx2.receivers |= (slot << (receiverIdx * 3)); + --slot; + g_model.receiverData[slot].used = 1; + #warning "USE 32bits copy" + g_model.receiverData[slot].channelMapping0 = (0 << 0) + (1 << 5) + (2 << 10) + (3 << 15) + (4 << 20) + (5 << 25) + ((uint64_t)6 << 30) + ((uint64_t)7 << 35) + ((uint64_t)8 << 40) + ((uint64_t)9 << 45) + ((uint64_t)10 << 50) + ((uint64_t)11 << 55); + g_model.receiverData[slot].channelMapping1 = (12 << 0) + (13 << 5) + (14 << 10) + (15 << 15) + (16 << 20) + (17 << 25) + ((uint64_t)18 << 30) + ((uint64_t)19 << 35) + ((uint64_t)20 << 40) + ((uint64_t)21 << 45) + ((uint64_t)22 << 50) + ((uint64_t)23 << 55); storageDirty(EE_MODEL); } } @@ -1278,17 +1282,19 @@ void menuModelSetup(event_t event) case ITEM_MODEL_INTERNAL_MODULE_PXX2_RECEIVER_1_PINMAP: case ITEM_MODEL_INTERNAL_MODULE_PXX2_RECEIVER_2_PINMAP: + case ITEM_MODEL_INTERNAL_MODULE_PXX2_RECEIVER_3_PINMAP: + case ITEM_MODEL_INTERNAL_MODULE_PXX2_RECEIVER_4_PINMAP: case ITEM_MODEL_EXTERNAL_MODULE_PXX2_RECEIVER_1_PINMAP: case ITEM_MODEL_EXTERNAL_MODULE_PXX2_RECEIVER_2_PINMAP: + case ITEM_MODEL_EXTERNAL_MODULE_PXX2_RECEIVER_3_PINMAP: + case ITEM_MODEL_EXTERNAL_MODULE_PXX2_RECEIVER_4_PINMAP: { - uint8_t receiverIdx = CURRENT_RECEIVER_EDITED(k); - uint8_t moduleIdx = CURRENT_MODULE_EDITED(k); - lcdDrawTextAlignedLeft(y, INDENT INDENT "Pinmap"); lcdDrawText(MODEL_SETUP_2ND_COLUMN, y, STR_SET, attr); if (event == EVT_KEY_BREAK(KEY_ENTER) && attr) { - g_receiverIdx = receiverIdx; - g_moduleIdx = moduleIdx; + uint8_t moduleIdx = CURRENT_MODULE_EDITED(k); + uint8_t receiverIdx = CURRENT_RECEIVER_EDITED(k); + g_receiverIdx = g_model.moduleData[moduleIdx].pxx2.getReceiverSlot(receiverIdx) - 1; pushMenu(menuModelPinmap); } } @@ -1296,24 +1302,39 @@ void menuModelSetup(event_t event) case ITEM_MODEL_INTERNAL_MODULE_PXX2_RECEIVER_1_TELEM: case ITEM_MODEL_INTERNAL_MODULE_PXX2_RECEIVER_2_TELEM: + case ITEM_MODEL_INTERNAL_MODULE_PXX2_RECEIVER_3_TELEM: + case ITEM_MODEL_INTERNAL_MODULE_PXX2_RECEIVER_4_TELEM: case ITEM_MODEL_EXTERNAL_MODULE_PXX2_RECEIVER_1_TELEM: case ITEM_MODEL_EXTERNAL_MODULE_PXX2_RECEIVER_2_TELEM: + case ITEM_MODEL_EXTERNAL_MODULE_PXX2_RECEIVER_3_TELEM: + case ITEM_MODEL_EXTERNAL_MODULE_PXX2_RECEIVER_4_TELEM: { + uint8_t moduleIdx = CURRENT_MODULE_EDITED(k); uint8_t receiverIdx = CURRENT_RECEIVER_EDITED(k); - // g_model.moduleData[INTERNAL_MODULE].pxx2.receivers[receiverIdx].telemetry = editCheckBox(g_model.moduleData[INTERNAL_MODULE].pxx2.receivers[receiverIdx].telemetry, MODEL_SETUP_2ND_COLUMN, y, INDENT INDENT "Telemetry", attr, event); + uint8_t receiverSlot = g_model.moduleData[moduleIdx].pxx2.getReceiverSlot(receiverIdx) - 1; + g_model.receiverData[receiverSlot].telemetry = editCheckBox(g_model.receiverData[receiverSlot].telemetry, MODEL_SETUP_2ND_COLUMN, y, INDENT INDENT "Telemetry", attr, event); + break; } - break; case ITEM_MODEL_INTERNAL_MODULE_PXX2_RECEIVER_1_BIND_SHARE: case ITEM_MODEL_INTERNAL_MODULE_PXX2_RECEIVER_2_BIND_SHARE: + case ITEM_MODEL_INTERNAL_MODULE_PXX2_RECEIVER_3_BIND_SHARE: + case ITEM_MODEL_INTERNAL_MODULE_PXX2_RECEIVER_4_BIND_SHARE: case ITEM_MODEL_EXTERNAL_MODULE_PXX2_RECEIVER_1_BIND_SHARE: case ITEM_MODEL_EXTERNAL_MODULE_PXX2_RECEIVER_2_BIND_SHARE: + case ITEM_MODEL_EXTERNAL_MODULE_PXX2_RECEIVER_3_BIND_SHARE: + case ITEM_MODEL_EXTERNAL_MODULE_PXX2_RECEIVER_4_BIND_SHARE: { - uint8_t receiverIdx = CURRENT_RECEIVER_EDITED(k); uint8_t moduleIdx = CURRENT_MODULE_EDITED(k); + uint8_t receiverIdx = CURRENT_RECEIVER_EDITED(k); + uint8_t receiverSlot = g_model.moduleData[moduleIdx].pxx2.getReceiverSlot(receiverIdx) - 1; - lcdDrawTextAlignedLeft(y, INDENT INDENT "---"); - // TODO later once first telemetry frame received => the RX name + if (zexist(g_model.receiverData[receiverSlot].name, PXX2_LEN_RX_NAME)) { + lcdDrawSizedText(INDENT_WIDTH * 2, y, g_model.receiverData[receiverSlot].name, PXX2_LEN_RX_NAME); + } + else { + lcdDrawTextAlignedLeft(y, INDENT INDENT "---"); + } lcdDrawText(MODEL_SETUP_2ND_COLUMN, y, STR_MODULE_BIND, menuHorizontalPosition==0 ? attr : 0); lcdDrawText(lcdLastRightPos + FW/2, y, BUTTON("Share"), menuHorizontalPosition==1 ? attr : 0); @@ -1880,7 +1901,7 @@ void menuModelFailsafe(event_t event) } // Gauge -#if !defined(PCBX7) && !defined(PCBX3) // X7 LCD doesn't like too many horizontal lines +#if !defined(PCBX7) // X7 LCD doesn't like too many horizontal lines lcdDrawRect(x+LCD_W-3-wbar, y, wbar+1, 6); #endif const uint8_t lenChannel = limit(1, (abs(channelValue) * wbar/2 + lim/2) / lim, wbar/2); @@ -1911,43 +1932,38 @@ void menuModelPinmap(event_t event) SIMPLE_SUBMENU_NOTITLE(sentModuleChannels(g_moduleIdx)); lcdDrawTextAlignedLeft(0, STR_PINMAPSET); - // for (uint8_t pos=0; pos= 8 ? 8 : 0); - - for (uint8_t line = 0; line < 8; line++) { - const int32_t channelValue = channelOutputs[getPinOuput(g_receiverIdx, g_moduleIdx, pin)]; + for (uint8_t i = 0; i < NUM_BODY_LINES; i++) { + coord_t y = MENU_HEADER_HEIGHT + 1 + i*FH; + uint8_t pin = menuVerticalOffset + i; + const int32_t channelValue = channelOutputs[getPinOuput(g_receiverIdx, pin)]; // Pin - lcdDrawText(0, y, "Pin", SMLSIZE); - lcdDrawNumber(lcdLastRightPos + 1, y, pin+1, SMLSIZE); + lcdDrawText(0, y, "Pin"); + lcdDrawNumber(lcdLastRightPos + 1, y, pin+1); // Channel - LcdFlags flags = SMLSIZE; + LcdFlags flags = 0; if (menuVerticalPosition == pin) { flags |= INVERS; if (s_editMode > 0) { - uint8_t channel = getPinOuput(g_receiverIdx, g_moduleIdx, pin); + uint8_t channel = getPinOuput(g_receiverIdx, pin); flags |= BLINK; CHECK_INCDEC_MODELVAR(event, channel, 0, sentModuleChannels(g_moduleIdx)); - setPinOuput(g_receiverIdx, g_moduleIdx, pin, channel); + setPinOuput(g_receiverIdx, pin, channel); } } - putsChn(8*FW, y, getPinOuput(g_receiverIdx, g_moduleIdx, pin)+1, flags); + putsChn(7*FW, y, getPinOuput(g_receiverIdx, pin)+1, flags); // Bargraph +#if !defined(PCBX7) // X7 LCD doesn't like too many horizontal lines + lcdDrawRect(LCD_W-3-wbar, y + 1, wbar+1, 4); +#endif const uint8_t lenChannel = limit(1, (abs(channelValue) * wbar/2 + lim/2) / lim, wbar/2); - const coord_t xChannel = (channelValue>0) ? x+LCD_W-3-wbar/2 : x+LCD_W-2-wbar/2-lenChannel; - lcdDrawHorizontalLine(xChannel, y+1, lenChannel, DOTTED, 0); - lcdDrawHorizontalLine(xChannel, y+2, lenChannel, DOTTED, 0); - - y += FH-1; - if (++pin > sentModuleChannels(g_moduleIdx)) - break; + const coord_t xChannel = (channelValue>0) ? LCD_W-3-wbar/2 : LCD_W-2-wbar/2-lenChannel; + lcdDrawHorizontalLine(xChannel, y+2, lenChannel, SOLID, 0); + lcdDrawHorizontalLine(xChannel, y+3, lenChannel, SOLID, 0); } } diff --git a/radio/src/pulses/modules.h b/radio/src/pulses/modules.h index 8b07460b6..5f8f78afc 100644 --- a/radio/src/pulses/modules.h +++ b/radio/src/pulses/modules.h @@ -206,14 +206,26 @@ static const int8_t maxChannelsXJT[] = { 0, 8, 0, 4 }; // relative to 8! constexpr int8_t MAX_TRAINER_CHANNELS_M8 = MAX_TRAINER_CHANNELS - 8; constexpr int8_t MAX_EXTRA_MODULE_CHANNELS_M8 = 8; // only 16ch PPM -inline uint8_t getPinOuput(uint8_t receiverIdx, uint8_t moduleIdx, uint8_t pin) +inline uint8_t getPinOuput(uint8_t receiverIdx, uint8_t pin) { - // TODO return ((g_model.moduleData[moduleIdx].pxx2.receivers[receiverIdx].channelMapping >> (pin + ((pin & 0x01) ? -1 : 1 )) * 4) & 0x0F); + if (pin < 12) { + return ((g_model.receiverData[receiverIdx].channelMapping0 >> (pin * 5)) & 0x1F); + } + else { + pin -= 12; + return ((g_model.receiverData[receiverIdx].channelMapping1 >> (pin * 5)) & 0x1F); + } } -inline void setPinOuput(uint8_t receiverIdx, uint8_t moduleIdx, uint8_t pin, uint8_t chan) +inline void setPinOuput(uint8_t receiverIdx, uint8_t pin, uint8_t chan) { - // TODO g_model.moduleData[moduleIdx].pxx2.receivers[receiverIdx].channelMapping = BF_SET(g_model.moduleData[moduleIdx].pxx2.receivers[receiverIdx].channelMapping, chan, (pin + ((pin & 0x01) ? -1 : 1 )) * 4, 4); + if (pin < 12) { + g_model.receiverData[receiverIdx].channelMapping0 = BF_SET(g_model.receiverData[receiverIdx].channelMapping0, chan, pin * 5, 5); + } + else { + pin -= 12; + g_model.receiverData[receiverIdx].channelMapping1 = BF_SET(g_model.receiverData[receiverIdx].channelMapping1, chan, pin * 5, 5); + } } inline int8_t maxModuleChannels_M8(uint8_t idx) From d0437be23d4588d30c3e5694819112af82e8cb36 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Mon, 4 Mar 2019 16:57:38 +0100 Subject: [PATCH 08/15] Fixes --- radio/src/gui/128x64/model_setup.cpp | 5 +++-- radio/src/opentx.h | 1 + radio/src/pulses/pxx2.cpp | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/radio/src/gui/128x64/model_setup.cpp b/radio/src/gui/128x64/model_setup.cpp index 59fb2ed4d..ed8131db1 100644 --- a/radio/src/gui/128x64/model_setup.cpp +++ b/radio/src/gui/128x64/model_setup.cpp @@ -264,7 +264,7 @@ enum MenuModelSetupItems { void onPXX2BindMenu(const char * result) { - reusableBuffer.moduleSetup.pxx2.bindSelectedReceiverIndex = (result - reusableBuffer.moduleSetup.pxx2.bindCandidateReceiversNames[0]) / sizeof(reusableBuffer.moduleSetup.pxx2.bindCandidateReceiversNames[0]); + reusableBuffer.moduleSetup.pxx2.bindSelectedReceiverIndex = (result - reusableBuffer.moduleSetup.pxx2.bindCandidateReceiversNames[0]) / PXX2_LEN_RX_NAME; reusableBuffer.moduleSetup.pxx2.bindStep = BIND_RX_NAME_SELECTED; } @@ -1344,6 +1344,7 @@ void menuModelSetup(event_t event) if (event == EVT_KEY_BREAK(KEY_ENTER)) { reusableBuffer.moduleSetup.pxx2.bindStep = BIND_START; reusableBuffer.moduleSetup.pxx2.bindCandidateReceiversCount = 0; + reusableBuffer.moduleSetup.pxx2.bindReceiverSlot = receiverSlot; moduleSettings[moduleIdx].mode ^= MODULE_MODE_BIND; } if (moduleSettings[moduleIdx].mode == MODULE_MODE_BIND) { @@ -1863,7 +1864,7 @@ void menuModelFailsafe(event_t event) const int32_t channelValue = channelOutputs[ch+channelStart]; int32_t failsafeValue = g_model.failsafeChannels[ch]; - //Channel + // Channel putsChn(x+1, y, ch+1, SMLSIZE); // Value diff --git a/radio/src/opentx.h b/radio/src/opentx.h index 9320c228f..0cb5d3bdf 100644 --- a/radio/src/opentx.h +++ b/radio/src/opentx.h @@ -1132,6 +1132,7 @@ union ReusableBuffer char registrationID[PXX2_LEN_REGISTRATION_ID]; char bindCandidateReceiversNames[PXX2_MAX_RECEIVERS_PER_MODULE][PXX2_LEN_RX_NAME]; uint8_t bindCandidateReceiversCount; + uint8_t bindReceiverSlot; union { uint8_t bindSelectedReceiverIndex; uint8_t shareReceiverIndex; diff --git a/radio/src/pulses/pxx2.cpp b/radio/src/pulses/pxx2.cpp index 4780e77fc..9bd209b31 100644 --- a/radio/src/pulses/pxx2.cpp +++ b/radio/src/pulses/pxx2.cpp @@ -143,8 +143,8 @@ bool Pxx2Pulses::setupBindFrame(uint8_t module) for (uint8_t i=0; i Date: Mon, 4 Mar 2019 18:58:08 +0100 Subject: [PATCH 09/15] Fix --- radio/src/pulses/pxx2.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/radio/src/pulses/pxx2.cpp b/radio/src/pulses/pxx2.cpp index 9bd209b31..e30de2bc6 100644 --- a/radio/src/pulses/pxx2.cpp +++ b/radio/src/pulses/pxx2.cpp @@ -134,9 +134,7 @@ bool Pxx2Pulses::setupBindFrame(uint8_t module) reusableBuffer.moduleSetup.pxx2.bindStep = BIND_OK; POPUP_INFORMATION(STR_BIND_OK); } - else { - return false; - } + return false; } else if (reusableBuffer.moduleSetup.pxx2.bindStep == BIND_RX_NAME_SELECTED) { Pxx2Transport::addByte(0x01); From b2e6d0da7ad5a1449727361ec1b6de107e150324 Mon Sep 17 00:00:00 2001 From: 3djc Date: Tue, 5 Mar 2019 09:22:09 +0100 Subject: [PATCH 10/15] Fixed receiver password not sent after reboot --- radio/src/pulses/pxx2.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/radio/src/pulses/pxx2.cpp b/radio/src/pulses/pxx2.cpp index e30de2bc6..28e65947b 100644 --- a/radio/src/pulses/pxx2.cpp +++ b/radio/src/pulses/pxx2.cpp @@ -147,7 +147,7 @@ bool Pxx2Pulses::setupBindFrame(uint8_t module) else { Pxx2Transport::addByte(0x00); for (uint8_t i=0; i Date: Tue, 5 Mar 2019 11:46:39 +0100 Subject: [PATCH 11/15] Fixes (TELEMETRY DATA0 missing) --- radio/src/pulses/pxx2.cpp | 39 +++++++------------ radio/src/pulses/pxx2.h | 25 +++++++----- .../arm/stm32/intmodule_serial_driver.cpp | 3 ++ radio/src/telemetry/telemetry.cpp | 2 +- 4 files changed, 35 insertions(+), 34 deletions(-) diff --git a/radio/src/pulses/pxx2.cpp b/radio/src/pulses/pxx2.cpp index 28e65947b..ad4e2cde5 100644 --- a/radio/src/pulses/pxx2.cpp +++ b/radio/src/pulses/pxx2.cpp @@ -104,7 +104,7 @@ void Pxx2Pulses::setupChannelsFrame(uint8_t module) } } -bool Pxx2Pulses::setupRegisterFrame(uint8_t module) +void Pxx2Pulses::setupRegisterFrame(uint8_t module) { addFrameType(PXX2_TYPE_C_MODULE, PXX2_TYPE_ID_REGISTER); @@ -120,23 +120,22 @@ bool Pxx2Pulses::setupRegisterFrame(uint8_t module) else { Pxx2Transport::addByte(0); } - - return true; // TODO not always } -bool Pxx2Pulses::setupBindFrame(uint8_t module) +void Pxx2Pulses::setupBindFrame(uint8_t module) { - addFrameType(PXX2_TYPE_C_MODULE, PXX2_TYPE_ID_BIND); - if (reusableBuffer.moduleSetup.pxx2.bindStep == BIND_WAIT) { if (get_tmr10ms() > reusableBuffer.moduleSetup.pxx2.bindWaitTimeout) { moduleSettings[module].mode = MODULE_MODE_NORMAL; reusableBuffer.moduleSetup.pxx2.bindStep = BIND_OK; POPUP_INFORMATION(STR_BIND_OK); } - return false; + return; } - else if (reusableBuffer.moduleSetup.pxx2.bindStep == BIND_RX_NAME_SELECTED) { + + addFrameType(PXX2_TYPE_C_MODULE, PXX2_TYPE_ID_BIND); + + if (reusableBuffer.moduleSetup.pxx2.bindStep == BIND_RX_NAME_SELECTED) { Pxx2Transport::addByte(0x01); for (uint8_t i=0; i 1000) { moduleSettings[module].counter = 1002; - return false; + return; } moduleSettings[module].counter = 1002; @@ -174,11 +171,9 @@ bool Pxx2Pulses::setupSpectrumAnalyser(uint8_t module) reusableBuffer.spectrum.step = 100000; // 100KHz Pxx2Transport::addWord(reusableBuffer.spectrum.step); - - return true; } -bool Pxx2Pulses::setupShareMode(uint8_t module) +void Pxx2Pulses::setupShareMode(uint8_t module) { addFrameType(PXX2_TYPE_C_MODULE, PXX2_TYPE_ID_RX_SETUP); @@ -191,24 +186,22 @@ bool Pxx2Pulses::setupShareMode(uint8_t module) } moduleSettings[module].mode = MODULE_MODE_NORMAL; - return true; } -bool Pxx2Pulses::setupFrame(uint8_t module) +void Pxx2Pulses::setupFrame(uint8_t module) { initFrame(); - bool result = true; uint8_t mode = moduleSettings[module].mode; if (mode == MODULE_MODE_REGISTER) - result = setupRegisterFrame(module); + setupRegisterFrame(module); else if (mode == MODULE_MODE_BIND) - result = setupBindFrame(module); + setupBindFrame(module); else if (mode == MODULE_MODE_SPECTRUM_ANALYSER) - result = setupSpectrumAnalyser(module); + setupSpectrumAnalyser(module); else if (mode == MODULE_MODE_SHARE) - result = setupShareMode(module); + setupShareMode(module); else setupChannelsFrame(module); @@ -217,8 +210,6 @@ bool Pxx2Pulses::setupFrame(uint8_t module) } endFrame(); - - return result; } template class PxxPulses; diff --git a/radio/src/pulses/pxx2.h b/radio/src/pulses/pxx2.h index 94d2ed885..117dddbfe 100644 --- a/radio/src/pulses/pxx2.h +++ b/radio/src/pulses/pxx2.h @@ -100,18 +100,18 @@ class Pxx2Transport: public DataBuffer, public Pxx2CrcMixin { class Pxx2Pulses: public PxxPulses { public: - bool setupFrame(uint8_t module); + void setupFrame(uint8_t module); protected: - bool setupRegisterFrame(uint8_t module); + void setupRegisterFrame(uint8_t module); - bool setupBindFrame(uint8_t module); + void setupBindFrame(uint8_t module); - bool setupShareMode(uint8_t module); + void setupShareMode(uint8_t module); void setupChannelsFrame(uint8_t module); - bool setupSpectrumAnalyser(uint8_t module); + void setupSpectrumAnalyser(uint8_t module); void addHead() { @@ -157,11 +157,18 @@ class Pxx2Pulses: public PxxPulses { void endFrame() { - // update the frame LEN = frame length minus the 2 first bytes - data[1] = getSize() - 2; + uint8_t size = getSize() - 2; - // now add the CRC - addCrc(); + if (size > 0) { + // update the frame LEN = frame length minus the 2 first bytes + data[1] = getSize() - 2; + + // now add the CRC + addCrc(); + } + else { + Pxx2Transport::initBuffer(); + } } }; diff --git a/radio/src/targets/common/arm/stm32/intmodule_serial_driver.cpp b/radio/src/targets/common/arm/stm32/intmodule_serial_driver.cpp index 30fcfda33..3cfdb2377 100755 --- a/radio/src/targets/common/arm/stm32/intmodule_serial_driver.cpp +++ b/radio/src/targets/common/arm/stm32/intmodule_serial_driver.cpp @@ -92,6 +92,9 @@ extern "C" void INTMODULE_USART_IRQHandler(void) void intmoduleSendBuffer(const uint8_t * data, uint8_t size) { + if (size == 0) + return; + DMA_InitTypeDef DMA_InitStructure; DMA_DeInit(INTMODULE_DMA_STREAM); DMA_InitStructure.DMA_Channel = INTMODULE_DMA_CHANNEL; diff --git a/radio/src/telemetry/telemetry.cpp b/radio/src/telemetry/telemetry.cpp index 2051be581..459a582b4 100644 --- a/radio/src/telemetry/telemetry.cpp +++ b/radio/src/telemetry/telemetry.cpp @@ -123,7 +123,7 @@ void processBindFrame(uint8_t module, uint8_t * frame) void processTelemetryFrame(uint8_t module, uint8_t * frame) { - sportProcessTelemetryPacketWithoutCrc(&frame[3]); + sportProcessTelemetryPacketWithoutCrc(&frame[2]); } void processSpectrumFrame(uint8_t module, uint8_t * frame) From 57a0aeffbba8538a7ed580a67b05fbb3e18cda99 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Tue, 5 Mar 2019 15:32:38 +0100 Subject: [PATCH 12/15] Fixes --- radio/src/dataconstants.h | 2 +- radio/src/io/frsky_device_firmware_update.cpp | 10 +++++----- radio/src/telemetry/telemetry.cpp | 8 ++++---- radio/src/telemetry/telemetry.h | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/radio/src/dataconstants.h b/radio/src/dataconstants.h index 3c34e019c..7f5a44b3e 100644 --- a/radio/src/dataconstants.h +++ b/radio/src/dataconstants.h @@ -793,7 +793,7 @@ enum BluetoothModes { // PXX2 constants #define PXX2_LEN_REGISTRATION_ID 8 -#define PXX2_LEN_RX_NAME 8 +#define PXX2_LEN_RX_NAME 8 #define PXX2_MAX_RECEIVERS_PER_MODULE 5 #endif // _DATACONSTANTS_H_ diff --git a/radio/src/io/frsky_device_firmware_update.cpp b/radio/src/io/frsky_device_firmware_update.cpp index 2fd6d484e..797cd939e 100644 --- a/radio/src/io/frsky_device_firmware_update.cpp +++ b/radio/src/io/frsky_device_firmware_update.cpp @@ -136,7 +136,7 @@ const uint8_t * DeviceFirmwareUpdate::readFrame(uint32_t timeout) } } -bool DeviceFirmwareUpdate::waitState(State state, uint32_t timeout) +bool DeviceFirmwareUpdate::waitState(State newState, uint32_t timeout) { #if defined(SIMU) UNUSED(state); @@ -150,8 +150,8 @@ bool DeviceFirmwareUpdate::waitState(State state, uint32_t timeout) return false; } - processFrame(&frame[1]); - return state == state; + processFrame(frame); + return state == newState; #endif } @@ -258,11 +258,11 @@ const char * DeviceFirmwareUpdate::uploadFile(const char *filename) count >>= 2; - for (UINT i=0; i> 2; // 32 bit word offset into buffer *((uint32_t *)(frame + 2)) = buffer[offset]; frame[6] = address & 0x000000FF; diff --git a/radio/src/telemetry/telemetry.cpp b/radio/src/telemetry/telemetry.cpp index 459a582b4..05ceab844 100644 --- a/radio/src/telemetry/telemetry.cpp +++ b/radio/src/telemetry/telemetry.cpp @@ -102,19 +102,19 @@ void processBindFrame(uint8_t module, uint8_t * frame) if (frame[3] == 0x00) { bool found = false; for (uint8_t i=0; i Date: Tue, 5 Mar 2019 15:49:01 +0100 Subject: [PATCH 13/15] Wait 1s OFF at the end of flash --- radio/src/io/frsky_device_firmware_update.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/radio/src/io/frsky_device_firmware_update.cpp b/radio/src/io/frsky_device_firmware_update.cpp index 797cd939e..380699487 100644 --- a/radio/src/io/frsky_device_firmware_update.cpp +++ b/radio/src/io/frsky_device_firmware_update.cpp @@ -303,9 +303,9 @@ void DeviceFirmwareUpdate::flashFile(const char * filename) EXTERNAL_MODULE_OFF(); SPORT_UPDATE_POWER_OFF(); - /* wait 2s off */ - watchdogSuspend(2000); - RTOS_WAIT_MS(2000); + /* wait 1s off */ + watchdogSuspend(1000); + RTOS_WAIT_MS(1000); startup(); @@ -328,6 +328,10 @@ void DeviceFirmwareUpdate::flashFile(const char * filename) waitState(SPORT_IDLE, 500); // Clear the fifo + /* wait 1s off */ + watchdogSuspend(1000); + RTOS_WAIT_MS(1000); + if (intPwr) INTERNAL_MODULE_ON(); if (extPwr) From 6c78f934540b3049f32496c1856af3e957fda47e Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Tue, 5 Mar 2019 16:58:12 +0100 Subject: [PATCH 14/15] Trainer / trainee on X-LiteS --- radio/src/main.cpp | 7 -- radio/src/pulses/ppm.cpp | 1 + radio/src/targets/taranis/CMakeLists.txt | 2 +- radio/src/targets/taranis/board.h | 11 ++- radio/src/targets/taranis/hal.h | 53 +++++++++---- radio/src/targets/taranis/trainer_driver.cpp | 80 +++++++++++++++----- 6 files changed, 111 insertions(+), 43 deletions(-) diff --git a/radio/src/main.cpp b/radio/src/main.cpp index 470ff7bec..c7a1ae721 100644 --- a/radio/src/main.cpp +++ b/radio/src/main.cpp @@ -98,13 +98,6 @@ bool isJackPlugged() #endif #if defined(PCBXLITES) -enum JackState -{ - SPEAKER_ACTIVE, - HEADPHONE_ACTIVE, - TRAINER_ACTIVE, -}; - uint8_t jackState = SPEAKER_ACTIVE; const char STR_JACK_HEADPHONE[] = "Headphone"; diff --git a/radio/src/pulses/ppm.cpp b/radio/src/pulses/ppm.cpp index 98099d340..9bf97ffec 100644 --- a/radio/src/pulses/ppm.cpp +++ b/radio/src/pulses/ppm.cpp @@ -53,6 +53,7 @@ void setupPulsesPPM(PpmPulsesData * ppmPulsesData, uint8_t channelsStart, int rest = limit(9000, rest, 65535); /* avoids that CCR2 is bigger than ARR which would cause reboot */ #if defined(STM32) *ppmPulsesData->ptr++ = rest; + *ppmPulsesData->ptr = 0; // it's needed in case PPM is sent without DMA (we stop when we reach this 0) #else *ptr = rest; *(ptr + 1) = 0; diff --git a/radio/src/targets/taranis/CMakeLists.txt b/radio/src/targets/taranis/CMakeLists.txt index ea1057007..1ec29efd5 100644 --- a/radio/src/targets/taranis/CMakeLists.txt +++ b/radio/src/targets/taranis/CMakeLists.txt @@ -170,7 +170,7 @@ else() ) endif() -if(NOT PCB STREQUAL XLITE AND NOT PCB STREQUAL XLITES) +if(NOT PCB STREQUAL XLITE) set(TARGET_SRC ${TARGET_SRC} trainer_driver.cpp diff --git a/radio/src/targets/taranis/board.h b/radio/src/targets/taranis/board.h index 5e2551c48..ae5c7bc5a 100644 --- a/radio/src/targets/taranis/board.h +++ b/radio/src/targets/taranis/board.h @@ -200,8 +200,17 @@ void extmoduleSendNextFrame(); #define SLAVE_MODE() (g_model.trainerData.mode == TRAINER_MODE_SLAVE) #if defined(PCBX9E) #define TRAINER_CONNECTED() (true) -#elif defined(PCBX7) +#elif defined(PCBX7) || defined(PCBX3) #define TRAINER_CONNECTED() (GPIO_ReadInputDataBit(TRAINER_DETECT_GPIO, TRAINER_DETECT_GPIO_PIN) == Bit_SET) +#elif defined(PCBXLITES) + enum JackState + { + SPEAKER_ACTIVE, + HEADPHONE_ACTIVE, + TRAINER_ACTIVE, + }; + extern uint8_t jackState; + #define TRAINER_CONNECTED() (jackState == TRAINER_ACTIVE) #elif defined(PCBXLITE) #define TRAINER_CONNECTED() false // there is no Trainer jack on Taranis X-Lite #else diff --git a/radio/src/targets/taranis/hal.h b/radio/src/targets/taranis/hal.h index 1cece580b..08ddd6aa8 100644 --- a/radio/src/targets/taranis/hal.h +++ b/radio/src/targets/taranis/hal.h @@ -816,33 +816,42 @@ #endif // Trainer Port -#if defined(PCBXLITE) - #define TRAINER_RCC_AHB1Periph 0 - #define TRAINER_RCC_APB1Periph 0 -#elif defined(PCBX3) - #define TRAINER_RCC_AHB1Periph (RCC_AHB1Periph_GPIOD) +#if defined(PCBXLITES) || defined(PCBX3) + // on these 2 radios the trainer port already uses DMA1_Stream6, we won't use the DMA + #define TRAINER_RCC_AHB1Periph RCC_AHB1Periph_GPIOD #define TRAINER_RCC_APB1Periph RCC_APB1Periph_TIM4 #define TRAINER_GPIO GPIOD #define TRAINER_IN_GPIO_PIN GPIO_Pin_13 // PD.13 #define TRAINER_IN_GPIO_PinSource GPIO_PinSource13 #define TRAINER_OUT_GPIO_PIN GPIO_Pin_12 // PD.12 #define TRAINER_OUT_GPIO_PinSource GPIO_PinSource12 +#if defined(PCBX3) #define TRAINER_DETECT_GPIO GPIOD #define TRAINER_DETECT_GPIO_PIN GPIO_Pin_11 // PD.11 +#endif #define TRAINER_TIMER TIM4 #define TRAINER_TIMER_IRQn TIM4_IRQn - #define TRAINER_GPIO_AF GPIO_AF_TIM4 - #define TRAINER_DMA DMA1 - #define TRAINER_DMA_CHANNEL DMA_Channel_5 - #define TRAINER_DMA_STREAM DMA1_Stream2 - #define TRAINER_DMA_IRQn DMA1_Stream2_IRQn - #define TRAINER_DMA_IRQHandler DMA1_Stream2_IRQHandler - #define TRAINER_DMA_FLAG_TC DMA_IT_TCIF2 + #define TRAINER_GPIO_AF GPIO_AF_TIM4 // TIM4_CH1 (Out) + TIM4_CH2 (In) #define TRAINER_TIMER_IRQn TIM4_IRQn #define TRAINER_TIMER_IRQHandler TIM4_IRQHandler #define TRAINER_TIMER_FREQ (PERI1_FREQUENCY * TIMER_MULT_APB1) + #define TRAINER_OUT_CCMR1 TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1PE; + #define TRAINER_IN_CCMR1 TIM_CCMR1_IC2F_0 | TIM_CCMR1_IC2F_1 | TIM_CCMR1_CC2S_0; + #define TRAINER_OUT_COUNTER_REGISTER TRAINER_TIMER->CCR1 + #define TRAINER_IN_COUNTER_REGISTER TRAINER_TIMER->CCR2 + #define TRAINER_SETUP_REGISTER TRAINER_TIMER->CCR3 + #define TRAINER_OUT_INTERRUPT_FLAG TIM_SR_CC3IF + #define TRAINER_OUT_INTERRUPT_ENABLE TIM_DIER_CC3IE + #define TRAINER_IN_INTERRUPT_ENABLE TIM_DIER_CC2IE + #define TRAINER_IN_INTERRUPT_FLAG TIM_SR_CC2IF + #define TRAINER_OUT_CCER TIM_CCER_CC1E + #define TRAINER_CCER_POLARYTY TIM_CCER_CC1P + #define TRAINER_IN_CCER TIM_CCER_CC2E +#elif defined(PCBXLITE) + #define TRAINER_RCC_AHB1Periph 0 + #define TRAINER_RCC_APB1Periph 0 #else - #define TRAINER_RCC_AHB1Periph (RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOC) + #define TRAINER_RCC_AHB1Periph (RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_DMA1) #define TRAINER_RCC_APB1Periph RCC_APB1Periph_TIM3 #define TRAINER_GPIO GPIOC #define TRAINER_IN_GPIO_PIN GPIO_Pin_8 // PC.08 @@ -863,6 +872,18 @@ #define TRAINER_TIMER_IRQn TIM3_IRQn #define TRAINER_TIMER_IRQHandler TIM3_IRQHandler #define TRAINER_TIMER_FREQ (PERI1_FREQUENCY * TIMER_MULT_APB1) + #define TRAINER_OUT_CCMR2 TIM_CCMR2_OC4M_1 | TIM_CCMR2_OC4M_2 | TIM_CCMR2_OC4PE; + #define TRAINER_IN_CCMR2 TIM_CCMR2_IC3F_0 | TIM_CCMR2_IC3F_1 | TIM_CCMR2_CC3S_0; + #define TRAINER_OUT_COUNTER_REGISTER TRAINER_TIMER->CCR4 + #define TRAINER_IN_COUNTER_REGISTER TRAINER_TIMER->CCR3 + #define TRAINER_SETUP_REGISTER TRAINER_TIMER->CCR1 + #define TRAINER_OUT_INTERRUPT_FLAG TIM_SR_CC1IF + #define TRAINER_OUT_INTERRUPT_ENABLE TIM_DIER_CC1IE + #define TRAINER_IN_INTERRUPT_ENABLE TIM_DIER_CC3IE + #define TRAINER_IN_INTERRUPT_FLAG TIM_SR_CC3IF + #define TRAINER_OUT_CCER TIM_CCER_CC4E + #define TRAINER_IN_CCER TIM_CCER_CC3E + #define TRAINER_CCER_POLARYTY TIM_CCER_CC4P #endif // Serial Port @@ -1181,7 +1202,7 @@ #define SD_RCC_AHB1Periph (RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_DMA1) #define SD_RCC_APB1Periph RCC_APB1Periph_SPI2 #define SD_GPIO_PRESENT_GPIO GPIOD -#if defined(PCBXLITE) +#if defined(PCBXLITE) || defined(PCBX3) #define SD_GPIO_PRESENT_GPIO_PIN GPIO_Pin_10 // PD.10 #else #define SD_GPIO_PRESENT_GPIO_PIN GPIO_Pin_9 // PD.09 @@ -1226,8 +1247,8 @@ #define JACK_DETECT_GPIO_PIN GPIO_Pin_13 // PC.13 #define AUDIO_SPEAKER_ENABLE_GPIO GPIOD #define AUDIO_SPEAKER_ENABLE_GPIO_PIN GPIO_Pin_14 // PD.14 - #define HEADPHONE_TRAINER_SWITCH_GPIO GPIOD - #define HEADPHONE_TRAINER_SWITCH_GPIO_PIN GPIO_Pin_13 // PD.13 + #define HEADPHONE_TRAINER_SWITCH_GPIO GPIOD + #define HEADPHONE_TRAINER_SWITCH_GPIO_PIN GPIO_Pin_9 // PD.09 #else #define AUDIO_RCC_AHB1Periph (RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_DMA1) #endif diff --git a/radio/src/targets/taranis/trainer_driver.cpp b/radio/src/targets/taranis/trainer_driver.cpp index 67eb441cb..000c0721b 100644 --- a/radio/src/targets/taranis/trainer_driver.cpp +++ b/radio/src/targets/taranis/trainer_driver.cpp @@ -20,7 +20,9 @@ #include "opentx.h" +#if defined(HEARTBEAT_USART) DMAFifo<32> heartbeatFifo __DMA (HEARTBEAT_DMA_Stream); +#endif void trainerSendNextFrame(); @@ -39,7 +41,11 @@ void init_trainer_ppm() TRAINER_TIMER->CR1 &= ~TIM_CR1_CEN; TRAINER_TIMER->PSC = TRAINER_TIMER_FREQ / 2000000 - 1; // 0.5uS TRAINER_TIMER->ARR = 45000; - TRAINER_TIMER->CCMR2 = TIM_CCMR2_OC4M_1 | TIM_CCMR2_OC4M_2 | TIM_CCMR2_OC4PE; // PWM mode 1 +#if defined(TRAINER_OUT_CCMR1) + TRAINER_TIMER->CCMR1 = TRAINER_OUT_CCMR1; +#elif defined(TRAINER_OUT_CCMR2) + TRAINER_TIMER->CCMR2 = TRAINER_OUT_CCMR2; +#endif TRAINER_TIMER->BDTR = TIM_BDTR_MOE; TRAINER_TIMER->EGR = 1; TRAINER_TIMER->DIER |= TIM_DIER_UDE; @@ -48,18 +54,23 @@ void init_trainer_ppm() setupPulsesPPMTrainer(); trainerSendNextFrame(); +#if defined(TRAINER_DMA_STREAM) NVIC_EnableIRQ(TRAINER_DMA_IRQn); NVIC_SetPriority(TRAINER_DMA_IRQn, 7); +#endif + NVIC_EnableIRQ(TRAINER_TIMER_IRQn); NVIC_SetPriority(TRAINER_TIMER_IRQn, 7); } void stop_trainer_ppm() { +#if defined(TRAINER_DMA_STREAM) NVIC_DisableIRQ(TRAINER_DMA_IRQn); - NVIC_DisableIRQ(TRAINER_TIMER_IRQn); - TRAINER_DMA_STREAM->CR &= ~DMA_SxCR_EN; // Disable DMA +#endif + + NVIC_DisableIRQ(TRAINER_TIMER_IRQn); TRAINER_TIMER->DIER = 0; TRAINER_TIMER->CR1 &= ~TIM_CR1_CEN; // Stop counter } @@ -79,10 +90,14 @@ void init_trainer_capture() TRAINER_TIMER->ARR = 0xFFFF; TRAINER_TIMER->PSC = (PERI1_FREQUENCY * TIMER_MULT_APB1) / 2000000 - 1; // 0.5uS TRAINER_TIMER->CR2 = 0; - TRAINER_TIMER->CCMR2 = TIM_CCMR2_IC3F_0 | TIM_CCMR2_IC3F_1 | TIM_CCMR2_CC3S_0; - TRAINER_TIMER->CCER = TIM_CCER_CC3E; +#if defined(TRAINER_IN_CCMR1) + TRAINER_TIMER->CCMR1 = TRAINER_IN_CCMR1; +#elif defined(TRAINER_IN_CCMR2) + TRAINER_TIMER->CCMR2 = TRAINER_IN_CCMR2; +#endif + TRAINER_TIMER->CCER = TRAINER_IN_CCER; TRAINER_TIMER->SR &= ~TIM_SR_CC3IF & ~TIM_SR_CC2IF & ~TIM_SR_UIF; // Clear flags - TRAINER_TIMER->DIER |= TIM_DIER_CC3IE; + TRAINER_TIMER->DIER |= TRAINER_IN_INTERRUPT_ENABLE; TRAINER_TIMER->CR1 = TIM_CR1_CEN; NVIC_EnableIRQ(TRAINER_TIMER_IRQn); @@ -98,18 +113,26 @@ void stop_trainer_capture() void trainerSendNextFrame() { - TRAINER_TIMER->CCR4 = GET_TRAINER_PPM_DELAY() * 2; - TRAINER_TIMER->CCER = TIM_CCER_CC4E | (GET_TRAINER_PPM_POLARITY() ? 0 : TIM_CCER_CC4P); - TRAINER_TIMER->CCR1 = *(trainerPulsesData.ppm.ptr - 1) - 4000; // 2mS in advance + TRAINER_OUT_COUNTER_REGISTER = GET_TRAINER_PPM_DELAY() * 2; + TRAINER_TIMER->CCER = TRAINER_OUT_CCER | (GET_TRAINER_PPM_POLARITY() ? 0 : TRAINER_CCER_POLARYTY); + TRAINER_SETUP_REGISTER = *(trainerPulsesData.ppm.ptr - 1) - 4000; // 2mS in advance +#if defined(TRAINER_DMA_STREAM) TRAINER_DMA_STREAM->CR &= ~DMA_SxCR_EN; // Disable DMA TRAINER_DMA_STREAM->CR |= TRAINER_DMA_CHANNEL | DMA_SxCR_DIR_0 | DMA_SxCR_MINC | DMA_SxCR_PSIZE_0 | DMA_SxCR_MSIZE_0 | DMA_SxCR_PL_0 | DMA_SxCR_PL_1; TRAINER_DMA_STREAM->PAR = CONVERT_PTR_UINT(&TRAINER_TIMER->ARR); TRAINER_DMA_STREAM->M0AR = CONVERT_PTR_UINT(trainerPulsesData.ppm.pulses); TRAINER_DMA_STREAM->NDTR = trainerPulsesData.ppm.ptr - trainerPulsesData.ppm.pulses; TRAINER_DMA_STREAM->CR |= DMA_SxCR_EN | DMA_SxCR_TCIE; // Enable DMA +#else + trainerPulsesData.ppm.ptr = trainerPulsesData.ppm.pulses; + TRAINER_TIMER->DIER |= TIM_DIER_UDE; + TRAINER_TIMER->SR &= ~TIM_SR_UIF; // Clear this flag + TRAINER_TIMER->DIER |= TIM_DIER_UIE; // Enable this interrupt +#endif } +#if defined(TRAINER_DMA_STREAM) extern "C" void TRAINER_DMA_IRQHandler() { if (!DMA_GetITStatus(TRAINER_DMA_STREAM, TRAINER_DMA_FLAG_TC)) @@ -117,9 +140,10 @@ extern "C" void TRAINER_DMA_IRQHandler() DMA_ClearITPendingBit(TRAINER_DMA_STREAM, TRAINER_DMA_FLAG_TC); - TRAINER_TIMER->SR &= ~TIM_SR_CC1IF; // Clear flag - TRAINER_TIMER->DIER |= TIM_DIER_CC1IE; // Enable this interrupt + TRAINER_TIMER->SR &= ~TRAINER_OUT_INTERRUPT_FLAG; // Clear flag + TRAINER_TIMER->DIER |= TRAINER_OUT_INTERRUPT_ENABLE; // Enable this interrupt } +#endif extern "C" void TRAINER_TIMER_IRQHandler() { @@ -129,14 +153,15 @@ extern "C" void TRAINER_TIMER_IRQHandler() bool doCapture = false; // What mode? in or out? - if ((TRAINER_TIMER->DIER & TIM_DIER_CC3IE) && (TRAINER_TIMER->SR & TIM_SR_CC3IF)) { + if ((TRAINER_TIMER->DIER & TRAINER_IN_INTERRUPT_ENABLE) && (TRAINER_TIMER->SR & TRAINER_IN_INTERRUPT_FLAG)) { // capture mode on trainer jack - capture = TRAINER_TIMER->CCR3; + capture = TRAINER_IN_COUNTER_REGISTER; if (TRAINER_CONNECTED() && currentTrainerMode == TRAINER_MODE_MASTER_TRAINER_JACK) { doCapture = true; } } +#if defined(TRAINER_MODULE_HEARTBEAT) if ((TRAINER_TIMER->DIER & TIM_DIER_CC2IE) && (TRAINER_TIMER->SR & TIM_SR_CC2IF)) { // capture mode on heartbeat pin (external module) capture = TRAINER_TIMER->CCR2; @@ -144,22 +169,36 @@ extern "C" void TRAINER_TIMER_IRQHandler() doCapture = true; } } +#endif if (doCapture) { captureTrainerPulses(capture); } // PPM out compare interrupt - if ((TRAINER_TIMER->DIER & TIM_DIER_CC1IE) && (TRAINER_TIMER->SR & TIM_SR_CC1IF)) { + if ((TRAINER_TIMER->DIER & TRAINER_OUT_INTERRUPT_ENABLE) && (TRAINER_TIMER->SR & TRAINER_OUT_INTERRUPT_FLAG)) { // compare interrupt - TRAINER_TIMER->DIER &= ~TIM_DIER_CC1IE; // stop this interrupt - TRAINER_TIMER->SR &= ~TIM_SR_CC1IF; // Clear flag + TRAINER_TIMER->DIER &= ~TRAINER_OUT_INTERRUPT_ENABLE; // stop this interrupt + TRAINER_TIMER->SR &= ~TRAINER_OUT_INTERRUPT_FLAG; // Clear flag setupPulsesPPMTrainer(); trainerSendNextFrame(); } + +#if !defined(TRAINER_DMA_STREAM) + // PPM out update interrupt + if ((TRAINER_TIMER->DIER & TIM_DIER_UIE) && (TRAINER_TIMER->SR & TIM_SR_UIF)) { + TRAINER_TIMER->SR &= ~TIM_SR_UIF; // Clear flag + TRAINER_TIMER->ARR = *trainerPulsesData.ppm.ptr++; + if (*trainerPulsesData.ppm.ptr == 0) { + TRAINER_TIMER->SR &= ~TRAINER_OUT_INTERRUPT_FLAG; // Clear this flag + TRAINER_TIMER->DIER |= TRAINER_OUT_INTERRUPT_ENABLE; // Enable this interrupt + } + } +#endif } -void init_cppm_on_heartbeat_capture(void) +#if defined(TRAINER_MODULE_HEARTBEAT) +void init_cppm_on_heartbeat_capture() { EXTERNAL_MODULE_ON(); @@ -196,7 +235,9 @@ void stop_cppm_on_heartbeat_capture() EXTERNAL_MODULE_OFF(); } } +#endif +#if defined(HEARTBEAT_USART) void init_sbus_on_heartbeat_capture() { EXTERNAL_MODULE_ON(); @@ -258,13 +299,16 @@ void stop_sbus_on_heartbeat_capture() EXTERNAL_MODULE_OFF(); } } +#endif int sbusGetByte(uint8_t * byte) { switch (currentTrainerMode) { +#if defined(HEARTBEAT_USART) case TRAINER_MODE_MASTER_SBUS_EXTERNAL_MODULE: return heartbeatFifo.pop(*byte); -#if !defined(PCBX7) && !defined(PCBX9E) && !defined(PCBX3) +#endif +#if !defined(PCBX7) && !defined(PCBX9E) && !defined(PCBX3) && !defined(PCBXLITE) case TRAINER_MODE_MASTER_BATTERY_COMPARTMENT: return serial2RxFifo.pop(*byte); #endif From e208c1db696603ebe6c3f3ed502a76ddf7cea619 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Tue, 5 Mar 2019 17:03:42 +0100 Subject: [PATCH 15/15] Remaining trace removed --- radio/src/telemetry/telemetry.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/radio/src/telemetry/telemetry.cpp b/radio/src/telemetry/telemetry.cpp index 05ceab844..ff7c37f34 100644 --- a/radio/src/telemetry/telemetry.cpp +++ b/radio/src/telemetry/telemetry.cpp @@ -221,7 +221,6 @@ void telemetryWakeup() #if defined(EXTMODULE_USART) if (extmoduleFifo.getFrame(frame)) { - TRACE("EXT Frame"); processModuleFrame(EXTERNAL_MODULE, frame); } #endif