自动化立体仓库 - WCS系统
#
luxiaotao1123
2020-08-05 7bb6bff9506d1b0153b814e45f622c4f8538f67c
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
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
package com.zy.common.HslCommunication.Profinet.Siemens;
 
import com.zy.common.HslCommunication.BasicFramework.SoftBasic;
import com.zy.common.HslCommunication.Core.IMessage.FetchWriteMessage;
import com.zy.common.HslCommunication.Core.Net.NetworkBase.NetworkDeviceBase;
import com.zy.common.HslCommunication.Core.Transfer.ReverseBytesTransform;
import com.zy.common.HslCommunication.Core.Types.OperateResult;
import com.zy.common.HslCommunication.Core.Types.OperateResultExOne;
import com.zy.common.HslCommunication.Core.Types.OperateResultExThree;
import com.zy.common.HslCommunication.StringResources;
 
/**
 * 使用了Fetch/Write协议来和西门子进行通讯,该种方法需要在PLC侧进行一些配置
 */
public class SiemensFetchWriteNet extends NetworkDeviceBase<FetchWriteMessage, ReverseBytesTransform> {
 
    /**
     * 实例化一个西门子的Fetch/Write协议的通讯对象
     */
    public SiemensFetchWriteNet() {
        WordLength = 2;
    }
 
 
    /**
     * 实例化一个西门子的Fetch/Write协议的通讯对象
     *
     * @param ipAddress PLC的Ip地址
     * @param port      PLC的端口
     */
    public SiemensFetchWriteNet(String ipAddress, int port) {
        WordLength = 2;
        setIpAddress(ipAddress);
        setPort(port);
    }
 
 
    /**
     * 从PLC读取数据,地址格式为I100,Q100,DB20.100,M100,T100,C100,以字节为单位
     *
     * @param address 起始地址,格式为I100,M100,Q100,DB20.100,T100,C100
     * @param length  读取的数量,以字节为单位
     * @return 带有成功标志的字节信息
     */
    @Override
    public OperateResultExOne<byte[]> Read(String address, short length) {
        OperateResultExOne<byte[]> result = new OperateResultExOne<byte[]>();
        OperateResultExOne<byte[]> command = BuildReadCommand(address, length);
        if (!command.IsSuccess) {
            result.CopyErrorFromOther(command);
            return result;
        }
 
        OperateResultExOne<byte[]> read = ReadFromCoreServer(command.Content);
        if (read.IsSuccess) {
            if (read.Content[8] == 0x00) {
                // 分析结果
                byte[] buffer = new byte[read.Content.length - 16];
                System.arraycopy(read.Content, 16, buffer, 0, buffer.length);
 
                result.Content = buffer;
                result.IsSuccess = true;
            } else {
                result.ErrorCode = read.Content[8];
                result.Message = "发生了异常,具体信息查找Fetch/Write协议文档";
            }
        } else {
            result.ErrorCode = read.ErrorCode;
            result.Message = read.Message;
        }
 
        return result;
    }
 
 
    /**
     * 读取指定地址的byte数据
     *
     * @param address 起始地址,格式为I100,M100,Q100,DB20.100
     * @return 返回写入结果
     */
    public OperateResultExOne<Byte> ReadByte(String address) {
        return GetByteResultFromBytes(Read(address, (short) 1));
    }
 
 
    /**
     * 将数据写入到PLC数据,地址格式为I100,Q100,DB20.100,M100,以字节为单位
     *
     * @param address 起始地址,格式为I100,M100,Q100,DB20.100
     * @param value   写入的数据,长度根据data的长度来指示
     * @return 返回写入结果
     */
    @Override
    public OperateResult Write(String address, byte[] value) {
        OperateResult result = new OperateResult();
 
        OperateResultExOne<byte[]> command = BuildWriteCommand(address, value);
        if (!command.IsSuccess) {
            result.CopyErrorFromOther(command);
            return result;
        }
 
 
        OperateResultExOne<byte[]> write = ReadFromCoreServer(command.Content);
        if (write.IsSuccess) {
            if (write.Content[8] != 0x00) {
                // 写入异常
                result.Message = "写入数据异常,代号为:" + String.valueOf(write.Content[8]);
            } else {
                result.IsSuccess = true;  // 写入成功
            }
        } else {
            result.ErrorCode = write.ErrorCode;
            result.Message = write.Message;
        }
        return result;
    }
 
    /**
     * 向PLC中写入bool数组,返回值说明,比如你写入M100,那么data[0]对应M100.0
     *
     * @param address 要写入的数据地址
     * @param values  要写入的实际数据,长度为8的倍数
     * @return 返回写入结果
     */
    public OperateResult Write(String address, boolean[] values) {
        return Write(address, SoftBasic.BoolArrayToByte(values));
    }
 
 
    /**
     * 向PLC中写入byte数据,返回值说明
     *
     * @param address 要写入的数据地址
     * @param value   要写入的实际数据
     * @return 返回写入结果
     */
    public OperateResult Write(String address, byte value) {
        return Write(address, new byte[]{value});
    }
 
 
    /**
     * 返回表示当前对象的字符串
     *
     * @return 字符串
     */
    @Override
    public String toString() {
        return "SiemensFetchWriteNet";
    }
 
 
 
 
    /**
     * 计算特殊的地址信息
     *
     * @param address 字符串信息
     * @return 实际值
     */
    public static int CalculateAddressStarted(String address) {
        if (address.indexOf('.') < 0) {
            return Integer.parseInt(address);
        } else {
            String[] temp = address.split("\\.");
            return Integer.parseInt(temp[0]);
        }
    }
 
 
    /**
     * 解析数据地址,解析出地址类型,起始地址,DB块的地址
     *
     * @param address 数据地址
     * @return 解析出地址类型,起始地址,DB块的地址
     */
    public static OperateResultExThree<Byte, Integer, Integer> AnalysisAddress(String address) {
        OperateResultExThree<Byte, Integer, Integer> result = new OperateResultExThree<Byte, Integer, Integer>();
        try {
            result.Content3 = 0;
            if (address.indexOf(0) == 'I') {
                result.Content1 = 0x03;
                result.Content2 = CalculateAddressStarted(address.substring(1));
            } else if (address.indexOf(0) == 'Q') {
                result.Content1 = 0x04;
                result.Content2 = CalculateAddressStarted(address.substring(1));
            } else if (address.indexOf(0) == 'M') {
                result.Content1 = 0x02;
                result.Content2 = CalculateAddressStarted(address.substring(1));
            } else if (address.indexOf(0) == 'D' || address.substring(0, 2).equals("DB")) {
                result.Content1 = 0x01;
                String[] adds = address.split("\\.");
                if (address.indexOf(1) == 'B') {
                    result.Content3 = Integer.parseInt(adds[0].substring(2));
                } else {
                    result.Content3 = Integer.parseInt(adds[0].substring(1));
                }
 
                if (result.Content3 > 255) {
                    result.Message = StringResources.Language.SiemensDBAddressNotAllowedLargerThan255();
                    return result;
                }
 
                result.Content2 = CalculateAddressStarted(address.substring(address.indexOf('.') + 1));
            } else if (address.indexOf(0) == 'T') {
                result.Content1 = 0x07;
                result.Content2 = CalculateAddressStarted(address.substring(1));
            } else if (address.indexOf(0) == 'C') {
                result.Content1 = 0x06;
                result.Content2 = CalculateAddressStarted(address.substring(1));
            } else {
                return new OperateResultExThree<Byte, Integer, Integer>(StringResources.Language.NotSupportedDataType());
            }
        } catch (Exception ex) {
            result.Message = ex.getMessage();
            return result;
        }
 
        result.IsSuccess = true;
        return result;
    }
 
 
    /**
     * 生成一个读取字数据指令头的通用方法
     *
     * @param address 地址
     * @param count   长度
     * @return 带结果标识的指令
     */
    public static OperateResultExOne<byte[]> BuildReadCommand(String address, int count) {
        OperateResultExThree<Byte, Integer, Integer> analysis = AnalysisAddress(address);
        if (!analysis.IsSuccess) return  OperateResultExOne.<byte[]>CreateFailedResult(analysis);
 
        byte[] _PLCCommand = new byte[16];
        _PLCCommand[0] = 0x53;
        _PLCCommand[1] = 0x35;
        _PLCCommand[2] = 0x10;
        _PLCCommand[3] = 0x01;
        _PLCCommand[4] = 0x03;
        _PLCCommand[5] = 0x05;
        _PLCCommand[6] = 0x03;
        _PLCCommand[7] = 0x08;
 
        // 指定数据区
        _PLCCommand[8] = analysis.Content1;
        _PLCCommand[9] = analysis.Content3.byteValue();
 
        // 指定数据地址
        _PLCCommand[10] = (byte) (analysis.Content2 / 256);
        _PLCCommand[11] = (byte) (analysis.Content2 % 256);
 
        if (analysis.Content1 == 0x01 || analysis.Content1 == 0x06 || analysis.Content1 == 0x07) {
            if (count % 2 != 0) {
                return new OperateResultExOne<byte[]>(StringResources.Language.SiemensReadLengthMustBeEvenNumber());
            } else {
                // 指定数据长度
                _PLCCommand[12] = (byte) (count / 2 / 256);
                _PLCCommand[13] = (byte) (count / 2 % 256);
            }
        } else {
            // 指定数据长度
            _PLCCommand[12] = (byte) (count / 256);
            _PLCCommand[13] = (byte) (count % 256);
        }
 
        _PLCCommand[14] = (byte) 0xff;
        _PLCCommand[15] = 0x02;
 
        return OperateResultExOne.CreateSuccessResult(_PLCCommand);
    }
 
 
    /**
     * 生成一个写入字节数据的指令
     *
     * @param address 地址
     * @param data    数据
     * @return 带结果标识的指令
     */
    public static OperateResultExOne<byte[]> BuildWriteCommand(String address, byte[] data) {
        if (data == null) data = new byte[0];
        OperateResultExThree<Byte, Integer, Integer> analysis = AnalysisAddress(address);
        if (!analysis.IsSuccess) return OperateResultExOne.<byte[]>CreateFailedResult(analysis);
 
 
        byte[] _PLCCommand = new byte[16 + data.length];
        _PLCCommand[0] = 0x53;
        _PLCCommand[1] = 0x35;
        _PLCCommand[2] = 0x10;
        _PLCCommand[3] = 0x01;
        _PLCCommand[4] = 0x03;
        _PLCCommand[5] = 0x03;
        _PLCCommand[6] = 0x03;
        _PLCCommand[7] = 0x08;
 
        // 指定数据区
        _PLCCommand[8] = analysis.Content1;
        _PLCCommand[9] = analysis.Content3.byteValue();
 
        // 指定数据地址
        _PLCCommand[10] = (byte) (analysis.Content2 / 256);
        _PLCCommand[11] = (byte) (analysis.Content2 % 256);
 
        if (analysis.Content1 == 0x01 || analysis.Content1 == 0x06 || analysis.Content1 == 0x07) {
            if (data.length % 2 != 0) {
                return new OperateResultExOne<byte[]>(StringResources.Language.SiemensReadLengthMustBeEvenNumber());
            } else {
                // 指定数据长度
                _PLCCommand[12] = (byte) (data.length / 2 / 256);
                _PLCCommand[13] = (byte) (data.length / 2 % 256);
            }
        } else {
            // 指定数据长度
            _PLCCommand[12] = (byte) (data.length / 256);
            _PLCCommand[13] = (byte) (data.length % 256);
        }
 
        _PLCCommand[14] = (byte) 0xff;
        _PLCCommand[15] = 0x02;
 
        // 放置数据
        System.arraycopy(data, 0, _PLCCommand, 16, data.length);
 
        return OperateResultExOne.<byte[]>CreateSuccessResult(_PLCCommand);
    }
 
}