node-opcua-address-space 2.87.0 → 2.89.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/dist/source/address_space_ts.d.ts +4 -4
- package/dist/source/address_space_ts.js +3 -3
- package/dist/source/address_space_ts.js.map +1 -1
- package/dist/source/helpers/argument_list.js +8 -12
- package/dist/source/helpers/argument_list.js.map +1 -1
- package/dist/source/helpers/call_helpers.d.ts +1 -1
- package/dist/source/helpers/multiform_func.d.ts +8 -8
- package/dist/source/interfaces/alarms_and_conditions/ua_condition_ex.d.ts +1 -1
- package/dist/source/interfaces/extension_object_constructor.d.ts +1 -1
- package/dist/source/interfaces/state_machine/ua_state_machine_type.d.ts +2 -2
- package/dist/source/loader/generateAddressSpaceRaw.d.ts +2 -2
- package/dist/source/loader/make_xml_extension_object_parser.d.ts +1 -1
- package/dist/source/loader/namespace_post_step.d.ts +1 -1
- package/dist/source/session_context.d.ts +1 -1
- package/dist/src/address_space.js +11 -11
- package/dist/src/address_space.js.map +1 -1
- package/dist/src/apply_condition_refresh.d.ts +1 -1
- package/dist/src/base_node_impl.js +44 -44
- package/dist/src/base_node_impl.js.map +1 -1
- package/dist/src/event_data.d.ts +2 -2
- package/dist/src/extension_object_array_node.d.ts +3 -41
- package/dist/src/extension_object_array_node.js +20 -54
- package/dist/src/extension_object_array_node.js.map +1 -1
- package/dist/src/idx_iterator.d.ts +8 -0
- package/dist/src/idx_iterator.js +51 -0
- package/dist/src/idx_iterator.js.map +1 -0
- package/dist/src/nodeid_manager.d.ts +3 -3
- package/dist/src/nodeset_tools/nodeset_to_xml.d.ts +1 -1
- package/dist/src/reference_impl.js +6 -6
- package/dist/src/reference_impl.js.map +1 -1
- package/dist/src/tool_isSupertypeOf.d.ts +4 -4
- package/dist/src/ua_data_type_impl.js +12 -12
- package/dist/src/ua_data_type_impl.js.map +1 -1
- package/dist/src/ua_method_impl.js +6 -6
- package/dist/src/ua_method_impl.js.map +1 -1
- package/dist/src/ua_object_impl.js +7 -7
- package/dist/src/ua_object_impl.js.map +1 -1
- package/dist/src/ua_object_type_impl.js +6 -6
- package/dist/src/ua_object_type_impl.js.map +1 -1
- package/dist/src/ua_reference_type_impl.d.ts +1 -1
- package/dist/src/ua_reference_type_impl.js +6 -6
- package/dist/src/ua_reference_type_impl.js.map +1 -1
- package/dist/src/ua_variable_impl.d.ts +15 -9
- package/dist/src/ua_variable_impl.js +57 -50
- package/dist/src/ua_variable_impl.js.map +1 -1
- package/dist/src/ua_variable_impl_ext_obj.d.ts +10 -6
- package/dist/src/ua_variable_impl_ext_obj.js +368 -189
- package/dist/src/ua_variable_impl_ext_obj.js.map +1 -1
- package/dist/src/ua_variable_type_impl.js +7 -7
- package/dist/src/ua_variable_type_impl.js.map +1 -1
- package/dist/src/ua_view_impl.js +3 -3
- package/dist/src/ua_view_impl.js.map +1 -1
- package/package.json +40 -40
- package/source/address_space_ts.ts +1 -1
- package/source/helpers/argument_list.ts +26 -26
- package/src/extension_object_array_node.ts +25 -63
- package/src/idx_iterator.ts +52 -0
- package/src/ua_variable_impl.ts +65 -55
- package/src/ua_variable_impl_ext_obj.ts +429 -231
- package/src/ua_variable_type_impl.ts +4 -4
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
import * as chalk from "chalk";
|
|
2
1
|
import assert from "node-opcua-assert";
|
|
3
2
|
import { BindExtensionObjectOptions, UADataType, UAVariable, UAVariableType } from "node-opcua-address-space-base";
|
|
4
|
-
import { NodeClass } from "node-opcua-data-model";
|
|
5
|
-
import { getCurrentClock, PreciseClock } from "node-opcua-date-time";
|
|
3
|
+
import { coerceQualifiedName, NodeClass } from "node-opcua-data-model";
|
|
4
|
+
import { getCurrentClock, PreciseClock, coerceClock } from "node-opcua-date-time";
|
|
6
5
|
import { DataValue } from "node-opcua-data-value";
|
|
7
6
|
import { make_debugLog, make_warningLog, checkDebugFlag, make_errorLog } from "node-opcua-debug";
|
|
8
7
|
import { ExtensionObject } from "node-opcua-extension-object";
|
|
9
|
-
import { NodeId } from "node-opcua-nodeid";
|
|
10
|
-
import { StatusCodes
|
|
8
|
+
import { NodeId, NodeIdType } from "node-opcua-nodeid";
|
|
9
|
+
import { StatusCodes } from "node-opcua-status-code";
|
|
11
10
|
import { StructureField } from "node-opcua-types";
|
|
12
11
|
import { lowerFirstLetter } from "node-opcua-utils";
|
|
13
|
-
import { DataType,
|
|
12
|
+
import { DataType, VariantLike, VariantArrayType } from "node-opcua-variant";
|
|
13
|
+
import { NumericRange } from "node-opcua-numeric-range";
|
|
14
14
|
|
|
15
|
-
import { valueRankToString } from "./base_node_private";
|
|
16
15
|
import { UAVariableImpl } from "./ua_variable_impl";
|
|
17
16
|
import { UADataTypeImpl } from "./ua_data_type_impl";
|
|
17
|
+
import { IndexIterator } from "./idx_iterator";
|
|
18
18
|
|
|
19
19
|
const doDebug = checkDebugFlag(__filename);
|
|
20
20
|
const debugLog = make_debugLog(__filename);
|
|
@@ -30,42 +30,64 @@ function w(str: string, n: number): string {
|
|
|
30
30
|
function isProxy(ext: any) {
|
|
31
31
|
return ext.$isProxy ? true : false;
|
|
32
32
|
}
|
|
33
|
+
function getProxyVariable(ext: any): UAVariable | null {
|
|
34
|
+
assert(isProxy(ext));
|
|
35
|
+
return ext.$variable as UAVariable | null;
|
|
36
|
+
}
|
|
33
37
|
|
|
34
|
-
function
|
|
38
|
+
function getProxyVariableForProp(ext: any, prop: string) {
|
|
39
|
+
const uaVariable = getProxyVariable(ext);
|
|
40
|
+
if (!uaVariable) return undefined;
|
|
41
|
+
return (uaVariable as any)[prop] as UAVariableImpl | undefined;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function getProxyTarget(ext: any): any {
|
|
35
45
|
assert(isProxy(ext));
|
|
36
|
-
|
|
46
|
+
const target = ext.$proxyTarget;
|
|
47
|
+
if (target && isProxy(target)) {
|
|
48
|
+
return getProxyTarget(target);
|
|
49
|
+
}
|
|
50
|
+
return target;
|
|
37
51
|
}
|
|
38
52
|
|
|
39
53
|
function unProxy(ext: ExtensionObject) {
|
|
40
54
|
return isProxy(ext) ? getProxyTarget(ext) : ext;
|
|
41
55
|
}
|
|
42
56
|
|
|
43
|
-
function _extensionObjectFieldGetter(target: any, key: string /*, receiver*/) {
|
|
57
|
+
function _extensionObjectFieldGetter(getVariable: () => UAVariable | null, target: any, key: string /*, receiver*/) {
|
|
44
58
|
if (key === "$isProxy") {
|
|
45
59
|
return true;
|
|
46
60
|
}
|
|
47
61
|
if (key === "$proxyTarget") {
|
|
48
62
|
return target;
|
|
49
63
|
}
|
|
64
|
+
if (key === "$variable") {
|
|
65
|
+
return getVariable();
|
|
66
|
+
}
|
|
67
|
+
|
|
50
68
|
if (target[key] === undefined) {
|
|
51
69
|
return undefined;
|
|
52
70
|
}
|
|
53
71
|
return target[key];
|
|
54
72
|
}
|
|
55
|
-
|
|
56
|
-
function _extensionObjectFieldSetter(variable: UAVariable, target: any, key: string, value: any /*, receiver*/): boolean {
|
|
73
|
+
function _extensionObjectFieldSetter(getVariable: () => UAVariable | null, target: any, key: string, value: any /*, receiver*/): boolean {
|
|
57
74
|
target[key] = value;
|
|
58
|
-
|
|
75
|
+
if (isProxy(target)) {
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
const uaVariable = getVariable();
|
|
79
|
+
if (!uaVariable) return true;
|
|
80
|
+
const child = (uaVariable as any)[key] as UAVariable | null;
|
|
59
81
|
if (child && child.touchValue) {
|
|
60
82
|
child.touchValue();
|
|
61
83
|
}
|
|
62
84
|
return true; // true means the set operation has succeeded
|
|
63
85
|
}
|
|
64
86
|
|
|
65
|
-
function makeHandler(
|
|
87
|
+
function makeHandler(getVariable: () => UAVariable | null) {
|
|
66
88
|
const handler = {
|
|
67
|
-
get: _extensionObjectFieldGetter,
|
|
68
|
-
set: _extensionObjectFieldSetter.bind(null,
|
|
89
|
+
get: _extensionObjectFieldGetter.bind(null, getVariable),
|
|
90
|
+
set: _extensionObjectFieldSetter.bind(null, getVariable)
|
|
69
91
|
};
|
|
70
92
|
return handler;
|
|
71
93
|
}
|
|
@@ -82,7 +104,6 @@ export function _touchValue(property: UAVariableImpl, now: PreciseClock): void {
|
|
|
82
104
|
property.$dataValue.serverTimestamp = now.timestamp;
|
|
83
105
|
property.$dataValue.serverPicoseconds = now.picoseconds;
|
|
84
106
|
property.$dataValue.statusCode = StatusCodes.Good;
|
|
85
|
-
|
|
86
107
|
if (property.minimumSamplingInterval === 0) {
|
|
87
108
|
if (property.listenerCount("value_changed") > 0) {
|
|
88
109
|
const clonedDataValue = property.readValue();
|
|
@@ -91,54 +112,48 @@ export function _touchValue(property: UAVariableImpl, now: PreciseClock): void {
|
|
|
91
112
|
}
|
|
92
113
|
}
|
|
93
114
|
|
|
94
|
-
export function propagateTouchValueUpward(self: UAVariableImpl, now: PreciseClock): void {
|
|
115
|
+
export function propagateTouchValueUpward(self: UAVariableImpl, now: PreciseClock, cache?: Set<UAVariable>): void {
|
|
95
116
|
_touchValue(self, now);
|
|
96
117
|
if (self.parent && self.parent.nodeClass === NodeClass.Variable) {
|
|
97
118
|
const parentVar = self.parent as UAVariableImpl;
|
|
98
119
|
if (!parentVar.isExtensionObject()) return;
|
|
99
|
-
|
|
120
|
+
|
|
121
|
+
if (cache) {
|
|
122
|
+
if (cache.has(parentVar)) return;
|
|
123
|
+
cache.add(parentVar);
|
|
124
|
+
}
|
|
125
|
+
propagateTouchValueUpward(parentVar, now, cache);
|
|
100
126
|
}
|
|
101
127
|
}
|
|
102
128
|
|
|
103
|
-
function propagateTouchValueDownward(self: UAVariableImpl, now: PreciseClock): void {
|
|
129
|
+
function propagateTouchValueDownward(self: UAVariableImpl, now: PreciseClock, cache?: Set<UAVariable>): void {
|
|
104
130
|
if (!self.isExtensionObject()) return;
|
|
105
131
|
// also propagate changes to embeded variables
|
|
106
132
|
const dataTypeNode = self.getDataTypeNode();
|
|
107
133
|
const definition = dataTypeNode.getStructureDefinition();
|
|
108
134
|
for (const field of definition.fields || []) {
|
|
109
135
|
const property = self.getChildByName(field.name!) as UAVariableImpl;
|
|
136
|
+
|
|
110
137
|
if (property) {
|
|
138
|
+
|
|
139
|
+
if (cache) {
|
|
140
|
+
if (cache.has(property)) {
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
cache.add(property);
|
|
144
|
+
}
|
|
145
|
+
|
|
111
146
|
_touchValue(property, now);
|
|
112
147
|
// to do cascade recursivelly ?
|
|
113
148
|
}
|
|
114
149
|
}
|
|
115
150
|
}
|
|
116
151
|
|
|
117
|
-
export function _setExtensionObject(self: UAVariableImpl, ext: ExtensionObject | ExtensionObject[]): void {
|
|
118
|
-
// assert(!(ext as any).$isProxy, "internal error ! ExtensionObject has already been proxied !");
|
|
119
|
-
if (Array.isArray(ext)) {
|
|
120
|
-
assert(self.valueRank === 1, "Only Array is supported for the time being");
|
|
121
|
-
ext = ext.map((e) => unProxy(e));
|
|
122
|
-
self.$dataValue.value.arrayType = VariantArrayType.Array;
|
|
123
|
-
self.$extensionObject = ext.map((e) => new Proxy(e, makeHandler(self)));
|
|
124
|
-
self.$dataValue.value.dataType = DataType.ExtensionObject;
|
|
125
|
-
self.$dataValue.value.value = self.$extensionObject;
|
|
126
|
-
self.$dataValue.statusCode = StatusCodes.Good;
|
|
127
|
-
return;
|
|
128
|
-
} else {
|
|
129
|
-
ext = unProxy(ext);
|
|
130
|
-
self.$extensionObject = new Proxy(ext, makeHandler(self));
|
|
131
|
-
self.$dataValue.value.dataType = DataType.ExtensionObject;
|
|
132
|
-
self.$dataValue.value.value = self.$extensionObject;
|
|
133
|
-
self.$dataValue.statusCode = StatusCodes.Good;
|
|
134
|
-
}
|
|
135
152
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
}
|
|
153
|
+
export function setExtensionObjectPartialValue(node: UAVariableImpl, partialObject: any, sourceTimestamp?: PreciseClock) {
|
|
154
|
+
|
|
155
|
+
const variablesToUpdate: Set<UAVariableImpl> = new Set();
|
|
140
156
|
|
|
141
|
-
export function setExtensionObjectValue(node: UAVariableImpl, partialObject: any) {
|
|
142
157
|
const extensionObject = node.$extensionObject;
|
|
143
158
|
if (!extensionObject) {
|
|
144
159
|
throw new Error("setExtensionObjectValue node has no extension object " + node.browseName.toString());
|
|
@@ -150,12 +165,30 @@ export function setExtensionObjectValue(node: UAVariableImpl, partialObject: any
|
|
|
150
165
|
if (extObject[prop] instanceof Object) {
|
|
151
166
|
_update_extension_object(extObject[prop], partialObject1[prop]);
|
|
152
167
|
} else {
|
|
153
|
-
|
|
168
|
+
|
|
169
|
+
if (isProxy(extObject)) {
|
|
170
|
+
// collect element we have to update
|
|
171
|
+
const target = getProxyTarget(extObject);
|
|
172
|
+
assert(!isProxy(target), "something wierd!");
|
|
173
|
+
target[prop] = partialObject1[prop];
|
|
174
|
+
const variable = getProxyVariableForProp(extObject, prop);
|
|
175
|
+
variable && variablesToUpdate.add(variable as UAVariableImpl);
|
|
176
|
+
} else {
|
|
177
|
+
extObject[prop] = partialObject1[prop];
|
|
178
|
+
}
|
|
154
179
|
}
|
|
155
180
|
}
|
|
156
181
|
}
|
|
157
|
-
|
|
158
182
|
_update_extension_object(extensionObject, partialObject);
|
|
183
|
+
|
|
184
|
+
const now = sourceTimestamp || getCurrentClock();
|
|
185
|
+
const cache: Set<UAVariable> = new Set();
|
|
186
|
+
for (const c of variablesToUpdate) {
|
|
187
|
+
if (cache.has(c)) continue;
|
|
188
|
+
propagateTouchValueUpward(c, now, cache);
|
|
189
|
+
propagateTouchValueDownward(c, now, cache);
|
|
190
|
+
cache.add(c);
|
|
191
|
+
}
|
|
159
192
|
}
|
|
160
193
|
|
|
161
194
|
function getOrCreateProperty(
|
|
@@ -193,7 +226,10 @@ function getOrCreateProperty(
|
|
|
193
226
|
browseName: { namespaceIndex: structureNamespace, name: field.name!.toString() },
|
|
194
227
|
componentOf: variableNode,
|
|
195
228
|
dataType: field.dataType,
|
|
196
|
-
minimumSamplingInterval: variableNode.minimumSamplingInterval
|
|
229
|
+
minimumSamplingInterval: variableNode.minimumSamplingInterval,
|
|
230
|
+
accessLevel: variableNode.accessLevel,
|
|
231
|
+
accessRestrictions: variableNode.accessRestrictions,
|
|
232
|
+
rolePermissions: variableNode.rolePermissions
|
|
197
233
|
}) as UAVariableImpl;
|
|
198
234
|
assert(property.minimumSamplingInterval === variableNode.minimumSamplingInterval);
|
|
199
235
|
}
|
|
@@ -207,164 +243,230 @@ function prepareVariantValue(dataType: DataType, value: VariantLike): VariantLik
|
|
|
207
243
|
return value;
|
|
208
244
|
}
|
|
209
245
|
|
|
210
|
-
function
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
246
|
+
function installExt(uaVariable: UAVariableImpl, ext: ExtensionObject) {
|
|
247
|
+
ext = unProxy(ext);
|
|
248
|
+
uaVariable.$extensionObject = new Proxy(ext, makeHandler(() => uaVariable));
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
const addressSpace = uaVariable.addressSpace;
|
|
252
|
+
const definition = uaVariable.dataTypeObj.getStructureDefinition();
|
|
253
|
+
const structure = addressSpace.findDataType("Structure")!;
|
|
254
|
+
for (const field of definition.fields || []) {
|
|
255
|
+
if (field.dataType) {
|
|
256
|
+
const dataTypeNode = addressSpace.findDataType(field.dataType);
|
|
257
|
+
// istanbul ignore next
|
|
258
|
+
if (dataTypeNode && dataTypeNode.isSupertypeOf(structure)) {
|
|
259
|
+
// sub structure .. let make an handler too
|
|
260
|
+
const camelCaseName = lowerFirstLetter(field.name!);
|
|
261
|
+
|
|
262
|
+
const subExtObj = uaVariable.$extensionObject[camelCaseName];
|
|
263
|
+
if (subExtObj) {
|
|
264
|
+
uaVariable.$extensionObject[camelCaseName] = new Proxy(subExtObj, makeHandler(() => {
|
|
265
|
+
return uaVariable.getComponentByName(field.name!) as UAVariable | null;
|
|
266
|
+
}));
|
|
267
|
+
} else {
|
|
268
|
+
warningLog("extension object is null");
|
|
221
269
|
}
|
|
222
|
-
const value = prepareVariantValue(dataType, propertyValue);
|
|
223
|
-
propertyNode.$dataValue.statusCode = StatusCodes.Good;
|
|
224
|
-
propertyNode.$dataValue.value.dataType = dataType;
|
|
225
|
-
propertyNode.$dataValue.value.value = value;
|
|
226
|
-
return new DataValue(propertyNode.$dataValue);
|
|
227
|
-
},
|
|
228
|
-
timestamped_set: (_dataValue: DataValue, callback: CallbackT<StatusCode>) => {
|
|
229
|
-
callback(null, StatusCodes.BadNotWritable);
|
|
230
270
|
}
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
234
273
|
}
|
|
235
274
|
|
|
236
275
|
export function _installExtensionObjectBindingOnProperties(
|
|
237
|
-
|
|
238
|
-
options
|
|
276
|
+
uaVariable: UAVariableImpl,
|
|
277
|
+
options?: BindExtensionObjectOptions
|
|
239
278
|
): void {
|
|
240
|
-
|
|
241
|
-
|
|
279
|
+
|
|
280
|
+
// may be extension object mechanism has alreday been install
|
|
281
|
+
// in this case we just need to rebind the properties...
|
|
282
|
+
if (uaVariable.$extensionObject) {
|
|
283
|
+
const extObj = uaVariable.$extensionObject;
|
|
284
|
+
uaVariable.bindExtensionObject(extObj, { createMissingProp: true, force: true });
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
if (uaVariable.$$extensionObjectArray) {
|
|
288
|
+
const extObj = uaVariable.$$extensionObjectArray;
|
|
289
|
+
_bindExtensionObjectArrayOrMatrix(uaVariable, extObj, { createMissingProp: true, force: true });
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const dataValue = uaVariable.readValue();
|
|
294
|
+
const extObj = dataValue.value.value;
|
|
295
|
+
if (extObj instanceof ExtensionObject) {
|
|
296
|
+
uaVariable.bindExtensionObject(extObj, { createMissingProp: true, force: true });
|
|
297
|
+
} else if (extObj instanceof Array) {
|
|
298
|
+
|
|
299
|
+
// istanbul ignore else
|
|
300
|
+
if (dataValue.value.arrayType === VariantArrayType.Array || dataValue.value.arrayType === VariantArrayType.Matrix) {
|
|
301
|
+
_bindExtensionObjectArrayOrMatrix(uaVariable, extObj, { createMissingProp: true, force: true });
|
|
302
|
+
} else {
|
|
303
|
+
throw new Error("Internal Error, unexpected case");
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
function _installFields2(uaVariable: UAVariableImpl, { get, set }: {
|
|
309
|
+
get: (fieldName: string) => any,
|
|
310
|
+
set: (fieldName: string, value: any, sourceTime: PreciseClock) => void;
|
|
311
|
+
}, options?: BindExtensionObjectOptions) {
|
|
312
|
+
|
|
313
|
+
options = options || { createMissingProp: false };
|
|
314
|
+
const dt = uaVariable.getDataTypeNode();
|
|
242
315
|
const definition = dt.getStructureDefinition();
|
|
243
316
|
|
|
244
317
|
for (const field of definition.fields || []) {
|
|
245
|
-
|
|
318
|
+
|
|
246
319
|
if (NodeId.sameNodeId(NodeId.nullNodeId, field.dataType)) {
|
|
247
320
|
warningLog("field.dataType is null ! ", field.name, NodeId.nullNodeId.toString());
|
|
248
321
|
warningLog(field.toString());
|
|
249
322
|
warningLog(" dataType replaced with BaseDataType ");
|
|
250
323
|
warningLog(definition.toString());
|
|
251
|
-
field.dataType =
|
|
324
|
+
field.dataType = uaVariable.resolveNodeId("BaseDataType");
|
|
252
325
|
}
|
|
253
326
|
|
|
254
|
-
const propertyNode = getOrCreateProperty(
|
|
327
|
+
const propertyNode = getOrCreateProperty(uaVariable, field, options);
|
|
255
328
|
if (!propertyNode) {
|
|
256
329
|
continue;
|
|
257
330
|
}
|
|
258
|
-
propertyNode.$dataValue.statusCode = StatusCodes.Good;
|
|
259
|
-
propertyNode.touchValue();
|
|
260
|
-
|
|
261
|
-
const basicDataType = addressSpace.findCorrespondingBasicDataType(field.dataType);
|
|
262
331
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
332
|
+
propertyNode.$dataValue.statusCode = StatusCodes.Good;
|
|
333
|
+
propertyNode.$dataValue.sourceTimestamp = uaVariable.$dataValue.sourceTimestamp;
|
|
334
|
+
propertyNode.$dataValue.sourcePicoseconds = uaVariable.$dataValue.sourcePicoseconds;
|
|
335
|
+
propertyNode.$dataValue.serverTimestamp = uaVariable.$dataValue.serverTimestamp;
|
|
336
|
+
propertyNode.$dataValue.serverPicoseconds = uaVariable.$dataValue.serverPicoseconds;
|
|
337
|
+
propertyNode.$dataValue.value.dataType = propertyNode.dataTypeObj.basicDataType;
|
|
338
|
+
propertyNode.$dataValue.value.arrayType = propertyNode.valueRank === -1 ? VariantArrayType.Scalar : (propertyNode.valueRank === 1 ? VariantArrayType.Array : VariantArrayType.Matrix)
|
|
339
|
+
propertyNode.$dataValue.value.dimensions =propertyNode.valueRank > 1 ? propertyNode.arrayDimensions : null;
|
|
340
|
+
|
|
341
|
+
const fieldName = field.name!;
|
|
342
|
+
installDataValueGetter(propertyNode, () => get(fieldName));
|
|
343
|
+
assert(propertyNode._inner_replace_dataValue);
|
|
344
|
+
propertyNode._inner_replace_dataValue = (dataValue: DataValue, indexRange?: NumericRange | null) => {
|
|
345
|
+
/** */
|
|
346
|
+
const sourceTime = coerceClock(dataValue.sourceTimestamp, dataValue.sourcePicoseconds);
|
|
347
|
+
const value = dataValue.value.value;
|
|
348
|
+
set(field.name!, value, sourceTime);
|
|
279
349
|
}
|
|
280
350
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
new Variant({
|
|
293
|
-
dataType: DataType.Null
|
|
294
|
-
})
|
|
295
|
-
);
|
|
296
|
-
} else {
|
|
297
|
-
const preparedValue = prepareVariantValue(basicDataType, prop);
|
|
298
|
-
propertyNode._internal_set_value(
|
|
299
|
-
new Variant({
|
|
300
|
-
dataType: basicDataType,
|
|
301
|
-
value: preparedValue
|
|
302
|
-
})
|
|
303
|
-
);
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
307
|
-
|
|
308
|
-
// property.camelCaseName = camelCaseName;
|
|
309
|
-
propertyNode.setValueFromSource = function (this: UAVariableImpl, variant: VariantLike) {
|
|
310
|
-
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
311
|
-
const inner_this = this;
|
|
312
|
-
const variant1 = Variant.coerce(variant);
|
|
313
|
-
inner_this.verifyVariantCompatibility(variant1);
|
|
314
|
-
|
|
315
|
-
// because self.$extensionObject is a Proxy with handlers that
|
|
316
|
-
// cascade the chagne we do not need to call touchValue() here
|
|
317
|
-
variableNode.$extensionObject[camelCaseName] = variant1.value;
|
|
318
|
-
};
|
|
351
|
+
if (propertyNode.dataTypeObj.basicDataType === DataType.ExtensionObject) {
|
|
352
|
+
_installFields2(propertyNode, {
|
|
353
|
+
get: (fieldName: string) => {
|
|
354
|
+
const mainFieldName = field.name!;
|
|
355
|
+
return get(mainFieldName)[lowerFirstLetter(fieldName)];
|
|
356
|
+
},
|
|
357
|
+
set: (fieldName: string, value: any, sourceTime: PreciseClock) => {
|
|
358
|
+
const mainFieldName = field.name!;
|
|
359
|
+
get(mainFieldName)[lowerFirstLetter(fieldName)] = value;
|
|
360
|
+
}
|
|
361
|
+
}, options);
|
|
319
362
|
}
|
|
320
|
-
assert(propertyNode.readValue().statusCode.equals(StatusCodes.Good));
|
|
321
|
-
bindProperty(variableNode, propertyNode, camelCaseName, basicDataType);
|
|
322
363
|
}
|
|
323
364
|
}
|
|
324
365
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
366
|
+
function installDataValueGetter(propertyNode: UAVariableImpl, get: () => any) {
|
|
367
|
+
Object.defineProperty(propertyNode.$dataValue.value, "value", { get });
|
|
368
|
+
const $ = propertyNode.$dataValue;
|
|
369
|
+
Object.defineProperty(propertyNode, "$dataValue", {
|
|
370
|
+
get() {
|
|
371
|
+
return $;
|
|
372
|
+
},
|
|
373
|
+
set: (value) => {
|
|
374
|
+
throw new Error("$dataValue is now frozen and should not be modified this way !\n contact sterfive.com");
|
|
375
|
+
}
|
|
376
|
+
});
|
|
377
|
+
}
|
|
333
378
|
|
|
334
|
-
|
|
379
|
+
function isVariableContainingExtensionObject(uaVariable: UAVariableImpl): boolean {
|
|
380
|
+
const addressSpace = uaVariable.addressSpace;
|
|
335
381
|
const structure = addressSpace.findDataType("Structure");
|
|
336
|
-
let extensionObject_;
|
|
337
382
|
|
|
338
383
|
if (!structure) {
|
|
339
384
|
// the addressSpace is limited and doesn't provide extension object
|
|
340
385
|
// bindExtensionObject cannot be performed and shall finish here.
|
|
341
|
-
return
|
|
386
|
+
return false;
|
|
342
387
|
}
|
|
343
388
|
|
|
344
389
|
assert(structure.browseName.toString() === "Structure", "expecting DataType Structure to be in IAddressSpace");
|
|
345
390
|
|
|
346
|
-
const dt =
|
|
391
|
+
const dt = uaVariable.getDataTypeNode() as UADataTypeImpl;
|
|
347
392
|
if (!dt.isSupertypeOf(structure)) {
|
|
393
|
+
return false;
|
|
394
|
+
}
|
|
395
|
+
return true;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
function _innerBindExtensionObjectScalar(uaVariable: UAVariableImpl,
|
|
399
|
+
{ get, set }: {
|
|
400
|
+
get: () => ExtensionObject;
|
|
401
|
+
set: (value: ExtensionObject, sourceTimestamp: PreciseClock) => void;
|
|
402
|
+
},
|
|
403
|
+
options?: BindExtensionObjectOptions
|
|
404
|
+
) {
|
|
405
|
+
|
|
406
|
+
uaVariable.$dataValue.statusCode = StatusCodes.Good;
|
|
407
|
+
uaVariable.$dataValue.value.dataType = DataType.ExtensionObject;
|
|
408
|
+
uaVariable.$dataValue.value.arrayType = VariantArrayType.Scalar;
|
|
409
|
+
|
|
410
|
+
uaVariable.setValueFromSource = function (this: UAVariableImpl, variant: VariantLike) {
|
|
411
|
+
setExtensionObjectPartialValue(this, variant.value);
|
|
412
|
+
};
|
|
413
|
+
|
|
414
|
+
installDataValueGetter(uaVariable, get);
|
|
415
|
+
assert(uaVariable._inner_replace_dataValue);
|
|
416
|
+
uaVariable._inner_replace_dataValue = (dataValue: DataValue, indexRange?: NumericRange | null) => {
|
|
417
|
+
/** */
|
|
418
|
+
const ext = dataValue.value.value;
|
|
419
|
+
const sourceTime = coerceClock(dataValue.sourceTimestamp, dataValue.sourcePicoseconds);
|
|
420
|
+
set(ext, sourceTime);
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
_installFields2(uaVariable, {
|
|
424
|
+
get: (fieldName: string) => {
|
|
425
|
+
const extObj = get() as any;
|
|
426
|
+
return extObj[lowerFirstLetter(fieldName)];
|
|
427
|
+
},
|
|
428
|
+
set: (fieldName: string, value: any, sourceTime: PreciseClock) => {
|
|
429
|
+
const extObj = get() as any;
|
|
430
|
+
extObj[lowerFirstLetter(fieldName)] = value;
|
|
431
|
+
//1 propagateTouchValueDownward(uaVariable, sourceTime);
|
|
432
|
+
//1 propagateTouchValueUpward(uaVariable, sourceTime);
|
|
433
|
+
}
|
|
434
|
+
}, options);
|
|
435
|
+
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
|
|
439
|
+
export function _bindExtensionObject(
|
|
440
|
+
uaVariable: UAVariableImpl,
|
|
441
|
+
optionalExtensionObject?: ExtensionObject,
|
|
442
|
+
options?: BindExtensionObjectOptions
|
|
443
|
+
): ExtensionObject | null {
|
|
444
|
+
options = options || { createMissingProp: false };
|
|
445
|
+
|
|
446
|
+
if (!isVariableContainingExtensionObject(uaVariable)) {
|
|
348
447
|
return null;
|
|
349
448
|
}
|
|
350
449
|
|
|
351
|
-
|
|
450
|
+
const addressSpace = uaVariable.addressSpace;
|
|
451
|
+
let extensionObject_;
|
|
452
|
+
|
|
453
|
+
// istanbul ignore next
|
|
454
|
+
if (uaVariable.valueRank !== -1 && uaVariable.valueRank !== 1) {
|
|
352
455
|
throw new Error("Cannot bind an extension object here, valueRank must be scalar (-1) or one-dimensional (1)");
|
|
353
456
|
}
|
|
354
|
-
|
|
457
|
+
|
|
355
458
|
// istanbul ignore next
|
|
356
|
-
|
|
357
|
-
debugLog(" ------------------------------ binding ", self.browseName.toString(), self.nodeId.toString());
|
|
358
|
-
}
|
|
459
|
+
doDebug && debugLog(" ------------------------------ binding ", uaVariable.browseName.toString(), uaVariable.nodeId.toString());
|
|
359
460
|
|
|
360
461
|
// ignore bindExtensionObject on sub extension object, bindExtensionObject has to be called from the top most object
|
|
361
462
|
if (
|
|
362
463
|
!options.force &&
|
|
363
|
-
|
|
364
|
-
(
|
|
464
|
+
uaVariable.parent &&
|
|
465
|
+
(uaVariable.parent.nodeClass === NodeClass.Variable || uaVariable.parent.nodeClass === NodeClass.VariableType)
|
|
365
466
|
) {
|
|
366
|
-
const parentDataType = (
|
|
467
|
+
const parentDataType = (uaVariable.parent as UAVariable | UAVariableType).dataType;
|
|
367
468
|
const dataTypeNode = addressSpace.findNode(parentDataType) as UADataType;
|
|
469
|
+
const structure = addressSpace.findDataType("Structure")!;
|
|
368
470
|
// istanbul ignore next
|
|
369
471
|
if (dataTypeNode && dataTypeNode.isSupertypeOf(structure)) {
|
|
370
472
|
// warningLog(
|
|
@@ -379,115 +481,212 @@ export function _bindExtensionObject(
|
|
|
379
481
|
}
|
|
380
482
|
|
|
381
483
|
// -------------------- make sure we do not bind a variable twice ....
|
|
382
|
-
if (
|
|
484
|
+
if (uaVariable.$extensionObject && !optionalExtensionObject) {
|
|
383
485
|
// istanbul ignore next
|
|
384
|
-
if (!
|
|
486
|
+
if (!uaVariable.checkExtensionObjectIsCorrect(uaVariable.$extensionObject!)) {
|
|
385
487
|
warningLog(
|
|
386
488
|
"on node : ",
|
|
387
|
-
|
|
388
|
-
|
|
489
|
+
uaVariable.browseName.toString(),
|
|
490
|
+
uaVariable.nodeId.toString(),
|
|
389
491
|
"dataType=",
|
|
390
|
-
|
|
492
|
+
uaVariable.dataType.toString({ addressSpace: uaVariable.addressSpace })
|
|
391
493
|
);
|
|
392
|
-
warningLog(
|
|
494
|
+
warningLog(uaVariable.$extensionObject?.toString());
|
|
393
495
|
throw new Error(
|
|
394
496
|
"bindExtensionObject: $extensionObject is incorrect: we are expecting a " +
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
497
|
+
uaVariable.dataType.toString({ addressSpace: uaVariable.addressSpace }) +
|
|
498
|
+
" but we got a " +
|
|
499
|
+
uaVariable.$extensionObject?.constructor.name
|
|
398
500
|
);
|
|
399
501
|
}
|
|
400
|
-
return
|
|
401
|
-
// throw new Error("Variable already bound");
|
|
502
|
+
return uaVariable.$extensionObject;
|
|
402
503
|
}
|
|
403
504
|
|
|
404
|
-
// ------------------------------------------------------
|
|
405
|
-
// make sure we have a structure
|
|
406
|
-
// ------------------------------------------------------
|
|
407
|
-
const s = self.readValue();
|
|
408
|
-
|
|
409
505
|
// istanbul ignore next
|
|
410
|
-
if (
|
|
411
|
-
warningLog("Warning the DataType associated with this Variable is abstract ",
|
|
506
|
+
if (uaVariable.dataTypeObj.isAbstract) {
|
|
507
|
+
warningLog("Warning the DataType associated with this Variable is abstract ", uaVariable.dataTypeObj.browseName.toString());
|
|
412
508
|
warningLog("You need to provide a extension object yourself ");
|
|
413
509
|
throw new Error("bindExtensionObject requires a extensionObject as associated dataType is only abstract");
|
|
414
510
|
}
|
|
415
511
|
|
|
512
|
+
const s = uaVariable.readValue();
|
|
416
513
|
if (s.value && s.value.dataType === DataType.ExtensionObject && s.value.value && optionalExtensionObject) {
|
|
417
514
|
// we want to replace the extension object
|
|
418
515
|
s.value.value = null;
|
|
419
516
|
}
|
|
420
517
|
innerBindExtensionObject();
|
|
421
|
-
assert(
|
|
422
|
-
return
|
|
518
|
+
assert(uaVariable.$extensionObject instanceof Object);
|
|
519
|
+
return uaVariable.$extensionObject;
|
|
423
520
|
|
|
424
521
|
function innerBindExtensionObject() {
|
|
522
|
+
|
|
425
523
|
if (s.value && (s.value.dataType === DataType.Null || (s.value.dataType === DataType.ExtensionObject && !s.value.value))) {
|
|
426
|
-
if (
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
timestamped_get() {
|
|
433
|
-
const d = new DataValue(self.$dataValue);
|
|
434
|
-
d.value.value = self.$extensionObject ? self.$extensionObject.clone() : null;
|
|
435
|
-
return d;
|
|
436
|
-
},
|
|
437
|
-
timestamped_set(dataValue: DataValue, callback: CallbackT<StatusCode>) {
|
|
438
|
-
const ext = dataValue.value.value;
|
|
439
|
-
if (!self.checkExtensionObjectIsCorrect(ext)) {
|
|
440
|
-
return callback(null, StatusCodes.BadInvalidArgument);
|
|
441
|
-
}
|
|
442
|
-
_setExtensionObject(self, ext);
|
|
443
|
-
callback(null, StatusCodes.Good);
|
|
444
|
-
}
|
|
445
|
-
},
|
|
446
|
-
true
|
|
447
|
-
);
|
|
448
|
-
_setExtensionObject(self, extensionObject_);
|
|
449
|
-
} else if (self.valueRank === 1 /** Array */) {
|
|
450
|
-
// create a structure and bind it
|
|
451
|
-
|
|
452
|
-
extensionObject_ = optionalExtensionObject || [];
|
|
453
|
-
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
454
|
-
self.bindVariable(
|
|
524
|
+
if (uaVariable.valueRank === -1 /** Scalar */) {
|
|
525
|
+
extensionObject_ = optionalExtensionObject || addressSpace.constructExtensionObject(uaVariable.dataType, {});
|
|
526
|
+
|
|
527
|
+
installExt(uaVariable, extensionObject_);
|
|
528
|
+
|
|
529
|
+
_innerBindExtensionObjectScalar(uaVariable,
|
|
455
530
|
{
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
return d;
|
|
463
|
-
},
|
|
464
|
-
timestamped_set(dataValue: DataValue, callback: CallbackT<StatusCode>) {
|
|
465
|
-
const ext = dataValue.value.value;
|
|
466
|
-
if (!self.checkExtensionObjectIsCorrect(ext)) {
|
|
467
|
-
return callback(null, StatusCodes.BadInvalidArgument);
|
|
468
|
-
}
|
|
469
|
-
_setExtensionObject(self, ext);
|
|
470
|
-
callback(null, StatusCodes.Good);
|
|
471
|
-
}
|
|
472
|
-
},
|
|
473
|
-
true
|
|
474
|
-
);
|
|
475
|
-
_setExtensionObject(self, extensionObject_);
|
|
531
|
+
get: () => uaVariable.$extensionObject,
|
|
532
|
+
set: (value: ExtensionObject) => installExt(uaVariable, value)
|
|
533
|
+
}, options);
|
|
534
|
+
return;
|
|
535
|
+
} else if (uaVariable.valueRank === 1 /** Array */) {
|
|
536
|
+
throw new Error("Should not get there ! Please fix me");
|
|
476
537
|
} else {
|
|
477
|
-
errorLog(
|
|
478
|
-
errorLog("Unsupported case ! valueRank= ",
|
|
538
|
+
errorLog(uaVariable.toString());
|
|
539
|
+
errorLog("Unsupported case ! valueRank= ", uaVariable.valueRank);
|
|
479
540
|
}
|
|
480
541
|
} else {
|
|
481
542
|
// verify that variant has the correct type
|
|
482
543
|
assert(s.value.dataType === DataType.ExtensionObject);
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
544
|
+
installExt(uaVariable, s.value.value);
|
|
545
|
+
_innerBindExtensionObjectScalar(uaVariable,
|
|
546
|
+
{
|
|
547
|
+
get: () => uaVariable.$extensionObject,
|
|
548
|
+
set: (value: ExtensionObject) => installExt(uaVariable, value)
|
|
549
|
+
}, options);
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
const getIndexAsText = (index: number | number[]): string => {
|
|
555
|
+
if (typeof index === "number")
|
|
556
|
+
return `${index}`;
|
|
557
|
+
return `${index.map((a) => a.toString()).join(",")}`;
|
|
558
|
+
}
|
|
559
|
+
const composeBrowseNameAndNodeId = (uaVariable: UAVariable, indexes: number[]) => {
|
|
560
|
+
const iAsText = getIndexAsText(indexes);
|
|
561
|
+
const browseName = coerceQualifiedName(iAsText);
|
|
562
|
+
let nodeId: NodeId | undefined;
|
|
563
|
+
if (uaVariable.nodeId.identifierType === NodeIdType.STRING) {
|
|
564
|
+
nodeId = new NodeId(NodeIdType.STRING, uaVariable.nodeId.value as string + `[${iAsText}]`, uaVariable.nodeId.namespace);
|
|
565
|
+
}
|
|
566
|
+
return { browseName, nodeId };
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
|
|
570
|
+
// eslint-disable-next-line max-statements
|
|
571
|
+
export function _bindExtensionObjectArrayOrMatrix(
|
|
572
|
+
uaVariable: UAVariableImpl,
|
|
573
|
+
optionalExtensionObjectArray?: ExtensionObject[],
|
|
574
|
+
options?: BindExtensionObjectOptions
|
|
575
|
+
): ExtensionObject[] {
|
|
576
|
+
// istanbul ignore next
|
|
577
|
+
if (uaVariable.valueRank < 1) {
|
|
578
|
+
throw new Error("Variable must be a MultiDimensional array");
|
|
579
|
+
}
|
|
580
|
+
const arrayDimensions = uaVariable.arrayDimensions || [];
|
|
581
|
+
// istanbul ignore next
|
|
582
|
+
if (!isVariableContainingExtensionObject(uaVariable)) {
|
|
583
|
+
return [];
|
|
584
|
+
}
|
|
585
|
+
if ((arrayDimensions.length === 0 || arrayDimensions.length === 1 && arrayDimensions[0] === 0) && optionalExtensionObjectArray) {
|
|
586
|
+
arrayDimensions[0] = optionalExtensionObjectArray.length;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
const totalLength = arrayDimensions.reduce((p, c) => p * c, 1);
|
|
590
|
+
|
|
591
|
+
/** */
|
|
592
|
+
const addressSpace = uaVariable.addressSpace;
|
|
593
|
+
if (optionalExtensionObjectArray) {
|
|
594
|
+
if (optionalExtensionObjectArray.length !== totalLength) {
|
|
595
|
+
throw new Error(`optionalExtensionObjectArray must have the expected number of element matching ${arrayDimensions}`)
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
if (!optionalExtensionObjectArray) {
|
|
599
|
+
optionalExtensionObjectArray = [];
|
|
600
|
+
for (let i = 0; i < totalLength; i++) {
|
|
601
|
+
optionalExtensionObjectArray[i] = addressSpace.constructExtensionObject(uaVariable.dataType, {});;
|
|
486
602
|
}
|
|
487
|
-
_installExtensionObjectBindingOnProperties(self, options!);
|
|
488
603
|
}
|
|
604
|
+
uaVariable.$$extensionObjectArray = optionalExtensionObjectArray;
|
|
605
|
+
uaVariable.$dataValue.value.arrayType = uaVariable.valueRank === 1 ? VariantArrayType.Array : VariantArrayType.Matrix;
|
|
606
|
+
uaVariable.$dataValue.value.dimensions = uaVariable.valueRank === 1 ? null : (uaVariable.arrayDimensions || []);
|
|
607
|
+
uaVariable.$dataValue.value.dataType = DataType.ExtensionObject;
|
|
608
|
+
uaVariable.$dataValue.value.value = uaVariable.$$extensionObjectArray;
|
|
609
|
+
|
|
610
|
+
uaVariable.bindVariable({
|
|
611
|
+
get: () => uaVariable.$dataValue.value
|
|
612
|
+
}, true);
|
|
613
|
+
|
|
614
|
+
|
|
615
|
+
const namespace = uaVariable.namespace;
|
|
616
|
+
const indexIterator = new IndexIterator(arrayDimensions);
|
|
617
|
+
for (let i = 0; i < totalLength; i++) {
|
|
618
|
+
|
|
619
|
+
const index = indexIterator.next();
|
|
620
|
+
|
|
621
|
+
const { browseName, nodeId } = composeBrowseNameAndNodeId(uaVariable, index);
|
|
622
|
+
|
|
623
|
+
|
|
624
|
+
|
|
625
|
+
let uaElement = uaVariable.getComponentByName(browseName) as UAVariableImpl | null;
|
|
626
|
+
if (!uaElement) {
|
|
627
|
+
uaElement = namespace.addVariable({
|
|
628
|
+
browseName,
|
|
629
|
+
nodeId,
|
|
630
|
+
componentOf: uaVariable,
|
|
631
|
+
dataType: uaVariable.dataType,
|
|
632
|
+
valueRank: -1,
|
|
633
|
+
accessLevel: uaVariable.accessLevel
|
|
634
|
+
}) as UAVariableImpl;
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
uaElement.$dataValue.value.dataType = DataType.ExtensionObject;
|
|
638
|
+
uaElement.$dataValue.statusCode = StatusCodes.Good;
|
|
639
|
+
uaElement.$dataValue.sourceTimestamp = uaVariable.$dataValue.sourceTimestamp;
|
|
640
|
+
uaElement.$dataValue.sourcePicoseconds = uaVariable.$dataValue.sourcePicoseconds;
|
|
641
|
+
uaElement.$dataValue.serverTimestamp = uaVariable.$dataValue.serverTimestamp;
|
|
642
|
+
uaElement.$dataValue.serverPicoseconds = uaVariable.$dataValue.serverPicoseconds;
|
|
643
|
+
uaElement.$dataValue.value.dataType = DataType.ExtensionObject;
|
|
644
|
+
uaElement.$dataValue.value.arrayType = VariantArrayType.Scalar;
|
|
645
|
+
|
|
646
|
+
{
|
|
647
|
+
const capturedIndex = i;
|
|
648
|
+
_innerBindExtensionObjectScalar(uaElement,
|
|
649
|
+
{
|
|
650
|
+
get: () => uaVariable.$$extensionObjectArray[capturedIndex],
|
|
651
|
+
set: (newValue: ExtensionObject, sourceTimestamp: PreciseClock) => {
|
|
652
|
+
uaVariable.$$extensionObjectArray[capturedIndex] = newValue;
|
|
653
|
+
uaVariable.touchValue();
|
|
654
|
+
propagateTouchValueDownward(uaVariable, sourceTimestamp);
|
|
655
|
+
propagateTouchValueUpward(uaVariable, sourceTimestamp);
|
|
656
|
+
},
|
|
657
|
+
|
|
658
|
+
}, { ...options, force: true });
|
|
659
|
+
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
return uaVariable.$$extensionObjectArray;
|
|
489
663
|
}
|
|
490
664
|
|
|
665
|
+
export function getElement(path: string | string[], data: any) {
|
|
666
|
+
if (typeof path === "string") {
|
|
667
|
+
path = path.split(".");
|
|
668
|
+
}
|
|
669
|
+
let a = data;
|
|
670
|
+
for (const e of path) {
|
|
671
|
+
a = a[e];
|
|
672
|
+
}
|
|
673
|
+
return a;
|
|
674
|
+
}
|
|
675
|
+
export function setElement(path: string | string[], data: any, value: any) {
|
|
676
|
+
if (typeof path === "string") {
|
|
677
|
+
path = path.split(".");
|
|
678
|
+
}
|
|
679
|
+
const last: string = path.pop()!;
|
|
680
|
+
let a = data;
|
|
681
|
+
for (const e of path) {
|
|
682
|
+
a = a[e];
|
|
683
|
+
}
|
|
684
|
+
a[last] = value;
|
|
685
|
+
}
|
|
686
|
+
export function incrementElement(path: string | string[], data: any) {
|
|
687
|
+
const value = getElement(path, data);
|
|
688
|
+
setElement(path, data, value + 1);
|
|
689
|
+
}
|
|
491
690
|
export function extractPartialData(path: string | string[], extensionObject: ExtensionObject) {
|
|
492
691
|
let name;
|
|
493
692
|
if (typeof path === "string") {
|
|
@@ -516,6 +715,5 @@ export function extractPartialData(path: string | string[], extensionObject: Ext
|
|
|
516
715
|
}
|
|
517
716
|
name = path[path.length - 1];
|
|
518
717
|
c1[name] = c2[name];
|
|
519
|
-
c1[name] += 1;
|
|
520
718
|
return partialData;
|
|
521
719
|
}
|