From 740fc4467f7b8600ab8b98a4079c0a5b46d31452 Mon Sep 17 00:00:00 2001 From: bkleiner Date: Sat, 10 Aug 2024 13:19:28 +0200 Subject: [PATCH] smartaudio: autmatically convert dbm values to labels --- src/driver/vtx/sa.c | 19 +++++++++--------- src/driver/vtx/sa.h | 1 + src/io/msp.c | 2 +- src/io/vtx.c | 2 +- src/io/vtx_smartaudio.c | 44 ++++++++++++++++++++++++++++++++--------- src/io/vtx_tramp.c | 3 +++ src/osd/render.c | 4 ++-- 7 files changed, 53 insertions(+), 22 deletions(-) diff --git a/src/driver/vtx/sa.c b/src/driver/vtx/sa.c index fc337c0a4..8fac5b98b 100644 --- a/src/driver/vtx/sa.c +++ b/src/driver/vtx/sa.c @@ -46,15 +46,11 @@ extern uint32_t vtx_last_request; extern uint8_t vtx_payload[32]; extern uint8_t vtx_payload_offset; -const uint8_t default_dac_power_levels[VTX_POWER_LEVEL_MAX] = { +const uint8_t default_dac_power_levels[4] = { 7, 16, 25, 40, - 40, - 40, - 40, - 40, }; static void serial_smart_audio_reconfigure() { @@ -125,13 +121,18 @@ static uint8_t serial_smart_audio_parse_packet(uint8_t cmd, uint8_t *payload, ui if (cmd == SA_CMD_GET_SETTINGS_V21) { smart_audio_settings.power = payload[5]; - const uint8_t count = max(payload[6], VTX_POWER_LEVEL_MAX); + smart_audio_settings.level_count = min(payload[6], VTX_POWER_LEVEL_MAX); - for (uint8_t i = 0; i < count; i++) { - smart_audio_settings.dac_power_levels[i] = payload[7 + i]; + // SmartAudio seems to report buf[8] + 1 power levels, but one of them is zero. + // zero is indeed a valid power level to set the vtx to, but it activates pit mode. + // crucially, after sending 0 dbm, the vtx does NOT report its power level to be 0 dbm. + // instead, it reports whatever value was set previously and it reports to be in pit mode. + for (uint8_t i = 0; i < smart_audio_settings.level_count; i++) { + smart_audio_settings.dac_power_levels[i] = payload[7 + i + 1]; //+ 1 to skip the first power level, as mentioned above } } else { - for (uint8_t i = 0; i < VTX_POWER_LEVEL_MAX; i++) { + smart_audio_settings.level_count = 4; + for (uint8_t i = 0; i < smart_audio_settings.level_count; i++) { smart_audio_settings.dac_power_levels[i] = default_dac_power_levels[i]; } } diff --git a/src/driver/vtx/sa.h b/src/driver/vtx/sa.h index 0ba68fc29..f597cf612 100644 --- a/src/driver/vtx/sa.h +++ b/src/driver/vtx/sa.h @@ -28,6 +28,7 @@ typedef struct { uint8_t power; uint8_t mode; uint16_t frequency; + uint8_t level_count; uint16_t dac_power_levels[8]; } smart_audio_settings_t; diff --git a/src/io/msp.c b/src/io/msp.c index 443c5edbd..dc4d20098 100644 --- a/src/io/msp.c +++ b/src/io/msp.c @@ -466,7 +466,7 @@ static void msp_process_serial_cmd(msp_t *msp, msp_magic_t magic, uint16_t cmd, case MSP_VTXTABLE_POWERLEVEL: { const uint8_t level = payload[0]; - if (level <= 0 || level > VTX_POWER_LEVEL_MAX) { + if (level <= 0 || level > vtx_actual.power_table.levels) { msp_send_error(msp, magic, cmd); break; } diff --git a/src/io/vtx.c b/src/io/vtx.c index 42b3e78ef..5f3c31aaa 100644 --- a/src/io/vtx.c +++ b/src/io/vtx.c @@ -400,7 +400,7 @@ void vtx_set(vtx_settings_t *vtx) { if (vtx_settings.pit_mode != VTX_PIT_MODE_NO_SUPPORT) vtx_settings.pit_mode = vtx->pit_mode; - vtx_settings.power_level = vtx->power_level < VTX_POWER_LEVEL_MAX ? vtx->power_level : (VTX_POWER_LEVEL_MAX - 1); + vtx_settings.power_level = vtx->power_level < vtx_settings.power_table.levels ? vtx->power_level : (vtx_settings.power_table.levels - 1); vtx_settings.band = vtx->band < VTX_BAND_MAX ? vtx->band : 0; vtx_settings.channel = vtx->channel < VTX_CHANNEL_MAX ? vtx->channel : 0; diff --git a/src/io/vtx_smartaudio.c b/src/io/vtx_smartaudio.c index 31bea9e06..975e19c3e 100644 --- a/src/io/vtx_smartaudio.c +++ b/src/io/vtx_smartaudio.c @@ -1,5 +1,6 @@ #include "vtx.h" +#include #include #include "driver/serial.h" @@ -17,17 +18,36 @@ extern smart_audio_settings_t smart_audio_settings; static bool smart_audio_needs_update = false; -static const char smart_audio_power_level_labels[VTX_POWER_LEVEL_MAX][VTX_POWER_LABEL_LEN] = { +static const char smart_audio_power_level_labels[4][VTX_POWER_LABEL_LEN] = { "25 ", - "100 ", "200 ", - "300 ", - "400 ", - " ", - " ", - " ", + "500 ", + "800 ", }; +static uint32_t smart_audio_dbi_to_mw(uint16_t dbi) { + uint16_t mw = (uint16_t)powf(10.0f, dbi / 10.0f); + if (dbi > 14) { + // For powers greater than 25mW round up to a multiple of 50 to match expectations + mw = 50 * ((mw + 25) / 50); + } + return mw; +} + +static char *i2a(char *ptr, uint32_t val) { + const uint32_t div = val / 10; + if (div > 0) + ptr = i2a(ptr, div); + *ptr = '0' + (val % 10); + return ptr + 1; +} + +static void smart_audio_write_mw(char *buf, uint32_t val) { + char *ptr = i2a(buf, val); + while (ptr != (buf + VTX_POWER_LABEL_LEN)) + *ptr++ = ' '; +} + vtx_detect_status_t vtx_smart_audio_update(vtx_settings_t *actual) { if (smart_audio_settings.version == 0 && vtx_connect_tries > SMART_AUDIO_DETECT_TRIES) { return VTX_DETECT_ERROR; @@ -55,9 +75,15 @@ vtx_detect_status_t vtx_smart_audio_update(vtx_settings_t *actual) { actual->channel = channel_index % VTX_CHANNEL_MAX; } - actual->power_table.levels = VTX_POWER_LEVEL_MAX; + actual->power_table.levels = smart_audio_settings.level_count; memcpy(actual->power_table.values, smart_audio_settings.dac_power_levels, sizeof(smart_audio_settings.dac_power_levels)); - memcpy(actual->power_table.labels, smart_audio_power_level_labels, sizeof(smart_audio_power_level_labels)); + if (smart_audio_settings.version == 3) { + for (uint32_t i = 0; i < smart_audio_settings.level_count; i++) { + smart_audio_write_mw(actual->power_table.labels[i], smart_audio_dbi_to_mw(smart_audio_settings.dac_power_levels[i])); + } + } else { + memcpy(actual->power_table.labels, smart_audio_power_level_labels, sizeof(smart_audio_power_level_labels)); + } if (smart_audio_settings.version == 2) { actual->power_level = min(smart_audio_settings.power, VTX_POWER_LEVEL_MAX - 1); diff --git a/src/io/vtx_tramp.c b/src/io/vtx_tramp.c index 21ccb59a2..640e2b531 100644 --- a/src/io/vtx_tramp.c +++ b/src/io/vtx_tramp.c @@ -21,6 +21,9 @@ static const uint16_t tramp_power_level_values[VTX_POWER_LEVEL_MAX] = { 200, 300, 400, + 0, + 0, + 0, }; static const char tramp_power_level_labels[VTX_POWER_LEVEL_MAX][VTX_POWER_LABEL_LEN] = { diff --git a/src/osd/render.c b/src/osd/render.c index b7de2d2ce..eced5b243 100644 --- a/src/osd/render.c +++ b/src/osd/render.c @@ -931,7 +931,7 @@ void osd_display() { static char power_level_labels_terminated[VTX_POWER_LEVEL_MAX][VTX_POWER_LABEL_LEN + 1]; if (!vtx_buffer_populated) { vtx_settings_copy = vtx_settings; - for (uint8_t i = 0; i < VTX_POWER_LEVEL_MAX; i++) { + for (uint8_t i = 0; i < vtx_settings.power_table.levels; i++) { memcpy(power_level_labels_terminated[i], vtx_settings.power_table.labels[i], VTX_POWER_LABEL_LEN); power_level_labels_terminated[i][VTX_POWER_LABEL_LEN] = 0; power_level_labels[i] = power_level_labels_terminated[i]; @@ -947,7 +947,7 @@ void osd_display() { const char *channel_labels[] = {"1", "2", "3", "4", "5", "6", "7", "8"}; osd_menu_select_enum_adjust(4, 5, "CHANNEL", 20, &vtx_settings_copy.channel, channel_labels, VTX_CHANNEL_1, VTX_CHANNEL_8); - osd_menu_select_enum_adjust(4, 6, "POWER LEVEL", 20, &vtx_settings_copy.power_level, power_level_labels, VTX_POWER_LEVEL_1, VTX_POWER_LEVEL_MAX - 1); + osd_menu_select_enum_adjust(4, 6, "POWER LEVEL", 20, &vtx_settings_copy.power_level, power_level_labels, VTX_POWER_LEVEL_1, vtx_settings.power_table.levels - 1); const char *pit_mode_labels[] = {"OFF", "ON ", "N/A"}; osd_menu_select(4, 7, "PITMODE");