defmodule QMI do
@moduledoc """
Qualcomm MSM Interface in Elixir
This module lets you send and receive messages from a QMI-enabled cellular
modem.
To use it, start a `QMI.Supervisor` in the supervision tree of your choosing
and pass it a name and interface. After that, use the service modules to send
it messages. For example:
```elixir
# In your application's supervision tree
children = [
#... other children ...
{QMI.Supervisor, ifname: "wwan0", name: MyApp.QMI}
#... other children ...
]
# Later on
iex> QMI.WirelessData.start_network_interface(MyApp.QMI, apn: "super")
:ok
iex> QMI.NetworkAccess.get_signal_strength(MyApp.QMI)
{:ok, %{rssi_reports: [%{radio: :lte, rssi: -74}]}}
```
"""
@typedoc """
The name passed to QMI.Supervisor
"""
@type name() :: atom()
@typedoc """
Structure that contains information about how to handle a QMI service message
* `:service_id` - which service this request is for
* `:payload` - iodata of the message being sent
* `:decode` - a function that will be used to decode the incoming response
"""
@type request() :: %{
service_id: non_neg_integer(),
payload: iodata(),
decode: (binary() -> :ok | {:ok, any()} | {:error, atom()})
}
@typedoc """
A function that is ran when QMI receives an indication
This function receives a map as the indication and returns `:ok`.
"""
@type indication_callback_fun() :: (map() -> :ok)
@doc """
Configure the framing when using linux
This should be called once the device appears and before an attempt is made to
connect to the network.
"""
@spec configure_linux(String.t()) :: :ok
def configure_linux(ifname) do
# This might not be true for all modems as some support 802.3 IP framing,
# however, on the EC25 supports raw IP framing. This feature can be detected
# and is probably a better solution that just forcing the raw IP framing.
File.write!("/sys/class/net/#{ifname}/qmi/raw_ip", "Y")
end
@doc """
Send a request over QMI and return the response
NOTE: the QMI name parameter is second to facilitate piping
"""
@spec call(request(), name()) :: any()
def call(request, qmi) do
with {:ok, client_id} <- QMI.ClientIDCache.get_client_id(qmi, request.service_id) do
QMI.Driver.call(qmi, client_id, request)
end
end
end