forked from PLCnext/CSharpExamples
-
Notifications
You must be signed in to change notification settings - Fork 0
/
DCG_example1.cs
221 lines (202 loc) · 5.8 KB
/
DCG_example1.cs
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
#region Copyright
//
// Copyright (c) Phoenix Contact GmbH & Co. KG. All rights reserved.
// Licensed under the MIT. See LICENSE file in the project root for full license information.
//
#endregion
using System.Iec61131Lib;
using System.Collections.Generic;
using Iec61131.Engineering.Prototypes.Common;
using Iec61131.Engineering.Prototypes.Methods;
using Iec61131.Engineering.Prototypes.Types;
using Iec61131.Engineering.Prototypes.Variables;
// This pattern represents the use case that a function block's method is executed by a another FB.
// Typically the first FB is put into a container and is accessed by a FB handle. For Download Changes support
// the FB must not be put into a container directly. This leads to a reference that cannot be removed during
// Download Change. The garbage collector will not finalize the instance.
namespace DcgBestPracticePattern2
{
[FunctionBlock]
public class SlaveFB2
{
[Input, DataType("BOOL")]
public bool In;
[Input, DataType("DINT")]
public int Handle;
[Output, DataType("DINT")]
public int Value;
// Do not permanently put a Function Block into a Container.
// This will cause a Memory leak and may cause resource leaks.
// Better create an impl class that is lazily (only when used by the active domain) added to the container and will execute all logic.
private SlaveFbImpl impl;
public SlaveFB2()
{
impl = new SlaveFbImpl();
}
~SlaveFB2()
{
if (Eclr.Environment.IsPrimaryDomain(this))
{
// The finalizer is typically executed in primary domain. This is done to access object references from this
// domain in order to do clean ups.
if (Handle != Container.InvalidHandle)
{
Container.GetInstance().Remove(Handle);
}
}
else
{
// When the type has been changed by adding, removing or changing fields by Download Changes
// then the Finalizer is executed in the secondary domain.
// In this case it is not possible to access object references from the primary domain.
}
}
[Initialization]
public void __Init()
{
}
[Execution]
public void __Process()
{
// Lazy initialization of container
if (Handle == Container.InvalidHandle)
{
Handle = Container.GetInstance().Add(impl);
}
impl.Process(this);
}
}
public class SlaveFbImpl
{
private int tempResult;
public SlaveFbImpl()
{
}
~SlaveFbImpl()
{
}
public void Process(SlaveFB2 fb)
{
// Accessing public data of the FB
if (fb.In)
{
fb.Value = tempResult;
}
}
public void Add1()
{
tempResult++;
}
public void Add10()
{
tempResult += 10;
}
}
public class Container
{
// Implementation of singleton pattern
private static Container instance;
internal static Container GetInstance()
{
if (instance == null)
{
instance = new Container();
}
return instance;
}
private Dictionary<int, SlaveFbImpl> fbs;
private int nextHandle = 1;
public const int InvalidHandle = 0;
private Container()
{
fbs = new Dictionary<int, SlaveFbImpl>();
}
~Container()
{
if (fbs != null)
{
}
}
internal int Add(SlaveFbImpl o)
{
int handle = Container.InvalidHandle;
lock (this)
{
handle = nextHandle;
fbs.Add(handle, o);
nextHandle++;
}
return handle;
}
internal bool Remove(int handle)
{
int fbHash = 0;
if (fbs.TryGetValue(handle, out SlaveFbImpl fb))
{
fbHash = fb.GetHashCode();
}
lock (this)
{
fbs.Remove(handle);
}
if (fbHash != 0)
{
return false;
}
return true;
}
internal SlaveFbImpl Get(int handle)
{
SlaveFbImpl fb;
lock (this)
{
fbs.TryGetValue(handle, out fb);
}
return fb;
}
}
[FunctionBlock]
public class MasterFB2
{
[Input, DataType("BOOL")]
public bool In;
[Input, DataType("DINT")]
public int Handle;
[Input, DataType("DINT")]
public int Job;
[Output, DataType("BOOL")]
public bool Done;
public MasterFB2()
{
}
[Initialization]
public void __Init()
{
}
[Execution]
public void __Process()
{
Done = false;
if(In)
{
SlaveFbImpl fb = Container.GetInstance().Get(Handle);
if (fb != null)
{
switch (Job)
{
case 0:
fb.Add1();
Done = true;
break;
case 1:
fb.Add10();
Done = true;
break;
default:
break;
}
}
}
}
}
}