Skip to main content

README.md

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

## Installation  

Add `pwmx` to your dependencies in `mix.exs`:

```elixir
def deps do
  [
    {:pwmx, "~> 0.1.0"}
  ]
end
```

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

```elixir
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.
```elixir
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.  
```elixir
{:ok, pid} = Pwmx.Output.start_link({"pwmchip0", 1})  
Pwmx.Output.enable(pid) |> Pwmx.Output.set_period(1_000_000, :us)  
```

## 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, start your own virtual backend and hand it to `Pwmx.Output` (or `Pwmx.open/3`). Each instance owns its state :

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

You can also fix the virtual board globally via configuration:

```elixir
# config/test.exs
config :pwmx, virtual_chips: %{"virtualchip0" => 4}
```

## What PWM outputs do I have ?

An helper function can help you. Note that this function **actually exports then closes each output** as it seems that after a bit of testing, it cannot be taken for granted that every output reported by `/sys/class/pwm/chip/npwm` is able to be opened. Note that already exported outputs by something else in your system will not show up in this list as the export will fail.

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

### Todo

- [ ] Sample project showing behavior on a host & on a board