feat: ELRS bind command support (#4907)

This commit is contained in:
3djc
2024-06-02 12:03:15 +10:00
committed by GitHub
parent c81c8b5354
commit d45450921d
30 changed files with 174 additions and 29 deletions
+6 -1
View File
@@ -1837,7 +1837,10 @@ void menuModelSetup(event_t event)
l_posHorz += 1;
}
if (isModuleBindRangeAvailable(moduleIdx)) {
lcdDrawText(bindButtonPos, y, STR_MODULE_BIND, l_posHorz == 1 ? attr : 0);
if (TELEMETRY_STREAMING() && isModuleELRS(moduleIdx))
lcdDrawText(bindButtonPos, y, STR_MODULE_UNBIND, l_posHorz == 1 ? attr : 0);
else
lcdDrawText(bindButtonPos, y, STR_MODULE_BIND, l_posHorz == 1 ? attr : 0);
if (isModuleRangeAvailable(moduleIdx)) {
lcdDrawText(lcdNextPos + 2, y, STR_MODULE_RANGE, l_posHorz == 2 ? attr : 0);
}
@@ -1881,6 +1884,8 @@ void menuModelSetup(event_t event)
}
else {
newFlag = MODULE_MODE_BIND;
if (isModuleELRS(moduleIdx))
AUDIO_PLAY(AU_SPECIAL_SOUND_CHEEP); // Since ELRS bind is just one frame, we need to play the sound manually
}
if (!event && (oldFlag != newFlag) &&
+6 -1
View File
@@ -1562,7 +1562,10 @@ void menuModelSetup(event_t event)
l_posHorz += 1;
}
if (isModuleBindRangeAvailable(moduleIdx)) {
lcdDrawText(bindButtonPos, y, STR_MODULE_BIND, l_posHorz == 1 ? attr : 0);
if (TELEMETRY_STREAMING() && isModuleCrossfire(moduleIdx))
lcdDrawText(bindButtonPos, y, STR_MODULE_UNBIND, l_posHorz == 1 ? attr : 0);
else
lcdDrawText(bindButtonPos, y, STR_MODULE_BIND, l_posHorz == 1 ? attr : 0);
if (isModuleRangeAvailable(moduleIdx)) {
lcdDrawText(lcdNextPos + FW, y, STR_MODULE_RANGE, l_posHorz == 2 ? attr : 0);
}
@@ -1600,6 +1603,8 @@ void menuModelSetup(event_t event)
}
else {
newFlag = MODULE_MODE_BIND;
if (isModuleCrossfire(moduleIdx))
AUDIO_PLAY(AU_SPECIAL_SOUND_CHEEP); // Since ELRS bind is just one frame, we need to play the sound manually
}
if (!event && (oldFlag != newFlag) &&
+18 -1
View File
@@ -102,6 +102,8 @@ class ModuleWindow : public Window
void startRSSIDialog(std::function<void()> closeHandler = nullptr);
void updateIDStaticText(int mdIdx);
void checkEvents() override;
};
struct FailsafeChoice : public Window {
@@ -156,6 +158,19 @@ ModuleWindow::ModuleWindow(Window* parent, uint8_t moduleIdx) :
lv_obj_add_event_cb(lvobj, mw_refresh_cb, LV_EVENT_REFRESH, this);
}
void ModuleWindow::checkEvents()
{
if (bindButton != nullptr) {
if (TELEMETRY_STREAMING() && isModuleELRS(moduleIdx))
bindButton->setText(STR_MODULE_UNBIND);
else if (isModuleELRS(moduleIdx))
bindButton->setText(STR_MODULE_BIND);
bindButton->show(isModuleBindRangeAvailable(moduleIdx));
}
Window::checkEvents();
}
void ModuleWindow::updateIDStaticText(int mdIdx)
{
if (idUnique == nullptr) return;
@@ -280,7 +295,7 @@ void ModuleWindow::updateModule()
}
});
if (isModuleBindRangeAvailable(moduleIdx)) {
if (isModuleBindRangeAvailable(moduleIdx) || isModuleCrossfire(moduleIdx)) {
bindButton = new TextButton(box, rect_t{}, STR_MODULE_BIND);
bindButton->setPressHandler([=]() -> uint8_t {
if (moduleState[moduleIdx].mode == MODULE_MODE_RANGECHECK) {
@@ -312,6 +327,8 @@ void ModuleWindow::updateModule()
}
#endif
moduleState[moduleIdx].mode = MODULE_MODE_BIND;
if (isModuleELRS(moduleIdx))
AUDIO_PLAY(AU_SPECIAL_SOUND_CHEEP); // Since ELRS bind is just one frame, we need to play the sound manually
#if defined(AFHDS2)
if (isModuleAFHDS2A(moduleIdx)) {
resetPulsesAFHDS2();
+3 -1
View File
@@ -126,7 +126,7 @@ class VersionDialog : public BaseDialog
new StaticText(int_rx_name_w, rect_t{}, "");
int_rx_name_w->hide();
// internal reciever status
// internal receiver status
int_rx_status_w = form->newLine(grid);
new StaticText(int_rx_status_w, rect_t{}, STR_STATUS);
int_rx_status =
@@ -195,6 +195,8 @@ class VersionDialog : public BaseDialog
// snprintf(statusText, 64, "%d Hz %" PRIu32 " Err", hz, telemetryErrors);
snprintf(statusText, 64, "%d Hz", hz);
status->setText(statusText);
snprintf(statusText, 64, "%s V%u.%u.%u", crossfireModuleStatus[module].name, crossfireModuleStatus[module].major, crossfireModuleStatus[module].minor, crossfireModuleStatus[module].revision);
name->setText(statusText);
module_status_w->show();
}
#endif
+20 -7
View File
@@ -32,7 +32,7 @@
#define MENU_BODY_TOP (FH + 1)
#define MENU_BODY_BOTTOM (LCD_H)
#if defined(PXX2)
#if defined(PXX2) || defined(CROSSFIRE)
constexpr uint8_t COLUMN2_X = 10 * FW;
#endif
@@ -84,7 +84,8 @@ void drawPXX2FullVersion(coord_t x, coord_t y, PXX2Version hwVersion, PXX2Versio
lcdDrawText(lcdNextPos, y, "/");
drawPXX2Version(lcdNextPos, y, swVersion);
}
#endif
#if defined(PXX2) || defined(CROSSFIRE)
void menuRadioModulesVersion(event_t event)
{
if (menuEvent) {
@@ -95,8 +96,8 @@ void menuRadioModulesVersion(event_t event)
}
title(STR_MENU_MODULES_RX_VERSION);
if (event == EVT_ENTRY) {
#if defined(PXX2)
if (event == EVT_ENTRY) {
memclear(&reusableBuffer.hardwareAndSettings.modules, sizeof(reusableBuffer.hardwareAndSettings.modules));
}
@@ -116,6 +117,7 @@ void menuRadioModulesVersion(event_t event)
reusableBuffer.hardwareAndSettings.updateTime = get_tmr10ms() + 1000 /* 10s*/;
}
#endif
coord_t y = (FH + 1) - menuVerticalOffset * FH;
@@ -166,6 +168,14 @@ void menuRadioModulesVersion(event_t event)
1000000 / getMixerSchedulerPeriod()/*, UINT32_C(telemetryErrors)*/);
lcdDrawText(COLUMN2_X, y, statusText);
y += FH;
lcdDrawText(INDENT_WIDTH, y, crossfireModuleStatus[module].name);
lcdDrawChar(lcdNextPos + 5, y, 'V');
lcdDrawNumber(lcdNextPos, y, crossfireModuleStatus[module].major);
lcdDrawChar(lcdNextPos, y, '.');
lcdDrawNumber(lcdNextPos, y, crossfireModuleStatus[module].minor);
lcdDrawChar(lcdNextPos, y, '.');
lcdDrawNumber(lcdNextPos, y, crossfireModuleStatus[module].revision);
y += FH;
continue;
}
#endif
@@ -174,12 +184,14 @@ void menuRadioModulesVersion(event_t event)
y += FH;
continue;
}
#if defined(PXX2)
uint8_t modelId = reusableBuffer.hardwareAndSettings.modules[module]
.information.modelID;
lcdDrawText(COLUMN2_X, y, getPXX2ModuleName(modelId));
#endif
}
y += FH;
#if defined(PXX2)
// Module version
if (y >= MENU_BODY_TOP && y < MENU_BODY_BOTTOM) {
if (reusableBuffer.hardwareAndSettings.modules[module].information.modelID) {
@@ -211,6 +223,7 @@ void menuRadioModulesVersion(event_t event)
y += FH;
}
}
#endif
}
uint8_t lines = (y - (FH + 1)) / FH + menuVerticalOffset;
@@ -243,7 +256,7 @@ enum MenuRadioVersionItems
#if defined(PCBTARANIS)
ITEM_RADIO_FIRMWARE_OPTIONS,
#endif
#if defined(PXX2)
#if defined(PXX2) || defined(CROSSFIRE)
ITEM_RADIO_MODULES_VERSION,
#endif
ITEM_RADIO_VERSION_COUNT
@@ -266,7 +279,7 @@ void menuRadioVersion(event_t event)
}
#endif
#if defined(PXX2)
#if defined(PXX2) || defined(CROSSFIRE)
lcdDrawText(INDENT_WIDTH, y, BUTTON(TR_MODULES_RX_VERSION), menuVerticalPosition == ITEM_RADIO_MODULES_VERSION ? INVERS : 0);
y += FH;
if (menuVerticalPosition == ITEM_RADIO_MODULES_VERSION && event == EVT_KEY_BREAK(KEY_ENTER)) {
+3
View File
@@ -1261,6 +1261,9 @@ uint8_t MENU_FIRST_LINE_EDIT(const uint8_t * horTab, uint8_t horTabMax)
uint8_t MODULE_BIND_ROWS(int moduleIdx)
{
if (isModuleELRS(moduleIdx) && (crossfireModuleStatus[moduleIdx].major >= 4 || (crossfireModuleStatus[moduleIdx].major == 3 && crossfireModuleStatus[moduleIdx].minor >= 4)))
return 1;
if (isModuleCrossfire(moduleIdx))
return 0;
+39
View File
@@ -42,6 +42,36 @@
#define MIN_FRAME_LEN 3
uint8_t createCrossfireBindFrame(uint8_t moduleIdx, uint8_t * frame)
{
uint8_t * buf = frame;
*buf++ = UART_SYNC; /* device address */
*buf++ = 7; /* frame length */
*buf++ = COMMAND_ID; /* cmd type */
if (TELEMETRY_STREAMING())
*buf++ = RECEIVER_ADDRESS; /* Destination is receiver (unbind) */
else
*buf++ = MODULE_ADDRESS; /* Destination is module */
*buf++ = RADIO_ADDRESS; /* Origin Address */
*buf++ = SUBCOMMAND_CRSF; /* sub command */
*buf++ = SUBCOMMAND_CRSF_BIND; /* initiate bind */
*buf++ = crc8_BA(frame + 2, 5);
*buf++ = crc8(frame + 2, 6);
return buf - frame;
}
uint8_t createCrossfirePingFrame(uint8_t moduleIdx, uint8_t * frame)
{
uint8_t * buf = frame;
*buf++ = UART_SYNC; /* device address */
*buf++ = 4; /* frame length */
*buf++ = PING_DEVICES_ID; /* cmd type */
*buf++ = BROADCAST_ADDRESS; /* Destination Address */
*buf++ = RADIO_ADDRESS; /* Origin Address */
*buf++ = crc8(frame + 2, 3);
return buf - frame;
}
uint8_t createCrossfireModelIDFrame(uint8_t moduleIdx, uint8_t * frame)
{
uint8_t * buf = frame;
@@ -98,6 +128,11 @@ static void setupPulsesCrossfire(uint8_t module, uint8_t*& p_buf,
if (moduleState[module].counter == CRSF_FRAME_MODELID) {
p_buf += createCrossfireModelIDFrame(module, p_buf);
moduleState[module].counter = CRSF_FRAME_MODELID_SENT;
} else if (moduleState[module].counter == CRSF_FRAME_MODELID_SENT && crossfireModuleStatus[module].queryCompleted == false) {
p_buf += createCrossfirePingFrame(module, p_buf);
} else if (moduleState[module].mode == MODULE_MODE_BIND) {
p_buf += createCrossfireBindFrame(module, p_buf);
moduleState[module].mode = MODULE_MODE_NORMAL;
} else {
/* TODO: nChannels */
p_buf += createCrossfireChannelsFrame(p_buf, channels);
@@ -307,6 +342,8 @@ static void* crossfireInit(uint8_t module)
}
#endif
}
memset(&crossfireModuleStatus[module], 0, sizeof(crossfireModuleStatus[module]));
}
#endif
@@ -321,6 +358,8 @@ static void crossfireDeInit(void* ctx)
{
auto mod_st = (etx_module_state_t*)ctx;
memset(&crossfireModuleStatus[modulePortGetModule(mod_st)], 0, sizeof(crossfireModuleStatus[modulePortGetModule(mod_st)]));
#if !defined(SIMU)
if (mod_st && (modulePortGetModule(mod_st) == EXTERNAL_MODULE)) {
auto drv = modulePortGetSerialDrv(mod_st->rx);
+14 -2
View File
@@ -28,6 +28,7 @@
#include "globals.h"
#include "MultiProtoDefs.h"
#include "hal/module_port.h"
#include "telemetry/crossfire.h"
#if defined(MULTIMODULE)
#include "telemetry/multi.h"
@@ -227,6 +228,11 @@ inline bool isModuleCrossfire(uint8_t idx)
return g_model.moduleData[idx].type == MODULE_TYPE_CROSSFIRE;
}
inline bool isModuleELRS(uint8_t idx)
{
return crossfireModuleStatus[idx].isELRS;
}
inline bool isInternalModuleCrossfire()
{
return g_eeGeneral.internalModule == MODULE_TYPE_CROSSFIRE;
@@ -237,6 +243,11 @@ inline bool isModuleCrossfire(uint8_t idx)
return false;
}
inline bool isModuleELRS(uint8_t idx)
{
return false;
}
inline bool isInternalModuleCrossfire()
{
return false;
@@ -607,7 +618,8 @@ inline bool isModuleBindRangeAvailable(uint8_t moduleIdx)
{
return isModulePXX2(moduleIdx) || isModulePXX1(moduleIdx) ||
isModuleDSM2(moduleIdx) || isModuleMultimodule(moduleIdx) ||
isModuleFlySky(moduleIdx) || isModuleDSMP(moduleIdx);
isModuleFlySky(moduleIdx) || isModuleDSMP(moduleIdx) ||
(isModuleELRS(moduleIdx) && (crossfireModuleStatus[moduleIdx].major >= 4 || (crossfireModuleStatus[moduleIdx].major == 3 && crossfireModuleStatus[moduleIdx].minor >= 4)));
}
inline uint32_t getNV14RfFwVersion()
@@ -621,7 +633,7 @@ inline uint32_t getNV14RfFwVersion()
inline bool isModuleRangeAvailable(uint8_t moduleIdx)
{
bool ret = isModuleBindRangeAvailable(moduleIdx) && !IS_RX_MULTI(moduleIdx);
bool ret = isModuleBindRangeAvailable(moduleIdx) && !IS_RX_MULTI(moduleIdx) && !isModuleCrossfire(moduleIdx);
#if defined(PCBNV14) && defined(AFHDS2)
ret = ret &&
(!isModuleAFHDS2A(moduleIdx) || NV14internalModuleFwVersion >= 0x1000E);
+14 -1
View File
@@ -20,7 +20,6 @@
*/
#include "crossfire.h"
#include "opentx.h"
// clang-format off
@@ -62,6 +61,8 @@ const CrossfireSensor crossfireSensors[] = {
};
// clang-format on
CrossfireModuleStatus crossfireModuleStatus[2] = {0};
const CrossfireSensor & getCrossfireSensor(uint8_t id, uint8_t subId)
{
if (id == LINK_ID)
@@ -260,6 +261,18 @@ void processCrossfireTelemetryFrame(uint8_t module, uint8_t* rxBuffer,
#if defined(LUA)
default:
if (id == DEVICE_INFO_ID && rxBuffer[4]== MODULE_ADDRESS) {
uint8_t nameSize = rxBuffer[1] - 18;
strncpy((char *)&crossfireModuleStatus[module].name, (const char *)&rxBuffer[5], CRSF_NAME_MAXSIZE);
crossfireModuleStatus[module].name[CRSF_NAME_MAXSIZE -1] = 0; // For some reason, GH din't like strlcpy
if (strncmp((const char *) &rxBuffer[5 + nameSize], "ELRS", 4) == 0)
crossfireModuleStatus[module].isELRS = true;
crossfireModuleStatus[module].major = rxBuffer[14 + nameSize];
crossfireModuleStatus[module].minor = rxBuffer[15 + nameSize];
crossfireModuleStatus[module].revision = rxBuffer[16 + nameSize];
crossfireModuleStatus[module].queryCompleted = true;
}
if (luaInputTelemetryFifo && luaInputTelemetryFifo->hasSpace(rxBufferCount - 2)) {
for (uint8_t i = 1; i < rxBufferCount - 1; i++) {
// destination address and CRC are skipped
+16
View File
@@ -29,6 +29,7 @@
#define BROADCAST_ADDRESS 0x00
#define RADIO_ADDRESS 0xEA
#define MODULE_ADDRESS 0xEE
#define RECEIVER_ADDRESS 0xEC
// Frame id
#define GPS_ID 0x02
@@ -50,6 +51,9 @@
#define UART_SYNC 0xC8
#define SUBCOMMAND_CRSF 0x10
#define COMMAND_MODEL_SELECT_ID 0x05
#define SUBCOMMAND_CRSF_BIND 0x01
constexpr uint8_t CRSF_NAME_MAXSIZE = 16;
struct CrossfireSensor {
const uint8_t id;
@@ -100,6 +104,18 @@ enum CrossfireFrames{
CRSF_FRAME_MODELID_SENT
};
struct CrossfireModuleStatus
{
uint8_t major;
uint8_t minor;
uint8_t revision;
char name[CRSF_NAME_MAXSIZE];
bool queryCompleted;
bool isELRS;
};
extern CrossfireModuleStatus crossfireModuleStatus[2];
void processCrossfireTelemetryFrame(uint8_t module, uint8_t* rxBuffer,
uint8_t rxBufferCount);
void crossfireSetDefault(int index, uint8_t id, uint8_t subId);
+1
View File
@@ -586,6 +586,7 @@ const char STR_EXPONAME[] = TR_EXPONAME;
const char STR_TRAINER[] = TR_TRAINER;
const char STR_CHANS[] = TR_CHANS;
const char STR_MODULE_BIND[] = TR_MODULE_BIND;
const char STR_MODULE_UNBIND[] = TR_MODULE_UNBIND;
const char STR_POWERMETER_ATTN_NEEDED[] = TR_POWERMETER_ATTN_NEEDED;
const char STR_PXX2_SELECT_RX[] = TR_PXX2_SELECT_RX;
const char STR_PXX2_DEFAULT[] = TR_PXX2_DEFAULT;
+1
View File
@@ -986,6 +986,7 @@ extern const char STR_EXPONAME[];
extern const char STR_TRAINER[];
extern const char STR_CHANS[];
extern const char STR_MODULE_BIND[];
extern const char STR_MODULE_UNBIND[];
extern const char STR_POWERMETER_ATTN_NEEDED[];
extern const char STR_PXX2_SELECT_RX[];
extern const char STR_PXX2_DEFAULT[];
+2 -1
View File
@@ -853,7 +853,8 @@
#define TR_BUZZER "蜂鸣器"
#define TR_BYTES "bytes"
#define TR_MODULE_BIND BUTTON(TR("对频", "对频"))
#define TR_POWERMETER_ATTN_NEEDED "需要串联衰减器"
#define TR_MODULE_UNBIND BUTTON("解绑")
#define TR_POWERMETER_ATTN_NEEDED "需要串联衰减器"
#define TR_PXX2_SELECT_RX "Select RX"
#define TR_PXX2_DEFAULT "<default>"
#define TR_BT_SELECT_DEVICE "选择设备"
+2 -1
View File
@@ -864,7 +864,8 @@
#define TR_BUZZER "Pípák"
#define TR_BYTES "[B]"
#define TR_MODULE_BIND BUTTON(TR("Bnd", "Bind"))
#define TR_POWERMETER_ATTN_NEEDED "Útlumový člen nutný!"
#define TR_MODULE_UNBIND BUTTON("Odpárovat")
#define TR_POWERMETER_ATTN_NEEDED "Útlumový člen nutný!"
#define TR_PXX2_SELECT_RX "Vyber RX..."
#define TR_PXX2_DEFAULT "<výchozí>"
#define TR_BT_SELECT_DEVICE "Vyberte zařízení"
+2 -1
View File
@@ -858,7 +858,8 @@
#define TR_BUZZER "Biper"
#define TR_BYTES "bytes"
#define TR_MODULE_BIND BUTTON(TR("Tils", "Tilslut"))
#define TR_POWERMETER_ATTN_NEEDED "Attestering nødvendig"
#define TR_MODULE_UNBIND BUTTON("Afkobl")
#define TR_POWERMETER_ATTN_NEEDED "Attestering nødvendig"
#define TR_PXX2_SELECT_RX "Vælg RX"
#define TR_PXX2_DEFAULT "<default>"
#define TR_BT_SELECT_DEVICE "Vælg enhed"
+1
View File
@@ -852,6 +852,7 @@
#define TR_BUZZER "Summer"
#define TR_BYTES "Bytes"
#define TR_MODULE_BIND BUTTON(TR("Bnd","Binden")) //9XR-Pro
#define TR_MODULE_UNBIND BUTTON("Trennen")
#define TR_POWERMETER_ATTN_NEEDED "Dämpfungsgl. nötig"
#define TR_PXX2_SELECT_RX "Wähle RX"
#define TR_PXX2_DEFAULT "<default>"
+2 -1
View File
@@ -858,7 +858,8 @@
#define TR_BUZZER "Buzzer"
#define TR_BYTES "bytes"
#define TR_MODULE_BIND BUTTON(TR("Bnd", "Bind"))
#define TR_POWERMETER_ATTN_NEEDED "Attenuator needed"
#define TR_MODULE_UNBIND BUTTON("Unbind")
#define TR_POWERMETER_ATTN_NEEDED "Attenuator needed"
#define TR_PXX2_SELECT_RX "Select RX"
#define TR_PXX2_DEFAULT "<default>"
#define TR_BT_SELECT_DEVICE "Select device"
+2 -1
View File
@@ -848,7 +848,8 @@
#define TR_BUZZER "Zumbador"
#define TR_BYTES "bytes"
#define TR_MODULE_BIND "[Enl.]"
#define TR_POWERMETER_ATTN_NEEDED "Necesita atenuador"
#define TR_MODULE_UNBIND BUTTON("Unbind")
#define TR_POWERMETER_ATTN_NEEDED "Necesita atenuador"
#define TR_PXX2_SELECT_RX "Selecciona RX..."
#define TR_PXX2_DEFAULT "<defecto>"
#define TR_BT_SELECT_DEVICE "Selecciona dispositivo"
+2 -1
View File
@@ -863,7 +863,8 @@
#define TR_BUZZER "Buzzer"
#define TR_BYTES "bytes"
#define TR_MODULE_BIND "[Bind]"
#define TR_POWERMETER_ATTN_NEEDED "Tarvitaan vaimennin"
#define TR_MODULE_UNBIND BUTTON("Unbind")
#define TR_POWERMETER_ATTN_NEEDED "Tarvitaan vaimennin"
#define TR_PXX2_SELECT_RX "Select RX"
#define TR_PXX2_DEFAULT "<default>"
#define TR_BT_SELECT_DEVICE "Select device"
+1
View File
@@ -854,6 +854,7 @@
#define TR_BUZZER "Bipeur"
#define TR_BYTES "bytes"
#define TR_MODULE_BIND BUTTON(TR("Bnd", "Bind"))
#define TR_MODULE_UNBIND BUTTON("Délier")
#define TR_POWERMETER_ATTN_NEEDED "Atténuateur requis"
#define TR_PXX2_SELECT_RX "Sélection RX..."
#define TR_PXX2_DEFAULT "<défaut>"
+2 -1
View File
@@ -857,7 +857,8 @@
#define TR_BUZZER "זמזם"
#define TR_BYTES "bytes"
#define TR_MODULE_BIND BUTTON(TR("Bnd", "צימוד"))
#define TR_POWERMETER_ATTN_NEEDED "Attenuator needed"
#define TR_MODULE_UNBIND BUTTON("Unbind")
#define TR_POWERMETER_ATTN_NEEDED "Attenuator needed"
#define TR_PXX2_SELECT_RX "Select RX"
#define TR_PXX2_DEFAULT "<default>"
#define TR_BT_SELECT_DEVICE "בחר מכשיר"
+1
View File
@@ -852,6 +852,7 @@
#define TR_BUZZER "Buzzer"
#define TR_BYTES "Bytes"
#define TR_MODULE_BIND TR("[Bnd]","[Bind]")
#define TR_MODULE_UNBIND BUTTON("Unbind")
#define TR_POWERMETER_ATTN_NEEDED "Attenuatore necessario"
#define TR_PXX2_SELECT_RX "Seleziona RX..."
#define TR_PXX2_DEFAULT "<default>"
+2 -1
View File
@@ -857,7 +857,8 @@
#define TR_BUZZER "ブザー"
#define TR_BYTES "バイト"
#define TR_MODULE_BIND BUTTON(TR("Bnd", "Bind"))
#define TR_POWERMETER_ATTN_NEEDED "減衰器が必要です"
#define TR_MODULE_UNBIND BUTTON("バインド解除")
#define TR_POWERMETER_ATTN_NEEDED "減衰器が必要です"
#define TR_PXX2_SELECT_RX "受信機選択"
#define TR_PXX2_DEFAULT "<default>"
#define TR_BT_SELECT_DEVICE "デバイス選択"
+2 -1
View File
@@ -849,7 +849,8 @@
#define TR_BUZZER "Zoemer"
#define TR_BYTES "bytes"
#define TR_MODULE_BIND TR("[Bnd]", "[Bind]")
#define TR_POWERMETER_ATTN_NEEDED "Attenuator needed"
#define TR_MODULE_UNBIND BUTTON("Unbind")
#define TR_POWERMETER_ATTN_NEEDED "Attenuator needed"
#define TR_PXX2_SELECT_RX "Select RX"
#define TR_PXX2_DEFAULT "<default>"
#define TR_BT_SELECT_DEVICE "Select device"
+2 -1
View File
@@ -850,7 +850,8 @@
#define TR_BUZZER "Brzęczyk"
#define TR_BYTES "bajty"
#define TR_MODULE_BIND TR("[BND]","[Bind]")
#define TR_POWERMETER_ATTN_NEEDED "Attenuator needed"
#define TR_MODULE_UNBIND BUTTON("Unbind")
#define TR_POWERMETER_ATTN_NEEDED "Attenuator needed"
#define TR_PXX2_SELECT_RX "Select RX"
#define TR_PXX2_DEFAULT "<default>"
#define TR_BT_SELECT_DEVICE "Wybierz urządzenie"
+2 -1
View File
@@ -861,7 +861,8 @@
#define TR_BUZZER "Buzzer"
#define TR_BYTES "bytes"
#define TR_MODULE_BIND BUTTON(TR("Bnd", "Bind"))
#define TR_POWERMETER_ATTN_NEEDED "Attenuator needed"
#define TR_MODULE_UNBIND BUTTON("Unbind")
#define TR_POWERMETER_ATTN_NEEDED "Attenuator needed"
#define TR_PXX2_SELECT_RX "Select RX"
#define TR_PXX2_DEFAULT "<default>"
#define TR_BT_SELECT_DEVICE "Select device"
+2 -1
View File
@@ -860,7 +860,8 @@
#define TR_BUZZER "Звук сигнал"
#define TR_BYTES "Байты"
#define TR_MODULE_BIND BUTTON(TR("Bnd", "Bind"))
#define TR_POWERMETER_ATTN_NEEDED "Требуется аттенюатор"
#define TR_MODULE_UNBIND BUTTON("Unbind")
#define TR_POWERMETER_ATTN_NEEDED "Требуется аттенюатор"
#define TR_PXX2_SELECT_RX "Выбор RX"
#define TR_PXX2_DEFAULT "<По умолчанию>"
#define TR_BT_SELECT_DEVICE "Выбор устройства"
+2 -1
View File
@@ -872,7 +872,8 @@
#define TR_BUZZER "Summer"
#define TR_BYTES "byte"
#define TR_MODULE_BIND BUTTON(TR("Bnd", "Bind"))
#define TR_POWERMETER_ATTN_NEEDED "Attenuator behövs"
#define TR_MODULE_UNBIND BUTTON("Glöm")
#define TR_POWERMETER_ATTN_NEEDED "Attenuator behövs"
#define TR_PXX2_SELECT_RX "Välj Rx"
#define TR_PXX2_DEFAULT "<default>"
#define TR_BT_SELECT_DEVICE "Välj enhet"
+2 -1
View File
@@ -858,7 +858,8 @@
#define TR_BUZZER "蜂鳴器"
#define TR_BYTES "bytes"
#define TR_MODULE_BIND BUTTON(TR("對頻", "對頻"))
#define TR_POWERMETER_ATTN_NEEDED "需要串聯衰減器"
#define TR_MODULE_UNBIND BUTTON("解綁")
#define TR_POWERMETER_ATTN_NEEDED "需要串聯衰減器"
#define TR_PXX2_SELECT_RX "Select RX"
#define TR_PXX2_DEFAULT "<default>"
#define TR_BT_SELECT_DEVICE "選擇設備"
+2 -1
View File
@@ -860,7 +860,8 @@
#define TR_BUZZER "Дзвоник"
#define TR_BYTES "байти"
#define TR_MODULE_BIND BUTTON(TR("Прив.", "Прив'язати"))
#define TR_POWERMETER_ATTN_NEEDED "Потрібен атенюатор"
#define TR_MODULE_UNBIND BUTTON("Відв'язати")
#define TR_POWERMETER_ATTN_NEEDED "Потрібен атенюатор"
#define TR_PXX2_SELECT_RX "Оберіть RX"
#define TR_PXX2_DEFAULT "<замовч>"
#define TR_BT_SELECT_DEVICE "Оберіть пристрій"