node-opcua-address-space 2.88.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/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 +1 -1
- package/dist/src/extension_object_array_node.js +11 -9
- package/dist/src/extension_object_array_node.js.map +1 -1
- 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.js +6 -6
- package/dist/src/ua_reference_type_impl.js.map +1 -1
- package/dist/src/ua_variable_impl.d.ts +4 -0
- package/dist/src/ua_variable_impl.js +41 -54
- package/dist/src/ua_variable_impl.js.map +1 -1
- package/dist/src/ua_variable_impl_ext_obj.d.ts +10 -8
- package/dist/src/ua_variable_impl_ext_obj.js +287 -240
- 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 +26 -26
- package/source/address_space_ts.ts +1 -1
- package/source/helpers/argument_list.ts +26 -26
- package/src/extension_object_array_node.ts +11 -10
- package/src/ua_variable_impl.ts +40 -51
- package/src/ua_variable_impl_ext_obj.ts +333 -288
- package/src/ua_variable_type_impl.ts +4 -4
|
@@ -1,23 +1,20 @@
|
|
|
1
|
-
import * as chalk from "chalk";
|
|
2
1
|
import assert from "node-opcua-assert";
|
|
3
|
-
import { BindExtensionObjectOptions, UADataType,
|
|
2
|
+
import { BindExtensionObjectOptions, UADataType, UAVariable, UAVariableType } from "node-opcua-address-space-base";
|
|
4
3
|
import { coerceQualifiedName, NodeClass } from "node-opcua-data-model";
|
|
5
|
-
import { getCurrentClock, PreciseClock,
|
|
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 {
|
|
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";
|
|
18
|
-
import { bindExtObjArrayNode } from "./extension_object_array_node";
|
|
19
17
|
import { IndexIterator } from "./idx_iterator";
|
|
20
|
-
import { DateTime } from "node-opcua-basic-types";
|
|
21
18
|
|
|
22
19
|
const doDebug = checkDebugFlag(__filename);
|
|
23
20
|
const debugLog = make_debugLog(__filename);
|
|
@@ -33,42 +30,64 @@ function w(str: string, n: number): string {
|
|
|
33
30
|
function isProxy(ext: any) {
|
|
34
31
|
return ext.$isProxy ? true : false;
|
|
35
32
|
}
|
|
33
|
+
function getProxyVariable(ext: any): UAVariable | null {
|
|
34
|
+
assert(isProxy(ext));
|
|
35
|
+
return ext.$variable as UAVariable | null;
|
|
36
|
+
}
|
|
36
37
|
|
|
37
|
-
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 {
|
|
38
45
|
assert(isProxy(ext));
|
|
39
|
-
|
|
46
|
+
const target = ext.$proxyTarget;
|
|
47
|
+
if (target && isProxy(target)) {
|
|
48
|
+
return getProxyTarget(target);
|
|
49
|
+
}
|
|
50
|
+
return target;
|
|
40
51
|
}
|
|
41
52
|
|
|
42
53
|
function unProxy(ext: ExtensionObject) {
|
|
43
54
|
return isProxy(ext) ? getProxyTarget(ext) : ext;
|
|
44
55
|
}
|
|
45
56
|
|
|
46
|
-
function _extensionObjectFieldGetter(target: any, key: string /*, receiver*/) {
|
|
57
|
+
function _extensionObjectFieldGetter(getVariable: () => UAVariable | null, target: any, key: string /*, receiver*/) {
|
|
47
58
|
if (key === "$isProxy") {
|
|
48
59
|
return true;
|
|
49
60
|
}
|
|
50
61
|
if (key === "$proxyTarget") {
|
|
51
62
|
return target;
|
|
52
63
|
}
|
|
64
|
+
if (key === "$variable") {
|
|
65
|
+
return getVariable();
|
|
66
|
+
}
|
|
67
|
+
|
|
53
68
|
if (target[key] === undefined) {
|
|
54
69
|
return undefined;
|
|
55
70
|
}
|
|
56
71
|
return target[key];
|
|
57
72
|
}
|
|
58
|
-
|
|
59
|
-
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 {
|
|
60
74
|
target[key] = value;
|
|
61
|
-
|
|
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;
|
|
62
81
|
if (child && child.touchValue) {
|
|
63
82
|
child.touchValue();
|
|
64
83
|
}
|
|
65
84
|
return true; // true means the set operation has succeeded
|
|
66
85
|
}
|
|
67
86
|
|
|
68
|
-
function makeHandler(
|
|
87
|
+
function makeHandler(getVariable: () => UAVariable | null) {
|
|
69
88
|
const handler = {
|
|
70
|
-
get: _extensionObjectFieldGetter,
|
|
71
|
-
set: _extensionObjectFieldSetter.bind(null,
|
|
89
|
+
get: _extensionObjectFieldGetter.bind(null, getVariable),
|
|
90
|
+
set: _extensionObjectFieldSetter.bind(null, getVariable)
|
|
72
91
|
};
|
|
73
92
|
return handler;
|
|
74
93
|
}
|
|
@@ -85,7 +104,6 @@ export function _touchValue(property: UAVariableImpl, now: PreciseClock): void {
|
|
|
85
104
|
property.$dataValue.serverTimestamp = now.timestamp;
|
|
86
105
|
property.$dataValue.serverPicoseconds = now.picoseconds;
|
|
87
106
|
property.$dataValue.statusCode = StatusCodes.Good;
|
|
88
|
-
|
|
89
107
|
if (property.minimumSamplingInterval === 0) {
|
|
90
108
|
if (property.listenerCount("value_changed") > 0) {
|
|
91
109
|
const clonedDataValue = property.readValue();
|
|
@@ -94,54 +112,48 @@ export function _touchValue(property: UAVariableImpl, now: PreciseClock): void {
|
|
|
94
112
|
}
|
|
95
113
|
}
|
|
96
114
|
|
|
97
|
-
export function propagateTouchValueUpward(self: UAVariableImpl, now: PreciseClock): void {
|
|
115
|
+
export function propagateTouchValueUpward(self: UAVariableImpl, now: PreciseClock, cache?: Set<UAVariable>): void {
|
|
98
116
|
_touchValue(self, now);
|
|
99
117
|
if (self.parent && self.parent.nodeClass === NodeClass.Variable) {
|
|
100
118
|
const parentVar = self.parent as UAVariableImpl;
|
|
101
119
|
if (!parentVar.isExtensionObject()) return;
|
|
102
|
-
|
|
120
|
+
|
|
121
|
+
if (cache) {
|
|
122
|
+
if (cache.has(parentVar)) return;
|
|
123
|
+
cache.add(parentVar);
|
|
124
|
+
}
|
|
125
|
+
propagateTouchValueUpward(parentVar, now, cache);
|
|
103
126
|
}
|
|
104
127
|
}
|
|
105
128
|
|
|
106
|
-
function propagateTouchValueDownward(self: UAVariableImpl, now: PreciseClock): void {
|
|
129
|
+
function propagateTouchValueDownward(self: UAVariableImpl, now: PreciseClock, cache?: Set<UAVariable>): void {
|
|
107
130
|
if (!self.isExtensionObject()) return;
|
|
108
131
|
// also propagate changes to embeded variables
|
|
109
132
|
const dataTypeNode = self.getDataTypeNode();
|
|
110
133
|
const definition = dataTypeNode.getStructureDefinition();
|
|
111
134
|
for (const field of definition.fields || []) {
|
|
112
135
|
const property = self.getChildByName(field.name!) as UAVariableImpl;
|
|
136
|
+
|
|
113
137
|
if (property) {
|
|
138
|
+
|
|
139
|
+
if (cache) {
|
|
140
|
+
if (cache.has(property)) {
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
cache.add(property);
|
|
144
|
+
}
|
|
145
|
+
|
|
114
146
|
_touchValue(property, now);
|
|
115
147
|
// to do cascade recursivelly ?
|
|
116
148
|
}
|
|
117
149
|
}
|
|
118
150
|
}
|
|
119
151
|
|
|
120
|
-
export function _setExtensionObject(self: UAVariableImpl, ext: ExtensionObject | ExtensionObject[], sourceTimestamp?: PreciseClock): void {
|
|
121
|
-
// assert(!(ext as any).$isProxy, "internal error ! ExtensionObject has already been proxied !");
|
|
122
|
-
if (Array.isArray(ext)) {
|
|
123
|
-
assert(self.valueRank === 1, "Only Array is supported for the time being");
|
|
124
|
-
ext = ext.map((e) => unProxy(e));
|
|
125
|
-
self.$dataValue.value.arrayType = VariantArrayType.Array;
|
|
126
|
-
self.$extensionObject = ext.map((e) => new Proxy(e, makeHandler(self)));
|
|
127
|
-
self.$dataValue.value.dataType = DataType.ExtensionObject;
|
|
128
|
-
self.$dataValue.value.value = self.$extensionObject;
|
|
129
|
-
self.$dataValue.statusCode = StatusCodes.Good;
|
|
130
|
-
return;
|
|
131
|
-
} else {
|
|
132
|
-
ext = unProxy(ext);
|
|
133
|
-
self.$extensionObject = new Proxy(ext, makeHandler(self));
|
|
134
|
-
self.$dataValue.value.dataType = DataType.ExtensionObject;
|
|
135
|
-
self.$dataValue.value.value = self.$extensionObject;
|
|
136
|
-
self.$dataValue.statusCode = StatusCodes.Good;
|
|
137
|
-
}
|
|
138
152
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
}
|
|
153
|
+
export function setExtensionObjectPartialValue(node: UAVariableImpl, partialObject: any, sourceTimestamp?: PreciseClock) {
|
|
154
|
+
|
|
155
|
+
const variablesToUpdate: Set<UAVariableImpl> = new Set();
|
|
143
156
|
|
|
144
|
-
export function setExtensionObjectValue(node: UAVariableImpl, partialObject: any) {
|
|
145
157
|
const extensionObject = node.$extensionObject;
|
|
146
158
|
if (!extensionObject) {
|
|
147
159
|
throw new Error("setExtensionObjectValue node has no extension object " + node.browseName.toString());
|
|
@@ -153,12 +165,30 @@ export function setExtensionObjectValue(node: UAVariableImpl, partialObject: any
|
|
|
153
165
|
if (extObject[prop] instanceof Object) {
|
|
154
166
|
_update_extension_object(extObject[prop], partialObject1[prop]);
|
|
155
167
|
} else {
|
|
156
|
-
|
|
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
|
+
}
|
|
157
179
|
}
|
|
158
180
|
}
|
|
159
181
|
}
|
|
160
|
-
|
|
161
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
|
+
}
|
|
162
192
|
}
|
|
163
193
|
|
|
164
194
|
function getOrCreateProperty(
|
|
@@ -213,155 +243,139 @@ function prepareVariantValue(dataType: DataType, value: VariantLike): VariantLik
|
|
|
213
243
|
return value;
|
|
214
244
|
}
|
|
215
245
|
|
|
216
|
-
function
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
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");
|
|
227
269
|
}
|
|
228
|
-
const value = prepareVariantValue(dataType, propertyValue);
|
|
229
|
-
propertyNode.$dataValue.statusCode = StatusCodes.Good;
|
|
230
|
-
propertyNode.$dataValue.value.dataType = dataType;
|
|
231
|
-
propertyNode.$dataValue.value.value = value;
|
|
232
|
-
return new DataValue(propertyNode.$dataValue);
|
|
233
|
-
},
|
|
234
|
-
timestamped_set: (_dataValue: DataValue, callback: CallbackT<StatusCode>) => {
|
|
235
|
-
|
|
236
|
-
propertyNode.setValueFromSource(_dataValue.value, _dataValue.statusCode, _dataValue.sourceTimestamp || new Date());
|
|
237
|
-
// callback(null, StatusCodes.BadNotWritable);
|
|
238
|
-
callback(null, StatusCodes.Good);
|
|
239
270
|
}
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
243
273
|
}
|
|
244
274
|
|
|
275
|
+
export function _installExtensionObjectBindingOnProperties(
|
|
276
|
+
uaVariable: UAVariableImpl,
|
|
277
|
+
options?: BindExtensionObjectOptions
|
|
278
|
+
): void {
|
|
245
279
|
|
|
246
|
-
|
|
247
|
-
|
|
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();
|
|
248
294
|
const extObj = dataValue.value.value;
|
|
249
295
|
if (extObj instanceof ExtensionObject) {
|
|
250
|
-
|
|
296
|
+
uaVariable.bindExtensionObject(extObj, { createMissingProp: true, force: true });
|
|
251
297
|
} else if (extObj instanceof Array) {
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
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 });
|
|
256
302
|
} else {
|
|
257
303
|
throw new Error("Internal Error, unexpected case");
|
|
258
304
|
}
|
|
259
|
-
} else {
|
|
260
|
-
const msg = `variableNode ${variableNode.browseName.toString()} doesn't have $extensionObject property`;
|
|
261
|
-
errorLog(msg);
|
|
262
|
-
errorLog(dataValue.toString());
|
|
263
|
-
throw new Error(msg);
|
|
264
305
|
}
|
|
265
306
|
}
|
|
266
|
-
export function _installExtensionObjectBindingOnProperties(
|
|
267
|
-
variableNode: UAVariableImpl,
|
|
268
|
-
options: BindExtensionObjectOptions
|
|
269
|
-
): void {
|
|
270
307
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
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();
|
|
277
315
|
const definition = dt.getStructureDefinition();
|
|
278
316
|
|
|
279
317
|
for (const field of definition.fields || []) {
|
|
280
|
-
|
|
318
|
+
|
|
281
319
|
if (NodeId.sameNodeId(NodeId.nullNodeId, field.dataType)) {
|
|
282
320
|
warningLog("field.dataType is null ! ", field.name, NodeId.nullNodeId.toString());
|
|
283
321
|
warningLog(field.toString());
|
|
284
322
|
warningLog(" dataType replaced with BaseDataType ");
|
|
285
323
|
warningLog(definition.toString());
|
|
286
|
-
field.dataType =
|
|
324
|
+
field.dataType = uaVariable.resolveNodeId("BaseDataType");
|
|
287
325
|
}
|
|
288
326
|
|
|
289
|
-
const propertyNode = getOrCreateProperty(
|
|
327
|
+
const propertyNode = getOrCreateProperty(uaVariable, field, options);
|
|
290
328
|
if (!propertyNode) {
|
|
291
329
|
continue;
|
|
292
330
|
}
|
|
293
|
-
propertyNode.$dataValue.statusCode = StatusCodes.Good;
|
|
294
|
-
propertyNode.$dataValue.sourceTimestamp = variableNode.$dataValue.sourceTimestamp;
|
|
295
|
-
propertyNode.$dataValue.sourcePicoseconds = variableNode.$dataValue.sourcePicoseconds;
|
|
296
|
-
propertyNode.$dataValue.serverTimestamp = variableNode.$dataValue.serverTimestamp;
|
|
297
|
-
propertyNode.$dataValue.serverPicoseconds = variableNode.$dataValue.serverPicoseconds;
|
|
298
|
-
|
|
299
|
-
//xx propertyNode.touchValue();
|
|
300
|
-
|
|
301
|
-
const basicDataType = addressSpace.findCorrespondingBasicDataType(field.dataType);
|
|
302
331
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
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);
|
|
319
349
|
}
|
|
320
350
|
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
new Variant({
|
|
333
|
-
dataType: DataType.Null
|
|
334
|
-
})
|
|
335
|
-
);
|
|
336
|
-
} else {
|
|
337
|
-
const preparedValue = prepareVariantValue(basicDataType, prop);
|
|
338
|
-
propertyNode._internal_set_value(
|
|
339
|
-
new Variant({
|
|
340
|
-
dataType: basicDataType,
|
|
341
|
-
value: preparedValue
|
|
342
|
-
})
|
|
343
|
-
);
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
347
|
-
|
|
348
|
-
// property.camelCaseName = camelCaseName;
|
|
349
|
-
propertyNode.setValueFromSource = function (this: UAVariableImpl, variant: VariantLike) {
|
|
350
|
-
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
351
|
-
const inner_this = this;
|
|
352
|
-
const variant1 = Variant.coerce(variant);
|
|
353
|
-
inner_this.verifyVariantCompatibility(variant1);
|
|
354
|
-
|
|
355
|
-
// because self.$extensionObject is a Proxy with handlers that
|
|
356
|
-
// cascade the chagne we do not need to call touchValue() here
|
|
357
|
-
variableNode.$extensionObject[camelCaseName] = variant1.value;
|
|
358
|
-
};
|
|
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);
|
|
359
362
|
}
|
|
360
|
-
assert(propertyNode.readValue().statusCode.equals(StatusCodes.Good));
|
|
361
|
-
bindProperty(variableNode, propertyNode, camelCaseName, basicDataType);
|
|
362
363
|
}
|
|
363
364
|
}
|
|
364
365
|
|
|
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
|
+
}
|
|
378
|
+
|
|
365
379
|
function isVariableContainingExtensionObject(uaVariable: UAVariableImpl): boolean {
|
|
366
380
|
const addressSpace = uaVariable.addressSpace;
|
|
367
381
|
const structure = addressSpace.findDataType("Structure");
|
|
@@ -379,38 +393,78 @@ function isVariableContainingExtensionObject(uaVariable: UAVariableImpl): boolea
|
|
|
379
393
|
return false;
|
|
380
394
|
}
|
|
381
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);
|
|
382
435
|
|
|
383
436
|
}
|
|
384
|
-
|
|
437
|
+
|
|
438
|
+
|
|
385
439
|
export function _bindExtensionObject(
|
|
386
|
-
|
|
387
|
-
optionalExtensionObject?: ExtensionObject
|
|
440
|
+
uaVariable: UAVariableImpl,
|
|
441
|
+
optionalExtensionObject?: ExtensionObject,
|
|
388
442
|
options?: BindExtensionObjectOptions
|
|
389
|
-
): ExtensionObject |
|
|
443
|
+
): ExtensionObject | null {
|
|
390
444
|
options = options || { createMissingProp: false };
|
|
391
445
|
|
|
392
|
-
if (!isVariableContainingExtensionObject(
|
|
446
|
+
if (!isVariableContainingExtensionObject(uaVariable)) {
|
|
393
447
|
return null;
|
|
394
448
|
}
|
|
395
|
-
|
|
449
|
+
|
|
450
|
+
const addressSpace = uaVariable.addressSpace;
|
|
396
451
|
let extensionObject_;
|
|
397
452
|
|
|
398
|
-
|
|
453
|
+
// istanbul ignore next
|
|
454
|
+
if (uaVariable.valueRank !== -1 && uaVariable.valueRank !== 1) {
|
|
399
455
|
throw new Error("Cannot bind an extension object here, valueRank must be scalar (-1) or one-dimensional (1)");
|
|
400
456
|
}
|
|
401
457
|
|
|
402
458
|
// istanbul ignore next
|
|
403
|
-
|
|
404
|
-
debugLog(" ------------------------------ binding ", self.browseName.toString(), self.nodeId.toString());
|
|
405
|
-
}
|
|
459
|
+
doDebug && debugLog(" ------------------------------ binding ", uaVariable.browseName.toString(), uaVariable.nodeId.toString());
|
|
406
460
|
|
|
407
461
|
// ignore bindExtensionObject on sub extension object, bindExtensionObject has to be called from the top most object
|
|
408
462
|
if (
|
|
409
463
|
!options.force &&
|
|
410
|
-
|
|
411
|
-
(
|
|
464
|
+
uaVariable.parent &&
|
|
465
|
+
(uaVariable.parent.nodeClass === NodeClass.Variable || uaVariable.parent.nodeClass === NodeClass.VariableType)
|
|
412
466
|
) {
|
|
413
|
-
const parentDataType = (
|
|
467
|
+
const parentDataType = (uaVariable.parent as UAVariable | UAVariableType).dataType;
|
|
414
468
|
const dataTypeNode = addressSpace.findNode(parentDataType) as UADataType;
|
|
415
469
|
const structure = addressSpace.findDataType("Structure")!;
|
|
416
470
|
// istanbul ignore next
|
|
@@ -427,121 +481,73 @@ export function _bindExtensionObject(
|
|
|
427
481
|
}
|
|
428
482
|
|
|
429
483
|
// -------------------- make sure we do not bind a variable twice ....
|
|
430
|
-
if (
|
|
484
|
+
if (uaVariable.$extensionObject && !optionalExtensionObject) {
|
|
431
485
|
// istanbul ignore next
|
|
432
|
-
if (!
|
|
486
|
+
if (!uaVariable.checkExtensionObjectIsCorrect(uaVariable.$extensionObject!)) {
|
|
433
487
|
warningLog(
|
|
434
488
|
"on node : ",
|
|
435
|
-
|
|
436
|
-
|
|
489
|
+
uaVariable.browseName.toString(),
|
|
490
|
+
uaVariable.nodeId.toString(),
|
|
437
491
|
"dataType=",
|
|
438
|
-
|
|
492
|
+
uaVariable.dataType.toString({ addressSpace: uaVariable.addressSpace })
|
|
439
493
|
);
|
|
440
|
-
warningLog(
|
|
494
|
+
warningLog(uaVariable.$extensionObject?.toString());
|
|
441
495
|
throw new Error(
|
|
442
496
|
"bindExtensionObject: $extensionObject is incorrect: we are expecting a " +
|
|
443
|
-
|
|
497
|
+
uaVariable.dataType.toString({ addressSpace: uaVariable.addressSpace }) +
|
|
444
498
|
" but we got a " +
|
|
445
|
-
|
|
499
|
+
uaVariable.$extensionObject?.constructor.name
|
|
446
500
|
);
|
|
447
501
|
}
|
|
448
|
-
return
|
|
449
|
-
// throw new Error("Variable already bound");
|
|
502
|
+
return uaVariable.$extensionObject;
|
|
450
503
|
}
|
|
451
504
|
|
|
452
|
-
// ------------------------------------------------------
|
|
453
|
-
// make sure we have a structure
|
|
454
|
-
// ------------------------------------------------------
|
|
455
|
-
const s = self.readValue();
|
|
456
|
-
|
|
457
505
|
// istanbul ignore next
|
|
458
|
-
if (
|
|
459
|
-
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());
|
|
460
508
|
warningLog("You need to provide a extension object yourself ");
|
|
461
509
|
throw new Error("bindExtensionObject requires a extensionObject as associated dataType is only abstract");
|
|
462
510
|
}
|
|
463
511
|
|
|
512
|
+
const s = uaVariable.readValue();
|
|
464
513
|
if (s.value && s.value.dataType === DataType.ExtensionObject && s.value.value && optionalExtensionObject) {
|
|
465
514
|
// we want to replace the extension object
|
|
466
515
|
s.value.value = null;
|
|
467
516
|
}
|
|
468
517
|
innerBindExtensionObject();
|
|
469
|
-
assert(
|
|
470
|
-
return
|
|
518
|
+
assert(uaVariable.$extensionObject instanceof Object);
|
|
519
|
+
return uaVariable.$extensionObject;
|
|
471
520
|
|
|
472
521
|
function innerBindExtensionObject() {
|
|
473
|
-
const makePreciseClock = (sourceTimestamp: DateTime, picoseconds?: number): PreciseClock =>
|
|
474
|
-
({ timestamp: sourceTimestamp as DateWithPicoseconds, picoseconds: picoseconds || 0 });
|
|
475
|
-
|
|
476
522
|
|
|
477
523
|
if (s.value && (s.value.dataType === DataType.Null || (s.value.dataType === DataType.ExtensionObject && !s.value.value))) {
|
|
478
|
-
if (
|
|
479
|
-
|
|
480
|
-
extensionObject_ = optionalExtensionObject || addressSpace.constructExtensionObject(self.dataType, {});
|
|
481
|
-
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
482
|
-
self.bindVariable(
|
|
483
|
-
{
|
|
484
|
-
timestamped_get() {
|
|
485
|
-
const d = new DataValue(self.$dataValue);
|
|
486
|
-
d.value.value = self.$extensionObject ? self.$extensionObject.clone() : null;
|
|
487
|
-
return d;
|
|
488
|
-
},
|
|
489
|
-
timestamped_set(dataValue: DataValue, callback: CallbackT<StatusCode>) {
|
|
490
|
-
const ext = dataValue.value.value;
|
|
491
|
-
if (!self.checkExtensionObjectIsCorrect(ext)) {
|
|
492
|
-
return callback(null, StatusCodes.BadInvalidArgument);
|
|
493
|
-
}
|
|
494
|
-
const sourceTime = coerceClock(dataValue.sourceTimestamp, dataValue.sourcePicoseconds);
|
|
495
|
-
_setExtensionObject(self, ext, sourceTime);
|
|
496
|
-
callback(null, StatusCodes.Good);
|
|
497
|
-
}
|
|
498
|
-
},
|
|
499
|
-
true
|
|
500
|
-
);
|
|
501
|
-
const sourceTime = coerceClock(self.$dataValue.sourceTimestamp, self.$dataValue.sourcePicoseconds);
|
|
502
|
-
_setExtensionObject(self, extensionObject_, sourceTime);
|
|
524
|
+
if (uaVariable.valueRank === -1 /** Scalar */) {
|
|
525
|
+
extensionObject_ = optionalExtensionObject || addressSpace.constructExtensionObject(uaVariable.dataType, {});
|
|
503
526
|
|
|
504
|
-
|
|
505
|
-
// create a structure and bind it
|
|
527
|
+
installExt(uaVariable, extensionObject_);
|
|
506
528
|
|
|
507
|
-
|
|
508
|
-
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
509
|
-
self.bindVariable(
|
|
529
|
+
_innerBindExtensionObjectScalar(uaVariable,
|
|
510
530
|
{
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
return d;
|
|
518
|
-
},
|
|
519
|
-
timestamped_set(dataValue: DataValue, callback: CallbackT<StatusCode>) {
|
|
520
|
-
const extensionObjectArray = dataValue.value.value;
|
|
521
|
-
if (!self.checkExtensionObjectIsCorrect(extensionObjectArray)) {
|
|
522
|
-
return callback(null, StatusCodes.BadInvalidArgument);
|
|
523
|
-
}
|
|
524
|
-
const sourceTime = coerceClock(dataValue.sourceTimestamp, dataValue.sourcePicoseconds);
|
|
525
|
-
_setExtensionObject(self, extensionObjectArray, sourceTime);
|
|
526
|
-
callback(null, StatusCodes.Good);
|
|
527
|
-
}
|
|
528
|
-
},
|
|
529
|
-
true
|
|
530
|
-
);
|
|
531
|
-
const sourceTime = coerceClock(self.$dataValue.sourceTimestamp, self.$dataValue.sourcePicoseconds);
|
|
532
|
-
_setExtensionObject(self, extensionObject_, sourceTime);
|
|
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");
|
|
533
537
|
} else {
|
|
534
|
-
errorLog(
|
|
535
|
-
errorLog("Unsupported case ! valueRank= ",
|
|
538
|
+
errorLog(uaVariable.toString());
|
|
539
|
+
errorLog("Unsupported case ! valueRank= ", uaVariable.valueRank);
|
|
536
540
|
}
|
|
537
541
|
} else {
|
|
538
542
|
// verify that variant has the correct type
|
|
539
543
|
assert(s.value.dataType === DataType.ExtensionObject);
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
544
|
+
installExt(uaVariable, s.value.value);
|
|
545
|
+
_innerBindExtensionObjectScalar(uaVariable,
|
|
546
|
+
{
|
|
547
|
+
get: () => uaVariable.$extensionObject,
|
|
548
|
+
set: (value: ExtensionObject) => installExt(uaVariable, value)
|
|
549
|
+
}, options);
|
|
543
550
|
}
|
|
544
|
-
_installExtensionObjectBindingOnProperties(self, options!);
|
|
545
551
|
}
|
|
546
552
|
}
|
|
547
553
|
|
|
@@ -560,24 +566,19 @@ const composeBrowseNameAndNodeId = (uaVariable: UAVariable, indexes: number[]) =
|
|
|
560
566
|
return { browseName, nodeId };
|
|
561
567
|
}
|
|
562
568
|
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
options?: BindExtensionObjectOptions
|
|
567
|
-
): ExtensionObject[] {
|
|
568
|
-
return _bindExtensionObjectMatrix(uaVariable, optionalExtensionObjectArray, options);
|
|
569
|
-
}
|
|
570
|
-
export function _bindExtensionObjectMatrix(
|
|
569
|
+
|
|
570
|
+
// eslint-disable-next-line max-statements
|
|
571
|
+
export function _bindExtensionObjectArrayOrMatrix(
|
|
571
572
|
uaVariable: UAVariableImpl,
|
|
572
573
|
optionalExtensionObjectArray?: ExtensionObject[],
|
|
573
574
|
options?: BindExtensionObjectOptions
|
|
574
575
|
): ExtensionObject[] {
|
|
575
|
-
|
|
576
|
+
// istanbul ignore next
|
|
576
577
|
if (uaVariable.valueRank < 1) {
|
|
577
578
|
throw new Error("Variable must be a MultiDimensional array");
|
|
578
579
|
}
|
|
579
580
|
const arrayDimensions = uaVariable.arrayDimensions || [];
|
|
580
|
-
|
|
581
|
+
// istanbul ignore next
|
|
581
582
|
if (!isVariableContainingExtensionObject(uaVariable)) {
|
|
582
583
|
return [];
|
|
583
584
|
}
|
|
@@ -601,16 +602,16 @@ export function _bindExtensionObjectMatrix(
|
|
|
601
602
|
}
|
|
602
603
|
}
|
|
603
604
|
uaVariable.$$extensionObjectArray = optionalExtensionObjectArray;
|
|
604
|
-
|
|
605
|
-
|
|
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;
|
|
606
609
|
|
|
607
610
|
uaVariable.bindVariable({
|
|
608
|
-
get: () =>
|
|
609
|
-
arrayType: VariantArrayType.Array,
|
|
610
|
-
dataType: DataType.ExtensionObject,
|
|
611
|
-
value: uaVariable.$$extensionObjectArray
|
|
612
|
-
})
|
|
611
|
+
get: () => uaVariable.$dataValue.value
|
|
613
612
|
}, true);
|
|
613
|
+
|
|
614
|
+
|
|
614
615
|
const namespace = uaVariable.namespace;
|
|
615
616
|
const indexIterator = new IndexIterator(arrayDimensions);
|
|
616
617
|
for (let i = 0; i < totalLength; i++) {
|
|
@@ -619,28 +620,73 @@ export function _bindExtensionObjectMatrix(
|
|
|
619
620
|
|
|
620
621
|
const { browseName, nodeId } = composeBrowseNameAndNodeId(uaVariable, index);
|
|
621
622
|
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
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
|
+
|
|
630
646
|
{
|
|
631
647
|
const capturedIndex = i;
|
|
632
|
-
uaElement
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
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
|
+
|
|
639
660
|
}
|
|
640
661
|
}
|
|
641
662
|
return uaVariable.$$extensionObjectArray;
|
|
642
663
|
}
|
|
643
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
|
+
}
|
|
644
690
|
export function extractPartialData(path: string | string[], extensionObject: ExtensionObject) {
|
|
645
691
|
let name;
|
|
646
692
|
if (typeof path === "string") {
|
|
@@ -669,6 +715,5 @@ export function extractPartialData(path: string | string[], extensionObject: Ext
|
|
|
669
715
|
}
|
|
670
716
|
name = path[path.length - 1];
|
|
671
717
|
c1[name] = c2[name];
|
|
672
|
-
c1[name] += 1;
|
|
673
718
|
return partialData;
|
|
674
719
|
}
|