Finish firmware contract.

pull/363/head
connor rigby 2017-10-24 06:21:23 -07:00
parent d0b2c00153
commit 78650b67e5
5 changed files with 166 additions and 33 deletions

View File

@ -6,17 +6,22 @@ defmodule Farmbot.Firmware do
@doc "Move the bot to a position."
def move_absolute(vec3) do
GenStage.call(__MODULE__, {:move_absolute, vec3})
GenStage.call(__MODULE__, {:move_absolute, [vec3]})
end
@doc "Calibrate an axis."
def calibrate(axis) do
GenStage.call(__MODULE__, {:calibrate, axis})
GenStage.call(__MODULE__, {:calibrate, [axis]})
end
@doc "Find home on an axis."
def find_home(axis) do
GenStage.call(__MODULE__, {:find_home, axis})
GenStage.call(__MODULE__, {:find_home, [axis]})
end
@doc "Manually set an axis's current position to zero."
def zero(axis) do
GenStage.call(__MODULE__, {:zero, [axis]})
end
@doc """
@ -24,7 +29,7 @@ defmodule Farmbot.Firmware do
For a list of paramaters see `Farmbot.Firmware.Gcode.Param`
"""
def update_param(param, val) do
GenStage.call(__MODULE__, {:update_param, param, val})
GenStage.call(__MODULE__, {:update_param, [param, val]})
end
@doc """
@ -32,27 +37,27 @@ defmodule Farmbot.Firmware do
For a list of paramaters see `Farmbot.Firmware.Gcode.Param`
"""
def read_param(param) do
GenStage.call(__MODULE__, {:read_param, param})
GenStage.call(__MODULE__, {:read_param, [param]})
end
@doc "Emergency lock Farmbot."
def emergency_lock() do
GenStage.call(__MODULE__, :emergency_lock)
GenStage.call(__MODULE__, {:emergency_lock, []})
end
@doc "Unlock Farmbot from Emergency state."
def emergency_unlock() do
GenStage.call(__MODULE__, :emergency_unlock)
GenStage.call(__MODULE__, {:emergency_unlock, []})
end
@doc "Read a pin."
def read_pin(pin, mode) do
GenStage.call(__MODULE__, {:read_pin, pin, mode})
GenStage.call(__MODULE__, {:read_pin, [pin, mode]})
end
@doc "Write a pin."
def write_pin(pin, mode, value) do
GenStage.call(__MODULE__, {:write_pin, pin, mode, value})
GenStage.call(__MODULE__, {:write_pin, [pin, mode, value]})
end
@doc "Start the firmware services."
@ -63,14 +68,32 @@ defmodule Farmbot.Firmware do
## GenStage
defmodule State do
defstruct handler: nil, idle: false
defstruct handler: nil, handler_mod: nil, idle: false
end
def init([]) do
handler_mod = Application.get_env(:farmbot, :behaviour)[:firmware_handler] || raise("No fw handler.")
handler_mod =
Application.get_env(:farmbot, :behaviour)[:firmware_handler] || raise("No fw handler.")
{:ok, handler} = handler_mod.start_link()
Process.link(handler)
{:producer_consumer, %State{handler: handler}, subscribe_to: [handler], dispatcher: GenStage.BroadcastDispatcher}
{
:producer_consumer,
%State{handler: handler, handler_mod: handler_mod},
subscribe_to: [handler], dispatcher: GenStage.BroadcastDispatcher
}
end
def handle_call({fun, args}, _from, %{handler: handler, handler_mod: handler_mod} = state) do
res =
case apply(handler_mod, fun, [handler | args]) do
{:ok, _} = res -> res
:ok = res -> res
{:error, _} = res -> res
end
{:reply, res, [], state}
end
def handle_events(gcodes, _from, state) do

View File

@ -38,6 +38,12 @@ defmodule Farmbot.Firmware.Handler do
@doc "Calibrate an axis."
@callback calibrate(handler, axis) :: fw_ret_val
@doc "Find home on an axis."
@callback find_home(handler, axis) :: fw_ret_val
@doc "Manually set an axis's current position to zero."
@callback zero(handler, axis) :: fw_ret_val
@doc "Update a paramater."
@callback update_param(handler, fw_param, number) :: fw_ret_val
@ -50,9 +56,6 @@ defmodule Farmbot.Firmware.Handler do
@doc "Unlock the firmware."
@callback emergency_unlock(handler) :: fw_ret_val
@doc "Find home on an axis."
@callback find_home(handler, axis) :: fw_ret_val
@doc "Read a pin."
@callback read_pin(handler, pin, pin_mode) :: {:ok, number} | {:error, term}

View File

@ -5,26 +5,106 @@ defmodule Farmbot.Firmware.StubHandler do
require Logger
@behaviour Farmbot.Firmware.Handler
alias Farmbot.Firmware.Vec3
## Firmware Handler Behaviour.
def start_link do
Logger.warn("Firmware is being stubbed.")
GenStage.start_link(__MODULE__, [])
end
def move_absolute(pos) do
GenStage.call(__MODULE__, {:move_absolute, pos})
def move_absolute(handler, pos) do
GenStage.call(handler, {:move_absolute, pos})
end
def calibrate(handler, axis) do
GenStage.call(handler, {:calibrate, axis})
end
def find_home(handler, axis) do
GenStage.call(handler, {:find_home, axis})
end
def zero(handler, axis) do
GenStage.call(handler, {:zero, axis})
end
def update_param(handler, param, val) do
GenStage.call(handler, {:update_param, param, val})
end
def read_param(handler, param) do
GenStage.call(handler, {:read_param, param})
end
def emergency_lock(handler) do
GenStage.call(handler, :emergency_lock)
end
def emergency_unlock(handler) do
GenStage.call(handler, :emergency_unlock)
end
def read_pin(handler, pin, pin_mode) do
GenStage.call(handler, {:read_pin, pin, pin_mode})
end
def write_pin(handler, pin, pin_mode, value) do
GenStage.call(handler, {:write_pin, pin, pin_mode, value})
end
## GenStage Behaviour
defmodule State do
defstruct []
defstruct pos: nil,
fw_params: %{},
locked?: false
end
def init([]) do
state = %State{}
state = %State{pos: struct(Vec3)}
{:producer, state, dispatcher: GenStage.BroadcastDispatcher}
end
def handle_demand(_amnt, state) do
{:noreply, [], state}
end
def handle_call({:move_absolute, pos}, _from, state) do
{:reply, :ok, [{:report_current_position, pos.x, pos.y, pos.z}], %{state | pos: pos}}
end
def handle_call({:calibrate, _axis}, _from, state) do
{:reply, :ok, [], state}
end
def handle_call({:find_home, _axis}, _from, state) do
{:reply, :ok, [], state}
end
def handle_call({:zero, axis}, _from, state) do
state = %{state | pos: %{state.pos | axis => 0}}
case axis do
:x -> {:reply, :ok, [{:report_current_position, 0, state.pos.y, state.pos.z}], state}
:y -> {:reply, :ok, [{:report_current_position, state.pos.x, 0, state.pos.z}], state}
:z -> {:reply, :ok, [{:report_current_position, state.pos.x, state.pos.y, 0}], state}
end
end
def handle_call({:update_param, param, val}, _from, state) do
{:reply, :ok, [], %{state | fw_params: Map.put(state.fw_params, param, val)}}
end
def handle_call({:read_param, param}, _from, state) do
{:reply, state.fw_params[param], [], state}
end
def handle_call(:emergency_lock, _from, state) do
{:reply, :ok, [], state}
end
def handle_call(:emergency_unlock, _from, state) do
{:reply, :ok, [], state}
end
end

View File

@ -7,16 +7,48 @@ defmodule Farmbot.Firmware.UartHandler do
alias Nerves.UART
require Logger
@doc """
Writes a string to the uart line
"""
def write(code) do
GenStage.call(__MODULE__, {:write, code}, :infinity)
def start_link do
GenStage.start_link(__MODULE__, [])
end
@doc "Starts a UART Firmware Handler."
def start_link do
GenStage.start_link(__MODULE__, [], name: __MODULE__)
def move_absolute(handler, pos) do
GenStage.call(handler, {:move_absolute, pos})
end
def calibrate(handler, axis) do
GenStage.call(handler, {:calibrate, axis})
end
def find_home(handler, axis) do
GenStage.call(handler, {:find_home, axis})
end
def zero(handler, axis) do
GenStage.call(handler, {:zero, axis})
end
def update_param(handler, param, val) do
GenStage.call(handler, {:update_param, param, val})
end
def read_param(handler, param) do
GenStage.call(handler, {:read_param, param})
end
def emergency_lock(handler) do
GenStage.call(handler, :emergency_lock)
end
def emergency_unlock(handler) do
GenStage.call(handler, :emergency_unlock)
end
def read_pin(handler, pin, pin_mode) do
GenStage.call(handler, {:read_pin, pin, pin_mode})
end
def write_pin(handler, pin, pin_mode, value) do
GenStage.call(handler, {:write_pin, pin, pin_mode, value})
end
## Private
@ -86,11 +118,6 @@ defmodule Farmbot.Firmware.UartHandler do
{:noreply, [], state}
end
def handle_call({:write, stuff}, _from, state) do
r = UART.write(state.nerves, stuff)
{:reply, r, [], state}
end
def handle_demand(_amnt, state) do
do_dispatch(state.codes, state)
end

View File

@ -1,7 +1,7 @@
defmodule Farmbot.Firmware.Vec3 do
@moduledoc "A three position vector."
defstruct [:x, :y, :z]
defstruct [x: -1, y: -1, z: -1]
@typedoc "Axis label."
@type axis :: :x | :y | :z