155 lines
4.3 KiB
Elixir
155 lines
4.3 KiB
Elixir
defmodule FarmbotFirmware.Request do
|
|
@moduledoc false
|
|
|
|
# sister module to FarmbotFirmware.Command
|
|
# see docs for FarmbotFirmware.request/1
|
|
|
|
alias FarmbotFirmware
|
|
alias FarmbotFirmware.GCODE
|
|
|
|
@spec request(GenServer.server(), GCODE.t()) ::
|
|
{:ok, GCODE.t()}
|
|
| {:error,
|
|
:invalid_command | :firmware_error | FarmbotFirmware.status()}
|
|
def request(firmware_server \\ FarmbotFirmware, code)
|
|
|
|
def request(firmware_server, {_tag, {kind, _}} = code) do
|
|
if kind not in [
|
|
:parameter_read,
|
|
:status_read,
|
|
:pin_read,
|
|
:end_stops_read,
|
|
:position_read,
|
|
:software_version_read
|
|
] do
|
|
raise ArgumentError, "#{kind} is not a valid request."
|
|
end
|
|
|
|
case GenServer.call(firmware_server, code, :infinity) do
|
|
{:ok, tag} ->
|
|
wait_for_request_result(tag, code)
|
|
|
|
{:error, status} ->
|
|
{:error, status}
|
|
end
|
|
end
|
|
|
|
def request(firmware_server, {_, _} = code) do
|
|
request(firmware_server, {to_string(:rand.uniform(100)), code})
|
|
end
|
|
|
|
# This is a bit weird but let me explain:
|
|
# if this function `receive`s
|
|
# * report_error
|
|
# * report_invalid
|
|
# * report_emergency_lock
|
|
# it needs to return an error.
|
|
# If this function `receive`s
|
|
# * report_success
|
|
# when no valid data has been collected from `wait_for_request_result_process`
|
|
# it needs to return an error.
|
|
# If this function `receive`s
|
|
# * report_success
|
|
# when valid data has been collected from `wait_for_request_result_process`
|
|
# it will return that data.
|
|
# If this function returns no data for 5 seconds, it needs to error.
|
|
defp wait_for_request_result(tag, code, result \\ nil) do
|
|
receive do
|
|
{tag, {:report_begin, []}} ->
|
|
wait_for_request_result(tag, code, result)
|
|
|
|
{tag, {:report_busy, []}} ->
|
|
wait_for_request_result(tag, code, result)
|
|
|
|
{tag, {:report_success, []}} ->
|
|
if result,
|
|
do: {:ok, {tag, result}},
|
|
else: wait_for_request_result(tag, code, result)
|
|
|
|
{_, {:report_error, _}} ->
|
|
{:error, :firmware_error}
|
|
|
|
{_, {:report_invalid, []}} ->
|
|
{:error, :invalid_command}
|
|
|
|
{_, {:report_emergency_lock, []}} ->
|
|
{:error, :emergency_lock}
|
|
|
|
{:error, reason} ->
|
|
{:error, reason}
|
|
|
|
{tag, report} ->
|
|
wait_for_request_result_process(report, tag, code, result)
|
|
after
|
|
10_000 ->
|
|
if result,
|
|
do: {:ok, {tag, result}},
|
|
else: {:error, "timeout waiting for request to complete"}
|
|
end
|
|
end
|
|
|
|
# {:parameter_read, [param]} => {:report_parameter_value, [{param, val}]}
|
|
defp wait_for_request_result_process(
|
|
{:report_parameter_value, _} = report,
|
|
tag,
|
|
{_, {:parameter_read, _}} = code,
|
|
_
|
|
) do
|
|
wait_for_request_result(tag, code, report)
|
|
end
|
|
|
|
# {:status_read, [status]} => {:report_status_value, [{status, value}]}
|
|
defp wait_for_request_result_process(
|
|
{:report_status_value, _} = report,
|
|
tag,
|
|
{_, {:status_read, _}} = code,
|
|
_
|
|
) do
|
|
wait_for_request_result(tag, code, report)
|
|
end
|
|
|
|
# {:pin_read, [pin]} => {:report_pin_value, [{pin, value}]}
|
|
defp wait_for_request_result_process(
|
|
{:report_pin_value, _} = report,
|
|
tag,
|
|
{_, {:pin_read, _}} = code,
|
|
_
|
|
) do
|
|
wait_for_request_result(tag, code, report)
|
|
end
|
|
|
|
# {:end_stops_read, []} => {:position_end_stops, end_stops}
|
|
defp wait_for_request_result_process(
|
|
{:report_end_stops, _} = report,
|
|
tag,
|
|
{_, {:end_stops_read, []}} = code,
|
|
_
|
|
) do
|
|
wait_for_request_result(tag, code, report)
|
|
end
|
|
|
|
# {:position_read, []} => {:position_report, [x: x, y: y, z: z]}
|
|
defp wait_for_request_result_process(
|
|
{:report_position, _} = report,
|
|
tag,
|
|
{_, {:position_read, []}} = code,
|
|
_
|
|
) do
|
|
wait_for_request_result(tag, code, report)
|
|
end
|
|
|
|
# {:software_version_read, []} => {:report_software_version, [version]}
|
|
defp wait_for_request_result_process(
|
|
{:report_software_version, _} = report,
|
|
tag,
|
|
{_, {:software_version_read, _}} = code,
|
|
_
|
|
) do
|
|
wait_for_request_result(tag, code, report)
|
|
end
|
|
|
|
defp wait_for_request_result_process(_report, tag, code, result) do
|
|
wait_for_request_result(tag, code, result)
|
|
end
|
|
end
|