Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion proto
Submodule proto updated from fd6a17 to ad1f47
14 changes: 14 additions & 0 deletions src/device-base.js
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,20 @@ export class DeviceBase extends EventEmitter {
return (this.type == DeviceType.BORON);
}

/**
* USB vendor ID.
*/
get vendorId() {
return this._dev.vendorId;
}

/**
* USB product ID.
*/
get productId() {
return this._dev.productId;
}

/**
* Set to `true` if this device is in the DFU mode.
*/
Expand Down
104 changes: 104 additions & 0 deletions src/device.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,18 @@ export const DeviceMode = fromProtobufEnum(proto.DeviceMode, {
LISTENING: 'LISTENING_MODE'
});

/**
* Logging levels.
*/
export const LogLevel = fromProtobufEnum(proto.logging.LogLevel, {
ALL: 'ALL',
TRACE: 'TRACE',
INFO: 'INFO',
WARN: 'WARN',
ERROR: 'ERROR',
NONE: 'NONE'
});

// Helper class used by Device.timeout()
class RequestSender {
constructor(dev, timeout) {
Expand Down Expand Up @@ -365,6 +377,98 @@ export class Device extends DeviceBase {
});
}

/**
* Add a log handler.
*
* @param {Object} options Options.
* @param {String} options.id Handler ID.
* @param {String} options.stream Output stream: `Serial`, `Serial1`, `USBSerial1`, etc.
* @param {String} [options.format] Message format: `default`, `json`.
* @param {String} [options.level] Default logging level: `trace`, `info`, `warn`, `error`, `none`, `all`.
* @param {Array} [options.filters] Category filters.
* @param {Number} [options.baudRate] Baud rate.
* @return {Promise}
*/
async addLogHandler({ id, stream, format, level, filters, baudRate }) {
const req = {
id,
level: LogLevel.toProtobuf(level || 'all')
};
switch ((format || 'default').toLowerCase()) {
case 'default': {
req.handlerType = proto.logging.LogHandlerType.DEFAULT_STREAM_HANDLER;
break;
}
case 'json': {
req.handlerType = proto.logging.LogHandlerType.JSON_STREAM_HANDLER;
break;
}
default: {
throw new RangeError(`Unknown message format: ${format}`);
}
}
if (!stream) {
throw new RangeError('Output stream is not specified');
}
switch (stream.toLowerCase()) {
case 'serial': {
req.streamType = proto.logging.StreamType.USB_SERIAL_STREAM;
req.serial = {
index: 0
};
break;
}
case 'usbserial1': {
req.streamType = proto.logging.StreamType.USB_SERIAL_STREAM;
req.serial = {
index: 1
};
break;
}
case 'serial1': {
req.streamType = proto.logging.StreamType.HW_SERIAL_STREAM;
req.serial = {
index: 1,
baudRate
};
break;
}
default: {
throw new RangeError(`Unknown output stream: ${stream}`);
}
}
if (filters) {
req.filters = filters.map(f => ({
category: f.category,
level: LogLevel.toProtobuf(f.level)
}));
}
return this.sendRequest(Request.ADD_LOG_HANDLER, req);
}

/**
* Remove a log handler.
*
* @param {Object} options Options.
* @param {String} options.id Handler ID.
* @return {Promise}
*/
async removeLogHandler({ id }) {
return this.sendRequest(Request.REMOVE_LOG_HANDLER, { id });
}

/**
* Get the list of active log handlers.
*
* @return {Promise<Object>}
*/
async getLogHandlers() {
const rep = await this.sendRequest(Request.GET_LOG_HANDLERS);
return rep.handlers.map(h => ({
id: h.id
}));
}

// Sends a Protobuf-encoded request
sendRequest(req, msg, opts) {
let buf = null;
Expand Down
16 changes: 16 additions & 0 deletions src/request.js
Original file line number Diff line number Diff line change
Expand Up @@ -251,5 +251,21 @@ export const Request = {
id: 1012,
request: proto.mesh.GetNetworkDiagnosticsRequest,
reply: proto.mesh.GetNetworkDiagnosticsReply
},
// Logging configuration
ADD_LOG_HANDLER: {
id: 1100,
request: proto.logging.AddLogHandlerRequest,
reply: proto.logging.AddLogHandlerReply
},
REMOVE_LOG_HANDLER: {
id: 1101,
request: proto.logging.RemoveLogHandlerRequest,
reply: proto.logging.RemoveLogHandlerReply
},
GET_LOG_HANDLERS: {
id: 1102,
request: proto.logging.GetLogHandlersRequest,
reply: proto.logging.GetLogHandlersReply
}
};
12 changes: 7 additions & 5 deletions test/device-base.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,10 @@ describe('device-base', () => {
usbDevs.push(fakeUsb.addArgonSom());
usbDevs.push(fakeUsb.addBoronSom());
// Enumerate detected devices
let devs = await getDevices();
const devs = await getDevices();
expect(devs.map(dev => dev.usbDevice)).to.have.all.members(usbDevs);
// Validate device types and platform IDs
expect(devs.map(dev => dev.vendorId)).to.have.all.members(usbDevs.map(dev => dev.vendorId));
expect(devs.map(dev => dev.productId)).to.have.all.members(usbDevs.map(dev => dev.productId));
expect(devs.map(dev => dev.type)).to.have.all.members(usbDevs.map(dev => dev.options.type));
expect(devs.map(dev => dev.platformId)).to.have.all.members(usbDevs.map(dev => dev.options.platformId));
});
Expand All @@ -79,9 +80,10 @@ describe('device-base', () => {
fakeUsb.addBoronSom({ dfu: true }),
fakeUsb.addXenonSom({ dfu: true })
];
let devs = await getDevices();
devs = devs.map(dev => dev.usbDevice);
expect(devs).to.have.all.members(usbDevs);
const devs = await getDevices();
expect(devs.map(dev => dev.usbDevice)).to.have.all.members(usbDevs);
expect(devs.map(dev => dev.vendorId)).to.have.all.members(usbDevs.map(dev => dev.vendorId));
expect(devs.map(dev => dev.productId)).to.have.all.members(usbDevs.map(dev => dev.productId));
});

it('can optionally exclude devices in the DFU mode', async () => {
Expand Down