# ๐ฆ Rust EtherNet/IP Driver
[](https://www.rust-lang.org)
[](https://github.com/sergiogallegos/rust-ethernet-ip/releases)
[](LICENSE)
[]()
[]()
[]()
[](https://crates.io/crates/rust-ethernet-ip)
[](https://docs.rs/rust-ethernet-ip)
[](https://crates.io/crates/rust-ethernet-ip)
[](https://github.com/sponsors/sergiogallegos)
A high-performance, production-ready EtherNet/IP communication library specifically designed for **Allen-Bradley CompactLogix and ControlLogix PLCs**. Built in pure Rust with focus on **PC applications**, offering exceptional performance, memory safety, and comprehensive industrial features.
**๐ฆ Available on [crates.io](https://crates.io/crates/rust-ethernet-ip)**
## ๐ฏ **Current Development Focus**
**We are focused on the .NET stack (C# wrappers and examples) for production-quality industrial automation applications.**
- ๐ฏ **Active Development**:
- C# wrapper library (`RustEtherNetIp.dll`)
- WinForms example application
- WPF example application
- ASP.NET example application
- Advanced features: TagGroup, Statistics, Batch Operations, STRING support, UDT arrays
- Rust native examples and library improvements
This focused approach ensures we deliver a robust, well-tested, production-ready .NET integration for industrial automation systems.
## ๐ฏ **Project Focus**
This library is specifically designed for:
- **Allen-Bradley CompactLogix** (L1x, L2x, L3x, L4x, L5x series)
- **Allen-Bradley ControlLogix** (L6x, L7x, L8x series)
- **PC Applications** (Windows, Linux, macOS)
- **Industrial Automation** software and SCADA systems
- **High-performance** data acquisition and control
### โ
**v0.6.2 New Features**
- **๐ Stream Injection API**: New `connect_with_stream()` for custom TCP transport
- Wrap streams for metrics/observability (bytes in/out)
- Apply custom socket options (keepalive, timeouts, bind local address)
- Reuse pre-established tunnels/connections
- Use in-memory streams for deterministic testing
- **๐งช Test Configuration**: Environment variable support for PLC testing
- `TEST_PLC_ADDRESS` - Set PLC IP address for tests
- `TEST_PLC_SLOT` - Set CPU slot number
- `SKIP_PLC_TESTS` - Skip PLC-dependent tests
- **๐ Fixed Nested UDT Access**: Fixed reading nested UDT members from array elements
- Correctly handles `Cell_NestData[90].PartData.Member` paths
- Now returns specific member values instead of entire UDT
### โ
**v0.6.1 Features**
- **๐งน Repository Cleanup**: Removed Go and Python wrappers to focus on Rust library and C# integration
- **๐ฆ Streamlined Examples**: Focused on Microsoft stack (WinForms, WPF, ASP.NET) and Rust native examples
- **๐ง Improved Documentation**: Updated all documentation to reflect current focus
### โ
**v0.6.0 Features**
- **๐ง Generic UDT Format**: New `UdtData` struct with `symbol_id` and raw bytes
- Works with any UDT without requiring prior knowledge of member structure
- Supports reading and writing UDTs generically
- Enables parsing UDT members using UDT definitions when needed
- **๐ Array Element Access**: Full read/write support for array elements using intelligent workaround
- Controller-scoped arrays: `gArrayTest[0]`, `gArrayTest[1]`, etc.
- Program-scoped arrays: `Program:MainProgram.ArrayTest[0]`
- BOOL array support: Automatic DWORD bit extraction for BOOL arrays
- Automatic detection and workaround for array element access
- **โ๏ธ Array Element Writing**: Write individual array elements with automatic array modification
- Reads entire array, modifies element, writes back seamlessly
- Supports all data types (DINT, REAL, BOOL, etc.)
- Works with both controller-scoped and program-scoped arrays
- **โ
Library Health**: All 31 unit tests passing, production-ready core library
### โ
**v0.5.4 Features**
- **๐ UDT Definition Discovery**: Automatic UDT structure detection from PLC
- **๐ท๏ธ Enhanced Tag Discovery**: Full attribute support with permissions and scope
- **๐ฆ Packet Size Negotiation**: Dynamic optimization for firmware 20+
- **๐ฃ๏ธ Route Path Support**: Slot configuration and multi-hop routing
- **๐พ Cache Management**: Smart caching for UDT definitions and tag attributes
- **๐ง CIP Services**: Full implementation of Services 0x03 and 0x4C
- **๐ฏ Program Tag Support**: Fixed program-scoped tag access with correct CIP path format
- **๐ง Enhanced UDT Parsing**: Intelligent multi-member UDT parsing with byte alignment detection
- **โก Advanced Chunked Reading**: Multiple strategies for large UDTs with intelligent error recovery
- **๐ฏ .NET Stack Focus**: Comprehensive C# wrapper with WinForms, WPF, and ASP.NET examples
> **๐ Major Milestone Achieved!**
> v0.6.0 introduces a new generic UDT format (`UdtData`) that works with any UDT without requiring prior knowledge of member structure. The library core is production-ready with all 31 unit tests passing.
## โจ **Key Features**
### ๐ **UDT Discovery & Management (v0.5.4)**
- **Automatic UDT Structure Detection**: No more manual offset/size/type specifications
- **CIP Service 0x03**: Get Attribute List for comprehensive tag metadata
- **CIP Service 0x4C**: Read Tag Fragmented for large data structures
- **Smart Caching**: UDT definitions and tag attributes cached for performance
- **Template Management**: Full UDT template parsing and member discovery
- **Program-Scoped Discovery**: Find tags within specific program scopes
### ๐ฃ๏ธ **Route Path Support (v0.5.4, Enhanced in v0.6.0)**
- **Slot Configuration**: Support for slots 0-31 (โ
Fully implemented and tested)
- **Backplane Routing**: Direct communication with CPUs in different slots (โ
Fully implemented)
- **Network Routing**: Multi-hop routing through network addresses and ports (โ
Implemented)
- **CIP Path Building**: Automatic CIP route path byte generation (โ
Implemented)
- **ControlLogix Support**: Tested with ControlLogix systems with CPUs in different slots
- **Remote Rack Connections**: Basic support exists, needs additional testing
- **Dynamic Path Building**: Automatic CIP route path generation from slots, ports, and addresses
### ๐ฆ **Packet Size Optimization (v0.5.4)**
- **Dynamic Negotiation**: Automatically negotiates optimal packet size with PLC
- **Firmware 20+ Support**: Enhanced performance for modern PLCs
- **Adaptive Sizing**: Adjusts packet size based on PLC capabilities
- **Performance Boost**: 20-30% improvement for large data transfers
### ๐ง **Enhanced UDT Processing** โ
**NEW in v0.5.4**
- **Intelligent Multi-Member Parsing**: Automatically detects and parses multiple UDT members (DINT, DINT, REAL)
- **Byte Alignment Detection**: Smart alignment detection with reasonableness checks
- **Advanced Chunked Reading**: Multiple strategies for large UDTs with intelligent error recovery
- **Cross-Language Support**: All improvements work seamlessly across Rust and C# wrappers
- **Performance Optimized**: Sub-5ms response times for complex UDT operations
### ๐ง **Connection Robustness**
- **Automatic session management** with proper registration/unregistration
- **Connection health monitoring** with configurable timeouts
- **Network resilience** handling for industrial environments
- **Comprehensive error handling** with detailed CIP error mapping
### โ ๏ธ **Known Limitations**
The following operations are **not supported** due to PLC firmware restrictions. These limitations are inherent to the Allen-Bradley PLC firmware and cannot be bypassed at the library level.
#### STRING Tag Writing
**Cannot write directly to STRING tags** (e.g., `gTest_STRING`, `Program:TestProgram.gTest_STRING`).
**Root Cause:** PLC firmware limitation (CIP Error 0x2107). The PLC rejects direct write operations to STRING tags, regardless of the communication method used.
**What Works:**
- โ
Reading STRING tags: `gTest_STRING` (read successfully)
- โ
Reading STRING members in UDTs: `gTestUDT.Member5_String` (read successfully)
**What Doesn't Work:**
- โ Writing simple STRING tags: `gTest_STRING` (write fails - PLC limitation)
- โ Writing program-scoped STRING tags: `Program:TestProgram.gTest_STRING` (write fails - PLC limitation)
- โ Writing STRING members in UDTs directly: `gTestUDT.Member5_String` (write fails - must write entire UDT)
**Workaround for STRING Members in UDTs:**
If the STRING is part of a UDT structure, you can write it by reading the entire UDT, modifying the STRING member in memory, then writing the entire UDT back:
```rust
// Read entire UDT
let mut udt = client.read_tag("gTestUDT").await?;
// Modify STRING member in memory (if UDT structure is known)
// ... modify UDT structure ...
// Write entire UDT back
client.write_tag("gTestUDT", udt).await?;
```
**Note:** For standalone STRING tags (not part of a UDT), there is no workaround at the communication library level. Alternative approaches may include using PLC ladder logic or other PLC-side mechanisms to update STRING values.
#### UDT Array Element Member Writing
**Cannot write directly to members of UDT array elements** (e.g., `gTestUDT_Array[0].Member1_DINT`).
**Root Cause:** PLC firmware limitation (CIP Error 0x2107). The PLC does not support direct write operations to individual members within UDT array elements.
**What Works:**
- โ
Reading UDT array element members: `gTestUDT_Array[0].Member1_DINT` (read successfully)
- โ
Writing entire UDT array elements: `gTestUDT_Array[0]` (write full UDT structure)
- โ
Writing UDT members (non-array): `gTestUDT.Member1_DINT` (write individual members of non-array UDTs)
- โ
Writing simple array elements: `gArray[5]` (write elements of simple arrays like DINT[], REAL[], etc.)
**What Doesn't Work:**
- โ Writing UDT array element members: `gTestUDT_Array[0].Member1_DINT` (write fails - PLC limitation)
- โ Writing program-scoped UDT array element members: `Program:TestProgram.gTestUDT_Array[0].Member1_DINT` (write fails - PLC limitation)
**Workaround:**
Use a read-modify-write pattern:
```rust
// Read entire UDT array element
let mut element = client.read_tag("gTestUDT_Array[0]").await?;
// Modify member in memory (if UDT structure is known)
// ... modify UDT structure ...
// Write entire UDT array element back
client.write_tag("gTestUDT_Array[0]", element).await?;
```
#### Summary of Limitations
**Test Results (392 tags tested):**
- โ
**333/392 tags** (84.9%) successfully read and written
- โ **59/392 tags** failed due to PLC firmware limitations:
- 55 tags: UDT array element member writes (e.g., `gTestUDT_Array[0].Member1_DINT`)
- 2 tags: Simple STRING tag writes (e.g., `gTest_STRING`)
- 2 tags: STRING member writes in UDTs (e.g., `gTestUDT.Member5_String`)
**Important Notes:**
- These limitations are **PLC firmware restrictions**, not library bugs
- The library correctly implements the EtherNet/IP and CIP protocols
- All read operations work correctly for all tag types
- Workarounds are available for UDT array element members and STRING members in UDTs
- Standalone STRING tag writes have no workaround at the communication library level
**๐ For detailed technical information about these limitations, including official Rockwell documentation references and technical background, see [AB_String_UDT_Write_Limitations.md](docs/AB_String_UDT_Write_Limitations.md).**
### ๐ **Advanced Tag Addressing** โ
**COMPLETED**
- **Program-scoped tags**: `Program:MainProgram.Tag1` โ
**FIXED in v0.5.4**
- **Array element access**: `MyArray[5]`, `MyArray[1,2,3]` โ
**WORKING in v0.5.5**
- Automatic workaround: Reads entire array and extracts element
- Supports read and write operations
- Works with controller-scoped and program-scoped arrays
- Special handling for BOOL arrays (DWORD bit extraction)
- **Bit-level operations**: `MyDINT.15` (access individual bits)
- **UDT member access**: `MyUDT.Member1.SubMember`
- **String operations**: `MyString.LEN`, `MyString.DATA[5]`
- **Complex nested paths**: `Program:Production.Lines[2].Stations[5].Motor.Status.15`
### ๐ **Complete Data Type Support** โ
**COMPLETED**
All Allen-Bradley native data types with proper CIP encoding:
- **BOOL** - Boolean values (CIP type 0x00C1)
- **SINT** - 8-bit signed integer (-128 to 127, CIP type 0x00C2)
- **INT** - 16-bit signed integer (-32,768 to 32,767, CIP type 0x00C3)
- **DINT** - 32-bit signed integer (-2.1B to 2.1B, CIP type 0x00C4)
- **LINT** - 64-bit signed integer (CIP type 0x00C5)
- **USINT** - 8-bit unsigned integer (0 to 255, CIP type 0x00C6)
- **UINT** - 16-bit unsigned integer (0 to 65,535, CIP type 0x00C7)
- **UDINT** - 32-bit unsigned integer (0 to 4.3B, CIP type 0x00C8)
- **ULINT** - 64-bit unsigned integer (CIP type 0x00C9)
- **REAL** - 32-bit IEEE 754 float (CIP type 0x00CA)
- **LREAL** - 64-bit IEEE 754 double (CIP type 0x00CB)
- **STRING** - Variable-length strings (CIP type 0x00DA)
- **UDT** - User Defined Types with full nesting support (CIP type 0x00A0)
### ๐ **Language Bindings**
#### **C# Integration** ๐ฏ **CURRENT FOCUS - Active Development**
- **Complete C# wrapper** with all data types
- **22 FFI functions** for seamless integration
- **Type-safe API** with comprehensive error handling
- **Cross-platform support** (Windows, Linux, macOS)
- **Production-ready examples**: WinForms, WPF, ASP.NET
- **Advanced features**: TagGroup, Statistics, Batch Operations, STRING support
- **Status**: Actively being polished to production quality
### โ ๏ธ **Comprehensive Error Handling** โ
**COMPLETED**
- **Detailed CIP error mapping** with 40+ error codes
- **Network-level diagnostics** and troubleshooting
- **Granular error types** for precise error handling
- **Automatic error recovery** for transient issues
### ๐๏ธ **Build System** โ
**COMPLETED**
- **Automated build scripts** for Windows and Linux/macOS
- **Cross-platform compilation** with proper library generation
- **Comprehensive testing** with 30+ unit tests
- **CI/CD ready** with GitHub Actions examples
### โก **Real-Time Subscriptions** โ
**NEW in v0.4.0**
- **Real-time tag monitoring** with configurable update intervals (1ms - 10s)
- **Event-driven notifications** for tag value changes
- **Multi-tag subscriptions** supporting hundreds of concurrent monitors
- **Automatic reconnection** and error recovery
- **Memory-efficient engine** with minimal CPU overhead
### ๐ **High-Performance Batch Operations** โ
**NEW in v0.4.0**
- **Batch read operations** - read up to 100+ tags in a single request
- **Batch write operations** - write multiple tags atomically
- **Parallel processing** with concurrent execution
- **Transaction support** with rollback capabilities
- **2,000+ ops/sec throughput** with intelligent packet packing
## ๐ญ **HMI/SCADA Production Demo**
Experience a **professional-grade HMI dashboard** showcasing real-world industrial data tracking and monitoring capabilities. This demo demonstrates the library's potential for building production-ready SCADA systems and industrial dashboards.

### ๐ฏ **Demo Features**
- **๐ Real-time Production Monitoring** - Live production counts, targets, and progress tracking
- **๐ OEE Analysis** - Overall Equipment Effectiveness with availability, performance, and quality metrics
- **๐ก๏ธ Process Parameters** - Temperature, pressure, vibration monitoring with color-coded alerts
- **โ๏ธ Machine Status** - Real-time machine state, shift information, and operator tracking
- **๐ง Maintenance Management** - Scheduled maintenance tracking and history
- **๐ฑ Responsive Design** - Works seamlessly on desktop, tablet, and mobile devices
### ๐ **Perfect for Demonstrations**
This demo showcases:
- **High-frequency data collection** (1-second intervals)
- **Professional HMI aesthetics** with industrial-grade visualizations
- **Real-world metrics** that matter to production managers
- **Scalable architecture** for larger SCADA systems
- **Modern web technologies** for cross-platform deployment
### ๐ท๏ธ **Required PLC Tags**
The demo reads 13 industrial tags including machine status, production metrics, process parameters, and OEE data. See the ASP.NET example for complete tag specifications and setup instructions.
## ๐ **Performance Characteristics**
Optimized for PC applications with excellent performance:
> **๐ Latest Performance Improvements (v0.6.2)**
>
> Recent optimizations and improvements:
> - **Generic UDT Format**: New `UdtData` struct enables universal UDT handling
> - **Memory allocation improvements**: 20-30% reduction in allocation overhead for network operations
> - **Batch operations**: 3-10x faster than individual operations
> - **Code quality**: Enhanced with idiomatic Rust patterns and clippy optimizations
> - **Network efficiency**: Optimized packet building with pre-allocated buffers
> - **Library Health**: All 31 unit tests passing, production-ready core
| Single Tag Read | 3,000+ ops/sec | <1ms | ~800B |
| Single Tag Write | 1,500+ ops/sec | <2ms | ~800B |
| Batch Operations | 2,000+ ops/sec | 5-20ms | ~2KB |
| Real-time Subscriptions | 1,000+ tags/sec | 1-10ms | ~1KB |
| Tag Path Parsing | 10,000+ ops/sec | <0.1ms | ~1KB |
| Connection Setup | N/A | 50-200ms | ~4KB |
| Memory per Connection | N/A | N/A | ~4KB base |
## ๐ **Development Roadmap**
### ๐ฅ **Phase 1: Core Enhancements** โ
**COMPLETED - January 2026**
- [x] Basic tag read/write operations
- [x] Connection management and session handling
- [x] **Enhanced tag path parsing** (Program-scoped, arrays, bit access)
- [x] **Complete data type support** (All Allen-Bradley types)
- [x] **C# wrapper integration** (22 FFI functions)
- [x] **Comprehensive testing** (30+ unit tests)
- [x] **Build automation** (Cross-platform build scripts)
- [x] **Documentation** (Examples, API docs, guides)
### โก **Phase 2: Advanced Features** โ
**COMPLETED - January 2026**
- [x] **Batch operations** (multi-tag read/write) โ
**COMPLETED**
- [x] **Real-time subscriptions** (tag change notifications) โ
**COMPLETED**
- [x] **Performance optimizations** (20% faster operations + memory improvements) โ
**COMPLETED**
- [x] **Enhanced error handling & recovery** โ
**COMPLETED**
### ๐ฏ **Phase 3: Production Ready** โ
**COMPLETED - January 2026**
- [x] **Production monitoring** - Comprehensive metrics and health checks
- [x] **Configuration management** - Production-ready config system
- [x] **Error handling** - Detailed CIP error mapping and recovery
- [x] **Performance optimization** - Batch operations and connection pooling
- [x] **Generic UDT Format** - Universal UDT handling with `UdtData` struct (v0.6.0)
- [x] **Library Testing** - All 31 unit tests passing
- [x] **Code Quality** - Comprehensive examples and tests updated for new API
- [x] **Community features** - Discord server, GitHub discussions, sponsorship program
### ๐ **Phase 4: Industrial Routing Support** โ
**PARTIALLY IMPLEMENTED**
- [x] **Basic slot configuration** - Support for CPUs in slots 0-31 (โ
Implemented in v0.6.0)
- [x] **Simple backplane routing** - Direct backplane communication (โ
Implemented in v0.6.0)
- [x] **Route path building** - CIP route path construction (โ
Implemented in v0.6.0)
- [x] **Network routing** - Multi-hop network routing via addresses and ports (โ
Implemented in v0.6.0)
- [x] **Path validation** - Route path verification and CIP byte construction (โ
Implemented in v0.6.0)
- [ ] **Remote rack support** - Connect to remote racks via network (โ ๏ธ Basic support exists, needs testing)
- [ ] **Advanced routing** - Complex network topologies (โ ๏ธ Basic support exists, needs validation)
- [ ] **Route discovery** - Automatic path detection (โ Not implemented)
**Note:** ControlLogix systems with CPUs in different slots can be tested using the `RoutePath` API.
Use `EipClient::with_route_path()` or `set_route_path()` with `RoutePath::new().add_slot(slot_number)`
to connect to ControlLogix CPUs in slots 0-31.
## ๐ ๏ธ **Installation**
### ๐ฆ **Rust Library (Crates.io)**
The easiest way to get started is by adding the crate to your `Cargo.toml`:
```toml
[dependencies]
```toml
[dependencies]
rust-ethernet-ip = "0.6.2"
tokio = { version = "1.0", features = ["full"] }
```
### C# Wrapper
Install via NuGet:
```xml
<PackageReference Include="RustEtherNetIp" Version="0.6.2" />
```
Or via Package Manager Console:
```powershell
Install-Package RustEtherNetIp
```
## ๐ **Quick Start**
### UDT Discovery (v0.5.4)
```rust
use rust_ethernet_ip::{EipClient, RoutePath};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Connect to PLC
let mut client = EipClient::connect("192.168.0.1:44818").await?;
// Discover UDT structure automatically
let definition = client.get_udt_definition("Part_Data").await?;
println!("UDT: {}", definition.name);
for member in &definition.members {
println!(" {}: {} (offset: {}, size: {} bytes)",
member.name,
get_data_type_name(member.data_type),
member.offset,
member.size
);
}
// Read UDT data using discovered structure
let udt_data = client.read_udt_chunked("Part_Data").await?;
// Read individual members using discovered offsets
for member in &definition.members {
let value = client.read_udt_member_by_offset(
"Part_Data",
member.offset as usize,
member.size as usize,
member.data_type
).await?;
println!("{}: {:?}", member.name, value);
}
Ok(())
}
```
### Route Path Support (v0.5.4)
```rust
// Create route path for slot 2
let route = RoutePath::new()
.add_slot(0) // Backplane slot 0
.add_slot(2); // Target slot 2
// Connect with route path
let mut client = EipClient::with_route_path("192.168.0.1:44818", route).await?;
// Read tags through the route
let value = client.read_tag("TestTag").await?;
```
### Stream Injection (v0.6.2) - Custom TCP Transport
```rust
use rust_ethernet_ip::EipClient;
use std::net::SocketAddr;
use tokio::net::TcpStream;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create a custom stream with socket options
let addr: SocketAddr = "192.168.1.100:44818".parse()?;
let stream = TcpStream::connect(addr).await?;
stream.set_nodelay(true)?;
stream.set_keepalive(true)?;
// Connect using the custom stream
let route = RoutePath::new().add_slot(0);
let mut client = EipClient::connect_with_stream(stream, Some(route)).await?;
// Use client normally
let value = client.read_tag("TestTag").await?;
Ok(())
}
```
**Benefits:**
- Wrap streams for metrics/observability (bytes in/out)
- Apply custom socket options (keepalive, timeouts, bind local address)
- Reuse pre-established tunnels/connections
- Use in-memory streams for deterministic testing
### Basic Usage
```rust
use rust_ethernet_ip::{EipClient, PlcValue};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Connect to CompactLogix PLC
let mut client = EipClient::connect("192.168.1.100:44818").await?;
// Read different data types
let motor_running = client.read_tag("Program:Main.MotorRunning").await?;
let production_count = client.read_tag("Program:Main.ProductionCount").await?;
let temperature = client.read_tag("Program:Main.Temperature").await?;
// Write values
client.write_tag("Program:Main.SetPoint", PlcValue::Dint(1500)).await?;
client.write_tag("Program:Main.StartButton", PlcValue::Bool(true)).await?;
println!("Motor running: {:?}", motor_running);
println!("Production count: {:?}", production_count);
println!("Temperature: {:?}", temperature);
Ok(())
}
```
### C# Usage
```csharp
using RustEtherNetIp;
using var client = new EtherNetIpClient();
if (client.Connect("192.168.1.100:44818"))
{
// Read different data types
bool motorRunning = client.ReadBool("Program:Main.MotorRunning");
int productionCount = client.ReadDint("Program:Main.ProductionCount");
float temperature = client.ReadReal("Program:Main.Temperature");
// Write values
client.WriteDint("Program:Main.SetPoint", 1500);
client.WriteBool("Program:Main.StartButton", true);
Console.WriteLine($"Motor running: {motorRunning}");
Console.WriteLine($"Production count: {productionCount}");
Console.WriteLine($"Temperature: {temperature:F1}ยฐC");
}
```
### Advanced Tag Addressing
```rust
// Program-scoped tags
let value = client.read_tag("Program:MainProgram.Tag1").await?;
// Array elements (v0.5.5 - automatic workaround)
let array_element = client.read_tag("Program:Main.MyArray[5]").await?;
// Writing array elements
client.write_tag("gArrayTest[0]", PlcValue::Dint(100)).await?;
// BOOL arrays work too
let bool_value = client.read_tag("gArrayBoolTest[5]").await?;
client.write_tag("gArrayBoolTest[5]", PlcValue::Bool(true)).await?;
let multi_dim = client.read_tag("Program:Main.Matrix[1,2,3]").await?;
// Bit access
let bit_value = client.read_tag("Program:Main.StatusWord.15").await?;
// UDT members
let udt_member = client.read_tag("Program:Main.MotorData.Speed").await?;
let nested_udt = client.read_tag("Program:Main.Recipe.Step1.Temperature").await?;
// String operations
let string_length = client.read_tag("Program:Main.ProductName.LEN").await?;
let string_char = client.read_tag("Program:Main.ProductName.DATA[0]").await?;
```
### Complete Data Type Examples
```rust
// All supported data types
let bool_val = client.read_tag("BoolTag").await?; // BOOL
let sint_val = client.read_tag("SintTag").await?; // SINT (-128 to 127)
let int_val = client.read_tag("IntTag").await?; // INT (-32,768 to 32,767)
let dint_val = client.read_tag("DintTag").await?; // DINT (-2.1B to 2.1B)
let lint_val = client.read_tag("LintTag").await?; // LINT (64-bit signed)
let usint_val = client.read_tag("UsintTag").await?; // USINT (0 to 255)
let uint_val = client.read_tag("UintTag").await?; // UINT (0 to 65,535)
let udint_val = client.read_tag("UdintTag").await?; // UDINT (0 to 4.3B)
let ulint_val = client.read_tag("UlintTag").await?; // ULINT (64-bit unsigned)
let real_val = client.read_tag("RealTag").await?; // REAL (32-bit float)
let lreal_val = client.read_tag("LrealTag").await?; // LREAL (64-bit double)
let string_val = client.read_tag("StringTag").await?; // STRING
let udt_val = client.read_tag("UdtTag").await?; // UDT
```
## โก **Batch Operations** โ
**COMPLETED**
**Dramatically improve performance** with batch operations that execute multiple read/write operations in a single network packet. Perfect for data acquisition, recipe management, and coordinated control scenarios.
### ๐ **Performance Benefits**
- **3-10x faster** than individual operations
- **Reduced network traffic** (1-5 packets instead of N packets for N operations)
- **Lower PLC CPU usage** due to fewer connection handling overheads
- **Better throughput** for data collection and control applications
### ๐ **Use Cases**
- **Data acquisition**: Reading multiple sensor values simultaneously
- **Recipe management**: Writing multiple setpoints at once
- **Status monitoring**: Reading multiple status flags efficiently
- **Coordinated control**: Atomic operations across multiple tags
### ๐ง **Basic Batch Reading**
```rust
use rust_ethernet_ip::{EipClient, BatchOperation, PlcValue};
// Read multiple tags in a single operation
let tags_to_read = vec![
"ProductionCount",
"Temperature_1",
"Temperature_2",
"Pressure_1",
"FlowRate",
];
let results = client.read_tags_batch(&tags_to_read).await?;
for (tag_name, result) in results {
match result {
Ok(value) => println!("๐ {}: {:?}", tag_name, value),
Err(error) => println!("โ {}: {}", tag_name, error),
}
}
```
### โ๏ธ **Basic Batch Writing**
```rust
// Write multiple tags in a single operation
let tags_to_write = vec![
("SetPoint_1", PlcValue::Real(75.5)),
("SetPoint_2", PlcValue::Real(80.0)),
("EnableFlag", PlcValue::Bool(true)),
("ProductionMode", PlcValue::Dint(2)),
("RecipeNumber", PlcValue::Dint(42)),
];
let results = client.write_tags_batch(&tags_to_write).await?;
for (tag_name, result) in results {
match result {
Ok(()) => println!("โ
{}: Write successful", tag_name),
Err(error) => println!("โ {}: {}", tag_name, error),
}
}
```
### ๐ **Mixed Operations (Reads + Writes)**
```rust
use rust_ethernet_ip::BatchOperation;
let operations = vec![
// Read current values
BatchOperation::Read { tag_name: "CurrentTemp".to_string() },
BatchOperation::Read { tag_name: "CurrentPressure".to_string() },
// Write new setpoints
BatchOperation::Write {
tag_name: "TempSetpoint".to_string(),
value: PlcValue::Real(78.5)
},
BatchOperation::Write {
tag_name: "PressureSetpoint".to_string(),
value: PlcValue::Real(15.2)
},
// Update control flags
BatchOperation::Write {
tag_name: "AutoModeEnabled".to_string(),
value: PlcValue::Bool(true)
},
];
let results = client.execute_batch(&operations).await?;
for result in results {
match result.operation {
BatchOperation::Read { tag_name } => {
match result.result {
Ok(Some(value)) => println!("๐ Read {}: {:?} ({}ฮผs)",
tag_name, value, result.execution_time_us),
Err(error) => println!("โ Read {}: {}", tag_name, error),
}
}
BatchOperation::Write { tag_name, .. } => {
match result.result {
Ok(_) => println!("โ
Write {}: Success ({}ฮผs)",
tag_name, result.execution_time_us),
Err(error) => println!("โ Write {}: {}", tag_name, error),
}
}
}
}
```
### โ๏ธ **Advanced Configuration**
```rust
use rust_ethernet_ip::BatchConfig;
// High-performance configuration
let high_perf_config = BatchConfig {
max_operations_per_packet: 50, // More operations per packet
max_packet_size: 4000, // Larger packets for modern PLCs
packet_timeout_ms: 1000, // Faster timeout
continue_on_error: true, // Don't stop on single failures
optimize_packet_packing: true, // Optimize packet efficiency
};
client.configure_batch_operations(high_perf_config);
// Conservative/reliable configuration
let conservative_config = BatchConfig {
max_operations_per_packet: 10, // Fewer operations per packet
max_packet_size: 504, // Smaller packets for compatibility
packet_timeout_ms: 5000, // Longer timeout
continue_on_error: false, // Stop on first error
optimize_packet_packing: false, // Preserve exact operation order
};
client.configure_batch_operations(conservative_config);
```
### ๐ **Performance Comparison Example**
```rust
use std::time::Instant;
let tags = vec!["Tag1", "Tag2", "Tag3", "Tag4", "Tag5"];
// Individual operations (traditional approach)
let individual_start = Instant::now();
for tag in &tags {
let _ = client.read_tag(tag).await?;
}
let individual_duration = individual_start.elapsed();
// Batch operations (optimized approach)
let batch_start = Instant::now();
let _ = client.read_tags_batch(&tags).await?;
let batch_duration = batch_start.elapsed();
let speedup = individual_duration.as_nanos() as f64 / batch_duration.as_nanos() as f64;
println!("๐ Performance improvement: {:.1}x faster with batch operations!", speedup);
```
### ๐จ **Error Handling**
```rust
// Batch operations provide detailed error information per operation
match client.execute_batch(&operations).await {
Ok(results) => {
let mut success_count = 0;
let mut error_count = 0;
for result in results {
match result.result {
Ok(_) => success_count += 1,
Err(_) => error_count += 1,
}
}
println!("๐ Results: {} successful, {} failed", success_count, error_count);
println!("๐ Success rate: {:.1}%",
(success_count as f32 / (success_count + error_count) as f32) * 100.0);
}
Err(e) => println!("โ Entire batch failed: {}", e),
}
```
### ๐ฏ **Best Practices**
- **Use batch operations for 3+ operations** to see significant performance benefits
- **Group similar operations** (reads together, writes together) for optimal packet packing
- **Adjust max_operations_per_packet** based on your PLC's capabilities (10-50 typical)
- **Use higher packet sizes** (up to 4000 bytes) for modern CompactLogix/ControlLogix PLCs
- **Enable continue_on_error** for data collection scenarios where partial results are acceptable
- **Disable optimize_packet_packing** if precise operation order is critical for your application
## ๐๏ธ **Building**
### Quick Build
```bash
# Windows
build.bat
# Linux/macOS
./build.sh
```
### Manual Build
```bash
# Build Rust library
cargo build --release --lib
# Copy to C# project (Windows)
copy target\release\rust_ethernet_ip.dll csharp\RustEtherNetIp\
# Build C# wrapper
cd csharp/RustEtherNetIp
dotnet build --configuration Release
```
See [BUILD.md](BUILD.md) for comprehensive build instructions.
## ๐งช **Testing**
Run the comprehensive test suite:
```bash
# Rust unit tests (30+ tests)
cargo test
# C# wrapper tests
cd csharp/RustEtherNetIp.Tests
dotnet test
# Run examples
cargo run --example advanced_tag_addressing
cargo run --example data_types_showcase
```
## ๐ฏ **Examples**
Explore comprehensive examples demonstrating all library capabilities:
### **๐ฅ๏ธ WPF Desktop Application** *(Recommended)*
Rich desktop application with MVVM architecture and modern UI.

```bash
cd examples/WpfExample
dotnet run
```
**Features:**
- โ
**MVVM architecture** with CommunityToolkit.Mvvm
- โ
**Real-time tag monitoring** with automatic refresh
- โ
**Advanced tag discovery** with type detection
- โ
**Performance benchmarking** with visual metrics
- โ
**Comprehensive logging** with timestamped activity
**Perfect for:** Desktop HMIs, engineering tools, maintenance applications
### **๐ช WinForms Application**
Traditional Windows Forms application with familiar UI patterns.

```bash
cd examples/WinFormsExample
dotnet run
```
**Features:**
- โ
**Classic Windows UI** with familiar controls
- โ
**Connection monitoring** with automatic reconnection
- โ
**Tag operations** with validation and error handling
- โ
**Performance testing** with real-time metrics
- โ
**Industrial styling** with professional appearance
**Perfect for:** Legacy system integration, simple HMIs, maintenance tools
### **๐ ASP.NET Core Web API**
RESTful API backend providing HTTP access to PLC functionality.

```bash
cd examples/AspNetExample
dotnet run
```
**Features:**
- โ
**RESTful endpoints** for all PLC operations
- โ
**Swagger documentation** with interactive API explorer
- โ
**Type-safe operations** with comprehensive validation
- โ
**Performance monitoring** with built-in benchmarking
- โ
**Production-ready** with proper error handling and logging
**Perfect for:** Web services, microservices, system integration, mobile backends
### **๐ฆ Rust Examples**
Native Rust examples demonstrating core library functionality.
```bash
# Advanced tag addressing showcase
cargo run --example advanced_tag_addressing
# Complete data types demonstration
cargo run --example data_types_showcase
# Batch operations performance demo
cargo run --example batch_operations_demo
# Stream injection example (v0.6.2)
cargo run --example stream_injection_example
# Nested UDT array test
cargo run --example test_cell_nestdata_udt
```
**Features:**
- โ
**Advanced tag parsing** with complex path examples
- โ
**All data types** with encoding demonstrations
- โ
**Performance examples** with async/await patterns
- โ
**Error handling** with comprehensive error types
- โ
**Batch operations** with performance comparisons and configuration examples
- โ
**Stream injection** for custom TCP transport (v0.6.2)
- โ
**Nested UDT arrays** with complex path support (v0.6.2)
**Perfect for:** Rust applications, embedded systems, high-performance scenarios
### **๐ Quick Start Guide**
1. **Choose your platform:**
- **Desktop/Windows** โ WPF or WinForms Application
- **Web API/Services** โ ASP.NET Core Web API
- **Native/Performance** โ Rust Examples
2. **Start the backend** (for web examples):
```bash
cd examples/AspNetExample
dotnet run
```
3. **Run your chosen example** and connect to your PLC at `192.168.0.1:44818`
4. **Explore features:**
- Tag discovery with advanced addressing
- Real-time monitoring and benchmarking
- All 13 Allen-Bradley data types
- Professional error handling and logging
### **๐ Example Structure**
```
examples/
โโโ WpfExample/ # WPF desktop application
โโโ WinFormsExample/ # WinForms desktop application
โโโ AspNetExample/ # ASP.NET Core Web API
โโโ rust_examples/ # Native Rust examples
โ โโโ advanced_tag_addressing.rs
โ โโโ data_types_showcase.rs
โ โโโ batch_operations_demo.rs
โโโ csharp_examples/ # Additional C# examples
```
Each example includes comprehensive documentation, setup instructions, and demonstrates different aspects of the library's capabilities.
## ๐ **Documentation**
- **[API Documentation](https://docs.rs/rust-ethernet-ip)** - Complete API reference
- **[Examples](examples/)** - Practical usage examples
- **[Build Guide](BUILD.md)** - Comprehensive build instructions
- **[C# Wrapper Guide](csharp/RustEtherNetIp/README.md)** - C# integration documentation
- **[Changelog](CHANGELOG.md)** - Version history and changes
- **[Crates.io Page](https://crates.io/crates/rust-ethernet-ip)** - Official crate registry page
## ๐ **Sponsor This Project**
This project is developed for the industrial automation community. If you find this library valuable for your projects, please consider sponsoring its development!
### ๐ฏ **Why Sponsor?**
- **๐ Accelerate Development** - Help fund new features, performance improvements, and platform support
- **๐ Priority Bug Fixes** - Get faster resolution of issues affecting your production systems
- **๐ก Feature Requests** - Influence the roadmap with your specific industrial automation needs
- **๐ Enhanced Documentation** - Support creation of comprehensive guides and tutorials
- **๐ง Professional Support** - Access to direct developer support for complex implementations
### ๐ฐ **Sponsorship Tiers**
- **โ Coffee** - Show appreciation for the project
- **๐ Feature Sponsor** - Fund specific feature development
- **๐ญ Enterprise Sponsor** - Priority support and custom development
- **๐ Platinum Sponsor** - Direct collaboration and roadmap input
### ๐ **Sponsor Benefits**
- **Priority issue resolution** for production-critical bugs
- **Direct access** to development team for technical questions
- **Early access** to new features and beta releases
- **Custom feature development** for your specific use cases
- **Recognition** in project documentation and releases
**[Sponsor on GitHub โ](https://github.com/sponsors/sergiogallegos)**
### ๐ฌ **Feedback & Feature Requests**
We value your input! Help us improve the library by sharing:
#### ๐ **Bug Reports**
- **Production Issues** - Critical bugs affecting your systems
- **Performance Problems** - Slow operations or memory issues
- **Compatibility Issues** - Problems with specific PLC models or configurations
- **Error Handling** - Unexpected errors or unclear error messages
#### ๐ก **Feature Requests**
- **New Data Types** - Additional Allen-Bradley data type support
- **Platform Support** - New operating systems or architectures
- **Performance Features** - Batch operations, caching, or optimization requests
- **Integration Features** - New language bindings or framework integrations
- **Industrial Features** - SCADA-specific functionality, alarms, or trending
#### ๐ **Use Case Sharing**
- **Success Stories** - How you're using the library in production
- **Performance Metrics** - Real-world performance data from your applications
- **Integration Examples** - Custom implementations or workarounds
- **Best Practices** - Tips for other users in similar industries
**[Submit Feedback โ](https://github.com/sergiogallegos/rust-ethernet-ip/issues/new/choose)**
## ๐ง **Troubleshooting**
Experiencing issues? Check out our comprehensive troubleshooting guide:
๐ **[Complete Troubleshooting Guide](docs/TROUBLESHOOTING.md)**
### Quick Reference: Common Errors
| **0x01** | Connection failure | Check tag name, scope, and External Access permissions |
| **0x04** | Path segment error | Verify tag path format (controller vs program-scoped) |
| **0x05** | Path destination unknown | Check ControlLogix slot routing |
| **0x16** | Object does not exist | Verify tag exists and is downloaded to PLC |
### Most Common Issues
**1. CIP Error 0x01: Connection Failure**
- โ
Verify tag name is exactly correct (case-sensitive)
- โ
Check if tag is program-scoped: use `"Program:ProgramName.TagName"`
- โ
Verify tag has External Access enabled in RSLogix/Studio 5000
- โ
Ensure tag is downloaded to PLC (not just saved)
- โ
For ControlLogix, check CPU slot routing
**2. Tag Not Found**
- Use `discover_tags()` to find available tags
- Check tag scope (Controller vs Program)
- Verify tag spelling (case-sensitive)
**3. ControlLogix Routing Issues**
- If CPU is in slot other than 0, specify route path:
```rust
let route = RoutePath::new().add_slot(3); let mut client = EipClient::with_route_path("192.168.1.100:44818", route).await?;
```
**4. Connection Timeout**
- Verify IP address and port (default: 44818)
- Check network connectivity (ping the PLC)
- Ensure firewall allows port 44818
- Verify PLC is in RUN mode
**5. Nested UDT Array Members (v0.6.2)**
- Complex paths like `Cell_NestData[90].PartData.Member` are now fully supported
- The library automatically uses `TagPath::parse()` for paths with member access after array brackets
- If you encounter issues, ensure the full path is correctly specified
**6. Testing Without PLC**
- Use `SKIP_PLC_TESTS=1` environment variable to skip PLC-dependent tests
- Set `TEST_PLC_ADDRESS` to your PLC IP for integration tests
- See `tests/README.md` for complete test configuration guide
For detailed troubleshooting steps, code examples, and debugging procedures, see the [Complete Troubleshooting Guide](docs/TROUBLESHOOTING.md).
## ๐ค **Community & Support**
- **[Discord Server](https://discord.gg/uzaM3tua)** - Community discussions, support, and development updates
- **[GitHub Issues](https://github.com/sergiogallegos/rust-ethernet-ip/issues)** - Bug reports and feature requests
- **[GitHub Discussions](https://github.com/sergiogallegos/rust-ethernet-ip/discussions)** - General questions and ideas
- **[Crates.io](https://crates.io/crates/rust-ethernet-ip)** - Official Rust package registry
## ๐ **Inspiration**
This project draws inspiration from excellent libraries in the industrial automation space:
- **[pylogix](https://github.com/dmroeder/pylogix)** - Python library for Allen-Bradley PLCs
- **[pycomm3](https://github.com/ottowayi/pycomm3)** - Python library for Allen-Bradley PLCs
- **[gologix](https://github.com/danomagnum/gologix)** - Go library for Allen-Bradley PLCs
- **[libplctag](https://github.com/libplctag/libplctag)** - Cross-platform PLC communication library
## ๐ **Contributing**
We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details on:
- Code style and standards
- Testing requirements
- Pull request process
- Development setup
## โ ๏ธ **Disclaimer and Liability**
### **Use at Your Own Risk**
This library is provided "AS IS" without warranty of any kind. Users assume full responsibility for its use in their applications and systems.
### **No Warranties**
The developers and contributors make **NO WARRANTIES, EXPRESS OR IMPLIED**, including but not limited to:
- **Merchantability** or fitness for a particular purpose
- **Reliability** or availability of the software
- **Accuracy** of data transmission or processing
- **Safety** for use in critical or production systems
### **Industrial Safety Responsibility**
- **๐ญ Industrial Use:** Users are solely responsible for ensuring this library meets their industrial safety requirements
- **๐ Safety Systems:** This library should NOT be used for safety-critical applications without proper validation
- **โ๏ธ Production Systems:** Thoroughly test in non-production environments before deploying to production systems
- **๐ Compliance:** Users must ensure compliance with all applicable industrial standards and regulations
### **Limitation of Liability**
Under no circumstances shall the developers, contributors, or associated parties be liable for:
- **Equipment damage** or malfunction
- **Production downtime** or operational disruptions
- **Data loss** or corruption
- **Personal injury** or property damage
- **Financial losses** of any kind
- **Consequential or indirect damages**
### **User Responsibilities**
By using this library, you acknowledge and agree that:
- You have the technical expertise to properly implement and test the library
- You will perform adequate testing before production deployment
- You will implement appropriate safety measures and fail-safes
- You understand the risks associated with industrial automation systems
- You accept full responsibility for any consequences of using this library
### **Indemnification**
Users agree to indemnify and hold harmless the developers and contributors from any claims, damages, or liabilities arising from the use of this library.
---
**โ ๏ธ IMPORTANT: This disclaimer is an integral part of the license terms. Use of this library constitutes acceptance of these terms.**
## ๐ **License**
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
---
**Built for the industrial automation community**
## ๐๏ธ Build All
To build all libraries and examples:
```bash
./build-all.bat
```
This script builds:
- Rust library (DLL/SO/DYLIB)
- C# wrapper and tests
- All example applications (WinForms, WPF, ASP.NET)
See [BUILD.md](BUILD.md) for details.
## ๐ Version
**Current Release:** v0.6.1 ([CHANGELOG.md](CHANGELOG.md))
## ๐ Changelog
### v0.6.2 (January 2026) - **CURRENT** ๐
- **NEW: Stream Injection API** - `connect_with_stream()` for custom TCP transport
- **NEW: Test Configuration** - Environment variable support for PLC testing
- **FIXED: Nested UDT Member Access** - Fixed reading nested UDT members from array elements
### v0.6.1 (January 2026)
- **๐งน Repository Cleanup**: Removed Go and Python wrappers to focus on Rust library and C# integration
- **๐ฆ Streamlined Examples**: Focused on Microsoft stack (WinForms, WPF, ASP.NET) and Rust native examples
- **๐ง Improved Documentation**: Updated all documentation to reflect current focus
### v0.6.0 (January 2026)
- **๐ง Generic UDT Format**: New `UdtData` struct with `symbol_id` and raw bytes
- **โ
Library Health**: All 31 unit tests passing, production-ready core
- **๐ Array Element Access**: Full read/write support for array elements
- **โ๏ธ Array Element Writing**: Write individual array elements with automatic array modification
- **๐ C# Wrapper Enhancements**: Batch operations, TagGroup, Statistics, Data Quality & Timestamp
- **๐ง Connection Fixes**: Fixed RoutePath handling in WinForms, WPF, and ASP.NET applications
- **๐ Documentation**: Comprehensive documentation for STRING and UDT array write limitations
### v0.5.5 (December 2025)
- **๐ Array Element Access**: Full read/write support for array elements using intelligent workaround
- **โ๏ธ Array Element Writing**: Write individual array elements with automatic array modification
- **๐ง BOOL Array Support**: Automatic DWORD bit extraction for BOOL arrays
### v0.5.4 (October 2025)
- **๐ UDT Definition Discovery**: Automatic UDT structure detection from PLC
- **๐ท๏ธ Enhanced Tag Discovery**: Full attribute support with permissions and scope
- **๐ฆ Packet Size Negotiation**: Dynamic optimization for firmware 20+
- **๐ฃ๏ธ Route Path Support**: Slot configuration and multi-hop routing
- **๐พ Cache Management**: Smart caching for UDT definitions and tag attributes
- **๐ง CIP Services**: Full implementation of Services 0x03 and 0x4C
- **๐งช Comprehensive Testing**: 14 new unit tests for UDT discovery features
- **๐ Documentation**: Complete API documentation and examples
See [CHANGELOG.md](CHANGELOG.md) for a full list of changes.
## ๐ Release Notes
See [RELEASE_NOTES_v0.5.0.md](RELEASE_NOTES_v0.5.0.md) for detailed release notes and migration info.