]> git.basschouten.com Git - openhab-addons.git/blob
097cba7e13b55f438897fc44bf26a5e573ee7e5e
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
7  * This program and the accompanying materials are made available under the
8  * terms of the Eclipse Public License 2.0 which is available at
9  * http://www.eclipse.org/legal/epl-2.0
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.plclogo.internal;
14
15 import org.slf4j.Logger;
16 import org.slf4j.LoggerFactory;
17
18 import Moka7.S7;
19 import Moka7.S7Client;
20
21 /**
22  * The {@link PLCLogoClient} is thread safe LOGO! client.
23  *
24  * @author Alexander Falkenstern - Initial contribution
25  */
26 public class PLCLogoClient extends S7Client {
27
28     private static final int MAX_RETRY_NUMBER = 10;
29     private final Logger logger = LoggerFactory.getLogger(PLCLogoClient.class);
30
31     private String plcIPAddress = "INVALID_IP";
32
33     /**
34      * Connects a client to a PLC
35      */
36     @Override
37     public synchronized int Connect() {
38         return super.Connect();
39     }
40
41     /**
42      * Connects a client to a PLC with specified parameters
43      *
44      * @param Address IP address of PLC
45      * @param LocalTSAP Local TSAP for the connection
46      * @param RemoteTSAP Remote TSAP for the connection
47      * @return Zero on success, error code otherwise
48      */
49     public synchronized int Connect(String Address, int LocalTSAP, int RemoteTSAP) {
50         SetConnectionParams(Address, LocalTSAP, RemoteTSAP);
51         return super.Connect();
52     }
53
54     /**
55      * Set connection parameters
56      *
57      * @param Address IP address of PLC
58      * @param LocalTSAP Local TSAP for the connection
59      * @param RemoteTSAP Remote TSAP for the connection
60      */
61     @Override
62     public void SetConnectionParams(String Address, int LocalTSAP, int RemoteTSAP) {
63         plcIPAddress = Address; // Store ip address for logging
64         super.SetConnectionParams(Address, LocalTSAP, RemoteTSAP);
65     }
66
67     /**
68      * Disconnects a client from a PLC
69      */
70     @Override
71     public synchronized void Disconnect() {
72         super.Disconnect();
73     }
74
75     /**
76      * Reads a data area from a PLC
77      *
78      * @param Area S7 Area ID. Can be S7AreaPE, S7AreaPA, S7AreaMK, S7AreaDB, S7AreaCT or S7AreaTM
79      * @param DBNumber S7 data block number
80      * @param Start First position within data block read from
81      * @param Amount Number of words to read
82      * @param WordLength Length of single word. Can be S7WLBit, S7WLByte, S7WLCounter or S7WLTimer
83      * @param Data Buffer to read into
84      * @return Zero on success, error code otherwise
85      */
86     @Override
87     public synchronized int ReadArea(int Area, int DBNumber, int Start, int Amount, int WordLength, byte[] Data) {
88         if (LastError != 0) {
89             logger.debug("Reconnect during read from {}: {}", plcIPAddress, ErrorText(LastError));
90             Disconnect();
91         }
92         if (!Connected) {
93             Connect();
94         }
95
96         final int packet = Math.min(Amount, 1024);
97         int offset = packet;
98
99         int retry = 0;
100         int result = -1;
101         do {
102             // read first portion directly to data
103             result = super.ReadArea(Area, DBNumber, Start, packet, WordLength, Data);
104             while ((result == 0) && (offset < Amount)) {
105                 byte[] buffer = new byte[Math.min(Amount - offset, packet)];
106                 result = super.ReadArea(Area, DBNumber, offset, buffer.length, WordLength, buffer);
107                 System.arraycopy(buffer, 0, Data, offset, buffer.length);
108                 offset = offset + buffer.length;
109             }
110
111             if (retry == MAX_RETRY_NUMBER) {
112                 logger.info("Giving up reading from {} after {} retries.", plcIPAddress, MAX_RETRY_NUMBER);
113                 break;
114             }
115
116             if (result != 0) {
117                 logger.info("Reconnect during read from {}: {}", plcIPAddress, ErrorText(result));
118                 retry = retry + 1;
119                 Disconnect();
120                 Connect();
121             }
122         } while (result != 0);
123
124         return result;
125     }
126
127     /**
128      * Reads a data block area from a PLC
129      *
130      * @param DBNumber S7 data block number
131      * @param Start First position within data block read from
132      * @param Amount Number of words to read
133      * @param WordLength Length of single word. Can be S7WLBit, S7WLByte, S7WLCounter or S7WLTimer
134      * @param Data Buffer to read into
135      * @return Zero on success, error code otherwise
136      */
137     public int readDBArea(int DBNumber, int Start, int Amount, int WordLength, byte[] Data) {
138         return ReadArea(S7.S7AreaDB, DBNumber, Start, Amount, WordLength, Data);
139     }
140
141     /**
142      * Writes a data area into a PLC
143      *
144      * @param Area S7 Area ID. Can be S7AreaPE, S7AreaPA, S7AreaMK, S7AreaDB, S7AreaCT or S7AreaTM
145      * @param DBNumber S7 data block number
146      * @param Start First position within data block write into
147      * @param Amount Number of words to write
148      * @param WordLength Length of single word. Can be S7WLBit, S7WLByte, S7WLCounter or S7WLTimer
149      * @param Data Buffer to write from
150      * @return Zero on success, error code otherwise
151      */
152     @Override
153     public synchronized int WriteArea(int Area, int DBNumber, int Start, int Amount, int WordLength, byte[] Data) {
154         if (LastError != 0) {
155             logger.debug("Reconnect during write to {}: {}", plcIPAddress, ErrorText(LastError));
156             Disconnect();
157         }
158         if (!Connected) {
159             Connect();
160         }
161
162         int retry = 0;
163         int result = -1;
164         do {
165             result = super.WriteArea(Area, DBNumber, Start, Amount, WordLength, Data);
166
167             if (retry == MAX_RETRY_NUMBER) {
168                 logger.info("Giving up writing to {} after {} retries.", plcIPAddress, MAX_RETRY_NUMBER);
169                 break;
170             }
171
172             if (result != 0) {
173                 logger.info("Reconnect during write to {}: {}", plcIPAddress, ErrorText(result));
174                 retry = retry + 1;
175                 Disconnect();
176                 Connect();
177             }
178         } while (result != 0);
179
180         return result;
181     }
182
183     /**
184      * Writes a data block area into a PLC
185      *
186      * @param DBNumber S7 data block number
187      * @param Start First position within data block write into
188      * @param Amount Number of words to write
189      * @param WordLength Length of single word. Can be S7WLBit, S7WLByte, S7WLCounter or S7WLTimer
190      * @param Data Buffer to write from
191      * @return Zero on success, error code otherwise
192      */
193     public int writeDBArea(int DBNumber, int Start, int Amount, int WordLength, byte[] Data) {
194         return WriteArea(S7.S7AreaDB, DBNumber, Start, Amount, WordLength, Data);
195     }
196
197     /**
198      * Returns, if client is already connected or not
199      *
200      * @return True, if client is connected and false otherwise
201      */
202     public synchronized boolean isConnected() {
203         return Connected;
204     }
205 }