### Docker Example Commands Source: https://github.com/mwieczorkiewicz/rust7/blob/main/CLAUDE.md Commands for managing a Dockerized SoftPLC, including starting, provisioning the database, running the example, and stopping the containers. Requires the `task` CLI. ```bash # Start the virtual PLC docker compose up -d ``` ```bash # Provision DB2 (required before running the example) curl -X POST 'http://localhost:8080/api/DataBlocks?id=2&size=1024' -H 'accept: */*' -d '' ``` ```bash # Run example task run # or without taskfile: cargo run ``` ```bash docker compose down ``` -------------------------------- ### Bit Addressing Formula Example Source: https://github.com/mwieczorkiewicz/rust7/blob/main/_autodocs/00-api-summary.md Calculates the start bit for S7 addressing using byte and bit offsets. Use the helper function for simpler bit access. ```rust start_bit = 45 * 8 + 3 = 363 client.read_area(S7_AREA_DB, 10, 363, S7_WL_BIT, &mut buf)?; // Or use helper: client.read_bit(S7_AREA_DB, 10, 45, 3)? ``` -------------------------------- ### Run Rust Examples Source: https://github.com/mwieczorkiewicz/rust7/blob/main/examples/docker/README.md Executes the Rust examples provided in the project. This command assumes a 'task' runner is available. ```shell task run ``` -------------------------------- ### Build and Start Docker Compose Containers Source: https://github.com/mwieczorkiewicz/rust7/blob/main/examples/docker/README.md Builds Docker images if necessary and starts the services defined in docker-compose.yml. This command is used for initial setup or when changes require a rebuild. ```shell docker compose up --build ``` -------------------------------- ### Run Diagnostics Example Source: https://github.com/mwieczorkiewicz/rust7/blob/main/examples/diagnostics/README.md Execute the diagnostics example against a real PLC or a local SoftPLC container. The PLC IP address defaults to 127.0.0.1 if not provided. ```bash cargo run -- 192.168.0.100 ``` ```bash cargo run ``` -------------------------------- ### Connection Setup Methods Source: https://github.com/mwieczorkiewicz/rust7/blob/main/doc/Documentation.md Methods for configuring the connection parameters before establishing a connection. ```APIDOC ## set_connection_type ### Description Changes the S7 connection type to the PLC. ### Prototype `set_connection_type` ``` ```APIDOC ## set_timeout ### Description Sets the operations timeout. ### Prototype `set_timeout` ``` ```APIDOC ## set_connection_port ### Description Sets the TCP Connection Port. ### Prototype `set_connection_port` ``` -------------------------------- ### Initialize S7Client in Rust Source: https://github.com/mwieczorkiewicz/rust7/blob/main/_autodocs/INDEX.md Demonstrates the basic initialization of the S7Client. This is the starting point for most operations. ```rust let client = S7Client::new(); ``` -------------------------------- ### Connect and Read DB Example Source: https://github.com/mwieczorkiewicz/rust7/blob/main/_autodocs/README.md Demonstrates creating an S7Client, connecting to a PLC, reading data from a database, and disconnecting. Ensure the IP address is correct for your PLC. ```rust use rust7::{S7Client, S7Error}; fn main() -> Result<(), S7Error> { let mut client = S7Client::new(); client.connect_s71200_1500("192.168.0.100")?; let mut buf = vec![0u8; 64]; client.read_db(100, 0, &mut buf)?; println!("Read {} bytes in {:.3} ms", buf.len(), client.last_time); client.disconnect(); Ok(()) } ``` -------------------------------- ### Rust Read CPU Info Example Source: https://github.com/mwieczorkiewicz/rust7/blob/main/_autodocs/03-types.md Example of how to read CPU information using the `read_cpu_info()` method and print details. Strings are trimmed of null bytes and trailing whitespace. ```rust let info = client.read_cpu_info()?; println!("Module: {}", info.module_type_name); println!("Name: {}", info.module_name); println!("Project: {}", info.as_name); println!("Serial: {}", info.serial_number); ``` -------------------------------- ### Install Docker Engine (Ubuntu/Debian) Source: https://github.com/mwieczorkiewicz/rust7/blob/main/examples/docker/README.md Installs Docker Engine, CLI, containerd, and plugins on Ubuntu/Debian systems. This command installs the core Docker components. ```shell sudo apt update sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y ``` -------------------------------- ### Example Usage of describe_event Source: https://github.com/mwieczorkiewicz/rust7/blob/main/doc/Documentation.md Demonstrates how to use the `describe_event` function to get a human-readable description for a diagnostic event ID and print it. ```rust use rust7::{describe_event, S7Client}; let info = describe_event(0x4302); println!("{}: {}", info.class, info.name.unwrap_or("(unknown)")); // Mode transitions: Mode transition from STARTUP to RUN ``` -------------------------------- ### Verify Docker Installation Source: https://github.com/mwieczorkiewicz/rust7/blob/main/examples/docker/README.md Checks the installed Docker version. This command is used on Linux, macOS, and Windows to confirm Docker is installed correctly. ```shell docker --version ``` -------------------------------- ### PLC Connection Workflow Example Source: https://github.com/mwieczorkiewicz/rust7/blob/main/doc/Documentation.md A basic loop demonstrating how to maintain a connection to a PLC, handling disconnections and read/write operations. It's recommended to disconnect and reconnect upon severe errors. ```rust while !exit_request{ if !Client.connected { let _ = client.connect_s71200_1500(ip_address); } if Client.connected { if !do_read_and_write() { // <-- returns false when severe error occurs Client.disconnect(); } } thread::sleep(100); } ``` -------------------------------- ### Install Docker Dependencies (Ubuntu/Debian) Source: https://github.com/mwieczorkiewicz/rust7/blob/main/examples/docker/README.md Installs necessary dependencies for adding Docker's official repository on Ubuntu/Debian systems. ```shell sudo apt install ca-certificates curl gnupg -y ``` -------------------------------- ### Start PLC in Docker Source: https://github.com/mwieczorkiewicz/rust7/blob/main/examples/docker/README.md Starts the PLC container in detached mode. Ensure you are in the directory containing the docker-compose.yml file. ```shell docker compose up -d ``` -------------------------------- ### Basic S7 Read and Write Example Source: https://github.com/mwieczorkiewicz/rust7/blob/main/_autodocs/07-examples.md Demonstrates connecting to an S7-1200/S7-1500 PLC, reading data from a DB, writing data to a DB, and disconnecting. Use this for simple, one-off operations. ```rust use rust7::{S7Client, S7Error}; fn main() -> Result<(), S7Error> { let mut client = S7Client::new(); // Connect to S7-1200/S7-1500 client.connect_s71200_1500("192.168.0.100")?; println!("Connected; PDU: {} bytes", client.pdu_length); // Read 64 bytes from DB100, starting at byte 0 let mut read_buf = vec![0u8; 64]; client.read_db(100, 0, &mut read_buf)?; println!("Read {} bytes in {:.3} ms", read_buf.len(), client.last_time); // Write 10 bytes to DB100, starting at byte 10 let write_data = b"Hello S7!!"; client.write_db(100, 10, write_data)?; println!("Wrote {} bytes in {:.3} ms", write_data.len(), client.last_time); // Disconnect client.disconnect(); println!("Disconnected"); Ok(()) } ``` -------------------------------- ### Add Docker GPG Key (Ubuntu/Debian) Source: https://github.com/mwieczorkiewicz/rust7/blob/main/examples/docker/README.md Installs Docker's official GPG key to ensure the authenticity of packages. This step is crucial for secure Docker installation. ```shell sudo install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \ sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg sudo chmod a+r /etc/apt/keyrings/docker.gpg ``` -------------------------------- ### Run Rust Application with Root Privileges Source: https://github.com/mwieczorkiewicz/rust7/blob/main/_autodocs/06-configuration.md Example of running a Rust application with root privileges using `sudo` to bind to the privileged port 102. ```bash sudo cargo run ``` -------------------------------- ### Bash Usage for Environment Variables Source: https://github.com/mwieczorkiewicz/rust7/blob/main/_autodocs/07-examples.md Demonstrates how to run the Rust S7 Client example using different environment variable settings for IP, port, and connection timeout. ```bash # Use defaults cargo run # Override with environment variables PLC_IP=192.168.0.100 PLC_PORT=102 cargo run # Slow network PLC_IP=remote.example.com CONN_TIMEOUT_MS=15000 cargo run ``` -------------------------------- ### Construct S7 Client Source: https://github.com/mwieczorkiewicz/rust7/blob/main/_autodocs/INDEX.md Instantiate a new S7 client object. This is the starting point for all interactions with the PLC. ```rust S7Client::new() -> S7Client ``` -------------------------------- ### Update and Upgrade Packages (Ubuntu/Debian) Source: https://github.com/mwieczorkiewicz/rust7/blob/main/examples/docker/README.md Updates the package list and upgrades installed packages on Ubuntu/Debian systems. This is a prerequisite for installing Docker. ```shell sudo apt update sudo apt upgrade -y ``` -------------------------------- ### Calculate Bit Addressing Formula Source: https://github.com/mwieczorkiewicz/rust7/blob/main/_autodocs/INDEX.md Provides the formula for calculating the start bit based on byte offset and bit index. Useful for precise data access. ```plaintext start_bit = byte_offset * 8 + bit_index ``` -------------------------------- ### Add Docker Repository (Ubuntu/Debian) Source: https://github.com/mwieczorkiewicz/rust7/blob/main/examples/docker/README.md Adds the Docker repository to your APT sources list. This allows your system to find and install Docker packages. ```shell echo \ "deb [arch=$(dpkg --print-architecture) \ signed-by=/etc/apt/keyrings/docker.gpg] \ https://download.docker.com/linux/ubuntu \ $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \ sudo tee /etc/apt/sources.list.d/docker.list > /dev/null ``` -------------------------------- ### Rust Describe Event Example Source: https://github.com/mwieczorkiewicz/rust7/blob/main/_autodocs/03-types.md Example of how to describe a diagnostic event using its ID and print the event class and name. The `name` field is `None` if the event ID is not found in standard lookup tables. ```rust let info = describe_event(0x4302); println!("Class: {}", info.class); // "Mode transitions" println!("Name: {:?}", info.name); // Some("Mode transition from STARTUP to RUN") ``` -------------------------------- ### Remote TSAP Formula Example Source: https://github.com/mwieczorkiewicz/rust7/blob/main/_autodocs/00-api-summary.md Calculates the remote TSAP for rack/slot-based systems using connection type, rack, and slot. ```rust remote_tsap = (0x01 << 8) + (0 * 0x20) + 0 = 0x0100 ``` -------------------------------- ### Configure iptables for Port Forwarding Source: https://github.com/mwieczorkiewicz/rust7/blob/main/_autodocs/06-configuration.md Example of using `iptables` to forward TCP traffic from a non-privileged port (2102) to the standard S7 port (102) on a target PLC. ```bash iptables -t nat -A PREROUTING -p tcp --dport 2102 -j DNAT --to-destination 192.168.0.100:102 ``` -------------------------------- ### Generate and Open Documentation Source: https://github.com/mwieczorkiewicz/rust7/blob/main/CLAUDE.md Create project documentation locally and open it in a web browser. `--no-deps` excludes dependencies from the documentation. ```bash cargo doc --no-deps --open ``` -------------------------------- ### Write Area - Bit Write Example Source: https://github.com/mwieczorkiewicz/rust7/blob/main/_autodocs/02-read-write-api.md Writes a single bit to a specified memory area. The start address is calculated as (byte_offset * 8 + bit_offset). Bit writes are atomic and non-destructive. ```rust // Write bit to DB10.DBX 45.3 let start_bit = 45 * 8 + 3; let value = [1u8]; // true client.write_area(S7_AREA_DB, 10, start_bit as u16, S7_WL_BIT, &value)?; ``` -------------------------------- ### Read Area - Bit Access Example Source: https://github.com/mwieczorkiewicz/rust7/blob/main/_autodocs/02-read-write-api.md Reads a single bit from a specified memory area. The start address is calculated as (byte_offset * 8 + bit_offset). Only the first byte of the buffer is used. ```rust // Read bit from DB10.DBX 45.3 (byte 45, bit 3) let start_bit = 45 * 8 + 3; let mut buf = [0u8; 1]; client.read_area(S7_AREA_DB, 10, start_bit as u16, S7_WL_BIT, &mut buf)?; let bit_value = buf[0] != 0; // true if bit is set ``` -------------------------------- ### Create S7Client Instance Source: https://github.com/mwieczorkiewicz/rust7/blob/main/_autodocs/00-api-summary.md Instantiate an S7Client using either the `new()` or `default()` method. The `new()` method is typically used when you intend to immediately configure and connect. ```rust let mut client = S7Client::new(); ``` ```rust let client = S7Client::default(); ``` -------------------------------- ### Configure S7 Client with Environment Variables Source: https://github.com/mwieczorkiewicz/rust7/blob/main/_autodocs/07-examples.md Sets up PLC connection parameters like IP address, port, and connection timeout using environment variables, with fallbacks to default values. Useful for flexible deployment across different environments. ```rust use rust7::S7Client; fn main() -> Result<(), Box> { // Read configuration from environment let plc_ip = std::env::var("PLC_IP") .unwrap_or_else(|_| "127.0.0.1".to_string()); let plc_port = std::env::var("PLC_PORT") .ok() .and_then(|p| p.parse::().ok()) .unwrap_or(102); let conn_timeout = std::env::var("CONN_TIMEOUT_MS") .ok() .and_then(|p| p.parse::().ok()) .unwrap_or(3000); println!("Configuration:"); println!(" IP: {}", plc_ip); println!(" Port: {}", plc_port); println!(" Connect timeout: {} ms", conn_timeout); // Configure and connect let mut client = S7Client::new(); if plc_port != 102 { client.set_connection_port(plc_port)?; } client.set_timeout(conn_timeout, 1000, 500)?; client.connect_s71200_1500(&plc_ip)?; println!("Connected; PDU = {}", client.pdu_length); // Perform operations let mut buf = vec![0u8; 50]; client.read_db(1, 0, &mut buf)?; client.disconnect(); Ok(()) } ``` -------------------------------- ### Run Full Test Suite Source: https://github.com/mwieczorkiewicz/rust7/blob/main/CLAUDE.md Execute the complete test suite, encompassing unit, documentation, and integration tests. ```bash # Full suite (unit + doc + integration) cargo test ``` -------------------------------- ### Configuration Methods Source: https://github.com/mwieczorkiewicz/rust7/blob/main/_autodocs/INDEX.md Methods for configuring the S7Client before establishing a connection. ```APIDOC ## Configuration (before connect) ### `set_connection_type(&mut self, u16)` Sets the connection type for the client. #### Parameters - `u16`: The connection type code. #### Returns - `Result<(), S7Error>`: Ok on success, or an S7Error on failure. ``` ```APIDOC ### `set_timeout(&mut self, u64, u64, u64)` Sets the timeout values for the client connection. #### Parameters - `u64`: Timeout value 1. - `u64`: Timeout value 2. - `u64`: Timeout value 3. #### Returns - `Result<(), S7Error>`: Ok on success, or an S7Error on failure. ``` ```APIDOC ### `set_connection_port(&mut self, u16)` Sets the connection port for the client. #### Parameters - `u16`: The connection port number. #### Returns - `Result<(), S7Error>`: Ok on success, or an S7Error on failure. ``` -------------------------------- ### S7Client Creation Source: https://github.com/mwieczorkiewicz/rust7/blob/main/_autodocs/00-api-summary.md Instantiate the S7Client using `new()` or `default()`. ```APIDOC ## S7Client Creation ### Description Instantiate the S7Client using `new()` or `default()`. ### Creation ```rust let mut client = S7Client::new(); // or let client = S7Client::default(); ``` ``` -------------------------------- ### S7Client Constructor and Connection Source: https://github.com/mwieczorkiewicz/rust7/blob/main/_autodocs/INDEX.md Details on initializing the S7Client, configuring connection parameters, and establishing a connection to the PLC. ```APIDOC ## S7Client Constructor and Connection ### Description This section covers the initialization of the `S7Client` and the various methods for establishing a connection to different Siemens PLC models. ### Methods - `S7Client::new()`: Constructor for creating a new S7Client instance. - `set_connection_type(type)`: Sets the connection type (e.g., PG, OP, S7). - `set_timeout(connection_timeout, read_timeout, write_timeout)`: Configures connection, read, and write timeouts. - `set_connection_port(port)`: Sets the connection port. - `connect_s71200_1500()`: Connects to S7-1200 and S7-1500 series PLCs. - `connect_s7300()`: Connects to S7-300 series PLCs. - `connect_rack_slot(rack, slot)`: Connects to S7-400, WinAC, and PLCSIM using rack and slot. - `connect_tsap(local_tsap, remote_tsap)`: Connects using direct TSAP for LOGO! and S7-200. - `disconnect()`: Closes the active connection to the PLC. ### State Properties - `connected`: Boolean indicating if the client is currently connected. - `pdu_length`: The negotiated PDU length. - `last_time`: Timestamp of the last communication. - `chunks`: Information about data chunking. ``` -------------------------------- ### Run Unit Tests Source: https://github.com/mwieczorkiewicz/rust7/blob/main/CLAUDE.md Execute unit tests for the library. No Docker is required for this command. ```bash # Unit tests (123 tests, no Docker required) cargo test --lib ``` -------------------------------- ### Configuration and Utility Methods Source: https://github.com/mwieczorkiewicz/rust7/blob/main/_autodocs/README.md Methods for configuring connection parameters and other utility functions. ```APIDOC ## set_timeout(co, rd, wr) ### Description Sets the connection, read, and write timeouts for the client. ### Method `set_timeout(co: u32, rd: u32, wr: u32)` ### Endpoint N/A (SDK method) ### Parameters - **co** (u32) - Required - Connection timeout in milliseconds. - **rd** (u32) - Required - Read timeout in milliseconds. - **wr** (u32) - Required - Write timeout in milliseconds. ### Request Example ```rust client.set_timeout(5000, 5000, 5000); ``` ### Response None. ``` -------------------------------- ### Describe Diagnostic Event Source: https://github.com/mwieczorkiewicz/rust7/blob/main/_autodocs/INDEX.md Get descriptive information for a specific diagnostic event code. This function is static and does not require a client instance. ```rust describe_event(u16) -> DiagEventInfo ``` -------------------------------- ### S7Client Constructor and Connection Methods Source: https://github.com/mwieczorkiewicz/rust7/blob/main/_autodocs/README.md Methods for creating an S7Client instance and establishing a connection to a Siemens PLC. ```APIDOC ## S7Client::new() ### Description Creates a new instance of the S7Client. ### Method `S7Client::new()` ### Endpoint N/A (SDK method) ### Parameters None ### Request Example ```rust let mut client = S7Client::new(); ``` ### Response Returns a new `S7Client` instance. ``` ```APIDOC ## connect_s71200_1500(ip) ### Description Establishes a connection to an S7-1200 or S7-1500 PLC. ### Method `connect_s71200_1500(ip: &str)` ### Endpoint N/A (SDK method) ### Parameters - **ip** (string) - Required - The IP address of the PLC. ### Request Example ```rust client.connect_s71200_1500("192.168.0.100")?; ``` ### Response Returns `Ok(())` on successful connection, or an `S7Error` on failure. ``` ```APIDOC ## connect_s7300() ### Description Establishes a connection to an S7-300 PLC. ### Method `connect_s7300()` ### Endpoint N/A (SDK method) ### Parameters None ### Request Example ```rust client.connect_s7300()?; ``` ### Response Returns `Ok(())` on successful connection, or an `S7Error` on failure. ``` ```APIDOC ## connect_rack_slot() ### Description Establishes a connection to an S7-400, WinAC, or PLCSIM PLC using rack and slot information. ### Method `connect_rack_slot(rack: u8, slot: u8)` ### Endpoint N/A (SDK method) ### Parameters - **rack** (u8) - Required - The rack number of the PLC. - **slot** (u8) - Required - The slot number of the PLC. ### Request Example ```rust client.connect_rack_slot(0, 2)?; ``` ### Response Returns `Ok(())` on successful connection, or an `S7Error` on failure. ``` ```APIDOC ## connect_tsap() ### Description Establishes a connection to a LOGO! or S7-200 PLC using TSAP (Transport Service Access Point). ### Method `connect_tsap(local_tsap: u16, remote_tsap: u16)` ### Endpoint N/A (SDK method) ### Parameters - **local_tsap** (u16) - Required - The local TSAP. - **remote_tsap** (u16) - Required - The remote TSAP. ### Request Example ```rust client.connect_tsap(0x0100, 0x0200)?; ``` ### Response Returns `Ok(())` on successful connection, or an `S7Error` on failure. ``` ```APIDOC ## disconnect() ### Description Closes the connection to the PLC. ### Method `disconnect()` ### Endpoint N/A (SDK method) ### Parameters None ### Request Example ```rust client.disconnect(); ``` ### Response None. ``` -------------------------------- ### Handling S7 Errors Source: https://github.com/mwieczorkiewicz/rust7/blob/main/_autodocs/03-types.md Example of how to handle `S7Error` results from client operations, differentiating between low-level and high-level errors for appropriate recovery actions. ```rust match client.read_db(1, 0, &mut buf) { Ok(_) => println!("Success"), Err(S7Error::IsoInvalidHeader) => { eprintln!("Low-level error; disconnecting"); client.disconnect(); } Err(S7Error::S7NotFound) => { eprintln!("High-level error; connection OK for retry"); } Err(e) => eprintln!("Error: {}", e), } ``` -------------------------------- ### Builder-Style Configuration for S7 Client Source: https://github.com/mwieczorkiewicz/rust7/blob/main/_autodocs/06-configuration.md Use this pattern for sequential configuration of the S7 client, chaining methods to set connection type, timeouts, port, and finally connecting to the PLC. ```rust let mut client = S7Client::new(); client .set_connection_type(CT_PG) .and_then(|_| client.set_timeout(5000, 1500, 750)) .and_then(|_| client.set_connection_port(102)) .and_then(|_| client.connect_s71200_1500("192.168.0.100"))?; ``` -------------------------------- ### Client Construction Source: https://github.com/mwieczorkiewicz/rust7/blob/main/_autodocs/INDEX.md Creates a new instance of the S7Client. ```APIDOC ## Client Construction ### `S7Client::new()` Creates a new instance of the S7Client. #### Returns - `S7Client`: A new S7Client instance. ``` -------------------------------- ### Create New S7Client Instance Source: https://github.com/mwieczorkiewicz/rust7/blob/main/_autodocs/01-s7client-core.md Instantiates a new S7Client with default settings. The client is initially in a disconnected state and requires subsequent connection calls. ```rust use rust7::S7Client; let mut client = S7Client::new(); // Client is now ready to configure and connect ``` -------------------------------- ### Write Data Block (DB) Source: https://github.com/mwieczorkiewicz/rust7/blob/main/_autodocs/INDEX.md Write data to a specific Data Block (DB) in the PLC. Requires the DB number, start address, and the data buffer. ```rust write_db(&mut self, u16, u16, &[u8]) -> Result<(), S7Error> ``` -------------------------------- ### Read Data Block (DB) Source: https://github.com/mwieczorkiewicz/rust7/blob/main/_autodocs/INDEX.md Read data from a specific Data Block (DB) in the PLC. Requires the DB number, start address, and a buffer for the data. ```rust read_db(&mut self, u16, u16, &mut [u8]) -> Result<(), S7Error> ``` -------------------------------- ### S7Client::new() Source: https://github.com/mwieczorkiewicz/rust7/blob/main/_autodocs/01-s7client-core.md Creates a new S7 client instance with default configuration. The client is initialized in a disconnected state and ready for further configuration before establishing a connection. ```APIDOC ## S7Client::new() ### Description Creates a new S7 client instance with default configuration. The client is initialized in a disconnected state and ready for further configuration before establishing a connection. ### Signature ```rust pub fn new() -> Self ``` ### Returns A new `S7Client` in disconnected state. ### Default Configuration - Connection type: `CT_PG` (programming device) - TCP port: `102` (standard S7 protocol port) - Connect timeout: `3000` ms - Read timeout: `1000` ms - Write timeout: `500` ms - PDU size: unset (negotiated on connect) ### Example ```rust use rust7::S7Client; let mut client = S7Client::new(); // Client is now ready to configure and connect ``` ### Notes - The client must be connected before any read/write operations. - Call one of the `connect_*` methods to establish a TCP connection. - Implements `Default` trait, so `S7Client::default()` is equivalent. ``` -------------------------------- ### Write Data Area Source: https://github.com/mwieczorkiewicz/rust7/blob/main/_autodocs/INDEX.md Write data to specified memory areas of the PLC. Requires specifying the area, start address, word length, and the data buffer. ```rust write_area(&mut self, u8, u16, u16, u8, &[u8]) -> Result<(), S7Error> ``` -------------------------------- ### Connect to S7-400/WinAC/PLCSIM PLC Source: https://github.com/mwieczorkiewicz/rust7/blob/main/_autodocs/INDEX.md Use this method for S7-400, WinAC, and PLCSIM PLC families. Requires IP address, rack, and slot. ```rust connect_rack_slot("192.168.0.100", 1, 4)? ``` ```rust connect_rack_slot("192.168.0.100", 0, 0)? ``` ```rust connect_rack_slot("192.168.0.100", 0, 1)? ``` -------------------------------- ### Read Data Area Source: https://github.com/mwieczorkiewicz/rust7/blob/main/_autodocs/INDEX.md Read data from specified memory areas of the PLC. Requires specifying the area, start address, word length, and a buffer for the data. ```rust read_area(&mut self, u8, u16, u16, u8, &mut [u8]) -> Result<(), S7Error> ``` -------------------------------- ### Connect with Different S7 Connection Types Source: https://github.com/mwieczorkiewicz/rust7/blob/main/_autodocs/06-configuration.md Demonstrates how to attempt connections using different S7 client types (CT_PG, CT_OP) when the default connection fails, particularly useful for legacy S7-300 systems. ```rust let mut client = S7Client::new(); // Try default CT_PG if client.connect_s7300("192.168.1.50").is_err() { eprintln!("CT_PG failed; trying CT_OP"); client.set_connection_type(CT_OP)?; client.connect_s7300("192.168.1.50")?; } ``` -------------------------------- ### Build and Test rust7 Project Source: https://github.com/mwieczorkiewicz/rust7/blob/main/CLAUDE.md Standard Cargo commands for building, checking, and testing the rust7 library. Use `cargo check` for faster iteration during development. ```bash cargo build cargo check # faster iteration cargo test ``` -------------------------------- ### Write Area - Byte Write Example Source: https://github.com/mwieczorkiewicz/rust7/blob/main/_autodocs/02-read-write-api.md Writes a block of bytes to a specified memory area. The buffer length determines the number of bytes to write. Auto-chunking handles data larger than PDU size. ```rust let data = b"Hello, S7!"; client.write_area(S7_AREA_DB, 1, 0, S7_WL_BYTE, data)?; ``` -------------------------------- ### Read Area - Byte Access Example Source: https://github.com/mwieczorkiewicz/rust7/blob/main/_autodocs/02-read-write-api.md Reads a block of bytes from a specified memory area. The buffer length determines the number of bytes to read. Auto-chunking handles data larger than PDU size. ```rust let mut buf = vec![0u8; 100]; client.read_area(S7_AREA_DB, 10, 0, S7_WL_BYTE, &mut buf)?; println!("Read {} bytes in {} chunks", buf.len(), client.chunks); ``` -------------------------------- ### S7 Connection PDU Length Field Source: https://github.com/mwieczorkiewicz/rust7/blob/main/doc/Documentation.md Represents the Protocol Data Unit (PDU) size negotiated during connection setup. A larger PDU length can reduce the number of round-trips for large data transfers. ```rust pub pdu_length: u16 ``` -------------------------------- ### Read and Write S7 Memory Areas Source: https://github.com/mwieczorkiewicz/rust7/blob/main/_autodocs/00-api-summary.md Use these generic methods for low-level access to any S7 memory area. Ensure you have the correct area, DB number, start offset, word length, and buffer size. ```rust client.read_area(area, db_number, start, wordlen, &mut buffer)?; client.write_area(area, db_number, start, wordlen, &buffer)?; ``` -------------------------------- ### Connect to PLCSIM with Rack/Slot Fallback Source: https://github.com/mwieczorkiewicz/rust7/blob/main/_autodocs/06-configuration.md Attempts to connect to PLCSIM on localhost, first trying slot 0 and falling back to slot 1 if the initial connection fails. Uses `connect_rack_slot()` with IP address, rack, and slot. ```rust let mut client = S7Client::new(); client.set_connection_port(102)?; // Try slot 0 first match client.connect_rack_slot("127.0.0.1", 0, 0) { Ok(_) => println!("Connected to PLCSIM slot 0"), Err(_) => { // Fallback to slot 1 client.connect_rack_slot("127.0.0.1", 0, 1)?; println!("Connected to PLCSIM slot 1"); } } ``` -------------------------------- ### Read/Write Low-Level Area Access Source: https://github.com/mwieczorkiewicz/rust7/blob/main/_autodocs/00-api-summary.md Provides generic methods for reading from and writing to any memory area of the PLC. Requires specifying the memory area, DB number (if applicable), start offset, word length, and a buffer for data. ```APIDOC ## Read/Write Low-Level (all areas) ### `read_area(area: u8, db_number: u16, start: u16, wordlen: u8, buffer: &mut [u8]) -> Result<()>` #### Description Reads data from a specified memory area of the PLC into a buffer. #### Parameters - `area` (u8) - Required - One of S7_AREA_* constants. - `db_number` (u16) - Required - DB number (ignored for non-DB areas). - `start` (u16) - Required - Byte or bit offset. - `wordlen` (u8) - Required - S7_WL_BYTE or S7_WL_BIT. - `buffer` (mutable slice of u8) - Required - Buffer to store read data. ### `write_area(area: u8, db_number: u16, start: u16, wordlen: u8, buffer: &[u8]) -> Result<()>` #### Description Writes data from a buffer to a specified memory area of the PLC. #### Parameters - `area` (u8) - Required - One of S7_AREA_* constants. - `db_number` (u16) - Required - DB number (ignored for non-DB areas). - `start` (u16) - Required - Byte or bit offset. - `wordlen` (u8) - Required - S7_WL_BYTE or S7_WL_BIT. - `buffer` (slice of u8) - Required - Buffer containing data to write. ``` -------------------------------- ### Run Integration Tests Source: https://github.com/mwieczorkiewicz/rust7/blob/main/CLAUDE.md Execute integration tests, which require Docker or Podman. This includes non-SZL and SZL probe tests. ```bash # Integration tests (9 non-SZL tests + 5 SZL probe tests; requires Docker or Podman) cargo test --test integration ``` -------------------------------- ### Increase Connection Timeout Source: https://github.com/mwieczorkiewicz/rust7/blob/main/_autodocs/05-errors.md If the initial connection attempt times out, especially on networks with potential delays, you can increase the client's connection timeout. This example sets a 30-second connect timeout before attempting to establish the S7 connection. ```rust client.set_timeout(30000, 1000, 500)?; // 30s connect timeout client.connect_s71200_1500("192.168.0.100")?; ``` -------------------------------- ### Forward Port 102 to a Usable Port Source: https://github.com/mwieczorkiewicz/rust7/blob/main/_autodocs/05-errors.md When running on Linux and encountering 'Permission denied' for port 102, you can use port forwarding. This example configures the S7 client to use port 2102, assuming port forwarding is set up to redirect traffic from 102 to 2102. ```rust client.set_connection_port(2102)?; // Use port 2102 instead client.connect_s71200_1500("192.168.0.100")?; ``` -------------------------------- ### Conditional Configuration with Environment Variables Source: https://github.com/mwieczorkiewicz/rust7/blob/main/_autodocs/06-configuration.md Configure the S7 client based on environment variables for IP address and port, with default values if variables are not set or invalid. ```rust let mut client = S7Client::new(); let ip = std::env::var("PLC_IP").unwrap_or_else(|_| "127.0.0.1".to_string()); let port = std::env::var("PLC_PORT") .ok() .and_then(|p| p.parse::().ok()) .unwrap_or(102); if port != 102 { client.set_connection_port(port)?; } client.connect_s71200_1500(&ip)?; ``` -------------------------------- ### Connect to LOGO! PLC Source: https://github.com/mwieczorkiewicz/rust7/blob/main/_autodocs/INDEX.md Use this method for LOGO! PLC family. Requires IP address, local TSAP, and remote TSAP. ```rust connect_tsap("192.168.0.100", 0x0100, 0x0201)? ``` -------------------------------- ### Handle SzlReadFailed on SoftPLC Source: https://github.com/mwieczorkiewicz/rust7/blob/main/_autodocs/05-errors.md The SZL read operation, used for fetching CPU information, is not supported by all PLC firmwares, notably the fbarresi/softplc Docker image. This example uses conditional compilation to skip SZL operations when running tests or in environments where it's known to fail, preventing errors. ```rust // Conditional compilation #[cfg(not(test))] { match client.read_cpu_info() { Ok(info) => println!("Module: {}", info.module_type_name), Err(S7Error::SzlReadFailed) => eprintln!("PLC firmware does not support SZL"), Err(e) => eprintln!("Error: {}", e), } } ``` -------------------------------- ### Validate S7 Client Configuration Before Connect Source: https://github.com/mwieczorkiewicz/rust7/blob/main/_autodocs/06-configuration.md Perform assertions to check the initial state of the S7 client (e.g., PDU length, connection status) before applying configuration and connecting. ```rust let mut client = S7Client::new(); // Validate parameters before connecting assert!(client.pdu_length == 0, "PDU should be unset before connect"); assert!(!client.connected, "Should start disconnected"); // Apply configuration client.set_timeout(3000, 1000, 500)?; client.set_connection_port(102)?; // Now safe to connect client.connect_s71200_1500("192.168.0.100")?; // Post-connect validation assert!(client.connected, "Should be connected"); assert!(client.pdu_length > 0, "PDU should be negotiated"); println!("Negotiated PDU: {} bytes", client.pdu_length); ``` -------------------------------- ### Handle Port 102 Permission Denied (Linux) Source: https://github.com/mwieczorkiewicz/rust7/blob/main/_autodocs/05-errors.md On Linux, binding to privileged ports like 102 requires elevated permissions. This example shows two common solutions: running the application with `sudo` or granting the executable the `cap_net_bind_service` capability, allowing it to bind to port 102 without root privileges. ```bash sudo cargo run ``` ```bash sudo setcap cap_net_bind_service=+ep ./target/debug/my_app ./target/debug/my_app # Now runs without sudo ```