Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/joylei/eip-rs

rseip - EIP&CIP client in pure Rust, for generic CIP and AB PLC
https://github.com/joylei/eip-rs

async cip eip industry plc rust

Last synced: 13 days ago
JSON representation

rseip - EIP&CIP client in pure Rust, for generic CIP and AB PLC

Awesome Lists containing this project

README

        

[EN](./README.md) | [中文](./README_zh.md)

# rseip
[![crates.io](https://img.shields.io/crates/v/rseip.svg)](https://crates.io/crates/rseip)
[![docs](https://docs.rs/rseip/badge.svg)](https://docs.rs/rseip)
[![build](https://github.com/joylei/eip-rs/workflows/build/badge.svg?branch=main)](https://github.com/joylei/eip-rs/actions?query=workflow%3A%22build%22)
[![license](https://img.shields.io/crates/l/rseip.svg)](https://github.com/joylei/eip-rs/blob/master/LICENSE)

Ethernet/IP (CIP) client in pure Rust, for generic CIP and AB PLC

## Features

- Pure Rust Library
- Asynchronous
- Prefer static dispatch
- Extensible
- Explicit Messaging (Connected / Unconnected)
- Open Source

### Services Supported for AB PLC

- Read Tag
- Write Tag
- Read Tag Fragmented
- Write Tag Fragmented
- Read Modify Write Tag
- Get Instance Attribute List (list tag)
- Read Template

## How to use

Add `rseip` to your cargo project's dependencies

```toml
rseip="0.3"
```

Please find detailed guides and examples from below sections.

## Example

### Tag Read/Write for Allen-bradley CompactLogIx device

```rust
use anyhow::Result;
use rseip::client::ab_eip::*;
use rseip::precludes::*;

#[tokio::main]
pub async fn main() -> Result<()> {
let mut client = AbEipClient::new_host_lookup("192.168.0.83")
.await?
.with_connection_path(PortSegment::default());
let tag = EPath::parse_tag("test_car1_x")?;
println!("read tag...");
let value: TagValue = client.read_tag(tag.clone()).await?;
println!("tag value: {:?}", value);
client.write_tag(tag, value).await?;
println!("write tag - done");
client.close().await?;
Ok(())
}
```

Please find more examples within [examples](https://github.com/Joylei/eip-rs/tree/main/examples).

## Guides
### Quick start

Add `rseip` to your cargo project's dependencies

```toml
rseip="0.3"
```

Then, import modules of `rseip` to your project
```rust
use rseip::client::ab_eip::*;
use rseip::precludes::*;
```

Then, create an unconnected client
```rust
let mut client = AbEipClient::new_host_lookup("192.168.0.83")
.await?
.with_connection_path(PortSegment::default());
```

or create a connection
```rust
let mut client =
AbEipConnection::new_host_lookup("192.168.0.83", OpenOptions::default()).await?;
```

#### Read from a tag
```rust
let tag = EPath::parse_tag("test_car1_x")?;
println!("read tag...");
let value: TagValue = client.read_tag(tag.clone()).await?;
```
#### Write to a tag
```rust
let tag = EPath::parse_tag("test_car1_x")?;
let value = TagValue {
tag_type: TagType::Dint,
value: 10_i32,
};
client.write_tag(tag, value).await?;
println!("write tag - done");
```

### About `TagValue`, `Decode`, and `Encode`

As you may know, there are atomic types, structure types, and array type of tags. The library provides `Encode` to encode values, `Decode` to decode values, and `TagValue` to manipulate tag data values. The library already implements `Encode` and `Decode` for some rust types: `bool`,`i8`,`u8`,`i16`,`u16`,`i32`,`u32`,`i64`,`u64`,`f32`,`f64`,`i128`,`u128`,`()`,`Option`,`Tuple`,`Vec`,`[T;N]`,`SmallVec`. For structure type, you need to implement `Encode` and `Decode` by yourself.

#### Read

To get a single value (atomic/structure), and you know the exact mapped type, do like this
```rust
let value: TagValue = client.read_tag(tag).await?;
println!("{:?}",value);
```

To get the tag type, and you do not care about the data part, do like this:
```rust
let value: TagValue<()> = client.read_tag(tag).await?;
println!("{:?}",value.tag_type);
```

To get the raw bytes whatever the data part holds, do like this:
```rust
let value: TagValue = client.read_tag(tag).await?;
```

To iterate values, and you know the exact mapped type, do like this:
```rust
let iter: TagValueTypedIter = client.read_tag(tag).await?;
println!("{:?}", iter.tag_type());
while let Some(res) = iter.next(){
println!("{:?}", res);
}
```

To iterate values, and you do not know the exact mapped type, do like this:
```rust
let iter: TagValueIter = client.read_tag(tag).await?;
println!("{:?}", iter.tag_type());
let res = iter.next::().unwrap();
println!("{:?}", res);
let res = iter.next::().unwrap();
println!("{:?}", res);
let res = iter.next::().unwrap();
println!("{:?}", res);
```

To read more than 1 elements of an `Array`, do like this:
```rust
let value: TagValue> = client.read_tag((tag,5_u16)).await?;
println!("{:?}",value);
```

#### Write

You must provide the tag type before you write to a tag. Normally, you can retrieve it by reading the tag. For structure type, you cannot reply on or persist the tag type (so called `structure handle`), it might change because it is a calculated value (CRC based).

To write a single value (atomic/structure), do like this:
```rust
let value = TagValue {
tag_type: TagType::Dint,
value: 10_i32,
};
client.write_tag(tag, value).await?;
```

To write raw bytes, do like this:
```rust
let bytes:&[u8] = &[0,1,2,3];
let value = TagValue {
tag_type: TagType::Dint,
value: bytes,
};
client.write_tag(tag, value).await?;
```

To write multiple values to an array, do like this:
```rust
let items: Vec = ...;
let value = TagValue {
tag_type: TagType::Dint,
value: items,
};
client.write_tag(tag, value).await?;
```

### Moreover

For some reasons, `TagValue` does not work for all type that implements `Encode` or `Decode`.

But you can work without `TagValue`. You can define your own value holder, as long as it implements `Encode` and `Decode`.

For simple cases, `Tuple` should be a good option.
```rust
let (tag_type,value):(TagType, i32) = client.read_tag(tag).await?;
client.write_tag(tag, (tag_type, 1_u16, value)).await?;
```

## License

MIT