UNPKG

ibctminer

Version:

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

869 lines (785 loc) 31.2 kB
const Delimiter = require('@serialport/parser-delimiter'); const Debug = require('../log')(); var SerialPort = require('serialport'); const EventEmitter = require('events'); // var waitUntil = require('wait-until'); var waitUntil = require('../waitUntil'); var crc32 = require('crc32'); const COMP = '[HS1]:'; const hwTarget = Buffer.from([0x00, 0x00, 0x00, 0x00, 0x1f, 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 TypeRecvJob = 0x55; 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 hs1cfg = { model: "Goldshell-HS1", algo: "blake2bsha3", varity: 0x4, targetFreq: 650, //MHz targetVoltage: 410, //mv targetTemp: 65, warnTemp: 115, offTemp: 125 }; class hs1 extends EventEmitter { constructor({devPath, algo, varity, crypto}) { super(); var _this = this; _this.devPath = devPath; _this.algo = algo; _this.crypto = crypto; _this.MinerShouldStop = false; _this.inited = false; _this.txTimeoutCnt = 0; _this.work = [{ jobID: 0 }, { jobID: 0 }, { jobID: 0 }, { jobID: 0 }]; _this.Job = []; _this.fakeJob = { overScan:false }; _this.job_id = null; _this.info = { firmwareVer: 'V0.0.1', modelName: 'Goldshell-HS1', sn:'unknown', //hashRation:0, workDepth:4, }; _this.firmware = { retryCnt : 2, FWPageSize : 256, curState : 0, curID : 0 } _this.submitNonce = null; _this.curJobid = 4; _this.jobsDone = 0; _this.status = { chips:0, temp:0, voltage:0, freq:0, varity:0x4, cores:0, goodcores:0, scanbits:0, scantime:0, tempwarn:0, fanwarn:0, powerwarn:0, rpm:0 }; _this.port = new SerialPort(_this.devPath, { baudRate: 115200, dataBits:8, stopBits:1, parity:'none', rtscts:false }, function (err) { if (err) { Debug.IbctLogErr(COMP, _this.devPath, '打开串口失败: ', err.message); return; } else Debug.IbctLogErr(COMP, _this.devPath, '打开串口成功'); }); const parser = _this.port.pipe(new Delimiter({ delimiter: pktEnder})); parser.on('data', function(data) { _this.hs1ParseNotify(_this, data); }); _this.on("error", function(err) { Debug.IbctLogDbg(COMP, err); }) _this.on("warning", function(err) { Debug.IbctLogDbg(COMP, err); }) } hs1ParseNotify(_this, data) { //Debug.IbctLogInfo(COMP, _this.devPath, 'Recv Pkt', data.toString('hex')); var location = data.indexOf(pktHeader); if(location === -1) { Debug.IbctLogErr(COMP, _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 nonce_l = data.readUInt32LE(12); var nonce_h = data.readUInt32LE(16); var nonce = Buffer.alloc(8); nonce.writeUInt32LE(nonce_l, 0); nonce.writeUInt32LE(nonce_h, 4); if(jobID !== _this.work[0].jobID && jobID !== _this.work[1].jobID && jobID !== _this.work[2].jobID && jobID !== _this.work[3].jobID) { Debug.IbctLogDbg(COMP, _this.devPath, 'Find Stale ', jobID, _this.work[0].jobID, _this.work[1].jobID, nonce.toString('hex')); } else { //Debug.IbctLogDbg(COMP, _this.devPath, 'Find Nonce ', nonce.toString('hex')); let i; if (jobID === _this.work[0].jobID) i = 0; else if (jobID === _this.work[1].jobID) i = 1; else if (jobID === _this.work[2].jobID) i = 2; else i = 3; if(_this.submitNonce) _this.submitNonce(null, nonce, _this.Job[i]); } break; case TypeRecvInfo: _this.recvInfoPkt = true; //Debug.IbctLogDbg(COMP, _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]); //if (data[typeLocation+1] === PV20) { //_this.info.workDepth = data[53]; //} else { //_this.info.hashRation = data.readUInt16LE(69); //_this.info.workDepth = data[101]; //} Debug.IbctLogDbg(_this.info); break; case TypeRecvFWState: _this.recvFWStatePkt = true; _this.firmware.curID = data.readUInt32LE(9); _this.firmware.curState = data[13]; break; case TypeRecvJob: _this.recvJobPkt = true; break; case TypeRecvBootMode: _this.recvBootModePkt = true; break; case TypeRecvState: _this.recvStatePkt = true; _this.recvQueryStatePkt = true; //Debug.IbctLogInfo(COMP, _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]; _this.status.tempwarn = data[25]; _this.status.fanwarn = data[26] _this.status.powerwarn = data[27] _this.status.rpm = data.readUInt16LE(28) break; case TypeRecvTestResult: _this.recvPTInfoPkt = true; break; default: Debug.IbctLogErr(COMP, _this.devPath, 'Recv Unsupported PKT Type', data[location + typeOffset]) break; } return; } hs1SendPkt (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(COMP, _this.devPath, 'Send pkt', msg.toString('hex')); _this.port.write(msg, function(err) { if (err) { Debug.IbctLogErr(COMP, _this.devPath, 'Error on write: ', err.message) } _this.port.drain(function(err) { if (err) { Debug.IbctLogErr(COMP, _this.devPath, 'Error on Drain: ', _this.devPath, err.message) } }) }) } hs1GetState(_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.hs1SendPkt(pktQueryStatus); /*TODO Wait response here*/ return true; } async hs1GetStaticInfo(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.hs1SendPkt(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(COMP, _this.devPath, '获取矿机信息出错'); resolve(2); } else { if(modelName === _this.info.modelName) { resolve(0); } else { resolve(1); } } }) }); } hs1SetBootMode() { 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.hs1SendPkt(pktSetBootMode); } hs1BurnFWInit() { 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.hs1SendPkt(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); } }) }) } hs1SetHWParams(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.hs1SendPkt(pktSetParam); /*TODO Wait response here*/ return true; } hs1SetHWParamsAndWait(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.hs1SendPkt(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(COMP, _this.devPath, '设置矿机参数出错'); resolve(1); } else { resolve(0); } }) }) } async hs1WriteJob(jobID, snonce, enonce, target, data) { var _this = this; _this.recvJobPkt = false; var pktSendJob = { header: Buffer.from(pktHeader), type: Buffer.from([TypeSendWork]), version: Buffer.from([PV]), pktlen: Buffer.alloc(4), target:Buffer.alloc(8), startNonce: Buffer.alloc(8), endNonce:Buffer.alloc(8), jobNum: Buffer.from([1]), jobID: Buffer.alloc(1), jobData:Buffer.alloc(128), ender:Buffer.from(pktEnder) }; pktSendJob.pktlen.writeUInt32LE(160, 0); //pktlen target.copy(pktSendJob.target, 0); snonce.copy(pktSendJob.startNonce, 0); enonce.copy(pktSendJob.endNonce, 0); pktSendJob.jobID[0] = jobID; data.copy(pktSendJob.jobData, 0); _this.hs1SendPkt(pktSendJob); return new Promise(function (resolve, reject) { waitUntil() .interval(40) .times(50) .condition(function() { return _this.recvJobPkt }) .done(function(result) { if(result === false) { reject(new Error(__('发送Work失败'))); } else { resolve(0); } }) }) } hs1SendFWPktAndWait(cnt, FWPKT) { var _this = this; _this.recvFWStatePkt = false; _this.firmware.curState = 0; _this.firmware.curID = 0; _this.hs1SendPkt(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.IbctLogDbg(COMP, _this.devPath, 'stopScanWork ...'); //_this.curJobid = 0; _this.MinerShouldStop = true; } async scanWork(workQueue, callback) { var _this = this; Debug.IbctLogInfo(COMP, _this.devPath, 'scanWork Begin ...'); if (!_this.inited) { callback(null, null, null); return; } if(_this.status.scantime === 0) { _this.status.scantime = 7000; //10s default } if (_this.MinerShouldStop) { _this.MinerShouldStop = false; if (_this.job_id === workQueue[0].job_id) { // new job arrived _this.fakeJob.overScan = false; // clean all workQueue workQueue.splice(0, workQueue.length); callback(null, null, _this.fakeJob); Debug.IbctLogDbg("new job arrived, scanWork again"); return; } } _this.job_id = workQueue[0].job_id; for(let i = 0; i < _this.info.workDepth; i++) { _this.Job[i] = workQueue.pop(); _this.work[i].target = Buffer.alloc(8); var target = _this.Job[i].target; if(Buffer.compare(hwTarget, target) > 0) { hwTarget.copy(_this.work[i].target, 0); _this.Job[i].hwTarget = hwTarget; } else { target.copy(_this.work[i].target, 0); _this.Job[i].hwTarget = target; } _this.work[i].target = _this.work[i].target.swap64(); _this.work[i].highNonce = parseInt((_this.Job[i].snonce) / 0x100000000) >>> 0; //_this.work[i].payload = Buffer.alloc(128); _this.work[i].data = Buffer.from(_this.Job[i].data); _this.work[i].snonce = Buffer.alloc(8); _this.work[i].snonce.writeUInt32LE(0, 0); _this.work[i].snonce.writeUInt32LE(_this.work[i].highNonce, 4); //Job.data.copy(_this.work[i].payload, 0); //Debug.IbctLogDbg(COMP, _this.work[i].payload.toString('hex')); _this.work[i].enonce = Buffer.alloc(8); _this.work[i].enonce.writeUInt32LE(0xffffffff, 0); _this.work[i].enonce.writeUInt32LE(_this.work[i].highNonce + 32, 4); _this.submitNonce = callback; // _this.MinerShouldStop = false; _this.jobsDone++; _this.work[i].jobID = _this.curJobid; _this.curJobid++; if (_this.curJobid === 16) _this.curJobid = 4; /* Debug.IbctLogInfo(COMP, _this.devPath, 'Work Target:', _this.work[i].target.toString('hex'), 'Work highNonce:', _this.work[i].highNonce.toString(16), 'Work jobID:', _this.work[i].jobID); */ await _this.hs1WriteJob(_this.work[i].jobID, _this.work[i].snonce, _this.work[i].enonce, _this.work[i].target, _this.work[i].data); } var interval = 50; //ms var times = 7000 / interval; waitUntil() .interval(interval) .times(times) .condition(function() { return _this.MinerShouldStop }) .done(function(result) { Debug.IbctLogDbg(COMP, _this.devPath, 'ScanWork Exit', result ? "(NewJob)...": "(ScanTime Out)..."); if (result === false) _this.fakeJob.overScan = true; else _this.fakeJob.overScan = false; callback(null, null, _this.fakeJob); }); } async setDevice(varity, freq, voltage) { var _this = this; _this.hs1SetHWParams(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(COMP, _this.devPath, 'hs1 detect...'); return await _this.hs1GetStaticInfo(modelName); } async init(params) { var _this = this; Debug.IbctLogErr(COMP, _this.devPath, 'hs1 init...'); if(_this.firmware.updating === true){ Debug.IbctLogErr(COMP, _this.devPath, 'Still Updating'); return 1; } if( _this.inited === true){ Debug.IbctLogErr(COMP, _this.devPath, 'Already Inited. return now'); return 0; } //_this.hs1SetHWParams(hs1cfg.varity, hs1cfg.targetFreq, hs1cfg.targetVoltage); var ret = await _this.hs1SetHWParamsAndWait(_this.varity, hs1cfg.targetFreq, hs1cfg.targetVoltage); if (ret) return ret; if (_this.intervalObj) { clearInterval(_this.intervalObj); _this.intervalObj = null; } _this.intervalObj = setInterval(function() { Debug.IbctLogErr(COMP, _this.devPath, 'Temp', _this.status.temp, 'RPM', _this.status.rpm, 'Tempwarn', _this.status.tempwarn, 'Fanwarn', _this.status.fanwarn, 'Powerwarn', _this.status.powerwarn,'Freq', _this.status.freq, 'Jobs', _this.jobsDone); _this.hs1GetState(_this); waitUntil() .interval(50) .times(10) .condition(function() { return _this.recvQueryStatePkt }) .done(function(result) { if(result === false) { _this.txTimeoutCnt++; Debug.IbctLogErr(COMP, _this.devPath, 'hs1GetState Timeout ', _this.txTimeoutCnt); if(_this.txTimeoutCnt > 10) { _this.emit("error", __('获得矿机状态超时')); _this.txTimeoutCnt = 0; } } else { _this.txTimeoutCnt = 0; if(_this.status.fanwarn) _this.emit("error", __('矿机风扇异常')); if(_this.status.powerwarn) _this.emit("error", __('矿机电源异常')); if((_this.status.temp > hs1cfg.offTemp) || (_this.status.tempwarn)) { _this.emit("error", __('矿机高温关机')); } else if(_this.status.temp > hs1cfg.warnTemp && _this.status.temp < hs1cfg.offTemp) { _this.emit("warning", __('矿机高温警报')); } } }); }, 5000); _this.inited = true; return 0; } async stop(enable, wait) { var _this = this; Debug.IbctLogErr(COMP, _this.devPath, 'hs1', enable ? 'remove...' : 'stop...'); if (!enable) { await _this.hs1SetHWParamsAndWait(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) { if (wait) { await _this.port.flush(function (err) { _this.port.close(function(err) { if(err) Debug.IbctLogDbg(COMP, err.message); }); }); } else { await this.port.flush() await this.port.close(function(err) { if(err) Debug.IbctLogDbg(COMP, err.message); }); return new Promise(function (resolve) { waitUntil() .interval(10) .times(50) .condition(function() { return !_this.port.isOpen; }) .done(function() { resolve(0); }) }) } } } async burnFirmware(firmware, callback) { var _this = this; if(_this.firmware.updating === true) { callback(__('升级中,请等待')); return; } if(_this.inited === true) { callback(__('挖矿中,请先暂停挖矿')); return; } var ret = await _this.hs1GetStaticInfo(_this.info.modelName); if (ret === 1) { callback(__('无法获取当前版本号')); return; } var init = await _this.hs1BurnFWInit(); 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(COMP, _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.hs1SendFWPktAndWait(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(COMP, _this.devPath, 'Updat firmware failed ' + err.message); _this.firmware.updating = false; callback(err.message); } } async rebootDev() { Debug.IbctLogErr(COMP, 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, true) _this.hs1SendPkt(pktReboot); } setLed(Enable) { Debug.IbctLogErr(COMP, '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.hs1SendPkt(pktSetLED); } async burnSNInfo(ptinfo) { var _this = this Debug.IbctLogErr(COMP, _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.hs1SendPkt(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(COMP, _this.devPath, 'Burn SN num failed..') resolve(__('写入SN序列号失败')) } else { resolve(null) } }) }) } } module.exports = function Geths1(options = {}) { return new hs1(options); }