Skip to main content

S7Client

Struct S7Client 

Source
pub struct S7Client<T: AsyncRead + AsyncWrite + Unpin + Send> { /* private fields */ }

Implementations§

Source§

impl<T: AsyncRead + AsyncWrite + Unpin + Send> S7Client<T>

Source

pub async fn from_transport(transport: T, params: ConnectParams) -> Result<Self>

Source

pub fn request_timeout(&self) -> Duration

Return the current request timeout.

Source

pub async fn get_exec_time(&self) -> u32

Returns the execution time of the last completed S7 operation in milliseconds.

Measures full round-trip: from send to response received. Equivalent to C Cli_GetExecTime.

Source

pub async fn is_connected(&self) -> bool

Returns whether the transport connection is alive.

Set to false when any I/O error is encountered. Equivalent to C Cli_GetConnected.

Source

pub async fn set_request_timeout(&self, timeout: Duration)

Update the request timeout at runtime.

This affects subsequent recv_s7 calls made by this client instance.

Source

pub fn get_param(&self, name: &str) -> Result<Duration>

Read a client parameter by name.

Supported names: "request_timeout", "connect_timeout", "pdu_size".

Source

pub fn set_param(&mut self, name: &str, value: Duration) -> Result<()>

Set a client parameter at runtime.

Supported names: "request_timeout" (Duration).

Source

pub async fn db_read(&self, db: u16, start: u32, length: u16) -> Result<Bytes>

Source

pub async fn read_area( &self, area: Area, db_number: u16, start: u32, element_count: u16, transport: TransportSize, ) -> Result<Bytes>

Read from any PLC area with explicit transport size.

For DB areas use db_read. For Marker/Timer/Counter use this method. Timer (area=Timer, transport=Timer) and Counter (area=Counter, transport=Counter) use element-index addressing (no ×8 shift) and return 2 bytes per element.

Source

pub async fn read_multi_vars( &self, items: &[MultiReadItem], ) -> Result<Vec<Bytes>>

Read multiple PLC regions in one or more S7 PDU exchanges.

Automatically batches items when the item count would exceed the Siemens hard limit of 20 per PDU, or when the encoded request or response would exceed the negotiated PDU size. Returns one Bytes per item in input order.

Unlike db_read, this accepts any Area and TransportSize.

Source

pub async fn write_multi_vars(&self, items: &[MultiWriteItem]) -> Result<()>

Write multiple PLC regions in one or more S7 PDU exchanges.

Automatically batches items when the count or encoded size would exceed the negotiated PDU size or the Siemens hard limit of 20 items per PDU. Returns Ok(()) only when all items are acknowledged with return code 0xFF.

Source

pub async fn db_write(&self, db: u16, start: u32, data: &[u8]) -> Result<()>

Source

pub async fn write_area( &self, area: Area, db_number: u16, start: u32, transport: TransportSize, data: &[u8], ) -> Result<()>

Write to any PLC area with explicit transport size.

For Timer/Counter areas the transport size byte in the request must match the area (0x1D / 0x1C). For Marker use TransportSize::Byte.

Source

pub async fn ab_read( &self, area: Area, db_number: u16, start: u32, length: u16, ) -> Result<Bytes>

Read from any PLC area using absolute addressing.

A convenience wrapper around read_multi_vars for a single area read.

Source

pub async fn ab_write( &self, area: Area, db_number: u16, start: u32, data: &[u8], ) -> Result<()>

Write to any PLC area using absolute addressing.

A convenience wrapper around write_multi_vars for a single area write.

Source

pub async fn mb_read(&self, start: u32, length: u16) -> Result<Bytes>

Read Merker (flag) bytes starting at start, length bytes.

Source

pub async fn mb_write(&self, start: u32, data: &[u8]) -> Result<()>

Write Merker (flag) bytes starting at start.

Source

pub async fn eb_read(&self, start: u32, length: u16) -> Result<Bytes>

Read I/O input (EB) bytes starting at start, length bytes.

Source

pub async fn eb_write(&self, start: u32, data: &[u8]) -> Result<()>

Write I/O input (EB) bytes starting at start.

Source

pub async fn ib_read(&self, start: u32, length: u16) -> Result<Bytes>

Read I/O output (AB) bytes starting at start, length bytes.

Source

pub async fn ib_write(&self, start: u32, data: &[u8]) -> Result<()>

Write I/O output (AB) bytes starting at start.

Source

pub async fn tm_read(&self, start: u32, amount: u16) -> Result<Bytes>

Read amount Timer words starting at timer index start.

Source

pub async fn tm_write(&self, start: u32, data: &[u8]) -> Result<()>

Write Timer S5Time words. data must be amount * 2 bytes (one word per timer).

Source

pub async fn ct_read(&self, start: u32, amount: u16) -> Result<Bytes>

Read amount Counter BCD words starting at counter index start.

Source

pub async fn ct_write(&self, start: u32, data: &[u8]) -> Result<()>

Write Counter BCD words. data must be amount * 2 bytes (one word per counter).

Source

pub async fn read_szl(&self, szl_id: u16, szl_index: u16) -> Result<SzlResponse>

Source

pub async fn read_clock(&self) -> Result<PlcDateTime>

Source

pub async fn set_clock(&self, dt: &PlcDateTime) -> Result<()>

Set the PLC clock (UserData function group 0x47 = clock, subfunction 0x02 = write).

Source

pub async fn set_clock_to_now(&self) -> Result<()>

Set the PLC clock to the host system time.

Uses std::time::SystemTime converted to a PlcDateTime. The weekday field is set to 0 (unknown) since SystemTime does not carry it.

Source

pub async fn force_bit( &self, area: Area, byte_addr: u32, bit: u8, value: bool, ) -> Result<()>

Force a bit in the process image output (Q) or process image input (I).

area must be Area::ProcessOutput (Q) or Area::ProcessInput (I). byte_addr is the byte address, bit is the bit number (0–7). value is true to force to 1, false to force to 0.

For outputs (Q): writes directly to the process image output — effective on the next CPU scan cycle. For inputs (I): writes to the process image input — note that many CPUs will overwrite this on the next scan cycle unless the CPU is in STOP mode or the input is truly “forced” via the CPU’s force table (STEP7 “Force Variables” function).

Source

pub async fn force_byte( &self, area: Area, byte_addr: u32, value: u8, ) -> Result<()>

Force a whole byte in the process image output (Q) or input (I).

Source

pub async fn force_cancel_byte(&self, area: Area, byte_addr: u32) -> Result<()>

Cancel force on a byte by writing 0x00 to it.

Source

pub async fn read_force_list(&self) -> Result<Bytes>

Read the SZL force table (SZL ID 0x0025) — returns raw SZL payload.

Returns an empty Bytes when the CPU reports no forced variables.

Source

pub async fn read_szl_list(&self) -> Result<Vec<u16>>

Read the list of all available SZL IDs from the PLC (SZL ID 0x0000).

Returns a Vec<u16> where each entry is a supported SZL ID.

Source

pub async fn copy_ram_to_rom(&self) -> Result<()>

Copy RAM data to ROM (function 0x43).

Copies the CPU’s work memory to its load memory (retain on power-off).

Source

pub async fn compress(&self) -> Result<()>

Compress the PLC work memory (function 0x42).

Reorganises memory to eliminate fragmentation. The PLC must be in STOP mode before calling this.

Source

pub async fn memory_reset(&self) -> Result<()>

Memory Reset — clears all work memory blocks.

The PLC must be in STOP mode before calling this. After memory reset the CPU will no longer have any OBs, FBs, FCs or DBs; it must be re-programmed before it can be restarted.

Source

pub async fn overall_reset(&self) -> Result<()>

Overall Reset — formats the entire PLC memory (load + work + retain).

More destructive than memory_reset: also wipes the load memory (Flash/RAM card). PLC must be in STOP mode.

Source

pub async fn upload_all_blocks( &self, block_types: &[u8], ) -> Result<Vec<(u8, u16, Vec<u8>)>>

Upload all blocks of given types from the PLC.

Returns a Vec of (block_type, block_number, data) tuples. Pass block_types as a slice of raw type bytes, e.g. &[0x38, 0x41, 0x43, 0x45] for OB, DB, FC, FB.

Source

pub async fn plc_stop(&self) -> Result<()>

Stop the PLC (S7 function code 0x29).

Sends a Job request with no additional data. Returns Ok(()) when the PLC acknowledges the command, or an error if the PLC rejects it (e.g., password-protected or CPU in a non-stoppable state).

Source

pub async fn plc_hot_start(&self) -> Result<()>

Hot-start (warm restart) the PLC (S7 function code 0x28).

A warm restart retains the DB content and retentive memory.

Source

pub async fn plc_cold_start(&self) -> Result<()>

Cold-start (full restart) the PLC (S7 function code 0x2A).

A cold start clears all DBs and non-retentive memory.

Source

pub async fn get_plc_status(&self) -> Result<PlcStatus>

Read the current PLC status via SZL 0x0424.

Returns one of [PlcStatus::Run], [PlcStatus::Stop], or [PlcStatus::Unknown].

Source

pub async fn get_order_code(&self) -> Result<OrderCode>

Read the PLC order code (SZL ID 0x0011).

The order code is a 20-character ASCII string (e.g. "6ES7 317-2EK14-0AB0").

Source

pub async fn get_cpu_info(&self) -> Result<CpuInfo>

Read detailed CPU information (SZL ID 0x001C).

Returns module type, serial number, plant identification, copyright and module name fields pre-parsed from the SZL response. Handles both classic S7-300/400 and S7-1200/1500 response formats.

Source

pub async fn get_cp_info(&self) -> Result<CpInfo>

Read communication processor information (SZL ID 0x0131, index 0x0001).

Returns maximum PDU length, connection count, and baud rates.

Source

pub async fn read_module_list(&self) -> Result<Vec<ModuleEntry>>

Read the rack module list (SZL ID 0x00A0).

Each entry is a 2-byte module type identifier.

Source

pub async fn list_blocks(&self) -> Result<BlockList>

List all blocks in the PLC grouped by type.

Uses UserData function group 0x43 (grBlocksInfo), SubFun 0x01 (ListAll). Response: 7 entries of [Zero(1) BType(1) BCount(2)] = 28 bytes data.

Source

pub async fn list_blocks_of_type(&self, block_type: u8) -> Result<Vec<u16>>

List all block numbers of a given type (grBlocksInfo / SFun_ListBoT = 0x02).

block_type is the raw byte: 0x38=OB, 0x41=DB, 0x42=SDB, 0x43=FC, 0x44=SFC, 0x45=FB, 0x46=SFB. Returns a sorted vec of block numbers.

Source

pub async fn get_ag_block_info( &self, block_type: u8, block_number: u16, ) -> Result<BlockInfo>

Get detailed information about a block stored on the PLC.

block_type should be one of the BlockType discriminant values (e.g. 0x41 for DB, 0x38 for OB).

Source

pub async fn get_pg_block_info( &self, block_type: u8, block_number: u16, ) -> Result<BlockInfo>

Get detailed block information from the PG perspective.

Same fields as get_ag_block_info but the information is from the programming-device viewpoint.

Source

pub fn parse_block_info(data: &[u8]) -> Result<BlockInfo>

Parse block info from raw block bytes obtained via upload or full_upload. No PLC connection required.

Equivalent to C Cli_GetPgBlockInfo offline parsing mode.

Source

pub async fn set_session_password(&self, password: &str) -> Result<()>

Set a session password for protected PLC access.

The password is obfuscated using the S7 nibble-swap + XOR-0x55 algorithm and sent as a Job PDU with function code 0x12. Passwords longer than 8 bytes are truncated.

Source

pub async fn clear_session_password(&self) -> Result<()>

Clear the session password on the PLC (function code 0x11).

Source

pub async fn get_protection(&self) -> Result<Protection>

Read the current protection level (SZL ID 0x0032, index 0x0004).

Returns the protection scheme identifiers and level; password_set is true when the PLC reports a non-empty password.

Source

pub async fn delete_block( &self, block_type: u8, block_number: u16, ) -> Result<()>

Delete a block from the PLC (S7 function code 0x1F).

Source

pub async fn upload(&self, block_type: u8, block_number: u16) -> Result<Vec<u8>>

Upload a PLC block via S7 PI-Upload (function 0x1D).

Returns the raw block bytes in Diagra format (20-byte header + payload). Use [BlockData::from_bytes] to parse the result.

Source

pub async fn full_upload( &self, block_type: u8, block_number: u16, ) -> Result<Vec<u8>>

Full-upload a PLC block including MC7 (executable) code (S7 function 0x1F).

Unlike upload which returns only the header/interface, full_upload returns the complete block including executable code.

Source

pub async fn get_pdu_length(&self) -> u16

Return the negotiated PDU length in bytes.

Source

pub async fn db_get(&self, db_number: u16) -> Result<Vec<u8>>

Upload a DB block (convenience wrapper around upload).

Source

pub async fn download( &self, block_type: u8, block_number: u16, data: &[u8], ) -> Result<()>

Download a block to the PLC (S7 function 0x1E).

data should be in Diagra format (20-byte header + payload, as returned by upload or built via [BlockData::to_bytes]).

Source

pub async fn create_db( &self, db_number: u16, size_bytes: u16, attrs: Option<&BlockAttributes>, ) -> Result<()>

Create a new empty DB on the PLC.

Downloads a minimal zero-filled DB block. The PLC must be in STOP mode or support online DB creation (S7-400 / S7-1500). If attrs is Some, the block attributes are applied before download.

Source

pub async fn compare_blocks( &self, local: &[(u8, u16, Vec<u8>)], report_plc_only: bool, ) -> Result<Vec<(u8, u16, BlockCmpResult)>>

Compare local block data against blocks currently on the PLC.

For each (block_type, block_number, local_bytes) entry in local, uploads the corresponding PLC block and compares CRC-32 checksums. Also reports blocks that exist only on the PLC (missing locally) when report_plc_only is true.

Source

pub async fn db_fill(&self, db_number: u16, value: u8) -> Result<()>

Fill a DB with a constant byte value.

Uses get_ag_block_info to determine the DB size, then writes every byte to value.

Source§

impl S7Client<TcpTransport>

Source

pub async fn connect(addr: SocketAddr, params: ConnectParams) -> Result<Self>

Source

pub async fn reconnect(&self) -> Result<()>

Re-establish the TCP connection and S7 negotiate handshake after a disconnect.

On success the client resumes normal operation. Returns an error if the reconnection attempt fails (caller may retry with back-off).

Source§

impl S7Client<UdpTransport>

Source

pub async fn connect_udp( addr: SocketAddr, params: ConnectParams, ) -> Result<Self>

Connect to a PLC using UDP transport.

Auto Trait Implementations§

§

impl<T> !Freeze for S7Client<T>

§

impl<T> !RefUnwindSafe for S7Client<T>

§

impl<T> Send for S7Client<T>

§

impl<T> Sync for S7Client<T>

§

impl<T> Unpin for S7Client<T>

§

impl<T> UnsafeUnpin for S7Client<T>
where T: UnsafeUnpin,

§

impl<T> UnwindSafe for S7Client<T>
where T: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.