diff --git a/lib/asn1.js b/lib/asn1.js index c33986d..0d1263e 100644 --- a/lib/asn1.js +++ b/lib/asn1.js @@ -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]); diff --git a/lib/client.js b/lib/client.js index e65c232..c153f27 100644 --- a/lib/client.js +++ b/lib/client.js @@ -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, @@ -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) => { diff --git a/lib/services.js b/lib/services.js index 2b33dac..07e770e 100644 --- a/lib/services.js +++ b/lib/services.js @@ -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); } @@ -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; @@ -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++; @@ -367,9 +352,7 @@ module.exports.decodeAtomicWriteFile = (buffer, offset, apduLen) => { isStream: isStream, objectId: objectId, position: position, - blockCount: blockCount, - blocks: blocks, - counts: counts + blocks: blocks }; }; diff --git a/test/integration/write-file.spec.js b/test/integration/write-file.spec.js index 4373845..027558a 100644 --- a/test/integration/write-file.spec.js +++ b/test/integration/write-file.spec.js @@ -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(); diff --git a/test/unit/bacnet-services.spec.js b/test/unit/bacnet-services.spec.js index 5269051..299a78d 100644 --- a/test/unit/bacnet-services.spec.js +++ b/test/unit/bacnet-services.spec.js @@ -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]] }); }); });