Skip to content

Commit

Permalink
Merge pull request #5 from HandyMiner/feature_hs1_plus
Browse files Browse the repository at this point in the history
- Add support for the HS1-PLUS
- Add support for Goldshell Firmware 0.0.4
  • Loading branch information
alexsmith540 authored Sep 24, 2020
2 parents b59c8ef + 0f6861c commit f6fc98a
Show file tree
Hide file tree
Showing 4 changed files with 152 additions and 37 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

**HandyMiner-Goldshell-CLI**

**Now Supporting the Goldshell HS1-Plus!**

### [HandyMiner-Goldshell-CLI Quick Start Guide](https://handyminer.github.io/HandyMiner-Goldshell-CLI/index.html)

**HandyMiner Team Donation Address (HNS): ```hs1qwfpd5ukdwdew7tn7vdgtk0luglgckp3klj44f8```**
Expand Down
65 changes: 57 additions & 8 deletions miner/GoldShell_Parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,62 @@ class GoldShellAsic{
const version = data[4];
const packetLen = parseInt(data.slice(5,5+4).reverse().toString('hex'),16);
const modelNameLen = data[9];
const modelName = data.slice(10,10+16).toString('utf8');;
const fwLen = data[26];
const fwVersion = data.slice(27,27+8).toString('utf8');
const serial = data.slice(35,35+32).toString('utf8');
const hashRate = data.slice(67,67+32);
const workDepth = data[99];
//console.log('parse infos???',modelName,serial);

let position = 10+modelNameLen;

const modelName = data.slice(10,position).toString('utf8');
let isHS1Plus = false;
if(modelName.indexOf('Plus') >= 0){
//hs1 plus
isHS1Plus = true;
position += 2;
}
else{
//is hs1
position += 3;
}

const fwLen = data[position];
position += 1;
const fwVersion = data.slice(position,position+fwLen).toString('utf8');
position += fwLen;

let fwVersionInt = fwVersion.split('.');
fwVersionInt = fwVersionInt.pop();
if(fwVersionInt.length > 0){
fwVersionInt = parseInt(fwVersionInt);
}

if(isHS1Plus){
position += 3; //whitespace at start of serial for hs1 plus..
}
else{
//hs1
position += 3;
}
let pNext = isHS1Plus ? position + 18 : position + (fwVersionInt >= 4 ? 18 : 32);
const serial = data.slice(position,pNext).toString('utf8');
const hashRate = data.slice(position, position+32);
let wdPosition = 99;
if(isHS1Plus){
wdPosition = 54+3;
}

if(!isHS1Plus && (fwVersionInt >= 4)){
//hs1 with firmware 0.0.4+
wdPosition = 50+3;
}
let workDepth = data[wdPosition];//data[99];
if(typeof workDepth == "undefined" || workDepth == 0 || workDepth > 8){
//in case future firmware changes workDepth location again
if(isHS1Plus){
workDepth = 8;
}
else{
workDepth = 4;
}
}

return {
serialPort:serialPath,
modelName,
Expand Down Expand Up @@ -50,7 +99,7 @@ class GoldShellAsic{
const fanWarn = data[26];
const powerWarn = data[27];
const fanRpm = parseInt(data.slice(28,28+2).reverse().toString('hex'),16);

return {
numChips,
numCores,
Expand Down
115 changes: 87 additions & 28 deletions miner/HandyMiner_GoldShell.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ class HandyMiner {
}
this.config = config;
this.solutionIDs = 0;
this.minerIsConnected = false;
if(this.config.muteWinningFanfare){
//I'd like not to revel in the glory of getting a block...
PlayWinningSound = false;
Expand Down Expand Up @@ -232,6 +233,7 @@ class HandyMiner {

this.propCalls = 1;
this.gpuDeviceBlocks = {};
this.nextDeviceBlocks = {}; //while we wait for jobs to write to the asic we can get sols back ... :facepalm:
this.workByHeaders = {};
this.isSubmitting = false;
this.solutionCache = [];
Expand Down Expand Up @@ -445,6 +447,7 @@ class HandyMiner {
resolve();
}
Object.keys(this.asicWorkers).map(workerID=>{

let resetDeviceParamsBuffer = new Buffer.from('A53C96A21010000000A200000000040000004169C35A','hex');
this.asicWorkers[workerID].write(resetDeviceParamsBuffer,err=>{
complete++;
Expand Down Expand Up @@ -593,7 +596,7 @@ class HandyMiner {
break;
case 'subscribe':
this.sid = d.result;
fs.writeFileSync(process.env.HOME+'/.HandyMiner/hnspool_sid.txt',this.sid);
fs.writeFileSync(process.env.HOME+'/.HandyMiner/hnspool_sid.txt',this.sid.toString('utf8'));
//this.nonce1 = d.result;
if(this.isMGoing){
this.nonce1Local = d.result;
Expand All @@ -615,7 +618,7 @@ class HandyMiner {
break;
case 'mining.set_difficulty':
case 'set_difficulty':

this.minerIsConnected = true;
if(!this.useStaticPoolDifficulty && this.config.mode == 'pool'){
let lastDiff = this.poolDifficulty;
//do adaptive diff here
Expand Down Expand Up @@ -812,6 +815,8 @@ class HandyMiner {
this.asicShares[asicID].invalid++;
}
}
//this.generateWork(d.id.split('_').pop(),true);
//console.log('stale work',d,d.id,this.solCache[d.id],this.asicNames[d.id.split('_').pop()]);
}
else if(!this.isMGoing && this.config.mode == 'pool' && this.host.indexOf('6block') >= 0 && d.error[0] == 'invalid'){
//add result to d to make sounds play
Expand Down Expand Up @@ -1148,21 +1153,37 @@ class HandyMiner {
console.log("HANDY:: \x1b[36mASIC %s (%s)\x1b[0m INITIALIZED",asicID,asicInfo.modelName);
}
//now init parameters
let setDeviceParamsBuffer = new Buffer.from('A53C96A21010000000A2EE028A02040000004169C35A','hex');
// |8A02| = frequency = 650, default hs1
// |A302| = 675
// |BC02| = 700
// | | 41 = temp target = 65C
// | | 5A = temp target = 90C
let params = 'A53C96A21010000000A2EE028A02040000004169C35A'; //default hs1 params
if(asicInfo.modelName.indexOf('Plus') >= 0){
//is hs1 plus, new frequencies!!
// |8A02| = frequency = 650 = ~102GH hs1plus, handyminer default
// |A302| = 675
// |BC02| = 700 = 110GH hs1plus
// |EE02| = 750 * use at your own risk...
params = 'A53C96A21010000000A2EE028A02040000004169C35A';
}
//
let setDeviceParamsBuffer = new Buffer.from(params,'hex');
this.asicWorkers[asicID].write(setDeviceParamsBuffer,err=>{
if(err){
console.error('error setting device params',err.toString('utf8'));
}
else{
this.generateWork(asicID);


if(this.minerIsConnected){
this.generateWork(asicID);
}
}
})
let timeInterval = 20000;
if(process.env.HANDYMINER_GUI_NODE_EXEC){
timeInterval = 5000;
}
let refreshJobsI = 0;
let sI = setInterval(()=>{
let bufferStats = new Buffer.from('A53C96A210100000005200000000000000000069C35A','hex');
//get operating temps
Expand All @@ -1171,7 +1192,19 @@ class HandyMiner {
//console.log('poll device info',err);

});

//refresh jobs every 20s to prevent nonce overflow
if(process.env.HANDYMINER_GUI_NODE_EXEC){
if(refreshJobsI % 4 == 0 && refreshJobsI > 0){
//this.refreshAllJobs(true);
this.generateWork(asicID,true);
}
refreshJobsI = refreshJobsI >= 4 ? 0 : refreshJobsI+1;
}
else{
//this.refreshAllJobs(true);
this.generateWork(asicID,true);
}

},timeInterval);
this.asicInfoLookupIntervals[asicID] = sI;
}
Expand All @@ -1188,6 +1221,8 @@ class HandyMiner {
break;
case 0x55:
//console.log('respond to job command');
let justFinished = this.asicWorkQueueNext[asicID] - 1;
this.gpuDeviceBlocks[justFinished+'_'+asicID] = this.nextDeviceBlocks[justFinished+'_'+asicID];
this.queueNextWork(asicID);

break;
Expand All @@ -1196,7 +1231,14 @@ class HandyMiner {
let asicNonceResponse = this.goldShellParser.parseASICNonce(data);
//console.log('nonce response',asicNonceResponse);
this.recordHashrate(asicID,asicNonceResponse.jobID,asicNonceResponse.nonce);
this.submitASICNonce(asicNonceResponse,asicID,this.gpuDeviceBlocks[asicNonceResponse.jobID+'_'+asicID]);
//this.submitASICNonce(asicNonceResponse,asicID,this.gpuDeviceBlocks[asicNonceResponse.jobID+'_'+asicID]);
let workSolved = typeof this.gpuDeviceBlocks[asicNonceResponse.jobID+'_'+asicID] == "undefined" ? this.nextDeviceBlocks[asicNonceResponse.jobID+'_'+asicID] : this.gpuDeviceBlocks[asicNonceResponse.jobID+'_'+asicID];
if(typeof workSolved == "undefined" && typeof this.nextDeviceBlocks[asicNonceResponse.jobID+'_'+asicID] != "undefined"){
this.gpuDeviceBlocks[asicNonceResponse.jobID+'_'+asicID] = this.nextDeviceBlocks[asicNonceResponse.jobID+'_'+asicID];
workSolved = this.gpuDeviceBlocks[asicNonceResponse.jobID+'_'+asicID];
}
//console.log('nonce solved',asicNonceResponse.jobID,asicID,workSolved);
this.submitASICNonce(asicNonceResponse,asicID,workSolved);

break;
}
Expand Down Expand Up @@ -1280,7 +1322,7 @@ class HandyMiner {
//console.log('to queue next',asicID);
let nextQueued = this.asicWorkQueueNext[asicID];

let work = this.gpuDeviceBlocks[nextQueued+'_'+asicID];
let work = this.nextDeviceBlocks[nextQueued+'_'+asicID];
//console.log('queued up',nextQueued,work);
if(typeof work != "undefined"){
//console.log('queue next work?',nextQueued);
Expand Down Expand Up @@ -1345,6 +1387,7 @@ class HandyMiner {
let totalAverageHashrate = sumAverages / sumAverageLength;
}*/

Object.keys(this.asicWorkers).map((asicID,asicI)=>{
perAsicRateNow[asicID] = 0;
perAsicRateAvg[asicID] = 0;
Expand Down Expand Up @@ -1394,6 +1437,9 @@ class HandyMiner {
sumRateNow += hashRatePerSecond;
sumRateAvg += hourlyAvg;
}
if(typeof this.asicStats[asicID] == "undefined"){
return; //no data yet
}
if(!process.env.HANDYRAW){
console.log('');
console.log(`\x1b[36m##### PORT\x1b[0m: ${asicID}, ${this.asicNames[asicID].modelName}${this.asicNames[asicID].serial}`)
Expand Down Expand Up @@ -1510,7 +1556,7 @@ class HandyMiner {
data += '69C35A';

serialConn.write(new Buffer.from(data,'hex'),err=>{

this.gpuDeviceBlocks[workerID+'_'+asicID] = this.nextDeviceBlocks[workerID+'_'+asicID];
})
}
spawnASICWorker(asicID,asicArrayI){
Expand Down Expand Up @@ -1734,7 +1780,7 @@ class HandyMiner {
}

}
refreshJob(jobData){
refreshJob(jobData,silenceRefreshLog){
let intensity = 0;
if(this.minerIntensity.toString().split(',').length == 1){
intensity = this.minerIntensity;
Expand All @@ -1747,16 +1793,25 @@ class HandyMiner {
id:jobData.gpuID,
intensity:intensity
}
this.getDeviceWork([workObject]);
this.getDeviceWork([workObject],silenceRefreshLog);
}
refreshAllJobs(){
refreshAllJobs(silenceRefreshLog){
//refresh all when we get difficulty notices in solo mode
Object.keys(this.gpuDeviceBlocks).map((k)=>{
let d = this.gpuDeviceBlocks[k];
let gpuID = d.gpu;
let platformID = d.platform;
this.refreshJob({gpuID:gpuID,platformID:platformID});
this.refreshJob({gpuID:gpuID,platformID:platformID},silenceRefreshLog);
})
if(Object.keys(this.gpuDeviceBlocks).length == 0 && Object.keys(this.nextDeviceBlocks).length > 0){
//has just started up lets refresh then...
Object.keys(this.nextDeviceBlocks).map((k)=>{
let d = this.nextDeviceBlocks[k];
let gpuID = d.gpu;
let platformID = d.platform;
this.refreshJob({gpuID:gpuID,platformID:platformID},silenceRefreshLog);
})
}
}
refreshOutstandingJobs(){
//refresh only people who have submitted and are awaiting things but got an error
Expand All @@ -1770,7 +1825,7 @@ class HandyMiner {
}
})
}
generateWork(asicID){
generateWork(asicID,silenceRefreshLog){
//here
//console.log('generate work then??',asicID,this.asicNames[asicID])
let workDepth = this.asicNames[asicID].workDepth;
Expand All @@ -1785,7 +1840,7 @@ class HandyMiner {
workObjects.push(workObject);

}
this.getDeviceWork(workObjects);
this.getDeviceWork(workObjects,silenceRefreshLog);
return false;

}
Expand Down Expand Up @@ -1946,7 +2001,7 @@ class HandyMiner {
//C. Above - 1 + 0.5

}
getDeviceWork(deviceWorkJSON){
getDeviceWork(deviceWorkJSON,silenceRefreshLog){
//array of getworks from stdin
const _this = this;

Expand All @@ -1964,7 +2019,10 @@ class HandyMiner {
workObject.nonce2 = nonce2String;

let work = this.getBlockHeader(nonce2String);
this.gpuDeviceBlocks[workObject.id+'_'+workObject.platform] = {


// this.gpuDeviceBlocks[workObject.id+'_'+workObject.platform] = {
this.nextDeviceBlocks[workObject.id+'_'+workObject.platform] = {
request:workObject,
nonce2:nonce2String,
work:work,
Expand All @@ -1977,25 +2035,26 @@ class HandyMiner {
return;
}

this.workByHeaders[work.header.toString('hex')] = this.gpuDeviceBlocks[workObject.id+'_'+workObject.platform];
this.workByHeaders[work.header.toString('hex')] = this.nextDeviceBlocks[workObject.id+'_'+workObject.platform];
let serialPort = workObject.platform;
let workerID = workObject.id;
//console.log('workerid',workerID,typeof workerID)
if(workerID == 1){
//console.log('should write work');
this.writeWorkToASIC(serialPort,workerID,this.gpuDeviceBlocks[workObject.id+'_'+workObject.platform]);
this.writeWorkToASIC(serialPort,workerID,this.nextDeviceBlocks[workObject.id+'_'+workObject.platform]);
}
if(process.env.HANDYRAW && !_this.isMGoing){
if(process.env.HANDYRAW && !_this.isMGoing && typeof silenceRefreshLog == "undefined"){
//log our difficulty and target information for dashboardface
process.stdout.write(JSON.stringify({difficulty:work.jobDifficulty,target:work.targetString,networkDifficulty:work.blockTemplate.difficulty,asic:serialPort,worker:workerID,platform:serialPort,type:'difficulty'})+'\n');
}
});

if(process.env.HANDYRAW){
process.stdout.write(JSON.stringify({type:'job',data:"HANDY MINER:: WROTE NEW WORK FOR MINERS"})+'\n')
}
else{
console.log("\x1b[36mHANDY MINER::\x1b[0m WROTE NEW WORK FOR MINERS"/*,messageStrings*/);
if(typeof silenceRefreshLog == "undefined"){
if(process.env.HANDYRAW){
process.stdout.write(JSON.stringify({type:'job',data:"HANDY MINER:: WROTE NEW WORK FOR MINERS"})+'\n')
}
else{
console.log("\x1b[36mHANDY MINER::\x1b[0m WROTE NEW WORK FOR MINERS"/*,messageStrings*/);
}
}

}
Expand All @@ -2022,4 +2081,4 @@ class HandyMiner {
}
}

module.exports = HandyMiner;
module.exports = HandyMiner;
7 changes: 6 additions & 1 deletion miner/dashboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,12 @@ class CLIDashboard{
this.asics[key].data.fan.push({fans:parseFloat(data.data.fanRpm),time:moment().format('HH:mm')});
this.asics[key].data.asicCoreClock.push({clock:parseFloat(data.data.frequency),time:moment().format('HH:mm')});
this.asics[key].data.asicMemoryClock.push({clock:parseFloat(data.data.frequency),time:moment().format('HH:mm')});
this.asics[key].data.power.push({power:57.0,time:moment().format('HH:mm')});
//no way to detect power, go by projected watts based on model..
let powerW = 57.0;
if(data.data.name.indexOf('Plus') >= 0){
powerW = 115.0;
}
this.asics[key].data.power.push({power:powerW,time:moment().format('HH:mm')});
this.asics[key].data.voltage.push({voltage:parseFloat(data.data.voltage),time:moment().format('HH:mm')});
this.asics[key].invalid = data.data.solutions.invalid;
this.asics[key].valid = data.data.solutions.valid;
Expand Down

0 comments on commit f6fc98a

Please sign in to comment.