defmodule ArtNet do @moduledoc """ Main API for encoding and decoding Art-Net packets. Use this module when working with complete Art-Net packets, including the `Art-Net\\0` identifier, OpCode, optional protocol version header, and packet payload. ```elixir {:ok, packet} = ArtNet.decode(binary) {:ok, binary} = ArtNet.encode(packet) ``` Packet structs are defined under `ArtNet.Packet`. Low-level field codecs live in `ArtNet.Decoder` and `ArtNet.Encoder`. This library provides encode/decode functionality only. It does not open sockets or transfer Art-Net packets over the network. """ alias ArtNet.{Packet, OpCode} @artnet_identifier ArtNet.Packet.identifier() @typedoc """ Any Art-Net packet struct generated by `ArtNet.Packet.Schema`. """ @type packet :: struct @doc """ Decodes a complete Art-Net binary into a packet struct. Returns `{:ok, packet}` on success or `{:error, %ArtNet.DecodeError{}}` when the identifier, OpCode, version header, payload, or packet validation fails. """ defdelegate decode(data), to: Packet @doc """ Decodes a complete Art-Net binary into a packet struct. Raises `ArtNet.DecodeError` when decoding fails. """ defdelegate decode!(data), to: Packet @doc """ Encodes an Art-Net packet struct into a complete Art-Net binary. Returns `{:ok, binary}` on success or `{:error, %ArtNet.EncodeError{}}` when the value is not a packet struct, packet validation fails, or any field cannot be encoded. """ defdelegate encode(packet), to: Packet @doc """ Encodes an Art-Net packet struct into a complete Art-Net binary. Raises `ArtNet.EncodeError` when encoding fails. """ defdelegate encode!(packet), to: Packet @doc """ Fetches the Art-Net packet opcode from a binary packet. The return value is `{:ok, op_code}` for a supported OpCode, such as `{:ok, :op_dmx}`, or `:error` if the binary does not start with the Art-Net identifier or the OpCode is not supported. ## Examples iex> ArtNet.fetch_op_code(<<0x41, 0x72, 0x74, 0x2D, 0x4E, 0x65, 0x74, 0x00, 0x00, 0x50, 0x00, 0x0E, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF>>) {:ok, :op_dmx} iex> ArtNet.fetch_op_code(<<0x41, 0x72, 0x74, 0x2D, 0x4E, 0x65, 0x74, 0x01, 0x00, 0x50, 0x00, 0x0E, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF>>) :error iex> ArtNet.fetch_op_code(<<0x41, 0x72, 0x74, 0x2D, 0x4E, 0x65, 0x74, 0x00, 0xFF, 0x7F, 0x00, 0x0E, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF>>) :error """ @spec fetch_op_code(binary) :: {:ok, OpCode.type()} | :error def fetch_op_code(<<@artnet_identifier, op_code::little-size(16), _rest::binary>>) do case OpCode.op_code_type(op_code) do nil -> :error op_code -> {:ok, op_code} end end def fetch_op_code(_) do :error end end