Current section
Files
Jump to
Current section
Files
lib/bacnet/protocol/vmac_entry.ex
defmodule BACnet.Protocol.VmacEntry do
@moduledoc """
A BACnetVMACEntry maps a virtual MAC address (VMAC) to the native MAC
address used by the underlying data link.
It is used by the `Virtual_MAC_Address_Table` property of the Network Port
object (see Annex H.7 of ASHRAE 135). Virtual MAC addressing is required by
some network types (e.g. Zigbee, certain IPv6 configurations) so that the
BACnet network layer can use an uniform 6-octet (or smaller) address space
while the real data-link addresses remain larger or differently formatted.
### ASN.1 (ASHRAE 135)
BACnetVMACEntry ::= SEQUENCE {
virtual-mac-address [0] OCTET STRING, -- maximum size 6 octets
native-mac-address [1] OCTET STRING
}
"""
alias BACnet.Protocol.ApplicationTags
@typedoc """
A single Virtual MAC Address table entry.
"""
@type t :: %__MODULE__{
virtual_mac_address: binary(),
native_mac_address: binary()
}
@fields [:virtual_mac_address, :native_mac_address]
@enforce_keys @fields
defstruct @fields
@doc """
Encodes a BACnetVMACEntry into application tags encoding.
"""
@spec encode(t(), Keyword.t()) ::
{:ok, ApplicationTags.encoding_list()} | {:error, term()}
def encode(%__MODULE__{} = entry, _opts \\ []) do
with true <- byte_size(entry.virtual_mac_address) <= 6,
{:ok, vmac_tag} <-
ApplicationTags.create_tag_encoding(0, :octet_string, entry.virtual_mac_address),
{:ok, nmac_tag} <-
ApplicationTags.create_tag_encoding(1, :octet_string, entry.native_mac_address) do
{:ok, [vmac_tag, nmac_tag]}
else
false -> {:error, :virtual_mac_too_long}
{:error, _err} = err -> err
end
end
@doc """
Parses a BACnetVMACEntry 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
[
{:tagged, {0, vmac, _len1}},
{:tagged, {1, nmac, _len2}}
| rest
]
when is_binary(vmac) and is_binary(nmac) and byte_size(vmac) <= 6 ->
entry = %__MODULE__{
virtual_mac_address: vmac,
native_mac_address: nmac
}
{:ok, {entry, rest}}
_other ->
{:error, :invalid_tags}
end
end
@doc """
Validates whether the given VMAC entry is well-formed.
"""
@spec valid?(t()) :: boolean()
def valid?(%__MODULE__{
virtual_mac_address: vmac,
native_mac_address: nmac
})
when is_binary(vmac) and byte_size(vmac) <= 6 and is_binary(nmac) and byte_size(nmac) > 0 do
true
end
def valid?(%__MODULE__{}), do: false
end