Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions docs/Settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -7688,6 +7688,56 @@ Enable the 3x shorter stopbit on softserial. Need for some IRC Tramp VTXes.

---

### vtx_tramp_power_a

Custom Tramp power level 1 in mW. Set consecutive ascending levels, then zeros; all zero keeps automatic tables. Reboot after changes. The reported maximum (or vtx_max_power_override) still limits power.

| Default | Min | Max |
| --- | --- | --- |
| 0 | 0 | 10000 |

---

### vtx_tramp_power_b

Custom Tramp power level 2 in mW. Set consecutive ascending levels, then zeros; all zero keeps automatic tables. Reboot after changes. The reported maximum (or vtx_max_power_override) still limits power.

| Default | Min | Max |
| --- | --- | --- |
| 0 | 0 | 10000 |

---

### vtx_tramp_power_c

Custom Tramp power level 3 in mW. Set consecutive ascending levels, then zeros; all zero keeps automatic tables. Reboot after changes. The reported maximum (or vtx_max_power_override) still limits power.

| Default | Min | Max |
| --- | --- | --- |
| 0 | 0 | 10000 |

---

### vtx_tramp_power_d

Custom Tramp power level 4 in mW. Set consecutive ascending levels, then zeros; all zero keeps automatic tables. Reboot after changes. The reported maximum (or vtx_max_power_override) still limits power.

| Default | Min | Max |
| --- | --- | --- |
| 0 | 0 | 10000 |

---

### vtx_tramp_power_e

Custom Tramp power level 5 in mW. Set consecutive ascending levels, then zeros; all zero keeps automatic tables. Reboot after changes. The reported maximum (or vtx_max_power_override) still limits power.

| Default | Min | Max |
| --- | --- | --- |
| 0 | 0 | 10000 |

---

### yaw_deadband

These are values (in us) by how much RC input can be different before it's considered valid. For transmitters with jitter on outputs, this value can be increased. Defaults are zero, but can be increased up to 10 or so if rc inputs twitch while idle.
Expand Down
65 changes: 65 additions & 0 deletions docs/VTx.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,68 @@ If you have problems getting SmartAudio working. There are a couple of CLI param
- If you are using softserial, you can try using the alternate method by setting [`vtx_smartaudio_alternate_softserial_method`](https://github.com/iNavFlight/inav/blob/master/docs/Settings.md#vtx_smartaudio_alternate_softserial_method) to OFF.

- If you are using TBS Sixty9 VTX you may consider to set count of stop bits to 1, using [`set vtx_smartaudio_stopbits = 1`](https://github.com/iNavFlight/inav/blob/master/docs/Settings.md#vtx_smartaudio_stopbits)

### Custom IRC Tramp power levels

Tramp normally selects a built-in power table from the maximum power reported by
its device. For devices with different levels, configure up to five ascending
power values in milliwatts with `vtx_tramp_power_a` through `vtx_tramp_power_e`.
Use consecutive entries followed by zeros. All zeros retain automatic selection;
an invalid table (gaps, duplicates, descending values) also falls back to automatic
selection. Reboot after changing the table.

For a BLITZ Whoop 2.5W:

```
set vtx_tramp_power_a = 25
set vtx_tramp_power_b = 400
set vtx_tramp_power_c = 1000
set vtx_tramp_power_d = 2500
set vtx_tramp_power_e = 0
set vtx_power = 1
save
```

This changes the power values and their labels, not the VTX's reported maximum.
The advertised custom table caps entries at that maximum and removes duplicate
capped levels, so each label matches the transmitted power value. Only if the hardware's
maximum is independently confirmed and the device reports it incorrectly, use
`vtx_max_power_override` to provide the correct maximum. It does not unlock the
VTX or verify actual RF power. Power selection remains one-based: this example
maps levels 1–4 to 25, 400, 1000 and 2500 mW when the effective maximum is
at least 2500 mW. A reported 400 mW maximum instead exposes only 25 and 400 mW.

The VTX settings parameter-group version changes from 2 to 3. Version-2 settings
are migrated with band, channel, power, low-power behavior, pit frequency, maximum
power override and frequency group preserved. The new table starts in automatic
selection mode.

### Tramp pit mode on an AUX switch

Assign **VTX PIT MODE** in Modes (permanent mode ID 73). For example, with the
first two mode-condition slots already in use, this assigns AUX5 / channel 9:

```
aux 2 73 4 1800 2100
save
```

The assigned range requests pit mode while disarmed. Arming exits pit mode and
prevents entering it in flight. The switch is ignored without a valid receiver
signal. Without a mode assignment, existing hardware-button/MSP control is left
alone. Pit mode changes use the Tramp `I` command (0 = enter, 1 = exit), and the
driver retries if subsequent status reports do not match the request. Retries are
bounded so an unsupported command cannot block channel or power changes, and a
reconnection renews the retry budget. Pending frequency, power and pit commands
are served in rotation so a rejected setting cannot starve another request.
Queued enter requests are cancelled on arming. The CMS power selection follows
the detected table and is clamped to its available levels before display or save.
Blackbox records the AUX switch in `flightModeFlags3` (bit 0). Verify the
VTX's own pit indicator before relying on it; driver support is not a guarantee
that every Tramp-compatible device implements the command.

The AUX pit-mode assignment is advertised only by drivers with functional pit-mode
read/write support (currently Tramp). Unsupported drivers do not receive AUX pit
commands. If a saved Tramp power index exceeds a shortened custom power table,
the runtime request uses its highest level, still capped by the device maximum;
the saved index is left unchanged.
5 changes: 5 additions & 0 deletions src/main/blackbox/blackbox.c
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,7 @@ static const blackboxSimpleFieldDefinition_t blackboxSlowFields[] = {
{"activeWpNumber", -1, UNSIGNED, PREDICT(0), ENCODING(UNSIGNED_VB)},
{"flightModeFlags", -1, UNSIGNED, PREDICT(0), ENCODING(UNSIGNED_VB)},
{"flightModeFlags2", -1, UNSIGNED, PREDICT(0), ENCODING(UNSIGNED_VB)},
{"flightModeFlags3", -1, UNSIGNED, PREDICT(0), ENCODING(UNSIGNED_VB)},
{"activeFlightModeFlags", -1, UNSIGNED, PREDICT(0), ENCODING(UNSIGNED_VB)},
{"stateFlags", -1, UNSIGNED, PREDICT(0), ENCODING(UNSIGNED_VB)},

Expand Down Expand Up @@ -625,6 +626,7 @@ typedef struct blackboxGpsState_s {
typedef struct blackboxSlowState_s {
uint32_t rcModeFlags;
uint32_t rcModeFlags2;
uint32_t rcModeFlags3;
uint32_t activeFlightModeFlags;
uint32_t stateFlags;
uint8_t failsafePhase;
Expand Down Expand Up @@ -1430,6 +1432,7 @@ static void writeSlowFrame(void)
blackboxWriteUnsignedVB(slowHistory.activeWpNumber);
blackboxWriteUnsignedVB(slowHistory.rcModeFlags);
blackboxWriteUnsignedVB(slowHistory.rcModeFlags2);
blackboxWriteUnsignedVB(slowHistory.rcModeFlags3);
blackboxWriteUnsignedVB(slowHistory.activeFlightModeFlags);
blackboxWriteUnsignedVB(slowHistory.stateFlags);

Expand Down Expand Up @@ -1512,6 +1515,8 @@ static void loadSlowState(blackboxSlowState_t *slow)
slow->rcModeFlags2 = rcModeActivationMask.bits[1]; // remaining bits of boxId_e
#endif

slow->rcModeFlags3 = rcModeActivationMask.bits[2]; // box IDs 64 and above
Comment thread
Raffi1202 marked this conversation as resolved.

// Also log Nav auto enabled flight modes rather than just those selected by boxmode
if (navigationGetHeadingControlState() == NAV_HEADING_CONTROL_AUTO) {
slow->rcModeFlags |= (1 << BOXHEADINGHOLD);
Expand Down
9 changes: 9 additions & 0 deletions src/main/cms/cms.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@
#include "io/osd.h"
#include "io/rcdevice_cam.h"

#ifdef USE_VTX_CONTROL
#include "cms/cms_menu_vtx.h"
#endif

#include "rx/rx.h"

// DisplayPort management
Expand Down Expand Up @@ -1591,6 +1595,11 @@ void cmsUpdate(timeUs_t currentTimeUs)

// Only scan keys and draw if we're not yielding
if (cmsYieldUntil == 0) {
#ifdef USE_VTX_CONTROL
if (currentCtx.menu == &cmsx_menuVtxControl) {
cmsVtxUpdatePowerMetadata();
}
#endif
// XXX: Note that one call to cmsScanKeys() might generate multiple keypresses
// when repeating, that's why cmsYieldDisplay() has to check for multiple calls.
rcDelayMs = cmsScanKeys(currentTimeMs, lastCalledMs, rcDelayMs);
Expand Down
28 changes: 26 additions & 2 deletions src/main/cms/cms_menu_vtx.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#if defined(USE_CMS) && defined(USE_VTX_CONTROL)

#include "common/printf.h"
#include "common/maths.h"
#include "common/utils.h"

#include "cms/cms.h"
Expand Down Expand Up @@ -57,6 +58,22 @@ static OSD_TAB_t cms_Vtx_EntBand = { &vtxBand, VTX_SETTINGS_BAND_COUNT, vtx58Ban
static OSD_TAB_t cms_Vtx_EntChan = { &vtxChan, VTX_SETTINGS_CHANNEL_COUNT, vtx58ChannelNames };
static OSD_TAB_t cms_Vtx_EntPower = { &vtxPower, VTX_SETTINGS_POWER_COUNT, vtx58DefaultPowerNames };
static const OSD_TAB_t cms_Vtx_EntPitMode = { &vtxPitMode, 2, vtxCmsPitModeNames };
static const char * const vtxUnknownPowerNames[] = { "---" };

void cmsVtxUpdatePowerMetadata(void)
{
vtxDeviceCapability_t capability;
if (vtxCommonGetDeviceCapability(vtxCommonDevice(), &capability)
&& capability.powerCount && capability.powerNames) {
cms_Vtx_EntPower.max = capability.powerCount;
cms_Vtx_EntPower.names = (const char * const *)capability.powerNames;
} else {
cms_Vtx_EntPower.max = 0;
cms_Vtx_EntPower.names = vtxUnknownPowerNames;
}
// Clamp the menu selection, preserving EEPROM until the pilot saves it.
vtxPower = MIN(vtxPower, cms_Vtx_EntPower.max);
}

static long cms_Vtx_configPitMode(displayPort_t *pDisp, const void *self)
{
Expand Down Expand Up @@ -100,7 +117,7 @@ static long cms_Vtx_configPower(displayPort_t *pDisp, const void *self)
UNUSED(pDisp);
UNUSED(self);

if (vtxPower == 0) {
if (vtxPower == 0 && cms_Vtx_EntPower.max > 0) {
vtxPower = 1;
}
return 0;
Expand Down Expand Up @@ -135,6 +152,7 @@ static void cms_Vtx_initSettings(void)
vtxBand = vtxSettingsConfig()->band;
vtxChan = vtxSettingsConfig()->channel;
vtxPower = vtxSettingsConfig()->power;
cmsVtxUpdatePowerMetadata();

// If device is ready - read actual PIT mode
if (vtxCommonDeviceIsReady(vtxDevice)) {
Expand All @@ -159,6 +177,12 @@ static long cms_Vtx_Commence(displayPort_t *pDisp, const void *self)
UNUSED(pDisp);
UNUSED(self);

cmsVtxUpdatePowerMetadata();

if (!cms_Vtx_EntPower.max) {
return MENU_CHAIN_BACK;
}

vtxCommonSetBandAndChannel(vtxCommonDevice(), vtxBand, vtxChan);
vtxCommonSetPowerByIndex(vtxCommonDevice(), vtxPower);
vtxCommonSetPitMode(vtxCommonDevice(), vtxPitMode == 2 ? 1 : 0);
Expand Down Expand Up @@ -243,7 +267,7 @@ static const OSD_Entry cms_menuVtxEntries[] =
OSD_TAB_CALLBACK_ENTRY("PIT", cms_Vtx_configPitMode, &cms_Vtx_EntPitMode),
OSD_TAB_CALLBACK_ENTRY("BAND", cms_Vtx_configBand, &cms_Vtx_EntBand),
OSD_TAB_CALLBACK_ENTRY("CHAN", cms_Vtx_configChan, &cms_Vtx_EntChan),
OSD_TAB_CALLBACK_ENTRY("POWER", cms_Vtx_configPower, &cms_Vtx_EntPower),
{ "POWER", {.func = cms_Vtx_configPower}, &cms_Vtx_EntPower, OME_TAB, DYNAMIC },

OSD_SUBMENU_ENTRY("SET", &cms_menuCommence),
OSD_BACK_AND_END_ENTRY,
Expand Down
2 changes: 2 additions & 0 deletions src/main/cms/cms_menu_vtx.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,5 @@
#pragma once

extern const CMS_Menu cmsx_menuVtxControl;

void cmsVtxUpdatePowerMetadata(void);
2 changes: 1 addition & 1 deletion src/main/cms/cms_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ typedef enum {
} CMSDataType_e;

// Use a function and data type to make sure switches are exhaustive
static inline CMSDataType_e CMS_DATA_TYPE(const OSD_Entry *entry) { return entry->flags & 0xF0; }
static inline CMSDataType_e CMS_DATA_TYPE(const OSD_Entry *entry) { return (CMSDataType_e)(entry->flags & 0xF0); }

typedef long (*CMSMenuFuncPtr)(const OSD_Entry *from);

Expand Down
7 changes: 7 additions & 0 deletions src/main/config/parameter_group.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@
#include "platform.h"

#include "parameter_group.h"
#ifdef USE_VTX_CONTROL
#include "config/vtx_settings_migration.h"
#endif
#include "common/maths.h"

const pgRegistry_t* pgFind(pgn_t pgn)
Expand Down Expand Up @@ -90,6 +93,10 @@ void pgLoad(const pgRegistry_t* reg, int profileIndex, const void *from, int siz
if (version == pgVersion(reg)) {
const int take = MIN(size, pgSize(reg));
memcpy(pgOffset(reg, profileIndex), from, take);
#ifdef USE_VTX_CONTROL
} else {
pgMigrateVtxSettings(reg, pgOffset(reg, profileIndex), from, size, version);
#endif
}
}

Expand Down
41 changes: 41 additions & 0 deletions src/main/config/vtx_settings_migration.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#pragma once

#include <stddef.h>
#include <string.h>
#include "config/parameter_group.h"
#include "config/parameter_group_ids.h"
#include "io/vtx.h"

// Version 2 placed frequencyGroup immediately after maxPowerOverride.
// Version 3 inserts the optional Tramp table before frequencyGroup.
typedef struct vtxSettingsConfigV2_s {
uint8_t band;
uint8_t channel;
uint8_t power;
uint16_t pitModeChan;
uint8_t lowPowerDisarm;
uint16_t maxPowerOverride;
uint8_t frequencyGroup;
} vtxSettingsConfigV2_t;

static inline bool pgMigrateVtxSettings(const pgRegistry_t *reg, void *to,
const void *from, int size, int version)
{
if (pgN(reg) != PG_VTX_SETTINGS_CONFIG || pgVersion(reg) != 3 || version != 2 ||
pgSize(reg) != sizeof(vtxSettingsConfig_t) || size != sizeof(vtxSettingsConfigV2_t)) {
return false;
}
// Copy from potentially unaligned EEPROM data through a local old record.
vtxSettingsConfigV2_t old;
memcpy(&old, from, sizeof(old));
vtxSettingsConfig_t *dest = (vtxSettingsConfig_t *)to;
dest->band = old.band;
dest->channel = old.channel;
dest->power = old.power;
dest->pitModeChan = old.pitModeChan;
dest->lowPowerDisarm = old.lowPowerDisarm;
dest->maxPowerOverride = old.maxPowerOverride;
dest->frequencyGroup = old.frequencyGroup;
memset(dest->trampPowerLevels, 0, sizeof(dest->trampPowerLevels));
return true;
}
1 change: 1 addition & 0 deletions src/main/drivers/vtx_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ typedef struct vtxDeviceCapability_s {
uint8_t bandCount;
uint8_t channelCount;
uint8_t powerCount;
bool supportsPitMode; // Functional read and write support for AUX control.
char **bandNames;
char **channelNames;
char **powerNames;
Expand Down
7 changes: 3 additions & 4 deletions src/main/fc/fc_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -598,10 +598,6 @@ void init(void)

imuInit();

// Sensors have now been detected, mspFcInit() can now be called
// to set the boxes up
mspFcInit();

cliInit(serialConfig());

failsafeInit();
Expand Down Expand Up @@ -754,6 +750,9 @@ void init(void)

#endif // USE_VTX_CONTROL

// Advertised modes depend on both detected sensors and initialized VTX capabilities.
mspFcInit();

// Now that everything has powered up the voltage and cell count be determined.
if (feature(FEATURE_VBAT | FEATURE_CURRENT_METER))
batteryInit();
Expand Down
4 changes: 3 additions & 1 deletion src/main/fc/fc_msp.c
Original file line number Diff line number Diff line change
Expand Up @@ -5135,7 +5135,9 @@ bool mspFCProcessInOutCommand(uint16_t cmdMSP, sbuf_t *dst, sbuf_t *src, mspResu
sbufWriteU8(dst, powerLevel);
sbufWriteU16(dst, 0);

const char *str = vtxDevice->capability.powerNames[powerLevel - 1];
// Tramp reserves label zero for the unselected "---" entry.
const uint8_t nameIndex = vtxCommonGetDeviceType(vtxDevice) == VTXDEV_TRAMP ? powerLevel : powerLevel - 1;
const char *str = vtxDevice->capability.powerNames[nameIndex];
const uint32_t str_len = strnlen(str, 5); // these _should_ all be null-terminated
sbufWriteU8(dst, str_len);
for (uint32_t i = 0; i < str_len; i++)
Expand Down
Loading
Loading