Packages
grizzly
5.2.1
9.1.4
9.1.2
9.1.1
9.1.0
9.0.0
8.15.3
8.15.2
8.15.1
8.15.0
8.14.0
8.13.0
8.12.0
8.11.3
8.11.2
8.11.1
8.11.0
8.10.0
8.9.0
8.8.1
8.8.0
8.7.1
8.7.0
8.6.12
8.6.11
8.6.10
8.6.9
8.6.8
8.6.7
retired
8.6.6
8.6.5
8.6.4
8.6.3
8.6.2
8.6.1
8.6.0
8.5.3
8.5.2
8.5.1
8.5.0
8.4.0
8.3.0
8.2.3
8.2.2
8.2.1
8.2.0
8.1.0
8.0.1
8.0.0
7.4.3
7.4.2
7.4.1
7.4.0
7.3.0
7.2.0
7.1.4
7.1.3
7.1.2
7.1.1
7.1.0
7.0.4
7.0.3
7.0.2
7.0.1
7.0.0
6.8.8
6.8.7
6.8.6
6.8.5
6.8.4
6.8.3
6.8.2
6.8.1
6.8.0
6.7.1
6.7.0
6.6.1
6.6.0
6.5.1
6.5.0
6.4.0
6.3.0
6.2.0
6.1.1
6.1.0
6.0.1
6.0.0
5.4.1
5.4.0
5.3.0
5.2.8
5.2.7
5.2.6
5.2.5
5.2.4
5.2.3
5.2.2
5.2.1
5.2.0
5.1.2
5.1.1
5.1.0
5.0.2
5.0.1
5.0.0
4.0.1
4.0.0
3.0.0
2.1.0
2.0.0
1.0.1
1.0.0
0.22.7
0.22.6
0.22.5
0.22.4
0.22.3
0.22.2
0.22.1
0.22.0
0.21.1
0.21.0
0.20.2
0.20.1
0.20.0
0.19.1
0.19.0
0.18.3
0.18.2
0.18.1
0.18.0
0.17.7
0.17.6
0.17.5
0.17.4
0.17.3
0.17.2
0.17.1
0.17.0
0.16.2
0.16.1
0.16.0
0.15.11
0.15.10
0.15.9
0.15.8
0.15.7
0.15.6
0.15.5
0.15.4
0.15.3
0.15.2
0.15.1
0.15.0
0.14.8
0.14.7
0.14.6
0.14.5
0.14.4
0.14.3
0.14.2
0.14.1
0.14.0
0.13.0
0.12.3
0.12.2
0.12.1
0.12.0
0.11.0
0.10.3
0.10.2
0.10.1
0.10.0
0.9.0
0.9.0-rc.4
0.9.0-rc.3
0.9.0-rc.2
0.9.0-rc.1
0.9.0-rc.0
0.8.8
0.8.7
0.8.6
0.8.5
0.8.4
0.8.3
0.8.2
0.8.1
0.8.0
0.7.0
0.6.6
0.6.5
0.6.4
0.6.3
0.6.2
0.6.1
0.6.0
0.5.0
0.4.3
0.4.2
Elixir Z-Wave library
Current section
Files
Jump to
Current section
Files
lib/grizzly/zwave/commands/multi_channel_command_encapsulation.ex
defmodule Grizzly.ZWave.Commands.MultiChannelCommandEncapsulation do
@moduledoc """
This command is used to encapsulate commands to or from a Multi Channel End Point.
Params:
* `:source_end_point` - the originating End Point (defaults to 0 - if 0, destination_end_point must be non-zero).
* `:bit_address?` - whether the End Point is bit-masked, or as-is (defaults to false)
* `:destination_end_point` - the destination End Point. (defaults to 0 - - if 0, source_end_point must be non-zero)
* `:command_class` - the command class of the command sent (required)
* `:command` - the name of the command (required)
* `:parameters` - the command parameters (required)
"""
@behaviour Grizzly.ZWave.Command
alias Grizzly.ZWave.{Command, DecodeError, CommandClasses, Decoder}
alias Grizzly.Commands.Table
alias Grizzly.ZWave.CommandClasses.MultiChannel
@type param ::
{:source_end_point, MultiChannel.end_point()}
| {:destination_end_point, MultiChannel.end_point()}
| {:bit_address?, boolean()}
| {:command_class, CommandClasses.command_class()}
| {:command, atom()}
| {:parameters, Command.params()}
@impl true
@spec new([param()]) :: {:ok, Command.t()}
def new(params) do
command = %Command{
name: :multi_channel_command_encapsulation,
command_byte: 0x0D,
command_class: MultiChannel,
params: params,
impl: __MODULE__
}
{:ok, command}
end
@impl true
@spec encode_params(Command.t()) :: binary()
def encode_params(command) do
source_end_point = Command.param(command, :source_end_point, 0)
destination_end_point = Command.param(command, :destination_end_point, 0)
bit_address? = Command.param(command, :bit_address?, false)
command_class = Command.param!(command, :command_class)
encapsulated_command_name = Command.param!(command, :command)
parameters = Command.param!(command, :parameters)
destination_end_point_byte = encode_destination_end_point(destination_end_point, bit_address?)
encoded_command_class = CommandClasses.to_byte(command_class)
encapsulated_command = make_command(encapsulated_command_name, parameters)
encapsulated_parameters =
apply(encapsulated_command.impl, :encode_params, [encapsulated_command])
encapsulated_command_byte = encapsulated_command.command_byte
if encapsulated_command_byte == nil do
# The no_operation command has no command byte
<<0x00::size(1), source_end_point::size(7), destination_end_point_byte,
encoded_command_class>>
else
<<0x00::size(1), source_end_point::size(7), destination_end_point_byte,
encoded_command_class, encapsulated_command_byte>>
end <>
encapsulated_parameters
end
@impl true
@spec decode_params(binary()) :: {:ok, [param()]} | {:error, DecodeError.t()}
def decode_params(
<<0x00::size(1), source_end_point::size(7), bit_address::size(1),
encoded_destination_end_point::size(7), command_class_byte, command_byte,
parameters_binary::binary>>
) do
{:ok, command_class} = CommandClasses.from_byte(command_class_byte)
bit_address? = bit_address == 1
destination_end_point =
decode_destination_end_point(encoded_destination_end_point, bit_address?)
with {:ok, encapsulated_command} <-
decode_command(command_class_byte, command_byte, parameters_binary) do
decoded_params = [
source_end_point: source_end_point,
bit_address?: bit_address?,
destination_end_point: destination_end_point,
command_class: command_class,
command: encapsulated_command.name,
parameters: encapsulated_command.params
]
{:ok, decoded_params}
else
{:error, %DecodeError{}} = error ->
error
end
end
defp encode_destination_end_point(0, _bit_address?), do: 0
defp encode_destination_end_point(destination_end_point, false)
when destination_end_point in 1..127,
do: destination_end_point
defp encode_destination_end_point(destination_end_point, true)
when destination_end_point in 1..7 do
<<byte>> =
for i <- 7..1, into: <<0x01::size(1)>> do
if destination_end_point == i, do: <<0x01::size(1)>>, else: <<0x00::size(1)>>
end
byte
end
defp make_command(command_name, parameters) do
{command_module, _} = Table.lookup(command_name)
{:ok, command} = apply(command_module, :new, [parameters])
command
end
defp decode_command(command_class_byte, command_byte, parameters_binary) do
Decoder.from_binary(<<command_class_byte, command_byte>> <> parameters_binary)
end
defp decode_destination_end_point(0, _bit_address?), do: 0
defp decode_destination_end_point(destination_end_point, false), do: destination_end_point
defp decode_destination_end_point(encoded_destination_end_point, true) do
bit_index =
for(<<(x::1 <- <<encoded_destination_end_point>>)>>, do: x)
|> Enum.reverse()
|> Enum.with_index()
|> Enum.find(fn {bit, _index} ->
bit == 1
end)
|> elem(1)
bit_index + 1
end
end