farmbot_os/farmbot_os/platform/target/gpio/circuits_gpio_handler.ex

57 lines
1.7 KiB
Elixir

defmodule FarmbotOS.Platform.Target.PinBindingWorker.CircuitsGPIOHandler do
@moduledoc "Circuits gpio handler for PinBindings"
@behaviour FarmbotCore.AssetWorker.FarmbotCore.Asset.PinBinding
require Logger
use GenServer
alias Circuits.GPIO
@debounce_timeout_ms 1000
def start_link(pin_number, fun) do
GenServer.start_link(__MODULE__, [pin_number, fun], name: name(pin_number))
end
def terminate(reason, state) do
Logger.warn(
"CircuitsGPIOHandler #{state.pin_number} crash: #{inspect(reason)}"
)
end
def init([pin_number, fun]) do
Logger.info("CircuitsGPIOHandler #{pin_number} init")
{:ok, pin} = GPIO.open(pin_number, :input)
:ok = GPIO.set_interrupts(pin, :rising)
# this has been checked on v1.3 and v1.5 hardware
# and it seems to be fine.
:ok = GPIO.set_pull_mode(pin, :pulldown)
{:ok, %{pin_number: pin_number, pin: pin, fun: fun, debounce: nil}}
end
def handle_info(:timeout, state) do
Logger.info("CircuitsGPIOHandler #{state.pin_number} debounce cleared")
{:noreply, %{state | debounce: nil}}
end
def handle_info(
{:circuits_gpio, pin, _timestamp, _},
%{debounce: timer} = state
)
when is_reference(timer) do
left = Process.read_timer(timer)
Logger.info("CircuitsGPIOHandler #{pin} still debounced for #{left} ms")
{:noreply, state}
end
def handle_info({:circuits_gpio, pin, _timestamp, _signal}, state) do
Logger.debug("CircuitsGPIOHandler #{pin} triggered")
state.fun.()
{:noreply, %{state | debounce: debounce_timer()}}
end
def name(pin_number), do: :"#{__MODULE__}.#{pin_number}"
defp debounce_timer,
do: Process.send_after(self(), :timeout, @debounce_timeout_ms)
end