Blackbox device type 'file' (SITL) considered working when file handler is available
[inav.git] / src / main / drivers / display.c
blob0ed37ddb4e69c5e9662d3f2fa0e6223225f63898
1 /*
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/>.
18 #include <stdbool.h>
19 #include <stdint.h>
20 #include <string.h>
22 #include "platform.h"
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);
55 return false;
58 static bool displayEmulateTextAttributes(displayPort_t *instance,
59 char *buf, size_t length,
60 textAttributes_t *attr)
62 UNUSED(instance);
64 // We only emulate blink for now, so there's no need to test
65 // for it again.
66 TEXT_ATTRIBUTES_REMOVE_BLINK(*attr);
67 if (getBlinkOnOff()) {
68 memset(buf, ' ', length);
69 buf[length] = '\0';
70 // Tell the caller to use buf
71 return true;
73 // Tell the caller to use s but with the updated attributes
74 return false;
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;
83 } else {
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)
141 instance->posX = x;
142 instance->posY = y;
145 int displayWrite(displayPort_t *instance, uint8_t x, uint8_t y, const char *s)
147 instance->posX = x + strlen(s);
148 instance->posY = y;
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;
158 instance->posY = y;
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.
166 s = 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);
179 #ifdef USE_SIMULATOR
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;
188 #endif
190 if (c > instance->maxChar) {
191 return -1;
193 instance->posX = x + 1;
194 instance->posY = y;
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) {
204 return -1;
206 if (displayAttributesRequireEmulation(instance, attr)) {
207 char ec[2];
208 if (displayEmulateTextAttributes(instance, ec, 1, &attr)) {
209 c = ec[0];
212 instance->posX = x + 1;
213 instance->posY = y;
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)
219 uint16_t dc;
220 textAttributes_t dattr;
222 if (!instance->vTable->readChar) {
223 return false;
226 if (!c) {
227 c = &dc;
230 if (!attr) {
231 attr = &dattr;
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);
262 return false;
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);
270 return -1;
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)
281 return true;
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;
304 return true;
306 #else
307 UNUSED(canvas);
308 UNUSED(instance);
309 #endif
310 return false;
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);