Create release.yml
[betaflight.git] / src / main / io / displayport_crsf.c
blob814de585b5740ae73fdc46c828db81d67a963a0c
1 /*
2 * This file is part of Cleanflight and Betaflight.
4 * Cleanflight and Betaflight are free software. You can redistribute
5 * this software and/or modify this software under the terms of the
6 * GNU General Public License as published by the Free Software
7 * Foundation, either version 3 of the License, or (at your option)
8 * any later version.
10 * Cleanflight and Betaflight are distributed in the hope that they
11 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
12 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this software.
18 * If not, see <http://www.gnu.org/licenses/>.
21 #include <stdbool.h>
22 #include <string.h>
24 #include "platform.h"
26 #if defined(USE_CRSF_CMS_TELEMETRY)
28 #include "cms/cms.h"
30 #include "common/maths.h"
31 #include "common/printf.h"
32 #include "common/time.h"
34 #include "drivers/display.h"
35 #include "drivers/time.h"
37 #include "displayport_crsf.h"
39 #define CRSF_DISPLAY_PORT_OPEN_DELAY_MS 400
40 #define CRSF_DISPLAY_PORT_CLEAR_DELAY_MS 45
42 static crsfDisplayPortScreen_t crsfScreen;
43 static timeMs_t delayTransportUntilMs = 0;
45 displayPort_t crsfDisplayPort;
47 static int crsfGrab(displayPort_t *displayPort)
49 return displayPort->grabCount = 1;
52 static int crsfClearScreen(displayPort_t *displayPort, displayClearOption_e options)
54 UNUSED(displayPort);
55 UNUSED(options);
56 memset(crsfScreen.buffer, ' ', sizeof(crsfScreen.buffer));
57 crsfScreen.updated = false;
58 crsfScreen.reset = true;
59 delayTransportUntilMs = millis() + CRSF_DISPLAY_PORT_CLEAR_DELAY_MS;
60 return 0;
63 static int crsfRelease(displayPort_t *displayPort)
65 displayPort->grabCount = 0;
66 return crsfClearScreen(displayPort, DISPLAY_CLEAR_WAIT);
69 static bool crsfDrawScreen(displayPort_t *displayPort)
71 UNUSED(displayPort);
72 return 0;
75 static int crsfScreenSize(const displayPort_t *displayPort)
77 return displayPort->rows * displayPort->cols;
81 static int crsfWriteString(displayPort_t *displayPort, uint8_t col, uint8_t row, uint8_t attr, const char *s)
83 UNUSED(displayPort);
84 UNUSED(attr);
85 if (row >= crsfScreen.rows || col >= crsfScreen.cols) {
86 return 0;
88 const size_t truncLen = MIN((int)strlen(s), crsfScreen.cols-col); // truncate at colCount
89 char *rowStart = &crsfScreen.buffer[row * crsfScreen.cols + col];
90 crsfScreen.updated |= memcmp(rowStart, s, truncLen);
91 if (crsfScreen.updated) {
92 memcpy(rowStart, s, truncLen);
94 return 0;
97 static int crsfWriteChar(displayPort_t *displayPort, uint8_t col, uint8_t row, uint8_t attr, uint8_t c)
99 char s[1];
100 tfp_sprintf(s, "%c", c);
101 return crsfWriteString(displayPort, col, row, attr, s);
104 static bool crsfIsTransferInProgress(const displayPort_t *displayPort)
106 UNUSED(displayPort);
107 return false;
110 static bool crsfIsSynced(const displayPort_t *displayPort)
112 UNUSED(displayPort);
113 return true;
116 static int crsfHeartbeat(displayPort_t *displayPort)
118 UNUSED(displayPort);
119 return 0;
122 static void crsfRedraw(displayPort_t *displayPort)
124 displayPort->rows = crsfScreen.rows;
125 displayPort->cols = crsfScreen.cols;
128 static uint32_t crsfTxBytesFree(const displayPort_t *displayPort)
130 UNUSED(displayPort);
131 return UINT32_MAX;
134 static const displayPortVTable_t crsfDisplayPortVTable = {
135 .grab = crsfGrab,
136 .release = crsfRelease,
137 .clearScreen = crsfClearScreen,
138 .drawScreen = crsfDrawScreen,
139 .screenSize = crsfScreenSize,
140 .writeString = crsfWriteString,
141 .writeChar = crsfWriteChar,
142 .isTransferInProgress = crsfIsTransferInProgress,
143 .heartbeat = crsfHeartbeat,
144 .redraw = crsfRedraw,
145 .isSynced = crsfIsSynced,
146 .txBytesFree = crsfTxBytesFree,
147 .layerSupported = NULL,
148 .layerSelect = NULL,
149 .layerCopy = NULL,
152 crsfDisplayPortScreen_t *crsfDisplayPortScreen(void)
154 return &crsfScreen;
157 void crsfDisplayPortMenuOpen(void)
159 if (cmsInMenu) {
160 return;
162 if (cmsDisplayPortSelect(&crsfDisplayPort)) {
163 cmsMenuOpen();
164 delayTransportUntilMs = millis() + CRSF_DISPLAY_PORT_OPEN_DELAY_MS;
168 void crsfDisplayPortMenuExit(void)
170 if (!cmsInMenu) {
171 return;
173 uint8_t exitMenu = CMS_EXIT;
174 cmsMenuExit(&crsfDisplayPort, &exitMenu);
177 void crsfDisplayPortSetDimensions(uint8_t rows, uint8_t cols)
179 crsfScreen.rows = MIN(rows, CRSF_DISPLAY_PORT_ROWS_MAX);
180 crsfScreen.cols = MIN(cols, CRSF_DISPLAY_PORT_COLS_MAX);
181 crsfRedraw(&crsfDisplayPort);
184 void crsfDisplayPortRefresh(void)
186 if (!cmsInMenu) {
187 crsfDisplayPortMenuOpen();
188 return;
190 crsfScreen.updated = true;
191 crsfScreen.reset = true;
192 delayTransportUntilMs = millis() + CRSF_DISPLAY_PORT_CLEAR_DELAY_MS;
195 bool crsfDisplayPortIsReady(void)
197 const timeMs_t currentTimeMs = millis();
198 const bool delayExpired = (currentTimeMs > delayTransportUntilMs);
199 const bool cmsReady = (cmsInMenu && (pCurrentDisplay == &crsfDisplayPort));
200 return (bool)(delayExpired && cmsReady);
203 static displayPort_t *displayPortCrsfInit()
205 crsfDisplayPortSetDimensions(CRSF_DISPLAY_PORT_ROWS_MAX, CRSF_DISPLAY_PORT_COLS_MAX);
206 displayInit(&crsfDisplayPort, &crsfDisplayPortVTable, DISPLAYPORT_DEVICE_TYPE_CRSF);
208 return &crsfDisplayPort;
211 void crsfDisplayportRegister(void)
213 cmsDisplayPortRegister(displayPortCrsfInit());
215 #endif