defmodule Grizzly.ZWave.DeviceClasses do @moduledoc """ Z-Wave device classes """ defmodule Generate do @moduledoc false import Grizzly.ZWave.GeneratedMappings, only: [ basic_device_class_mappings: 0, generic_device_class_mappings: 0, specific_device_class_mappings: 0 ] defmacro __before_compile__(_) do basic_mappings = basic_device_class_mappings() generic_mappings = generic_device_class_mappings() specific_mappings = specific_device_class_mappings() basic_device_class_from_byte = for {byte, device_class} <- basic_mappings do quote do def basic_device_class_from_byte(unquote(byte)), do: {:ok, unquote(device_class)} end end basic_device_class_to_byte = for {byte, device_class} <- basic_mappings do quote do def basic_device_class_to_byte(unquote(device_class)), do: unquote(byte) end end generic_device_class_from_byte = for {byte, device_class} <- generic_mappings do quote do def generic_device_class_from_byte(unquote(byte)), do: {:ok, unquote(device_class)} end end generic_device_class_to_byte = for {byte, device_class} <- generic_mappings do quote do def generic_device_class_to_byte(unquote(device_class)), do: unquote(byte) end end specific_device_class_from_byte = for {gen_class, byte, spec_class} <- specific_mappings do quote do def specific_device_class_from_byte(unquote(gen_class), unquote(byte)), do: {:ok, unquote(spec_class)} end end specific_device_class_to_byte = for {gen_class, byte, spec_class} <- specific_mappings do quote do def specific_device_class_to_byte(unquote(gen_class), unquote(spec_class)), do: unquote(byte) end end basic_classes_union = basic_mappings |> Enum.map(&elem(&1, 1)) |> Enum.reverse() |> Enum.reduce(&{:|, [], [&1, &2]}) generic_classes_union = generic_mappings |> Enum.map(&elem(&1, 1)) |> Enum.reverse() |> Enum.reduce(&{:|, [], [&1, &2]}) specific_classes_union = specific_mappings |> Enum.map(&elem(&1, 2)) |> Enum.reverse() |> Enum.uniq() |> Enum.reduce(&{:|, [], [&1, &2]}) quote do @type basic_device_class :: unquote(basic_classes_union) @type generic_device_class :: unquote(generic_classes_union) @type specific_device_class :: unquote(specific_classes_union) @doc """ Try to make a basic device class from a byte """ @spec basic_device_class_from_byte(byte()) :: {:ok, basic_device_class()} | {:ok, :unknown} unquote(basic_device_class_from_byte) def basic_device_class_from_byte(_byte), do: {:ok, :unknown} @doc """ Make a byte from a device class """ @spec basic_device_class_to_byte(basic_device_class()) :: byte() unquote(basic_device_class_to_byte) @doc """ Try to get the generic device class for the byte """ @spec generic_device_class_from_byte(byte()) :: {:ok, generic_device_class()} | {:ok, :unknown} unquote(generic_device_class_from_byte) def generic_device_class_from_byte(_byte), do: {:ok, :unknown} @doc """ Turn the generic device class into a byte """ @spec generic_device_class_to_byte(generic_device_class()) :: byte() unquote(generic_device_class_to_byte) @doc """ Try to get the specific device class from the byte given the generic device class """ @spec specific_device_class_from_byte(generic_device_class(), byte()) :: {:ok, specific_device_class()} | {:ok, :unknown} unquote(specific_device_class_from_byte) def specific_device_class_from_byte(_, _byte), do: {:ok, :unknown} @doc """ Make the specific device class into a byte """ @spec specific_device_class_to_byte(generic_device_class(), specific_device_class()) :: byte() unquote(specific_device_class_to_byte) end end end @before_compile Generate end