farmbot_os/lib/bot_state/trackers/hardware_tracker.ex

144 lines
4.4 KiB
Elixir

defmodule Farmbot.BotState.Hardware do
@moduledoc """
tracks mcu_params, pins, location
"""
require Logger
alias Farmbot.StateTracker
@behaviour StateTracker
use StateTracker,
name: __MODULE__,
model: [
location: [-1,-1,-1],
end_stops: {-1,-1,-1,-1,-1,-1},
mcu_params: %{},
pins: %{},
]
@type t :: %__MODULE__.State{
location: location,
end_stops: end_stops,
mcu_params: mcu_params,
pins: pins,
}
@type location :: [number, ...]
@type mcu_params :: map
@type pins :: map
@type end_stops :: {integer,integer,integer,integer,integer,integer}
# Callback that happens when this module comes up
def load([]) do
{:ok, p} = get_config("params")
initial_state = %State{mcu_params: p}
spawn fn() ->
case set_initial_params(initial_state) do
{:ok, :no_params} ->
Logger.info ">> is reading default Hardware params."
Farmbot.CeleryScript.Command.read_all_params(%{}, [])
:ok ->
Logger.info ">> Hardware Params set"
{:error, reason} ->
Logger.error(">> Error setting Hardware Params: #{inspect reason}")
end
end
{:ok, initial_state}
end
@doc """
Takes a Hardware State object, and makes it happen
"""
@spec set_initial_params(State.t) :: {:ok, :no_params} | :ok | {:error, term}
def set_initial_params(%State{} = state) do
# BUG(Connor): The first param is rather unstable for some reason.
# Try to send a fake packet just to make sure we have a good
# Connection to the Firmware
Farmbot.CeleryScript.Command.read_param(%{label: "param_version"}, [])
Farmbot.Serial.Gcode.Handler.block_send "F83"
if Enum.empty?(state.mcu_params) do
{:ok, :no_params}
else
config_pairs = Enum.map(state.mcu_params, fn({param, val}) ->
%Farmbot.CeleryScript.Ast{kind: "pair",
args: %{label: param, value: val}, body: []}
end)
Farmbot.CeleryScript.Command.config_update(%{package: "arduino_firmware"},
config_pairs)
:ok
end
end
def handle_call({:get_pin, pin_number}, _from, %State{} = state) do
dispatch Map.get(state.pins, Integer.to_string(pin_number)), state
end
def handle_call(:get_current_pos, _from, %State{} = state) do
dispatch state.location, state
end
def handle_call(:get_all_mcu_params, _from, %State{} = state) do
dispatch state.mcu_params, state
end
def handle_call({:get_param, param}, _from, %State{} = state) do
dispatch Map.get(state.mcu_params, param), state
end
def handle_call(event, _from, %State{} = state) do
Logger.error ">> got an unhandled call in " <>
"Hardware tracker: #{inspect event}"
dispatch :unhandled, state
end
def handle_cast({:set_pos, {x, y, z}}, %State{} = state) do
dispatch %State{state | location: [x,y,z]}
end
def handle_cast({:set_pin_value, {pin, value}}, %State{} = state) do
pin_state = state.pins
new_pin_value =
case Map.get(pin_state, Integer.to_string(pin)) do
nil ->
%{mode: -1, value: value}
%{mode: mode, value: _} ->
%{mode: mode, value: value}
end
Logger.info ">> set pin: #{pin}: #{new_pin_value.value}"
new_pin_state = Map.put(pin_state, Integer.to_string(pin), new_pin_value)
dispatch %State{state | pins: new_pin_state}
end
def handle_cast({:set_pin_mode, {pin, mode}}, %State{} = state) do
pin_state = state.pins
new_pin_value =
case Map.get(pin_state, Integer.to_string(pin)) do
nil -> %{mode: mode, value: -1}
%{mode: _, value: value} -> %{mode: mode, value: value}
end
new_pin_state = Map.put(pin_state, Integer.to_string(pin), new_pin_value)
dispatch %State{state | pins: new_pin_state}
end
def handle_cast({:set_param, {param_atom, value}}, %State{} = state)
when is_atom(param_atom) do
param_string = Atom.to_string(param_atom)
new_params = Map.put(state.mcu_params, param_string, value)
put_config("params", new_params)
dispatch %State{state | mcu_params: new_params}
end
def handle_cast({:set_end_stops, {xa,xb,ya,yb,za,zc}}, %State{} = state) do
dispatch %State{state | end_stops: {xa,xb,ya,yb,za,zc}}
end
# catch all.
def handle_cast(event, %State{} = state) do
Logger.error ">> got an unhandled cast " <>
"in Hardware tracker: #{inspect event}"
dispatch state
end
end