UNPKG

intchains_ibctminer

Version:

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

715 lines (640 loc) 25.5 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 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 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 FWPageSize = 512; const sncfg = { model: "simplenode", algo: "scrypt", varity: 0x30, targetFreq: 700, //MHz targetVoltage: 750, //mv targetTemp: 65, warnTemp: 115, offTemp: 125 }; 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.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, votage:0, freq:0, varity:0x30, cores:0, goodcores:0, scanbits:0, scantime:0 }; _this.port = new SerialPort(_this.devPath, { baudRate: 115200, dataBits:8, stopBits:1, parity:'none', rtscts:false }); const parser = _this.port.pipe(new Delimiter({ delimiter: pktEnder})); parser.on('data', function(data) { _this.snParseNotify(_this, data); }); } 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]; break; case TypeRecvTestResult: 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, 'Uart Connection Timeout'); _this.emit("error", "Connection Timeout"); 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) { _this.emit("error", "Connection Timeout"); 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, 'Uart Connection Timeout'); _this.emit("error", "Connection Timeout"); 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) { _this.emit("error", "Connection Timeout"); reject(new Error('Connection Timeout')); } else if(_this.firmware.curState === 0x02) { if(cnt < _this.firmware.retryCnt){ resolve(1); } else { reject(new Error('UartData 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 = (_this.work.jobID + 1 ) & 0xf; /* 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.IbctLogDbg('[SN]:', _this.devPath, 'simpleNode detect...'); return await _this.snGetStaticInfo(modelName); } async init(params) { var _this = this; if(_this.firmware.updating === true){ Debug.IbctLogErr('[SN]:',_this.devPath, 'Still Updateing'); return 1; } Debug.IbctLogDbg('[SN]:', _this.devPath, 'simpleNode init...'); _this.snSetHWParams(sncfg.varity, sncfg.targetFreq, sncfg.targetVoltage); var ret = await _this.snSetHWParamsAndWait(sncfg.varity, sncfg.targetFreq, sncfg.targetVoltage); if (ret) return ret; _this.inited = true; _this.intervalObj = setInterval(function() { Debug.IbctLogErr('[SN]:',_this.devPath, 'Temp', _this.status.temp, '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) { Debug.IbctLogErr('[SN]:',_this.devPath, 'Uart Connection Timeout'); _this.emit("error", "Connection Timeout"); } else if(_this.status.temp > sncfg.warnTemp && _this.status.temp < sncfg.offTemp) { _this.emit("warning", "High Temperature Warning"); } else if(_this.status.temp > sncfg.offTemp) { _this.emit("error", "Over Temperature stop device"); } }); }, 5000); return 0; } async stop() { var _this = this; Debug.IbctLogDbg('[SN]:', _this.devPath, 'simpleNode stop...'); _this.snSetHWParams(0, 0, 0); _this.inited = false; _this.freq = 0; _this.voltage = 0; _this.work.jobID = 0; _this.jobsDone = 0; _this.MinerShouldStop = true; if (_this.intervalObj) { clearInterval(_this.intervalObj); } // _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('Still Updateing'); return; } if(_this.inited === true) { callback('Still Mining'); return; } var init = await _this.snBurnFWInit(); if(init === 0) { _this.firmware.updating = true; } else { _this.firmware.updating = false; callback('Burn Init Failed'); } var fwLen = firmware.length; var totalPktNum = Math.ceil(firmware.length / _this.firmware.FWPageSize) var id = 0; Debug.IbctLogInfo('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(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]: Updat firmware failed ' + err.message); _this.firmware.updating = false; callback(err.message); } } async rebootDev() { Debug.IbctLogDbg('[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) }; _this.snSendPkt(pktReboot); } setLed(Enable) { Debug.IbctLogDbg('[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); } } module.exports = function getSimplenode(options = {}) { return new simplenode(options); }