Skip to content

Commit

Permalink
Merge 1c4b876 into cf789b5
Browse files Browse the repository at this point in the history
  • Loading branch information
erossignon committed Jan 3, 2023
2 parents cf789b5 + 1c4b876 commit 12a6fca
Show file tree
Hide file tree
Showing 26 changed files with 12,848 additions and 116 deletions.
Expand Up @@ -5,10 +5,10 @@ import { UAVariable } from "./ua_variable";
import { UAVariableType } from "./ua_variable_type";

// {{ Dynamic Array Variable
export interface UADynamicVariableArray<T extends ExtensionObject> extends UAVariable {
export interface UADynamicVariableArray<T extends ExtensionObject= ExtensionObject> extends UAVariable {
$$variableType: UAVariableType;
$$dataType: UADataType;
$$extensionObjectArray: T[];
$$getElementBrowseName: (obj: T) => QualifiedName;
$$getElementBrowseName: (obj: T, index: number) => QualifiedName;
$$indexPropertyName: string;
}
4 changes: 2 additions & 2 deletions packages/node-opcua-address-space-base/source/ua_variable.ts
Expand Up @@ -346,12 +346,12 @@ export interface UAVariable extends BaseNode, VariableAttributes, IPropertyAndCo
): ExtensionObject | ExtensionObject[] | null;

bindExtensionObjectScalar(
optionalExtensionObject: ExtensionObject,
optionalExtensionObject?: ExtensionObject,
options?: BindExtensionObjectOptions
): ExtensionObject | null;

bindExtensionObjectArray(
optionalExtensionObjectArray: ExtensionObject[],
optionalExtensionObjectArray?: ExtensionObject[],
options?: BindExtensionObjectOptions
): ExtensionObject[] | null;

Expand Down
Expand Up @@ -23,7 +23,7 @@ const errorLog = make_errorLog(__filename);
*
*/

function getExtObjArrayNodeValue<T extends ExtensionObject>(this: UADynamicVariableArray<T>) {
function getExtObjArrayNodeValue<T extends ExtensionObject>(this: UADynamicVariableArray<T>) {
return new Variant({
arrayType: VariantArrayType.Array,
dataType: DataType.ExtensionObject,
Expand All @@ -38,7 +38,7 @@ function removeElementByIndex<T extends ExtensionObject>(uaArrayVariableNode: UA

const addressSpace = uaArrayVariableNode.addressSpace;
const extObj = _array[elementIndex];
const browseName = uaArrayVariableNode.$$getElementBrowseName(extObj);
const browseName = uaArrayVariableNode.$$getElementBrowseName(extObj, elementIndex);

// remove element from global array (inefficient)
uaArrayVariableNode.$$extensionObjectArray.splice(elementIndex, 1);
Expand Down Expand Up @@ -68,14 +68,6 @@ function removeElementByIndex<T extends ExtensionObject>(uaArrayVariableNode: UA
/**
*
* create a node Variable that contains a array of ExtensionObject of a given type
* @method createExtObjArrayNode
* @param parentFolder
* @param options
* @param options.browseName
* @param options.complexVariableType
* @param options.variableType the type of Extension objects stored in the array.
* @param options.indexPropertyName
* @return {Object|UAVariable}
*/
export function createExtObjArrayNode<T extends ExtensionObject>(parentFolder: UAObject, options: any): UADynamicVariableArray<T> {
assert(typeof options.variableType === "string");
Expand Down Expand Up @@ -126,7 +118,9 @@ export function createExtObjArrayNode<T extends ExtensionObject>(parentFolder: U

return uaArrayVariableNode;
}
function _getElementBrowseName<T extends ExtensionObject>(this: UADynamicVariableArray<T>, extObj: ExtensionObject) {

function _getElementBrowseName<T extends ExtensionObject>
(this: UADynamicVariableArray<T>, extObj: ExtensionObject, index: number | number[]) {
const indexPropertyName1 = this.$$indexPropertyName;

if (!Object.prototype.hasOwnProperty.call(extObj, indexPropertyName1)) {
Expand All @@ -137,13 +131,7 @@ function _getElementBrowseName<T extends ExtensionObject>(this: UADynamicVariabl
const browseName = (extObj as any)[indexPropertyName1].toString();
return browseName;
};
/**
* @method bindExtObjArrayNode
* @param uaArrayVariableNode
* @param variableTypeNodeId
* @param indexPropertyName
* @return
*/

export function bindExtObjArrayNode<T extends ExtensionObject>(
uaArrayVariableNode: UADynamicVariableArray<T>,
variableTypeNodeId: string | NodeId,
Expand All @@ -155,26 +143,23 @@ export function bindExtObjArrayNode<T extends ExtensionObject>(
const addressSpace = uaArrayVariableNode.addressSpace;

const variableType = addressSpace.findVariableType(variableTypeNodeId);

// istanbul ignore next
if (!variableType || variableType.nodeId.isEmpty()) {
throw new Error("Cannot find VariableType " + variableTypeNodeId.toString());
}

const structure = addressSpace.findDataType("Structure");

// istanbul ignore next
if (!structure) {
throw new Error("Structure Type not found: please check your nodeset file");
}

let dataType = addressSpace.findDataType(variableType.dataType);

// istanbul ignore next
if (!dataType) {
throw new Error("Cannot find DataType " + variableType.dataType.toString());
}

assert(dataType.isSupertypeOf(structure), "expecting a structure (= ExtensionObject) here ");

assert(!uaArrayVariableNode.$$variableType, "uaArrayVariableNode has already been bound !");
Expand All @@ -197,7 +182,6 @@ export function bindExtObjArrayNode<T extends ExtensionObject>(
};
// bind the readonly
uaArrayVariableNode.bindVariable(bindOptions, true);

return uaArrayVariableNode;
}

Expand All @@ -208,20 +192,9 @@ export function bindExtObjArrayNode<T extends ExtensionObject>(
* @param uaArrayVariableNode {UAVariable}
* @return {UAVariable}
*
* @method addElement
* add a new element in a ExtensionObject Array variable
* @param nodeVariable a variable already exposing an extension objects
* @param uaArrayVariableNode {UAVariable}
* @return {UAVariable}
*
* @method addElement
* add a new element in a ExtensionObject Array variable
* @param constructor constructor of the extension object to create
* @param uaArrayVariableNode {UAVariable}
* @return {UAVariable}
*/
export function addElement<T extends ExtensionObject>(
options: any /* ExtensionObjectConstructor | ExtensionObject | UAVariable*/,
options: UAVariableImpl | ExtensionObject | Record<string, unknown>,
uaArrayVariableNode: UADynamicVariableArray<T>
): UAVariable {
assert(uaArrayVariableNode, " must provide an UAVariable containing the array");
Expand Down Expand Up @@ -256,19 +229,20 @@ export function addElement<T extends ExtensionObject>(
});
// xx elVar.bindExtensionObject();
} else {
if (options instanceof Constructor) {
if (options instanceof ExtensionObject) {
// extension object has already been created
extensionObject = options as T;
} else {
extensionObject = addressSpace.constructExtensionObject(uaArrayVariableNode.$$dataType, options) as T;
}
browseName = uaArrayVariableNode.$$getElementBrowseName(extensionObject);
const index = uaArrayVariableNode.$$extensionObjectArray?.length || 0;
browseName = uaArrayVariableNode.$$getElementBrowseName(extensionObject, index);
elVar = uaArrayVariableNode.$$variableType.instantiate({
browseName,
componentOf: uaArrayVariableNode.nodeId,
value: { dataType: DataType.ExtensionObject, value: extensionObject }
}) as UAVariableImpl;
elVar.bindExtensionObject(extensionObject, { force: true });
elVar.bindExtensionObject(extensionObject, { force: true });
elVar.$extensionObject = extensionObject;
}

Expand All @@ -279,19 +253,6 @@ export function addElement<T extends ExtensionObject>(
}

/**
*
* @method removeElement
* @param uaArrayVariableNode {UAVariable}
* @param element {number} index of element to remove in array
*
*
* @method removeElement
* @param uaArrayVariableNode {UAVariable}
* @param element {UAVariable} node of element to remove in array
*
* @method removeElement
* @param uaArrayVariableNode {UAVariable}
* @param element {ExtensionObject} extension object of the node of element to remove in array
*
*/
export function removeElement<T extends ExtensionObject>(
Expand All @@ -305,7 +266,7 @@ export function removeElement<T extends ExtensionObject>(
if (_array.length === 0) {
throw new Error(" cannot remove an element from an empty array ");
}

let elementIndex = -1;

if (typeof element === "number") {
Expand All @@ -316,7 +277,7 @@ export function removeElement<T extends ExtensionObject>(
// find element by name
const browseNameToFind = element.browseName.name!.toString();
elementIndex = _array.findIndex((obj: any, i: number) => {
const browseName = uaArrayVariableNode.$$getElementBrowseName(obj).toString();
const browseName = uaArrayVariableNode.$$getElementBrowseName(obj, elementIndex).toString();
return browseName === browseNameToFind;
});
} else if (typeof element === "function") {
Expand All @@ -327,7 +288,7 @@ export function removeElement<T extends ExtensionObject>(
assert(_array[0].constructor.name === (element as any).constructor.name, "element must match");
elementIndex = _array.findIndex((x: any) => x === element);
}

// istanbul ignore next
if (elementIndex < 0) {
throw new Error("removeElement: cannot find element matching " + element.toString());
Expand Down
52 changes: 52 additions & 0 deletions packages/node-opcua-address-space/src/idx_iterator.ts
@@ -0,0 +1,52 @@




export class IndexIterator {

public current: number[] | null = null;
constructor(private limits: number[]) {
this.reset();
}
public reset() {
this.current = [];
for (let i = 0; i < this.limits.length; i++) {
this.current[i] = 0;
}
}
public increment() {
if (!this.current) return;


const increase = (n: number): boolean => {
if (n < 0) {
return false;
}
if (!this.current) return false;
if (this.current[n] + 1 >= this.limits[n]) {
if (n==0) {
this.current = null;
return false;
}
this.current[n] = 0;
return increase(n - 1);
}
this.current[n] = this.current[n] + 1;
return true;
}
const n = this.limits.length - 1;
if (!increase(n)) {
this.current = null;
}
}
public next(): number[] {
if (!this.current) {
throw new Error("Outof bond");
}
const r = [... this.current];
this.increment();
return r;
}


}
47 changes: 34 additions & 13 deletions packages/node-opcua-address-space/src/ua_variable_impl.ts
Expand Up @@ -28,7 +28,8 @@ import {
AccessLevelFlag,
makeAccessLevelFlag,
AttributeIds,
isDataEncoding
isDataEncoding,
QualifiedName
} from "node-opcua-data-model";
import { extractRange, sameDataValue, DataValue, DataValueLike, DataValueT } from "node-opcua-data-value";
import { coerceClock, getCurrentClock, PreciseClock } from "node-opcua-date-time";
Expand Down Expand Up @@ -87,6 +88,8 @@ import {
propagateTouchValueUpward,
setExtensionObjectValue,
_bindExtensionObject,
_bindExtensionObjectArray,
_bindExtensionObjectMatrix,
_installExtensionObjectBindingOnProperties,
_setExtensionObject,
_touchValue
Expand Down Expand Up @@ -1471,24 +1474,41 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
* @return {ExtensionObject}
*/
public bindExtensionObjectScalar(
optionalExtensionObject: ExtensionObject,
optionalExtensionObject?: ExtensionObject,
options?: BindExtensionObjectOptions
): ExtensionObject | null {
return this.bindExtensionObject(optionalExtensionObject, options) as ExtensionObject | null;
return _bindExtensionObject(this, optionalExtensionObject, options) as ExtensionObject;
}

public bindExtensionObjectArray(
optionalExtensionObject: ExtensionObject[],
optionalExtensionObject?: ExtensionObject[],
options?: BindExtensionObjectOptions
): ExtensionObject[] | null {
return this.bindExtensionObject(optionalExtensionObject, options) as ExtensionObject[] | null;
assert(this.valueRank === 1, "expecting a Array variable here");
return _bindExtensionObjectArray(this, optionalExtensionObject, options) as ExtensionObject[];
}

public bindExtensionObject(
optionalExtensionObject?: ExtensionObject | ExtensionObject[],
options?: BindExtensionObjectOptions
): ExtensionObject | ExtensionObject[] | null {
return _bindExtensionObject(this, optionalExtensionObject, options);
if (optionalExtensionObject) {
if (optionalExtensionObject instanceof Array) {
return this.bindExtensionObjectArray(optionalExtensionObject, options);
} else {
return this.bindExtensionObjectScalar(optionalExtensionObject, options);
}
}
assert(optionalExtensionObject === undefined);
if (this.valueRank === -1) {
return this.bindExtensionObjectScalar(undefined, options);
} else if (this.valueRank === 1) {
return this.bindExtensionObjectArray(undefined, options);
} else if (this.valueRank > 1) {
return _bindExtensionObjectMatrix(this, undefined, options);
}
// unsupported case ...
return null;
}

public updateExtensionObjectPartial(partialExtensionObject?: { [key: string]: any }): ExtensionObject {
Expand Down Expand Up @@ -1830,14 +1850,15 @@ UAVariableImpl.prototype.writeAttribute = thenify.withCallback(UAVariableImpl.pr
UAVariableImpl.prototype.historyRead = thenify.withCallback(UAVariableImpl.prototype.historyRead);
UAVariableImpl.prototype.readValueAsync = thenify.withCallback(UAVariableImpl.prototype.readValueAsync);

export interface UAVariableImpl {
$$variableType?: any;
$$dataType?: any;
$$getElementBrowseName: any;
$$extensionObjectArray: any;
$$indexPropertyName: any;
export interface UAVariableImplExtArray {
$$variableType?: UAVariableType;
$$dataType: UADataType;
$$getElementBrowseName: (extObject: ExtensionObject, index: number | number[]) => QualifiedName;
$$extensionObjectArray: ExtensionObject[];
$$indexPropertyName: string;
}
export interface UAVariableImpl extends UAVariableImplExtArray {
}

function check_valid_array(dataType: DataType, array: any): boolean {
if (Array.isArray(array)) {
return true;
Expand Down

0 comments on commit 12a6fca

Please sign in to comment.