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 e… (#9129)
Add OSD background support for the static portions of display elements
This commit is contained in:
commit
8548189bc6
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