Ethernet/IP (CIP) client in pure Rust, for generic CIP and AB PLC
- Pure Rust Library
- Asynchronous
- Prefer static dispatch
- Extensible
- Explicit Messaging (Connected / Unconnected)
- Open Source
- Read Tag
- Write Tag
- Read Tag Fragmented
- Write Tag Fragmented
- Read Modify Write Tag
- Get Instance Attribute List (list tag)
- Read Template
Add rseip
to your cargo project's dependencies
rseip="0.3"
Please find detailed guides and examples from below sections.
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<i32> = 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.
Add rseip
to your cargo project's dependencies
rseip="0.3"
Then, import modules of rseip
to your project
use rseip::client::ab_eip::*;
use rseip::precludes::*;
Then, create an unconnected client
let mut client = AbEipClient::new_host_lookup("192.168.0.83")
.await?
.with_connection_path(PortSegment::default());
or create a connection
let mut client =
AbEipConnection::new_host_lookup("192.168.0.83", OpenOptions::default()).await?;
let tag = EPath::parse_tag("test_car1_x")?;
println!("read tag...");
let value: TagValue<i32> = client.read_tag(tag.clone()).await?;
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");
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.
To get a single value (atomic/structure), and you know the exact mapped type, do like this
let value: TagValue<MyType> = client.read_tag(tag).await?;
println!("{:?}",value);
To get the tag type, and you do not care about the data part, do like this:
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:
let value: TagValue<Bytes> = client.read_tag(tag).await?;
To iterate values, and you know the exact mapped type, do like this:
let iter: TagValueTypedIter<MyType> = 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:
let iter: TagValueIter = client.read_tag(tag).await?;
println!("{:?}", iter.tag_type());
let res = iter.next::<bool>().unwrap();
println!("{:?}", res);
let res = iter.next::<i32>().unwrap();
println!("{:?}", res);
let res = iter.next::<MyType>().unwrap();
println!("{:?}", res);
To read more than 1 elements of an Array
, do like this:
let value: TagValue<Vec<MyType>> = client.read_tag((tag,5_u16)).await?;
println!("{:?}",value);
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:
let value = TagValue {
tag_type: TagType::Dint,
value: 10_i32,
};
client.write_tag(tag, value).await?;
To write raw bytes, do like this:
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:
let items: Vec<MyType> = ...;
let value = TagValue {
tag_type: TagType::Dint,
value: items,
};
client.write_tag(tag, value).await?;
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.
let (tag_type,value):(TagType, i32) = client.read_tag(tag).await?;
client.write_tag(tag, (tag_type, 1_u16, value)).await?;
MIT