Packages
grizzly
6.8.6
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/node_id_list.ex
defmodule Grizzly.ZWave.NodeIdList do
@moduledoc false
# This module contains helpers for parsing and encoding a list of node ids
# into a binary with bytes that are bitmasks of the node ids contained in the
# list. This is common in network commands that contain a list of node ids in
# the Z-Wave network.
@node_ids_list_len 29
@doc """
Parse a binary mask of node ids
"""
@spec parse(binary()) :: [Grizzly.ZWave.node_id()]
def parse(node_ids) when byte_size(node_ids) == @node_ids_list_len do
unmask(node_ids, &node_id_modifier/2)
end
def parse(<<node_ids::binary-size(@node_ids_list_len), 0x00::16, _rest::binary>>) do
unmask(node_ids, &node_id_modifier/2)
end
def parse(
<<node_ids::binary-size(@node_ids_list_len), extended_node_ids_list_len::16,
extended_node_ids_list::binary-size(extended_node_ids_list_len)>>
) do
unmask(node_ids, &node_id_modifier/2) ++
unmask(extended_node_ids_list, &node_id_extended_modifier/2)
end
defp unmask(node_ids_bin, modifier) do
unmask(node_ids_bin, 0, [], modifier)
end
defp unmask(<<>>, _byte_offset, node_ids_list, _modifier) do
Enum.sort(node_ids_list)
end
defp unmask(<<masked_byte::binary-size(1), rest::binary>>, byte_offset, node_id_list, modifier) do
new_node_id_list = add_node_ids_in_byte(masked_byte, node_id_list, byte_offset, modifier)
unmask(rest, byte_offset + 1, new_node_id_list, modifier)
end
defp add_node_ids_in_byte(byte, node_id_list, byte_offset, modifier) do
<<eight::1, seven::1, six::1, five::1, four::1, three::1, two::1, one::1>> = byte
node_ids = [
{one, 1},
{two, 2},
{three, 3},
{four, 4},
{five, 5},
{six, 6},
{seven, 7},
{eight, 8}
]
Enum.reduce(node_ids, node_id_list, fn
{0, _id}, ids -> ids
{1, id}, ids -> [modifier.(id, byte_offset) | ids]
end)
end
defp node_id_modifier(node_id, byte_offset), do: node_id + byte_offset * 8
defp node_id_extended_modifier(node_id, byte_offset),
do: node_id_modifier(node_id, byte_offset) + 255
@typedoc """
Options for when to encode the node list into a the binary mask
* `:extended` - weather or not the node list contains extended ids
(default `true`). For some command classes that predate Z-Wave long range
the node list binary only contains 29 bytes. After command class versions
that support 16 bit node ids the binary list will at minium contain 31
bytes, 29 for the 8 bit node ids and 2 bytes for the byte size of the
extended node id binary. If there are no extended node ids then this the
byte size bytes will be `0x00000`.
"""
@type to_binary_opt() :: {:extended, boolean()}
@doc """
Make a list of node ids into the binary node id list mask
"""
@spec to_binary([Grizzly.ZWave.node_id()], [to_binary_opt()]) :: binary()
def to_binary(node_id_list, opts \\ []) do
contains_extended? = Keyword.get(opts, :extended, true)
{node_ids, node_ids_extended} = :lists.partition(fn id -> id < 256 end, node_id_list)
node_ids_binary = node_ids_to_binary(node_ids)
if contains_extended? do
extended_node_ids_binary = extended_node_ids_to_binary(node_ids_extended)
extended_node_id_list_len = byte_size(extended_node_ids_binary)
<<node_ids_binary::binary, <<extended_node_id_list_len::16>>,
extended_node_ids_binary::binary>>
else
node_ids_binary
end
end
defp node_ids_to_binary(node_ids, opts \\ []) do
number_bytes = opts[:bytes] || 29
offset = opts[:offset] || 0
node_id_map = Enum.reduce(node_ids, %{}, fn id, hash -> Map.put(hash, id, id) end)
for byte_index <- 0..(number_bytes - 1), into: <<>> do
for bit_index <- 8..1, into: <<>> do
node_id = byte_index * 8 + bit_index + offset
if node_id_map[node_id], do: <<1::size(1)>>, else: <<0::size(1)>>
end
end
end
defp extended_node_ids_to_binary([]) do
<<>>
end
defp extended_node_ids_to_binary(node_ids) do
max = Enum.max(node_ids)
# Subtract 31 because the extended node ids start at the
# 31st byte of a node list binary mask. If we did not subtract
# the number of bytes would start at 32.
num_bytes = floor(max / 8) - 31
node_ids_to_binary(node_ids, offset: 255, bytes: num_bytes)
end
end