From aaafe445db2f3c510114ea796457090711becfcc Mon Sep 17 00:00:00 2001 From: Raphael Coeffic Date: Wed, 16 Oct 2019 15:29:10 +0200 Subject: [PATCH] Added support for flashing AVR multi on horus targets (#6888) * Added support for flashing AVR multi on horus targets taranis soft serial Added support for flashing AVR multi on horus targets taranis soft serial * Added support for multi V2 signature (hex code) * Check multi signature before flashing * small clean-up * Cosmetics * Fix v2 signature check * Cosmetics --- .../src/gui/common/stdlcd/radio_sdmanager.cpp | 2 + radio/src/io/multi_firmware_update.cpp | 231 +++++++++++++----- radio/src/io/multi_firmware_update.h | 20 +- .../common/arm/stm32/heartbeat_driver.cpp | 3 + .../arm/stm32/rotary_encoder_driver.cpp | 4 + radio/src/targets/horus/board.cpp | 1 + radio/src/targets/horus/board.h | 3 + radio/src/targets/horus/hal.h | 10 + radio/src/targets/horus/telemetry_driver.cpp | 129 +++++++++- radio/src/targets/taranis/board.h | 5 + radio/src/targets/taranis/hal.h | 17 ++ .../src/targets/taranis/telemetry_driver.cpp | 151 +++++++++++- radio/src/trainer.h | 1 + radio/src/translations.cpp | 3 + radio/src/translations.h | 3 + radio/src/translations/cz.h.txt | 3 + radio/src/translations/de.h.txt | 5 +- radio/src/translations/en.h.txt | 3 + radio/src/translations/es.h.txt | 5 +- radio/src/translations/fi.h.txt | 5 +- radio/src/translations/fr.h.txt | 3 + radio/src/translations/it.h.txt | 5 +- radio/src/translations/nl.h.txt | 5 +- radio/src/translations/pl.h.txt | 5 +- radio/src/translations/pt.h.txt | 5 +- radio/src/translations/se.h.txt | 5 +- 26 files changed, 544 insertions(+), 88 deletions(-) diff --git a/radio/src/gui/common/stdlcd/radio_sdmanager.cpp b/radio/src/gui/common/stdlcd/radio_sdmanager.cpp index d15c1243c..88bfea658 100644 --- a/radio/src/gui/common/stdlcd/radio_sdmanager.cpp +++ b/radio/src/gui/common/stdlcd/radio_sdmanager.cpp @@ -220,6 +220,7 @@ void onSdManagerMenu(const char * result) FrskyDeviceFirmwareUpdate device(SPORT_MODULE); device.flashFirmware(lfn); } +#if defined(MULTIMODULE) #if defined(INTERNAL_MODULE_MULTI) else if (result == STR_FLASH_INTERNAL_MULTI) { getSelectionFullPath(lfn); @@ -230,6 +231,7 @@ void onSdManagerMenu(const char * result) getSelectionFullPath(lfn); multiFlashFirmware(EXTERNAL_MODULE, lfn); } +#endif #if defined(BLUETOOTH) else if (result == STR_FLASH_BLUETOOTH_MODULE) { getSelectionFullPath(lfn); diff --git a/radio/src/io/multi_firmware_update.cpp b/radio/src/io/multi_firmware_update.cpp index dcc6d6e7b..bf5ca4105 100644 --- a/radio/src/io/multi_firmware_update.cpp +++ b/radio/src/io/multi_firmware_update.cpp @@ -26,8 +26,6 @@ #define UPDATE_MULTI_EXT_BIN ".bin" -//#define DEBUG_EXT_MODULE_FLASH - class MultiFirmwareUpdateDriver { public: @@ -39,6 +37,7 @@ class MultiFirmwareUpdateDriver virtual bool getByte(uint8_t& byte) const = 0; virtual void sendByte(uint8_t byte) const = 0; virtual void clear() const = 0; + virtual void deinit() const {} private: bool getRxByte(uint8_t& byte) const; @@ -47,6 +46,7 @@ class MultiFirmwareUpdateDriver const char * getDeviceSignature(uint8_t* signature) const; const char * loadAddress(uint32_t offset) const; const char * progPage(uint8_t* buffer, uint16_t size) const; + void leaveProgMode() const; }; #if defined(INTERNAL_MODULE_MULTI) @@ -77,16 +77,21 @@ class MultiInternalUpdateDriver: public MultiFirmwareUpdateDriver { intmoduleFifo.clear(); } + + void deinit() const override + { + clear(); + } }; static const MultiInternalUpdateDriver multiInternalUpdateDriver; #endif -class MultiExternalUpdateDriver: public MultiFirmwareUpdateDriver +class MultiExternalSoftSerialUpdateDriver: public MultiFirmwareUpdateDriver { public: - MultiExternalUpdateDriver() = default; + MultiExternalSoftSerialUpdateDriver() = default; protected: void init() const override @@ -102,7 +107,7 @@ class MultiExternalUpdateDriver: public MultiFirmwareUpdateDriver #endif EXTERNAL_MODULE_ON(); - telemetryPortInit(57600, TELEMETRY_SERIAL_DEFAULT); + telemetryPortInvertedInit(57600); } bool getByte(uint8_t& byte) const override @@ -119,9 +124,15 @@ class MultiExternalUpdateDriver: public MultiFirmwareUpdateDriver { telemetryClearFifo(); } + + void deinit() const override + { + telemetryPortInvertedInit(0); + clear(); + } }; -static const MultiExternalUpdateDriver multiExternalUpdateDriver; +static const MultiExternalSoftSerialUpdateDriver multiExternalSoftSerialUpdateDriver; bool MultiFirmwareUpdateDriver::getRxByte(uint8_t& byte) const { @@ -150,10 +161,10 @@ bool MultiFirmwareUpdateDriver::checkRxByte(uint8_t byte) const const char * MultiFirmwareUpdateDriver::waitForInitialSync() const { - clear(); - uint8_t byte; int retries = 1000; + + clear(); do { // Send sync request sendByte(STK_GET_SYNC); @@ -214,16 +225,14 @@ const char * MultiFirmwareUpdateDriver::loadAddress(uint32_t offset) const const char * MultiFirmwareUpdateDriver::progPage(uint8_t* buffer, uint16_t size) const { sendByte(STK_PROG_PAGE); - // page size 256 - sendByte(1); - sendByte(0); + + // page size + sendByte(size >> 8); + sendByte(size & 0xFF); + // flash/eeprom flag sendByte(0); - // #if defined(DEBUG_EXT_MODULE_FLASH) - // TRACE("writing at 0x%X", writeOffset << 1); - // #endif - for (uint16_t i=0; i < size; i++) { sendByte(buffer[i]); } @@ -245,6 +254,16 @@ const char * MultiFirmwareUpdateDriver::progPage(uint8_t* buffer, uint16_t size) return nullptr; } +void MultiFirmwareUpdateDriver::leaveProgMode() const +{ + sendByte(STK_LEAVE_PROGMODE); + sendByte(CRC_EOP); + + // eat last sync byte + checkRxByte(STK_INSYNC); + deinit(); +} + const char * MultiFirmwareUpdateDriver::flashFirmware(FIL* file, const char* label) const { const char* result = nullptr; @@ -255,24 +274,39 @@ const char * MultiFirmwareUpdateDriver::flashFirmware(FIL* file, const char* lab RTOS_WAIT_MS(500); result = waitForInitialSync(); - if (result != nullptr) + if (result) { + leaveProgMode(); return result; + } unsigned char signature[4]; // 3 bytes signature + STK_OK result = getDeviceSignature(signature); - if (result != nullptr) + if (result) { + leaveProgMode(); return result; + } - uint8_t buffer[256]; // page size = 256 - uint32_t writeOffset = 0x1000; // start offset (word address) + uint8_t buffer[256]; + uint16_t pageSize = 128; + uint32_t writeOffset = 0; + + if (signature[0] != 0x1E) { + leaveProgMode(); + return "Wrong signature"; + } + + if (signature[1] == 0x55 && signature[2] == 0xAA) { + pageSize = 256; + writeOffset = 0x1000; // start offset (word address) + } while (!f_eof(file)) { drawProgressScreen(label, STR_WRITING, file->fptr, file->obj.objsize); UINT count=0; - memclear(buffer, 256); - if (f_read(file, buffer, 256, &count) != FR_OK) { + memclear(buffer, pageSize); + if (f_read(file, buffer, pageSize, &count) != FR_OK) { result = "Error reading file"; break; } @@ -283,28 +317,23 @@ const char * MultiFirmwareUpdateDriver::flashFirmware(FIL* file, const char* lab clear(); result = loadAddress(writeOffset); - if (result != nullptr) { + if (result) { break; } - result = progPage(buffer, 256); - if (result != nullptr) { + result = progPage(buffer, pageSize); + if (result) { break; } - writeOffset += 128; // page / 2 + writeOffset += pageSize / 2; } if (f_eof(file)) { drawProgressScreen(label, STR_WRITING, file->fptr, file->obj.objsize); } - sendByte(STK_LEAVE_PROGMODE); - sendByte(CRC_EOP); - - // eat last sync byte - checkRxByte(STK_INSYNC); - + leaveProgMode(); return result; } @@ -316,19 +345,9 @@ const char * MultiFirmwareUpdateDriver::flashFirmware(FIL* file, const char* lab #define MULTI_SIGN_TELEM_INVERSION_OFFSET 13 #define MULTI_SIGN_VERSION_OFFSET 15 -const char * MultiFirmwareInformation::readMultiFirmwareInformation(const char * filename) +const char * MultiFirmwareInformation::readV1Signature(const char * buffer) { - FIL file; - f_open(&file, filename, FA_READ); - char buffer[MULTI_SIGN_SIZE]; - UINT count; - - f_lseek(&file, f_size(&file) - MULTI_SIGN_SIZE); - if (f_read(&file, buffer, MULTI_SIGN_SIZE, &count) != FR_OK || count != MULTI_SIGN_SIZE) { - return "Error reading file"; - } - - if(!memcmp(buffer, "multi-stm", 9)) + if (!memcmp(buffer, "multi-stm", 9)) boardType = FIRMWARE_MULTI_STM; else if (!memcmp(buffer, "multi-avr", 9)) boardType = FIRMWARE_MULTI_AVR; @@ -348,9 +367,9 @@ const char * MultiFirmwareInformation::readMultiFirmwareInformation(const char * bootloaderCheck = false; if(buffer[MULTI_SIGN_TELEM_TYPE_OFFSET] == 't') - telemetryType = FIRMWARE_MULTI_TELEM_MULTI; + telemetryType = FIRMWARE_MULTI_TELEM_MULTI_STATUS; else if (buffer[MULTI_SIGN_TELEM_TYPE_OFFSET] == 's') - telemetryType = FIRMWARE_MULTI_TELEM_STATUS; + telemetryType = FIRMWARE_MULTI_TELEM_MULTI_TELEMETRY; else telemetryType = FIRMWARE_MULTI_TELEM_NONE; @@ -362,23 +381,115 @@ const char * MultiFirmwareInformation::readMultiFirmwareInformation(const char * return nullptr; } +const char * MultiFirmwareInformation::readV2Signature(const char * buffer) +{ + // new format + uint32_t options = 0; + const char * beg = buffer + 7; + const char * cursor = beg; + while (cursor - beg < 8) { + options <<= 4; + if (*cursor >= '0' && *cursor <= '9') + options |= *cursor - '0'; + else if (*cursor >= 'a' && *cursor <= 'f') + options |= *cursor - 'a' + 10; + else if (*cursor >= 'A' && *cursor <= 'F') + options |= *cursor - 'A' + 10; + else + break; // should be '-' + cursor++; + } + if (cursor - beg < 8) + return "Invalid signature"; -const char * multiFlashFirmware(uint8_t moduleIdx, const char * filename) + boardType = options & 0x3; + optibootSupport = options & 0x80 ? true : false; + telemetryInversion = options & 0x200 ? true : false; + bootloaderCheck = options & 0x100 ? true : false; + + telemetryType = FIRMWARE_MULTI_TELEM_NONE; + if (options & 0x400) + telemetryType = FIRMWARE_MULTI_TELEM_MULTI_STATUS; + if (options & 0x800) + telemetryType = FIRMWARE_MULTI_TELEM_MULTI_TELEMETRY; + + return nullptr; +} + +const char * MultiFirmwareInformation::readMultiFirmwareInformation(const char * filename) { FIL file; - const char * result = nullptr; + if (f_open(&file, filename, FA_READ) != FR_OK) + return "Error opening file"; - const char * ext = getFileExtension(filename); - if (ext && strcasecmp(ext, UPDATE_MULTI_EXT_BIN)) { - return "Wrong file extension"; + const char * err = readMultiFirmwareInformation(&file); + f_close(&file); + + return err; +} + +const char * MultiFirmwareInformation::readMultiFirmwareInformation(FIL * file) +{ + char buffer[MULTI_SIGN_SIZE]; + UINT count; + + if (f_size(file) < MULTI_SIGN_SIZE) + return "File too small"; + + f_lseek(file, f_size(file) - MULTI_SIGN_SIZE); + if (f_read(file, buffer, MULTI_SIGN_SIZE, &count) != FR_OK || count != MULTI_SIGN_SIZE) { + return "Error reading file"; } + if (!memcmp(buffer, "multi-x", 7)) { + return readV2Signature(buffer); + } + + return readV1Signature(buffer); +} + +bool multiFlashFirmware(uint8_t moduleIdx, const char * filename) +{ + FIL file; + if (f_open(&file, filename, FA_READ) != FR_OK) { - return "Error opening file"; + POPUP_WARNING("Not a valid file"); + return false; } + MultiFirmwareInformation firmwareFile; + if (firmwareFile.readMultiFirmwareInformation(&file)) { + f_close(&file); + POPUP_WARNING("Not a valid file"); + return false; + } + f_lseek(&file, 0); + + if (moduleIdx == EXTERNAL_MODULE) { + if (!firmwareFile.isMultiExternalFirmware()) { + f_close(&file); + POPUP_WARNING(STR_NEEDS_FILE); + SET_WARNING_INFO(STR_EXT_MULTI_SPEC, strlen(STR_EXT_MULTI_SPEC), 0); + return false; + } + } + else { + if (!firmwareFile.isMultiInternalFirmware()) { + f_close(&file); + POPUP_WARNING(STR_NEEDS_FILE); + SET_WARNING_INFO(STR_INT_MULTI_SPEC, strlen(STR_INT_MULTI_SPEC), 0); + return false; + } + } + + const MultiFirmwareUpdateDriver* driver = &multiExternalSoftSerialUpdateDriver; +#if defined(INTERNAL_MODULE_MULTI) + if (moduleIdx == INTERNAL_MODULE) + driver = &multiInternalUpdateDriver; +#endif + pausePulses(); #if defined(INTERNAL_MODULE_MULTI) @@ -397,14 +508,7 @@ const char * multiFlashFirmware(uint8_t moduleIdx, const char * filename) watchdogSuspend(2000); RTOS_WAIT_MS(2000); - // TODO: real update here - const MultiFirmwareUpdateDriver* driver = &multiExternalUpdateDriver; -#if defined(INTERNAL_MODULE_MULTI) - if (moduleIdx == INTERNAL_MODULE) - driver = &multiInternalUpdateDriver; -#endif - - result = driver->flashFirmware(&file, getBasename(filename)); + const char * result = driver->flashFirmware(&file, getBasename(filename)); f_close(&file); AUDIO_PLAY(AU_SPECIAL_SOUND_BEEP1 ); @@ -425,8 +529,10 @@ const char * multiFlashFirmware(uint8_t moduleIdx, const char * filename) /* wait 2s off */ watchdogSuspend(2000); RTOS_WAIT_MS(2000); - telemetryClearFifo(); + // reset telemetry protocol + telemetryInit(255); + #if defined(INTERNAL_MODULE_MULTI) if (intPwr) { INTERNAL_MODULE_ON(); @@ -439,9 +545,8 @@ const char * multiFlashFirmware(uint8_t moduleIdx, const char * filename) setupPulsesExternalModule(); } - //state = SPORT_IDLE; resumePulses(); - return result; + return result == nullptr; } -#endif \ No newline at end of file +#endif diff --git a/radio/src/io/multi_firmware_update.h b/radio/src/io/multi_firmware_update.h index 45c6f8e91..6713d5cfb 100644 --- a/radio/src/io/multi_firmware_update.h +++ b/radio/src/io/multi_firmware_update.h @@ -21,6 +21,8 @@ #ifndef OPENTX_MULTI_FIRMWARE_H #define OPENTX_MULTI_FIRMWARE_H +#include "ff.h" + /* Signature format is multi-[board type]-[bootloader support][check for bootloader][multi telemetry type][telemetry inversion][debug]-[firmware version] Where: [board type] is avr, stm, or orx @@ -36,15 +38,15 @@ class MultiFirmwareInformation { public: enum MultiFirmwareBoardType { + FIRMWARE_MULTI_AVR = 0, FIRMWARE_MULTI_STM, - FIRMWARE_MULTI_AVR, FIRMWARE_MULTI_ORX, }; enum MultiFirmwareTelemetryType { - FIRMWARE_MULTI_TELEM_MULTI, - FIRMWARE_MULTI_TELEM_STATUS, - FIRMWARE_MULTI_TELEM_NONE, + FIRMWARE_MULTI_TELEM_NONE = 0, + FIRMWARE_MULTI_TELEM_MULTI_STATUS, // erSkyTX + FIRMWARE_MULTI_TELEM_MULTI_TELEMETRY, // OpenTX }; bool isMultiStmFirmware() const @@ -69,15 +71,16 @@ class MultiFirmwareInformation { bool isMultiInternalFirmware() const { - return (boardType == FIRMWARE_MULTI_STM && telemetryInversion == false && optibootSupport == true && telemetryType == FIRMWARE_MULTI_TELEM_STATUS); + return (boardType == FIRMWARE_MULTI_STM && telemetryInversion == false && optibootSupport == true && bootloaderCheck == true && telemetryType == FIRMWARE_MULTI_TELEM_MULTI_TELEMETRY); } bool isMultiExternalFirmware() const { - return (telemetryInversion == false && optibootSupport == true && telemetryType == FIRMWARE_MULTI_TELEM_STATUS); + return (boardType == FIRMWARE_MULTI_STM && telemetryInversion == true && optibootSupport == true && bootloaderCheck == true && telemetryType == FIRMWARE_MULTI_TELEM_MULTI_TELEMETRY); } const char * readMultiFirmwareInformation(const char * filename); + const char * readMultiFirmwareInformation(FIL * file); private: uint8_t boardType; @@ -89,8 +92,11 @@ class MultiFirmwareInformation { uint8_t firmwareVersionMinor; uint8_t firmwareVersionRevision; uint8_t firmwareVersionSubRevision; + + const char * readV1Signature(const char * buffer); + const char * readV2Signature(const char * buffer); }; -const char* multiFlashFirmware(uint8_t module, const char * filename); +bool multiFlashFirmware(uint8_t module, const char * filename); #endif //OPENTX_MULTI_FIRMWARE_H diff --git a/radio/src/targets/common/arm/stm32/heartbeat_driver.cpp b/radio/src/targets/common/arm/stm32/heartbeat_driver.cpp index 926c05c63..70ce2b394 100644 --- a/radio/src/targets/common/arm/stm32/heartbeat_driver.cpp +++ b/radio/src/targets/common/arm/stm32/heartbeat_driver.cpp @@ -83,5 +83,8 @@ void check_intmodule_heartbeat() extern "C" void INTMODULE_HEARTBEAT_EXTI_IRQHandler() { check_intmodule_heartbeat(); + #if defined(TELEMETRY_EXTI_REUSE_INTERRUPT_INTMODULE_HEARTBEAT) + check_telemetry_exti(); + #endif } #endif diff --git a/radio/src/targets/common/arm/stm32/rotary_encoder_driver.cpp b/radio/src/targets/common/arm/stm32/rotary_encoder_driver.cpp index 758043c3a..f43090f04 100644 --- a/radio/src/targets/common/arm/stm32/rotary_encoder_driver.cpp +++ b/radio/src/targets/common/arm/stm32/rotary_encoder_driver.cpp @@ -133,6 +133,10 @@ extern "C" void ROTARY_ENCODER_EXTI_IRQHandler1(void) #if !defined(BOOT) && defined(INTMODULE_HEARTBEAT_REUSE_INTERRUPT_ROTARY_ENCODER) check_intmodule_heartbeat(); #endif + +#if !defined(BOOT) && defined(TELEMETRY_EXTI_REUSE_INTERRUPT_ROTARY_ENCODER) + check_telemetry_exti(); +#endif } #if defined(ROTARY_ENCODER_EXTI_IRQn2) diff --git a/radio/src/targets/horus/board.cpp b/radio/src/targets/horus/board.cpp index 0ec6e9746..db0c28416 100644 --- a/radio/src/targets/horus/board.cpp +++ b/radio/src/targets/horus/board.cpp @@ -120,6 +120,7 @@ void boardInit() HAPTIC_RCC_APB2Periph | INTMODULE_RCC_APB2Periph | EXTMODULE_RCC_APB2Periph | + TELEMETRY_RCC_APB2Periph | BT_RCC_APB2Periph | BACKLIGHT_RCC_APB2Periph, ENABLE); diff --git a/radio/src/targets/horus/board.h b/radio/src/targets/horus/board.h index c9d72c8ab..1ac470fa3 100644 --- a/radio/src/targets/horus/board.h +++ b/radio/src/targets/horus/board.h @@ -568,6 +568,9 @@ bool telemetryGetByte(uint8_t * byte); void telemetryClearFifo(); extern uint32_t telemetryErrors; +// soft-serial +void telemetryPortInvertedInit(uint32_t baudrate); + // Sport update driver #if defined(PCBX10) && !defined(RADIO_T16) void sportUpdatePowerOn(); diff --git a/radio/src/targets/horus/hal.h b/radio/src/targets/horus/hal.h index 0df645d4b..e7afa6ddb 100644 --- a/radio/src/targets/horus/hal.h +++ b/radio/src/targets/horus/hal.h @@ -365,6 +365,7 @@ // Telemetry #define TELEMETRY_RCC_AHB1Periph (RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_DMA1) #define TELEMETRY_RCC_APB1Periph RCC_APB1Periph_USART2 +#define TELEMETRY_RCC_APB2Periph RCC_APB2Periph_TIM10 #define TELEMETRY_DIR_GPIO GPIOD #define TELEMETRY_DIR_GPIO_PIN GPIO_Pin_4 // PD.04 #define TELEMETRY_GPIO GPIOD @@ -374,6 +375,15 @@ #define TELEMETRY_GPIO_PinSource_RX GPIO_PinSource6 #define TELEMETRY_GPIO_AF GPIO_AF_USART2 #define TELEMETRY_USART USART2 +#define TELEMETRY_EXTI_PortSource EXTI_PortSourceGPIOD +#define TELEMETRY_EXTI_PinSource EXTI_PinSource6 +#define TELEMETRY_EXTI_LINE EXTI_Line6 +#define TELEMETRY_EXTI_IRQn EXTI9_5_IRQn +#define TELEMETRY_EXTI_IRQHandler EXTI9_5_IRQHandler +#define TELEMETRY_EXTI_TRIGGER EXTI_Trigger_Rising +#define TELEMETRY_TIMER TIM11 +#define TELEMETRY_TIMER_IRQn TIM1_TRG_COM_TIM11_IRQn +#define TELEMETRY_TIMER_IRQHandler TIM1_TRG_COM_TIM11_IRQHandler #if defined(PCBX12S) #define TELEMETRY_DMA_Stream_RX DMA1_Stream5 #define TELEMETRY_DMA_Channel_RX DMA_Channel_4 diff --git a/radio/src/targets/horus/telemetry_driver.cpp b/radio/src/targets/horus/telemetry_driver.cpp index 2ca7c6c0a..fe143cfe2 100644 --- a/radio/src/targets/horus/telemetry_driver.cpp +++ b/radio/src/targets/horus/telemetry_driver.cpp @@ -28,6 +28,17 @@ DMAFifo telemetryDMAFifo __DMA (TELEMETRY_DMA_Stream_RX); uint8_t telemetryFifoMode; #endif +static void telemetryInitDirPin() +{ + GPIO_InitTypeDef GPIO_InitStructure; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; + GPIO_InitStructure.GPIO_Pin = TELEMETRY_DIR_GPIO_PIN; + GPIO_Init(TELEMETRY_DIR_GPIO, &GPIO_InitStructure); + GPIO_ResetBits(TELEMETRY_DIR_GPIO, TELEMETRY_DIR_GPIO_PIN); +} + void telemetryPortInit(uint32_t baudrate, uint8_t mode) { if (baudrate == 0) { @@ -55,11 +66,7 @@ void telemetryPortInit(uint32_t baudrate, uint8_t mode) GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; GPIO_Init(TELEMETRY_GPIO, &GPIO_InitStructure); - GPIO_InitStructure.GPIO_Pin = TELEMETRY_DIR_GPIO_PIN; - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; - GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; - GPIO_Init(TELEMETRY_DIR_GPIO, &GPIO_InitStructure); - GPIO_ResetBits(TELEMETRY_DIR_GPIO, TELEMETRY_DIR_GPIO_PIN); + telemetryInitDirPin(); USART_InitStructure.USART_BaudRate = baudrate; if (mode & TELEMETRY_SERIAL_8E2) { @@ -126,6 +133,95 @@ void telemetryPortInit(uint32_t baudrate, uint8_t mode) #endif } +// soft serial vars +static uint8_t rxBitCount; +static uint8_t rxByte; + +void telemetryPortInvertedInit(uint32_t baudrate) +{ + if (baudrate == 0) { + NVIC_DisableIRQ(TELEMETRY_EXTI_IRQn); + NVIC_DisableIRQ(TELEMETRY_TIMER_IRQn); + + EXTI_InitTypeDef EXTI_InitStructure; + EXTI_StructInit(&EXTI_InitStructure); + EXTI_InitStructure.EXTI_Line = TELEMETRY_EXTI_LINE; + EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; + EXTI_InitStructure.EXTI_Trigger = TELEMETRY_EXTI_TRIGGER; + EXTI_InitStructure.EXTI_LineCmd = DISABLE; + EXTI_Init(&EXTI_InitStructure); + return; + } + + rxBitCount = 0; + + // configure bit sample timer + RCC->APB2ENR |= RCC_APB2ENR_TIM11EN; + TELEMETRY_TIMER->PSC = (PERI2_FREQUENCY * TIMER_MULT_APB2) / 2000000 - 1; // 0.5uS + TELEMETRY_TIMER->CCER = 0; + TELEMETRY_TIMER->CCMR1 = 0; + TELEMETRY_TIMER->CR1 = TIM_CR1_CEN; + TELEMETRY_TIMER->DIER = TIM_DIER_UIE; + + NVIC_SetPriority(TELEMETRY_TIMER_IRQn, 0); + NVIC_EnableIRQ(TELEMETRY_TIMER_IRQn); + + // init TELEMETRY_RX_GPIO_PIN + GPIO_InitTypeDef GPIO_InitStructure; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN; + GPIO_InitStructure.GPIO_Pin = TELEMETRY_RX_GPIO_PIN; + GPIO_Init(TELEMETRY_GPIO, &GPIO_InitStructure); + + telemetryInitDirPin(); + + // Connect EXTI line to TELEMETRY RX pin + SYSCFG_EXTILineConfig(TELEMETRY_EXTI_PortSource, TELEMETRY_EXTI_PinSource); + + // Configure EXTI for raising edge (start bit) + EXTI_InitTypeDef EXTI_InitStructure; + EXTI_StructInit(&EXTI_InitStructure); + EXTI_InitStructure.EXTI_Line = TELEMETRY_EXTI_LINE; + EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; + EXTI_InitStructure.EXTI_Trigger = TELEMETRY_EXTI_TRIGGER; + EXTI_InitStructure.EXTI_LineCmd = ENABLE; + EXTI_Init(&EXTI_InitStructure); + + NVIC_SetPriority(TELEMETRY_EXTI_IRQn, 0); + NVIC_EnableIRQ(TELEMETRY_EXTI_IRQn); +} + +void telemetryPortInvertedRxBit() +{ + if (rxBitCount < 8) { + if (rxBitCount == 0) { + TELEMETRY_TIMER->ARR = 34; + rxByte = 0; + } + else { + rxByte >>= 1; + } + + if (GPIO_ReadInputDataBit(TELEMETRY_GPIO, TELEMETRY_RX_GPIO_PIN) == Bit_RESET) + rxByte |= 0x80; + + ++rxBitCount; + } + else if (rxBitCount == 8) { + + telemetryNoDMAFifo.push(rxByte); + rxBitCount = 0; + + // disable timer + TELEMETRY_TIMER->CR1 &= ~TIM_CR1_CEN; + + // re-enable start bit interrupt + EXTI->IMR |= EXTI_IMR_MR6; + } +} + void telemetryPortSetDirectionOutput() { TELEMETRY_DIR_GPIO->BSRRL = TELEMETRY_DIR_GPIO_PIN; // output enable @@ -253,6 +349,29 @@ extern "C" void TELEMETRY_USART_IRQHandler(void) } } +extern "C" void TELEMETRY_EXTI_IRQHandler(void) +{ + if (EXTI_GetITStatus(TELEMETRY_EXTI_LINE) != RESET) { + + if (rxBitCount == 0) { + + TELEMETRY_TIMER->ARR = 48; // 1,5 cycle from start at 57600bps + TELEMETRY_TIMER->CR1 |= TIM_CR1_CEN; + + // disable start bit interrupt + EXTI->IMR &= ~EXTI_IMR_MR6; + } + + EXTI_ClearITPendingBit(TELEMETRY_EXTI_LINE); + } +} + +extern "C" void TELEMETRY_TIMER_IRQHandler() +{ + TELEMETRY_TIMER->SR &= ~TIM_SR_UIF; + telemetryPortInvertedRxBit(); +} + // TODO we should have telemetry in an higher layer, functions above should move to a sport_driver.cpp bool telemetryGetByte(uint8_t * byte) { diff --git a/radio/src/targets/taranis/board.h b/radio/src/targets/taranis/board.h index 903d3a19b..e21267199 100644 --- a/radio/src/targets/taranis/board.h +++ b/radio/src/targets/taranis/board.h @@ -192,6 +192,8 @@ void check_intmodule_heartbeat(); #define check_intmodule_heartbeat() #endif +void check_telemetry_exti(); + // SBUS int sbusGetByte(uint8_t * byte); @@ -680,6 +682,9 @@ bool telemetryGetByte(uint8_t * byte); void telemetryClearFifo(); extern uint32_t telemetryErrors; +// soft-serial +void telemetryPortInvertedInit(uint32_t baudrate); + // PCBREV driver #if defined(PCBX7) #define IS_PCBREV_40() (GPIO_ReadInputDataBit(PCBREV_GPIO, PCBREV_GPIO_PIN) == Bit_SET) diff --git a/radio/src/targets/taranis/hal.h b/radio/src/targets/taranis/hal.h index 4a0bb49d7..53cc66618 100644 --- a/radio/src/targets/taranis/hal.h +++ b/radio/src/targets/taranis/hal.h @@ -1284,6 +1284,23 @@ #define TELEMETRY_DMA_TX_FLAG_TC DMA_IT_TCIF6 #define TELEMETRY_USART_IRQHandler USART2_IRQHandler #define TELEMETRY_USART_IRQn USART2_IRQn +#define TELEMETRY_EXTI_PortSource EXTI_PortSourceGPIOD +#define TELEMETRY_EXTI_PinSource EXTI_PinSource6 +#define TELEMETRY_EXTI_LINE EXTI_Line6 +#define TELEMETRY_EXTI_IRQn EXTI9_5_IRQn +#define TELEMETRY_EXTI_TRIGGER EXTI_Trigger_Rising + +#if defined(RADIO_X7) + #define TELEMETRY_EXTI_REUSE_INTERRUPT_ROTARY_ENCODER +#elif defined(PCBXLITE) || defined(PCBX9LITE) || (defined(PCBX9DP) && PCBREV >= 2019) + #define TELEMETRY_EXTI_IRQHandler EXTI9_5_IRQHandler +#else + #define TELEMETRY_EXTI_REUSE_INTERRUPT_INTMODULE_HEARTBEAT +#endif + +#define TELEMETRY_TIMER TIM11 +#define TELEMETRY_TIMER_IRQn TIM1_TRG_COM_TIM11_IRQn +#define TELEMETRY_TIMER_IRQHandler TIM1_TRG_COM_TIM11_IRQHandler // PCBREV #if defined(PCBX7) diff --git a/radio/src/targets/taranis/telemetry_driver.cpp b/radio/src/targets/taranis/telemetry_driver.cpp index b439dc906..3c9618f03 100644 --- a/radio/src/targets/taranis/telemetry_driver.cpp +++ b/radio/src/targets/taranis/telemetry_driver.cpp @@ -23,6 +23,17 @@ Fifo telemetryFifo; uint32_t telemetryErrors = 0; +static void telemetryInitDirPin() +{ + GPIO_InitTypeDef GPIO_InitStructure; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; + GPIO_InitStructure.GPIO_Pin = TELEMETRY_DIR_GPIO_PIN; + GPIO_Init(TELEMETRY_DIR_GPIO, &GPIO_InitStructure); + TELEMETRY_DIR_INPUT(); +} + void telemetryPortInit(uint32_t baudrate, uint8_t mode) { if (baudrate == 0) { @@ -48,11 +59,7 @@ void telemetryPortInit(uint32_t baudrate, uint8_t mode) GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; GPIO_Init(TELEMETRY_GPIO, &GPIO_InitStructure); - GPIO_InitStructure.GPIO_Pin = TELEMETRY_DIR_GPIO_PIN; - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; - GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; - GPIO_Init(TELEMETRY_DIR_GPIO, &GPIO_InitStructure); - TELEMETRY_DIR_INPUT(); + telemetryInitDirPin(); USART_DeInit(TELEMETRY_USART); USART_InitTypeDef USART_InitStructure; @@ -77,6 +84,110 @@ void telemetryPortInit(uint32_t baudrate, uint8_t mode) NVIC_EnableIRQ(TELEMETRY_USART_IRQn); } +// soft serial vars +static uint8_t rxBitCount; +static uint8_t rxByte; + +//TODO: +// - only 57600 supported for now +// - handle other bitrates as well? +// +void telemetryPortInvertedInit(uint32_t baudrate) +{ + if (baudrate == 0) { + + //TODO: + // - handle conflict with HEARTBEAT disabled for trainer input... + // - probably need to stop trainer input/output and restore after this is closed +#if !defined(TELEMETRY_EXTI_REUSE_INTERRUPT_ROTARY_ENCODER) && !defined(TELEMETRY_EXTI_REUSE_INTERRUPT_INTMODULE_HEARTBEAT) + NVIC_DisableIRQ(TELEMETRY_EXTI_IRQn); +#endif + NVIC_DisableIRQ(TELEMETRY_TIMER_IRQn); + + EXTI_InitTypeDef EXTI_InitStructure; + EXTI_StructInit(&EXTI_InitStructure); + EXTI_InitStructure.EXTI_Line = TELEMETRY_EXTI_LINE; + EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; + EXTI_InitStructure.EXTI_Trigger = TELEMETRY_EXTI_TRIGGER; + EXTI_InitStructure.EXTI_LineCmd = DISABLE; + EXTI_Init(&EXTI_InitStructure); + return; + } + + rxBitCount = 0; + + // configure bit sample timer + RCC->APB2ENR |= RCC_APB2ENR_TIM11EN; + TELEMETRY_TIMER->PSC = (PERI2_FREQUENCY * TIMER_MULT_APB2) / 2000000 - 1; // 0.5uS + TELEMETRY_TIMER->CCER = 0; + TELEMETRY_TIMER->CCMR1 = 0; + TELEMETRY_TIMER->CR1 = TIM_CR1_CEN; + TELEMETRY_TIMER->DIER = TIM_DIER_UIE; + + NVIC_SetPriority(TELEMETRY_TIMER_IRQn, 0); + NVIC_EnableIRQ(TELEMETRY_TIMER_IRQn); + + // init TELEMETRY_RX_GPIO_PIN + GPIO_InitTypeDef GPIO_InitStructure; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN; + GPIO_InitStructure.GPIO_Pin = TELEMETRY_RX_GPIO_PIN; + GPIO_Init(TELEMETRY_GPIO, &GPIO_InitStructure); + + telemetryInitDirPin(); + + // Connect EXTI line to TELEMETRY RX pin + SYSCFG_EXTILineConfig(TELEMETRY_EXTI_PortSource, TELEMETRY_EXTI_PinSource); + + // Configure EXTI for raising edge (start bit) + EXTI_InitTypeDef EXTI_InitStructure; + EXTI_StructInit(&EXTI_InitStructure); + EXTI_InitStructure.EXTI_Line = TELEMETRY_EXTI_LINE; + EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; + EXTI_InitStructure.EXTI_Trigger = TELEMETRY_EXTI_TRIGGER; + EXTI_InitStructure.EXTI_LineCmd = ENABLE; + EXTI_Init(&EXTI_InitStructure); + + //TODO: + // - handle conflict with HEARTBEAT disabled for trainer input... + // - probably need to stop trainer input/output and restore after this is closed +#if !defined(TELEMETRY_EXTI_REUSE_INTERRUPT_ROTARY_ENCODER) && !defined(TELEMETRY_EXTI_REUSE_INTERRUPT_INTMODULE_HEARTBEAT) + NVIC_SetPriority(TELEMETRY_EXTI_IRQn, 0); + NVIC_EnableIRQ(TELEMETRY_EXTI_IRQn); +#endif +} + +void telemetryPortInvertedRxBit() +{ + if (rxBitCount < 8) { + if (rxBitCount == 0) { + TELEMETRY_TIMER->ARR = 34; + rxByte = 0; + } + else { + rxByte >>= 1; + } + + if (GPIO_ReadInputDataBit(TELEMETRY_GPIO, TELEMETRY_RX_GPIO_PIN) == Bit_RESET) + rxByte |= 0x80; + + ++rxBitCount; + } + else if (rxBitCount == 8) { + + telemetryFifo.push(rxByte); + rxBitCount = 0; + + // disable timer + TELEMETRY_TIMER->CR1 &= ~TIM_CR1_CEN; + + // re-enable start bit interrupt + EXTI->IMR |= EXTI_IMR_MR6; + } +} + void telemetryPortSetDirectionOutput() { TELEMETRY_DIR_OUTPUT(); @@ -217,6 +328,36 @@ extern "C" void TELEMETRY_USART_IRQHandler(void) } } +void check_telemetry_exti() +{ + if (EXTI_GetITStatus(TELEMETRY_EXTI_LINE) != RESET) { + + if (rxBitCount == 0) { + + TELEMETRY_TIMER->ARR = 48; // 1,5 cycle from start at 57600bps + TELEMETRY_TIMER->CR1 |= TIM_CR1_CEN; + + // disable start bit interrupt + EXTI->IMR &= ~EXTI_IMR_MR6; + } + + EXTI_ClearITPendingBit(TELEMETRY_EXTI_LINE); + } +} + +#if defined(TELEMETRY_EXTI_IRQHandler) +extern "C" void TELEMETRY_EXTI_IRQHandler(void) +{ + check_telemetry_exti(); +} +#endif + +extern "C" void TELEMETRY_TIMER_IRQHandler() +{ + TELEMETRY_TIMER->SR &= ~TIM_SR_UIF; + telemetryPortInvertedRxBit(); +} + // TODO we should have telemetry in an higher layer, functions above should move to a sport_driver.cpp bool telemetryGetByte(uint8_t * byte) { diff --git a/radio/src/trainer.h b/radio/src/trainer.h index 6f5549cc7..e3c67acac 100644 --- a/radio/src/trainer.h +++ b/radio/src/trainer.h @@ -35,6 +35,7 @@ extern uint8_t currentTrainerMode; void checkTrainerSignalWarning(); void checkTrainerSettings(); +void forceResetTrainerSettings(); // Needs to be inlined to avoid slow function calls in ISR routines inline void captureTrainerPulses(uint16_t capture) diff --git a/radio/src/translations.cpp b/radio/src/translations.cpp index 55758d390..9f7f8247e 100644 --- a/radio/src/translations.cpp +++ b/radio/src/translations.cpp @@ -677,6 +677,9 @@ const char STR_PROTOCOL_INVALID[] = TR_PROTOCOL_INVALID; const char STR_MODULE_STATUS[] = TR_MODULE_STATUS; const char STR_MODULE_SYNC[] = TR_MODULE_SYNC; const char STR_MULTI_SERVOFREQ[] = TR_MULTI_SERVOFREQ; +const char STR_NEEDS_FILE[] = TR_NEEDS_FILE; +const char STR_EXT_MULTI_SPEC[] = TR_EXT_MULTI_SPEC; +const char STR_INT_MULTI_SPEC[] = TR_INT_MULTI_SPEC; #endif #if LCD_W < 212 diff --git a/radio/src/translations.h b/radio/src/translations.h index 814d2669c..038c4eea1 100644 --- a/radio/src/translations.h +++ b/radio/src/translations.h @@ -537,6 +537,9 @@ extern const char STR_WAITING_FOR_TX[]; #define STR_UPDATE_LIST STR_DELAYDOWN #endif +extern const char STR_NEEDS_FILE[]; +extern const char STR_EXT_MULTI_SPEC[]; +extern const char STR_INT_MULTI_SPEC[]; extern const char STR_CAT_NOT_EMPTY[]; extern const char STR_WARNING[]; extern const char STR_STORAGE_WARNING[]; diff --git a/radio/src/translations/cz.h.txt b/radio/src/translations/cz.h.txt index 2fd44ac86..bb1916f94 100644 --- a/radio/src/translations/cz.h.txt +++ b/radio/src/translations/cz.h.txt @@ -714,6 +714,9 @@ #define TR_SPECTRUM_ANALYSER_EXT "Spektální an. (EXT)" #define TR_SPECTRUM_ANALYSER_INT "Spektální an. (INT)" #define TR_SDCARD_FULL "Plná SD karta" +#define TR_NEEDS_FILE "NEEDS FILE" +#define TR_EXT_MULTI_SPEC "opentx-inv" +#define TR_INT_MULTI_SPEC "stm-opentx-noinv" #define TR_INCOMPATIBLE "Nekompatibilní" #define TR_WARNING "KONTROLA" #define TR_EEPROMWARN "EEPROM" diff --git a/radio/src/translations/de.h.txt b/radio/src/translations/de.h.txt index bd92d701d..9ca6518ae 100644 --- a/radio/src/translations/de.h.txt +++ b/radio/src/translations/de.h.txt @@ -715,7 +715,10 @@ #define TR_POWER_METER_INT "Power Meter (INT)" #define TR_SPECTRUM_ANALYSER_EXT "Spectrum (EXT)" #define TR_SPECTRUM_ANALYSER_INT "Spectrum (INT)" -#define TR_SDCARD_FULL "SD-Karte voll" +#define TR_SDCARD_FULL "SD-Karte voll" +#define TR_NEEDS_FILE "NEEDS FILE" +#define TR_EXT_MULTI_SPEC "opentx-inv" +#define TR_INT_MULTI_SPEC "stm-opentx-noinv" #define TR_INCOMPATIBLE "Nicht kompatibel" #define TR_WARNING "WARNUNG" #define TR_EEPROMWARN "EEPROM" diff --git a/radio/src/translations/en.h.txt b/radio/src/translations/en.h.txt index c0280a685..1e1f9f2e0 100644 --- a/radio/src/translations/en.h.txt +++ b/radio/src/translations/en.h.txt @@ -715,6 +715,9 @@ #define TR_SPECTRUM_ANALYSER_EXT "Spectrum (EXT)" #define TR_SPECTRUM_ANALYSER_INT "Spectrum (INT)" #define TR_SDCARD_FULL "SD card full" +#define TR_NEEDS_FILE "NEEDS FILE" +#define TR_EXT_MULTI_SPEC "opentx-inv" +#define TR_INT_MULTI_SPEC "stm-opentx-noinv" #define TR_INCOMPATIBLE "Incompatible" #define TR_WARNING "WARNING" #define TR_EEPROMWARN "EEPROM" diff --git a/radio/src/translations/es.h.txt b/radio/src/translations/es.h.txt index 49c469444..f68de52c7 100644 --- a/radio/src/translations/es.h.txt +++ b/radio/src/translations/es.h.txt @@ -738,7 +738,10 @@ #define TR_POWER_METER_INT "Power Meter (INT)" #define TR_SPECTRUM_ANALYSER_EXT "Spectrum (EXT)" #define TR_SPECTRUM_ANALYSER_INT "Spectrum (INT)" -#define TR_SDCARD_FULL "SD Card Full" +#define TR_SDCARD_FULL "SD Card Full" +#define TR_NEEDS_FILE "NEEDS FILE" +#define TR_EXT_MULTI_SPEC "opentx-inv" +#define TR_INT_MULTI_SPEC "stm-opentx-noinv" #define TR_INCOMPATIBLE "Incompatible" #define TR_WARNING "AVISO" #define TR_EEPROMWARN "EEPROM" diff --git a/radio/src/translations/fi.h.txt b/radio/src/translations/fi.h.txt index 6773fc1aa..490dfc35b 100644 --- a/radio/src/translations/fi.h.txt +++ b/radio/src/translations/fi.h.txt @@ -732,7 +732,10 @@ #define TR_POWER_METER_INT "Power Meter (INT)" #define TR_SPECTRUM_ANALYSER_EXT "Spectrum (EXT)" #define TR_SPECTRUM_ANALYSER_INT "Spectrum (INT)" -#define TR_SDCARD_FULL "SD Card Full" +#define TR_SDCARD_FULL "SD Card Full" +#define TR_NEEDS_FILE "NEEDS FILE" +#define TR_EXT_MULTI_SPEC "opentx-inv" +#define TR_INT_MULTI_SPEC "stm-opentx-noinv" #define TR_INCOMPATIBLE "Incompatible" #define TR_WARNING "WARNING" #define TR_EEPROMWARN "FINSKA" diff --git a/radio/src/translations/fr.h.txt b/radio/src/translations/fr.h.txt index 5e42b17c4..be2e60f4b 100644 --- a/radio/src/translations/fr.h.txt +++ b/radio/src/translations/fr.h.txt @@ -736,6 +736,9 @@ #define TR_SPECTRUM_ANALYSER_EXT TR("Spectre (EXT)", "Analyseur spectre (EXT)") #define TR_SPECTRUM_ANALYSER_INT TR("Spectre (INT)", "Analyseur spectre (INT)") #define TR_SDCARD_FULL "Carte SD pleine" +#define TR_NEEDS_FILE "NEEDS FILE" +#define TR_EXT_MULTI_SPEC "opentx-inv" +#define TR_INT_MULTI_SPEC "stm-opentx-noinv" #define TR_INCOMPATIBLE "Incompatible" #define TR_WARNING "ALERTE" #define TR_EEPROMWARN "EEPROM" diff --git a/radio/src/translations/it.h.txt b/radio/src/translations/it.h.txt index 2a53c794c..167f8240d 100644 --- a/radio/src/translations/it.h.txt +++ b/radio/src/translations/it.h.txt @@ -733,7 +733,10 @@ #define TR_POWER_METER_INT "Power Meter (INT)" #define TR_SPECTRUM_ANALYSER_EXT "Spectrum (EXT)" #define TR_SPECTRUM_ANALYSER_INT "Spectrum (INT)" -#define TR_SDCARD_FULL "SD Card Piena" +#define TR_SDCARD_FULL "SD Card Piena" +#define TR_NEEDS_FILE "NEEDS FILE" +#define TR_EXT_MULTI_SPEC "opentx-inv" +#define TR_INT_MULTI_SPEC "stm-opentx-noinv" #define TR_INCOMPATIBLE "Incompatibile" #define TR_WARNING "AVVISO" #define TR_EEPROMWARN "EEPROM" diff --git a/radio/src/translations/nl.h.txt b/radio/src/translations/nl.h.txt index 21ea8354b..f57f1eb75 100644 --- a/radio/src/translations/nl.h.txt +++ b/radio/src/translations/nl.h.txt @@ -720,7 +720,10 @@ #define TR_POWER_METER_INT "Power Meter (INT)" #define TR_SPECTRUM_ANALYSER_EXT "Spectrum (EXT)" #define TR_SPECTRUM_ANALYSER_INT "Spectrum (INT)" -#define TR_SDCARD_FULL "SD-Kaart vol" +#define TR_SDCARD_FULL "SD-Kaart vol" +#define TR_NEEDS_FILE "NEEDS FILE" +#define TR_EXT_MULTI_SPEC "opentx-inv" +#define TR_INT_MULTI_SPEC "stm-opentx-noinv" #define TR_INCOMPATIBLE "Niet compatibel" #define TR_WARNING "MELDING" #define TR_EEPROMWARN "EEPROM" diff --git a/radio/src/translations/pl.h.txt b/radio/src/translations/pl.h.txt index b2d8d9cc9..45c2d3807 100644 --- a/radio/src/translations/pl.h.txt +++ b/radio/src/translations/pl.h.txt @@ -733,7 +733,10 @@ #define TR_POWER_METER_INT "Power Meter (INT)" #define TR_SPECTRUM_ANALYSER_EXT "Spectrum (EXT)" #define TR_SPECTRUM_ANALYSER_INT "Spectrum (INT)" -#define TR_SDCARD_FULL "Karta Pełna " +#define TR_SDCARD_FULL "Karta Pełna " +#define TR_NEEDS_FILE "NEEDS FILE" +#define TR_EXT_MULTI_SPEC "opentx-inv" +#define TR_INT_MULTI_SPEC "stm-opentx-noinv" #define TR_INCOMPATIBLE "Niekompatybilne" #define TR_WARNING "UWAGA" #define TR_EEPROMWARN "EEPROM" diff --git a/radio/src/translations/pt.h.txt b/radio/src/translations/pt.h.txt index 7d0a6d372..217590c1f 100644 --- a/radio/src/translations/pt.h.txt +++ b/radio/src/translations/pt.h.txt @@ -723,7 +723,10 @@ #define TR_POWER_METER_INT "Power Meter (INT)" #define TR_SPECTRUM_ANALYSER_EXT "Spectrum (EXT)" #define TR_SPECTRUM_ANALYSER_INT "Spectrum (INT)" -#define TR_SDCARD_FULL "SD Card Full" +#define TR_SDCARD_FULL "SD Card Full" +#define TR_NEEDS_FILE "NEEDS FILE" +#define TR_EXT_MULTI_SPEC "opentx-inv" +#define TR_INT_MULTI_SPEC "stm-opentx-noinv" #define TR_INCOMPATIBLE "Incompativel" #define TR_WARNING "AVISO" #define TR_EEPROMWARN "EEPROM" diff --git a/radio/src/translations/se.h.txt b/radio/src/translations/se.h.txt index 8b6b86a02..7e6aa1499 100644 --- a/radio/src/translations/se.h.txt +++ b/radio/src/translations/se.h.txt @@ -732,7 +732,10 @@ #define TR_POWER_METER_INT "Power Meter (INT)" #define TR_SPECTRUM_ANALYSER_EXT "Spectrum (EXT)" #define TR_SPECTRUM_ANALYSER_INT "Spectrum (INT)" -#define TR_SDCARD_FULL "SD-kort Fullt" +#define TR_SDCARD_FULL "SD-kort Fullt" +#define TR_NEEDS_FILE "NEEDS FILE" +#define TR_EXT_MULTI_SPEC "opentx-inv" +#define TR_INT_MULTI_SPEC "stm-opentx-noinv" #define TR_INCOMPATIBLE "Inkompatibel" #define TR_WARNING "VARNING" #define TR_EEPROMWARN "EEPROM"