Skip to content

Commit

Permalink
Add scaleFactor to DataObject
Browse files Browse the repository at this point in the history
  • Loading branch information
wilkinsw committed Dec 15, 2023
1 parent 9122d15 commit 3dda94e
Show file tree
Hide file tree
Showing 5 changed files with 144 additions and 36 deletions.
74 changes: 74 additions & 0 deletions source/device.js
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,43 @@ class Device extends EventEmitter {
return entry.value;
}

/**
* Get the scale factor of an EDS entry.
*
* @param {number | string} index - index or name of the entry.
* @returns {number | bigint | string | Date} entry value.
*/
getScale(index) {
const entry = this.eds.getEntry(index);
if (!entry) {
if (typeof index === 'number')
index = '0x' + index.toString(16);

throw new EdsError(`entry ${index} does not exist`);
}

return entry.scaleFactor;
}

/**
* Get the scale factor of an EDS sub-entry.
*
* @param {number | string} index - index or name of the entry.
* @param {number} subIndex - sub-object index.
* @returns {number | bigint | string | Date} entry value.
*/
getScaleArray(index, subIndex) {
const entry = this.eds.getSubEntry(index, subIndex);
if (!entry) {
if (typeof index === 'number')
index = '0x' + index.toString(16);

throw new EdsError(`entry ${index}[${subIndex}] does not exist`);
}

return entry.scaleFactor;
}

/**
* Get the raw value of an EDS entry.
*
Expand Down Expand Up @@ -518,6 +555,43 @@ class Device extends EventEmitter {

entry.raw = raw;
}

/**
* Set the scale factor of an EDS entry.
*
* @param {number | string} index - index or name of the entry.
* @param {number} scaleFactor - value to set.
*/
setScale(index, scaleFactor) {
const entry = this.eds.getEntry(index);
if (!entry) {
if (typeof index === 'number')
index = '0x' + index.toString(16);

throw new EdsError(`entry ${index} does not exist`);
}

entry.scaleFactor = scaleFactor;
}

/**
* Set the scale factor of an EDS sub-entry.
*
* @param {number | string} index - index or name of the entry.
* @param {number} subIndex - array sub-index to set;
* @param {number} scaleFactor - value to set.
*/
setScaleArray(index, subIndex, scaleFactor) {
const entry = this.eds.getSubEntry(index, subIndex);
if (!entry) {
if (typeof index === 'number')
index = '0x' + index.toString(16);

throw new EdsError(`entry ${index}[${subIndex}] does not exist`);
}

entry.scaleFactor = scaleFactor;
}
}

module.exports = exports = Device;
5 changes: 3 additions & 2 deletions source/eds.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ class EdsError extends Error {
* @param {boolean} data.pdoMapping - enable PDO mapping.
* @param {boolean} data.compactSubObj - use the compact sub-object format.
* @param {number | string | Date} data.defaultValue - default value.
* @param {number} data.scaleFactor - optional multiplier for numeric types.
* @fires 'update' on value change.
* @see CiA306 "Object descriptions" (§4.6.3)
*/
Expand Down Expand Up @@ -347,7 +348,7 @@ class DataObject extends EventEmitter {
*/
get value() {
if (!this.subNumber)
return rawToType(this.raw, this.dataType);
return rawToType(this.raw, this.dataType, this.scaleFactor);

const data = [];
for (let i = 1; i <= this._subObjects[0].value; ++i) {
Expand All @@ -364,7 +365,7 @@ class DataObject extends EventEmitter {
if (this.subNumber)
throw new EdsError(`not supported for type ${this.objectTypeString}`);

this.raw = typeToRaw(value, this.dataType);
this.raw = typeToRaw(value, this.dataType, this.scaleFactor);
}

/**
Expand Down
35 changes: 18 additions & 17 deletions source/functions/raw_to_type.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,47 +36,48 @@ function rawToDate(raw) {
*
* @param {Buffer} raw - data to convert.
* @param {DataType | string} type - how to interpret the data.
* @param {number} [scaleFactor] - optional multiplier for numeric types.
* @returns {number | bigint | string | Date} converted data.
*/
function rawToType(raw, type) {
function rawToType(raw, type, scaleFactor=1.0) {
if (typeof type === 'string')
type = DataType[type];

switch (type) {
case DataType.BOOLEAN:
return !!raw.readUInt8();
case DataType.INTEGER8:
return raw.readInt8();
return raw.readInt8() * scaleFactor;
case DataType.INTEGER16:
return raw.readInt16LE();
return raw.readInt16LE() * scaleFactor;
case DataType.INTEGER24:
return raw.readIntLE(0, 3);
return raw.readIntLE(0, 3) * scaleFactor;
case DataType.INTEGER32:
return raw.readInt32LE();
return raw.readInt32LE() * scaleFactor;
case DataType.INTEGER40:
return raw.readIntLE(0, 5);
return raw.readIntLE(0, 5) * scaleFactor;
case DataType.INTEGER48:
return raw.readIntLE(0, 6);
return raw.readIntLE(0, 6) * scaleFactor;
case DataType.INTEGER64:
return raw.readBigInt64LE()
return raw.readBigInt64LE() * BigInt(scaleFactor);
case DataType.UNSIGNED8:
return raw.readUInt8();
return raw.readUInt8() * scaleFactor;
case DataType.UNSIGNED16:
return raw.readUInt16LE();
return raw.readUInt16LE() * scaleFactor;
case DataType.UNSIGNED24:
return raw.readUIntLE(0, 3);
return raw.readUIntLE(0, 3) * scaleFactor;
case DataType.UNSIGNED32:
return raw.readUInt32LE();
return raw.readUInt32LE() * scaleFactor;
case DataType.UNSIGNED40:
return raw.readUIntLE(0, 5);
return raw.readUIntLE(0, 5) * scaleFactor;
case DataType.UNSIGNED48:
return raw.readUIntLE(0, 6);
return raw.readUIntLE(0, 6) * scaleFactor;
case DataType.UNSIGNED64:
return raw.readBigUInt64LE();
return raw.readBigUInt64LE() * BigInt(scaleFactor);
case DataType.REAL32:
return raw.readFloatLE();
return raw.readFloatLE() * scaleFactor;
case DataType.REAL64:
return raw.readDoubleLE();
return raw.readDoubleLE() * scaleFactor;
case DataType.VISIBLE_STRING:
case DataType.UNICODE_STRING:
return rawToString(raw);
Expand Down
35 changes: 18 additions & 17 deletions source/functions/type_to_raw.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,10 @@ function dateToRaw(value) {
*
* @param {number | bigint | string | Date} value - data to convert.
* @param {DataType | string} type - how to interpret the data.
* @param {number} [scaleFactor] - optional multiplier for numeric types.
* @returns {Buffer} converted Buffer.
*/
function typeToRaw(value, type) {
function typeToRaw(value, type, scaleFactor=1.0) {
if (value === undefined || value === null)
value = 0;

Expand All @@ -54,75 +55,75 @@ function typeToRaw(value, type) {
break;
case DataType.INTEGER8:
raw = Buffer.alloc(1);
raw.writeInt8(value)
raw.writeInt8(value / scaleFactor)
break;
case DataType.UNSIGNED8:
raw = Buffer.alloc(1);
raw.writeUInt8(value)
raw.writeUInt8(value / scaleFactor)
break;
case DataType.INTEGER16:
raw = Buffer.alloc(2);
raw.writeInt16LE(value);
raw.writeInt16LE(value / scaleFactor);
break;
case DataType.UNSIGNED16:
raw = Buffer.alloc(2);
raw.writeUInt16LE(value);
raw.writeUInt16LE(value / scaleFactor);
break;
case DataType.INTEGER24:
raw = Buffer.alloc(3);
raw.writeIntLE(value, 0, 3);
raw.writeIntLE(value / scaleFactor, 0, 3);
break;
case DataType.UNSIGNED24:
raw = Buffer.alloc(3);
raw.writeUIntLE(value, 0, 3);
raw.writeUIntLE(value / scaleFactor, 0, 3);
break;
case DataType.INTEGER32:
raw = Buffer.alloc(4);
raw.writeInt32LE(value);
raw.writeInt32LE(value / scaleFactor);
break;
case DataType.UNSIGNED32:
raw = Buffer.alloc(4);
raw.writeUInt32LE(value);
raw.writeUInt32LE(value / scaleFactor);
break;
case DataType.INTEGER40:
raw = Buffer.alloc(5);
raw.writeIntLE(value, 0, 5);
raw.writeIntLE(value / scaleFactor, 0, 5);
break;
case DataType.UNSIGNED40:
raw = Buffer.alloc(5);
raw.writeUIntLE(value, 0, 5);
raw.writeUIntLE(value / scaleFactor, 0, 5);
break;
case DataType.INTEGER48:
raw = Buffer.alloc(6);
raw.writeIntLE(value, 0, 6);
raw.writeIntLE(value / scaleFactor, 0, 6);
break;
case DataType.UNSIGNED48:
raw = Buffer.alloc(6);
raw.writeUIntLE(value, 0, 6);
raw.writeUIntLE(value / scaleFactor, 0, 6);
break;
case DataType.INTEGER56:
case DataType.INTEGER64:
if (typeof value != 'bigint')
value = BigInt(value);

raw = Buffer.alloc(8);
raw.writeBigInt64LE(value);
raw.writeBigInt64LE(value / BigInt(scaleFactor));
break;
case DataType.UNSIGNED56:
case DataType.UNSIGNED64:
if (typeof value != 'bigint')
value = BigInt(value);

raw = Buffer.alloc(8);
raw.writeBigUInt64LE(value);
raw.writeBigUInt64LE(value / BigInt(scaleFactor));
break;
case DataType.REAL32:
raw = Buffer.alloc(4);
raw.writeFloatLE(value);
raw.writeFloatLE(value / scaleFactor);
break;
case DataType.REAL64:
raw = Buffer.alloc(8);
raw.writeDoubleLE(value);
raw.writeDoubleLE(value / scaleFactor);
break;
case DataType.VISIBLE_STRING:
raw = stringToRaw(value);
Expand Down
31 changes: 31 additions & 0 deletions test/test_eds.js
Original file line number Diff line number Diff line change
Expand Up @@ -424,4 +424,35 @@ describe('Eds', function () {
expect(() => eds.removeSubEntry(0x2000, 0)).to.throw(EdsError);
});
});

describe('Scaling', function () {
let eds;

before(function () {
eds = new Eds();
});

it('should scale numeric values', function () {
const obj = eds.addEntry(0x2000, {
parameterName: 'VAR',
objectType: ObjectType.VAR,
dataType: DataType.UNSIGNED8,
accessType: AccessType.READ_WRITE,
defaultValue: 2,
});

// 2 * 10 = 20
obj.scaleFactor = 10;
expect(obj.value).to.equal(20);

// 2 * 0.5 = 1
obj.scaleFactor = 0.5;
expect(obj.value).to.equal(1);

// 5 / 0.5 = 10
obj.value = 5;
obj.scaleFactor = 1;
expect(obj.value).to.equal(10);
});
});
});

0 comments on commit 3dda94e

Please sign in to comment.