lib/led_strip_driver/spi_driver.ex

defmodule Fledex.LedStripDriver.SpiDriver do
  alias Fledex.Color.Correction

  @behaviour Fledex.LedStripDriver.Driver
  use Fledex.Color.Types

  @impl true
  @spec init(map) :: map
  def init(init_module_args) do
    config = %{
      dev: init_module_args[:dev] || "spidev0.0",
      mode: init_module_args[:mode] || 0,
      bits_per_word: init_module_args[:bits_per_word] || 8,
      speed_hz: init_module_args[:speed_hz] || 1_000_000,
      delay_us: init_module_args[:delay_us] || 10,
      lsb_first: init_module_args[:lsb_first] || false,
      color_correction: init_module_args[:color_correction] || Correction.no_color_correction(),
      ref: nil
    }

    put_in(config.ref, open_spi(config))
  end

  @spec open_spi(map) :: reference
  def open_spi(config) do
    {:ok, ref} =
      Circuits.SPI.open(config.dev,
        mode: config.mode,
        bits_per_word: config.bits_per_word,
        speed_hz: config.speed_hz,
        delay_us: config.delay_us,
        lsb_first: config.lsb_first
      )

    ref
  end

  @impl true
  @spec transfer(list(colorint), pos_integer, map) :: map
  def transfer(leds, _counter, config) do
    binary = leds
      |> Correction.apply_rgb_correction(config.color_correction)
      |> Enum.reduce(<<>>, fn led, acc ->
        {r,g,b} = Fledex.Color.Utils.convert_to_subpixels(led)
        acc <> <<r, g, b>>
      end)
    {:ok, _} = Circuits.SPI.transfer(config.ref, binary)
    config
  end

  @impl true
  @spec terminate(reason, map) :: :ok
        when reason: :normal | :shutdown | {:shutdown, term()} | term()
  def terminate(_reason, config) do
    Circuits.SPI.close(config.ref)
  end
end