mirror of
https://github.com/betaflight/betaflight.git
synced 2025-07-15 20:35:33 +03:00
Add OSD background support for the static portions of display elements
Significantly reduces the time the OSD task spends drawing elements that are completely or mostly static. The larger the element the more time savings are realized. Currently implemented support for: - Crosshairs - Artificial Horizon Sidebars - Craft name - Display name - Stick overlay Since the static portions are only rendered once, the static elements add no processing time to the OSD task. As an example, enabling the above elements prior to these changes results in a total rendering time of 47us. After the enhancements they take only 6us (basically the rendering phase minimum overhead). So effectively 41us are removed from the OSD task. Opens the possibility to add large mostly static elements with no additional overhead. An example would be a camera framing element that might draw a "box" around most of the screen. Previously this would add significant processing overhead to the OSD task, but now it will have no impact.
This commit is contained in:
parent
de768751b4
commit
5f5ee33718
15 changed files with 305 additions and 49 deletions
|
@ -720,6 +720,7 @@ void cmsMenuOpen(void)
|
||||||
currentCtx = (cmsCtx_t){ &menuMain, 0, 0 };
|
currentCtx = (cmsCtx_t){ &menuMain, 0, 0 };
|
||||||
menuStackIdx = 0;
|
menuStackIdx = 0;
|
||||||
setArmingDisabled(ARMING_DISABLED_CMS_MENU);
|
setArmingDisabled(ARMING_DISABLED_CMS_MENU);
|
||||||
|
displayLayerSelect(pCurrentDisplay, DISPLAYPORT_LAYER_FOREGROUND); // make sure the foreground layer is active
|
||||||
} else {
|
} else {
|
||||||
// Switch display
|
// Switch display
|
||||||
displayPort_t *pNextDisplay = cmsDisplayPortSelectNext();
|
displayPort_t *pNextDisplay = cmsDisplayPortSelectNext();
|
||||||
|
|
|
@ -115,6 +115,33 @@ uint16_t displayTxBytesFree(const displayPort_t *instance)
|
||||||
return instance->vTable->txBytesFree(instance);
|
return instance->vTable->txBytesFree(instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool displayLayerSupported(displayPort_t *instance, displayPortLayer_e layer)
|
||||||
|
{
|
||||||
|
if (layer == DISPLAYPORT_LAYER_FOREGROUND) {
|
||||||
|
// Every device must support the foreground (default) layer
|
||||||
|
return true;
|
||||||
|
} else if (layer < DISPLAYPORT_LAYER_COUNT && instance->vTable->layerSupported) {
|
||||||
|
return instance->vTable->layerSupported(instance, layer);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool displayLayerSelect(displayPort_t *instance, displayPortLayer_e layer)
|
||||||
|
{
|
||||||
|
if (instance->vTable->layerSelect) {
|
||||||
|
return instance->vTable->layerSelect(instance, layer);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool displayLayerCopy(displayPort_t *instance, displayPortLayer_e destLayer, displayPortLayer_e sourceLayer)
|
||||||
|
{
|
||||||
|
if (instance->vTable->layerCopy && sourceLayer != destLayer) {
|
||||||
|
return instance->vTable->layerCopy(instance, destLayer, sourceLayer);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void displayInit(displayPort_t *instance, const displayPortVTable_t *vTable)
|
void displayInit(displayPort_t *instance, const displayPortVTable_t *vTable)
|
||||||
{
|
{
|
||||||
instance->vTable = vTable;
|
instance->vTable = vTable;
|
||||||
|
|
|
@ -20,6 +20,12 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
DISPLAYPORT_LAYER_FOREGROUND,
|
||||||
|
DISPLAYPORT_LAYER_BACKGROUND,
|
||||||
|
DISPLAYPORT_LAYER_COUNT,
|
||||||
|
} displayPortLayer_e;
|
||||||
|
|
||||||
struct displayPortVTable_s;
|
struct displayPortVTable_s;
|
||||||
|
|
||||||
typedef struct displayPort_s {
|
typedef struct displayPort_s {
|
||||||
|
@ -52,6 +58,9 @@ typedef struct displayPortVTable_s {
|
||||||
void (*resync)(displayPort_t *displayPort);
|
void (*resync)(displayPort_t *displayPort);
|
||||||
bool (*isSynced)(const displayPort_t *displayPort);
|
bool (*isSynced)(const displayPort_t *displayPort);
|
||||||
uint32_t (*txBytesFree)(const displayPort_t *displayPort);
|
uint32_t (*txBytesFree)(const displayPort_t *displayPort);
|
||||||
|
bool (*layerSupported)(displayPort_t *displayPort, displayPortLayer_e layer);
|
||||||
|
bool (*layerSelect)(displayPort_t *displayPort, displayPortLayer_e layer);
|
||||||
|
bool (*layerCopy)(displayPort_t *displayPort, displayPortLayer_e destLayer, displayPortLayer_e sourceLayer);
|
||||||
} displayPortVTable_t;
|
} displayPortVTable_t;
|
||||||
|
|
||||||
typedef struct displayPortProfile_s {
|
typedef struct displayPortProfile_s {
|
||||||
|
@ -81,3 +90,7 @@ void displayResync(displayPort_t *instance);
|
||||||
bool displayIsSynced(const displayPort_t *instance);
|
bool displayIsSynced(const displayPort_t *instance);
|
||||||
uint16_t displayTxBytesFree(const displayPort_t *instance);
|
uint16_t displayTxBytesFree(const displayPort_t *instance);
|
||||||
void displayInit(displayPort_t *instance, const displayPortVTable_t *vTable);
|
void displayInit(displayPort_t *instance, const displayPortVTable_t *vTable);
|
||||||
|
bool displayLayerSupported(displayPort_t *instance, displayPortLayer_e layer);
|
||||||
|
bool displayLayerSelect(displayPort_t *instance, displayPortLayer_e layer);
|
||||||
|
bool displayLayerCopy(displayPort_t *instance, displayPortLayer_e destLayer, displayPortLayer_e sourceLayer);
|
||||||
|
|
||||||
|
|
|
@ -181,6 +181,15 @@
|
||||||
#define __spiBusTransactionEnd(busdev) {IOHi((busdev)->busdev_u.spi.csnPin);spiSetDivisor((busdev)->busdev_u.spi.instance, MAX7456_RESTORE_CLK);}
|
#define __spiBusTransactionEnd(busdev) {IOHi((busdev)->busdev_u.spi.csnPin);spiSetDivisor((busdev)->busdev_u.spi.instance, MAX7456_RESTORE_CLK);}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define MAX7456_SUPPORTED_LAYER_COUNT (DISPLAYPORT_LAYER_BACKGROUND + 1)
|
||||||
|
|
||||||
|
typedef struct max7456Layer_s {
|
||||||
|
uint8_t buffer[VIDEO_BUFFER_CHARS_PAL];
|
||||||
|
} max7456Layer_t;
|
||||||
|
|
||||||
|
static max7456Layer_t displayLayers[MAX7456_SUPPORTED_LAYER_COUNT];
|
||||||
|
static displayPortLayer_e activeLayer = DISPLAYPORT_LAYER_FOREGROUND;
|
||||||
|
|
||||||
busDevice_t max7456BusDevice;
|
busDevice_t max7456BusDevice;
|
||||||
busDevice_t *busdev = &max7456BusDevice;
|
busDevice_t *busdev = &max7456BusDevice;
|
||||||
|
|
||||||
|
@ -188,11 +197,10 @@ static uint16_t max7456SpiClock = MAX7456_SPI_CLK;
|
||||||
|
|
||||||
uint16_t maxScreenSize = VIDEO_BUFFER_CHARS_PAL;
|
uint16_t maxScreenSize = VIDEO_BUFFER_CHARS_PAL;
|
||||||
|
|
||||||
// We write everything in screenBuffer and then compare
|
// We write everything to the active layer and then compare
|
||||||
// screenBuffer with shadowBuffer to upgrade only changed chars.
|
// it with shadowBuffer to update only changed chars.
|
||||||
// This solution is faster then redrawing entire screen.
|
// This solution is faster then redrawing entire screen.
|
||||||
|
|
||||||
static uint8_t screenBuffer[VIDEO_BUFFER_CHARS_PAL+40]; // For faster writes we use memcpy so we need some space to don't overwrite buffer
|
|
||||||
static uint8_t shadowBuffer[VIDEO_BUFFER_CHARS_PAL];
|
static uint8_t shadowBuffer[VIDEO_BUFFER_CHARS_PAL];
|
||||||
|
|
||||||
//Max chars to update in one idle
|
//Max chars to update in one idle
|
||||||
|
@ -222,6 +230,16 @@ static uint8_t previousInvertRegister = INVALID_PREVIOUS_REGISTER_STATE;
|
||||||
|
|
||||||
static void max7456DrawScreenSlow(void);
|
static void max7456DrawScreenSlow(void);
|
||||||
|
|
||||||
|
static uint8_t *getLayerBuffer(displayPortLayer_e layer)
|
||||||
|
{
|
||||||
|
return displayLayers[layer].buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t *getActiveLayerBuffer(void)
|
||||||
|
{
|
||||||
|
return getLayerBuffer(activeLayer);
|
||||||
|
}
|
||||||
|
|
||||||
static uint8_t max7456Send(uint8_t add, uint8_t data)
|
static uint8_t max7456Send(uint8_t add, uint8_t data)
|
||||||
{
|
{
|
||||||
spiTransferByte(busdev->busdev_u.spi.instance, add);
|
spiTransferByte(busdev->busdev_u.spi.instance, add);
|
||||||
|
@ -349,11 +367,21 @@ uint8_t max7456GetRowsCount(void)
|
||||||
return (videoSignalReg & VIDEO_MODE_PAL) ? VIDEO_LINES_PAL : VIDEO_LINES_NTSC;
|
return (videoSignalReg & VIDEO_MODE_PAL) ? VIDEO_LINES_PAL : VIDEO_LINES_NTSC;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// When clearing the shadow buffer we fill with 0 so that the characters will
|
||||||
|
// be flagged as changed when compared to the 0x20 used in the layer buffers.
|
||||||
static void max7456ClearShadowBuffer(void)
|
static void max7456ClearShadowBuffer(void)
|
||||||
{
|
{
|
||||||
memset(shadowBuffer, 0, maxScreenSize);
|
memset(shadowBuffer, 0, maxScreenSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Buffer is filled with the whitespace character (0x20)
|
||||||
|
static void max7456ClearLayer(displayPortLayer_e layer)
|
||||||
|
{
|
||||||
|
memset(getLayerBuffer(layer), 0x20, VIDEO_BUFFER_CHARS_PAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void max7456ReInit(void)
|
void max7456ReInit(void)
|
||||||
{
|
{
|
||||||
uint8_t srdata = 0;
|
uint8_t srdata = 0;
|
||||||
|
@ -422,6 +450,11 @@ void max7456PreInit(const max7456Config_t *max7456Config)
|
||||||
|
|
||||||
bool max7456Init(const max7456Config_t *max7456Config, const vcdProfile_t *pVcdProfile, bool cpuOverclock)
|
bool max7456Init(const max7456Config_t *max7456Config, const vcdProfile_t *pVcdProfile, bool cpuOverclock)
|
||||||
{
|
{
|
||||||
|
// initialize all layers
|
||||||
|
for (unsigned i = 0; i < MAX7456_SUPPORTED_LAYER_COUNT; i++) {
|
||||||
|
max7456ClearLayer(i);
|
||||||
|
}
|
||||||
|
|
||||||
max7456HardwareReset();
|
max7456HardwareReset();
|
||||||
|
|
||||||
if (!max7456Config->csTag || !max7456Config->spiDevice) {
|
if (!max7456Config->csTag || !max7456Config->spiDevice) {
|
||||||
|
@ -568,33 +601,58 @@ void max7456Brightness(uint8_t black, uint8_t white)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//just fill with spaces with some tricks
|
|
||||||
void max7456ClearScreen(void)
|
void max7456ClearScreen(void)
|
||||||
{
|
{
|
||||||
memset(screenBuffer, 0x20, VIDEO_BUFFER_CHARS_PAL);
|
max7456ClearLayer(activeLayer);
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t* max7456GetScreenBuffer(void)
|
|
||||||
{
|
|
||||||
return screenBuffer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void max7456WriteChar(uint8_t x, uint8_t y, uint8_t c)
|
void max7456WriteChar(uint8_t x, uint8_t y, uint8_t c)
|
||||||
{
|
{
|
||||||
|
uint8_t *buffer = getActiveLayerBuffer();
|
||||||
if (x < CHARS_PER_LINE && y < VIDEO_LINES_PAL) {
|
if (x < CHARS_PER_LINE && y < VIDEO_LINES_PAL) {
|
||||||
screenBuffer[y * CHARS_PER_LINE + x] = c;
|
buffer[y * CHARS_PER_LINE + x] = c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void max7456Write(uint8_t x, uint8_t y, const char *buff)
|
void max7456Write(uint8_t x, uint8_t y, const char *buff)
|
||||||
{
|
{
|
||||||
if (y < VIDEO_LINES_PAL) {
|
if (y < VIDEO_LINES_PAL) {
|
||||||
|
uint8_t *buffer = getActiveLayerBuffer();
|
||||||
for (int i = 0; buff[i] && x + i < CHARS_PER_LINE; i++) {
|
for (int i = 0; buff[i] && x + i < CHARS_PER_LINE; i++) {
|
||||||
screenBuffer[y * CHARS_PER_LINE + x + i] = buff[i];
|
buffer[y * CHARS_PER_LINE + x + i] = buff[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool max7456LayerSupported(displayPortLayer_e layer)
|
||||||
|
{
|
||||||
|
if (layer == DISPLAYPORT_LAYER_FOREGROUND || layer == DISPLAYPORT_LAYER_BACKGROUND) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool max7456LayerSelect(displayPortLayer_e layer)
|
||||||
|
{
|
||||||
|
if (max7456LayerSupported(layer)) {
|
||||||
|
activeLayer = layer;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool max7456LayerCopy(displayPortLayer_e destLayer, displayPortLayer_e sourceLayer)
|
||||||
|
{
|
||||||
|
if ((sourceLayer != destLayer) && max7456LayerSupported(sourceLayer) && max7456LayerSupported(destLayer)) {
|
||||||
|
memcpy(getLayerBuffer(destLayer), getLayerBuffer(sourceLayer), VIDEO_BUFFER_CHARS_PAL);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool max7456DmaInProgress(void)
|
bool max7456DmaInProgress(void)
|
||||||
{
|
{
|
||||||
#ifdef MAX7456_DMA_CHANNEL_TX
|
#ifdef MAX7456_DMA_CHANNEL_TX
|
||||||
|
@ -607,7 +665,7 @@ bool max7456DmaInProgress(void)
|
||||||
bool max7456BuffersSynced(void)
|
bool max7456BuffersSynced(void)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < maxScreenSize; i++) {
|
for (int i = 0; i < maxScreenSize; i++) {
|
||||||
if (screenBuffer[i] != shadowBuffer[i]) {
|
if (displayLayers[DISPLAYPORT_LAYER_FOREGROUND].buffer[i] != shadowBuffer[i]) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -679,16 +737,18 @@ void max7456DrawScreen(void)
|
||||||
|
|
||||||
max7456ReInitIfRequired(false);
|
max7456ReInitIfRequired(false);
|
||||||
|
|
||||||
|
uint8_t *buffer = getActiveLayerBuffer();
|
||||||
|
|
||||||
int buff_len = 0;
|
int buff_len = 0;
|
||||||
for (int k = 0; k < MAX_CHARS2UPDATE; k++) {
|
for (int k = 0; k < MAX_CHARS2UPDATE; k++) {
|
||||||
if (screenBuffer[pos] != shadowBuffer[pos]) {
|
if (buffer[pos] != shadowBuffer[pos]) {
|
||||||
spiBuff[buff_len++] = MAX7456ADD_DMAH;
|
spiBuff[buff_len++] = MAX7456ADD_DMAH;
|
||||||
spiBuff[buff_len++] = pos >> 8;
|
spiBuff[buff_len++] = pos >> 8;
|
||||||
spiBuff[buff_len++] = MAX7456ADD_DMAL;
|
spiBuff[buff_len++] = MAX7456ADD_DMAL;
|
||||||
spiBuff[buff_len++] = pos & 0xff;
|
spiBuff[buff_len++] = pos & 0xff;
|
||||||
spiBuff[buff_len++] = MAX7456ADD_DMDI;
|
spiBuff[buff_len++] = MAX7456ADD_DMDI;
|
||||||
spiBuff[buff_len++] = screenBuffer[pos];
|
spiBuff[buff_len++] = buffer[pos];
|
||||||
shadowBuffer[pos] = screenBuffer[pos];
|
shadowBuffer[pos] = buffer[pos];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (++pos >= maxScreenSize) {
|
if (++pos >= maxScreenSize) {
|
||||||
|
@ -712,23 +772,24 @@ void max7456DrawScreen(void)
|
||||||
static void max7456DrawScreenSlow(void)
|
static void max7456DrawScreenSlow(void)
|
||||||
{
|
{
|
||||||
bool escapeCharFound;
|
bool escapeCharFound;
|
||||||
|
uint8_t *buffer = getActiveLayerBuffer();
|
||||||
|
|
||||||
__spiBusTransactionBegin(busdev);
|
__spiBusTransactionBegin(busdev);
|
||||||
|
|
||||||
// Enable auto-increment mode and update every character in the screenBuffer.
|
// Enable auto-increment mode and update every character in the active buffer.
|
||||||
// The "escape" character 0xFF must be skipped as it causes the MAX7456 to exit auto-increment mode.
|
// The "escape" character 0xFF must be skipped as it causes the MAX7456 to exit auto-increment mode.
|
||||||
max7456Send(MAX7456ADD_DMAH, 0);
|
max7456Send(MAX7456ADD_DMAH, 0);
|
||||||
max7456Send(MAX7456ADD_DMAL, 0);
|
max7456Send(MAX7456ADD_DMAL, 0);
|
||||||
max7456Send(MAX7456ADD_DMM, displayMemoryModeReg | 1);
|
max7456Send(MAX7456ADD_DMM, displayMemoryModeReg | 1);
|
||||||
|
|
||||||
for (int xx = 0; xx < maxScreenSize; xx++) {
|
for (int xx = 0; xx < maxScreenSize; xx++) {
|
||||||
if (screenBuffer[xx] == END_STRING) {
|
if (buffer[xx] == END_STRING) {
|
||||||
escapeCharFound = true;
|
escapeCharFound = true;
|
||||||
max7456Send(MAX7456ADD_DMDI, ' '); // replace the 0xFF character with a blank in the first pass to avoid terminating auto-increment
|
max7456Send(MAX7456ADD_DMDI, ' '); // replace the 0xFF character with a blank in the first pass to avoid terminating auto-increment
|
||||||
} else {
|
} else {
|
||||||
max7456Send(MAX7456ADD_DMDI, screenBuffer[xx]);
|
max7456Send(MAX7456ADD_DMDI, buffer[xx]);
|
||||||
}
|
}
|
||||||
shadowBuffer[xx] = screenBuffer[xx];
|
shadowBuffer[xx] = buffer[xx];
|
||||||
}
|
}
|
||||||
|
|
||||||
max7456Send(MAX7456ADD_DMDI, END_STRING);
|
max7456Send(MAX7456ADD_DMDI, END_STRING);
|
||||||
|
@ -738,7 +799,7 @@ static void max7456DrawScreenSlow(void)
|
||||||
// to update them with direct addressing
|
// to update them with direct addressing
|
||||||
if (escapeCharFound) {
|
if (escapeCharFound) {
|
||||||
for (int xx = 0; xx < maxScreenSize; xx++) {
|
for (int xx = 0; xx < maxScreenSize; xx++) {
|
||||||
if (screenBuffer[xx] == END_STRING) {
|
if (buffer[xx] == END_STRING) {
|
||||||
max7456Send(MAX7456ADD_DMAH, xx >> 8);
|
max7456Send(MAX7456ADD_DMAH, xx >> 8);
|
||||||
max7456Send(MAX7456ADD_DMAL, xx & 0xFF);
|
max7456Send(MAX7456ADD_DMAL, xx & 0xFF);
|
||||||
max7456Send(MAX7456ADD_DMDI, END_STRING);
|
max7456Send(MAX7456ADD_DMDI, END_STRING);
|
||||||
|
|
|
@ -20,6 +20,8 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "drivers/display.h"
|
||||||
|
|
||||||
/** PAL or NTSC, value is number of chars total */
|
/** PAL or NTSC, value is number of chars total */
|
||||||
#define VIDEO_BUFFER_CHARS_NTSC 390
|
#define VIDEO_BUFFER_CHARS_NTSC 390
|
||||||
#define VIDEO_BUFFER_CHARS_PAL 480
|
#define VIDEO_BUFFER_CHARS_PAL 480
|
||||||
|
@ -27,7 +29,6 @@
|
||||||
#define VIDEO_LINES_PAL 16
|
#define VIDEO_LINES_PAL 16
|
||||||
|
|
||||||
extern uint16_t maxScreenSize;
|
extern uint16_t maxScreenSize;
|
||||||
|
|
||||||
struct vcdProfile_s;
|
struct vcdProfile_s;
|
||||||
void max7456HardwareReset(void);
|
void max7456HardwareReset(void);
|
||||||
struct max7456Config_s;
|
struct max7456Config_s;
|
||||||
|
@ -42,6 +43,8 @@ void max7456Write(uint8_t x, uint8_t y, const char *buff);
|
||||||
void max7456WriteChar(uint8_t x, uint8_t y, uint8_t c);
|
void max7456WriteChar(uint8_t x, uint8_t y, uint8_t c);
|
||||||
void max7456ClearScreen(void);
|
void max7456ClearScreen(void);
|
||||||
void max7456RefreshAll(void);
|
void max7456RefreshAll(void);
|
||||||
uint8_t* max7456GetScreenBuffer(void);
|
|
||||||
bool max7456DmaInProgress(void);
|
bool max7456DmaInProgress(void);
|
||||||
bool max7456BuffersSynced(void);
|
bool max7456BuffersSynced(void);
|
||||||
|
bool max7456LayerSupported(displayPortLayer_e layer);
|
||||||
|
bool max7456LayerSelect(displayPortLayer_e layer);
|
||||||
|
bool max7456LayerCopy(displayPortLayer_e destLayer, displayPortLayer_e sourceLayer);
|
||||||
|
|
|
@ -138,7 +138,10 @@ static const displayPortVTable_t crsfDisplayPortVTable = {
|
||||||
.heartbeat = crsfHeartbeat,
|
.heartbeat = crsfHeartbeat,
|
||||||
.resync = crsfResync,
|
.resync = crsfResync,
|
||||||
.isSynced = crsfIsSynced,
|
.isSynced = crsfIsSynced,
|
||||||
.txBytesFree = crsfTxBytesFree
|
.txBytesFree = crsfTxBytesFree,
|
||||||
|
.layerSupported = NULL,
|
||||||
|
.layerSelect = NULL,
|
||||||
|
.layerCopy = NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
crsfDisplayPortScreen_t *crsfDisplayPortScreen(void)
|
crsfDisplayPortScreen_t *crsfDisplayPortScreen(void)
|
||||||
|
|
|
@ -119,7 +119,10 @@ static const displayPortVTable_t hottVTable = {
|
||||||
.isTransferInProgress = hottIsTransferInProgress,
|
.isTransferInProgress = hottIsTransferInProgress,
|
||||||
.heartbeat = hottHeartbeat,
|
.heartbeat = hottHeartbeat,
|
||||||
.resync = hottResync,
|
.resync = hottResync,
|
||||||
.txBytesFree = hottTxBytesFree
|
.txBytesFree = hottTxBytesFree,
|
||||||
|
.layerSupported = NULL,
|
||||||
|
.layerSelect = NULL,
|
||||||
|
.layerCopy = NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
displayPort_t *displayPortHottInit()
|
displayPort_t *displayPortHottInit()
|
||||||
|
|
|
@ -148,6 +148,24 @@ static uint32_t txBytesFree(const displayPort_t *displayPort)
|
||||||
return UINT32_MAX;
|
return UINT32_MAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool layerSupported(displayPort_t *displayPort, displayPortLayer_e layer)
|
||||||
|
{
|
||||||
|
UNUSED(displayPort);
|
||||||
|
return max7456LayerSupported(layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool layerSelect(displayPort_t *displayPort, displayPortLayer_e layer)
|
||||||
|
{
|
||||||
|
UNUSED(displayPort);
|
||||||
|
return max7456LayerSelect(layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool layerCopy(displayPort_t *displayPort, displayPortLayer_e destLayer, displayPortLayer_e sourceLayer)
|
||||||
|
{
|
||||||
|
UNUSED(displayPort);
|
||||||
|
return max7456LayerCopy(destLayer, sourceLayer);
|
||||||
|
}
|
||||||
|
|
||||||
static const displayPortVTable_t max7456VTable = {
|
static const displayPortVTable_t max7456VTable = {
|
||||||
.grab = grab,
|
.grab = grab,
|
||||||
.release = release,
|
.release = release,
|
||||||
|
@ -161,6 +179,9 @@ static const displayPortVTable_t max7456VTable = {
|
||||||
.resync = resync,
|
.resync = resync,
|
||||||
.isSynced = isSynced,
|
.isSynced = isSynced,
|
||||||
.txBytesFree = txBytesFree,
|
.txBytesFree = txBytesFree,
|
||||||
|
.layerSupported = layerSupported,
|
||||||
|
.layerSelect = layerSelect,
|
||||||
|
.layerCopy = layerCopy,
|
||||||
};
|
};
|
||||||
|
|
||||||
displayPort_t *max7456DisplayPortInit(const vcdProfile_t *vcdProfile)
|
displayPort_t *max7456DisplayPortInit(const vcdProfile_t *vcdProfile)
|
||||||
|
|
|
@ -167,7 +167,10 @@ static const displayPortVTable_t mspDisplayPortVTable = {
|
||||||
.heartbeat = heartbeat,
|
.heartbeat = heartbeat,
|
||||||
.resync = resync,
|
.resync = resync,
|
||||||
.isSynced = isSynced,
|
.isSynced = isSynced,
|
||||||
.txBytesFree = txBytesFree
|
.txBytesFree = txBytesFree,
|
||||||
|
.layerSupported = NULL,
|
||||||
|
.layerSelect = NULL,
|
||||||
|
.layerCopy = NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
displayPort_t *displayPortMspInit(void)
|
displayPort_t *displayPortMspInit(void)
|
||||||
|
|
|
@ -114,7 +114,10 @@ static const displayPortVTable_t oledVTable = {
|
||||||
.heartbeat = oledHeartbeat,
|
.heartbeat = oledHeartbeat,
|
||||||
.resync = oledResync,
|
.resync = oledResync,
|
||||||
.isSynced = oledIsSynced,
|
.isSynced = oledIsSynced,
|
||||||
.txBytesFree = oledTxBytesFree
|
.txBytesFree = oledTxBytesFree,
|
||||||
|
.layerSupported = NULL,
|
||||||
|
.layerSelect = NULL,
|
||||||
|
.layerCopy = NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
displayPort_t *displayPortOledInit(void *device)
|
displayPort_t *displayPortOledInit(void *device)
|
||||||
|
|
|
@ -130,7 +130,10 @@ static const displayPortVTable_t srxlVTable = {
|
||||||
.heartbeat = srxlHeartbeat,
|
.heartbeat = srxlHeartbeat,
|
||||||
.resync = srxlResync,
|
.resync = srxlResync,
|
||||||
.isSynced = srxlIsSynced,
|
.isSynced = srxlIsSynced,
|
||||||
.txBytesFree = srxlTxBytesFree
|
.txBytesFree = srxlTxBytesFree,
|
||||||
|
.layerSupported = NULL,
|
||||||
|
.layerSelect = NULL,
|
||||||
|
.layerCopy = NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
displayPort_t *displayPortSrxlInit()
|
displayPort_t *displayPortSrxlInit()
|
||||||
|
|
|
@ -124,6 +124,8 @@ static displayPort_t *osdDisplayPort;
|
||||||
static bool suppressStatsDisplay = false;
|
static bool suppressStatsDisplay = false;
|
||||||
static uint8_t osdStatsRowCount = 0;
|
static uint8_t osdStatsRowCount = 0;
|
||||||
|
|
||||||
|
static bool backgroundLayerSupported = false;
|
||||||
|
|
||||||
#ifdef USE_ESC_SENSOR
|
#ifdef USE_ESC_SENSOR
|
||||||
escSensorData_t *osdEscDataCombined;
|
escSensorData_t *osdEscDataCombined;
|
||||||
#endif
|
#endif
|
||||||
|
@ -225,15 +227,30 @@ void changeOsdProfileIndex(uint8_t profileIndex)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void osdAnalyzeActiveElements(void)
|
||||||
|
{
|
||||||
|
osdAddActiveElements();
|
||||||
|
osdDrawActiveElementsBackground(osdDisplayPort);
|
||||||
|
}
|
||||||
|
|
||||||
static void osdDrawElements(timeUs_t currentTimeUs)
|
static void osdDrawElements(timeUs_t currentTimeUs)
|
||||||
{
|
{
|
||||||
displayClearScreen(osdDisplayPort);
|
|
||||||
|
|
||||||
// Hide OSD when OSDSW mode is active
|
// Hide OSD when OSDSW mode is active
|
||||||
if (IS_RC_MODE_ACTIVE(BOXOSD)) {
|
if (IS_RC_MODE_ACTIVE(BOXOSD)) {
|
||||||
|
displayClearScreen(osdDisplayPort);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (backgroundLayerSupported) {
|
||||||
|
// Background layer is supported, overlay it onto the foreground
|
||||||
|
// so that we only need to draw the active parts of the elements.
|
||||||
|
displayLayerCopy(osdDisplayPort, DISPLAYPORT_LAYER_FOREGROUND, DISPLAYPORT_LAYER_BACKGROUND);
|
||||||
|
} else {
|
||||||
|
// Background layer not supported, just clear the foreground in preparation
|
||||||
|
// for drawing the elements including their backgrounds.
|
||||||
|
displayClearScreen(osdDisplayPort);
|
||||||
|
}
|
||||||
|
|
||||||
osdDrawActiveElements(osdDisplayPort, currentTimeUs);
|
osdDrawActiveElements(osdDisplayPort, currentTimeUs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -342,6 +359,9 @@ void osdInit(displayPort_t *osdDisplayPortToUse)
|
||||||
cmsDisplayPortRegister(osdDisplayPort);
|
cmsDisplayPortRegister(osdDisplayPort);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
backgroundLayerSupported = displayLayerSupported(osdDisplayPort, DISPLAYPORT_LAYER_BACKGROUND);
|
||||||
|
displayLayerSelect(osdDisplayPort, DISPLAYPORT_LAYER_FOREGROUND);
|
||||||
|
|
||||||
armState = ARMING_FLAG(ARMED);
|
armState = ARMING_FLAG(ARMED);
|
||||||
|
|
||||||
osdResetAlarms();
|
osdResetAlarms();
|
||||||
|
@ -372,6 +392,8 @@ void osdInit(displayPort_t *osdDisplayPortToUse)
|
||||||
#ifdef USE_OSD_PROFILES
|
#ifdef USE_OSD_PROFILES
|
||||||
setOsdProfile(osdConfig()->osdProfileIndex);
|
setOsdProfile(osdConfig()->osdProfileIndex);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
osdElementsInit(backgroundLayerSupported);
|
||||||
osdAnalyzeActiveElements();
|
osdAnalyzeActiveElements();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -921,7 +943,6 @@ void osdUpdate(timeUs_t currentTimeUs)
|
||||||
#else
|
#else
|
||||||
#define DRAW_FREQ_DENOM 10 // MWOSD @ 115200 baud (
|
#define DRAW_FREQ_DENOM 10 // MWOSD @ 115200 baud (
|
||||||
#endif
|
#endif
|
||||||
#define STATS_FREQ_DENOM 50
|
|
||||||
|
|
||||||
if (counter % DRAW_FREQ_DENOM == 0) {
|
if (counter % DRAW_FREQ_DENOM == 0) {
|
||||||
osdRefresh(currentTimeUs);
|
osdRefresh(currentTimeUs);
|
||||||
|
|
|
@ -311,6 +311,7 @@ void osdWarnSetState(uint8_t warningIndex, bool enabled);
|
||||||
bool osdWarnGetState(uint8_t warningIndex);
|
bool osdWarnGetState(uint8_t warningIndex);
|
||||||
void osdSuppressStats(bool flag);
|
void osdSuppressStats(bool flag);
|
||||||
|
|
||||||
|
void osdAnalyzeActiveElements(void);
|
||||||
uint8_t getCurrentOsdProfileIndex(void);
|
uint8_t getCurrentOsdProfileIndex(void);
|
||||||
void changeOsdProfileIndex(uint8_t profileIndex);
|
void changeOsdProfileIndex(uint8_t profileIndex);
|
||||||
bool osdElementVisible(uint16_t value);
|
bool osdElementVisible(uint16_t value);
|
||||||
|
|
|
@ -28,14 +28,31 @@
|
||||||
|
|
||||||
Next add the element to the osdElementDisplayOrder array defined in this file.
|
Next add the element to the osdElementDisplayOrder array defined in this file.
|
||||||
If the element needs special runtime conditional processing then it should be added
|
If the element needs special runtime conditional processing then it should be added
|
||||||
to the osdAnalyzeActiveElements() function instead.
|
to the osdAddActiveElements() function instead.
|
||||||
|
|
||||||
Create the function to "draw" the element. It should be named like "osdElementSomething()"
|
Create the function to "draw" the element.
|
||||||
where the "Something" describes the element.
|
------------------------------------------
|
||||||
|
It should be named like "osdElementSomething()" where the "Something" describes
|
||||||
|
the element. The drawing function should only render the dynamic portions of the
|
||||||
|
element. If the element has static (unchanging) portions then those should be
|
||||||
|
rendered in the background function. The exception to this is elements that are
|
||||||
|
expected to blink (have a warning associated). In this case the entire element
|
||||||
|
must be handled in the main draw function and you can't use the background capability.
|
||||||
|
|
||||||
Add the mapping from the element ID added in the first step to the function
|
Add the mapping from the element ID added in the first step to the function
|
||||||
created in the third step to the osdElementDrawFunction array.
|
created in the third step to the osdElementDrawFunction array.
|
||||||
|
|
||||||
|
Create the function to draw the element's static (background) portion.
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
If an element has static (unchanging) portions then create a function to draw only those
|
||||||
|
parts. It should be named like "osdBackgroundSomething()" where the "Something" matches
|
||||||
|
the related element function.
|
||||||
|
|
||||||
|
Add the mapping for the element ID to the background drawing function to the
|
||||||
|
osdElementBackgroundFunction array.
|
||||||
|
|
||||||
|
Accelerometer reqirement:
|
||||||
|
-------------------------
|
||||||
If the new element utilizes the accelerometer, add it to the osdElementsNeedAccelerometer() function.
|
If the new element utilizes the accelerometer, add it to the osdElementsNeedAccelerometer() function.
|
||||||
|
|
||||||
Finally add a CLI parameter for the new element in cli/settings.c.
|
Finally add a CLI parameter for the new element in cli/settings.c.
|
||||||
|
@ -152,6 +169,7 @@ static const char compassBar[] = {
|
||||||
|
|
||||||
static unsigned activeOsdElementCount = 0;
|
static unsigned activeOsdElementCount = 0;
|
||||||
static uint8_t activeOsdElementArray[OSD_ITEM_COUNT];
|
static uint8_t activeOsdElementArray[OSD_ITEM_COUNT];
|
||||||
|
static bool backgroundLayerSupported = false;
|
||||||
|
|
||||||
// Blink control
|
// Blink control
|
||||||
static bool blinkState = true;
|
static bool blinkState = true;
|
||||||
|
@ -578,7 +596,7 @@ static void osdElementCoreTemperature(osdElementParms_t *element)
|
||||||
}
|
}
|
||||||
#endif // USE_ADC_INTERNAL
|
#endif // USE_ADC_INTERNAL
|
||||||
|
|
||||||
static void osdElementCraftName(osdElementParms_t *element)
|
static void osdBackgroundCraftName(osdElementParms_t *element)
|
||||||
{
|
{
|
||||||
if (strlen(pilotConfig()->name) == 0) {
|
if (strlen(pilotConfig()->name) == 0) {
|
||||||
strcpy(element->buff, "CRAFT_NAME");
|
strcpy(element->buff, "CRAFT_NAME");
|
||||||
|
@ -639,7 +657,7 @@ static void osdElementCrashFlipArrow(osdElementParms_t *element)
|
||||||
}
|
}
|
||||||
#endif // USE_ACC
|
#endif // USE_ACC
|
||||||
|
|
||||||
static void osdElementCrosshairs(osdElementParms_t *element)
|
static void osdBackgroundCrosshairs(osdElementParms_t *element)
|
||||||
{
|
{
|
||||||
element->buff[0] = SYM_AH_CENTER_LINE;
|
element->buff[0] = SYM_AH_CENTER_LINE;
|
||||||
element->buff[1] = SYM_AH_CENTER;
|
element->buff[1] = SYM_AH_CENTER;
|
||||||
|
@ -665,7 +683,7 @@ static void osdElementDisarmed(osdElementParms_t *element)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void osdElementDisplayName(osdElementParms_t *element)
|
static void osdBackgroundDisplayName(osdElementParms_t *element)
|
||||||
{
|
{
|
||||||
if (strlen(pilotConfig()->displayName) == 0) {
|
if (strlen(pilotConfig()->displayName) == 0) {
|
||||||
strcpy(element->buff, "DISPLAY_NAME");
|
strcpy(element->buff, "DISPLAY_NAME");
|
||||||
|
@ -862,7 +880,7 @@ static void osdElementGpsSpeed(osdElementParms_t *element)
|
||||||
}
|
}
|
||||||
#endif // USE_GPS
|
#endif // USE_GPS
|
||||||
|
|
||||||
static void osdElementHorizonSidebars(osdElementParms_t *element)
|
static void osdBackgroundHorizonSidebars(osdElementParms_t *element)
|
||||||
{
|
{
|
||||||
// Draw AH sides
|
// Draw AH sides
|
||||||
const int8_t hudwidth = AH_SIDEBAR_WIDTH_POS;
|
const int8_t hudwidth = AH_SIDEBAR_WIDTH_POS;
|
||||||
|
@ -1078,7 +1096,7 @@ static void osdElementRssiDbm(osdElementParms_t *element)
|
||||||
#endif // USE_RX_RSSI_DBM
|
#endif // USE_RX_RSSI_DBM
|
||||||
|
|
||||||
#ifdef USE_OSD_STICK_OVERLAY
|
#ifdef USE_OSD_STICK_OVERLAY
|
||||||
static void osdElementStickOverlay(osdElementParms_t *element)
|
static void osdBackgroundStickOverlay(osdElementParms_t *element)
|
||||||
{
|
{
|
||||||
const uint8_t xpos = element->elemPosX;
|
const uint8_t xpos = element->elemPosX;
|
||||||
const uint8_t ypos = element->elemPosY;
|
const uint8_t ypos = element->elemPosY;
|
||||||
|
@ -1097,6 +1115,14 @@ static void osdElementStickOverlay(osdElementParms_t *element)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
element->drawElement = false; // element already drawn
|
||||||
|
}
|
||||||
|
|
||||||
|
static void osdElementStickOverlay(osdElementParms_t *element)
|
||||||
|
{
|
||||||
|
const uint8_t xpos = element->elemPosX;
|
||||||
|
const uint8_t ypos = element->elemPosY;
|
||||||
|
|
||||||
// Now draw the cursor
|
// Now draw the cursor
|
||||||
rc_alias_e vertical_channel, horizontal_channel;
|
rc_alias_e vertical_channel, horizontal_channel;
|
||||||
|
|
||||||
|
@ -1410,7 +1436,7 @@ static void osdElementWarnings(osdElementParms_t *element)
|
||||||
// Elements positioned later in the list will overlay the earlier
|
// Elements positioned later in the list will overlay the earlier
|
||||||
// ones if their character positions overlap
|
// ones if their character positions overlap
|
||||||
// Elements that need special runtime conditional processing should be added
|
// Elements that need special runtime conditional processing should be added
|
||||||
// to osdAnalyzeActiveElements()
|
// to osdAddActiveElements()
|
||||||
|
|
||||||
static const uint8_t osdElementDisplayOrder[] = {
|
static const uint8_t osdElementDisplayOrder[] = {
|
||||||
OSD_MAIN_BATT_VOLTAGE,
|
OSD_MAIN_BATT_VOLTAGE,
|
||||||
|
@ -1487,15 +1513,15 @@ static const uint8_t osdElementDisplayOrder[] = {
|
||||||
const osdElementDrawFn osdElementDrawFunction[OSD_ITEM_COUNT] = {
|
const osdElementDrawFn osdElementDrawFunction[OSD_ITEM_COUNT] = {
|
||||||
[OSD_RSSI_VALUE] = osdElementRssi,
|
[OSD_RSSI_VALUE] = osdElementRssi,
|
||||||
[OSD_MAIN_BATT_VOLTAGE] = osdElementMainBatteryVoltage,
|
[OSD_MAIN_BATT_VOLTAGE] = osdElementMainBatteryVoltage,
|
||||||
[OSD_CROSSHAIRS] = osdElementCrosshairs,
|
[OSD_CROSSHAIRS] = NULL, // only has background
|
||||||
#ifdef USE_ACC
|
#ifdef USE_ACC
|
||||||
[OSD_ARTIFICIAL_HORIZON] = osdElementArtificialHorizon,
|
[OSD_ARTIFICIAL_HORIZON] = osdElementArtificialHorizon,
|
||||||
#endif
|
#endif
|
||||||
[OSD_HORIZON_SIDEBARS] = osdElementHorizonSidebars,
|
[OSD_HORIZON_SIDEBARS] = NULL, // only has background
|
||||||
[OSD_ITEM_TIMER_1] = osdElementTimer,
|
[OSD_ITEM_TIMER_1] = osdElementTimer,
|
||||||
[OSD_ITEM_TIMER_2] = osdElementTimer,
|
[OSD_ITEM_TIMER_2] = osdElementTimer,
|
||||||
[OSD_FLYMODE] = osdElementFlymode,
|
[OSD_FLYMODE] = osdElementFlymode,
|
||||||
[OSD_CRAFT_NAME] = osdElementCraftName,
|
[OSD_CRAFT_NAME] = NULL, // only has background
|
||||||
[OSD_THROTTLE_POS] = osdElementThrottlePosition,
|
[OSD_THROTTLE_POS] = osdElementThrottlePosition,
|
||||||
#ifdef USE_VTX_COMMON
|
#ifdef USE_VTX_COMMON
|
||||||
[OSD_VTX_CHANNEL] = osdElementVtxChannel,
|
[OSD_VTX_CHANNEL] = osdElementVtxChannel,
|
||||||
|
@ -1571,7 +1597,7 @@ const osdElementDrawFn osdElementDrawFunction[OSD_ITEM_COUNT] = {
|
||||||
[OSD_STICK_OVERLAY_LEFT] = osdElementStickOverlay,
|
[OSD_STICK_OVERLAY_LEFT] = osdElementStickOverlay,
|
||||||
[OSD_STICK_OVERLAY_RIGHT] = osdElementStickOverlay,
|
[OSD_STICK_OVERLAY_RIGHT] = osdElementStickOverlay,
|
||||||
#endif
|
#endif
|
||||||
[OSD_DISPLAY_NAME] = osdElementDisplayName,
|
[OSD_DISPLAY_NAME] = NULL, // only has background
|
||||||
#if defined(USE_DSHOT_TELEMETRY) || defined(USE_ESC_SENSOR)
|
#if defined(USE_DSHOT_TELEMETRY) || defined(USE_ESC_SENSOR)
|
||||||
[OSD_ESC_RPM_FREQ] = osdElementEscRpmFreq,
|
[OSD_ESC_RPM_FREQ] = osdElementEscRpmFreq,
|
||||||
#endif
|
#endif
|
||||||
|
@ -1588,6 +1614,20 @@ const osdElementDrawFn osdElementDrawFunction[OSD_ITEM_COUNT] = {
|
||||||
[OSD_RC_CHANNELS] = osdElementRcChannels,
|
[OSD_RC_CHANNELS] = osdElementRcChannels,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Define the mapping between the OSD element id and the function to draw its background (static part)
|
||||||
|
// Only necessary to define the entries that actually have a background function
|
||||||
|
|
||||||
|
const osdElementDrawFn osdElementBackgroundFunction[OSD_ITEM_COUNT] = {
|
||||||
|
[OSD_CROSSHAIRS] = osdBackgroundCrosshairs,
|
||||||
|
[OSD_HORIZON_SIDEBARS] = osdBackgroundHorizonSidebars,
|
||||||
|
[OSD_CRAFT_NAME] = osdBackgroundCraftName,
|
||||||
|
#ifdef USE_OSD_STICK_OVERLAY
|
||||||
|
[OSD_STICK_OVERLAY_LEFT] = osdBackgroundStickOverlay,
|
||||||
|
[OSD_STICK_OVERLAY_RIGHT] = osdBackgroundStickOverlay,
|
||||||
|
#endif
|
||||||
|
[OSD_DISPLAY_NAME] = osdBackgroundDisplayName,
|
||||||
|
};
|
||||||
|
|
||||||
static void osdAddActiveElement(osd_items_e element)
|
static void osdAddActiveElement(osd_items_e element)
|
||||||
{
|
{
|
||||||
if (VISIBLE(osdConfig()->item_pos[element])) {
|
if (VISIBLE(osdConfig()->item_pos[element])) {
|
||||||
|
@ -1598,7 +1638,7 @@ static void osdAddActiveElement(osd_items_e element)
|
||||||
// Examine the elements and build a list of only the active (enabled)
|
// Examine the elements and build a list of only the active (enabled)
|
||||||
// ones to speed up rendering.
|
// ones to speed up rendering.
|
||||||
|
|
||||||
void osdAnalyzeActiveElements(void)
|
void osdAddActiveElements(void)
|
||||||
{
|
{
|
||||||
activeOsdElementCount = 0;
|
activeOsdElementCount = 0;
|
||||||
|
|
||||||
|
@ -1638,10 +1678,14 @@ void osdAnalyzeActiveElements(void)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool osdDrawSingleElement(displayPort_t *osdDisplayPort, uint8_t item)
|
static void osdDrawSingleElement(displayPort_t *osdDisplayPort, uint8_t item)
|
||||||
{
|
{
|
||||||
|
if (!osdElementDrawFunction[item]) {
|
||||||
|
// Element has no drawing function
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (BLINK(item)) {
|
if (BLINK(item)) {
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t elemPosX = OSD_X(osdConfig()->item_pos[item]);
|
uint8_t elemPosX = OSD_X(osdConfig()->item_pos[item]);
|
||||||
|
@ -1661,8 +1705,32 @@ static bool osdDrawSingleElement(displayPort_t *osdDisplayPort, uint8_t item)
|
||||||
if (element.drawElement) {
|
if (element.drawElement) {
|
||||||
displayWrite(osdDisplayPort, elemPosX, elemPosY, buff);
|
displayWrite(osdDisplayPort, elemPosX, elemPosY, buff);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
static void osdDrawSingleElementBackground(displayPort_t *osdDisplayPort, uint8_t item)
|
||||||
|
{
|
||||||
|
if (!osdElementBackgroundFunction[item]) {
|
||||||
|
// Element has no background drawing function
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t elemPosX = OSD_X(osdConfig()->item_pos[item]);
|
||||||
|
uint8_t elemPosY = OSD_Y(osdConfig()->item_pos[item]);
|
||||||
|
char buff[OSD_ELEMENT_BUFFER_LENGTH] = "";
|
||||||
|
|
||||||
|
osdElementParms_t element;
|
||||||
|
element.item = item;
|
||||||
|
element.elemPosX = elemPosX;
|
||||||
|
element.elemPosY = elemPosY;
|
||||||
|
element.buff = (char *)&buff;
|
||||||
|
element.osdDisplayPort = osdDisplayPort;
|
||||||
|
element.drawElement = true;
|
||||||
|
|
||||||
|
// Call the element background drawing function
|
||||||
|
osdElementBackgroundFunction[item](&element);
|
||||||
|
if (element.drawElement) {
|
||||||
|
displayWrite(osdDisplayPort, elemPosX, elemPosY, buff);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void osdDrawActiveElements(displayPort_t *osdDisplayPort, timeUs_t currentTimeUs)
|
void osdDrawActiveElements(displayPort_t *osdDisplayPort, timeUs_t currentTimeUs)
|
||||||
|
@ -1681,10 +1749,33 @@ void osdDrawActiveElements(displayPort_t *osdDisplayPort, timeUs_t currentTimeUs
|
||||||
blinkState = (currentTimeUs / 200000) % 2;
|
blinkState = (currentTimeUs / 200000) % 2;
|
||||||
|
|
||||||
for (unsigned i = 0; i < activeOsdElementCount; i++) {
|
for (unsigned i = 0; i < activeOsdElementCount; i++) {
|
||||||
|
if (!backgroundLayerSupported) {
|
||||||
|
// If the background layer isn't supported then we
|
||||||
|
// have to draw the element's static layer as well.
|
||||||
|
osdDrawSingleElementBackground(osdDisplayPort, activeOsdElementArray[i]);
|
||||||
|
}
|
||||||
osdDrawSingleElement(osdDisplayPort, activeOsdElementArray[i]);
|
osdDrawSingleElement(osdDisplayPort, activeOsdElementArray[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void osdDrawActiveElementsBackground(displayPort_t *osdDisplayPort)
|
||||||
|
{
|
||||||
|
if (backgroundLayerSupported) {
|
||||||
|
displayLayerSelect(osdDisplayPort, DISPLAYPORT_LAYER_BACKGROUND);
|
||||||
|
displayClearScreen(osdDisplayPort);
|
||||||
|
for (unsigned i = 0; i < activeOsdElementCount; i++) {
|
||||||
|
osdDrawSingleElementBackground(osdDisplayPort, activeOsdElementArray[i]);
|
||||||
|
}
|
||||||
|
displayLayerSelect(osdDisplayPort, DISPLAYPORT_LAYER_FOREGROUND);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void osdElementsInit(bool backgroundLayerFlag)
|
||||||
|
{
|
||||||
|
backgroundLayerSupported = backgroundLayerFlag;
|
||||||
|
activeOsdElementCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
void osdResetAlarms(void)
|
void osdResetAlarms(void)
|
||||||
{
|
{
|
||||||
memset(blinkBits, 0, sizeof(blinkBits));
|
memset(blinkBits, 0, sizeof(blinkBits));
|
||||||
|
|
|
@ -45,8 +45,10 @@ char osdGetMetersToSelectedUnitSymbol(void);
|
||||||
int32_t osdGetSpeedToSelectedUnit(int32_t value);
|
int32_t osdGetSpeedToSelectedUnit(int32_t value);
|
||||||
char osdGetSpeedToSelectedUnitSymbol(void);
|
char osdGetSpeedToSelectedUnitSymbol(void);
|
||||||
char osdGetTemperatureSymbolForSelectedUnit(void);
|
char osdGetTemperatureSymbolForSelectedUnit(void);
|
||||||
void osdAnalyzeActiveElements(void);
|
void osdAddActiveElements(void);
|
||||||
void osdDrawActiveElements(displayPort_t *osdDisplayPort, timeUs_t currentTimeUs);
|
void osdDrawActiveElements(displayPort_t *osdDisplayPort, timeUs_t currentTimeUs);
|
||||||
|
void osdDrawActiveElementsBackground(displayPort_t *osdDisplayPort);
|
||||||
|
void osdElementsInit(bool backgroundLayerFlag);
|
||||||
void osdResetAlarms(void);
|
void osdResetAlarms(void);
|
||||||
void osdUpdateAlarms(void);
|
void osdUpdateAlarms(void);
|
||||||
bool osdElementsNeedAccelerometer(void);
|
bool osdElementsNeedAccelerometer(void);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue