Update FrSky SPI RX.md
[betaflight.git] / src / main / io / displayport_crsf.c
blob8276bfc77ef8dc0ca84eb73dbbd3cf661369e070
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"
29 #include "common/maths.h"
30 #include "common/printf.h"
31 #include "common/time.h"
32 #include "drivers/display.h"
33 #include "drivers/time.h"
34 #include "io/displayport_crsf.h"
36 #define CRSF_DISPLAY_PORT_OPEN_DELAY_MS 400
37 #define CRSF_DISPLAY_PORT_CLEAR_DELAY_MS 45
39 static crsfDisplayPortScreen_t crsfScreen;
40 static timeMs_t delayTransportUntilMs = 0;
42 displayPort_t crsfDisplayPort;
44 static int crsfGrab(displayPort_t *displayPort)
46 return displayPort->grabCount = 1;
49 static int crsfClearScreen(displayPort_t *displayPort)
51 UNUSED(displayPort);
52 memset(crsfScreen.buffer, ' ', sizeof(crsfScreen.buffer));
53 memset(crsfScreen.pendingTransport, 0, sizeof(crsfScreen.pendingTransport));
54 crsfScreen.reset = true;
55 delayTransportUntilMs = millis() + CRSF_DISPLAY_PORT_CLEAR_DELAY_MS;
56 return 0;
59 static int crsfRelease(displayPort_t *displayPort)
61 displayPort->grabCount = 0;
62 return crsfClearScreen(displayPort);
65 static int crsfDrawScreen(displayPort_t *displayPort)
67 UNUSED(displayPort);
68 return 0;
71 static int crsfScreenSize(const displayPort_t *displayPort)
73 return displayPort->rows * displayPort->cols;
77 static int crsfWriteString(displayPort_t *displayPort, uint8_t col, uint8_t row, const char *s)
79 UNUSED(displayPort);
80 if (row >= crsfScreen.rows || col >= crsfScreen.cols) {
81 return 0;
83 const size_t truncLen = MIN((int)strlen(s), crsfScreen.cols-col); // truncate at colCount
84 char *rowStart = &crsfScreen.buffer[row * crsfScreen.cols + col];
85 crsfScreen.pendingTransport[row] = memcmp(rowStart, s, truncLen);
86 if (crsfScreen.pendingTransport[row]) {
87 memcpy(rowStart, s, truncLen);
89 return 0;
92 static int crsfWriteChar(displayPort_t *displayPort, uint8_t col, uint8_t row, uint8_t c)
94 char s[1];
95 tfp_sprintf(s, "%c", c);
96 return crsfWriteString(displayPort, col, row, s);
99 static bool crsfIsTransferInProgress(const displayPort_t *displayPort)
101 UNUSED(displayPort);
102 return false;
105 static bool crsfIsSynced(const displayPort_t *displayPort)
107 UNUSED(displayPort);
108 return true;
111 static int crsfHeartbeat(displayPort_t *displayPort)
113 UNUSED(displayPort);
114 return 0;
117 static void crsfResync(displayPort_t *displayPort)
119 displayPort->rows = crsfScreen.rows;
120 displayPort->cols = crsfScreen.cols;
123 static uint32_t crsfTxBytesFree(const displayPort_t *displayPort)
125 UNUSED(displayPort);
126 return UINT32_MAX;
129 static const displayPortVTable_t crsfDisplayPortVTable = {
130 .grab = crsfGrab,
131 .release = crsfRelease,
132 .clearScreen = crsfClearScreen,
133 .drawScreen = crsfDrawScreen,
134 .screenSize = crsfScreenSize,
135 .writeString = crsfWriteString,
136 .writeChar = crsfWriteChar,
137 .isTransferInProgress = crsfIsTransferInProgress,
138 .heartbeat = crsfHeartbeat,
139 .resync = crsfResync,
140 .isSynced = crsfIsSynced,
141 .txBytesFree = crsfTxBytesFree
144 crsfDisplayPortScreen_t *crsfDisplayPortScreen(void)
146 return &crsfScreen;
149 void crsfDisplayPortMenuOpen(void)
151 if (cmsInMenu) {
152 return;
154 if (cmsDisplayPortSelect(&crsfDisplayPort)) {
155 cmsMenuOpen();
156 delayTransportUntilMs = millis() + CRSF_DISPLAY_PORT_OPEN_DELAY_MS;
160 void crsfDisplayPortMenuExit(void)
162 if (!cmsInMenu) {
163 return;
165 uint8_t exitMenu = CMS_EXIT;
166 cmsMenuExit(&crsfDisplayPort, &exitMenu);
169 void crsfDisplayPortSetDimensions(uint8_t rows, uint8_t cols)
171 crsfScreen.rows = MIN(rows, CRSF_DISPLAY_PORT_ROWS_MAX);
172 crsfScreen.cols = MIN(cols, CRSF_DISPLAY_PORT_COLS_MAX);
173 crsfResync(&crsfDisplayPort);
176 void crsfDisplayPortRefresh(void)
178 if (!cmsInMenu) {
179 crsfDisplayPortMenuOpen();
180 return;
182 memset(crsfScreen.pendingTransport, 1, crsfScreen.rows);
183 crsfScreen.reset = true;
184 delayTransportUntilMs = millis() + CRSF_DISPLAY_PORT_CLEAR_DELAY_MS;
187 int crsfDisplayPortNextRow(void)
189 const timeMs_t currentTimeMs = millis();
190 if (currentTimeMs < delayTransportUntilMs) {
191 return -1;
193 for(unsigned int i=0; i<CRSF_DISPLAY_PORT_ROWS_MAX; i++) {
194 if (crsfScreen.pendingTransport[i]) {
195 return i;
198 return -1;
201 displayPort_t *displayPortCrsfInit()
203 crsfDisplayPortSetDimensions(CRSF_DISPLAY_PORT_ROWS_MAX, CRSF_DISPLAY_PORT_COLS_MAX);
204 displayInit(&crsfDisplayPort, &crsfDisplayPortVTable);
205 return &crsfDisplayPort;
208 #endif