#pragma once #include "AP_Frsky_SPort.h" #if AP_FRSKY_SPORT_PASSTHROUGH_ENABLED #include #include "AP_Frsky_SPortParser.h" #include "AP_Frsky_MAVlite.h" #include "AP_Frsky_Telem.h" #if HAL_WITH_FRSKY_TELEM_BIDIRECTIONAL #include "AP_Frsky_MAVlite_SPortToMAVlite.h" #include "AP_Frsky_MAVlite_MAVliteToSPort.h" #include "AP_Frsky_MAVliteMsgHandler.h" #define SPORT_TX_PACKET_DUPLICATES 1 // number of duplicates packets we send (fport only) #endif class AP_Frsky_SPort_Passthrough : public AP_Frsky_SPort, public AP_RCTelemetry { public: AP_Frsky_SPort_Passthrough(AP_HAL::UARTDriver *port, bool use_external_data, AP_Frsky_Parameters *&frsky_parameters) : AP_Frsky_SPort(port), AP_RCTelemetry(WFQ_LAST_ITEM), _use_external_data(use_external_data), _frsky_parameters(frsky_parameters) { singleton = this; } static AP_Frsky_SPort_Passthrough *get_singleton(void) { return singleton; } bool init() override; bool init_serial_port() override; // passthrough WFQ scheduler bool is_packet_ready(uint8_t idx, bool queue_empty) override; void process_packet(uint8_t idx) override; void adjust_packet_weight(bool queue_empty) override; // setup ready for passthrough operation void setup_wfq_scheduler(void) override; bool get_next_msg_chunk(void) override; bool get_telem_data(sport_packet_t* packet_array, uint8_t &packet_count, const uint8_t max_size) override; #if HAL_WITH_FRSKY_TELEM_BIDIRECTIONAL bool set_telem_data(const uint8_t frame, const uint16_t appid, const uint32_t data) override; #endif //HAL_WITH_FRSKY_TELEM_BIDIRECTIONAL void queue_text_message(MAV_SEVERITY severity, const char *text) override { AP_RCTelemetry::queue_message(severity, text); } enum PassthroughPacketType : uint8_t { TEXT = 0, // 0x5000 status text (dynamic) ATTITUDE = 1, // 0x5006 Attitude and range (dynamic) GPS_LAT = 2, // 0x800 GPS lat GPS_LON = 3, // 0x800 GPS lon VEL_YAW = 4, // 0x5005 Vel and Yaw AP_STATUS = 5, // 0x5001 AP status GPS_STATUS = 6, // 0x5002 GPS status HOME = 7, // 0x5004 Home BATT_2 = 8, // 0x5008 Battery 2 status BATT_1 = 9, // 0x5008 Battery 1 status PARAM = 10, // 0x5007 parameters RPM = 11, // 0x500A rpm sensors 1 and 2 UDATA = 12, // user data #if HAL_WITH_FRSKY_TELEM_BIDIRECTIONAL MAV = 13, // mavlite #endif //HAL_WITH_FRSKY_TELEM_BIDIRECTIONAL TERRAIN = 14, // 0x500B terrain data WIND = 15, // 0x500C wind data WAYPOINT = 16, // 0x500D waypoint data WFQ_LAST_ITEM // must be last }; protected: void send() override; private: AP_Frsky_Parameters *&_frsky_parameters; enum PassthroughParam : uint8_t { NONE = 0, FRAME_TYPE = 1, BATT_FS_VOLTAGE = 2, BATT_FS_CAPACITY = 3, BATT_CAPACITY_1 = 4, BATT_CAPACITY_2 = 5, TELEMETRY_FEATURES = 6 }; enum PassthroughFeatures : uint8_t { BIDIR = 0, SCRIPTING = 1, }; // methods to convert flight controller data to FrSky SPort Passthrough (OpenTX) format uint32_t calc_param(void); uint32_t calc_batt(uint8_t instance); uint32_t calc_ap_status(void); uint32_t calc_home(void); uint32_t calc_velandyaw(void); uint32_t calc_attiandrng(void); uint32_t calc_rpm(void); uint32_t calc_terrain(void); uint32_t calc_wind(void); uint32_t calc_waypoint(void); // use_external_data is set when this library will // be providing data to another transport, such as FPort bool _use_external_data; struct { sport_packet_t packet; bool pending; } external_data; struct { uint32_t chunk; // a "chunk" (four characters/bytes) at a time of the queued message to be sent uint8_t repeats; // send each message "chunk" 3 times to make sure the entire messsage gets through without getting cut uint8_t char_index; // index of which character to get in the message } _msg_chunk; // passthrough default sensor id uint8_t downlink_sensor_id = 0x1B; #if HAL_WITH_FRSKY_TELEM_BIDIRECTIONAL // bidirectional sport telemetry struct { uint8_t uplink_sensor_id = 0x0D; uint8_t downlink1_sensor_id = 0x34; uint8_t downlink2_sensor_id = 0x67; uint8_t tx_packet_duplicates; ObjectBuffer_TS rx_packet_queue{SPORT_PACKET_QUEUE_LENGTH}; ObjectBuffer_TS tx_packet_queue{SPORT_PACKET_QUEUE_LENGTH}; } _SPort_bidir; AP_Frsky_SPortParser _sport_handler; AP_Frsky_MAVlite_SPortToMAVlite sport_to_mavlite; AP_Frsky_MAVlite_MAVliteToSPort mavlite_to_sport; void set_sensor_id(AP_Int8 idx, uint8_t &sensor); // tx/rx sport packet processing void queue_rx_packet(const AP_Frsky_SPort::sport_packet_t sp); void process_rx_queue(void); void process_tx_queue(void); // create an object to handle incoming mavlite messages; a // callback method is provided to allow the handler to send responses bool send_message(const AP_Frsky_MAVlite_Message &txmsg); AP_Frsky_MAVliteMsgHandler mavlite{FUNCTOR_BIND_MEMBER(&AP_Frsky_SPort_Passthrough::send_message, bool, const AP_Frsky_MAVlite_Message &)}; #endif void send_sport_frame(uint8_t frame, uint16_t appid, uint32_t data); // true if we need to respond to the last polling byte bool is_passthrough_byte(const uint8_t byte) const; uint8_t _paramID; uint32_t calc_gps_status(void); static AP_Frsky_SPort_Passthrough *singleton; }; namespace AP { AP_Frsky_SPort_Passthrough *frsky_passthrough_telem(); }; #endif // AP_FRSKY_SPORT_PASSTHROUGH_ENABLED