Skip to content

Commit c9bcdaf

Browse files
committed
add Connection Manager diagnostics using generic CIP object read API
1 parent 5e62919 commit c9bcdaf

3 files changed

Lines changed: 76 additions & 2 deletions

File tree

src/client/traits.rs

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::io;
22

33
use crate::cip::CipError;
44
use crate::client::ForwardOpenError;
5-
use crate::types::{CipValue, IdentityInfo, SymbolInfo};
5+
use crate::types::{CipValue, ConnectionManagerInfo, IdentityInfo, SymbolInfo};
66
use crate::MultiResult;
77

88
pub trait ConnectionManagement {
@@ -75,6 +75,22 @@ pub trait TagReadWrite {
7575
IdentityInfo::decode(&raw).map_err(|_| CipError::VendorSpecific(0xFC))
7676
}
7777

78+
async fn read_connection_manager_attribute(
79+
&mut self,
80+
attribute_id: u8,
81+
) -> Result<CipValue, CipError> {
82+
self.read_object_attribute(0x06, 0x01, attribute_id).await
83+
}
84+
85+
async fn read_connection_manager_attributes(&mut self) -> Result<Vec<u8>, CipError> {
86+
self.read_object_attributes(0x06, 0x01).await
87+
}
88+
89+
async fn read_connection_manager(&mut self) -> Result<ConnectionManagerInfo, CipError> {
90+
let raw = self.read_connection_manager_attributes().await?;
91+
ConnectionManagerInfo::decode(&raw).map_err(|_| CipError::VendorSpecific(0xFC))
92+
}
93+
7894
async fn read_bool(&mut self, tag: &str) -> Result<bool, CipError>;
7995
async fn read_sint(&mut self, tag: &str) -> Result<i8, CipError>;
8096
async fn read_int(&mut self, tag: &str) -> Result<i16, CipError>;
@@ -237,4 +253,24 @@ mod tests {
237253
assert_eq!(identity.product_name, "TestProduct");
238254
assert_eq!(identity.state, 0x05);
239255
}
256+
257+
#[tokio::test]
258+
async fn test_read_connection_manager_default_impl() {
259+
let mut raw = Vec::new();
260+
raw.extend_from_slice(&0x0102u16.to_le_bytes());
261+
raw.extend_from_slice(&0x0304u16.to_le_bytes());
262+
raw.extend_from_slice(&0x0506u16.to_le_bytes());
263+
264+
let mut client = StubIdentityClient {
265+
raw_attributes: raw,
266+
};
267+
let info = client
268+
.read_connection_manager()
269+
.await
270+
.expect("read_connection_manager should succeed");
271+
272+
assert_eq!(info.revision, 0x0102);
273+
assert_eq!(info.status, 0x0304);
274+
assert_eq!(info.configuration_capability, 0x0506);
275+
}
240276
}

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,4 @@ pub use client::{
1818
SymbolBrowsing, TagReadWrite,
1919
};
2020

21-
pub use types::{CipType, CipValue, IdentityInfo, MultiResult};
21+
pub use types::{CipType, CipValue, ConnectionManagerInfo, IdentityInfo, MultiResult};

src/types.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,31 @@ impl IdentityInfo {
134134
}
135135
}
136136

137+
#[derive(Debug, Clone, PartialEq)]
138+
pub struct ConnectionManagerInfo {
139+
pub revision: u16,
140+
pub status: u16,
141+
pub configuration_capability: u16,
142+
}
143+
144+
impl ConnectionManagerInfo {
145+
pub fn decode(data: &[u8]) -> Result<Self, &'static str> {
146+
if data.len() < 6 {
147+
return Err("not enough connection manager attribute data");
148+
}
149+
150+
let revision = u16::from_le_bytes([data[0], data[1]]);
151+
let status = u16::from_le_bytes([data[2], data[3]]);
152+
let configuration_capability = u16::from_le_bytes([data[4], data[5]]);
153+
154+
Ok(Self {
155+
revision,
156+
status,
157+
configuration_capability,
158+
})
159+
}
160+
}
161+
137162
impl CipValue {
138163
pub fn type_name(&self) -> &'static str {
139164
match self {
@@ -199,4 +224,17 @@ mod tests {
199224
assert_eq!(identity.product_name, "TestProduct");
200225
assert_eq!(identity.state, 0x05);
201226
}
227+
228+
#[test]
229+
fn test_connection_manager_info_decode() {
230+
let mut raw = Vec::new();
231+
raw.extend_from_slice(&0x0102u16.to_le_bytes());
232+
raw.extend_from_slice(&0x0304u16.to_le_bytes());
233+
raw.extend_from_slice(&0x0506u16.to_le_bytes());
234+
235+
let info = ConnectionManagerInfo::decode(&raw).expect("decode should succeed");
236+
assert_eq!(info.revision, 0x0102);
237+
assert_eq!(info.status, 0x0304);
238+
assert_eq!(info.configuration_capability, 0x0506);
239+
}
202240
}

0 commit comments

Comments
 (0)