forked from thinkgos/go-iecp5
/
csys.go
301 lines (279 loc) · 9.16 KB
/
csys.go
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
// Copyright 2020 iotopo (thinkgo@aliyun.com). All rights reserved.
// Use of this source code is governed by a version 3 of the GNU General
// Public License, license that can be found in the LICENSE file.
package asdu
import (
"time"
)
// 在控制方向系统信息的应用服务数据单元
// InterrogationCmd send a new interrogation command [C_IC_NA_1]. 总召唤命令, 只有单个信息对象(SQ = 0)
// [C_IC_NA_1] See companion standard 101, subclass 7.3.4.1
// 传送原因(coa)用于
// 控制方向:
// <6> := 激活
// <8> := 停止激活
// 监视方向:
// <7> := 激活确认
// <9> := 停止激活确认
// <10> := 激活终止
// <44> := 未知的类型标识
// <45> := 未知的传送原因
// <46> := 未知的应用服务数据单元公共地址
// <47> := 未知的信息对象地址
func InterrogationCmd(c Connect, coa CauseOfTransmission, ca CommonAddr, qoi QualifierOfInterrogation) error {
if !(coa.Cause == Activation || coa.Cause == Deactivation) {
return ErrCmdCause
}
if err := c.Params().Valid(); err != nil {
return err
}
u := NewASDU(c.Params(), Identifier{
C_IC_NA_1,
VariableStruct{IsSequence: false, Number: 1},
coa,
0,
ca,
})
if err := u.AppendInfoObjAddr(InfoObjAddrIrrelevant); err != nil {
return err
}
u.AppendBytes(byte(qoi))
return c.Send(u)
}
// CounterInterrogationCmd send Counter Interrogation command [C_CI_NA_1],计数量召唤命令,只有单个信息对象(SQ = 0)
// [C_CI_NA_1] See companion standard 101, subclass 7.3.4.2
// 传送原因(coa)用于
// 控制方向:
// <6> := 激活
// 监视方向:
// <7> := 激活确认
// <10> := 激活终止
// <44> := 未知的类型标识
// <45> := 未知的传送原因
// <46> := 未知的应用服务数据单元公共地址
// <47> := 未知的信息对象地址
func CounterInterrogationCmd(c Connect, coa CauseOfTransmission, ca CommonAddr, qcc QualifierCountCall) error {
if err := c.Params().Valid(); err != nil {
return err
}
coa.Cause = Activation
u := NewASDU(c.Params(), Identifier{
C_CI_NA_1,
VariableStruct{IsSequence: false, Number: 1},
coa,
0,
ca,
})
if err := u.AppendInfoObjAddr(InfoObjAddrIrrelevant); err != nil {
return err
}
u.AppendBytes(qcc.Value())
return c.Send(u)
}
// ReadCmd send read command [C_RD_NA_1], 读命令, 只有单个信息对象(SQ = 0)
// [C_RD_NA_1] See companion standard 101, subclass 7.3.4.3
// 传送原因(coa)用于
// 控制方向:
// <5> := 请求
// 监视方向:
// <44> := 未知的类型标识
// <45> := 未知的传送原因
// <46> := 未知的应用服务数据单元公共地址
// <47> := 未知的信息对象地址
func ReadCmd(c Connect, coa CauseOfTransmission, ca CommonAddr, ioa InfoObjAddr) error {
if err := c.Params().Valid(); err != nil {
return err
}
coa.Cause = Request
u := NewASDU(c.Params(), Identifier{
C_RD_NA_1,
VariableStruct{IsSequence: false, Number: 1},
coa,
0,
ca,
})
if err := u.AppendInfoObjAddr(ioa); err != nil {
return err
}
return c.Send(u)
}
// ClockSynchronizationCmd send clock sync command [C_CS_NA_1],时钟同步命令, 只有单个信息对象(SQ = 0)
// [C_CS_NA_1] See companion standard 101, subclass 7.3.4.4
// 传送原因(coa)用于
// 控制方向:
// <6> := 激活
// 监视方向:
// <7> := 激活确认
// <10> := 激活终止
// <44> := 未知的类型标识
// <45> := 未知的传送原因
// <46> := 未知的应用服务数据单元公共地址
// <47> := 未知的信息对象地址
func ClockSynchronizationCmd(c Connect, coa CauseOfTransmission, ca CommonAddr, t time.Time) error {
if err := c.Params().Valid(); err != nil {
return err
}
coa.Cause = Activation
u := NewASDU(c.Params(), Identifier{
C_CS_NA_1,
VariableStruct{IsSequence: false, Number: 1},
coa,
0,
ca,
})
if err := u.AppendInfoObjAddr(InfoObjAddrIrrelevant); err != nil {
return err
}
u.AppendBytes(CP56Time2a(t, u.InfoObjTimeZone)...)
return c.Send(u)
}
// TestCommand send test command [C_TS_NA_1],测试命令, 只有单个信息对象(SQ = 0)
// [C_TS_NA_1] See companion standard 101, subclass 7.3.4.5
// 传送原因(coa)用于
// 控制方向:
// <6> := 激活
// 监视方向:
// <7> := 激活确认
// <44> := 未知的类型标识
// <45> := 未知的传送原因
// <46> := 未知的应用服务数据单元公共地址
// <47> := 未知的信息对象地址
func TestCommand(c Connect, coa CauseOfTransmission, ca CommonAddr) error {
if err := c.Params().Valid(); err != nil {
return err
}
coa.Cause = Activation
u := NewASDU(c.Params(), Identifier{
C_TS_NA_1,
VariableStruct{IsSequence: false, Number: 1},
coa,
0,
ca,
})
if err := u.AppendInfoObjAddr(InfoObjAddrIrrelevant); err != nil {
return err
}
u.AppendBytes(byte(FBPTestWord&0xff), byte(FBPTestWord>>8))
return c.Send(u)
}
// ResetProcessCmd send reset process command [C_RP_NA_1],复位进程命令, 只有单个信息对象(SQ = 0)
// [C_RP_NA_1] See companion standard 101, subclass 7.3.4.6
// 传送原因(coa)用于
// 控制方向:
// <6> := 激活
// 监视方向:
// <7> := 激活确认
// <44> := 未知的类型标识
// <45> := 未知的传送原因
// <46> := 未知的应用服务数据单元公共地址
// <47> := 未知的信息对象地址
func ResetProcessCmd(c Connect, coa CauseOfTransmission, ca CommonAddr, qrp QualifierOfResetProcessCmd) error {
if err := c.Params().Valid(); err != nil {
return err
}
coa.Cause = Activation
u := NewASDU(c.Params(), Identifier{
C_RP_NA_1,
VariableStruct{IsSequence: false, Number: 1},
coa,
0,
ca,
})
if err := u.AppendInfoObjAddr(InfoObjAddrIrrelevant); err != nil {
return err
}
u.AppendBytes(byte(qrp))
return c.Send(u)
}
// DelayAcquireCommand send delay acquire command [C_CD_NA_1],延时获得命令, 只有单个信息对象(SQ = 0)
// [C_CD_NA_1] See companion standard 101, subclass 7.3.4.7
// 传送原因(coa)用于
// 控制方向:
// <3> := 突发
// <6> := 激活
// 监视方向:
// <7> := 激活确认
// <44> := 未知的类型标识
// <45> := 未知的传送原因
// <46> := 未知的应用服务数据单元公共地址
// <47> := 未知的信息对象地址
func DelayAcquireCommand(c Connect, coa CauseOfTransmission, ca CommonAddr, msec uint16) error {
if !(coa.Cause == Spontaneous || coa.Cause == Activation) {
return ErrCmdCause
}
if err := c.Params().Valid(); err != nil {
return err
}
u := NewASDU(c.Params(), Identifier{
C_CD_NA_1,
VariableStruct{IsSequence: false, Number: 1},
coa,
0,
ca,
})
if err := u.AppendInfoObjAddr(InfoObjAddrIrrelevant); err != nil {
return err
}
u.AppendCP16Time2a(msec)
return c.Send(u)
}
// TestCommandCP56Time2a send test command [C_TS_TA_1],测试命令, 只有单个信息对象(SQ = 0)
// 传送原因(coa)用于
// 控制方向:
// <6> := 激活
// 监视方向:
// <7> := 激活确认
// <44> := 未知的类型标识
// <45> := 未知的传送原因
// <46> := 未知的应用服务数据单元公共地址
// <47> := 未知的信息对象地址
func TestCommandCP56Time2a(c Connect, coa CauseOfTransmission, ca CommonAddr, t time.Time) error {
if err := c.Params().Valid(); err != nil {
return err
}
u := NewASDU(c.Params(), Identifier{
C_TS_TA_1,
VariableStruct{IsSequence: false, Number: 1},
coa,
0,
ca,
})
if err := u.AppendInfoObjAddr(InfoObjAddrIrrelevant); err != nil {
return err
}
u.AppendUint16(FBPTestWord)
u.AppendCP56Time2a(t, u.InfoObjTimeZone)
return c.Send(u)
}
// GetInterrogationCmd [C_IC_NA_1] 获取总召唤信息体(信息对象地址,召唤限定词)
func (sf *ASDU) GetInterrogationCmd() (InfoObjAddr, QualifierOfInterrogation) {
return sf.DecodeInfoObjAddr(), QualifierOfInterrogation(sf.infoObj[0])
}
// GetCounterInterrogationCmd [C_CI_NA_1] 获得计量召唤信息体(信息对象地址,计量召唤限定词)
func (sf *ASDU) GetCounterInterrogationCmd() (InfoObjAddr, QualifierCountCall) {
return sf.DecodeInfoObjAddr(), ParseQualifierCountCall(sf.infoObj[0])
}
// GetReadCmd [C_RD_NA_1] 获得读命令信息地址
func (sf *ASDU) GetReadCmd() InfoObjAddr {
return sf.DecodeInfoObjAddr()
}
// GetClockSynchronizationCmd [C_CS_NA_1] 获得时钟同步命令信息体(信息对象地址,时间)
func (sf *ASDU) GetClockSynchronizationCmd() (InfoObjAddr, time.Time) {
return sf.DecodeInfoObjAddr(), sf.DecodeCP56Time2a()
}
// GetTestCommand [C_TS_NA_1],获得测试命令信息体(信息对象地址,是否是测试字)
func (sf *ASDU) GetTestCommand() (InfoObjAddr, bool) {
return sf.DecodeInfoObjAddr(), sf.DecodeUint16() == FBPTestWord
}
// GetResetProcessCmd [C_RP_NA_1] 获得复位进程命令信息体(信息对象地址,复位进程命令限定词)
func (sf *ASDU) GetResetProcessCmd() (InfoObjAddr, QualifierOfResetProcessCmd) {
return sf.DecodeInfoObjAddr(), QualifierOfResetProcessCmd(sf.infoObj[0])
}
// GetDelayAcquireCommand [C_CD_NA_1] 获取延时获取命令信息体(信息对象地址,延时毫秒数)
func (sf *ASDU) GetDelayAcquireCommand() (InfoObjAddr, uint16) {
return sf.DecodeInfoObjAddr(), sf.DecodeUint16()
}
// GetTestCommandCP56Time2a [C_TS_TA_1],获得测试命令信息体(信息对象地址,是否是测试字)
func (sf *ASDU) GetTestCommandCP56Time2a() (InfoObjAddr, bool, time.Time) {
return sf.DecodeInfoObjAddr(), sf.DecodeUint16() == FBPTestWord, sf.DecodeCP56Time2a()
}