modbus_iiot/core/
modbustelegram.rs1
2
3use core::consts::*;
4use core::datatransformation::*;
5
6pub struct ModbusTelegram
9{
10 transaction_identifier : u16,
11 unit_identifier : u8,
12 function_code : u8,
13 payload : Vec< u8 >,
14 expected_bytes : u8
15}
16
17impl ModbusTelegram
18{
19 pub fn new ( transaction_identifier : u16, unit_identifier : u8, function_code : u8, payload : &Vec< u8 >, expected_bytes : u8 ) -> Option< ModbusTelegram >
20 {
21 let reply : Option< ModbusTelegram >;
22
23 if transaction_identifier > 0x0000 && function_code > 0x00
24 {
25 reply = Some(
26 ModbusTelegram
27 {
28 transaction_identifier : transaction_identifier,
29 unit_identifier : unit_identifier,
30 function_code : function_code,
31 payload : payload.clone (),
32 expected_bytes : expected_bytes
33 }
34 );
35 }
36 else
37 {
38 reply = None;
39 }
40
41 return reply;
42 }
43
44 pub fn new_from_bytes ( bytes : &Vec< u8 > ) -> Option< ModbusTelegram >
45 {
46 let reply : Option< ModbusTelegram >;
47
48 if bytes.len () > 9
49 {
50 let response_transaction_identifier : Option< u16 > = extract_word_from_bytearray ( &bytes,
51 0 );
52 let response_unit_identifier : Option< u8 > = extract_byte_from_bytearray ( &bytes,
53 6 );
54 let response_function_code : Option< u8 > = extract_byte_from_bytearray ( &bytes,
55 7 );
56 let function_code : u8 = response_function_code.unwrap ();
57 let response_payload : Option< Vec< u8 > > = extract_payload_by_function_code ( function_code,
58 &bytes );
59
60 if response_transaction_identifier.is_some () &&
61 response_unit_identifier.is_some () &&
62 response_payload.is_some ()
63 {
64 reply = Some(
65 ModbusTelegram
66 {
67 transaction_identifier : response_transaction_identifier.unwrap (),
68 unit_identifier : response_unit_identifier.unwrap (),
69 function_code : function_code,
70 payload : response_payload.unwrap (),
71 expected_bytes : 0x00
72 }
73 );
74 }
75 else
76 {
77 reply = None;
78 }
79 }
80 else
81 {
82 reply = None;
83 }
84
85 return reply;
86 }
87
88 pub fn get_bytes ( &self ) -> Option< Vec< u8 > >
89 {
90 let mut reply : Vec< u8 > = vec![];
91
92 let length_for_header : u16 = self.payload.len () as u16 + MODBUS_UNIT_IDENTIFIER_LENGTH + MODBUS_FUNCTION_CODE_LENGTH;
93
94 append_word_to_bytearray ( &mut reply,
95 self.transaction_identifier );
96 append_word_to_bytearray ( &mut reply,
97 MODBUS_PROTOCOL_IDENTIFIER_TCP );
98 append_word_to_bytearray ( &mut reply,
99 length_for_header );
100 append_byte_to_bytearray ( &mut reply,
101 self.unit_identifier );
102 append_byte_to_bytearray ( &mut reply,
103 self.function_code );
104 append_bytearray_to_bytearray ( &mut reply,
105 &self.payload );
106
107 return Some( reply );
108 }
109
110 pub fn get_expected_byte_count ( &self ) -> Option< u8 >
111 {
112 let reply : Option< u8 >;
113
114 if self.expected_bytes > MODBUS_HEADER_SIZE
115 {
116 reply = Some( self.expected_bytes );
117 }
118 else
119 {
120 reply = None;
121 }
122
123 return reply;
124 }
125
126 pub fn get_function_code ( &self ) -> Option< u8 >
127 {
128 let reply : Option< u8 >;
129
130 if self.function_code > 0x00
131 {
132 reply = Some( self.function_code );
133 }
134 else
135 {
136 reply = None;
137 }
138
139 return reply;
140 }
141
142 pub fn get_payload ( &self ) -> Option< Vec< u8 > >
143 {
144 return Some( self.payload.clone () );
145 }
146}
147
148#[test]
151fn test_extract_payload_by_function_code ()
152{
153 let mut test_data_1 : Vec< u8 > = vec![];
154 test_data_1.push ( 0x00 ) ; test_data_1.push ( 0xA0 ); test_data_1.push ( 0x00 ); test_data_1.push ( 0x00 ); test_data_1.push ( 0x00 ); test_data_1.push ( 0x09 ); test_data_1.push ( 0x01 ); test_data_1.push ( 0x03 ); test_data_1.push ( 0x06 ); test_data_1.push ( 0xF0 ); test_data_1.push ( 0x0F ); test_data_1.push ( 0x00 ); test_data_1.push ( 0xFF ); test_data_1.push ( 0xFF ); test_data_1.push ( 0x00 ); let result_data_1 : Option< Vec< u8 > > = extract_payload_by_function_code ( 0x03,
171 &test_data_1 );
172 assert! ( result_data_1.is_some () );
173
174 let result_bytes_1 : Vec< u8 > = result_data_1.unwrap ();
175 assert_eq! ( result_bytes_1.len (), 7 );
176 assert_eq! ( result_bytes_1[ 0 ], 0x06 );
177 assert_eq! ( result_bytes_1[ 1 ], 0xF0 );
178 assert_eq! ( result_bytes_1[ 2 ], 0x0F );
179 assert_eq! ( result_bytes_1[ 3 ], 0x00 );
180 assert_eq! ( result_bytes_1[ 4 ], 0xFF );
181 assert_eq! ( result_bytes_1[ 5 ], 0xFF );
182 assert_eq! ( result_bytes_1[ 6 ], 0x00 );
183
184 let mut test_data_2 : Vec< u8 > = vec![];
185 test_data_2.push ( 0x00 ); test_data_2.push ( 0xA0 ); test_data_2.push ( 0x00 ); test_data_2.push ( 0x00 ); test_data_2.push ( 0x00 ); test_data_2.push ( 0x06 ); test_data_2.push ( 0x01 ); test_data_2.push ( 0x10 ); test_data_2.push ( 0x01 ); test_data_2.push ( 0x00 ); test_data_2.push ( 0x00 ); test_data_2.push ( 0x10 ); let result_data_2 : Option< Vec< u8 > > = extract_payload_by_function_code ( 0x10,
199 &test_data_2 );
200 assert! ( result_data_2.is_some () );
201
202 let result_bytes_2 : Vec< u8 > = result_data_2.unwrap ();
203 assert_eq! ( result_bytes_2.len (), 4 );
204 assert_eq! ( result_bytes_2[ 0 ], 0x01 );
205 assert_eq! ( result_bytes_2[ 1 ], 0x00 );
206 assert_eq! ( result_bytes_2[ 2 ], 0x00 );
207 assert_eq! ( result_bytes_2[ 3 ], 0x10 );
208}
209
210fn extract_payload_by_function_code ( function_code : u8, bytes : &Vec< u8 > ) -> Option< Vec< u8 > >
211{
212 let reply : Option< Vec< u8 > >;
213
214 match function_code
215 {
216 0x01 => { reply = extract_payload_with_byte_count ( &bytes ); }
217 0x02 => { reply = extract_payload_with_byte_count ( &bytes ); }
218 0x03 => { reply = extract_payload_with_byte_count ( &bytes ); }
219 0x04 => { reply = extract_payload_with_byte_count ( &bytes ); }
220 0x05 => { reply = extract_payload_without_byte_count ( &bytes ); }
221 0x06 => { reply = extract_payload_without_byte_count ( &bytes ); }
222 0x0F => { reply = extract_payload_without_byte_count ( &bytes ); }
223 0x10 => { reply = extract_payload_without_byte_count ( &bytes ); }
224 _ => { reply = None; }
225 }
226
227 return reply;
228}
229
230#[test]
233fn test_extract_payload_with_byte_count ()
234{
235 let mut test_data : Vec< u8 > = vec![];
236
237 test_data.push ( 0x00 ); test_data.push ( 0xA0 ); test_data.push ( 0x00 ); test_data.push ( 0x00 ); test_data.push ( 0x00 ); test_data.push ( 0x09 ); test_data.push ( 0x01 ); test_data.push ( 0x03 ); test_data.push ( 0x06 ); test_data.push ( 0xF0 ); test_data.push ( 0x0F ); test_data.push ( 0x00 ); test_data.push ( 0xFF ); test_data.push ( 0xFF ); test_data.push ( 0x00 ); let result_data : Option< Vec< u8 > > = extract_payload_with_byte_count ( &test_data );
254 assert! ( result_data.is_some () );
255
256 let result_bytes : Vec< u8 > = result_data.unwrap ();
257 assert_eq! ( result_bytes.len (), 7 );
258 assert_eq! ( result_bytes[ 0 ], 0x06 );
259 assert_eq! ( result_bytes[ 1 ], 0xF0 );
260 assert_eq! ( result_bytes[ 2 ], 0x0F );
261 assert_eq! ( result_bytes[ 3 ], 0x00 );
262 assert_eq! ( result_bytes[ 4 ], 0xFF );
263 assert_eq! ( result_bytes[ 5 ], 0xFF );
264 assert_eq! ( result_bytes[ 6 ], 0x00 );
265}
266
267fn extract_payload_with_byte_count ( bytes : &Vec< u8 > ) -> Option< Vec< u8 > >
268{
269 let reply : Option< Vec< u8 > >;
270
271 let byte_count : Option< u8 > = extract_byte_from_bytearray ( &bytes,
272 8 );
273 let count : u8 = byte_count.unwrap () + 1;
274
275 reply = extract_bytes_from_bytearray ( &bytes,
276 8,
277 count );
278
279 return reply;
280}
281
282#[test]
285fn test_extract_payload_without_byte_count ()
286{
287 let mut test_data : Vec< u8 > = vec![];
288
289 test_data.push ( 0x00 ) ; test_data.push ( 0xA0 ); test_data.push ( 0x00 ); test_data.push ( 0x00 ); test_data.push ( 0x00 ); test_data.push ( 0x06 ); test_data.push ( 0x01 ); test_data.push ( 0x10 ); test_data.push ( 0x01 ); test_data.push ( 0x00 ); test_data.push ( 0x00 ); test_data.push ( 0x10 ); let result_data : Option< Vec< u8 > > = extract_payload_without_byte_count ( &test_data );
303 assert! ( result_data.is_some () );
304
305 let result_bytes : Vec< u8 > = result_data.unwrap ();
306 assert_eq! ( result_bytes.len (), 4 );
307 assert_eq! ( result_bytes[ 0 ], 0x01 );
308 assert_eq! ( result_bytes[ 1 ], 0x00 );
309 assert_eq! ( result_bytes[ 2 ], 0x00 );
310 assert_eq! ( result_bytes[ 3 ], 0x10 );
311}
312
313fn extract_payload_without_byte_count ( bytes : &Vec< u8 > ) -> Option< Vec< u8 > >
314{
315 let reply : Option< Vec< u8 > >;
316
317 let byte_count : u8 = bytes.len () as u8 - MODBUS_HEADER_SIZE - 1; reply = extract_bytes_from_bytearray ( &bytes,
320 8,
321 byte_count );
322
323 return reply;
324}
325
326#[test]
329fn test_verify_function_code ()
330{
331 let l_payload : Vec< u8 > = vec![ 0x00, 0xFF, 0x00, 0x0A ];
332
333 let test_data_request : Option< ModbusTelegram > = ModbusTelegram::new ( 0x00A0,
334 0x01,
335 0x01,
336 &l_payload,
337 0x00 );
338 assert! ( test_data_request.is_some () );
339
340 let test_data_response : Option< ModbusTelegram > = ModbusTelegram::new ( 0x00A0,
341 0x01,
342 0x01,
343 &l_payload,
344 0x00 );
345 assert! ( test_data_response.is_some () );
346
347 let is_equal : bool = verify_function_code ( &test_data_request.unwrap (),
348 &test_data_response.unwrap () );
349 assert! ( is_equal );
350}
351
352pub fn verify_function_code ( request_telegram : &ModbusTelegram, response_telegram : &ModbusTelegram ) -> bool
353{
354 let mut reply : bool = false;
355
356 if let Some( function_code_request ) = request_telegram.get_function_code ()
357 {
358 if let Some( function_code_response ) = response_telegram.get_function_code ()
359 {
360 if function_code_request == function_code_response
361 {
362 reply = true;
363 }
364 }
365 }
366
367 return reply;
368}