/* Inspired by work done here https://github.com/PX4/Firmware/tree/master/src/drivers/frsky_telemetry from Stefan Rado https://github.com/opentx/opentx/tree/2.3/radio/src/telemetry from the OpenTX team This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* FRSKY Telemetry library */ #include "AP_Frsky_Telem.h" #include "AP_Frsky_Parameters.h" #include #include #include "AP_Frsky_D.h" #include "AP_Frsky_SPort.h" #include "AP_Frsky_SPort_Passthrough.h" extern const AP_HAL::HAL& hal; AP_Frsky_Telem *AP_Frsky_Telem::singleton; AP_Frsky_Telem::AP_Frsky_Telem() { singleton = this; #if HAL_WITH_FRSKY_TELEM_BIDIRECTIONAL _frsky_parameters = &AP::vehicle()->frsky_parameters; #endif //HAL_WITH_FRSKY_TELEM_BIDIRECTIONAL } AP_Frsky_Telem::~AP_Frsky_Telem(void) { singleton = nullptr; } /* * init - perform required initialisation */ bool AP_Frsky_Telem::init(bool use_external_data) { const AP_SerialManager &serial_manager = AP::serialmanager(); // check for protocol configured for a serial port - only the first serial port with one of these protocols will then run (cannot have FrSky on multiple serial ports) AP_HAL::UARTDriver *port; if ((port = serial_manager.find_serial(AP_SerialManager::SerialProtocol_FrSky_D, 0))) { _backend = new AP_Frsky_D(port); } else if ((port = serial_manager.find_serial(AP_SerialManager::SerialProtocol_FrSky_SPort, 0))) { _backend = new AP_Frsky_SPort(port); } else if (use_external_data || (port = serial_manager.find_serial(AP_SerialManager::SerialProtocol_FrSky_SPort_Passthrough, 0))) { _backend = new AP_Frsky_SPort_Passthrough(port, use_external_data, _frsky_parameters); } if (_backend == nullptr) { return false; } if (!_backend->init()) { delete _backend; _backend = nullptr; return false; } return true; } bool AP_Frsky_Telem::_get_telem_data(AP_Frsky_Backend::sport_packet_t* packet_array, uint8_t &packet_count, const uint8_t max_size) { if (_backend == nullptr) { return false; } if (packet_array == nullptr) { return false; } return _backend->get_telem_data(packet_array, packet_count, max_size); } #if HAL_WITH_FRSKY_TELEM_BIDIRECTIONAL bool AP_Frsky_Telem::_set_telem_data(uint8_t frame, uint16_t appid, uint32_t data) { if (_backend == nullptr) { return false; } return _backend->set_telem_data(frame, appid, data); } #endif void AP_Frsky_Telem::try_create_singleton_for_external_data() { // try to allocate an AP_Frsky_Telem object only if we are disarmed if (!singleton && !hal.util->get_soft_armed()) { new AP_Frsky_Telem(); // initialize the passthrough scheduler if (singleton) { singleton->init(true); } } } /* fetch Sport data for an external transport, such as FPort */ bool AP_Frsky_Telem::get_telem_data(AP_Frsky_Backend::sport_packet_t* packet_array, uint8_t &packet_count, const uint8_t max_size) { try_create_singleton_for_external_data(); if (singleton == nullptr) { return false; } return singleton->_get_telem_data(packet_array, packet_count, max_size); } #if HAL_WITH_FRSKY_TELEM_BIDIRECTIONAL /* allow external transports (e.g. FPort), to supply telemetry data */ bool AP_Frsky_Telem::set_telem_data(const uint8_t frame, const uint16_t appid, const uint32_t data) { try_create_singleton_for_external_data(); if (singleton == nullptr) { return false; } return singleton->_set_telem_data(frame, appid, data); } #endif namespace AP { AP_Frsky_Telem *frsky_telem() { return AP_Frsky_Telem::get_singleton(); } };