text: /****************************************************************************
   *
   *   Copyright (c) 2012-2018 PX4 Development Team. All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   * 3. Neither the name PX4 nor the names of its contributors may be
   *    used to endorse or promote products derived from this software
   *    without specific prior written permission.
   *
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
   * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
   * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
   * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
   * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
   * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   * POSSIBILITY OF SUCH DAMAGE.
   *
   ****************************************************************************/
  
  /**
   * @file mavlink_main.h
   *
   * MAVLink 2.0 protocol interface definition.
   *
   * @author Lorenz Meier <lorenz@px4.io>
   * @author Anton Babushkin <anton.babushkin@me.com>
   */
  
  #pragma once
  
  #include <pthread.h>
  #include <stdbool.h>
  
  #ifdef __PX4_NUTTX
  #include <nuttx/fs/fs.h>
  #else
  #include <arpa/inet.h>
  #include <drivers/device/device.h>
  #include <sys/socket.h>
  #endif
  
  #if defined(CONFIG_NET) || !defined(__PX4_NUTTX)
  #include <net/if.h>
  #include <netinet/in.h>
  #endif
  
  #include <containers/List.hpp>
  #include <parameters/param.h>
  #include <perf/perf_counter.h>
  #include <px4_platform_common/cli.h>
  #include <px4_platform_common/px4_config.h>
  #include <px4_platform_common/defines.h>
  #include <px4_platform_common/getopt.h>
  #include <px4_platform_common/module.h>
  #include <px4_platform_common/module_params.h>
  #include <px4_platform_common/posix.h>
  #include <uORB/Publication.hpp>
  #include <uORB/PublicationMulti.hpp>
  #include <uORB/SubscriptionInterval.hpp>
  #include <uORB/topics/parameter_update.h>
  #include <uORB/topics/radio_status.h>
  #include <uORB/topics/telemetry_status.h>
  #include <uORB/topics/vehicle_command.h>
  #include <uORB/topics/vehicle_command_ack.h>
  #include <uORB/topics/vehicle_status.h>
  
  #include "mavlink_command_sender.h"
  #include "mavlink_events.h"
  #include "mavlink_messages.h"
  #include "mavlink_receiver.h"
  #include "mavlink_shell.h"
  #include "mavlink_ulog.h"
  
  #define DEFAULT_BAUD_RATE       57600
  #define DEFAULT_DEVICE_NAME     "/dev/ttyS1"
  
  #define HASH_PARAM              "_HASH_CHECK"
  
  #if defined(CONFIG_NET) || defined(__PX4_POSIX)
  # define MAVLINK_UDP
  # define DEFAULT_REMOTE_PORT_UDP 14550 ///< GCS port per MAVLink spec
  #endif // CONFIG_NET || __PX4_POSIX
  
  enum class Protocol {
  	SERIAL = 0,
  #if defined(MAVLINK_UDP)
  	UDP,
  #endif // MAVLINK_UDP
  };
  
  using namespace time_literals;
  
  class Mavlink final : public ModuleParams
  {
  
  public:
  	/**
  	 * Constructor
  	 */
  	Mavlink();
  
  	/**
  	 * Destructor, also kills the mavlinks task.
  	 */
  	~Mavlink();
  
  	/**
  	* Start the mavlink task.
  	 *
  	 * @return OK on success.
  	 */
  	static int		start(int argc, char *argv[]);
  
  	bool running() const { return _task_running.load(); }
  	bool should_exit() const { return _task_should_exit.load(); }
  	void request_stop()
  	{
  		_task_should_exit.store(true);
  		_receiver.request_stop();
  	}
  
  	/**
  	 * Display the mavlink status.
  	 */
  	void			display_status();
  
  	/**
  	 * Display the status of all enabled streams.
  	 */
  	void			display_status_streams();
  
  	static int		stop_command(int argc, char *argv[]);
  	static int		stream_command(int argc, char *argv[]);
  
  	static int		instance_count();
  
  	static Mavlink		*new_instance();
  
  	static Mavlink 		*get_instance_for_device(const char *device_name);
  
  	mavlink_message_t 	*get_buffer() { return &_mavlink_buffer; }
  
  	mavlink_status_t 	*get_status() { return &_mavlink_status; }
  
  	/**
  	 * Set the MAVLink version
  	 *
  	 * Currently supporting v1 and v2
  	 *
  	 * @param version MAVLink version
  	 */
  	void			set_proto_version(unsigned version);
  
  	static int		destroy_all_instances();
  
  	static int		get_status_all_instances(bool show_streams_status);
  
  	static bool		serial_instance_exists(const char *device_name, Mavlink *self);
  
  	static bool		component_was_seen(int system_id, int component_id, Mavlink *self = nullptr);
  
  	static void		forward_message(const mavlink_message_t *msg, Mavlink *self);
  
  	bool			check_events() const { return _should_check_events.load(); }
  	void			check_events_enable() { _should_check_events.store(true); }
  	void			check_events_disable() { _should_check_events.store(false); }
  
  	int			get_uart_fd() const { return _uart_fd; }
  
  	/**
  	 * Get the MAVLink system id.
  	 *
  	 * @return The system ID of this vehicle
  	 */
  	int			get_system_id() const { return mavlink_system.sysid; }
  
  	/**
  	 * Get the MAVLink component id.
  	 *
  	 * @return The component ID of this vehicle
  	 */
  	int			get_component_id() const { return mavlink_system.compid; }
  
  	const char *_device_name{DEFAULT_DEVICE_NAME};
  
  	enum MAVLINK_MODE {
  		MAVLINK_MODE_NORMAL = 0,
  		MAVLINK_MODE_CUSTOM,
  		MAVLINK_MODE_ONBOARD,
  		MAVLINK_MODE_OSD,
  		MAVLINK_MODE_MAGIC,
  		MAVLINK_MODE_CONFIG,
  		MAVLINK_MODE_IRIDIUM,
  		MAVLINK_MODE_MINIMAL,
  		MAVLINK_MODE_EXTVISION,
  		MAVLINK_MODE_EXTVISIONMIN,
  		MAVLINK_MODE_GIMBAL,
  		MAVLINK_MODE_ONBOARD_LOW_BANDWIDTH,
  		MAVLINK_MODE_COUNT
  	};
  
  	enum BROADCAST_MODE {
  		BROADCAST_MODE_OFF = 0,
  		BROADCAST_MODE_ON,
  		BROADCAST_MODE_MULTICAST
  	};
  
  	enum FLOW_CONTROL_MODE {
  		FLOW_CONTROL_OFF = 0,
  		FLOW_CONTROL_AUTO,
  		FLOW_CONTROL_ON
  	};
  
  	static const char *mavlink_mode_str(enum MAVLINK_MODE mode)
  	{
  		switch (mode) {
  		case MAVLINK_MODE_NORMAL:
  			return "Normal";
  
  		case MAVLINK_MODE_CUSTOM:
  			return "Custom";
  
  		case MAVLINK_MODE_ONBOARD:
  			return "Onboard";
  
  		case MAVLINK_MODE_OSD:
  			return "OSD";
  
  		case MAVLINK_MODE_MAGIC:
  			return "Magic";
  
  		case MAVLINK_MODE_CONFIG:
  			return "Config";
  
  		case MAVLINK_MODE_IRIDIUM:
  			return "Iridium";
  
  		case MAVLINK_MODE_MINIMAL:
  			return "Minimal";
  
  		case MAVLINK_MODE_EXTVISION:
  			return "ExtVision";
  
  		case MAVLINK_MODE_EXTVISIONMIN:
  			return "ExtVisionMin";
  
  		case MAVLINK_MODE_GIMBAL:
  			return "Gimbal";
  
  		case MAVLINK_MODE_ONBOARD_LOW_BANDWIDTH:
  			return "OnboardLowBandwidth";
  
  		default:
  			return "Unknown";
  		}
  	}
  
  	enum MAVLINK_MODE	get_mode() { return _mode; }
  
  	bool			get_hil_enabled() { return _hil_enabled; }
  
  	bool			get_use_hil_gps() { return _param_mav_usehilgps.get(); }
  
  	bool			get_forward_externalsp() { return _param_mav_fwdextsp.get(); }
  
  	bool			get_flow_control_enabled() { return _flow_control_mode; }
  
  	bool			get_forwarding_on() { return _forwarding_on; }
  
  	bool			is_connected() { return _tstatus.heartbeat_type_gcs; }
  
  #if defined(MAVLINK_UDP)
  	static Mavlink 		*get_instance_for_network_port(unsigned long port);
  
  	bool			broadcast_enabled() { return _mav_broadcast == BROADCAST_MODE_ON; }
  
  	bool			multicast_enabled() { return _mav_broadcast == BROADCAST_MODE_MULTICAST; }
  #endif // MAVLINK_UDP
  
  	/**
  	 * Set the boot complete flag on all instances
  	 *
  	 * Setting the flag unblocks parameter transmissions, which are gated
  	 * beforehand to ensure that the system is fully initialized.
  	 */
  	static void		set_boot_complete();
  
  	/**
  	 * Get the free space in the transmit buffer
  	 *
  	 * @return free space in the UART TX buffer
  	 */
  	unsigned		get_free_tx_buf();
  
  	static int		start_helper(int argc, char *argv[]);
  
  	/**
  	 * Enable / disable Hardware in the Loop simulation mode.
  	 *
  	 * @param hil_enabled	The new HIL enable/disable state.
  	 * @return		OK if the HIL state changed, ERROR if the
  	 *			requested change could not be made or was
  	 *			redundant.
  	 */
  	int			set_hil_enabled(bool hil_enabled);
  
  	/**
  	 * Set manual input generation mode
  	 *
  	 * Set to true to generate RC_INPUT messages on the system bus from
  	 * MAVLink messages.
  	 *
  	 * @param generation_enabled If set to true, generate RC_INPUT messages
  	 */
  	void			set_generate_virtual_rc_input(bool generation_enabled) { _generate_rc = generation_enabled; }
  
  	/**
  	 * Set communication protocol for this mavlink instance
  	 */
  	void 			set_protocol(Protocol p) { _protocol = p; }
  
  	/**
  	 * Get the manual input generation mode
  	 *
  	 * @return true if manual inputs should generate RC data
  	 */
  	bool			should_generate_virtual_rc_input() { return _generate_rc; }
  
  	/**
  	 * This is the beginning of a MAVLINK_START_UART_SEND/MAVLINK_END_UART_SEND transaction
  	 */
  	void 			send_start(int length);
  
  	/**
  	 * Buffer bytes to send out on the link.
  	 */
  	void			send_bytes(const uint8_t *buf, unsigned packet_len);
  
  	/**
  	 * Flush the transmit buffer and send one MAVLink packet
  	 */
  	void             	send_finish();
  
  	/**
  	 * Resend message as is, don't change sequence number and CRC.
  	 */
  	void			resend_message(mavlink_message_t *msg) { _mavlink_resend_uart(_channel, msg); }
  
  	void			handle_message(const mavlink_message_t *msg);
  
  	int			get_instance_id() const { return _instance_id; }
  
  	/**
  	 * Enable / disable hardware flow control.
  	 *
  	 * @param enabled	True if hardware flow control should be enabled
  	 */
  	int			setup_flow_control(enum FLOW_CONTROL_MODE enabled);
  
  	mavlink_channel_t	get_channel() const { return _channel; }
  
  	void			configure_stream_threadsafe(const char *stream_name, float rate = -1.0f);
  
  	orb_advert_t		*get_mavlink_log_pub() { return &_mavlink_log_pub; }
  
  	/**
  	 * Send a status text with loglevel INFO
  	 *
  	 * @param string the message to send (will be capped by mavlink max string length)
  	 */
  	void			send_statustext_info(const char *string);
  
  	/**
  	 * Send a status text with loglevel CRITICAL
  	 *
  	 * @param string the message to send (will be capped by mavlink max string length)
  	 */
  	void			send_statustext_critical(const char *string);
  
  	/**
  	 * Send a status text with loglevel EMERGENCY
  	 *
  	 * @param string the message to send (will be capped by mavlink max string length)
  	 */
  	void			send_statustext_emergency(const char *string);
  
  	/**
  	 * Send a status text with loglevel, the difference from mavlink_log_xxx() is that message sent
  	 * only on this mavlink connection. Useful for reporting communication specific, not system-wide info
  	 * only to client interested in it. Message will be not sent immediately but queued in buffer as
  	 * for mavlink_log_xxx().
  	 *
  	 * @param string the message to send (will be capped by mavlink max string length)
  	 * @param severity the log level
  	 */
  	void			send_statustext(unsigned char severity, const char *string);
  
  	/**
  	 * Send the capabilities of this autopilot in terms of the MAVLink spec
  	 */
  	bool 			send_autopilot_capabilities();
  
  	/**
  	 * Send the protocol version of MAVLink
  	 */
  	void			send_protocol_version();
  
  	List<MavlinkStream *> &get_streams() { return _streams; }
  
  	float			get_rate_mult() const { return _rate_mult; }
  
  	float			get_baudrate() { return _baudrate; }
  
  	/* Functions for waiting to start transmission until message received. */
  	void			set_has_received_messages(bool received_messages) { _received_messages = received_messages; }
  	bool			get_has_received_messages() { return _received_messages; }
  	void			set_wait_to_transmit(bool wait) { _wait_to_transmit = wait; }
  	bool			get_wait_to_transmit() { return _wait_to_transmit; }
  	bool			should_transmit() { return (_transmitting_enabled && (!_wait_to_transmit || (_wait_to_transmit && _received_messages))); }
  
  	bool			message_buffer_write(const void *ptr, int size);
  
  	void			lockMessageBufferMutex(void) { pthread_mutex_lock(&_message_buffer_mutex); }
  	void			unlockMessageBufferMutex(void) { pthread_mutex_unlock(&_message_buffer_mutex); }
  
  	/**
  	 * Count transmitted bytes
  	 */
  	void			count_txbytes(unsigned n) { _bytes_tx += n; };
  
  	/**
  	 * Count bytes not transmitted because of errors
  	 */
  	void			count_txerrbytes(unsigned n) { _bytes_txerr += n; };
  
  	/**
  	 * Count received bytes
  	 */
  	void			count_rxbytes(unsigned n) { _bytes_rx += n; };
  
  	/**
  	 * Get the receive status of this MAVLink link
  	 */
  	telemetry_status_s	&telemetry_status() { return _tstatus; }
  	void                    telemetry_status_updated() { _tstatus_updated = true; }
  
  	void			set_telemetry_status_type(uint8_t type) { _tstatus.type = type; }
  
  	void			update_radio_status(const radio_status_s &radio_status);
  
  	unsigned		get_system_type() { return _param_mav_type.get(); }
  
  	Protocol 		get_protocol() const { return _protocol; }
  
  	int 			get_socket_fd() { return _socket_fd; };
  
  #if defined(MAVLINK_UDP)
  	unsigned short		get_network_port() { return _network_port; }
  
  	unsigned short		get_remote_port() { return _remote_port; }
  
  	const in_addr		query_netmask_addr(const int socket_fd, const ifreq &ifreq);
  
  	const in_addr		compute_broadcast_addr(const in_addr &host_addr, const in_addr &netmask_addr);
  
  	struct sockaddr_in 	&get_client_source_address() { return _src_addr; }
  
  	void			set_client_source_initialized() { _src_addr_initialized = true; }
  
  	bool			get_client_source_initialized() { return _src_addr_initialized; }
  #endif
  
  	uint64_t		get_start_time() { return _mavlink_start_time; }
  
  	static bool		boot_complete() { return _boot_complete; }
  
  	bool			is_usb_uart() { return _is_usb_uart; }
  
  	int			get_data_rate()		{ return _datarate; }
  	void			set_data_rate(int rate) { if (rate > 0) { _datarate = rate; } }
  
  	unsigned		get_main_loop_delay() const { return _main_loop_delay; }
  
  	/** get the Mavlink shell. Create a new one if there isn't one. It is *always* created via MavlinkReceiver thread.
  	 *  Returns nullptr if shell cannot be created */
  	MavlinkShell		*get_shell();
  	/** close the Mavlink shell if it is open */
  	void			close_shell();
  
  	/** get ulog streaming if active, nullptr otherwise */
  	MavlinkULog		*get_ulog_streaming() { return _mavlink_ulog; }
  	void			try_start_ulog_streaming(uint8_t target_system, uint8_t target_component)
  	{
  		if (_mavlink_ulog) { return; }
  
  		_mavlink_ulog = MavlinkULog::try_start(_datarate, 0.7f, target_system, target_component);
  	}
  
  	const events::SendProtocol &get_events_protocol() const { return _events; };
  	bool ftp_enabled() const { return _ftp_on; }
  
  	bool hash_check_enabled() const { return _param_mav_hash_chk_en.get(); }
  	bool forward_heartbeats_enabled() const { return _param_mav_hb_forw_en.get(); }
  	bool odometry_loopback_enabled() const { return _param_mav_odom_lp.get(); }
  
  	bool failure_injection_enabled() const { return _param_sys_failure_injection_enabled.get(); }
  
  	struct ping_statistics_s {
  		uint64_t last_ping_time;
  		uint32_t last_ping_seq;
  		uint32_t dropped_packets;
  		float last_rtt;
  		float mean_rtt;
  		float max_rtt;
  		float min_rtt;
  	};
  
  	/**
  	 * Get the ping statistics of this MAVLink link
  	 */
  	struct ping_statistics_s &get_ping_statistics() { return _ping_stats; }
  
  	static hrt_abstime &get_first_start_time() { return _first_start_time; }
  
  	bool radio_status_critical() const { return _radio_status_critical; }
  
  private:
  	MavlinkReceiver 	_receiver;
  
  	int			_instance_id{-1};
  	int			_task_id{-1};
  
  	px4::atomic_bool	_task_should_exit{false};
  	px4::atomic_bool	_task_running{false};
  
  	bool			_transmitting_enabled{true};
  	bool			_transmitting_enabled_commanded{false};
  	bool			_first_heartbeat_sent{false};
  
  	orb_advert_t		_mavlink_log_pub{nullptr};
  
  	uORB::Publication<vehicle_command_ack_s> _vehicle_command_ack_pub{ORB_ID(vehicle_command_ack)};
  	uORB::PublicationMulti<telemetry_status_s> _telemetry_status_pub{ORB_ID(telemetry_status)};
  
  	uORB::Subscription _event_sub{ORB_ID(event)};
  	uORB::SubscriptionInterval _parameter_update_sub{ORB_ID(parameter_update), 1_s};
  	uORB::Subscription _vehicle_command_sub{ORB_ID(vehicle_command)};
  	uORB::Subscription _vehicle_command_ack_sub{ORB_ID(vehicle_command_ack)};
  	uORB::Subscription _vehicle_status_sub{ORB_ID(vehicle_status)};
  
  	static bool		_boot_complete;
  
  	static constexpr int	MAVLINK_MIN_INTERVAL{1500};
  	static constexpr int	MAVLINK_MAX_INTERVAL{10000};
  	static constexpr float	MAVLINK_MIN_MULTIPLIER{0.0005f};
  
  	mavlink_message_t	_mavlink_buffer {};
  	mavlink_status_t	_mavlink_status {};
  
  	/* states */
  	bool			_hil_enabled{false};		/**< Hardware In the Loop mode */
  	bool			_generate_rc{false};		/**< Generate RC messages from manual input MAVLink messages */
  	bool			_is_usb_uart{false};		/**< Port is USB */
  	bool			_wait_to_transmit{false};  	/**< Wait to transmit until received messages. */
  	bool			_received_messages{false};	/**< Whether we've received valid mavlink messages. */
  
  	px4::atomic_bool	_should_check_events{false};    /**< Events subscription: only one MAVLink instance should check */
  
  	unsigned		_main_loop_delay{1000};	/**< mainloop delay, depends on data rate */
  
  	List<MavlinkStream *>		_streams;
  
  	MavlinkShell		*_mavlink_shell{nullptr};
  	MavlinkULog		*_mavlink_ulog{nullptr};
  	static events::EventBuffer	*_event_buffer;
  	events::SendProtocol		_events{*_event_buffer, *this};
  
  	MAVLINK_MODE 		_mode{MAVLINK_MODE_NORMAL};
  
  	mavlink_channel_t	_channel{MAVLINK_COMM_0};
  
  	bool			_forwarding_on{false};
  	bool			_ftp_on{false};
  	bool			_use_software_mav_throttling{false};
  
  	int			_uart_fd{-1};
  
  	int			_baudrate{57600};
  	int			_datarate{1000};		///< data rate for normal streams (attitude, position, etc.)
  	float			_rate_mult{1.0f};
  
  	bool			_radio_status_available{false};
  	bool			_radio_status_critical{false};
  	float			_radio_status_mult{1.0f};
  
  	/**
  	 * If the queue index is not at 0, the queue sending
  	 * logic will send parameters from the current index
  	 * to len - 1, the end of the param list.
  	 */
  	unsigned int		_mavlink_param_queue_index{0};
  
  	bool			_mavlink_link_termination_allowed{false};
  
  	char			*_subscribe_to_stream{nullptr};
  	float			_subscribe_to_stream_rate{0.0f};  ///< rate of stream to subscribe to (0=disable, -1=unlimited, -2=default)
  	bool			_udp_initialised{false};
  
  	FLOW_CONTROL_MODE	_flow_control_mode{Mavlink::FLOW_CONTROL_OFF};
  
  	uint64_t		_last_write_success_time{0};
  	uint64_t		_last_write_try_time{0};
  	uint64_t		_mavlink_start_time{0};
  	int32_t			_protocol_version_switch{-1};
  	int32_t			_protocol_version{0};
  
  	unsigned		_bytes_tx{0};
  	unsigned		_bytes_txerr{0};
  	unsigned		_bytes_rx{0};
  	hrt_abstime		_bytes_timestamp{0};
  
  #if defined(MAVLINK_UDP)
  	BROADCAST_MODE		_mav_broadcast {BROADCAST_MODE_OFF};
  
  	sockaddr_in		_myaddr {};
  	sockaddr_in		_src_addr {};
  	sockaddr_in		_bcast_addr {};
  
  	bool			_src_addr_initialized{false};
  	bool			_broadcast_address_found{false};
  	bool			_broadcast_address_not_found_warned{false};
  	bool			_broadcast_failed_warned{false};
  
  	unsigned short		_network_port{14556};
  	unsigned short		_remote_port{DEFAULT_REMOTE_PORT_UDP};
  #endif // MAVLINK_UDP
  
  	uint8_t			_buf[MAVLINK_MAX_PACKET_LEN] {};
  	unsigned		_buf_fill{0};
  
  	bool			_tx_buffer_low{false};
  
  	const char 		*_interface_name{nullptr};
  
  	int			_socket_fd{-1};
  	Protocol		_protocol{Protocol::SERIAL};
  
  	radio_status_s		_rstatus {};
  	telemetry_status_s	_tstatus {};
  	bool                    _tstatus_updated{false};
  
  	ping_statistics_s	_ping_stats {};
  
  	struct mavlink_message_buffer {
  		int write_ptr;
  		int read_ptr;
  		int size;
  		char *data;
  	};
  
  	mavlink_message_buffer	_message_buffer {};
  
  	pthread_mutex_t		_message_buffer_mutex {};
  	pthread_mutex_t		_send_mutex {};
  	pthread_mutex_t         _radio_status_mutex {};
  
  	DEFINE_PARAMETERS(
  		(ParamInt<px4::params::MAV_SYS_ID>) _param_mav_sys_id,
  		(ParamInt<px4::params::MAV_COMP_ID>) _param_mav_comp_id,
  		(ParamInt<px4::params::MAV_PROTO_VER>) _param_mav_proto_ver,
  		(ParamInt<px4::params::MAV_SIK_RADIO_ID>) _param_sik_radio_id,
  		(ParamInt<px4::params::MAV_TYPE>) _param_mav_type,
  		(ParamBool<px4::params::MAV_USEHILGPS>) _param_mav_usehilgps,
  		(ParamBool<px4::params::MAV_FWDEXTSP>) _param_mav_fwdextsp,
  		(ParamBool<px4::params::MAV_HASH_CHK_EN>) _param_mav_hash_chk_en,
  		(ParamBool<px4::params::MAV_HB_FORW_EN>) _param_mav_hb_forw_en,
  		(ParamBool<px4::params::MAV_ODOM_LP>) _param_mav_odom_lp,
  		(ParamInt<px4::params::MAV_RADIO_TOUT>)      _param_mav_radio_timeout,
  		(ParamInt<px4::params::SYS_HITL>) _param_sys_hitl,
  		(ParamBool<px4::params::SYS_FAILURE_EN>) _param_sys_failure_injection_enabled
  	)
  
  	perf_counter_t _loop_perf{perf_alloc(PC_ELAPSED, MODULE_NAME": tx run elapsed")};                      /**< loop performance counter */
  	perf_counter_t _loop_interval_perf{perf_alloc(PC_INTERVAL, MODULE_NAME": tx run interval")};           /**< loop interval performance counter */
  	perf_counter_t _send_byte_error_perf{perf_alloc(PC_COUNT, MODULE_NAME": send_bytes error")};           /**< send bytes error count */
  
  	void			mavlink_update_parameters();
  
  	int mavlink_open_uart(const int baudrate = DEFAULT_BAUD_RATE,
  			      const char *uart_name = DEFAULT_DEVICE_NAME,
  			      const FLOW_CONTROL_MODE flow_control = FLOW_CONTROL_AUTO);
  
  	static constexpr unsigned RADIO_BUFFER_CRITICAL_LOW_PERCENTAGE = 25;
  	static constexpr unsigned RADIO_BUFFER_LOW_PERCENTAGE = 35;
  	static constexpr unsigned RADIO_BUFFER_HALF_PERCENTAGE = 50;
  
  	static hrt_abstime _first_start_time;
  
  	/**
  	 * Configure a single stream.
  	 * @param stream_name
  	 * @param rate streaming rate in Hz, -1 = unlimited rate
  	 * @return 0 on success, <0 on error
  	 */
  	int configure_stream(const char *stream_name, const float rate = -1.0f);
  
  	/**
  	 * Configure default streams according to _mode for either all streams or only a single
  	 * stream.
  	 * @param configure_single_stream: if nullptr, configure all streams, else only a single stream
  	 * @return 0 on success, <0 on error
  	 */
  	int configure_streams_to_default(const char *configure_single_stream = nullptr);
  
  	int message_buffer_init(int size);
  
  	void message_buffer_destroy();
  
  	int message_buffer_count();
  
  	int message_buffer_is_empty() const { return (_message_buffer.read_ptr == _message_buffer.write_ptr); }
  
  	int message_buffer_get_ptr(void **ptr, bool *is_part);
  
  	void message_buffer_mark_read(int n) { _message_buffer.read_ptr = (_message_buffer.read_ptr + n) % _message_buffer.size; }
  
  	void pass_message(const mavlink_message_t *msg);
  
  	void publish_telemetry_status();
  
  	void check_requested_subscriptions();
  
  	/**
  	 * Reconfigure a SiK radio if requested by MAV_SIK_RADIO_ID
  	 *
  	 * This convenience function allows to re-configure a connected
  	 * SiK radio without removing it from the main system harness.
  	 */
  	void configure_sik_radio();
  
  	/**
  	 * Update rate mult so total bitrate will be equal to _datarate.
  	 */
  	void update_rate_mult();
  
  #if defined(MAVLINK_UDP)
  	void find_broadcast_address();
  
  	void init_udp();
  #endif // MAVLINK_UDP
  
  
  	void set_channel();
  
  	bool set_instance_id();
  
  	/**
  	 * Main mavlink task.
  	 */
  	int task_main(int argc, char *argv[]);
  
  	// Disallow copy construction and move assignment.
  	Mavlink(const Mavlink &) = delete;
  	Mavlink operator=(const Mavlink &) = delete;
  };
  