1use crate::{builder::*, error::*};
2use bytes::{Buf, BufMut, BytesMut};
3use num_enum::{
4 FromPrimitive, IntoPrimitive,
5 TryFromPrimitive,
6};
7#[derive(Debug, Eq, PartialEq)]
10pub enum Frame {
11 Job { header: Header, job: Job },
13 AckData {
15 header: HearderAckData,
16 ack_data: AckData,
17 },
18}
19
20impl Frame {
21 pub fn job_setup(
22 pdu_ref: u16,
23 ) -> FrameJobSetupBuilder {
24 FrameJobSetupBuilder::default()
25 .pdu_ref(pdu_ref)
26 }
27
28 pub fn job_write_var(
29 pdu_ref: u16,
30 ) -> FrameJobWriteVarBuilder {
31 FrameJobWriteVarBuilder::default()
32 .pdu_ref(pdu_ref)
33 }
34
35 pub fn job_read_var(
36 pdu_ref: u16,
37 ) -> FrameJobReadVarBuilder {
38 FrameJobReadVarBuilder::default()
39 .pdu_ref(pdu_ref)
40 }
41}
42
43#[derive(Debug, Eq, PartialEq)]
44pub struct Header {
45 pub protocol_id: u8,
47 pub reserved: u16,
48 pub pdu_ref: u16,
49 pub parameter_len: u16,
50 pub data_len: u16,
51}
52
53impl Default for Header {
54 fn default() -> Self {
55 Self {
56 protocol_id: 0x32,
57 reserved: 0,
58 pdu_ref: 0x0400,
59 parameter_len: 0,
60 data_len: 0,
61 }
62 }
63}
64
65impl Header {
66 pub fn init(
67 pdu_ref: u16,
68 parameter_len: u16,
69 data_len: u16,
70 ) -> Self {
71 Self {
72 protocol_id: 0x32,
73 reserved: 0,
74 pdu_ref,
75 parameter_len,
76 data_len,
77 }
78 }
79
80 pub(crate) fn decode(
81 src: &mut BytesMut,
82 ) -> Self {
83 let protocol_id = src.get_u8();
84 src.get_u8();
85 let reserved = src.get_u16();
86 let pdu_ref = src.get_u16();
87 let parameter_len = src.get_u16();
88 let data_len = src.get_u16();
89 Self {
90 protocol_id,
91 reserved,
92 pdu_ref,
93 parameter_len,
94 data_len,
95 }
96 }
97}
98
99#[derive(Debug, Eq, PartialEq)]
100pub struct HearderAckData {
101 pub(crate) protocol_id: u8,
103 pub(crate) reserved: u16,
104 pub(crate) pdu_ref: u16,
105 pub(crate) parameter_len: u16,
106 pub(crate) data_len: u16,
107 pub(crate) error_class: u8,
108 pub(crate) error_code: u8,
109}
110
111impl HearderAckData {
112 pub fn init(
113 pdu_ref: u16,
114 parameter_len: u16,
115 data_len: u16,
116 error_class: u8,
117 error_code: u8,
118 ) -> Self {
119 Self {
120 protocol_id: 0x32,
121 reserved: 0,
122 pdu_ref,
123 parameter_len,
124 data_len,
125 error_class,
126 error_code,
127 }
128 }
129
130 pub(crate) fn decode(
131 src: &mut BytesMut,
132 ) -> Self {
133 let protocol_id = src.get_u8();
134 src.get_u8();
135 let reserved = src.get_u16();
136 let pdu_ref = src.get_u16();
137 let parameter_len = src.get_u16();
138 let data_len = src.get_u16();
139 let error_class = src.get_u8();
140 let error_code = src.get_u8();
141 Self {
142 protocol_id,
143 reserved,
144 pdu_ref,
145 parameter_len,
146 data_len,
147 error_class,
148 error_code,
149 }
150 }
151}
152
153#[derive(Debug, Eq, PartialEq)]
164pub enum Job {
165 SetupCommunication(SetupCommunication),
167 WriteVar(WriteVarJob),
169 ReadVar(ReadVarJob),
171}
172
173impl Job {
174 pub(crate) fn decode(
175 src: &mut BytesMut,
176 ) -> Result<Self> {
177 let function = src.get_u8();
178 match function {
179 0x04 => {
180 let count = src.get_u8();
181 let mut parameters_item =
182 Vec::with_capacity(
183 count as usize,
184 );
185 for _ in 0..count {
186 parameters_item.push(
187 ItemRequest::decode(src)?,
188 );
189 }
190 Ok(Self::ReadVar(ReadVarJob {
191 count: 0,
192 parameters_item,
193 }))
194 },
195 0x05 => {
196 let count = src.get_u8();
197 let mut parameters_item =
198 Vec::with_capacity(
199 count as usize,
200 );
201 for _ in 0..count {
202 parameters_item.push(
203 ItemRequest::decode(src)?,
204 );
205 }
206 let mut data_item =
207 Vec::with_capacity(
208 count as usize,
209 );
210 for _ in 0..count {
211 data_item.push(
212 DataItemVal::decode(src)?,
213 );
214 }
215 Ok(Self::WriteVar(WriteVarJob {
216 count: 0,
217 parameters_item,
218 data_item,
219 }))
220 },
221 0xf0 => {
222 let data =
223 SetupCommunication::decode(
224 src,
225 )?;
226 Ok(Self::SetupCommunication(data))
227 },
228 _ => Err(Error::Error(format!(
229 "not support function: {}",
230 function
231 ))),
232 }
233 }
234}
235
236#[derive(Debug, Eq, PartialEq)]
237pub enum AckData {
238 SetupCommunication(SetupCommunication),
240 WriteVar(WriteVarAckData),
242 ReadVar(ReadVarAckData),
244}
245
246impl AckData {
247 pub(crate) fn decode(
248 src: &mut BytesMut,
249 ) -> Result<Self> {
250 let function = src.get_u8();
251 match function {
252 0x04 => {
253 let count = src.get_u8();
254 let mut data_item =
255 Vec::with_capacity(
256 count as usize,
257 );
258 for _ in 0..count {
259 data_item.push(
260 DataItemVal::decode(src)?,
261 );
262 }
263 Ok(Self::ReadVar(
264 ReadVarAckData {
265 count,
266 data_item,
267 },
268 ))
269 },
270 0x05 => {
271 let count = src.get_u8();
272 let mut data_item =
280 Vec::with_capacity(
281 count as usize,
282 );
283 for _ in 0..count {
284 data_item.push(DataItemWriteResponse::decode(src)?);
285 }
286 Ok(Self::WriteVar(
287 WriteVarAckData {
288 count,
289 data_item,
290 },
291 ))
292 },
293 0xf0 => {
294 let data =
295 SetupCommunication::decode(
296 src,
297 )?;
298 Ok(Self::SetupCommunication(data))
299 },
300 _ => Err(Error::Error(format!(
301 "not support function: {}",
302 function
303 ))),
304 }
305 }
306}
307#[derive(Default, Debug, Eq, PartialEq)]
310pub struct WriteVarJob {
311 count: u8,
312 parameters_item: Vec<ItemRequest>,
313 data_item: Vec<DataItemVal>,
314}
315
316impl WriteVarJob {
317 pub fn bytes_len_data(&self) -> u16 {
318 self.data_item
319 .iter()
320 .fold(0, |len, x| len + x.bytes_len())
321 }
322
323 pub fn bytes_len_parameter(&self) -> u16 {
324 self.parameters_item
325 .iter()
326 .fold(2, |len, x| len + x.bytes_len())
327 }
328
329 pub fn add_item(
330 &mut self,
331 x: (ItemRequest, DataItemVal),
332 ) {
333 self.count += 1;
334 self.parameters_item.push(x.0);
335 self.data_item.push(x.1);
336 }
337
338 pub(crate) fn encode(
339 self,
340 dst: &mut BytesMut,
341 ) {
342 dst.put_u8(self.count);
343 self.parameters_item
344 .into_iter()
345 .for_each(|x| x.encode(dst));
346 self.data_item
347 .into_iter()
348 .for_each(|x| x.encode(dst));
349 }
350}
351
352#[derive(Debug, Eq, PartialEq, Default)]
353pub struct WriteVarAckData {
354 count: u8,
355 data_item: Vec<DataItemWriteResponse>,
356}
357
358impl WriteVarAckData {
359 pub fn data_item(
360 self,
361 ) -> Vec<DataItemWriteResponse> {
362 self.data_item
363 }
364
365 pub fn add_response(
366 mut self,
367 response: DataItemWriteResponse,
368 ) -> Self {
369 self.count += 1;
370 self.data_item.push(response);
371 self
372 }
373
374 pub(crate) fn encode(
375 self,
376 dst: &mut BytesMut,
377 ) {
378 dst.put_u8(self.count);
379 self.data_item
380 .into_iter()
381 .for_each(|x| x.encode(dst));
382 }
383}
384
385#[derive(Default, Debug, Eq, PartialEq)]
386pub struct ReadVarJob {
387 count: u8,
388 parameters_item: Vec<ItemRequest>,
389}
390impl ReadVarJob {
391 pub fn bytes_len_data(&self) -> u16 {
392 0
393 }
394
395 pub fn bytes_len_parameter(&self) -> u16 {
396 self.parameters_item
397 .iter()
398 .fold(2, |len, x| len + x.bytes_len())
399 }
400
401 pub fn add_item(&mut self, x: ItemRequest) {
402 self.count += 1;
403 self.parameters_item.push(x);
404 }
405
406 pub(crate) fn encode(
407 self,
408 dst: &mut BytesMut,
409 ) {
410 dst.put_u8(self.count);
411 self.parameters_item
412 .into_iter()
413 .for_each(|x| x.encode(dst));
414 }
415}
416
417#[derive(Debug, Eq, PartialEq, Default)]
418pub struct ReadVarAckData {
419 count: u8,
420 data_item: Vec<DataItemVal>,
421}
422impl ReadVarAckData {
423 pub fn data_item(self) -> Vec<DataItemVal> {
424 self.data_item
425 }
426
427 pub fn add_response(
428 mut self,
429 value: DataItemVal,
430 ) -> Self {
431 self.count += 1;
432 self.data_item.push(value);
433 self
434 }
435
436 pub(crate) fn encode(
437 self,
438 dst: &mut BytesMut,
439 ) {
440 dst.put_u8(self.count);
441 self.data_item
442 .into_iter()
443 .for_each(|x| x.encode(dst));
444 }
445}
446
447#[derive(Debug, Eq, PartialEq)]
448pub struct SetupCommunication {
449 reserved: u8,
450 max_amq_calling: u16,
451 max_amq_called: u16,
452 pdu_length: u16,
453}
454
455impl SetupCommunication {
456 pub fn init(
457 max_amq_calling: u16,
458 max_amq_called: u16,
459 pdu_length: u16,
460 ) -> Self {
461 Self {
462 reserved: 0,
463 max_amq_calling,
464 max_amq_called,
465 pdu_length,
466 }
467 }
468
469 fn len() -> usize {
470 7
471 }
472
473 pub(crate) fn encode(
474 self,
475 dst: &mut BytesMut,
476 ) {
477 dst.put_u8(self.reserved);
478 dst.extend_from_slice(
479 self.max_amq_calling
480 .to_be_bytes()
481 .as_slice(),
482 );
483 dst.extend_from_slice(
484 self.max_amq_called
485 .to_be_bytes()
486 .as_slice(),
487 );
488 dst.extend_from_slice(
489 self.pdu_length
490 .to_be_bytes()
491 .as_slice(),
492 );
493 }
494
495 fn decode(
496 src: &mut BytesMut,
497 ) -> Result<Self> {
498 if src.len() < Self::len() {
499 return Err(Error::Error(
500 "data of SetupCommunication not \
501 enough"
502 .to_string(),
503 ));
504 }
505 let reserved = src.get_u8();
506 let max_amq_calling = src.get_u16();
507 let max_amq_called = src.get_u16();
508 let pdu_length = src.get_u16();
509 Ok(Self {
510 reserved,
511 max_amq_calling,
512 max_amq_called,
513 pdu_length,
514 })
515 }
516
517 pub fn pdu_length(&self) -> u16 {
518 self.pdu_length
519 }
520}
521#[derive(Debug, Eq, PartialEq)]
522pub struct ItemRequest {
523 variable_specification: u8,
525 follow_length: u8,
526 syntax_id: Syntax,
527 transport_size_type: TransportSize,
528 length: u16,
529 db_number: DbNumber,
530 area: Area,
531 address: Address,
532}
533
534impl ItemRequest {
535 pub fn new(
536 transport_size_type: TransportSize,
537 db_number: DbNumber,
538 area: Area,
539 byte_addr: u16,
540 bit_addr: u8,
541 length: u16,
542 ) -> Self {
543 Self {
544 variable_specification: 0x12,
545 follow_length: 10,
546 syntax_id: Syntax::S7Any,
547 transport_size_type,
548 length,
549 db_number,
550 area,
551 address: Address {
552 byte_addr,
553 bit_addr,
554 },
555 }
556 }
557
558 pub fn init_db_byte(
559 db_number: u16,
560 byte_addr: u16,
561 bit_addr: u8,
562 length: u16,
563 ) -> Self {
564 Self {
565 variable_specification: 0x12,
566 follow_length: 10,
567 syntax_id: Syntax::S7Any,
568 transport_size_type:
569 TransportSize::Byte,
570 length,
571 db_number: DbNumber::DbNumber(
572 db_number,
573 ),
574 area: Area::DataBlocks,
575 address: Address {
576 byte_addr,
577 bit_addr,
578 },
579 }
580 }
581
582 pub fn init_db_bit(
583 db_number: u16,
584 byte_addr: u16,
585 bit_addr: u8,
586 length: u16,
587 ) -> Self {
588 Self {
589 variable_specification: 0x12,
590 follow_length: 10,
591 syntax_id: Syntax::S7Any,
592 transport_size_type:
593 TransportSize::Bit,
594 length,
595 db_number: DbNumber::DbNumber(
596 db_number,
597 ),
598 area: Area::DataBlocks,
599 address: Address {
600 byte_addr,
601 bit_addr,
602 },
603 }
604 }
605
606 pub fn bytes_len(&self) -> u16 {
607 12
608 }
609
610 fn encode(self, dst: &mut BytesMut) {
611 dst.put_u8(self.variable_specification);
612 dst.put_u8(self.follow_length);
613 dst.put_u8(self.syntax_id.into());
614 dst.put_u8(
615 self.transport_size_type.into(),
616 );
617 dst.extend_from_slice(
618 self.length.to_be_bytes().as_slice(),
619 );
620 dst.put_u16(self.db_number.into());
621 dst.put_u8(self.area.into());
622 dst.extend_from_slice(
623 self.address.to_bytes().as_slice(),
624 );
625 }
626
627 fn decode(
628 src: &mut BytesMut,
629 ) -> Result<Self> {
630 if src.len() < 12 {
631 return Err(Error::Error(
632 "item request byte's length is not enough"
633 .to_string(),
634 ));
635 }
636 let variable_specification = src.get_u8();
637 let follow_length = src.get_u8();
638 let syntax_id =
639 Syntax::from(src.get_u8());
640 let transport_size_type =
641 TransportSize::from(src.get_u8());
642 let length = src.get_u16();
643 let db_number =
644 DbNumber::from(src.get_u16());
645 let area = Area::from(src.get_u8());
646 let address = Address::from_bytes(
647 src.get_u8(),
648 src.get_u8(),
649 src.get_u8(),
650 );
651 Ok(Self {
652 variable_specification,
653 follow_length,
654 syntax_id,
655 transport_size_type,
656 length,
657 db_number,
658 area,
659 address,
660 })
661 }
662}
663
664#[derive(Debug, Eq, PartialEq)]
665pub struct DataItemWriteResponse {
666 return_code: ReturnCode,
667}
668
669impl DataItemWriteResponse {
670 pub fn init(return_code: ReturnCode) -> Self {
671 Self { return_code }
672 }
673
674 fn encode(self, dst: &mut BytesMut) {
675 dst.put_u8(self.return_code.into());
676 }
677
678 fn decode(
679 src: &mut BytesMut,
680 ) -> Result<Self> {
681 if src.len() == 0 {
682 return Err(Error::Error(
683 "byte's length is zero"
684 .to_string(),
685 ));
686 }
687 Ok(Self {
688 return_code: ReturnCode::try_from(
689 src.get_u8(),
690 )?,
691 })
692 }
693}
694#[derive(Debug, Eq, PartialEq)]
695pub struct DataItemVal {
696 pub return_code: ReturnCode,
697 pub transport_size_type: TransportSize,
699 pub length: u16,
702 pub data: Vec<u8>,
703}
704
705impl DataItemVal {
706 pub fn init_with_bytes(
707 return_code: ReturnCode,
708 data: &[u8],
709 ) -> Self {
710 Self {
711 return_code,
712 transport_size_type:
713 TransportSize::Word,
714 length: (data.len() as u16) * 8,
715 data: data.to_vec(),
716 }
717 }
718
719 pub fn init_with_bit(
720 return_code: ReturnCode,
721 data: bool,
722 ) -> Self {
723 Self {
724 return_code,
725 transport_size_type:
726 TransportSize::Char,
727 length: 8,
728 data: if data {
729 vec![1]
730 } else {
731 vec![0]
732 },
733 }
734 }
735
736 pub fn bytes_len(&self) -> u16 {
737 self.data.len() as u16 + 4
738 }
739
740 fn real_bytes_len(
741 transport_size_type: TransportSize,
742 length: u16,
743 ) -> usize {
744 if length == 0 {
745 return 0;
746 }
747 match transport_size_type {
748 TransportSize::Bit => length as usize,
749 TransportSize::Byte => {
750 (length / 8) as usize
751 },
752 _ => {
753 (length / 8) as usize
755 },
756 }
757 }
758
759 fn encode(self, dst: &mut BytesMut) {
760 dst.put_u8(self.return_code.into());
761 dst.put_u8(
762 self.transport_size_type.into(),
763 );
764 dst.extend_from_slice(
765 self.length.to_be_bytes().as_slice(),
766 );
767 dst.extend_from_slice(
768 self.data.as_slice(),
769 );
770 }
771
772 fn decode(
773 src: &mut BytesMut,
774 ) -> Result<Self> {
775 if src.len() < 4 {
776 return Err(Error::Error(
777 format!("data item val byte's length is not enough: {}"
778 , src.len()),
779 ));
780 }
781 let return_code =
782 ReturnCode::try_from(src.get_u8())?;
783 let transport_size_type =
784 TransportSize::from(src.get_u8());
785 let length = src.get_u16();
786 let bytes_len = Self::real_bytes_len(
787 transport_size_type,
788 length,
789 );
790 let fill_byte_len = bytes_len % 2;
791 if src.len() < bytes_len {
792 return Err(Error::Error(
793 format!("data item val byte's length is not enough: {} < {}", src.len(), bytes_len),
794 ));
795 }
796 let mut data =
797 Vec::with_capacity(bytes_len);
798 for _ in 0..bytes_len {
799 data.push(src.get_u8())
800 }
801 if fill_byte_len > 0 && src.len() >= 1 {
802 src.get_u8();
803 }
804 Ok(Self {
805 return_code,
806 transport_size_type,
807 length,
808 data,
809 })
810 }
811}
812
813#[derive(
814 Debug,
815 IntoPrimitive,
816 TryFromPrimitive,
817 Eq,
818 PartialEq,
819)]
820#[repr(u8)]
821pub enum ReturnCode {
822 Reserved = 0,
824 HwFault = 1,
826 NotAllow = 3,
828 InvalidAddress = 5,
830 NotSupported = 6,
832 SizeMismatch = 7,
834 Err = 0x0a,
836 Success = 0xff,
838}
839
840#[derive(
841 Debug,
842 Copy,
843 Clone,
844 IntoPrimitive,
845 Eq,
846 FromPrimitive,
847 PartialEq,
848)]
849#[repr(u8)]
867pub enum TransportSize {
868 Bit = 0x01,
869 Byte = 0x02,
870 Char = 0x03,
871 Word = 0x04,
872 Int = 0x05,
873 DWord = 0x06,
874 DInt = 0x07,
875 Real = 0x08,
876 Counter = 0x1C,
877 Timer = 0x1D,
878 #[num_enum(catch_all)]
879 NotSupport(u8),
880 }
900#[derive(
901 Debug,
902 IntoPrimitive,
903 FromPrimitive,
904 Eq,
905 PartialEq,
906)]
907#[repr(u8)]
908pub enum Area {
909 ProcessInput = 0x81,
910 ProcessOutput = 0x82,
911 DataBlocks = 0x84,
912 Merker = 0x83,
913 Counter = 0x1c,
914 Timer = 0x1d,
915 #[num_enum(catch_all)]
916 NotSupport(u8),
917}
918
919#[derive(
920 Debug,
921 IntoPrimitive,
922 FromPrimitive,
923 Eq,
924 PartialEq,
925)]
926#[repr(u8)]
927pub enum Syntax {
928 S7Any = 0x10,
929 #[num_enum(catch_all)]
930 NotSupport(u8),
931}
932#[derive(
933 Debug,
934 IntoPrimitive,
935 FromPrimitive,
936 Eq,
937 PartialEq,
938)]
939#[repr(u16)]
940pub enum DbNumber {
941 NotIn = 0,
942 #[num_enum(catch_all)]
943 DbNumber(u16),
944}
945#[derive(Debug, Eq, PartialEq)]
946pub struct Address {
947 byte_addr: u16,
948 bit_addr: u8,
949}
950
951impl Address {
952 pub fn to_bytes(&self) -> [u8; 3] {
953 let [byte_0, byte_1] =
954 self.byte_addr.to_be_bytes();
955 [
956 byte_0 >> 5,
957 byte_0 << 3 | byte_1 >> 5,
958 byte_1 << 3 | self.bit_addr,
959 ]
960 }
961
962 pub fn from_bytes(
963 index_0: u8,
964 index_1: u8,
965 index_2: u8,
966 ) -> Self {
967 let index_0 = index_0 << 5 | index_1 >> 3;
968 let index_1 = index_1 << 5 | index_2 >> 3;
969
970 let byte_addr = u16::from_be_bytes([
971 index_0, index_1,
972 ]);
973 let bit_addr = index_2 & 0b0000_0111;
974 Self {
975 byte_addr,
976 bit_addr,
977 }
978 }
979}
980
981#[cfg(test)]
982mod test {
983 use super::Address;
984
985 #[test]
986 fn check_address() {
987 let addr = Address {
988 byte_addr: 0b0000000100101100,
989 bit_addr: 0,
990 };
991 assert_eq!(addr.byte_addr, 300);
992 assert_eq!(addr.to_bytes(), [0, 9, 0x60])
993 }
994}