#include "LinkManager.h" #include "LinkInterface.h" #include "qserialport.h" #include "qserialportinfo.h" #include "SerialLink.h" #include "ApmFirmwareConfig.h" ApmFirmwareConfig::ApmFirmwareConfig(QWidget *parent) : QWidget(parent) { ui.setupUi(this); //firmwareStatus = 0; m_betaFirmwareChecked = false; m_tempFirmwareFile=0; // //QNetworkRequest req(QUrl("https://raw.github.com/diydrones/binary/master/Firmware/firmware2.xml")); m_networkManager = new QNetworkAccessManager(this); connect(ui.roverPushButton,SIGNAL(clicked()),this,SLOT(burnButtonClicked())); connect(ui.planePushButton,SIGNAL(clicked()),this,SLOT(burnButtonClicked())); connect(ui.copterPushButton,SIGNAL(clicked()),this,SLOT(burnButtonClicked())); connect(ui.hexaPushButton,SIGNAL(clicked()),this,SLOT(burnButtonClicked())); connect(ui.octaQuadPushButton,SIGNAL(clicked()),this,SLOT(burnButtonClicked())); connect(ui.octaPushButton,SIGNAL(clicked()),this,SLOT(burnButtonClicked())); connect(ui.quadPushButton,SIGNAL(clicked()),this,SLOT(burnButtonClicked())); connect(ui.triPushButton,SIGNAL(clicked()),this,SLOT(burnButtonClicked())); connect(ui.y6PushButton,SIGNAL(clicked()),this,SLOT(burnButtonClicked())); requestFirmwares(); connect(ui.betaFirmwareButton,SIGNAL(clicked(bool)),this,SLOT(betaFirmwareButtonClicked(bool))); ui.progressBar->setMaximum(100); ui.progressBar->setValue(0); ui.progressBar->setVisible(false); ui.textBrowser->setVisible(false); connect(ui.showOutputCheckBox,SIGNAL(clicked(bool)),ui.textBrowser,SLOT(setShown(bool))); } void ApmFirmwareConfig::requestBetaFirmwares() { m_betaFirmwareChecked = true; QNetworkReply *reply1 = m_networkManager->get(QNetworkRequest(QUrl("http://firmware.diydrones.com/Copter/beta/apm2-heli/git-version.txt"))); QNetworkReply *reply2 = m_networkManager->get(QNetworkRequest(QUrl("http://firmware.diydrones.com/Copter/beta/apm2-quad/git-version.txt"))); QNetworkReply *reply3 = m_networkManager->get(QNetworkRequest(QUrl("http://firmware.diydrones.com/Copter/beta/apm2-hexa/git-version.txt"))); QNetworkReply *reply4 = m_networkManager->get(QNetworkRequest(QUrl("http://firmware.diydrones.com/Copter/beta/apm2-octa/git-version.txt"))); QNetworkReply *reply5 = m_networkManager->get(QNetworkRequest(QUrl("http://firmware.diydrones.com/Copter/beta/apm2-octa-quad/git-version.txt"))); QNetworkReply *reply6 = m_networkManager->get(QNetworkRequest(QUrl("http://firmware.diydrones.com/Copter/beta/apm2-tri/git-version.txt"))); QNetworkReply *reply7 = m_networkManager->get(QNetworkRequest(QUrl("http://firmware.diydrones.com/Copter/beta/apm2-y6/git-version.txt"))); QNetworkReply *reply8 = m_networkManager->get(QNetworkRequest(QUrl("http://firmware.diydrones.com/Plane/beta/apm2/git-version.txt"))); QNetworkReply *reply9 = m_networkManager->get(QNetworkRequest(QUrl("http://firmware.diydrones.com/Rover/beta/apm2/git-version.txt"))); m_buttonToUrlMap[ui.roverPushButton] = "http://firmware.diydrones.com/Rover/beta/apm2/APMrover2.hex"; m_buttonToUrlMap[ui.planePushButton] = "http://firmware.diydrones.com/Plane/beta/apm2/ArduPlane.hex"; m_buttonToUrlMap[ui.copterPushButton] = "http://firmware.diydrones.com/Copter/beta/apm2-heli/ArduCopter.hex"; m_buttonToUrlMap[ui.hexaPushButton] = "http://firmware.diydrones.com/Copter/beta/apm2-hexa/ArduCopter.hex"; m_buttonToUrlMap[ui.octaQuadPushButton] = "http://firmware.diydrones.com/Copter/beta/apm2-octa-quad/ArduCopter.hex"; m_buttonToUrlMap[ui.octaPushButton] = "http://firmware.diydrones.com/Copter/beta/apm2-octa/ArduCopter.hex"; m_buttonToUrlMap[ui.quadPushButton] = "http://firmware.diydrones.com/Copter/beta/apm2-quad/ArduCopter.hex"; m_buttonToUrlMap[ui.triPushButton] = "http://firmware.diydrones.com/Copter/beta/apm2-tri/ArduCopter.hex"; m_buttonToUrlMap[ui.y6PushButton] = "http://firmware.diydrones.com/Copter/beta/apm2-y6/ArduCopter.hex"; //http://firmware.diydrones.com/Plane/stable/apm2/ArduPlane.hex connect(reply1,SIGNAL(finished()),this,SLOT(firmwareListFinished())); connect(reply1,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(firmwareListError(QNetworkReply::NetworkError))); connect(reply2,SIGNAL(finished()),this,SLOT(firmwareListFinished())); connect(reply2,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(firmwareListError(QNetworkReply::NetworkError))); connect(reply3,SIGNAL(finished()),this,SLOT(firmwareListFinished())); connect(reply3,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(firmwareListError(QNetworkReply::NetworkError))); connect(reply4,SIGNAL(finished()),this,SLOT(firmwareListFinished())); connect(reply4,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(firmwareListError(QNetworkReply::NetworkError))); connect(reply5,SIGNAL(finished()),this,SLOT(firmwareListFinished())); connect(reply5,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(firmwareListError(QNetworkReply::NetworkError))); connect(reply6,SIGNAL(finished()),this,SLOT(firmwareListFinished())); connect(reply6,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(firmwareListError(QNetworkReply::NetworkError))); connect(reply7,SIGNAL(finished()),this,SLOT(firmwareListFinished())); connect(reply7,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(firmwareListError(QNetworkReply::NetworkError))); connect(reply8,SIGNAL(finished()),this,SLOT(firmwareListFinished())); connect(reply8,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(firmwareListError(QNetworkReply::NetworkError))); connect(reply9,SIGNAL(finished()),this,SLOT(firmwareListFinished())); connect(reply9,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(firmwareListError(QNetworkReply::NetworkError))); qDebug() << "Getting Beta firmware..."; } void ApmFirmwareConfig::requestFirmwares() { m_betaFirmwareChecked = false; QNetworkReply *reply1 = m_networkManager->get(QNetworkRequest(QUrl("http://firmware.diydrones.com/Copter/stable/apm2-heli/git-version.txt"))); QNetworkReply *reply2 = m_networkManager->get(QNetworkRequest(QUrl("http://firmware.diydrones.com/Copter/stable/apm2-quad/git-version.txt"))); QNetworkReply *reply3 = m_networkManager->get(QNetworkRequest(QUrl("http://firmware.diydrones.com/Copter/stable/apm2-hexa/git-version.txt"))); QNetworkReply *reply4 = m_networkManager->get(QNetworkRequest(QUrl("http://firmware.diydrones.com/Copter/stable/apm2-octa/git-version.txt"))); QNetworkReply *reply5 = m_networkManager->get(QNetworkRequest(QUrl("http://firmware.diydrones.com/Copter/stable/apm2-octa-quad/git-version.txt"))); QNetworkReply *reply6 = m_networkManager->get(QNetworkRequest(QUrl("http://firmware.diydrones.com/Copter/stable/apm2-tri/git-version.txt"))); QNetworkReply *reply7 = m_networkManager->get(QNetworkRequest(QUrl("http://firmware.diydrones.com/Copter/stable/apm2-y6/git-version.txt"))); QNetworkReply *reply8 = m_networkManager->get(QNetworkRequest(QUrl("http://firmware.diydrones.com/Plane/stable/apm2/git-version.txt"))); QNetworkReply *reply9 = m_networkManager->get(QNetworkRequest(QUrl("http://firmware.diydrones.com/Rover/stable/apm2/git-version.txt"))); m_buttonToUrlMap[ui.roverPushButton] = "http://firmware.diydrones.com/Rover/stable/apm2/APMrover2.hex"; m_buttonToUrlMap[ui.planePushButton] = "http://firmware.diydrones.com/Plane/stable/apm2/ArduPlane.hex"; m_buttonToUrlMap[ui.copterPushButton] = "http://firmware.diydrones.com/Copter/stable/apm2-heli/ArduCopter.hex"; m_buttonToUrlMap[ui.hexaPushButton] = "http://firmware.diydrones.com/Copter/stable/apm2-hexa/ArduCopter.hex"; m_buttonToUrlMap[ui.octaQuadPushButton] = "http://firmware.diydrones.com/Copter/stable/apm2-octa-quad/ArduCopter.hex"; m_buttonToUrlMap[ui.octaPushButton] = "http://firmware.diydrones.com/Copter/stable/apm2-octa/ArduCopter.hex"; m_buttonToUrlMap[ui.quadPushButton] = "http://firmware.diydrones.com/Copter/stable/apm2-quad/ArduCopter.hex"; m_buttonToUrlMap[ui.triPushButton] = "http://firmware.diydrones.com/Copter/stable/apm2-tri/ArduCopter.hex"; m_buttonToUrlMap[ui.y6PushButton] = "http://firmware.diydrones.com/Copter/stable/apm2-y6/ArduCopter.hex"; //http://firmware.diydrones.com/Plane/stable/apm2/ArduPlane.hex connect(reply1,SIGNAL(finished()),this,SLOT(firmwareListFinished())); connect(reply1,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(firmwareListError(QNetworkReply::NetworkError))); connect(reply2,SIGNAL(finished()),this,SLOT(firmwareListFinished())); connect(reply2,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(firmwareListError(QNetworkReply::NetworkError))); connect(reply3,SIGNAL(finished()),this,SLOT(firmwareListFinished())); connect(reply3,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(firmwareListError(QNetworkReply::NetworkError))); connect(reply4,SIGNAL(finished()),this,SLOT(firmwareListFinished())); connect(reply4,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(firmwareListError(QNetworkReply::NetworkError))); connect(reply5,SIGNAL(finished()),this,SLOT(firmwareListFinished())); connect(reply5,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(firmwareListError(QNetworkReply::NetworkError))); connect(reply6,SIGNAL(finished()),this,SLOT(firmwareListFinished())); connect(reply6,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(firmwareListError(QNetworkReply::NetworkError))); connect(reply7,SIGNAL(finished()),this,SLOT(firmwareListFinished())); connect(reply7,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(firmwareListError(QNetworkReply::NetworkError))); connect(reply8,SIGNAL(finished()),this,SLOT(firmwareListFinished())); connect(reply8,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(firmwareListError(QNetworkReply::NetworkError))); connect(reply9,SIGNAL(finished()),this,SLOT(firmwareListFinished())); connect(reply9,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(firmwareListError(QNetworkReply::NetworkError))); qDebug() << "Getting Stable firmware..."; } void ApmFirmwareConfig::betaFirmwareButtonClicked(bool betafirmwareenabled) { if (betafirmwareenabled) { QMessageBox::information(0,"Warning","Beta firmwares are from the latest trunk. Use at your own risk!!"); ui.label->setText("

Beta Firmware

"); ui.betaFirmwareButton->setText("Stable Firmware"); requestBetaFirmwares(); } else { ui.label->setText("

Firmware

"); ui.betaFirmwareButton->setText("Beta Firmware"); requestFirmwares(); } } void ApmFirmwareConfig::firmwareProcessFinished(int status) { QProcess *proc = qobject_cast(sender()); if (!proc) { return; } if (status != 0) { //Error of some kind QMessageBox::information(0,"Error","An error has occured during the upload process. See window for details"); ui.textBrowser->setVisible(true); ui.showOutputCheckBox->setChecked(true); ui.textBrowser->setPlainText(ui.textBrowser->toPlainText().append("\n\nERROR!!\n" + proc->errorString())); QScrollBar *sb = ui.textBrowser->verticalScrollBar(); if (sb) { sb->setValue(sb->maximum()); } ui.statusLabel->setText("Error during upload"); } else { //Ensure we're reading 100% ui.progressBar->setValue(100); ui.statusLabel->setText("Upload complete"); } //qDebug() << "Upload finished!" << QString::number(status); m_tempFirmwareFile->deleteLater(); //This will remove the temporary file. m_tempFirmwareFile = 0; } void ApmFirmwareConfig::firmwareProcessReadyRead() { QProcess *proc = qobject_cast(sender()); if (!proc) { return; } QString output = proc->readAllStandardError() + proc->readAllStandardOutput(); if (output.contains("Writing")) { //firmwareStatus->resetProgress(); ui.progressBar->setValue(0); } else if (output.contains("Reading")) { ui.progressBar->setValue(50); } if (output.startsWith("#")) { ui.progressBar->setValue(ui.progressBar->value()+1); ui.textBrowser->setPlainText(ui.textBrowser->toPlainText().append(output)); QScrollBar *sb = ui.textBrowser->verticalScrollBar(); if (sb) { sb->setValue(sb->maximum()); } } else { ui.textBrowser->setPlainText(ui.textBrowser->toPlainText().append(output + "\n")); QScrollBar *sb = ui.textBrowser->verticalScrollBar(); if (sb) { sb->setValue(sb->maximum()); } } qDebug() << "E:" << output; //qDebug() << "AVR Output:" << proc->readAllStandardOutput(); //qDebug() << "AVR Output:" << proc->readAllStandardError(); } void ApmFirmwareConfig::downloadFinished() { qDebug() << "Download finished, burning firmware"; QNetworkReply *reply = qobject_cast(sender()); if (!reply) { return; } QByteArray hex = reply->readAll(); m_tempFirmwareFile = new QTemporaryFile(); m_tempFirmwareFile->open(); m_tempFirmwareFile->write(hex); m_tempFirmwareFile->flush(); m_tempFirmwareFile->close(); //tempfirmware.fileName() QProcess *process = new QProcess(this); connect(process,SIGNAL(finished(int)),this,SLOT(firmwareProcessFinished(int))); connect(process,SIGNAL(readyReadStandardOutput()),this,SLOT(firmwareProcessReadyRead())); connect(process,SIGNAL(readyReadStandardError()),this,SLOT(firmwareProcessReadyRead())); connect(process,SIGNAL(error(QProcess::ProcessError)),this,SLOT(firmwareProcessError(QProcess::ProcessError))); QList portList = QSerialPortInfo::availablePorts(); foreach (const QSerialPortInfo &info, portList) { qDebug() << "PortName : " << info.portName() << "Description : " << info.description(); qDebug() << "Manufacturer: " << info.manufacturer(); } //info.manufacturer() == "Arduino LLC (www.arduino.cc)" //info.description() == "%mega2560.name%" qDebug() << "Attempting to reset port"; QSerialPort port; port.setPortName(m_detectedComPort); port.open(QIODevice::ReadWrite); port.setDataTerminalReady(true); port.waitForBytesWritten(250); port.setDataTerminalReady(false); port.close(); ui.statusLabel->setText("Burning"); QString avrdudeExecutable; QStringList stringList; #ifdef Q_OS_WIN stringList = QStringList() << "-Cavrdude/avrdude.conf" << "-pm2560" << "-cstk500" << QString("-P").append(m_detectedComPort) << QString("-Uflash:w:").append(m_tempFirmwareFile->fileName()).append(":i"); avrdudeExecutable = "avrdude/avrdude.exe"; #endif #ifdef Q_OS_MAC stringList = QStringList() << "-v" << "-pm2560" << "-cstk500" << QString("-P/dev/cu.").append(m_detectedComPort) << QString("-Uflash:w:").append(m_tempFirmwareFile->fileName()).append(":i"); avrdudeExecutable = "/usr/local/CrossPack-AVR/bin/avrdude"; #endif // Start the Flashing qDebug() << avrdudeExecutable << stringList; process->start(avrdudeExecutable,stringList); } void ApmFirmwareConfig::firmwareProcessError(QProcess::ProcessError error) { qDebug() << "Error:" << error; } void ApmFirmwareConfig::firmwareDownloadProgress(qint64 received,qint64 total) { ui.progressBar->setValue( 100.0 * ((double)received/(double)total)); } void ApmFirmwareConfig::burnButtonClicked() { QPushButton *senderbtn = qobject_cast(sender()); if (m_buttonToUrlMap.contains(senderbtn)) { bool foundconnected = false; for (int i=0;igetLinks().size();i++) { if (LinkManager::instance()->getLinks()[i]->isConnected()) { //This is likely the serial link we want. SerialLink *link = qobject_cast(LinkManager::instance()->getLinks()[i]); if (!link) { qDebug() << "Eror, trying to program over a non serial link. This should not happen"; return; } if (!(QMessageBox::question(this,"WARNING","You are about to upload new firmware to your board. This will disconnect you if you are currently connected. Be sure the MAV is on the ground, and connected over USB/Serial link.\n\nDo you wish to proceed?",QMessageBox::Yes,QMessageBox::No) == QMessageBox::Yes)) { return; } m_detectedComPort = link->getPortName(); link->requestReset(); foundconnected = true; link->disconnect(); link->wait(1000); // Wait 1 second for it to disconnect. } } if (!foundconnected) { QMessageBox::information(0,"Error","You must be connected to a MAV over serial link to flash firmware. Please connect to a MAV then try again"); return; } qDebug() << "Go download:" << m_buttonToUrlMap[senderbtn]; QNetworkReply *reply = m_networkManager->get(QNetworkRequest(QUrl(m_buttonToUrlMap[senderbtn]))); //http://firmware.diydrones.com/Plane/stable/apm2/ArduPlane.hex connect(reply,SIGNAL(finished()),this,SLOT(downloadFinished())); connect(reply,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(firmwareListError(QNetworkReply::NetworkError))); connect(reply,SIGNAL(downloadProgress(qint64,qint64)),this,SLOT(firmwareDownloadProgress(qint64,qint64))); ui.statusLabel->setText("Downloading"); ui.progressBar->setVisible(true); } } void ApmFirmwareConfig::firmwareListError(QNetworkReply::NetworkError error) { QNetworkReply *reply = qobject_cast(sender()); qDebug() << "Error!" << reply->errorString(); } bool ApmFirmwareConfig::stripVersionFromGitReply(QString url, QString reply,QString type,QString stable,QString *out) { if (url.contains(type) && url.contains("git-version.txt") && url.contains(stable)) { QString version = reply.mid(reply.indexOf("APMVERSION:")+12).replace("\n","").replace("\r","").trimmed(); *out = version; return true; } return false; } void ApmFirmwareConfig::firmwareListFinished() { QNetworkReply *reply = qobject_cast(sender()); QString replystr = reply->readAll(); QString outstr = ""; if (stripVersionFromGitReply(reply->url().toString(),replystr,"apm2-heli",(m_betaFirmwareChecked ? "beta" : "stable"),&outstr)) { if (m_betaFirmwareChecked) { ui.copterLabel->setText("BETA " + outstr); } else { ui.copterLabel->setText(outstr); } return; } if (stripVersionFromGitReply(reply->url().toString(),replystr,"apm2-quad",(m_betaFirmwareChecked ? "beta" : "stable"),&outstr)) { if (m_betaFirmwareChecked) { ui.quadLabel->setText("BETA " + outstr); } else { ui.quadLabel->setText(outstr); } return; } if (stripVersionFromGitReply(reply->url().toString(),replystr,"apm2-hexa",(m_betaFirmwareChecked ? "beta" : "stable"),&outstr)) { if (m_betaFirmwareChecked) { ui.hexaLabel->setText("BETA " + outstr); } else { ui.hexaLabel->setText(outstr); } return; } if (stripVersionFromGitReply(reply->url().toString(),replystr,"apm2-octa-quad",(m_betaFirmwareChecked ? "beta" : "stable"),&outstr)) { if (m_betaFirmwareChecked) { ui.octaQuadLabel->setText("BETA " + outstr); } else { ui.octaQuadLabel->setText(outstr); } return; } if (stripVersionFromGitReply(reply->url().toString(),replystr,"apm2-octa",(m_betaFirmwareChecked ? "beta" : "stable"),&outstr)) { if (m_betaFirmwareChecked) { ui.octaLabel->setText("BETA " + outstr); } else { ui.octaLabel->setText(outstr); } return; } if (stripVersionFromGitReply(reply->url().toString(),replystr,"apm2-tri",(m_betaFirmwareChecked ? "beta" : "stable"),&outstr)) { if (m_betaFirmwareChecked) { ui.triLabel->setText("BETA " + outstr); } else { ui.triLabel->setText(outstr); } return; } if (stripVersionFromGitReply(reply->url().toString(),replystr,"apm2-y6",(m_betaFirmwareChecked ? "beta" : "stable"),&outstr)) { if (m_betaFirmwareChecked) { ui.y6Label->setText("BETA " + outstr); } else { ui.y6Label->setText(outstr); } return; } if (stripVersionFromGitReply(reply->url().toString(),replystr,"Plane",(m_betaFirmwareChecked ? "beta" : "stable"),&outstr)) { if (m_betaFirmwareChecked) { ui.planeLabel->setText("BETA " + outstr); } else { ui.planeLabel->setText(outstr); } return; } if (stripVersionFromGitReply(reply->url().toString(),replystr,"Rover",(m_betaFirmwareChecked ? "beta" : "stable"),&outstr)) { if (m_betaFirmwareChecked) { ui.roverLabel->setText("BETA " + outstr); } else { ui.roverLabel->setText(outstr); } return; } qDebug() << "Match not found for:" << reply->url(); qDebug() << "Git version line:" << replystr; } ApmFirmwareConfig::~ApmFirmwareConfig() { }