Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Removable modems #17

Open
LostKobrakai opened this issue Feb 10, 2020 · 0 comments
Open

Removable modems #17

LostKobrakai opened this issue Feb 10, 2020 · 0 comments

Comments

@LostKobrakai
Copy link
Contributor

LostKobrakai commented Feb 10, 2020

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 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
Supervisor.child_spec({RentoryHub.Hardware.UsbDetector, id: "12d1:1f01"},
        id: {RentoryHub.Hardware.UsbDetector, "12d1:1f01"}
      ),

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).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant