{"id":15725216,"url":"https://github.com/joylei/eip-rs","last_synced_at":"2026-03-04T23:01:53.136Z","repository":{"id":57663561,"uuid":"419579139","full_name":"Joylei/eip-rs","owner":"Joylei","description":"rseip - EIP\u0026CIP client in pure Rust, for generic CIP and AB PLC","archived":false,"fork":false,"pushed_at":"2024-03-21T21:20:01.000Z","size":584,"stargazers_count":59,"open_issues_count":5,"forks_count":6,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-11-16T21:23:44.498Z","etag":null,"topics":["async","cip","eip","industry","plc","rust"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Joylei.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-10-21T04:21:56.000Z","updated_at":"2025-10-20T14:01:07.000Z","dependencies_parsed_at":"2024-10-24T19:07:09.925Z","dependency_job_id":"a3faebf9-c412-42e5-87e6-763912e69107","html_url":"https://github.com/Joylei/eip-rs","commit_stats":{"total_commits":210,"total_committers":3,"mean_commits":70.0,"dds":0.00952380952380949,"last_synced_commit":"16e2236afb65acc9c82ebdcfbdcbba72e93b3887"},"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/Joylei/eip-rs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Joylei%2Feip-rs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Joylei%2Feip-rs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Joylei%2Feip-rs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Joylei%2Feip-rs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Joylei","download_url":"https://codeload.github.com/Joylei/eip-rs/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Joylei%2Feip-rs/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30098086,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-04T22:49:54.894Z","status":"ssl_error","status_checked_at":"2026-03-04T22:49:48.883Z","response_time":59,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["async","cip","eip","industry","plc","rust"],"created_at":"2024-10-03T22:20:04.955Z","updated_at":"2026-03-04T23:01:53.111Z","avatar_url":"https://github.com/Joylei.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"[EN](./README.md) | [中文](./README_zh.md)\n\n# rseip\n[![crates.io](https://img.shields.io/crates/v/rseip.svg)](https://crates.io/crates/rseip)\n[![docs](https://docs.rs/rseip/badge.svg)](https://docs.rs/rseip)\n[![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)\n[![license](https://img.shields.io/crates/l/rseip.svg)](https://github.com/joylei/eip-rs/blob/master/LICENSE)\n\nEthernet/IP (CIP) client in pure Rust, for generic CIP and AB PLC\n\n## Features\n\n- Pure Rust Library\n- Asynchronous\n- Prefer static dispatch\n- Extensible\n- Explicit Messaging (Connected / Unconnected)\n- Open Source\n\n### Services Supported for AB PLC\n\n- Read Tag\n- Write Tag\n- Read Tag Fragmented\n- Write Tag Fragmented\n- Read Modify Write Tag\n- Get Instance Attribute List (list tag)\n- Read Template\n\n## How to use\n\nAdd `rseip` to your cargo project's dependencies\n\n```toml\nrseip=\"0.3\"\n```\n\nPlease find detailed guides and examples from below sections.\n\n\n## Example\n\n### Tag Read/Write for Allen-bradley CompactLogIx device\n\n```rust\nuse anyhow::Result;\nuse rseip::client::ab_eip::*;\nuse rseip::precludes::*;\n\n#[tokio::main]\npub async fn main() -\u003e Result\u003c()\u003e {\n    let mut client = AbEipClient::new_host_lookup(\"192.168.0.83\")\n        .await?\n        .with_connection_path(PortSegment::default());\n    let tag = EPath::parse_tag(\"test_car1_x\")?;\n    println!(\"read tag...\");\n    let value: TagValue\u003ci32\u003e = client.read_tag(tag.clone()).await?;\n    println!(\"tag value: {:?}\", value);\n    client.write_tag(tag, value).await?;\n    println!(\"write tag - done\");\n    client.close().await?;\n    Ok(())\n}\n```\n\nPlease find more examples within [examples](https://github.com/Joylei/eip-rs/tree/main/examples).\n\n## Guides\n### Quick start\n\nAdd `rseip` to your cargo project's dependencies\n\n```toml\nrseip=\"0.3\"\n```\n\nThen, import modules of `rseip` to your project\n```rust\nuse rseip::client::ab_eip::*;\nuse rseip::precludes::*;\n```\n\nThen, create an unconnected client\n```rust\nlet mut client = AbEipClient::new_host_lookup(\"192.168.0.83\")\n    .await?\n    .with_connection_path(PortSegment::default());\n```\n\nor create a connection\n```rust\nlet mut client =\n    AbEipConnection::new_host_lookup(\"192.168.0.83\", OpenOptions::default()).await?;\n```\n\n#### Read from a tag\n```rust\nlet tag = EPath::parse_tag(\"test_car1_x\")?;\nprintln!(\"read tag...\");\nlet value: TagValue\u003ci32\u003e = client.read_tag(tag.clone()).await?;\n```\n#### Write to a tag\n```rust\nlet tag = EPath::parse_tag(\"test_car1_x\")?;\nlet value = TagValue {\n  tag_type: TagType::Dint,\n  value: 10_i32,\n};\nclient.write_tag(tag, value).await?;\nprintln!(\"write tag - done\");\n```\n\n### About `TagValue`, `Decode`, and `Encode`\n\nAs 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.\n\n#### Read\n\nTo get a single value (atomic/structure), and you know the exact mapped type, do like this\n```rust\nlet value: TagValue\u003cMyType\u003e = client.read_tag(tag).await?;\nprintln!(\"{:?}\",value);\n```\n\nTo get the tag type, and you do not care about the data part, do like this:\n```rust\nlet value: TagValue\u003c()\u003e = client.read_tag(tag).await?;\nprintln!(\"{:?}\",value.tag_type);\n```\n\nTo get the raw bytes whatever the data part holds, do like this:\n```rust\nlet value: TagValue\u003cBytes\u003e = client.read_tag(tag).await?;\n```\n\nTo iterate values, and you know the exact mapped type, do like this:\n```rust\nlet iter: TagValueTypedIter\u003cMyType\u003e = client.read_tag(tag).await?;\nprintln!(\"{:?}\", iter.tag_type());\nwhile let Some(res) = iter.next(){\n  println!(\"{:?}\", res);\n}\n```\n\nTo iterate values, and you do not know the exact mapped type, do like this:\n```rust\nlet iter: TagValueIter = client.read_tag(tag).await?;\nprintln!(\"{:?}\", iter.tag_type());\nlet res = iter.next::\u003cbool\u003e().unwrap();\nprintln!(\"{:?}\", res);\nlet res = iter.next::\u003ci32\u003e().unwrap();\nprintln!(\"{:?}\", res);\nlet res = iter.next::\u003cMyType\u003e().unwrap();\nprintln!(\"{:?}\", res);\n```\n\nTo read more than 1 elements of an `Array`, do like this:\n```rust\nlet value: TagValue\u003cVec\u003cMyType\u003e\u003e = client.read_tag((tag,5_u16)).await?;\nprintln!(\"{:?}\",value);\n```\n\n#### Write\n\nYou 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).\n\nTo write a single value (atomic/structure), do like this:\n```rust\nlet value = TagValue {\n  tag_type: TagType::Dint,\n  value: 10_i32,\n};\nclient.write_tag(tag, value).await?;\n```\n\nTo write raw bytes, do like this:\n```rust\nlet bytes:\u0026[u8] = \u0026[0,1,2,3];\nlet value = TagValue {\n  tag_type: TagType::Dint,\n  value: bytes,\n};\nclient.write_tag(tag, value).await?;\n```\n\nTo write multiple values to an array, do like this:\n```rust\nlet items: Vec\u003cMyType\u003e = ...;\nlet value = TagValue {\n  tag_type: TagType::Dint,\n  value: items,\n};\nclient.write_tag(tag, value).await?;\n```\n\n### Moreover\n\nFor some reasons, `TagValue` does not work for all type that implements `Encode` or `Decode`.\n\nBut you can work without `TagValue`. You can define your own value holder, as long as it implements `Encode` and `Decode`.\n\nFor simple cases, `Tuple` should be a good option.\n```rust\nlet (tag_type,value):(TagType, i32) = client.read_tag(tag).await?;\nclient.write_tag(tag, (tag_type, 1_u16, value)).await?;\n```\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjoylei%2Feip-rs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjoylei%2Feip-rs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjoylei%2Feip-rs/lists"}