wuyouming666
2024-03-26 90110ed128dd9212caf3b7d5fb4a8d5f870d2905
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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
package com.mes.common.PlcTools;
 
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
public class MockS7PLCtwo {
    private static volatile MockS7PLCtwo instance; // 单例实例
    private ConcurrentHashMap<String, String> memory = new ConcurrentHashMap<>();
    private String storageFilePath = "mockPLCData.properties";
 
    // 私有化构造函数
    private MockS7PLCtwo() {
        // 在构造函数中尝试加载现有的模拟数据
        try (FileInputStream fis = new FileInputStream(storageFilePath)) {
            Properties properties = new Properties();
            properties.load(fis);
            properties.forEach((key, value) -> memory.put(String.valueOf(key), String.valueOf(value)));
        } catch (IOException e) {
            System.out.println("没有找到现有的模拟数据文件,将创建一个新的。");
        }
    }
 
    // 公共静态方法获取类的唯一实例
    public static MockS7PLCtwo getInstance() {
        if (instance == null) {
            synchronized (MockS7PLCtwo.class) {
                if (instance == null)
                    instance = new MockS7PLCtwo();
            }
        }
        return instance;
    }
 
    // 修改写入方法以持久化数据
    public void writeByte(String address, byte[] data) {
        memory.put(address, new String(data, StandardCharsets.ISO_8859_1));
        saveMemory();
    }
 
    // 修改读取方法以从持久化的数据中读取
    public byte[] readByte(String address,int count) {
        String value = memory.getOrDefault(address, "");
        byte[] bytes = value.getBytes(StandardCharsets.ISO_8859_1);
        if (count >= 0 && count <= bytes.length) {
            byte[] result = new byte[count];
            System.arraycopy(bytes, 0, result, 0, count);
            return result;
        } else {
            // 如果请求的字节数超出了实际可用的字节数,则返回全部可用的字节
            return bytes;
        }
    }
 
 
 
 
 
 
    public void writeInt16(String address, short data) {
        memory.put(address, Short.toString(data));
        saveMemory();
    }
 
    public Short readInt16(String address) {
        String value = memory.get(address);
        return value != null ? Short.parseShort(value) : null;
    }
 
    public void writeBoolean(String address, boolean data) {
        memory.put(address, Boolean.toString(data));
        saveMemory();
    }
 
    public Boolean readBoolean(String address) {
        String value = memory.get(address);
        return value != null ? Boolean.parseBoolean(value) : null;
    }
 
    public void writeString(String address, String data) {
        memory.put(address, data);
        saveMemory();
    }
 
    public String readString(String address) {
        return memory.getOrDefault(address, "");
    }
 
    public void writeTime(String address, long data) {
        memory.put(address, Long.toString(data));
        saveMemory();
    }
 
    public Long readTime(String address) {
        String value = memory.get(address);
        return value != null ? Long.parseLong(value) : null;
    }
 
    // 添加一个方法来保存数据到文件
    private void saveMemory() {
        Properties properties = new Properties();
        properties.putAll(memory);
        try (FileOutputStream fos = new FileOutputStream(storageFilePath)) {
            properties.store(fos, "Mock S7 PLC Data");
        } catch (IOException e) {
            System.out.println("保存模拟数据失败:" + e.getMessage());
        }
    }
 
    // 连续写入多个Word
    public void writeword(String address, List<Short> data) {
        for (int i = 0; i < data.size(); i++) {
            String addr = calculateAddress(address, i * 2); // 假设每个word占两个地址单位
            memory.put(addr, Short.toString(data.get(i)));
 
        }
        saveMemory();
    }
 
    // 不连续地址word写入多个Word
    public void WriteWords(List<String> addresses, List<Short> datas) {
        if (addresses.size() != datas.size()) {
            throw new IllegalArgumentException("地址列表和数据列表的大小必须相同。");
        }
 
        for (int i = 0; i < addresses.size(); i++) {
            String addr = addresses.get(i);
            short data = datas.get(i);
            // 假设这里使用内存映射来模拟PLC写入操作
            memory.put(addr, Short.toString(data));
        }
        saveMemory(); // 在所有数据写入后保存更改
    }
 
    // 连续读取多个Word
    public List<Short> readwords(String address, int count) {
        List<Short> result = new ArrayList<>();
        for (int i = 0; i < count; i++) {
            String addr = calculateAddress(address, i * 2); // 同上,每个word占两个地址单位
 
            //System.out.println(addr);
 
            String value = memory.get(addr);
            if (value != null) {
                result.add(Short.parseShort(value));
            } else {
                result.add(null); // 或者考虑抛出异常或其他错误处理
            }
        }
        return result;
    }
 
 
    public List<Short> ReadWords(List<String> addresses) {
        List<Short> datas = new ArrayList<>();
 
        for (String addr : addresses) {
            // 从内存映射中获取数据
            String dataStr = memory.get(addr);
 
            // 将字符串转换成short类型,并添加到结果列表中
            // 这里假设数据已经以适当的方式存储(例如,作为短整型的字符串表示)
            // 如果读取的数据为空或转换失败,你可能需要处理这些情况
            try {
                short data = Short.parseShort(dataStr);
                datas.add(data);
            } catch (NumberFormatException e) {
                System.err.println("读取地址 " + addr + " 的数据时出错: " + e.getMessage());
 
            }
        }
 
        return datas;
    }
 
 
 
 
 
    // 连续写入多个Bit
    public void writebits(String address, List<Boolean> data) {
        for (int i = 0; i < data.size(); i++) {
            String addr = calculateAddress(address, i); // 假设每个bit占一个地址单位
            memory.put(addr, Boolean.toString(data.get(i)));
        }
        saveMemory();
    }
 
//bit分散地址读取
    public List<Boolean> readBits(List<String> addresses) {
        List<Boolean> results = new ArrayList<>();
        for (String address : addresses) {
            // 对于每个地址,直接使用 calculateAddress 来处理可能的位偏移
            // 这里假设 calculateAddress 已经足够智能以处理单个位的偏移
            // 由于我们是逐个读取,每次偏移量都是0
            String addr = calculateAddress(address, 0);
            String value = memory.get(addr);
            if (value != null) {
                results.add(Boolean.parseBoolean(value));
            } else {
                // 如果地址对应的值不存在于内存中,可以选择添加 null 或抛出异常
                // 这里选择添加 null,但在实际应用中应根据具体需求决定
                results.add(null);
            }
        }
        return results;
    }
 
    // 连续读取多个Bit
    public List<Boolean> readbits(String address, int count) {
        List<Boolean> result = new ArrayList<>();
        for (int i = 0; i < count; i++) {
            String addr = calculateAddress(address, i); // 同上,每个bit占一个地址单位
            String value = memory.get(addr);
            if (value != null) {
                result.add(Boolean.parseBoolean(value));
            } else {
                result.add(null); // 或者考虑抛出异常或其他错误处理
            }
        }
        return result;
    }
 
    // 计算连续地址
//    private String calculateAddress(String baseAddress, int offset) {
//        // 支持带字母的地址格式
//        Pattern pattern = Pattern.compile("(\\D*)(\\d+)");
//        Matcher matcher = pattern.matcher(baseAddress);
//        if (matcher.find()) {
//            String prefix = matcher.group(1);
//            int address = Integer.parseInt(matcher.group(2));
//            return prefix + (address + offset);
//        } else {
//            throw new IllegalArgumentException("Invalid address format: " + baseAddress);
//        }
//    }
 
    private String calculateAddress(String baseAddress, int offset) {
        // 分割地址为数据块、字偏移和位偏移(如果有)
        Pattern pattern = Pattern.compile("(DB\\d+)\\.(\\d+)(?:\\.(\\d+))?");
        Matcher matcher = pattern.matcher(baseAddress);
        if (matcher.find()) {
            String dbNumber = matcher.group(1); // 数据块编号,如 "DB100"
            int wordOffset = Integer.parseInt(matcher.group(2)); // 字偏移
            String bitOffsetStr = matcher.group(3); // 位偏移,可能为空
 
            if (bitOffsetStr != null) {
                // 存在位偏移,进行位操作
                int bitOffset = Integer.parseInt(bitOffsetStr);
                int totalBitOffset = bitOffset + offset;
                // 计算新的字偏移和位偏移
                int newWordOffset = wordOffset + (totalBitOffset / 8);
                int newBitOffset = totalBitOffset % 8;
                return String.format("%s.%d.%d", dbNumber, newWordOffset, newBitOffset);
            } else {
                // 仅存在字偏移,进行字操作
                // 注意:假设每个字占用2个字节
                int newWordOffset = wordOffset + (offset );
                return String.format("%s.%d", dbNumber, newWordOffset);
            }
        } else {
            throw new IllegalArgumentException("Invalid address format: " + baseAddress);
        }
    }
 
 
 
 
}