2 * This file is part of INAV Project.
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
6 * You can obtain one at http://mozilla.org/MPL/2.0/.
8 * Alternatively, the contents of this file may be used under the terms
9 * of the GNU General Public License Version 3, as described below:
11 * This file is free software: you may copy, redistribute and/or modify
12 * it under the terms of the GNU General Public License as published by the
13 * Free Software Foundation, either version 3 of the License, or (at your
14 * option) any later version.
16 * This file is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
19 * Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program. If not, see http://www.gnu.org/licenses/.
31 #if defined(USE_OSD) && defined(USE_HDZERO_OSD)
33 #include "common/utils.h"
34 #include "common/printf.h"
35 #include "common/time.h"
37 #include "drivers/display.h"
38 #include "drivers/display_font_metadata.h"
39 #include "drivers/osd_symbols.h"
41 #include "msp/msp_protocol.h"
42 #include "msp/msp_serial.h"
44 #include "displayport_hdzero_osd.h"
46 #define MSP_HEARTBEAT 0
48 #define MSP_CLEAR_SCREEN 2
49 #define MSP_WRITE_STRING 3
50 #define MSP_DRAW_SCREEN 4
53 #define FONT_PAGE_ATTRIBUTE 0x01
55 static mspPort_t hdzeroMspPort
;
56 static displayPort_t hdzeroOsdDisplayPort
;
57 static bool hdzeroVtxReady
;
62 #define SCREENSIZE (ROWS*COLS)
63 static uint8_t screen
[SCREENSIZE
];
64 static uint8_t fontPage
[SCREENSIZE
/ 8 + 1]; // page bits for each character (to address 512 char font)
66 extern uint8_t cliMode
;
68 static int output(displayPort_t
*displayPort
, uint8_t cmd
, uint8_t *subcmd
, int len
)
75 return mspSerialPushPort(cmd
, subcmd
, len
, &hdzeroMspPort
, MSP_V1
);
78 static int heartbeat(displayPort_t
*displayPort
)
80 uint8_t subcmd
[] = { MSP_HEARTBEAT
};
81 return output(displayPort
, MSP_DISPLAYPORT
, subcmd
, sizeof(subcmd
));
84 static int release(displayPort_t
*displayPort
)
86 uint8_t subcmd
[] = { MSP_RELEASE
};
87 return output(displayPort
, MSP_DISPLAYPORT
, subcmd
, sizeof(subcmd
));
90 static int clearScreen(displayPort_t
*displayPort
)
94 memset(screen
, SYM_BLANK
, sizeof(screen
));
95 memset(fontPage
, 0, sizeof(fontPage
));
100 * Write up to three populated rows at a time, skipping blank lines.
101 * This gives a refresh rate to the VTX of approximately 10 to 62Hz
102 * depending on how much data is displayed.
104 static int drawScreen(displayPort_t
*displayPort
) // 62.5hz
106 static uint8_t row
= 0, clearSent
= 0;
107 uint8_t subcmd
[COLS
+ 4], len
, col
, page
, aPage
, rowsToPrint
;
108 uint16_t lineIdx
, idx
, end
;
113 // Find a row with something to print
115 // Strip leading and trailing spaces for the selected row
116 lineIdx
= row
* COLS
;
118 end
= idx
+ COLS
- 1;
120 while ((screen
[idx
] == SYM_BLANK
|| screen
[end
] == SYM_BLANK
) && idx
<= end
) {
121 if (screen
[idx
] == SYM_BLANK
)
123 if (screen
[end
] == SYM_BLANK
)
126 } while (idx
> end
&& ++row
< ROWS
);
130 // Start the transaction
131 subcmd
[0] = MSP_CLEAR_SCREEN
;
132 charsOut
+= output(displayPort
, MSP_DISPLAYPORT
, subcmd
, 1);
136 // Split the line up into strings from the same font page and output them.
137 // (note spaces are printed to save overhead on small elements)
140 page
= (fontPage
[idx
>> 3] >> (idx
& 0x07)) & FONT_PAGE_ATTRIBUTE
;
143 subcmd
[len
++] = screen
[idx
++];
144 aPage
= (fontPage
[idx
>> 3] >> (idx
& 0x07)) & FONT_PAGE_ATTRIBUTE
;
145 } while (idx
<= end
&& (aPage
== page
|| screen
[idx
] == SYM_BLANK
));
147 subcmd
[0] = MSP_WRITE_STRING
;
151 charsOut
+= output(displayPort
, MSP_DISPLAYPORT
, subcmd
, len
);
153 } while (++row
< ROWS
&& --rowsToPrint
);
156 // End the transaction if required and reset the counters
158 subcmd
[0] = MSP_DRAW_SCREEN
;
159 charsOut
+= output(displayPort
, MSP_DISPLAYPORT
, subcmd
, 1);
167 static int setHdMode(displayPort_t
*displayPort
)
170 subcmd
[0] = MSP_SET_HD
;
171 subcmd
[1] = 0; // future font index
172 subcmd
[2] = 1; // 0 SD 1 HD
174 return output(displayPort
, MSP_DISPLAYPORT
, subcmd
, sizeof(subcmd
));
177 static int grab(displayPort_t
*displayPort
)
179 return heartbeat(displayPort
);
182 static int screenSize(const displayPort_t
*displayPort
)
189 // Intercept writeString and write to a buffer instead (1st page of font file only)
190 static int writeString(displayPort_t
*displayPort
, uint8_t col
, uint8_t row
, const char *string
, textAttributes_t attr
)
195 uint16_t i
, pos
, len
, end
, idx
;
197 pos
= (row
* COLS
) + col
;
198 if (pos
>= SCREENSIZE
)
201 len
= strlen(string
);
203 // Allow word wrap and truncate of past the screen end
205 if (end
>= SCREENSIZE
)
206 len
= end
- SCREENSIZE
;
208 // Copy the string into the screen buffer
209 memcpy(screen
+ pos
, string
, len
);
211 // Clear the page bits for all the characters in the string
212 for (i
= 0; i
< len
; i
++) {
214 fontPage
[idx
>> 3] &= ~(1 << (idx
& 0x07));
220 // Write character to screen and page buffers (supports 512 char fonts)
221 static int writeChar(displayPort_t
*displayPort
, uint8_t col
, uint8_t row
, uint16_t c
, textAttributes_t attr
)
229 pos
= (row
* COLS
) + col
;
230 if (pos
>= SCREENSIZE
)
233 // Copy character into screen buffer
237 bitmask
= 1 << (pos
& 0x07);
239 // Save index of the character's font page
241 fontPage
[idx
] |= bitmask
;
243 fontPage
[idx
] &= ~bitmask
;
248 static bool readChar(displayPort_t
*displayPort
, uint8_t col
, uint8_t row
, uint16_t *c
, textAttributes_t
*attr
)
254 pos
= (row
* COLS
) + col
;
255 if (pos
>= SCREENSIZE
)
258 chr
= (fontPage
[pos
>> 3] >> (pos
& 0x07)) & FONT_PAGE_ATTRIBUTE
;
259 *c
= (chr
<< 8) | screen
[pos
];
263 *attr
= TEXT_ATTRIBUTES_NONE
;
268 static bool isTransferInProgress(const displayPort_t
*displayPort
)
275 static void resync(displayPort_t
*displayPort
)
277 displayPort
->rows
= ROWS
;
278 displayPort
->cols
= COLS
;
279 setHdMode(displayPort
);
282 static uint32_t txBytesFree(const displayPort_t
*displayPort
)
286 return mspSerialTxBytesFree();
289 static textAttributes_t
supportedTextAttributes(const displayPort_t
*displayPort
)
293 textAttributes_t attr
= TEXT_ATTRIBUTES_NONE
;
294 //TEXT_ATTRIBUTES_ADD_INVERTED(attr);
295 //TEXT_ATTRIBUTES_ADD_SOLID_BG(attr);
299 static bool getFontMetadata(displayFontMetadata_t
*metadata
, const displayPort_t
*displayPort
)
303 metadata
->charCount
= 512;
304 metadata
->version
= 3;
309 static bool isReady(displayPort_t
*displayPort
)
313 return hdzeroVtxReady
;
316 static const displayPortVTable_t hdzeroOsdVTable
= {
319 .clearScreen
= clearScreen
,
320 .drawScreen
= drawScreen
,
321 .screenSize
= screenSize
,
322 .writeString
= writeString
,
323 .writeChar
= writeChar
,
324 .readChar
= readChar
,
325 .isTransferInProgress
= isTransferInProgress
,
326 .heartbeat
= heartbeat
,
328 .txBytesFree
= txBytesFree
,
329 .supportedTextAttributes
= supportedTextAttributes
,
330 .getFontMetadata
= getFontMetadata
,
334 void hdzeroOsdSerialInit(void)
336 memset(&hdzeroMspPort
, 0, sizeof(mspPort_t
));
338 serialPortConfig_t
*portConfig
= findSerialPortConfig(FUNCTION_HDZERO_OSD
);
341 serialPort_t
*port
= openSerialPort(portConfig
->identifier
, FUNCTION_HDZERO_OSD
, NULL
, NULL
,
342 baudRates
[portConfig
->msp_baudrateIndex
], MODE_RXTX
, SERIAL_NOT_INVERTED
);
344 resetMspPort(&hdzeroMspPort
, port
);
348 displayPort_t
* hdzeroOsdDisplayPortInit(void)
350 memset(screen
, SYM_BLANK
, sizeof(screen
));
351 memset(fontPage
, 0, sizeof(fontPage
));
352 displayInit(&hdzeroOsdDisplayPort
, &hdzeroOsdVTable
);
353 return &hdzeroOsdDisplayPort
;
356 void hdzeroOsdSerialProcess(mspEvaluateNonMspData_e evaluateNonMspData
, mspProcessCommandFnPtr mspProcessCommandFn
)
358 if (hdzeroMspPort
.port
) {
359 // Process normal MSP command
360 mspSerialProcessOnePort(&hdzeroMspPort
, evaluateNonMspData
, mspProcessCommandFn
);
361 hdzeroVtxReady
= true;
365 #endif // USE_HDZERO_OSD