joylei / eip-rs Goto Github PK
View Code? Open in Web Editor NEWrseip - EIP&CIP client in pure Rust, for generic CIP and AB PLC
License: MIT License
rseip - EIP&CIP client in pure Rust, for generic CIP and AB PLC
License: MIT License
Hi my name is Francisco, I'm from Brazil and I am a industrial automation engineer. I'm a beginner rust user. I working in a project to collect data from 4 logix controllers and I'm using yours lib. I can connect with 1 controller using the default port segment, but in my case, the other 3 controllers are connected in a 1756-EN2T module, so I have:
The backplane, on slot 0 1756-L82ES (172.16.1.130), on slot 6 1756-EN2T (192.168.0.1) where I have the other 3 controllers, connected on another backplane by 1756-EN2TR on slot 3 (192.168.0.2). Is it possible to do that communication? Could you help me?
I was just wondering how I would read an address like O:1/0
from a SLC 500 style PLC. Trying to use something like this let tag = EPath::parse_tag("O:1/0")?;
does not work.
Hi,
I really appreciate this crate. Thank you for putting it together.
I am new to Ethernet/IP and I have a question.
When trying to read float type tags, I get a compiler error saying that Encode Decode are not implemented for f32. What's the best way to read and write f32 values for REAL type tags on AB PLCs?
Thanks
unresolved import
futures_util::SinkExt``
When cloning, the library itself builds ok though.
let template = client.find_template(tag_info.1).await?;
println!("template instance:\n{:?}", template);
These statements work for a small (<500 bytes) templates, but do not work for a large (>500 bytes) templates:
let info = client.read_template(&template).call().await?;
println!("template definition:\n{:?}", info);
Can eip-rs Read and Write UDTs?
I need a grab a UDT instance from my CompactLogix PLCs, can that be done? And then Mapped to a struct?
Example UDT on PLC
- Type: MyUDT
- MyDint1 : DINT
- MyDint2: DINT
- MyString1 : STRING
- MyString2 : STRING
Path to an instance on PLC that is in Program1
\Program1.MyUdtInstance1
Rust Type:
struct MyUDT {
MyDint1: i32,
MyDint2: i32,
MyString1 : String
MyString2 : String
}
I was not able to read a tag in a controller with this command:
This is the output:
read tag...Connection { addr: xx.xx.xx.xx:44818, origin_options: OpenOptions { o_t_connection_id: 0, t_o_connection_id: 0, priority_tick_time: 3, timeout_ticks: 250, connection_serial_number: 6332, vendor_id: 255, originator_serial_number: 4294967295, o_t_rpi: 16960, t_o_rpi: 16960, timeout_multiplier: 3, connection_path: EPath([Port(PortSegment { port: 1, link: b"\0" }), Class(2), Instance(1)]), o_t_params: ConnectionParameters { redundant_owner: false, connection_type: P2P, variable_length: Fixed, priority: High, connection_size: 504 }, t_o_params: ConnectionParameters { redundant_owner: false, connection_type: P2P, variable_length: Fixed, priority: High, connection_size: 504 }, transport_direction: Server, transport_class: Class3, transport_trigger: Application, large_open: false }, connected_options: None, service: None, seq_id: 0 }
read tag...EPath([Symbol("Cfg_LoSeverity")])
Error: Custom { kind: "custom", msg: "forward open failed" }
I have worked through the example you provided in the ReadMe, and it works great! I can read/write tags without a hitch.
The issue arises when I attempt to create a background task to handle the reading/writing of tags. Rust Analyzer gives me the following error:
future cannot be sent between threads safely
the trait `std::marker::Send` is not implemented for `dyn std::future::Future<Output = Result<rseip::client::ab_eip::TagValue<i32>, ClientError>>`rustc
[main.rs(18, 32): ]()future is not `Send` as it awaits another future which is not `Send`
[spawn.rs(127, 21): ]()required by a bound in `tokio::spawn`
However, in the docs, it specifically says that ClientError is Send and TagValue is Send so long as T is also Send. This might just be my inexperience with tokio, but I am wondering if you could shed some light on how to do this properly.
Here is my sample code:
use rseip::client::ab_eip::*;
use rseip::precludes::*;
#[tokio::main]
async fn main(){
tokio::spawn(async move {
background().await;
});
}
async fn background() -> 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(())
}
Thank you in advance!
template instance:
Template { instance_id: 1575, handle: 13998, member_count: 233, object_size: 1411, struct_size: 1868 }
thread 'main' panicked at 'assertion failed: self.remaining() >= dst.len()', ../.cargo/registry/src/github.com-1ecc6299db9ec823/bytes-1.1.0/src/buf/buf_impl.rs:253:9
stack backtrace:
0: rust_begin_unwind
at /rustc/6a705566166debf5eff88c57140df607fa409aaa/library/std/src/panicking.rs:584:5
1: core::panicking::panic_fmt
at /rustc/6a705566166debf5eff88c57140df607fa409aaa/library/core/src/panicking.rs:143:14
2: core::panicking::panic
at /rustc/6a705566166debf5eff88c57140df607fa409aaa/library/core/src/panicking.rs:48:5
3: bytes::buf::buf_impl::Buf::copy_to_slice
at ../.cargo/registry/src/github.com-1ecc6299db9ec823/bytes-1.1.0/src/buf/buf_impl.rs:253:9
4: bytes::buf::buf_impl::Buf::get_u16_le
at ../.cargo/registry/src/github.com-1ecc6299db9ec823/bytes-1.1.0/src/buf/buf_impl.rs:354:9
5: <rseip::client::ab_eip::template::decoder::DefaultDefinitionDecoder as rseip::client::ab_eip::template::decoder::DefinitionDecoder>::partial_decode
at ./src/client/ab_eip/template/decoder.rs:60:39
6: rseip::client::ab_eip::template::TemplateRead<T,D>::call::{{closure}}
at ./src/client/ab_eip/template.rs:197:13
7: <core::future::from_generator::GenFuture as core::future::future::Future>::poll
at /rustc/6a705566166debf5eff88c57140df607fa409aaa/library/core/src/future/mod.rs:91:19
8: rseip::main::{{closure}}
at ./src/main.rs:30:54
9: <core::future::from_generator::GenFuture as core::future::future::Future>::poll
at /rustc/6a705566166debf5eff88c57140df607fa409aaa/library/core/src/future/mod.rs:91:19
10: tokio::park::thread::CachedParkThread::block_on::{{closure}}
at ../.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/src/park/thread.rs:263:54
11: tokio::coop::with_budget::{{closure}}
at ../.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/src/coop.rs:102:9
12: std::thread::local::LocalKey::try_with
at /rustc/6a705566166debf5eff88c57140df607fa409aaa/library/std/src/thread/local.rs:413:16
13: std::thread::local::LocalKey::with
at /rustc/6a705566166debf5eff88c57140df607fa409aaa/library/std/src/thread/local.rs:389:9
14: tokio::coop::with_budget
at ../.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/src/coop.rs:95:5
15: tokio::coop::budget
at ../.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/src/coop.rs:72:5
16: tokio::park::thread::CachedParkThread::block_on
at ../.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/src/park/thread.rs:263:31
17: tokio::runtime::enter::Enter::block_on
at ../.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/src/runtime/enter.rs:151:13
18: tokio::runtime::thread_pool::ThreadPool::block_on
at ../.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/src/runtime/thread_pool/mod.rs:73:9
19: tokio::runtime::Runtime::block_on
at ../.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/src/runtime/mod.rs:477:43
20: rseip::main
at ./src/main.rs:33:5
21: core::ops::function::FnOnce::call_once
at /rustc/6a705566166debf5eff88c57140df607fa409aaa/library/core/src/ops/function.rs:227:5
note: Some details are omitted, run with RUST_BACKTRACE=full
for a verbose backtrace.
Have just tried your library, stuck with setting up the dependencies, which tokio should be used?
Would be cool to have examples that can be run out of the box
trying to read the data from omron controller.
Getting this error
Error: custom - cip error: message reply status CIP general status: 1, extended status: 516
timeout
What could be wrong? Type or what? With python I am able to read the data using CPPPO library btw so the problem not related to controller and it's settings
Used the default example and stuck on infinite reading tag with no errors follow...
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.1.2")
.await?
.with_connection_path(PortSegment::default());
let tag = EPath::parse_tag("Temperature")?;
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(())
}
Compiling wintek_rust v0.1.0 (/Users/user/git/foam/project)
Finished dev [unoptimized + debuginfo] target(s) in 0.53s
Running `target/debug/project`
read tag...
The following snippet produces undefined behavior.
use std::io;
use rseip::precludes::{AbEipClient, PortSegment, AbService};
use futures::stream::StreamExt;
async fn init() -> io::Result<()> {
let mut client = AbEipClient::new_host_lookup("10.0.10.70")
.await
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?
.with_connection_path(PortSegment::default());
let tags = client
.list_tag()
.call()
.collect::<Vec<_>>()
.await
.into_iter()
.collect::<Result<Vec<_>, _>>()
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
for tag in tags {
println!("{tag:?}")
}
}
Output:
SymbolInstance { id: 0x01, name: "��\0\0\u{c}\0M", symbol_type: SymbolType { type: "atomic", dims: 0, type_code: 0x69 } }
SymbolInstance { id: 0x02, name: "Rev��\0\0\u{c}\0", symbol_type: SymbolType { type: "atomic", dims: 0, type_code: 0xc4 } }
SymbolInstance { id: 0x03, name: "_Ava��\0\0\u{c}\0M", symbol_type: SymbolType { type: "atomic", dims: 0, type_code: 0x70 } }
SymbolInstance { id: 0x04, name: "Ret�\u{742}\0\0\u{8}\0Man", symbol_type: SymbolType { type: "atomic", dims: 0, type_code: 0x68 } }
SymbolInstance { id: 0x05, name: "\u{2}\0\0\u{c}\0Man_M6_C_Rev��\0\0", symbol_type: SymbolType { type: "struct", dims: 0, instance_id: 0xf83 } }
SymbolInstance { id: 0x06, name: "_C�\u{80}\0\u{c}\0Ma", symbol_type: SymbolType { type: "atomic", dims: 0, type_code: 0xc4 } }
SymbolInstance { id: 0x07, name: "ev��", symbol_type: SymbolType { type: "atomic", dims: 0, type_code: 0xc4 } }
SymbolInstance { id: 0x08, name: "8_C_Rev��\0\u{f}\0Man_Palet_OK_L", symbol_type: SymbolType { type: "atomic", dims: 0, type_code: 0xc4 } }
SymbolInstance { id: 0x09, name: "\0Man_Retroce", symbol_type: SymbolType { type: "atomic", dims: 0, type_code: 0x69 } }
SymbolInstance { id: 0x0a, name: "\0�\0\u{8}\0Marcha_C��\0", symbol_type: SymbolType { type: "atomic", dims: 0, type_code: 0x7e } }
SymbolInstance { id: 0x0b, name: "cuadra_Pla", symbol_type: SymbolType { type: "struct", dims: 0, instance_id: 0xdba } }
SymbolInstance { id: 0x0c, name: "\0\0\u{13}\0Mem_Fi", symbol_type: SymbolType { type: "struct", dims: 0, instance_id: 0xb24 } }
SymbolInstance { id: 0x0d, name: "eta_C��\0\u{f}\0Me", symbol_type: SymbolType { type: "atomic", dims: 0, type_code: 0x69 } }
SymbolInstance { id: 0x0e, name: "OK_L9��\0\u{14}\0Mem_Laye", symbol_type: SymbolType { type: "atomic", dims: 0, type_code: 0x7e } }
SymbolInstance { id: 0x0f, name: "te_C��\0\u{13}\0M", symbol_type: SymbolType { type: "struct", dims: 0, instance_id: 0xb9d } }
thread 'main' panicked at 'byte index 15 is out of bounds of `_Encoder_C��`', library/core/src/fmt/mod.rs:2472:30
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Encoder/Decoder should pass in some context data, as it need to validate buffer size/enforce connection size restriction
I happened across this lib just about the time you made your first commit. I am impressed by the rapid development.
I am wonder what your future plans/goals are for this lib.
I actually started writing some code to use your early work to read the template / structure data out of the processor. I then took another look at the repository, and BAM......already there!!!!! Impressive!!!!
How to use type bytes?
let value: TagValue<Bytes> = client.read_tag(tag).await?;
error[E0412]: cannot find type `Bytes` in this scope
--> src/main.rs:12:25
|
12 | let value: TagValue<Bytes> = client.read_tag(tag.clone()).await?;
| ^^^^^ not found in this scope
|
help: consider importing one of these items
|
1 | use core::str::Bytes;
|
1 | use std::io::Bytes;
|
1 | use std::str::Bytes;
|
I have tried all imports suggested by the compiler but did not succeed
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.