Pure Elixir library to interact with the sysfs interface to hardware PWM on Linux.

Usage

Fully manual

If you wish to just write and read to the sysfs Pwm interface, you can find path helpers in the Pwmx.Paths module.

iex> File.read(Pwmx.Paths.duty_cycle_path("pwmchip0", "1"))

Helper functions

If you want an Elixir interface instead of calling File.write/2 or File.read/1 yourself, the module Pwmx.Backend.Sysfs.Ops has a stateless interface that actually performs the reads and writes.

iex> Pwmx.Backend.Sysfs.Ops.get_duty_cycle("pwmchip0", 1)

Managed

The Pwmx.Output module can be used to spin up a genserver representing your output, managing its state.

iex> {:ok, pid} = Pwmx.Output.start_link({"virtualchip0", 1})
iex> Pwmx.Output.enable(pid) |> Pwmx.Output.set_period(1_000, :ms)
iex> 1_000_000_000 = Pwmx.Output.get_period(pid)

Testing & non-linux hosts

In a test or non-linux environment, the Pwmx.Backend.Sysfs module is not used, and calls are instead dispatched to Pwmx.Backend.Virtual, which keeps track of your operations on PWM outputs with the Pwmx.State struct. This struct isn't meant to be used directly as it wouldn't be of particular help.

The application supervises a default backend registered as Pwmx.Backend. To test code that drives PWM outputs without stepping on shared state, start your own isolated, configurable virtual backend and pass it to Pwmx.Output.start_link/2 (or Pwmx.open/3). Each instance holds its own state, so tests can run concurrently:

iex> {:ok, backend} = Pwmx.Backend.start_link(mode: :virtual, virtual_chips: %{"virtualchip0" => 4})
iex> {:ok, pid} = Pwmx.Output.start_link({"virtualchip0", 1}, backend: backend)
iex> Pwmx.Output.enable(pid) |> Pwmx.Output.set_period(1_000, :ms)
iex> 1_000_000_000 = Pwmx.Output.get_period(pid)

Summary

Functions

Lists the available outputs. Accepts an optional backend instance, defaulting to the application-supervised Pwmx.Backend.

Spins up a Pwmx.Output GenServer. Accepts the same options as Pwmx.Output.start_link/2, notably :backend to bind it to a specific backend instance.

Functions

list_available_outputs(backend \\ Pwmx.Backend)

@spec list_available_outputs(GenServer.server()) :: [{binary(), integer()}]

Lists the available outputs. Accepts an optional backend instance, defaulting to the application-supervised Pwmx.Backend.

iex> Pwmx.list_available_outputs()
[
  {"virtualchip0", 0},
  {"virtualchip0", 1},
  {"virtualchip0", 2},
  {"virtualchip0", 3}
]

open(chip, output, opts \\ [])

@spec open(binary(), integer(), keyword()) :: {:error, :normal} | {:ok, pid()}

Spins up a Pwmx.Output GenServer. Accepts the same options as Pwmx.Output.start_link/2, notably :backend to bind it to a specific backend instance.

iex> {:ok, _pid} = Pwmx.open("virtualchip0", 3)