Skip to content
/ abex Public

An Elixir wrapper of libplctag library for accessing Allen-Bradley PLC data over Ethernet.

License

Notifications You must be signed in to change notification settings

valiot/abex

Repository files navigation

abex Logo


Valiot Logo

ABex - Allen-Bradley PLC Communication Library

ABex is an Elixir library for communicating with Allen-Bradley PLCs using libplctag (v2.6.12). It provides both a high-level GenServer-based interface and a low-level raw interface for advanced use cases.

Features

  • 🔌 GenServer-based interface for stateful PLC connections
  • 🚀 Raw interface with direct access to all libplctag features
  • 📊 Multiple data types: integers (8/16/32/64-bit), floats (32/64-bit), strings, bits
  • 🏭 Wide PLC support: ControlLogix, CompactLogix, Micro800, PLC-5, SLC 500, MicroLogix
  • 📋 Tag listing with UDT (User Defined Type) introspection
  • Array operations and batch read/write
  • 🔍 Metadata reading for tag discovery
  • ⏱️ Configurable timeouts and debug levels

Installation

Add abex to your list of dependencies in mix.exs:

def deps do
  [
    {:abex, "~> 0.2.0"},
    # the current elixir-cmake (0.1.0) hex package is not compatible.
    {:elixir_cmake, github: "valiot/elixir-cmake", override: true}
  ]
end

Usage

ABex provides two interfaces: Abex.Tag (high-level GenServer) and Abex.Tag.Raw (low-level direct access).

High-Level Interface: Abex.Tag

The GenServer-based interface maintains a persistent connection to the PLC.

1. Start a Tag Process

{:ok, tag_pid} = Abex.Tag.start_link(
  ip: "192.168.1.10",
  cpu: "lgx",        # ControlLogix
  path: "1,0"        # PLC path
)

Options:

  • ip - PLC IP address (required)
  • path - Path to the device containing the named data (default: "1,0")
  • cpu - PLC type (default: "lgx")
    • Supported: lgx, clgx, controllogix, compactlogix, micro800, micrologix, mlgx, plc5, slc, slc500, flexlogix, flgx

2. List All Tags

{:ok, tags} = Abex.Tag.get_all_tags(tag_pid)

# Returns a map with controller tags and program tags
%{
  controller_tags: %{
    "MyTag" => %{
      tag_instance_id: "...",
      tag_type: "...",
      element_length: 4,
      array_dim: "..."
    }
  },
  program_tags: %{
    "MyProgram" => %{...}
  }
}

3. Read Tag Data

{:ok, [value]} = Abex.Tag.read(tag_pid,
  name: "MyTag",
  data_type: "uint32",
  elem_size: 4,
  elem_count: 1
)

# Read array
{:ok, values} = Abex.Tag.read(tag_pid,
  name: "MyArray",
  data_type: "real32",
  elem_size: 4,
  elem_count: 10
)

Read Options:

  • name - Tag name (required)
  • data_type - Data type: "uint8", "uint16", "uint32", "sint8", "sint16", "sint32", "real32", etc.
  • elem_size - Element size in bytes (required)
  • elem_count - Number of elements to read (required)

4. Write Tag Data

:ok = Abex.Tag.write(tag_pid,
  name: "MyTag",
  data_type: "uint32",
  elem_size: 4,
  elem_count: 1,
  value: "42"
)

Low-Level Interface: Abex.Tag.Raw

The raw interface provides access to all libplctag features without maintaining a GenServer connection.

Read Operations

# Simple read
{:ok, [value]} = Abex.Tag.Raw.read(
  type: :uint32,
  gateway: "192.168.1.10",
  path: "1,0",
  plc: :ControlLogix,
  name: "MyTag"
)

# Read with timeout and debug
{:ok, [temp]} = Abex.Tag.Raw.read(
  type: :real32,
  gateway: "192.168.1.10",
  path: "1,0",
  plc: :ControlLogix,
  name: "Temperature",
  timeout: 10000,
  debug: :info
)

# Read 64-bit integer
{:ok, [big_value]} = Abex.Tag.Raw.read(
  type: :uint64,
  gateway: "192.168.1.10",
  path: "1,0",
  plc: :ControlLogix,
  name: "BigCounter"
)

# Read string
{:ok, [text]} = Abex.Tag.Raw.read(
  type: :string,
  gateway: "192.168.1.10",
  path: "1,0",
  plc: :ControlLogix,
  name: "MessageText"
)

Write Operations

# Write single value
:ok = Abex.Tag.Raw.write(
  type: :uint32,
  gateway: "192.168.1.10",
  path: "1,0",
  plc: :ControlLogix,
  name: "MyTag",
  values: 42
)

# Write array
:ok = Abex.Tag.Raw.write(
  type: :real32,
  gateway: "192.168.1.10",
  path: "1,0",
  plc: :ControlLogix,
  name: "MyArray",
  values: [1.5, 2.5, 3.5, 4.5]
)

Metadata Reading

{:ok, metadata} = Abex.Tag.Raw.read_metadata(
  gateway: "192.168.1.10",
  path: "1,0",
  plc: :ControlLogix,
  name: "MyTag"
)

Raw Interface Options:

  • type - Data type atom: :uint8, :uint16, :uint32, :uint64, :sint8, :sint16, :sint32, :sint64, :real32, :real64, :string, :bit, :raw, :metadata
  • gateway - PLC IP address (required)
  • path - PLC path (required for most PLCs)
  • plc - PLC type atom: :ControlLogix, :CompactLogix, :Micro800, :PLC5, :SLC500, :MicroLogix, :FlexLogix
  • name - Tag name (required)
  • values - Value or list of values to write (for write operations)
  • elem_count - Number of elements for arrays (optional)
  • elem_size - Size of each element in bytes (optional)
  • timeout - Timeout in milliseconds (optional, default: 5000)
  • debug - Debug level: :none, :error, :warn, :info, :detail, :all (optional)

Debug Logging:

When debug is set to :info or higher, libplctag will output detailed diagnostic information including:

  • Connection attempts and status
  • Tag creation and lifecycle
  • Read/write operations
  • Network communication details
  • Threading and session information

This debug output is captured and included in error messages, making it visible on both development machines and embedded systems (Nerves). This is particularly useful for troubleshooting PLC connectivity issues.

Supported Data Types

Unsigned Integers

  • uint8 / :uint8 - 8-bit unsigned (0 to 255)
  • uint16 / :uint16 - 16-bit unsigned (0 to 65,535)
  • uint32 / :uint32 - 32-bit unsigned (0 to 4,294,967,295)
  • uint64 / :uint64 - 64-bit unsigned (0 to 18,446,744,073,709,551,615)

Signed Integers

  • sint8 / :sint8 - 8-bit signed (-128 to 127)
  • sint16 / :sint16 - 16-bit signed (-32,768 to 32,767)
  • sint32 / :sint32 - 32-bit signed (-2,147,483,648 to 2,147,483,647)
  • sint64 / :sint64 - 64-bit signed

Floating Point

  • real32 / :real32 - 32-bit float (IEEE 754 single precision)
  • real64 / :real64 - 64-bit float (IEEE 754 double precision)

Other Types

  • string / :string - PLC string type
  • bit / :bit - Single bit value
  • raw / :raw - Raw byte access
  • metadata / :metadata - Tag metadata (type, size, etc.)

Supported PLC Types

PLC Family Aliases
ControlLogix lgx, controllogix, contrologix
CompactLogix clgx, compactlogix
Micro800 micro800
PLC-5 plc, plc5
SLC 500 slc, slc500
MicroLogix micrologix, mlgx
FlexLogix flexlogix, flgx

Building from Source

ABex includes C bindings to libplctag, which are built automatically using CMake:

# Clone the repository
git clone https://github.com/valiot/abex.git
cd abex

# Update submodules
git submodule update --init --recursive

# Get dependencies and compile
mix deps.get
mix compile

The build process will:

  1. Build libplctag v2.6.12 from the submodule
  2. Compile custom C programs (rw_tag, tag_list)
  3. Include the tag_rw2 example from libplctag
  4. Generate Elixir BEAM files

Building for Nerves (Embedded Systems)

ABex fully supports Nerves for embedded Linux systems like Raspberry Pi. All executables are always linked statically with libplctag, ensuring consistent behavior across development and production environments without requiring shared libraries on the target system.

Verified Platforms

  • ✅ Raspberry Pi 3B+ (ARM Cortex-A53)
  • ✅ Raspberry Pi 4 (ARM Cortex-A72)
  • ✅ Raspberry Pi Zero W
  • ✅ BeagleBone Black

Troubleshooting Nerves

If you encounter "command not found" errors (exit code 127):

  1. Ensure you're using a recent version of ABex (>= 0.2.1)
  2. Verify the binaries are in priv/: ls /srv/erlang/lib/abex-*/priv/
  3. Check binary architecture matches target: file /srv/erlang/lib/abex-*/priv/rw_tag
  4. Try a clean rebuild: mix deps.clean abex --build && mix compile

For detailed debugging steps and platform-specific notes, see NERVES_DEBUG.md.

Documentation

Documentation can be generated with ExDoc:

mix docs

Once published, the docs can be found at https://hexdocs.pm/abex.

License

Copyright (c) Valiot

Credits

ABex uses libplctag, an open-source library for communicating with PLCs.

Special thanks to the libplctag team for their excellent work.

About

An Elixir wrapper of libplctag library for accessing Allen-Bradley PLC data over Ethernet.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •