Packages
grizzly
0.8.8
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/packet.ex
defmodule Grizzly.Packet do
@moduledoc """
Module for working with raw Z/IP packets
This is used to marshall a Z/IP packet of bytes
into an Elixir data structure for use to work with.
This data structure is a more "lower level" representation of
the messaging between this library and Z-Wave. Most the time
you should probably be working with a `Grizzly.Message`.
This structure is for internal byte string parsing.
"""
# TODO: @mattludwigs - make a `to_message` function here or a `from_packet` function in
# Grizzly.Message to have no need to expose a Packet to the client.
require Logger
alias Grizzly.Packet.{Decode, BodyParser, HeaderExtension}
@type t :: %__MODULE__{
seq_number: non_neg_integer | nil,
body: any,
types: [type],
raw?: boolean,
header_extensions: HeaderExtension.t()
}
@type type :: :ack_response | :nack_response | :nack_waiting
defstruct seq_number: nil, body: nil, types: [], raw?: false, header_extensions: []
@spec new(options :: keyword) :: t
def new(opts \\ []) do
struct(__MODULE__, opts)
end
@doc """
Return Z/IP binary for the heart beat packet
"""
@spec heart_beat() :: <<_::24>>
def heart_beat() do
<<0x23, 0x03, 0x80>>
end
@spec decode(binary) :: t()
def decode(<<0x23, 0x03, 0x40>>) do
%__MODULE__{types: [:ack_response], body: :heart_beat}
end
def decode(zip_packet_binary) do
_ = Logger.debug("[GATEWAY]: received - #{inspect(zip_packet_binary)}")
if raw?(zip_packet_binary) do
body = Decode.raw(zip_packet_binary)
%__MODULE__{raw?: true, body: body}
else
types = Decode.get_packet_types(zip_packet_binary)
body =
zip_packet_binary
|> Decode.get_body()
|> BodyParser.parse()
seq_number = Decode.get_sequence_number(zip_packet_binary)
header_extensions = Decode.get_header_extensions(zip_packet_binary)
packet = %__MODULE__{
types: types,
body: body,
seq_number: seq_number,
header_extensions: header_extensions
}
packet
end
end
@spec sleeping_delay?(t()) :: boolean()
def sleeping_delay?(%__MODULE__{header_extensions: header_ext}) do
# This function kinda a hack for right now, idealy we can add some meta
# data to packet about which node we are communicating with, so
# then make smarter handling of wake up nodes.
case HeaderExtension.get_expected_delay(header_ext) do
{:ok, seconds} when seconds > 1 -> true
{:ok, _} -> false
nil -> false
end
end
@spec put_expected_delay(t(), seconds :: non_neg_integer()) :: t()
def put_expected_delay(%__MODULE__{header_extensions: hext} = packet, seconds) do
# TODO: right now we don't do any checking on which header extensions
# are currently part of the header extensions.
expected_delay = HeaderExtension.expected_delay_from_seconds(seconds)
%{packet | header_extensions: [hext] ++ [expected_delay]}
end
@spec log(t) :: t | no_return
def log(packet) do
_ =
unless heart_beat_response(packet) do
_ = Logger.debug("Received Packet: #{inspect(packet)}")
end
packet
end
@spec header(seq_number :: non_neg_integer) :: binary
def header(seq_number) do
<<0x23, 0x02, 0x80, 0xD0, seq_number, 0x00, 0x00, 0x03, 0x02, 0x00>>
end
@spec raw?(binary() | Grizzly.Packet.t()) :: any()
def raw?(<<0x23, _rest::binary>>), do: false
def raw?(%__MODULE__{raw?: raw}), do: raw
def raw?(bin) when is_binary(bin), do: true
@spec heart_beat_response(t()) :: boolean()
def heart_beat_response(%__MODULE__{body: :heart_beat, types: [:ack_response]}) do
true
end
def heart_beat_response(%__MODULE__{}), do: false
@spec ack_request?(t()) :: boolean
def ack_request?(%__MODULE__{types: [:ack_request]}), do: true
def ack_request?(%__MODULE__{}), do: false
@spec as_ack_response(Grizzly.seq_number()) :: binary()
def as_ack_response(seq_number) do
<<0x23, 0x02, 0x40, 0x10, seq_number, 0x00, 0x00>>
end
end