UNPKG

ibctminer

Version:

```js const IntMiner = require('./src'); const Debug = require('./src/log')(); const fs = require('fs'); const COMP = '[SIPC]';

830 lines (748 loc) 29.3 kB
const Delimiter = require('@serialport/parser-delimiter'); const Debug = require('../log')(); var SerialPort = require('serialport'); //const minerconfig = require('./config/minerconfig') const EventEmitter = require('events'); var waitUntil = require('wait-until'); var crc32 = require('crc32'); const COMP = '[SN]'; const hwTarget = Buffer.from([0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]); const PV = 0x10; const PV20 = 0x20; const TypeSetBootMode = 0xA3; const TypeUpdateFW = 0xAA; const TypeQueryInfo = 0xA4; const TypeProductTest = 0xAB; const TypeSetLED = 0xA6; const TypeSendWork = 0xA1; const TypeSetHWParams = 0xA2; const TypeReboot = 0xAC; const TypeRecvNonce = 0x51; const TypeRecvState = 0X52; const TypeRecvBootMode = 0x53; const TypeRecvInfo = 0x54; const TypeRecvFWState = 0x5A; const TypeRecvTestResult = 0x5B; const pktHeader = Buffer.from([0xA5, 0x3C, 0x96]); const pktEnder = Buffer.from([0x69, 0xC3, 0x5A]); const typeOffset = 0; const sncfg = { model: "simplenode", algo: "scrypt", varity: 0x30, targetFreq: 700, //MHz targetVoltage: 750, //mv targetTemp: 65, warnTemp: 115, offTemp: 125 }; function version_compare(version1, version2) { let v1 = version1.split('.'); let v2 = version2.split('.'); let r0 = parseInt(v1[0]); let r1 = parseInt(v1[1]); let r2 = parseInt(v1[2]); let s = r0 * 100 + r1 * 10 + r2; r0 = parseInt(v2[0]); r1 = parseInt(v2[1]); r2 = parseInt(v2[2]); let d = r0 * 100 + r1 * 10 + r2; if (s === d) return 0; else if (s < d) return 1; else return 2; } class simplenode extends EventEmitter { constructor({devPath, algo, varity}) { super(); var _this = this; _this.algo = algo; _this.devPath = devPath; _this.MinerShouldStop = false; _this.inited = false; _this.txTimeoutCnt = 0; _this.work = { jobID: 0, target: 0, snonce: 0 }; _this.info = { firmwareVer: 'V0.0.1', modelName: 'simplenode', sn:'unknown', hashRation: 0 }; _this.firmware = { retryCnt : 2, FWPageSize : 512, curState : 0, curID : 0 } _this.submitNonce = null; _this.jobsDone = 0; _this.status = { chips:0, temp:0, voltage:0, freq:0, varity:0x30, cores:0, goodcores:0, scanbits:0, scantime:0, tempwarn:0 }; _this.port = new SerialPort(_this.devPath, { baudRate: 115200, dataBits:8, stopBits:1, parity:'none', rtscts:false }, function (err) { if (err) { // _this.emit("error", "打开串口失败"); Debug.IbctLogErr('[SN]:',_this.devPath, '打开串口失败: ', err.message); return; } }); Debug.IbctLogErr('[SN]:',_this.devPath, '打开串口成功 '); const parser = _this.port.pipe(new Delimiter({ delimiter: pktEnder})); parser.on('data', function(data) { _this.snParseNotify(_this, data); }); _this.on("error", function(err) { Debug.IbctLogDbg(COMP, err); }) _this.on("warning", function(err) { Debug.IbctLogDbg(COMP, err); }) } snParseNotify(_this, data) { //Debug.IbctLogInfo('[SN]:',_this.devPath, 'Recv Pkt', data.toString('hex')); var location = data.indexOf(pktHeader); if(location === -1) { Debug.IbctLogErr('[SN]:',_this.devPath, 'Recv Invalid PKT', data); return; } var typeLocation = location + pktHeader.length + typeOffset; switch(data[typeLocation]) { case TypeRecvNonce: var jobID = data[9]; //var chipID = data[10]; //var coreID = data[11]; var lowNonce = data.readUInt32LE(12); //nonce var nonce = Buffer.alloc(8); nonce.writeUInt32BE(_this.work.highNonce, 0); nonce.writeUInt32BE(lowNonce, 4); if(jobID !== _this.work.jobID) { Debug.IbctLogDbg('[SN]:',_this.devPath, 'Find Stale ', jobID, _this.work.jobID, nonce.toString('hex')); } else { // nonce.copy(_this.work.data, 72); //Debug.IbctLogDbg('[SN]:',_this.devPath, 'Find Nonce ', nonce.toString('hex')); //Debug.IbctLogDbg('[SimpleNode]:','Work Data', _this.work.data.toString('hex')); //var result = myalgo.genHash(_this.work.data, 80, 0x30); //Debug.IbctLogInfo('[SimpleNode]:','result', result.toString(16)); if(_this.submitNonce) _this.submitNonce(null, nonce); } break; case TypeRecvInfo: _this.recvInfoPkt = true; //Debug.IbctLogDbg('[SN]:',_this.devPath, 'RecvInfoPkt::', data.toString('hex')); _this.info.modelName = data.toString('utf8', 10, 10 + data[9]); _this.info.firmwareVer = data.toString('utf8', 27, 27 + data[26]); _this.info.sn = data.toString('utf8', 36, 36 + data[35]); _this.info.hashRation = data.readUInt16LE(69); Debug.IbctLogDbg(_this.info); break; case TypeRecvFWState: _this.recvFWStatePkt = true; _this.firmware.curID = data.readUInt32LE(9); _this.firmware.curState = data[13]; break; case TypeRecvBootMode: _this.recvBootModePkt = true; break; case TypeRecvState: _this.recvStatePkt = true; _this.recvQueryStatePkt = true; //Debug.IbctLogInfo('[SN]:',_this.devPath, 'RecvState pkt::', data.toString('hex')); _this.status.chips = data[9]; _this.status.cores = data[10]; _this.status.goodcores = data[11]; _this.status.scanbits = data[12]; _this.status.scantime = data.readUInt16LE(13) * 100; //ms _this.status.voltage = data.readUInt16LE(15); //mV _this.status.freq = data.readUInt16LE(17); //MHz _this.status.varity = data.readUInt32LE(19); _this.status.temp = data[23]; _this.status.hwreboot = data[24]; if (data[typeLocation+1] === PV20) _this.status.tempwarn = data[25]; else _this.status.tempwarn = 0; break; case TypeRecvTestResult: _this.recvPTInfoPkt = true; break; default: Debug.IbctLogErr('[SN]:',_this.devPath, 'Recv Unsupported PKT Type', data[location + typeOffset]) break; } return; } snSendPkt (pkt) { var _this = this; var offset = 0; var length = 0; Object.keys(pkt).forEach(function(key) { if(Buffer.isBuffer(pkt[key])) { length += pkt[key].length; } }); var msg = Buffer.alloc(length); Object.keys(pkt).forEach(function(key) { if(Buffer.isBuffer(pkt[key])) { pkt[key].copy(msg, offset); offset += pkt[key].length; } }); // Debug.IbctLogDbg('[SN]:',_this.devPath, 'Send pkt', msg.toString('hex')); _this.port.write(msg, function(err) { if (err) { Debug.IbctLogErr('[SN]:', _this.devPath, 'Error on write: ', err.message) } _this.port.drain(function(err) { if (err) { Debug.IbctLogErr('[SN]:', _this.devPath, 'Error on Drain: ', _this.devPath, err.message) } }) }) } snGetState(_this) { var pktQueryStatus = { header: Buffer.from(pktHeader), type: Buffer.from([TypeSetHWParams]), version: Buffer.from([PV]), pktlen: Buffer.from([0x7, 0x0 ,0x0 ,0x0]), flag:Buffer.from([0x52]), ender:Buffer.from(pktEnder) }; _this.recvQueryStatePkt = false; _this.snSendPkt(pktQueryStatus); /*TODO Wait response here*/ return true; } async snGetStaticInfo(modelName) { var _this = this; var pktQueryInfo = { header: Buffer.from(pktHeader), type: Buffer.from([TypeQueryInfo]), version: Buffer.from([PV]), pktlen: Buffer.from([0x6, 0x0 ,0x0 ,0x0]), ender:Buffer.from(pktEnder) }; _this.recvInfoPkt = false; _this.snSendPkt(pktQueryInfo); return new Promise(function (resolve, reject) { waitUntil() .interval(50) .times(10) .condition(function() { return _this.recvInfoPkt }) .done(function(result) { if(result === false) { Debug.IbctLogErr('[SN]:',_this.devPath, '获取矿机信息出错'); resolve(1); } else { if(modelName === _this.info.modelName) { resolve(0); } else { resolve(1); } } }) }); } snSetBootMode() { var _this = this; var pktSetBootMode = { header: Buffer.from(pktHeader), type: Buffer.from([TypeSetBootMode]), version: Buffer.from([PV]), pktlen: Buffer.from([0x7, 0x0 ,0x0 ,0x0]), ender:Buffer.from(pktEnder) }; _this.recvBootModePkt = false; _this.snSendPkt(pktSetBootMode); } snBurnFWInit() { var _this = this; var pktSetBootMode = { header: Buffer.from(pktHeader), type: Buffer.from([TypeSetBootMode]), version: Buffer.from([PV]), pktlen: Buffer.from([0x6, 0x0 ,0x0 ,0x0]), ender:Buffer.from(pktEnder) }; _this.recvBootModePkt = false; _this.snSendPkt(pktSetBootMode); return new Promise(function (resolve, reject) { waitUntil() .interval(20) .times(50) .condition(function() { return _this.recvBootModePkt }) .done(function(result) { if(result === false) { resolve(1); } else { resolve(0); } }) }) } snSetHWParams(varity, freq, voltage) { var _this = this; var pktSetParam = { header: Buffer.from(pktHeader), type: Buffer.from([TypeSetHWParams]), version: Buffer.from([PV]), pktlen: Buffer.from([0x10, 0x00, 0x00, 0x00]), flag:Buffer.from([0xA2]), voltage: Buffer.alloc(2), freq:Buffer.alloc(2), varity:Buffer.alloc(4), targettemp:Buffer.from([80]), ender:Buffer.from(pktEnder) }; pktSetParam.varity.writeUInt32LE(varity, 0); pktSetParam.freq.writeUInt16LE(freq, 0); pktSetParam.voltage.writeUInt16LE(voltage, 0); _this.recvStatePkt = false; _this.snSendPkt(pktSetParam); /*TODO Wait response here*/ return true; } snSetHWParamsAndWait(varity, freq, voltage) { var _this = this; var pktSetParam = { header: Buffer.from(pktHeader), type: Buffer.from([TypeSetHWParams]), version: Buffer.from([PV]), pktlen: Buffer.from([0x10, 0x00, 0x00, 0x00]), flag:Buffer.from([0xA2]), voltage: Buffer.alloc(2), freq:Buffer.alloc(2), varity:Buffer.alloc(4), targettemp:Buffer.from([80]), ender:Buffer.from(pktEnder) }; pktSetParam.varity.writeUInt32LE(varity, 0); pktSetParam.freq.writeUInt16LE(freq, 0); pktSetParam.voltage.writeUInt16LE(voltage, 0); _this.recvStatePkt = false; _this.snSendPkt(pktSetParam); return new Promise(function (resolve, reject) { waitUntil() .interval(20) .times(50) .condition(function() { return _this.recvStatePkt }) .done(function(result) { if(result === false) { Debug.IbctLogErr('[SN]:',_this.devPath, '设置矿机参数出错'); resolve(1); } else { resolve(0); } }) }) } async snWriteJob(jobID, target, data) { var _this = this; var pktSendJob = { header: Buffer.from(pktHeader), type: Buffer.from([TypeSendWork]), version: Buffer.from([PV]), pktlen: Buffer.alloc(4), target:Buffer.alloc(4), startNonce: Buffer.from([0,0,0,0,0,0,0,0]), endNonce:Buffer.from([0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff]), jobNum: Buffer.from([1]), jobID: Buffer.alloc(1), jobData:Buffer.alloc(80), ender:Buffer.from(pktEnder) }; pktSendJob.pktlen.writeUInt32LE(108, 0); //pktlen pktSendJob.target.writeUInt32LE(target, 0); //pktSendJob.startNonce.writeUInt32LE(0, 0); //pktSendJob.startNonce.writeUInt32LE(0, 4); //pktSendJob.endNonce.writeUInt32LE(0xffffffff, 0); //pktSendJob.endNonce.writeUInt32LE(0xffffffff, 4); pktSendJob.jobID[0] = jobID; data.copy(pktSendJob.jobData, 0); _this.snSendPkt(pktSendJob); return true; } snSendFWPktAndWait(cnt, FWPKT) { var _this = this; _this.recvFWStatePkt = false; _this.firmware.curState = 0; _this.firmware.curID = 0; _this.snSendPkt(FWPKT); return new Promise(function (resolve, reject) { waitUntil() .interval(20) .times(50) .condition(function() { return _this.recvFWStatePkt }) .done(function(result) { if(result === false) { reject(new Error(__('烧录连接超时'))); } else if(_this.firmware.curState === 0x02) { if(cnt < _this.firmware.retryCnt){ resolve(1); } else { reject(new Error(__('串口出错'))); } } else { resolve(0); } }) }) } async stopScanWork() { var _this = this; Debug.IbctLogInfo('[SN]:', _this.devPath, 'stopScanWork ...'); _this.work.jobID = 0; _this.MinerShouldStop = true; } async scanWork(Job, callback) { var _this = this; Debug.IbctLogInfo('[SN]:', _this.devPath, 'scanWork Begin ...'); if (!_this.inited) { callback(null, null); return; } if(_this.status.scantime === 0) { _this.status.scantime = 300000; //10s default } if(Buffer.compare(hwTarget, Job.target) > 0) { for(var i = 0; hwTarget[i]===0; i++); _this.work.target = (i<<24) | (hwTarget[i] << 16) | (hwTarget[i + 1] << 8) | hwTarget[i + 2]; Job.hwTarget = hwTarget; } else { for(var i = 0; Job.target[i]===0; i++); _this.work.target = (i<<24) | (Job.target[i] << 16) | (Job.target[i + 1] << 8) | Job.target[i + 2]; Job.hwTarget =Job.target; } _this.work.highNonce = parseInt((Job.snonce) / 0x100000000) >>> 0; _this.work.payload = Buffer.alloc(80); _this.work.data = Buffer.from(Job.data); Job.data.writeUInt32BE( _this.work.highNonce, 72); var part1 = Buffer.alloc(32); var part2 = Buffer.alloc(32); var part3 = Buffer.alloc(16); Job.data.copy(part1, 0, 0, 32); Job.data.copy(part2, 0, 32, 64); Job.data.copy(part3, 0, 64, 80); var part11 = Buffer.from(part1); var part22 = Buffer.from(part2); var part33 = Buffer.from(part3); for(var i = 0; i < 8; i++){ part1.writeUInt32LE(part11.readUInt32LE((7- i) *4), i * 4); part2.writeUInt32LE(part22.readUInt32LE((7- i) *4), i * 4); } for(var i = 0; i < 4; i++){ part3.writeUInt32LE(part33.readUInt32LE((3- i) *4), i * 4); } part1.copy(_this.work.payload, 0); part2.copy(_this.work.payload, 32); part3.copy(_this.work.payload, 64); _this.submitNonce = callback; _this.MinerShouldStop = false; _this.jobsDone++; _this.work.jobID++; if(_this.work.jobID === 16) _this.work.jobID = 1; /* Debug.IbctLogInfo('[SN]:', _this.devPath, 'Work Target:', _this.work.target.toString(16), 'Work highNonce:', _this.work.highNonce.toString(16), 'Work jobID:', _this.work.jobID); */ _this.snWriteJob(_this.work.jobID, _this.work.target, _this.work.payload); var interval = 50; //ms var times = (60000 - 500) / interval; waitUntil() .interval(interval) .times(times) .condition(function() { return _this.MinerShouldStop }) .done(function(result) { Debug.IbctLogInfo('[SN]:', _this.devPath, 'ScanWork Exit', result ? "(NewJob)...": "(ScanTime Out)..."); callback(null, null); }); } async setDevice(varity, freq, voltage) { var _this = this; _this.snSetHWParams(varity, freq, voltage); } getInfo() { var _this = this; return _this.info; } getState() { var _this = this; return _this.status; } async detect(modelName) { var _this = this; Debug.IbctLogErr('[SN]:', _this.devPath, 'simpleNode detect...'); return await _this.snGetStaticInfo(modelName); } async init(params) { var _this = this; Debug.IbctLogErr('[SN]:', _this.devPath, 'simpleNode init...'); if(_this.firmware.updating === true){ Debug.IbctLogErr('[SN]:',_this.devPath, 'Still Updating'); return 1; } if( _this.inited === true){ Debug.IbctLogErr('[SN]:',_this.devPath, 'Already Inited. return now'); return 0; } //_this.snSetHWParams(sncfg.varity, sncfg.targetFreq, sncfg.targetVoltage); var ret = await _this.snSetHWParamsAndWait(sncfg.varity, sncfg.targetFreq, sncfg.targetVoltage); if (ret) return ret; if (_this.intervalObj) { clearInterval(_this.intervalObj); _this.intervalObj = null; } _this.intervalObj = setInterval(function() { Debug.IbctLogErr('[SN]:',_this.devPath, 'Temp', _this.status.temp, 'Tempwarn', _this.status.tempwarn, 'Freq', _this.status.freq, 'Jobs', _this.jobsDone); _this.snGetState(_this); waitUntil() .interval(50) .times(10) .condition(function() { return _this.recvQueryStatePkt }) .done(function(result) { if(result === false) { _this.txTimeoutCnt++; Debug.IbctLogErr('[SN]:',_this.devPath, 'snGetState Timeout ', _this.txTimeoutCnt); if(_this.txTimeoutCnt > 10) { _this.emit("error", __('获得矿机状态超时')); _this.txTimeoutCnt = 0; } } else { _this.txTimeoutCnt = 0; if((_this.status.temp > sncfg.offTemp) || (_this.status.tempwarn)) { _this.emit("error", __('矿机高温关机')); } else if(_this.status.temp > sncfg.warnTemp && _this.status.temp < sncfg.offTemp) { _this.emit("warning", __('矿机高温警报')); } } }); }, 5000); _this.inited = true; return 0; } async stop(enable) { var _this = this; Debug.IbctLogErr('[SN]:', _this.devPath, 'simpleNode', enable ? 'remove...' : 'stop...'); if (!enable) { await _this.snSetHWParamsAndWait(0, 0, 0); } _this.inited = false; _this.txTimeoutCnt = 0; _this.freq = 0; _this.voltage = 0; _this.work.jobID = 0; _this.jobsDone = 0; _this.MinerShouldStop = true; if (_this.intervalObj) { clearInterval(_this.intervalObj); _this.intervalObj = null; } if (enable) { await _this.port.flush(function (err) { _this.port.close(function(err) { if(err) Debug.IbctLogDbg('[SN]:',err.message); }); }); } } async burnFirmware(firmware, callback) { var _this = this; if(_this.firmware.updating === true) { callback(__('升级中,请等待')); return; } if(_this.inited === true) { callback(__('挖矿中,请先暂停挖矿')); return; } var ret = await _this.snGetStaticInfo(_this.info.modelName); if (ret === 1) { callback(__('无法获取当前版本号')); return; } ret = version_compare(_this.info.firmwareVer, '0.0.7'); if (ret === 1) _this.firmware.FWPageSize = 512; else _this.firmware.FWPageSize = 256; var init = await _this.snBurnFWInit(); if(init === 0) { _this.firmware.updating = true; } else { _this.firmware.updating = false; callback(__('烧入固件初始化失败')); return; } var fwLen = firmware.length; var totalPktNum = Math.ceil(firmware.length / _this.firmware.FWPageSize) var id = 0; Debug.IbctLogErr('[SN]:', _this.devPath, 'BurnFW, CurVersion:', _this.info.firmwareVer, 'FW lenth' , fwLen , "PKTnum", totalPktNum); try { while(fwLen > 0) { var currentLen = (fwLen > _this.firmware.FWPageSize) ? _this.firmware.FWPageSize : fwLen; var curStart = firmware.length - fwLen; var curEnd = curStart + currentLen; var pktUpdateFW = { header: Buffer.from(pktHeader), type: Buffer.from([TypeUpdateFW]), version: Buffer.from([PV]), pktLen: Buffer.alloc(4), pktID:Buffer.alloc(4), pageSize:Buffer.alloc(4), curLen:Buffer.alloc(4), flag:Buffer.alloc(1), crc32: Buffer.alloc(4), fwData:Buffer.alloc(currentLen), ender:Buffer.from(pktEnder) }; pktUpdateFW.curLen.writeUInt32LE(currentLen, 0); pktUpdateFW.pktID.writeUInt32LE(id, 0); pktUpdateFW.pageSize.writeUInt32LE(_this.firmware.FWPageSize, 0); pktUpdateFW.pktLen.writeUInt32LE(23 + currentLen); firmware.copy(pktUpdateFW.fwData, 0, curStart, curEnd); fwLen -= currentLen; if(fwLen) { pktUpdateFW.flag[0] = 0x00; } else { pktUpdateFW.flag[0] = 0x01;//last } var msg = Buffer.alloc(23 + currentLen); //console.log('3====>', curStart, curEnd, currentLen, fwLen); pktUpdateFW.type.copy(msg, 0); pktUpdateFW.version.copy(msg, 1); pktUpdateFW.pktLen.copy(msg, 2); pktUpdateFW.pktID.copy(msg, 6); pktUpdateFW.pageSize.copy(msg, 10); pktUpdateFW.curLen.copy(msg, 14); pktUpdateFW.flag.copy(msg, 18); pktUpdateFW.crc32.copy(msg, 19); pktUpdateFW.fwData.copy(msg, 23); var crcValue = parseInt(crc32(msg), 16); pktUpdateFW.crc32.writeUInt32LE(crcValue, 0); for(var i = 0; i < _this.firmware.retryCnt; i++) { var success = await _this.snSendFWPktAndWait(i + 1, pktUpdateFW); if(success === 0) break; } if(fwLen === 0) { _this.firmware.updating = false; } callback(null, ((id + 1) / totalPktNum).toFixed(3)); id++; } } catch(err) { Debug.IbctLogErr('[SN]:', _this.devPath, 'Updat firmware failed ' + err.message); _this.firmware.updating = false; callback(err.message); } } async rebootDev() { Debug.IbctLogErr('[SN]: Set', this.devPath, 'reboot'); var _this = this; var pktReboot = { header: Buffer.from(pktHeader), type: Buffer.from([TypeReboot]), version: Buffer.from([PV]), pktlen: Buffer.from([0x6, 0x0 ,0x0 ,0x0]), ender:Buffer.from(pktEnder) }; await _this.stop(true) _this.snSendPkt(pktReboot); } setLed(Enable) { Debug.IbctLogErr('[SN]: Set', this.devPath, 'Led to', Enable ? 'ON' : 'OFF'); var _this = this; var ledFlag = Enable === true ? 1 : 0; var pktSetLED = { header: Buffer.from(pktHeader), type: Buffer.from([TypeSetLED]), version: Buffer.from([PV]), pktlen: Buffer.from([0xb, 0x0 ,0x0 ,0x0]), Flag:Buffer.from([ledFlag]), led:Buffer.from([0xE8, 0x3, 0xC8, 0x0]), //ON 1s OFF:200ms ender:Buffer.from(pktEnder) }; _this.snSendPkt(pktSetLED); } async burnSNInfo(ptinfo) { var _this = this Debug.IbctLogErr('[SN]', _this.devPath, 'Burn Sn Num..', ptinfo) var pktPTInfo = { header: Buffer.from(pktHeader), type: Buffer.from([TypeProductTest]), version: Buffer.from([PV]), pktlen: Buffer.from([70, 0x0, 0x0, 0x0]), SNInfo: Buffer.alloc(32), HashInfo: Buffer.alloc(32), ender: Buffer.from(pktEnder) } if (ptinfo.sn) { var sn = Buffer.from(ptinfo.sn) pktPTInfo.SNInfo[0] = sn.length sn.copy(pktPTInfo.SNInfo, 1) } else { pktPTInfo.SNInfo[0] = 0 } _this.recvPTInfoPkt = false; _this.snSendPkt(pktPTInfo) return new Promise(function (resolve, reject) { waitUntil() .interval(50) .times(10) .condition(function () { return _this.recvPTInfoPkt }) .done(function (result) { if (result === false) { Debug.IbctLogErr('[SN]:', _this.devPath, 'Burn SN num failed..') resolve(__('写入SN序列号失败')) } else { resolve(null) } }) }) } } module.exports = function getSimplenode(options = {}) { return new simplenode(options); }