UNPKG

weblab-instrument

Version:
686 lines (634 loc) 20.4 kB
/** * 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); };