defmodule BACnet.Protocol.LimitEnable do @moduledoc """ BACnet Limit Enable is a two-bit bit string that controls which of the intrinsic or algorithmic limit-detection mechanisms are active for an object (primarily Analog Input/Value, Large Analog Value, etc.). | Bit | Name | When TRUE the corresponding limit algorithm runs | |-----|--------------------|:--------------------------------------------------------| | 0 | LOW_LIMIT_ENABLE | Low-limit (low-limit + deadband) detection is enabled | | 1 | HIGH_LIMIT_ENABLE | High-limit (high-limit + deadband) detection is enabled | The flags appear as the `limit_enable` property and directly affect whether `OUT_OF_RANGE` or `OUT_OF_RANGE` / `DOUBLE_OUT_OF_RANGE` events can be generated. ### BACnet Specification References - **ASN.1** (Clause 21): `BACnetLimitEnable ::= BIT STRING { low-limit-enable (0), high-limit-enable (1) }` - **Object types**: Used by Analog Input (12.2), Analog Value (12.4), Large Analog Value (12.39), and several other numeric objects that support intrinsic alarming. ### Examples (Doc Test) ```elixir iex> enable = %LimitEnable{low_limit_enable: true, high_limit_enable: true} iex> enable.low_limit_enable true ``` ### See Also - `BACnet.Protocol.Constants` - `BACnet.Protocol.EventParameters` """ alias BACnet.Protocol.ApplicationTags # TODO: Throw argument error in encode if not valid @typedoc """ Two Boolean flags controlling low- and high-limit detection (see module docs). """ @type t :: %__MODULE__{ low_limit_enable: boolean(), high_limit_enable: boolean() } @fields [ :low_limit_enable, :high_limit_enable ] @enforce_keys @fields defstruct @fields @doc """ Encodes a BACnet limit enable into application tags encoding. """ @spec encode(t(), Keyword.t()) :: {:ok, ApplicationTags.encoding_list()} | {:error, term()} def encode(%__MODULE__{} = flags, _opts \\ []) do {:ok, [to_bitstring(flags)]} end @doc """ Creates from an application tag bitstring a limit enable. """ @spec from_bitstring(tuple()) :: t() def from_bitstring(bitstring) when is_tuple(bitstring) and tuple_size(bitstring) == 2 do %__MODULE__{ low_limit_enable: elem(bitstring, 0), high_limit_enable: elem(bitstring, 1) } end @doc """ Parses a BACnet limit enable from application tags encoding. """ @spec parse(ApplicationTags.encoding_list()) :: {:ok, {t(), rest :: ApplicationTags.encoding_list()}} | {:error, term()} def parse(tags) when is_list(tags) do case tags do [{:bitstring, {_b1, _b2} = bs} | rest] -> {:ok, {from_bitstring(bs), rest}} _else -> {:error, :invalid_tags} end end @doc """ Creates an application tag bitstring from a limit enable. """ @spec to_bitstring(t()) :: BACnet.Protocol.ApplicationTags.primitive_encoding() def to_bitstring(%__MODULE__{} = t) do {:bitstring, {t.low_limit_enable, t.high_limit_enable}} end @doc """ Validates whether the given limit enable is in form valid. It only validates the struct is valid as per type specification. """ @spec valid?(t()) :: boolean() def valid?( %__MODULE__{ low_limit_enable: low_limit, high_limit_enable: high_limit } = _t ) when is_boolean(low_limit) and is_boolean(high_limit), do: true def valid?(%__MODULE__{} = _t), do: false end