/** ****************************************************************************** * * @file uploadergadgetwidget.cpp * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. * @addtogroup GCSPlugins GCS Plugins * @{ * @addtogroup YModemUploader YModem Serial Uploader Plugin * @{ * @brief The YModem protocol serial uploader plugin *****************************************************************************/ /* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "uploadergadgetwidget.h" UploaderGadgetWidget::UploaderGadgetWidget(QWidget *parent) : QWidget(parent) { m_config = new Ui_UploaderWidget(); m_config->setupUi(this); currentStep = IAP_STATE_READY; resetOnly=false; //m_config->systemElements->addTab((QWidget*)new deviceWidget(),QString("Device")); connect(m_config->haltButton, SIGNAL(clicked()), this, SLOT(goToBootloader())); connect(m_config->resetButton, SIGNAL(clicked()), this, SLOT(systemReset())); connect(m_config->bootButton, SIGNAL(clicked()), this, SLOT(systemBoot())); } /** Tell the mainboard to go to bootloader: - Send the relevant IAP commands - setup callback for MoBo acknowledge */ void UploaderGadgetWidget::goToBootloader(UAVObject* callerObj, bool success) { ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); UAVObjectManager *objManager = pm->getObject(); UAVObject *fwIAP = dynamic_cast(objManager->getObject(QString("FirmwareIAPObj"))); switch (currentStep) { case IAP_STATE_READY: // The board is running, send the 1st IAP Reset order: fwIAP->getField("Command")->setValue("1122"); connect(fwIAP,SIGNAL(transactionCompleted(UAVObject*,bool)),this,SLOT(goToBootloader(UAVObject*, bool))); currentStep = IAP_STATE_STEP_1; fwIAP->updated(); clearLog(); log(QString("IAP Step 1")); break; case IAP_STATE_STEP_1: if (!success) { log(QString("Oops, failure step 1")); log("Reset did NOT happen"); currentStep == IAP_STATE_READY; disconnect(fwIAP, SIGNAL(transactionCompleted(UAVObject*,bool)),this,SLOT(goToBootloader(UAVObject*, bool))); break; } delay::msleep(600); fwIAP->getField("Command")->setValue("2233"); currentStep = IAP_STATE_STEP_2; fwIAP->updated(); log(QString("IAP Step 2")); break; case IAP_STATE_STEP_2: if (!success) { log(QString("Oops, failure step 2")); log("Reset did NOT happen"); currentStep == IAP_STATE_READY; disconnect(fwIAP, SIGNAL(transactionCompleted(UAVObject*,bool)),this,SLOT(goToBootloader(UAVObject*, bool))); break; } delay::msleep(600); fwIAP->getField("Command")->setValue("3344"); currentStep = IAP_STEP_RESET; fwIAP->updated(); log(QString("IAP Step 3")); break; case IAP_STEP_RESET: { currentStep = IAP_STATE_READY; if (success) { log("Oops, unexpected success step 3"); log("Reset did NOT happen"); disconnect(fwIAP, SIGNAL(transactionCompleted(UAVObject*,bool)),this,SLOT(goToBootloader(UAVObject*, bool))); break; } // The board is now reset: we have to disconnect telemetry Core::ConnectionManager *cm = Core::ICore::instance()->connectionManager(); cm->disconnectDevice(); log("Board Reset"); ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); disconnect(fwIAP, SIGNAL(transactionCompleted(UAVObject*,bool)),this,SLOT(goToBootloader(UAVObject*, bool))); if (resetOnly) { resetOnly=false; break; } // stop the polling thread: otherwise it will mess up DFU RawHIDConnection *cnx = pm->getObject(); cnx->suspendPolling(); // Tell the mainboard to get into bootloader state: log("Going into Bootloader mode..."); OP_DFU dfu(true); dfu.AbortOperation(); if(!dfu.enterDFU(0)) { log("Could not enter DFU mode."); return; } m_config->boardStatus->setText("Bootloader"); currentStep = IAP_STATE_BOOTLOADER; OP_DFU::Status ret=dfu.StatusRequest(); dfu.findDevices(); log(QString("Found ") + QString::number(dfu.numberOfDevices) + QString(" device(s).")); // Delete all previous tabs: for (int i=0; i< m_config->systemElements->count(); i++) { QWidget *qw = m_config->systemElements->widget(i); m_config->systemElements->removeTab(i); delete qw; } for(int i=0;isetDeviceID(i); dw->setDfu(&dfu); dw->populate(); m_config->systemElements->addTab(dw, QString("Device") + QString::number(i)); } m_config->haltButton->setEnabled(false); m_config->resetButton->setEnabled(false); m_config->bootButton->setEnabled(true); } } } /** Tell the mainboard to reset: - Send the relevant IAP commands - setup callback for MoBo acknowledge */ void UploaderGadgetWidget::systemReset() { resetOnly = true; m_config->textBrowser->clear(); log("Board Reset initiated."); goToBootloader(); } /** Tells the system to boot (from Bootloader state) */ void UploaderGadgetWidget::systemBoot() { if (currentStep == IAP_STATE_BOOTLOADER) { clearLog(); OP_DFU dfu(true); dfu.AbortOperation(); if(!dfu.enterDFU(0)) { log("Could not enter DFU mode."); return; } log("Booting system..."); dfu.JumpToApp(); currentStep = IAP_STATE_READY; // stop the polling thread: otherwise it will mess up DFU ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); RawHIDConnection *cnx = pm->getObject(); cnx->resumePolling(); m_config->bootButton->setEnabled(false); m_config->haltButton->setEnabled(true); m_config->resetButton->setEnabled(true); m_config->boardStatus->setText("Running"); } else { log("Not in bootloader mode!"); } } /** Update log entry */ void UploaderGadgetWidget::log(QString str) { m_config->textBrowser->append(str); } void UploaderGadgetWidget::clearLog() { m_config->textBrowser->clear(); } //user pressed send, send file using a new thread with qymodem library void UploaderGadgetWidget::send() { Ymodem->SendFileT(openFileNameLE->text()); } //destructor !!?! do I need to delete something else? UploaderGadgetWidget::~UploaderGadgetWidget() { delete Port; delete Ymodem; } //from load configuration, creates a new qymodemsend class with the the port /** Cteates a new qymodemsend class. @param port The serial port to use. */ void UploaderGadgetWidget::setPort(QextSerialPort* port) { Port=port; Ymodem=new QymodemSend(*Port); //only now can we connect this signals //signals errors connect(Ymodem,SIGNAL(Error(QString,int)) ,this,SLOT(error(QString,int))); //signals new information connect(Ymodem,SIGNAL(Information(QString,int)), this,SLOT(info(QString,int))); //signals new percentage value connect(Ymodem,SIGNAL(Percent(int)), this,SLOT(updatePercSlot(int))); } /** Updates progress bar value. @param i New percentage value. */ void UploaderGadgetWidget::updatePercSlot(int i) { progressBar->setValue(i); } /** Opens an open file dialog. */ void UploaderGadgetWidget::setOpenFileName() { QFileDialog::Options options; QString selectedFilter; QString fileName = QFileDialog::getOpenFileName(this, tr("QFileDialog::getOpenFileName()"), openFileNameLE->text(), tr("All Files (*);;Text Files (*.bin)"), &selectedFilter, options); if (!fileName.isEmpty()) openFileNameLE->setText(fileName); } /** Shows a message box with an error string. @param errorString The error string to display. @param errorNumber Not used */ void UploaderGadgetWidget::error(QString errorString, int errorNumber) { QMessageBox msgBox; msgBox.setIcon(QMessageBox::Critical); msgBox.setText(errorString); msgBox.exec(); status->setText(errorString); } /** Shows a message box with an information string. @param infoString The information string to display. @param infoNumber Not used */ void UploaderGadgetWidget::info(QString infoString, int infoNumber) { status->setText(infoString); }