Packages
grizzly
9.0.0
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/trace/record.ex
defmodule Grizzly.Trace.Record do
@moduledoc """
Data structure for a single item in the trace log
"""
alias Grizzly.Trace
alias Grizzly.ZWave
alias Grizzly.ZWave.Command
alias Grizzly.ZWave.Commands.ZIPPacket
require Logger
@type t() :: %__MODULE__{
timestamp: Time.t(),
binary: binary(),
src: Trace.src() | nil,
dest: Trace.dest() | nil
}
@type opt() :: {:src, Trace.src()} | {:dest, Trace.dest()} | {:timestamp, Time.t()}
defstruct src: nil, dest: nil, binary: nil, timestamp: nil
@doc """
Make a new `Grizzly.Record.t()` from a binary
"""
@spec new(Trace.src(), Trace.dest(), binary(), Time.t()) :: t()
def new(src, dest, binary, timestamp \\ Time.utc_now()) do
%__MODULE__{
src: src,
dest: dest,
binary: binary,
timestamp: timestamp
}
end
@doc """
Turn a record into the string format
"""
@spec to_string(t(), Trace.format()) :: String.t()
def to_string(record, format \\ :text)
def to_string(record, :text) do
%__MODULE__{timestamp: ts, src: src, dest: dest, binary: binary} = record
ts = Time.truncate(ts, :millisecond)
prefix = "#{Time.to_string(ts)} #{src_to_string(src)} -> #{dest_to_string(dest)}"
try do
case ZWave.from_binary(binary) do
{:ok, zip_packet} ->
"#{prefix} #{command_info_str(zip_packet, binary)}"
{:error, _} ->
"#{prefix} #{inspect(binary, limit: 500)}"
end
rescue
e ->
Logger.error(Exception.format(:error, e, __STACKTRACE__))
"#{prefix} DECODING ERROR #{inspect(binary, limit: 500)}"
end
end
def to_string(record, :raw) do
%__MODULE__{timestamp: ts, src: src, dest: dest, binary: binary} = record
time = ts |> Time.truncate(:millisecond) |> Time.to_string()
"#{time} #{src_to_string(src)} -> #{dest_to_string(dest)}: #{inspect(binary, limit: 500)}"
end
@doc """
Returns the remote node in the trace record, i.e., the node that is not :grizzly.
"""
def remote_node(%__MODULE__{src: :grizzly, dest: dest}), do: dest
def remote_node(%__MODULE__{src: src, dest: :grizzly}), do: src
defp src_to_string(:grizzly), do: src_to_string("G")
defp src_to_string(src), do: src |> Kernel.to_string() |> String.pad_leading(3)
defp dest_to_string(:grizzly), do: dest_to_string("G")
defp dest_to_string(dest), do: dest |> Kernel.to_string() |> String.pad_trailing(3)
defp command_info_str(%Command{name: :keep_alive} = cmd, _binary) do
case Command.param!(cmd, :ack_flag) do
:ack_request ->
" keep_alive (ack req)"
_ ->
" keep_alive (ack resp)"
end
end
defp command_info_str(zip_packet, binary) do
seq_number = Command.param!(zip_packet, :seq_number)
flag = Command.param!(zip_packet, :flag)
cond do
flag == :nack_waiting ->
expected_delay = ZIPPacket.extension(zip_packet, :expected_delay, nil)
command_info_empty_response(seq_number, flag) <>
" expected_delay=#{inspect(expected_delay)}"
flag in [:ack_response, :nack_response, :nack_waiting] ->
command_info_empty_response(seq_number, flag)
Command.param(zip_packet, :command) == nil ->
" no_operation"
true ->
command_info_with_encapsulated_command(seq_number, zip_packet, binary)
end
end
defp command_info_empty_response(seq_number, flag) do
"#{seq_number_to_str(seq_number)} #{flag}"
end
defp command_info_with_encapsulated_command(seq_number, zip_packet, binary) do
command = Command.param!(zip_packet, :command)
command_binary = ZIPPacket.unwrap(binary)
with :supervision_get <- command.name,
encap_bin = Command.param!(command, :encapsulated_command),
{:ok, inner_command} <-
Grizzly.ZWave.from_binary(encap_bin) do
"#{seq_number_to_str(seq_number)} supervision_get(#{inner_command.name}) #{inspect(encap_bin, limit: 500)}"
else
_ ->
"#{seq_number_to_str(seq_number)} #{command.name} #{inspect(command_binary, limit: 500)}"
end
rescue
err ->
Logger.error("""
[Grizzly.Trace] Expected an encapsulated command, but no command param was found.
Binary: #{inspect(binary, limit: 500)}
This is probably a bug -- please report it along with the stack trace and, if
possible, the corresponding line in the trace file.
#{Exception.format(:error, err, __STACKTRACE__)}
""")
command_name =
try do
zip_packet.name
rescue
_ -> "UNKNOWN COMMAND"
end
"#{seq_number_to_str(seq_number)} ENCODING ERROR #{command_name} #{inspect(binary, limit: 500)}"
end
defp seq_number_to_str(seq_number) do
String.pad_trailing(Kernel.to_string(seq_number), 4, " ")
end
end