ADS.Symbol (yaads v0.1.0)

Copy Markdown View Source

A PLC's description of one of its variables: its name, the name of its type, where it is, and how big.

A PLC has a table of its symbols when the project is built with symbols, as TwinCAT does by default. ADS.Client.symbol/3 asks for one by name (index group 0xF009), and ADS.Client.symbols/2 uploads all of them (0xF00B, its size from 0xF00F). Each is an entry of variable length:

BytesField
4the entry's length, padding included
4, 4index group and offset
4size in bytes
4ADS data type id (see ADS.Type.id_name/1)
4flags
2, 2, 2lengths of the name, the type and the comment
...the name, the type and the comment, each with a zero after it
16the type's GUID, if flagged (0x0008)
...attributes, if flagged (0x1000): a count of 2 bytes, then each with a byte for the length of its name and one for its value, and both with a zero after

Beckhoff's manuals don't describe this layout, only how to ask for it; it's written here from general knowledge of the format, not from another implementation's code, and is yet to be checked against a PLC.

Beckhoff recommends reaching a variable by a handle from its name, as ADS.Client does, rather than by its index group and offset, which change when the program does.

Summary

Functions

The symbol entry at the start of the bytes, as in the answer to a request by name; its strings in UTF-8 if they are, as plain ASCII is, or else in the code page (see ADS.Codepage).

Every symbol entry in the bytes, as uploaded; the strings as for decode/2.

The flags of a symbol by name, those that are known: :persistent, :read_only and so on.

Types

t()

@type t() :: %ADS.Symbol{
  attributes: %{required(String.t()) => String.t()},
  comment: String.t(),
  data_type: atom() | non_neg_integer(),
  flags: non_neg_integer(),
  guid: String.t() | nil,
  index_group: ADS.index_group(),
  index_offset: ADS.index_offset(),
  name: String.t(),
  size: non_neg_integer(),
  type: String.t()
}

Functions

decode(bytes, codepage \\ ADS.Codepage.default())

@spec decode(binary(), ADS.Codepage.t()) :: {:ok, t()} | :error

The symbol entry at the start of the bytes, as in the answer to a request by name; its strings in UTF-8 if they are, as plain ASCII is, or else in the code page (see ADS.Codepage).

decode_all(bytes, codepage \\ ADS.Codepage.default())

@spec decode_all(binary(), ADS.Codepage.t()) :: {:ok, [t()]} | :error

Every symbol entry in the bytes, as uploaded; the strings as for decode/2.

flags(symbol)

@spec flags(t()) :: [atom()]

The flags of a symbol by name, those that are known: :persistent, :read_only and so on.