commit
76d9cc3e38
|
@ -26,6 +26,7 @@ COMMON_SRC = \
|
|||
drivers/bus_spi_pinconfig.c \
|
||||
drivers/buttons.c \
|
||||
drivers/display.c \
|
||||
drivers/display_canvas.c \
|
||||
drivers/dma_reqmap.c \
|
||||
drivers/exti.c \
|
||||
drivers/io.c \
|
||||
|
@ -152,12 +153,14 @@ COMMON_SRC = \
|
|||
drivers/vtx_common.c \
|
||||
drivers/vtx_table.c \
|
||||
io/dashboard.c \
|
||||
io/displayport_frsky_osd.c \
|
||||
io/displayport_max7456.c \
|
||||
io/displayport_msp.c \
|
||||
io/displayport_oled.c \
|
||||
io/displayport_srxl.c \
|
||||
io/displayport_crsf.c \
|
||||
io/displayport_hott.c \
|
||||
io/frsky_osd.c \
|
||||
io/rcdevice_cam.c \
|
||||
io/rcdevice.c \
|
||||
io/gps.c \
|
||||
|
|
|
@ -1253,8 +1253,8 @@ static void cliSerial(char *cmdline)
|
|||
|
||||
ptr = nextArg(ptr);
|
||||
if (ptr) {
|
||||
val = atoi(ptr);
|
||||
portConfig.functionMask = val & 0xFFFF;
|
||||
val = strtoul(ptr, NULL, 10);
|
||||
portConfig.functionMask = val;
|
||||
validArgumentCount++;
|
||||
}
|
||||
|
||||
|
|
|
@ -484,7 +484,7 @@ static const char* const lookupTableDshotBitbangedTimer[] = {
|
|||
};
|
||||
|
||||
static const char * const lookupTableOsdDisplayPortDevice[] = {
|
||||
"NONE", "AUTO", "MAX7456", "MSP",
|
||||
"NONE", "AUTO", "MAX7456", "MSP", "FRSKYOSD"
|
||||
};
|
||||
|
||||
#ifdef USE_OSD
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* This file is part of INAV.
|
||||
* This file is part of Cleanflight, Betaflight and INAV.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* This file is part of Cleanflight, Betaflight and INAV.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms
|
||||
* of the GNU General Public License Version 3, as described below:
|
||||
*
|
||||
* This file is free software: you may copy, redistribute and/or modify
|
||||
* it under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
* @author Alberto Garcia Hierro <alberto@garciahierro.com>
|
||||
*/
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
#include "common/uvarint.h"
|
||||
|
||||
int uvarintEncode(uint32_t val, uint8_t *ptr, size_t size)
|
||||
{
|
||||
unsigned ii = 0;
|
||||
while (val > 0x80) {
|
||||
if (ii >= size) {
|
||||
return -1;
|
||||
}
|
||||
ptr[ii] = (val & 0xFF) | 0x80;
|
||||
val >>= 7;
|
||||
ii++;
|
||||
}
|
||||
if (ii >= size) {
|
||||
return -1;
|
||||
}
|
||||
ptr[ii] = val & 0xFF;
|
||||
return ii + 1;
|
||||
}
|
||||
|
||||
int uvarintDecode(uint32_t *val, const uint8_t *ptr, size_t size)
|
||||
{
|
||||
unsigned s = 0;
|
||||
*val = 0;
|
||||
for (size_t ii = 0; ii < size; ii++) {
|
||||
uint8_t b = ptr[ii];
|
||||
if (b < 0x80) {
|
||||
if (ii > 5 || (ii == 5 && b > 1)) {
|
||||
// uint32_t overflow
|
||||
return -2;
|
||||
}
|
||||
*val |= ((uint32_t)b) << s;
|
||||
return ii + 1;
|
||||
}
|
||||
*val |= ((uint32_t)(b & 0x7f)) << s;
|
||||
s += 7;
|
||||
}
|
||||
// no value could be decoded and we have no data left
|
||||
return -1;
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* This file is part of Cleanflight, Betaflight and INAV.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms
|
||||
* of the GNU General Public License Version 3, as described below:
|
||||
*
|
||||
* This file is free software: you may copy, redistribute and/or modify
|
||||
* it under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
* @author Alberto Garcia Hierro <alberto@garciahierro.com>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
int uvarintEncode(uint32_t val, uint8_t *ptr, size_t size);
|
||||
int uvarintDecode(uint32_t *val, const uint8_t *ptr, size_t size);
|
|
@ -26,6 +26,9 @@
|
|||
|
||||
#include "common/utils.h"
|
||||
|
||||
#include "drivers/display_canvas.h"
|
||||
#include "drivers/osd.h"
|
||||
|
||||
#include "display.h"
|
||||
|
||||
void displayClearScreen(displayPort_t *instance)
|
||||
|
@ -142,6 +145,54 @@ bool displayLayerCopy(displayPort_t *instance, displayPortLayer_e destLayer, dis
|
|||
return false;
|
||||
}
|
||||
|
||||
bool displayWriteFontCharacter(displayPort_t *instance, uint16_t addr, const osdCharacter_t *chr)
|
||||
{
|
||||
if (instance->vTable->writeFontCharacter) {
|
||||
return instance->vTable->writeFontCharacter(instance, addr, chr);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool displayIsReady(displayPort_t *instance)
|
||||
{
|
||||
if (instance->vTable->isReady) {
|
||||
return instance->vTable->isReady(instance);
|
||||
}
|
||||
// Drivers that don't provide an isReady method are
|
||||
// assumed to be immediately ready (either by actually
|
||||
// begin ready very quickly or by blocking)
|
||||
return true;
|
||||
}
|
||||
|
||||
void displayBeginTransaction(displayPort_t *instance, displayTransactionOption_e opts)
|
||||
{
|
||||
if (instance->vTable->beginTransaction) {
|
||||
instance->vTable->beginTransaction(instance, opts);
|
||||
}
|
||||
}
|
||||
|
||||
void displayCommitTransaction(displayPort_t *instance)
|
||||
{
|
||||
if (instance->vTable->commitTransaction) {
|
||||
instance->vTable->commitTransaction(instance);
|
||||
}
|
||||
}
|
||||
|
||||
bool displayGetCanvas(displayCanvas_t *canvas, const displayPort_t *instance)
|
||||
{
|
||||
#if defined(USE_CANVAS)
|
||||
if (canvas && instance->vTable->getCanvas && instance->vTable->getCanvas(canvas, instance)) {
|
||||
canvas->gridElementWidth = canvas->width / instance->cols;
|
||||
canvas->gridElementHeight = canvas->height / instance->rows;
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
UNUSED(canvas);
|
||||
UNUSED(instance);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
void displayInit(displayPort_t *instance, const displayPortVTable_t *vTable)
|
||||
{
|
||||
instance->vTable = vTable;
|
||||
|
|
|
@ -35,6 +35,15 @@ typedef enum {
|
|||
DISPLAYPORT_LAYER_COUNT,
|
||||
} displayPortLayer_e;
|
||||
|
||||
typedef enum {
|
||||
DISPLAY_TRANSACTION_OPT_NONE = 0,
|
||||
DISPLAY_TRANSACTION_OPT_PROFILED = 1 << 0,
|
||||
DISPLAY_TRANSACTION_OPT_RESET_DRAWING = 1 << 1,
|
||||
} displayTransactionOption_e;
|
||||
|
||||
|
||||
struct displayCanvas_s;
|
||||
struct osdCharacter_s;
|
||||
struct displayPortVTable_s;
|
||||
|
||||
typedef struct displayPort_s {
|
||||
|
@ -68,6 +77,11 @@ typedef struct displayPortVTable_s {
|
|||
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);
|
||||
bool (*writeFontCharacter)(displayPort_t *instance, uint16_t addr, const struct osdCharacter_s *chr);
|
||||
bool (*isReady)(displayPort_t *displayPort);
|
||||
void (*beginTransaction)(displayPort_t *displayPort, displayTransactionOption_e opts);
|
||||
void (*commitTransaction)(displayPort_t *displayPort);
|
||||
bool (*getCanvas)(struct displayCanvas_s *canvas, const displayPort_t *displayPort);
|
||||
} displayPortVTable_t;
|
||||
|
||||
void displayGrab(displayPort_t *instance);
|
||||
|
@ -85,6 +99,11 @@ void displayHeartbeat(displayPort_t *instance);
|
|||
void displayResync(displayPort_t *instance);
|
||||
bool displayIsSynced(const displayPort_t *instance);
|
||||
uint16_t displayTxBytesFree(const displayPort_t *instance);
|
||||
bool displayWriteFontCharacter(displayPort_t *instance, uint16_t addr, const struct osdCharacter_s *chr);
|
||||
bool displayIsReady(displayPort_t *instance);
|
||||
void displayBeginTransaction(displayPort_t *instance, displayTransactionOption_e opts);
|
||||
void displayCommitTransaction(displayPort_t *instance);
|
||||
bool displayGetCanvas(struct displayCanvas_s *canvas, const displayPort_t *instance);
|
||||
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);
|
||||
|
|
|
@ -0,0 +1,277 @@
|
|||
/*
|
||||
* This file is part of Cleanflight, Betaflight and INAV.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms
|
||||
* of the GNU General Public License Version 3, as described below:
|
||||
*
|
||||
* This file is free software: you may copy, redistribute and/or modify
|
||||
* it under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
* @author Alberto Garcia Hierro <alberto@garciahierro.com>
|
||||
*/
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
#include "drivers/display_canvas.h"
|
||||
|
||||
void displayCanvasSetStrokeColor(displayCanvas_t *displayCanvas, displayCanvasColor_e color)
|
||||
{
|
||||
if (displayCanvas->vTable->setStrokeColor) {
|
||||
displayCanvas->vTable->setStrokeColor(displayCanvas, color);
|
||||
}
|
||||
}
|
||||
|
||||
void displayCanvasSetFillColor(displayCanvas_t *displayCanvas, displayCanvasColor_e color)
|
||||
{
|
||||
if (displayCanvas->vTable->setFillColor) {
|
||||
displayCanvas->vTable->setFillColor(displayCanvas, color);
|
||||
}
|
||||
}
|
||||
|
||||
void displayCanvasSetStrokeAndFillColor(displayCanvas_t *displayCanvas, displayCanvasColor_e color)
|
||||
{
|
||||
if (displayCanvas->vTable->setStrokeAndFillColor) {
|
||||
displayCanvas->vTable->setStrokeAndFillColor(displayCanvas, color);
|
||||
} else {
|
||||
displayCanvasSetStrokeColor(displayCanvas, color);
|
||||
displayCanvasSetFillColor(displayCanvas, color);
|
||||
}
|
||||
}
|
||||
|
||||
void displayCanvasSetColorInversion(displayCanvas_t *displayCanvas, bool inverted)
|
||||
{
|
||||
if (displayCanvas->vTable->setColorInversion) {
|
||||
displayCanvas->vTable->setColorInversion(displayCanvas, inverted);
|
||||
}
|
||||
}
|
||||
|
||||
void displayCanvasSetPixel(displayCanvas_t *displayCanvas, int x, int y, displayCanvasColor_e color)
|
||||
{
|
||||
if (displayCanvas->vTable->setPixel) {
|
||||
displayCanvas->vTable->setPixel(displayCanvas, x, y, color);
|
||||
}
|
||||
}
|
||||
|
||||
void displayCanvasSetPixelToStrokeColor(displayCanvas_t *displayCanvas, int x, int y)
|
||||
{
|
||||
if (displayCanvas->vTable->setPixelToStrokeColor) {
|
||||
displayCanvas->vTable->setPixelToStrokeColor(displayCanvas, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
void displayCanvasSetPixelToFillColor(displayCanvas_t *displayCanvas, int x, int y)
|
||||
{
|
||||
if (displayCanvas->vTable->setPixelToFillColor) {
|
||||
displayCanvas->vTable->setPixelToFillColor(displayCanvas, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
void displayCanvasSetStrokeWidth(displayCanvas_t *displayCanvas, unsigned w)
|
||||
{
|
||||
if (displayCanvas->vTable->setStrokeWidth) {
|
||||
displayCanvas->vTable->setStrokeWidth(displayCanvas, w);
|
||||
}
|
||||
}
|
||||
|
||||
void displayCanvasSetLineOutlineType(displayCanvas_t *displayCanvas, displayCanvasOutlineType_e outlineType)
|
||||
{
|
||||
if (displayCanvas->vTable->setLineOutlineType) {
|
||||
displayCanvas->vTable->setLineOutlineType(displayCanvas, outlineType);
|
||||
}
|
||||
}
|
||||
|
||||
void displayCanvasSetLineOutlineColor(displayCanvas_t *displayCanvas, displayCanvasColor_e outlineColor)
|
||||
{
|
||||
if (displayCanvas->vTable->setLineOutlineColor) {
|
||||
displayCanvas->vTable->setLineOutlineColor(displayCanvas, outlineColor);
|
||||
}
|
||||
}
|
||||
|
||||
void displayCanvasClipToRect(displayCanvas_t *displayCanvas, int x, int y, int w, int h)
|
||||
{
|
||||
if (displayCanvas->vTable->clipToRect) {
|
||||
displayCanvas->vTable->clipToRect(displayCanvas, x, y, w, h);
|
||||
}
|
||||
}
|
||||
|
||||
void displayCanvasClearRect(displayCanvas_t *displayCanvas, int x, int y, int w, int h)
|
||||
{
|
||||
if (displayCanvas->vTable->clearRect) {
|
||||
displayCanvas->vTable->clearRect(displayCanvas, x, y, w, h);
|
||||
}
|
||||
}
|
||||
|
||||
void displayCanvasResetDrawingState(displayCanvas_t *displayCanvas)
|
||||
{
|
||||
if (displayCanvas->vTable->resetDrawingState) {
|
||||
displayCanvas->vTable->resetDrawingState(displayCanvas);
|
||||
}
|
||||
}
|
||||
|
||||
void displayCanvasDrawCharacter(displayCanvas_t *displayCanvas, int x, int y, uint16_t chr, displayCanvasBitmapOption_t opts)
|
||||
{
|
||||
if (displayCanvas->vTable->drawCharacter) {
|
||||
displayCanvas->vTable->drawCharacter(displayCanvas, x, y, chr, opts);
|
||||
}
|
||||
}
|
||||
|
||||
void displayCanvasDrawCharacterMask(displayCanvas_t *displayCanvas, int x, int y, uint16_t chr, displayCanvasColor_e color, displayCanvasBitmapOption_t opts)
|
||||
{
|
||||
if (displayCanvas->vTable->drawCharacterMask) {
|
||||
displayCanvas->vTable->drawCharacterMask(displayCanvas, x, y, chr, color, opts);
|
||||
}
|
||||
}
|
||||
|
||||
void displayCanvasDrawString(displayCanvas_t *displayCanvas, int x, int y, const char *s, displayCanvasBitmapOption_t opts)
|
||||
{
|
||||
if (displayCanvas->vTable->drawString) {
|
||||
displayCanvas->vTable->drawString(displayCanvas, x, y, s, opts);
|
||||
}
|
||||
}
|
||||
|
||||
void displayCanvasDrawStringMask(displayCanvas_t *displayCanvas, int x, int y, const char *s, displayCanvasColor_e color, displayCanvasBitmapOption_t opts)
|
||||
{
|
||||
if (displayCanvas->vTable->drawStringMask) {
|
||||
displayCanvas->vTable->drawStringMask(displayCanvas, x, y, s, color, opts);
|
||||
}
|
||||
}
|
||||
|
||||
void displayCanvasMoveToPoint(displayCanvas_t *displayCanvas, int x, int y)
|
||||
{
|
||||
if (displayCanvas->vTable->moveToPoint) {
|
||||
displayCanvas->vTable->moveToPoint(displayCanvas, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
void displayCanvasStrokeLineToPoint(displayCanvas_t *displayCanvas, int x, int y)
|
||||
{
|
||||
if (displayCanvas->vTable->strokeLineToPoint) {
|
||||
displayCanvas->vTable->strokeLineToPoint(displayCanvas, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
void displayCanvasStrokeTriangle(displayCanvas_t *displayCanvas, int x1, int y1, int x2, int y2, int x3, int y3)
|
||||
{
|
||||
if (displayCanvas->vTable->strokeTriangle) {
|
||||
displayCanvas->vTable->strokeTriangle(displayCanvas, x1, y1, x2, y2, x3, y3);
|
||||
}
|
||||
}
|
||||
|
||||
void displayCanvasFillTriangle(displayCanvas_t *displayCanvas, int x1, int y1, int x2, int y2, int x3, int y3)
|
||||
{
|
||||
if (displayCanvas->vTable->fillTriangle) {
|
||||
displayCanvas->vTable->fillTriangle(displayCanvas, x1, y1, x2, y2, x3, y3);
|
||||
}
|
||||
}
|
||||
|
||||
void displayCanvasFillStrokeTriangle(displayCanvas_t *displayCanvas, int x1, int y1, int x2, int y2, int x3, int y3)
|
||||
{
|
||||
if (displayCanvas->vTable->fillStrokeTriangle) {
|
||||
displayCanvas->vTable->fillStrokeTriangle(displayCanvas, x1, y1, x2, y2, x3, y3);
|
||||
}
|
||||
}
|
||||
|
||||
void displayCanvasStrokeRect(displayCanvas_t *displayCanvas, int x, int y, int w, int h)
|
||||
{
|
||||
if (displayCanvas->vTable->strokeRect) {
|
||||
displayCanvas->vTable->strokeRect(displayCanvas, x, y, w, h);
|
||||
}
|
||||
}
|
||||
|
||||
void displayCanvasFillRect(displayCanvas_t *displayCanvas, int x, int y, int w, int h)
|
||||
{
|
||||
if (displayCanvas->vTable->fillRect) {
|
||||
displayCanvas->vTable->fillRect(displayCanvas, x, y, w, h);
|
||||
}
|
||||
}
|
||||
|
||||
void displayCanvasFillStrokeRect(displayCanvas_t *displayCanvas, int x, int y, int w, int h)
|
||||
{
|
||||
if (displayCanvas->vTable->fillStrokeRect) {
|
||||
displayCanvas->vTable->fillStrokeRect(displayCanvas, x, y, w, h);
|
||||
}
|
||||
}
|
||||
|
||||
void displayCanvasStrokeEllipseInRect(displayCanvas_t *displayCanvas, int x, int y, int w, int h)
|
||||
{
|
||||
if (displayCanvas->vTable->strokeEllipseInRect) {
|
||||
displayCanvas->vTable->strokeEllipseInRect(displayCanvas, x, y, w, h);
|
||||
}
|
||||
}
|
||||
|
||||
void displayCanvasFillEllipseInRect(displayCanvas_t *displayCanvas, int x, int y, int w, int h)
|
||||
{
|
||||
if (displayCanvas->vTable->fillEllipseInRect) {
|
||||
displayCanvas->vTable->fillEllipseInRect(displayCanvas, x, y, w, h);
|
||||
}
|
||||
}
|
||||
|
||||
void displayCanvasFillStrokeEllipseInRect(displayCanvas_t *displayCanvas, int x, int y, int w, int h)
|
||||
{
|
||||
if (displayCanvas->vTable->fillStrokeEllipseInRect) {
|
||||
displayCanvas->vTable->fillStrokeEllipseInRect(displayCanvas, x, y, w, h);
|
||||
}
|
||||
}
|
||||
|
||||
void displayCanvasCtmReset(displayCanvas_t *displayCanvas)
|
||||
{
|
||||
if (displayCanvas->vTable->ctmReset) {
|
||||
displayCanvas->vTable->ctmReset(displayCanvas);
|
||||
}
|
||||
}
|
||||
|
||||
void displayCanvasCtmSet(displayCanvas_t *displayCanvas, float m11, float m12, float m21, float m22, float m31, float m32)
|
||||
{
|
||||
if (displayCanvas->vTable->ctmSet) {
|
||||
displayCanvas->vTable->ctmSet(displayCanvas, m11, m12, m21, m22, m31, m32);
|
||||
}
|
||||
}
|
||||
|
||||
void displayCanvasCtmTranslate(displayCanvas_t *displayCanvas, float tx, float ty)
|
||||
{
|
||||
if (displayCanvas->vTable->ctmTranslate) {
|
||||
displayCanvas->vTable->ctmTranslate(displayCanvas, tx, ty);
|
||||
}
|
||||
}
|
||||
|
||||
void displayCanvasCtmScale(displayCanvas_t *displayCanvas, float sx, float sy)
|
||||
{
|
||||
if (displayCanvas->vTable->ctmScale) {
|
||||
displayCanvas->vTable->ctmScale(displayCanvas, sx, sy);
|
||||
}
|
||||
}
|
||||
|
||||
void displayCanvasCtmRotate(displayCanvas_t *displayCanvas, float r)
|
||||
{
|
||||
if (displayCanvas->vTable->ctmRotate) {
|
||||
displayCanvas->vTable->ctmRotate(displayCanvas, r);
|
||||
}
|
||||
}
|
||||
|
||||
void displayCanvasContextPush(displayCanvas_t *displayCanvas)
|
||||
{
|
||||
if (displayCanvas->vTable->contextPush) {
|
||||
displayCanvas->vTable->contextPush(displayCanvas);
|
||||
}
|
||||
}
|
||||
|
||||
void displayCanvasContextPop(displayCanvas_t *displayCanvas)
|
||||
{
|
||||
if (displayCanvas->vTable->contextPop) {
|
||||
displayCanvas->vTable->contextPop(displayCanvas);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,143 @@
|
|||
/*
|
||||
* This file is part of Cleanflight, Betaflight and INAV.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms
|
||||
* of the GNU General Public License Version 3, as described below:
|
||||
*
|
||||
* This file is free software: you may copy, redistribute and/or modify
|
||||
* it under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
* @author Alberto Garcia Hierro <alberto@garciahierro.com>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef enum {
|
||||
DISPLAY_CANVAS_BITMAP_OPT_INVERT_COLORS = 1 << 0,
|
||||
DISPLAY_CANVAS_BITMAP_OPT_SOLID_BACKGROUND = 1 << 1,
|
||||
DISPLAY_CANVAS_BITMAP_OPT_ERASE_TRANSPARENT = 1 << 2,
|
||||
} displayCanvasBitmapOption_t;
|
||||
|
||||
typedef enum {
|
||||
DISPLAY_CANVAS_COLOR_BLACK = 0,
|
||||
DISPLAY_CANVAS_COLOR_TRANSPARENT = 1,
|
||||
DISPLAY_CANVAS_COLOR_WHITE = 2,
|
||||
DISPLAY_CANVAS_COLOR_GRAY = 3,
|
||||
} displayCanvasColor_e;
|
||||
|
||||
typedef enum {
|
||||
DISPLAY_CANVAS_OUTLINE_TYPE_NONE = 0,
|
||||
DISPLAY_CANVAS_OUTLINE_TYPE_TOP = 1 << 0,
|
||||
DISPLAY_CANVAS_OUTLINE_TYPE_RIGHT = 1 << 1,
|
||||
DISPLAY_CANVAS_OUTLINE_TYPE_BOTTOM = 1 << 2,
|
||||
DISPLAY_CANVAS_OUTLINE_TYPE_LEFT = 1 << 3,
|
||||
} displayCanvasOutlineType_e;
|
||||
|
||||
struct displayCanvasVTable_s;
|
||||
|
||||
typedef struct displayCanvas_s {
|
||||
const struct displayCanvasVTable_s *vTable;
|
||||
void *device;
|
||||
uint16_t width;
|
||||
uint16_t height;
|
||||
uint8_t gridElementWidth;
|
||||
uint8_t gridElementHeight;
|
||||
} displayCanvas_t;
|
||||
|
||||
typedef struct displayCanvasVTable_s {
|
||||
void (*setStrokeColor)(displayCanvas_t *displayCanvas, displayCanvasColor_e color);
|
||||
void (*setFillColor)(displayCanvas_t *displayCanvas, displayCanvasColor_e color);
|
||||
void (*setStrokeAndFillColor)(displayCanvas_t *displayCanvas, displayCanvasColor_e color);
|
||||
void (*setColorInversion)(displayCanvas_t *displayCanvas, bool inverted);
|
||||
void (*setPixel)(displayCanvas_t *displayCanvas, int x, int y, displayCanvasColor_e color);
|
||||
void (*setPixelToStrokeColor)(displayCanvas_t *displayCanvas, int x, int y);
|
||||
void (*setPixelToFillColor)(displayCanvas_t *displayCanvas, int x, int y);
|
||||
void (*setStrokeWidth)(displayCanvas_t *displayCanvas, unsigned w);
|
||||
void (*setLineOutlineType)(displayCanvas_t *displayCanvas, displayCanvasOutlineType_e outlineType);
|
||||
void (*setLineOutlineColor)(displayCanvas_t *displayCanvas, displayCanvasColor_e outlineColor);
|
||||
|
||||
void (*clipToRect)(displayCanvas_t *displayCanvas, int x, int y, int w, int h);
|
||||
void (*clearRect)(displayCanvas_t *displayCanvas, int x, int y, int w, int h);
|
||||
void (*resetDrawingState)(displayCanvas_t *displayCanvas);
|
||||
void (*drawCharacter)(displayCanvas_t *displayCanvas, int x, int y, uint16_t chr, displayCanvasBitmapOption_t opts);
|
||||
void (*drawCharacterMask)(displayCanvas_t *displayCanvas, int x, int y, uint16_t chr, displayCanvasColor_e color, displayCanvasBitmapOption_t opts);
|
||||
void (*drawString)(displayCanvas_t *displayCanvas, int x, int y, const char *s, displayCanvasBitmapOption_t opts);
|
||||
void (*drawStringMask)(displayCanvas_t *displayCanvas, int x, int y, const char *s, displayCanvasColor_e color, displayCanvasBitmapOption_t opts);
|
||||
void (*moveToPoint)(displayCanvas_t *displayCanvas, int x, int y);
|
||||
void (*strokeLineToPoint)(displayCanvas_t *displayCanvas, int x, int y);
|
||||
void (*strokeTriangle)(displayCanvas_t *displayCanvas, int x1, int y1, int x2, int y2, int x3, int y3);
|
||||
void (*fillTriangle)(displayCanvas_t *displayCanvas, int x1, int y1, int x2, int y2, int x3, int y3);
|
||||
void (*fillStrokeTriangle)(displayCanvas_t *displayCanvas, int x1, int y1, int x2, int y2, int x3, int y3);
|
||||
void (*strokeRect)(displayCanvas_t *displayCanvas, int x, int y, int w, int h);
|
||||
void (*fillRect)(displayCanvas_t *displayCanvas, int x, int y, int w, int h);
|
||||
void (*fillStrokeRect)(displayCanvas_t *displayCanvas, int x, int y, int w, int h);
|
||||
void (*strokeEllipseInRect)(displayCanvas_t *displayCanvas, int x, int y, int w, int h);
|
||||
void (*fillEllipseInRect)(displayCanvas_t *displayCanvas, int x, int y, int w, int h);
|
||||
void (*fillStrokeEllipseInRect)(displayCanvas_t *displayCanvas, int x, int y, int w, int h);
|
||||
|
||||
void (*ctmReset)(displayCanvas_t *displayCanvas);
|
||||
void (*ctmSet)(displayCanvas_t *displayCanvas, float m11, float m12, float m21, float m22, float m31, float m32);
|
||||
void (*ctmTranslate)(displayCanvas_t *displayCanvas, float tx, float ty);
|
||||
void (*ctmScale)(displayCanvas_t *displayCanvas, float sx, float sy);
|
||||
void (*ctmRotate)(displayCanvas_t *displayCanvas, float r);
|
||||
|
||||
void (*contextPush)(displayCanvas_t *displayCanvas);
|
||||
void (*contextPop)(displayCanvas_t *displayCanvas);
|
||||
} displayCanvasVTable_t;
|
||||
|
||||
|
||||
void displayCanvasSetStrokeColor(displayCanvas_t *displayCanvas, displayCanvasColor_e color);
|
||||
void displayCanvasSetFillColor(displayCanvas_t *displayCanvas, displayCanvasColor_e color);
|
||||
void displayCanvasSetStrokeAndFillColor(displayCanvas_t *displayCanvas, displayCanvasColor_e color);
|
||||
void displayCanvasSetColorInversion(displayCanvas_t *displayCanvas, bool inverted);
|
||||
void displayCanvasSetPixel(displayCanvas_t *displayCanvas, int x, int y, displayCanvasColor_e);
|
||||
void displayCanvasSetPixelToStrokeColor(displayCanvas_t *displayCanvas, int x, int y);
|
||||
void displayCanvasSetPixelToFillColor(displayCanvas_t *displayCanvas, int x, int y);
|
||||
void displayCanvasSetStrokeWidth(displayCanvas_t *displayCanvas, unsigned w);
|
||||
void displayCanvasSetLineOutlineType(displayCanvas_t *displayCanvas, displayCanvasOutlineType_e outlineType);
|
||||
void displayCanvasSetLineOutlineColor(displayCanvas_t *displayCanvas, displayCanvasColor_e outlineColor);
|
||||
|
||||
void displayCanvasClipToRect(displayCanvas_t *displayCanvas, int x, int y, int w, int h);
|
||||
void displayCanvasClearRect(displayCanvas_t *displayCanvas, int x, int y, int w, int h);
|
||||
void displayCanvasResetDrawingState(displayCanvas_t *displayCanvas);
|
||||
void displayCanvasDrawCharacter(displayCanvas_t *displayCanvas, int x, int y, uint16_t chr, displayCanvasBitmapOption_t opts);
|
||||
void displayCanvasDrawCharacterMask(displayCanvas_t *displayCanvas, int x, int y, uint16_t chr, displayCanvasColor_e color, displayCanvasBitmapOption_t opts);
|
||||
void displayCanvasDrawString(displayCanvas_t *displayCanvas, int x, int y, const char *s, displayCanvasBitmapOption_t opts);
|
||||
void displayCanvasDrawStringMask(displayCanvas_t *displayCanvas, int x, int y, const char *s, displayCanvasColor_e color, displayCanvasBitmapOption_t opts);
|
||||
void displayCanvasMoveToPoint(displayCanvas_t *displayCanvas, int x, int y);
|
||||
void displayCanvasStrokeLineToPoint(displayCanvas_t *displayCanvas, int x, int y);
|
||||
void displayCanvasStrokeTriangle(displayCanvas_t *displayCanvas, int x1, int y1, int x2, int y2, int x3, int y3);
|
||||
void displayCanvasFillTriangle(displayCanvas_t *displayCanvas, int x1, int y1, int x2, int y2, int x3, int y3);
|
||||
void displayCanvasFillStrokeTriangle(displayCanvas_t *displayCanvas, int x1, int y1, int x2, int y2, int x3, int y3);
|
||||
void displayCanvasStrokeRect(displayCanvas_t *displayCanvas, int x, int y, int w, int h);
|
||||
void displayCanvasFillRect(displayCanvas_t *displayCanvas, int x, int y, int w, int h);
|
||||
void displayCanvasFillStrokeRect(displayCanvas_t *displayCanvas, int x, int y, int w, int h);
|
||||
void displayCanvasStrokeEllipseInRect(displayCanvas_t *displayCanvas, int x, int y, int w, int h);
|
||||
void displayCanvasFillEllipseInRect(displayCanvas_t *displayCanvas, int x, int y, int w, int h);
|
||||
void displayCanvasFillStrokeEllipseInRect(displayCanvas_t *displayCanvas, int x, int y, int w, int h);
|
||||
|
||||
void displayCanvasCtmReset(displayCanvas_t *displayCanvas);
|
||||
void displayCanvasCtmSet(displayCanvas_t *displayCanvas, float m11, float m12, float m21, float m22, float m31, float m32);
|
||||
void displayCanvasCtmTranslate(displayCanvas_t *displayCanvas, float tx, float ty);
|
||||
void displayCanvasCtmScale(displayCanvas_t *displayCanvas, float sx, float sy);
|
||||
void displayCanvasCtmRotate(displayCanvas_t *displayCanvas, float r);
|
||||
|
||||
void displayCanvasContextPush(displayCanvas_t *displayCanvas);
|
||||
void displayCanvasContextPop(displayCanvas_t *displayCanvas);
|
|
@ -36,8 +36,9 @@
|
|||
#include "drivers/io.h"
|
||||
#include "drivers/light_led.h"
|
||||
#include "drivers/max7456.h"
|
||||
#include "drivers/max7456_symbols.h"
|
||||
#include "drivers/nvic.h"
|
||||
#include "drivers/osd.h"
|
||||
#include "drivers/osd_symbols.h"
|
||||
#include "drivers/time.h"
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* This file is part of Cleanflight, Betaflight and INAV
|
||||
*
|
||||
* Cleanflight, Betaflight and INAV are free software. You can
|
||||
* redistribute this software and/or modify this software under
|
||||
* the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* Cleanflight, Betaflight and INAV are distributed in the hope that
|
||||
* they will be useful, but WITHOUT ANY WARRANTY; without even the
|
||||
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software.
|
||||
*
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "common/utils.h"
|
||||
|
||||
#define OSD_CHAR_WIDTH 12
|
||||
#define OSD_CHAR_HEIGHT 18
|
||||
#define OSD_CHAR_BITS_PER_PIXEL 2
|
||||
#define OSD_CHAR_VISIBLE_BYTES (OSD_CHAR_WIDTH * OSD_CHAR_HEIGHT * OSD_CHAR_BITS_PER_PIXEL / 8)
|
||||
// Only the first 54 bytes of a character represent visible data. However, some OSD drivers
|
||||
// accept 64 bytes and use the extra 10 bytes for metadata.
|
||||
#define OSD_CHAR_BYTES 64
|
||||
|
||||
#define OSD_CHARACTER_COLOR_BLACK 0
|
||||
#define OSD_CHARACTER_COLOR_TRANSPARENT 1
|
||||
#define OSD_CHARACTER_COLOR_WHITE 2
|
||||
|
||||
// 3 is unused but it's interpreted as transparent by all drivers
|
||||
|
||||
// Video Character Display parameters
|
||||
|
||||
typedef enum {
|
||||
VIDEO_SYSTEM_AUTO = 0,
|
||||
VIDEO_SYSTEM_PAL,
|
||||
VIDEO_SYSTEM_NTSC
|
||||
} videoSystem_e;
|
||||
|
||||
typedef enum {
|
||||
OSD_DRIVER_NONE = 0,
|
||||
OSD_DRIVER_MAX7456 = 1,
|
||||
} osdDriver_e;
|
||||
|
||||
// osdCharacter_t represents the binary data for an OSD
|
||||
// character. All OSD drivers use the same character format
|
||||
// as defined by OSD_CHARACTER_WIDTH, OSD_CHARACTER_HEIGHT
|
||||
// and OSD_CHARACTER_BITS_PER_PIXEL.
|
||||
typedef struct osdCharacter_s {
|
||||
uint8_t data[OSD_CHAR_BYTES];
|
||||
} osdCharacter_t;
|
|
@ -101,6 +101,7 @@
|
|||
#include "io/asyncfatfs/asyncfatfs.h"
|
||||
#include "io/beeper.h"
|
||||
#include "io/dashboard.h"
|
||||
#include "io/displayport_frsky_osd.h"
|
||||
#include "io/displayport_max7456.h"
|
||||
#include "io/displayport_msp.h"
|
||||
#include "io/displayport_srxl.h"
|
||||
|
@ -786,6 +787,18 @@ void init(void)
|
|||
case OSD_DISPLAYPORT_DEVICE_AUTO:
|
||||
FALLTHROUGH;
|
||||
|
||||
#if defined(USE_FRSKYOSD)
|
||||
// Test OSD_DISPLAYPORT_DEVICE_FRSKYOSD first, since an FC could
|
||||
// have a builtin MAX7456 but also an FRSKYOSD connected to an
|
||||
// uart.
|
||||
case OSD_DISPLAYPORT_DEVICE_FRSKYOSD:
|
||||
osdDisplayPort = frskyOsdDisplayPortInit(vcdProfile()->video_system);
|
||||
if (osdDisplayPort || device == OSD_DISPLAYPORT_DEVICE_FRSKYOSD) {
|
||||
break;
|
||||
}
|
||||
FALLTHROUGH;
|
||||
#endif
|
||||
|
||||
#if defined(USE_MAX7456)
|
||||
case OSD_DISPLAYPORT_DEVICE_MAX7456:
|
||||
// If there is a max7456 chip for the OSD configured and detectd then use it.
|
||||
|
|
|
@ -0,0 +1,503 @@
|
|||
/*
|
||||
* This file is part of Cleanflight, Betaflight and INAV
|
||||
*
|
||||
* Cleanflight, Betaflight and INAV are free software. You can
|
||||
* redistribute this software and/or modify this software under
|
||||
* the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* Cleanflight, Betaflight and INAV are distributed in the hope that
|
||||
* they will be useful, but WITHOUT ANY WARRANTY; without even the
|
||||
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software.
|
||||
*
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
#if defined(USE_FRSKYOSD)
|
||||
|
||||
#include "common/utils.h"
|
||||
|
||||
#include "drivers/display.h"
|
||||
#include "drivers/display_canvas.h"
|
||||
|
||||
#include "io/displayport_frsky_osd.h"
|
||||
#include "io/frsky_osd.h"
|
||||
|
||||
static displayPort_t frskyOsdDisplayPort;
|
||||
|
||||
static int grab(displayPort_t *displayPort)
|
||||
{
|
||||
UNUSED(displayPort);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int release(displayPort_t *displayPort)
|
||||
{
|
||||
UNUSED(displayPort);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int clearScreen(displayPort_t *displayPort)
|
||||
{
|
||||
UNUSED(displayPort);
|
||||
frskyOsdClearScreen();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drawScreen(displayPort_t *displayPort)
|
||||
{
|
||||
UNUSED(displayPort);
|
||||
frskyOsdUpdate();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int screenSize(const displayPort_t *displayPort)
|
||||
{
|
||||
UNUSED(displayPort);
|
||||
return frskyOsdGetGridRows() * frskyOsdGetGridCols();
|
||||
}
|
||||
|
||||
static int writeString(displayPort_t *displayPort, uint8_t x, uint8_t y, uint8_t attr, const char *s)
|
||||
{
|
||||
UNUSED(displayPort);
|
||||
UNUSED(attr);
|
||||
|
||||
frskyOsdDrawStringInGrid(x, y, s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int writeChar(displayPort_t *displayPort, uint8_t x, uint8_t y, uint8_t attr, uint8_t c)
|
||||
{
|
||||
UNUSED(displayPort);
|
||||
UNUSED(attr);
|
||||
|
||||
frskyOsdDrawCharInGrid(x, y, c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool isTransferInProgress(const displayPort_t *displayPort)
|
||||
{
|
||||
UNUSED(displayPort);
|
||||
return false;
|
||||
}
|
||||
|
||||
static void updateGridSize(displayPort_t *displayPort)
|
||||
{
|
||||
displayPort->rows = frskyOsdGetGridRows();
|
||||
displayPort->cols = frskyOsdGetGridCols();
|
||||
}
|
||||
|
||||
static void resync(displayPort_t *displayPort)
|
||||
{
|
||||
UNUSED(displayPort);
|
||||
// TODO(agh): Do we need to flush the screen here?
|
||||
// MAX7456's driver does a full redraw in resync(),
|
||||
// so some callers might be expecting that.
|
||||
frskyOsdUpdate();
|
||||
updateGridSize(displayPort);
|
||||
}
|
||||
|
||||
static int heartbeat(displayPort_t *displayPort)
|
||||
{
|
||||
UNUSED(displayPort);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t txBytesFree(const displayPort_t *displayPort)
|
||||
{
|
||||
UNUSED(displayPort);
|
||||
return UINT32_MAX;
|
||||
}
|
||||
|
||||
static bool writeFontCharacter(displayPort_t *instance, uint16_t addr, const osdCharacter_t *chr)
|
||||
{
|
||||
UNUSED(instance);
|
||||
|
||||
return frskyOsdWriteFontCharacter(addr, chr);
|
||||
}
|
||||
|
||||
static bool isReady(displayPort_t *instance)
|
||||
{
|
||||
if (frskyOsdIsReady()) {
|
||||
updateGridSize(instance);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void beginTransaction(displayPort_t *instance, displayTransactionOption_e opts)
|
||||
{
|
||||
UNUSED(instance);
|
||||
|
||||
frskyOsdTransactionOptions_e frskyOpts = 0;
|
||||
if (opts & DISPLAY_TRANSACTION_OPT_PROFILED) {
|
||||
frskyOpts |= FRSKY_OSD_TRANSACTION_OPT_PROFILED;
|
||||
}
|
||||
if (opts & DISPLAY_TRANSACTION_OPT_RESET_DRAWING) {
|
||||
frskyOpts |= FRSKY_OSD_TRANSACTION_OPT_RESET_DRAWING;
|
||||
}
|
||||
|
||||
frskyOsdBeginTransaction(frskyOpts);
|
||||
}
|
||||
|
||||
static void commitTransaction(displayPort_t *instance)
|
||||
{
|
||||
UNUSED(instance);
|
||||
|
||||
frskyOsdCommitTransaction();
|
||||
}
|
||||
|
||||
static frskyOsdColor_e frskyOsdGetColor(displayCanvasColor_e color)
|
||||
{
|
||||
switch (color)
|
||||
{
|
||||
case DISPLAY_CANVAS_COLOR_BLACK:
|
||||
return FRSKY_OSD_COLOR_BLACK;
|
||||
case DISPLAY_CANVAS_COLOR_TRANSPARENT:
|
||||
return FRSKY_OSD_COLOR_TRANSPARENT;
|
||||
case DISPLAY_CANVAS_COLOR_WHITE:
|
||||
return FRSKY_OSD_COLOR_WHITE;
|
||||
case DISPLAY_CANVAS_COLOR_GRAY:
|
||||
return FRSKY_OSD_COLOR_GRAY;
|
||||
}
|
||||
return FRSKY_OSD_COLOR_BLACK;
|
||||
}
|
||||
|
||||
static void setStrokeColor(displayCanvas_t *displayCanvas, displayCanvasColor_e color)
|
||||
{
|
||||
UNUSED(displayCanvas);
|
||||
|
||||
frskyOsdSetStrokeColor(frskyOsdGetColor(color));
|
||||
}
|
||||
|
||||
static void setFillColor(displayCanvas_t *displayCanvas, displayCanvasColor_e color)
|
||||
{
|
||||
UNUSED(displayCanvas);
|
||||
|
||||
frskyOsdSetFillColor(frskyOsdGetColor(color));
|
||||
}
|
||||
|
||||
static void setStrokeAndFillColor(displayCanvas_t *displayCanvas, displayCanvasColor_e color)
|
||||
{
|
||||
UNUSED(displayCanvas);
|
||||
|
||||
frskyOsdSetStrokeAndFillColor(frskyOsdGetColor(color));
|
||||
}
|
||||
|
||||
static void setColorInversion(displayCanvas_t *displayCanvas, bool inverted)
|
||||
{
|
||||
UNUSED(displayCanvas);
|
||||
|
||||
frskyOsdSetColorInversion(inverted);
|
||||
}
|
||||
|
||||
static void setPixel(displayCanvas_t *displayCanvas, int x, int y, displayCanvasColor_e color)
|
||||
{
|
||||
UNUSED(displayCanvas);
|
||||
|
||||
frskyOsdSetPixel(x, y, frskyOsdGetColor(color));
|
||||
}
|
||||
|
||||
static void setPixelToStrokeColor(displayCanvas_t *displayCanvas, int x, int y)
|
||||
{
|
||||
UNUSED(displayCanvas);
|
||||
|
||||
frskyOsdSetPixelToStrokeColor(x, y);
|
||||
}
|
||||
|
||||
static void setPixelToFillColor(displayCanvas_t *displayCanvas, int x, int y)
|
||||
{
|
||||
UNUSED(displayCanvas);
|
||||
|
||||
frskyOsdSetPixelToFillColor(x, y);
|
||||
}
|
||||
|
||||
static void setStrokeWidth(displayCanvas_t *displayCanvas, unsigned w)
|
||||
{
|
||||
UNUSED(displayCanvas);
|
||||
|
||||
frskyOsdSetStrokeWidth(w);
|
||||
}
|
||||
|
||||
static void setLineOutlineType(displayCanvas_t *displayCanvas, displayCanvasOutlineType_e outlineType)
|
||||
{
|
||||
UNUSED(displayCanvas);
|
||||
|
||||
frskyOsdSetLineOutlineType(outlineType);
|
||||
}
|
||||
|
||||
static void setLineOutlineColor(displayCanvas_t *displayCanvas, displayCanvasColor_e outlineColor)
|
||||
{
|
||||
UNUSED(displayCanvas);
|
||||
|
||||
frskyOsdSetLineOutlineColor(outlineColor);
|
||||
}
|
||||
|
||||
static void clipToRect(displayCanvas_t *displayCanvas, int x, int y, int w, int h)
|
||||
{
|
||||
UNUSED(displayCanvas);
|
||||
|
||||
frskyOsdClipToRect(x, y, w, h);
|
||||
}
|
||||
|
||||
static void clearRect(displayCanvas_t *displayCanvas, int x, int y, int w, int h)
|
||||
{
|
||||
UNUSED(displayCanvas);
|
||||
|
||||
frskyOsdClearRect(x, y, w, h);
|
||||
}
|
||||
|
||||
static void resetDrawingState(displayCanvas_t *displayCanvas)
|
||||
{
|
||||
UNUSED(displayCanvas);
|
||||
|
||||
frskyOsdResetDrawingState();
|
||||
}
|
||||
|
||||
static void drawCharacter(displayCanvas_t *displayCanvas, int x, int y, uint16_t chr, displayCanvasBitmapOption_t opts)
|
||||
{
|
||||
UNUSED(displayCanvas);
|
||||
|
||||
frskyOsdDrawCharacter(x, y, chr, opts);
|
||||
}
|
||||
|
||||
static void drawCharacterMask(displayCanvas_t *displayCanvas, int x, int y, uint16_t chr, displayCanvasColor_e color, displayCanvasBitmapOption_t opts)
|
||||
{
|
||||
UNUSED(displayCanvas);
|
||||
|
||||
frskyOsdDrawCharacterMask(x, y, chr, frskyOsdGetColor(color), opts);
|
||||
}
|
||||
|
||||
static void drawString(displayCanvas_t *displayCanvas, int x, int y, const char *s, displayCanvasBitmapOption_t opts)
|
||||
{
|
||||
UNUSED(displayCanvas);
|
||||
|
||||
frskyOsdDrawString(x, y, s, opts);
|
||||
}
|
||||
|
||||
static void drawStringMask(displayCanvas_t *displayCanvas, int x, int y, const char *s, displayCanvasColor_e color, displayCanvasBitmapOption_t opts)
|
||||
{
|
||||
UNUSED(displayCanvas);
|
||||
|
||||
frskyOsdDrawStringMask(x, y, s, frskyOsdGetColor(color), opts);
|
||||
}
|
||||
|
||||
static void moveToPoint(displayCanvas_t *displayCanvas, int x, int y)
|
||||
{
|
||||
UNUSED(displayCanvas);
|
||||
|
||||
frskyOsdMoveToPoint(x, y);
|
||||
}
|
||||
|
||||
static void strokeLineToPoint(displayCanvas_t *displayCanvas, int x, int y)
|
||||
{
|
||||
UNUSED(displayCanvas);
|
||||
|
||||
frskyOsdStrokeLineToPoint(x, y);
|
||||
}
|
||||
|
||||
static void strokeTriangle(displayCanvas_t *displayCanvas, int x1, int y1, int x2, int y2, int x3, int y3)
|
||||
{
|
||||
UNUSED(displayCanvas);
|
||||
|
||||
frskyOsdStrokeTriangle(x1, y1, x2, y2, x3, y3);
|
||||
}
|
||||
|
||||
static void fillTriangle(displayCanvas_t *displayCanvas, int x1, int y1, int x2, int y2, int x3, int y3)
|
||||
{
|
||||
UNUSED(displayCanvas);
|
||||
|
||||
frskyOsdFillTriangle(x1, y1, x2, y2, x3, y3);
|
||||
}
|
||||
|
||||
static void fillStrokeTriangle(displayCanvas_t *displayCanvas, int x1, int y1, int x2, int y2, int x3, int y3)
|
||||
{
|
||||
UNUSED(displayCanvas);
|
||||
|
||||
frskyOsdFillStrokeTriangle(x1, y1, x2, y2, x3, y3);
|
||||
}
|
||||
|
||||
static void strokeRect(displayCanvas_t *displayCanvas, int x, int y, int w, int h)
|
||||
{
|
||||
UNUSED(displayCanvas);
|
||||
|
||||
frskyOsdStrokeRect(x, y, w, h);
|
||||
}
|
||||
|
||||
static void fillRect(displayCanvas_t *displayCanvas, int x, int y, int w, int h)
|
||||
{
|
||||
UNUSED(displayCanvas);
|
||||
|
||||
frskyOsdFillRect(x, y, w, h);
|
||||
}
|
||||
|
||||
static void fillStrokeRect(displayCanvas_t *displayCanvas, int x, int y, int w, int h)
|
||||
{
|
||||
UNUSED(displayCanvas);
|
||||
|
||||
frskyOsdFillStrokeRect(x, y, w, h);
|
||||
}
|
||||
|
||||
static void strokeEllipseInRect(displayCanvas_t *displayCanvas, int x, int y, int w, int h)
|
||||
{
|
||||
UNUSED(displayCanvas);
|
||||
|
||||
frskyOsdStrokeEllipseInRect(x, y, w, h);
|
||||
}
|
||||
|
||||
static void fillEllipseInRect(displayCanvas_t *displayCanvas, int x, int y, int w, int h)
|
||||
{
|
||||
UNUSED(displayCanvas);
|
||||
|
||||
frskyOsdFillEllipseInRect(x, y, w, h);
|
||||
}
|
||||
|
||||
static void fillStrokeEllipseInRect(displayCanvas_t *displayCanvas, int x, int y, int w, int h)
|
||||
{
|
||||
UNUSED(displayCanvas);
|
||||
|
||||
frskyOsdFillStrokeEllipseInRect(x, y, w, h);
|
||||
}
|
||||
|
||||
static void ctmReset(displayCanvas_t *displayCanvas)
|
||||
{
|
||||
UNUSED(displayCanvas);
|
||||
|
||||
frskyOsdCtmReset();
|
||||
}
|
||||
|
||||
static void ctmSet(displayCanvas_t *displayCanvas, float m11, float m12, float m21, float m22, float m31, float m32)
|
||||
{
|
||||
UNUSED(displayCanvas);
|
||||
|
||||
frskyOsdCtmSet(m11, m12, m21, m22, m31, m32);
|
||||
}
|
||||
|
||||
static void ctmTranslate(displayCanvas_t *displayCanvas, float tx, float ty)
|
||||
{
|
||||
UNUSED(displayCanvas);
|
||||
|
||||
frskyOsdCtmTranslate(tx, ty);
|
||||
}
|
||||
|
||||
static void ctmScale(displayCanvas_t *displayCanvas, float sx, float sy)
|
||||
{
|
||||
UNUSED(displayCanvas);
|
||||
|
||||
frskyOsdCtmScale(sx, sy);
|
||||
}
|
||||
|
||||
static void ctmRotate(displayCanvas_t *displayCanvas, float r)
|
||||
{
|
||||
UNUSED(displayCanvas);
|
||||
|
||||
frskyOsdCtmRotate(r);
|
||||
}
|
||||
|
||||
static void contextPush(displayCanvas_t *displayCanvas)
|
||||
{
|
||||
UNUSED(displayCanvas);
|
||||
|
||||
frskyOsdContextPush();
|
||||
}
|
||||
|
||||
static void contextPop(displayCanvas_t *displayCanvas)
|
||||
{
|
||||
UNUSED(displayCanvas);
|
||||
|
||||
frskyOsdContextPop();
|
||||
}
|
||||
|
||||
|
||||
static const displayCanvasVTable_t frskyOsdCanvasVTable = {
|
||||
.setStrokeColor = setStrokeColor,
|
||||
.setFillColor = setFillColor,
|
||||
.setStrokeAndFillColor = setStrokeAndFillColor,
|
||||
.setColorInversion = setColorInversion,
|
||||
.setPixel = setPixel,
|
||||
.setPixelToStrokeColor = setPixelToStrokeColor,
|
||||
.setPixelToFillColor = setPixelToFillColor,
|
||||
.setStrokeWidth = setStrokeWidth,
|
||||
.setLineOutlineType = setLineOutlineType,
|
||||
.setLineOutlineColor = setLineOutlineColor,
|
||||
|
||||
.clipToRect = clipToRect,
|
||||
.clearRect = clearRect,
|
||||
.resetDrawingState = resetDrawingState,
|
||||
.drawCharacter = drawCharacter,
|
||||
.drawCharacterMask = drawCharacterMask,
|
||||
.drawString = drawString,
|
||||
.drawStringMask = drawStringMask,
|
||||
.moveToPoint = moveToPoint,
|
||||
.strokeLineToPoint = strokeLineToPoint,
|
||||
.strokeTriangle = strokeTriangle,
|
||||
.fillTriangle = fillTriangle,
|
||||
.fillStrokeTriangle = fillStrokeTriangle,
|
||||
.strokeRect = strokeRect,
|
||||
.fillRect = fillRect,
|
||||
.fillStrokeRect = fillStrokeRect,
|
||||
.strokeEllipseInRect = strokeEllipseInRect,
|
||||
.fillEllipseInRect = fillEllipseInRect,
|
||||
.fillStrokeEllipseInRect = fillStrokeEllipseInRect,
|
||||
|
||||
.ctmReset = ctmReset,
|
||||
.ctmSet = ctmSet,
|
||||
.ctmTranslate = ctmTranslate,
|
||||
.ctmScale = ctmScale,
|
||||
.ctmRotate = ctmRotate,
|
||||
|
||||
.contextPush = contextPush,
|
||||
.contextPop = contextPop,
|
||||
};
|
||||
|
||||
static bool getCanvas(displayCanvas_t *canvas, const displayPort_t *instance)
|
||||
{
|
||||
UNUSED(instance);
|
||||
|
||||
canvas->vTable = &frskyOsdCanvasVTable;
|
||||
canvas->width = frskyOsdGetPixelWidth();
|
||||
canvas->height = frskyOsdGetPixelHeight();
|
||||
return true;
|
||||
}
|
||||
|
||||
static const displayPortVTable_t frskyOsdVTable = {
|
||||
.grab = grab,
|
||||
.release = release,
|
||||
.clearScreen = clearScreen,
|
||||
.drawScreen = drawScreen,
|
||||
.screenSize = screenSize,
|
||||
.writeString = writeString,
|
||||
.writeChar = writeChar,
|
||||
.isTransferInProgress = isTransferInProgress,
|
||||
.heartbeat = heartbeat,
|
||||
.resync = resync,
|
||||
.txBytesFree = txBytesFree,
|
||||
.writeFontCharacter = writeFontCharacter,
|
||||
.isReady = isReady,
|
||||
.beginTransaction = beginTransaction,
|
||||
.commitTransaction = commitTransaction,
|
||||
.getCanvas = getCanvas,
|
||||
};
|
||||
|
||||
displayPort_t *frskyOsdDisplayPortInit(const videoSystem_e videoSystem)
|
||||
{
|
||||
if (frskyOsdInit(videoSystem)) {
|
||||
displayInit(&frskyOsdDisplayPort, &frskyOsdVTable);
|
||||
resync(&frskyOsdDisplayPort);
|
||||
return &frskyOsdDisplayPort;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif // USE_FRSKYOSD
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* This file is part of Cleanflight, Betaflight and INAV
|
||||
*
|
||||
* Cleanflight, Betaflight and INAV are free software. You can
|
||||
* redistribute this software and/or modify this software under
|
||||
* the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* Cleanflight, Betaflight and INAV are distributed in the hope that
|
||||
* they will be useful, but WITHOUT ANY WARRANTY; without even the
|
||||
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software.
|
||||
*
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "drivers/osd.h"
|
||||
|
||||
typedef struct displayPort_s displayPort_t;
|
||||
|
||||
displayPort_t *frskyOsdDisplayPortInit(const videoSystem_e videoSystem);
|
|
@ -29,6 +29,7 @@
|
|||
|
||||
#include "drivers/display.h"
|
||||
#include "drivers/max7456.h"
|
||||
#include "drivers/osd.h"
|
||||
|
||||
#include "config/config.h"
|
||||
|
||||
|
@ -156,6 +157,13 @@ static bool layerCopy(displayPort_t *displayPort, displayPortLayer_e destLayer,
|
|||
return max7456LayerCopy(destLayer, sourceLayer);
|
||||
}
|
||||
|
||||
static bool writeFontCharacter(displayPort_t *instance, uint16_t addr, const osdCharacter_t *chr)
|
||||
{
|
||||
UNUSED(instance);
|
||||
|
||||
return max7456WriteNvm(addr, (const uint8_t *)chr);
|
||||
}
|
||||
|
||||
static const displayPortVTable_t max7456VTable = {
|
||||
.grab = grab,
|
||||
.release = release,
|
||||
|
@ -172,6 +180,7 @@ static const displayPortVTable_t max7456VTable = {
|
|||
.layerSupported = layerSupported,
|
||||
.layerSelect = layerSelect,
|
||||
.layerCopy = layerCopy,
|
||||
.writeFontCharacter = writeFontCharacter,
|
||||
};
|
||||
|
||||
displayPort_t *max7456DisplayPortInit(const vcdProfile_t *vcdProfile)
|
||||
|
|
|
@ -0,0 +1,927 @@
|
|||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
#if defined(USE_FRSKYOSD)
|
||||
|
||||
#include "common/crc.h"
|
||||
#include "common/maths.h"
|
||||
#include "common/time.h"
|
||||
#include "common/utils.h"
|
||||
#include "common/uvarint.h"
|
||||
|
||||
#include "drivers/time.h"
|
||||
|
||||
#include "io/frsky_osd.h"
|
||||
#include "io/serial.h"
|
||||
|
||||
#define FRSKY_OSD_BAUDRATE 115200
|
||||
#define FRSKY_OSD_SUPPORTED_API_VERSION 1
|
||||
|
||||
#define FRSKY_OSD_PREAMBLE_BYTE_0 '$'
|
||||
#define FRSKY_OSD_PREAMBLE_BYTE_1 'A'
|
||||
|
||||
#define FRSKY_OSD_GRID_BUFFER_CHAR_BITS 9
|
||||
#define FRSKY_OSD_GRID_BUFFER_CHAR_MASK ((1 << FRSKY_OSD_GRID_BUFFER_CHAR_BITS) - 1)
|
||||
#define FRSKY_OSD_GRID_BUFFER_ENCODE(chr, attr) ((chr & FRSKY_OSD_GRID_BUFFER_CHAR_MASK) | (attr << FRSKY_OSD_GRID_BUFFER_CHAR_BITS))
|
||||
|
||||
#define FRSKY_OSD_CHAR_ATTRIBUTE_COLOR_INVERSE (1 << 0)
|
||||
#define FRSKY_OSD_CHAR_ATTRIBUTE_SOLID_BACKGROUND (1 << 1)
|
||||
|
||||
#define FRSKY_OSD_CHAR_DATA_BYTES 54
|
||||
#define FRSKY_OSD_CHAR_METADATA_BYTES 10
|
||||
#define FRSKY_OSD_CHAR_TOTAL_BYTES (FRSKY_OSD_CHAR_DATA_BYTES + FRSKY_OSD_CHAR_METADATA_BYTES)
|
||||
|
||||
#define FRSKY_OSD_SEND_BUFFER_SIZE 192
|
||||
#define FRSKY_OSD_RECV_BUFFER_SIZE 128
|
||||
|
||||
#define FRSKY_OSD_CMD_RESPONSE_ERROR 0
|
||||
|
||||
#define FRSKY_OSD_INFO_INTERVAL_MS 1000
|
||||
|
||||
#define FRSKY_OSD_TRACE(...)
|
||||
#define FRSKY_OSD_DEBUG(...)
|
||||
#define FRSKY_OSD_ERROR(...)
|
||||
#define FRSKY_OSD_ASSERT(x)
|
||||
|
||||
typedef enum
|
||||
{
|
||||
OSD_CMD_RESPONSE_ERROR = 0,
|
||||
|
||||
OSD_CMD_INFO = 1,
|
||||
OSD_CMD_READ_FONT = 2,
|
||||
OSD_CMD_WRITE_FONT = 3,
|
||||
OSD_CMD_GET_CAMERA = 4,
|
||||
OSD_CMD_SET_CAMERA = 5,
|
||||
OSD_CMD_GET_ACTIVE_CAMERA = 6,
|
||||
OSD_CMD_GET_OSD_ENABLED = 7,
|
||||
OSD_CMD_SET_OSD_ENABLED = 8,
|
||||
|
||||
OSD_CMD_TRANSACTION_BEGIN = 16,
|
||||
OSD_CMD_TRANSACTION_COMMIT = 17,
|
||||
OSD_CMD_TRANSACTION_BEGIN_PROFILED = 18,
|
||||
OSD_CMD_TRANSACTION_BEGIN_RESET_DRAWING = 19,
|
||||
|
||||
OSD_CMD_DRAWING_SET_STROKE_COLOR = 22,
|
||||
OSD_CMD_DRAWING_SET_FILL_COLOR = 23,
|
||||
OSD_CMD_DRAWING_SET_STROKE_AND_FILL_COLOR = 24,
|
||||
OSD_CMD_DRAWING_SET_COLOR_INVERSION = 25,
|
||||
OSD_CMD_DRAWING_SET_PIXEL = 26,
|
||||
OSD_CMD_DRAWING_SET_PIXEL_TO_STROKE_COLOR = 27,
|
||||
OSD_CMD_DRAWING_SET_PIXEL_TO_FILL_COLOR = 28,
|
||||
OSD_CMD_DRAWING_SET_STROKE_WIDTH = 29,
|
||||
OSD_CMD_DRAWING_SET_LINE_OUTLINE_TYPE = 30,
|
||||
OSD_CMD_DRAWING_SET_LINE_OUTLINE_COLOR = 31,
|
||||
|
||||
OSD_CMD_DRAWING_CLIP_TO_RECT = 40,
|
||||
OSD_CMD_DRAWING_CLEAR_SCREEN = 41,
|
||||
OSD_CMD_DRAWING_CLEAR_RECT = 42,
|
||||
OSD_CMD_DRAWING_RESET = 43,
|
||||
OSD_CMD_DRAWING_DRAW_BITMAP = 44,
|
||||
OSD_CMD_DRAWING_DRAW_BITMAP_MASK = 45,
|
||||
OSD_CMD_DRAWING_DRAW_CHAR = 46,
|
||||
OSD_CMD_DRAWING_DRAW_CHAR_MASK = 47,
|
||||
OSD_CMD_DRAWING_DRAW_STRING = 48,
|
||||
OSD_CMD_DRAWING_DRAW_STRING_MASK = 49,
|
||||
OSD_CMD_DRAWING_MOVE_TO_POINT = 50,
|
||||
OSD_CMD_DRAWING_STROKE_LINE_TO_POINT = 51,
|
||||
OSD_CMD_DRAWING_STROKE_TRIANGLE = 52,
|
||||
OSD_CMD_DRAWING_FILL_TRIANGLE = 53,
|
||||
OSD_CMD_DRAWING_FILL_STROKE_TRIANGLE = 54,
|
||||
OSD_CMD_DRAWING_STROKE_RECT = 55,
|
||||
OSD_CMD_DRAWING_FILL_RECT = 56,
|
||||
OSD_CMD_DRAWING_FILL_STROKE_RECT = 57,
|
||||
OSD_CMD_DRAWING_STROKE_ELLIPSE_IN_RECT = 58,
|
||||
OSD_CMD_DRAWING_FILL_ELLIPSE_IN_RECT = 59,
|
||||
OSD_CMD_DRAWING_FILL_STROKE_ELLIPSE_IN_RECT = 60,
|
||||
|
||||
OSD_CMD_CTM_RESET = 80,
|
||||
OSD_CMD_CTM_SET = 81,
|
||||
OSD_CMD_CTM_TRANSLATE = 82,
|
||||
OSD_CMD_CTM_SCALE = 83,
|
||||
OSD_CMD_CTM_ROTATE = 84,
|
||||
OSD_CMD_CTM_ROTATE_ABOUT = 85,
|
||||
OSD_CMD_CTM_SHEAR = 86,
|
||||
OSD_CMD_CTM_SHEAR_ABOUT = 87,
|
||||
OSD_CMD_CTM_MULTIPLY = 88,
|
||||
|
||||
OSD_CMD_CONTEXT_PUSH = 100,
|
||||
OSD_CMD_CONTEXT_POP = 101,
|
||||
|
||||
// MAX7456 emulation commands
|
||||
OSD_CMD_DRAW_GRID_CHR = 110,
|
||||
OSD_CMD_DRAW_GRID_STR = 111,
|
||||
} osdCommand_e;
|
||||
|
||||
typedef enum {
|
||||
RECV_STATE_NONE,
|
||||
RECV_STATE_SYNC,
|
||||
RECV_STATE_LENGTH,
|
||||
RECV_STATE_DATA,
|
||||
RECV_STATE_CHECKSUM,
|
||||
RECV_STATE_DONE,
|
||||
} frskyOsdRecvState_e;
|
||||
|
||||
typedef struct frskyOsdInfoResponse_s {
|
||||
uint8_t magic[3];
|
||||
uint8_t versionMajor;
|
||||
uint8_t versionMinor;
|
||||
uint8_t versionPatch;
|
||||
uint8_t gridRows;
|
||||
uint8_t gridColumns;
|
||||
uint16_t pixelWidth;
|
||||
uint16_t pixelHeight;
|
||||
uint8_t tvStandard;
|
||||
uint8_t hasDetectedCamera;
|
||||
uint16_t maxFrameSize;
|
||||
uint8_t contextStackSize;
|
||||
} __attribute__((packed)) frskyOsdInfoResponse_t;
|
||||
|
||||
typedef struct frskyOsdFontCharacter_s {
|
||||
uint16_t addr;
|
||||
struct {
|
||||
uint8_t bitmap[FRSKY_OSD_CHAR_DATA_BYTES]; // 12x18 2bpp
|
||||
uint8_t metadata[FRSKY_OSD_CHAR_METADATA_BYTES];
|
||||
} data;
|
||||
} __attribute__((packed)) frskyOsdCharacter_t;
|
||||
|
||||
typedef struct frskyOsdDrawGridCharCmd_s {
|
||||
uint8_t gx;
|
||||
uint8_t gy;
|
||||
uint16_t chr;
|
||||
uint8_t opts;
|
||||
} __attribute__((packed)) frskyOsdDrawGridCharCmd_t;
|
||||
|
||||
typedef struct frskyOsdDrawGridStrHeaderCmd_s {
|
||||
uint8_t gx;
|
||||
uint8_t gy;
|
||||
uint8_t opts;
|
||||
// uvarint with size and blob folow
|
||||
} __attribute__((packed)) frskyOsdDrawGridStrHeaderCmd_t;
|
||||
|
||||
typedef struct frskyOsdPoint_s {
|
||||
int x : 12;
|
||||
int y : 12;
|
||||
} __attribute__((packed)) frskyOsdPoint_t;
|
||||
|
||||
typedef struct frskyOsdSize_s {
|
||||
int w : 12;
|
||||
int h : 12;
|
||||
} __attribute__((packed)) frskyOsdSize_t;
|
||||
|
||||
typedef struct frskyOsdRect_s {
|
||||
frskyOsdPoint_t origin;
|
||||
frskyOsdSize_t size;
|
||||
} __attribute__((packed)) frskyOsdRect_t;
|
||||
|
||||
typedef struct frskyOsdTriangle_s {
|
||||
frskyOsdPoint_t p1;
|
||||
frskyOsdPoint_t p2;
|
||||
frskyOsdPoint_t p3;
|
||||
} __attribute__((packed)) frskyOsdTriangle_t;
|
||||
|
||||
typedef struct frskyOsdSetPixel_s {
|
||||
frskyOsdPoint_t p;
|
||||
uint8_t color;
|
||||
} __attribute__((packed)) frskyOsdSetPixel_t;
|
||||
|
||||
typedef struct frskyOsdDrawCharacterCmd_s {
|
||||
frskyOsdPoint_t p;
|
||||
uint16_t chr;
|
||||
uint8_t opts;
|
||||
} __attribute__((packed)) frskyOsdDrawCharacterCmd_t;
|
||||
|
||||
typedef struct frskyOsdDrawCharacterMaskCmd_s {
|
||||
frskyOsdDrawCharacterCmd_t dc;
|
||||
uint8_t maskColor;
|
||||
} __attribute__((packed)) frskyOsdDrawCharacterMaskCmd_t;
|
||||
|
||||
typedef struct frskyOsdDrawStrCommandHeaderCmd_s {
|
||||
frskyOsdPoint_t p;
|
||||
uint8_t opts;
|
||||
// uvarint with size and blob follow
|
||||
} __attribute__((packed)) frskyOsdDrawStrCommandHeaderCmd_t;
|
||||
|
||||
typedef struct frskyOsdDrawStrMaskCommandHeaderCmd_s {
|
||||
frskyOsdPoint_t p;
|
||||
uint8_t opts;
|
||||
uint8_t maskColor;
|
||||
// uvarint with size and blob follow
|
||||
} __attribute__((packed)) frskyOsdDrawStrMaskCommandHeaderCmd_t;
|
||||
|
||||
|
||||
typedef struct frskyOsdState_s {
|
||||
struct {
|
||||
uint8_t data[FRSKY_OSD_SEND_BUFFER_SIZE];
|
||||
uint8_t pos;
|
||||
} sendBuffer;
|
||||
struct {
|
||||
uint8_t state;
|
||||
uint8_t crc;
|
||||
uint16_t expected;
|
||||
uint8_t expectedShift;
|
||||
uint8_t data[FRSKY_OSD_RECV_BUFFER_SIZE];
|
||||
uint8_t pos;
|
||||
} recvBuffer;
|
||||
struct {
|
||||
uint8_t major;
|
||||
uint8_t minor;
|
||||
timeMs_t nextRequest;
|
||||
struct {
|
||||
uint8_t rows;
|
||||
uint8_t columns;
|
||||
} grid;
|
||||
struct {
|
||||
uint16_t width;
|
||||
uint16_t height;
|
||||
} viewport;
|
||||
} info;
|
||||
struct {
|
||||
uint16_t addr;
|
||||
osdCharacter_t *chr;
|
||||
} recvOsdCharacter;
|
||||
serialPort_t *port;
|
||||
bool initialized;
|
||||
timeMs_t nextInfoRequest;
|
||||
} frskyOsdState_t;
|
||||
|
||||
static frskyOsdState_t state;
|
||||
|
||||
static uint8_t frskyOsdChecksum(uint8_t crc, uint8_t c)
|
||||
{
|
||||
return crc8_dvb_s2(crc, c);
|
||||
}
|
||||
|
||||
static void frskyOsdResetReceiveBuffer(void)
|
||||
{
|
||||
state.recvBuffer.state = RECV_STATE_NONE;
|
||||
state.recvBuffer.crc = 0;
|
||||
state.recvBuffer.expected = 0;
|
||||
state.recvBuffer.expectedShift = 0;
|
||||
state.recvBuffer.pos = 0;
|
||||
}
|
||||
|
||||
static void frskyOsdResetSendBuffer(void)
|
||||
{
|
||||
state.sendBuffer.pos = 0;
|
||||
}
|
||||
|
||||
static void frskyOsdProcessCommandU8(uint8_t *crc, uint8_t c)
|
||||
{
|
||||
while (serialTxBytesFree(state.port) == 0) {
|
||||
};
|
||||
serialWrite(state.port, c);
|
||||
if (crc) {
|
||||
*crc = crc8_dvb_s2(*crc, c);
|
||||
}
|
||||
}
|
||||
|
||||
static void frskyOsdSendCommand(uint8_t cmd, const void *payload, size_t size)
|
||||
{
|
||||
int required = size + 1;
|
||||
FRSKY_OSD_ASSERT(required <= sizeof(state.sendBuffer.data));
|
||||
int rem = sizeof(state.sendBuffer.data) - state.sendBuffer.pos;
|
||||
if (rem < required) {
|
||||
frskyOsdFlushSendBuffer();
|
||||
}
|
||||
state.sendBuffer.data[state.sendBuffer.pos++] = cmd;
|
||||
const uint8_t *ptr = payload;
|
||||
for (size_t ii = 0; ii < size; ii++, ptr++) {
|
||||
state.sendBuffer.data[state.sendBuffer.pos++] = *ptr;
|
||||
}
|
||||
}
|
||||
|
||||
static void frskyOsdStateReset(serialPort_t *port)
|
||||
{
|
||||
frskyOsdResetReceiveBuffer();
|
||||
frskyOsdResetSendBuffer();
|
||||
state.info.grid.rows = 0;
|
||||
state.info.grid.columns = 0;
|
||||
state.info.viewport.width = 0;
|
||||
state.info.viewport.height = 0;
|
||||
|
||||
state.port = port;
|
||||
state.initialized = false;
|
||||
}
|
||||
|
||||
static void frskyOsdUpdateReceiveBuffer(void)
|
||||
{
|
||||
while (serialRxBytesWaiting(state.port) > 0) {
|
||||
uint8_t c = serialRead(state.port);
|
||||
switch ((frskyOsdRecvState_e)state.recvBuffer.state) {
|
||||
case RECV_STATE_NONE:
|
||||
if (c != FRSKY_OSD_PREAMBLE_BYTE_0) {
|
||||
break;
|
||||
}
|
||||
state.recvBuffer.state = RECV_STATE_SYNC;
|
||||
break;
|
||||
case RECV_STATE_SYNC:
|
||||
if (c != FRSKY_OSD_PREAMBLE_BYTE_1) {
|
||||
frskyOsdResetReceiveBuffer();
|
||||
break;
|
||||
}
|
||||
state.recvBuffer.state = RECV_STATE_LENGTH;
|
||||
break;
|
||||
case RECV_STATE_LENGTH:
|
||||
state.recvBuffer.crc = frskyOsdChecksum(state.recvBuffer.crc, c);
|
||||
state.recvBuffer.expected |= (c & 0x7F) << state.recvBuffer.expectedShift;
|
||||
state.recvBuffer.expectedShift += 7;
|
||||
if (c < 0x80) {
|
||||
// Full uvarint decoded. Check against buffer size.
|
||||
if (state.recvBuffer.expected > sizeof(state.recvBuffer.data)) {
|
||||
FRSKY_OSD_ERROR("Can't handle payload of size %u with a buffer of size %u",
|
||||
state.recvBuffer.expected, sizeof(state.recvBuffer.data));
|
||||
frskyOsdResetReceiveBuffer();
|
||||
break;
|
||||
}
|
||||
FRSKY_OSD_TRACE("Payload of size %u", state.recvBuffer.expected);
|
||||
state.recvBuffer.state = state.recvBuffer.expected > 0 ? RECV_STATE_DATA : RECV_STATE_CHECKSUM;
|
||||
}
|
||||
break;
|
||||
case RECV_STATE_DATA:
|
||||
state.recvBuffer.data[state.recvBuffer.pos++] = c;
|
||||
state.recvBuffer.crc = frskyOsdChecksum(state.recvBuffer.crc, c);
|
||||
if (state.recvBuffer.pos == state.recvBuffer.expected) {
|
||||
state.recvBuffer.state = RECV_STATE_CHECKSUM;
|
||||
}
|
||||
break;
|
||||
case RECV_STATE_CHECKSUM:
|
||||
if (c != state.recvBuffer.crc) {
|
||||
FRSKY_OSD_DEBUG("Checksum error %u != %u. Discarding %u bytes",
|
||||
c, state.recvBuffer.crc, state.recvBuffer.pos);
|
||||
frskyOsdResetReceiveBuffer();
|
||||
break;
|
||||
}
|
||||
state.recvBuffer.state = RECV_STATE_DONE;
|
||||
break;
|
||||
case RECV_STATE_DONE:
|
||||
FRSKY_OSD_DEBUG("Received unexpected byte %u after data", c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool frskyOsdIsResponseAvailable(void)
|
||||
{
|
||||
return state.recvBuffer.state == RECV_STATE_DONE;
|
||||
}
|
||||
|
||||
static bool frskyOsdHandleCommand(osdCommand_e cmd, const void *payload, size_t size)
|
||||
{
|
||||
switch (cmd) {
|
||||
case OSD_CMD_RESPONSE_ERROR:
|
||||
{
|
||||
if (size >= 2) {
|
||||
FRSKY_OSD_ERROR("Received an error %02x in response to command %u", *(ptr + 1), *ptr);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OSD_CMD_INFO:
|
||||
{
|
||||
if (size < sizeof(frskyOsdInfoResponse_t)) {
|
||||
break;
|
||||
}
|
||||
const frskyOsdInfoResponse_t *resp = payload;
|
||||
if (resp->magic[0] != 'A' || resp->magic[1] != 'G' || resp->magic[2] != 'H') {
|
||||
FRSKY_OSD_ERROR("Invalid magic number %x %x %x, expecting AGH",
|
||||
resp->magic[0], resp->magic[1], resp->magic[2]);
|
||||
return false;
|
||||
}
|
||||
state.info.major = resp->versionMajor;
|
||||
state.info.minor = resp->versionMinor;
|
||||
state.info.grid.rows = resp->gridRows;
|
||||
state.info.grid.columns = resp->gridColumns;
|
||||
state.info.viewport.width = resp->pixelWidth;
|
||||
state.info.viewport.height = resp->pixelHeight;
|
||||
if (!state.initialized) {
|
||||
FRSKY_OSD_DEBUG("FrSky OSD initialized. Version %u.%u.%u, pixels=%ux%u, grid=%ux%u",
|
||||
resp->versionMajor, resp->versionMinor, resp->versionPatch,
|
||||
resp->pixelWidth, resp->pixelHeight, resp->gridColumns, resp->gridRows);
|
||||
state.initialized = true;
|
||||
frskyOsdClearScreen();
|
||||
frskyOsdResetDrawingState();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case OSD_CMD_READ_FONT:
|
||||
{
|
||||
if (!state.recvOsdCharacter.chr) {
|
||||
FRSKY_OSD_DEBUG("Got unexpected font character");
|
||||
break;
|
||||
}
|
||||
if (size < sizeof(uint16_t) + FRSKY_OSD_CHAR_TOTAL_BYTES) {
|
||||
FRSKY_OSD_TRACE("Received buffer too small for a character: %u bytes", size);
|
||||
break;
|
||||
}
|
||||
const frskyOsdCharacter_t *chr = payload;
|
||||
state.recvOsdCharacter.addr = chr->addr;
|
||||
FRSKY_OSD_TRACE("Received character %u", chr->addr);
|
||||
// Skip character address
|
||||
memcpy(state.recvOsdCharacter.chr->data, &chr->data, MIN(sizeof(state.recvOsdCharacter.chr->data), (size_t)FRSKY_OSD_CHAR_TOTAL_BYTES));
|
||||
return true;
|
||||
}
|
||||
case OSD_CMD_WRITE_FONT:
|
||||
{
|
||||
// We only wait for the confirmation, we're not interested in the data
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool frskyOsdDispatchResponse(void)
|
||||
{
|
||||
const uint8_t *payload = state.recvBuffer.data;
|
||||
int remaining = (int)state.recvBuffer.pos;
|
||||
bool ok = false;
|
||||
if (remaining > 0) {
|
||||
// OSD sends commands one by one, so we don't need to handle
|
||||
// a frame with multiple ones.
|
||||
uint8_t cmd = *payload;
|
||||
payload++;
|
||||
remaining--;
|
||||
if (frskyOsdHandleCommand(cmd, payload, remaining)) {
|
||||
ok = true;
|
||||
} else {
|
||||
FRSKY_OSD_DEBUG("Discarding buffer due to unhandled command %u (%d bytes remaining)", cmd, remaining);
|
||||
}
|
||||
}
|
||||
frskyOsdResetReceiveBuffer();
|
||||
return ok;
|
||||
}
|
||||
|
||||
static void frskyOsdClearReceiveBuffer(void)
|
||||
{
|
||||
frskyOsdUpdateReceiveBuffer();
|
||||
|
||||
if (frskyOsdIsResponseAvailable()) {
|
||||
frskyOsdDispatchResponse();
|
||||
} else if (state.recvBuffer.pos > 0) {
|
||||
FRSKY_OSD_DEBUG("Discarding receive buffer with %u bytes", state.recvBuffer.pos);
|
||||
frskyOsdResetReceiveBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
static void frskyOsdSendAsyncCommand(uint8_t cmd, const void *data, size_t size)
|
||||
{
|
||||
FRSKY_OSD_TRACE("Send async cmd %u", cmd);
|
||||
frskyOsdSendCommand(cmd, data, size);
|
||||
}
|
||||
|
||||
static bool frskyOsdSendSyncCommand(uint8_t cmd, const void *data, size_t size, timeMs_t timeout)
|
||||
{
|
||||
FRSKY_OSD_TRACE("Send sync cmd %u", cmd);
|
||||
frskyOsdClearReceiveBuffer();
|
||||
frskyOsdSendCommand(cmd, data, size);
|
||||
frskyOsdFlushSendBuffer();
|
||||
timeMs_t end = millis() + timeout;
|
||||
while (millis() < end) {
|
||||
frskyOsdUpdateReceiveBuffer();
|
||||
if (frskyOsdIsResponseAvailable() && frskyOsdDispatchResponse()) {
|
||||
FRSKY_OSD_DEBUG("Got sync response");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
FRSKY_OSD_DEBUG("Sync response failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool frskyOsdShouldRequestInfo(void)
|
||||
{
|
||||
return !frskyOsdIsReady() || millis() > state.nextInfoRequest;
|
||||
}
|
||||
|
||||
static void frskyOsdRequestInfo(void)
|
||||
{
|
||||
timeMs_t now = millis();
|
||||
if (state.info.nextRequest < now) {
|
||||
uint8_t version = FRSKY_OSD_SUPPORTED_API_VERSION;
|
||||
frskyOsdSendAsyncCommand(OSD_CMD_INFO, &version, sizeof(version));
|
||||
frskyOsdFlushSendBuffer();
|
||||
state.info.nextRequest = now + FRSKY_OSD_INFO_INTERVAL_MS;
|
||||
}
|
||||
}
|
||||
|
||||
bool frskyOsdInit(videoSystem_e videoSystem)
|
||||
{
|
||||
UNUSED(videoSystem);
|
||||
FRSKY_OSD_TRACE("frskyOsdInit()");
|
||||
// TODO: Use videoSystem to set the signal standard when
|
||||
// no input is detected.
|
||||
const serialPortConfig_t *portConfig = findSerialPortConfig(FUNCTION_FRSKY_OSD);
|
||||
if (portConfig) {
|
||||
FRSKY_OSD_TRACE("FrSky OSD configured, trying to connect...");
|
||||
portOptions_e portOptions = 0;
|
||||
serialPort_t *port = openSerialPort(portConfig->identifier,
|
||||
FUNCTION_FRSKY_OSD, NULL, NULL, FRSKY_OSD_BAUDRATE,
|
||||
MODE_RXTX, portOptions);
|
||||
|
||||
if (port) {
|
||||
frskyOsdStateReset(port);
|
||||
frskyOsdRequestInfo();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool frskyOsdIsReady(void)
|
||||
{
|
||||
return state.info.minor > 0 || state.info.major > 0;
|
||||
}
|
||||
|
||||
void frskyOsdUpdate(void)
|
||||
{
|
||||
if (!state.port) {
|
||||
return;
|
||||
}
|
||||
frskyOsdUpdateReceiveBuffer();
|
||||
|
||||
if (frskyOsdIsResponseAvailable()) {
|
||||
frskyOsdDispatchResponse();
|
||||
}
|
||||
|
||||
if (frskyOsdShouldRequestInfo()) {
|
||||
frskyOsdRequestInfo();
|
||||
}
|
||||
}
|
||||
|
||||
void frskyOsdBeginTransaction(frskyOsdTransactionOptions_e opts)
|
||||
{
|
||||
if (opts & FRSKY_OSD_TRANSACTION_OPT_PROFILED) {
|
||||
frskyOsdPoint_t p = { .x = 0, .y = 10};
|
||||
frskyOsdSendAsyncCommand(OSD_CMD_TRANSACTION_BEGIN_PROFILED, &p, sizeof(p));
|
||||
if (opts & FRSKY_OSD_TRANSACTION_OPT_RESET_DRAWING) {
|
||||
frskyOsdResetDrawingState();
|
||||
}
|
||||
} else if (opts & FRSKY_OSD_TRANSACTION_OPT_RESET_DRAWING) {
|
||||
frskyOsdSendAsyncCommand(OSD_CMD_TRANSACTION_BEGIN_RESET_DRAWING, NULL, 0);
|
||||
} else {
|
||||
frskyOsdSendAsyncCommand(OSD_CMD_TRANSACTION_BEGIN, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void frskyOsdCommitTransaction(void)
|
||||
{
|
||||
// Check wether the only command in the queue is a transaction begin.
|
||||
// In that, case, discard the send buffer since it will make generate
|
||||
// an empty transaction.
|
||||
if (state.sendBuffer.pos == 1) {
|
||||
if (state.sendBuffer.data[0] == OSD_CMD_TRANSACTION_BEGIN ||
|
||||
state.sendBuffer.data[0] == OSD_CMD_TRANSACTION_BEGIN_RESET_DRAWING) {
|
||||
|
||||
state.sendBuffer.pos = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
frskyOsdSendAsyncCommand(OSD_CMD_TRANSACTION_COMMIT, NULL, 0);
|
||||
frskyOsdFlushSendBuffer();
|
||||
}
|
||||
|
||||
void frskyOsdFlushSendBuffer(void)
|
||||
{
|
||||
if (state.sendBuffer.pos > 0) {
|
||||
frskyOsdProcessCommandU8(NULL, FRSKY_OSD_PREAMBLE_BYTE_0);
|
||||
frskyOsdProcessCommandU8(NULL, FRSKY_OSD_PREAMBLE_BYTE_1);
|
||||
|
||||
uint8_t crc = 0;
|
||||
uint8_t buffer[4];
|
||||
int lengthSize = uvarintEncode(state.sendBuffer.pos, buffer, sizeof(buffer));
|
||||
for (int ii = 0; ii < lengthSize; ii++) {
|
||||
frskyOsdProcessCommandU8(&crc, buffer[ii]);
|
||||
}
|
||||
for (unsigned ii = 0; ii < state.sendBuffer.pos; ii++) {
|
||||
frskyOsdProcessCommandU8(&crc, state.sendBuffer.data[ii]);
|
||||
}
|
||||
frskyOsdProcessCommandU8(NULL, crc);
|
||||
state.sendBuffer.pos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool frskyOsdReadFontCharacter(unsigned char_address, osdCharacter_t *chr)
|
||||
{
|
||||
uint16_t addr = char_address;
|
||||
|
||||
state.recvOsdCharacter.addr = UINT16_MAX;
|
||||
state.recvOsdCharacter.chr = chr;
|
||||
|
||||
// 500ms should be more than enough to receive ~70 bytes @ 115200 bps
|
||||
bool ok = frskyOsdSendSyncCommand(OSD_CMD_READ_FONT, &addr, sizeof(addr), 500);
|
||||
|
||||
state.recvOsdCharacter.chr = NULL;
|
||||
|
||||
if (ok && state.recvOsdCharacter.addr == addr) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool frskyOsdWriteFontCharacter(unsigned char_address, const osdCharacter_t *chr)
|
||||
{
|
||||
frskyOsdCharacter_t c;
|
||||
STATIC_ASSERT(sizeof(*chr) == sizeof(c.data), invalid_character_size);
|
||||
|
||||
memcpy(&c.data, chr, sizeof(c.data));
|
||||
c.addr = char_address;
|
||||
FRSKY_OSD_TRACE("Writing font character %u", char_address);
|
||||
frskyOsdSendSyncCommand(OSD_CMD_WRITE_FONT, &c, sizeof(c), 1000);
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned frskyOsdGetGridRows(void)
|
||||
{
|
||||
return state.info.grid.rows;
|
||||
}
|
||||
|
||||
unsigned frskyOsdGetGridCols(void)
|
||||
{
|
||||
return state.info.grid.columns;
|
||||
}
|
||||
|
||||
unsigned frskyOsdGetPixelWidth(void)
|
||||
{
|
||||
return state.info.viewport.width;
|
||||
}
|
||||
|
||||
unsigned frskyOsdGetPixelHeight(void)
|
||||
{
|
||||
return state.info.viewport.height;
|
||||
}
|
||||
|
||||
static void frskyOsdSendCharInGrid(unsigned x, unsigned y, uint16_t chr)
|
||||
{
|
||||
uint8_t payload[] = {
|
||||
x,
|
||||
y,
|
||||
chr & 0xFF,
|
||||
chr >> 8,
|
||||
0,
|
||||
};
|
||||
frskyOsdSendAsyncCommand(OSD_CMD_DRAW_GRID_CHR, payload, sizeof(payload));
|
||||
}
|
||||
|
||||
static void frskyOsdSendAsyncBlobCommand(uint8_t cmd, const void *header, size_t headerSize, const void *blob, size_t blobSize)
|
||||
{
|
||||
uint8_t payload[128];
|
||||
|
||||
memcpy(payload, header, headerSize);
|
||||
|
||||
int uvarintSize = uvarintEncode(blobSize, &payload[headerSize], sizeof(payload) - headerSize);
|
||||
memcpy(&payload[headerSize + uvarintSize], blob, blobSize);
|
||||
frskyOsdSendAsyncCommand(cmd, payload, headerSize + uvarintSize + blobSize);
|
||||
}
|
||||
|
||||
void frskyOsdDrawStringInGrid(unsigned x, unsigned y, const char *buff)
|
||||
{
|
||||
frskyOsdDrawGridStrHeaderCmd_t cmd;
|
||||
cmd.gx = x;
|
||||
cmd.gy = y;
|
||||
cmd.opts = 0;
|
||||
|
||||
frskyOsdSendAsyncBlobCommand(OSD_CMD_DRAW_GRID_STR, &cmd, sizeof(cmd), buff, strlen(buff) + 1);
|
||||
}
|
||||
|
||||
void frskyOsdDrawCharInGrid(unsigned x, unsigned y, uint16_t chr)
|
||||
{
|
||||
frskyOsdSendCharInGrid(x, y, chr);
|
||||
}
|
||||
|
||||
void frskyOsdClearScreen(void)
|
||||
{
|
||||
if (!frskyOsdIsReady()) {
|
||||
return;
|
||||
}
|
||||
frskyOsdSendAsyncCommand(OSD_CMD_DRAWING_CLEAR_SCREEN, NULL, 0);
|
||||
}
|
||||
|
||||
void frskyOsdSetStrokeColor(frskyOsdColor_e color)
|
||||
{
|
||||
uint8_t c = color;
|
||||
frskyOsdSendAsyncCommand(OSD_CMD_DRAWING_SET_STROKE_COLOR, &c, sizeof(c));
|
||||
}
|
||||
|
||||
void frskyOsdSetFillColor(frskyOsdColor_e color)
|
||||
{
|
||||
uint8_t c = color;
|
||||
frskyOsdSendAsyncCommand(OSD_CMD_DRAWING_SET_FILL_COLOR, &c, sizeof(c));
|
||||
}
|
||||
|
||||
void frskyOsdSetStrokeAndFillColor(frskyOsdColor_e color)
|
||||
{
|
||||
uint8_t c = color;
|
||||
frskyOsdSendAsyncCommand(OSD_CMD_DRAWING_SET_STROKE_AND_FILL_COLOR, &c, sizeof(c));
|
||||
}
|
||||
|
||||
void frskyOsdSetColorInversion(bool inverted)
|
||||
{
|
||||
uint8_t c = inverted ? 1 : 0;
|
||||
frskyOsdSendAsyncCommand(OSD_CMD_DRAWING_SET_COLOR_INVERSION, &c, sizeof(c));
|
||||
}
|
||||
|
||||
void frskyOsdSetPixel(int x, int y, frskyOsdColor_e color)
|
||||
{
|
||||
frskyOsdSetPixel_t sp = {.p = {.x = x, .y = y}, .color = color};
|
||||
frskyOsdSendAsyncCommand(OSD_CMD_DRAWING_SET_PIXEL, &sp, sizeof(sp));
|
||||
}
|
||||
|
||||
void frskyOsdSetPixelToStrokeColor(int x, int y)
|
||||
{
|
||||
frskyOsdPoint_t p = { .x = x, .y = y};
|
||||
frskyOsdSendAsyncCommand(OSD_CMD_DRAWING_SET_PIXEL_TO_STROKE_COLOR, &p, sizeof(p));
|
||||
}
|
||||
|
||||
void frskyOsdSetPixelToFillColor(int x, int y)
|
||||
{
|
||||
frskyOsdPoint_t p = { .x = x, .y = y};
|
||||
frskyOsdSendAsyncCommand(OSD_CMD_DRAWING_SET_PIXEL_TO_FILL_COLOR, &p, sizeof(p));
|
||||
}
|
||||
|
||||
void frskyOsdSetStrokeWidth(unsigned width)
|
||||
{
|
||||
uint8_t w = width;
|
||||
frskyOsdSendAsyncCommand(OSD_CMD_DRAWING_SET_STROKE_WIDTH, &w, sizeof(w));
|
||||
}
|
||||
|
||||
void frskyOsdSetLineOutlineType(frskyOsdLineOutlineType_e outlineType)
|
||||
{
|
||||
uint8_t type = outlineType;
|
||||
frskyOsdSendAsyncCommand(OSD_CMD_DRAWING_SET_LINE_OUTLINE_TYPE, &type, sizeof(type));
|
||||
}
|
||||
|
||||
void frskyOsdSetLineOutlineColor(frskyOsdColor_e outlineColor)
|
||||
{
|
||||
uint8_t color = outlineColor;
|
||||
frskyOsdSendAsyncCommand(OSD_CMD_DRAWING_SET_LINE_OUTLINE_COLOR, &color, sizeof(color));
|
||||
}
|
||||
|
||||
void frskyOsdClipToRect(int x, int y, int w, int h)
|
||||
{
|
||||
frskyOsdRect_t r = { .origin = { .x = x, .y = y}, .size = {.w = w, .h = h}};
|
||||
frskyOsdSendAsyncCommand(OSD_CMD_DRAWING_CLIP_TO_RECT, &r, sizeof(r));
|
||||
}
|
||||
|
||||
void frskyOsdClearRect(int x, int y, int w, int h)
|
||||
{
|
||||
frskyOsdRect_t r = { .origin = { .x = x, .y = y}, .size = {.w = w, .h = h}};
|
||||
frskyOsdSendAsyncCommand(OSD_CMD_DRAWING_CLEAR_RECT, &r, sizeof(r));
|
||||
}
|
||||
|
||||
void frskyOsdResetDrawingState(void)
|
||||
{
|
||||
frskyOsdSendAsyncCommand(OSD_CMD_DRAWING_RESET, NULL, 0);
|
||||
}
|
||||
|
||||
void frskyOsdDrawCharacter(int x, int y, uint16_t chr, uint8_t opts)
|
||||
{
|
||||
frskyOsdDrawCharacterCmd_t dc = { .p = {.x = x, .y = y}, .chr = chr, .opts = opts};
|
||||
frskyOsdSendAsyncCommand(OSD_CMD_DRAWING_DRAW_CHAR, &dc, sizeof(dc));
|
||||
}
|
||||
|
||||
void frskyOsdDrawCharacterMask(int x, int y, uint16_t chr, frskyOsdColor_e color, uint8_t opts)
|
||||
{
|
||||
frskyOsdDrawCharacterMaskCmd_t dc = { .dc = { .p = {.x = x, .y = y}, .chr = chr, .opts = opts}, .maskColor = color};
|
||||
frskyOsdSendAsyncCommand(OSD_CMD_DRAWING_DRAW_CHAR_MASK, &dc, sizeof(dc));
|
||||
}
|
||||
|
||||
void frskyOsdDrawString(int x, int y, const char *s, uint8_t opts)
|
||||
{
|
||||
frskyOsdDrawStrCommandHeaderCmd_t cmd;
|
||||
cmd.p.x = x;
|
||||
cmd.p.y = y;
|
||||
cmd.opts = opts;
|
||||
|
||||
frskyOsdSendAsyncBlobCommand(OSD_CMD_DRAWING_DRAW_STRING, &cmd, sizeof(cmd), s, strlen(s) + 1);
|
||||
}
|
||||
|
||||
void frskyOsdDrawStringMask(int x, int y, const char *s, frskyOsdColor_e color, uint8_t opts)
|
||||
{
|
||||
frskyOsdDrawStrMaskCommandHeaderCmd_t cmd;
|
||||
cmd.p.x = x;
|
||||
cmd.p.y = y;
|
||||
cmd.opts = opts;
|
||||
cmd.maskColor = color;
|
||||
|
||||
frskyOsdSendAsyncBlobCommand(OSD_CMD_DRAWING_DRAW_STRING_MASK, &cmd, sizeof(cmd), s, strlen(s) + 1);
|
||||
}
|
||||
|
||||
void frskyOsdMoveToPoint(int x, int y)
|
||||
{
|
||||
frskyOsdPoint_t p = { .x = x, .y = y};
|
||||
frskyOsdSendAsyncCommand(OSD_CMD_DRAWING_MOVE_TO_POINT, &p, sizeof(p));
|
||||
}
|
||||
|
||||
void frskyOsdStrokeLineToPoint(int x, int y)
|
||||
{
|
||||
frskyOsdPoint_t p = { .x = x, .y = y};
|
||||
frskyOsdSendAsyncCommand(OSD_CMD_DRAWING_STROKE_LINE_TO_POINT, &p, sizeof(p));
|
||||
}
|
||||
|
||||
void frskyOsdStrokeTriangle(int x1, int y1, int x2, int y2, int x3, int y3)
|
||||
{
|
||||
frskyOsdTriangle_t t = {.p1 = {.x = x1, .y = y1}, .p2 = {.x = x2, .y = y2}, .p3 = { .x = x3, .y = y3}};
|
||||
frskyOsdSendAsyncCommand(OSD_CMD_DRAWING_STROKE_TRIANGLE, &t, sizeof(t));
|
||||
}
|
||||
|
||||
void frskyOsdFillTriangle(int x1, int y1, int x2, int y2, int x3, int y3)
|
||||
{
|
||||
frskyOsdTriangle_t t = {.p1 = {.x = x1, .y = y1}, .p2 = {.x = x2, .y = y2}, .p3 = { .x = x3, .y = y3}};
|
||||
frskyOsdSendAsyncCommand(OSD_CMD_DRAWING_FILL_TRIANGLE, &t, sizeof(t));
|
||||
}
|
||||
|
||||
void frskyOsdFillStrokeTriangle(int x1, int y1, int x2, int y2, int x3, int y3)
|
||||
{
|
||||
frskyOsdTriangle_t t = {.p1 = {.x = x1, .y = y1}, .p2 = {.x = x2, .y = y2}, .p3 = { .x = x3, .y = y3}};
|
||||
frskyOsdSendAsyncCommand(OSD_CMD_DRAWING_FILL_STROKE_TRIANGLE, &t, sizeof(t));
|
||||
}
|
||||
|
||||
void frskyOsdStrokeRect(int x, int y, int w, int h)
|
||||
{
|
||||
frskyOsdRect_t r = { .origin = { .x = x, .y = y}, .size = {.w = w, .h = h}};
|
||||
frskyOsdSendAsyncCommand(OSD_CMD_DRAWING_STROKE_RECT, &r, sizeof(r));
|
||||
}
|
||||
|
||||
void frskyOsdFillRect(int x, int y, int w, int h)
|
||||
{
|
||||
frskyOsdRect_t r = { .origin = { .x = x, .y = y}, .size = {.w = w, .h = h}};
|
||||
frskyOsdSendAsyncCommand(OSD_CMD_DRAWING_FILL_RECT, &r, sizeof(r));
|
||||
}
|
||||
|
||||
void frskyOsdFillStrokeRect(int x, int y, int w, int h)
|
||||
{
|
||||
frskyOsdRect_t r = { .origin = { .x = x, .y = y}, .size = {.w = w, .h = h}};
|
||||
frskyOsdSendAsyncCommand(OSD_CMD_DRAWING_FILL_STROKE_RECT, &r, sizeof(r));
|
||||
}
|
||||
|
||||
void frskyOsdStrokeEllipseInRect(int x, int y, int w, int h)
|
||||
{
|
||||
frskyOsdRect_t r = { .origin = { .x = x, .y = y}, .size = {.w = w, .h = h}};
|
||||
frskyOsdSendAsyncCommand(OSD_CMD_DRAWING_STROKE_ELLIPSE_IN_RECT, &r, sizeof(r));
|
||||
}
|
||||
|
||||
void frskyOsdFillEllipseInRect(int x, int y, int w, int h)
|
||||
{
|
||||
frskyOsdRect_t r = { .origin = { .x = x, .y = y}, .size = {.w = w, .h = h}};
|
||||
frskyOsdSendAsyncCommand(OSD_CMD_DRAWING_FILL_ELLIPSE_IN_RECT, &r, sizeof(r));
|
||||
}
|
||||
|
||||
void frskyOsdFillStrokeEllipseInRect(int x, int y, int w, int h)
|
||||
{
|
||||
frskyOsdRect_t r = { .origin = { .x = x, .y = y}, .size = {.w = w, .h = h}};
|
||||
frskyOsdSendAsyncCommand(OSD_CMD_DRAWING_FILL_STROKE_ELLIPSE_IN_RECT, &r, sizeof(r));
|
||||
}
|
||||
|
||||
void frskyOsdCtmReset(void)
|
||||
{
|
||||
frskyOsdSendAsyncCommand(OSD_CMD_CTM_RESET, NULL, 0);
|
||||
}
|
||||
|
||||
void frskyOsdCtmSet(float m11, float m12, float m21, float m22, float m31, float m32)
|
||||
{
|
||||
float values[] = {
|
||||
m11, m12,
|
||||
m21, m22,
|
||||
m31, m32,
|
||||
};
|
||||
frskyOsdSendAsyncCommand(OSD_CMD_CTM_SET, values, sizeof(values));
|
||||
}
|
||||
|
||||
void frskyOsdCtmTranslate(float tx, float ty)
|
||||
{
|
||||
float values[] = {
|
||||
tx,
|
||||
ty,
|
||||
};
|
||||
frskyOsdSendAsyncCommand(OSD_CMD_CTM_TRANSLATE, values, sizeof(values));
|
||||
}
|
||||
|
||||
void frskyOsdCtmScale(float sx, float sy)
|
||||
{
|
||||
float values[] = {
|
||||
sx,
|
||||
sy,
|
||||
};
|
||||
frskyOsdSendAsyncCommand(OSD_CMD_CTM_SCALE, values, sizeof(values));
|
||||
}
|
||||
|
||||
void frskyOsdCtmRotate(float r)
|
||||
{
|
||||
frskyOsdSendAsyncCommand(OSD_CMD_CTM_ROTATE, &r, sizeof(r));
|
||||
}
|
||||
|
||||
void frskyOsdContextPush(void)
|
||||
{
|
||||
frskyOsdSendAsyncCommand(OSD_CMD_CONTEXT_PUSH, NULL, 0);
|
||||
}
|
||||
|
||||
void frskyOsdContextPop(void)
|
||||
{
|
||||
frskyOsdSendAsyncCommand(OSD_CMD_CONTEXT_POP, NULL, 0);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,86 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "drivers/display.h"
|
||||
#include "drivers/osd.h"
|
||||
|
||||
typedef enum {
|
||||
FRSKY_OSD_TRANSACTION_OPT_PROFILED = 1 << 0,
|
||||
FRSKY_OSD_TRANSACTION_OPT_RESET_DRAWING = 1 << 1,
|
||||
} frskyOsdTransactionOptions_e;
|
||||
|
||||
typedef enum {
|
||||
FRSKY_OSD_COLOR_BLACK = 0,
|
||||
FRSKY_OSD_COLOR_TRANSPARENT = 1,
|
||||
FRSKY_OSD_COLOR_WHITE = 2,
|
||||
FRSKY_OSD_COLOR_GRAY = 3,
|
||||
} frskyOsdColor_e;
|
||||
|
||||
typedef enum {
|
||||
FRSKY_OSD_OUTLINE_TYPE_NONE = 0,
|
||||
FRSKY_OSD_OUTLINE_TYPE_TOP = 1 << 0,
|
||||
FRSKY_OSD_OUTLINE_TYPE_RIGHT = 1 << 1,
|
||||
FRSKY_OSD_OUTLINE_TYPE_BOTTOM = 1 << 2,
|
||||
FRSKY_OSD_OUTLINE_TYPE_LEFT = 1 << 3,
|
||||
} frskyOsdLineOutlineType_e;
|
||||
|
||||
bool frskyOsdInit(videoSystem_e videoSystem);
|
||||
bool frskyOsdIsReady(void);
|
||||
void frskyOsdUpdate(void);
|
||||
void frskyOsdBeginTransaction(frskyOsdTransactionOptions_e opts);
|
||||
void frskyOsdCommitTransaction(void);
|
||||
void frskyOsdFlushSendBuffer(void);
|
||||
bool frskyOsdReadFontCharacter(unsigned char_address, osdCharacter_t *chr);
|
||||
bool frskyOsdWriteFontCharacter(unsigned char_address, const osdCharacter_t *chr);
|
||||
|
||||
unsigned frskyOsdGetGridRows(void);
|
||||
unsigned frskyOsdGetGridCols(void);
|
||||
|
||||
unsigned frskyOsdGetPixelWidth(void);
|
||||
unsigned frskyOsdGetPixelHeight(void);
|
||||
|
||||
void frskyOsdDrawStringInGrid(unsigned x, unsigned y, const char *buff);
|
||||
void frskyOsdDrawCharInGrid(unsigned x, unsigned y, uint16_t chr);
|
||||
bool frskyOsdReadCharInGrid(unsigned x, unsigned y, uint16_t *c);
|
||||
void frskyOsdClearScreen(void);
|
||||
|
||||
void frskyOsdSetStrokeColor(frskyOsdColor_e color);
|
||||
void frskyOsdSetFillColor(frskyOsdColor_e color);
|
||||
void frskyOsdSetStrokeAndFillColor(frskyOsdColor_e color);
|
||||
void frskyOsdSetColorInversion(bool inverted);
|
||||
void frskyOsdSetPixel(int x, int y, frskyOsdColor_e color);
|
||||
void frskyOsdSetPixelToStrokeColor(int x, int y);
|
||||
void frskyOsdSetPixelToFillColor(int x, int y);
|
||||
void frskyOsdSetStrokeWidth(unsigned width);
|
||||
void frskyOsdSetLineOutlineType(frskyOsdLineOutlineType_e outlineType);
|
||||
void frskyOsdSetLineOutlineColor(frskyOsdColor_e outlineColor);
|
||||
|
||||
void frskyOsdClipToRect(int x, int y, int w, int h);
|
||||
void frskyOsdClearRect(int x, int y, int w, int h);
|
||||
void frskyOsdResetDrawingState(void);
|
||||
void frskyOsdDrawCharacter(int x, int y, uint16_t chr, uint8_t opts);
|
||||
void frskyOsdDrawCharacterMask(int x, int y, uint16_t chr, frskyOsdColor_e color, uint8_t opts);
|
||||
void frskyOsdDrawString(int x, int y, const char *s, uint8_t opts);
|
||||
void frskyOsdDrawStringMask(int x, int y, const char *s, frskyOsdColor_e color, uint8_t opts);
|
||||
void frskyOsdMoveToPoint(int x, int y);
|
||||
void frskyOsdStrokeLineToPoint(int x, int y);
|
||||
void frskyOsdStrokeTriangle(int x1, int y1, int x2, int y2, int x3, int y3);
|
||||
void frskyOsdFillTriangle(int x1, int y1, int x2, int y2, int x3, int y3);
|
||||
void frskyOsdFillStrokeTriangle(int x1, int y1, int x2, int y2, int x3, int y3);
|
||||
void frskyOsdStrokeRect(int x, int y, int w, int h);
|
||||
void frskyOsdFillRect(int x, int y, int w, int h);
|
||||
void frskyOsdFillStrokeRect(int x, int y, int w, int h);
|
||||
void frskyOsdStrokeEllipseInRect(int x, int y, int w, int h);
|
||||
void frskyOsdFillEllipseInRect(int x, int y, int w, int h);
|
||||
void frskyOsdFillStrokeEllipseInRect(int x, int y, int w, int h);
|
||||
|
||||
void frskyOsdCtmReset(void);
|
||||
void frskyOsdCtmSet(float m11, float m12, float m21, float m22, float m31, float m32);
|
||||
void frskyOsdCtmTranslate(float tx, float ty);
|
||||
void frskyOsdCtmScale(float sx, float sy);
|
||||
void frskyOsdCtmRotate(float r);
|
||||
|
||||
void frskyOsdContextPush(void);
|
||||
void frskyOsdContextPop(void);
|
|
@ -119,7 +119,7 @@ serialPortConfig_t *serialFindPortConfigurationMutable(serialPortIdentifier_e id
|
|||
return NULL;
|
||||
}
|
||||
|
||||
PG_REGISTER_WITH_RESET_FN(serialConfig_t, serialConfig, PG_SERIAL_CONFIG, 0);
|
||||
PG_REGISTER_WITH_RESET_FN(serialConfig_t, serialConfig, PG_SERIAL_CONFIG, 1);
|
||||
|
||||
void pgResetFn_serialConfig(serialConfig_t *serialConfig)
|
||||
{
|
||||
|
|
|
@ -49,6 +49,7 @@ typedef enum {
|
|||
FUNCTION_VTX_TRAMP = (1 << 13), // 8192
|
||||
FUNCTION_RCDEVICE = (1 << 14), // 16384
|
||||
FUNCTION_LIDAR_TF = (1 << 15), // 32768
|
||||
FUNCTION_FRSKY_OSD = (1 << 16), // 65536
|
||||
} serialPortFunction_e;
|
||||
|
||||
#define TELEMETRY_SHAREABLE_PORT_FUNCTIONS_MASK (FUNCTION_TELEMETRY_FRSKY_HUB | FUNCTION_TELEMETRY_LTM | FUNCTION_TELEMETRY_MAVLINK)
|
||||
|
@ -113,7 +114,7 @@ serialPort_t *findSharedSerialPort(uint16_t functionMask, serialPortFunction_e s
|
|||
// configuration
|
||||
//
|
||||
typedef struct serialPortConfig_s {
|
||||
uint16_t functionMask;
|
||||
uint32_t functionMask;
|
||||
serialPortIdentifier_e identifier;
|
||||
uint8_t msp_baudrateIndex;
|
||||
uint8_t gps_baudrateIndex;
|
||||
|
|
|
@ -57,6 +57,7 @@
|
|||
#include "drivers/io.h"
|
||||
#include "drivers/max7456.h"
|
||||
#include "drivers/motor.h"
|
||||
#include "drivers/osd.h"
|
||||
#include "drivers/pwm_output.h"
|
||||
#include "drivers/sdcard.h"
|
||||
#include "drivers/serial.h"
|
||||
|
@ -3294,22 +3295,42 @@ static mspResult_e mspCommonProcessInCommand(mspDescriptor_t srcDesc, uint8_t cm
|
|||
break;
|
||||
|
||||
case MSP_OSD_CHAR_WRITE:
|
||||
#ifdef USE_MAX7456
|
||||
{
|
||||
uint8_t font_data[64];
|
||||
const uint8_t addr = sbufReadU8(src);
|
||||
for (int i = 0; i < 54; i++) {
|
||||
font_data[i] = sbufReadU8(src);
|
||||
osdCharacter_t chr;
|
||||
size_t osdCharacterBytes;
|
||||
uint16_t addr;
|
||||
if (dataSize >= OSD_CHAR_VISIBLE_BYTES + 2) {
|
||||
if (dataSize >= OSD_CHAR_BYTES + 2) {
|
||||
// 16 bit address, full char with metadata
|
||||
addr = sbufReadU16(src);
|
||||
osdCharacterBytes = OSD_CHAR_BYTES;
|
||||
} else if (dataSize >= OSD_CHAR_BYTES + 1) {
|
||||
// 8 bit address, full char with metadata
|
||||
addr = sbufReadU8(src);
|
||||
osdCharacterBytes = OSD_CHAR_BYTES;
|
||||
} else {
|
||||
// 16 bit character address, only visible char bytes
|
||||
addr = sbufReadU16(src);
|
||||
osdCharacterBytes = OSD_CHAR_VISIBLE_BYTES;
|
||||
}
|
||||
} else {
|
||||
// 8 bit character address, only visible char bytes
|
||||
addr = sbufReadU8(src);
|
||||
osdCharacterBytes = OSD_CHAR_VISIBLE_BYTES;
|
||||
}
|
||||
// !!TODO - replace this with a device independent implementation
|
||||
if (!max7456WriteNvm(addr, font_data)) {
|
||||
for (unsigned ii = 0; ii < MIN(osdCharacterBytes, sizeof(chr.data)); ii++) {
|
||||
chr.data[ii] = sbufReadU8(src);
|
||||
}
|
||||
displayPort_t *osdDisplayPort = osdGetDisplayPort();
|
||||
if (!osdDisplayPort) {
|
||||
return MSP_RESULT_ERROR;
|
||||
}
|
||||
|
||||
if (!displayWriteFontCharacter(osdDisplayPort, addr, &chr)) {
|
||||
return MSP_RESULT_ERROR;
|
||||
}
|
||||
}
|
||||
break;
|
||||
#else
|
||||
return MSP_RESULT_ERROR;
|
||||
#endif
|
||||
#endif // OSD
|
||||
|
||||
default:
|
||||
|
|
|
@ -54,7 +54,7 @@
|
|||
|
||||
#include "drivers/display.h"
|
||||
#include "drivers/flash.h"
|
||||
#include "drivers/max7456_symbols.h"
|
||||
#include "drivers/osd_symbols.h"
|
||||
#include "drivers/sdcard.h"
|
||||
#include "drivers/time.h"
|
||||
|
||||
|
@ -126,6 +126,7 @@ static uint8_t armState;
|
|||
static uint8_t osdProfile = 1;
|
||||
#endif
|
||||
static displayPort_t *osdDisplayPort;
|
||||
static bool osdIsReady;
|
||||
|
||||
static bool suppressStatsDisplay = false;
|
||||
static uint8_t osdStatsRowCount = 0;
|
||||
|
@ -136,6 +137,8 @@ static bool backgroundLayerSupported = false;
|
|||
escSensorData_t *osdEscDataCombined;
|
||||
#endif
|
||||
|
||||
STATIC_ASSERT(OSD_POS_MAX == OSD_POS(31,31), OSD_POS_MAX_incorrect);
|
||||
|
||||
PG_REGISTER_WITH_RESET_FN(osdConfig_t, osdConfig, PG_OSD_CONFIG, 6);
|
||||
|
||||
// Controls the display order of the OSD post-flight statistics.
|
||||
|
@ -354,26 +357,16 @@ static void osdDrawLogo(int x, int y)
|
|||
}
|
||||
}
|
||||
|
||||
void osdInit(displayPort_t *osdDisplayPortToUse)
|
||||
static void osdCompleteInitialization(void)
|
||||
{
|
||||
if (!osdDisplayPortToUse) {
|
||||
return;
|
||||
}
|
||||
|
||||
STATIC_ASSERT(OSD_POS_MAX == OSD_POS(31,31), OSD_POS_MAX_incorrect);
|
||||
|
||||
osdDisplayPort = osdDisplayPortToUse;
|
||||
#ifdef USE_CMS
|
||||
cmsDisplayPortRegister(osdDisplayPort);
|
||||
#endif
|
||||
|
||||
backgroundLayerSupported = displayLayerSupported(osdDisplayPort, DISPLAYPORT_LAYER_BACKGROUND);
|
||||
displayLayerSelect(osdDisplayPort, DISPLAYPORT_LAYER_FOREGROUND);
|
||||
|
||||
armState = ARMING_FLAG(ARMED);
|
||||
|
||||
osdResetAlarms();
|
||||
|
||||
backgroundLayerSupported = displayLayerSupported(osdDisplayPort, DISPLAYPORT_LAYER_BACKGROUND);
|
||||
displayLayerSelect(osdDisplayPort, DISPLAYPORT_LAYER_FOREGROUND);
|
||||
|
||||
displayBeginTransaction(osdDisplayPort, DISPLAY_TRANSACTION_OPT_RESET_DRAWING);
|
||||
displayClearScreen(osdDisplayPort);
|
||||
|
||||
osdDrawLogo(3, 1);
|
||||
|
@ -394,8 +387,6 @@ void osdInit(displayPort_t *osdDisplayPortToUse)
|
|||
}
|
||||
#endif
|
||||
|
||||
displayResync(osdDisplayPort);
|
||||
|
||||
resumeRefreshAt = micros() + (4 * REFRESH_1S);
|
||||
#ifdef USE_OSD_PROFILES
|
||||
setOsdProfile(osdConfig()->osdProfileIndex);
|
||||
|
@ -403,6 +394,25 @@ void osdInit(displayPort_t *osdDisplayPortToUse)
|
|||
|
||||
osdElementsInit(backgroundLayerSupported);
|
||||
osdAnalyzeActiveElements();
|
||||
displayCommitTransaction(osdDisplayPort);
|
||||
|
||||
osdIsReady = true;
|
||||
}
|
||||
|
||||
void osdInit(displayPort_t *osdDisplayPortToUse)
|
||||
{
|
||||
if (!osdDisplayPortToUse) {
|
||||
return;
|
||||
}
|
||||
|
||||
osdDisplayPort = osdDisplayPortToUse;
|
||||
#ifdef USE_CMS
|
||||
cmsDisplayPortRegister(osdDisplayPort);
|
||||
#endif
|
||||
|
||||
if (displayIsReady(osdDisplayPort)) {
|
||||
osdCompleteInitialization();
|
||||
}
|
||||
}
|
||||
|
||||
bool osdInitialized(void)
|
||||
|
@ -838,6 +848,14 @@ STATIC_UNIT_TESTED void osdRefresh(timeUs_t currentTimeUs)
|
|||
static bool osdStatsVisible = false;
|
||||
static timeUs_t osdStatsRefreshTimeUs;
|
||||
|
||||
if (!osdIsReady) {
|
||||
if (!displayIsReady(osdDisplayPort)) {
|
||||
displayResync(osdDisplayPort);
|
||||
return;
|
||||
}
|
||||
osdCompleteInitialization();
|
||||
}
|
||||
|
||||
// detect arm/disarm
|
||||
if (armState != ARMING_FLAG(ARMED)) {
|
||||
if (ARMING_FLAG(ARMED)) {
|
||||
|
@ -887,6 +905,8 @@ STATIC_UNIT_TESTED void osdRefresh(timeUs_t currentTimeUs)
|
|||
}
|
||||
lastTimeUs = currentTimeUs;
|
||||
|
||||
displayBeginTransaction(osdDisplayPort, DISPLAY_TRANSACTION_OPT_RESET_DRAWING);
|
||||
|
||||
if (resumeRefreshAt) {
|
||||
if (cmp32(currentTimeUs, resumeRefreshAt) < 0) {
|
||||
// in timeout period, check sticks for activity to resume display.
|
||||
|
@ -929,6 +949,7 @@ STATIC_UNIT_TESTED void osdRefresh(timeUs_t currentTimeUs)
|
|||
osdDrawElements(currentTimeUs);
|
||||
displayHeartbeat(osdDisplayPort);
|
||||
}
|
||||
displayCommitTransaction(osdDisplayPort);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1012,4 +1033,9 @@ bool osdNeedsAccelerometer(void)
|
|||
}
|
||||
#endif // USE_ACC
|
||||
|
||||
displayPort_t *osdGetDisplayPort(void)
|
||||
{
|
||||
return osdDisplayPort;
|
||||
}
|
||||
|
||||
#endif // USE_OSD
|
||||
|
|
|
@ -227,6 +227,7 @@ typedef enum {
|
|||
OSD_DISPLAYPORT_DEVICE_AUTO,
|
||||
OSD_DISPLAYPORT_DEVICE_MAX7456,
|
||||
OSD_DISPLAYPORT_DEVICE_MSP,
|
||||
OSD_DISPLAYPORT_DEVICE_FRSKYOSD,
|
||||
} osdDisplayPortDevice_e;
|
||||
|
||||
// Make sure the number of warnings do not exceed the available 32bit storage
|
||||
|
@ -319,3 +320,4 @@ bool osdElementVisible(uint16_t value);
|
|||
bool osdGetVisualBeeperState(void);
|
||||
statistic_t *osdGetStats(void);
|
||||
bool osdNeedsAccelerometer(void);
|
||||
struct displayPort_s *osdGetDisplayPort(void);
|
||||
|
|
|
@ -85,8 +85,8 @@
|
|||
#include "config/feature.h"
|
||||
|
||||
#include "drivers/display.h"
|
||||
#include "drivers/max7456_symbols.h"
|
||||
#include "drivers/dshot.h"
|
||||
#include "drivers/osd_symbols.h"
|
||||
#include "drivers/time.h"
|
||||
#include "drivers/vtx_common.h"
|
||||
|
||||
|
|
|
@ -24,12 +24,6 @@
|
|||
|
||||
// Video Character Display parameters
|
||||
|
||||
enum VIDEO_SYSTEMS {
|
||||
VIDEO_SYSTEM_AUTO = 0,
|
||||
VIDEO_SYSTEM_PAL,
|
||||
VIDEO_SYSTEM_NTSC
|
||||
};
|
||||
|
||||
typedef struct vcdProfile_s {
|
||||
uint8_t video_system;
|
||||
int8_t h_offset;
|
||||
|
|
|
@ -318,7 +318,9 @@
|
|||
|
||||
#if (FLASH_SIZE > 256)
|
||||
#define USE_AIRMODE_LPF
|
||||
#define USE_CANVAS
|
||||
#define USE_DASHBOARD
|
||||
#define USE_FRSKYOSD
|
||||
#define USE_GPS
|
||||
#define USE_GPS_NMEA
|
||||
#define USE_GPS_UBLOX
|
||||
|
|
|
@ -439,9 +439,11 @@ COMMON_FLAGS = \
|
|||
ifeq ($(shell $(CC) -v 2>&1 | grep -q "clang version" && echo "clang"),clang)
|
||||
COMMON_FLAGS += -fblocks
|
||||
ifndef CYGWIN
|
||||
ifndef MACOSX
|
||||
LDFLAGS += -lBlocksRuntime
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
USE_PTHREAD = YES
|
||||
USE_COVERAGE = YES
|
||||
|
|
|
@ -33,7 +33,7 @@ extern "C" {
|
|||
#include "common/printf.h"
|
||||
#include "common/streambuf.h"
|
||||
|
||||
#include "drivers/max7456_symbols.h"
|
||||
#include "drivers/osd_symbols.h"
|
||||
#include "drivers/persistent.h"
|
||||
#include "drivers/serial.h"
|
||||
#include "drivers/system.h"
|
||||
|
|
|
@ -36,7 +36,7 @@ extern "C" {
|
|||
|
||||
#include "common/time.h"
|
||||
|
||||
#include "drivers/max7456_symbols.h"
|
||||
#include "drivers/osd_symbols.h"
|
||||
#include "drivers/persistent.h"
|
||||
#include "drivers/serial.h"
|
||||
|
||||
|
|
Loading…
Reference in New Issue