2 * This file is part of Cleanflight.
4 * Cleanflight is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * Cleanflight is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with Cleanflight. If not, see <http://www.gnu.org/licenses/>.
23 #if defined(USE_OSD) && defined(USE_FRSKYOSD)
25 #include "common/maths.h"
26 #include "common/utils.h"
28 #include "drivers/display.h"
29 #include "drivers/display_canvas.h"
30 #include "drivers/display_font_metadata.h"
31 #include "drivers/display_widgets.h"
33 #include "io/displayport_frsky_osd.h"
34 #include "io/frsky_osd.h"
36 static displayPort_t frskyOSDDisplayPort
;
38 static int grab(displayPort_t
*displayPort
)
44 static int release(displayPort_t
*displayPort
)
50 static int clearScreen(displayPort_t
*displayPort
)
53 frskyOSDClearScreen();
57 static int drawScreen(displayPort_t
*displayPort
)
65 static int screenSize(const displayPort_t
*displayPort
)
68 return frskyOSDGetGridRows() * frskyOSDGetGridCols();
71 static int writeString(displayPort_t
*displayPort
, uint8_t x
, uint8_t y
, const char *s
, textAttributes_t attr
)
75 frskyOSDDrawStringInGrid(x
, y
, s
, attr
);
79 static int writeChar(displayPort_t
*displayPort
, uint8_t x
, uint8_t y
, uint16_t c
, textAttributes_t attr
)
83 frskyOSDDrawCharInGrid(x
, y
, c
, attr
);
87 static bool readChar(displayPort_t
*displayPort
, uint8_t x
, uint8_t y
, uint16_t *c
, textAttributes_t
*attr
)
91 return frskyOSDReadCharInGrid(x
, y
, c
, attr
);
94 static bool isTransferInProgress(const displayPort_t
*displayPort
)
100 static void updateGridSize(displayPort_t
*displayPort
)
102 displayPort
->rows
= frskyOSDGetGridRows();
103 displayPort
->cols
= frskyOSDGetGridCols();
106 static void resync(displayPort_t
*displayPort
)
109 // TODO(agh): Do we need to flush the screen here?
110 // MAX7456's driver does a full redraw in resync(),
111 // so some callers might be expecting that.
112 updateGridSize(displayPort
);
115 static int heartbeat(displayPort_t
*displayPort
)
121 static uint32_t txBytesFree(const displayPort_t
*displayPort
)
127 static textAttributes_t
supportedTextAttributes(const displayPort_t
*displayPort
)
131 textAttributes_t attr
= TEXT_ATTRIBUTES_NONE
;
132 TEXT_ATTRIBUTES_ADD_INVERTED(attr
);
133 TEXT_ATTRIBUTES_ADD_SOLID_BG(attr
);
137 static bool getFontMetadata(displayFontMetadata_t
*metadata
, const displayPort_t
*displayPort
)
143 metadata
->charCount
= 512;
144 return frskyOSDReadFontCharacter(FONT_METADATA_CHR_INDEX
, &chr
) &&
145 displayFontMetadataUpdateFromCharacter(metadata
, &chr
);
149 static int writeFontCharacter(displayPort_t
*instance
, uint16_t addr
, const osdCharacter_t
*chr
)
153 frskyOSDWriteFontCharacter(addr
, chr
);
157 static bool isReady(displayPort_t
*instance
)
159 if (frskyOSDIsReady()) {
160 updateGridSize(instance
);
166 static void beginTransaction(displayPort_t
*instance
, displayTransactionOption_e opts
)
170 frskyOSDTransactionOptions_e frskyOpts
= 0;
171 if (opts
& DISPLAY_TRANSACTION_OPT_PROFILED
) {
172 frskyOpts
|= FRSKY_OSD_TRANSACTION_OPT_PROFILED
;
174 if (opts
& DISPLAY_TRANSACTION_OPT_RESET_DRAWING
) {
175 frskyOpts
|= FRSKY_OSD_TRANSACTION_OPT_RESET_DRAWING
;
178 frskyOSDBeginTransaction(frskyOpts
);
181 static void commitTransaction(displayPort_t
*instance
)
185 frskyOSDCommitTransaction();
188 static frskyOSDColor_e
frskyOSDGetColor(displayCanvasColor_e color
)
192 case DISPLAY_CANVAS_COLOR_BLACK
:
193 return FRSKY_OSD_COLOR_BLACK
;
194 case DISPLAY_CANVAS_COLOR_TRANSPARENT
:
195 return FRSKY_OSD_COLOR_TRANSPARENT
;
196 case DISPLAY_CANVAS_COLOR_WHITE
:
197 return FRSKY_OSD_COLOR_WHITE
;
198 case DISPLAY_CANVAS_COLOR_GRAY
:
199 return FRSKY_OSD_COLOR_GRAY
;
201 return FRSKY_OSD_COLOR_BLACK
;
204 static void setStrokeColor(displayCanvas_t
*displayCanvas
, displayCanvasColor_e color
)
206 UNUSED(displayCanvas
);
208 frskyOSDSetStrokeColor(frskyOSDGetColor(color
));
211 static void setFillColor(displayCanvas_t
*displayCanvas
, displayCanvasColor_e color
)
213 UNUSED(displayCanvas
);
215 frskyOSDSetFillColor(frskyOSDGetColor(color
));
218 static void setStrokeAndFillColor(displayCanvas_t
*displayCanvas
, displayCanvasColor_e color
)
220 UNUSED(displayCanvas
);
222 frskyOSDSetStrokeAndFillColor(frskyOSDGetColor(color
));
225 static void setColorInversion(displayCanvas_t
*displayCanvas
, bool inverted
)
227 UNUSED(displayCanvas
);
229 frskyOSDSetColorInversion(inverted
);
232 static void setPixel(displayCanvas_t
*displayCanvas
, int x
, int y
, displayCanvasColor_e color
)
234 UNUSED(displayCanvas
);
236 frskyOSDSetPixel(x
, y
, frskyOSDGetColor(color
));
239 static void setPixelToStrokeColor(displayCanvas_t
*displayCanvas
, int x
, int y
)
241 UNUSED(displayCanvas
);
243 frskyOSDSetPixelToStrokeColor(x
, y
);
246 static void setPixelToFillColor(displayCanvas_t
*displayCanvas
, int x
, int y
)
248 UNUSED(displayCanvas
);
250 frskyOSDSetPixelToFillColor(x
, y
);
253 static void setStrokeWidth(displayCanvas_t
*displayCanvas
, unsigned w
)
255 UNUSED(displayCanvas
);
257 frskyOSDSetStrokeWidth(w
);
260 static void setLineOutlineType(displayCanvas_t
*displayCanvas
, displayCanvasOutlineType_e outlineType
)
262 UNUSED(displayCanvas
);
264 frskyOSDSetLineOutlineType((frskyOSDLineOutlineType_e
)outlineType
);
267 static void setLineOutlineColor(displayCanvas_t
*displayCanvas
, displayCanvasColor_e outlineColor
)
269 UNUSED(displayCanvas
);
271 frskyOSDSetLineOutlineColor((frskyOSDColor_e
)outlineColor
);
274 static void clipToRect(displayCanvas_t
*displayCanvas
, int x
, int y
, int w
, int h
)
276 UNUSED(displayCanvas
);
278 frskyOSDClipToRect(x
, y
, w
, h
);
281 static void clearRect(displayCanvas_t
*displayCanvas
, int x
, int y
, int w
, int h
)
283 UNUSED(displayCanvas
);
285 frskyOSDClearRect(x
, y
, w
, h
);
288 static void resetDrawingState(displayCanvas_t
*displayCanvas
)
290 UNUSED(displayCanvas
);
292 frskyOSDResetDrawingState();
295 static void drawCharacter(displayCanvas_t
*displayCanvas
, int x
, int y
, uint16_t chr
, displayCanvasBitmapOption_t opts
)
297 UNUSED(displayCanvas
);
299 frskyOSDDrawCharacter(x
, y
, chr
, opts
);
302 static void drawCharacterMask(displayCanvas_t
*displayCanvas
, int x
, int y
, uint16_t chr
, displayCanvasColor_e color
, displayCanvasBitmapOption_t opts
)
304 UNUSED(displayCanvas
);
306 frskyOSDDrawCharacterMask(x
, y
, chr
, frskyOSDGetColor(color
), opts
);
309 static void drawString(displayCanvas_t
*displayCanvas
, int x
, int y
, const char *s
, displayCanvasBitmapOption_t opts
)
311 UNUSED(displayCanvas
);
313 frskyOSDDrawString(x
, y
, s
, opts
);
316 static void drawStringMask(displayCanvas_t
*displayCanvas
, int x
, int y
, const char *s
, displayCanvasColor_e color
, displayCanvasBitmapOption_t opts
)
318 UNUSED(displayCanvas
);
320 frskyOSDDrawStringMask(x
, y
, s
, frskyOSDGetColor(color
), opts
);
323 static void moveToPoint(displayCanvas_t
*displayCanvas
, int x
, int y
)
325 UNUSED(displayCanvas
);
327 frskyOSDMoveToPoint(x
, y
);
330 static void strokeLineToPoint(displayCanvas_t
*displayCanvas
, int x
, int y
)
332 UNUSED(displayCanvas
);
334 frskyOSDStrokeLineToPoint(x
, y
);
337 static void strokeTriangle(displayCanvas_t
*displayCanvas
, int x1
, int y1
, int x2
, int y2
, int x3
, int y3
)
339 UNUSED(displayCanvas
);
341 frskyOSDStrokeTriangle(x1
, y1
, x2
, y2
, x3
, y3
);
344 static void fillTriangle(displayCanvas_t
*displayCanvas
, int x1
, int y1
, int x2
, int y2
, int x3
, int y3
)
346 UNUSED(displayCanvas
);
348 frskyOSDFillTriangle(x1
, y1
, x2
, y2
, x3
, y3
);
351 static void fillStrokeTriangle(displayCanvas_t
*displayCanvas
, int x1
, int y1
, int x2
, int y2
, int x3
, int y3
)
353 UNUSED(displayCanvas
);
355 frskyOSDFillStrokeTriangle(x1
, y1
, x2
, y2
, x3
, y3
);
358 static void strokeRect(displayCanvas_t
*displayCanvas
, int x
, int y
, int w
, int h
)
360 UNUSED(displayCanvas
);
362 frskyOSDStrokeRect(x
, y
, w
, h
);
365 static void fillRect(displayCanvas_t
*displayCanvas
, int x
, int y
, int w
, int h
)
367 UNUSED(displayCanvas
);
369 frskyOSDFillRect(x
, y
, w
, h
);
372 static void fillStrokeRect(displayCanvas_t
*displayCanvas
, int x
, int y
, int w
, int h
)
374 UNUSED(displayCanvas
);
376 frskyOSDFillStrokeRect(x
, y
, w
, h
);
379 static void strokeEllipseInRect(displayCanvas_t
*displayCanvas
, int x
, int y
, int w
, int h
)
381 UNUSED(displayCanvas
);
383 frskyOSDStrokeEllipseInRect(x
, y
, w
, h
);
386 static void fillEllipseInRect(displayCanvas_t
*displayCanvas
, int x
, int y
, int w
, int h
)
388 UNUSED(displayCanvas
);
390 frskyOSDFillEllipseInRect(x
, y
, w
, h
);
393 static void fillStrokeEllipseInRect(displayCanvas_t
*displayCanvas
, int x
, int y
, int w
, int h
)
395 UNUSED(displayCanvas
);
397 frskyOSDFillStrokeEllipseInRect(x
, y
, w
, h
);
400 static void ctmReset(displayCanvas_t
*displayCanvas
)
402 UNUSED(displayCanvas
);
407 static void ctmSet(displayCanvas_t
*displayCanvas
, float m11
, float m12
, float m21
, float m22
, float m31
, float m32
)
409 UNUSED(displayCanvas
);
411 frskyOSDCtmSet(m11
, m12
, m21
, m22
, m31
, m32
);
414 static void ctmTranslate(displayCanvas_t
*displayCanvas
, float tx
, float ty
)
416 UNUSED(displayCanvas
);
418 frskyOSDCtmTranslate(tx
, ty
);
421 static void ctmScale(displayCanvas_t
*displayCanvas
, float sx
, float sy
)
423 UNUSED(displayCanvas
);
425 frskyOSDCtmScale(sx
, sy
);
428 static void ctmRotate(displayCanvas_t
*displayCanvas
, float r
)
430 UNUSED(displayCanvas
);
432 frskyOSDCtmRotate(r
);
435 static void contextPush(displayCanvas_t
*displayCanvas
)
437 UNUSED(displayCanvas
);
439 frskyOSDContextPush();
442 static void contextPop(displayCanvas_t
*displayCanvas
)
444 UNUSED(displayCanvas
);
446 frskyOSDContextPop();
449 static int supportedInstances(displayWidgets_t
*widgets
, displayWidgetType_e widgetType
)
453 if (frskyOSDSupportsWidgets()) {
454 switch (widgetType
) {
455 case DISPLAY_WIDGET_TYPE_AHI
:
457 case DISPLAY_WIDGET_TYPE_SIDEBAR
:
458 return FRSKY_OSD_WIDGET_ID_SIDEBAR_LAST
- FRSKY_OSD_WIDGET_ID_SIDEBAR_FIRST
+ 1;
464 static bool configureAHI(displayWidgets_t
*widgets
, unsigned instance
, const widgetAHIConfiguration_t
*config
)
468 if (frskyOSDSupportsWidgets() && instance
== 0) {
469 frskyOSDWidgetAHIConfig_t cfg
= {
470 .rect
.origin
.x
= config
->rect
.x
,
471 .rect
.origin
.y
= config
->rect
.y
,
472 .rect
.size
.w
= config
->rect
.w
,
473 .rect
.size
.h
= config
->rect
.h
,
474 .style
= config
->style
,
475 .options
= config
->options
,
476 .crosshairMargin
= config
->crosshairMargin
,
477 .strokeWidth
= config
->strokeWidth
,
479 return frskyOSDSetWidgetConfig(FRSKY_OSD_WIDGET_ID_AHI
, &cfg
, sizeof(cfg
));
484 static bool drawAHI(displayWidgets_t
*widgets
, unsigned instance
, const widgetAHIData_t
*data
)
488 if (frskyOSDSupportsWidgets() && instance
== 0) {
489 frskyOSDWidgetAHIData_t ahiData
= {
490 .pitch
= frskyOSDQuantize(data
->pitch
, 0, 2 * M_PIf
, 12),
491 .roll
= frskyOSDQuantize(data
->roll
, 0, 2 * M_PIf
, 12),
493 return frskyOSDDrawWidget(FRSKY_OSD_WIDGET_ID_AHI
, &ahiData
, sizeof(ahiData
));
498 static bool configureSidebar(displayWidgets_t
*widgets
, unsigned instance
, const widgetSidebarConfiguration_t
*config
)
502 if (frskyOSDSupportsWidgets()) {
503 frskyOSDWidgetID_e id
= FRSKY_OSD_WIDGET_ID_SIDEBAR_FIRST
+ instance
;
504 if (id
<= FRSKY_OSD_WIDGET_ID_SIDEBAR_LAST
) {
505 frskyOSDWidgetSidebarConfig_t cfg
= {
506 .rect
.origin
.x
= config
->rect
.x
,
507 .rect
.origin
.y
= config
->rect
.y
,
508 .rect
.size
.w
= config
->rect
.w
,
509 .rect
.size
.h
= config
->rect
.h
,
510 .options
= config
->options
,
511 .divisions
= config
->divisions
,
512 .counts_per_step
= config
->counts_per_step
,
513 .unit
= config
->unit
,
515 return frskyOSDSetWidgetConfig(id
, &cfg
, sizeof(cfg
));
521 static bool drawSidebar(displayWidgets_t
*widgets
, unsigned instance
, int32_t data
)
525 if (frskyOSDSupportsWidgets()) {
526 frskyOSDWidgetID_e id
= FRSKY_OSD_WIDGET_ID_SIDEBAR_FIRST
+ instance
;
527 if (id
<= FRSKY_OSD_WIDGET_ID_SIDEBAR_LAST
) {
528 frskyOSDWidgetSidebarData_t sidebarData
= {
531 return frskyOSDDrawWidget(id
, &sidebarData
, sizeof(sidebarData
));
537 static const displayWidgetsVTable_t frskyOSDWidgetsVTable
= {
538 .supportedInstances
= supportedInstances
,
539 .configureAHI
= configureAHI
,
541 .configureSidebar
= configureSidebar
,
542 .drawSidebar
= drawSidebar
,
545 static bool getWidgets(displayWidgets_t
*widgets
, const displayCanvas_t
*displayCanvas
)
547 if (frskyOSDSupportsWidgets()) {
548 widgets
->device
= displayCanvas
->device
;
549 widgets
->vTable
= &frskyOSDWidgetsVTable
;
555 static const displayCanvasVTable_t frskyOSDCanvasVTable
= {
556 .setStrokeColor
= setStrokeColor
,
557 .setFillColor
= setFillColor
,
558 .setStrokeAndFillColor
= setStrokeAndFillColor
,
559 .setColorInversion
= setColorInversion
,
560 .setPixel
= setPixel
,
561 .setPixelToStrokeColor
= setPixelToStrokeColor
,
562 .setPixelToFillColor
= setPixelToFillColor
,
563 .setStrokeWidth
= setStrokeWidth
,
564 .setLineOutlineType
= setLineOutlineType
,
565 .setLineOutlineColor
= setLineOutlineColor
,
567 .clipToRect
= clipToRect
,
568 .clearRect
= clearRect
,
569 .resetDrawingState
= resetDrawingState
,
570 .drawCharacter
= drawCharacter
,
571 .drawCharacterMask
= drawCharacterMask
,
572 .drawString
= drawString
,
573 .drawStringMask
= drawStringMask
,
574 .moveToPoint
= moveToPoint
,
575 .strokeLineToPoint
= strokeLineToPoint
,
576 .strokeTriangle
= strokeTriangle
,
577 .fillTriangle
= fillTriangle
,
578 .fillStrokeTriangle
= fillStrokeTriangle
,
579 .strokeRect
= strokeRect
,
580 .fillRect
= fillRect
,
581 .fillStrokeRect
= fillStrokeRect
,
582 .strokeEllipseInRect
= strokeEllipseInRect
,
583 .fillEllipseInRect
= fillEllipseInRect
,
584 .fillStrokeEllipseInRect
= fillStrokeEllipseInRect
,
586 .ctmReset
= ctmReset
,
588 .ctmTranslate
= ctmTranslate
,
589 .ctmScale
= ctmScale
,
590 .ctmRotate
= ctmRotate
,
592 .contextPush
= contextPush
,
593 .contextPop
= contextPop
,
595 .getWidgets
= getWidgets
,
598 static bool getCanvas(displayCanvas_t
*canvas
, const displayPort_t
*instance
)
600 canvas
->device
= instance
->device
;
601 canvas
->vTable
= &frskyOSDCanvasVTable
;
602 canvas
->width
= frskyOSDGetPixelWidth();
603 canvas
->height
= frskyOSDGetPixelHeight();
607 static const displayPortVTable_t frskyOSDVTable
= {
610 .clearScreen
= clearScreen
,
611 .drawScreen
= drawScreen
,
612 .screenSize
= screenSize
,
613 .writeString
= writeString
,
614 .writeChar
= writeChar
,
615 .readChar
= readChar
,
616 .isTransferInProgress
= isTransferInProgress
,
617 .heartbeat
= heartbeat
,
619 .txBytesFree
= txBytesFree
,
620 .supportedTextAttributes
= supportedTextAttributes
,
621 .getFontMetadata
= getFontMetadata
,
622 .writeFontCharacter
= writeFontCharacter
,
624 .beginTransaction
= beginTransaction
,
625 .commitTransaction
= commitTransaction
,
626 .getCanvas
= getCanvas
,
629 displayPort_t
*frskyOSDDisplayPortInit(const videoSystem_e videoSystem
)
631 if (frskyOSDInit(videoSystem
)) {
632 displayInit(&frskyOSDDisplayPort
, &frskyOSDVTable
);
633 resync(&frskyOSDDisplayPort
);
634 frskyOSDDisplayPort
.displayPortType
= "FrSky PixelOSD";
635 return &frskyOSDDisplayPort
;
640 #endif // USE_FRSKYOSD