11use std:: io;
22
33use crate :: cip:: {
4- build_read_request, build_write_request, decode_cip_response, decode_write_response, CipError ,
4+ build_get_attribute_all_request, build_get_attribute_single_request, build_read_request,
5+ build_write_request, decode_cip_response, decode_write_response, CipError ,
56} ;
67use crate :: client:: { ConnectedMessaging , TagReadWrite , UnconnectedMessaging } ;
78use crate :: types:: CipValue ;
@@ -20,23 +21,9 @@ impl TagReadWrite for EthernetIpClient {
2021 } ;
2122
2223 let res = res. map_err ( |_| CipError :: VendorSpecific ( 0xFF ) ) ?;
24+ let payload = parse_cip_response_payload ( & res) ?;
2325
24- if res. len ( ) < 4 {
25- return Err ( CipError :: VendorSpecific ( 0xFE ) ) ;
26- }
27-
28- let general_status = res[ 2 ] ;
29- if general_status != 0 {
30- return Err ( CipError :: from ( general_status) ) ;
31- }
32-
33- let ext_words = res[ 3 ] as usize ;
34- let data_start = 4 + ext_words * 2 ;
35- if res. len ( ) < data_start {
36- return Err ( CipError :: VendorSpecific ( 0xFD ) ) ;
37- }
38-
39- decode_cip_response ( & res[ data_start..] ) . ok_or ( CipError :: VendorSpecific ( 0xFC ) )
26+ decode_cip_response ( payload) . ok_or ( CipError :: VendorSpecific ( 0xFC ) )
4027 }
4128
4229 async fn write_tag ( & mut self , tag : & str , value : CipValue ) -> Result < ( ) , CipError > {
@@ -66,27 +53,56 @@ impl TagReadWrite for EthernetIpClient {
6653 } ;
6754
6855 let res = res. map_err ( |_| CipError :: VendorSpecific ( 0xFF ) ) ?;
56+ let payload = parse_cip_response_payload ( & res) ?;
6957
70- if res . len ( ) < 4 {
71- return Err ( CipError :: VendorSpecific ( 0xFE ) ) ;
58+ if payload . len ( ) < 2 {
59+ return Err ( CipError :: VendorSpecific ( 0xFD ) ) ;
7260 }
7361
74- let general_status = res[ 2 ] ;
75- if general_status != 0 {
76- return Err ( CipError :: from ( general_status) ) ;
77- }
62+ let type_id = u16:: from_le_bytes ( [ payload[ 0 ] , payload[ 1 ] ] ) ;
63+ let payload = & payload[ 2 ..] ;
7864
79- let ext_words = res [ 3 ] as usize ;
80- let data_start = 4 + ext_words * 2 ;
65+ Ok ( crate :: cip :: decode_cip_data_list ( type_id , payload ) )
66+ }
8167
82- if res. len ( ) < data_start + 2 {
83- return Err ( CipError :: VendorSpecific ( 0xFD ) ) ;
84- }
68+ async fn read_object_attribute (
69+ & mut self ,
70+ class_id : u8 ,
71+ instance_id : u8 ,
72+ attribute_id : u8 ,
73+ ) -> Result < CipValue , CipError > {
74+ let cip =
75+ build_get_attribute_single_request ( class_id, instance_id, attribute_id, self . slot ) ;
8576
86- let type_id = u16:: from_le_bytes ( [ res[ data_start] , res[ data_start + 1 ] ] ) ;
87- let payload = & res[ data_start + 2 ..] ;
77+ let res: io:: Result < Vec < u8 > > = if self . connected {
78+ self . send_unit_data ( cip) . await
79+ } else {
80+ self . send_rr_data ( cip) . await
81+ } ;
8882
89- Ok ( crate :: cip:: decode_cip_data_list ( type_id, payload) )
83+ let res = res. map_err ( |_| CipError :: VendorSpecific ( 0xFF ) ) ?;
84+ let payload = parse_cip_response_payload ( & res) ?;
85+
86+ decode_cip_response ( payload) . ok_or ( CipError :: VendorSpecific ( 0xFC ) )
87+ }
88+
89+ async fn read_object_attributes (
90+ & mut self ,
91+ class_id : u8 ,
92+ instance_id : u8 ,
93+ ) -> Result < Vec < u8 > , CipError > {
94+ let cip = build_get_attribute_all_request ( class_id, instance_id, self . slot ) ;
95+
96+ let res: io:: Result < Vec < u8 > > = if self . connected {
97+ self . send_unit_data ( cip) . await
98+ } else {
99+ self . send_rr_data ( cip) . await
100+ } ;
101+
102+ let res = res. map_err ( |_| CipError :: VendorSpecific ( 0xFF ) ) ?;
103+ let payload = parse_cip_response_payload ( & res) ?;
104+
105+ Ok ( payload. to_vec ( ) )
90106 }
91107
92108 async fn write_tag_multi ( & mut self , tag : & str , values : & [ CipValue ] ) -> Result < ( ) , CipError > {
@@ -182,3 +198,22 @@ impl TagReadWrite for EthernetIpClient {
182198 . await
183199 }
184200}
201+
202+ fn parse_cip_response_payload ( res : & [ u8 ] ) -> Result < & [ u8 ] , CipError > {
203+ if res. len ( ) < 4 {
204+ return Err ( CipError :: VendorSpecific ( 0xFE ) ) ;
205+ }
206+
207+ let general_status = res[ 2 ] ;
208+ if general_status != 0 {
209+ return Err ( CipError :: from ( general_status) ) ;
210+ }
211+
212+ let ext_words = res[ 3 ] as usize ;
213+ let data_start = 4 + ext_words * 2 ;
214+ if res. len ( ) < data_start {
215+ return Err ( CipError :: VendorSpecific ( 0xFD ) ) ;
216+ }
217+
218+ Ok ( & res[ data_start..] )
219+ }
0 commit comments