#cip #eip #ethernet #industry #codec

rseip

rseip - 纯Rust实现的Ethernet/IP (CIP) 客户端

6 个版本

0.3.1 2022年11月14日
0.3.0 2022年4月16日
0.2.1 2022年3月1日
0.2.0 2022年2月25日
0.1.1 2021年12月9日

#256 in 异步

每月 40 次下载

MIT 许可证

275KB
7K SLoC

EN | 中文

rseip

crates.io docs build license

纯Rust实现的Ethernet/IP (CIP) 客户端,适用于通用CIP和AB PLC

特性

  • 纯Rust库
  • 异步
  • 优先静态调度
  • 可扩展
  • 显式消息(已连接/未连接)
  • 开源

支持的AB PLC服务

  • 读取标签
  • 写入标签
  • 读取碎片化标签
  • 写入碎片化标签
  • 读取/修改/写入标签
  • 获取实例属性列表(标签列表)
  • 读取模板

使用方法

rseip 添加到您的 cargo 项目的依赖中

rseip="0.3"

请从以下部分找到详细的指南和示例。

示例

Allen-bradley CompactLogIx 设备的标签读取/写入

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(())
}

请从 示例 中找到更多示例。

指南

快速入门

rseip 添加到您的 cargo 项目的依赖中

rseip="0.3"

然后,将 rseip 的模块导入到您的项目中

use rseip::client::ab_eip::*;
use rseip::precludes::*;

然后,创建一个未连接客户端

let mut client = AbEipClient::new_host_lookup("192.168.0.83")
    .await?
    .with_connection_path(PortSegment::default());

或创建一个连接

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");

关于 TagValueDecodeEncode

正如您所知,存在原子类型、结构类型和数组类型的标签。库提供了用于编码值的 Encode、用于解码值的 Decode 以及用于操作标签数据值的 TagValue。库已经为一些 Rust 类型实现了 EncodeDecodebooli8u8i16u16i32u32i64u64f32f64i128u128()OptionTupleVec[T;N]SmallVec。对于结构类型,您需要自行实现 EncodeDecode

读取

要获取单个值(原子/结构),并且您知道确切的映射类型,可以这样做

let value: TagValue<MyType> = client.read_tag(tag).await?;
println!("{:?}",value);

要获取标签类型,并且您不关心数据部分,可以这样做

let value: TagValue<()> = client.read_tag(tag).await?;
println!("{:?}",value.tag_type);

要获取原始字节,无论数据部分包含什么,可以这样做

let value: TagValue<Bytes> = client.read_tag(tag).await?;

要迭代值,并且您知道确切的映射类型,可以这样做

let iter: TagValueTypedIter<MyType> = client.read_tag(tag).await?;
println!("{:?}", iter.tag_type());
while let Some(res) = iter.next(){
  println!("{:?}", res);
}

要迭代值,并且您不知道确切的映射类型,可以这样做

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);

要读取 Array 的多个元素,可以这样做

let value: TagValue<Vec<MyType>> = client.read_tag((tag,5_u16)).await?;
println!("{:?}",value);

写入

在向标签写入之前,您必须提供标签类型。通常,您可以通过读取标签来检索它。对于结构类型,您不能依赖于或持久化标签类型(所谓 structure handle),因为它可能会改变,因为它是一个计算值(基于 CRC)。

要写入单个值(原子/结构),可以这样做

let value = TagValue {
  tag_type: TagType::Dint,
  value: 10_i32,
};
client.write_tag(tag, value).await?;

要写入原始字节,可以这样做

let bytes:&[u8] = &[0,1,2,3];
let value = TagValue {
  tag_type: TagType::Dint,
  value: bytes,
};
client.write_tag(tag, value).await?;

要将多个值写入数组,可以这样做

let items: Vec<MyType> = ...;
let value = TagValue {
  tag_type: TagType::Dint,
  value: items,
};
client.write_tag(tag, value).await?;

此外

由于某些原因,TagValue 并不适用于所有实现了 EncodeDecode 的类型。

但您可以在没有 TagValue 的情况下工作。您可以定义自己的值持有器,只要它实现了 EncodeDecode

对于简单的情况,Tuple 应该是一个不错的选择。

let (tag_type,value):(TagType, i32) = client.read_tag(tag).await?;
client.write_tag(tag, (tag_type, 1_u16, value)).await?;

许可

MIT

依赖项

~4–16MB
~157K SLoC