From 45aad0d3790ec1da661b130b1279747b3a7b2d6c Mon Sep 17 00:00:00 2001 From: Bruce Luckcuck Date: Thu, 26 Mar 2020 13:37:58 -0400 Subject: [PATCH] Add support for OSD element type variants Extends the OSD element position setting to include a 2 bit selector for alternate representations of the element. So up to 4 variants of an element can be supported. Meant to be used instead of adding new elements when the request is a mutually exclusive variant of an existing element. If there are no variants of an element then the logic falls back to "type 1" (`OSD_ELEMENT_TYPE_1`) which is the only representation of the element. As an example, in this PR the "Battery usage" element has been extended to 4 types: 1. The original capacity remaining graphical bar (shrinks as battery is used) - this is the default. 2. Capacity used graphical bar (grows as battery is used). 3. Remaining capacity numerical percentage (goes down as battery is used). 4. Capacity used numerical percentage (goes up as battery is used). When extending an element it is not necessary to support all 4 types and the element rendering code should default to the original type 1 version for unsupported types. Will require Configurator support. Since the 2 high bits of the `uint16` were previously unused the setting will default to the "type 1" original variant in all cases where an incompatible Configurator is used. --- src/main/osd/osd.h | 4 ++- src/main/osd/osd_elements.c | 57 ++++++++++++++++++++++++++++--------- src/main/osd/osd_elements.h | 8 ++++++ 3 files changed, 55 insertions(+), 14 deletions(-) diff --git a/src/main/osd/osd.h b/src/main/osd/osd.h index 518ed72c0f6..e612d5c930b 100644 --- a/src/main/osd/osd.h +++ b/src/main/osd/osd.h @@ -56,7 +56,7 @@ extern const char * const osdTimerSourceNames[OSD_NUM_TIMER_TYPES]; #define OSD_PROFILE_BITS_POS 11 #define OSD_PROFILE_MASK (((1 << OSD_PROFILE_COUNT) - 1) << OSD_PROFILE_BITS_POS) #define OSD_POS_MAX 0x3FF -#define OSD_POSCFG_MAX (OSD_PROFILE_MASK | 0x3FF) // For CLI values +#define OSD_POSCFG_MAX UINT16_MAX // element positions now use all 16 bits #define OSD_PROFILE_FLAG(x) (1 << ((x) - 1 + OSD_PROFILE_BITS_POS)) #define OSD_PROFILE_1_FLAG OSD_PROFILE_FLAG(1) @@ -73,9 +73,11 @@ extern const char * const osdTimerSourceNames[OSD_NUM_TIMER_TYPES]; // Character coordinate #define OSD_POSITION_BITS 5 // 5 bits gives a range 0-31 #define OSD_POSITION_XY_MASK ((1 << OSD_POSITION_BITS) - 1) +#define OSD_POSITION_TYPE_MASK 0xC000 // bits 14-15 #define OSD_POS(x,y) ((x & OSD_POSITION_XY_MASK) | ((y & OSD_POSITION_XY_MASK) << OSD_POSITION_BITS)) #define OSD_X(x) (x & OSD_POSITION_XY_MASK) #define OSD_Y(x) ((x >> OSD_POSITION_BITS) & OSD_POSITION_XY_MASK) +#define OSD_TYPE(x) ((x & OSD_POSITION_TYPE_MASK) >> 14) // Timer configuration // Stored as 15[alarm:8][precision:4][source:4]0 diff --git a/src/main/osd/osd_elements.c b/src/main/osd/osd_elements.c index 8fe95f0f59a..71e4e4f8364 100644 --- a/src/main/osd/osd_elements.c +++ b/src/main/osd/osd_elements.c @@ -1027,22 +1027,51 @@ static void osdElementMainBatteryUsage(osdElementParms_t *element) // Set length of indicator bar #define MAIN_BATT_USAGE_STEPS 11 // Use an odd number so the bar can be centered. - // Calculate constrained value - const float value = constrain(batteryConfig()->batteryCapacity - getMAhDrawn(), 0, batteryConfig()->batteryCapacity); + const int usedCapacity = getMAhDrawn(); + int displayBasis = usedCapacity; - // Calculate mAh used progress - const uint8_t mAhUsedProgress = (batteryConfig()->batteryCapacity) ? ceilf((value / (batteryConfig()->batteryCapacity / MAIN_BATT_USAGE_STEPS))) : 0; + switch (element->type) { + case OSD_ELEMENT_TYPE_3: // mAh remaining percentage (counts down as battery is used) + displayBasis = constrain(batteryConfig()->batteryCapacity - usedCapacity, 0, batteryConfig()->batteryCapacity); + FALLTHROUGH; - // Create empty battery indicator bar - element->buff[0] = SYM_PB_START; - for (int i = 1; i <= MAIN_BATT_USAGE_STEPS; i++) { - element->buff[i] = i <= mAhUsedProgress ? SYM_PB_FULL : SYM_PB_EMPTY; - } - element->buff[MAIN_BATT_USAGE_STEPS + 1] = SYM_PB_CLOSE; - if (mAhUsedProgress > 0 && mAhUsedProgress < MAIN_BATT_USAGE_STEPS) { - element->buff[1 + mAhUsedProgress] = SYM_PB_END; + case OSD_ELEMENT_TYPE_4: // mAh used percentage (counts up as battery is used) + { + int displayPercent = 0; + if (batteryConfig()->batteryCapacity) { + displayPercent = constrain(lrintf(100.0f * displayBasis / batteryConfig()->batteryCapacity), 0, 100); + } + tfp_sprintf(element->buff, "%c%d%%", SYM_MAH, displayPercent); + break; + } + + case OSD_ELEMENT_TYPE_2: // mAh used graphical progress bar (grows as battery is used) + displayBasis = constrain(batteryConfig()->batteryCapacity - usedCapacity, 0, batteryConfig()->batteryCapacity); + FALLTHROUGH; + + case OSD_ELEMENT_TYPE_1: // mAh remaining graphical progress bar (shrinks as battery is used) + default: + { + uint8_t remainingCapacityBars = 0; + + if (batteryConfig()->batteryCapacity) { + const float batteryRemaining = constrain(batteryConfig()->batteryCapacity - displayBasis, 0, batteryConfig()->batteryCapacity); + remainingCapacityBars = ceilf((batteryRemaining / (batteryConfig()->batteryCapacity / MAIN_BATT_USAGE_STEPS))); + } + + // Create empty battery indicator bar + element->buff[0] = SYM_PB_START; + for (int i = 1; i <= MAIN_BATT_USAGE_STEPS; i++) { + element->buff[i] = i <= remainingCapacityBars ? SYM_PB_FULL : SYM_PB_EMPTY; + } + element->buff[MAIN_BATT_USAGE_STEPS + 1] = SYM_PB_CLOSE; + if (remainingCapacityBars > 0 && remainingCapacityBars < MAIN_BATT_USAGE_STEPS) { + element->buff[1 + remainingCapacityBars] = SYM_PB_END; + } + element->buff[MAIN_BATT_USAGE_STEPS+2] = '\0'; + break; + } } - element->buff[MAIN_BATT_USAGE_STEPS+2] = '\0'; } static void osdElementMainBatteryVoltage(osdElementParms_t *element) @@ -1839,6 +1868,7 @@ static void osdDrawSingleElement(displayPort_t *osdDisplayPort, uint8_t item) element.item = item; element.elemPosX = elemPosX; element.elemPosY = elemPosY; + element.type = OSD_TYPE(osdElementConfig()->item_pos[item]); element.buff = (char *)&buff; element.osdDisplayPort = osdDisplayPort; element.drawElement = true; @@ -1866,6 +1896,7 @@ static void osdDrawSingleElementBackground(displayPort_t *osdDisplayPort, uint8_ element.item = item; element.elemPosX = elemPosX; element.elemPosY = elemPosY; + element.type = OSD_TYPE(osdElementConfig()->item_pos[item]); element.buff = (char *)&buff; element.osdDisplayPort = osdDisplayPort; element.drawElement = true; diff --git a/src/main/osd/osd_elements.h b/src/main/osd/osd_elements.h index ed724171626..1a4ce60ff36 100644 --- a/src/main/osd/osd_elements.h +++ b/src/main/osd/osd_elements.h @@ -24,10 +24,18 @@ #include "osd/osd.h" +typedef enum { + OSD_ELEMENT_TYPE_1 = 0, + OSD_ELEMENT_TYPE_2, + OSD_ELEMENT_TYPE_3, + OSD_ELEMENT_TYPE_4 +} osdElementType_e; + typedef struct osdElementParms_s { uint8_t item; uint8_t elemPosX; uint8_t elemPosY; + osdElementType_e type; char *buff; displayPort_t *osdDisplayPort; bool drawElement;