diff --git a/lib/farmbot/bot_state/bot_state.ex b/lib/farmbot/bot_state/bot_state.ex index 31ce3971..d8eb482e 100644 --- a/lib/farmbot/bot_state/bot_state.ex +++ b/lib/farmbot/bot_state/bot_state.ex @@ -228,7 +228,7 @@ defmodule Farmbot.BotState do { :producer_consumer, struct(__MODULE__, configuration: Map.delete(settings, "user_env"), user_env: user_env), - subscribe_to: [Farmbot.Firmware, Farmbot.System.ConfigStorage.Dispatcher], + subscribe_to: [Farmbot.Firmware, Farmbot.System.ConfigStorage.Dispatcher, Farmbot.System.GPIO], dispatcher: GenStage.BroadcastDispatcher } end diff --git a/lib/farmbot/system/gpio/gpio.ex b/lib/farmbot/system/gpio/gpio.ex index 6cacbc1b..9ca0bdbd 100644 --- a/lib/farmbot/system/gpio/gpio.ex +++ b/lib/farmbot/system/gpio/gpio.ex @@ -31,7 +31,7 @@ defmodule Farmbot.System.GPIO do def handle_events(pin_triggers, _from, state) do t = Enum.uniq(pin_triggers) IO.puts "Got triggers: #{inspect t}" - for {pin, _} <- t do + for {:pin_trigger, pin} <- t do sequence_id = state.registered[pin] if sequence_id do Logger.busy 1, "Starting Sequence: #{sequence_id} from pin: #{pin}" diff --git a/lib/farmbot/system/gpio/stub_handler.ex b/lib/farmbot/system/gpio/stub_handler.ex index 61f20017..b721b7bf 100644 --- a/lib/farmbot/system/gpio/stub_handler.ex +++ b/lib/farmbot/system/gpio/stub_handler.ex @@ -1,4 +1,42 @@ defmodule Farmbot.System.GPIO.StubHandler do @moduledoc "Stub for handling GPIO." @behaviour Farmbot.System.GPIO.Handler + use GenStage + + def test_fire(pin) do + GenStage.call(__MODULE__, {:test_fire, pin}) + end + + def register_pin(num) do + GenStage.call(__MODULE__, {:register_pin, num}) + end + + def start_link do + GenStage.start_link(__MODULE__, [], [name: __MODULE__]) + end + + def init([]) do + {:producer, %{}, [dispatcher: GenStage.BroadcastDispatcher]} + end + + def handle_demand(_amnt, state) do + {:noreply, [], state} + end + + def handle_call({:register_pin, num}, _from, state) do + {:reply, :ok, [], Map.put(state, num, :enabled)} + end + + def handle_call({:test_fire, pin}, _from, state) do + case state[pin] do + nil -> {:reply, :error, [], state} + :enabled -> + send self(), {:do_test_fire, pin} + {:reply, :ok, [], state} + end + end + + def handle_info({:do_test_fire, pin}, state) do + {:noreply, [{:pin_trigger, pin}], state} + end end diff --git a/lib/farmbot/system/supervisor.ex b/lib/farmbot/system/supervisor.ex index 52d9118a..f7960dd2 100644 --- a/lib/farmbot/system/supervisor.ex +++ b/lib/farmbot/system/supervisor.ex @@ -23,7 +23,8 @@ defmodule Farmbot.System.Supervisor do |> Enum.map(fn child -> fb_init(child, [[], [name: child]]) end) after_init_children = [ - supervisor(Farmbot.System.Updates, []) + supervisor(Farmbot.System.Updates, []), + worker(Farmbot.System.GPIO, []) ] supervise(before_init_children ++ init_mods ++ after_init_children, strategy: :one_for_all) diff --git a/nerves/target/gpio/ale_handler.ex b/nerves/target/gpio/ale_handler.ex index f21e59e6..96e8caf1 100644 --- a/nerves/target/gpio/ale_handler.ex +++ b/nerves/target/gpio/ale_handler.ex @@ -23,11 +23,11 @@ defmodule Farmbot.Target.GPIO.AleHandler do defmodule PinState do @moduledoc false - defstruct [:pin, :state, :signal] + defstruct [:pin, :state, :signal, :timer] end def init([]) do - {:producer, struct(State, [pins: %{}]), dispatcher: GenStage.BroadcastDispatcher} + {:producer, struct(State, [pins: %{}]), [dispatcher: GenStage.BroadcastDispatcher]} end def handle_demand(_amnt, state) do @@ -36,22 +36,40 @@ defmodule Farmbot.Target.GPIO.AleHandler do def handle_call({:register_pin, num}, _from, state) do with {:ok, pin} <- GPIO.start_link(num, :input), - :ok <- GPIO.set_int(pin, :both) do - {:reply, :ok, [], %{state | pins: Map.put(state.pins, num, struct(PinState, [pin: pin, state: nil, signal: :falling]))}} + :ok <- GPIO.set_int(pin, :rising) do + {:reply, :ok, [], %{state | pins: Map.put(state.pins, num, struct(PinState, [pin: pin, state: nil, signal: :rising]))}} else {:error, _} = err-> {:reply, err, [], state} err -> {:reply, {:error, err}, [], state} end end + def handle_info({:gpio_interrupt, pin, :rising}, state) do + IO.puts "got rising signal. Dispatching: #{pin}" + pin_state = state.pins[pin] + if pin_state.timer do + new_state = %{state | pins: %{state.pins | pin => %{pin_state | state: :rising}}} + {:noreply, [], new_state} + else + timer = Process.send_after(self(), {:gpio_timer, pin}, 5000) + new_state = %{state | pins: %{state.pins | pin => %{pin_state | timer: timer, state: :rising}}} + {:noreply, [{:pin_trigger, pin}], new_state} + end + end + def handle_info({:gpio_interrupt, pin, signal}, state) do pin_state = state.pins[pin] new_state = %{state | pins: %{state.pins | pin => %{pin_state | state: signal}}} - if (pin_state.state != signal) && (pin_state.signal == signal) do - IO.puts "#{pin_state.state} => #{new_state.pins[pin].state}" - {:noreply, [{pin, pin_state}], new_state} + {:noreply, [], new_state} + end + + def handle_info({:gpio_timer, pin}, state) do + pin_state = state.pins[pin] + if pin_state do + new_pin_state = %{pin_state | timer: nil} + {:noreply, [], %{state | pins: %{state.pins | pin => new_pin_state}}} else - {:noreply, [], new_state} + {:noreply, [], state} end end end