How to set ImmersionRC Tramp VTX configuration?

https://betaflight.com/assets/files/vtx_table_irc_tramp_us-8cd6f98f573d283686383f65d43f5c3a.json

At the bottom level, you see the power levels. The numerical part makes it’s way over the wire and the label is what is displayed instead. The idea is to just change the labels to match the real power level.

I have a Zeus Nano VTX using Tramp which works 25 100 200 400 where 400 is actually 350mW.

EDIT: I assume that the software for Tramp has not been changed in years and that manufacturers just change the hardware circuit to match their power levels.
Yuri will scold me for my assumptions again :stuck_out_tongue_winking_eye:

Ok.
Exact final power is not related to the protocol, it depends by hw and vtx production controls, anyway.

What I assert is that betaflight works, inav and ardupilot have lot of problems, because they rely too much on tech specs that cannot be verified completely, otherwise everything should be ok, but it is not.

Alfredo

What is supposed to happen is tramp is supposed to advertise the power levels it supports. Unfortunately some manufacturers do not support the setting the power levels they advertise - you have to use the predefined tramp levels. I have considered introducing an option bit that allows you to try both ways.

I will dump here my modif to inav code, look for // commented-deleted code and // tcra comment (modified parts).
Then I will explain what I think.

vtx_tramp.c :

//const uint16_t trampPowerTable_5G8_200[VTX_TRAMP_5G8_MAX_POWER_COUNT] = { 25, 100, 200, 200, 200 };
//const char * const trampPowerNames_5G8_200[VTX_TRAMP_5G8_MAX_POWER_COUNT + 1] = { “—”, "25 ", “100”, “200”, “200”, “200” };
//
//const uint16_t trampPowerTable_5G8_400[VTX_TRAMP_5G8_MAX_POWER_COUNT] = { 25, 100, 200, 400, 400 };
//const char * const trampPowerNames_5G8_400[VTX_TRAMP_5G8_MAX_POWER_COUNT + 1] = { “—”, "25 ", “100”, “200”, “400”, “400” };
//
//const uint16_t trampPowerTable_5G8_600[VTX_TRAMP_5G8_MAX_POWER_COUNT] = { 25, 100, 200, 400, 600 };
//const char * const trampPowerNames_5G8_600[VTX_TRAMP_5G8_MAX_POWER_COUNT + 1] = { “—”, "25 ", “100”, “200”, “400”, “600” };
//
//const uint16_t trampPowerTable_5G8_800[VTX_TRAMP_5G8_MAX_POWER_COUNT] = { 25, 100, 200, 500, 800 };
//const char * const trampPowerNames_5G8_800[VTX_TRAMP_5G8_MAX_POWER_COUNT + 1] = { “—”, "25 ", “100”, “200”, “500”, “800” };

//const uint16_t trampPowerTable_1G3_800[VTX_TRAMP_1G3_MAX_POWER_COUNT] = { 25, 200, 800 };
//const char * const trampPowerNames_1G3_800[VTX_TRAMP_1G3_MAX_POWER_COUNT + 1] = { “—”, "25 ", “200”, “800” };

// tcra : added 1600
const uint16_t trampPowerTable_5G8_1600[VTX_TRAMP_5G8_MAX_POWER_COUNT] = { 25, 400, 800, 1600 };
const char * const trampPowerNames_5G8_1600[VTX_TRAMP_5G8_MAX_POWER_COUNT + 1] = { “—”, "25 ", “400”, “800”, “1K6” };

//const uint16_t trampPowerTable_1G3_2000[VTX_TRAMP_1G3_MAX_POWER_COUNT] = { 25, 200, 2000 };
//const char * const trampPowerNames_1G3_2000[VTX_TRAMP_1G3_MAX_POWER_COUNT + 1] = { “—”, "25 ", “200”, “2000” };

static void vtxProtoUpdatePowerMetadata(uint16_t maxPower)
{
switch (vtxSettingsConfig()->frequencyGroup) {
case FREQUENCYGROUP_1G3:
// if (maxPower >= 2000) {
// vtxState.metadata.powerTablePtr = trampPowerTable_1G3_2000;
// vtxState.metadata.powerTableCount = VTX_TRAMP_1G3_MAX_POWER_COUNT;
//
// impl_vtxDevice.capability.powerNames = (char **)trampPowerNames_1G3_2000;
// impl_vtxDevice.capability.powerCount = VTX_TRAMP_1G3_MAX_POWER_COUNT;
// }
// else {
// vtxState.metadata.powerTablePtr = trampPowerTable_1G3_800;
// vtxState.metadata.powerTableCount = VTX_TRAMP_1G3_MAX_POWER_COUNT;
//
// impl_vtxDevice.capability.powerNames = (char **)trampPowerNames_1G3_800;
// impl_vtxDevice.capability.powerCount = VTX_TRAMP_1G3_MAX_POWER_COUNT;
// }
// impl_vtxDevice.capability.bandCount = VTX_TRAMP_1G3_BAND_COUNT;
// impl_vtxDevice.capability.channelCount = VTX_TRAMP_1G3_CHANNEL_COUNT;
// impl_vtxDevice.capability.bandNames = (char **)vtx1G3BandNames;
// impl_vtxDevice.capability.channelNames = (char **)vtx1G3ChannelNames;
break;
default:
// tcra : added
// if (maxPower >= 1600) {
// Max power 1600mW: Use 25, 400, 800, 1600 table
vtxState.metadata.powerTablePtr = trampPowerTable_5G8_1600;
vtxState.metadata.powerTableCount = VTX_TRAMP_5G8_MAX_POWER_COUNT;

            impl_vtxDevice.capability.powerNames = (char **)trampPowerNames_5G8_1600;
            impl_vtxDevice.capability.powerCount = VTX_TRAMP_5G8_MAX_POWER_COUNT;

// }
// else if (maxPower >= 800) {
// // Max power 800mW: Use 25, 100, 200, 500, 800 table
// vtxState.metadata.powerTablePtr = trampPowerTable_5G8_800;
// vtxState.metadata.powerTableCount = VTX_TRAMP_5G8_MAX_POWER_COUNT;
//
// impl_vtxDevice.capability.powerNames = (char **)trampPowerNames_5G8_800;
// impl_vtxDevice.capability.powerCount = VTX_TRAMP_5G8_MAX_POWER_COUNT;
// }
// else if (maxPower >= 600) {
// // Max power 600mW: Use 25, 100, 200, 400, 600 table
// vtxState.metadata.powerTablePtr = trampPowerTable_5G8_600;
// vtxState.metadata.powerTableCount = VTX_TRAMP_5G8_MAX_POWER_COUNT;
//
// impl_vtxDevice.capability.powerNames = (char **)trampPowerNames_5G8_600;
// impl_vtxDevice.capability.powerCount = VTX_TRAMP_5G8_MAX_POWER_COUNT;
// }
// else if (maxPower >= 400) {
// // Max power 400mW: Use 25, 100, 200, 400 table
// vtxState.metadata.powerTablePtr = trampPowerTable_5G8_400;
// vtxState.metadata.powerTableCount = 4;
//
// impl_vtxDevice.capability.powerNames = (char **)trampPowerNames_5G8_400;
// impl_vtxDevice.capability.powerCount = 4;
// }
// else if (maxPower >= 200) {
// // Max power 200mW: Use 25, 100, 200 table
// vtxState.metadata.powerTablePtr = trampPowerTable_5G8_200;
// vtxState.metadata.powerTableCount = 3;
//
// impl_vtxDevice.capability.powerNames = (char **)trampPowerNames_5G8_200;
// impl_vtxDevice.capability.powerCount = 3;
// }
// else {
// // Default to standard TRAMP 600mW VTX
// vtxState.metadata.powerTablePtr = trampPowerTable_5G8_600;
// vtxState.metadata.powerTableCount = VTX_TRAMP_5G8_MAX_POWER_COUNT;
//
// impl_vtxDevice.capability.powerNames = (char **)trampPowerNames_5G8_600;
// impl_vtxDevice.capability.powerCount = VTX_TRAMP_5G8_MAX_POWER_COUNT;
// }
break;
}
}

bool vtxTrampInit(void)
{
serialPortConfig_t *portConfig = findSerialPortConfig(FUNCTION_VTX_TRAMP);

if (portConfig) {
    portOptions_t portOptions = 0;
    portOptions = portOptions | (vtxConfig()->halfDuplex ? SERIAL_BIDIR : SERIAL_UNIDIR);
    portOptions = portOptions | (vtxConfig()->softSerialShortStop ? SERIAL_SHORTSTOP : SERIAL_LONGSTOP);
    vtxState.port = openSerialPort(portConfig->identifier, FUNCTION_VTX_TRAMP, NULL, NULL, 9600, MODE_RXTX, portOptions);
}

if (!vtxState.port) {
    return false;
}

// vtxProtoUpdatePowerMetadata(600);
vtxProtoUpdatePowerMetadata(1600); // tcra (hardcoded 1600)
vtxCommonSetDevice(&impl_vtxDevice);

vtxState.protoState = VTX_STATE_RESET;

return true;

}

vtx_tramp.h :

// #define VTX_TRAMP_5G8_MAX_POWER_COUNT 5
#define VTX_TRAMP_5G8_MAX_POWER_COUNT 4 //tcra

Explanation / comments :
After unsuccesful triaIs, I deleted code not meaningful for the test and harcoded vtx BF table (json file part related to power). I also hardcoded max power to 1600.

What I noticed in the original code is that there are sometime 4, sometime 5 values, max is 5.
If 5 are defined, not always 5 are initialized or used (bad programming (?)) and in the following code it is assumed 5 values are available. This does not convince me.
This code works (4 levels), the original does not.
So, in the eend, there is a big mess. vtx_override_max_power parameter in inav cli is not sufficient to take into account all cases.
Why I use inav as an example ?
Because this code does not rely on vtx capabilities responses, it relies only on vtx BF table and IT WORKS. The device is just only commanded, not queried.
If You (@andyp1per ) may/do think about changing the code in copter, I think that at least all available levels and level number must be available / configured as VTX_### config parameters.
These may be cloned in (e.g.) MissionPlanner to correctly map BF vtx table (power part).

Do not esitate to ask me more details if You do not understand.

Hope this help,

Alfredo

This has been requested many times. The issue is its a big increase in flash cost. This could be amortized by just adding lua bindings. But really it’s not something I have a particular desire or time to work on - PR’s welcome.

@andyp1per :
With reference to arducopter 4.5.7, I compiled a custom vtx code that in SmartAudio uses 200, 400, 800, 1600 mw for Akk Race Ranger (old version, new advertized version starts from 25mw).
I found somewhere (dont remember exactly where on internet) that Akk Race Ranger uses smartaudio 2.0, so I searched for smartaudio 2.0 code in arducopter sources.

Why do I speak about Smartaudio here ?
→ because (read following notes …) I think it is pertinent to this discussion about not-compliant devices and because I got a problem similar to the one related to recent merge / discussion (AP_VideoTX: Fix _configuration_finished indication for Tramp VTX by menschel · Pull Request #28584 · ArduPilot/ardupilot · GitHub) in Smartaudio code .

In other words, to put Akk Race Ranger to work in Arducopter, I had to “bypass” protocol responses or queries.
I practised “big-bang” programming and IT WORKS !!! (see following code here).

But …
on OSD, now vtx milliwatt power display blinks all the time.
This is why I refer recent merge (AP_VideoTX: Fix _configuration_finished indication for Tramp VTX by menschel · Pull Request #28584 · ArduPilot/ardupilot · GitHub).

Do You think that vtx power blinking in OSD might be related to my modif (it is not not based on protocol responses …) or does exist some preexisting code problem in handling delays ? I see some delay device-depend code there in the sources…, that sound like last moment adjustements for putting to work some non standard vtx.

I attach here
4 images with the custom changes
2 images where the osd vtx power blinking problem much probably resides.

Thanks in advance if You have a look …

Alfredo


Addendum :
I had to force MAX_VTX_POWER to 1600 (nominal max is 1000) in MissionPlanner.
(but this is another story … :slight_smile: )

Alfredo