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)
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/>.
28 #include "io/rcdevice.h"
32 #include "rcdevice_osd.h"
34 #define VIDEO_BUFFER_CHARS_PAL 480
36 static uint8_t columnCount
= 30;
38 static runcamDevice_t runcamOSDDevice
;
39 runcamDevice_t
*osdDevice
= &runcamOSDDevice
;
41 static uint8_t video_system
;
42 static uint16_t maxScreenSize
= VIDEO_BUFFER_CHARS_PAL
;
44 #ifdef USE_PARTICLE_DRAW
45 #define MAX_CHARS2UPDATE 20
46 static uint8_t screenBuffer
[VIDEO_BUFFER_CHARS_PAL
+ 40]; // For faster writes
47 // we use memcpy so we
51 static uint8_t shadowBuffer
[VIDEO_BUFFER_CHARS_PAL
];
52 static bool rcdeviceOSDLock
= false;
55 bool rcdeviceOSDInit(const vcdProfile_t
*vcdProfile
)
57 if (!runcamDeviceInit(osdDevice
)) {
61 if ((osdDevice
->info
.features
& RCDEVICE_PROTOCOL_FEATURE_DISPLAYP_PORT
) == 0) {
65 // get screen column count
66 runcamDeviceSettingDetail_t settingDetail
;
67 if (!runcamDeviceGetSettingDetail(osdDevice
, RCDEVICE_PROTOCOL_SETTINGID_DISP_COLUMNS
, &settingDetail
)) {
71 columnCount
= settingDetail
.value
;
73 video_system
= vcdProfile
->video_system
;
74 if (video_system
== VIDEO_SYSTEM_AUTO
) {
75 // fetch current video mode from device
76 runcamDeviceSettingDetail_t settingDetail
;
77 if (!runcamDeviceGetSettingDetail(osdDevice
, RCDEVICE_PROTOCOL_SETTINGID_DISP_TV_MODE
, &settingDetail
)) {
80 video_system
= settingDetail
.value
;
83 runcamDeviceWriteSettingResponse_t response
;
85 if (video_system
== VIDEO_SYSTEM_NTSC
) {
87 } else if (video_system
== VIDEO_SYSTEM_PAL
) {
91 if (!runcamDeviceWriteSetting(osdDevice
, RCDEVICE_PROTOCOL_SETTINGID_DISP_TV_MODE
, &tvMode
, sizeof(uint8_t), &response
)) {
95 if (response
.resultCode
) {
101 uint8_t charsetID
= 0;
102 runcamDeviceWriteSettingResponse_t updateCharsetResp
;
103 if (!runcamDeviceWriteSetting(osdDevice
, RCDEVICE_PROTOCOL_SETTINGID_DISP_CHARSET
, &charsetID
, sizeof(uint8_t), &updateCharsetResp
) || updateCharsetResp
.resultCode
!= 0) {
107 #ifdef USE_PARTICLE_DRAW
108 memset(shadowBuffer
, 2, VIDEO_BUFFER_CHARS_PAL
);
111 // fill screen with ' '
112 rcdeviceOSDClearScreen(NULL
);
116 int rcdeviceOSDGrab(displayPort_t
*displayPort
)
120 // resumeRefreshAt = 0;
124 int rcdeviceOSDRelease(displayPort_t
*displayPort
)
130 int rcdeviceOSDDrawScreen(displayPort_t
*displayPort
)
134 #ifdef USE_PARTICLE_DRAW
135 static uint16_t pos
= 0;
138 if (!rcdeviceOSDLock
) {
139 rcdeviceOSDLock
= true;
143 for (k
= 0; k
< MAX_CHARS2UPDATE
; k
++) {
144 if (screenBuffer
[pos
] != shadowBuffer
[pos
]) {
145 shadowBuffer
[pos
] = screenBuffer
[pos
];
146 uint8_t x
= pos
% columnCount
;
147 uint8_t y
= pos
/ columnCount
;
150 data
[dataLen
++] = screenBuffer
[pos
];
153 if (++pos
>= maxScreenSize
) {
158 runcamDeviceDispWriteChars(osdDevice
, data
, dataLen
);
160 rcdeviceOSDLock
= false;
166 int rcdeviceOSDWriteString(displayPort_t
*displayPort
, uint8_t x
, uint8_t y
, const char *buff
)
169 #if !defined(USE_PARTICLE_DRAW)
170 runcamDeviceDispWriteHorizontalString(osdDevice
, x
, y
, buff
);
172 for (int xpos
= x
; *buff
&& xpos
< columnCount
; xpos
++) {
173 screenBuffer
[y
* columnCount
+ xpos
] = *buff
++;
179 int rcdeviceOSDWriteChar(displayPort_t
*displayPort
, uint8_t x
, uint8_t y
, uint8_t c
)
182 #if !defined(USE_PARTICLE_DRAW)
183 runcamDeviceDispWriteChar(osdDevice
, x
, y
, c
);
185 screenBuffer
[y
* columnCount
+ x
] = c
;
191 int rcdeviceOSDClearScreen(displayPort_t
*displayPort
)
195 #if defined(USE_PARTICLE_DRAW)
196 memset(screenBuffer
, 0x20, sizeof(screenBuffer
));
198 runcamDeviceDispFillRegion(osdDevice
, 0, 0, 255, 255, ' ');
204 bool rcdeviceOSDIsTransferInProgress(const displayPort_t
*displayPort
)
210 bool rcdeviceOSDIsSynced(const displayPort_t
*displayPort
)
216 int rcdeviceOSDHeartbeat(displayPort_t
*displayPort
)
222 void rcdeviceOSDResync(displayPort_t
*displayPort
)
226 if (video_system
== VIDEO_SYSTEM_PAL
) {
227 displayPort
->rows
= RCDEVICE_PROTOCOL_OSD_VIDEO_LINES_PAL
;
229 displayPort
->rows
= RCDEVICE_PROTOCOL_OSD_VIDEO_LINES_NTSC
;
232 displayPort
->cols
= columnCount
;
233 maxScreenSize
= displayPort
->rows
* displayPort
->cols
;
236 uint32_t rcdeviceOSDTxBytesFree(const displayPort_t
*displayPort
)
242 int rcdeviceScreenSize(const displayPort_t
*displayPort
)
244 return displayPort
->rows
* displayPort
->cols
;