s7_comm/
packet.rs

1use crate::{builder::*, error::*};
2use bytes::{Buf, BufMut, BytesMut};
3use num_enum::{
4    FromPrimitive, IntoPrimitive,
5    TryFromPrimitive,
6};
7/// more info: https://github.com/wireshark/wireshark/blob/master/epan/dissectors/packet-s7comm.c
8
9#[derive(Debug, Eq, PartialEq)]
10pub enum Frame {
11    /// 0x01
12    Job { header: Header, job: Job },
13    /// 0x03
14    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    /// 0x32?
46    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    /// 0x32?
102    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(IntoPrimitive, FromPrimitive)]
154// #[repr(u8)]
155// pub enum Rosctr {
156//     /// 0x01
157//     Job,
158//     /// 0x02
159//     Ack = 0x02,
160//     /// 0x03
161//     AckData = 0x03,
162// }
163#[derive(Debug, Eq, PartialEq)]
164pub enum Job {
165    /// 0xf0
166    SetupCommunication(SetupCommunication),
167    /// 0x05
168    WriteVar(WriteVarJob),
169    /// 0x04
170    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    /// 0xf0
239    SetupCommunication(SetupCommunication),
240    /// 0x05
241    WriteVar(WriteVarAckData),
242    /// 0x04
243    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 parameters_item =
273                // Vec::with_capacity(count as
274                // usize);
275                // for _ in 0..count {
276                //     parameters_item.
277                // push(ItemRequest::decode(src)?
278                // ); }
279                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//////////////////////////////////////
308
309#[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    /// always = 0x12?
524    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    /// always = 0x04?
698    pub transport_size_type: TransportSize,
699    // Data Length * 8 (if not bit or timer or
700    // counter)
701    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                // todo ?
754                (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    /// 0
823    Reserved = 0,
824    /// Hardware error
825    HwFault = 1,
826    /// Accessing the object not allowed
827    NotAllow = 3,
828    /// Invalid address
829    InvalidAddress = 5,
830    /// Data type not supported
831    NotSupported = 6,
832    /// Data type inconsistent
833    SizeMismatch = 7,
834    /// Object does not exist
835    Err = 0x0a,
836    /// Success
837    Success = 0xff,
838}
839
840#[derive(
841    Debug,
842    Copy,
843    Clone,
844    IntoPrimitive,
845    Eq,
846    FromPrimitive,
847    PartialEq,
848)]
849// #define S7COMM_DATA_TRANSPORT_SIZE_NULL     0
850// #define S7COMM_DATA_TRANSPORT_SIZE_BBIT     3
851// /* bit access, len is in bits */
852// #define S7COMM_DATA_TRANSPORT_SIZE_BBYTE    4
853// /* byte/word/dword access, len is in bits */
854// #define S7COMM_DATA_TRANSPORT_SIZE_BINT     5
855// /* integer access, len is in bits */
856// #define S7COMM_DATA_TRANSPORT_SIZE_BDINT    6
857// /* integer access, len is in bytes */
858// #define S7COMM_DATA_TRANSPORT_SIZE_BREAL    7
859// /* real access, len is in bytes */
860// #define S7COMM_DATA_TRANSPORT_SIZE_BSTR     9
861// /* octet string, len is in bytes */
862// #define S7COMM_DATA_TRANSPORT_SIZE_NCKADDR1 17
863// /* NCK address description, fixed length */
864// #define S7COMM_DATA_TRANSPORT_SIZE_NCKADDR2 18
865// /* NCK address description, fixed length */
866#[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    // Null = 0x00,
881    // /// bit access, len is in bits
882    // Bit = 0x03,
883    // /// byte/word/dword access, len is in bits?
884    // Byte = 0x04,
885    // /// integer access, len is in bits
886    // Int = 0x05,
887    // /// integer access, len is in bytes
888    // Dint = 0x06,
889    // /// real access, len is in bytes
890    // Real = 0x07,
891    // /// octet string, len is in bytes
892    // Str = 0x09,
893    // /// NCK address description, fixed length
894    // NckAddr1 = 0x1C,
895    // /// NCK address description, fixed length
896    // NckAddr2 = 0x12,
897    // #[num_enum(catch_all)]
898    // NotSupport(u8),
899}
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}