Skip to content

Commit

Permalink
fix(service): correct atomicWriteFile service functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
fh1ch committed Dec 30, 2017
1 parent 0e34f9f commit 8a28088
Show file tree
Hide file tree
Showing 5 changed files with 35 additions and 55 deletions.
2 changes: 1 addition & 1 deletion lib/asn1.js
Expand Up @@ -864,7 +864,7 @@ const decodeDoubleSafe = (buffer, offset, lenValue) => {
}
};

const decodeOctetString = (buffer, offset, maxLength, octetStringOffset, octetStringLength) => {
const decodeOctetString = module.exports.decodeOctetString = (buffer, offset, maxLength, octetStringOffset, octetStringLength) => {
const octetString = [];
for (let i = octetStringOffset; i < (octetStringOffset + octetStringLength); i++) {
octetString.push(buffer[offset + i]);
Expand Down
4 changes: 2 additions & 2 deletions lib/client.js
Expand Up @@ -725,7 +725,7 @@ class Client extends EventEmitter {
});
}

writeFile(address, objectId, position, count, fileBuffer, options, next) {
writeFile(address, objectId, position, fileBuffer, options, next) {
next = next || options;
const settings = {
maxSegments: options.maxSegments || baEnum.MaxSegments.MAX_SEG65,
Expand All @@ -735,7 +735,7 @@ class Client extends EventEmitter {
const buffer = this._getBuffer();
baNpdu.encode(buffer, baEnum.NpduControls.PRIORITY_NORMAL_MESSAGE | baEnum.NpduControls.EXPECTING_REPLY, address);
baAdpu.encodeConfirmedServiceRequest(buffer, baEnum.PduTypes.PDU_TYPE_CONFIRMED_SERVICE_REQUEST, baEnum.ConfirmedServices.SERVICE_CONFIRMED_ATOMIC_WRITE_FILE, settings.maxSegments, settings.maxAdpu, settings.invokeId, 0, 0);
baServices.encodeAtomicWriteFile(buffer, true, objectId, position, 1, fileBuffer, count);
baServices.encodeAtomicWriteFile(buffer, false, objectId, position, fileBuffer);
baBvlc.encode(buffer.buffer, baEnum.BvlcFunctions.BVLC_ORIGINAL_UNICAST_NPDU, buffer.offset);
this._transport.send(buffer.buffer, buffer.offset, address);
this._addCallback(settings.invokeId, (err, data) => {
Expand Down
59 changes: 21 additions & 38 deletions lib/services.js
Expand Up @@ -270,19 +270,19 @@ module.exports.decodeAtomicReadFileAcknowledge = (buffer, offset) => {
};
};

module.exports.encodeAtomicWriteFile = (buffer, isStream, objectId, position, blockCount, blocks, counts) => {
module.exports.encodeAtomicWriteFile = (buffer, isStream, objectId, position, blocks) => {
baAsn1.encodeApplicationObjectId(buffer, objectId.type, objectId.instance);
if (isStream) {
baAsn1.encodeOpeningTag(buffer, 0);
baAsn1.encodeApplicationSigned(buffer, position);
baAsn1.encodeApplicationOctetString(buffer, blocks[0], 0, counts[0]);
baAsn1.encodeApplicationOctetString(buffer, blocks[0], 0, blocks[0].length);
baAsn1.encodeClosingTag(buffer, 0);
} else {
baAsn1.encodeOpeningTag(buffer, 1);
baAsn1.encodeApplicationSigned(buffer, position);
baAsn1.encodeApplicationUnsigned(buffer, blockCount);
for (let i = 0; i < blockCount; i++) {
baAsn1.encodeApplicationOctetString(buffer, blocks[i], 0, counts[i]);
baAsn1.encodeApplicationUnsigned(buffer, blocks.length);
for (let i = 0; i < blocks.length; i++) {
baAsn1.encodeApplicationOctetString(buffer, blocks[i], 0, blocks[i].length);
}
baAsn1.encodeClosingTag(buffer, 1);
}
Expand All @@ -292,13 +292,12 @@ module.exports.decodeAtomicWriteFile = (buffer, offset, apduLen) => {
let len = 0;
let result;
let decodedValue;
let isStream = true;
let position = -1;
let blockCount = 0;
let blocks = null;
let counts = null;
let isStream;
let position;
let blocks = [];
let blockCount;
result = baAsn1.decodeTagNumberAndValue(buffer, offset + len);
len += result.length;
len += result.len;
if (result.tagNumber !== baEnum.ApplicationTags.BACNET_APPLICATION_TAG_OBJECT_ID) return;
decodedValue = baAsn1.decodeObjectId(buffer, offset + len);
len += decodedValue.len;
Expand All @@ -307,55 +306,41 @@ module.exports.decodeAtomicWriteFile = (buffer, offset, apduLen) => {
isStream = true;
len++;
result = baAsn1.decodeTagNumberAndValue(buffer, offset + len);
len += result.length;
len += result.len;
if (result.tagNumber !== baEnum.ApplicationTags.BACNET_APPLICATION_TAG_SIGNED_INT) return;
decodedValue = baAsn1.decodeSigned(buffer, offset + len, result.value);
len += decodedValue.len;
position = decodedValue.value;
result = baAsn1.decodeTagNumberAndValue(buffer, offset + len);
len += result.length;
len += result.len;
if (result.tagNumber !== baEnum.ApplicationTags.BACNET_APPLICATION_TAG_OCTET_STRING) return;
blockCount = 1;

// TODO: Implement

/*
blocks = new byte[1][];
blocks[0] = new byte[len_value_type];
counts = new int[] { len_value_type };*/

len += baAsn1.decodeOctetString(buffer, offset + len, apduLen, blocks[0], 0, result.value);

decodedValue = baAsn1.decodeOctetString(buffer, offset + len, apduLen, 0, result.value);
len += decodedValue.len;
blocks.push(decodedValue.value);
if (!baAsn1.decodeIsClosingTagNumber(buffer, offset + len, 0)) return;
len++;
} else if (baAsn1.decodeIsOpeningTagNumber(buffer, offset + len, 1)) {
isStream = false;
len++;
result = baAsn1.decodeTagNumberAndValue(buffer, offset + len);
len += result.length;
len += result.len;
if (result.tagNumber !== baEnum.ApplicationTags.BACNET_APPLICATION_TAG_SIGNED_INT) return;
decodedValue = baAsn1.decodeSigned(buffer, offset + len, result.value);
len += decodedValue.len;
position = decodedValue.value;
result = baAsn1.decodeTagNumberAndValue(buffer, offset + len);
len += result.length;
len += result.len;
if (result.tagNumber !== baEnum.ApplicationTags.BACNET_APPLICATION_TAG_UNSIGNED_INT) return;
decodedValue = baAsn1.decodeUnsigned(buffer, offset + len, result.value);
len += decodedValue.len;
blockCount = decodedValue.value;

// TODO: Implement
/*blocks = new byte[block_count][];
counts = new int[block_count];*/

for (let i = 0; i < blockCount; i++) {
result = baAsn1.decodeTagNumberAndValue(buffer, offset + len);
len += result.len;
/*blocks[i] = new byte[len_value_type];
counts[i] = len_value_type;*/
if (result.tagNumber !== baEnum.ApplicationTags.BACNET_APPLICATION_TAG_OCTET_STRING) return;
len += baAsn1.decodeOctetString(buffer, offset + len, apduLen, blocks[i], 0, result.value);

decodedValue = baAsn1.decodeOctetString(buffer, offset + len, apduLen, 0, result.value);
len += decodedValue.len;
blocks.push(decodedValue.value);
}
if (!baAsn1.decodeIsClosingTagNumber(buffer, offset + len, 1)) return;
len++;
Expand All @@ -367,9 +352,7 @@ module.exports.decodeAtomicWriteFile = (buffer, offset, apduLen) => {
isStream: isStream,
objectId: objectId,
position: position,
blockCount: blockCount,
blocks: blocks,
counts: counts
blocks: blocks
};
};

Expand Down
2 changes: 1 addition & 1 deletion test/integration/write-file.spec.js
Expand Up @@ -6,7 +6,7 @@ const utils = require('./utils');
describe('bacstack - writeFile integration', () => {
it('should return a timeout error if no device is available', (next) => {
const client = new utils.bacnetClient({adpuTimeout: 200});
client.writeFile('127.0.0.1', {type: 10, instance: 2}, 0, 4, [5, 6, 7 , 8], (err, value) => {
client.writeFile('127.0.0.1', {type: 10, instance: 2}, 0, [[5, 6, 7, 8], [5, 6, 7, 8]], (err, value) => {
expect(err.message).to.eql('ERR_TIMEOUT');
expect(value).to.eql(undefined);
client.close();
Expand Down
23 changes: 10 additions & 13 deletions test/unit/bacnet-services.spec.js
Expand Up @@ -1243,33 +1243,30 @@ describe('bacstack - Services layer', () => {
});
});

// TODO: Correct test behaviour
describe.skip('AtomicWriteFile', () => {
describe('AtomicWriteFile', () => {
it('should successfully encode and decode as stream', () => {
const buffer = utils.getBuffer();
// (buffer, isStream, objectId, position, blockCount, blocks, counts);
baServices.encodeAtomicWriteFile(buffer, true, {type: 51, instance: 2}, 0, 100, [12, 12], 2);
baServices.encodeAtomicWriteFile(buffer, true, {type: 12, instance: 51}, 5, [[12, 12]]);
const result = baServices.decodeAtomicWriteFile(buffer.buffer, 0, buffer.offset);
delete result.len;
expect(result).to.deep.equal({
objectId: {type: 51, instance: 2},
count: 12,
objectId: {type: 12, instance: 51},
isStream: true,
position: -50
position: 5,
blocks: [[12, 12]]
});
});

it('should successfully encode and decode as non-stream', () => {
const buffer = utils.getBuffer();
// (buffer, isStream, objectId, position, blockCount, blocks, counts);
baServices.encodeAtomicWriteFile(buffer, false, {type: 51, instance: 2}, 0, 100, [12, 12], 2);
baServices.encodeAtomicWriteFile(buffer, false, {type: 12, instance: 88}, 10, [[12, 12], [12, 12]]);
const result = baServices.decodeAtomicWriteFile(buffer.buffer, 0, buffer.offset);
delete result.len;
expect(result).to.deep.equal({
objectId: {type: 51, instance: 2},
count: 12,
isStream: true,
position: -50
objectId: {type: 12, instance: 88},
isStream: false,
position: 10,
blocks: [[12, 12], [12, 12]]
});
});
});
Expand Down

0 comments on commit 8a28088

Please sign in to comment.