Line data Source code
1 : /* 2 : * This file is free software: you can redistribute it and/or modify it 3 : * under the terms of the GNU General Public License as published by the 4 : * Free Software Foundation, either version 3 of the License, or 5 : * (at your option) any later version. 6 : * 7 : * This file is distributed in the hope that it will be useful, but 8 : * WITHOUT ANY WARRANTY; without even the implied warranty of 9 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 10 : * See the GNU General Public License for more details. 11 : * 12 : * You should have received a copy of the GNU General Public License along 13 : * with this program. If not, see <http://www.gnu.org/licenses/>. 14 : * 15 : * Code by Andrew Tridgell and Siddharth Bharat Purohit 16 : */ 17 : #pragma once 18 : 19 : #include "AP_RCProtocol_config.h" 20 : 21 : #include <AP_HAL/AP_HAL.h> 22 : #include <AP_Common/AP_Common.h> 23 : #if AP_RCPROTOCOL_MAVLINK_RADIO_ENABLED 24 : #include <GCS_MAVLink/GCS_MAVLink.h> 25 : #endif 26 : 27 : #define MAX_RCIN_CHANNELS 18 28 : #define MIN_RCIN_CHANNELS 5 29 : 30 : class AP_RCProtocol_Backend; 31 : 32 : class AP_RCProtocol { 33 : public: 34 : 35 : enum rcprotocol_t { 36 : #if AP_RCPROTOCOL_PPMSUM_ENABLED 37 : PPMSUM = 0, 38 : #endif 39 : #if AP_RCPROTOCOL_IBUS_ENABLED 40 : IBUS = 1, 41 : #endif 42 : #if AP_RCPROTOCOL_SBUS_ENABLED 43 : SBUS = 2, 44 : #endif 45 : #if AP_RCPROTOCOL_SBUS_NI_ENABLED 46 : SBUS_NI = 3, 47 : #endif 48 : #if AP_RCPROTOCOL_DSM_ENABLED 49 : DSM = 4, 50 : #endif 51 : #if AP_RCPROTOCOL_SUMD_ENABLED 52 : SUMD = 5, 53 : #endif 54 : #if AP_RCPROTOCOL_SRXL_ENABLED 55 : SRXL = 6, 56 : #endif 57 : #if AP_RCPROTOCOL_SRXL2_ENABLED 58 : SRXL2 = 7, 59 : #endif 60 : #if AP_RCPROTOCOL_CRSF_ENABLED 61 : CRSF = 8, 62 : #endif 63 : #if AP_RCPROTOCOL_ST24_ENABLED 64 : ST24 = 9, 65 : #endif 66 : #if AP_RCPROTOCOL_FPORT_ENABLED 67 : FPORT = 10, 68 : #endif 69 : #if AP_RCPROTOCOL_FPORT2_ENABLED 70 : FPORT2 = 11, 71 : #endif 72 : #if AP_RCPROTOCOL_FASTSBUS_ENABLED 73 : FASTSBUS = 12, 74 : #endif 75 : #if AP_RCPROTOCOL_DRONECAN_ENABLED 76 : DRONECAN = 13, 77 : #endif 78 : #if AP_RCPROTOCOL_GHST_ENABLED 79 : GHST = 14, 80 : #endif 81 : #if AP_RCPROTOCOL_MAVLINK_RADIO_ENABLED 82 : MAVLINK_RADIO = 15, 83 : #endif 84 : #if AP_RCPROTOCOL_JOYSTICK_SFML_ENABLED 85 : JOYSTICK_SFML = 16, 86 : #endif 87 : #if AP_RCPROTOCOL_UDP_ENABLED 88 : UDP = 17, 89 : #endif 90 : #if AP_RCPROTOCOL_FDM_ENABLED 91 : FDM = 18, 92 : #endif 93 : #if AP_RCPROTOCOL_RADIO_ENABLED 94 : RADIO = 19, 95 : #endif 96 : #if AP_RCPROTOCOL_IOMCU_ENABLED 97 : IOMCU = 20, 98 : #endif // AP_RCPROTOCOL_IOMCU_ENABLED 99 : #if AP_RCPROTOCOL_EMLID_RCIO_ENABLED 100 : EMLID_RCIO = 21, 101 : #endif 102 : NONE //last enum always is None 103 : }; 104 : 105 : // return protocol name as a string 106 : static const char *protocol_name_from_protocol(rcprotocol_t protocol); 107 : 108 : #if AP_RCPROTOCOL_ENABLED 109 : 110 2094 : AP_RCProtocol() {} 111 : ~AP_RCProtocol(); 112 : friend class AP_RCProtocol_Backend; 113 : 114 : void init(); 115 : bool valid_serial_prot() const 116 : { 117 : return _valid_serial_prot; 118 : } 119 : bool should_search(uint32_t now_ms) const; 120 : void process_pulse(uint32_t width_s0, uint32_t width_s1); 121 : void process_pulse_list(const uint32_t *widths, uint16_t n, bool need_swap); 122 : bool process_byte(uint8_t byte, uint32_t baudrate); 123 : void process_handshake(uint32_t baudrate); 124 : void update(void); 125 : 126 2200594 : bool failsafe_active() const { 127 2200594 : return _failsafe_active; 128 : } 129 7510171 : void set_failsafe_active(bool active) { 130 7510171 : _failsafe_active = active; 131 7510171 : } 132 : 133 : void disable_for_pulses(enum rcprotocol_t protocol) { 134 : _disabled_for_pulses |= (1U<<(uint8_t)protocol); 135 : } 136 : 137 : #if !defined(__clang__) 138 : // in the case we've disabled most backends then the "return true" in 139 : // the following method can never be reached, and the compiler gets 140 : // annoyed at that. 141 : #pragma GCC diagnostic push 142 : #pragma GCC diagnostic ignored "-Wswitch-unreachable" 143 : #endif 144 : 145 : // for protocols without strong CRCs we require 3 good frames to lock on 146 0 : bool requires_3_frames(enum rcprotocol_t p) { 147 0 : switch (p) { 148 : #if AP_RCPROTOCOL_DSM_ENABLED 149 0 : case DSM: 150 : #endif 151 : #if AP_RCPROTOCOL_FASTSBUS_ENABLED 152 : case FASTSBUS: 153 : #endif 154 : #if AP_RCPROTOCOL_SBUS_ENABLED 155 : case SBUS: 156 : #endif 157 : #if AP_RCPROTOCOL_SBUS_NI_ENABLED 158 : case SBUS_NI: 159 : #endif 160 : #if AP_RCPROTOCOL_PPMSUM_ENABLED 161 : case PPMSUM: 162 : #endif 163 : #if AP_RCPROTOCOL_FPORT_ENABLED 164 : case FPORT: 165 : #endif 166 : #if AP_RCPROTOCOL_FPORT2_ENABLED 167 : case FPORT2: 168 : #endif 169 : #if AP_RCPROTOCOL_CRSF_ENABLED 170 : case CRSF: 171 : #endif 172 : #if AP_RCPROTOCOL_GHST_ENABLED 173 : case GHST: 174 : #endif 175 0 : return true; 176 : #if AP_RCPROTOCOL_IBUS_ENABLED 177 0 : case IBUS: 178 : #endif 179 : #if AP_RCPROTOCOL_SUMD_ENABLED 180 : case SUMD: 181 : #endif 182 : #if AP_RCPROTOCOL_SRXL_ENABLED 183 : case SRXL: 184 : #endif 185 : #if AP_RCPROTOCOL_SRXL2_ENABLED 186 : case SRXL2: 187 : #endif 188 : #if AP_RCPROTOCOL_ST24_ENABLED 189 : case ST24: 190 : #endif 191 : #if AP_RCPROTOCOL_DRONECAN_ENABLED 192 : case DRONECAN: 193 : #endif 194 : #if AP_RCPROTOCOL_MAVLINK_RADIO_ENABLED 195 : case MAVLINK_RADIO: 196 : #endif 197 : #if AP_RCPROTOCOL_JOYSTICK_SFML_ENABLED 198 : case JOYSTICK_SFML: 199 : #endif 200 : #if AP_RCPROTOCOL_UDP_ENABLED 201 : case UDP: 202 : #endif 203 : #if AP_RCPROTOCOL_FDM_ENABLED 204 : case FDM: 205 : #endif 206 : #if AP_RCPROTOCOL_RADIO_ENABLED 207 : case RADIO: 208 : #endif 209 : #if AP_RCPROTOCOL_IOMCU_ENABLED 210 : case IOMCU: 211 : #endif // AP_RCPROTOCOL_IOMCU_ENABLED 212 : #if AP_RCPROTOCOL_EMLID_RCIO_ENABLED 213 : case EMLID_RCIO: 214 : #endif 215 : case NONE: 216 0 : return false; 217 : } 218 0 : return false; 219 : } 220 : #if !defined(__clang__) 221 : #pragma GCC diagnostic pop 222 : #endif 223 : 224 : uint8_t num_channels(); 225 : uint16_t read(uint8_t chan); 226 : void read(uint16_t *pwm, uint8_t n); 227 : bool new_input(); 228 : void start_bind(); 229 : int16_t get_RSSI(void) const; 230 : int16_t get_rx_link_quality(void) const; 231 : 232 : // return detected protocol. In the case that backend can provide 233 : // information on what *it* is decoding that will be returned by 234 : // this method. As opposed to "protocol_name" which will be the 235 : // backend name e.g. "IOMCU". 236 : const char *detected_protocol_name() const; 237 : 238 : // return detected protocol 239 : enum rcprotocol_t protocol_detected(void) const { 240 : return _detected_protocol; 241 : } 242 : 243 : // add a UART for RCIN 244 : void add_uart(AP_HAL::UARTDriver* uart); 245 1 : bool has_uart() const { return added.uart != nullptr; } 246 : 247 : // set allowed RC protocols 248 : void set_rc_protocols(uint32_t mask) { 249 : rc_protocols_mask = mask; 250 : } 251 : 252 : class SerialConfig { 253 : public: 254 : void apply_to_uart(AP_HAL::UARTDriver *uart) const; 255 : 256 : uint32_t baud; 257 : uint8_t parity; 258 : uint8_t stop_bits; 259 : bool invert_rx; 260 : }; 261 : 262 : // return true if we are decoding a byte stream, instead of pulses 263 36179583 : bool using_uart(void) const { 264 36179583 : return _detected_with_bytes; 265 : } 266 : 267 : // handle mavlink radio 268 : #if AP_RCPROTOCOL_MAVLINK_RADIO_ENABLED 269 : void handle_radio_rc_channels(const mavlink_radio_rc_channels_t* packet); 270 : #endif 271 : 272 : // some backends have a struct LinkStatus and a field _link_status, avoid name clash 273 : struct RcLinkStatus { 274 : int16_t link_quality = -1; 275 : int16_t tx_power = -1; 276 : int8_t rssi_dbm = -1; 277 : int8_t snr = INT8_MIN; 278 : int8_t active_antenna = -1; 279 : }; 280 : volatile struct RcLinkStatus _rc_link_status; 281 : 282 : const volatile RcLinkStatus& get_link_status() const { return _rc_link_status; } 283 : 284 : private: 285 : void check_added_uart(void); 286 : 287 : // return true if a specific protocol is enabled 288 : bool protocol_enabled(enum rcprotocol_t protocol) const; 289 : 290 : // explicitly investigate a backend for data, as opposed to 291 : // feeding the backend a byte (or pulse-train) at a time and 292 : // having them make an "add_input" callback): 293 : bool detect_async_protocol(rcprotocol_t protocol); 294 : 295 : enum rcprotocol_t _detected_protocol = NONE; 296 : uint16_t _disabled_for_pulses; 297 : bool _detected_with_bytes; 298 : AP_RCProtocol_Backend *backend[NONE]; 299 : bool _new_input; 300 : uint32_t _last_input_ms; 301 : bool _failsafe_active; 302 : bool _valid_serial_prot; 303 : 304 : // optional additional uart 305 : struct { 306 : AP_HAL::UARTDriver *uart; 307 : bool opened; 308 : uint32_t last_config_change_ms; 309 : uint8_t config_num; 310 : } added; 311 : 312 : // allowed RC protocols mask (first bit means "all") 313 : uint32_t rc_protocols_mask; 314 : 315 : rcprotocol_t _last_detected_protocol; 316 : bool _last_detected_using_uart; 317 : void announce_detected(); 318 : 319 : #endif // AP_RCPROTOCOL_ENABLED 320 : 321 : }; 322 : 323 : #if AP_RCPROTOCOL_ENABLED 324 : namespace AP { 325 : AP_RCProtocol &RC(); 326 : }; 327 : 328 : #include "AP_RCProtocol_Backend.h" 329 : #endif // AP_RCPROTOCOL_ENABLED