@@ -2,7 +2,7 @@ use std::io;
22
33use crate :: cip:: CipError ;
44use crate :: client:: ForwardOpenError ;
5- use crate :: types:: { CipValue , SymbolInfo } ;
5+ use crate :: types:: { CipValue , IdentityInfo , SymbolInfo } ;
66use crate :: MultiResult ;
77
88pub trait ConnectionManagement {
@@ -70,6 +70,11 @@ pub trait TagReadWrite {
7070 self . read_object_attributes ( 0x01 , 0x01 ) . await
7171 }
7272
73+ async fn read_identity ( & mut self ) -> Result < IdentityInfo , CipError > {
74+ let raw = self . read_identity_attributes ( ) . await ?;
75+ IdentityInfo :: decode ( & raw ) . map_err ( |_| CipError :: VendorSpecific ( 0xFC ) )
76+ }
77+
7378 async fn read_bool ( & mut self , tag : & str ) -> Result < bool , CipError > ;
7479 async fn read_sint ( & mut self , tag : & str ) -> Result < i8 , CipError > ;
7580 async fn read_int ( & mut self , tag : & str ) -> Result < i16 , CipError > ;
@@ -108,3 +113,128 @@ pub trait MultipleServicePacket {
108113pub trait SymbolBrowsing {
109114 async fn browse_symbols ( & mut self ) -> Result < Vec < SymbolInfo > , CipError > ;
110115}
116+
117+ #[ cfg( test) ]
118+ mod tests {
119+ use super :: * ;
120+
121+ struct StubIdentityClient {
122+ raw_attributes : Vec < u8 > ,
123+ }
124+
125+ #[ async_trait:: async_trait]
126+ impl TagReadWrite for StubIdentityClient {
127+ async fn read_tag ( & mut self , _: & str ) -> Result < CipValue , CipError > {
128+ Err ( CipError :: VendorSpecific ( 0xFF ) )
129+ }
130+
131+ async fn write_tag ( & mut self , _: & str , _: CipValue ) -> Result < ( ) , CipError > {
132+ Err ( CipError :: VendorSpecific ( 0xFF ) )
133+ }
134+
135+ async fn read_tag_multi ( & mut self , _: & str , _: usize ) -> Result < Vec < CipValue > , CipError > {
136+ Err ( CipError :: VendorSpecific ( 0xFF ) )
137+ }
138+
139+ async fn write_tag_multi ( & mut self , _: & str , _: & [ CipValue ] ) -> Result < ( ) , CipError > {
140+ Err ( CipError :: VendorSpecific ( 0xFF ) )
141+ }
142+
143+ async fn read_object_attribute (
144+ & mut self ,
145+ _: u8 ,
146+ _: u8 ,
147+ _: u8 ,
148+ ) -> Result < CipValue , CipError > {
149+ Err ( CipError :: VendorSpecific ( 0xFF ) )
150+ }
151+
152+ async fn read_object_attributes ( & mut self , _: u8 , _: u8 ) -> Result < Vec < u8 > , CipError > {
153+ Ok ( self . raw_attributes . clone ( ) )
154+ }
155+
156+ async fn read_bool ( & mut self , _: & str ) -> Result < bool , CipError > {
157+ Err ( CipError :: VendorSpecific ( 0xFF ) )
158+ }
159+
160+ async fn read_sint ( & mut self , _: & str ) -> Result < i8 , CipError > {
161+ Err ( CipError :: VendorSpecific ( 0xFF ) )
162+ }
163+
164+ async fn read_int ( & mut self , _: & str ) -> Result < i16 , CipError > {
165+ Err ( CipError :: VendorSpecific ( 0xFF ) )
166+ }
167+
168+ async fn read_dint ( & mut self , _: & str ) -> Result < i32 , CipError > {
169+ Err ( CipError :: VendorSpecific ( 0xFF ) )
170+ }
171+
172+ async fn read_real ( & mut self , _: & str ) -> Result < f32 , CipError > {
173+ Err ( CipError :: VendorSpecific ( 0xFF ) )
174+ }
175+
176+ async fn read_string ( & mut self , _: & str ) -> Result < String , CipError > {
177+ Err ( CipError :: VendorSpecific ( 0xFF ) )
178+ }
179+
180+ async fn write_bool ( & mut self , _: & str , _: bool ) -> Result < ( ) , CipError > {
181+ Err ( CipError :: VendorSpecific ( 0xFF ) )
182+ }
183+
184+ async fn write_sint ( & mut self , _: & str , _: i8 ) -> Result < ( ) , CipError > {
185+ Err ( CipError :: VendorSpecific ( 0xFF ) )
186+ }
187+
188+ async fn write_int ( & mut self , _: & str , _: i16 ) -> Result < ( ) , CipError > {
189+ Err ( CipError :: VendorSpecific ( 0xFF ) )
190+ }
191+
192+ async fn write_dint ( & mut self , _: & str , _: i32 ) -> Result < ( ) , CipError > {
193+ Err ( CipError :: VendorSpecific ( 0xFF ) )
194+ }
195+
196+ async fn write_real ( & mut self , _: & str , _: f32 ) -> Result < ( ) , CipError > {
197+ Err ( CipError :: VendorSpecific ( 0xFF ) )
198+ }
199+
200+ async fn write_string ( & mut self , _: & str , _: & str ) -> Result < ( ) , CipError > {
201+ Err ( CipError :: VendorSpecific ( 0xFF ) )
202+ }
203+ }
204+
205+ #[ tokio:: test]
206+ async fn test_read_identity_default_impl ( ) {
207+ let mut raw = Vec :: new ( ) ;
208+ raw. extend_from_slice ( & 0x1234u16 . to_le_bytes ( ) ) ;
209+ raw. extend_from_slice ( & 0x5678u16 . to_le_bytes ( ) ) ;
210+ raw. extend_from_slice ( & 0x9ABCu16 . to_le_bytes ( ) ) ;
211+ raw. extend_from_slice ( & [ 0x01 , 0x02 ] ) ;
212+ raw. extend_from_slice ( & 0x3344u16 . to_le_bytes ( ) ) ;
213+ raw. extend_from_slice ( & 0x11223344u32 . to_le_bytes ( ) ) ;
214+
215+ let product_name = b"TestProduct" ;
216+ raw. extend_from_slice ( & ( product_name. len ( ) as u16 ) . to_le_bytes ( ) ) ;
217+ raw. extend_from_slice ( product_name) ;
218+ raw. extend ( std:: iter:: repeat_n ( 0 , 82 - product_name. len ( ) ) ) ;
219+
220+ raw. push ( 0x05 ) ;
221+
222+ let mut client = StubIdentityClient {
223+ raw_attributes : raw,
224+ } ;
225+ let identity = client
226+ . read_identity ( )
227+ . await
228+ . expect ( "read_identity should succeed" ) ;
229+
230+ assert_eq ! ( identity. vendor_id, 0x1234 ) ;
231+ assert_eq ! ( identity. device_type, 0x5678 ) ;
232+ assert_eq ! ( identity. product_code, 0x9ABC ) ;
233+ assert_eq ! ( identity. revision_major, 0x01 ) ;
234+ assert_eq ! ( identity. revision_minor, 0x02 ) ;
235+ assert_eq ! ( identity. status, 0x3344 ) ;
236+ assert_eq ! ( identity. serial_number, 0x11223344 ) ;
237+ assert_eq ! ( identity. product_name, "TestProduct" ) ;
238+ assert_eq ! ( identity. state, 0x05 ) ;
239+ }
240+ }
0 commit comments