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/>.
24 #include "common/printf.h"
25 #include "common/utils.h"
27 #include "fc/rc_controls.h"
28 #include "fc/runtime_config.h"
30 #include "io/beeper.h"
31 #include "io/rcdevice_cam.h"
32 #include "io/osd_joystick.h"
38 #define IS_HI(X) (rxGetChannelValue(X) > FIVE_KEY_CABLE_JOYSTICK_MAX)
39 #define IS_LO(X) (rxGetChannelValue(X) < FIVE_KEY_CABLE_JOYSTICK_MIN)
40 #define IS_MID(X) (rxGetChannelValue(X) > FIVE_KEY_CABLE_JOYSTICK_MID_START && rxGetChannelValue(X) < FIVE_KEY_CABLE_JOYSTICK_MID_END)
41 static runcamDevice_t runcamDevice
;
42 runcamDevice_t
*camDevice
= &runcamDevice
;
43 rcdeviceSwitchState_t switchStates
[BOXCAMERA3
- BOXCAMERA1
+ 1];
44 bool rcdeviceInMenu
= false;
45 bool isButtonPressed
= false;
46 bool waitingDeviceResponse
= false;
49 static bool isFeatureSupported(uint8_t feature
)
53 if (!rcdeviceIsEnabled() && osdJoystickEnabled() ) {
59 if (camDevice
->info
.features
& feature
) {
66 bool rcdeviceIsEnabled(void)
68 return camDevice
->serialPort
!= NULL
;
71 static void rcdeviceCameraControlProcess(void)
73 for (boxId_e i
= BOXCAMERA1
; i
<= BOXCAMERA3
; i
++) {
74 uint8_t switchIndex
= i
- BOXCAMERA1
;
76 if (IS_RC_MODE_ACTIVE(i
)) {
77 // check last state of this mode, if it's true, then ignore it.
78 // Here is a logic to make a toggle control for this mode
79 if (switchStates
[switchIndex
].isActivated
) {
83 uint8_t behavior
= RCDEVICE_PROTOCOL_CAM_CTRL_UNKNOWN_CAMERA_OPERATION
;
84 uint8_t behavior1
= RCDEVICE_PROTOCOL_CAM_CTRL_UNKNOWN_CAMERA_OPERATION
;
87 if (isFeatureSupported(RCDEVICE_PROTOCOL_FEATURE_SIMULATE_WIFI_BUTTON
)) {
88 // avoid display wifi page when arming, in the next firmware(>2.0) of rcsplit we have change the wifi page logic:
89 // when the wifi was turn on it won't turn off the analog video output,
90 // and just put a wifi indicator on the right top of the video output. here is for the old split firmware
91 if (!ARMING_FLAG(ARMED
)) {
92 behavior
= RCDEVICE_PROTOCOL_CAM_CTRL_SIMULATE_WIFI_BTN
;
94 behavior1
= RCDEVICE_PROTOCOL_CAM_CTRL_SIMULATE_WIFI_BTN
;
98 if (isFeatureSupported(RCDEVICE_PROTOCOL_FEATURE_SIMULATE_POWER_BUTTON
)) {
99 behavior
= RCDEVICE_PROTOCOL_CAM_CTRL_SIMULATE_POWER_BTN
;
100 behavior1
= RCDEVICE_PROTOCOL_CAM_CTRL_SIMULATE_POWER_BTN
;
104 if (isFeatureSupported(RCDEVICE_PROTOCOL_FEATURE_CHANGE_MODE
)) {
105 // avoid change camera mode when arming
106 if (!ARMING_FLAG(ARMED
)) {
107 behavior
= RCDEVICE_PROTOCOL_CAM_CTRL_CHANGE_MODE
;
109 behavior1
= RCDEVICE_PROTOCOL_CAM_CTRL_CHANGE_MODE
;
115 if ((behavior
!= RCDEVICE_PROTOCOL_CAM_CTRL_UNKNOWN_CAMERA_OPERATION
) && rcdeviceIsEnabled()) {
116 runcamDeviceSimulateCameraButton(camDevice
, behavior
);
117 switchStates
[switchIndex
].isActivated
= true;
121 else if ((behavior1
!= RCDEVICE_PROTOCOL_CAM_CTRL_UNKNOWN_CAMERA_OPERATION
) && osdJoystickEnabled()) {
123 case RCDEVICE_PROTOCOL_CAM_CTRL_SIMULATE_WIFI_BTN
:
124 osdJoystickSimulate5KeyButtonPress(RCDEVICE_CAM_KEY_ENTER
);
126 case RCDEVICE_PROTOCOL_CAM_CTRL_SIMULATE_POWER_BTN
:
127 osdJoystickSimulate5KeyButtonPress(RCDEVICE_CAM_KEY_UP
);
129 case RCDEVICE_PROTOCOL_CAM_CTRL_CHANGE_MODE
:
130 osdJoystickSimulate5KeyButtonPress(RCDEVICE_CAM_KEY_DOWN
);
133 switchStates
[switchIndex
].isActivated
= true;
141 if (osdJoystickEnabled() && switchStates
[switchIndex
].isActivated
) {
142 osdJoystickSimulate5KeyButtonRelease();
146 switchStates
[switchIndex
].isActivated
= false;
151 static void rcdeviceSimulationOSDCableFailed(rcdeviceResponseParsingContext_t
*ctx
)
153 waitingDeviceResponse
= false;
154 if (ctx
->command
== RCDEVICE_PROTOCOL_COMMAND_5KEY_CONNECTION
) {
155 uint8_t operationID
= ctx
->paramData
[0];
156 if (operationID
== RCDEVICE_PROTOCOL_5KEY_CONNECTION_CLOSE
) {
162 static void rcdeviceSimulationRespHandle(rcdeviceResponseParsingContext_t
*ctx
)
164 if (ctx
->result
!= RCDEVICE_RESP_SUCCESS
) {
165 rcdeviceSimulationOSDCableFailed(ctx
);
166 waitingDeviceResponse
= false;
170 switch (ctx
->command
) {
171 case RCDEVICE_PROTOCOL_COMMAND_5KEY_SIMULATION_RELEASE
:
172 isButtonPressed
= false;
174 case RCDEVICE_PROTOCOL_COMMAND_5KEY_CONNECTION
:
176 // the high 4 bits is the operationID that we sent
177 // the low 4 bits is the result code
178 isButtonPressed
= true;
179 uint8_t operationID
= ctx
->paramData
[0];
180 bool errorCode
= (ctx
->recvBuf
[1] & 0x0F);
181 if (operationID
== RCDEVICE_PROTOCOL_5KEY_CONNECTION_OPEN
) {
182 if (errorCode
== 1) {
183 rcdeviceInMenu
= true;
184 beeper(BEEPER_CAM_CONNECTION_OPEN
);
186 beeper(BEEPER_CAM_CONNECTION_CLOSE
);
188 } else if (operationID
== RCDEVICE_PROTOCOL_5KEY_CONNECTION_CLOSE
) {
189 if (errorCode
== 1) {
190 rcdeviceInMenu
= false;
191 beeper(BEEPER_CAM_CONNECTION_CLOSE
);
196 case RCDEVICE_PROTOCOL_COMMAND_5KEY_SIMULATION_PRESS
:
197 isButtonPressed
= true;
201 waitingDeviceResponse
= false;
204 static void rcdeviceCamSimulate5KeyCablePress(rcdeviceCamSimulationKeyEvent_e key
)
206 uint8_t operation
= RCDEVICE_PROTOCOL_5KEY_SIMULATION_NONE
;
208 case RCDEVICE_CAM_KEY_LEFT
:
209 operation
= RCDEVICE_PROTOCOL_5KEY_SIMULATION_LEFT
;
211 case RCDEVICE_CAM_KEY_UP
:
212 operation
= RCDEVICE_PROTOCOL_5KEY_SIMULATION_UP
;
214 case RCDEVICE_CAM_KEY_RIGHT
:
215 operation
= RCDEVICE_PROTOCOL_5KEY_SIMULATION_RIGHT
;
217 case RCDEVICE_CAM_KEY_DOWN
:
218 operation
= RCDEVICE_PROTOCOL_5KEY_SIMULATION_DOWN
;
220 case RCDEVICE_CAM_KEY_ENTER
:
221 operation
= RCDEVICE_PROTOCOL_5KEY_SIMULATION_SET
;
223 case RCDEVICE_CAM_KEY_NONE
:
225 operation
= RCDEVICE_PROTOCOL_5KEY_SIMULATION_NONE
;
229 runcamDeviceSimulate5KeyOSDCableButtonPress(camDevice
, operation
, rcdeviceSimulationRespHandle
);
232 void rcdeviceSend5KeyOSDCableSimualtionEvent(rcdeviceCamSimulationKeyEvent_e key
)
235 case RCDEVICE_CAM_KEY_CONNECTION_OPEN
:
236 runcamDeviceOpen5KeyOSDCableConnection(camDevice
, rcdeviceSimulationRespHandle
);
238 case RCDEVICE_CAM_KEY_CONNECTION_CLOSE
:
239 runcamDeviceClose5KeyOSDCableConnection(camDevice
, rcdeviceSimulationRespHandle
);
241 case RCDEVICE_CAM_KEY_ENTER
:
242 case RCDEVICE_CAM_KEY_LEFT
:
243 case RCDEVICE_CAM_KEY_UP
:
244 case RCDEVICE_CAM_KEY_RIGHT
:
245 case RCDEVICE_CAM_KEY_DOWN
:
246 rcdeviceCamSimulate5KeyCablePress(key
);
248 case RCDEVICE_CAM_KEY_RELEASE
:
249 runcamDeviceSimulate5KeyOSDCableButtonRelease(camDevice
, rcdeviceSimulationRespHandle
);
251 case RCDEVICE_CAM_KEY_NONE
:
257 static void rcdevice5KeySimulationProcess(timeUs_t currentTimeUs
)
259 UNUSED(currentTimeUs
);
267 if (ARMING_FLAG(ARMED
)) {
271 if (isButtonPressed
) {
272 if (IS_MID(YAW
) && IS_MID(PITCH
) && IS_MID(ROLL
)) {
273 if ( rcdeviceIsEnabled() ) {
274 rcdeviceSend5KeyOSDCableSimualtionEvent(RCDEVICE_CAM_KEY_RELEASE
);
275 waitingDeviceResponse
= true;
279 else if (osdJoystickEnabled()) {
280 osdJoystickSimulate5KeyButtonRelease();
281 isButtonPressed
= false;
287 if (waitingDeviceResponse
) {
291 rcdeviceCamSimulationKeyEvent_e key
= RCDEVICE_CAM_KEY_NONE
;
293 if (IS_MID(THROTTLE
) && IS_MID(ROLL
) && IS_MID(PITCH
) && IS_LO(YAW
)) { // Disconnect Lo YAW
294 if (rcdeviceInMenu
) {
295 key
= RCDEVICE_CAM_KEY_CONNECTION_CLOSE
;
298 if (rcdeviceInMenu
) {
299 if (IS_LO(ROLL
)) { // Left LO ROLL
300 key
= RCDEVICE_CAM_KEY_LEFT
;
301 } else if (IS_HI(PITCH
)) { // Up HI PITCH
302 key
= RCDEVICE_CAM_KEY_UP
;
303 } else if (IS_HI(ROLL
)) { // Right HI ROLL
304 key
= RCDEVICE_CAM_KEY_RIGHT
;
305 } else if (IS_LO(PITCH
)) { // Down LO PITCH
306 key
= RCDEVICE_CAM_KEY_DOWN
;
307 } else if (IS_MID(THROTTLE
) && IS_MID(ROLL
) && IS_MID(PITCH
) && IS_HI(YAW
)) { // Enter HI YAW
308 key
= RCDEVICE_CAM_KEY_ENTER
;
311 if (IS_MID(THROTTLE
) && IS_MID(ROLL
) && IS_MID(PITCH
) && IS_HI(YAW
)) { // Enter HI YAW
312 key
= RCDEVICE_CAM_KEY_CONNECTION_OPEN
;
317 if (key
!= RCDEVICE_CAM_KEY_NONE
) {
318 if ( rcdeviceIsEnabled() ) {
319 rcdeviceSend5KeyOSDCableSimualtionEvent(key
);
320 waitingDeviceResponse
= true;
324 else if (osdJoystickEnabled()) {
325 if ( key
== RCDEVICE_CAM_KEY_CONNECTION_OPEN
) {
326 rcdeviceInMenu
= true;
327 } else if ( key
== RCDEVICE_CAM_KEY_CONNECTION_CLOSE
) {
328 rcdeviceInMenu
= false;
330 osdJoystickSimulate5KeyButtonPress(key
);
335 isButtonPressed
= true;
340 void rcdeviceUpdate(timeUs_t currentTimeUs
)
342 if ( rcdeviceIsEnabled() ) {
343 rcdeviceReceive(currentTimeUs
);
346 rcdeviceCameraControlProcess();
348 rcdevice5KeySimulationProcess(currentTimeUs
);
351 void rcdeviceInit(void)
354 runcamDeviceInit(camDevice
);
356 for (boxId_e i
= BOXCAMERA1
; i
<= BOXCAMERA3
; i
++) {
357 uint8_t switchIndex
= i
- BOXCAMERA1
;
358 switchStates
[switchIndex
].isActivated
= true;