weblab-instrument
Version:
communication with instrument through usb
686 lines (634 loc) • 20.4 kB
JavaScript
/**
* Module use to communicate with GWINSTEK's DSO through Ethernet or USB
*
* @module instrument-com
*/
/* eslint no-restricted-syntax: 0 */
/* eslint no-await-in-loop: 0 */
import cmdObj from './sys/dmm-command.json';
const EventEmitter = require('events').EventEmitter;
const debug = require('debug');
const log = debug('dmm:log');
const sysConstant = require('./sys/sysConstant.js');
const syscmd = require('./dmm/system.js');
const confcmd = require('./dmm/config.js');
const meascmd = require('./dmm/measure.js');
const usbDev = require('./dev/devUsb.js');
const base = require('./dev/base.js');
/**
* Create all needed private properties and method
*
* @private
* @constructor DmmObject
*
* @return {Object} Private method used to control DSO
*/
function DmmObject() {
this.dev = new base.Dev();
// uitl.inherits(this.dev, base.Dev);
// assign dso system command process method to dmmObj.sys
this.sys = syscmd.initDmmSysObj.call(this, 'sys');
this.conf = confcmd.initConfObj.call(this, 'conf');
this.meas = meascmd.initMeasObj.call(this, 'meas');
this.cmdEvent = new EventEmitter();
this.commandObj = cmdObj;
this.dev.commandObj = this.commandObj;
return this;
}
/**
* The class define all needed public properties and methods
*
* @class dmmctrl
*
*
*/
function DmmControl(dmmObj) {
const dmmctrl = {};
/**
* The method belong to dmmctrl class used to release device's resource.
*
* @method closeDev
* @return {null} null
*
*/
dmmctrl.closeDev = function closeDev() {
return new Promise(((resolve, reject) => {
dmmctrl.disconnect()
.then(resolve)
.catch((e) => {
reject(e);
});
}));
};
/**
* The method belong to dmmctrl class used to connect to device,
* connect method must be called and wait to complete before any dmmctrl method.
*
* @method connect
*
*
*/
dmmctrl.connect = function connect(dontCheckdev) {
const self = this;
return new Promise(((resolve, reject) => {
function conn(e) {
if (e) {
reject(e);
} else {
resolve();
}
}
self.dev.usbConnect(conn, dontCheckdev);
}));
}.bind(dmmObj);
/**
* The method belong to dmmctrl class used to disconnect from device.
*
* @method disconnect
*
*
*/
dmmctrl.disconnect = function disconnect() {
log('disconnect');
const self = this;
return new Promise(((resolve, reject) => {
function disconnectDone(e) {
if (e) {
log('disconnect return');
log(e);
reject(e);
} else {
resolve();
}
}
self.dev.asyncWrite = 'done';
self.dev.queryBlock = false;
self.dev.state.setTimeout = false;
if (self.dev.state.conn !== 'disconnected') {
self.dev.cmdSequence = [];
if (self.dev.writeTimeoutObj !== null) {
clearTimeout(self.dev.writeTimeoutObj);
}
self.dev.usbDisconnect(disconnectDone);
} else {
resolve();
}
}));
}.bind(dmmObj);
/**
*
*/
dmmctrl.getSetup = function getSetup() {
const self = this;
return new Promise(((resolve, reject) => {
function getDone(e) {
if (e) {
reject(e);
} else {
resolve({
func: self.sys.func,
autorange: self.sys.autorange,
range: self.conf.range,
});
}
}
const cmd = [];
log('dmm getSetup');
cmd.push({ id: 'sys', prop: 'Function', arg: '', cb: null, method: 'get' });
cmd.push({ id: 'sys', prop: 'AutoRange', arg: '', cb: null, method: 'get' });
cmd.push({ id: 'conf', prop: 'QueryRange', arg: '', cb: getDone, method: 'get' });
self.dev.cmdSequence = self.dev.cmdSequence.concat(cmd);
self.cmdEvent.emit('cmdWrite', cmd);
}));
}.bind(dmmObj);
/**
*
*/
dmmctrl.setSetup = function setSetup(setup) {
const self = this;
return new Promise(((resolve, reject) => {
function setDone(e) {
if (e) {
log('dmm.setSetup error');
log(e);
reject(e);
} else {
resolve();
}
}
const cmd = [];
let func;
let range;
log('dmm setSetup');
log(setup);
if (setup.func.slice(0, -2) === 'VOLT') {
func = '"VOLT"';
range = 'RangeVoltDC';
} else if (setup.func.slice(0, -2) === 'VOLT:AC') {
func = '"VOLT:AC"';
range = 'RangeVoltAC';
} else if (setup.func.slice(0, -2) === 'VOLT:DCAC') {
func = '"VOLT:DCAC"';
range = 'RangeVoltDCAC';
} else if (setup.func.slice(0, -2) === 'CURR') {
func = '"CURR"';
range = 'RangeCurrDC';
} else if (setup.func.slice(0, -2) === 'CURR:AC') {
func = '"CURR:AC"';
range = 'RangeVoltAC';
} else if (setup.func.slice(0, -2) === 'CURR:DCAC') {
func = '"CURR:DCAC"';
range = 'RangeVoltDCAC';
} else if (setup.func.slice(0, -2) === 'RES') {
func = '"RES"';
range = 'RangeResistance';
}
cmd.push({ id: 'sys', prop: 'Function', arg: func, cb: null, method: 'set' });
cmd.push({ id: 'sys', prop: 'delay_for_a_while', arg: 300, cb: null, method: 'set' });
if (setup.autorange.slice(0, -2) === '0') {
cmd.push({ id: 'sys', prop: 'AutoRange', arg: 'OFF', cb: null, method: 'set' });
} else {
cmd.push({ id: 'sys', prop: 'AutoRange', arg: 'ON', cb: null, method: 'set' });
}
cmd.push({ id: 'sys', prop: 'delay_for_a_while', arg: 300, cb: null, method: 'set' });
cmd.push({ id: 'conf', prop: range, arg: setup.range.slice(0, -2), cb: setDone, method: 'set' });
self.dev.cmdSequence = self.dev.cmdSequence.concat(cmd);
self.cmdEvent.emit('cmdWrite', cmd);
}));
}.bind(dmmObj);
/**
* Channel property of device.
*
* @property funcProp
* @type Object
* @param {String} Gets the function for the display
*/
dmmctrl.getSysProp = function getSysProp(sysProp) {
const self = this;
return new Promise(((resolve, reject) => {
function getDone(e) {
if (e) {
reject(e);
} else {
resolve(self.sys);
}
}
const cmd = [];
log(sysProp);
if (sysProp.func !== undefined) {
cmd.push({ id: 'sys', prop: 'Function', arg: '', cb: null, method: 'get' });
}
if (sysProp.autorange !== undefined) {
cmd.push({ id: 'sys', prop: 'AutoRange', arg: '', cb: null, method: 'get' });
}
if (sysProp.val !== undefined) {
cmd.push({ id: 'sys', prop: 'VAL', arg: '', cb: null, method: 'get' });
}
if (cmd.length > 0) {
cmd[cmd.length - 1].cb = getDone;
self.dev.cmdSequence = self.dev.cmdSequence.concat(cmd);
// log(self.dev.cmdSequence);
self.cmdEvent.emit('cmdWrite', cmd);
} else {
log('getSysProp do nothing');
reject(['400', 'Parameter Error']);
}
}));
}.bind(dmmObj);
/**
* Channel property of device.
*
* @property funcProp
* @type Object
* @param {String} Sets the function for the display
*/
dmmctrl.setSysProp = function setSysProp(sysProp) {
const self = this;
return new Promise(((resolve, reject) => {
function setDone(e) {
if (e) {
reject(e);
} else {
resolve();
}
}
const cmd = [];
if (sysProp.func !== undefined) {
cmd.push({ id: 'sys', prop: 'Function', arg: sysProp.func, cb: null, method: 'set' });
}
if (sysProp.autorange !== undefined) {
cmd.push({ id: 'sys', prop: 'AutoRange', arg: sysProp.autorange, cb: null, method: 'set' });
}
if (cmd.length > 0) {
cmd[cmd.length - 1].cb = setDone;
self.dev.cmdSequence = self.dev.cmdSequence.concat(cmd);
// log(self.dev.cmdSequence);
self.cmdEvent.emit('cmdWrite', cmd);
} else {
log('setSysProp do nothing');
reject(['400', 'Parameter Error']);
}
}));
}.bind(dmmObj);
/**
* Channel property of device.
*
* @property fmProperty
* @type Object
* @param {String} type
* @param {String} source
* @param {String} freq
* @param {String} state
* @param {String} depth
* @param {String} deviation
* @param {String} rate
* @param {String} ampl
*/
dmmctrl.setRangeProp = function setRangeProp(confProp) {
const self = this;
return new Promise(((resolve, reject) => {
const cmd = [];
function setDone(e) {
if (e) {
reject(e);
} else {
resolve();
}
}
log(confProp);
if (confProp === undefined) {
reject(['400', 'Parameter Error']);
return;
}
if (confProp.type === undefined) {
reject(['400', 'Parameter Error']);
return;
}
const prop = `Range${sysConstant.dmmFuncType[confProp.type]}`;
cmd.push({ id: 'conf', prop, arg: confProp.range, cb: setDone, method: 'set' });
self.dev.cmdSequence = self.dev.cmdSequence.concat(cmd);
self.cmdEvent.emit('cmdWrite', cmd);
}));
}.bind(dmmObj);
/**
*
*
*/
dmmctrl.getRangeProp = function getRangeProp() {
const self = this;
return new Promise(((resolve, reject) => {
const cmd = [];
function getDone(e) {
if (e) {
reject(e);
} else {
resolve(self.conf);
}
}
cmd.push({ id: 'conf', prop: 'QueryRange', arg: '', cb: getDone, method: 'get' });
self.dev.cmdSequence = self.dev.cmdSequence.concat(cmd);
// log(self.dev.cmdSequence);
self.cmdEvent.emit('cmdWrite', cmd);
}));
}.bind(dmmObj);
/**
* Channel property of device.
*
* @property mesaProp
* @type Object
* @param {String} position Specify the distance with triggered pointer of the main window
* @param {String} zposition Specify the distance with triggered pointer of the zoom window
* @param {String} scale Specify the time divison of the main window
* @param {String} zscale Specify the time divison of the zoom window
* @param {String} mode Specify which mode device on
* @param {String} expand Specify timebase expand by center or trigger position
*/
dmmctrl.getMeasProp = function getMeasProp(mesaProp) {
const self = this;
return new Promise(((resolve, reject) => {
function getDone(e) {
if (e) {
reject(e);
} else {
resolve(self.meas);
}
}
const cmd = [];
log(mesaProp);
if (mesaProp === undefined) {
reject(['400', 'Parameter Error']);
return;
}
const prop = `Meas${sysConstant.dmmFuncType[mesaProp]}`;
cmd.push({ id: 'meas', prop, arg: '', cb: getDone, method: 'get' });
self.dev.cmdSequence = self.dev.cmdSequence.concat(cmd);
// log(self.dev.cmdSequence);
self.cmdEvent.emit('cmdWrite', cmd);
}));
}.bind(dmmObj);
/**
*
*/
dmmctrl.getMeas = function getMeas(sysProp) {
const self = this;
return new Promise(((resolve, reject) => {
function getDone(e) {
if (e) {
reject(e);
} else {
resolve(self.sys.val);
}
}
const cmd = [];
log(sysProp);
cmd.push({ id: 'sys', prop: 'VAL', arg: '', cb: getDone, method: 'get' });
self.dev.cmdSequence = self.dev.cmdSequence.concat(cmd);
self.cmdEvent.emit('cmdWrite', cmd);
}));
}.bind(dmmObj);
/**
* The method belong to dmmctrl class used to set the device into default state
*
* @method run
*
*
*/
dmmctrl.default = function defaultInit() {
const self = this;
log('run');
return new Promise(((resolve, reject) => {
function sysRun(e) {
if (e) {
reject(e);
} else {
resolve();
}
}
log('run promise');
const sysCmd = [
{ id: 'sys', prop: 'RST', arg: '', cb: sysRun, method: 'set' },
];
self.dev.cmdSequence = self.dev.cmdSequence.concat(sysCmd);
log('run :send cmdWrite');
self.cmdEvent.emit('cmdWrite', sysCmd);
}));
}.bind(dmmObj);
/**
* The method belong to dmmctrl class used to set the device into local state
*
* @method force
*
*/
dmmctrl.local = function local() {
const self = this;
return new Promise(((resolve, reject) => {
function sysLocal(e) {
if (e) {
reject(e);
} else {
resolve();
}
}
const sysCmd = [
{ id: 'sys', prop: 'SysLocal', arg: '', cb: sysLocal, method: 'set' },
];
self.dev.cmdSequence = self.dev.cmdSequence.concat(sysCmd);
self.cmdEvent.emit('cmdWrite', sysCmd);
}));
}.bind(dmmObj);
/**
* The method belong to dmmctrl class used to set the device into remote state
*
* @method force
*
*/
dmmctrl.remote = function remote() {
const self = this;
return new Promise(((resolve, reject) => {
function sysRemote(e) {
if (e) {
reject(e);
} else {
resolve();
}
}
const sysCmd = [
{ id: 'sys', prop: 'SysRemote', arg: '', cb: sysRemote, method: 'set' },
];
self.dev.cmdSequence = self.dev.cmdSequence.concat(sysCmd);
self.cmdEvent.emit('cmdWrite', sysCmd);
}));
}.bind(dmmObj);
/**
*
* @method force
*
*/
dmmctrl.clear = function clear() {
const self = this;
return new Promise(((resolve, reject) => {
function sysClear(e) {
if (e) {
reject(e);
} else {
resolve();
}
}
const sysCmd = [
{ id: 'sys', prop: 'CLS', arg: '', cb: sysClear, method: 'set' },
];
self.dev.cmdSequence = self.dev.cmdSequence.concat(sysCmd);
self.cmdEvent.emit('cmdWrite', sysCmd);
}));
}.bind(dmmObj);
/**
*
*/
dmmctrl.model = function model() {
const self = this;
return new Promise(((resolve) => {
const serialNumber = self.dev.usb.serialNumber;
resolve({ model: self.dev.gdsModel, type: self.dev.gdsType, serialNumber });
}));
}.bind(dmmObj);
/**
*
*/
dmmctrl.clearEvent = function clearEvent() {
const self = this;
return new Promise(((resolve) => {
if (self.dev.writeTimeoutObj) {
clearTimeout(self.dev.writeTimeoutObj);
}
self.dev.asyncWrite = 'done';
self.dev.queryBlock = false;
self.dev.state.setTimeout = false;
if (self.dev.state.timeoutObj) {
clearTimeout(self.dev.state.timeoutObj);
}
resolve();
}));
}.bind(dmmObj);
/**
*
*
* @method maxChNum
*
*/
dmmctrl.maxch = function maxch() {
const self = this;
return new Promise(((resolve) => {
resolve(self.dev.maxChNum.toString());
}));
}.bind(dmmObj);
return dmmctrl;
}
async function cmdWrite() {
const self = this;
let cb = null;
const cmd = [];
async function sendCmd(cmdItem) {
return new Promise(((resolve, reject) => {
if (cmdItem.method === 'set') {
// log(self['sys']);
self[cmdItem.id].prop.set(cmdItem.prop, cmdItem.arg, (err) => {
if (err) {
reject(err);
return;
}
resolve();
});
} else {
self[cmdItem.id].prop.get(cmdItem.prop, cmdItem.arg, (err) => {
if (err) {
reject(err);
return;
}
resolve();
});
}
}));
}
// log(this.dev.cmdSequence);
if (this.dev.asyncWrite === 'busy') {
log('async write busy');
log(this.dev.cmdSequence);
return;
}
for (let i = 0, len = this.dev.cmdSequence.length; i < len; i += 1) {
cmd[i] = this.dev.cmdSequence.shift();
// avoid missing async callback, flush command buffer when find cb exist
if (cmd[i].cb !== null) {
cb = cmd[i].cb;
break;
}
}
if (self.dev.state.conn === 'disconnected') {
if (cb) {
cb('device disconnect');
}
self.dev.asyncWrite = 'done';
return;
}
if (cmd.length === 0) {
self.dev.asyncWrite = 'done';
return;
}
self.dev.asyncWrite = 'busy';
for (const cmdItem of cmd) {
try {
await sendCmd(cmdItem);
} catch (err) {
log(`send cmd ${cmdItem} error: ${err}`);
self.dev.usbDisconnect(() => {
self.dev.usbConnect(() => {
self.dev.cmdSequence = [];
self.dev.asyncWrite = 'done';
if (cb) {
cb(err);
}
});
});
return;
}
}
log('async/await write done');
if (self.dev.writeTimeoutObj) {
clearTimeout(self.dev.writeTimeoutObj);
}
self.dev.asyncWrite = 'done';
self.dev.state.conn = 'connected';
if (self.dev.cmdSequence.length !== 0) {
self.cmdEvent.emit('cmdWrite', self.dev.cmdSequence);
}
if (cb) {
cb();
}
}
/**
* Create new instance that used to communicate with instrument through USB
*
* @class DmmUSB
* @constructor
* @extends dmmctrl
* @param {string} vid Vender ID bind to USB device
* @param {string} pid Product ID bind to USB device
*
* @return {Object} Return dmmctrl object
*/
exports.DmmUSB = function DmmUSB(device) {
const dmmObj = new DmmObject();
// log(dmmObj);
log('DmmUSB:');
if (dmmObj.dev.usbConnect) {
log('we have usbConnect');
} else {
log('we dont have usbConnect');
}
dmmObj.cmdEvent.on('cmdWrite', () => {
log('trigger cmdEvent');
cmdWrite.call(dmmObj);
});
usbDev.BindUsbObj(dmmObj.dev, device);
return DmmControl(dmmObj);
};