1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
use serde::{Deserialize, Serialize};

/// Client Connection Type
/// 16 possible connections limited by the
/// hardware The types are defined from the
/// highest to lowest priority
/// The basic connections are the first which
/// would be closed if there aren't enough
/// resources
#[derive(
    Debug, Clone, Copy, Serialize, Deserialize,
)]
pub enum ConnectionType {
    /// Connect to the PLC programming console
    /// (Programmiergeräte). German for
    /// programming device.
    PG    = 1,
    /// Connect to the PLC Siemens HMI panel
    OP    = 2,
    /// Basic connection for generic data
    /// transfer connection
    /// 14 Basic connections
    Basic = 3
}

impl Default for ConnectionType {
    fn default() -> Self {
        Self::OP
    }
}

#[derive(
    Debug, Clone, Serialize, Deserialize,
)]
pub enum ConnectMode {
    Tsap {
        conn_type:   ConnectionType,
        local_tsap:  u16,
        remote_tsap: u16
    },
    RackSlot {
        conn_type: ConnectionType,
        rack:      u16,
        slot:      u16
    }
}
impl ConnectMode {
    pub fn init_tsap(
        conn_type: ConnectionType,
        local_tsap: u16,
        remote_tsap: u16
    ) -> Self {
        Self::Tsap {
            conn_type,
            local_tsap,
            remote_tsap
        }
    }

    pub fn init_rack_slot(
        conn_type: ConnectionType,
        rack: u16,
        slot: u16
    ) -> Self {
        Self::RackSlot {
            conn_type,
            rack,
            slot
        }
    }

    pub fn conn_type(&self) -> &ConnectionType {
        match self {
            ConnectMode::Tsap {
                conn_type,
                ..
            } => conn_type,
            ConnectMode::RackSlot {
                conn_type,
                ..
            } => conn_type
        }
    }

    pub fn local_tsap(&self) -> [u8; 2] {
        match self {
            ConnectMode::Tsap {
                local_tsap,
                ..
            } => [
                (local_tsap >> 8) as u8,
                *local_tsap as u8
            ],
            ConnectMode::RackSlot { .. } => {
                [0x01, 0x00]
            },
        }
    }

    pub fn remote_tsap(&self) -> [u8; 2] {
        let remote_tsap = match self {
            ConnectMode::Tsap {
                remote_tsap,
                ..
            } => *remote_tsap,
            ConnectMode::RackSlot {
                rack,
                slot,
                conn_type
            } => {
                ((*conn_type as u16) << 8)
                    + (rack * 0x20)
                    + slot
            },
        };
        [
            (remote_tsap >> 8) as u8,
            remote_tsap as u8
        ]
    }
}