#include "miningpage.h" #include "ui_miningpage.h" MiningPage::MiningPage(QWidget *parent) : QWidget(parent), ui(new Ui::MiningPage) { ui->setupUi(this); setFixedSize(400, 420); minerActive = false; minerProcess = new QProcess(this); minerProcess->setProcessChannelMode(QProcess::MergedChannels); readTimer = new QTimer(this); acceptedShares = 0; rejectedShares = 0; roundAcceptedShares = 0; roundRejectedShares = 0; initThreads = 0; connect(readTimer, SIGNAL(timeout()), this, SLOT(readProcessOutput())); connect(ui->startButton, SIGNAL(pressed()), this, SLOT(startPressed())); connect(ui->typeBox, SIGNAL(currentIndexChanged(int)), this, SLOT(typeChanged(int))); connect(ui->debugCheckBox, SIGNAL(toggled(bool)), this, SLOT(debugToggled(bool))); connect(minerProcess, SIGNAL(started()), this, SLOT(minerStarted())); connect(minerProcess, SIGNAL(error(QProcess::ProcessError)), this, SLOT(minerError(QProcess::ProcessError))); connect(minerProcess, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(minerFinished())); connect(minerProcess, SIGNAL(readyRead()), this, SLOT(readProcessOutput())); } MiningPage::~MiningPage() { minerProcess->kill(); delete ui; } void MiningPage::setModel(ClientModel *model) { this->model = model; loadSettings(); bool pool = model->getMiningType() == ClientModel::PoolMining; ui->threadsBox->setValue(model->getMiningThreads()); ui->typeBox->setCurrentIndex(pool ? 1 : 0); // if (model->getMiningStarted()) // startPressed(); } void MiningPage::startPressed() { initThreads = ui->threadsBox->value(); if (minerActive == false) { saveSettings(); if (getMiningType() == ClientModel::SoloMining) minerStarted(); else startPoolMining(); } else { if (getMiningType() == ClientModel::SoloMining) minerFinished(); else stopPoolMining(); } } void MiningPage::startPoolMining() { QStringList args; QString url = ui->serverLine->text(); if (!url.contains("://")) // Any protocol is accepted url.prepend("http://"); QString urlLine = QString("%1:%2").arg(url, ui->portLine->text()); QString userpassLine = QString("%1:%2").arg(ui->usernameLine->text(), ui->passwordLine->text()); args << "--algo" << "scrypt"; args << "--scantime" << ui->scantimeBox->text().toAscii(); args << "--url" << urlLine.toAscii(); args << "--userpass" << userpassLine.toAscii(); args << "--threads" << ui->threadsBox->text().toAscii(); args << "--retries" << "-1"; // Retry forever. args << "-P"; // This is needed for this to work correctly on Windows. Extra protocol dump helps flush the buffer quicker. threadSpeed.clear(); acceptedShares = 0; rejectedShares = 0; roundAcceptedShares = 0; roundRejectedShares = 0; // If minerd is in current path, then use that. Otherwise, assume minerd is in the path somewhere. QString program = QDir::current().filePath("minerd"); if (!QFile::exists(program)) program = "minerd"; if (ui->debugCheckBox->isChecked()) ui->list->addItem(args.join(" ").prepend(" ").prepend(program)); ui->mineSpeedLabel->setText("Speed: N/A"); ui->shareCount->setText("Accepted: 0 - Rejected: 0"); minerProcess->start(program,args); minerProcess->waitForStarted(-1); readTimer->start(500); } void MiningPage::stopPoolMining() { ui->mineSpeedLabel->setText(""); minerProcess->kill(); readTimer->stop(); } void MiningPage::saveSettings() { model->setMiningDebug(ui->debugCheckBox->isChecked()); model->setMiningScanTime(ui->scantimeBox->value()); model->setMiningServer(ui->serverLine->text()); model->setMiningPort(ui->portLine->text()); model->setMiningUsername(ui->usernameLine->text()); model->setMiningPassword(ui->passwordLine->text()); } void MiningPage::loadSettings() { ui->debugCheckBox->setChecked(model->getMiningDebug()); ui->scantimeBox->setValue(model->getMiningScanTime()); ui->serverLine->setText(model->getMiningServer()); ui->portLine->setText(model->getMiningPort()); ui->usernameLine->setText(model->getMiningUsername()); ui->passwordLine->setText(model->getMiningPassword()); } void MiningPage::readProcessOutput() { QByteArray output; minerProcess->reset(); output = minerProcess->readAll(); QString outputString(output); if (!outputString.isEmpty()) { QStringList list = outputString.split("\n", QString::SkipEmptyParts); int i; for (i=0; idebugCheckBox->isChecked()) { ui->list->addItem(line.trimmed()); ui->list->scrollToBottom(); } if (line.contains("(yay!!!)")) reportToList("Share accepted", SHARE_SUCCESS, getTime(line)); else if (line.contains("(booooo)")) reportToList("Share rejected", SHARE_FAIL, getTime(line)); else if (line.contains("LONGPOLL detected new block")) reportToList("LONGPOLL detected a new block", LONGPOLL, getTime(line)); else if (line.contains("Supported options:")) reportToList("Miner didn't start properly. Try checking your settings.", ERROR, NULL); else if (line.contains("The requested URL returned error: 403")) reportToList("Couldn't connect. Please check your username and password.", ERROR, NULL); else if (line.contains("HTTP request failed")) reportToList("Couldn't connect. Please check pool server and port.", ERROR, NULL); else if (line.contains("JSON-RPC call failed")) reportToList("Couldn't communicate with server. Retrying in 30 seconds.", ERROR, NULL); else if (line.contains("thread ") && line.contains("khash/s")) { QString threadIDstr = line.at(line.indexOf("thread ")+7); int threadID = threadIDstr.toInt(); int threadSpeedindx = line.indexOf(","); QString threadSpeedstr = line.mid(threadSpeedindx); threadSpeedstr.chop(8); threadSpeedstr.remove(", "); threadSpeedstr.remove(" "); threadSpeedstr.remove('\n'); double speed=0; speed = threadSpeedstr.toDouble(); threadSpeed[threadID] = speed; updateSpeed(); } } } } void MiningPage::minerError(QProcess::ProcessError error) { if (error == QProcess::FailedToStart) { reportToList("No dig such fail", ERROR, NULL); } } void MiningPage::minerFinished() { if (getMiningType() == ClientModel::SoloMining) reportToList("Solo dig stop", ERROR, NULL); else reportToList("Dig exit", ERROR, NULL); ui->list->addItem(""); minerActive = false; resetMiningButton(); model->setMining(getMiningType(), false, initThreads, 0); } void MiningPage::minerStarted() { if (!minerActive) if (getMiningType() == ClientModel::SoloMining) reportToList("Solo dig start", ERROR, NULL); else reportToList("Dig start", STARTED, NULL); minerActive = true; resetMiningButton(); model->setMining(getMiningType(), true, initThreads, 0); } void MiningPage::updateSpeed() { double totalSpeed=0; int totalThreads=0; QMapIterator iter(threadSpeed); while(iter.hasNext()) { iter.next(); totalSpeed += iter.value(); totalThreads++; } // If all threads haven't reported the hash speed yet, make an assumption if (totalThreads != initThreads) { totalSpeed = (totalSpeed/totalThreads)*initThreads; } QString speedString = QString("%1").arg(totalSpeed); QString threadsString = QString("%1").arg(initThreads); QString acceptedString = QString("%1").arg(acceptedShares); QString rejectedString = QString("%1").arg(rejectedShares); QString roundAcceptedString = QString("%1").arg(roundAcceptedShares); QString roundRejectedString = QString("%1").arg(roundRejectedShares); if (totalThreads == initThreads) ui->mineSpeedLabel->setText(QString("Speed: %1 khash/sec - %2 thread(s)").arg(speedString, threadsString)); else ui->mineSpeedLabel->setText(QString("Speed: ~%1 khash/sec - %2 thread(s)").arg(speedString, threadsString)); ui->shareCount->setText(QString("Accepted: %1 (%3) - Rejected: %2 (%4)").arg(acceptedString, rejectedString, roundAcceptedString, roundRejectedString)); model->setMining(getMiningType(), true, initThreads, totalSpeed*1000); } void MiningPage::reportToList(QString msg, int type, QString time) { QString message; if (time == NULL) message = QString("[%1] - %2").arg(QTime::currentTime().toString(), msg); else message = QString("[%1] - %2").arg(time, msg); switch(type) { case SHARE_SUCCESS: acceptedShares++; roundAcceptedShares++; updateSpeed(); break; case SHARE_FAIL: rejectedShares++; roundRejectedShares++; updateSpeed(); break; case LONGPOLL: roundAcceptedShares = 0; roundRejectedShares = 0; break; default: break; } ui->list->addItem(message); ui->list->scrollToBottom(); } // Function for fetching the time QString MiningPage::getTime(QString time) { if (time.contains("[")) { time.resize(21); time.remove("["); time.remove("]"); time.remove(0,11); return time; } else return NULL; } void MiningPage::enableMiningControls(bool enable) { ui->typeBox->setEnabled(enable); ui->threadsBox->setEnabled(enable); ui->scantimeBox->setEnabled(enable); ui->serverLine->setEnabled(enable); ui->portLine->setEnabled(enable); ui->usernameLine->setEnabled(enable); ui->passwordLine->setEnabled(enable); } void MiningPage::enablePoolMiningControls(bool enable) { ui->scantimeBox->setEnabled(enable); ui->serverLine->setEnabled(enable); ui->portLine->setEnabled(enable); ui->usernameLine->setEnabled(enable); ui->passwordLine->setEnabled(enable); } ClientModel::MiningType MiningPage::getMiningType() { if (ui->typeBox->currentIndex() == 0) // Solo Mining { return ClientModel::SoloMining; } else if (ui->typeBox->currentIndex() == 1) // Pool Mining { return ClientModel::PoolMining; } return ClientModel::SoloMining; } void MiningPage::typeChanged(int index) { if (index == 0) // Solo Mining { enablePoolMiningControls(false); } else if (index == 1) // Pool Mining { enablePoolMiningControls(true); } } void MiningPage::debugToggled(bool checked) { model->setMiningDebug(checked); } void MiningPage::resetMiningButton() { ui->startButton->setText(minerActive ? "Stop Dig" : "Start Dig"); enableMiningControls(!minerActive); }