defmodule MAVLink.Util.SITL do
@moduledoc """
Provide SITL specific support e.g RC channel forwarding
"""
require Logger
alias MAVLink.Router, as: MAV
alias APM.Message.RcChannelsRaw
alias APM.Message.RequestDataStream
import MAVLink.Util.FocusManager, only: [focus: 0]
@resend_stream_interval 90
def forward_rc(sitl_rc_in_port \\ 5501) do
with {:ok, {system_id, component_id, mavlink_version}} <- focus() do
forward_rc(system_id, component_id, mavlink_version, sitl_rc_in_port)
end
end
def forward_rc(system_id, component_id, mavlink_version, sitl_rc_in_port) do
Task.start_link(__MODULE__, :_connect, [system_id, component_id, mavlink_version, sitl_rc_in_port])
end
def _connect(system_id, component_id, mavlink_version, sitl_rc_in_port) do
with {:ok, socket} <- :gen_udp.open(0, [:binary, ip: {127, 0, 0, 1}]),
:ok <- MAV.subscribe message: RcChannelsRaw, source_system: system_id, source_component: component_id do
Logger.info("Start forwarding RC from vehicle #{system_id}.#{component_id} to SITL rc-in port #{sitl_rc_in_port}}")
_forward(system_id, component_id, mavlink_version, sitl_rc_in_port, socket, 0)
else
_ ->
Logger.warn("Could not subscribe or open port to forward RC from vehicle #{system_id}.#{component_id}")
end
end
def _forward(system_id, component_id, mavlink_version, sitl_rc_in_port, socket, 0) do
MAV.pack_and_send(%RequestDataStream{
target_system: system_id,
target_component: 0, # APM Planner sends this, doesn't work with real component id
req_stream_id: APM.encode(:mav_data_stream_rc_channels, :mav_data_stream), # TODO Not a bitmask, where is clue in MAVlink that this field is related?
req_message_rate: 18,
start_stop: 1
}, mavlink_version)
_forward(system_id, component_id, mavlink_version, sitl_rc_in_port, socket, @resend_stream_interval)
end
def _forward(system_id, component_id, mavlink_version, sitl_rc_in_port, socket, count) do
receive do
%RcChannelsRaw{
chan1_raw: c1,
chan2_raw: c2,
chan3_raw: c3,
chan4_raw: c4,
chan5_raw: c5,
chan6_raw: c6,
chan7_raw: c7,
chan8_raw: c8
} ->
:gen_udp.send(
socket,
{127, 0, 0, 1}, # TODO accept destination IP as parameter
sitl_rc_in_port,
<<
c1::little-unsigned-integer-size(16),
c2::little-unsigned-integer-size(16),
c3::little-unsigned-integer-size(16),
c4::little-unsigned-integer-size(16),
c5::little-unsigned-integer-size(16),
c6::little-unsigned-integer-size(16),
c7::little-unsigned-integer-size(16),
c8::little-unsigned-integer-size(16)
>>)
_forward(system_id, component_id, mavlink_version, sitl_rc_in_port, socket, count - 1)
end
end
end