re implement uart

pull/363/head
connor rigby 2017-11-08 12:55:16 -08:00
parent a86e986a1d
commit 31dc503bd6
10 changed files with 144 additions and 36 deletions

View File

@ -8,6 +8,7 @@ defmodule Farmbot.BotState do
@env Mix.env()
alias Farmbot.CeleryScript.AST
use Farmbot.Logger
defstruct mcu_params: %{},
jobs: %{},
@ -26,7 +27,13 @@ defmodule Farmbot.BotState do
user_env: %{},
process_info: %{}
@valid_sync_status [ :locked, :maintenance, :sync_error, :sync_now, :synced, :syncing, :unknown,]
@doc "Get a current pin value."
def get_pin_value(num) do
GenStage.call(__MODULE__, {:get_pin_value, num})
end
@valid_sync_status [ :locked, :maintenance, :sync_error, :sync_now, :synced, :syncing, :unknown]
@doc "Set the sync status above ticker to a message."
def set_sync_status(cmd) when cmd in @valid_sync_status do
GenStage.call(__MODULE__, {:set_sync_status, cmd})
end
@ -61,10 +68,21 @@ defmodule Farmbot.BotState do
end
def handle_events(events, _from, state) do
# Logger.busy 3, "begin handle bot state events"
state = do_handle(events, state)
# Logger.success 3, "Finish handle bot state events"
{:noreply, [state], state}
end
def handle_call({:get_pin_value, pin}, _from, state) do
case state.pins[pin] do
nil ->
{:reply, {:error, :unknown_pin}, [], state}
%{value: value} ->
{:reply, {:ok, value}, [], state}
end
end
def handle_call(:force_state_push, _from, state) do
{:reply, state, [state], state}
end

View File

@ -118,6 +118,7 @@ defmodule Farmbot.BotState.Transport.GenMQTT.Client do
{:ok, encoded_ast} = AST.encode(ast)
json = Poison.encode!(encoded_ast)
GenMQTT.publish(self(), frontend_topic(state.device), json, 0, false)
Logger.success 3, "bot state pushed"
{:noreply, state}
end

View File

@ -54,7 +54,9 @@ defmodule Farmbot.BotState.Transport.GenMQTT do
Client.emit(client, ast)
handle_bot_state_events(rest, {internal_state, old_bot_state})
new_bot_state ->
Client.push_bot_state(client, new_bot_state)
if new_bot_state != old_bot_state do
Client.push_bot_state(client, new_bot_state)
end
handle_bot_state_events(rest, {internal_state, new_bot_state})
end
end

View File

@ -3,12 +3,25 @@ defmodule Farmbot.CeleryScript.AST.Node.TogglePin do
use Farmbot.CeleryScript.AST.Node
alias Farmbot.CeleryScript.AST.Node
allow_args [:pin_number]
use Farmbot.Logger
def execute(%{pin_number: num}, _, env) do
env = mutate_env(env)
case Farmbot.Firmware.read_pin(num, :digital) do
{:ok, 0} -> Node.WritePin.execute(%{pin_mode: :digital, pin_number: num, pin_value: 1}, [], env)
{:ok, 1} -> Node.WritePin.execute(%{pin_mode: :digital, pin_number: num, pin_value: 0}, [], env)
case Farmbot.BotState.get_pin_value(num) do
{:ok, 0} -> Node.WritePin.execute(%{pin_mode: :digital, pin_number: num, pin_value: 1}, [], env)
{:ok, 1} -> Node.WritePin.execute(%{pin_mode: :digital, pin_number: num, pin_value: 0}, [], env)
res when res == {:ok, -1} or res == {:error, :unknown_pin} ->
Logger.warn 2, "unknonw pin value. Setting to zero."
Node.WritePin.execute(%{pin_mode: :digital, pin_number: num, pin_value: 0}, [], env)
{:error, reason} -> {:error, reason, env}
end
end
defp do_get_pin_value(num, env) do
case Farmbot.BotState.get_pin_value(num) do
{:ok, 0} -> Node.WritePin.execute(%{pin_mode: :digital, pin_number: num, pin_value: 1}, [], env)
{:ok, 1} -> Node.WritePin.execute(%{pin_mode: :digital, pin_number: num, pin_value: 0}, [], env)
{:ok, -1} -> Node.WritePin.execute(%{pin_mode: :digital, pin_number: num, pin_value: 0}, [], env)
{:error, reason} -> {:error, reason, env}
end
end

View File

@ -6,7 +6,12 @@ defmodule Farmbot.CeleryScript.AST.Node.WritePin do
def execute(%{pin_mode: mode, pin_value: value, pin_number: num}, [], env) do
env = mutate_env(env)
case Farmbot.Firmware.write_pin(num, mode, value) do
:ok -> {:ok, env}
:ok ->
{:ok, env}
# case Farmbot.Firmware.read_pin(num, mode) do
# :ok -> {:ok, env}
# {:error, reason} -> {:error, reason, env}
# end
{:error, reason} -> {:error, reason, env}
end
end

View File

@ -2,7 +2,6 @@ defmodule Farmbot.CeleryScript.AST.Node.Zero do
@moduledoc false
use Farmbot.CeleryScript.AST.Node
allow_args [:axis]
@default_speed 100
def execute(%{axis: :all}, _, env) do
env = mutate_env(env)
@ -11,7 +10,7 @@ defmodule Farmbot.CeleryScript.AST.Node.Zero do
def execute(%{axis: axis}, _, env) do
env = mutate_env(env)
case Farmbot.Firmware.zero(axis, @default_speed) do
case Farmbot.Firmware.zero(axis) do
:ok -> {:ok, env}
{:error, reason} -> {:error, reason, env}
end

View File

@ -25,8 +25,8 @@ defmodule Farmbot.Firmware do
end
@doc "Manually set an axis's current position to zero."
def zero(axis, speed) do
GenStage.call(__MODULE__, {:zero, [axis, speed]})
def zero(axis) do
GenStage.call(__MODULE__, {:zero, [axis]})
end
@doc """
@ -90,7 +90,15 @@ defmodule Farmbot.Firmware do
}
end
def handle_info({:EXIT, _, reason}, state) do
Logger.error 1, "Firmware handler: #{state.handler_mod} died: #{inspect reason}"
{:ok, handler} = state.handler_mod.start_link()
new_state = %{state | handler: handler}
{:noreply, [], new_state}
end
def handle_call({fun, args}, _from, %{handler: handler, handler_mod: handler_mod} = state) do
Logger.debug 3, "Firmware command: #{fun}#{inspect(args)}"
res =
case apply(handler_mod, fun, [handler | args]) do
{:ok, _} = res -> res
@ -107,13 +115,6 @@ defmodule Farmbot.Firmware do
{:noreply, diffs, state}
end
def handle_info({:EXIT, _, reason}, state) do
Logger.error 1, "Firmware handler: #{state.handler_mod} died: #{inspect reason}"
{:ok, handler} = state.handler_mod.start_link()
new_state = %{state | handler: handler}
{:noreply, [], new_state}
end
defp handle_gcodes(codes, state, acc \\ [])
defp handle_gcodes([], state, acc), do: {Enum.reverse(acc), state}
@ -148,7 +149,7 @@ defmodule Farmbot.Firmware do
end
defp handle_gcode({:report_pin_mode, pin, mode_atom}, state) do
# Logger.debug "Got pin mode report: #{pin}: #{mode_atom}"
Logger.debug 3, "Got pin mode report: #{pin}: #{mode_atom}"
mode = if(mode_atom == :digital, do: 0, else: 1)
case state.pins[pin] do
%{mode: _, value: _} = pin_map ->
@ -159,7 +160,7 @@ defmodule Farmbot.Firmware do
end
defp handle_gcode({:report_pin_value, pin, value}, state) do
# Logger.debug "Got pin value report: #{pin}: #{value} old: #{inspect state.pins[pin]}"
Logger.debug 3, "Got pin value report: #{pin}: #{value} old: #{inspect state.pins[pin]}"
case state.pins[pin] do
%{mode: _, value: _} = pin_map ->
{:pins, %{pin => %{pin_map | value: value}}, %{state | pins: %{state.pins | pin => %{pin_map | value: value}}}}

View File

@ -45,7 +45,7 @@ defmodule Farmbot.Firmware.Handler do
@callback find_home(handler, axis, speed) :: fw_ret_val
@doc "Manually set an axis's current position to zero."
@callback zero(handler, axis, speed) :: fw_ret_val
@callback zero(handler, axis) :: fw_ret_val
@doc "Home an axis."
@callback home(handler, axis, speed) :: fw_ret_val

View File

@ -30,8 +30,8 @@ defmodule Farmbot.Firmware.StubHandler do
GenStage.call(handler, {:home, axis, speed})
end
def zero(handler, axis, speed) do
GenStage.call(handler, {:zero, axis, speed})
def zero(handler, axis) do
GenStage.call(handler, {:zero, axis})
end
def update_param(handler, param, val) do
@ -104,7 +104,7 @@ defmodule Farmbot.Firmware.StubHandler do
{:reply, :ok, [{:report_pin_mode, pin, mode}, {:report_pin_value, pin, value}], state}
end
def handle_call({:zero, axis, _speed}, _from, state) do
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}

View File

@ -28,8 +28,8 @@ defmodule Farmbot.Firmware.UartHandler do
GenStage.call(handler, {:home, axis, speed})
end
def zero(handler, axis, speed) do
GenStage.call(handler, {:zero, axis, speed})
def zero(handler, axis) do
GenStage.call(handler, {:zero, axis})
end
def update_param(handler, param, val) do
@ -61,8 +61,7 @@ defmodule Farmbot.Firmware.UartHandler do
defmodule State do
@moduledoc false
defstruct [
:nerves,
:codes
:nerves
]
end
@ -76,7 +75,7 @@ defmodule Farmbot.Firmware.UartHandler do
Process.link(nerves)
case open_tty(nerves, tty) do
:ok -> {:producer, %State{nerves: nerves, codes: []}, dispatcher: GenStage.BroadcastDispatcher}
:ok -> {:producer, %State{nerves: nerves}, dispatcher: GenStage.BroadcastDispatcher}
err -> {:stop, err, :no_state}
end
end
@ -116,7 +115,7 @@ defmodule Farmbot.Firmware.UartHandler do
end
def handle_info({:nerves_uart, _, {_q, gcode}}, state) do
do_dispatch([gcode | state.codes], state)
{:noreply, [gcode], state}
end
def handle_info({:nerves_uart, _, bin}, state) when is_binary(bin) do
@ -125,8 +124,82 @@ defmodule Farmbot.Firmware.UartHandler do
end
def handle_call({:move_absolute, pos, speed}, _from, state) do
UART.write(state.nerves, "G00 X#{pos.x} Y#{pos.y} Z#{pos.z} A#{speed} B#{speed} C#{speed}")
{:noreply, [], state}
r = UART.write(state.nerves, "G00 X#{pos.x} Y#{pos.y} Z#{pos.z} A#{speed} B#{speed} C#{speed}")
{:reply, r, [], state}
end
def handle_call({:calibrate, axis, _speed}, _from, state) do
num = case axis |> to_string() do
"x" -> 14
"y" -> 15
"z" -> 16
end
r = UART.write(state.nerves, "F#{num}")
{:reply, r, [], state}
end
def handle_call({:find_home, axis, speed}, _from, state) do
cmd = case axis |> to_string() do
"x" -> "11 A#{speed}"
"y" -> "12 B#{speed}"
"z" -> "13 C#{speed}"
end
r = UART.write(state.nerves, "F#{cmd}")
{:reply, r, [], state}
end
def handle_call({:home, axis, speed}, _from, state) do
cmd = case axis |> to_string() do
"x" -> "X0 A#{speed}"
"y" -> "Y0 B#{speed}"
"z" -> "Z0 C#{speed}"
end
r = UART.write(state.nerves, "G00 #{cmd}")
{:reply, r, [], state}
end
def handle_call({:zero, axis}, _from, state) do
axis_format = case axis |> to_string() do
"x" -> "X"
"y" -> "Y"
"z" -> "Z"
end
r = UART.write(state.nerves, "F84 #{axis_format}")
{:reply, r, [], state}
end
def handle_call(:emergency_lock, _from, state) do
r = UART.write(state.nerves, "E")
{:reply, r, [], state}
end
def handle_call(:emergency_unlock, _from, state) do
r = UART.write(state.nerves, "F09")
{:reply, r, [], state}
end
def handle_call({:read_pin, pin, mode}, _from, state) do
encoded_mode = if(mode == :digital, do: 0, else: 1)
case UART.write(state.nerves, "F43 P#{pin} M#{encoded_mode}") do
:ok ->
Process.sleep(100)
r = UART.write(state.nerves, "F42 P#{pin} M#{encoded_mode}")
{:reply, r, [{:report_pin_mode, pin, mode}], state}
err ->
{:reply, err, [], state}
end
end
def handle_call({:write_pin, pin, mode, value}, _from, state) do
encoded_mode = if(mode == :digital, do: 0, else: 1)
case UART.write(state.nerves, "F43 P#{pin} M#{encoded_mode}") do
:ok ->
Process.sleep(100)
r = UART.write(state.nerves, "F41 P#{pin} V#{value} M#{encoded_mode}")
{:reply, r, [{:report_pin_mode, pin, mode}, {:report_pin_value, pin, value}], state}
err ->
{:reply, err, [], state}
end
end
def handle_call(_call, _from, state) do
@ -134,10 +207,6 @@ defmodule Farmbot.Firmware.UartHandler do
end
def handle_demand(_amnt, state) do
do_dispatch(state.codes, state)
end
defp do_dispatch(codes, state) do
{:noreply, Enum.reverse(codes), %{state | codes: []}}
{:noreply, [], state}
end
end