$search
00001 #include <QFileDialog> 00002 #include <QMessageBox> 00003 #include <QDebug> 00004 #include <QPushButton> 00005 #include <QVBoxLayout> 00006 #include <QHBoxLayout> 00007 #include <QProgressBar> 00008 #include <QLineEdit> 00009 #include <QLabel> 00010 #include <QGroupBox> 00011 #include <QListWidget> 00012 #include <QApplication> 00013 #include <QTextCodec> 00014 #include <QTranslator> 00015 #include <QLibraryInfo> 00016 #include <QtConcurrentRun> 00017 #include <memory> 00018 #include <iostream> 00019 00020 #include "../common/consts.h" 00021 #include "../utils/HexFile.h" 00022 00023 #include "ThymioFlasher.h" 00024 #include "ThymioFlasher.moc" 00025 00026 namespace Aseba 00027 { 00028 using namespace Dashel; 00029 using namespace std; 00030 00031 typedef std::map<int, std::pair<std::string, std::string> > PortsMap; 00032 00033 QtBootloaderInterface::QtBootloaderInterface(Stream* stream, int dest): 00034 BootloaderInterface(stream, dest), 00035 pagesCount(0), 00036 pagesDoneCount(0) 00037 {} 00038 00039 void QtBootloaderInterface::writeHexGotDescription(unsigned pagesCount) 00040 { 00041 this->pagesCount = pagesCount; 00042 this->pagesDoneCount = 0; 00043 } 00044 00045 void QtBootloaderInterface::writePageStart(unsigned pageNumber, const uint8* data, bool simple) 00046 { 00047 pagesDoneCount += 1; 00048 emit flashProgress((100*pagesDoneCount)/pagesCount); 00049 } 00050 00051 void QtBootloaderInterface::errorWritePageNonFatal(unsigned pageNumber) 00052 { 00053 qDebug() << "Warning, error while writing page" << pageNumber << "continuing ..."; 00054 } 00055 00056 00057 ThymioFlasherDialog::ThymioFlasherDialog(const std::string& target): 00058 target(target) 00059 { 00060 // Create the gui ... 00061 setWindowTitle(tr("Thymio Firmware Updater")); 00062 00063 QVBoxLayout* mainLayout = new QVBoxLayout(this); 00064 00065 QHBoxLayout *imageLayout = new QHBoxLayout(); 00066 QLabel* image = new QLabel(this); 00067 image->setPixmap(QPixmap(":/images/thymioflasher.png")); 00068 imageLayout->addStretch(); 00069 imageLayout->addWidget(image); 00070 imageLayout->addStretch(); 00071 mainLayout->addLayout(imageLayout); 00072 00073 // file selector 00074 QGroupBox* fileGroupBox = new QGroupBox(tr("Firmware file")); 00075 QHBoxLayout *fileLayout = new QHBoxLayout(); 00076 lineEdit = new QLineEdit(this); 00077 fileButton = new QPushButton(tr("Select..."), this); 00078 fileButton->setIcon(QIcon(":/images/fileopen.svgz")); 00079 fileLayout->addWidget(fileButton); 00080 fileLayout->addWidget(lineEdit); 00081 fileGroupBox->setLayout(fileLayout); 00082 mainLayout->addWidget(fileGroupBox); 00083 00084 // progress bar 00085 progressBar = new QProgressBar(this); 00086 progressBar->setValue(0); 00087 progressBar->setRange(0, 100); 00088 mainLayout->addWidget(progressBar); 00089 00090 // flash and quit buttons 00091 QHBoxLayout *flashLayout = new QHBoxLayout(); 00092 flashButton = new QPushButton(tr("Update"), this); 00093 flashButton->setEnabled(false); 00094 flashLayout->addWidget(flashButton); 00095 quitButton = new QPushButton(tr("Quit"), this); 00096 flashLayout->addWidget(quitButton); 00097 mainLayout->addItem(flashLayout); 00098 00099 // connections 00100 connect(fileButton, SIGNAL(clicked()), SLOT(openFile())); 00101 connect(flashButton, SIGNAL(clicked()), SLOT(doFlash())); 00102 connect(quitButton, SIGNAL(clicked()), SLOT(close())); 00103 connect(&flashFutureWatcher, SIGNAL(finished()), SLOT(flashFinished())); 00104 00105 show(); 00106 } 00107 00108 ThymioFlasherDialog::~ThymioFlasherDialog() 00109 { 00110 flashFuture.waitForFinished(); 00111 } 00112 00113 void ThymioFlasherDialog::setupFlashButtonState() 00114 { 00115 flashButton->setEnabled( 00116 !lineEdit->text().isEmpty() 00117 ); 00118 } 00119 00120 void ThymioFlasherDialog::openFile(void) 00121 { 00122 QString name = QFileDialog::getOpenFileName(this, tr("Select hex file"), QString(), tr("Hex files (*.hex)")); 00123 lineEdit->setText(name); 00124 setupFlashButtonState(); 00125 } 00126 00127 void ThymioFlasherDialog::doFlash(void) 00128 { 00129 // warning message 00130 const int warnRet = QMessageBox::warning(this, tr("Pre-update warning"), tr("Your are about to write a new firmware to the Thymio II. Make sure that the robot is charged and that the USB cable is properly connected.<p><b>Do not unplug the robot during the update!</b></p>Are you sure you want to proceed?"), QMessageBox::No|QMessageBox::Yes, QMessageBox::No); 00131 if (warnRet != QMessageBox::Yes) 00132 return; 00133 00134 // disable buttons while flashing 00135 quitButton->setEnabled(false); 00136 flashButton->setEnabled(false); 00137 fileButton->setEnabled(false); 00138 lineEdit->setEnabled(false); 00139 00140 // start flash thread 00141 Q_ASSERT(!flashFuture.isRunning()); 00142 const string hexFileName(lineEdit->text().toLocal8Bit().constData()); 00143 flashFuture = QtConcurrent::run(this, &ThymioFlasherDialog::flashThread, target, hexFileName); 00144 flashFutureWatcher.setFuture(flashFuture); 00145 } 00146 00147 ThymioFlasherDialog::FlashResult ThymioFlasherDialog::flashThread(const std::string& _target, const std::string& hexFileName) const 00148 { 00149 // open stream 00150 Dashel::Hub hub; 00151 Dashel::Stream* stream(0); 00152 try 00153 { 00154 stream = hub.connect(_target); 00155 } 00156 catch (Dashel::DashelException& e) 00157 { 00158 return FlashResult(FlashResult::WARNING, tr("Cannot connect to target"), tr("Cannot connect to target: %1").arg(e.what())); 00159 } 00160 00161 // do flash 00162 try 00163 { 00164 QtBootloaderInterface bootloaderInterface(stream, 1); 00165 connect(&bootloaderInterface, SIGNAL(flashProgress(int)), this, SLOT(flashProgress(int)), Qt::QueuedConnection); 00166 bootloaderInterface.writeHex(hexFileName, true, true); 00167 } 00168 catch (HexFile::Error& e) 00169 { 00170 return FlashResult(FlashResult::WARNING, tr("Update Error"), tr("Unable to read Hex file: %1").arg(e.toString().c_str())); 00171 } 00172 catch (BootloaderInterface::Error& e) 00173 { 00174 return FlashResult(FlashResult::FAILURE, tr("Update Error"), tr("A bootloader error happened during the update process: %1").arg(e.what())); 00175 } 00176 catch (Dashel::DashelException& e) 00177 { 00178 return FlashResult(FlashResult::FAILURE, tr("Update Error"), tr("A communication error happened during the update process: %1").arg(e.what())); 00179 } 00180 return FlashResult(); 00181 } 00182 00183 void ThymioFlasherDialog::flashProgress(int percentage) 00184 { 00185 progressBar->setValue(percentage); 00186 } 00187 00188 void ThymioFlasherDialog::flashFinished() 00189 { 00190 // re-enable buttons 00191 quitButton->setEnabled(true); 00192 flashButton->setEnabled(true); 00193 fileButton->setEnabled(true); 00194 lineEdit->setEnabled(true); 00195 00196 // handle flash result 00197 const FlashResult& result(flashFutureWatcher.result()); 00198 if (result.status == FlashResult::WARNING) 00199 { 00200 QMessageBox::warning(this, result.title, result.text); 00201 } 00202 else if (result.status == FlashResult::FAILURE) 00203 { 00204 QMessageBox::critical(this, result.title, result.text); 00205 close(); 00206 } 00207 } 00208 }; 00209 00210 00211 int main(int argc, char *argv[]) 00212 { 00213 QApplication app(argc, argv); 00214 00215 QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8")); 00216 00217 QTranslator qtTranslator; 00218 QTranslator translator; 00219 app.installTranslator(&qtTranslator); 00220 app.installTranslator(&translator); 00221 qtTranslator.load(QString("qt_") + QLocale::system().name(), QLibraryInfo::location(QLibraryInfo::TranslationsPath)); 00222 translator.load(QString(":/thymioflasher_") + QLocale::system().name()); 00223 00224 const Aseba::PortsMap ports = Dashel::SerialPortEnumerator::getPorts(); 00225 std::string target("ser:device="); 00226 bool thymioFound(false); 00227 bool thymiosFound(false); 00228 for (Aseba::PortsMap::const_iterator it = ports.begin(); it != ports.end(); ++it) 00229 { 00230 if (it->second.second.compare(0,9,"Thymio-II") == 0) 00231 { 00232 if (thymioFound) 00233 thymiosFound = true; 00234 thymioFound = true; 00235 target += it->second.first; 00236 //std::cout << target << std::endl; 00237 } 00238 } 00239 if (!thymioFound) 00240 { 00241 QMessageBox::critical(0, QApplication::tr("Thymio II not found"), QApplication::tr("<p><b>Cannot find Thymio II!</b></p><p>Plug Thymio II or use the command-line updater.</p>")); 00242 return 1; 00243 } 00244 if (thymiosFound) 00245 { 00246 QMessageBox::critical(0, QApplication::tr("Multiple Thymio II found"), QApplication::tr("<p><b>More than one Thymio II found!</b></p><p>Plug a single Thymio II or use the command-line updater.</p>")); 00247 return 2; 00248 } 00249 00250 Aseba::ThymioFlasherDialog flasher(target); 00251 00252 return app.exec(); 00253 }