UNPKG

ble-mesh-serial-interface-js

Version:

An npm package for Node.js that provides an API to control a router node in a BLE mesh network via the serial port.

608 lines (495 loc) 18.9 kB
'use strict'; const expect = require('chai').expect; const assert = require('chai').assert; const BLEMeshSerialInterface = require('../BLEMeshSerialInterface'); const MESH_ACCESS_ADDR = 0x8E89BED6; const MESH_INTERVAL_MIN_MS = 100; const MESH_ADVERTISING_CHANNEL = 38; const MESH_ACCESS_ADDR_ARRAY = [0x8e, 0x89, 0xbe, 0xd6]; const MESH_INTERVAL_MIN_MS_ARRAY = [0, 0, 0, 100]; const FIRST_COM_PORT = 'COM45'; function checkError(err) { if (err) { console.log(err); } } function arraysEqual(arr1, arr2) { if(arr1.length !== arr2.length) return false; for(let i = arr1.length; i--;) { if(arr1[i] !== arr2[i]) return false; } return true; } const bleMeshSerialInterfaceAPI = new BLEMeshSerialInterface(); describe('helper function tests', function() { it('tests bleMeshSerialInterfaceAPI.buildResponse() on single command response', () => { const resp = new Buffer([0x03, 0x84, 0x74, 0x00]); bleMeshSerialInterfaceAPI.buildResponse(resp); expect(bleMeshSerialInterfaceAPI._responseQueue.shift().toString('hex')).to.equal(resp.toString('hex')); expect(bleMeshSerialInterfaceAPI._tempBuildResponse).to.equal(null); }); it('tests bleMeshSerialInterfaceAPI.buildResponse() on single event response', () => { const resp = new Buffer([0x03, 0xb3, 0x00, 0x00]); bleMeshSerialInterfaceAPI.buildResponse(resp); expect(bleMeshSerialInterfaceAPI._responseQueue.shift().toString('hex')).to.equal(resp.toString('hex')); expect(bleMeshSerialInterfaceAPI._tempBuildResponse).to.equal(null); }); it('tests bleMeshSerialInterfaceAPI.buildResponse() on two event responses', () => { const resp = new Buffer([0x04, 0xb3, 0x00, 0x00, 0x00, 0x05, 0xb4, 0x00, 0x00, 0x00, 0x00]); bleMeshSerialInterfaceAPI.buildResponse(resp); expect(bleMeshSerialInterfaceAPI._responseQueue.shift().toString('hex')).to.equal(resp.slice(0, 5).toString('hex')); expect(bleMeshSerialInterfaceAPI._responseQueue.shift().toString('hex')).to.equal(resp.slice(5).toString('hex')); expect(bleMeshSerialInterfaceAPI._tempBuildResponse).to.equal(null); }); it('tests bleMeshSerialInterfaceAPI.buildResponse() on a response that comes in two data events', () => { const resp1 = new Buffer([0x06, 0xb3, 0x00, 0x00]); const resp2 = new Buffer([0x00, 0x00, 0x00]); const expectedResp = Buffer.concat([resp1, resp2]); bleMeshSerialInterfaceAPI.buildResponse(resp1); bleMeshSerialInterfaceAPI.buildResponse(resp2); expect(bleMeshSerialInterfaceAPI._responseQueue.shift().toString('hex')).to.equal(expectedResp.toString('hex')); expect(bleMeshSerialInterfaceAPI._tempBuildResponse).to.equal(null); }); it('tests bleMeshSerialInterfaceAPI.buildResponse() on a broken up response followed by two responses', () => { const resp1 = new Buffer([0x06, 0xb3, 0x00, 0x00]); const resp2 = new Buffer([0x00, 0x00, 0x00, 0x04, 0xb4, 0x00, 0x00, 0x00]); const expectedResp = Buffer.concat([resp1, resp2]); bleMeshSerialInterfaceAPI.buildResponse(resp1); bleMeshSerialInterfaceAPI.buildResponse(resp2); expect(bleMeshSerialInterfaceAPI._responseQueue.shift().toString('hex')).to.equal(expectedResp.slice(0, 7).toString('hex')); expect(bleMeshSerialInterfaceAPI._responseQueue.shift().toString('hex')).to.equal(expectedResp.slice(7).toString('hex')); expect(bleMeshSerialInterfaceAPI._tempBuildResponse).to.equal(null); }); it('tests bleMeshSerialInterfaceAPI.isCommandResponse()', () => { const resp = new Buffer([0x01, 0x82]); let res = bleMeshSerialInterfaceAPI.isCommandResponse(resp); expect(res).to.equal(true); const resp2 = new Buffer([0x01, 0x84]); res = bleMeshSerialInterfaceAPI.isCommandResponse(resp2); expect(res).to.equal(true); const resp3 = new Buffer([0x0]); res = bleMeshSerialInterfaceAPI.isCommandResponse(resp3); expect(res).to.equal(true); const resp4 = new Buffer([0x1, 0x81]); res = bleMeshSerialInterfaceAPI.isCommandResponse(resp4); expect(res).to.equal(false); }); it('tests bleMeshSerialInterfaceAPI.bytesArrayToUnsignedInt()', () => { const handle1 = [0x0, 0x0]; expect(bleMeshSerialInterfaceAPI.bytesArrayToUnsignedInt(handle1)).to.equal(0); const handle2 = [0x0, 0x1]; expect(bleMeshSerialInterfaceAPI.bytesArrayToUnsignedInt(handle2)).to.equal(1); const handle3 = [0xFF, 0xFF]; expect(bleMeshSerialInterfaceAPI.bytesArrayToUnsignedInt(handle3)).to.equal(65535); const handle4 = [0xFF, 0xFF, 0xFF, 0xFF]; expect(bleMeshSerialInterfaceAPI.bytesArrayToUnsignedInt(handle4)).to.equal(4294967295); }); }); describe('nRF Open Mesh serial interface command unit tests -- tests are not self-contained', () => { before(function(done) { bleMeshSerialInterfaceAPI.openSerialPort(FIRST_COM_PORT, err => { bleMeshSerialInterfaceAPI.once('deviceStarted', data => { console.log('device started') //done(); }); bleMeshSerialInterfaceAPI.radioReset(err => { console.log('reset') checkError(err) done() }); }); }); it('prompts slave to echo one byte back to host', done => { const buf = [0x01]; bleMeshSerialInterfaceAPI.echo(buf, (err, res) => { checkError(err); expect(res.toString()).to.equal(buf.toString()); done(); }); }); it('prompts slave to echo two bytes back to host', done => { const buf = [0x01, 0x02]; bleMeshSerialInterfaceAPI.echo(buf, (err, res) => { checkError(err); expect(res.toString()).to.equal(buf.toString()); done(); }); }); it('prompts slave to echo too many bytes back to host', done => { const buf = new Array(30).fill(0xff); bleMeshSerialInterfaceAPI.echo(buf, (err, res) => { checkError(err); expect(res.toString()).to.equal(buf.toString()); done(); }); }); it('prompts slave to return its build version', done => { const buf = [0x0, 0x8, 0x5]; bleMeshSerialInterfaceAPI.buildVersionGet((err, res) => { checkError(err); expect(res.toString()).to.equal(buf.toString()); done(); }); }); it('prompts slave to initialize the mesh', done => { bleMeshSerialInterfaceAPI.init(MESH_ACCESS_ADDR, MESH_INTERVAL_MIN_MS, MESH_ADVERTISING_CHANNEL, err => { if (err) { console.log(err); assert(false, 'error initializing the device'); } done(); }); }); it('prompts slave to initialize the mesh, already initialize so should fail with status code error', done => { bleMeshSerialInterfaceAPI.init(MESH_ACCESS_ADDR, MESH_INTERVAL_MIN_MS, MESH_ADVERTISING_CHANNEL, err => { if (err) { console.log(err); done(); } assert(false, 'error, should not have succeeded to initialize an already initialized device'); }); }); it('prompts slave to set the value of handle 0', done => { bleMeshSerialInterfaceAPI.valueSet(0, [0x00, 0x01, 0x02], err => { if (err) { console.log(err); assert(false, 'error setting the value of a handle on the mesh'); } done(); }); }); it('prompts slave to get the value of handle 0', done => { const buf = [0, 1, 2]; bleMeshSerialInterfaceAPI.valueGet(0, (err, res) => { checkError(err); expect(0).to.equal(res.handle); assert(arraysEqual(buf, res.data), 'incorrect value for handle 0'); done(); }); }); it('set the value of a handle, and then get it directly after', done => { const buf = [0, 1, 2]; bleMeshSerialInterfaceAPI.valueSet(0, buf, err => { if (err) { console.log(err); assert(false, 'failed to set the value of handle 0'); } bleMeshSerialInterfaceAPI.valueGet(0, (err, res) => { checkError(err); assert(arraysEqual(0, res.handle), 'incorrect handle'); assert(arraysEqual(buf, res.data), 'incorrect value for handle 0'); done(); }); }); }); it('prompts slave to set the persistence of handle 0', done => { bleMeshSerialInterfaceAPI.flagSet(0, 1, err => { if (err) { console.log(err); assert(false, 'failed to set the persistence flag of handle 1'); } done(); }); }); it('prompts slave to get the persistence of handle 0', done => { bleMeshSerialInterfaceAPI.flagGet(0, (err, res) => { checkError(err); assert(arraysEqual(res.handle, 0), 'persistence of handle 1 has not been set yet'); assert(res.flagIndex == 0, 'incorrect flagIndex'); assert(res.flagValue == 1, 'incorrect flagValue'); done(); }); }); it('prompts slave to set the persistence of handle 0', done => { bleMeshSerialInterfaceAPI.flagSet(0, 0, err => { if (err) { console.log(err); assert(false, 'failed to set the persistence flag of handle 1'); } done(); }); }); it('prompts slave to get the persistence of handle 0', done => { bleMeshSerialInterfaceAPI.flagGet(0, (err, res) => { checkError(err); assert(arraysEqual(res.handle, 0), 'persistence of handle 1 has not been set yet'); assert(res.flagIndex == 0, 'incorrect flagIndex'); assert(res.flagValue == 0, 'incorrect flagValue'); done(); }); }); it('prompts slave to set the tx event on handle 0', done => { bleMeshSerialInterfaceAPI.txEventSet(0, 1, err => { if (err) { console.log(err); assert(false, 'failed to set the tx event on handle 0'); } done(); }); }); it('prompts slave to get the tx event of handle 0', done => { bleMeshSerialInterfaceAPI.txEventGet(0, (err, res) => { checkError(err); assert(arraysEqual(res, [0, 0, 0, 1]), 'tx event on handle 0 has not been set yet'); done(); }); }); it('prompts slave to enable handle 1', done => { bleMeshSerialInterfaceAPI.valueEnable(1, err => { if (err) { console.log(err); assert(false, 'failed to enable handle 1'); } done(); }); }); it('prompts slave to disable handle 1', done => { bleMeshSerialInterfaceAPI.valueDisable(1, err => { if (err) { console.log(err); assert(false, 'failed to disable handle 1'); } done(); }); }); it('prompts slave to return its access address', done => { bleMeshSerialInterfaceAPI.accessAddrGet((err, res) => { checkError(err); assert(arraysEqual(MESH_ACCESS_ADDR, res.accessAddr), 'incorrect mesh access address'); done(); }); }); it('prompts slave to return its advertising channel', done => { bleMeshSerialInterfaceAPI.channelGet((err, res) => { console.log(res.channel) checkError(err); assert(MESH_ADVERTISING_CHANNEL == res.channel, 'incorrect mesh advertising channel'); done(); }); }); it('prompts slave to return its minimum rebroadcasting interval', done => { bleMeshSerialInterfaceAPI.intervalMinGet((err, res) => { checkError(err); assert(arraysEqual(MESH_INTERVAL_MIN_MS, res.intervalMin), 'incorrect minimum rebroadcasting interval'); done(); }); }); it('prompts slave to stop the mesh from broadcasting', done => { bleMeshSerialInterfaceAPI.stop(err => { if (err) { console.log(err); assert(false, 'failed to stop the mesh from broadcasting'); } done(); }); }); it('prompts slave to start broadcasting on the mesh', done => { bleMeshSerialInterfaceAPI.start(err => { if (err) { console.log(err); assert(false, 'failed to start broadcasting on the mesh'); } done(); }); }); it('prompts the slave to perform a radio reset', done => { bleMeshSerialInterfaceAPI.once('deviceStarted', () => { done(); }); bleMeshSerialInterfaceAPI.radioReset(err => { if (err) { console.log(err); assert(false, 'failed to reset the slave'); } }); }); it('prompts slave to echo two bytes back to host', done => { const buf = [0x01, 0x02]; bleMeshSerialInterfaceAPI.echo(buf, (err, res) => { checkError(err); assert(arraysEqual(buf, res), 'echoed data is not equal to what was sent'); done(); }); }); it('sends dfu data packet', done => { // This should fail since the FW doesn't have a bootloader/isn't configured for DFU. const buf = new Array(23).fill(0xff); bleMeshSerialInterfaceAPI.dfuData(buf, (err, res) => { if (err) { console.log(err); done(); } }); }); }); describe('nRF Open Mesh self contained serial interface unit tests', () => { beforeEach(function(done) { bleMeshSerialInterfaceAPI.openSerialPort(FIRST_COM_PORT, err => { bleMeshSerialInterfaceAPI.once('deviceStarted', data => { done(); }); bleMeshSerialInterfaceAPI.radioReset(err => { checkError(err) }); }); }); after(function(done) { bleMeshSerialInterfaceAPI.closeSerialPort(err => { checkError(err); done(); }); }); it('prompts slave to echo one byte back to host', done => { const buf = [0x01]; bleMeshSerialInterfaceAPI.echo(buf, (err, res) => { checkError(err); assert(arraysEqual(buf, res), 'echoed data is not equal to what was sent'); done(); }); }); it('prompts slave to echo two bytes back to host', done => { const buf = [0x01, 0x02]; bleMeshSerialInterfaceAPI.echo(buf, (err, res) => { checkError(err); assert(arraysEqual(buf, res), 'echoed data is not equal to what was sent'); done(); }); }); }); /*describe('nRF Open Mesh self contained DFU serial interface unit tests', () => { beforeEach(function(done) { const fwid = [0x11, 0x78, 0xfe, 0xff, 0x64, 0, 1, 1, 0x59, 0, 0, 0, 1, 0, 1, 0, 0, 0]; bleMeshSerialInterfaceAPI.openSerialPort(FIRST_COM_PORT, err => { bleMeshSerialInterfaceAPI.once('eventDFU', data => { assert(arraysEqual(fwid, data), 'incorrect DFU Beacon (FWID) received from device'); done(); }); bleMeshSerialInterfaceAPI.radioReset(err => { checkError(err) }); }); }); afterEach(function(done) { bleMeshSerialInterfaceAPI.closeSerialPort(err => { checkError(err); bleMeshSerialInterfaceAPI = null; done(); }); }); it('prompts slave to echo one byte back to host', done => { const buf = [0x01]; bleMeshSerialInterfaceAPI.echo(buf, (err, res) => { checkError(err); assert(arraysEqual(buf, res), 'echoed data is not equal to what was sent'); done(); }); }); it('sends dfu fwid data packet', done => { const fwid = [0xfe, 0xff, 0x64, 0, 1, 1, 0x59, 0, 0, 0, 1, 0, 2, 0, 0, 0]; const ackFWID = [0xfe, 0xff]; const expectedEvent = [0xfd, 0xff]; bleMeshSerialInterfaceAPI.once('eventDFU', data => { assert(arraysEqual(expectedEvent, data.slice(2, 4)), 'incorrect DFU event received in protocol'); done(); }); bleMeshSerialInterfaceAPI.dfuData(fwid, (err, res) => { checkError(err); assert(arraysEqual(ackFWID, res), 'incorrect DFU FWID ACK received from device'); }); }); });*/ /*describe('BLE Smart Mesh serial interface command unit tests -- tests are not self-contained', () => { before(function(done) { bleMeshSerialInterfaceAPI.openSerialPort(FIRST_COM_PORT, err => { checkError(err); bleMeshSerialInterfaceAPI.on('deviceStarted', data => { }); done(); }); }); after(function(done) { bleMeshSerialInterfaceAPI.closeSerialPort(err => { checkError(err); bleMeshSerialInterfaceAPI = null; done(); }); }); it('prompts slave to echo one byte back to host', done => { const buf = [0x01]; bleMeshSerialInterfaceAPI.echo(buf, (err, res) => { checkError(err); assert(arraysEqual(buf, res), 'echoed data is not equal to what was sent'); done(); }); }); it('prompts slave to echo two bytes back to host', done => { const buf = [0x01, 0x02]; bleMeshSerialInterfaceAPI.echo(buf, (err, res) => { checkError(err); assert(arraysEqual(buf, res), 'echoed data is not equal to what was sent'); done(); }); }); it('prompts slave to echo too many bytes back to host', done => { const buf = new Array(30).fill(0xff); bleMeshSerialInterfaceAPI.echo(buf, (err, res) => { checkError(err); assert(arraysEqual(buf, res), 'echoed data is not equal to what was sent'); done(); }); }); it('prompts slave to return its build version', done => { const buf = [1, 0]; bleMeshSerialInterfaceAPI.getVersion((err, res) => { checkError(err); assert(arraysEqual(buf, res), 'unexpected build version returned'); done(); }); }); it('prompts slave to set its key-pair for use in encrypting provisioning data', done => { bleMeshSerialInterfaceAPI.setKeyPair(err => { if (err) { console.log(err); assert(false, 'failed to set key-pair'); } done(); }); }); it('prompts slave to set its provisioning capabilities', done => { bleMeshSerialInterfaceAPI.setCapabilities(err => { if (err) { console.log(err); assert(false, 'failed to set key-pair'); } done(); }); }); it('prompts slave to initialize a provisioning context', done => { const contextID = 2; bleMeshSerialInterfaceAPI.provInitContext(contextID, (err, res) => { checkError(err); assert(arraysEqual(contextID, res[0]), 'failed to initialize a provisioning context'); done(); }); }); it('prompts slave to start scanning for un-provisioned devices', done => { bleMeshSerialInterfaceAPI.provStartScan(err => { if (err) { console.log(err); assert(false, 'failed to start scanning'); } done(); }); }); it('prompts slave to stop scanning for un-provisioned devices', done => { bleMeshSerialInterfaceAPI.provStopScan(err => { if (err) { console.log(err); assert(false, 'failed to stop scanning'); } done(); }); }); }); */