Skip to content
Permalink
Browse files

Add new RPC for `toggle_pin`

This was previously implemented as a "macro" that just expanded
`toggle_pin` to a series of `read_pin` -> `write_pin` -> `read_pin` this
lead to three logs instead of just one. The implementation is still
mostly the same, but now there is less logging.

Also factored all pin control into it's own module
  • Loading branch information...
ConnorRigby committed Sep 9, 2019
1 parent c559e94 commit 39f0595335af813dc5ebddf499bd502c91a0fff4
@@ -799,13 +799,7 @@ defmodule FarmbotCeleryScript.Compiler do

compile :toggle_pin, %{pin_number: pin_number} do
quote location: :keep do
# mode 0 = digital
case FarmbotCeleryScript.SysCalls.read_pin(unquote(compile_ast(pin_number)), 0) do
0 -> FarmbotCeleryScript.SysCalls.write_pin(unquote(compile_ast(pin_number)), 0, 1)
_ -> FarmbotCeleryScript.SysCalls.write_pin(unquote(compile_ast(pin_number)), 0, 0)
end

FarmbotCeleryScript.SysCalls.read_pin(unquote(compile_ast(pin_number)), 0)
FarmbotCeleryScript.SysCalls.toggle_pin(unquote(pin_number))
end
end

@@ -51,6 +51,7 @@ defmodule FarmbotCeleryScript.SysCalls do
@callback point(point_type :: String.t(), resource_id) :: number() | error()
@callback power_off() :: ok_or_error
@callback read_pin(pin_num :: number(), pin_mode :: number()) :: number | error()
@callback toggle_pin(pin_num :: number()) :: ok_or_error
@callback read_status() :: ok_or_error
@callback reboot() :: ok_or_error
@callback resource_update(String.t(), resource_id, map()) :: ok_or_error
@@ -220,6 +221,10 @@ defmodule FarmbotCeleryScript.SysCalls do
number_or_error(sys_calls, :read_pin, [pin_num, pin_mode])
end

def toggle_pin(sys_calls \\ @sys_calls, pun_num) do
ok_or_error(sys_calls, :toggle_pin, [pun_num])
end

def read_status(sys_calls \\ @sys_calls) do
ok_or_error(sys_calls, :read_status, [])
end
@@ -94,6 +94,9 @@ defmodule FarmbotCeleryScript.SysCalls.Stubs do
@impl true
def read_pin(pin_num, pin_mode), do: error(:read_pin, [pin_num, pin_mode])

@impl true
def toggle_pin(pin_num), do: error(:toggle_pin, [pin_num])

@impl true
def read_status(), do: error(:read_status, [])

@@ -7,9 +7,7 @@ defmodule FarmbotOS.SysCalls do

alias FarmbotCore.Asset.{
BoxLed,
Peripheral,
Private,
Sensor
Private
}

alias FarmbotOS.SysCalls.{
@@ -20,7 +18,8 @@ defmodule FarmbotOS.SysCalls do
FactoryReset,
FlashFirmware,
SendMessage,
SetPinIOMode
SetPinIOMode,
PinControl
}

alias FarmbotOS.Lua
@@ -64,6 +63,15 @@ defmodule FarmbotOS.SysCalls do
defdelegate eval_assertion(comment, expression), to: Lua
defdelegate log_assertion(passed?, type, message), to: Lua

@impl true
defdelegate read_pin(number, mode), to: PinControl

@impl true
defdelegate write_pin(number, mode, value), to: PinControl

@impl true
defdelegate toggle_pin(number), to: PinControl

@impl true
def log(message) do
if FarmbotCore.Asset.fbos_config(:sequence_body_log) do
@@ -176,231 +184,6 @@ defmodule FarmbotOS.SysCalls do
end
end

@impl true
def read_pin(%Peripheral{pin: _} = data, mode) do
do_read_pin(data, mode)
end

def read_pin(%Sensor{pin: pin} = data, mode) do
case do_read_pin(data, mode) do
{:error, _} = error ->
error

value ->
position = get_position()

params = %{
pin: pin,
mode: mode,
value: value,
x: position[:x],
y: position[:y],
z: position[:z]
}

_ = Asset.new_sensor_reading!(params)
value
end
end

def read_pin(%BoxLed{}, _mode) do
# {:error, "cannot read values of BoxLed"}
1
end

def read_pin(pin_number, mode) when is_number(pin_number) do
sensor = Asset.get_sensor_by_pin(pin_number)
peripheral = Asset.get_peripheral_by_pin(pin_number)

cond do
is_map(sensor) ->
read_pin(sensor, mode)

is_map(peripheral) ->
read_pin(peripheral, mode)

true ->
do_read_pin(pin_number, mode)
end
end

# digital peripheral

defp do_read_pin(%Peripheral{pin: pin_number, label: label}, 0) when is_number(pin_number) do
case FarmbotFirmware.request({:pin_read, [p: pin_number, m: 0]}) do
{:ok, {_, {:report_pin_value, [p: _, v: 1]}}} ->
FarmbotCore.Logger.info(2, "The #{label} peripheral value is ON (digital)")
1

{:ok, {_, {:report_pin_value, [p: _, v: 0]}}} ->
FarmbotCore.Logger.info(2, "The #{label} peripheral value is OFF (digital)")
0

# Just in case
{:ok, {_, {:report_pin_value, [p: _, v: value]}}} ->
FarmbotCore.Logger.info(2, "The #{label} peripheral value is #{value} (analog)")
value

{:error, reason} ->
{:error, "Firmware error: #{inspect(reason)}"}
end
end

# analog peripheral

defp do_read_pin(%Peripheral{pin: pin_number, label: label}, 1) when is_number(pin_number) do
case FarmbotFirmware.request({:pin_read, [p: pin_number, m: 1]}) do
{:ok, {_, {:report_pin_value, [p: _, v: value]}}} ->
FarmbotCore.Logger.info(2, "The #{label} peripheral value is #{value} (analog)")
value

{:error, reason} ->
{:error, "Firmware error: #{inspect(reason)}"}
end
end

# digital sensor

defp do_read_pin(%Sensor{pin: pin_number, label: label}, 0) when is_number(pin_number) do
case FarmbotFirmware.request({:pin_read, [p: pin_number, m: 0]}) do
{:ok, {_, {:report_pin_value, [p: _, v: 1]}}} ->
FarmbotCore.Logger.info(2, "The #{label} sensor value is 1 (digital)")
1

{:ok, {_, {:report_pin_value, [p: _, v: 0]}}} ->
FarmbotCore.Logger.info(2, "The #{label} sensor value is 0 (digital)")
0

{:ok, {_, {:report_pin_value, [p: _, v: value]}}} ->
FarmbotCore.Logger.info(2, "The #{label} sensor value is #{value} (analog)")

{:error, reason} ->
{:error, "Firmware error: #{inspect(reason)}"}
end
end

# analog sensor

defp do_read_pin(%Sensor{pin: pin_number, label: label}, 1) when is_number(pin_number) do
case FarmbotFirmware.request({:pin_read, [p: pin_number, m: 1]}) do
{:ok, {_, {:report_pin_value, [p: _, v: value]}}} ->
FarmbotCore.Logger.info(2, "The #{label} sensor value is #{value} (analog)")
value

{:error, reason} ->
{:error, "Firmware error: #{inspect(reason)}"}
end
end

# Generic pin digital
defp do_read_pin(pin_number, 0) when is_number(pin_number) do
case FarmbotFirmware.request({:pin_read, [p: pin_number, m: 0]}) do
{:ok, {_, {:report_pin_value, [p: _, v: 0]}}} ->
FarmbotCore.Logger.info(2, "Pin #{pin_number} value is OFF (digital)")
0

{:ok, {_, {:report_pin_value, [p: _, v: 1]}}} ->
FarmbotCore.Logger.info(2, "Pin #{pin_number} value is ON (digital)")
1

{:ok, {_, {:report_pin_value, [p: _, v: value]}}} ->
FarmbotCore.Logger.info(2, "Pin #{pin_number} is #{value} (analog)")
value

{:error, reason} ->
{:error, "Firmware error: #{inspect(reason)}"}
end
end

# Generic pin digital
defp do_read_pin(pin_number, 1) when is_number(pin_number) do
case FarmbotFirmware.request({:pin_read, [p: pin_number, m: 1]}) do
{:ok, {_, {:report_pin_value, [p: _, v: value]}}} ->
FarmbotCore.Logger.info(2, "Pin #{pin_number} is #{value} (analog)")
value

{:error, reason} ->
{:error, "Firmware error: #{inspect(reason)}"}
end
end

@impl true

# Peripheral digital
def write_pin(%Peripheral{pin: pin, label: label}, 0, 1) do
FarmbotCore.Logger.info(2, "Turning the #{label} ON (digital)")
do_write_pin(pin, 0, 1)
end

def write_pin(%Peripheral{pin: pin, label: label}, 0, 0) do
FarmbotCore.Logger.info(2, "Turning the #{label} OFF (digital)")
do_write_pin(pin, 0, 0)
end

# Peripheral analog
def write_pin(%Peripheral{pin: pin, label: label}, 1, value) do
FarmbotCore.Logger.info(2, "Setting the #{label} to #{value} (analog)")
do_write_pin(pin, 0, 0)
end

def write_pin(%Sensor{pin: _pin}, _mode, _value) do
{:error, "cannot write Sensor value. Use a Peripheral"}
end

def write_pin(%BoxLed{id: 3}, 0, 1) do
FarmbotCore.Logger.info(2, "Turning Boxled3 ON")
Leds.white4(:solid)
:ok
end

def write_pin(%BoxLed{id: 3}, 0, 0) do
FarmbotCore.Logger.info(2, "Turning Boxled3 OFF")
Leds.white4(:off)
:ok
end

def write_pin(%BoxLed{id: 4}, 0, 1) do
FarmbotCore.Logger.info(2, "Turning Boxled4 ON")
Leds.white5(:solid)
:ok
end

def write_pin(%BoxLed{id: 4}, 0, 0) do
FarmbotCore.Logger.info(2, "Turning Boxled4 OFF")
Leds.white5(:off)
:ok
end

def write_pin(%BoxLed{id: id}, _mode, _) do
{:error, "cannon write Boxled#{id} in analog mode"}
end

# Generic pin digital
def write_pin(pin, 0, 1) do
FarmbotCore.Logger.info(2, "Turning pin #{pin} ON (digital)")
do_write_pin(pin, 0, 1)
end

def write_pin(pin, 0, 0) do
FarmbotCore.Logger.info(2, "Turning pin #{pin} OFF (digital)")
do_write_pin(pin, 0, 0)
end

def write_pin(pin, 1, value) do
FarmbotCore.Logger.info(2, "Setting pin #{pin} to #{value} (analog)")
do_write_pin(pin, 1, value)
end

def do_write_pin(pin_number, mode, value) do
case FarmbotFirmware.command({:pin_write, [p: pin_number, v: value, m: mode]}) do
:ok ->
:ok

{:error, reason} ->
{:error, "Firmware error: #{inspect(reason)}"}
end
end

@impl true
def point(kind, id) do
case Asset.get_point(id: id) do

0 comments on commit 39f0595

Please sign in to comment.
You can’t perform that action at this time.