Fix WS2812 led definition
[inav.git] / src / main / io / rcdevice_cam.c
blob36a0f998690c742d5b97f3d15e94ae37fa204d8b
1 /*
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/>.
18 #include <stdbool.h>
19 #include <stdint.h>
20 #include <stddef.h>
22 #include "cms/cms.h"
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"
33 #include "rx/rx.h"
35 #ifdef USE_RCDEVICE
37 #define IS_HI(X) (rxGetChannelValue(X) > FIVE_KEY_CABLE_JOYSTICK_MAX)
38 #define IS_LO(X) (rxGetChannelValue(X) < FIVE_KEY_CABLE_JOYSTICK_MIN)
39 #define IS_MID(X) (rxGetChannelValue(X) > FIVE_KEY_CABLE_JOYSTICK_MID_START && rxGetChannelValue(X) < FIVE_KEY_CABLE_JOYSTICK_MID_END)
40 static runcamDevice_t runcamDevice;
41 runcamDevice_t *camDevice = &runcamDevice;
42 rcdeviceSwitchState_t switchStates[BOXCAMERA3 - BOXCAMERA1 + 1];
43 bool rcdeviceInMenu = false;
44 bool isButtonPressed = false;
45 bool waitingDeviceResponse = false;
48 static bool isFeatureSupported(uint8_t feature)
50 if (camDevice->info.features & feature) {
51 return true;
54 return false;
57 bool rcdeviceIsEnabled(void)
59 return camDevice->serialPort != NULL;
62 static void rcdeviceCameraControlProcess(void)
64 for (boxId_e i = BOXCAMERA1; i <= BOXCAMERA3; i++) {
65 uint8_t switchIndex = i - BOXCAMERA1;
67 if (IS_RC_MODE_ACTIVE(i)) {
68 // check last state of this mode, if it's true, then ignore it.
69 // Here is a logic to make a toggle control for this mode
70 if (switchStates[switchIndex].isActivated) {
71 continue;
74 uint8_t behavior = RCDEVICE_PROTOCOL_CAM_CTRL_UNKNOWN_CAMERA_OPERATION;
75 switch (i) {
76 case BOXCAMERA1:
77 if (isFeatureSupported(RCDEVICE_PROTOCOL_FEATURE_SIMULATE_WIFI_BUTTON)) {
78 // avoid display wifi page when arming, in the next firmware(>2.0) of rcsplit we have change the wifi page logic:
79 // when the wifi was turn on it won't turn off the analog video output,
80 // and just put a wifi indicator on the right top of the video output. here is for the old split firmware
81 if (!ARMING_FLAG(ARMED)) {
82 behavior = RCDEVICE_PROTOCOL_CAM_CTRL_SIMULATE_WIFI_BTN;
85 break;
86 case BOXCAMERA2:
87 if (isFeatureSupported(RCDEVICE_PROTOCOL_FEATURE_SIMULATE_POWER_BUTTON)) {
88 behavior = RCDEVICE_PROTOCOL_CAM_CTRL_SIMULATE_POWER_BTN;
90 break;
91 case BOXCAMERA3:
92 if (isFeatureSupported(RCDEVICE_PROTOCOL_FEATURE_CHANGE_MODE)) {
93 // avoid change camera mode when arming
94 if (!ARMING_FLAG(ARMED)) {
95 behavior = RCDEVICE_PROTOCOL_CAM_CTRL_CHANGE_MODE;
98 break;
99 default:
100 break;
102 if (behavior != RCDEVICE_PROTOCOL_CAM_CTRL_UNKNOWN_CAMERA_OPERATION) {
103 runcamDeviceSimulateCameraButton(camDevice, behavior);
104 switchStates[switchIndex].isActivated = true;
106 } else {
107 switchStates[switchIndex].isActivated = false;
112 static void rcdeviceSimulationOSDCableFailed(rcdeviceResponseParsingContext_t *ctx)
114 waitingDeviceResponse = false;
115 if (ctx->command == RCDEVICE_PROTOCOL_COMMAND_5KEY_CONNECTION) {
116 uint8_t operationID = ctx->paramData[0];
117 if (operationID == RCDEVICE_PROTOCOL_5KEY_CONNECTION_CLOSE) {
118 return;
123 static void rcdeviceSimulationRespHandle(rcdeviceResponseParsingContext_t *ctx)
125 if (ctx->result != RCDEVICE_RESP_SUCCESS) {
126 rcdeviceSimulationOSDCableFailed(ctx);
127 waitingDeviceResponse = false;
128 return;
131 switch (ctx->command) {
132 case RCDEVICE_PROTOCOL_COMMAND_5KEY_SIMULATION_RELEASE:
133 isButtonPressed = false;
134 break;
135 case RCDEVICE_PROTOCOL_COMMAND_5KEY_CONNECTION:
137 // the high 4 bits is the operationID that we sent
138 // the low 4 bits is the result code
139 isButtonPressed = true;
140 uint8_t operationID = ctx->paramData[0];
141 bool errorCode = (ctx->recvBuf[1] & 0x0F);
142 if (operationID == RCDEVICE_PROTOCOL_5KEY_CONNECTION_OPEN) {
143 if (errorCode == 1) {
144 rcdeviceInMenu = true;
145 beeper(BEEPER_CAM_CONNECTION_OPEN);
146 } else {
147 beeper(BEEPER_CAM_CONNECTION_CLOSE);
149 } else if (operationID == RCDEVICE_PROTOCOL_5KEY_CONNECTION_CLOSE) {
150 if (errorCode == 1) {
151 rcdeviceInMenu = false;
152 beeper(BEEPER_CAM_CONNECTION_CLOSE);
156 break;
157 case RCDEVICE_PROTOCOL_COMMAND_5KEY_SIMULATION_PRESS:
158 isButtonPressed = true;
159 break;
162 waitingDeviceResponse = false;
165 static void rcdeviceCamSimulate5KeyCablePress(rcdeviceCamSimulationKeyEvent_e key)
167 uint8_t operation = RCDEVICE_PROTOCOL_5KEY_SIMULATION_NONE;
168 switch (key) {
169 case RCDEVICE_CAM_KEY_LEFT:
170 operation = RCDEVICE_PROTOCOL_5KEY_SIMULATION_LEFT;
171 break;
172 case RCDEVICE_CAM_KEY_UP:
173 operation = RCDEVICE_PROTOCOL_5KEY_SIMULATION_UP;
174 break;
175 case RCDEVICE_CAM_KEY_RIGHT:
176 operation = RCDEVICE_PROTOCOL_5KEY_SIMULATION_RIGHT;
177 break;
178 case RCDEVICE_CAM_KEY_DOWN:
179 operation = RCDEVICE_PROTOCOL_5KEY_SIMULATION_DOWN;
180 break;
181 case RCDEVICE_CAM_KEY_ENTER:
182 operation = RCDEVICE_PROTOCOL_5KEY_SIMULATION_SET;
183 break;
184 case RCDEVICE_CAM_KEY_NONE:
185 default:
186 operation = RCDEVICE_PROTOCOL_5KEY_SIMULATION_NONE;
187 break;
190 runcamDeviceSimulate5KeyOSDCableButtonPress(camDevice, operation, rcdeviceSimulationRespHandle);
193 void rcdeviceSend5KeyOSDCableSimualtionEvent(rcdeviceCamSimulationKeyEvent_e key)
195 switch (key) {
196 case RCDEVICE_CAM_KEY_CONNECTION_OPEN:
197 runcamDeviceOpen5KeyOSDCableConnection(camDevice, rcdeviceSimulationRespHandle);
198 break;
199 case RCDEVICE_CAM_KEY_CONNECTION_CLOSE:
200 runcamDeviceClose5KeyOSDCableConnection(camDevice, rcdeviceSimulationRespHandle);
201 break;
202 case RCDEVICE_CAM_KEY_ENTER:
203 case RCDEVICE_CAM_KEY_LEFT:
204 case RCDEVICE_CAM_KEY_UP:
205 case RCDEVICE_CAM_KEY_RIGHT:
206 case RCDEVICE_CAM_KEY_DOWN:
207 rcdeviceCamSimulate5KeyCablePress(key);
208 break;
209 case RCDEVICE_CAM_KEY_RELEASE:
210 runcamDeviceSimulate5KeyOSDCableButtonRelease(camDevice, rcdeviceSimulationRespHandle);
211 break;
212 case RCDEVICE_CAM_KEY_NONE:
213 default:
214 break;
218 static void rcdevice5KeySimulationProcess(timeUs_t currentTimeUs)
220 UNUSED(currentTimeUs);
222 #ifdef USE_CMS
223 if (cmsInMenu) {
224 return;
226 #endif
228 if (camDevice->serialPort == 0 || ARMING_FLAG(ARMED)) {
229 return;
232 if (isButtonPressed) {
233 if (IS_MID(YAW) && IS_MID(PITCH) && IS_MID(ROLL)) {
234 rcdeviceSend5KeyOSDCableSimualtionEvent(RCDEVICE_CAM_KEY_RELEASE);
235 waitingDeviceResponse = true;
237 } else {
238 if (waitingDeviceResponse) {
239 return;
242 rcdeviceCamSimulationKeyEvent_e key = RCDEVICE_CAM_KEY_NONE;
244 if (IS_MID(THROTTLE) && IS_MID(ROLL) && IS_MID(PITCH) && IS_LO(YAW)) { // Disconnect Lo YAW
245 if (rcdeviceInMenu) {
246 key = RCDEVICE_CAM_KEY_CONNECTION_CLOSE;
248 } else {
249 if (rcdeviceInMenu) {
250 if (IS_LO(ROLL)) { // Left LO ROLL
251 key = RCDEVICE_CAM_KEY_LEFT;
252 } else if (IS_HI(PITCH)) { // Up HI PITCH
253 key = RCDEVICE_CAM_KEY_UP;
254 } else if (IS_HI(ROLL)) { // Right HI ROLL
255 key = RCDEVICE_CAM_KEY_RIGHT;
256 } else if (IS_LO(PITCH)) { // Down LO PITCH
257 key = RCDEVICE_CAM_KEY_DOWN;
258 } else if (IS_MID(THROTTLE) && IS_MID(ROLL) && IS_MID(PITCH) && IS_HI(YAW)) { // Enter HI YAW
259 key = RCDEVICE_CAM_KEY_ENTER;
261 } else {
262 if (IS_MID(THROTTLE) && IS_MID(ROLL) && IS_MID(PITCH) && IS_HI(YAW)) { // Enter HI YAW
263 key = RCDEVICE_CAM_KEY_CONNECTION_OPEN;
268 if (key != RCDEVICE_CAM_KEY_NONE) {
269 rcdeviceSend5KeyOSDCableSimualtionEvent(key);
270 isButtonPressed = true;
271 waitingDeviceResponse = true;
276 void rcdeviceUpdate(timeUs_t currentTimeUs)
278 rcdeviceReceive(currentTimeUs);
280 rcdeviceCameraControlProcess();
282 rcdevice5KeySimulationProcess(currentTimeUs);
285 void rcdeviceInit(void)
287 // open serial port
288 runcamDeviceInit(camDevice);
290 for (boxId_e i = BOXCAMERA1; i <= BOXCAMERA3; i++) {
291 uint8_t switchIndex = i - BOXCAMERA1;
292 switchStates[switchIndex].isActivated = true;
296 #endif