RentoryHub.Hardware.Usb is mostly borrowed from Toolshed's lsusb
defmodule RentoryHub.Hardware.Usb do
@doc "Find out if a USB device is available"
def available?(id) do
Enum.any?(usb_information(), &match_id_in_information(&1, id))
end
defp match_id_in_information(%{"PRODUCT" => pid}, id), do: to_vidpid(pid) == id
defp match_id_in_information(_, _), do: false
@doc "Information about all usb devices available"
def usb_information do
Path.wildcard("/sys/bus/usb/devices/*/uevent")
|> Enum.map(&File.read!/1)
|> Enum.map(&parse_kv_config/1)
|> Enum.filter(&(&1["DEVTYPE"] == "usb_device"))
end
defp parse_kv_config(contents) do
contents
|> String.split("\n")
|> Enum.flat_map(&parse_kv/1)
|> Enum.into(%{})
end
defp parse_kv(""), do: []
defp parse_kv(<<"#", _rest::binary>>), do: []
defp parse_kv(key_equals_value) do
[key, value] = String.split(key_equals_value, "=", parts: 2, trim: true)
[{key, value}]
end
defp to_vidpid(""), do: "?"
defp to_vidpid(raw) do
# The VIDPID comes in as "vid/pid/somethingelse"
[vid_str, pid_str, _] = String.split(raw, "/", trim: true)
vid = String.pad_leading(vid_str, 4, "0")
pid = String.pad_leading(pid_str, 4, "0")
vid <> ":" <> pid
end
end
RentoryHub.Hardware.UsbDetector polls usb devices and uses some pubsub to notify other parties. This is use to trigger the usb_modeswitch I need for my modem. It could also detect the modem and "enable" ppp afterwards, but currently there's not really an api for vintagenet to enable/disable ppp.
defmodule RentoryHub.Hardware.UsbDetector do
use GenStateMachine, callback_mode: [:handle_event_function, :state_enter]
alias RentoryHub.Hardware.Usb
def start_link(init_arg) do
GenStateMachine.start_link(__MODULE__, init_arg)
end
@impl GenStateMachine
def init(init_arg) do
id = Keyword.fetch!(init_arg, :id)
interval = Keyword.get(init_arg, :interval, :timer.seconds(10))
{:ok, check_state(id), %{id: id, interval: interval}, tick_timeout_action(interval)}
end
def handle_event(:enter, _, state, %{id: id}) do
RentoryHub.PubSub.publish("usb/#{id}", %{state: state})
:keep_state_and_data
end
@impl GenStateMachine
def handle_event({:timeout, :tick}, _, state, %{id: id, interval: interval} = data) do
case check_state(id) do
^state -> {:keep_state_and_data, tick_timeout_action(interval)}
state -> {:next_state, state, data, tick_timeout_action(interval)}
end
end
defp tick_timeout_action(interval) do
{{:timeout, :tick}, interval, %{}}
end
defp check_state(id) do
if Usb.available?(id), do: :available, else: :unavailable
end
end
I'm actually wondering if this should be a concern for vintage_net at all. Maybe the device detection part is one thing and vintage_net_lte should just handle a tty file being available or not (or coming/going).
As requested on the forums: https://elixirforum.com/t/vintagenet-a-new-network-configuration-library-for-nerves/27535/3
What I have right now are a few related modules:
RentoryHub.Hardware.Usb
is mostly borrowed fromToolshed
'slsusb
RentoryHub.Hardware.UsbDetector
polls usb devices and uses some pubsub to notify other parties. This is use to trigger the usb_modeswitch I need for my modem. It could also detect the modem and "enable" ppp afterwards, but currently there's not really an api for vintagenet to enable/disable ppp.I'm actually wondering if this should be a concern for vintage_net at all. Maybe the device detection part is one thing and vintage_net_lte should just handle a tty file being available or not (or coming/going).