Packages
grizzly
9.1.2
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/generic.ex
defmodule Grizzly.ZWave.Commands.Generic do
@moduledoc """
Generic encoder and decoder for Z-Wave commands.
"""
@behaviour Grizzly.ZWave.Command
alias Grizzly.ZWave.Command
alias Grizzly.ZWave.CommandSpec
alias Grizzly.ZWave.DecodeError
alias Grizzly.ZWave.ParamSpec
@impl Grizzly.ZWave.Command
def encode_params(spec, cmd) do
do_encode_params(spec.params, cmd, [])
end
# Base case: no more params to encode
defp do_encode_params([], _cmd, parts) do
for bitstring <- Enum.reverse(parts), into: <<>>, do: bitstring
end
# Recursive case: encode the next param
defp do_encode_params([{name, param_spec} | params], cmd, parts) do
value =
cond do
match?({:length, _}, param_spec.type) ->
{:length, other_param} = param_spec.type
other_value = Command.param!(cmd, other_param)
byte_size(other_value)
param_spec.required and param_spec.type not in [:constant, :reserved] ->
Command.param!(cmd, name)
true ->
Keyword.get(cmd.params, name, param_spec.default)
end
# When we get to a non-required param that is not present, stop encoding
if not Keyword.has_key?(cmd.params, name) and param_spec.required == false do
do_encode_params([], cmd, parts)
else
encoded_value = ParamSpec.encode_value(param_spec, value, cmd.params)
# For params of type {:length, other_param}, we need to put the encoded
# value into the params because the later param probably has its size
# specified as {:variable, this_param}
cmd =
case param_spec.type do
# Put the bit length into prams even though we're encoding the byte length
{:length, _} -> Command.put_param(cmd, name, value * 8)
_ -> cmd
end
parts = [encoded_value | parts]
do_encode_params(params, cmd, parts)
end
end
@impl Grizzly.ZWave.Command
def decode_params(%CommandSpec{} = spec, binary) do
do_decode_params(spec.params, binary, [])
end
# Base case: we ran out of params to decode. Doesn't matter if there's anything
# left in the binary since the spec says to ignore it.
defp do_decode_params([], _binary, decoded_params), do: {:ok, Enum.reverse(decoded_params)}
# Alt base case: We ran out of binary before we ran out of params. That's okay
# if the next param isn't required, but otherwise, we need to error out.
defp do_decode_params([{name, param_spec} | params], <<>>, decoded_params) do
cond do
param_spec.required and param_spec.size != :variable ->
{:error, %DecodeError{param: name, value: nil, reason: "unexpected end of command"}}
param_spec.type == :binary and param_spec.size == :variable ->
do_decode_params(params, <<>>, [{name, <<>>} | decoded_params])
param_spec.required ->
{:error, %DecodeError{param: name, value: nil, reason: "unexpected end of command"}}
true ->
do_decode_params(params, <<>>, [{name, nil} | decoded_params])
end
end
# Recursive case: Decode the next param
defp do_decode_params([{name, param_spec} | params], binary, decoded_params) do
with {:ok, {actual_size, value, rest}} <-
ParamSpec.take_bits(param_spec, binary, decoded_params),
{:ok, decoded_value} <-
ParamSpec.decode_value(%{param_spec | size: actual_size}, value, decoded_params) do
if ParamSpec.include_when_decoding?(param_spec) do
do_decode_params(params, rest, [{name, decoded_value} | decoded_params])
else
do_decode_params(params, rest, decoded_params)
end
end
end
end