defmodule Grizzly.ZWave.Commands.NodeInformationSend do
@moduledoc """
Instruct a node to send its Node Information Frame to another node (typically
a controller).
### Params
* seq_number - the sequence number of the network managment command (required)
* destination_node_id - the node that should receive the node information frame (required)
* tx_options - the transmission options for the target node to use when sending its NIF (optional)
"""
@behaviour Grizzly.ZWave.Command
import Bitwise
alias Grizzly.ZWave.Command
alias Grizzly.ZWave.CommandClasses.NetworkManagementBasicNode
@type tx_opt :: :ack | :low_power | :no_route | :explore
@type param ::
{:seq_number, Grizzly.seq_number()}
| {:destination_node_id, Grizzly.node_id()}
| {:tx_options, [tx_opt()]}
@impl Grizzly.ZWave.Command
def new(params) do
command = %Command{
name: :node_information_send,
command_byte: 0x05,
command_class: NetworkManagementBasicNode,
params: params,
impl: __MODULE__
}
{:ok, command}
end
@impl Grizzly.ZWave.Command
@spec encode_params(Command.t()) :: binary()
def encode_params(command) do
seq_number = Command.param!(command, :seq_number)
destination_node_id = Command.param!(command, :destination_node_id)
tx_options = Command.param(command, :tx_options, []) |> encode_tx_options()
<<seq_number::8, 0::8, destination_node_id::8, tx_options::8>>
end
@impl Grizzly.ZWave.Command
@spec decode_params(binary()) :: {:ok, [param()]}
def decode_params(<<seq_number::8, _reserved::8, destination_node_id::8, tx_options::8>>) do
{:ok,
[
seq_number: seq_number,
destination_node_id: destination_node_id,
tx_options: decode_tx_options(tx_options)
]}
end
@spec encode_tx_options([tx_opt()]) :: byte()
defp encode_tx_options(tx_options) do
Enum.reduce(tx_options, 0, fn tx_option, acc ->
acc ||| tx_opt_to_byte(tx_option)
end)
end
@spec decode_tx_options(byte()) :: [tx_opt()]
defp decode_tx_options(tx_options) do
[
if((tx_options &&& 0x01) == 0x01, do: :ack),
if((tx_options &&& 0x02) == 0x02, do: :low_power),
if((tx_options &&& 0x10) == 0x10, do: :no_route),
if((tx_options &&& 0x20) == 0x20, do: :explore)
]
|> Enum.filter(&Function.identity/1)
end
@spec tx_opt_to_byte(tx_opt()) :: byte()
defp tx_opt_to_byte(:ack), do: 0x01
defp tx_opt_to_byte(:low_power), do: 0x02
defp tx_opt_to_byte(:no_route), do: 0x10
defp tx_opt_to_byte(:explore), do: 0x20
end