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/>.
24 #include "common/utils.h"
26 #include "config/parameter_group_ids.h"
28 #include "drivers/display.h"
29 #include "drivers/display_canvas.h"
30 #include "drivers/display_font_metadata.h"
31 #include "drivers/time.h"
33 #include "fc/settings.h"
34 #include "fc/runtime_config.h"
36 // XXX: This is the number of characters in a MAX7456 line.
37 // Increment this number appropiately or enable support for
38 // multiple iterations in displayWriteWithAttr() if bigger
39 // displays are supported (implementation can be found in commit
40 // 22a48278 before it was deleted).
41 #define DISPLAY_MAX_STRING_SIZE 30
43 PG_REGISTER_WITH_RESET_TEMPLATE(displayConfig_t
, displayConfig
, PG_DISPLAY_CONFIG
, 0);
45 PG_RESET_TEMPLATE(displayConfig_t
, displayConfig
,
46 .force_sw_blink
= SETTING_DISPLAY_FORCE_SW_BLINK_DEFAULT
49 static bool displayAttributesRequireEmulation(displayPort_t
*instance
, textAttributes_t attr
)
51 if (attr
& ~instance
->cachedSupportedTextAttributes
) {
52 // We only emulate blink for now
53 return TEXT_ATTRIBUTES_HAVE_BLINK(attr
);
58 static bool displayEmulateTextAttributes(displayPort_t
*instance
,
59 char *buf
, size_t length
,
60 textAttributes_t
*attr
)
64 // We only emulate blink for now, so there's no need to test
66 TEXT_ATTRIBUTES_REMOVE_BLINK(*attr
);
67 if (getBlinkOnOff()) {
68 memset(buf
, ' ', length
);
70 // Tell the caller to use buf
73 // Tell the caller to use s but with the updated attributes
77 static void displayUpdateMaxChar(displayPort_t
*instance
)
79 if (displayIsReady(instance
)) {
80 displayFontMetadata_t metadata
;
81 if (displayGetFontMetadata(&metadata
, instance
)) {
82 instance
->maxChar
= metadata
.charCount
- 1;
84 // Assume 8-bit character implementation
85 instance
->maxChar
= 255;
90 void displayClearScreen(displayPort_t
*instance
)
92 instance
->vTable
->clearScreen(instance
);
93 instance
->cleared
= true;
94 instance
->cursorRow
= -1;
97 void displayDrawScreen(displayPort_t
*instance
)
99 if (instance
->rows
== 0 || instance
->cols
== 0) {
100 // Display not fully initialized yet
101 displayResync(instance
);
103 instance
->vTable
->drawScreen(instance
);
106 int displayScreenSize(const displayPort_t
*instance
)
108 return instance
->vTable
->screenSize(instance
);
111 void displayGrab(displayPort_t
*instance
)
113 instance
->vTable
->grab(instance
);
114 instance
->vTable
->clearScreen(instance
);
115 ++instance
->grabCount
;
118 void displayRelease(displayPort_t
*instance
)
120 instance
->vTable
->release(instance
);
121 // displayPort_t is changing owner. Clear it, since
122 // the new owner might expect a clear canvas.
123 instance
->vTable
->clearScreen(instance
);
124 --instance
->grabCount
;
127 void displayReleaseAll(displayPort_t
*instance
)
129 instance
->vTable
->release(instance
);
130 instance
->grabCount
= 0;
133 bool displayIsGrabbed(const displayPort_t
*instance
)
135 // can be called before initialised
136 return (instance
&& instance
->grabCount
> 0);
139 void displaySetXY(displayPort_t
*instance
, uint8_t x
, uint8_t y
)
145 int displayWrite(displayPort_t
*instance
, uint8_t x
, uint8_t y
, const char *s
)
147 instance
->posX
= x
+ strlen(s
);
149 return instance
->vTable
->writeString(instance
, x
, y
, s
, TEXT_ATTRIBUTES_NONE
);
152 int displayWriteWithAttr(displayPort_t
*instance
, uint8_t x
, uint8_t y
, const char *s
, textAttributes_t attr
)
154 size_t length
= strlen(s
);
155 char buf
[DISPLAY_MAX_STRING_SIZE
+ 1];
157 instance
->posX
= x
+ length
;
160 if (displayAttributesRequireEmulation(instance
, attr
)) {
161 // We can't overwrite s, so we use an intermediate buffer if we need
162 // text attribute emulation.
163 size_t blockSize
= length
> sizeof(buf
) ? sizeof(buf
) : length
;
164 if (displayEmulateTextAttributes(instance
, buf
, blockSize
, &attr
)) {
165 // Emulation required rewriting the string, use buf.
170 return instance
->vTable
->writeString(instance
, x
, y
, s
, attr
);
173 int displayWriteChar(displayPort_t
*instance
, uint8_t x
, uint8_t y
, uint16_t c
)
175 if (instance
->maxChar
== 0) {
176 displayUpdateMaxChar(instance
);
180 if (ARMING_FLAG(SIMULATOR_MODE_HITL
)) {
181 //some FCs do not power max7456 from USB power
182 //driver can not read font metadata
183 //chip assumed to not support second bank of font
184 //artifical horizon, variometer and home direction are not drawn ( display.c: displayUpdateMaxChar())
185 //return dummy metadata to let all OSD elements to work in simulator mode
186 instance
->maxChar
= 512;
190 if (c
> instance
->maxChar
) {
193 instance
->posX
= x
+ 1;
195 return instance
->vTable
->writeChar(instance
, x
, y
, c
, TEXT_ATTRIBUTES_NONE
);
198 int displayWriteCharWithAttr(displayPort_t
*instance
, uint8_t x
, uint8_t y
, uint16_t c
, textAttributes_t attr
)
200 if (instance
->maxChar
== 0) {
201 displayUpdateMaxChar(instance
);
203 if (c
> instance
->maxChar
) {
206 if (displayAttributesRequireEmulation(instance
, attr
)) {
208 if (displayEmulateTextAttributes(instance
, ec
, 1, &attr
)) {
212 instance
->posX
= x
+ 1;
214 return instance
->vTable
->writeChar(instance
, x
, y
, c
, attr
);
217 bool displayReadCharWithAttr(displayPort_t
*instance
, uint8_t x
, uint8_t y
, uint16_t *c
, textAttributes_t
*attr
)
220 textAttributes_t dattr
;
222 if (!instance
->vTable
->readChar
) {
234 return instance
->vTable
->readChar(instance
, x
, y
, c
, attr
);
237 bool displayIsTransferInProgress(const displayPort_t
*instance
)
239 return instance
->vTable
->isTransferInProgress(instance
);
242 void displayHeartbeat(displayPort_t
*instance
)
244 instance
->vTable
->heartbeat(instance
);
247 void displayResync(displayPort_t
*instance
)
249 instance
->vTable
->resync(instance
);
252 uint16_t displayTxBytesFree(const displayPort_t
*instance
)
254 return instance
->vTable
->txBytesFree(instance
);
257 bool displayGetFontMetadata(displayFontMetadata_t
*metadata
, const displayPort_t
*instance
)
259 if (instance
->vTable
->getFontMetadata
) {
260 return instance
->vTable
->getFontMetadata(metadata
, instance
);
265 int displayWriteFontCharacter(displayPort_t
*instance
, uint16_t addr
, const osdCharacter_t
*chr
)
267 if (instance
->vTable
->writeFontCharacter
) {
268 return instance
->vTable
->writeFontCharacter(instance
, addr
, chr
);
273 bool displayIsReady(displayPort_t
*instance
)
275 if (instance
->vTable
->isReady
) {
276 return instance
->vTable
->isReady(instance
);
278 // Drivers that don't provide an isReady method are
279 // assumed to be immediately ready (either by actually
280 // begin ready very quickly or by blocking)
284 void displayBeginTransaction(displayPort_t
*instance
, displayTransactionOption_e opts
)
286 if (instance
->vTable
->beginTransaction
) {
287 instance
->vTable
->beginTransaction(instance
, opts
);
291 void displayCommitTransaction(displayPort_t
*instance
)
293 if (instance
->vTable
->commitTransaction
) {
294 instance
->vTable
->commitTransaction(instance
);
298 bool displayGetCanvas(displayCanvas_t
*canvas
, const displayPort_t
*instance
)
300 #if defined(USE_CANVAS)
301 if (canvas
&& instance
->vTable
->getCanvas
&& instance
->vTable
->getCanvas(canvas
, instance
)) {
302 canvas
->gridElementWidth
= canvas
->width
/ instance
->cols
;
303 canvas
->gridElementHeight
= canvas
->height
/ instance
->rows
;
313 void displayInit(displayPort_t
*instance
, const displayPortVTable_t
*vTable
)
315 instance
->vTable
= vTable
;
316 instance
->vTable
->clearScreen(instance
);
317 instance
->useFullscreen
= false;
318 instance
->cleared
= true;
319 instance
->grabCount
= 0;
320 instance
->cursorRow
= -1;
321 instance
->cachedSupportedTextAttributes
= TEXT_ATTRIBUTES_NONE
;
322 if (vTable
->supportedTextAttributes
) {
323 instance
->cachedSupportedTextAttributes
= vTable
->supportedTextAttributes(instance
);
325 if (displayConfig()->force_sw_blink
) {
326 TEXT_ATTRIBUTES_REMOVE_BLINK(instance
->cachedSupportedTextAttributes
);
329 instance
->maxChar
= 0;
330 displayUpdateMaxChar(instance
);