Skip to content

Instantly share code, notes, and snippets.

@adkron
Created June 26, 2017 22:13
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save adkron/ade02c0576ce01272ab6368be6dbe883 to your computer and use it in GitHub Desktop.
defmodule Zwave.Controller do
@moduledoc """
Handles low level Zwave control
"""
alias Zwave.{
ControllerLocator,
Configuration,
Status,
}
use Status
@soft_reset_command <<0x08>>
@type t :: %Zwave.Controller{
config: Configuration.t
}
defstruct [:port, :name, :uart, :gpio, :config]
@spec init(Configuration.t)
:: t
def init(configuration) do
%__MODULE__{config: configuration}
end
@spec start(%__MODULE__{
port: binary,
name: String.t,
config: Configuration.t
}
| {:error, any})
:: %__MODULE__{
port: binary,
uart: pid,
gpio: pid | :none,
name: String.t,
config: Configuration.t,
}
| {:error, any}
def start({:error, _} = error), do: error
def start(%__MODULE__{port: port, config: config} = controller) do
with {:ok, uart} <- start_uart(config),
{:ok, gpio} <- start_gpio(config),
:ok <- open_serial_port(config, uart, port),
do: %{controller | uart: uart, gpio: gpio}
end
def reset(%{gpio: :none} = controller), do: soft_reset(controller)
def reset(controller), do: hard_reset(controller)
@spec soft_reset(
%__MODULE__{
uart: pid,
port: String.t,
config: Configuration.t,
}
)
:: :ok
def soft_reset(%{uart: uart, port: port, config: config} = controller) do
close_serial_port(config, uart)
open_serial_port(config, uart, port)
write(controller, Status.not_acknowledge)
write(controller, @soft_reset_command)
Process.sleep(1_500)
:ok
end
@spec hard_reset(
%__MODULE__{
uart: pid,
gpio: pid,
port: String.t,
config: Configuration.t,
}
)
:: :ok
def hard_reset(%{uart: uart, gpio: gpio, port: port, config: config}) do
close_serial_port(config, uart)
assert_module_reset(config, gpio)
open_serial_port(config, uart, port)
release_module_reset(config, gpio)
Process.sleep(500)
:ok
end
@spec find(%__MODULE__{config: Configuration.t})
:: %__MODULE__{
port: integer,
name: String.t,
config: Configuration.t,
}
| {:error, :no_controller}
def find(%{config: config}) do
case ControllerLocator.find(config.uart.enumerate) do
%__MODULE__{} = controller -> %{controller | config: config}
error -> error
end
end
@spec write(%__MODULE__{
uart: pid,
config: Configuration.t,
}, Zwave.wire_protocol | Zwave.command)
:: :ok
| {:error, any}
def write(controller, {_, data}) do
write(controller, data)
end
def write(%{uart: pid, config: %{uart: uart}}, data) do
uart.write(pid, data)
end
@spec start_uart(Configuration.t)
:: {:ok, pid} | {:error, any}
defp start_uart(%{uart: uart}) do
uart.start_link
end
@spec start_gpio(Configuration.t)
:: {:ok, pid | :none}
defp start_gpio(%Configuration{reset_pin: :none}), do: {:ok, :none}
defp start_gpio(%Configuration{gpio: gpio, reset_pin: reset_pin}) do
gpio.start_link(reset_pin, :output)
end
@spec open_serial_port(Configuration.t, pid, port :: String.t)
:: :ok
| {:error, term}
defp open_serial_port(%Configuration{uart: uart}, pid, port) do
uart.open(pid,
port,
active: true,
speed: 115_200,
framing: Zwave.Framing)
end
@spec close_serial_port(Configuration.t, pid)
:: :ok
| {:error, term}
defp close_serial_port(%{uart: uart}, pid) do
uart.close(pid)
end
@spec assert_module_reset(Configuration.t, pid)
:: :ok
| {:error, term}
defp assert_module_reset(%{gpio: gpio}, pid) do
gpio.write(pid, 0)
end
@spec release_module_reset(Configuration.t, pid)
:: :ok
| {:error, term}
defp release_module_reset(%{gpio: gpio}, pid) do
gpio.write(pid, 1)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment